Problem Statement
Today, people need to use CEX to buy and sell cryptocurrency with their fiat currency. Such approach has many drawbacks such as,
- User needs to take the burden to register and maintain another account in a centralized financial service, such as CEX or USDC official app.
- By aggregating supply and need, CEX can gain unfair advantage to help them charge high fees.
- Privacy concerns. For fiat/crypto trade, CEX knows who in physical world send/receive the money (through their bank account info) and which crypto address the fund is transferred to/from.
ZK and Web3 Solution
For ZK part, we build this application based on the source code of original Tornado.cash (sorry, the source code is no longer legitimately available), lift the amount limitation and migrated to the latest version of circom and snarkjs for better performance and code quality. The ZKP serves the purpose of breaking the link between fiat and crypto transactions. There is no way one can tell that a PayPal user purchased certain amount of USDC and deposited to a specific Polygon address. For Web3 part, we implemented a PayPal relayer that can relay PayPal deposits to Polygon network and make payouts to sellers based on instructions from the blockchain transactions.
Neither buyer nor seller needs to register to use this service. And thanks to the low transaction fee of Polygon, the platform can only charge a fractional fee compared with traditional CEX service (except the fee charged by PayPal or banks) in order to fulfill the transaction.
Note: for the purpose of demonstrating technical feasibility, we only implemented USDC/USD pair trade in current milestone.
Use Cases
- Sell Coin: Anyone who possess a Polygon address and would like to sell their coins for fiat currency, can deposit the coins to zkMarket.Finance and provide a PayPal account email to receive fiat. Once the coins are sold, zkMarket.Finance will payout the fiat to their PayPal accounts.
- Buy Coin: to purchase crypto coins, user simply specifies how many fiats she wants to spend and a Polygon address to receive the coins. The fiat payment is done through PayPal and the purchased coins are settled to user’s Polygon address. By leveraging ZKP technology, the connection between Paypal account and Polygon address is broken, thus shield the transaction for better privacy.
Technical Workflows
Purchase USDC (Happy Path)
- Buyer specifies amount of fiat she wants to spend and a Polygon address.
- Buyer generates a
commitment(hash of nullifier, secret and amount) in browser and initializes a PayPal payment to deposit the fiat together withcommitmentto zkMarket.Finance PayPal account. - Once the fiat is received, zkMarket.Finance PayPal relayer register the
commitmentand amount to Polygon zkMarket.Finance contract (a.k.a, PaypalUSDCAssetPool). Note: at this time, zkMarket.Finance doesn’t know the received amount matches the amount hashed intocommitment. - Buyer submits a
commitmentzkSnark proof to PaypalUSDCAssetPool to prove she knows the nullifier and secret, and the amount incommitmentmatches what has been registered by PayPal relayer in previous step. Once verified by PaypalUSDCAssetPool, thecommitmentis inserted to Merkle tree. - Buyer submits a zkSnark proof with a recipient address to PaypalUSDCAssetPool to prove she knows nullifier, secret and the Merkle path to the
commitment. Once verified by PaypalUSDCAssetPool, a certain amount (PayPal Deposit - Fee) of USDC will be transferred to the specified recipient address. PaypalUSDCAssetPool saves hash of nullifier so that it can reject same proof in the future to avoid double spending.
Note: PaypalUSDCAssetPool doesn’t know what exact commitment is spent. It only knows the not revealed commitment is included in Merkle tree by verifying the zkSnark proof. This means PaypalUSDCAssetPool can’t link commitment with recipient address.
Sell USDC
- Seller deposit a certain amount of USDC to PaypalUSDCAssetPool and specify her PayPal email address for receiving fiat fund. PaypalUSDCAssetPool records this info in Polygon.
- Once a purchase is made, PaypalUSDCAssetPool take turns to find sellers that can satisfy such purchase, transfer the coins to buyer and deduct sellers’ amount accordingly.
- PaypalUSDCAssetPool emits events to instruct zkMarket.Finance PayPal relayer payout these sellers from zkMarket.Finance’s PayPal account.
Component
- zkmarket-core (this repository): zkSnark circuits and smart contracts that compose the core logic of this application.
- zkmarket -ui: a ReactJS based web application for end users.
- zkmarket -relayer:
- PayPal relayer services to relay transactions between Polygon and PayPal.
- Proof relayer for submitting proofs on user’s behalf. It is a trustless service that solves the "
pay gas fee without revealing the identity" issue.
Challenges and Learnings
ZKP is quite new and I’m also new to Web3 development, the tools are still in their nascent stage. It takes me way more expected time to debug and test the circuits and the contracts even it seems logically simple. The simple formatting issues could take me couple of days to figure out the problem. Sometimes it’s frustrating but I’m always thrilled once fixed the problem. I guess this is a great way to learn.
In the middle of the project, I decided to add more tests for circuits and contracts. This approach is quite effective, not only its improved the code quality significantly but also it helps to catch early bugs embedded in previous code that could cause me days to figure out. More importantly, this approach gives me more confident and take the whole progress under control.
I got aware of this hackathon just couple of weeks before the deadline and don’t have much time to find team to contribute more effort on this project. Especially, I think it would still need quite a lot of work to improve UX and error handling part before we can say it is product ready. I’m sure this can be done better for future by better planning.
Built With
- circom
- faas
- javascript
- react
- solidity
Log in or sign up for Devpost to join the conversation.