So how we came to this idea-> im user of bybit and to buy/sell you need to communicate with people for providing info agree on agreements😆 and furthermost you are sharing your data. Its public its visible for the system for company and in our time if somebody will hack all information easy will go to black market. Soo we come up with zkProof circuits idea. All info about deposit order creation will go to the circuit our platform will approve this check with KYC if user is true man able to trade on our platform. So info about user will be just aprovments from user database is storing only order information about when order came when was approved, was it done with amm or fully with spot.
As you see shortly we can say that our platform - Zoro is about privacy - no one will see what you are doing. Protection - database will be hacked or somebody wants to speculate or change data it will be not possible because everything is in the circuits you can just see the order formations and flow. To tell the truth we wen crazy with this project we used a lot of tools and we did not finished in the way we wanted, so we will continue to work on it because its really cool idea and with this project we gain so much knowledge and skills so we ready to go to noir to rewrite their libraries because they are not working. Make a call with envio because their tool is not supporting macOS sillicon for the container creation(not able to build circuits<-redis-> backend architecture so frustrating) suggest improvments to openZeppelin with their contracts audition.
Off chain balances and user actions are managed by circuits and zk proofs, to offer users privacy, and MEV protection. It was difficult to strike a balnce between correctness and decentralization with the computational limits of noir circuits. Thus to batch orders we decided to proof single actions off chain, batch verify on chain, and then update the balances. This proved to be a much bigger challange than we had thought it to be and being quite new to Noir, we could not finish this project correctly. Balances are stored in a merkle tree in leafs, as utxos. When there is a change in balance new output utxos are created and old input utxos are mark as spent with nullififers. We proof each action in a single circuit per chain where we proof the commitment of the leaf (its value) its correctly computed and that the output utxo leaf's value corresponds to the spent input. In a batch we aggregate all actions's outputs in a subtree and proof its appendance to the main tree on chain, the nullifiers computed in the circuits off chain are then mapped to booleans on chain to avoid double spending. After verification on chain is proven all balances are updated. If there are any withdrawals in the batch they are executed on the same batch verification call. We use a very simple merkle tree (non indexed) to minimize the complexity of the circuit and avoid too many constraints.
We had plans of cross chain features that unfortunately we couldnt develop due to lack of time and knowledge, but we are still happy from everything that we have learnt in this challange.
This hackathon was huge debugging for web3 existing tools😆😆😆 but it was fun, thank you
It's made with pain- so i started backend on rust first - but its too complicated to communicate with noir cucuits so i switched to nest.js framework. For the database i used favorite postgres database and i open for myself Prisma ORM very cool tool need to create something same for decentralized db in web3(future project idea😆). For the frontend of course react and for the contract creation Foundry(sorry hardhat, your tools are good for small projects but they are extremely unsupportive for our zkPOrderBook)
- to catch data from contracts i used envio - docks are good for simple connection but not for the microservise based projects - extremely unsupported tool for containerization:
--my aim was to connect to redis to make envio able to send data to backend and redis at the same time - so i dockerise envio indexer from created by generated docker-compose file but could not run: first -because of my amd based system and even with the changed platform in dockerfile its was not working too, i tried to use different images one of them worked but the second problem came immediately - envio container could not see graphQL container(even with external network) and container was not running because to run it need connection to graphQl database. I thought of connecting grathQL to redis but with this system it will just loose time so i stopped with simple db connection.
- for the amm im using uniswap (but in the project can see only contract because we had problems with circuits from noir and we could not finish it and deploy)
So in the end we will continue to work on this project, for hackathon i quess it was very big idea(but we are too green to rise this in 15 days )
-----and circuits part
User actions are received (either from frontend, or form contract events). We use event logs, and signatures to verify the validity of action data. Actions are queued if the user has enough "pending" balance.
- Upon quoing we update the pending/locked balance depending on the action.
- Available balnce tracks verified balances that are not locked or pending, the user can "inmediately" withdraw if they wanted, pending balance tracks the "future" balance if all the queued actions were to be successfully verified, and "locked" balance represents the balance that correspond to new unsettled orders.
-Periodically or when the batch is full, we proof a batch. This starts off by going through the action queue and checking if there is enough balance available between all unspent utxo for this user, if so then the action is removed from the queue and "processed". All "processed" actions will pick utxos mark them as spent, and append newly created outputs to the batch subtree. Then these inputs and output utxo along with user secrets and other acitons details are used to proof off chian the correctness of the the spent input utxos and hte new output utxos.
NOIR PROBLEM
Because of the nature of noir we need to have fixed sizes so we allow different fixed amount of max inputs and outputs for each action. This is specially problematic for inputs, as if we were to allow too many, our circuits could explode because of constraints and be too inefficient and expensive, but too little and a user will be stuck with dust unable to do any balance movements. To mitigate this problem we have an extra action "join" that joins a bunch of dust (small input utxos) into a single output utxo. We keep queueing this actions (for the next upcoming batches if batches become full), and in the very next batch we schedule early our action to act witht all the unified dust as input. In each off chain circuit we proove also the nullifier of spent inputs. All nullfiiers of the batch, the withdrawal details of the batch, and the subtree of outputs are sent to the smart contract to be verified against the latest root, if succesfull the new root will be recorded and off chain the subtree of outputs will be added to the permanent record and available balances updated accordingly. This design allows us some more flexibility in the variety of actions as we can proof any type of user action and batch them with a set of maximum output utxos. It is a simple but cheaper alternative, that offers cheap privacy, in a practical and transparent manner. Our goal is not to make a mixer, but to make privacy more accessible, the idea originally focused on kyc too but we were too short on time to start considering this properly.