Files
tycho-protocol-sdk/protocol-testing/src/tycho_rpc.rs
dianacarvalho1 b577e7d6b2 refactor: Misc improvements to code (#277)
* refactor: Misc improvements to code

- Decouple validating logic from TychoRunner
- Move all data fetching and decoding the tycho message into the same method
- Split validate_state into validate_state, validate_token_balances and simulate_and_execute
- Make rpc_provider and runtime attributes of TestRunner
- Add references where possible to avoid clones
- Remove unnecessary code
- Make clippy happy

#time 2h 36m

#time 0m


#time 3m

* chore: Use tycho deps and foundry from tycho_simulation

This is to try to decrease the risk of using conflicting versions in the different repositories

#time 32m


#time 0m

* chore: Read RPC_URL in main.rs

#time 10m

* fix: Support eth trades (skip balance and allowance overwrites) and set balance overwrite to amount in

For tokens like USDC setting the balance super high was making us getting blacklisted

#time 1h 12m

* fix: Fix curve tests and filter components_by_id with the expected_component_ids

#time 1h 30m


#time 0m

* fix: Don't use all the possible executor addresses. Hardcode just one for the test

Refactor overwrites logic:
- renamed functions
- moved logic around that fits together
- don't use StateOverrides and then convert to alloy overrides. Use alloy's directly

#time 1h 21m

* fix: Assume that the executors mapping starts at storage value 1

Move setup_router_overwrites away from the rpc and into the execution file
Delete unnecessary get_storage_at

#time 33m
2025-09-25 17:27:05 +01:00

157 lines
4.5 KiB
Rust

use std::{collections::HashMap, error::Error as StdError, fmt};
use tracing::debug;
use tycho_simulation::{
tycho_client::{rpc::RPCClient, HttpRPCClient},
tycho_common::{
dto::{
Chain, PaginationParams, ProtocolComponent, ProtocolComponentsRequestBody,
ResponseAccount, ResponseProtocolState, ResponseToken, StateRequestBody, VersionParam,
},
models::token::Token,
Bytes,
},
};
/// Custom error type for RPC operations
#[derive(Debug)]
pub enum RpcError {
ClientError(String),
}
impl fmt::Display for RpcError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RpcError::ClientError(msg) => write!(f, "RPC client error: {msg}"),
}
}
}
impl StdError for RpcError {}
impl From<Box<dyn StdError>> for RpcError {
fn from(error: Box<dyn StdError>) -> Self {
RpcError::ClientError(error.to_string())
}
}
impl From<tycho_simulation::tycho_client::RPCError> for RpcError {
fn from(error: tycho_simulation::tycho_client::RPCError) -> Self {
RpcError::ClientError(error.to_string())
}
}
/// Client for interacting with the Tycho RPC server
pub struct TychoClient {
http_client: HttpRPCClient,
}
impl TychoClient {
pub fn new(host: &str) -> Result<Self, RpcError> {
let http_client =
HttpRPCClient::new(host, None).map_err(|e| RpcError::ClientError(e.to_string()))?;
Ok(Self { http_client })
}
/// Gets protocol components from the RPC server
pub async fn get_protocol_components(
&self,
protocol_system: &str,
chain: Chain,
) -> Result<Vec<ProtocolComponent>, RpcError> {
let request = ProtocolComponentsRequestBody::system_filtered(protocol_system, None, chain);
let chunk_size = 100;
let concurrency = 1;
let response = self
.http_client
.get_protocol_components_paginated(&request, chunk_size, concurrency)
.await?;
Ok(response.protocol_components)
}
/// Gets protocol state from the RPC server
pub async fn get_protocol_state(
&self,
protocol_system: &str,
component_ids: Vec<String>,
chain: Chain,
) -> Result<Vec<ResponseProtocolState>, RpcError> {
let chunk_size = 100;
let concurrency = 1;
let version: tycho_simulation::tycho_common::dto::VersionParam = VersionParam::default();
let protocol_states = self
.http_client
.get_protocol_states_paginated(
chain,
&component_ids,
protocol_system,
true,
&version,
chunk_size,
concurrency,
)
.await?;
Ok(protocol_states.states)
}
/// Gets contract state from the RPC server
pub async fn get_contract_state(
&self,
protocol_system: &str,
chain: Chain,
) -> Result<Vec<ResponseAccount>, RpcError> {
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(&request_body)
.await?;
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> {
debug!("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)
}
}