Skip to content

Commit

Permalink
refactoring form idl
Browse files Browse the repository at this point in the history
  • Loading branch information
faddat committed Dec 31, 2024
1 parent 536bd89 commit 94ee5a6
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 130 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

81 changes: 45 additions & 36 deletions packages/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::{anyhow, Result};
use clap::Parser;
use libcheese::common::USDC_MINT;
use libcheese::common::{parse_other_token_name, CHEESE_MINT};
use libcheese::common::{is_blacklisted, parse_other_token_name, CHEESE_MINT};
use libcheese::jupiter::fetch_jupiter_prices;
use libcheese::meteora::{fetch_meteora_cheese_pools, MeteoraPool};
use libcheese::raydium::{fetch_raydium_cheese_pools, fetch_raydium_mint_ids};
Expand All @@ -16,6 +16,7 @@ use tokio::time;
const SOL_PER_TX: f64 = 0.000005; // Approximate SOL cost per transaction
const LOOP_INTERVAL: Duration = Duration::from_secs(30);
const MIN_PROFIT_USD: f64 = 1.0; // Minimum profit in USD to execute trade
const MAX_USDC_INPUT: f64 = 10.0; // Maximum USDC input for any trade

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
Expand All @@ -40,12 +41,12 @@ struct DisplayPool {
other_symbol: String,
cheese_qty: String,
other_qty: String,
pool_type: String,
pool_version: String,
tvl: String,
volume_usd: String,
fee: String,
pool_address: String,
cheese_price: String, // e.g. "$0.000057"
cheese_price: String,
}

#[derive(Debug, Default)]
Expand Down Expand Up @@ -226,7 +227,7 @@ async fn run_iteration(executor: &Option<TradeExecutor>) -> Result<()> {
};

// Print table header
println!("\n| Source | Other Mint | Other Name | Pool Type | CHEESE Qty | Other Qty | Liquidity($) | Volume($) | Fee | CHEESE Price | Pool Address |");
println!("\n| Source | Other Mint | Other Name | Version | CHEESE Qty | Other Qty | Liquidity($) | Volume($) | Fee | CHEESE Price | Pool Address |");
println!("|----------|----------------------------------------------|------------|------------|------------|-----------|--------------|-----------|-------|--------------|----------------------------------------------|");

// Prepare display pools
Expand All @@ -242,6 +243,12 @@ async fn run_iteration(executor: &Option<TradeExecutor>) -> Result<()> {
};

let other_mint = pool.pool_token_mints[other_ix].clone();

// Skip blacklisted tokens
if is_blacklisted(&other_mint) {
continue;
}

let other_symbol = mint_to_symbol
.get(&other_mint)
.cloned()
Expand All @@ -258,14 +265,14 @@ async fn run_iteration(executor: &Option<TradeExecutor>) -> Result<()> {

display_pools.push(DisplayPool {
source: "Meteora".to_string(),
other_mint,
other_symbol,
other_mint: other_mint.to_string(),
other_symbol: other_symbol.to_string(),
cheese_qty: format!("{:.2}", cheese_qty),
other_qty: format!("{:.2}", other_qty),
pool_type: pool.pool_type.clone(),
pool_version: pool.pool_version.to_string(),
tvl: format!("{:.2}", pool.pool_tvl),
volume_usd: format!("{:.2}", pool.daily_volume),
fee: format!("{}%", pool.total_fee_pct.trim_end_matches('%')),
fee: format!("{:.2}%", pool.total_fee_pct.trim_end_matches('%')),
pool_address: pool.pool_address.clone(),
cheese_price: format!("${:.6}", cheese_usdc_price),
});
Expand Down Expand Up @@ -302,7 +309,7 @@ async fn run_iteration(executor: &Option<TradeExecutor>) -> Result<()> {
other_symbol,
cheese_qty: format!("{:.2}", cheese_qty),
other_qty: format!("{:.2}", other_qty),
pool_type: pool.r#type.clone(),
pool_version: pool.r#type.clone(),
tvl: format!("{:.2}", pool.tvl),
volume_usd: format!("{:.2}", pool.day.volume),
fee: format!("{:.2}%", pool.feeRate * 100.0),
Expand Down Expand Up @@ -348,7 +355,7 @@ async fn run_iteration(executor: &Option<TradeExecutor>) -> Result<()> {
pool.source,
pool.other_mint,
pool.other_symbol,
pool.pool_type,
pool.pool_version,
pool.cheese_qty,
pool.other_qty,
format!("{:.2}", tvl),
Expand Down Expand Up @@ -390,12 +397,7 @@ async fn run_iteration(executor: &Option<TradeExecutor>) -> Result<()> {
.iter()
.find(|p| p.pool_address == opp.pool_address)
.unwrap();
let fee_percent = pool
.total_fee_pct
.trim_end_matches('%')
.parse::<f64>()
.unwrap()
/ 100.0;
let fee_percent = pool.total_fee_pct.trim_end_matches('%').parse::<f64>()? / 100.0;

println!("\nPool: {} ({})", opp.pool_address, opp.symbol);
println!("├─ Implied CHEESE price: ${:.10}", opp.implied_price);
Expand Down Expand Up @@ -581,49 +583,56 @@ async fn run_iteration(executor: &Option<TradeExecutor>) -> Result<()> {
}

fn find_arbitrage_opportunities(
pools: &[MeteoraPool],
mut cheese_usdc_price: f64,
meteora_pools: &[MeteoraPool],
cheese_usdc_price: f64,
) -> Result<Vec<ArbitrageOpportunity>> {
let mut opportunities = Vec::new();

for pool in pools {
// Skip pools with derived prices
if pool.derived {
continue;
}

for pool in meteora_pools {
let (cheese_ix, other_ix) = if pool.pool_token_mints[0] == CHEESE_MINT {
(0, 1)
} else {
(1, 0)
};

let cheese_qty: f64 = pool.pool_token_amounts[cheese_ix].parse()?;
let other_qty: f64 = pool.pool_token_amounts[other_ix].parse()?;
let is_usdc_pool = pool.pool_token_mints.contains(&USDC_MINT.to_string());
let other_mint = &pool.pool_token_mints[other_ix];

// If this is the USDC pool, use it to set the CHEESE price
if is_usdc_pool {
cheese_usdc_price = other_qty / cheese_qty; // USDC is worth $1, so price = USDC/CHEESE
// Skip blacklisted tokens
if is_blacklisted(other_mint) {
continue;
}

let fee_percent: f64 = pool.total_fee_pct.trim_end_matches('%').parse::<f64>()? / 100.0;
let cheese_qty: f64 = pool.pool_token_amounts[cheese_ix].parse()?;
let other_qty: f64 = pool.pool_token_amounts[other_ix].parse()?;

// If this is USDC, use price of 1.0
let other_price = if other_mint == USDC_MINT {
1.0 // USDC is always worth $1
} else {
cheese_usdc_price
};

let implied_price = (other_qty * other_price) / cheese_qty;
let price_diff_pct = ((implied_price - cheese_usdc_price) / cheese_usdc_price) * 100.0;

let fee_percent = pool.total_fee_pct.trim_end_matches('%').parse::<f64>()? / 100.0;

if cheese_qty <= 0.0 || other_qty <= 0.0 {
continue;
}

let implied_price = (other_qty * cheese_usdc_price) / cheese_qty;
let price_diff_pct = ((implied_price - cheese_usdc_price) / cheese_usdc_price) * 100.0;

// If price difference is significant (>1%)
if price_diff_pct.abs() > 1.0 {
let max_trade_size = if is_usdc_pool {
// Calculate max trade size based on pool liquidity
let pool_based_size = if pool.pool_token_mints.contains(&USDC_MINT.to_string()) {
cheese_qty * 0.1
} else {
cheese_qty * 0.05
}; // 10% of pool liquidity
};

// Limit by MAX_USDC_INPUT
let max_trade_size = (MAX_USDC_INPUT / cheese_usdc_price).min(pool_based_size);

let price_diff_per_cheese = (implied_price - cheese_usdc_price).abs();
let gross_profit = max_trade_size * price_diff_per_cheese;

Expand Down
1 change: 1 addition & 0 deletions packages/libcheese/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ spl-associated-token-account = "6.0.0"
spl-token = "4.0.0"
bincode = "1.3"
base64 = "0.22.1"
lazy_static = "1.4.0"
15 changes: 15 additions & 0 deletions packages/libcheese/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
use lazy_static::lazy_static;
use serde::de::{self, Deserializer};
use serde::Deserialize;
use std::collections::HashSet;

pub const CHEESE_MINT: &str = "A3hzGcTxZNSc7744CWB2LR5Tt9VTtEaQYpP6nwripump";
pub const USDC_MINT: &str = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";

lazy_static! {
pub static ref BLACKLISTED_MINTS: HashSet<&'static str> = {
let mut s = HashSet::new();
s.insert("27VkFr6b6DHoR6hSYZjUDbwJsV6MPSFqPavXLg8nduHW"); // OSHO
// Add other problematic tokens here
s
};
}

pub fn de_string_to_f64<'de, D>(deserializer: D) -> std::result::Result<f64, D::Error>
where
D: Deserializer<'de>,
Expand All @@ -30,3 +41,7 @@ pub fn parse_other_token_name(pool_name: &str) -> String {
}
pool_name.to_string()
}

pub fn is_blacklisted(mint: &str) -> bool {
BLACKLISTED_MINTS.contains(mint)
}
Loading

0 comments on commit 94ee5a6

Please sign in to comment.