- todo - [ ] multisig setup (multiple owners) - [x] setup whitelist storage (vercel edge) - [x] update smart contract according to the spec below - [ ] complete smart contract testing - [ ] verify hash function on the smart contract - [ ] function to generate deterministic hashes from twitter handles - [ ] function to generate merkle tree - [ ] - **Smart contract** - SPEC - `whitelistTransfersPaused` and `publicMintsPaused` - bool variables - can only be changed by the owner - **`MINT_PRICE`** - public variable, controllable by the multisig - price of non-whitelisted mints - default to 0.1ETH - **`publicMint()`** - public variable, controllable by the multisig - if `true`, `mintTo()` function should allow mints without a `hash` provided - if `false`, `mintTo()` will require a **valid** hash to mint successfully - **`usedHashes(string => boolean)`** - mapping to store all the hashes / merkle leaves that have been consumed - **`minters(address => boolean)`** - a mapping of all addresses that minted an NFT - if an address has minted an NFT, they shouldn't be able to mint again - **`mintTo(address, hash)`** - address (reciever of the NFT), hash (optional) - check if address is in `minters()` - if yes, revert - if not -> continue - check if address owns an NFT already (`balanceOf`) - if yes, revert - if no --> continue - **if hash provided** - check if hash has been used already (`usedHashes`) - if used, revert - if not, continue - check hash validity - if not valid, revert - if valid, continue - check msg.value - check value -> if > 0; revert - if 0 -> continue - mint - increment counter - add hash to `usedHashes` - add address to `minters()` - **if hash not provided** - check if `publicMint()` is true - if false -> revert - if true, check `msg.value = MINT_PRICE` - if false, revert - if yes, mint - **`updateMerkleRoot()`** - admin only function - updates the `root` public variable - TESTING - **mintTo**(address, bytes32) - should not be able to mint if invalid hash - address should not be able to mint if already has a token - should not be able to mint twice - with two valid hashes - should not be able to mint twice with a single valid hash - should not be able to mint with a invalid hash - function should not allow value transfer (free mint) - address should not be able to mint if - **mintTo**(address) - should not mint if paused - **App: Client** - take the list of all twitter handles - generate deterministic hashes - create merkle tree - update smart contract with the merkle root (`updateMerkleRoot()`) - user connects their twitter account [nextauth???], the server checks if currently connected twitter account is in the whitelist or not [from the database] - if it's not - display a message saying you're not in the whitelist - if publicMint() is true -> display an option to mint + display the mint price - if publicMint() is false -> display a message asking to wait until public mint happens - if it is - display mint option and price as `0 ether` - prompt to connect wallet - api call to generate hash on the server (server generates the hash and returns it back) - check if address is present in `minters()` - check if hash is valid (on-chain call) - send connected wallet address + hash as the params for `mintTo()` function - wait for the transaction to go thru - **App: Whitelist storage** - key value store to keep maintain an array `whitelist`, a key `root`, and a json object `used` - `whitelist`: array of strings - array of all whitelisted twitter handles - `root`: merkle root of all the deterministic hashes of twitter handles - `used`: json object of keys as twitter handles and value as the hash used to claim their nft (updated after a tx goes thru) - **App: Server** - api to update whitelist - add new member in whitelist array (twitter handle) - generate new hash - update `root` (generate merkle tree) - api to create whitelist - accept an array of strings (twitter handles) - create merkle tree, generate root - update `root` - api to fetch all whitelisted handles - fetch `whitelist` array - api to fetch if a give handle is whitelisted or not - query `whitelist` array - api to fetch all used hashes + twitter handles that have initiated the transaction - query `used` object - api to generate and return hash given a twitter handle - run a util function - Hash generation - encrypt twitter handle using a secret key (server .env)