Anon Exchange uses Semaphore protocol to create an NFT exchange that can protect the anonymity of NFT sellers and buyers.
Semaphore is a zero-knowledge protocol that allows you to cast a signal (for example, a vote or endorsement) as a provable group member without revealing your identity. Additionally, it provides a simple mechanism to prevent double-signaling. Use cases include private voting, whistleblowing, anonymous DAOs and mixers.
This project utilizes the privacy setup of Semaphore protocol to form groups of buyers and sellers. So when transactions happen, public cannot tell the actual identities involved in the trade, while double spending can also be prevented.
For the simplicity of the initial system, we make the all NFTs traded at 0.01 ETH. It is possible to extend to other price levels in the future to support different sizes of transactions. More in the last section for future ideas.
NFT Seller can perform the following 2 operations
List NFT on the smart contract and get Semaphore id
Claim ETH using the Semaphore id after the NFT is sold. A new address could be specified to receive the ETH. From public people can not tell among all the sellers whose NFT got sold withdrew the fund.
NFT Buyer can perform the following 2 operations
Deposit ETH to the smart contract and get Semaphore id. With the id buyer can prove that it is eligible to buy the listed NFTs
Buy NFT with the proof generated by Semaphore id. A new address could be specified to receive the NFT. From public people can not tell among all the depositors who made the purchase.
There are 2 Semaphore groups for anonymity of seller and buyer.
NFT_SOLD_SELLER_GROUP_ID
: consist of sellers whose NFT got sold
ETH_DEPOSITED_BUYER_GROUP_ID
: consist of buyers who have deposited 0.01 ETH
The Semaphore id can only be signaled once, so it can prevent the issue of double spending.
When a 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.
A 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 Buyer or Seller is one in the group but wouldn't be able connect the NFT purchase to the original payer.
A demo app is developed to implement the operation flows above: anon-exchange.vercel.app. It’s deployed on Sepolia testnet.
The experience should be self explanatory. Some special notes
At the listing NFT page, it allows user to mint test NFT to experience the project
At the pages “Buy NFT” and “Claim ETH”, users do not need to connect wallet to perform the operation. The transaction is handled by relayer wallet so the privacy is preserved
The project uses randomly generated UUID as private secret to construct the Semaphore ID. There are other approaches to do it as well. A common practice could be asking the user to sign a message using wallet. The demo app avoid it deliberately to emphasize that user can operate completely without the wallet. For more information, please refer to the document here: https://semaphore.pse.dev/docs/guides/identities#create-deterministic-identities.
More trading sizes
Merkle forest is something to be explored to support different prices so users can trade different prices of NFTs. Or even allow users to create new groups freely. However the privacy would be reduced when the users are split to many groups and less members in the group.
ERC20 payment
Building on the previous point. It’s also possible to create group of buyers that pay in ERC20 with a set amount.
Support listing more asset types
Besides selling NFTs, it is possible to list ERC20 or other asset types, or even a bundle of assets. More generally, it can be any defined operations that can be triggered when buyers pay. For example, it can be a transfer of smart contract wallet ownership.
Sustainable relayer
To take from fee from the trades to make the relayer operation sustainable, or employ incentives for anyone to run a relayer.