From b54ccfd7707422cf79555e54c9d924172b8e1df0 Mon Sep 17 00:00:00 2001 From: BokkyPooBah Date: Thu, 22 Feb 2024 01:05:14 +1100 Subject: [PATCH] names wip --- docs/index.html | 2 + docs/index.js | 1 + docs/names.js | 631 ++++++++++++++++++++++++++++++++++++++++++++++++ docs/routes.js | 4 + 4 files changed, 638 insertions(+) create mode 100644 docs/names.js diff --git a/docs/index.html b/docs/index.html index 5b49916..c063992 100644 --- a/docs/index.html +++ b/docs/index.html @@ -64,6 +64,7 @@ + @@ -101,6 +102,7 @@ Addresses + Names diff --git a/docs/index.js b/docs/index.js index b692052..a9dd3ed 100644 --- a/docs/index.js +++ b/docs/index.js @@ -63,6 +63,7 @@ const store = new Vuex.Store({ connection: connectionModule, welcome: welcomeModule, collections: collectionsModule, + names: namesModule, tokens: tokensModule, owners: ownersModule, sales: salesModule, diff --git a/docs/names.js b/docs/names.js new file mode 100644 index 0000000..4866e71 --- /dev/null +++ b/docs/names.js @@ -0,0 +1,631 @@ +const Names = { + template: ` +
+ + + + + + + Drip {{ modalFaucet.selectedFaucet && faucets.filter(e => e.address == modalFaucet.selectedFaucet)[0] ? (faucets.filter(e => e.address == modalFaucet.selectedFaucet)[0].drip + ' Tokens') : '' }} + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + + + + + + Exclude Junk + + + + + + + Include Junk + + + + + + Junk + + +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ + + {{ sync.total == null ? (sync.completed + ' ' + sync.section) : (sync.completed + '/' + sync.total + ' ' + ((sync.completed / sync.total) * 100).toFixed(0) + '% ' + sync.section) }} + + +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ {{ filteredSortedItems.length + '/' + totalCollections }} +
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ `, + data: function () { + return { + count: 0, + reschedule: true, + settings: { + filter: null, + junkFilter: null, + favouritesOnly: false, + currentPage: 1, + pageSize: 100, + sortOption: 'tokenidasc', + version: 0, + }, + transfer: { + item: null, + stealthPrivateKey: null, + }, + modalFaucet: { + selectedFaucet: null, + }, + sortOptions: [ + { value: 'tokenidasc', text: '▲ TokenId' }, + { value: 'tokeniddsc', text: '▼ TokenId' }, + ], + fields: [ + { key: 'number', label: '#', sortable: false, thStyle: 'width: 5%;', tdClass: 'text-truncate text-muted small' }, + // { key: 'tokenId', label: 'TokenId', sortable: false, thStyle: 'width: 16%;', thClass: 'text-left', tdClass: 'text-truncate' }, + { key: 'image', label: 'Image', sortable: false, thStyle: 'width: 10%;', thClass: 'text-left', tdClass: 'text-truncate' }, + { key: 'name', label: 'Name/Description', sortable: false, thStyle: 'width: 25%;', thClass: 'text-left', tdClass: 'text-left' }, + { key: 'owner', label: 'Owner/Tags', sortable: false, thStyle: 'width: 30%;', thClass: 'text-left', tdClass: 'text-left' }, + { key: 'attributes', label: 'Attributes', sortable: false, thStyle: 'width: 30%;', thClass: 'text-left', tdClass: 'text-left' }, + ], + } + }, + computed: { + powerOn() { + return store.getters['connection/powerOn']; + }, + coinbase() { + return store.getters['connection/coinbase']; + }, + chainId() { + return store.getters['connection/chainId']; + }, + chainInfo() { + return store.getters['config/chainInfo']; + }, + sync() { + return store.getters['data/sync']; + }, + pageSizes() { + return store.getters['config/pageSizes']; + }, + collections() { + return store.getters['data/collections']; + }, + selectedCollection() { + return store.getters['data/selectedCollection']; + }, + ens() { + return store.getters['data/ens']; + }, + idFilter: { + get: function () { + return store.getters['data/idFilter']; + }, + set: function (idFilter) { + store.dispatch('data/setIdFilter', idFilter); + }, + }, + ownerFilter: { + get: function () { + return store.getters['data/ownerFilter']; + }, + set: function (ownerFilter) { + store.dispatch('data/setOwnerFilter', ownerFilter); + }, + }, + showSideFilter: { + get: function () { + return store.getters['data/showSideFilter']; + }, + set: function (show) { + store.dispatch('data/setShowSideFilter', show); + }, + }, + selectedCollection: { + get: function () { + return store.getters['data/selectedCollection']; + }, + set: function (sc) { + store.dispatch('data/setSelectedCollection', sc); + // store.dispatch('viewToken/setMine', mine); + }, + }, + tokens() { + return store.getters['data/tokens']; + }, + + addresses() { + return store.getters['data/addresses']; + }, + registry() { + return store.getters['data/registry']; + }, + tokenContracts() { + return store.getters['data/tokenContracts']; + }, + tokenMetadata() { + return store.getters['data/tokenMetadata']; + }, + + collectionsOptions() { + const results = []; + results.push({ value: null, text: '(select an NFT collection)' }); + for (const [address, data] of Object.entries(this.collections[this.chainId] || {})) { + results.push({ + value: address, + text: data.symbol + ": " + data.name, + }); + } + return results; + }, + + + faucets() { + return FAUCETS && FAUCETS[this.chainId]; + }, + faucetsOptions() { + const results = []; + if (FAUCETS && FAUCETS[this.chainId]) { + results.push({ value: null, text: '(select a faucet)' }); + for (const item of FAUCETS[this.chainId]) { + if (item.type == "erc721") { + results.push({ + value: item.address, + text: item.drip + " x " + (item.type == "erc20" ? "ERC-20 " : "ERC-721 ") + item.symbol + ' ' + item.name + (item.type == "erc20" ? " (" + item.decimals + " dp)" : "") + ' @ ' + item.address.substring(0, this.ADDRESS_SEGMENT_LENGTH + 2) + '...' + item.address.slice(-this.ADDRESS_SEGMENT_LENGTH), + }); + } + } + } + return results; + }, + + totalCollections() { + const tokens = this.tokens[this.chainId] && this.tokens[this.chainId][this.selectedCollection] || {}; + return (store.getters['data/forceRefresh'] % 2) == 0 ? Object.keys(tokens).length : Object.keys(tokens).length; + }, + filteredItems() { + const results = (store.getters['data/forceRefresh'] % 2) == 0 ? store.getters['data/filteredTokens'] : store.getters['data/filteredTokens']; + let regex = null; + if (this.settings.filter != null && this.settings.filter.length > 0) { + try { + regex = new RegExp(this.settings.filter, 'i'); + } catch (e) { + console.log("filteredItems - regex error: " + e.message); + regex = new RegExp(/thequickbrowndogjumpsoverthelazyfox/, 'i'); + } + } + return results; + }, + filteredSortedItems() { + const results = this.filteredItems; + if (this.settings.sortOption == 'tokenidasc') { + results.sort((a, b) => { + return a.tokenId - b.tokenId; + }); + } else if (this.settings.sortOption == 'tokeniddsc') { + results.sort((a, b) => { + return b.tokenId - a.tokenId; + }); + } + return results; + }, + pagedFilteredSortedItems() { + // logInfo("Names", "pagedFilteredSortedItems - results[0..1]: " + JSON.stringify(this.filteredSortedItems.slice(0, 2), null, 2)); + return this.filteredSortedItems.slice((this.settings.currentPage - 1) * this.settings.pageSize, this.settings.currentPage * this.settings.pageSize); + }, + + }, + methods: { + viewFaucets() { + console.log(moment().format("HH:mm:ss") + " viewFaucets"); + this.$bvModal.show('modal-faucets'); + }, + async drip() { + console.log(moment().format("HH:mm:ss") + " drip BEGIN: " + JSON.stringify(this.modalFaucet, null, 2)); + const provider = new ethers.providers.Web3Provider(window.ethereum); + const signer = provider.getSigner(); + const faucetInfo = FAUCETS[this.chainId] && FAUCETS[this.chainId].filter(e => e.address == this.modalFaucet.selectedFaucet)[0] || null; + if (faucetInfo) { + console.log("faucetInfo: " + JSON.stringify(faucetInfo, null, 2)); + if (faucetInfo.type == "erc20") { + try { + const tx = await signer.sendTransaction({ to: faucetInfo.address, value: "0" }); + console.log("tx: " + JSON.stringify(tx)); + } catch (e) { + console.log("drip ERC-20 - error: " + JSON.stringify(e)); + } + } else { + const testToadzContract = new ethers.Contract(faucetInfo.address, TESTTOADZABI, provider); + const testToadzContractWithSigner = testToadzContract.connect(provider.getSigner()); + try { + const tx = await testToadzContractWithSigner.mint(3); + console.log("tx: " + JSON.stringify(tx)); + } catch (e) { + console.log("drip ERC-721 - error: " + JSON.stringify(e)); + } + } + } + }, + + saveTokenTag(info) { + logInfo("Names", ".methods.saveTokenTag - info: " + JSON.stringify(info, null, 2)); + store.dispatch('data/saveTokenTag', info); + }, + toggleTokenContractJunk(item) { + logInfo("Names", ".methods.toggleTokenContractJunk - item: " + JSON.stringify(item, null, 2)); + store.dispatch('data/toggleTokenContractJunk', item); + }, + toggleTokenContractFavourite(item) { + logInfo("Names", ".methods.toggleTokenContractFavourite - item: " + JSON.stringify(item, null, 2)); + store.dispatch('data/toggleTokenContractFavourite', item); + }, + + async requestReservoirAPITokenMetadataRefresh(token) { + logInfo("Names", ".methods.requestReservoirAPITokenMetadataRefresh - token: " + JSON.stringify(token, null, 2)); + const options = { + method: 'POST', + // mode: 'no-cors', // cors, no-cors, *cors, same-origin + headers: {accept: '*/*', 'content-type': 'application/json', 'x-api-key': 'demo-api-key'}, + body: JSON.stringify({ + overrideCoolDown: false, + token: token.contract + ':' + token.tokenId, + }) + }; + console.log("options: " + JSON.stringify(options, null, 2)); + const results = await fetch('https://api.reservoir.tools/tokens/refresh/v1', options) + .then(response => response.json()) + .then(response => console.log(response)) + .catch(err => console.error(err)); + console.log("results: " + JSON.stringify(results)); + + this.$bvToast.toast("Please retry after 5 minutes if required", { + title: 'Metadata Refresh Requested. Please refresh the collection metadata in a few minutes', + autoHideDelay: 5000, + appendToast: true, + }); + // setTimeout(function() { + // store.dispatch('data/refreshTokenMetadata', token); + // }, 5000); + // alert("Request sent and will data will be auto-refreshed in 5 seconds. Manually refresh the locally cached token metadata if required") + }, + + nameOrAddress(address, length = 18) { + if (address) { + if (this.ens[address]) { + if (length == 0) { + return this.ens[address]; + } else { + if (this.ens[address].length <= length) { + return this.ens[address]; + } else { + return this.ens[address].substring(0, length - 10) + "..." + this.ens[address].slice(-7); + } + } + } else { + if (length == 0) { + return address; + } else { + return address.substring(0, ((length - 2) / 2) + 2) + "..." + address.slice(-(length - 2)/2); + } + } + } + return null; + }, + + copyToClipboard(str) { + navigator.clipboard.writeText(str); + }, + formatETH(e, precision = 0) { + try { + if (precision == 0) { + return e ? ethers.utils.formatEther(e).replace(/\B(? 1000000000000n) { + ts = ts / 1000; + } + if (store.getters['config/settings'].reportingDateTime) { + return moment.unix(ts).utc().format("YYYY-MM-DD HH:mm:ss"); + } else { + return moment.unix(ts).format("YYYY-MM-DD HH:mm:ss"); + } + } + return null; + }, + commify0(n) { + if (n != null) { + return Number(n).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 0 }); + } + return null; + }, + rowSelected(item) { + logInfo("Names", "methods.rowSelected BEGIN: " + JSON.stringify(item, null, 2)); + // if (item && item.length > 0) { + // store.dispatch('viewToken/viewToken', { address: item[0].address, tokenId: item[0].tokenId }); + // this.$refs.tokenContractsTable.clearSelected(); + // } + }, + + async revealTransferSpendingPrivateKey() { + function computeStealthKey(ephemeralPublicKey, viewingPrivateKey, spendingPrivateKey) { + const result = {}; + result.sharedSecret = nobleCurves.secp256k1.getSharedSecret(viewingPrivateKey.substring(2), ephemeralPublicKey.substring(2), false); + result.hashedSharedSecret = ethers.utils.keccak256(result.sharedSecret.slice(1)); + const stealthPrivateKeyNumber = (BigInt(spendingPrivateKey) + BigInt(result.hashedSharedSecret)) % BigInt(SECP256K1_N); + const stealthPrivateKeyString = stealthPrivateKeyNumber.toString(16); + result.stealthPrivateKey = "0x" + stealthPrivateKeyString.padStart(64, '0'); + result.stealthPublicKey = "0x" + nobleCurves.secp256k1.ProjectivePoint.fromPrivateKey(stealthPrivateKeyNumber).toHex(false); + result.stealthAddress = ethers.utils.computeAddress(result.stealthPublicKey); + return result; + } + + console.log(moment().format("HH:mm:ss") + " revealTransferSpendingPrivateKey - transfer: " + JSON.stringify(this.transfer, null, 2)); + const stealthMetaAddressData = this.addresses[this.transfer.item.linkedTo.stealthMetaAddress]; + console.log(moment().format("HH:mm:ss") + " revealTransferSpendingPrivateKey - stealthMetaAddressData: " + JSON.stringify(stealthMetaAddressData, null, 2)); + const phraseInHex = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(stealthMetaAddressData.phrase)); + const signature = await ethereum.request({ + method: 'personal_sign', + params: [phraseInHex, this.coinbase], + }); + const signature1 = signature.slice(2, 66); + const signature2 = signature.slice(66, 130); + // Hash "v" and "r" values using SHA-256 + const hashedV = ethers.utils.sha256("0x" + signature1); + const hashedR = ethers.utils.sha256("0x" + signature2); + const n = ethers.BigNumber.from(SECP256K1_N); + // Calculate the private keys by taking the hash values modulo the curve order + const privateKey1 = ethers.BigNumber.from(hashedV).mod(n); + const privateKey2 = ethers.BigNumber.from(hashedR).mod(n); + const keyPair1 = new ethers.Wallet(privateKey1.toHexString()); + const keyPair2 = new ethers.Wallet(privateKey2.toHexString()); + const spendingPrivateKey = keyPair1.privateKey; + const viewingPrivateKey = keyPair2.privateKey; + const spendingPublicKey = ethers.utils.computePublicKey(keyPair1.privateKey, true); + const viewingPublicKey = ethers.utils.computePublicKey(keyPair2.privateKey, true); + // const stealthMetaAddress = "st:eth:" + spendingPublicKey + viewingPublicKey.substring(2); + console.log(moment().format("HH:mm:ss") + " revealTransferSpendingPrivateKey - spendingPrivateKey: " + spendingPrivateKey); + const computedStealthKey = computeStealthKey(this.transfer.item.ephemeralPublicKey, viewingPrivateKey, spendingPrivateKey); + const stealthPrivateKey = computedStealthKey.stealthPrivateKey; + // Vue.set(this.transfer, 'stealthPrivateKey', stealthPrivateKey); + this.transfer.stealthPrivateKey = stealthPrivateKey; + console.log("this.transfer: " + JSON.stringify(this.transfer, null, 2)); + }, + + async timeoutCallback() { + logDebug("Names", "timeoutCallback() count: " + this.count); + + this.count++; + var t = this; + if (this.reschedule) { + setTimeout(function() { + t.timeoutCallback(); + }, 15000); + } + }, + }, + beforeDestroy() { + logDebug("Names", "beforeDestroy()"); + }, + mounted() { + logDebug("Names", "mounted() $route: " + JSON.stringify(this.$route.params)); + store.dispatch('data/restoreState'); + if ('nftSpreadsTokensSettings' in localStorage) { + const tempSettings = JSON.parse(localStorage.nftSpreadsTokensSettings); + if ('version' in tempSettings && tempSettings.version == 0) { + this.settings = tempSettings; + this.settings.currentPage = 1; + } + } + this.reschedule = true; + logDebug("Names", "Calling timeoutCallback()"); + this.timeoutCallback(); + }, + destroyed() { + this.reschedule = false; + }, +}; + +const namesModule = { + namespaced: true, + state: { + params: null, + executing: false, + executionQueue: [], + }, + getters: { + params: state => state.params, + executionQueue: state => state.executionQueue, + }, + mutations: { + deQueue(state) { + logDebug("namesModule", "deQueue(" + JSON.stringify(state.executionQueue) + ")"); + state.executionQueue.shift(); + }, + updateParams(state, params) { + state.params = params; + logDebug("namesModule", "updateParams('" + params + "')") + }, + updateExecuting(state, executing) { + state.executing = executing; + logDebug("namesModule", "updateExecuting(" + executing + ")") + }, + }, + actions: { + }, +}; diff --git a/docs/routes.js b/docs/routes.js index da62809..9a4a861 100644 --- a/docs/routes.js +++ b/docs/routes.js @@ -26,6 +26,10 @@ const routes = [{ path: '/sales', component: Sales, name: 'Sales', + }, { + path: '/names', + component: Names, + name: 'Names', }, { path: '/tokens', component: Tokens,