From def49e7ddfb068324d87a3001088742de5cb8d2c Mon Sep 17 00:00:00 2001 From: Thales Date: Sun, 4 May 2025 23:12:44 -0300 Subject: [PATCH] feat: fix test runner. Working version to get_amount_out --- protocol-testing/Cargo.lock | 101 +++++++++++++++++++++++++--- protocol-testing/Cargo.toml | 4 +- protocol-testing/src/config.rs | 2 +- protocol-testing/src/test_runner.rs | 63 +++++++++-------- protocol-testing/src/tycho_rpc.rs | 70 +++++++++++++------ 5 files changed, 178 insertions(+), 62 deletions(-) diff --git a/protocol-testing/Cargo.lock b/protocol-testing/Cargo.lock index 19cef25..9fdfdc8 100644 --- a/protocol-testing/Cargo.lock +++ b/protocol-testing/Cargo.lock @@ -82,6 +82,8 @@ dependencies = [ "alloy-rpc-client", "alloy-rpc-types", "alloy-serde", + "alloy-signer", + "alloy-signer-local", "alloy-transport", "alloy-transport-http", ] @@ -2078,6 +2080,18 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "dialoguer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +dependencies = [ + "console", + "shell-words", + "tempfile", + "zeroize", +] + [[package]] name = "dialoguer" version = "0.11.0" @@ -2292,6 +2306,30 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enum_delegate" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8ea75f31022cba043afe037940d73684327e915f88f62478e778c3de914cd0a" +dependencies = [ + "enum_delegate_lib", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "enum_delegate_lib" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1f6c3800b304a6be0012039e2a45a322a093539c45ab818d9e6895a39c90fe" +dependencies = [ + "proc-macro2", + "quote", + "rand 0.8.5", + "syn 1.0.109", +] + [[package]] name = "enumn" version = "0.1.14" @@ -2374,7 +2412,7 @@ dependencies = [ "serde_json", "sha3", "thiserror 1.0.69", - "uint", + "uint 0.9.5", ] [[package]] @@ -2405,7 +2443,7 @@ dependencies = [ "impl-serde", "primitive-types", "scale-info", - "uint", + "uint 0.9.5", ] [[package]] @@ -2473,6 +2511,17 @@ dependencies = [ "ws_stream_wasm", ] +[[package]] +name = "evm_ekubo_sdk" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea508be2fca38161c011c360afd34e9a6df2579273cd77b8e51aba11f35f59db" +dependencies = [ + "insta", + "num-traits", + "uint 0.10.0", +] + [[package]] name = "eyre" version = "0.6.12" @@ -2660,7 +2709,7 @@ dependencies = [ "alloy-sol-types", "base64 0.22.1", "chrono", - "dialoguer", + "dialoguer 0.11.0", "ecdsa", "eyre", "forge-script-sequence", @@ -3912,6 +3961,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "insta" +version = "1.43.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "154934ea70c58054b556dd430b99a98c2a7ff5309ac9891597e339b5c28f4371" +dependencies = [ + "console", + "once_cell", + "similar", +] + [[package]] name = "instant" version = "0.1.13" @@ -4938,7 +4998,7 @@ dependencies = [ "impl-rlp", "impl-serde", "scale-info", - "uint", + "uint 0.9.5", ] [[package]] @@ -5089,7 +5149,7 @@ dependencies = [ "tracing", "tracing-subscriber", "tycho-client", - "tycho-core", + "tycho-common", "tycho-simulation", ] @@ -7154,7 +7214,9 @@ dependencies = [ [[package]] name = "tycho-client" -version = "0.61.1" +version = "0.66.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f6fa393d638764970a7f6ae5e0890cdb7af8a5e7acf7a6182e33c72a4aa673" dependencies = [ "anyhow", "async-trait", @@ -7173,13 +7235,15 @@ dependencies = [ "tracing", "tracing-appender", "tracing-subscriber", - "tycho-core", + "tycho-common", "uuid 1.15.1", ] [[package]] -name = "tycho-core" -version = "0.61.1" +name = "tycho-common" +version = "0.66.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d4c3669a1169a4a86139553efa537bbf35378689beefdd8be706a1fe924d5d" dependencies = [ "anyhow", "async-trait", @@ -7201,13 +7265,16 @@ dependencies = [ [[package]] name = "tycho-simulation" -version = "0.77.1" +version = "0.99.1" dependencies = [ "alloy", "alloy-primitives", "alloy-sol-types", "chrono", + "dialoguer 0.10.4", "dotenv", + "enum_delegate", + "evm_ekubo_sdk", "foundry-config", "foundry-evm", "futures 0.3.31", @@ -7228,7 +7295,7 @@ dependencies = [ "tokio-stream", "tracing", "tycho-client", - "tycho-core", + "tycho-common", "uuid 1.15.1", ] @@ -7286,6 +7353,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unarray" version = "0.1.4" diff --git a/protocol-testing/Cargo.toml b/protocol-testing/Cargo.toml index 09fbf0e..04d1b20 100644 --- a/protocol-testing/Cargo.toml +++ b/protocol-testing/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" # Logging & Tracing tracing = "0.1.37" # Tycho dependencies -tycho-core = { path = "../../tycho-indexer/tycho-core", package = "tycho-core" } -tycho-client = { path = "../../tycho-indexer/tycho-client", package = "tycho-client" } +tycho-common = "0.66.4" +tycho-client = "0.66.4" tycho-simulation = { path = "../../tycho-simulation", features = ["evm"] } # EVM dependencies alloy = { version = "0.5.4", features = ["arbitrary", "json", "dyn-abi", "sol-types", "contract", "provider-http"] } diff --git a/protocol-testing/src/config.rs b/protocol-testing/src/config.rs index 8774a51..6b5c262 100644 --- a/protocol-testing/src/config.rs +++ b/protocol-testing/src/config.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use colored::Colorize; use serde::{Deserialize, Serialize}; use similar::{ChangeTag, TextDiff}; -use tycho_core::{dto::ProtocolComponent, Bytes}; +use tycho_common::{dto::ProtocolComponent, Bytes}; /// Represents a ProtocolComponent with its main attributes #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/protocol-testing/src/test_runner.rs b/protocol-testing/src/test_runner.rs index aba2477..1259d76 100644 --- a/protocol-testing/src/test_runner.rs +++ b/protocol-testing/src/test_runner.rs @@ -8,7 +8,7 @@ use figment::{ use postgres::{Client, Error, NoTls}; use tokio::runtime::Runtime; use tracing::{debug, info}; -use tycho_core::{ +use tycho_common::{ dto::{Chain, ProtocolComponent, ResponseAccount, ResponseProtocolState}, Bytes, }; @@ -162,12 +162,17 @@ fn validate_state( .block_on(tycho_client.get_protocol_components(protocol_system, chain)) .expect("Failed to get protocol components"); + let expected_ids = expected_components + .iter() + .map(|c| c.base.id.clone()) + .collect::>(); + let protocol_states = rt - .block_on(tycho_client.get_protocol_state(protocol_system, chain)) + .block_on(tycho_client.get_protocol_state(protocol_system, expected_ids, chain)) .expect("Failed to get protocol state"); let vm_storages = rt - .block_on(tycho_client.get_contract_state(Vec::new(), protocol_system, chain)) + .block_on(tycho_client.get_contract_state(protocol_system, chain)) .expect("Failed to get contract state"); // Create a map of component IDs to components for easy lookup @@ -200,7 +205,7 @@ fn validate_state( let component = components_by_id .get(&component_id) - .unwrap(); + .expect("Failed to get component from Tycho"); let diff = expected_component .base @@ -269,7 +274,7 @@ fn validate_state( // Step 3: Run Tycho Simulation let mut decoder = TychoStreamDecoder::new(); - decoder.register_decoder::>("test_protocol", None); + decoder.register_decoder::>("test_protocol"); // Mock a stream message, with only a Snapshot and no deltas let mut states: HashMap = HashMap::new(); @@ -286,16 +291,17 @@ fn validate_state( .into_iter() .map(|x| (x.address.clone(), x)) .collect(); - let snapshot = Snapshot { states, vm_storage }; + let bytes = [0u8; 32]; + let state_msgs: HashMap = HashMap::from([( String::from("test_protocol"), StateSyncMessage { header: Header { - hash: Default::default(), + hash: Bytes::from(bytes), number: stop_block, - parent_hash: Default::default(), + parent_hash: Bytes::from(bytes), revert: false, }, snapshots: snapshot, @@ -304,14 +310,12 @@ fn validate_state( }, )]); - let all_tokens = rt.block_on(load_all_tokens( - "localhost:4242", - true, - None, - Chain::Ethereum.into(), - None, - None, - )); + let all_tokens = rt + .block_on(tycho_client.get_tokens(Chain::Ethereum, None, None)) + .expect("Failed to get tokens"); + info!("Loaded {} tokens", all_tokens.len()); + + rt.block_on(decoder.set_tokens(all_tokens)); let mut pairs: HashMap> = HashMap::new(); @@ -329,6 +333,9 @@ fn validate_state( // This is where we get blocked. Currently, Tycho Simulation expects the runtime to be // prebuild and accessible from TychoSim - we should allow passing it when parsing the block + + // TODO: Since we don't have balances on the VM State, we could try to use Limits, otherwise ask the user + // to specify a set of values on the YAML file. for (id, state) in block_msg.states.iter() { if let Some(tokens) = pairs.get(id) { let formatted_token_str = format!("{:}/{:}", &tokens[0].symbol, &tokens[1].symbol); @@ -338,18 +345,18 @@ fn validate_state( .map(|price| println!("Spot price {:?}: {:?}", formatted_token_str, price)) .map_err(|e| eprintln!("Error calculating spot price for Pool {:?}: {:?}", id, e)) .ok(); - let amount_in = - BigUint::from(1u32) * BigUint::from(10u32).pow(tokens[0].decimals as u32); - state - .get_amount_out(amount_in, &tokens[0], &tokens[1]) - .map(|result| { - println!( - "Amount out for trading 1 {:?} -> {:?}: {:?} (takes {:?} gas)", - &tokens[0].symbol, &tokens[1].symbol, result.amount, result.gas - ) - }) - .map_err(|e| eprintln!("Error calculating amount out for Pool {:?}: {:?}", id, e)) - .ok(); + // let amount_in = + // BigUint::from(1u32) * BigUint::from(10u32).pow(tokens[0].decimals as u32); + // state + // .get_amount_out(amount_in, &tokens[0], &tokens[1]) + // .map(|result| { + // println!( + // "Amount out for trading 1 {:?} -> {:?}: {:?} (takes {:?} gas)", + // &tokens[0].symbol, &tokens[1].symbol, result.amount, result.gas + // ) + // }) + // .map_err(|e| eprintln!("Error calculating amount out for Pool {:?}: {:?}", id, + // e)) .ok(); } } } diff --git a/protocol-testing/src/tycho_rpc.rs b/protocol-testing/src/tycho_rpc.rs index ecd9db6..2928b6b 100644 --- a/protocol-testing/src/tycho_rpc.rs +++ b/protocol-testing/src/tycho_rpc.rs @@ -1,13 +1,17 @@ -use std::{error::Error as StdError, fmt}; +use std::{collections::HashMap, error::Error as StdError, fmt}; +use tracing::info; use tycho_client::{rpc::RPCClient, HttpRPCClient}; -use tycho_core::{ +use tycho_common::{ dto::{ - Chain, ProtocolComponent, ProtocolComponentsRequestBody, ResponseAccount, - ResponseProtocolState, VersionParam, + Chain, PaginationParams, ProtocolComponent, ProtocolComponentsRequestBody, ResponseAccount, + ResponseProtocolState, StateRequestBody, VersionParam, }, models::Address, + Bytes, }; +use tycho_common::dto::ResponseToken; +use tycho_simulation::models::Token; /// Custom error type for RPC operations #[derive(Debug)] @@ -74,18 +78,18 @@ impl TychoClient { pub async fn get_protocol_state( &self, protocol_system: &str, + component_ids: Vec, chain: Chain, ) -> Result, RpcError> { let chunk_size = 100; let concurrency = 1; - let ids: &[String] = &[]; - let version: tycho_core::dto::VersionParam = VersionParam::default(); + let version: tycho_common::dto::VersionParam = VersionParam::default(); let protocol_states = self .http_client .get_protocol_states_paginated( chain, - ids, + &component_ids, protocol_system, true, &version, @@ -100,27 +104,53 @@ impl TychoClient { /// Gets contract state from the RPC server pub async fn get_contract_state( &self, - contract_ids: Vec
, protocol_system: &str, chain: Chain, ) -> Result, RpcError> { - // Pagination parameters - let chunk_size = 100; - let concurrency = 1; - let version: tycho_core::dto::VersionParam = VersionParam::default(); + let request_body = StateRequestBody { + contract_ids: None, + protocol_system: protocol_system.to_string(), + version: Default::default(), + chain, + pagination: PaginationParams { page: 0, page_size: 100 }, + }; let contract_states = self .http_client - .get_contract_state_paginated( - chain, - &contract_ids, - protocol_system, - &version, - chunk_size, - concurrency, - ) + .get_contract_state(&request_body) .await?; Ok(contract_states.accounts) } + + pub async fn get_tokens( + &self, + chain: Chain, + min_quality: Option, + max_days_since_last_trade: Option, + ) -> Result, RpcError> { + info!("Loading tokens from Tycho..."); + + #[allow(clippy::mutable_key_type)] + let res = self + .http_client + .get_all_tokens(chain, min_quality, max_days_since_last_trade, 3_000) + .await? + .into_iter() + .map(|token| { + let mut token_clone: ResponseToken = token.clone(); + // Set default gas if empty + // TODO: Check if this interferes with simulation logic + if token_clone.gas.is_empty() { + token_clone.gas = vec![Some(44000_u64)]; + } + ( + token_clone.address.clone(), + token_clone.try_into().expect("Failed to convert token"), + ) + }) + .collect::>(); + + Ok(res) + } }