An anonymous NFT exchange based on Semaphore protocol.
For the simplicity of the initial system, we make the NFT all traded at 0.1 ETH. It is possible to extend to other price tiers in the future.
NFT Seller can perform following 2 operations
- List NFT on the smart contract and get Semaphore id
- Claim ETH using the Semaphore id after NFT is sold. A new address should be provided to receive the ETH
NFT Buyer can perform following 2 operations
- Deposit ETH to the smart contract and get Semaphore id. With the id buyer is eligible to buy the listed NFTs
- Buy NFT with the proof generated by Semaphore id. A new address should be provided to receive the NFT
There are 2 Semaphore groups to achieve the anonymous of seller and buyer.
NFT_SOLD_SELLER_GROUP_ID
: Sellers whose NFT got soldETH_DEPOSITED_BUYER_GROUP_ID
: Buyers who have deposited the ETH
There are mainly 6 functions
listNFT()
: called by sellerdepositETH()
: called by buyerbuyAndClaimNFT()
: can be called by anyone, triggered by buyerclaimETH()
: can be called by anyone, triggered by sellerwithdrawETH()
: called by buyer to withdraw unspent ETHdelistNFT()
: called by seller to delist unsold NFT
When seller lists the NFT on the exchange, a Semaphore identity is generated. Seller needs to note down the private Semaphore id (trapdoor and nullifier). The smart contract will record the NFT with the corresponding public Semaphore id.
Buyer needs to deposit ETH before it can buy NFT. When buyer deposits, a Semaphore id is generated. Buyer needs to note down the private id (trapdoor and nullifier). The smart contract will add the public id into ETH_DEPOSITED_BUYER_GROUP_ID
.
Buyer submits the Semaphore proof that anonymously prove its membership of ETH_DEPOSITED_BUYER_GROUP_ID
. Smart contract will verify the proof and signal the operation to prevent double spending. Buyer will provide a fresh address to receive the NFT. Additionally, the Semaphore id of seller associated with the sold NFT is added to NFT_SOLD_SELLER_GROUP_ID
.
Seller who wants to claim the ETH will submit the proof generated by its private Semaphore id, anonymously proving that it's a member of NFT_SOLD_SELLER_GROUP_ID
and eligible to claim ETH. Smart contract will verify the proof, and signal the operation so it cannot be double claimed. Seller will also provide a fresh address to receive the ETH.
Note that transaction for buying NFT and claiming ETH can be sent from any address as long as the proof is valid. To remain anonymous the approach of this project is to maintain a relayer. The relayer will just submit the transaction for the user. From public people can only know Buy or Seller is one in the group but wouldn't be able connect the NFT purchase to the original payer.
Populate the environment variables in .env
according to .env.example
Go to contracts/
- Install dependencies
yarn
- Set up snark files
yarn download:snark-artifacts
-
Run test
yarn test
-
Coverage
yarn coverage
-
Local network deployment for developemnt
npx hardhat node # in another terminal yarn deploy:local
The project uses Next.js framework and Vercel for deployment
To config the contract addresses
- Fill in the addresses in
wagmi.config.ts
- Run
yarn wagmi
to genereate the fileabis.ts
-
Start Local
yarn start
-
Local watch mode
yarn dev
-
Build
yarn build