Skip to content

Commit 2a379cd

Browse files
authored
feat: add an e2e example with on-chain verification (#45)
1 parent f429a09 commit 2a379cd

File tree

12 files changed

+214
-23
lines changed

12 files changed

+214
-23
lines changed

.github/workflows/pr.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
strategy:
2727
matrix:
2828
example:
29-
- uniswap
29+
- uniswap-basic
3030
- multiplexer
3131
- verify-quorum
3232
- example-deploy

Cargo.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,18 @@ Then, from the root directory of the repository, run
140140
```RUST_LOG=info cargo run --bin [example] --release```
141141

142142
where `[example]` is one of the following
143-
* `uniswap`
143+
* `uniswap-basic`
144144
* Fetches the price of the UNI / WETH pair on Uniswap V3. By default, this does not generate a proof.
145145
* Running `RUST_LOG=info cargo run --bin [example] --release -- --prove` will generate a plonk proof. This requires
146146
significant computational resources, so we recommend using the [SP1 Prover network](https://docs.succinct.xyz/docs/generating-proofs/prover-network).
147147
* Outputs a file called [plonk-fixture.json](examples/uniswap/contracts/src/fixtures/plonk-fixture.json), which contains everything you need to verify the proof on chain.
148-
* To see an example of on-chain verification, take a look at the [contracts](./examples/uniswap/contracts/) directory.
148+
* `uniswap-onchain-verify`
149+
* Fetches the price of the WETH / USDC pair on Uniswap V3 on Sepolia.
150+
* This example demonstrate on-chain verification, with the following variations:
151+
* By default, the `blockhash()` opcode is used, allowing to verify up to 256 blocks old.
152+
* If you provides a Beacon RPC endpoint with the `--beacon-sepolia-rpc-url` argument, the proof will be verified on chain with the beacon root using [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788), up to 8191 blocks old (~27h).
153+
* The window can even be extended up to the Cancun hardfork by chaining beacon roots (see the `--reference-block` argument).
154+
* The contract can be found at the [contracts](./examples/uniswap/contracts/) directory.
149155
* `multiplexer`
150156
* Calls a contract that fetches the prices of many different collateral assets.
151157
* The source code of this contract is found [here](./examples/multiplexer/ZkOracleHelper.sol).

crates/client-executor/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use revm::{
1818
};
1919
use revm_primitives::{Address, Bytes, TxKind, B256, U256};
2020
use rsp_client_executor::io::{TrieDB, WitnessInput};
21-
use rsp_primitives::genesis::Genesis;
2221

2322
mod anchor;
2423
pub use anchor::{
@@ -30,6 +29,8 @@ pub use anchor::{
3029
mod errors;
3130
pub use errors::ClientError;
3231

32+
pub use rsp_primitives::genesis::Genesis;
33+
3334
/// Input to a contract call.
3435
///
3536
/// Can be used to call an existing contract or create a new one. If used to create a new one,

examples/uniswap/client/src/main.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ sp1_zkvm::entrypoint!(main);
44
use alloy_primitives::{address, Address};
55
use alloy_sol_macro::sol;
66
use alloy_sol_types::SolValue;
7-
use sp1_cc_client_executor::{io::EvmSketchInput, ClientExecutor, ContractInput};
7+
use sp1_cc_client_executor::{io::EvmSketchInput, ClientExecutor, ContractInput, Genesis};
88
sol! {
99
/// Simplified interface of the IUniswapV3PoolState interface.
1010
interface IUniswapV3PoolState {
@@ -14,21 +14,28 @@ sol! {
1414
}
1515

1616
/// Address of Uniswap V3 pool.
17-
const CONTRACT: Address = address!("1d42064Fc4Beb5F8aAF85F4617AE8b3b5B8Bd801");
17+
const MAINNET_POOL_CONTRACT: Address = address!("1d42064Fc4Beb5F8aAF85F4617AE8b3b5B8Bd801");
18+
const SEPOLIA_POOL_CONTRACT: Address = address!("3289680dD4d6C10bb19b899729cda5eEF58AEfF1");
1819

1920
pub fn main() {
2021
// Read the state sketch from stdin. Use this during the execution in order to
2122
// access Ethereum state.
2223
let state_sketch_bytes = sp1_zkvm::io::read::<Vec<u8>>();
2324
let state_sketch = bincode::deserialize::<EvmSketchInput>(&state_sketch_bytes).unwrap();
2425

26+
let pool_contract = match state_sketch.genesis {
27+
Genesis::Mainnet => MAINNET_POOL_CONTRACT,
28+
Genesis::Sepolia => SEPOLIA_POOL_CONTRACT,
29+
_ => unimplemented!(),
30+
};
31+
2532
// Initialize the client executor with the state sketch.
2633
// This step also validates all of the storage against the provided state root.
2734
let executor = ClientExecutor::new(&state_sketch).unwrap();
2835

2936
// Execute the slot0 call using the client executor.
3037
let slot0_call = IUniswapV3PoolState::slot0Call {};
31-
let call = ContractInput::new_call(CONTRACT, Address::default(), slot0_call);
38+
let call = ContractInput::new_call(pool_contract, Address::default(), slot0_call);
3239
let public_vals = executor.execute(call).unwrap();
3340

3441
// Commit the abi-encoded output.

examples/uniswap/contracts/src/UniswapCall.sol

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,14 @@
22
pragma solidity ^0.8.20;
33

44
import {ISP1Verifier} from "@sp1-contracts/ISP1Verifier.sol";
5-
6-
/// The public values returned by the contract call execution.
7-
struct ContractPublicValues {
8-
bytes32 blockHash;
9-
address callerAddress;
10-
address contractAddress;
11-
bytes contractCalldata;
12-
bytes contractOutput;
13-
}
5+
import {ContractPublicValues, ContractCall} from "@sp1-contracts/v4.0.0-rc.3/utils/ContractCall.sol";
146

157
/// @title SP1 UniswapCall.
16-
/// @notice This contract implements a simple example of verifying the proof of call to a smart
8+
/// @notice This contract implements a simple example of verifying the proof of call to a smart
179
/// contract.
1810
contract UniswapCall {
11+
using ContractCall for ContractPublicValues;
12+
1913
/// @notice The address of the SP1 verifier contract.
2014
address public verifier;
2115

@@ -37,7 +31,9 @@ contract UniswapCall {
3731
{
3832
ISP1Verifier(verifier).verifyProof(uniswapCallProgramVKey, _publicValues, _proofBytes);
3933
ContractPublicValues memory publicValues = abi.decode(_publicValues, (ContractPublicValues));
34+
publicValues.verify();
35+
4036
uint160 sqrtPriceX96 = abi.decode(publicValues.contractOutput, (uint160));
4137
return sqrtPriceX96;
4238
}
43-
}
39+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"vkey": "0x006df5a20ab3395bf84fdc4985d6192e7064116a8a9038ebc804f97a48cfb182",
3-
"publicValues": "0x00000000000000000000000000000000000000000000000000000000000000204804cee837fd95195099e56fc5ed546c5982c751d137c4ec3dfed763c9bb491e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d42064fc4beb5f8aaf85f4617ae8b3b5b8bd80100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000043850c7bd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000cdebb6337bcb5fd82c7f27affffffffffffffffffffffffffffffffffffffffffffffffffffffffffff165f0000000000000000000000000000000000000000000000000000000000000071000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
4-
"proof": "0x1b34fe1100d29922b9e027076c956a91f32d155d523262525e67d428abb24cb3b62229a11dfc1e164fc7a0a51269ce32918fb6188406921ffb995b8bccffd1d7d4a2d98f0b473858b5656d9a4ce20a2f0016c4853d2f5d9600903d4390961c18fbc932fe03cc0aeba69cb3a0fdadf479cb0d99d6f4c69fd7aba46684e20dda3be066baf9287dead39b7fd91a45b25b461043cf43651fb8bfd3152c1f4df548a6cc17994c29a4e98e954d80573cdcf1d919e64ba726a8f99923f5dbc588b55ba6f8963dc01bbb726544f623aa112641fada4a2f409e3736b6a4a20bc4d570ec19155e6774296fce6ccb84b12d483a2e4a3de50129c3c09cd0221967f60cbdbb27a990b4222e2665b003df069430a724ddca95e22ee4afe2e4ee71e226399d660e70a60dc0031b8a4c66ffb9ebb81f70f24cac5bb5114b809808b1bebae801446468c60e0127fb8dab4cdf91bb0c43ddf3517faac2fa937bf081983e3bb1ac4a79d8889fd62ee130ee5c599683ff5b80a84dcd30fbd2bf7848aead2148b5ffb208093e9c3404146c9008801b22087be4060a0ae9778a4f772cf6da986733b252b9126c8d7c2a7b0cea4aebcd223b740bf2b7ba9d328d20e3f55fa3f91c50918ab9596ea0c402002adaec79b7c241ca9f0b42b6b58ad0388d94eb3961c3585bf4e71fd344ca1ec4985048a2edf8abbee3741dd7d09be79a35bb01f8edfea4dd52eced8e58c023d7f63b58d0ed4b571c3c7d4e81e66cd79b8616d4288fb2e1062f7740cc545403a49836074385144ccbb5758787d69bf476f96cb64d31837db471652d30f0950bd238b3ed1ca453c488d76431e5b6559c0464cde4f3fb3b590de139480aac381d815ccfc10b141441336ebc5041af8db6236192ea49b316663602ba012d5fce1a37908a4bbf343a6860b2fb319dfc47df8bea295416c91714df152ce417841b19a550e285e4fac811e602be4537f6aee7ae3e04262ad0c55ea808113d38591505a1fb52f276c3490cc3d34f3f97749d89f7a7f161e3c9fc0a5efce265f219a603f6a689e9598cd28e601f276db9bcb9f7a6f0a9caa70c6734e758d221f026ce1c71c8bb23a69ea2cfa0a11e6d6c61790284fccf78562597eb92a94f40eb2a0406ee7d661eeb3f8bb8c2f54293ac8a0be8870fdab6f27cc584e9ec8d63bf6dfb182279cbf3749cec04b6a16ae7a9af4ffa5ccad5917789bb6f8538e23600a2d7"
2+
"vkey": "0x00976b3c18f25b95bc6abc51747acd5c6a4a54470e9af5388e05ffcda0c664cd",
3+
"publicValues": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000013a54c04804cee837fd95195099e56fc5ed546c5982c751d137c4ec3dfed763c9bb491e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d42064fc4beb5f8aaf85f4617ae8b3b5b8bd80100000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000043850c7bd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000cdebb6337bcb5fd82c7f27affffffffffffffffffffffffffffffffffffffffffffffffffffffffffff165f0000000000000000000000000000000000000000000000000000000000000071000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
4+
"proof": "0x1b34fe111796212ededc6111f5ebc8b42c35e8be9561919653288b2028783a21c238167112cc9c3efa3ba040b2a357a5d9f9c7fce2146f74450d519176971bf238d5033202c0126857efcf4fb1bbad6caeb3479f0d7543e0a600ffdff922111c89aee05f1e07115ec5db1c09f3c25f2d81e74e021d5b75e29ab264dbd805f759770373301c82fc96e4e956896cb8223964cd320c07488e2015a4c19cda1f453afaf4407901519ca5f17151bef6718c657496cf43a96f549dd42d8e07ca6685d3ff2d2628027a509099846dba11b271a382652defe1efe585cfc6171361588462ea140c8c16f9430c9ec9baf7a64e904c3732aadd150faac6fec6e80d1e529706a0ad60aa072ea175ac6fb9745e5592f3e3b87ffe0af80cc3fb35f0e9636546e66a128d4a08c1e722e2beec33b2b579e336a8d32a2dc8fa2942f8c46e0997476b213c78e500670ba2429778a3254b256534a4041808dd07ee3b29f7a914c8870ce91890d724e0ac5d9204238cd86a47ad09617031361bfcb6b75ecb3608e1a79bd46c9c4c130ee9edc143ff6fd2e7319d8ec06a738a20b84e4fe8e9aad6a712149c9cd47901b3584463aba91c6c134ebfa4ebbde355ad83c2d5a77cefc80c73ad1efa3e5c2e66c0537d1a8d6126745328f90c4bc9fe984c29e435334bdda2320653f2a6b41288e406623d9af0fa8b1d68630121ba17e0c399ae3497caad5e4b320866e2ce236c4e7bef70ea9b6918281fc186ab45cfaa28c585102a982a8fc1ec02f652a51db10ddc68fff2d2dbdd38f4e4cd9b8db3db27251eae41655627c9fb1c53270d1df70b60d0a3e1934468cdef9152de88bfbd763b4f4a196f8851dcb09420df9624e989259d2b32c0dd5beb3aef3663c844a35e45ee8367ef7b47159ad872481b1e089dc5d719769450b13b834a932040c5e928d22458038aaa13caba3569d6b1112954bb43ddd0e614bc05bed91b13cfd800e5902642da9093c07a7157d2963410e01e2382e87db8f325b9241a8f22848ce5b11fa82e41a1e5de3070aa0200ca1c76dc199b4ea6594db37c68d7ebf063b80bff90dcc7cd7bc7ddea61167d360225dc60994d3d2fe35ed3e55a8dc5686e1e62b5f561ac67033a9ae73d21d47ec50a08c02355319516065e278a00f01cac6d6904d129cce3223e96f2095b0220ca1c1d2e49f3883c536d822c14a5bb562308c8dbf1df566ca81f7646355173f842"
55
}

examples/uniswap/contracts/test/UniswapCall.t.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {Test, console} from "forge-std/Test.sol";
55
import {stdJson} from "forge-std/StdJson.sol";
66
import {SP1VerifierGateway} from "@sp1-contracts/SP1VerifierGateway.sol";
77
import {UniswapCall} from "../src/UniswapCall.sol";
8-
import "forge-std/console.sol";
98

109
struct SP1ProofFixtureJson {
1110
bytes proof;
@@ -31,6 +30,9 @@ contract UniswapCallTest is Test {
3130
SP1ProofFixtureJson memory fixture = loadFixture();
3231
verifier = address(new SP1VerifierGateway(address(1)));
3332
uniswapCall = new UniswapCall(verifier, fixture.vkey);
33+
34+
vm.roll(20600100);
35+
vm.setBlockhash(20600000, 0x4804cee837fd95195099e56fc5ed546c5982c751d137c4ec3dfed763c9bb491e);
3436
}
3537

3638
function test_ValidUniswapCallProof() public {

examples/uniswap/host/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,21 @@ version = "0.1.0"
33
name = "uniswap"
44
edition = "2021"
55

6+
[[bin]]
7+
name = "uniswap-basic"
8+
path = "src/basic.rs"
9+
10+
[[bin]]
11+
name = "uniswap-onchain-verify"
12+
path = "src/onchain_verify.rs"
13+
614
[dependencies]
715
# workspace
816
sp1-cc-host-executor = { path = "../../../crates/host-executor" }
917
sp1-cc-client-executor = { path = "../../../crates/client-executor" }
1018

19+
alloy-contract.workspace = true
20+
alloy-node-bindings.workspace = true
1121
alloy-primitives.workspace = true
1222
alloy-sol-types.workspace = true
1323
alloy-rpc-types.workspace = true

0 commit comments

Comments
 (0)