An extension of the previous version of Anonymous NFT Exchange. Added functionalities to allow listing of ERC20 tokens.
Deployed contract: https://explorer.testnet.mantle.xyz/address/0xDD98f5E7269f8eCfb62b77CC8bCbf791BEFF8cC2 Tweet: https://x.com/lilioo826/status/1716009796862930957?s=20
Had some issue deploying to zkEVM testnet, getting error not enough step counters to continue the execution
. Instructed by polygon teammember to deploy to Mumbai instead: https://discord.com/channels/554623348622098432/819516356616781834/1165545531871870996
The deployment of the contract got stuck: https://sepolia.scrollscan.dev/tx/0x940d964729e7af1c350fea0ea927cf4122a5fd5844db97470eb7101696964095. Tested on fork mode locally is it's working ok.
For the simplicity of the initial system, we make the assets all traded at 0.01 ETH. It is possible to extend to other price tiers in the future.
Seller can perform following 2 operations
- List on the smart contract and get Semaphore id
- Claim ETH using the Semaphore id after the asset is sold. A new address should be provided to receive the ETH
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 assets
- Buy the asset with the proof generated by Semaphore id. A new address should be provided to receive the asset
There are 2 Semaphore groups to achieve the anonymous of seller and buyer.
ASSET_SOLD_SELLER_GROUP_ID
: Sellers whose asset got soldETH_DEPOSITED_BUYER_GROUP_ID
: Buyers who have deposited the ETH
There are mainly 6 functions
list()
: called by sellerdeposit()
: called by buyerbuyAndClaim()
: can be called by anyone, triggered by buyerclaimETH()
: can be called by anyone, triggered by sellerwithdrawETH()
: called by buyer to withdraw unspent ETHdelist()
: called by seller to delist unsold asset
When seller lists the asset 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 asset with the corresponding public Semaphore id.
Buyer needs to deposit ETH before it can buy asset. 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 asset. Additionally, the Semaphore id of seller associated with the sold asset is added to ASSET_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 asset 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