craft-nft

A standalone NFT implementation for real-world arts and crafts assets
Log | Files | Refs | README

commit f4899995d51f200254b8de2745001a6df68c3fa6
parent fb2dea044f73e4e2934c692fca2340350eb17421
Author: lash <dev@holbrook.no>
Date:   Thu,  2 Mar 2023 14:03:56 +0000

Add wallet generation to qr app

Diffstat:
Mjs/qrread.html | 10++++++++++
Mjs/qrread.js | 55++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mjs/qrread_ui.js | 8++++++++
3 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/js/qrread.html b/js/qrread.html @@ -102,6 +102,15 @@ window.addEventListener('load', () => { }); window.dispatchEvent(e); }); + + document.getElementById('keyFileGenerate').addEventListener("click", (o) => { + //const btn = document.getElementById('keyFileGenerate'); + //btn.setAttribute('disabled', 1); + document.getElementById('keyFile').value = null; + const passphrase = document.getElementById('keyFilePassword').value; + generateWallet(passphrase); + }); + document.getElementById('scanManualMint').addEventListener("click", (o) => { const addr = document.getElementById("scanAddress").value; manualConfirmHandler(addr); @@ -122,6 +131,7 @@ window.addEventListener('load', () => { <textarea cols="80" rows="24" id="keyFile"></textarea> <label for="keyFilePassword">Keyfile passphrase</label> <input type="password" id="keyFilePassword" /> + <button id="keyFileGenerate">generate wallet</button> <button id="keyFileSubmit">unlock wallet</button> </div> <div class="pane" id="connect"> diff --git a/js/qrread.js b/js/qrread.js @@ -10,9 +10,12 @@ const STATE = { SCAN_CONFIRM: 128, SCAN_DONE: 256, AIEE: 512, + WALLET_GENERATED: 1024, + WALLET_FAIL: 2048, }; var settings = { + keyFile: undefined, privateKey: undefined, tokenAddress: undefined, tokenId: undefined, @@ -214,12 +217,33 @@ async function signAndSend() { setStatus('verifying transactions...', STATUS_BUSY); } +function unlockWalletProgress(v) { + setStatus("unlocking wallet: " + parseInt(v * 100) + "%", STATUS_BUSY); +} + async function keyFileHandler(v, passphrase) { - setStatus('unlocking keyfile...', STATUS_BUSY); + //setStatus('unlocking keyfile...', STATUS_BUSY); console.debug('wallet', settings.wallet); // make sure dom updates are executed before unlock - setTimeout(() => { - settings.wallet = ethers.Wallet.fromEncryptedJsonSync(v, passphrase); + setTimeout(async () => { + try { + settings.wallet = await ethers.Wallet.fromEncryptedJson(v, passphrase, unlockWalletProgress); + } catch(e) { + state |= STATE.WALLET_SETTINGS; + const ev = new CustomEvent('uistate', { + detail: { + delta: STATE.WALLET_FAIL, + settings: settings, + }, + bubbles: true, + cancelable: true, + composed: false, + }); + window.dispatchEvent(ev); + setStatus('keyfile unlock fail. wrong passphrase?', STATUS_ERROR); + console.error(e); + return; + } state |= STATE.WALLET_SETTINGS; const e = new CustomEvent('uistate', { detail: { @@ -495,6 +519,31 @@ async function requestHandler(tokenBatch, amount) { window.dispatchEvent(e); } +function generateWalletProgress(v) { + setStatus('encrypting wallet for ' + settings.wallet.address + ": " + parseInt(v * 100) + "%", STATUS_BUSY); +} + +async function generateWallet(passphrase) { + setStatus('generating new wallet', STATUS_BUSY); + const mn = await ethers.Wallet.createRandom(); + const wallet = new ethers.Wallet(mn.privateKey); + settings.wallet = wallet; + const keyfile = await wallet.encrypt(passphrase, {}, generateWalletProgress); + settings.keyFile = keyfile; + console.debug('settings now', settings); + setStatus('generated new wallet: ' + settings.wallet.address + ". <blink>REMEMBER TO COPY AND STORE!</blink>", STATUS_OK); + const e = new CustomEvent('uistate', { + detail: { + delta: STATE.WALLET_GENERATED, + settings: settings, + }, + bubbles: true, + cancelable: true, + composed: false, + }); + window.dispatchEvent(e); +} + const nftAbi = [{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_minter","type":"address"},{"indexed":true,"internalType":"uint48","name":"_count","type":"uint48"},{"indexed":true,"internalType":"bool","name":"_capped","type":"bool"},{"indexed":false,"internalType":"bytes32","name":"_tokenId","type":"bytes32"}],"name":"Allocate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_operator","type":"address"},{"indexed":false,"internalType":"bool","name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_minter","type":"address"},{"indexed":true,"internalType":"address","name":"_beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"_multiHash","type":"bytes"}],"name":"Msg","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_data","type":"bytes32"}],"name":"TransferWithData","type":"event"},{"inputs":[{"internalType":"uint8","name":"_length","type":"uint8"},{"internalType":"uint64","name":"_codecId","type":"uint64"},{"internalType":"string","name":"_uriPrefix","type":"string"}],"name":"addCodec","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_writer","type":"address"}],"name":"addWriter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"content","type":"bytes32"},{"internalType":"int48","name":"count","type":"int48"}],"name":"allocate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURL","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_writer","type":"address"}],"name":"deleteWriter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_truncatedId","type":"bytes32"}],"name":"getDigest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getDigestHex","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getMsg","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_writer","type":"address"}],"name":"isWriter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"bytes32","name":"_content","type":"bytes32"},{"internalType":"uint16","name":"_batch","type":"uint16"},{"internalType":"uint48","name":"_index","type":"uint48"}],"name":"mintExactFromBatchTo","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"bytes32","name":"_content","type":"bytes32"},{"internalType":"uint16","name":"_batch","type":"uint16"}],"name":"mintFromBatchTo","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"bytes32","name":"_content","type":"bytes32"}],"name":"mintTo","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"mintedToken","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"multiCodecs","outputs":[{"internalType":"uint8","name":"l","type":"uint8"},{"internalType":"uint8","name":"codecRLength","type":"uint8"},{"internalType":"uint8","name":"prefixRLength","type":"uint8"},{"internalType":"bytes16","name":"prefix","type":"bytes16"},{"internalType":"bytes8","name":"codec","type":"bytes8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseString","type":"string"}],"name":"setBaseURL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_content","type":"bytes32"},{"internalType":"uint16","name":"_batch","type":"uint16"},{"internalType":"uint48","name":"_cap","type":"uint48"}],"name":"setCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_digest","type":"bytes"}],"name":"setMsg","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_codec","type":"uint256"}],"name":"setMsgCodec","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_digest","type":"bytes"}],"name":"toHash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"toHex","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"_digest","type":"bytes"}],"name":"toURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"toURL","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"token","outputs":[{"internalType":"uint48","name":"count","type":"uint48"},{"internalType":"uint48","name":"cursor","type":"uint48"},{"internalType":"bool","name":"sparse","type":"bool"},{"internalType":"bool","name":"capped","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokens","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]; diff --git a/js/qrread_ui.js b/js/qrread_ui.js @@ -46,6 +46,14 @@ function setStatus(s, typ) { window.addEventListener('uistate', (e) => { console.debug('statechange', e); switch (e.detail.delta) { + case STATE.WALLET_GENERATED: + document.getElementById("keyFile").value = e.detail.settings.keyFile; + break; + case STATE.WALLET_FAIL: + const btn = document.getElementById("keyFileSubmit"); + btn.removeAttribute('disabled'); + console.debug(btn); + break; case STATE.WALLET_SETTINGS: updateSettingsView('Wallet address', e.detail.settings.wallet.address); document.getElementById("start").style.display = "none";