From c45b89eb3e4bcb283a35f12aa0107e4924115e09 Mon Sep 17 00:00:00 2001 From: zizou <111426680+flopell@users.noreply.github.com> Date: Tue, 31 Dec 2024 09:02:05 +0100 Subject: [PATCH] test(uniswap_v4): add a test for Uniswap V4 simulation This test relies on a Sepolia state that was indexed with version `0.1.0` of the UniswapV4 Substreams module. --- .../assets/sepolia_state_block_7239119.json | 39 +++++++++++ src/evm/protocol/uniswap_v4/state.rs | 64 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 src/evm/protocol/uniswap_v4/assets/sepolia_state_block_7239119.json diff --git a/src/evm/protocol/uniswap_v4/assets/sepolia_state_block_7239119.json b/src/evm/protocol/uniswap_v4/assets/sepolia_state_block_7239119.json new file mode 100644 index 00000000..d8ebfd73 --- /dev/null +++ b/src/evm/protocol/uniswap_v4/assets/sepolia_state_block_7239119.json @@ -0,0 +1,39 @@ +{ + "state": { + "component_id": "0x12e4510bc312b3e459340cbee3e281d81671083f56161c0c6673dee018cab4d0", + "attributes": { + "tick": "0x00", + "balance_owner": "0x8c4bcbe6b9ef47855f97e675296fa3f6fafa5f1a", + "sqrt_price_x96": "0x01000000000000000000000000", + "protocol_fees/one2zero": "0x00", + "fee": "0x0bb8", + "liquidity": "0x09184f0b3680", + "ticks/887220/net-liquidity": "0xf6e7b0f4c980", + "ticks/-887220/net-liquidity": "0x09184f0b3680", + "protocol_fees/zero2one": "0x00" + }, + "balances": { + "0x647e32181a64f4ffd4f0b0b4b052ec05b277729c": "0x09184f0b3680", + "0xe390a1c311b26f14ed0d55d3b0261c2320d15ca5": "0x09184f0b3680" + } + }, + "component": { + "id": "0x12e4510bc312b3e459340cbee3e281d81671083f56161c0c6673dee018cab4d0", + "protocol_system": "uniswap_v4", + "protocol_type_name": "uniswap_v4_pool", + "chain": "ethereum", + "tokens": [ + "0x647e32181a64f4ffd4f0b0b4b052ec05b277729c", + "0xe390a1c311b26f14ed0d55d3b0261c2320d15ca5" + ], + "contract_ids": [], + "static_attributes": { + "hooks": "0x0000000000000000000000000000000000000000", + "pool_id": "0x12e4510bc312b3e459340cbee3e281d81671083f56161c0c6673dee018cab4d0", + "tick_spacing": "0x3c" + }, + "change": "Creation", + "creation_tx": "0x3d458bfd841ee29b03958b19f737255286c9ce9b4026220c47f8a015b8ed6d1a", + "created_at": "2024-10-31T14:23:12" + } +} diff --git a/src/evm/protocol/uniswap_v4/state.rs b/src/evm/protocol/uniswap_v4/state.rs index cf3bd95c..e0c93930 100644 --- a/src/evm/protocol/uniswap_v4/state.rs +++ b/src/evm/protocol/uniswap_v4/state.rs @@ -382,9 +382,14 @@ mod tests { str::FromStr, }; + use num_bigint::ToBigUint; + use num_traits::FromPrimitive; + use serde_json::Value; + use tycho_client::feed::synchronizer::ComponentWithState; use tycho_core::hex_bytes::Bytes; use super::*; + use crate::protocol::models::TryFromWithBlock; #[test] fn test_delta_transition() { @@ -440,4 +445,63 @@ mod tests { 9800 ); } + + #[tokio::test] + /// Compares a quote that we got from the UniswapV4 Quoter contract on Sepolia with a simulation + /// using Tycho-simulation and a state extracted with Tycho-indexer + async fn test_swap_sim() { + let data_str = include_str!("assets/sepolia_state_block_7239119.json"); + let data: Value = serde_json::from_str(data_str).expect("Failed to parse JSON"); + + let state: ComponentWithState = serde_json::from_value(data) + .expect("Expected json to match ComponentWithState structure"); + + let usv4_state = + UniswapV4State::try_from_with_block(state, Default::default(), &Default::default()) + .await + .unwrap(); + + let t0 = Token::new( + "0x647e32181a64f4ffd4f0b0b4b052ec05b277729c", + 18, + "T0", + 10_000.to_biguint().unwrap(), + ); + let t1 = Token::new( + "0xe390a1c311b26f14ed0d55d3b0261c2320d15ca5", + 18, + "T0", + 10_000.to_biguint().unwrap(), + ); + + let res = usv4_state + .get_amount_out(BigUint::from_u64(1000000000000000000).unwrap(), &t0, &t1) + .unwrap(); + + // This amount comes from a call to the `quoteExactInputSingle` on the quoter contract on a + // sepolia node with these arguments + // ``` + // {"poolKey":{"currency0":"0x647e32181a64f4ffd4f0b0b4b052ec05b277729c","currency1":"0xe390a1c311b26f14ed0d55d3b0261c2320d15ca5","fee":"3000","tickSpacing":"60","hooks":"0x0000000000000000000000000000000000000000"},"zeroForOne":true,"exactAmount":"1000000000000000000","hookData":"0x"} + // ``` + // Here is the curl for it: + // + // ``` + // curl -X POST https://eth-sepolia.api.onfinality.io/public \ + // -H "Content-Type: application/json" \ + // -d '{ + // "jsonrpc": "2.0", + // "method": "eth_call", + // "params": [ + // { + // "to": "0xCd8716395D55aD17496448a4b2C42557001e9743", + // "data": "0xaa9d21cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000647e32181a64f4ffd4f0b0b4b052ec05b277729c000000000000000000000000e390a1c311b26f14ed0d55d3b0261c2320d15ca50000000000000000000000000000000000000000000000000000000000000bb8000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000" + // }, + // "0x6e75cf" + // ], + // "id": 1 + // }' + // ``` + let expected_amount = BigUint::from(9999909699895_u64); + assert_eq!(res.amount, expected_amount); + } }