commit 4d3568c4b5b9c68562fcdad8ec767abb6da9ef9d
parent ce63038cf2e88ea42056d67af57c0ed16e0d7fc1
Author: lash <dev@holbrook.no>
Date: Tue, 21 Feb 2023 14:21:55 +0000
Implement metadata endpoint
Diffstat:
3 files changed, 73 insertions(+), 9 deletions(-)
diff --git a/js/qrread.html b/js/qrread.html
@@ -3,6 +3,7 @@
<title>webcam</title>
<script src="node_modules/jsqr/dist/jsQR.js"></script>
<script src="node_modules/ethers/dist/ethers.umd.min.js"></script>
+ <script src="src/wala.js"></script>
<script src="qrread.js"></script>
<script src="qrread_ui.js"></script>
<link rel="stylesheet" href="style.css"></link>
@@ -25,18 +26,28 @@ window.addEventListener('load', () => {
return keyFileHandler(keyFile, keyFilePassword);
});
document.getElementById('chainSubmit').addEventListener("click", (o) => {
- const chainId = document.getElementById("chainId").value;
- const chainRpcUrl = document.getElementById("chainRpcUrl").value;
const submit = document.getElementById('chainSubmit');
submit.setAttribute('disabled', 1);
- return chainHandler(chainRpcUrl, chainId);
+ const chainId = document.getElementById("chainId").value;
+ const chainRpcUrl = document.getElementById("chainRpcUrl").value;
+ chainHandler(chainRpcUrl, chainId);
+ let metaUrl = document.getElementById("metaUrl").value;
+ if (metaUrl != '') {
+ metaHandler(metaUrl);
+ }
});
document.getElementById('contractSubmit').addEventListener("click", (o) => {
const tokenAddress = document.getElementById("contractAddress").value;
return contractHandler(tokenAddress);
});
document.getElementById('requestSubmit').addEventListener("click", (o) => {
- const tokenBatch = document.getElementById("tokenBatch").value;
+ let tokenBatch = undefined;
+ const batches = document.getElementsByName('tokenBatch');
+ for(let i = 0; i < batches.length; i++){
+ if(batches[i].checked){
+ tokenBatch = batches[i].value;
+ }
+ }
const amount = document.getElementById("requestAmount").value;
return requestHandler(tokenBatch, amount);
});
@@ -95,6 +106,8 @@ window.addEventListener('load', () => {
<input type="text" id="chainRpcUrl" value="http://localhost:8545" />
<label for="chainId">Chain ID</label>
<input type="text" id="chainId" />
+ <label for="metaUrl">Data URL (optional)</label>
+ <input type="text" id="metaUrl" value="" />
<button id="chainSubmit">connect to network</button>
</div>
<div class="pane" id="contract">
@@ -110,10 +123,14 @@ window.addEventListener('load', () => {
<button id="requestSubmit">create request</button>
</div>
<div class="pane" id="read">
- <h2>Scan QR code</h2>
+ <h2>Mint token(s)</h2>
<dl>
<dt>Token Id</dt>
<dd id="scanTokenId"></dd>
+ <dt>Token Name</dt>
+ <dd id="scanTokenMetaName">(unavailable)</dd>
+ <dt>Token Description</dt>
+ <dd id="scanTokenMetaDescription">(unavailable)</dd>
<dt>Batch</dt>
<dd id="scanTokenBatch"></dd>
<dt>Amount</dt>
diff --git a/js/qrread.js b/js/qrread.js
@@ -21,6 +21,8 @@ var settings = {
wallet: undefined,
chainId: undefined,
dataPost: undefined,
+ metaInterface: undefined,
+ metaCanWrite: false,
mintAmount: 1,
minedAmount: 0,
failedAmount: 0,
@@ -167,13 +169,29 @@ async function scanContract(addr) {
setTimeout(scanContractTokens, 0, addr);
}
-function contractHandler(addr) {
+async function contractHandler(addr) {
checkState(STATE.WALLET_SETTINGS | STATE.NETWORK_SETTINGS, true);
setStatus('check if wallet can mint...', STATUS_BUSY);
setTimeout(checkContractOwner, 0, addr);
}
+async function metaHandler(url) {
+ settings.metaInterface = new Wala(url);
+ try {
+ settings.metaInterface.put('foo');
+ settings.metaCanWrite = true;
+ } catch {
+ console.warn('cannot write to data URL', url);
+ }
+ //try {
+ // settings.metaInterface.get('');
+ //} catch(e) {
+ // console.warn('cannot read from data URL', url, e);
+ // settings.metaInterace = undefined;
+ //}
+}
+
async function scanContractTokens(contractAddress) {
const contract = new ethers.Contract(contractAddress, nftAbi, settings.provider);
let i = 0;
@@ -237,12 +255,41 @@ async function scanContractTokens(contractAddress) {
setStatus('found ' + c + ' available token batches in contract', STATUS_OK);
}
-function requestHandler(tokenBatch, amount) {
- setStatus('scan QR code or manually enter address...', STATUS_BUSY);
+async function scanTokenMetadata(tokenId) {
+ if (settings.metaInterface === undefined) {
+ console.debug('skip metadata lookup since interface is not available');
+ return;
+ }
+ setStatus('scan token metadata...', STATUS_BUSY);
+ if (tokenId.length < 64) {
+ setStatus('invalid token id length', STATUS_ERROR);
+ throw 'invalid token id length';
+ } else if (tokenId.substring(0, 2) == '0x') {
+ tokenId = tokenId.substring(2);
+ }
+ let r = undefined;
+ try {
+ r = await settings.metaInterface.get(tokenId);
+ } catch(e) {
+ setStatus('metadata lookup failed', STATUS_ERROR);
+ document.getElementById('scanTokenMetaName').innerHTML = '(unavailable)';
+ document.getElementById('scanTokenMetaDescription').innerHTML = '(unavailable)';
+ return;
+ }
+ const o = JSON.parse(r);
+ setStatus('found token metadata', STATUS_OK);
+ console.debug('metadata token', tokenId, o);
+ document.getElementById('scanTokenMetaName').innerHTML = o['name'];
+ document.getElementById('scanTokenMetaDescription').innerHTML = o['description'];
+}
+
+async function requestHandler(tokenBatch, amount) {
const v = tokenBatch.split('.');
let batchNumberHex = "0000000000000000000000000000000000000000000000000000000000000000" + v[1].toString(16);
batchNumberHex = batchNumberHex.slice(-64);
let tokenId = v[0].substring(2);
+ await scanTokenMetadata(tokenId);
+ setStatus('scan QR code or manually enter address...', STATUS_BUSY);
settings.dataPost = tokenId + batchNumberHex;
settings.tokenId = tokenId;
settings.batchNumber = v[1];
diff --git a/js/qrread_ui.js b/js/qrread_ui.js
@@ -98,7 +98,7 @@ window.addEventListener('token', (e) => {
const ls = document.getElementById('tokenChooser');
const v = e.detail.tokenId + '.' + e.detail.batch;
const input = document.createElement('input');
- input.setAttribute('id', 'tokenBatch');
+ input.setAttribute('id', 'tokenBatch.' + v);
input.setAttribute('name', 'tokenBatch');
input.setAttribute('type', 'radio');
input.setAttribute('value', v);