From 74546c9ac509e5a97afbbad3ecaea37a7a8c20da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Willy=20Rom=C3=A3o?= Date: Wed, 4 Oct 2023 12:50:00 +0100 Subject: [PATCH] refactor(exchange): wip refactoring internal methods of the mod --- src/asset/mod.rs | 14 ++++++++ src/cmd/helpers.rs | 53 +++++++++++++++++------------ src/config/exchange.rs | 2 +- src/config/mod.rs | 9 +++-- src/config/network.rs | 15 +++++++-- src/exchange/config.rs | 76 ++++++++++++++++++++++++++++++++++++++++-- src/exchange/mod.rs | 27 +++++++++++++-- 7 files changed, 161 insertions(+), 35 deletions(-) diff --git a/src/asset/mod.rs b/src/asset/mod.rs index 745ebb3..d30044b 100644 --- a/src/asset/mod.rs +++ b/src/asset/mod.rs @@ -54,6 +54,20 @@ impl Asset { }) } + #[cfg(test)] + pub fn dummy_asset(address: &str, path_asset_address: &str) -> Self { + let network = Network::default(); + Asset { + name: "dummy".to_string(), + kind: "dummy".to_string(), + network_id: network.name().to_string(), + address: address.to_string(), + slippage: 0.0, + path_asset: path_asset_address.to_string(), + network: Network::default(), + } + } + pub fn slippage(&self) -> f64 { self.slippage } diff --git a/src/cmd/helpers.rs b/src/cmd/helpers.rs index b9323f7..6fe92b1 100644 --- a/src/cmd/helpers.rs +++ b/src/cmd/helpers.rs @@ -2,10 +2,8 @@ use std::str::FromStr; use crate::{ asset::Asset, - config::{ - exchange::Exchange, network::Network, wallet::Wallet, withdraw_wallet::WithdrawWallet, - Config, - }, + config::{network::Network, wallet::Wallet, withdraw_wallet::WithdrawWallet, Config}, + exchange::Exchange, rebalancer::config::RebalancerConfig, utils::math, }; @@ -15,21 +13,18 @@ use web3::types::{Address, H160, U256}; //TODO: add constants to all keys in value_of -#[tracing::instrument(name = "get exchange from command args", level = "debug", skip(args))] +#[tracing::instrument(name = "get exchange from command args", level = "debug", skip(args))] pub fn get_exchange(args: &ArgMatches) -> Result<&Exchange, anyhow::Error> { match args.get_one::("exchange") { - Some(n) => { - let network = Config::global() - .exchanges - .get(n) - .context("exchange not found")?; - Ok(network) + Some(exchange_name) => { + let exchange = Exchange::try_from((Config::global(), exchange_name))?; + Ok(&exchange) } None => Err(anyhow::anyhow!("--exchange is required")), } } -#[tracing::instrument(name = "get network from command args", level = "debug", skip(args))] +#[tracing::instrument(name = "get network from command args", level = "debug", skip(args))] pub fn get_network(args: &ArgMatches) -> Result<&Network, anyhow::Error> { match args.get_one::("network") { Some(n) => { @@ -43,7 +38,7 @@ pub fn get_network(args: &ArgMatches) -> Result<&Network, anyhow::Error> { } } -#[tracing::instrument(name = "get address from command args", level = "debug", skip(args))] +#[tracing::instrument(name = "get address from command args", level = "debug", skip(args))] pub fn get_address(args: &ArgMatches) -> Result { match args.get_one::("address") { Some(a) => Address::from_str(a).map_err(|e| anyhow::anyhow!(e)), @@ -51,7 +46,7 @@ pub fn get_address(args: &ArgMatches) -> Result { } } -#[tracing::instrument(name = "get wallet from command args", level = "debug", skip(args))] +#[tracing::instrument(name = "get wallet from command args", level = "debug", skip(args))] pub fn get_wallet(args: &ArgMatches) -> Result<&Wallet, anyhow::Error> { let config = Config::global(); match args.get_one::("wallet") { @@ -106,7 +101,11 @@ pub fn get_amount(args: &ArgMatches, asset_decimals: u8) -> Result Result { match args.get_one::("amount") { Some(amount) => Ok(*amount), @@ -114,7 +113,11 @@ pub fn get_amount_f64(args: &ArgMatches) -> Result { } } -#[tracing::instrument(name = "get slippage in f64 from command args", level = "debug", skip(args))] +#[tracing::instrument( + name = "get slippage in f64 from command args", + level = "debug", + skip(args) +)] pub fn get_slippage(args: &ArgMatches) -> Result { match args.get_one::("slippage") { Some(f) if *f > 0.0 && *f <= 100.0 => Ok(*f), @@ -126,7 +129,11 @@ pub fn get_slippage(args: &ArgMatches) -> Result { } } -#[tracing::instrument(name = "get input token in network from command args", level = "debug", skip(args))] +#[tracing::instrument( + name = "get input token in network from command args", + level = "debug", + skip(args) +)] pub fn get_token_input_in_network_from_args( args: &ArgMatches, network_id: &str, @@ -141,7 +148,11 @@ pub fn get_token_input_in_network_from_args( } } -#[tracing::instrument(name = "get output token in network from command args", level = "debug", skip(args))] +#[tracing::instrument( + name = "get output token in network from command args", + level = "debug", + skip(args) +)] pub fn get_token_output_in_network_from_args( args: &ArgMatches, network_id: &str, @@ -184,7 +195,7 @@ pub fn get_withdraw_wallet(args: &ArgMatches) -> WithdrawWallet { } } -#[tracing::instrument(name = "get hide zero from command args", level = "debug", skip(args))] +#[tracing::instrument(name = "get hide zero from command args", level = "debug", skip(args))] pub fn get_hide_zero(args: &ArgMatches) -> bool { match args.get_one::("hide-zero") { Some(b) => b.parse().unwrap_or(false), @@ -192,12 +203,12 @@ pub fn get_hide_zero(args: &ArgMatches) -> bool { } } -#[tracing::instrument(name = "get run every from command args", level = "debug", skip(args))] +#[tracing::instrument(name = "get run every from command args", level = "debug", skip(args))] pub fn get_run_every(args: &ArgMatches) -> Option<&u32> { args.get_one::("run-every") } -#[tracing::instrument(name = "get track from command args", level = "debug", skip(args))] +#[tracing::instrument(name = "get track from command args", level = "debug", skip(args))] pub fn get_track(args: &ArgMatches) -> bool { match args.get_one::("track") { Some(b) => b.parse().unwrap_or(false), diff --git a/src/config/exchange.rs b/src/config/exchange.rs index 365cf34..4158c4a 100644 --- a/src/config/exchange.rs +++ b/src/config/exchange.rs @@ -47,7 +47,7 @@ impl Exchange { } pub fn kind(&self) -> &str { - self.kind.as_str() + self..as_str() } pub fn network_id(&self) -> &str { diff --git a/src/config/mod.rs b/src/config/mod.rs index 0e5cabc..90b9b97 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,4 @@ mod decrypt_wallet; -pub mod exchange; pub mod network; pub mod wallet; pub mod withdraw_wallet; @@ -8,10 +7,10 @@ use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize}; use crate::{ - asset::config::AssetsConfig, notification::config::Notifications, - rebalancer::config::RebalancersConfig, + asset::config::AssetsConfig, exchange::config::ExchangesConfig, + notification::config::Notifications, rebalancer::config::RebalancersConfig, }; -use exchange::Exchanges; + use network::Networks; use wallet::Wallets; use withdraw_wallet::WithdrawWallets; @@ -30,7 +29,7 @@ pub struct Config { pub wallets: Wallets, pub withdraw_wallets: Option, pub networks: Networks, - pub exchanges: Exchanges, + pub exchanges: ExchangesConfig, pub assets: AssetsConfig, pub rebalancers: Option, pub notifications: Option, diff --git a/src/config/network.rs b/src/config/network.rs index b034f76..e96801f 100644 --- a/src/config/network.rs +++ b/src/config/network.rs @@ -6,8 +6,8 @@ use web3::{ Web3, }; -use super::{exchange::Exchange, wallet::Wallet, Config}; -use crate::{asset::Asset, utils::scalar::BigDecimal}; +use super::{wallet::Wallet, Config}; +use crate::{asset::Asset, exchange::Exchange, utils::scalar::BigDecimal}; #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct Network { @@ -22,6 +22,14 @@ pub struct Network { wrapped_asset: Option, } +impl Default for Network { + fn default() -> Self { + Self { + ..Default::default() + } + } +} + impl Network { pub fn rpc_url(&self) -> &str { self.rpc_url.as_str() @@ -86,7 +94,8 @@ impl Network { .exchanges .hashmap() .values() - .filter(|e| e.network_id() == self.name) + .filter(|exchange_config| exchange_config.network_id() == self.name) + .map(|config| &Exchange::new(config)) .collect() } diff --git a/src/exchange/config.rs b/src/exchange/config.rs index 1fd6cbd..af29774 100644 --- a/src/exchange/config.rs +++ b/src/exchange/config.rs @@ -1,4 +1,5 @@ use crate::asset::Asset; +use crate::config::Config; use crate::utils::resources::{exists_resource_file_fs_or_res, get_resource_file_fs_or_res}; use crate::utils::scalar::BigDecimal; use crate::utils::{self, math}; @@ -20,7 +21,6 @@ use web3::{ use crate::config::network::Network; use crate::config::wallet::Wallet; -use crate::config::Config; use super::swap_tokens_for_tokens; @@ -179,18 +179,23 @@ impl ExchangeConfig { // input -> path_asset -> path_asset from output -> output //TODO: check liquidity of directly path let mut v = vec![]; + //let network = self.get_network(); // let wrapped_asset = network.get_wrapped_asset(); let input_path_asset = input_asset.get_path_asset(); let output_path_asset = output_asset.get_path_asset(); + let same_input_output_path_asset = input_path_asset.address() == output_path_asset.address(); + let input_asset_is_same_of_some_asset_path = input_asset.address() == input_path_asset.address() || input_asset.address() == output_path_asset.address(); + let output_asset_is_same_of_some_asset_path = output_asset.address() == input_path_asset.address() || output_asset.address() == output_path_asset.address(); + // let has_direct_route = match self.get_factory_pair(input_asset, output_asset).await { // Some(a) => (a.to_string().as_str() != ZERO_ADDRESS), // _ => false, @@ -498,8 +503,8 @@ impl ExchangeConfig { } #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct Exchanges(HashMap); -impl Exchanges { +pub struct ExchangesConfig(HashMap); +impl ExchangesConfig { pub fn hashmap(&self) -> &HashMap { &self.0 } @@ -507,3 +512,68 @@ impl Exchanges { self.0.get(key) } } + + +#[cfg(test)] +mod test { + use crate::asset::Asset; + use crate::config::Config; + + use super::ExchangeConfig; + + fn get_exchange() -> &'static ExchangeConfig{ + Config::global().exchanges.0.values().last().unwrap() + } + + #[tokio::test] + async fn test_same_path_assets() { + let route_builder = get_exchange(); + + // TODO: remove this generation of data, use the test_config.yaml + // FIXME: continue from here + let input_asset = Asset::dummy_asset("0x1", "0x2"); + let output_asset = Asset::dummy_asset("0x3", "0x2"); + + let result = route_builder.build_route_for(&input_asset, &output_asset).await; + let expected = vec!["0x1", "0x2", "0x3"]; + assert_eq!(result, expected); + } + + #[tokio::test] + async fn test_input_asset_is_path_asset() { + let route_builder = ...; // instantiate your struct + + let input_asset = dummy_asset("0x2", "0x2"); // input_asset is its own path_asset + let output_asset = dummy_asset("0x3", "0x4"); + + let result = route_builder.build_route_for(&input_asset, &output_asset).await; + let expected = vec!["0x2", "0x3"]; + assert_eq!(result, expected); + } + + #[tokio::test] + async fn test_output_asset_is_path_asset() { + let route_builder = ...; // instantiate your struct + + let input_asset = dummy_asset("0x1", "0x2"); + let output_asset = dummy_asset("0x4", "0x4"); // output_asset is its own path_asset + + let result = route_builder.build_route_for(&input_asset, &output_asset).await; + let expected = vec!["0x1", "0x4"]; + assert_eq!(result, expected); + } + + #[tokio::test] + async fn test_generic_case() { + let route_builder = ...; // instantiate your struct + + let input_asset = dummy_asset("0x1", "0x2"); + let output_asset = dummy_asset("0x3", "0x4"); + + let result = route_builder.build_route_for(&input_asset, &output_asset).await; + let expected = vec!["0x1", "0x2", "0x4", "0x3"]; + assert_eq!(result, expected); + } + + // ... Other test cases +} diff --git a/src/exchange/mod.rs b/src/exchange/mod.rs index 55b7a56..024831c 100644 --- a/src/exchange/mod.rs +++ b/src/exchange/mod.rs @@ -1,13 +1,36 @@ use crate::config::network::Network; - -use self::config::ExchangeConfig; +use crate::config::Config; pub mod config; pub mod swap_eth_for_tokens; pub mod swap_tokens_for_tokens; +use anyhow::Context; + +use self::config::ExchangeConfig; pub struct Exchange { config: ExchangeConfig, network: Network, } + +impl Exchange { + pub fn new(config: &ExchangeConfig) -> Self { + let network = config.get_network(); + Self { + config: config.clone(), + network: network.clone(), + } + } +} + +impl TryFrom<(&Config, &String)> for Exchange { + type Error = anyhow::Error; + fn try_from(t: (&Config, &String)) -> Result { + let config = + t.0.exchanges + .get(t.1) + .context(format!("exchange '{}' not found", t.1))?; + Ok(Exchange::new(config)) + } +}