---
# System prepended metadata

title: Spec

---

- 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)