feat: fix test runner. Working version to get_amount_out

This commit is contained in:
Thales
2025-05-04 23:12:44 -03:00
committed by Tamara
parent afd5527b15
commit def49e7ddf
5 changed files with 178 additions and 62 deletions

View File

@@ -82,6 +82,8 @@ dependencies = [
"alloy-rpc-client", "alloy-rpc-client",
"alloy-rpc-types", "alloy-rpc-types",
"alloy-serde", "alloy-serde",
"alloy-signer",
"alloy-signer-local",
"alloy-transport", "alloy-transport",
"alloy-transport-http", "alloy-transport-http",
] ]
@@ -2078,6 +2080,18 @@ dependencies = [
"unicode-xid", "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]] [[package]]
name = "dialoguer" name = "dialoguer"
version = "0.11.0" version = "0.11.0"
@@ -2292,6 +2306,30 @@ dependencies = [
"zeroize", "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]] [[package]]
name = "enumn" name = "enumn"
version = "0.1.14" version = "0.1.14"
@@ -2374,7 +2412,7 @@ dependencies = [
"serde_json", "serde_json",
"sha3", "sha3",
"thiserror 1.0.69", "thiserror 1.0.69",
"uint", "uint 0.9.5",
] ]
[[package]] [[package]]
@@ -2405,7 +2443,7 @@ dependencies = [
"impl-serde", "impl-serde",
"primitive-types", "primitive-types",
"scale-info", "scale-info",
"uint", "uint 0.9.5",
] ]
[[package]] [[package]]
@@ -2473,6 +2511,17 @@ dependencies = [
"ws_stream_wasm", "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]] [[package]]
name = "eyre" name = "eyre"
version = "0.6.12" version = "0.6.12"
@@ -2660,7 +2709,7 @@ dependencies = [
"alloy-sol-types", "alloy-sol-types",
"base64 0.22.1", "base64 0.22.1",
"chrono", "chrono",
"dialoguer", "dialoguer 0.11.0",
"ecdsa", "ecdsa",
"eyre", "eyre",
"forge-script-sequence", "forge-script-sequence",
@@ -3912,6 +3961,17 @@ dependencies = [
"generic-array", "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]] [[package]]
name = "instant" name = "instant"
version = "0.1.13" version = "0.1.13"
@@ -4938,7 +4998,7 @@ dependencies = [
"impl-rlp", "impl-rlp",
"impl-serde", "impl-serde",
"scale-info", "scale-info",
"uint", "uint 0.9.5",
] ]
[[package]] [[package]]
@@ -5089,7 +5149,7 @@ dependencies = [
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"tycho-client", "tycho-client",
"tycho-core", "tycho-common",
"tycho-simulation", "tycho-simulation",
] ]
@@ -7154,7 +7214,9 @@ dependencies = [
[[package]] [[package]]
name = "tycho-client" name = "tycho-client"
version = "0.61.1" version = "0.66.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84f6fa393d638764970a7f6ae5e0890cdb7af8a5e7acf7a6182e33c72a4aa673"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -7173,13 +7235,15 @@ dependencies = [
"tracing", "tracing",
"tracing-appender", "tracing-appender",
"tracing-subscriber", "tracing-subscriber",
"tycho-core", "tycho-common",
"uuid 1.15.1", "uuid 1.15.1",
] ]
[[package]] [[package]]
name = "tycho-core" name = "tycho-common"
version = "0.61.1" version = "0.66.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03d4c3669a1169a4a86139553efa537bbf35378689beefdd8be706a1fe924d5d"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -7201,13 +7265,16 @@ dependencies = [
[[package]] [[package]]
name = "tycho-simulation" name = "tycho-simulation"
version = "0.77.1" version = "0.99.1"
dependencies = [ dependencies = [
"alloy", "alloy",
"alloy-primitives", "alloy-primitives",
"alloy-sol-types", "alloy-sol-types",
"chrono", "chrono",
"dialoguer 0.10.4",
"dotenv", "dotenv",
"enum_delegate",
"evm_ekubo_sdk",
"foundry-config", "foundry-config",
"foundry-evm", "foundry-evm",
"futures 0.3.31", "futures 0.3.31",
@@ -7228,7 +7295,7 @@ dependencies = [
"tokio-stream", "tokio-stream",
"tracing", "tracing",
"tycho-client", "tycho-client",
"tycho-core", "tycho-common",
"uuid 1.15.1", "uuid 1.15.1",
] ]
@@ -7286,6 +7353,18 @@ dependencies = [
"static_assertions", "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]] [[package]]
name = "unarray" name = "unarray"
version = "0.1.4" version = "0.1.4"

View File

@@ -7,8 +7,8 @@ edition = "2021"
# Logging & Tracing # Logging & Tracing
tracing = "0.1.37" tracing = "0.1.37"
# Tycho dependencies # Tycho dependencies
tycho-core = { path = "../../tycho-indexer/tycho-core", package = "tycho-core" } tycho-common = "0.66.4"
tycho-client = { path = "../../tycho-indexer/tycho-client", package = "tycho-client" } tycho-client = "0.66.4"
tycho-simulation = { path = "../../tycho-simulation", features = ["evm"] } tycho-simulation = { path = "../../tycho-simulation", features = ["evm"] }
# EVM dependencies # EVM dependencies
alloy = { version = "0.5.4", features = ["arbitrary", "json", "dyn-abi", "sol-types", "contract", "provider-http"] } alloy = { version = "0.5.4", features = ["arbitrary", "json", "dyn-abi", "sol-types", "contract", "provider-http"] }

View File

@@ -3,7 +3,7 @@ use std::collections::HashMap;
use colored::Colorize; use colored::Colorize;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use similar::{ChangeTag, TextDiff}; use similar::{ChangeTag, TextDiff};
use tycho_core::{dto::ProtocolComponent, Bytes}; use tycho_common::{dto::ProtocolComponent, Bytes};
/// Represents a ProtocolComponent with its main attributes /// Represents a ProtocolComponent with its main attributes
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]

View File

@@ -8,7 +8,7 @@ use figment::{
use postgres::{Client, Error, NoTls}; use postgres::{Client, Error, NoTls};
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
use tracing::{debug, info}; use tracing::{debug, info};
use tycho_core::{ use tycho_common::{
dto::{Chain, ProtocolComponent, ResponseAccount, ResponseProtocolState}, dto::{Chain, ProtocolComponent, ResponseAccount, ResponseProtocolState},
Bytes, Bytes,
}; };
@@ -162,12 +162,17 @@ fn validate_state(
.block_on(tycho_client.get_protocol_components(protocol_system, chain)) .block_on(tycho_client.get_protocol_components(protocol_system, chain))
.expect("Failed to get protocol components"); .expect("Failed to get protocol components");
let expected_ids = expected_components
.iter()
.map(|c| c.base.id.clone())
.collect::<Vec<String>>();
let protocol_states = rt 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"); .expect("Failed to get protocol state");
let vm_storages = rt 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"); .expect("Failed to get contract state");
// Create a map of component IDs to components for easy lookup // Create a map of component IDs to components for easy lookup
@@ -200,7 +205,7 @@ fn validate_state(
let component = components_by_id let component = components_by_id
.get(&component_id) .get(&component_id)
.unwrap(); .expect("Failed to get component from Tycho");
let diff = expected_component let diff = expected_component
.base .base
@@ -269,7 +274,7 @@ fn validate_state(
// Step 3: Run Tycho Simulation // Step 3: Run Tycho Simulation
let mut decoder = TychoStreamDecoder::new(); let mut decoder = TychoStreamDecoder::new();
decoder.register_decoder::<EVMPoolState<PreCachedDB>>("test_protocol", None); decoder.register_decoder::<EVMPoolState<PreCachedDB>>("test_protocol");
// Mock a stream message, with only a Snapshot and no deltas // Mock a stream message, with only a Snapshot and no deltas
let mut states: HashMap<String, ComponentWithState> = HashMap::new(); let mut states: HashMap<String, ComponentWithState> = HashMap::new();
@@ -286,16 +291,17 @@ fn validate_state(
.into_iter() .into_iter()
.map(|x| (x.address.clone(), x)) .map(|x| (x.address.clone(), x))
.collect(); .collect();
let snapshot = Snapshot { states, vm_storage }; let snapshot = Snapshot { states, vm_storage };
let bytes = [0u8; 32];
let state_msgs: HashMap<String, StateSyncMessage> = HashMap::from([( let state_msgs: HashMap<String, StateSyncMessage> = HashMap::from([(
String::from("test_protocol"), String::from("test_protocol"),
StateSyncMessage { StateSyncMessage {
header: Header { header: Header {
hash: Default::default(), hash: Bytes::from(bytes),
number: stop_block, number: stop_block,
parent_hash: Default::default(), parent_hash: Bytes::from(bytes),
revert: false, revert: false,
}, },
snapshots: snapshot, snapshots: snapshot,
@@ -304,14 +310,12 @@ fn validate_state(
}, },
)]); )]);
let all_tokens = rt.block_on(load_all_tokens( let all_tokens = rt
"localhost:4242", .block_on(tycho_client.get_tokens(Chain::Ethereum, None, None))
true, .expect("Failed to get tokens");
None, info!("Loaded {} tokens", all_tokens.len());
Chain::Ethereum.into(),
None, rt.block_on(decoder.set_tokens(all_tokens));
None,
));
let mut pairs: HashMap<String, Vec<Token>> = HashMap::new(); let mut pairs: HashMap<String, Vec<Token>> = HashMap::new();
@@ -329,6 +333,9 @@ fn validate_state(
// This is where we get blocked. Currently, Tycho Simulation expects the runtime to be // 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 // 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() { for (id, state) in block_msg.states.iter() {
if let Some(tokens) = pairs.get(id) { if let Some(tokens) = pairs.get(id) {
let formatted_token_str = format!("{:}/{:}", &tokens[0].symbol, &tokens[1].symbol); 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(|price| println!("Spot price {:?}: {:?}", formatted_token_str, price))
.map_err(|e| eprintln!("Error calculating spot price for Pool {:?}: {:?}", id, e)) .map_err(|e| eprintln!("Error calculating spot price for Pool {:?}: {:?}", id, e))
.ok(); .ok();
let amount_in = // let amount_in =
BigUint::from(1u32) * BigUint::from(10u32).pow(tokens[0].decimals as u32); // BigUint::from(1u32) * BigUint::from(10u32).pow(tokens[0].decimals as u32);
state // state
.get_amount_out(amount_in, &tokens[0], &tokens[1]) // .get_amount_out(amount_in, &tokens[0], &tokens[1])
.map(|result| { // .map(|result| {
println!( // println!(
"Amount out for trading 1 {:?} -> {:?}: {:?} (takes {:?} gas)", // "Amount out for trading 1 {:?} -> {:?}: {:?} (takes {:?} gas)",
&tokens[0].symbol, &tokens[1].symbol, result.amount, result.gas // &tokens[0].symbol, &tokens[1].symbol, result.amount, result.gas
) // )
}) // })
.map_err(|e| eprintln!("Error calculating amount out for Pool {:?}: {:?}", id, e)) // .map_err(|e| eprintln!("Error calculating amount out for Pool {:?}: {:?}", id,
.ok(); // e)) .ok();
} }
} }
} }

View File

@@ -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_client::{rpc::RPCClient, HttpRPCClient};
use tycho_core::{ use tycho_common::{
dto::{ dto::{
Chain, ProtocolComponent, ProtocolComponentsRequestBody, ResponseAccount, Chain, PaginationParams, ProtocolComponent, ProtocolComponentsRequestBody, ResponseAccount,
ResponseProtocolState, VersionParam, ResponseProtocolState, StateRequestBody, VersionParam,
}, },
models::Address, models::Address,
Bytes,
}; };
use tycho_common::dto::ResponseToken;
use tycho_simulation::models::Token;
/// Custom error type for RPC operations /// Custom error type for RPC operations
#[derive(Debug)] #[derive(Debug)]
@@ -74,18 +78,18 @@ impl TychoClient {
pub async fn get_protocol_state( pub async fn get_protocol_state(
&self, &self,
protocol_system: &str, protocol_system: &str,
component_ids: Vec<String>,
chain: Chain, chain: Chain,
) -> Result<Vec<ResponseProtocolState>, RpcError> { ) -> Result<Vec<ResponseProtocolState>, RpcError> {
let chunk_size = 100; let chunk_size = 100;
let concurrency = 1; let concurrency = 1;
let ids: &[String] = &[]; let version: tycho_common::dto::VersionParam = VersionParam::default();
let version: tycho_core::dto::VersionParam = VersionParam::default();
let protocol_states = self let protocol_states = self
.http_client .http_client
.get_protocol_states_paginated( .get_protocol_states_paginated(
chain, chain,
ids, &component_ids,
protocol_system, protocol_system,
true, true,
&version, &version,
@@ -100,27 +104,53 @@ impl TychoClient {
/// Gets contract state from the RPC server /// Gets contract state from the RPC server
pub async fn get_contract_state( pub async fn get_contract_state(
&self, &self,
contract_ids: Vec<Address>,
protocol_system: &str, protocol_system: &str,
chain: Chain, chain: Chain,
) -> Result<Vec<ResponseAccount>, RpcError> { ) -> Result<Vec<ResponseAccount>, RpcError> {
// Pagination parameters let request_body = StateRequestBody {
let chunk_size = 100; contract_ids: None,
let concurrency = 1; protocol_system: protocol_system.to_string(),
let version: tycho_core::dto::VersionParam = VersionParam::default(); version: Default::default(),
chain,
pagination: PaginationParams { page: 0, page_size: 100 },
};
let contract_states = self let contract_states = self
.http_client .http_client
.get_contract_state_paginated( .get_contract_state(&request_body)
chain,
&contract_ids,
protocol_system,
&version,
chunk_size,
concurrency,
)
.await?; .await?;
Ok(contract_states.accounts) Ok(contract_states.accounts)
} }
pub async fn get_tokens(
&self,
chain: Chain,
min_quality: Option<i32>,
max_days_since_last_trade: Option<u64>,
) -> Result<HashMap<Bytes, Token>, 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::<HashMap<_, Token>>();
Ok(res)
}
} }