Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sync dev and main #31

Merged
merged 4 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions .env.bak

This file was deleted.

2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions bin/reflux/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ log = "0.4.21"
simple_logger = "5.0.0"
clap = { version = "4.5.7", features = ["derive"] }
dotenv = "0.15.0"
futures-util = "0.3.30"

# workspace dependencies
account-aggregation = { workspace = true }
storage = { workspace = true }
config = { workspace = true }
routing-engine = { workspace = true }
api = { workspace = true }
thiserror = "1.0.61"
85 changes: 79 additions & 6 deletions bin/reflux/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::Arc;
use std::time::Duration;

use axum::http::Method;
use clap::Parser;
use dotenv::dotenv;
use futures_util::future::join_all;
use log::{debug, error, info};
use tokio::join;
use tokio::sync::Mutex;
use tower_http::cors::{Any, CorsLayer};

Expand All @@ -19,6 +22,10 @@ use routing_engine::settlement_engine::{generate_erc20_instance_map, SettlementE
use storage::{ControlFlow, MessageQueue, RedisClient};
use storage::mongodb_client::MongoDBClient;

use crate::utils::find_lowest_transfer_amount_usd;

mod utils;

#[derive(Parser, Debug)]
struct Args {
/// Run the Solver (default)
Expand All @@ -29,6 +36,10 @@ struct Args {
#[arg(short, long)]
indexer: bool,

/// Run the utility to find the lowest transfer amount in USD for all possible token pairs
#[arg(short, long)]
find_lowest_transfer_amounts_usd: bool,

/// Config file path
#[arg(short, long, default_value = "config.yaml")]
config: String,
Expand All @@ -48,11 +59,6 @@ async fn main() {
panic!("Cannot run both indexer and solver at the same time");
}

if !args.indexer && !args.solver {
args.solver = true;
debug!("Running Solver by default");
}

// Load configuration from yaml
let config =
Arc::new(Config::build_from_file(&args.config).expect("Failed to load config file"));
Expand All @@ -61,6 +67,11 @@ async fn main() {
run_indexer(config).await;
} else if args.solver {
run_solver(config).await;
} else if args.find_lowest_transfer_amounts_usd {
run_find_lowest_transfer_amount_usd(config).await;
} else {
info!("Running Solver by default");
run_solver(config).await;
}
}

Expand Down Expand Up @@ -228,4 +239,66 @@ async fn run_indexer(config: Arc<Config>) {
Ok(_) => info!("Indexer Job Completed"),
Err(e) => error!("Indexer Job Failed: {}", e),
};
}
}

async fn run_find_lowest_transfer_amount_usd(config: Arc<Config>) {
let redis_client = RedisClient::build(&config.infra.redis_url).await.unwrap();
let bungee_client = BungeeClient::new(&config.bungee.base_url, &config.bungee.api_key)
.expect("Failed to Instantiate Bungee Client");
let token_price_provider = Arc::new(Mutex::new(CoingeckoClient::new(
config.coingecko.base_url.clone(),
config.coingecko.api_key.clone(),
redis_client.clone(),
Duration::from_secs(config.coingecko.expiry_sec),
)));

let mut results = Vec::new();

// Intentionally not running these concurrently to avoid rate limiting
for (_, token_a) in config.tokens.iter() {
for (chain_a, _) in token_a.by_chain.iter() {
for (_, token_b) in config.tokens.iter() {
for (chain_b, _) in token_b.by_chain.iter() {
if token_a.symbol != token_b.symbol || chain_a != chain_b {
results.push((
(
*chain_a,
*chain_b,
token_a.symbol.clone(),
token_b.symbol.clone(),
false,
),
find_lowest_transfer_amount_usd(
&config,
*chain_a,
*chain_b,
&token_a.symbol,
&token_b.symbol,
false,
&bungee_client,
Arc::clone(&token_price_provider),
)
.await,
))
}
}
}
}
}

for result in results {
let (route, amount_result) = result;

match amount_result {
Ok(amount) => {
info!(
"Found lowest transfer amount in USD for token {} on chain {} to token {} on chain {}: {}",
route.2, route.0, route.3, route.1, amount
);
}
Err(e) => {
error!("Failed to find lowest transfer amount in USD: {}", e);
}
}
}
}
95 changes: 95 additions & 0 deletions bin/reflux/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use std::sync::Arc;

use log::{debug, info};
use thiserror::Error;
use tokio::sync::Mutex;

use config::Config;
use routing_engine::{CostType, Route, token_price};
use routing_engine::source::RouteSource;
use routing_engine::token_price::TokenPriceProvider;
use routing_engine::token_price::utils::Errors;

const TOKEN_AMOUNT_USD_LOWER_BOUND: f64 = 0.0;
const TOKEN_AMOUNT_USD_UPPER_BOUND: f64 = 25.0;
const DIFFERENCE_THRESHOLD_USD: f64 = 0.5;

pub async fn find_lowest_transfer_amount_usd<
Source: RouteSource,
PriceProvider: TokenPriceProvider,
>(
config: &Config,
from_chain_id: u32,
to_chain_id: u32,
from_token_id: &String,
to_token_id: &String,
is_smart_contract_deposit: bool,
source: &Source,
token_price_provider: Arc<Mutex<PriceProvider>>,
) -> Result<f64, FindLowestTransferAmountErr<Source, PriceProvider>> {
debug!(
"Finding lowest transfer amount in USD for token {} on chain {} to token {} on chain {}",
from_token_id, from_chain_id, to_token_id, to_chain_id
);

let mut low = TOKEN_AMOUNT_USD_LOWER_BOUND;
let mut high = TOKEN_AMOUNT_USD_UPPER_BOUND;

loop {
let route = Route::build(
config,
&from_chain_id,
&to_chain_id,
from_token_id,
to_token_id,
is_smart_contract_deposit,
)?;

if high - low < DIFFERENCE_THRESHOLD_USD {
info!("Found lowest transfer amount in USD: {} for route {}", high, route);
break Ok(high);
}

debug!("Trying with low: {} and high: {} for route {}", low, high, route);

let mid = (low + high) / 2.0;

let from_token_amount_in_wei = token_price::utils::get_token_amount_from_value_in_usd(
&config,
&token_price_provider.lock().await,
from_token_id,
from_chain_id,
&mid,
)
.await
.map_err(FindLowestTransferAmountErr::GetTokenAmountFromValueInUsdErr)?;

let result = source
.fetch_least_cost_route_and_cost_in_usd(
&route,
&from_token_amount_in_wei,
None,
None,
&CostType::Fee,
)
.await;

if result.is_err() {
low = mid;
} else {
high = mid;
}
}
}

#[derive(Error, Debug)]
pub enum FindLowestTransferAmountErr<T: RouteSource, U: TokenPriceProvider> {
#[error("Failed to build route")]
RouteBuildErr(#[from] routing_engine::RouteError),

#[error("Failed to fetch route cost")]
FetchRouteCostErr(T::FetchRouteCostError),

#[error("Failed to get token amount from value in usd")]
GetTokenAmountFromValueInUsdErr(Errors<U::Error>),
}
Loading