feat: Add test for UniswapV2

- Used a random post-Shanghai-created USV2 pool state with enough liquidity for the test

Necessary fixes:
- Don't hardcode to EVMPoolState
- Don't expect adapter to always be set.
- UniswapV2 names its module differently for some reason... this seems like a special case so instead of updating all integration test yamls, I'm just hardcoding it in test_runner.rs. Perhaps not the best decision?
- Log the static attributes if not found.
- Get the substreams yaml path from config instead of hardcoding it.
This commit is contained in:
TAMARA LIPOWSKI
2025-09-19 01:35:21 -04:00
committed by Tamara
parent 9f4ff71b70
commit 12e6e48a78
3 changed files with 58 additions and 27 deletions

View File

@@ -66,8 +66,8 @@ impl ProtocolComponentExpectation {
} }
None => { None => {
diffs.push(format!( diffs.push(format!(
"Field 'static_attributes' mismatch for {}: Key '{}' not found", "Field 'static_attributes' mismatch for {}: Key '{}' not found. Available attributes: {:?}",
self.id, key self.id, key, other.static_attributes,
)); ));
} }
} }
@@ -136,7 +136,7 @@ pub struct IntegrationTest {
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
pub struct IntegrationTestsConfig { pub struct IntegrationTestsConfig {
pub substreams_yaml_path: String, pub substreams_yaml_path: String,
pub adapter_contract: String, pub adapter_contract: Option<String>,
pub adapter_build_signature: Option<String>, pub adapter_build_signature: Option<String>,
pub adapter_build_args: Option<String>, pub adapter_build_args: Option<String>,
pub initialized_accounts: Option<Vec<String>>, pub initialized_accounts: Option<Vec<String>>,

View File

@@ -22,7 +22,10 @@ use tycho_simulation::{
evm::{ evm::{
decoder::TychoStreamDecoder, decoder::TychoStreamDecoder,
engine_db::tycho_db::PreCachedDB, engine_db::tycho_db::PreCachedDB,
protocol::{u256_num::bytes_to_u256, vm::state::EVMPoolState}, protocol::{
u256_num::bytes_to_u256, uniswap_v2::state::UniswapV2State,
uniswap_v3::state::UniswapV3State, vm::state::EVMPoolState,
},
}, },
protocol::models::DecoderContext, protocol::models::DecoderContext,
tycho_client::feed::{ tycho_client::feed::{
@@ -84,13 +87,6 @@ impl TestRunner {
); );
return Ok(()); return Ok(());
} }
let substreams_yaml_path = self
.substreams_path
.join("substreams.yaml");
if !substreams_yaml_path.exists() {
warn!("substreams.yaml file not found at {}", self.substreams_path.display());
return Ok(());
}
let config = match Self::parse_config(&config_yaml_path) { let config = match Self::parse_config(&config_yaml_path) {
Ok(cfg) => cfg, Ok(cfg) => cfg,
@@ -100,6 +96,14 @@ impl TestRunner {
} }
}; };
let substreams_yaml_path = self
.substreams_path
.join(&config.substreams_yaml_path);
if !substreams_yaml_path.exists() {
warn!("substreams.yaml file not found at {}", substreams_yaml_path.display());
return Ok(());
}
let tests = match &self.match_test { let tests = match &self.match_test {
Some(filter) => config Some(filter) => config
.tests .tests
@@ -340,9 +344,15 @@ fn validate_state(
return Ok(()); return Ok(());
} }
// Build/find the adapter contract let adapter_contract_path;
let adapter_contract_path = let mut adapter_contract_path_str: Option<&str> = None;
match adapter_contract_builder.find_contract(&config.adapter_contract) {
// Adapter contract will only be configured for VM protocols, not natively implemented
// protocols.
if let Some(adapter_contract_name) = &config.adapter_contract {
// Build/find the adapter contract
adapter_contract_path = match adapter_contract_builder.find_contract(adapter_contract_name)
{
Ok(path) => { Ok(path) => {
info!("Found adapter contract at: {}", path.display()); info!("Found adapter contract at: {}", path.display());
path path
@@ -351,7 +361,7 @@ fn validate_state(
info!("Adapter contract not found, building it..."); info!("Adapter contract not found, building it...");
adapter_contract_builder adapter_contract_builder
.build_target( .build_target(
&config.adapter_contract, adapter_contract_name,
config config
.adapter_build_signature .adapter_build_signature
.as_deref(), .as_deref(),
@@ -361,21 +371,36 @@ fn validate_state(
} }
}; };
info!("Using adapter contract: {}", adapter_contract_path.display()); info!("Using adapter contract: {}", adapter_contract_path.display());
let adapter_contract_path_str: &str = adapter_contract_path.to_str().unwrap(); adapter_contract_path_str = Some(adapter_contract_path.to_str().unwrap());
}
// Clear the shared database state to ensure test isolation // Clear the shared database state to ensure test isolation
// This prevents state from previous tests from affecting the current test // This prevents state from previous tests from affecting the current test
tycho_simulation::evm::engine_db::SHARED_TYCHO_DB.clear(); tycho_simulation::evm::engine_db::SHARED_TYCHO_DB.clear();
let mut decoder = TychoStreamDecoder::new(); let mut decoder = TychoStreamDecoder::new();
let decoder_context = DecoderContext::new() let mut decoder_context = DecoderContext::new().vm_traces(vm_traces);
.vm_adapter_path(adapter_contract_path_str)
.vm_traces(vm_traces); if let Some(vm_adapter_path) = adapter_contract_path_str {
decoder.register_decoder_with_context::<EVMPoolState<PreCachedDB>>( decoder_context = decoder_context.vm_adapter_path(vm_adapter_path);
protocol_system, }
decoder_context, match protocol_system.as_str() {
); "uniswap_v2" | "sushiswap_v2" => {
decoder
.register_decoder_with_context::<UniswapV2State>(protocol_system, decoder_context);
}
"uniswap_v3" | "pancakeswap_v3" => {
decoder
.register_decoder_with_context::<UniswapV3State>(protocol_system, decoder_context);
}
_ => {
decoder.register_decoder_with_context::<EVMPoolState<PreCachedDB>>(
protocol_system,
decoder_context,
);
}
}
// 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();
@@ -398,8 +423,8 @@ fn validate_state(
state, state,
component: component.clone(), component: component.clone(),
component_tvl: None, component_tvl: None,
entrypoints: vec![], entrypoints: vec![], // UniswapV4 is not supported for SDK testing at the moment
}; // TODO };
states.insert(component_id.clone(), component_with_state); states.insert(component_id.clone(), component_with_state);
} }
// Convert vm_storages to a HashMap - match Python behavior exactly // Convert vm_storages to a HashMap - match Python behavior exactly

View File

@@ -39,6 +39,12 @@ impl TychoRunner {
let all_accounts = self.initialized_accounts.clone(); let all_accounts = self.initialized_accounts.clone();
// Determine the correct module name based on protocol system
let module_name = match protocol_system {
"uniswap_v2" => "map_pool_events",
_ => "map_protocol_changes",
};
cmd.args([ cmd.args([
"--database-url", "--database-url",
self.db_url.as_str(), self.db_url.as_str(),
@@ -46,7 +52,7 @@ impl TychoRunner {
"--spkg", "--spkg",
spkg_path, spkg_path,
"--module", "--module",
"map_protocol_changes", module_name,
"--protocol-type-names", "--protocol-type-names",
&protocol_type_names.join(","), &protocol_type_names.join(","),
"--protocol-system", "--protocol-system",