├── tests ├── parity-dev.pwds ├── run-parity.sh ├── parity-keys │ └── UTC--2019-06-25T00-14-25Z--24d70b97-fff9-d322-e760-4b8cc2e21751 ├── parity-dev.json ├── source-mapper.js └── takoyaki.js ├── heroku-app ├── Procfile ├── static │ ├── favicon.ico │ ├── debug.html │ ├── logo-metamask.svg │ ├── index.html │ ├── script.js │ └── history.js ├── package.json ├── README.md └── static-fallback │ ├── debug.html │ ├── logo-metamask.svg │ ├── index.html │ ├── script.js │ └── history.js ├── lib ├── ethers-browser.js ├── assets │ ├── takoyaki.ai │ ├── favicon-16.png │ ├── favicon-256.png │ ├── favicon-32.png │ └── favicon-48.png ├── .npmignore ├── thirdparty.d.ts ├── scripts │ ├── generate.js │ └── README.md ├── lib │ ├── random.d.ts │ ├── svg-parser.d.ts │ ├── random.js │ ├── index.d.ts │ └── svg-parser.js ├── tsconfig.json ├── rollup.config.js ├── LICENSE.md ├── package.json ├── src.ts │ ├── random.ts │ └── svg-parser.ts └── README.md ├── .gitignore ├── static ├── favicon.ico ├── spinner.gif ├── background.jpg ├── style-mobile.css ├── logo-metamask.svg ├── style.css └── history.js ├── contracts └── Wallet.sol ├── LICENSE ├── package.json ├── README.md ├── .circleci └── config.yml ├── bin ├── deploy.js ├── build-history.js └── ens.js └── index.html /tests/parity-dev.pwds: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /heroku-app/Procfile: -------------------------------------------------------------------------------- 1 | web: node index.js 2 | -------------------------------------------------------------------------------- /lib/ethers-browser.js: -------------------------------------------------------------------------------- 1 | module.exports = global.ethers; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | wallet.json 4 | *~ 5 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricmoo/Takoyaki/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /static/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricmoo/Takoyaki/HEAD/static/spinner.gif -------------------------------------------------------------------------------- /static/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricmoo/Takoyaki/HEAD/static/background.jpg -------------------------------------------------------------------------------- /lib/assets/takoyaki.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricmoo/Takoyaki/HEAD/lib/assets/takoyaki.ai -------------------------------------------------------------------------------- /lib/.npmignore: -------------------------------------------------------------------------------- 1 | assets/ 2 | scripts/ 3 | 4 | rollup.config.js 5 | 6 | src.ts/ 7 | tsconfig.json 8 | -------------------------------------------------------------------------------- /lib/assets/favicon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricmoo/Takoyaki/HEAD/lib/assets/favicon-16.png -------------------------------------------------------------------------------- /lib/assets/favicon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricmoo/Takoyaki/HEAD/lib/assets/favicon-256.png -------------------------------------------------------------------------------- /lib/assets/favicon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricmoo/Takoyaki/HEAD/lib/assets/favicon-32.png -------------------------------------------------------------------------------- /lib/assets/favicon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricmoo/Takoyaki/HEAD/lib/assets/favicon-48.png -------------------------------------------------------------------------------- /heroku-app/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ricmoo/Takoyaki/HEAD/heroku-app/static/favicon.ico -------------------------------------------------------------------------------- /contracts/Wallet.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.9; 2 | 3 | contract Wallet { 4 | uint public count; 5 | 6 | function onERC721Received(address from, address to, uint256 tokenId, bytes memory _data) public returns (bytes4) { 7 | count++; 8 | return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/thirdparty.d.ts: -------------------------------------------------------------------------------- 1 | declare module "aes-js" { 2 | export class Counter { 3 | constructor(iv: Uint8Array); 4 | } 5 | export namespace ModeOfOperation { 6 | class ctr{ 7 | constructor(key: Uint8Array, counter?: Counter); 8 | decrypt(data: Uint8Array): Uint8Array; 9 | encrypt(data: Uint8Array): Uint8Array; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/run-parity.sh: -------------------------------------------------------------------------------- 1 | DIR="/tmp/test-parity-$(date +%Y-%m-%d_%H-%M-%S)" 2 | echo "Running Parity in ${DIR}..." 3 | mkdir "${DIR}" 4 | mkdir "${DIR}/keys" 5 | 6 | cp -r ./parity-keys "${DIR}/keys/DevelopmentChain" 7 | 8 | parity --chain ./parity-dev.json \ 9 | --unlock=0x7454a8F5a7c7555d79B172C89D20E1f4e4CC226C --password ./parity-dev.pwds \ 10 | --gasprice 1000000000 \ 11 | -d "${DIR}" 12 | -------------------------------------------------------------------------------- /lib/scripts/generate.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const fs = require("fs"); 4 | const { resolve } = require("path"); 5 | 6 | const { parse } = require("../lib/svg-parser"); 7 | 8 | let _SVG = fs.readFileSync(resolve(__dirname, "../assets/takoyaki.svg")).toString(); 9 | let SVG = parse(_SVG).render(); 10 | 11 | fs.writeFileSync(resolve(__dirname, "../src.ts/asset.ts"), `export const svg = ${ JSON.stringify(SVG) };`); 12 | -------------------------------------------------------------------------------- /tests/parity-keys/UTC--2019-06-25T00-14-25Z--24d70b97-fff9-d322-e760-4b8cc2e21751: -------------------------------------------------------------------------------- 1 | {"id":"24d70b97-fff9-d322-e760-4b8cc2e21751","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"45d392cd16dbbd5c0f5b2d145c112da9"},"ciphertext":"b001ccd09fc5431dc055975b58ee61f86e85529245506c04182c902716e750e5","kdf":"pbkdf2","kdfparams":{"c":10240,"dklen":32,"prf":"hmac-sha256","salt":"028594da27a0e864105f33b912e5dc6ce7c75ecd13c81bfc158fe963d30c93bb"},"mac":"374bf2e9144b74b889708abc19e9ebc164f90bc27e83fd9f01da4571a9f81a70"},"address":"7454a8f5a7c7555d79b172c89d20e1f4e4cc226c","name":"","meta":"{}"} -------------------------------------------------------------------------------- /lib/lib/random.d.ts: -------------------------------------------------------------------------------- 1 | export declare class Random { 2 | readonly seed: string; 3 | constructor(seeds: string | Array); 4 | subRandom(seed: string): Random; 5 | bytes32(key: string): string; 6 | bytes6(key: string): string; 7 | number(key: string): number; 8 | range(key: string, lo: number, hi: number): number; 9 | choice(key: string, options: Array): any; 10 | boolean(key: string): boolean; 11 | color(key: string, hue: number, dHue: number, sat: number, dSat: number, lum: number, dLum: number): string; 12 | static random(): Random; 13 | } 14 | -------------------------------------------------------------------------------- /heroku-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "takoyaki-app", 3 | "version": "0.0.1", 4 | "description": "Takoyaki metadata service.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "takoyaki", 12 | "ethereum" 13 | ], 14 | "author": "Richard Moore (https://www.ricmoo.com)", 15 | "license": "MIT", 16 | "dependencies": { 17 | "aws-sdk": "2.521.0", 18 | "convert-svg-to-png": "^0.5.0", 19 | "ethers": ">=5.0.0-beta.157", 20 | "punycode": "^2.1.1", 21 | "takoyaki": ">=0.0.15" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/scripts/README.md: -------------------------------------------------------------------------------- 1 | takoyaki.eth: Scripts 2 | ===================== 3 | 4 | Simple scripts needed for development and building. 5 | 6 | 7 | generate.js 8 | ----------- 9 | 10 | The `generate.js` script loads and parses the **master SVG** file 11 | and dumps it as a JavaScript variable so that the main library 12 | can simply `require("./asset.js")` it. 13 | 14 | Currently the space saved is less than the zlib library requires, 15 | but as new features are added to the **master SVG**, it may begin 16 | to make sense to compress it. 17 | 18 | This script is executed as part of the `npm run dist` target in 19 | the [NPM library folder](../). 20 | 21 | 22 | License 23 | ------- 24 | 25 | MIT License. 26 | -------------------------------------------------------------------------------- /lib/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "lib": [ "es2015", "es5", "dom" ], 5 | "module": "commonjs", 6 | "target": "es5", 7 | "moduleResolution": "node", 8 | 9 | "outDir": "./lib/", 10 | 11 | "declaration": true, 12 | 13 | "preserveSymlinks": true, 14 | 15 | "preserveWatchOutput": true, 16 | "pretty": false, 17 | 18 | "forceConsistentCasingInFileNames": true, 19 | 20 | "noFallthroughCasesInSwitch": true, 21 | "noImplicitAny": true, 22 | "noImplicitReturns": true, 23 | "noUnusedLocals": true 24 | }, 25 | "include": [ 26 | "./src.ts/*.ts", 27 | "./thirdparty.d.ts" 28 | ], 29 | "exclude": [ ] 30 | } 31 | 32 | -------------------------------------------------------------------------------- /lib/rollup.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import resolve from 'rollup-plugin-node-resolve'; 4 | import commonjs from 'rollup-plugin-commonjs'; 5 | import builtins from 'rollup-plugin-node-builtins'; 6 | 7 | import { terser } from "rollup-plugin-terser"; 8 | 9 | 10 | export default commandLineArgs => { 11 | let minify = commandLineArgs.configMinify; 12 | 13 | let output = "./dist/takoyaki.umd.js"; 14 | const plugins = [ 15 | builtins(), 16 | resolve({ 17 | mainFields: [ "browser", "module", "main" ] 18 | }), 19 | commonjs({ }) 20 | ]; 21 | 22 | if (minify) { 23 | output = "./dist/takoyaki.umd.min.js" 24 | plugins.push(terser()); 25 | } 26 | 27 | return { 28 | input: "./lib/index.js", 29 | output: { 30 | file: output, 31 | format: "umd", 32 | name: "Takoyaki", 33 | exports: "named", 34 | }, 35 | plugins: plugins 36 | }; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Richard Moore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Richard Moore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "takoyaki", 3 | "version": "0.0.15", 4 | "description": "The Takoyaki NFT library.", 5 | "main": "./lib/index.js", 6 | "browser": { 7 | "ethers": "./ethers-browser.js" 8 | }, 9 | "scripts": { 10 | "dist": "npm run build && node ./scripts/generate.js && tsc -p tsconfig.json && rollup -c && rollup -c --configMinify", 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "build": "tsc -p ./tsconfig.json", 13 | "auto-build": "npm run build -- -w" 14 | }, 15 | "keywords": [ 16 | "ethereum", 17 | "takoyaki", 18 | "nft", 19 | "takoyakinft" 20 | ], 21 | "author": "Richard Moore ", 22 | "license": "MIT", 23 | "dependencies": { 24 | "aes-js": "3.0.0", 25 | "ethers": ">=5.0.0-beta.156", 26 | "punycode": "2.1.1" 27 | }, 28 | "devDependencies": { 29 | "@types/node": "^12.7.4", 30 | "rollup": "^1.20.3", 31 | "rollup-plugin-commonjs": "^10.1.0", 32 | "rollup-plugin-node-builtins": "^2.1.2", 33 | "rollup-plugin-node-resolve": "^5.2.0", 34 | "rollup-plugin-terser": "^5.1.1", 35 | "typescript": "3.6.2" 36 | }, 37 | "repository": { 38 | "type": "git", 39 | "url": "git://github.com/ricmoo/Takoyaki.git" 40 | }, 41 | "bugs": { 42 | "url": "https://github.com/ricmoo/Takoyaki/issues" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/lib/svg-parser.d.ts: -------------------------------------------------------------------------------- 1 | export interface NodeLike { 2 | _parentNode: NodeLike; 3 | render(): string; 4 | clone(): NodeLike; 5 | } 6 | export declare type Attributes = { 7 | [attribute: string]: string; 8 | }; 9 | export declare class SvgNode implements NodeLike { 10 | readonly name: string; 11 | readonly attributes: Attributes; 12 | readonly selfClose: boolean; 13 | children: Array; 14 | _parentNode: NodeLike; 15 | constructor(name: string, attributes: string | Attributes, selfClose: boolean); 16 | render(): string; 17 | clone(): SvgNode; 18 | remove(): void; 19 | static isNode(value: any): value is SvgNode; 20 | } 21 | export declare class Data implements NodeLike { 22 | readonly content: string; 23 | _parentNode: NodeLike; 24 | constructor(content: string); 25 | render(): string; 26 | clone(): Data; 27 | } 28 | export declare class SvgDocument implements NodeLike { 29 | readonly definition: string; 30 | readonly svg: SvgNode; 31 | readonly _links: { 32 | [id: string]: Array; 33 | }; 34 | _parentNode: NodeLike; 35 | constructor(definition: string, svg: SvgNode); 36 | render(): string; 37 | clone(): SvgDocument; 38 | getElementById(id: string): SvgNode; 39 | } 40 | export declare function parse(text: string): SvgDocument; 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "version": "0.0.1", 4 | "description": "ENS Registrar, management website and metadata website for takoyaki.eth subnames.", 5 | "scripts": { 6 | "deploy-heroku": "git subtree push --prefix heroku-app heroku master", 7 | "deploy-heroku-force": "git push heroku `git subtree split --prefix heroku-app master`:master --force", 8 | "setup-heroku": "heroku git:remote -a takoyaki-nft", 9 | "local": "./build.sh && cd heroku-app && heroku local web", 10 | "local-live": "python -m SimpleHTTPServer 5000", 11 | "flatten": "meeseeks flatten index.html > dist/index.html", 12 | "dist": "./build.sh", 13 | "test": "mocha --timeout 600000 tests/test" 14 | }, 15 | "keywords": [ 16 | "Ethereum", 17 | "ENS", 18 | "takoyaki" 19 | ], 20 | "author": "Richard Moore (https://www.ricmoo.com)", 21 | "contributors": [ 22 | "Yuet-Loo Wong (http://www.yuetloo.com)" 23 | ], 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/ricmoo/Takoyaki/issues" 27 | }, 28 | "homepage": "https://takoyaki.cafe/", 29 | "dependencies": { 30 | "ethers": ">=5.0.0-beta.156" 31 | }, 32 | "devDependencies": { 33 | "@ethersproject/cli": ">=5.0.0-beta.143", 34 | "mocha": "^6.2.0", 35 | "rollup": "^1.20.3", 36 | "rollup-plugin-commonjs": "^10.1.0", 37 | "rollup-plugin-node-builtins": "^2.1.2", 38 | "rollup-plugin-node-resolve": "^5.2.0", 39 | "rollup-plugin-terser": "^5.1.1", 40 | "terser": "^4.3.1" 41 | }, 42 | "repository": { 43 | "type": "git", 44 | "url": "git://github.com/ricmoo/Takoyaki.git" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | takoyaki.eth 2 | ============ 3 | 4 | Each Takoyaki is a unique, cute ERC-721 Octopus token, which is also 5 | an [ENS name](https://ens.domains). It is meant as a fun and easy way 6 | to start your foray into ENS, which allows you to use a friendly name 7 | for your Ethereum address, rather than a long string of hexidecimal 8 | characters. 9 | 10 | Takoyaki began was our [ETHNewYork](https://ethnewyork.com) hackathon project. 11 | 12 | We've since spruced it up a bit and are releasing it. :) 13 | 14 | 15 | Web Interface 16 | ------------- 17 | 18 | By far, the easiest way to interact with Takoyaki, is using our website, https://takoyaki.cafe. 19 | 20 | 21 | Contract 22 | -------- 23 | 24 | The contract is deployed on Ropsten and will soon be deployed to Mainnet. 25 | 26 | See: [Takoyaki Contract](https://github.com/ricmoo/Takoyaki/tree/master/contracts) 27 | 28 | 29 | API 30 | --- 31 | 32 | The API allows anyone to easily interact with the Registrar and ERC-721 token 33 | contract on the Ethereum network, as well as generate the traits from on-chain 34 | data and finally render (entirely on the client side) a give Takoyaki for a 35 | given set of traits. 36 | 37 | See: [Takoyaki NPM Library](https://github.com/ricmoo/Takoyaki/tree/master/lib) 38 | 39 | 40 | Metadata Service 41 | ---------------- 42 | 43 | The Metadata service is designed to be run on Heroku, and can be run locally 44 | or deployed to your own Heroku instance. 45 | 46 | See: [Takoyaki Metadata Service](https://github.com/ricmoo/Takoyaki/tree/master/metadata-service) 47 | 48 | 49 | Command Line Interface 50 | ---------------------- 51 | 52 | This is still under constructions... 53 | 54 | ``` 55 | /home/ricmoo> takoyaki --help 56 | 57 | Usage: 58 | takoyaki commit LABEL [ --salt SALT ] [ --owner ADDRESS ] 59 | takoyaki reveal LABEL [ --salt SALT ] [ --owner ADDRESS ] 60 | ``` 61 | 62 | 63 | License 64 | ------- 65 | 66 | All code is released under the MIT license and all artwork under the 67 | Creative Commons CC-BY-4.0 license. 68 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | machine: 9 | image: ubuntu-1604:201903-01 10 | 11 | working_directory: ~/repo 12 | 13 | steps: 14 | - checkout 15 | 16 | - run: 17 | name: Prepare to run parity 18 | command: | 19 | mkdir -p /tmp/parity/keys 20 | cp -r tests/parity-keys /tmp/parity/keys/DevelopmentChain 21 | cp tests/parity-dev.json /tmp/parity 22 | cp tests/parity-dev.pwds /tmp/parity 23 | chmod -R 777 /tmp/parity 24 | 25 | - run: ls -la /tmp/parity 26 | 27 | - run: 28 | name: Starting Parity 29 | command: docker run -d -p 8545:8545 -p 8546:8546 -p 30303:30303 -p 30303:30303/udp --name parity -v /tmp/parity:/home/parity/.local/share/io.parity.ethereum parity/parity:v2.4.8-stable --chain /home/parity/.local/share/io.parity.ethereum/parity-dev.json --unlock=0x7454a8F5a7c7555d79B172C89D20E1f4e4CC226C --password /home/parity/.local/share/io.parity.ethereum/parity-dev.pwds --min-gas-price 1000000000 --jsonrpc-interface all 30 | 31 | # Download and cache dependencies 32 | - restore_cache: 33 | keys: 34 | - v1-dependencies-{{ checksum "package.json" }} 35 | # fallback to using the latest cache if no exact match is found 36 | - v1-dependencies- 37 | 38 | - run: npm install 39 | 40 | - save_cache: 41 | paths: 42 | - node_modules 43 | key: v1-dependencies-{{ checksum "package.json" }} 44 | 45 | - run: 46 | name: Waiting for Parity to be ready 47 | command: | 48 | for i in `seq 1 20`; 49 | do 50 | nc -z localhost 8545 && echo Success && exit 0 51 | echo -n . 52 | sleep 2 53 | done 54 | docker ps -a 55 | docker logs parity 56 | echo Failed waiting for Parity && exit 1 57 | 58 | # run tests! 59 | - run: 60 | name: run tests 61 | command: | 62 | [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm 63 | [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion 64 | nvm install 10.15.3 65 | node -v 66 | npm test 67 | date 68 | -------------------------------------------------------------------------------- /lib/src.ts/random.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import { utils } from "ethers"; 4 | 5 | const hex = "0123456789abcdef"; 6 | 7 | export class Random { 8 | readonly seed: string; 9 | 10 | constructor(seeds: string | Array) { 11 | let seed: string = null; 12 | if (Array.isArray(seeds)) { 13 | seed = ("0x" + seeds.map((s) => s.substring(2)).join("")); 14 | } else { 15 | seed = seeds; 16 | } 17 | utils.defineReadOnly(this, "seed", utils.keccak256(seed)); 18 | } 19 | 20 | subRandom(seed: string): Random { 21 | return new Random([ this.seed, seed ]); 22 | } 23 | 24 | // Random 32 bytes 25 | bytes32(key: string): string { 26 | return utils.keccak256(this.seed + utils.id(key).substring(2)); 27 | } 28 | 29 | bytes6(key: string): string { 30 | return utils.keccak256(this.seed + utils.id(key).substring(2)).substring(0, 14); 31 | } 32 | 33 | // Random number between 0 (inclusive) and 1 (exclusive) 34 | number(key: string): number { 35 | let value = parseInt(this.bytes32(key).substring(2, 14), 16); 36 | return value / 0x1000000000000; 37 | } 38 | 39 | // Return a random value in the range [ lo, hi - 1 ] 40 | range(key: string, lo: number, hi: number): number { 41 | return lo + parseInt(String(this.number(key) * (hi - lo))) 42 | } 43 | 44 | // Random choice from the Array options 45 | choice(key: string, options: Array): any { 46 | return options[this.range(key, 0, options.length)]; 47 | } 48 | 49 | // Random boolean value 50 | boolean(key: string): boolean { 51 | return this.choice(key, [ false, true ]); 52 | } 53 | 54 | // Returns a random color for seed with ((hue +/- (dHue/2)), (sat + dSat?), (lum + dLum?)) 55 | color(key: string, hue: number, dHue: number, sat: number, dSat: number, lum: number, dLum: number): string { 56 | hue = (720 + hue - (dHue / 2) + this.number(key + "-hue") * dHue) % 360; 57 | sat += this.number(key + "-sat") * dSat; 58 | lum += this.number(key + "-lum") * dLum; 59 | return "hsl(" + parseInt(String(hue)) + ", " + parseInt(String(sat)) + "%, " + parseInt(String(lum)) + "%)"; 60 | } 61 | 62 | static random(): Random { 63 | let seed = "0x"; 64 | while (seed.length < 66) { 65 | seed += hex[parseInt(String(Math.random() * 16))]; 66 | } 67 | return new Random(seed); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/lib/random.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var ethers_1 = require("ethers"); 4 | var hex = "0123456789abcdef"; 5 | var Random = /** @class */ (function () { 6 | function Random(seeds) { 7 | var seed = null; 8 | if (Array.isArray(seeds)) { 9 | seed = ("0x" + seeds.map(function (s) { return s.substring(2); }).join("")); 10 | } 11 | else { 12 | seed = seeds; 13 | } 14 | ethers_1.utils.defineReadOnly(this, "seed", ethers_1.utils.keccak256(seed)); 15 | } 16 | Random.prototype.subRandom = function (seed) { 17 | return new Random([this.seed, seed]); 18 | }; 19 | // Random 32 bytes 20 | Random.prototype.bytes32 = function (key) { 21 | return ethers_1.utils.keccak256(this.seed + ethers_1.utils.id(key).substring(2)); 22 | }; 23 | Random.prototype.bytes6 = function (key) { 24 | return ethers_1.utils.keccak256(this.seed + ethers_1.utils.id(key).substring(2)).substring(0, 14); 25 | }; 26 | // Random number between 0 (inclusive) and 1 (exclusive) 27 | Random.prototype.number = function (key) { 28 | var value = parseInt(this.bytes32(key).substring(2, 14), 16); 29 | return value / 0x1000000000000; 30 | }; 31 | // Return a random value in the range [ lo, hi - 1 ] 32 | Random.prototype.range = function (key, lo, hi) { 33 | return lo + parseInt(String(this.number(key) * (hi - lo))); 34 | }; 35 | // Random choice from the Array options 36 | Random.prototype.choice = function (key, options) { 37 | return options[this.range(key, 0, options.length)]; 38 | }; 39 | // Random boolean value 40 | Random.prototype.boolean = function (key) { 41 | return this.choice(key, [false, true]); 42 | }; 43 | // Returns a random color for seed with ((hue +/- (dHue/2)), (sat + dSat?), (lum + dLum?)) 44 | Random.prototype.color = function (key, hue, dHue, sat, dSat, lum, dLum) { 45 | hue = (720 + hue - (dHue / 2) + this.number(key + "-hue") * dHue) % 360; 46 | sat += this.number(key + "-sat") * dSat; 47 | lum += this.number(key + "-lum") * dLum; 48 | return "hsl(" + parseInt(String(hue)) + ", " + parseInt(String(sat)) + "%, " + parseInt(String(lum)) + "%)"; 49 | }; 50 | Random.random = function () { 51 | var seed = "0x"; 52 | while (seed.length < 66) { 53 | seed += hex[parseInt(String(Math.random() * 16))]; 54 | } 55 | return new Random(seed); 56 | }; 57 | return Random; 58 | }()); 59 | exports.Random = Random; 60 | -------------------------------------------------------------------------------- /static/style-mobile.css: -------------------------------------------------------------------------------- 1 | body { 2 | position: relative; 3 | } 4 | 5 | .background { 6 | background: url(./background.jpg) no-repeat; 7 | background-size: 700px 384px; 8 | position: relative; 9 | width: 100%; 10 | } 11 | 12 | .background.top { 13 | background-position: right bottom; 14 | height: 170px; 15 | } 16 | 17 | .background.bottom { 18 | background-position: top; 19 | top: -50px; 20 | height: 300px; 21 | } 22 | 23 | .searchbar { 24 | border: 2px solid #000; 25 | border-radius: 17px; 26 | box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.5); 27 | font-size: 20px; 28 | left: 30px; 29 | line-height: 30px; 30 | height: 34px; 31 | padding: 0px 15px; 32 | top: 60px; 33 | width: 200px; 34 | } 35 | 36 | .searchbar input { 37 | font-size: 14px; 38 | padding: 0 5px 0 20px; 39 | } 40 | 41 | #background { 42 | display: none; 43 | height: 0; 44 | width: 0; 45 | } 46 | 47 | #card { 48 | background: transparent; 49 | box-shadow: none; 50 | border: none; 51 | border-radius: 0; 52 | padding: 0px 20px 30px; 53 | position: relative; 54 | top: 0px; 55 | left: 0; 56 | transform: translate(0, 0); 57 | width: 100%; 58 | } 59 | 60 | #button-close { 61 | top: 15px; 62 | right: 10px; 63 | } 64 | 65 | #search { 66 | background: transparent; 67 | box-shadow: none; 68 | border: none; 69 | border-radius: 0; 70 | padding: 0px 20px 20px; 71 | position: relative; 72 | top: 0px; 73 | left: 0; 74 | transform: translate(0, 0); 75 | width: 100%; 76 | } 77 | 78 | #search .title { 79 | font-size: 20px; 80 | font-weight: bold; 81 | } 82 | 83 | .address { 84 | font-size: 12px; 85 | } 86 | 87 | .about { 88 | border-radius: 0; 89 | padding: 20px 24px; 90 | overflow: hidden; 91 | margin-top: -10px; 92 | margin-left: -20px; 93 | } 94 | 95 | .about .background.overlay { 96 | background-position: top; 97 | bottom: -280px; 98 | display: block; 99 | height: 300px; 100 | left: 0; 101 | position: absolute; 102 | } 103 | 104 | #card .about .title { 105 | font-size: 20px; 106 | font-weight: bold; 107 | position: relative; 108 | } 109 | 110 | .about p { 111 | font-size: 16px; 112 | position: relative; 113 | margin: 12px 0; 114 | } 115 | 116 | .button-container { 117 | margin-top: 0px; 118 | } 119 | 120 | .button.enabled:hover { 121 | transform: translate(-50%, 0); 122 | } 123 | 124 | .about > div { 125 | margin: 20px 0; 126 | } 127 | -------------------------------------------------------------------------------- /tests/parity-dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DevelopmentChain", 3 | "engine": { 4 | "instantSeal": null 5 | }, 6 | "params": { 7 | "gasLimitBoundDivisor": "0x0400", 8 | "accountStartNonce": "0x0", 9 | "maximumExtraDataSize": "0x20", 10 | "minGasLimit": "0x1388", 11 | "networkID" : "0x11", 12 | "registrar" : "0x0000000000000000000000000000000000001337", 13 | "maxCodeSize": 24576, 14 | "maxCodeSizeTransition": "0x0", 15 | "eip98Transition": "0x7fffffffffffff", 16 | "eip140Transition": "0x0", 17 | "eip145Transition": "0x0", 18 | "eip150Transition": "0x0", 19 | "eip155Transition": "0x0", 20 | "eip160Transition": "0x0", 21 | "eip161abcTransition": "0x0", 22 | "eip161dTransition": "0x0", 23 | "eip211Transition": "0x0", 24 | "eip214Transition": "0x0", 25 | "eip658Transition": "0x0", 26 | "wasmActivationTransition": "0x0" 27 | }, 28 | "genesis": { 29 | "seal": { 30 | "generic": "0x0" 31 | }, 32 | "difficulty": "0x20000", 33 | "author": "0x0000000000000000000000000000000000000000", 34 | "timestamp": "0x00", 35 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 36 | "extraData": "0x", 37 | "gasLimit": "0x7A1200" 38 | }, 39 | "accounts": { 40 | "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, 41 | "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, 42 | "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, 43 | "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, 44 | "0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } }, 45 | "0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } }, 46 | "0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, 47 | "0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, 48 | "0x7454a8f5a7c7555d79b172c89d20e1f4e4cc226c": { "balance": "1606938044258990275541962092341162602522202993782792835301376" } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/lib/index.d.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber, Contract, ContractInterface, providers, Signer } from "ethers"; 2 | export declare type State = "available" | "grace" | "owned"; 3 | export declare type Genes = { 4 | salt: string; 5 | seeds: Array; 6 | generation?: number; 7 | tokenId?: string; 8 | commitBlock?: number; 9 | revealBlock?: number; 10 | name?: string; 11 | addr?: string; 12 | expires?: number; 13 | status?: State; 14 | owner?: string; 15 | upkeepFee?: BigNumber; 16 | }; 17 | export declare type Traits = { 18 | genes: Genes; 19 | state: number; 20 | eyes: number; 21 | mouth: number; 22 | mouth_r: number; 23 | mouth_s: number; 24 | tattoo: number; 25 | tattoo_d: number; 26 | tattoo_a: number; 27 | tattoo_r: number; 28 | tattoo_c: string; 29 | color1: number; 30 | color2: number; 31 | body_c: string; 32 | tentacle1_outside_c: string; 33 | tentacle2_outside_c: string; 34 | tentacle3_outside_c: string; 35 | tentacle4_outside_c: string; 36 | tentacle1_inside_c: string; 37 | tentacle2_inside_c: string; 38 | tentacle3_inside_c: string; 39 | tentacle4_inside_c: string; 40 | tentacle1_r: number; 41 | tentacle2_r: number; 42 | tentacle3_r: number; 43 | tentacle4_r: number; 44 | }; 45 | export declare function getLabelColor(label: string, sat?: number, lum?: number): string; 46 | export declare function getTraits(genes: Genes): Traits; 47 | export declare function getSvg(traits: Traits, backgroundColor?: string): string; 48 | export declare function submitReveal(signedTx: string, local?: boolean): Promise; 49 | export declare function getTakoyakiUrl(tokenIdOrLabel: string): string; 50 | export declare type Hints = { 51 | blockNumber?: number; 52 | name?: string; 53 | salt?: string; 54 | commitBlock?: number; 55 | revealBlock?: number; 56 | }; 57 | declare class TakoyakiContract extends Contract { 58 | readonly decimals = 0; 59 | readonly name = "Takoyaki"; 60 | readonly symbol = "TAKO"; 61 | _blockSeedCache: { 62 | [blockTag: string]: Promise; 63 | }; 64 | constructor(addressOrName: string, contractInterface: ContractInterface, signerOrProvider: Signer | providers.Provider); 65 | _getBlockSeed(blockNumber: number, currentBlockNumber?: number): Promise; 66 | getTraits(tokenId: string, hints?: Hints): Promise; 67 | getTransactions(label: string, owner: string, salt: string, prefundRevealer: string): Promise<{ 68 | commit: string; 69 | reveal: string; 70 | }>; 71 | tokenURI(tokenId: string): string; 72 | } 73 | export declare function urlToLabel(url: string): string; 74 | export declare function labelToUrl(label: string, local?: boolean): string; 75 | export declare function normalizeLabel(label: string): string; 76 | export declare function connect(signerOrProvider: Signer | providers.Provider): TakoyakiContract; 77 | export {}; 78 | -------------------------------------------------------------------------------- /tests/source-mapper.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function SourceMapper(source) { 4 | this._source = source; 5 | this._mapping = { }; 6 | } 7 | 8 | SourceMapper.prototype.set = function(key, value, count) { 9 | this._mapping[key] = { value: value, count: (count || null) }; 10 | } 11 | 12 | SourceMapper.prototype.clear = function(key) { 13 | delete this._mapping[key]; 14 | } 15 | 16 | SourceMapper.prototype._getKeys = function() { 17 | let keys = { }; 18 | function replacer(all, line, key, value) { 19 | keys[key] = true; 20 | return ""; 21 | } 22 | this._source.replace(/(.*\/\*!Test:\s*([a-z0-9_]*)\s*=\s*"([^"]*)"\s*\*\/)/ig, replacer); 23 | return Object.keys(keys); 24 | } 25 | 26 | SourceMapper.prototype._getSource = function() { 27 | let source = this._source; 28 | let warnings = [ ]; 29 | 30 | let counts = { }; 31 | this.keys.forEach((key) => { 32 | counts[key] = 0; 33 | }); 34 | 35 | Object.keys(this._mapping).forEach((key) => { 36 | if (counts[key] !== 0) { 37 | warnings.push({ line: `Unknown key: ${ key }`, type: "UNKNOWN_KEY", key: key }); 38 | } 39 | }); 40 | 41 | const replacer = (match, all, line, key, value) => { 42 | let mapping = this._mapping[key]; 43 | 44 | if (mapping.value == null) { 45 | counts[key]++; 46 | return all; 47 | } 48 | 49 | if (!mapping) { 50 | warnings.push({ line: `Missing mapping: ${ key }`, type: "MISSING_MAPPING", key: key }); 51 | return all; 52 | } 53 | 54 | let loc = line.indexOf(value); 55 | if (loc === -1) { 56 | throw new Error("Nothing to replace (expected: " + JSON.stringify(value) + ")"); 57 | } 58 | 59 | counts[key]++; 60 | line = all.substring(0, loc) + mapping.value + all.substring(loc + value.length); 61 | 62 | return line; 63 | } 64 | source = source.replace(/((.*)\/\*!Test:\s*([a-z0-9_]*)\s*=\s*"([^"]*)"\s*\*\/)/ig, replacer); 65 | 66 | Object.keys(counts).forEach((key) => { 67 | if (counts[key] === 0) { 68 | warnings.push({ line: `Unused key: ${ key }`, type: "UNUSED_KEY", key: key }); 69 | } 70 | }); 71 | 72 | Object.keys(this._mapping).forEach((key) => { 73 | let count = this._mapping[key].count; 74 | if (count != null && count !== counts[key]) { 75 | throw new Error(`Mapping count mismatch: ${ key } (expected: ${ count }, found: ${ counts[key] })`); 76 | } 77 | }); 78 | 79 | return { source: source, warnings: warnings } 80 | } 81 | 82 | Object.defineProperty(SourceMapper.prototype, "keys", { 83 | enumerable: true, 84 | get: function() { return this._getKeys(); } 85 | }); 86 | 87 | Object.defineProperty(SourceMapper.prototype, "source", { 88 | enumerable: true, 89 | get: function() { return this._getSource().source; } 90 | }); 91 | 92 | Object.defineProperty(SourceMapper.prototype, "warnings", { 93 | enumerable: true, 94 | get: function() { return this._getSource().warnings; } 95 | }); 96 | 97 | module.exports.SourceMapper = SourceMapper; 98 | 99 | -------------------------------------------------------------------------------- /heroku-app/README.md: -------------------------------------------------------------------------------- 1 | Metadata Service 2 | ================ 3 | 4 | The Metadata Service provides a simple Heroku backend to to 5 | compliment the `tokenURI` contract call, returning a JSON 6 | description of a given NFT, and generating SVG and PNG images 7 | for each token. 8 | 9 | 10 | Endpoints 11 | --------- 12 | 13 | **[https://takoyaki.cafe/json/TOKEN_ID](https://takoyaki.cafe/json/b05e424817fb90aa7a79e9da5c5f94070a316219c6ebb863a9ff7ca357dc9fa9/)** 14 | 15 | Generates the JSON description of the *TOKEN_ID* Takoyaki Token. 16 | 17 | 18 | **[https://takoyaki.cafe/svg/ENCODED_TRAITS](https://takoyaki.cafe/svg/1_7269636d6f6f_670f0aec6d79467f07bfdc7fe6a934b807692e85f13ee6b7bc6da69b7188f23e_6b6b4fb95221_7265b22d098e_aa698013d271_82422dcd5539_394b95c369ec/)** 19 | 20 | Generates the SVG of the Takoyaki Token with the *ENCODED_TRAITS* 21 | (see below for the encoding). 22 | 23 | 24 | **[https://takoyaki.cafe/png/ENCODED_TRAITS?size=:SIZE](https://takoyaki.cafe/png/1_7269636d6f6f_670f0aec6d79467f07bfdc7fe6a934b807692e85f13ee6b7bc6da69b7188f23e_6b6b4fb95221_7265b22d098e_aa698013d271_82422dcd5539_394b95c369ec/)** 25 | 26 | Rasterizes the above SVG into a PNG for a Takoyaki Token with the 27 | *ENCODED_TRAITS* as a *SIZE* x *SIZE* pixel PNG. 28 | 29 | If the size query parameter is ommitted, a default size of 256 30 | will be used. The maximum size is 1024x1024 pixels. 31 | 32 | 33 | **[https://takoyaki.cafe/profile/HEX_ENCODED_NAME](https://takoyaki.cafe/profile/7269636d6f6f/)** 34 | 35 | Generates a PNG (600px x 600px) by the *HEX_ENCODED_NAME* with its background color. This is 36 | used for the Open Graph headers, which can be generated prior to knowing the traits. As a 37 | result this call is slower, as it has to lookup (on the blockchain) the traits. 38 | 39 | 40 | Token ID 41 | -------- 42 | 43 | The token ID of a Takoyaki is the keccak256 of the normalized UTF-8 bytes of its name. 44 | 45 | The name can be normalized using the nameprep normalization. 46 | 47 | 48 | Encoding Traits 49 | --------------- 50 | 51 | The traits are an underscore (i.e. `_`) delimited set of hex strings. The fields are: 52 | 53 | - **version:** currently only `1` is supported, which indicates the following fields: 54 | - **name:** the hex encoded UTF-8 string label 55 | - **salt:** the 32 byte (64 nibble) salt used during commit 56 | - **seed0** through **seed4:** each of these 5 seeds is a 6 byte (12 nibble) seed based on the block hashes following certain block intervals after the commit and reveal 57 | 58 | Future versions will allow different parameters, which the version will be used to indicate. 59 | 60 | 61 | Managing 62 | -------- 63 | 64 | **Local Testing** 65 | 66 | To run locally and test new updates, from **this** directory, run: 67 | 68 | ``` 69 | /home/ricmoo/takoyaki/metadata-service> npm run local 70 | ``` 71 | 72 | **Production Deployment** 73 | 74 | All code to be deployed must be checked into git, as Heroku uses git 75 | to manage deployments. To deploy the service to Heroku, from the 76 | repositories **root** folder, run: 77 | 78 | ``` 79 | /home/ricmoo/takoyaki> npm run deploy-metadata-service 80 | ``` 81 | 82 | **Logging into Heroku** 83 | 84 | The first time using Heroku after cloning th repository, you must log into 85 | Herkou. If you are deploying this you will need to update the package.json 86 | to reflect a Heroku host you own. This must be run from the **root** folder. 87 | 88 | ``` 89 | /home/ricmoo/takoyaki> npm run setup-heroku 90 | ``` 91 | 92 | 93 | License 94 | ------- 95 | 96 | MIT License 97 | -------------------------------------------------------------------------------- /bin/deploy.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // Run using @ethersproject/cli 4 | 5 | // Ropsten: 6 | // /home/ricmoo> ethers --account wallet.json --network ropsten run scripts/deploy.js 7 | 8 | // Homestead: 9 | // /home/ricmoo> ethers --account wallet.json run scripts/deploy.js 10 | 11 | const fs = require("fs"); 12 | 13 | const { solc } = require("@ethersproject/cli"); 14 | const { ethers } = require("ethers"); 15 | 16 | function getAbi(fragment) { 17 | console.log(fragment); 18 | if (fragment.type === "event") { 19 | return { 20 | name: fragment.name, 21 | inputs: fragment.inputs.map((fragment) => getAbi(fragment)), 22 | type: "event" 23 | }; 24 | 25 | } else if (fragment.type === "function") { 26 | return { 27 | constant: fragment.constant, 28 | mutabilityState: fragment.mutabilityState, 29 | name: fragment.name, 30 | inputs: fragment.inputs.map((fragment) => getAbi(fragment)), 31 | outputs: fragment.inputs.map((fragment) => getAbi(fragment)), 32 | type: "function" 33 | }; 34 | 35 | } else if (fragment._isParamType) { 36 | let result = { 37 | type: fragment.type 38 | }; 39 | if (typeof(fragment.indexed) === "boolean") { 40 | result.indexed = fragment.indexed; 41 | } 42 | return result; 43 | } else { 44 | console.log("Unahndled:" , fragment); 45 | } 46 | } 47 | 48 | (async function() { 49 | let code = solc.compile(fs.readFileSync("./contracts/TakoyakiRegistrar.sol").toString(), { 50 | optimize: true 51 | }).filter((c) => (c.name === "TakoyakiRegistrar"))[0]; 52 | //console.dir(code, { depth: null }); 53 | //let abi = JSON.stringify(code.interface.fragments.map((fragment) => getAbi(fragment)).filter((abi) => (!!abi))); 54 | //console.log(abi, abi.length); 55 | /* 56 | let hrAbi = JSON.stringify(code.interface.fragments.map((fragment) => { 57 | fragment = Fragment.from(fragment.format(true)); 58 | return fragment.format("minimal") 59 | })); 60 | console.log(hrAbi, hrAbi.length); 61 | */ 62 | 63 | // Set the admin to be the controller of takoyaki.eth before calling this script 64 | 65 | 66 | let admin = accounts[0]; 67 | let adminAddress = await admin.getAddress(); 68 | let network = await provider.getNetwork(); 69 | 70 | let factory = new ContractFactory(code.interface, code.bytecode, admin); 71 | 72 | let contract = await factory.deploy(network.ensAddress, namehash("takoyaki.eth"), "resolver.eth", { 73 | gasLimit: 3000000 74 | }) 75 | console.log("Point the takoyaki.eth controller to:", contract.address); 76 | 77 | let receipt = await contract.deployed(); 78 | console.log(receipt); 79 | 80 | let reverseNodehash = namehash(contract.address.substring(2) + ".addr.reverse"); 81 | 82 | // Set the resolver of the reverse name record 83 | let ensAbi = [ 84 | "function setResolver(bytes32 nodehash, address resolver) @250000", 85 | "function setOwner(bytes32 nodehash, address owner) @250000" 86 | ]; 87 | 88 | let ensContract = new Contract(network.ensAddress, ensAbi, admin); 89 | let tx = await ensContract.setResolver(reverseNodehash, "resolver.eth"); 90 | receipt = await tx.wait(); 91 | console.log(receipt); 92 | 93 | // Set the name in the reverse name record resolver 94 | let resolverAbi = [ 95 | "function setName(bytes32 nodehash, string name) @250000" 96 | ]; 97 | 98 | let resolverContract = new Contract("resolver.eth", resolverAbi, admin); 99 | tx = await resolverContract.setName(reverseNodehash, "takoyaki.eth"); 100 | receipt = await tx.wait(); 101 | console.log(receipt); 102 | 103 | // TODO: Set the ABI for takoyaki.eth 104 | 105 | // @TODO: Set the contract as the controller of takoyaki.eth 106 | 107 | })(); 108 | -------------------------------------------------------------------------------- /tests/takoyaki.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const ethers = require('ethers'); 4 | const Takoyaki = require('../lib/lib'); 5 | 6 | const getEvent = (contract, receipt, eventName) => 7 | receipt.logs 8 | .map(log => contract.interface.parseLog(log)) 9 | .filter(Boolean) 10 | .find(({ name }) => name === eventName); 11 | 12 | const register = async (provider, signer, label) => { 13 | const takoyaki = Takoyaki.connect(signer); 14 | const salt = ethers.utils.keccak256(ethers.utils.randomBytes(32)); 15 | 16 | const fee = await takoyaki.fee(label); 17 | const options = { value: fee }; 18 | 19 | const blindedCommit = await takoyaki.makeBlindedCommitment(label, signer.address, salt); 20 | 21 | let tx = await takoyaki.commit( 22 | blindedCommit, 23 | ethers.constants.AddressZero, 24 | 0, 25 | options 26 | ); 27 | let receipt = await tx.wait(); 28 | 29 | await provider.mineBlocks(5); 30 | 31 | tx = await takoyaki.reveal(label, signer.address, salt); 32 | return tx.wait(); 33 | }; 34 | 35 | const getTokenId = (contract, receipt) => { 36 | const transferEvent = getEvent(contract, receipt, 'Transfer'); 37 | 38 | if (!transferEvent) { 39 | throw new Error('Missing transfer event'); 40 | } 41 | 42 | if (transferEvent.values.length !== 3) { 43 | throw new Error( 44 | `Expect 3 parameters for the transfer event, but got ${ 45 | transferEvent.values.length 46 | }` 47 | ); 48 | } 49 | 50 | const tokenId = transferEvent.values[2]; 51 | return tokenId; 52 | }; 53 | 54 | const safeTransfer = async (signer, owner, newOwner, tokenId, data) => { 55 | const abi = data 56 | ? [ "function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public @150000" ] 57 | : [ "function safeTransferFrom(address from, address to, uint256 tokenId) public @150000"]; 58 | 59 | let contract = new ethers.Contract("takoyaki.eth", abi, signer); 60 | 61 | const tx = data 62 | ? await contract.safeTransferFrom(owner.address, newOwner.address, tokenId, data) 63 | : await contract.safeTransferFrom(owner.address, newOwner.address, tokenId); 64 | 65 | const receipt = await tx.wait(); 66 | return receipt; 67 | }; 68 | 69 | const submitBlindedCommit = async (provider, signer, label) => { 70 | const salt = ethers.utils.keccak256(ethers.utils.randomBytes(32)); 71 | 72 | const takoyaki = Takoyaki.connect(signer); 73 | const fee = await takoyaki.fee(label); 74 | const options = { value: fee }; 75 | 76 | const blindedCommit = await takoyaki.makeBlindedCommitment(label, signer.address, salt); 77 | let tx = await takoyaki.commit( 78 | blindedCommit, 79 | ethers.constants.AddressZero, 80 | 0, 81 | options 82 | ); 83 | 84 | const receipt = await tx.wait(); 85 | await provider.mineBlocks(5); 86 | 87 | const commitEvent = getEvent(takoyaki, receipt, 'Committed'); 88 | if (!commitEvent) { 89 | throw new Error('missing commit event'); 90 | } 91 | 92 | if (commitEvent.values.length !== 2) { 93 | throw new Error( 94 | `Expect 2 parameters for the commit event, but got ${ 95 | commitEvent.values.length 96 | }` 97 | ); 98 | } 99 | 100 | if( blindedCommit !== commitEvent.values[1]) { 101 | throw new Error(`blindedCommit mismatch, expect ${blindedCommit} got ${commitEvent.values[1]}`); 102 | } 103 | 104 | return blindedCommit; 105 | }; 106 | 107 | const syncUpkeepFee = async (admin, signer, tokenId) => { 108 | const takoyaki = Takoyaki.connect(signer); 109 | const smallerFee = await takoyaki.getTakoyaki(tokenId).then(token => token.upkeepFee.sub(1)); 110 | 111 | const takoyakiAdmin = Takoyaki.connect(admin); 112 | const feeTx = await takoyakiAdmin.setFee(smallerFee); 113 | await feeTx.wait(); 114 | 115 | const syncTx = await takoyaki.syncUpkeepFee(tokenId); 116 | await syncTx.wait(); 117 | 118 | return smallerFee; 119 | }; 120 | 121 | module.exports = { 122 | connect: Takoyaki.connect, 123 | getEvent, 124 | getTokenId, 125 | register, 126 | safeTransfer, 127 | submitBlindedCommit, 128 | syncUpkeepFee 129 | }; 130 | -------------------------------------------------------------------------------- /bin/build-history.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const fs = require("fs"); 4 | 5 | const ethers = require("ethers"); 6 | 7 | const takoyaki = require("../lib"); 8 | 9 | const provider = ethers.getDefaultProvider("ropsten"); 10 | const Takoyaki = takoyaki.connect(provider); 11 | 12 | function escapeChar(value) { 13 | value = value.toString(16); 14 | while (value.length < 4) { value = "0" + value; } 15 | return "\\u" + value; 16 | } 17 | 18 | function escape(text) { 19 | let bytes = ethers.utils.toUtf8Bytes(text); 20 | 21 | let result = ""; 22 | let i = 0; 23 | 24 | while (i < bytes.length) { 25 | let c = bytes[i++]; 26 | 27 | if (c >> 7 === 0) { 28 | result += String.fromCharCode(c); 29 | continue; 30 | } 31 | 32 | // Multibyte; how many bytes left for this character? 33 | let extraLength = null; 34 | let overlongMask = null; 35 | 36 | // 110x xxxx 10xx xxxx 37 | if ((c & 0xe0) === 0xc0) { 38 | extraLength = 1; 39 | overlongMask = 0x7f; 40 | 41 | // 1110 xxxx 10xx xxxx 10xx xxxx 42 | } else if ((c & 0xf0) === 0xe0) { 43 | extraLength = 2; 44 | overlongMask = 0x7ff; 45 | 46 | // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx 47 | } else if ((c & 0xf8) === 0xf0) { 48 | extraLength = 3; 49 | overlongMask = 0xffff; 50 | 51 | } else { 52 | if ((c & 0xc0) === 0x80) { 53 | throw new Error("invalid utf8 byte sequence; unexpected continuation byte"); 54 | } 55 | throw new Error("invalid utf8 byte sequence; invalid prefix"); 56 | } 57 | 58 | // Do we have enough bytes in our data? 59 | if (i + extraLength > bytes.length) { 60 | throw new Error("invalid utf8 byte sequence; too short"); 61 | } 62 | 63 | // Remove the length prefix from the char 64 | let res = c & ((1 << (8 - extraLength - 1)) - 1); 65 | 66 | for (let j = 0; j < extraLength; j++) { 67 | let nextChar = bytes[i]; 68 | 69 | // Invalid continuation byte 70 | if ((nextChar & 0xc0) != 0x80) { 71 | res = null; 72 | break; 73 | }; 74 | res = (res << 6) | (nextChar & 0x3f); 75 | i++; 76 | } 77 | 78 | if (res === null) { 79 | throw new Error("invalid utf8 byte sequence; invalid continuation byte"); 80 | } 81 | 82 | // Check for overlong seuences (more bytes than needed) 83 | if (res <= overlongMask) { 84 | throw new Error("invalid utf8 byte sequence; overlong"); 85 | } 86 | 87 | // Maximum code point 88 | if (res > 0x10ffff) { 89 | throw new Error("invalid utf8 byte sequence; out-of-range"); 90 | } 91 | 92 | // Reserved for UTF-16 surrogate halves 93 | if (res >= 0xd800 && res <= 0xdfff) { 94 | throw new Error("invalid utf8 byte sequence; utf-16 surrogate"); 95 | } 96 | 97 | if (res <= 0xffff) { 98 | result += escapeChar(res); 99 | continue; 100 | } 101 | 102 | res -= 0x10000; 103 | result += escapeChar(((res >> 10) & 0x3ff) + 0xd800); 104 | result += escapeChar((res & 0x3ff) + 0xdc00); 105 | } 106 | 107 | return result; 108 | } 109 | 110 | 111 | (async function() { 112 | const output = [ ]; 113 | 114 | let logs = await Takoyaki.queryFilter("Registered", 0, "latest"); 115 | logs.forEach((log) => { 116 | console.log(log); 117 | output.push({ 118 | tokenId: log.values[1].toHexString(), 119 | name: log.values[2], 120 | }); 121 | }); 122 | 123 | return output; 124 | })().then(async (tokens) => { 125 | for (let i = 0; i < tokens.length; i++) { 126 | if (tokens[i].seeds) { continue; } 127 | 128 | let traits = await Takoyaki.getTraits(tokens[i].tokenId); 129 | tokens[i].salt = traits.genes.salt; 130 | tokens[i].seeds = traits.genes.seeds; 131 | } 132 | console.log(tokens, tokens.length); 133 | 134 | fs.writeFileSync("history.js", `const TakoyakiHistory = ${ escape(JSON.stringify(tokens)) };`); 135 | }); 136 | 137 | // @TODO: 138 | // - Check that the state is 5 139 | // - Continue from the last block in the existing history 140 | -------------------------------------------------------------------------------- /heroku-app/static/debug.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Takoyaki Example Links 4 | 5 | 6 |

Local Testing

7 | 28 | 29 |

Edge Cache Testing

30 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /heroku-app/static-fallback/debug.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Takoyaki Example Links 4 | 5 | 6 |

Local Testing

7 | 28 | 29 |

Edge Cache Testing

30 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /static/logo-metamask.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /heroku-app/static/logo-metamask.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /heroku-app/static-fallback/logo-metamask.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /heroku-app/static-fallback/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Takoyaki!!! 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 26 |
27 | 73 |
74 |
.takoyaki.eth
75 |
76 | 83 | 84 |
Adopt me...
85 |
86 |
87 |
88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Takoyaki!!! 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 20 | 48 |
49 | 96 |
97 |
.takoyaki.eth
98 |
99 |
100 |
Adopt me...
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | Takoyaki NFT 2 | ============ 3 | 4 | Welcome to the Takoyaki NFT library. 5 | 6 | The goal of this library is to simplify interacting with the 7 | Takoyaki NFTs (Non-Fungible Tokens) on the Ethereum blockchain. 8 | 9 | It contains the art asset rendering and trait computation functions 10 | needed to create client side SVG files for a given set of traits 11 | as well as the algorithms required to compute the traits from the 12 | on-chain data for a given Takoyaki. 13 | 14 | Installing 15 | ---------- 16 | 17 | ``` 18 | /home/ricmoo/my-project> npm install --save takoyaki 19 | ``` 20 | 21 | ```javascript 22 | const Takoyaki = require("takoyaki"); 23 | ``` 24 | 25 | API 26 | --- 27 | 28 | ### Rendering and Display Logic 29 | 30 | **Takoyaki.getSvg ( traits [ , backgroundColor ] )** => *string* 31 | 32 | Create an SVG string for the appearance `traits` and optionally a 33 | `backgroundColor` (100% transparent, by default). 34 | 35 | **Takoyaki.getLabelColor ( label [ , saturation = 90 [ , luminence = 90 ] ] )** => *string* 36 | 37 | Create an `hsl(hue, saturation, luminence)` color for the given label, which can be 38 | used for the background (sat = 90, lum = 90), or adding lighter/darker features, 39 | such as borders or text. 40 | 41 | **Takoyaki.SVG** => *string* 42 | 43 | The raw SVG that is processed to generate individual Takoyaki. 44 | 45 | 46 | ### Traits 47 | 48 | **Takoyaki.getTraits ( [ genes ] )** => *Traits* 49 | 50 | Compute the traits for a given set of genes, which should include a `salt` and 51 | `seeds`, which is an Array of up to 5 bytes6. If genes is omitted, a random set 52 | of traits is returned. 53 | 54 | 55 | ### URLs and Labels 56 | 57 | **Takoyaki.urlToLabel ( hostname )** => *string* 58 | 59 | Converts a hostname into the label, accounting for [Punycode](https://en.wikipedia.org/wiki/Punycode), 60 | so international and emoji names can be used. 61 | 62 | **Takoyaki.labelToUrl ( label )** => *string* 63 | 64 | Converts a label into the Punycode hostname. 65 | 66 | **Takoyaki.nomarlizeLabel ( label )** => *string* 67 | 68 | Normalize a label string, folding cases, UTF-8 composition and UTF-8 canonical 69 | representation as per punycode. 70 | 71 | 72 | ### Takoyaki Contract 73 | 74 | **Takoyaki.connect ( providerOrProvider )** => *TakoyakiContract* 75 | 76 | Return a Contract instance to interact with the blockchain values for Takoyaki 77 | Tokens. 78 | 79 | **contract.getTransactions ( label , owner , salt [ , prefundRevealer ] )** => *Object* 80 | 81 | Returns an object with two transaction Objects, `commit` and `reveal`, which can be 82 | signed and sent to the network to commit and reveal. You MUST have a delay of at least 83 | 4 blocks between commit and reveal, and no more than 5,760 blocks. 84 | 85 | This is the recommended method of using this library. 86 | 87 | **contract.getTraits ( tokenId [ , hints ] )** => *Promise:Traits* 88 | 89 | Returns the traits for a given Takoyaki. The hints can be used to save network 90 | calls and to indicate information which is not yet available, such as the `salt` 91 | prior to the reveal. 92 | 93 | **contract.tokenURI ( tokenId )** => *Promise:string* 94 | 95 | Returns the URL of a JSON description of the token 96 | 97 | **contract.totalSupply ( )** => *Promise:BigNumber* 98 | 99 | Returns the total number of Takoyaki currently issued. This may be higher than 100 | the actual number, since the total supply is only decremented for expired 101 | Takoyaki Tokens when `destroy` is called them. 102 | 103 | **contract.symbol** => *string* 104 | 105 | Returns "TAKO" 106 | 107 | **contract.name** => *string* 108 | 109 | Returns "Takoyaki" 110 | 111 | **contract.fee ( )** => *Promise:BigNumber* 112 | 113 | Returns the fee for a Takoyaki. 114 | 115 | **contract.isValidLabel ( label )** => *boolean* 116 | 117 | Returns true if and only if the label is valid. 118 | 119 | **contract.getTakoyaki ( tokenId )** => *Promise:Object* 120 | 121 | TODO 122 | 123 | **contract.commit ( blindedCommit , prefundedRevealer , prefundAmount )** => *Promise:TransactionResponse* 124 | 125 | TODO 126 | 127 | **contract.cancelCommit ( blindedCommit )** => *TransactionResponse* 128 | 129 | TODO 130 | 131 | **contract.reveal ( label , owner , salt )** => *TransactionResponse* 132 | 133 | TODO 134 | 135 | **contract.renew ( tokenId )** => *TransactionResponse* 136 | 137 | TODO 138 | 139 | **contract.reclaim ( tokenId , owner )** => *TransactionResponse* 140 | 141 | TODO 142 | 143 | **contract.destroy ( tokenId )** => *TransactionResponse* 144 | 145 | TODO 146 | 147 | **contract.available ( tokenId )** => *Promise:boolean* 148 | 149 | TODO 150 | 151 | **contract.getTakoyaki ( tokenId )** => *Promise:Object* 152 | 153 | TODO 154 | 155 | **contract.ownerOf ( tokenId )** => *Promise:string* 156 | 157 | Returns the owner the *tokenId* Takoyaki. 158 | 159 | **contract.balanceOf ( address )** => *Promise:BigNumber* 160 | 161 | Returns the number of Takoyaki tokens that *address* owns. 162 | 163 | **contract.approve ( toAddress , tokenId )** => *Promise:TransactionResponse* 164 | 165 | TODO 166 | 167 | **contract.getApproved ( tokenId )** => *Promise:string* 168 | 169 | TODO 170 | 171 | **contract.setApprovedForAll ( toAddress , isApproved )** => *Promise:TransactionResponse* 172 | 173 | TODO 174 | 175 | **contract.isApprovedForAll ( owner , operator )** => *Promise:boolean* 176 | 177 | TODO 178 | 179 | **contract.transferFrom ( fromAddress , toAddress, tokenId )** => *Promise:TransactionResponse* 180 | 181 | TODO 182 | 183 | **contract.safeTransferFrom ( fromAddress , toAddress , tokenId , data )** => *Promise:TransactionResponse* 184 | 185 | TODO 186 | 187 | 188 | 189 | License 190 | ------- 191 | 192 | All code is provided under the [MIT license](https://opensource.org/licenses/MIT) and all artwork is provided 193 | under the [Creative Commons cc-by 4.0](https://creativecommons.org/licenses/by/4.0/) 194 | license. 195 | 196 | -------------------------------------------------------------------------------- /heroku-app/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Takoyaki!!! 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 20 | 48 |
49 | 96 |
97 |
.takoyaki.eth
98 |
99 |
100 |
Adopt me...
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /lib/lib/svg-parser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var SvgNode = /** @class */ (function () { 4 | function SvgNode(name, attributes, selfClose) { 5 | var _this = this; 6 | this.name = name; 7 | this.attributes = {}; 8 | this.selfClose = selfClose; 9 | this.children = []; 10 | this._parentNode = null; 11 | // Populate the attributes 12 | if (typeof (attributes) === "string") { 13 | var replacer = function (all, key, value) { 14 | _this.attributes[key] = value.replace(/\s+/g, " "); 15 | return ""; 16 | }; 17 | attributes = (attributes || "").replace(/([a-z:]+)\s*=\s*"(([^"]|\\.)*)"/ig, replacer); 18 | // Check for unprocessed attributes 19 | if (attributes.trim().length) { 20 | throw new Error("Junk attributes leftover: " + JSON.stringify(attributes)); 21 | } 22 | } 23 | else if (attributes) { 24 | Object.keys(attributes).forEach(function (key) { 25 | _this.attributes[key] = attributes[key]; 26 | }); 27 | } 28 | ///Object.freeze(this.attributes); 29 | ///Object.freeze(this.children); 30 | //Object.freeze(this); 31 | } 32 | SvgNode.prototype.render = function () { 33 | var _this = this; 34 | var result = "<" + this.name; 35 | result += Object.keys(this.attributes).map(function (key) { return " " + key + "=\"" + _this.attributes[key] + "\""; }).join(""); 36 | // Self-closing tag; just close it and we're done 37 | if (this.selfClose) { 38 | return result + " />"; 39 | } 40 | // Can have children; add them and include a closing tag 41 | result += ">"; 42 | result += this.children.map(function (child) { return child.render(); }).join(""); 43 | result += ""; 44 | return result; 45 | }; 46 | SvgNode.prototype.clone = function () { 47 | var node = new SvgNode(this.name, this.attributes, this.selfClose); 48 | this.children.forEach(function (child) { 49 | node.children.push(child.clone()); 50 | }); 51 | return node; 52 | }; 53 | SvgNode.prototype.remove = function () { 54 | var _this = this; 55 | var node = (this._parentNode); 56 | node.children = node.children.filter(function (child) { return (child !== _this); }); 57 | }; 58 | SvgNode.isNode = function (value) { 59 | return (value instanceof SvgNode); 60 | }; 61 | return SvgNode; 62 | }()); 63 | exports.SvgNode = SvgNode; 64 | var Data = /** @class */ (function () { 65 | function Data(content) { 66 | this.content = content; 67 | this._parentNode = null; 68 | } 69 | Data.prototype.render = function () { 70 | return this.content; 71 | }; 72 | Data.prototype.clone = function () { 73 | return new Data(this.content); 74 | }; 75 | return Data; 76 | }()); 77 | exports.Data = Data; 78 | var SvgDocument = /** @class */ (function () { 79 | function SvgDocument(definition, svg) { 80 | var _this = this; 81 | this.definition = definition; 82 | this.svg = svg; 83 | this._links = {}; 84 | var visit = function (node) { 85 | (node.children || []).forEach(function (child) { 86 | child._parentNode = node; 87 | visit(child); 88 | }); 89 | if (node.attributes == null) { 90 | return; 91 | } 92 | var id = node.attributes["id"]; 93 | if (id == null) { 94 | return; 95 | } 96 | if (_this._links[id] == null) { 97 | _this._links[id] = [node]; 98 | } 99 | else { 100 | _this._links[id].push(node); 101 | } 102 | }; 103 | visit(this.svg); 104 | this.svg._parentNode = this; 105 | //Object.freeze(this._links); 106 | //Object.freeze(this); 107 | } 108 | SvgDocument.prototype.render = function () { 109 | return this.definition + this.svg.render(); 110 | }; 111 | SvgDocument.prototype.clone = function () { 112 | return new SvgDocument(this.definition, this.svg.clone()); 113 | }; 114 | SvgDocument.prototype.getElementById = function (id) { 115 | var el = this._links[id]; 116 | if (el) { 117 | return el[0]; 118 | } 119 | return null; 120 | }; 121 | return SvgDocument; 122 | }()); 123 | exports.SvgDocument = SvgDocument; 124 | function parse(text) { 125 | var stack = [{ content: "", children: [] }]; 126 | function replacer(all, both, contents, data) { 127 | var match = null; 128 | if (data != null) { 129 | // Data 130 | if ((data || "").trim() === "") { 131 | return ""; 132 | } 133 | stack[stack.length - 1].children.push(new Data(data)); 134 | } 135 | else if (match = contents.match(/^<\s*([a-z0-9]+)(\s+((.|\n)*)\/\s*)>$/i)) { 136 | // Self-closing tag 137 | stack[stack.length - 1].children.push(new SvgNode(match[1], match[3], true)); 138 | } 139 | else if (match = contents.match(/^<\s*\/\s*((.|\n)*)\s*>$/i)) { 140 | // Closing tag 141 | var node = stack.pop(); 142 | if (node.name !== match[1]) { 143 | throw new Error("closing tag mismatch; " + match[1] + " != " + node.name); 144 | } 145 | } 146 | else if (match = contents.match(/^<\s*([a-z0-9]+)(\s+((.|\n)*))?>$/i)) { 147 | // Opening tag 148 | var node = new SvgNode(match[1], match[3], false); 149 | stack[stack.length - 1].children.push(node); 150 | stack.push(node); 151 | } 152 | else if (match = contents.match(/^<\?/im)) { 153 | // XML Definition 154 | if (stack[0].content) { 155 | throw new Error("duplicate xml definition"); 156 | } 157 | stack[0].content = contents; 158 | } 159 | else if (match = contents.match(/^/im)) { 160 | // Comment 161 | } 162 | else { 163 | throw new Error(JSON.stringify(contents)); 164 | } 165 | return ""; 166 | } 167 | text = text.replace(/((<[^>]*>)|(([^<>]|\n)*))/mg, replacer); 168 | // Check for unprocessed XML 169 | if (text.trim() !== "") { 170 | throw new Error("Junk XML leftover: " + JSON.stringify(text)); 171 | } 172 | // Some basic sanity checks 173 | if (stack.length !== 1) { 174 | throw new Error("missing close tags"); 175 | } 176 | if (stack[0].children.length !== 1) { 177 | throw new Error("too many svg tags"); 178 | } 179 | return new SvgDocument(stack[0].content, stack[0].children[0]); 180 | } 181 | exports.parse = parse; 182 | -------------------------------------------------------------------------------- /lib/src.ts/svg-parser.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // This is meant to be a very quick and dirty SVG parser. The SVG produced by 4 | // Adobe Illustrator is well-formed, so for the most part. There has been very 5 | // little work into sanitizing the input and providing useful error messages. 6 | 7 | export interface NodeLike { 8 | _parentNode: NodeLike; // @TODO: rename to parentNode? 9 | render(): string; 10 | clone(): NodeLike; 11 | } 12 | 13 | export type Attributes = { [ attribute: string ]: string }; 14 | 15 | export class SvgNode implements NodeLike { 16 | readonly name: string; 17 | readonly attributes: Attributes; 18 | readonly selfClose: boolean; 19 | children: Array // @TODO: would be nice if this was redonly... 20 | _parentNode: NodeLike; 21 | 22 | constructor(name: string, attributes: string | Attributes, selfClose: boolean) { 23 | this.name = name; 24 | this.attributes = { }; 25 | this.selfClose = selfClose; 26 | this.children = [ ]; 27 | 28 | this._parentNode = null; 29 | 30 | // Populate the attributes 31 | if (typeof(attributes) === "string") { 32 | let replacer = (all: string, key: string, value: string): string => { 33 | this.attributes[key] = value.replace(/\s+/g, " "); 34 | return ""; 35 | } 36 | 37 | attributes = (attributes || "").replace(/([a-z:]+)\s*=\s*"(([^"]|\\.)*)"/ig, replacer); 38 | 39 | // Check for unprocessed attributes 40 | if (attributes.trim().length) { 41 | throw new Error("Junk attributes leftover: " + JSON.stringify(attributes)); 42 | } 43 | } else if (attributes) { 44 | Object.keys(attributes).forEach((key) => { 45 | this.attributes[key] = (attributes)[key]; 46 | }); 47 | } 48 | 49 | ///Object.freeze(this.attributes); 50 | ///Object.freeze(this.children); 51 | //Object.freeze(this); 52 | } 53 | 54 | render(): string { 55 | let result = "<" + this.name; 56 | result += Object.keys(this.attributes).map((key) => ` ${ key }="${ this.attributes[key] }"`).join(""); 57 | 58 | // Self-closing tag; just close it and we're done 59 | if (this.selfClose) { return result + " />"; } 60 | 61 | // Can have children; add them and include a closing tag 62 | result += ">"; 63 | result += this.children.map((child) => child.render()).join(""); 64 | result += ""; 65 | 66 | return result; 67 | } 68 | 69 | clone(): SvgNode { 70 | let node = new SvgNode(this.name, this.attributes, this.selfClose); 71 | this.children.forEach((child) => { 72 | node.children.push(child.clone()); 73 | }); 74 | return node; 75 | } 76 | 77 | remove(): void { 78 | const node: SvgNode = ((this._parentNode)); 79 | node.children = node.children.filter((child) => (child !== this)); 80 | } 81 | 82 | static isNode(value: any): value is SvgNode { 83 | return (value instanceof SvgNode); 84 | } 85 | } 86 | 87 | 88 | export class Data implements NodeLike { 89 | readonly content: string; 90 | _parentNode: NodeLike; 91 | 92 | constructor(content: string) { 93 | this.content = content 94 | this._parentNode = null; 95 | } 96 | 97 | render(): string { 98 | return this.content; 99 | } 100 | 101 | clone(): Data { 102 | return new Data(this.content); 103 | } 104 | } 105 | 106 | export class SvgDocument implements NodeLike { 107 | readonly definition: string; 108 | readonly svg: SvgNode; 109 | readonly _links: { [ id: string ]: Array }; 110 | _parentNode: NodeLike; 111 | 112 | constructor(definition: string, svg: SvgNode) { 113 | this.definition = definition; 114 | this.svg = svg; 115 | 116 | this._links = { }; 117 | 118 | let visit = (node: any) => { 119 | (node.children || []).forEach((child: any) => { 120 | child._parentNode = node; 121 | visit(child); 122 | }); 123 | 124 | if (node.attributes == null) { return; } 125 | let id = node.attributes["id"]; 126 | if (id == null) { return; } 127 | 128 | if (this._links[id] == null) { 129 | this._links[id] = [ node ]; 130 | } else { 131 | this._links[id].push(node); 132 | } 133 | } 134 | visit(this.svg); 135 | 136 | this.svg._parentNode = this; 137 | 138 | //Object.freeze(this._links); 139 | //Object.freeze(this); 140 | } 141 | 142 | render(): string { 143 | return this.definition + this.svg.render(); 144 | } 145 | 146 | clone(): SvgDocument { 147 | return new SvgDocument(this.definition, this.svg.clone()) 148 | } 149 | 150 | getElementById(id: string): SvgNode { 151 | let el = this._links[id]; 152 | if (el) { return el[0]; } 153 | return null; 154 | } 155 | } 156 | 157 | export function parse(text: string): SvgDocument { 158 | let stack: Array = [ { content: "", children: [ ] } ]; 159 | 160 | function replacer(all: string, both: string, contents: string, data: string): string { 161 | let match = null; 162 | 163 | if (data != null) { 164 | // Data 165 | if ((data || "").trim() === "") { return ""; } 166 | stack[stack.length - 1].children.push(new Data(data)); 167 | 168 | } else if (match = contents.match(/^<\s*([a-z0-9]+)(\s+((.|\n)*)\/\s*)>$/i)) { 169 | // Self-closing tag 170 | stack[stack.length - 1].children.push(new SvgNode(match[1], match[3], true)); 171 | 172 | } else if (match = contents.match(/^<\s*\/\s*((.|\n)*)\s*>$/i)) { 173 | // Closing tag 174 | let node = stack.pop(); 175 | if (node.name !== match[1]) { throw new Error(`closing tag mismatch; ${ match[1] } != ${ node.name }`); } 176 | 177 | } else if (match = contents.match(/^<\s*([a-z0-9]+)(\s+((.|\n)*))?>$/i)) { 178 | // Opening tag 179 | let node = new SvgNode(match[1], match[3], false); 180 | stack[stack.length - 1].children.push(node); 181 | stack.push(node) 182 | 183 | } else if (match = contents.match(/^<\?/im)) { 184 | // XML Definition 185 | if (stack[0].content) { throw new Error("duplicate xml definition"); } 186 | stack[0].content = contents; 187 | 188 | } else if (match = contents.match(/^/im)) { 189 | // Comment 190 | 191 | } else { 192 | throw new Error(JSON.stringify(contents)); 193 | } 194 | 195 | return ""; 196 | } 197 | 198 | text = text.replace(/((<[^>]*>)|(([^<>]|\n)*))/mg, replacer); 199 | 200 | // Check for unprocessed XML 201 | if (text.trim() !== "") { 202 | throw new Error("Junk XML leftover: " + JSON.stringify(text)); 203 | } 204 | 205 | // Some basic sanity checks 206 | if (stack.length !== 1) { throw new Error("missing close tags"); } 207 | if (stack[0].children.length !== 1) { throw new Error("too many svg tags"); } 208 | 209 | return new SvgDocument(stack[0].content, stack[0].children[0]); 210 | } 211 | 212 | -------------------------------------------------------------------------------- /heroku-app/static/script.js: -------------------------------------------------------------------------------- 1 | (function(){function getSvg(traits){return Takoyaki.getSvg(traits).replace('',"")}{const Background=document.getElementById("background");const Card=document.getElementById("card");const Search=document.getElementById("search");const SetTile={};let lastHighlight=-1;function isVisible(el){let cx=window.innerWidth/2;let cy=window.innerHeight/2;let panel=null;if(Card.style.display==="block"){panel=Card.getBoundingClientRect()}else if(Search.style.dispaly==="block"){panel=Search.getBoundingClientRect()}else{return true}let box=el.getBoundingClientRect();let point={x:box.left+.25*box.width,y:box.top+.25*box.height};if(point.x>cx){point.x+=box.width/2}if(point.y>cy){point.y+=box.height/2}if(point.x<0||point.x>window.innerWidth||point.y<0||point.y>window.innerHeight){return false}point={x:box.left+.5*box.width,y:box.top+.5*box.height};if(point.xpanel.right||point.ypanel.bottom){return true}return false}let nextZIndex=1;function createTakoyakiTile(id){let tile=document.createElement("div");tile.className="tile";tile.id=id;tile.style.zIndex=nextZIndex++;Background.appendChild(tile);let _front=document.createElement("div");_front.className="backdrop";tile.appendChild(_front);let front=document.createElement("div");_front.appendChild(front);let _back=document.createElement("div");_back.className="backdrop";tile.appendChild(_back);let back=document.createElement("div");_back.appendChild(back);let current=1;SetTile[id]=function(label,traits){let div=current%2?back:front;div.style.background=Takoyaki.getLabelColor(label);div.style.borderColor=Takoyaki.getLabelColor(label,90,50);if(current>2){div.classList.add("highlight");setTimeout(()=>{div.classList.remove("highlight")},4e3)}current++;div.innerHTML=getSvg(traits);tile.style.zIndex=nextZIndex++;let span=document.createElement("span");span.textContent=label;div.appendChild(span);_back.style.transform="rotateY("+current*180+"deg) translateZ(0.1px)";_front.style.transform="rotateY("+(current+1)*180+"deg) translateZ(0.1px)"};return tile}function fillBackground(){document.body.classList.remove("animated");let inflight=0;let ox=(window.innerWidth%165-160)/2;let oy=(window.innerHeight%165-160)/2;let i=0;for(let x=0;x20||value.match(/\.|\s/)){searchbar.value=lastValue;event.preventDefault();event.stopPropagation();return false}lastValue=value;return true};searchbar.onkeyup=function(event){if(event.which===13){location.href=Takoyaki.labelToUrl(searchbar.value,local)}}}const label=Takoyaki.urlToLabel(location.hostname);const local=location.hostname.split(".").pop()==="local";const errors={UNSUPPORTED_NETWORK:"UNSUPPORTED_NETWORK"};const{providerPromise:providerPromise,getSigner:getSigner}=function(){const requiredNetwork="ropsten";let providerOptions={infura:"6189cea41bac431286af08a06df219be",etherscan:"9D13ZE7XSBTJ94N9BNJ2MA33VMAY2YPIRB",nodesmith:"f1b3ce218afb412bb4a6657825141885",alchemy:"JrWxtuwXu_V5zN5kMUCnMRpxmqmuuT_h"};if(window.ethereum){let lastNetwork=-1e3;function checkNetwork(){ethereum.send("eth_chainId").then(result=>{let network=ethers.providers.getNetwork(ethers.BigNumber.from(result.result).toNumber());if(lastNetwork>=0&&network.chainId!==lastNetwork){return location.reload()}lastNetwork=network.chainId;setTimeout(checkNetwork,1e3)},error=>{console.log(error);setTimeout(checkNetwork,1e3)})}let networkPromise=ethereum.send("eth_chainId",[]).then(result=>{let network=ethers.providers.getNetwork(ethers.BigNumber.from(result.result).toNumber());lastNetwork=network.chainId;setTimeout(checkNetwork,1e3);if(network.name!==requiredNetwork){return Promise.reject(new Error(errors.UNSUPPORTED_NETWORK))}return network});let providerPromise=networkPromise.then(network=>{return new ethers.providers.Web3Provider(ethereum)},error=>{return ethers.getDefaultProvider(requiredNetwork,providerOptions)});let signerPromise=null;let getSigner=()=>{if(signerPromise==null){signerPromise=providerPromise.then(provider=>{if(provider.getSigner==null){return Promise.reject("unsupported network")}return window.ethereum.enable().then(allowed=>{if(allowed&&allowed.length){return provider.getSigner(allowed[0])}return Promise.reject(new Error("no authorized signer"))})})}return signerPromise};return{providerPromise:providerPromise,getSigner:getSigner}}return{providerPromise:Promise.resolve(ethers.getDefaultProvider(requiredNetwork,providerOptions)),getSigner:()=>Promise.resolve(null)}}();{if(window.ethereum){providerPromise.then(provider=>{if(provider.getSigner==null){document.getElementById("about-wrong-network").classList.remove("hidden")}else{document.getElementById("about-ok").classList.remove("hidden")}})}else{document.getElementById("about-no-ethereum").classList.remove("hidden")}}{const userAgentComps=[];(navigator.userAgent||navigator.vendor||window.opera||"").replace(/([a-z0-9]+)/gi,(function(all,word){userAgentComps.push(word.toLowerCase());return""}));if(userAgentComps.join(" ").match(/(ios|iphone|ipad|ipod|android)/i)){const url="https://metamask.app.link/dapp/"+location.host.split(":")[0]+"/";console.log("Mobile Device: Set MetaMask link = "+url);document.getElementById("link-metamask").setAttribute("href",url)}}const AdoptButton=document.getElementById("button-adopt");const TakoyakiContainer=document.getElementById("takoyaki");function draw(traits){TakoyakiContainer.innerHTML=getSvg(traits)}const pendingHints={};async function register(label){const tokenId=ethers.utils.id(label);if(!pendingHints[tokenId]){pendingHints[tokenId]={}}let hints=pendingHints[tokenId];const provider=await providerPromise;const dustWallet=function(){let dustMnemonic=localStorage.getItem("dust-wallet-mnemonic");if(!ethers.utils.isValidMnemonic(dustMnemonic)){let wallet=ethers.Wallet.createRandom();localStorage.setItem("dust-wallet-mnemonic",wallet.mnemonic);return wallet.connect(provider)}return ethers.Wallet.fromMnemonic(dustMnemonic).connect(provider)}();console.log("Dust Wallet:",dustWallet.address);let signer=await getSigner();let owner=await signer.getAddress();let takoyaki=Takoyaki.connect(signer);let salt=ethers.utils.keccak256(await dustWallet.signMessage("salt:"+label));hints.salt=ethers.utils.keccak256(ethers.utils.concat([tokenId,salt]));let txs=await takoyaki.getTransactions(label,owner,salt,dustWallet.address);console.log(txs);let signedRevealTx=await dustWallet.signTransaction(txs.reveal);console.log("Signed Reveal Transaction:",signedRevealTx);try{await Takoyaki.submitReveal(signedRevealTx)}catch(error){console.log(error);throw new Error("Could not submit to reveal service")}let tx=null;try{tx=await signer.sendTransaction(txs.commit)}catch(error){console.log(error);throw new Error("Cancelled Transaction.")}let receipt=await tx.wait();hints.commitBlock=receipt.blockNumber;console.log("COMMITED",receipt.blockNumber);await tx.wait(4);console.log("Sending reveal...");tx=await provider.sendTransaction(signedRevealTx);receipt=await tx.wait();hints.revealBlock=receipt.blockNumber;return true}if(label){console.log("LABEL",label);const Card=document.getElementById("card");Card.style.display="block";document.getElementById("label").textContent=label;document.getElementById("populate-label").textContent=label;document.title=label+" || Takoyaki!!";let tokenId=ethers.utils.id(label);if(!pendingHints[tokenId]){pendingHints[tokenId]={}}let hints=pendingHints[tokenId];hints.name=label;providerPromise.then(provider=>{const contract=Takoyaki.connect(provider);let polling=false;function check(blockNumber){if(blockNumber){hints.blockNumber=blockNumber}contract.getTraits(tokenId,hints).then(traits=>{draw(traits);if(traits.genes.addr){document.body.classList.add("has-addr");const addr=traits.genes.addr;document.getElementById("addr-top").textContent=" "+addr.substring(0,12)+" "+addr.substring(12,22)+" ";document.getElementById("addr-bottom").textContent=" "+addr.substring(22,32)+" "+addr.substring(32,42)+" ";document.getElementById("spacer").remove()}if(traits.state===5){if(polling){provider.off("block",check);polling=false}}else{if(traits.genes.status==="available"){AdoptButton.classList.add("available");AdoptButton.classList.add("enabled")}if(!polling){provider.on("block",check);polling=true}}})}check()})}else{const Search=document.getElementById("search");Search.style.display="block";function pulse(wait,callback){setTimeout((function(){document.body.classList.add("pulse");setTimeout((function(){document.body.classList.remove("pulse");callback()}),1)}),wait)}pulse(1500,(function(){pulse(300)}))}AdoptButton.onclick=function(){document.getElementById("about").classList.remove("hidden")};document.getElementById("button-close").onclick=function(){document.getElementById("about").classList.add("hidden")};document.getElementById("button-hatch").onclick=function(){document.getElementById("about").classList.add("hidden");AdoptButton.classList.remove("enabled");AdoptButton.classList.add("running");register(label).then(()=>{},error=>{console.log(error);alert(error.message);AdoptButton.classList.remove("running");AdoptButton.classList.add("enabled")})}})(); -------------------------------------------------------------------------------- /static/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | margin: 0; 4 | } 5 | 6 | body { 7 | height: 100%; 8 | margin: 0; 9 | position: realtive; 10 | } 11 | 12 | div { 13 | box-sizing: border-box; 14 | } 15 | 16 | input { 17 | box-sizing: border-box; 18 | } 19 | 20 | .center { 21 | text-align: center; 22 | } 23 | 24 | .warning { 25 | color: #d44; 26 | } 27 | 28 | #background { 29 | height: 100%; 30 | overflow: hidden; 31 | position: relative; 32 | width: 100%; 33 | z-index: 1; 34 | } 35 | 36 | #background .tile { 37 | perspective: 500px; 38 | height: 160px; 39 | transform-style: preserve-3d; 40 | position: absolute; 41 | width: 160px; 42 | z-index: 1 43 | } 44 | 45 | #background .tile div.backdrop { 46 | background: #fff; 47 | border-radius: 10px; 48 | height: 160px; 49 | overflow: hidden; 50 | position: absolute; 51 | transform-style: preserve-3d; 52 | width: 160px; 53 | } 54 | 55 | #background .tile div.backdrop div { 56 | backface-visibility: hidden; 57 | -webkit-backface-visibility: hidden; 58 | border-radius: 10px; 59 | border: 1px solid black; 60 | height: 160px; 61 | opacity: 0.2; 62 | overflow: hidden; 63 | position: absolute; 64 | transform-style: preserve-3d; 65 | width: 160px; 66 | } 67 | 68 | body.animated #background .tile div.backdrop { 69 | transition: transform 2.0s ease-out; 70 | } 71 | 72 | body.animated #background .tile div.backdrop div { 73 | transition: opacity 1.5s linear; 74 | } 75 | 76 | #background .tile div.backdrop div.highlight { 77 | opacity: 1; 78 | } 79 | 80 | #background .tile:hover div.backdrop div { 81 | opacity: 1; 82 | transition: opacity 0.8s linear, transform 1.0s ease-out; 83 | } 84 | 85 | body.animated #background .tile div.highlight { 86 | transition: opacity 0.1s linear, transform 1.0s ease-out; 87 | } 88 | 89 | #background .tile span { 90 | bottom: 6px; 91 | color: #888; 92 | display: block; 93 | font-family: monospace; 94 | font-size: 16px; 95 | height: 20px; 96 | left: 0; 97 | line-heght: 20px; 98 | overflow: hidden; 99 | pointer-events: none; 100 | position: absolute; 101 | text-align: center; 102 | text-overflow: ellipsis; 103 | white-space: nowrap; 104 | width: 160px; 105 | } 106 | 107 | #search { 108 | background: #fff; 109 | border: 5px solid #333; 110 | border-radius: 40px; 111 | box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.25); 112 | display: none; 113 | left: 50%; 114 | padding: 30px 40px 20px; 115 | position: absolute; 116 | top: 50%; 117 | transform: translate(-50%, -50%); 118 | width: 500px; 119 | z-index: 2; 120 | } 121 | 122 | #search .title { 123 | text-align: center; 124 | } 125 | 126 | #search input { 127 | border: none; 128 | color: #999; 129 | font-size: 40px; 130 | font-family: monospace; 131 | outline: none; 132 | text-align: center; 133 | text-transform: lowercase; 134 | width: 100%; 135 | } 136 | 137 | #search-warning { 138 | color: #f88; 139 | height: 40px; 140 | font-family: sans-serif; 141 | font-style: italic; 142 | line-height: 40px; 143 | padding-right: 30px; 144 | position: absolute; 145 | pointer-events: none; 146 | text-align: right; 147 | right: 0; 148 | white-space: nowrap; 149 | dddwidth: 100px; 150 | } 151 | 152 | #card { 153 | background: #fff; 154 | border: 5px solid #333; 155 | border-radius: 40px; 156 | box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.25); 157 | display: none; 158 | left: 50%; 159 | padding: 20px 40px 40px; 160 | position: absolute; 161 | top: 50%; 162 | transform: translate(-50%, -50%); 163 | width: 500px; 164 | z-index: 2; 165 | } 166 | 167 | #card .title { 168 | color: #999; 169 | font-size: 50px; 170 | font-family: monospace; 171 | text-align: center; 172 | overflow: hidden; 173 | text-overflow: ellipsis; 174 | white-space: nowrap; 175 | } 176 | 177 | .searchbar { 178 | background: #fff; 179 | border: 3px solid #000; 180 | border-radius: 29px; 181 | box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.5); 182 | font-size: 30px; 183 | left: 30px; 184 | line-height: 50px; 185 | height: 58px; 186 | padding: 0px 20px; 187 | position: absolute; 188 | top: 30px; 189 | transition: transform 0.2s ease-out; 190 | width: 300px; 191 | z-index: 1000000; 192 | } 193 | 194 | body.pulse .searchbar { 195 | transform: scale(1.2, 1.2); 196 | transition: none; 197 | } 198 | 199 | .searchbar input::placeholder { 200 | font-style: italic; 201 | } 202 | 203 | .searchbar .icon-search { 204 | display: inline-block; 205 | position: absolute; 206 | transform: rotate(45deg); 207 | } 208 | 209 | .searchbar input { 210 | border: none; 211 | outline: none; 212 | font-size: 22px; 213 | margin: 0; 214 | padding: 0 5px 0 30px; 215 | width: 100%; 216 | } 217 | 218 | 219 | .subtitle { 220 | color: #aaa; 221 | font-family: monospace; 222 | font-size: 22px; 223 | text-align: right; 224 | } 225 | 226 | .subtitle b { 227 | padding-left: 1px; 228 | padding-right: 2px; 229 | } 230 | 231 | .takoyaki { 232 | margin: 10px 0 10px 50%; 233 | text-align: center; 234 | height: 256px; 235 | transform: translate(-50%, 0); 236 | width: 256px; 237 | } 238 | 239 | .button.metamask-logo { 240 | padding: 10px 10px 10px 60px; 241 | width: 300px; 242 | } 243 | 244 | .button.metamask-logo .img { 245 | height: 45px; 246 | left: 32px; 247 | position: absolute; 248 | transform: translate(-50%, -50%); 249 | top: 50%; 250 | width: 45px; 251 | } 252 | 253 | .button.metamask-logo .img img { 254 | height: 100%; 255 | width: 100%; 256 | } 257 | 258 | .about .background.overlay { 259 | display: none; 260 | } 261 | 262 | .about .button-container { 263 | height: 40px; 264 | } 265 | 266 | .about .button-container.hidden { 267 | display: none; 268 | } 269 | 270 | .button { 271 | border: 2px solid #1c87be; 272 | background: #ef91f2; 273 | border-radius: 6px; 274 | color: #fff; 275 | cursor: pointer; 276 | font-family: sans-serif; 277 | font-weight: bold; 278 | left: 50%; 279 | opacity: 0.1; 280 | padding: 10px 18px; 281 | position: absolute; 282 | transform: translate(-50%, 0); 283 | transition: opacity 0.1s linear; 284 | } 285 | 286 | .button div { 287 | white-space: nowrap; 288 | } 289 | 290 | .button.enabled { 291 | opacity: 1; 292 | transition: opacity 0.1s linear, transform 0.2s ease-out; 293 | } 294 | 295 | .button.enabled:hover { 296 | background-color: #befcff; 297 | border: 2px solid #b24ab5; 298 | box-shadow: 3px 3px 10px hsl(298, 50%, 70%); 299 | color: #ef91f2; 300 | transform: translate(-50%, 0) scale(1.1); 301 | } 302 | 303 | .button.running { 304 | opacity: 1; 305 | background: url(./spinner.gif) no-repeat center center; 306 | color: transparent; 307 | } 308 | 309 | .button .emphasis { 310 | color: #befcff; 311 | } 312 | 313 | .button.enabled:hover .emphasis { 314 | color: #b24ab5; 315 | } 316 | 317 | .button .small { 318 | font-weight: normal; 319 | font-size: 0.96em; 320 | font-style: italic; 321 | } 322 | 323 | .address { 324 | margin: auto: 0; 325 | position: relative; 326 | text-align: center; 327 | } 328 | 329 | .address .hexstring { 330 | color: #444; 331 | font-family: monospace; 332 | font-size: 18px; 333 | letter-spacing: 0.1ex; 334 | pointer-events: none; 335 | position: relative; 336 | -moz-user-select: all; 337 | -webkit-user-select: all; 338 | -ms-user-select: all; 339 | user-select: all; 340 | } 341 | 342 | body.has-addr .hexstring { 343 | pointer-events: auto; 344 | } 345 | 346 | .address .hexstring div { 347 | display: inline-block; 348 | } 349 | 350 | #addr-top { 351 | margin-left: -40px; 352 | white-space: pre; 353 | } 354 | 355 | #spacer { 356 | display: block; 357 | height: 0; 358 | } 359 | 360 | #addr-bottom { 361 | margin-right: -58px; 362 | white-space: pre; 363 | } 364 | 365 | #button-adopt { 366 | display: none; 367 | } 368 | 369 | #button-adopt.available { 370 | display: block; 371 | } 372 | 373 | .about { 374 | background-color: #fff; 375 | border-radius: 40px; 376 | display: flex; 377 | flex-direction: column; 378 | flex-wrap: nowrap; 379 | justify-context: space-between; 380 | margin-top: -20px; 381 | margin-left: -40px; 382 | height: 100%; 383 | padding: 10px 44px 40px; 384 | position: absolute; 385 | transition: opacity 0.1s linear; 386 | width: 100%; 387 | z-index: 3; 388 | } 389 | 390 | .about.hidden { 391 | opacity: 0; 392 | pointer-events: none; 393 | } 394 | 395 | .about > div { 396 | margin: auto 0; 397 | text-align: center; 398 | } 399 | 400 | .about p { 401 | font-size: 18px; 402 | margin: auto 0; 403 | line-height: 2.6ex; 404 | } 405 | 406 | .about p a { 407 | border-bottom: 1px dashed #00f; 408 | color: #44f; 409 | padding-left: 2px; 410 | padding-right: 2px; 411 | dddfont-family: sans-serif; 412 | text-decoration: none; 413 | } 414 | 415 | .about p a:hover { 416 | border-bottom: 1px solid #000; 417 | color: #000; 418 | } 419 | 420 | #button-close { 421 | background: #ddd; 422 | border-radius: 15px; 423 | color: #fff; 424 | display: block; 425 | font-size: 22px; 426 | font-weight: bold; 427 | height: 30px; 428 | line-height: 30px; 429 | position: absolute; 430 | right: 20px; 431 | text-align: center; 432 | text-decoration: none; 433 | top: 20px; 434 | width: 30px; 435 | } 436 | 437 | #button-close:hover { 438 | background:: #888; 439 | } 440 | 441 | 442 | #search .title { 443 | color: #999; 444 | font-size: 30px; 445 | font-family: sans-serif; 446 | } 447 | 448 | #card .about .title { 449 | color: #999; 450 | font-size: 30px; 451 | font-family: sans-serif; 452 | } 453 | 454 | #search p { 455 | font-size: 18px; 456 | line-height: 2.6ex; 457 | } 458 | 459 | #search p a { 460 | border-bottom: 1px dashed #00f; 461 | color: #44f; 462 | padding-left: 2px; 463 | padding-right: 2px; 464 | dddfont-family: sans-serif; 465 | text-decoration: none; 466 | } 467 | 468 | #search p a:hover { 469 | border-bottom: 1px solid #000; 470 | color: #000; 471 | } 472 | -------------------------------------------------------------------------------- /bin/ens.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | const { inherits } = require('util'); 6 | const { ethers } = require('ethers'); 7 | const utils = ethers.utils; 8 | const { cli: CLI, solc } = require('@ethersproject/cli'); 9 | const fs = require('fs'); 10 | 11 | const MIN_REGISTRATION_DURATION_IN_DAYS = 28; 12 | const PERMANENT_REGISTRAR_ID = '0x018fac06'; 13 | const REGISTER_TIMEOUT = 70000; 14 | const INVALID_ADDRESS = '0x0000000000000000000000000000000000000000'; 15 | 16 | const TAKOYAKI_ADDRESS = '0x6C7c09740209c9c3EdcF65971D4616FFf0054621'; 17 | 18 | const ENS_ABI = [ 19 | 'function resolver(bytes32 nodehash) view returns (address addr)' 20 | ]; 21 | 22 | const RESOLVER_ABI = [ 23 | 'function interfaceImplementer(bytes32 namehash, bytes4 interfaceID) view returns (address addr)' 24 | ]; 25 | 26 | const CONTROLLER_ABI = [ 27 | 'function register(string name, address owner, uint duration, bytes32 secret) external payable', 28 | 'function commit(bytes32 commitment) public', 29 | 'function rentPrice(string name, uint duration) view public returns(uint)', 30 | 'function available(string name) view public returns(bool)', 31 | 'function makeCommitment(string name, address owner, bytes32 secret) pure public returns(bytes32)' 32 | ]; 33 | 34 | const TAKOYAKI_ABI = [ 35 | 'function isValidLabel(string label) public view returns (bool)', 36 | 'function reveal(string label, bytes32 randomValue, address owner) public', 37 | 'function fee() public view returns (uint256)', 38 | 'function commit(bytes32 txPreimage) public payable returns (address)' 39 | ]; 40 | 41 | const cli = new CLI.CLI(); 42 | 43 | function RegisterPlugin() {} 44 | inherits(RegisterPlugin, CLI.Plugin); 45 | 46 | function DeployPlugin() {} 47 | inherits(DeployPlugin, CLI.Plugin); 48 | 49 | function SimulatePlugin() {} 50 | inherits(SimulatePlugin, CLI.Plugin); 51 | 52 | DeployPlugin.getHelp = function() { 53 | return { 54 | name: 'deploy ENS_NAME', 55 | help: 'deploy the takoyaki contract for ENS_NAME' 56 | }; 57 | }; 58 | 59 | DeployPlugin.prototype.prepareArgs = async function(args) { 60 | await CLI.Plugin.prototype.prepareArgs.call(this, args); 61 | if (args.length !== 1) { 62 | this.throwUsageError('deploy requires ENS_NAME'); 63 | } 64 | 65 | if (this.accounts.length !== 1) { 66 | this.throwError('deploy requires an account'); 67 | } 68 | 69 | this.ensName = args[0]; 70 | }; 71 | 72 | DeployPlugin.prototype.run = async function(a) { 73 | await CLI.Plugin.prototype.run.call(this); 74 | let code = solc.compile( 75 | fs.readFileSync('./contracts/TakoyakiRegistrar.sol').toString(), 76 | { 77 | optimize: true 78 | } 79 | ).filter(c => c.name === 'TakoyakiRegistrar')[0]; 80 | 81 | let factory = new ethers.ContractFactory( 82 | code.interface, 83 | code.bytecode, 84 | this.accounts[0] 85 | ); 86 | 87 | let network = await this.provider.getNetwork(); 88 | let contract = await factory.deploy( 89 | network.ensAddress, 90 | ethers.utils.namehash(this.ensName), 91 | { 92 | gasLimit: 2000000 93 | } 94 | ); 95 | 96 | let receipt = await contract.deployed(); 97 | console.log(receipt); 98 | }; 99 | 100 | SimulatePlugin.getHelp = function() { 101 | return { 102 | name: 'simulate ENS_NAME LABEL', 103 | help: 'simulate creating a subdomain LABEL every 15 seconds' 104 | }; 105 | }; 106 | 107 | SimulatePlugin.prototype.prepareArgs = async function(args) { 108 | await CLI.Plugin.prototype.prepareArgs.call(this, args); 109 | if (args.length !== 2) { 110 | this.throwUsageError('simulate requires ENS_NAME and LABEL'); 111 | } 112 | 113 | if (this.accounts.length !== 1) { 114 | this.throwError('simulate requires an account'); 115 | } 116 | 117 | this.ensName = args[0]; 118 | this.label = args[1]; 119 | }; 120 | 121 | const runSimulator = (round, simulator) => { 122 | setTimeout(async () => { 123 | try { 124 | const gasPrice = await simulator.provider.getGasPrice(); 125 | let randomValue = utils.hexlify(ethers.utils.randomBytes(32)); 126 | let label = simulator.label + round; 127 | let revealTx = await simulator.registrar.populateTransaction.reveal( 128 | label, 129 | randomValue, 130 | simulator.owner 131 | ); 132 | revealTx.nonce = 0; 133 | revealTx.chainId = simulator.chainId; 134 | revealTx.gasPrice = gasPrice.mul(11).div(10); 135 | revealTx.gasLimit = 250000; 136 | 137 | revealTx = await utils.resolveProperties(revealTx); 138 | 139 | let revealPreimage = utils.keccak256( 140 | utils.serializeTransaction(revealTx) 141 | ); 142 | 143 | let commitTx = await simulator.registrar.commit(revealPreimage, { 144 | gasPrice: gasPrice, 145 | gasLimit: 500000, 146 | value: utils.parseEther('0.1') 147 | }); 148 | 149 | let receipt = await commitTx.wait(); 150 | let serializedReveal = utils.serializeTransaction(revealTx, { 151 | r: receipt.logs[0].data, 152 | s: '0x0c70dead0c70dead0c70dead0c70dead0c70dead0c70dead0c70dead0c70dead', 153 | recoveryParam: 0 154 | }); 155 | 156 | let tx = await simulator.provider.sendTransaction(serializedReveal); 157 | //receipt = await simulator.provider.waitForTransaction(tx.hash); 158 | console.log('done:', label, tx); 159 | 160 | runSimulator(round + 1, simulator); 161 | } catch (err) { 162 | console.log(err); 163 | } 164 | }, simulator.timeout); 165 | }; 166 | 167 | SimulatePlugin.prototype.run = async function(a) { 168 | await CLI.Plugin.prototype.run.call(this); 169 | 170 | this.timeout = 15000; 171 | this.chainId = await this.provider.getNetwork().then(n => n.chainId); 172 | this.owner = await this.accounts[0].getAddress(); 173 | this.registrar = new ethers.Contract( 174 | TAKOYAKI_ADDRESS, 175 | TAKOYAKI_ABI, 176 | this.accounts[0] 177 | ); 178 | runSimulator(1, this); 179 | }; 180 | 181 | RegisterPlugin.getHelp = function() { 182 | return { 183 | name: 'register ENS_NAME DURATION', 184 | help: 'register the ENS name for DURATION in days' 185 | }; 186 | }; 187 | 188 | RegisterPlugin.getOptionHelp = function() { 189 | return [ 190 | { 191 | name: '[ --owner ENS_OWNER_ADDRESS ]', 192 | help: 'ENS owner address' 193 | } 194 | ]; 195 | }; 196 | 197 | RegisterPlugin.prototype.prepareOptions = async function(argParser) { 198 | await CLI.Plugin.prototype.prepareOptions.call(this, argParser); 199 | this.ensOwner = argParser.consumeOption('owner'); 200 | }; 201 | 202 | RegisterPlugin.prototype.prepareArgs = async function(args) { 203 | await Plugin.prototype.prepareArgs.call(this, args); 204 | 205 | if (args.length !== 2) { 206 | this.throwUsageError('register requires ENS_NAME and DURATION'); 207 | } 208 | 209 | this.ensName = args[0]; 210 | this.ensNameHash = ethers.utils.namehash(this.ensName); 211 | this.durationInDays = Number(args[1]); 212 | 213 | if (!Number.isInteger(this.durationInDays)) { 214 | this.throwError('Duration must be an integer'); 215 | } 216 | 217 | const domains = this.ensName.split('.'); 218 | if (domains.length !== 2) { 219 | this.throwError('register only supports top level domain currently'); 220 | } 221 | 222 | this.ensTLD = domains[1]; 223 | this.ensLabel = domains[0]; 224 | 225 | if (this.accounts.length !== 1) { 226 | this.throwError('register requires an account'); 227 | } 228 | 229 | this.dump('ENS Name: ' + this.ensName, {}); 230 | this.dump('ENS Name Hash: ' + this.ensNameHash, {}); 231 | this.dump('duration(days): ' + this.durationInDays, {}); 232 | 233 | if (this.durationInDays < MIN_REGISTRATION_DURATION_IN_DAYS) { 234 | this.throwError( 235 | `Duration must be greater than ${MIN_REGISTRATION_DURATION_IN_DAYS} days` 236 | ); 237 | } 238 | 239 | this.duration = this.durationInDays * 24 * 3600; 240 | this.dump('duration: ' + this.duration, {}); 241 | }; 242 | 243 | const getRegistrarAddress = async (provider, name) => { 244 | const namehash = ethers.utils.namehash(name); 245 | const contract = new ethers.Contract( 246 | provider.network.ensAddress, 247 | ENS_ABI, 248 | provider 249 | ); 250 | 251 | const resolverAddress = await contract.resolver(namehash); 252 | this.dump('resolver address: ' + resolverAddress, {}); 253 | 254 | if (resolverAddress === INVALID_ADDRESS) { 255 | throw new Error( 256 | `The top level domain, ${name}, is not current supported by ENS` 257 | ); 258 | } 259 | 260 | const Resolver = new ethers.Contract(resolverAddress, RESOLVER_ABI, provider); 261 | const registrarAddress = await Resolver.interfaceImplementer( 262 | namehash, 263 | PERMANENT_REGISTRAR_ID 264 | ); 265 | 266 | this.dump('registrar address: ' + registrarAddress, {}); 267 | return registrarAddress; 268 | }; 269 | 270 | RegisterPlugin.prototype.run = async function(a) { 271 | await CLI.Plugin.prototype.run.call(this); 272 | 273 | this.dump('ENS address: ' + this.provider.network.ensAddress, {}); 274 | 275 | const registrarAddress = await getRegistrarAddress( 276 | this.provider, 277 | this.ensTLD 278 | ); 279 | 280 | if (registrarAddress === INVALID_ADDRESS) { 281 | this.throwError(`registrar address is invalid`); 282 | } 283 | 284 | const contract = new ethers.Contract( 285 | registrarAddress, 286 | CONTROLLER_ABI, 287 | this.accounts[0] 288 | ); 289 | 290 | const available = await contract.available(this.ensLabel); 291 | if (!available) { 292 | this.throwError(`${this.ensName} is not available`); 293 | } 294 | 295 | const value = await contract.rentPrice(this.ensLabel, this.duration); 296 | const overrides = { 297 | gasLimit: 1000000, 298 | value 299 | }; 300 | 301 | const owner = this.ensOwner 302 | ? this.ensOwner 303 | : await this.accounts[0].getAddress(); 304 | this.dump('ens owner: ' + owner, {}); 305 | 306 | const secret = ethers.utils.hexlify(ethers.utils.randomBytes(32)); 307 | this.dump('secret: ' + secret, {}); 308 | 309 | const commitment = await contract.makeCommitment( 310 | this.ensLabel, 311 | owner, 312 | secret 313 | ); 314 | this.dump('commitment: ' + commitment, {}); 315 | 316 | const tx = await contract.commit(commitment); 317 | await tx.wait(); 318 | 319 | // wait for timeout before revealing/registering the ens name 320 | setTimeout(async () => { 321 | await contract.register( 322 | this.ensLabel, 323 | owner, 324 | this.duration, 325 | secret, 326 | overrides 327 | ); 328 | }, REGISTER_TIMEOUT); 329 | }; 330 | 331 | cli.addPlugin('register', RegisterPlugin); 332 | cli.addPlugin('deploy', DeployPlugin); 333 | cli.addPlugin('simulate', SimulatePlugin); 334 | 335 | cli.run(process.argv.slice(2)).catch(err => { 336 | this.throwError(err); 337 | }); 338 | -------------------------------------------------------------------------------- /heroku-app/static-fallback/script.js: -------------------------------------------------------------------------------- 1 | (function(){function getSvg(traits){return Takoyaki.getSvg(traits).replace('',"")}(function(){const Background=document.getElementById("background");const Card=document.getElementById("card");const Search=document.getElementById("search");const SetTile={};let lastHighlight=-1;function isVisible(el){let cx=window.innerWidth/2;let cy=window.innerHeight/2;let panel=null;if(Card.style.display==="block"){panel=Card.getBoundingClientRect()}else if(Search.style.dispaly==="block"){panel=Search.getBoundingClientRect()}else{return true}let box=el.getBoundingClientRect();let point={x:box.left+.25*box.width,y:box.top+.25*box.height};if(point.x>cx){point.x+=box.width/2}if(point.y>cy){point.y+=box.height/2}if(point.x<0||point.x>window.innerWidth||point.y<0||point.y>window.innerHeight){return false}point={x:box.left+.5*box.width,y:box.top+.5*box.height};if(point.xpanel.right||point.ypanel.bottom){return true}return false}let nextZIndex=1;function createTakoyakiTile(id){let tile=document.createElement("div");tile.className="tile";tile.id=id;tile.style.zIndex=nextZIndex++;Background.appendChild(tile);let _front=document.createElement("div");_front.className="backdrop";tile.appendChild(_front);let front=document.createElement("div");_front.appendChild(front);let _back=document.createElement("div");_back.className="backdrop";tile.appendChild(_back);let back=document.createElement("div");_back.appendChild(back);let current=1;SetTile[id]=function(label,traits){let div=current%2?back:front;div.style.background=Takoyaki.getLabelColor(label);div.style.borderColor=Takoyaki.getLabelColor(label,90,50);if(current>2){div.classList.add("highlight");setTimeout(()=>{div.classList.remove("highlight")},4e3)}current++;div.innerHTML=getSvg(traits);tile.style.zIndex=nextZIndex++;let span=document.createElement("span");span.textContent=label;div.appendChild(span);_back.style.transform="rotateY("+current*180+"deg) translateZ(0.1px)";_front.style.transform="rotateY("+(current+1)*180+"deg) translateZ(0.1px)"};return tile}function fillBackground(){document.body.classList.remove("animated");let inflight=0;let ox=(window.innerWidth%165-160)/2;let oy=(window.innerHeight%165-160)/2;let i=0;for(let x=0;x{infoCopy.textContent="copy?";infoCopy.classList.remove("highlight");timer=null},1e3);try{input.value=ethers.utils.getAddress(address.textContent.replace(/\s/g,""));input.focus();input.select();document.execCommand("copy");infoCopy.textContent="Copied!"}catch(error){infoCopy.textContent="error...";console.log(error)}infoCopy.classList.add("highlight")}})();const local=location.hostname.split(".").pop()==="local";const label=Takoyaki.urlToLabel(location.hostname);const errors={UNSUPPORTED_NETWORK:"UNSUPPORTED_NETWORK"};const{providerPromise:providerPromise,getSigner:getSigner}=function(){const requiredNetwork="ropsten";let providerOptions={infura:"6189cea41bac431286af08a06df219be",etherscan:"9D13ZE7XSBTJ94N9BNJ2MA33VMAY2YPIRB",nodesmith:"f1b3ce218afb412bb4a6657825141885",alchemy:"JrWxtuwXu_V5zN5kMUCnMRpxmqmuuT_h"};if(window.ethereum){let lastNetwork=-1e3;function checkNetwork(){ethereum.send("eth_chainId").then(result=>{let network=ethers.providers.getNetwork(ethers.BigNumber.from(result.result).toNumber());if(lastNetwork>=0&&network.chainId!==lastNetwork){return location.reload()}lastNetwork=network.chainId;setTimeout(checkNetwork,1e3)},error=>{console.log(error);setTimeout(checkNetwork,1e3)})}let networkPromise=ethereum.send("eth_chainId",[]).then(result=>{let network=ethers.providers.getNetwork(ethers.BigNumber.from(result.result).toNumber());lastNetwork=network.chainId;setTimeout(checkNetwork,1e3);if(network.name!==requiredNetwork){return Promise.reject(new Error(errors.UNSUPPORTED_NETWORK))}return network});let providerPromise=networkPromise.then(network=>{return new ethers.providers.Web3Provider(ethereum)},error=>{return ethers.getDefaultProvider(requiredNetwork,providerOptions)});let signerPromise=null;let getSigner=()=>{if(signerPromise==null){signerPromise=providerPromise.then(provider=>{if(provider.getSigner==null){return Promise.reject("unsupported network")}return window.ethereum.enable().then(allowed=>{if(allowed&&allowed.length){return provider.getSigner(allowed[0])}return Promise.reject(new Error("no authorized signer"))})})}return signerPromise};return{providerPromise:providerPromise,getSigner:getSigner}}return{providerPromise:Promise.resolve(ethers.getDefaultProvider(requiredNetwork,providerOptions)),getSigner:()=>Promise.resolve(null)}}();(function(){if(window.ethereum){providerPromise.then(provider=>{if(provider.getSigner==null){document.getElementById("about-wrong-network").classList.remove("hidden")}else{document.getElementById("about-ok").classList.remove("hidden")}})}else{document.getElementById("about-no-ethereum").classList.remove("hidden")}})();const AdoptButton=document.getElementById("button-adopt");const TakoyakiContainer=document.getElementById("takoyaki");function draw(traits){TakoyakiContainer.innerHTML=getSvg(traits)}const pendingHints={};async function register(label){const tokenId=ethers.utils.id(label);if(!pendingHints[tokenId]){pendingHints[tokenId]={}}let hints=pendingHints[tokenId];const provider=await providerPromise;const dustWallet=function(){let dustMnemonic=localStorage.getItem("dust-wallet-mnemonic");if(!ethers.utils.isValidMnemonic(dustMnemonic)){let wallet=ethers.Wallet.createRandom();localStorage.setItem("dust-wallet-mnemonic",wallet.mnemonic);return wallet.connect(provider)}return ethers.Wallet.fromMnemonic(dustMnemonic).connect(provider)}();console.log("Dust Wallet:",dustWallet.address);let signer=await getSigner();let owner=await signer.getAddress();let takoyaki=Takoyaki.connect(signer);let salt=ethers.utils.keccak256(await dustWallet.signMessage("salt:"+label));hints.salt=salt;let txs=await takoyaki.getTransactions(label,owner,salt,dustWallet.address);console.log(txs);let signedRevealTx=await dustWallet.signTransaction(txs.reveal);console.log("Signed Reveal Transaction:",signedRevealTx);try{await Takoyaki.submitReveal(signedRevealTx);console.log("Done")}catch(error){console.log(error);throw new Error("Could not submit to reveal service")}let tx=null;try{tx=await signer.sendTransaction(txs.commit)}catch(error){console.log(error);throw new Error("Cancelled Transaction.")}let receipt=await tx.wait();hints.commitBlock=receipt.blockNumber;console.log("COMMITED",receipt.blockNumber);await tx.wait(4);console.log("Sending reveal...");tx=await provider.sendTransaction(signedRevealTx);receipt=await tx.wait();hints.revealBlock=receipt.blockNumber;return true}function updateAddress(provider,tokenId){let nodehash=ethers.utils.keccak256(ethers.utils.concat([ethers.utils.namehash("takoyaki.eth"),tokenId]));provider.call({to:provider.getNetwork().then(n=>n.ensAddress),data:"0x0178b8bf"+nodehash.substring(2)}).then(data=>{let resolverAddr=ethers.utils.getAddress(ethers.utils.hexDataSlice(data,12));if(resolverAddr===ethers.constants.AddressZero){return null}return provider.call({to:ethers.utils.getAddress(ethers.utils.hexDataSlice(data,12)),data:"0x3b3b57de"+nodehash.slice(2)}).then(data=>{let addr=ethers.utils.getAddress(ethers.utils.hexDataSlice(data,12));document.getElementById("address").textContent=addr.substring(0,12)+" "+addr.substring(12,22)+" \n "+addr.substring(22,32)+" "+addr.substring(32,42)+" ";document.getElementById("icon-copy").classList.remove("hidden");return addr})})}if(label){console.log("LABEL",label);const Card=document.getElementById("card");Card.style.display="block";document.getElementById("label").textContent=label;document.getElementById("populate-label").textContent=label;document.title=label+" || Takoyaki!!";let tokenId=ethers.utils.id(label);if(!pendingHints[tokenId]){pendingHints[tokenId]={}}let hints=pendingHints[tokenId];hints.name=label;providerPromise.then(provider=>{let contract=Takoyaki.connect(provider);contract.getTraits(tokenId).then(traits=>{let traitsDraw=ethers.utils.shallowCopy(traits);traitsDraw.state=0;draw(traitsDraw);function drawNext(){if(traitsDraw.state{draw(traits);if(traits.state===5){updateAddress(provider,tokenId);provider.off("block",onBlock)}})}provider.on("block",onBlock)}}setTimeout(drawNext,200)})})}else{const Search=document.getElementById("search");Search.style.display="block";let input=document.getElementById("input-search");let button=document.getElementById("button-search");input.onkeyup=function(event){if(!button.classList.contains("enabled")){return}if(event.which===13){location.href=Takoyaki.labelToUrl(input.value,local)}};input.oninput=function(){let length=ethers.utils.toUtf8Bytes(input.value).length;let error=null;if(length===0){error=" "}else if(input.value.toLowerCase().substring(0,2)==="0x"){error='Begins with "0x".'}else if(length<3){error="Too short."}else if(length>20){error="Too long."}if(error){button.classList.remove("enabled")}else{button.classList.add("enabled")}document.getElementById("search-warning").textContent=error};button.onclick=function(){if(!button.classList.contains("enabled")){return}location.href=Takoyaki.labelToUrl(input.value,local)};input.focus()}AdoptButton.onclick=function(){document.getElementById("about").classList.remove("hidden")};document.getElementById("button-close").onclick=function(){document.getElementById("about").classList.add("hidden")};document.getElementById("button-hatch").onclick=function(){document.getElementById("about").classList.add("hidden");AdoptButton.classList.remove("enabled");AdoptButton.classList.add("running");register(label).then(()=>{},error=>{console.log(error);alert(error.message);AdoptButton.classList.remove("running");AdoptButton.classList.add("enabled")})}})(); -------------------------------------------------------------------------------- /static/history.js: -------------------------------------------------------------------------------- 1 | const TakoyakiHistory = [{"tokenId":"0xb05e424817fb90aa7a79e9da5c5f94070a316219c6ebb863a9ff7ca357dc9fa9","name":"ricmoo","salt":"0x9ac41b0384eb71c85151f34afb86a1c95ae31913b5de1817fe540b1683e6c5e3","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xc31bd4b91a0d6536561d3cbe7dde66f46938c584368ca2c56c4cef8553ddafd8","name":"loo","salt":"0xab56dfee3c036ceb14489bd6c2825778305e9dd2c7cab2890746889ac8426959","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x1e66721bb1bd77d2641c77ea1d61e8abb92bf69c64fcc90c2c6ad518d1b50db1","name":"moo","salt":"0x659244ac7bfee8cc56c847611abd010f0b77e57ec063d130e08e7690db2b079f","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xbb2ac203ba5b2786d7fc8530982b07fb71660208fd18fb2b5d198f6c94c22df9","name":"takoyaki","salt":"0x5f1e1136c4ba86e20ce0e05a80df3d39a8e47a959b90abc6ad6bc858c4a916dd","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x2e6654d03f4e3cd0cdb09066fb86057ec8f9a9a17fb5a6f7ba79eaa46e4358e3","name":"registrar","salt":"0x1c7b838ee072655f633c739299074bb814fc6e9702b1b69f3ee20295df297df4","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xf23ec0bb4210edd5cba85afd05127efcd2fc6a781bfed49188da1081670b22d8","name":"admin","salt":"0xe7ae479afa696804db45b60c83cd96f947b2968ad6e7fb3a9f633a34a7e6e6cd","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8","name":"hello","salt":"0x39a9f7db7e06c29ac40e4df3f9e7eea9feff1e5dab6a49b65fc021d29627316f","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xbc6bb462e38af7da48e0ae7b5cbae860141c04e5af2cf92328cd6548df111fcb","name":"xxx","salt":"0xac44143c66f9b7953af2516d520d88a613595005b3c848e161241c625b89505e","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x89d19301adce5f2de231f0d8b0f8062bbc4a7117f9ad8e259159b0f4330c6d55","name":"turkey","salt":"0x95877f75d3aed9a1442304e45741add68cd5d28d3e92d7cf6e076397951f3cb2","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xf9d587505fbd50e1ef16e3511e85f5d6486f2ff22e4093ba65f28f58e969e092","name":"turtle","salt":"0xda48f8ba8fbe36fc3119c37076d23cfdd2dcd32fb302f13f45d9aef339c9484e","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x3094c6b18a36643abf79a3ae944ec99f0fdafd155f9b9db373f551fb060d8d37","name":"moose","salt":"0xbe3f5886f63f6fcbae2cf2968e9b3f4b2cd1a0ee493cd88856675cc97c89c28c","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x38e47a7b719dce63662aeaf43440326f551b8a7ee198cee35cb5d517f2d296a2","name":"bob","salt":"0xccfff0f686820fd4988d4ba577c026fa7d849ad4ee4c7cb639ee3cf324f394e5","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x99d872182b3ca96305de9cfd58e2e44f996a5187c1cb67bac92e547f529cfcf9","name":"aurani","salt":"0x6ccf72e86018bf10a0d766e94d88683101a73d3ed4593045f836f89fbd80b928","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xec6fa3ec747a5662bb19f8358d8c5b59cf7b9603a8d3aeee24e320111bb5b051","name":"yuet","salt":"0xba6fe1c2367af252f802de610b9ace1163078a732c710c4848de42e1386316a0","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x9b1df0025ecb2ca9a10e186a98dc9a0f42e9b41572b846b2f13a75e81e27744b","name":"\u305f\u3053\u713c\u304d","salt":"0x498aa30597661689cc41a778b538e36d86ca3a1ecffbdc13d0a029e965e4d503","seeds":["0x5a2f07ed5581","0x7c560b25d07f","0xbd35b7be0cb9","0xd83ee16327b8","0xe95ee63d57af"]},{"tokenId":"0x2b13798fcebac6d075f34a7edfa2e6dc536615be5162fe83d914c363a3515cf2","name":"dipper","salt":"0x598ac2a23357d1b31de41e2f821bc06236a1fa9dee43b15b1669e3f06c7a1ff0","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x751d2d6c1e18eccac3d6d3c477000a32239c6a269baa9900f21ac63c1e81310b","name":"mabel","salt":"0x541d4f4537dc94c1754bb35660d4007ba538ab847e65afbf20cfe085027ccec2","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x4dab0fee114f38e238c099d88daa8fe022f8364b13ba589d2b87850732da7954","name":"stan","salt":"0x7b7a010ca65d24d7844bf3a8a1abd2775c62234a420818e98e66a881b7e4f9c5","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x53199f95900b529152da29cdc096590488dc855d6253103eebd4b3adfe39e3ed","name":"soos","salt":"0x185e6fad72e1f5f3dc080de8ba0e49a6eeb5b8e82a00837978a4829e4d04d529","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x1375cd3639ad63ba00e777c66a7f24e4b3392a847a2b33fa7e750a984f771a92","name":"wendy","salt":"0x43e78720486d49db6f5c0422d1e9f559f30e4c278f13e4ae70d11eb6ea066c64","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x866acb8cc1e941243f40d4bf05a8c1ba2e6756be398e1c5f9a9de47e3a377c8c","name":"waddles","salt":"0x37be9d360bb6dc80e040876a7886e7242755491e7c602218cae1afaa6ad76c05","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x840463345ad81fb522028b524ea3afb85667709ad9e8e2342a0f6fe830b8f9cb","name":"candy","salt":"0x56cd259626189d8bcd16a7a1a2465f0ac64c39347f30e22634ddf83d106a45a0","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x67aa22d3ee3108fb5eaa480e11ebeb93480dfd48f1b7662fa4056a7c6053d151","name":"b-cipher","salt":"0xd7d5709388a4dc4c4ac7af980dde79b0dffc29f20aad491404d37fed7eb2b186","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xf40bb94b63a4534c8409656224edcb3893177bee2fc1f34f8a2fdfe22e8e8e53","name":"tambry","salt":"0x96329002bfa02cf469257664943df6021fb7110d657f86a71da0a67acdc71366","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x3fda8b709b6aab3ddd6bd0007d6e77856be06f948090129aab80d6199f9bae4d","name":"lazy-susan","salt":"0xf69d5d91615c6823a5c785d5c174dfd56b3efb67d7a636067f0d4bac5705d611","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xa933114a9c2f08089f9f6f3dfe5801a06244ef8e56410d5c00519c01e484936d","name":"timebaby","salt":"0x21ffe16eb8534575174d99167bdc23af6b2833e044180c4c966c669602fa583a","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xa277182f2d62455121a767ac95e4b5c2876f2d366e03eb514e5546c64a1b2b3b","name":"pvenkman","salt":"0x6824091fb697db54adbe72f1b24c05735210814598a6994a86e778729833d9ae","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x9ab242d3b3d08a9bb85b5436ad7dbd81dda41cf4cddc9ac372ff34f2a7eca381","name":"raymond","salt":"0x2dc6484a8965b70455bba0519a17dad8d337a384d3722513a492a3e3a988719b","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x7f895f2514a2910e56a24c830288ca898001b1e3093c06529fe8819d760021bf","name":"dana","salt":"0x464f3d98f1d40c1e7aee016ea0eb4abee1df37aa2b06e54baf63ee174dc621d4","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xab3688c5c116198dfeaf6aa0d5912ba415a688723c65f2e710745cdf2654c2a2","name":"egon","salt":"0x48d74f2a6aa59c0366ea201fda015898433b236de8cb1dead4c640811abf23bf","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x836c94c1cba711e905f024042ecf04dc94d2506f3df25577eac24fb5bee766da","name":"loius","salt":"0xb91c83f0eeb76eef45eb43b601cc3c0b010c25537e75d7978eb0d02e3ef655cf","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xe51c35fb5aa4e750f840ef9e5684442e7fe219bf4ae942143ee7f1924c361719","name":"winston","salt":"0xbbb73d9297f774b82de437d74a2d0c944ca6f9f2fba2d394a55fb1389216e607","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x9ba563eec25dd2b52b1eeb6d146e40dc88901ccd6d42e65a18bbf432813f2cbd","name":"janine","salt":"0x61c23cabe6a45b5d189c8c21f8bc79b60360b25cb70de479e373fc5ae8598c89","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x223c9568acdd0b9be57c8c1d012e0daf940f40387bc1d02547f1587d073f1ada","name":"leonardo","salt":"0xe9d466fc87b2f79fc47dfc85c481c18785546795dbe5858060cb24f89b63f260","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x9a4c86a27710bd80c78115fba61832a6cd662f20363c4d56dea3eaeff60a5102","name":"michelangelo","salt":"0xa626fa0d0d484cb4c6e397f0cc5603035e7e6847bf76823735197e9f771187f2","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xce5cb0fcb097f5799a828308c2a35b53be49a24884e66fdea0d4428910596523","name":"donatello","salt":"0x8c8c4c8a7d68d2b83c7dc42a85e6c98805260bf2d9fa11f4e0e049c2e2a47250","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0xe67b7863d3e32eebfca660ab833c5255836279d57aeb1b5c275832f1bbd7944a","name":"raphael","salt":"0x4fec85719ddfde965afb72be61c9c0a458c3237d11081894feee0cf3589e7708","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0x88fac394255abe8c95591c819c6abbcd45adf6fb65b509856e58163387301d02","name":"splinter","salt":"0xb474e2543e12b5f07affd12615d0ad66455285b0dfa409ef09411c0d052df753","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0x47331a0becddb3fbc9400d3c12401299404594bde406aae6759f6f088b2ce3b6","name":"april","salt":"0xd0f95737d7fe4131bbe9284d57dadf9d8d81255faf2110a780c9b7ec65004865","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0xdf0ef0e796cef4eb2552d1f78163f19092564aefe0aed912f844ba3631d9fa8b","name":"krang4ever","salt":"0xa37eca94820f948695b39801e606f6f33e8ddec3a722f28f652561a90371f700","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0xb194e85d12b6f2e8dd55c4955333b1a58d259d13c5c3999603124d365fa14e64","name":"tim","salt":"0xce6dd587075af58e6c29c00eccffe7462f5b52313f862ed3ceef6a4ebac6b197","seeds":["0xb98ab5709252","0x15380ac1da68","0x4a1b666b7203","0x2362ecc03ac4","0x30c7ca5399f7"]},{"tokenId":"0x788ada68367139adafc3cbae89eef5a40049cf0ff7cfe2c4e584edfc29ec7730","name":"whatsup","salt":"0xf6c98c436980fd0433dbea4b1aaafee64458a89e44b2d300f82fb78dd7ab1ca5","seeds":["0x76bbf9d1526d","0xb63ca11d30fa","0xc89db5f1169d","0x67af2492fd0f","0x4452aae0dd14"]},{"tokenId":"0xfb0afd7307167ce3af5a9c807643c66309fa46d1c527f63f4cf5fc593401b765","name":"msholozi","salt":"0xa712369f24e0ae78d10371792e4d8ffb004243b9f90a361acdde8b274db4dbee","seeds":["0x3e2112b6fcad","0x3571872b754a","0x4abe376b7917","0x1fa03dd630a7","0xdad9f6d1cd7e"]},{"tokenId":"0x9c4b7a6b4af91b44be8d9bb66d41e82589f01974702d3bf1d9b4407a55593c3c","name":"john","salt":"0x15fa2cc7037229669d4493baf6ef316cbc88786ce860813bf3df84c410a1ab15","seeds":["0xa195be08d3d1","0xe781f1c63e3f","0x805aeecec2cc","0xbd1fa12cce2b","0x80257e0a0d0d"]},{"tokenId":"0xb83330129510a2461236adc7254a3b4e2f2fa25457c7dcb82be80de0f8c96183","name":"alex","salt":"0x5601579f7205415c7ab9020860aa6b09ee96a5f41b165a810fbeb8fe58abe43b","seeds":["0x96c90cd6bc13","0x679e5e613e0a","0xfa6409a2c64c","0x5df98c147fce","0x72d1b5f42ccd"]},{"tokenId":"0x7b6ff5e570f4b3d03a8b3676eeffebaf2c951e43e2bd458aca78aabd6b1b30d8","name":"sandra","salt":"0x9263e667a74d2554b7aebe35cf47aca3dc2a759307d41507abae9e0f47e63d9b","seeds":["0x6ef49908bf77","0x642b86dbc53b","0xe4b34483e00a","0xf2e0f9afae9b","0xe9fc4c9413d0"]},{"tokenId":"0x408f03ab78bc13e6304da5357a4b0b4447b1c81f3a32d6a913938cadbfdfc05a","name":"jon","salt":"0xa15a98ab11e86912df12c872829c9d95a74d4f5a6198d860648b01400a8b5b32","seeds":["0x4044578426bb","0x5affa4592698","0xf50e40213a0f","0x656829ad0384","0x2a6298a9155f"]},{"tokenId":"0xd929655926738198522a96823be92b737028c20bc6fb9906b5d788a67623fa6a","name":"coogan","salt":"0x4512662ef9ee76e8930295c89bf4fb32006d7c7576076bbe2b73e20e82cba460","seeds":["0xcb68e041c01d","0x2409b1944045","0x2a6298a9155f","0x8253f85d6949","0x13d0e53695fd"]},{"tokenId":"0x514982bc8f5109775101ebdee34a5b2fe0914428968bd9e09d69da7e82b6ad2c","name":"leeraj","salt":"0xe6be825bf3347514cd94fbc06d3dd7a8dac71213612c8314fd37a2b63da7eaee","seeds":["0xe1924d07ca6f","0x940a41de2553","0x0de57e85feec","0xddabb6004c9b","0x86b9e0ea8ba1"]},{"tokenId":"0x23f71d6edcf6e2d3177bf037f15ee70c7e9f9717132a9f78c5c8161c62bd5f2a","name":"kendall","salt":"0x1cd4d248f3fc223a009c51b65308453253eec681e6e680f33044c2c06f2e62c6","seeds":["0x3852b30afd92","0x0fddee4416eb","0x763dce5621ac","0xd7b793ccda5f","0xd27105b6cdd9"]},{"tokenId":"0x39fd2e80dd48229393ceb969fb81b6925614bc2a05dcae6ef92442d16030b3b4","name":"cypherpunk","salt":"0x596ddff0a03552e310954bf5b2553c1d75f38fd16a59c0f22a2818ea06a8248d","seeds":["0xdff62fc448ec","0x21dbf32bf9ec","0x3e5b860885e7","0x8c03db580609","0xb61f8b6bf32f"]},{"tokenId":"0x095f96e7f1dbd8eb9a5c14efba5e1fe4702831a4c382e3a397a608156075eda7","name":"mokn","salt":"0xc0a1993d00f66d51b06421dff6734812f05d6a4fe8343acff1359bfdff8c804e","seeds":["0x36a24a3d72f0","0xf6a9a21f630f","0xa7624a4a4c40","0xc7e36f02a4dc","0xe92d0f440402"]},{"tokenId":"0x2ad640472aec21c16ff6a557f533aa30c3dd44ed1d625960ebb62bbad551bb35","name":"cri","salt":"0x87babea66cf88f505338e0d247165d197f86dec77332bf317f82d0c91e58c25c","seeds":["0x7f723c9bc4ad","0x475733f5b1a2","0x17ff88a8fac6","0x466c0d51c0a5","0x58887b56ff39"]},{"tokenId":"0x903f7a9785b844fe6bb5db048dfbbd8530aeb6e23d262cce9643f9ef23fb5280","name":"unicefinnovation","salt":"0xcbe6a0237e36e0de8c77ef2b1e62d30f2102931c2db6a289a177c68a9171b0ec","seeds":["0xbfaa7828cc6c","0x26f919656cf2","0x8861019103fa","0x0bd67b2cebb2","0x298ffeb0be34"]},{"tokenId":"0xd11570f3bf2c8bc97826cfcdf149860362b355201eae78794a34eb06351e601f","name":"dragon","salt":"0xe50a09cb21bdf8d3fa24276e60956a15b4631377892a488443ea58fddd590773","seeds":["0x4ea2acf4dd0f","0x1b22f86230b1","0xe3ed7bd47ec7","0x701392370ad2","0x4203cead5e12"]},{"tokenId":"0xa81a96f7ee0298b0bfe5383bff1fd967d18f3ef21fd51fd76a96cf26fbacbcd5","name":"jenny","salt":"0x7f832b2ef62b67294a10ee277228d2c4aa3e38e4908b319814ebf859d2050eac","seeds":["0xafab1063acf8","0x85b9d28188d6","0xe63aa0f806da","0x51bffd5baf09","0xda2176e234ed"]},{"tokenId":"0xba61c49004983bc461eab0db54ee9ce072d24f4d0413f9702c2dd48538ef0eb6","name":"kamal","salt":"0x8b341c95ff0773255ee51093d7de761af3ac4a76701759b1d53d5610bc6cb147","seeds":["0xe6e45fc9c0af","0x60c6a5de920f","0x4dc229ed8080","0x6e9561a1e32f","0x4a20665865bd"]},{"tokenId":"0xdfcac4f4aaabe9f69fb8660e01cdb727355ca2386e050610e0cd4eb292976c6c","name":"zain","salt":"0x0e8753908049202b4fae59c544bebafe70f96a1c775ff6ae6807d3cbe7216abb","seeds":["0x2b688a15dc5d","0x1e900b08bec5","0xd9101e8f524b","0x23d38ea47eed","0xd08f433933df"]},{"tokenId":"0x04771c25633ef4931e253cba514a3424afdec1c563f945250e12e25caefd7fc0","name":"teo","salt":"0x437b3c28101bc52459215ff093c423f4db06a4d45989e53511b2bccccda9d2d3","seeds":["0x5896b040de0e","0x323017bd0dfd","0x057b38f7a9c9","0x74d29572d027","0x5763757a6d43"]},{"tokenId":"0xe65f89eab4e7fc4cdade2363a9b071ba23e49d6e9c1dbb7acdc59558fdb834bd","name":"caleblau","salt":"0xc54f3a1a51a8c1fb334e6387d1b0af719051c899804d49e6c7cfeb6709da3001","seeds":["0x68e3f4fe9a36","0xadc5533710b7","0x5fb756d1b2a7","0x4bc288b63c00","0xf9420b2512b6"]},{"tokenId":"0x5653ebbfa872cd6d0e211eda2d048757f2d64ff559166a1dc016f5bf01562506","name":"ethne","salt":"0x9a99a73cff39c1ce3eed9f301140034a3b486bd1caa8d37c76010123448759aa","seeds":["0xc7fb29c70a56","0x94ea45e0c5ef","0x0d3f9a2d2c57","0x74f2a250e9e2","0x3e1b4bda9ab3"]},{"tokenId":"0x124d0c456d49f779f496a0c4efee97fb10240d7fccd3336a23701a6fae76bd44","name":"muffins","salt":"0x560ecc7b38c6d6ce7e32b97f3d67697cea03e40a689b90c924751f6f557ef454","seeds":["0x95add7e92441","0x51022d8a2dc0","0x32eef0ce07cc","0x5674cff9eb93","0xd17f6aafd54c"]},{"tokenId":"0xce899681965a38777124c1289185d73179017762039814a595baafb7b2646027","name":"sven","salt":"0xdfba6ce1f510c7414ad9924f9704562b9abc8761202ce7b4ce5d747ef6b359f5","seeds":["0x699cbcd6f6b7","0x62d1b3e25666","0xcf2b8e69cdf3","0x458640ad6364","0x2c7c562794b4"]},{"tokenId":"0x07cee237862ac552fe3582f50b9d624b6de9c9784eb9b8e0e3b5ed3ae7a75a54","name":"asobimasu","salt":"0xc44fb5e998d30ea435c79c454654e1b5380253dd69d75e3e48be040187e2901f","seeds":["0x492554f0a165","0x7bfb8d8ea69a","0xb8bb3afc6334","0x53c73f8f58b3","0x8b119ec4a5fe"]},{"tokenId":"0x344bffa221eb76ebe2f482bfa37db2b9e85e6d76a89e25fe19d73be82021d2cc","name":"johnnathan","salt":"0x0b6ab3e59bba18c96229321b61c9ebb40e1c98b403315acb0a227fd3d5aad010","seeds":["0xa85ad8bdf273","0x21283ec77534","0xef49ae912071","0xe12ab8a0d10b","0x99aebd0f8d42"]},{"tokenId":"0x0ac1b4664d8039d3514536dbcd255edfc9eda1954331d0b66219f077a1b0b7a4","name":"eric","salt":"0x0fa8d752318a72bc39596ea54472807036ba649d8a520fe0f63eb21885f2a06c","seeds":["0x7edb42d55d5b","0x6467357be978","0x2b785c7c15f4","0xb3082cff1ccd","0xde9b1d66de6d"]},{"tokenId":"0x024012064ed07e7f07c831e707019ee3da7205f3f24d9ad53ea41af3435a2790","name":"gribbles","salt":"0x42a57a64faf40fa395c00d4ddac8cbf7e909654bda79ea7d46c857aeb68afad5","seeds":["0x52af098e5e9f","0x27ed2ed2a863","0xb74b9ac63849","0xbcf4c539a20f","0x13f00d3c3dd2"]},{"tokenId":"0x135ce50c8320b2cc19a06209909df6ac7c136c12473dbc5e588a124db0a5afbc","name":"govin","salt":"0x822ad2abc96fdd1f93c6a3c873ae70d3acbeeb823e33a97a7ab99e91b57571ff","seeds":["0xe37808487cbf","0xe03bd01e5847","0x9f40445b74a2","0x1d37087af23d","0x306f7a5cce18"]},{"tokenId":"0x3fb27a6b64ff8fb19701b72bebf34ca375df5d5820959ea0681b4b97c73dc065","name":"blamo","salt":"0x5f155c9efb002b1b38089f065874c92bd9ac407205693aa6909371bbc92be46b","seeds":["0x1739076a98b5","0x3f4f6eff6561","0xc9c1f2194c44","0xa807d8bcfd81","0x33c7b9bf5051"]},{"tokenId":"0x3215cb94feb0773b21ab2232a66243df60edc50dbda447ebef19fe416afdc961","name":"oodlesofmood","salt":"0x96a37d6fa130324ef53d249f5571c1de84e04a8caa43198f4ccf103d261b614b","seeds":["0xfb09a950910b","0x4282de8f1eb9","0x71f454414a98","0xafb6f70f1d7b","0x594463f7bbc2"]},{"tokenId":"0x456e171461d7b39f7ffcff68976022cd7cfd020eceb707f6b4b83e2fcddf8086","name":"antoine","salt":"0x38fa2286dcfc3a7de513d824c24292f679e59573c2c7679f838b59cbc6a97e49","seeds":["0xbbe12ce0497f","0x54a0d37e52ee","0xad922a37eb7a","0xa16666cb2506","0x151a805ec4ac"]},{"tokenId":"0xdca4c60a98c38ce1279025c29434419f72a4f220b94842d5c850b849d82025fe","name":"antoinesucks","salt":"0xbe1d0ebb33c565710632e1d546c93c3edc20d35a9663bcd8ec5affca7d954f4f","seeds":["0xcb177a8e42cb","0xfb21dfe9f446","0xb2ef64542cb1","0xdc7b363e7771","0xac1339424dc4"]},{"tokenId":"0x8e91d626f88633b04b4b904b6a1a0c7ce273a418f6f46563ffa0985cc450139c","name":"brendan","salt":"0xea27e478c956851fd8315f3e6d93e0720f04da26a902cec570b0909fc97def74","seeds":["0xe7fea1a84fce","0xd9a3bd6e6398","0xec67912b9fb4","0xf07b3cde18d5","0x74caa04b8575"]}]; -------------------------------------------------------------------------------- /heroku-app/static/history.js: -------------------------------------------------------------------------------- 1 | const TakoyakiHistory = [{"tokenId":"0xb05e424817fb90aa7a79e9da5c5f94070a316219c6ebb863a9ff7ca357dc9fa9","name":"ricmoo","salt":"0x9ac41b0384eb71c85151f34afb86a1c95ae31913b5de1817fe540b1683e6c5e3","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xc31bd4b91a0d6536561d3cbe7dde66f46938c584368ca2c56c4cef8553ddafd8","name":"loo","salt":"0xab56dfee3c036ceb14489bd6c2825778305e9dd2c7cab2890746889ac8426959","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x1e66721bb1bd77d2641c77ea1d61e8abb92bf69c64fcc90c2c6ad518d1b50db1","name":"moo","salt":"0x659244ac7bfee8cc56c847611abd010f0b77e57ec063d130e08e7690db2b079f","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xbb2ac203ba5b2786d7fc8530982b07fb71660208fd18fb2b5d198f6c94c22df9","name":"takoyaki","salt":"0x5f1e1136c4ba86e20ce0e05a80df3d39a8e47a959b90abc6ad6bc858c4a916dd","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x2e6654d03f4e3cd0cdb09066fb86057ec8f9a9a17fb5a6f7ba79eaa46e4358e3","name":"registrar","salt":"0x1c7b838ee072655f633c739299074bb814fc6e9702b1b69f3ee20295df297df4","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xf23ec0bb4210edd5cba85afd05127efcd2fc6a781bfed49188da1081670b22d8","name":"admin","salt":"0xe7ae479afa696804db45b60c83cd96f947b2968ad6e7fb3a9f633a34a7e6e6cd","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8","name":"hello","salt":"0x39a9f7db7e06c29ac40e4df3f9e7eea9feff1e5dab6a49b65fc021d29627316f","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xbc6bb462e38af7da48e0ae7b5cbae860141c04e5af2cf92328cd6548df111fcb","name":"xxx","salt":"0xac44143c66f9b7953af2516d520d88a613595005b3c848e161241c625b89505e","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x89d19301adce5f2de231f0d8b0f8062bbc4a7117f9ad8e259159b0f4330c6d55","name":"turkey","salt":"0x95877f75d3aed9a1442304e45741add68cd5d28d3e92d7cf6e076397951f3cb2","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xf9d587505fbd50e1ef16e3511e85f5d6486f2ff22e4093ba65f28f58e969e092","name":"turtle","salt":"0xda48f8ba8fbe36fc3119c37076d23cfdd2dcd32fb302f13f45d9aef339c9484e","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x3094c6b18a36643abf79a3ae944ec99f0fdafd155f9b9db373f551fb060d8d37","name":"moose","salt":"0xbe3f5886f63f6fcbae2cf2968e9b3f4b2cd1a0ee493cd88856675cc97c89c28c","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x38e47a7b719dce63662aeaf43440326f551b8a7ee198cee35cb5d517f2d296a2","name":"bob","salt":"0xccfff0f686820fd4988d4ba577c026fa7d849ad4ee4c7cb639ee3cf324f394e5","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x99d872182b3ca96305de9cfd58e2e44f996a5187c1cb67bac92e547f529cfcf9","name":"aurani","salt":"0x6ccf72e86018bf10a0d766e94d88683101a73d3ed4593045f836f89fbd80b928","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xec6fa3ec747a5662bb19f8358d8c5b59cf7b9603a8d3aeee24e320111bb5b051","name":"yuet","salt":"0xba6fe1c2367af252f802de610b9ace1163078a732c710c4848de42e1386316a0","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x9b1df0025ecb2ca9a10e186a98dc9a0f42e9b41572b846b2f13a75e81e27744b","name":"\u305f\u3053\u713c\u304d","salt":"0x498aa30597661689cc41a778b538e36d86ca3a1ecffbdc13d0a029e965e4d503","seeds":["0x5a2f07ed5581","0x7c560b25d07f","0xbd35b7be0cb9","0xd83ee16327b8","0xe95ee63d57af"]},{"tokenId":"0x2b13798fcebac6d075f34a7edfa2e6dc536615be5162fe83d914c363a3515cf2","name":"dipper","salt":"0x598ac2a23357d1b31de41e2f821bc06236a1fa9dee43b15b1669e3f06c7a1ff0","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x751d2d6c1e18eccac3d6d3c477000a32239c6a269baa9900f21ac63c1e81310b","name":"mabel","salt":"0x541d4f4537dc94c1754bb35660d4007ba538ab847e65afbf20cfe085027ccec2","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x4dab0fee114f38e238c099d88daa8fe022f8364b13ba589d2b87850732da7954","name":"stan","salt":"0x7b7a010ca65d24d7844bf3a8a1abd2775c62234a420818e98e66a881b7e4f9c5","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x53199f95900b529152da29cdc096590488dc855d6253103eebd4b3adfe39e3ed","name":"soos","salt":"0x185e6fad72e1f5f3dc080de8ba0e49a6eeb5b8e82a00837978a4829e4d04d529","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x1375cd3639ad63ba00e777c66a7f24e4b3392a847a2b33fa7e750a984f771a92","name":"wendy","salt":"0x43e78720486d49db6f5c0422d1e9f559f30e4c278f13e4ae70d11eb6ea066c64","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x866acb8cc1e941243f40d4bf05a8c1ba2e6756be398e1c5f9a9de47e3a377c8c","name":"waddles","salt":"0x37be9d360bb6dc80e040876a7886e7242755491e7c602218cae1afaa6ad76c05","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x840463345ad81fb522028b524ea3afb85667709ad9e8e2342a0f6fe830b8f9cb","name":"candy","salt":"0x56cd259626189d8bcd16a7a1a2465f0ac64c39347f30e22634ddf83d106a45a0","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x67aa22d3ee3108fb5eaa480e11ebeb93480dfd48f1b7662fa4056a7c6053d151","name":"b-cipher","salt":"0xd7d5709388a4dc4c4ac7af980dde79b0dffc29f20aad491404d37fed7eb2b186","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xf40bb94b63a4534c8409656224edcb3893177bee2fc1f34f8a2fdfe22e8e8e53","name":"tambry","salt":"0x96329002bfa02cf469257664943df6021fb7110d657f86a71da0a67acdc71366","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x3fda8b709b6aab3ddd6bd0007d6e77856be06f948090129aab80d6199f9bae4d","name":"lazy-susan","salt":"0xf69d5d91615c6823a5c785d5c174dfd56b3efb67d7a636067f0d4bac5705d611","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xa933114a9c2f08089f9f6f3dfe5801a06244ef8e56410d5c00519c01e484936d","name":"timebaby","salt":"0x21ffe16eb8534575174d99167bdc23af6b2833e044180c4c966c669602fa583a","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xa277182f2d62455121a767ac95e4b5c2876f2d366e03eb514e5546c64a1b2b3b","name":"pvenkman","salt":"0x6824091fb697db54adbe72f1b24c05735210814598a6994a86e778729833d9ae","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x9ab242d3b3d08a9bb85b5436ad7dbd81dda41cf4cddc9ac372ff34f2a7eca381","name":"raymond","salt":"0x2dc6484a8965b70455bba0519a17dad8d337a384d3722513a492a3e3a988719b","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x7f895f2514a2910e56a24c830288ca898001b1e3093c06529fe8819d760021bf","name":"dana","salt":"0x464f3d98f1d40c1e7aee016ea0eb4abee1df37aa2b06e54baf63ee174dc621d4","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xab3688c5c116198dfeaf6aa0d5912ba415a688723c65f2e710745cdf2654c2a2","name":"egon","salt":"0x48d74f2a6aa59c0366ea201fda015898433b236de8cb1dead4c640811abf23bf","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x836c94c1cba711e905f024042ecf04dc94d2506f3df25577eac24fb5bee766da","name":"loius","salt":"0xb91c83f0eeb76eef45eb43b601cc3c0b010c25537e75d7978eb0d02e3ef655cf","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xe51c35fb5aa4e750f840ef9e5684442e7fe219bf4ae942143ee7f1924c361719","name":"winston","salt":"0xbbb73d9297f774b82de437d74a2d0c944ca6f9f2fba2d394a55fb1389216e607","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x9ba563eec25dd2b52b1eeb6d146e40dc88901ccd6d42e65a18bbf432813f2cbd","name":"janine","salt":"0x61c23cabe6a45b5d189c8c21f8bc79b60360b25cb70de479e373fc5ae8598c89","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x223c9568acdd0b9be57c8c1d012e0daf940f40387bc1d02547f1587d073f1ada","name":"leonardo","salt":"0xe9d466fc87b2f79fc47dfc85c481c18785546795dbe5858060cb24f89b63f260","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x9a4c86a27710bd80c78115fba61832a6cd662f20363c4d56dea3eaeff60a5102","name":"michelangelo","salt":"0xa626fa0d0d484cb4c6e397f0cc5603035e7e6847bf76823735197e9f771187f2","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xce5cb0fcb097f5799a828308c2a35b53be49a24884e66fdea0d4428910596523","name":"donatello","salt":"0x8c8c4c8a7d68d2b83c7dc42a85e6c98805260bf2d9fa11f4e0e049c2e2a47250","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0xe67b7863d3e32eebfca660ab833c5255836279d57aeb1b5c275832f1bbd7944a","name":"raphael","salt":"0x4fec85719ddfde965afb72be61c9c0a458c3237d11081894feee0cf3589e7708","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0x88fac394255abe8c95591c819c6abbcd45adf6fb65b509856e58163387301d02","name":"splinter","salt":"0xb474e2543e12b5f07affd12615d0ad66455285b0dfa409ef09411c0d052df753","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0x47331a0becddb3fbc9400d3c12401299404594bde406aae6759f6f088b2ce3b6","name":"april","salt":"0xd0f95737d7fe4131bbe9284d57dadf9d8d81255faf2110a780c9b7ec65004865","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0xdf0ef0e796cef4eb2552d1f78163f19092564aefe0aed912f844ba3631d9fa8b","name":"krang4ever","salt":"0xa37eca94820f948695b39801e606f6f33e8ddec3a722f28f652561a90371f700","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0xb194e85d12b6f2e8dd55c4955333b1a58d259d13c5c3999603124d365fa14e64","name":"tim","salt":"0xce6dd587075af58e6c29c00eccffe7462f5b52313f862ed3ceef6a4ebac6b197","seeds":["0xb98ab5709252","0x15380ac1da68","0x4a1b666b7203","0x2362ecc03ac4","0x30c7ca5399f7"]},{"tokenId":"0x788ada68367139adafc3cbae89eef5a40049cf0ff7cfe2c4e584edfc29ec7730","name":"whatsup","salt":"0xf6c98c436980fd0433dbea4b1aaafee64458a89e44b2d300f82fb78dd7ab1ca5","seeds":["0x76bbf9d1526d","0xb63ca11d30fa","0xc89db5f1169d","0x67af2492fd0f","0x4452aae0dd14"]},{"tokenId":"0xfb0afd7307167ce3af5a9c807643c66309fa46d1c527f63f4cf5fc593401b765","name":"msholozi","salt":"0xa712369f24e0ae78d10371792e4d8ffb004243b9f90a361acdde8b274db4dbee","seeds":["0x3e2112b6fcad","0x3571872b754a","0x4abe376b7917","0x1fa03dd630a7","0xdad9f6d1cd7e"]},{"tokenId":"0x9c4b7a6b4af91b44be8d9bb66d41e82589f01974702d3bf1d9b4407a55593c3c","name":"john","salt":"0x15fa2cc7037229669d4493baf6ef316cbc88786ce860813bf3df84c410a1ab15","seeds":["0xa195be08d3d1","0xe781f1c63e3f","0x805aeecec2cc","0xbd1fa12cce2b","0x80257e0a0d0d"]},{"tokenId":"0xb83330129510a2461236adc7254a3b4e2f2fa25457c7dcb82be80de0f8c96183","name":"alex","salt":"0x5601579f7205415c7ab9020860aa6b09ee96a5f41b165a810fbeb8fe58abe43b","seeds":["0x96c90cd6bc13","0x679e5e613e0a","0xfa6409a2c64c","0x5df98c147fce","0x72d1b5f42ccd"]},{"tokenId":"0x7b6ff5e570f4b3d03a8b3676eeffebaf2c951e43e2bd458aca78aabd6b1b30d8","name":"sandra","salt":"0x9263e667a74d2554b7aebe35cf47aca3dc2a759307d41507abae9e0f47e63d9b","seeds":["0x6ef49908bf77","0x642b86dbc53b","0xe4b34483e00a","0xf2e0f9afae9b","0xe9fc4c9413d0"]},{"tokenId":"0x408f03ab78bc13e6304da5357a4b0b4447b1c81f3a32d6a913938cadbfdfc05a","name":"jon","salt":"0xa15a98ab11e86912df12c872829c9d95a74d4f5a6198d860648b01400a8b5b32","seeds":["0x4044578426bb","0x5affa4592698","0xf50e40213a0f","0x656829ad0384","0x2a6298a9155f"]},{"tokenId":"0xd929655926738198522a96823be92b737028c20bc6fb9906b5d788a67623fa6a","name":"coogan","salt":"0x4512662ef9ee76e8930295c89bf4fb32006d7c7576076bbe2b73e20e82cba460","seeds":["0xcb68e041c01d","0x2409b1944045","0x2a6298a9155f","0x8253f85d6949","0x13d0e53695fd"]},{"tokenId":"0x514982bc8f5109775101ebdee34a5b2fe0914428968bd9e09d69da7e82b6ad2c","name":"leeraj","salt":"0xe6be825bf3347514cd94fbc06d3dd7a8dac71213612c8314fd37a2b63da7eaee","seeds":["0xe1924d07ca6f","0x940a41de2553","0x0de57e85feec","0xddabb6004c9b","0x86b9e0ea8ba1"]},{"tokenId":"0x23f71d6edcf6e2d3177bf037f15ee70c7e9f9717132a9f78c5c8161c62bd5f2a","name":"kendall","salt":"0x1cd4d248f3fc223a009c51b65308453253eec681e6e680f33044c2c06f2e62c6","seeds":["0x3852b30afd92","0x0fddee4416eb","0x763dce5621ac","0xd7b793ccda5f","0xd27105b6cdd9"]},{"tokenId":"0x39fd2e80dd48229393ceb969fb81b6925614bc2a05dcae6ef92442d16030b3b4","name":"cypherpunk","salt":"0x596ddff0a03552e310954bf5b2553c1d75f38fd16a59c0f22a2818ea06a8248d","seeds":["0xdff62fc448ec","0x21dbf32bf9ec","0x3e5b860885e7","0x8c03db580609","0xb61f8b6bf32f"]},{"tokenId":"0x095f96e7f1dbd8eb9a5c14efba5e1fe4702831a4c382e3a397a608156075eda7","name":"mokn","salt":"0xc0a1993d00f66d51b06421dff6734812f05d6a4fe8343acff1359bfdff8c804e","seeds":["0x36a24a3d72f0","0xf6a9a21f630f","0xa7624a4a4c40","0xc7e36f02a4dc","0xe92d0f440402"]},{"tokenId":"0x2ad640472aec21c16ff6a557f533aa30c3dd44ed1d625960ebb62bbad551bb35","name":"cri","salt":"0x87babea66cf88f505338e0d247165d197f86dec77332bf317f82d0c91e58c25c","seeds":["0x7f723c9bc4ad","0x475733f5b1a2","0x17ff88a8fac6","0x466c0d51c0a5","0x58887b56ff39"]},{"tokenId":"0x903f7a9785b844fe6bb5db048dfbbd8530aeb6e23d262cce9643f9ef23fb5280","name":"unicefinnovation","salt":"0xcbe6a0237e36e0de8c77ef2b1e62d30f2102931c2db6a289a177c68a9171b0ec","seeds":["0xbfaa7828cc6c","0x26f919656cf2","0x8861019103fa","0x0bd67b2cebb2","0x298ffeb0be34"]},{"tokenId":"0xd11570f3bf2c8bc97826cfcdf149860362b355201eae78794a34eb06351e601f","name":"dragon","salt":"0xe50a09cb21bdf8d3fa24276e60956a15b4631377892a488443ea58fddd590773","seeds":["0x4ea2acf4dd0f","0x1b22f86230b1","0xe3ed7bd47ec7","0x701392370ad2","0x4203cead5e12"]},{"tokenId":"0xa81a96f7ee0298b0bfe5383bff1fd967d18f3ef21fd51fd76a96cf26fbacbcd5","name":"jenny","salt":"0x7f832b2ef62b67294a10ee277228d2c4aa3e38e4908b319814ebf859d2050eac","seeds":["0xafab1063acf8","0x85b9d28188d6","0xe63aa0f806da","0x51bffd5baf09","0xda2176e234ed"]},{"tokenId":"0xba61c49004983bc461eab0db54ee9ce072d24f4d0413f9702c2dd48538ef0eb6","name":"kamal","salt":"0x8b341c95ff0773255ee51093d7de761af3ac4a76701759b1d53d5610bc6cb147","seeds":["0xe6e45fc9c0af","0x60c6a5de920f","0x4dc229ed8080","0x6e9561a1e32f","0x4a20665865bd"]},{"tokenId":"0xdfcac4f4aaabe9f69fb8660e01cdb727355ca2386e050610e0cd4eb292976c6c","name":"zain","salt":"0x0e8753908049202b4fae59c544bebafe70f96a1c775ff6ae6807d3cbe7216abb","seeds":["0x2b688a15dc5d","0x1e900b08bec5","0xd9101e8f524b","0x23d38ea47eed","0xd08f433933df"]},{"tokenId":"0x04771c25633ef4931e253cba514a3424afdec1c563f945250e12e25caefd7fc0","name":"teo","salt":"0x437b3c28101bc52459215ff093c423f4db06a4d45989e53511b2bccccda9d2d3","seeds":["0x5896b040de0e","0x323017bd0dfd","0x057b38f7a9c9","0x74d29572d027","0x5763757a6d43"]},{"tokenId":"0xe65f89eab4e7fc4cdade2363a9b071ba23e49d6e9c1dbb7acdc59558fdb834bd","name":"caleblau","salt":"0xc54f3a1a51a8c1fb334e6387d1b0af719051c899804d49e6c7cfeb6709da3001","seeds":["0x68e3f4fe9a36","0xadc5533710b7","0x5fb756d1b2a7","0x4bc288b63c00","0xf9420b2512b6"]},{"tokenId":"0x5653ebbfa872cd6d0e211eda2d048757f2d64ff559166a1dc016f5bf01562506","name":"ethne","salt":"0x9a99a73cff39c1ce3eed9f301140034a3b486bd1caa8d37c76010123448759aa","seeds":["0xc7fb29c70a56","0x94ea45e0c5ef","0x0d3f9a2d2c57","0x74f2a250e9e2","0x3e1b4bda9ab3"]},{"tokenId":"0x124d0c456d49f779f496a0c4efee97fb10240d7fccd3336a23701a6fae76bd44","name":"muffins","salt":"0x560ecc7b38c6d6ce7e32b97f3d67697cea03e40a689b90c924751f6f557ef454","seeds":["0x95add7e92441","0x51022d8a2dc0","0x32eef0ce07cc","0x5674cff9eb93","0xd17f6aafd54c"]},{"tokenId":"0xce899681965a38777124c1289185d73179017762039814a595baafb7b2646027","name":"sven","salt":"0xdfba6ce1f510c7414ad9924f9704562b9abc8761202ce7b4ce5d747ef6b359f5","seeds":["0x699cbcd6f6b7","0x62d1b3e25666","0xcf2b8e69cdf3","0x458640ad6364","0x2c7c562794b4"]},{"tokenId":"0x07cee237862ac552fe3582f50b9d624b6de9c9784eb9b8e0e3b5ed3ae7a75a54","name":"asobimasu","salt":"0xc44fb5e998d30ea435c79c454654e1b5380253dd69d75e3e48be040187e2901f","seeds":["0x492554f0a165","0x7bfb8d8ea69a","0xb8bb3afc6334","0x53c73f8f58b3","0x8b119ec4a5fe"]},{"tokenId":"0x344bffa221eb76ebe2f482bfa37db2b9e85e6d76a89e25fe19d73be82021d2cc","name":"johnnathan","salt":"0x0b6ab3e59bba18c96229321b61c9ebb40e1c98b403315acb0a227fd3d5aad010","seeds":["0xa85ad8bdf273","0x21283ec77534","0xef49ae912071","0xe12ab8a0d10b","0x99aebd0f8d42"]},{"tokenId":"0x0ac1b4664d8039d3514536dbcd255edfc9eda1954331d0b66219f077a1b0b7a4","name":"eric","salt":"0x0fa8d752318a72bc39596ea54472807036ba649d8a520fe0f63eb21885f2a06c","seeds":["0x7edb42d55d5b","0x6467357be978","0x2b785c7c15f4","0xb3082cff1ccd","0xde9b1d66de6d"]},{"tokenId":"0x024012064ed07e7f07c831e707019ee3da7205f3f24d9ad53ea41af3435a2790","name":"gribbles","salt":"0x42a57a64faf40fa395c00d4ddac8cbf7e909654bda79ea7d46c857aeb68afad5","seeds":["0x52af098e5e9f","0x27ed2ed2a863","0xb74b9ac63849","0xbcf4c539a20f","0x13f00d3c3dd2"]},{"tokenId":"0x135ce50c8320b2cc19a06209909df6ac7c136c12473dbc5e588a124db0a5afbc","name":"govin","salt":"0x822ad2abc96fdd1f93c6a3c873ae70d3acbeeb823e33a97a7ab99e91b57571ff","seeds":["0xe37808487cbf","0xe03bd01e5847","0x9f40445b74a2","0x1d37087af23d","0x306f7a5cce18"]},{"tokenId":"0x3fb27a6b64ff8fb19701b72bebf34ca375df5d5820959ea0681b4b97c73dc065","name":"blamo","salt":"0x5f155c9efb002b1b38089f065874c92bd9ac407205693aa6909371bbc92be46b","seeds":["0x1739076a98b5","0x3f4f6eff6561","0xc9c1f2194c44","0xa807d8bcfd81","0x33c7b9bf5051"]},{"tokenId":"0x3215cb94feb0773b21ab2232a66243df60edc50dbda447ebef19fe416afdc961","name":"oodlesofmood","salt":"0x96a37d6fa130324ef53d249f5571c1de84e04a8caa43198f4ccf103d261b614b","seeds":["0xfb09a950910b","0x4282de8f1eb9","0x71f454414a98","0xafb6f70f1d7b","0x594463f7bbc2"]},{"tokenId":"0x456e171461d7b39f7ffcff68976022cd7cfd020eceb707f6b4b83e2fcddf8086","name":"antoine","salt":"0x38fa2286dcfc3a7de513d824c24292f679e59573c2c7679f838b59cbc6a97e49","seeds":["0xbbe12ce0497f","0x54a0d37e52ee","0xad922a37eb7a","0xa16666cb2506","0x151a805ec4ac"]},{"tokenId":"0xdca4c60a98c38ce1279025c29434419f72a4f220b94842d5c850b849d82025fe","name":"antoinesucks","salt":"0xbe1d0ebb33c565710632e1d546c93c3edc20d35a9663bcd8ec5affca7d954f4f","seeds":["0xcb177a8e42cb","0xfb21dfe9f446","0xb2ef64542cb1","0xdc7b363e7771","0xac1339424dc4"]},{"tokenId":"0x8e91d626f88633b04b4b904b6a1a0c7ce273a418f6f46563ffa0985cc450139c","name":"brendan","salt":"0xea27e478c956851fd8315f3e6d93e0720f04da26a902cec570b0909fc97def74","seeds":["0xe7fea1a84fce","0xd9a3bd6e6398","0xec67912b9fb4","0xf07b3cde18d5","0x74caa04b8575"]}]; -------------------------------------------------------------------------------- /heroku-app/static-fallback/history.js: -------------------------------------------------------------------------------- 1 | const TakoyakiHistory = [{"tokenId":"0xb05e424817fb90aa7a79e9da5c5f94070a316219c6ebb863a9ff7ca357dc9fa9","name":"ricmoo","salt":"0x9ac41b0384eb71c85151f34afb86a1c95ae31913b5de1817fe540b1683e6c5e3","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xc31bd4b91a0d6536561d3cbe7dde66f46938c584368ca2c56c4cef8553ddafd8","name":"loo","salt":"0xab56dfee3c036ceb14489bd6c2825778305e9dd2c7cab2890746889ac8426959","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x1e66721bb1bd77d2641c77ea1d61e8abb92bf69c64fcc90c2c6ad518d1b50db1","name":"moo","salt":"0x659244ac7bfee8cc56c847611abd010f0b77e57ec063d130e08e7690db2b079f","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xbb2ac203ba5b2786d7fc8530982b07fb71660208fd18fb2b5d198f6c94c22df9","name":"takoyaki","salt":"0x5f1e1136c4ba86e20ce0e05a80df3d39a8e47a959b90abc6ad6bc858c4a916dd","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x2e6654d03f4e3cd0cdb09066fb86057ec8f9a9a17fb5a6f7ba79eaa46e4358e3","name":"registrar","salt":"0x1c7b838ee072655f633c739299074bb814fc6e9702b1b69f3ee20295df297df4","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xf23ec0bb4210edd5cba85afd05127efcd2fc6a781bfed49188da1081670b22d8","name":"admin","salt":"0xe7ae479afa696804db45b60c83cd96f947b2968ad6e7fb3a9f633a34a7e6e6cd","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8","name":"hello","salt":"0x39a9f7db7e06c29ac40e4df3f9e7eea9feff1e5dab6a49b65fc021d29627316f","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xbc6bb462e38af7da48e0ae7b5cbae860141c04e5af2cf92328cd6548df111fcb","name":"xxx","salt":"0xac44143c66f9b7953af2516d520d88a613595005b3c848e161241c625b89505e","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x89d19301adce5f2de231f0d8b0f8062bbc4a7117f9ad8e259159b0f4330c6d55","name":"turkey","salt":"0x95877f75d3aed9a1442304e45741add68cd5d28d3e92d7cf6e076397951f3cb2","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xf9d587505fbd50e1ef16e3511e85f5d6486f2ff22e4093ba65f28f58e969e092","name":"turtle","salt":"0xda48f8ba8fbe36fc3119c37076d23cfdd2dcd32fb302f13f45d9aef339c9484e","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x3094c6b18a36643abf79a3ae944ec99f0fdafd155f9b9db373f551fb060d8d37","name":"moose","salt":"0xbe3f5886f63f6fcbae2cf2968e9b3f4b2cd1a0ee493cd88856675cc97c89c28c","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x38e47a7b719dce63662aeaf43440326f551b8a7ee198cee35cb5d517f2d296a2","name":"bob","salt":"0xccfff0f686820fd4988d4ba577c026fa7d849ad4ee4c7cb639ee3cf324f394e5","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x99d872182b3ca96305de9cfd58e2e44f996a5187c1cb67bac92e547f529cfcf9","name":"aurani","salt":"0x6ccf72e86018bf10a0d766e94d88683101a73d3ed4593045f836f89fbd80b928","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0xec6fa3ec747a5662bb19f8358d8c5b59cf7b9603a8d3aeee24e320111bb5b051","name":"yuet","salt":"0xba6fe1c2367af252f802de610b9ace1163078a732c710c4848de42e1386316a0","seeds":["0x8113053a2a92","0xfc58bfdd46a1","0x0bc0392cd345","0x7eeca77eb593","0x593fedc86eb3"]},{"tokenId":"0x9b1df0025ecb2ca9a10e186a98dc9a0f42e9b41572b846b2f13a75e81e27744b","name":"\u305f\u3053\u713c\u304d","salt":"0x498aa30597661689cc41a778b538e36d86ca3a1ecffbdc13d0a029e965e4d503","seeds":["0x5a2f07ed5581","0x7c560b25d07f","0xbd35b7be0cb9","0xd83ee16327b8","0xe95ee63d57af"]},{"tokenId":"0x2b13798fcebac6d075f34a7edfa2e6dc536615be5162fe83d914c363a3515cf2","name":"dipper","salt":"0x598ac2a23357d1b31de41e2f821bc06236a1fa9dee43b15b1669e3f06c7a1ff0","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x751d2d6c1e18eccac3d6d3c477000a32239c6a269baa9900f21ac63c1e81310b","name":"mabel","salt":"0x541d4f4537dc94c1754bb35660d4007ba538ab847e65afbf20cfe085027ccec2","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x4dab0fee114f38e238c099d88daa8fe022f8364b13ba589d2b87850732da7954","name":"stan","salt":"0x7b7a010ca65d24d7844bf3a8a1abd2775c62234a420818e98e66a881b7e4f9c5","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x53199f95900b529152da29cdc096590488dc855d6253103eebd4b3adfe39e3ed","name":"soos","salt":"0x185e6fad72e1f5f3dc080de8ba0e49a6eeb5b8e82a00837978a4829e4d04d529","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x1375cd3639ad63ba00e777c66a7f24e4b3392a847a2b33fa7e750a984f771a92","name":"wendy","salt":"0x43e78720486d49db6f5c0422d1e9f559f30e4c278f13e4ae70d11eb6ea066c64","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x866acb8cc1e941243f40d4bf05a8c1ba2e6756be398e1c5f9a9de47e3a377c8c","name":"waddles","salt":"0x37be9d360bb6dc80e040876a7886e7242755491e7c602218cae1afaa6ad76c05","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x840463345ad81fb522028b524ea3afb85667709ad9e8e2342a0f6fe830b8f9cb","name":"candy","salt":"0x56cd259626189d8bcd16a7a1a2465f0ac64c39347f30e22634ddf83d106a45a0","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x67aa22d3ee3108fb5eaa480e11ebeb93480dfd48f1b7662fa4056a7c6053d151","name":"b-cipher","salt":"0xd7d5709388a4dc4c4ac7af980dde79b0dffc29f20aad491404d37fed7eb2b186","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xf40bb94b63a4534c8409656224edcb3893177bee2fc1f34f8a2fdfe22e8e8e53","name":"tambry","salt":"0x96329002bfa02cf469257664943df6021fb7110d657f86a71da0a67acdc71366","seeds":["0x9032f2f2010e","0x6f5a82948a7e","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x3fda8b709b6aab3ddd6bd0007d6e77856be06f948090129aab80d6199f9bae4d","name":"lazy-susan","salt":"0xf69d5d91615c6823a5c785d5c174dfd56b3efb67d7a636067f0d4bac5705d611","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xa933114a9c2f08089f9f6f3dfe5801a06244ef8e56410d5c00519c01e484936d","name":"timebaby","salt":"0x21ffe16eb8534575174d99167bdc23af6b2833e044180c4c966c669602fa583a","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xa277182f2d62455121a767ac95e4b5c2876f2d366e03eb514e5546c64a1b2b3b","name":"pvenkman","salt":"0x6824091fb697db54adbe72f1b24c05735210814598a6994a86e778729833d9ae","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x9ab242d3b3d08a9bb85b5436ad7dbd81dda41cf4cddc9ac372ff34f2a7eca381","name":"raymond","salt":"0x2dc6484a8965b70455bba0519a17dad8d337a384d3722513a492a3e3a988719b","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x7f895f2514a2910e56a24c830288ca898001b1e3093c06529fe8819d760021bf","name":"dana","salt":"0x464f3d98f1d40c1e7aee016ea0eb4abee1df37aa2b06e54baf63ee174dc621d4","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xab3688c5c116198dfeaf6aa0d5912ba415a688723c65f2e710745cdf2654c2a2","name":"egon","salt":"0x48d74f2a6aa59c0366ea201fda015898433b236de8cb1dead4c640811abf23bf","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x836c94c1cba711e905f024042ecf04dc94d2506f3df25577eac24fb5bee766da","name":"loius","salt":"0xb91c83f0eeb76eef45eb43b601cc3c0b010c25537e75d7978eb0d02e3ef655cf","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xe51c35fb5aa4e750f840ef9e5684442e7fe219bf4ae942143ee7f1924c361719","name":"winston","salt":"0xbbb73d9297f774b82de437d74a2d0c944ca6f9f2fba2d394a55fb1389216e607","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x9ba563eec25dd2b52b1eeb6d146e40dc88901ccd6d42e65a18bbf432813f2cbd","name":"janine","salt":"0x61c23cabe6a45b5d189c8c21f8bc79b60360b25cb70de479e373fc5ae8598c89","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x223c9568acdd0b9be57c8c1d012e0daf940f40387bc1d02547f1587d073f1ada","name":"leonardo","salt":"0xe9d466fc87b2f79fc47dfc85c481c18785546795dbe5858060cb24f89b63f260","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0x9a4c86a27710bd80c78115fba61832a6cd662f20363c4d56dea3eaeff60a5102","name":"michelangelo","salt":"0xa626fa0d0d484cb4c6e397f0cc5603035e7e6847bf76823735197e9f771187f2","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0x2ee513cc4f75","0x54ce095eadde","0x1a261d0cac43"]},{"tokenId":"0xce5cb0fcb097f5799a828308c2a35b53be49a24884e66fdea0d4428910596523","name":"donatello","salt":"0x8c8c4c8a7d68d2b83c7dc42a85e6c98805260bf2d9fa11f4e0e049c2e2a47250","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0xe67b7863d3e32eebfca660ab833c5255836279d57aeb1b5c275832f1bbd7944a","name":"raphael","salt":"0x4fec85719ddfde965afb72be61c9c0a458c3237d11081894feee0cf3589e7708","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0x88fac394255abe8c95591c819c6abbcd45adf6fb65b509856e58163387301d02","name":"splinter","salt":"0xb474e2543e12b5f07affd12615d0ad66455285b0dfa409ef09411c0d052df753","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0x47331a0becddb3fbc9400d3c12401299404594bde406aae6759f6f088b2ce3b6","name":"april","salt":"0xd0f95737d7fe4131bbe9284d57dadf9d8d81255faf2110a780c9b7ec65004865","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0xdf0ef0e796cef4eb2552d1f78163f19092564aefe0aed912f844ba3631d9fa8b","name":"krang4ever","salt":"0xa37eca94820f948695b39801e606f6f33e8ddec3a722f28f652561a90371f700","seeds":["0x5314a6042a4b","0x20c2fc675e9d","0xb04ebdb4a307","0xe71c526aa134","0xbdddbaa86557"]},{"tokenId":"0xb194e85d12b6f2e8dd55c4955333b1a58d259d13c5c3999603124d365fa14e64","name":"tim","salt":"0xce6dd587075af58e6c29c00eccffe7462f5b52313f862ed3ceef6a4ebac6b197","seeds":["0xb98ab5709252","0x15380ac1da68","0x4a1b666b7203","0x2362ecc03ac4","0x30c7ca5399f7"]},{"tokenId":"0x788ada68367139adafc3cbae89eef5a40049cf0ff7cfe2c4e584edfc29ec7730","name":"whatsup","salt":"0xf6c98c436980fd0433dbea4b1aaafee64458a89e44b2d300f82fb78dd7ab1ca5","seeds":["0x76bbf9d1526d","0xb63ca11d30fa","0xc89db5f1169d","0x67af2492fd0f","0x4452aae0dd14"]},{"tokenId":"0xfb0afd7307167ce3af5a9c807643c66309fa46d1c527f63f4cf5fc593401b765","name":"msholozi","salt":"0xa712369f24e0ae78d10371792e4d8ffb004243b9f90a361acdde8b274db4dbee","seeds":["0x3e2112b6fcad","0x3571872b754a","0x4abe376b7917","0x1fa03dd630a7","0xdad9f6d1cd7e"]},{"tokenId":"0x9c4b7a6b4af91b44be8d9bb66d41e82589f01974702d3bf1d9b4407a55593c3c","name":"john","salt":"0x15fa2cc7037229669d4493baf6ef316cbc88786ce860813bf3df84c410a1ab15","seeds":["0xa195be08d3d1","0xe781f1c63e3f","0x805aeecec2cc","0xbd1fa12cce2b","0x80257e0a0d0d"]},{"tokenId":"0xb83330129510a2461236adc7254a3b4e2f2fa25457c7dcb82be80de0f8c96183","name":"alex","salt":"0x5601579f7205415c7ab9020860aa6b09ee96a5f41b165a810fbeb8fe58abe43b","seeds":["0x96c90cd6bc13","0x679e5e613e0a","0xfa6409a2c64c","0x5df98c147fce","0x72d1b5f42ccd"]},{"tokenId":"0x7b6ff5e570f4b3d03a8b3676eeffebaf2c951e43e2bd458aca78aabd6b1b30d8","name":"sandra","salt":"0x9263e667a74d2554b7aebe35cf47aca3dc2a759307d41507abae9e0f47e63d9b","seeds":["0x6ef49908bf77","0x642b86dbc53b","0xe4b34483e00a","0xf2e0f9afae9b","0xe9fc4c9413d0"]},{"tokenId":"0x408f03ab78bc13e6304da5357a4b0b4447b1c81f3a32d6a913938cadbfdfc05a","name":"jon","salt":"0xa15a98ab11e86912df12c872829c9d95a74d4f5a6198d860648b01400a8b5b32","seeds":["0x4044578426bb","0x5affa4592698","0xf50e40213a0f","0x656829ad0384","0x2a6298a9155f"]},{"tokenId":"0xd929655926738198522a96823be92b737028c20bc6fb9906b5d788a67623fa6a","name":"coogan","salt":"0x4512662ef9ee76e8930295c89bf4fb32006d7c7576076bbe2b73e20e82cba460","seeds":["0xcb68e041c01d","0x2409b1944045","0x2a6298a9155f","0x8253f85d6949","0x13d0e53695fd"]},{"tokenId":"0x514982bc8f5109775101ebdee34a5b2fe0914428968bd9e09d69da7e82b6ad2c","name":"leeraj","salt":"0xe6be825bf3347514cd94fbc06d3dd7a8dac71213612c8314fd37a2b63da7eaee","seeds":["0xe1924d07ca6f","0x940a41de2553","0x0de57e85feec","0xddabb6004c9b","0x86b9e0ea8ba1"]},{"tokenId":"0x23f71d6edcf6e2d3177bf037f15ee70c7e9f9717132a9f78c5c8161c62bd5f2a","name":"kendall","salt":"0x1cd4d248f3fc223a009c51b65308453253eec681e6e680f33044c2c06f2e62c6","seeds":["0x3852b30afd92","0x0fddee4416eb","0x763dce5621ac","0xd7b793ccda5f","0xd27105b6cdd9"]},{"tokenId":"0x39fd2e80dd48229393ceb969fb81b6925614bc2a05dcae6ef92442d16030b3b4","name":"cypherpunk","salt":"0x596ddff0a03552e310954bf5b2553c1d75f38fd16a59c0f22a2818ea06a8248d","seeds":["0xdff62fc448ec","0x21dbf32bf9ec","0x3e5b860885e7","0x8c03db580609","0xb61f8b6bf32f"]},{"tokenId":"0x095f96e7f1dbd8eb9a5c14efba5e1fe4702831a4c382e3a397a608156075eda7","name":"mokn","salt":"0xc0a1993d00f66d51b06421dff6734812f05d6a4fe8343acff1359bfdff8c804e","seeds":["0x36a24a3d72f0","0xf6a9a21f630f","0xa7624a4a4c40","0xc7e36f02a4dc","0xe92d0f440402"]},{"tokenId":"0x2ad640472aec21c16ff6a557f533aa30c3dd44ed1d625960ebb62bbad551bb35","name":"cri","salt":"0x87babea66cf88f505338e0d247165d197f86dec77332bf317f82d0c91e58c25c","seeds":["0x7f723c9bc4ad","0x475733f5b1a2","0x17ff88a8fac6","0x466c0d51c0a5","0x58887b56ff39"]},{"tokenId":"0x903f7a9785b844fe6bb5db048dfbbd8530aeb6e23d262cce9643f9ef23fb5280","name":"unicefinnovation","salt":"0xcbe6a0237e36e0de8c77ef2b1e62d30f2102931c2db6a289a177c68a9171b0ec","seeds":["0xbfaa7828cc6c","0x26f919656cf2","0x8861019103fa","0x0bd67b2cebb2","0x298ffeb0be34"]},{"tokenId":"0xd11570f3bf2c8bc97826cfcdf149860362b355201eae78794a34eb06351e601f","name":"dragon","salt":"0xe50a09cb21bdf8d3fa24276e60956a15b4631377892a488443ea58fddd590773","seeds":["0x4ea2acf4dd0f","0x1b22f86230b1","0xe3ed7bd47ec7","0x701392370ad2","0x4203cead5e12"]},{"tokenId":"0xa81a96f7ee0298b0bfe5383bff1fd967d18f3ef21fd51fd76a96cf26fbacbcd5","name":"jenny","salt":"0x7f832b2ef62b67294a10ee277228d2c4aa3e38e4908b319814ebf859d2050eac","seeds":["0xafab1063acf8","0x85b9d28188d6","0xe63aa0f806da","0x51bffd5baf09","0xda2176e234ed"]},{"tokenId":"0xba61c49004983bc461eab0db54ee9ce072d24f4d0413f9702c2dd48538ef0eb6","name":"kamal","salt":"0x8b341c95ff0773255ee51093d7de761af3ac4a76701759b1d53d5610bc6cb147","seeds":["0xe6e45fc9c0af","0x60c6a5de920f","0x4dc229ed8080","0x6e9561a1e32f","0x4a20665865bd"]},{"tokenId":"0xdfcac4f4aaabe9f69fb8660e01cdb727355ca2386e050610e0cd4eb292976c6c","name":"zain","salt":"0x0e8753908049202b4fae59c544bebafe70f96a1c775ff6ae6807d3cbe7216abb","seeds":["0x2b688a15dc5d","0x1e900b08bec5","0xd9101e8f524b","0x23d38ea47eed","0xd08f433933df"]},{"tokenId":"0x04771c25633ef4931e253cba514a3424afdec1c563f945250e12e25caefd7fc0","name":"teo","salt":"0x437b3c28101bc52459215ff093c423f4db06a4d45989e53511b2bccccda9d2d3","seeds":["0x5896b040de0e","0x323017bd0dfd","0x057b38f7a9c9","0x74d29572d027","0x5763757a6d43"]},{"tokenId":"0xe65f89eab4e7fc4cdade2363a9b071ba23e49d6e9c1dbb7acdc59558fdb834bd","name":"caleblau","salt":"0xc54f3a1a51a8c1fb334e6387d1b0af719051c899804d49e6c7cfeb6709da3001","seeds":["0x68e3f4fe9a36","0xadc5533710b7","0x5fb756d1b2a7","0x4bc288b63c00","0xf9420b2512b6"]},{"tokenId":"0x5653ebbfa872cd6d0e211eda2d048757f2d64ff559166a1dc016f5bf01562506","name":"ethne","salt":"0x9a99a73cff39c1ce3eed9f301140034a3b486bd1caa8d37c76010123448759aa","seeds":["0xc7fb29c70a56","0x94ea45e0c5ef","0x0d3f9a2d2c57","0x74f2a250e9e2","0x3e1b4bda9ab3"]},{"tokenId":"0x124d0c456d49f779f496a0c4efee97fb10240d7fccd3336a23701a6fae76bd44","name":"muffins","salt":"0x560ecc7b38c6d6ce7e32b97f3d67697cea03e40a689b90c924751f6f557ef454","seeds":["0x95add7e92441","0x51022d8a2dc0","0x32eef0ce07cc","0x5674cff9eb93","0xd17f6aafd54c"]},{"tokenId":"0xce899681965a38777124c1289185d73179017762039814a595baafb7b2646027","name":"sven","salt":"0xdfba6ce1f510c7414ad9924f9704562b9abc8761202ce7b4ce5d747ef6b359f5","seeds":["0x699cbcd6f6b7","0x62d1b3e25666","0xcf2b8e69cdf3","0x458640ad6364","0x2c7c562794b4"]},{"tokenId":"0x07cee237862ac552fe3582f50b9d624b6de9c9784eb9b8e0e3b5ed3ae7a75a54","name":"asobimasu","salt":"0xc44fb5e998d30ea435c79c454654e1b5380253dd69d75e3e48be040187e2901f","seeds":["0x492554f0a165","0x7bfb8d8ea69a","0xb8bb3afc6334","0x53c73f8f58b3","0x8b119ec4a5fe"]},{"tokenId":"0x344bffa221eb76ebe2f482bfa37db2b9e85e6d76a89e25fe19d73be82021d2cc","name":"johnnathan","salt":"0x0b6ab3e59bba18c96229321b61c9ebb40e1c98b403315acb0a227fd3d5aad010","seeds":["0xa85ad8bdf273","0x21283ec77534","0xef49ae912071","0xe12ab8a0d10b","0x99aebd0f8d42"]},{"tokenId":"0x0ac1b4664d8039d3514536dbcd255edfc9eda1954331d0b66219f077a1b0b7a4","name":"eric","salt":"0x0fa8d752318a72bc39596ea54472807036ba649d8a520fe0f63eb21885f2a06c","seeds":["0x7edb42d55d5b","0x6467357be978","0x2b785c7c15f4","0xb3082cff1ccd","0xde9b1d66de6d"]},{"tokenId":"0x024012064ed07e7f07c831e707019ee3da7205f3f24d9ad53ea41af3435a2790","name":"gribbles","salt":"0x42a57a64faf40fa395c00d4ddac8cbf7e909654bda79ea7d46c857aeb68afad5","seeds":["0x52af098e5e9f","0x27ed2ed2a863","0xb74b9ac63849","0xbcf4c539a20f","0x13f00d3c3dd2"]},{"tokenId":"0x135ce50c8320b2cc19a06209909df6ac7c136c12473dbc5e588a124db0a5afbc","name":"govin","salt":"0x822ad2abc96fdd1f93c6a3c873ae70d3acbeeb823e33a97a7ab99e91b57571ff","seeds":["0xe37808487cbf","0xe03bd01e5847","0x9f40445b74a2","0x1d37087af23d","0x306f7a5cce18"]},{"tokenId":"0x3fb27a6b64ff8fb19701b72bebf34ca375df5d5820959ea0681b4b97c73dc065","name":"blamo","salt":"0x5f155c9efb002b1b38089f065874c92bd9ac407205693aa6909371bbc92be46b","seeds":["0x1739076a98b5","0x3f4f6eff6561","0xc9c1f2194c44","0xa807d8bcfd81","0x33c7b9bf5051"]},{"tokenId":"0x3215cb94feb0773b21ab2232a66243df60edc50dbda447ebef19fe416afdc961","name":"oodlesofmood","salt":"0x96a37d6fa130324ef53d249f5571c1de84e04a8caa43198f4ccf103d261b614b","seeds":["0xfb09a950910b","0x4282de8f1eb9","0x71f454414a98","0xafb6f70f1d7b","0x594463f7bbc2"]},{"tokenId":"0x456e171461d7b39f7ffcff68976022cd7cfd020eceb707f6b4b83e2fcddf8086","name":"antoine","salt":"0x38fa2286dcfc3a7de513d824c24292f679e59573c2c7679f838b59cbc6a97e49","seeds":["0xbbe12ce0497f","0x54a0d37e52ee","0xad922a37eb7a","0xa16666cb2506","0x151a805ec4ac"]},{"tokenId":"0xdca4c60a98c38ce1279025c29434419f72a4f220b94842d5c850b849d82025fe","name":"antoinesucks","salt":"0xbe1d0ebb33c565710632e1d546c93c3edc20d35a9663bcd8ec5affca7d954f4f","seeds":["0xcb177a8e42cb","0xfb21dfe9f446","0xb2ef64542cb1","0xdc7b363e7771","0xac1339424dc4"]},{"tokenId":"0x8e91d626f88633b04b4b904b6a1a0c7ce273a418f6f46563ffa0985cc450139c","name":"brendan","salt":"0xea27e478c956851fd8315f3e6d93e0720f04da26a902cec570b0909fc97def74","seeds":["0xe7fea1a84fce","0xd9a3bd6e6398","0xec67912b9fb4","0xf07b3cde18d5","0x74caa04b8575"]}]; --------------------------------------------------------------------------------