A platform that provides balance hiding for DAO treasuries. Based on work done by Griffin Dunaif & Dan Boneh.
Front-running is a consistent issue that many DAOs built on non-privacy enabled chains encounter in their day-to-day operations. One class of DAOs that are particularly impacted are collector DAOs that participate in sealed-bid auctions. Public verifiability of their treasuries puts them at a significant disadvantage, with the most prominent example being ConstitutionDAO's loss in late 2021.
Balance hiding is a promising solution. The treasury implementation provided in this repository satisfies this property using a simple scheme based on elliptic curve diffie-hellman key exchange. The core components of the scheme are as follows.
One contract instance for this treasury is designed to support multiple DAOs that form an anonymity set. Rather than sending ETH to a different contract per treasury, contributors are meant to send ETH to this main contract, along with a cryptographic puzzle that only the DAO manager(s) know the solution to. The puzzle is a diffie-hellman shared key that's derived from the DAO manager's public key (not the same as their ethereum pubkey) and a nonce sampled by the contributor. Two important properties of this shared key are
- Safety is protected by the hardness of discrete-log. Adversaries can't withdraw funds that don't belong to them.
- Anonymity follows from the decisional diffie-hellman assumption. The shared key doesn't reveal anything about the target DAO public key. Thus, outside observers only know the total balance of all DAOs on the platform, but not how much each DAO is entitled to.
Treasury managers check each deposit as it comes in to see whether their secret key can solve the attached puzzle. They can then redeem leaves posting a zkSNARK proof that verifies 1) knowledge of the secret and 2) inclusion of these leaves in the on-chain merkle tree.
The above figure further specifies the puzzle attached to each leaf.
- The SNARK is built on the circom / snarkjs stack. I use the SNARK-friendly elliptic curve babyjubjub to avoid any non-native arithmetic when using a prover instantiated over bn128. The main circuit,
verif-manager.circom
, utilizes the IncrementalMerkleTree and Poseidon Hash implementations from Semaphore. - The contracts are meant for EVM deployment, so they are written in Solidity. They use the corresponding Solidity implementation of IncrementalMerkleTree from Semaphore.
- The CLI carries out babyjubjub keygen using Onther-Tech's library and proof generation using snarkjs.
- Main contract:
0x5dAb294C7698B8Bd1a3d90557223349Fe5B35BbD
- Groth16 verifier:
0xac71523A21Dd82C7645Edec341e90022aDF51F98
Variable(s) that must be set at the beginning of the setup process: [RPC_URL
]
Download the ptau file that supports up to 2^{17}
constraints (`po
rsOfTau28_hez_final_17.ptauin the [Hermez trusted setup](https://github.com/iden3/snarkjs#7-prepare-phase-2)) and put it in
./artifacts/circom`
mkdir -p artifacts/circom
cd artifacts/circom
curl https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_17.ptau --output powersOfTau28_hez_final_17.ptau
Navigate into the circuits/
directory, install the dependencies, and compile.
cd circuits/
yarn
Compile the circuit.
yarn dev
Run the test harness.
yarn test
Navigate into the contracts/
directory and install the dependencies
cd contracts/
yarn
Deploy the contracts that hold the poseidon hash functions.
cd src/
ts-node deploy_poseidon.ts
Copy these addresses over to instantiate hasherT3
and hasherT6
in src/PrivateTreasury.sol
. Now deploy the SNARK verifier.
cd script/
bash forge_create_local_verifier.sh
Copy the verifier address over to VERIFIER
var in script/forge_create_local.sh
. Now deploy the main contract.
cd script/
bash forge_create_local_verifier.sh
Set these variables in your .env
file: [MANAGER_ETH_PRIVKEY
, CONTRIBUTOR1_ETH_PRIVKEY
, CONTRACT_ADDR
, CONTRACT_ABI_PATH
]. Now you are ready to create a new treasury
ts-node create.ts
Use the outputs from this run to set these variables in your .env
file: [TREASURY_PRIVKEY
, TREASURY_PUB_X
, TREASURY_PUB_Y
]. Now deposit ETH into the treasury you just created.
ts-node deposit.ts
Withdraw ETH from the treasury.
ts-node withdraw.ts
- Switch to C++ witness generation for SNARK.
- Implement CLI functions as MetaMask Snaps.
- Store frontier nodes for Merkle tree off-chain to make gas consumption for deposits reasonable.
- Fork JuiceBox / Aragon & add private treasuries feature.
- [optional] Write a ledger VM to support proof generation.