Trustless oracle of historical Uniswap v3 TWAP using ZK
Clone this repository (and git submodule dependencies) with
git clone --recurse-submodules -j8 https://github.com/axiom-crypto/uniswap-v3-oracles.git
cd uniswap-v3-oracles
Optional: symlink existing params
folder to circuits/params
to avoid regenerating NOT FOR PRODUCTION trusted setup files. (It's fine to ignore this if you don't know what it means.)
If you want to use the same universal trusted setup as the one we use, so that the SNARK verifier matches the one deployed on mainnet, then you can download the following trusted setup files:
# start in uniswap-v3-oracles directory
cd circuits
mkdir -p params
wget https://axiom-crypto.s3.amazonaws.com/params/kzg_bn254_18.srs -O params/kzg_bn254_18.srs
wget https://axiom-crypto.s3.amazonaws.com/params/kzg_bn254_23.srs -O params/kzg_bn254_23.srs
cd ..
cp .env.example .env
Fill in .env
with your INFURA_ID
. In order for Forge to access ETH_RPC_URL
for testing, we need to export .env
:
set -a
source .env
set +a
We use foundry for smart contract development and testing. You can follow these instructions to install it.
We fork mainnet for tests, so make sure that .env
variables have been exported.
After installing foundry
, in the contracts
directory, run:
forge install
forge test
For verbose logging of events and gas tracking, run
forge test -vvvv
We can test contract deployment with a local fork of Ethereum mainnet using Foundry anvil. To start the local anvil node by forking mainnet from a specified block number, make sure .env
is exported, then run:
bash script/start_anvil.sh
in the contracts
directory. Now that anvil is running, we can deploy both the SNARK verifier and the UniswapV3Oracle
contract by running
# MAKE SURE .env IS EXPORTED
bash script/deploy_local.sh
from the contracts
directory. This will print out verbose logs of the deployment, including the addresses of the two deployed contracts (SNARK verifier and UniswapV3Oracle
).
Note that UniswapV3Oracle.s.sol
is using deployed_verifier.yul
as the verifier contract. This depends on the universal trusted setup used, so you may need to change it for local testing.
In the circuits
directory, run:
cargo run --bin v3_twap_proof --release -- --pool <UNISWAP V3 POOL ADDRESS> --start <TWAP START BLOCK NUMBER> --end <TWAP END BLOCK NUMBER>
# For example:
# cargo run --bin v3_twap_proof --release -- --pool 0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640 --start 12376729 --end 16416686
If this is the first time running, it will generate proving keys (and trusted setup files if they don't exist already).
The proof calldata is written as a hex string to circuits/data/mainnet_*_*_*_evm.calldata
.
You can pass an optional --create-contract
flag to the binary for it to produce the Yul code for the on-chain contract to verify the ZK proof. Note that this verifier depends on the universal trusted setup you provide in the params
directory. The trusted setup auto-generated by the binary is UNSAFE. See here for more about trusted setups and how to get a trusted setup that was actually created via a multi-party computation.
We provide the Yul code for the verifier contract generated using a trusted setup derived from the perpetual powers of tau ceremony shared by Semaphore and Hermez.
Note: The proof generation requires up to 40GB of RAM to complete. If you do not have enough RAM, you can set up swap to compensate (this is done automatically on Macs) at the tradeoff of slower runtimes.
See here, for a technical overview of what the circuit is doing.
For convenience we provide an implementation of a server that receives POST JSON requests for v3 TWAP proofs. The benefit of the server is that it holds the proving keys in memory and does not re-read from file each time. To use the server you must have already generated a trusted setup and the proving keys (using the v3_twap_proof
binary): this is primarily a safety precaution.
This is provided as a developer tool only. DO NOT USE FOR PRODUCTION. To build the server binary, run
cargo build --bin v3_twap_server --features "server" --no-default-features --release
The binary is located in ./target/release/v3_twap_server
. You must start the binary from the circuits
directory for file paths to work appropriately. Running the binary will start the server on localhost:8000
.
Once the server is running, you can query it via
curl -X POST -i "http://localhost:8000/uniswap-v3" -H "Content-Type: application/json" -d @data/task.t.json
where task.t.json
is a JSON file with an example request.