Skip to main content
Glama

Ethereum MCP Server

pool.rs6.27 kB
//! Uniswap V3 pool operations use crate::abis::{UniswapV3Factory, UniswapV3Pool, ERC20}; use crate::ethereum::utils; use alloy::primitives::{Address, Uint}; use anyhow::{Context, Result}; use rust_decimal::Decimal; /// Get the Uniswap V3 pool address for a token pair and fee tier pub async fn get_uniswap_v3_pool_address<P: alloy::providers::Provider>( token_a: Address, token_b: Address, fee: u64, factory_address: Address, provider: &P, ) -> Result<Address> { let factory = UniswapV3Factory::new(factory_address, provider); let fee_uint = Uint::from(fee); // Try direct order let pool = factory.getPool(token_a, token_b, fee_uint).call().await .context("Failed to call getPool on UniswapV3Factory")?; if pool != Address::ZERO { return Ok(pool); } // Try reversed order just in case let pool_reversed = factory.getPool(token_b, token_a, fee_uint).call().await .context("Failed to call getPool (reversed) on UniswapV3Factory")?; Ok(pool_reversed) } /// Get token0 and token1 addresses from a Uniswap V3 pool pub async fn get_pool_tokens<P: alloy::providers::Provider>( pool_address: Address, provider: &P, ) -> Result<(Address, Address)> { tracing::info!("Getting tokens from pool: {:?}", pool_address); let pool = UniswapV3Pool::new(pool_address, provider); // Get token addresses let token0_result = pool.token0().call().await .context("Failed to call token0() on pool")?; let token1_result = pool.token1().call().await .context("Failed to call token1() on pool")?; let token0 = token0_result; let token1 = token1_result; Ok((token0, token1)) } /// Get the current price from a Uniswap V3 pool by reading slot0 /// Returns the price as Decimal for token1/token0 (accounting for decimals) pub async fn get_pool_price<P: alloy::providers::Provider>( pool_address: Address, provider: &P, ) -> Result<Decimal> { tracing::info!("Getting price from pool: {:?}", pool_address); let pool = UniswapV3Pool::new(pool_address, provider); // Get slot0 data let slot0_result = pool.slot0().call().await .context("Failed to call slot0() on pool")?; let sqrt_price_x96 = slot0_result.sqrtPriceX96; // Get token addresses let token0_result = pool.token0().call().await .context("Failed to call token0() on pool")?; let token1_result = pool.token1().call().await .context("Failed to call token1() on pool")?; let token0 = token0_result; let token1 = token1_result; // Get token decimals let token0_decimals = get_token_decimals_helper(token0, provider).await.unwrap_or(18u8); let token1_decimals = get_token_decimals_helper(token1, provider).await.unwrap_or(18u8); // Convert sqrtPriceX96 to price // Price = (sqrtPriceX96 / 2^96)^2 // With decimals: Price = (sqrtPriceX96 / 2^96)^2 * (10^token0_decimals / 10^token1_decimals) // Calculate price using U256 first to avoid overflow, then convert to Decimal // Price = (sqrtPriceX96 / 2^96)^2 * 10^(token0_decimals - token1_decimals) use alloy::primitives::U256; let q96 = U256::from(1u128 << 96); let sqrt_price_u256 = U256::from(sqrt_price_x96); // Use high precision scale factor (18 decimals) let scale = U256::from(10u128.pow(18)); // Calculate ratio with high precision: (sqrt_price * scale) / q96 let ratio = (sqrt_price_u256 * scale) / q96; // Convert to Decimal, then divide by scale to get the actual ratio let ratio_dec = Decimal::from(ratio.to::<u128>()) / Decimal::from(10u128.pow(18)); // Square the ratio to get price let mut price_dec = ratio_dec * ratio_dec; // Apply decimal adjustment let decimal_diff: i32 = (token0_decimals as i32) - (token1_decimals as i32); if decimal_diff > 0 { let adj = utils::power_of_10(decimal_diff); price_dec *= adj; } else if decimal_diff < 0 { let adj = utils::power_of_10(-decimal_diff); price_dec /= adj; } Ok(price_dec) } /// Calculate minimum amount out based on pool price, amount in, and slippage /// Returns the minimum amount out with slippage tolerance applied pub async fn calculate_min_amount_out<P: alloy::providers::Provider>( pool_address: Address, from_token: Address, to_token: Address, amount_in: Decimal, slippage_percentage: Decimal, provider: &P, ) -> Result<Decimal> { tracing::info!("Calculating min amount out for swap: {:?} -> {:?}, amount_in: {}, slippage: {}%", from_token, to_token, amount_in, slippage_percentage); // Get pool price and token addresses let pool_price = get_pool_price(pool_address, provider).await?; let (token0, token1) = get_pool_tokens(pool_address, provider).await?; // Determine the expected output amount based on token order in the pool // get_pool_price returns token1/token0, so we need to adjust based on swap direction let expected_amount_out = if from_token == token0 && to_token == token1 { // Swapping token0 -> token1, so use price directly amount_in * pool_price } else if from_token == token1 && to_token == token0 { // Swapping token1 -> token0, so use inverse price amount_in / pool_price } else { return Err(anyhow::anyhow!( "Token mismatch: from_token and to_token don't match pool structure (token0: {:?}, token1: {:?})", token0, token1 )); }; // Apply slippage tolerance let min_amount_out = expected_amount_out * (Decimal::from(1) - slippage_percentage / Decimal::from(100)); tracing::info!("Calculated min amount out: {} (expected: {}, slippage: {}%)", min_amount_out, expected_amount_out, slippage_percentage); Ok(min_amount_out) } /// Helper function to get token decimals async fn get_token_decimals_helper<P: alloy::providers::Provider>( token_address: Address, provider: &P, ) -> Result<u8> { let erc20 = ERC20::new(token_address, provider); let decimals_result = erc20.decimals().call().await .context("Failed to call decimals()")?; Ok(decimals_result) }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Joshuashen022/ethereum-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server