utils.rs•3.36 kB
use alloy::primitives::{Address, Bytes, U256};
use rust_decimal::Decimal;
/// Helper function to raise 10 to a power for decimal conversion
pub fn power_of_10(power: i32) -> Decimal {
let mut result = Decimal::from(1u64);
let base = Decimal::from(10u64);
for _ in 0..power {
result *= base;
}
result
}
/// Calculate Uniswap V3 swap path from token addresses
pub fn calculate_path(from_token: Address, to_token: Address, fee: u64) -> Bytes {
// Build V3 path params
let fee = fee as u32;
// Encode the swap path: tokenIn + fee + tokenOut, as per Uniswap V3 exactInput path encoding
// path = tokenIn (20 bytes) | fee (3 bytes BE) | tokenOut (20 bytes)
let mut path_vec = Vec::with_capacity(20 + 3 + 20);
path_vec.extend_from_slice(from_token.as_slice());
let fee_bytes = fee.to_be_bytes();
path_vec.extend_from_slice(&fee_bytes[1..]); // u64 -> 8 bytes, take last 3 bytes
path_vec.extend_from_slice(to_token.as_slice());
Bytes::copy_from_slice(&path_vec)
}
/// Convert Wei to ETH
pub fn wei_to_eth(wei: &U256) -> String {
// Handle zero case
if wei.is_zero() {
return "0".to_string();
}
// Convert wei to string representation
let wei_str = wei.to_string();
let len = wei_str.len();
if len <= 18 {
// Pad with zeros
let padded = format!("{:0>18}", wei_str);
let result = format!("0.{}", padded.trim_end_matches('0'));
// Handle case where all decimals were trimmed (e.g., "0." -> "0")
if result == "0." {
"0".to_string()
} else {
result
}
} else {
// Split into integral and decimal parts
let integral = &wei_str[..len - 18];
let decimal = &wei_str[len - 18..];
let trimmed_decimal = decimal.trim_end_matches('0');
if trimmed_decimal.is_empty() {
integral.to_string()
} else {
format!("{}.{}", integral, trimmed_decimal)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_wei_to_eth() {
// 1 ETH
let one_eth = U256::from(1_000_000_000_000_000_000u64);
assert_eq!(wei_to_eth(&one_eth), "1");
// 0.5 ETH
let half_eth = U256::from(500_000_000_000_000_000u64);
assert_eq!(wei_to_eth(&half_eth), "0.5");
// 0.001 ETH
let milli = U256::from(1_000_000_000_000_000u64);
assert_eq!(wei_to_eth(&milli), "0.001");
// 1 Wei
let one_wei = U256::from(1u64);
assert_eq!(wei_to_eth(&one_wei), "0.000000000000000001");
// 100 Wei
let hundred_wei = U256::from(100u64);
assert_eq!(wei_to_eth(&hundred_wei), "0.0000000000000001");
// 0 Wei
let zero = U256::from(0u64);
assert_eq!(wei_to_eth(&zero), "0");
}
#[test]
fn test_calculate_path_large_fee() {
let token1: Address = "0xfdffb411c4a70aa7c95d5c981a6fb4da867e1111".parse().unwrap();
let token2: Address = "0x8d0d000ee44948fc98c9b98a4fa4921476f08b0d".parse().unwrap();
// Test large fee value (max 3 bytes)
let path = calculate_path(token1, token2, 100u64);
assert_eq!(path.to_string(), "0xfdffb411c4a70aa7c95d5c981a6fb4da867e11110000648d0d000ee44948fc98c9b98a4fa4921476f08b0d".to_string())
}
}