From 95f1e0322e85847af7bc90d9f217f2a446159b13 Mon Sep 17 00:00:00 2001 From: codeesura Date: Mon, 11 Dec 2023 15:27:41 +0300 Subject: [PATCH] new feature --- Cargo.toml | 5 ++ README.md | 43 ++++++++--------- src/main.rs | 130 +++++++++++++++++++++++++++++++++++----------------- 3 files changed, 111 insertions(+), 67 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 14e48e1..364bc5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +ethers = "2.0" +tokio = { version = "1.32", features = ["full"] } +serde = "1.0" +serde_json = "1.0" +eyre = "0.6" \ No newline at end of file diff --git a/README.md b/README.md index 586f962..4161bd3 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,26 @@ -# Optimal ETH Trade Profit Calculator +# Crypto Arbitrage Analyzer -This repository contains a Rust program that simulates trade scenarios between two exchanges and calculates the maximum possible profit and the corresponding amount of Ethereum (ETH) needed to achieve that profit. +This repository houses a Rust-based application purpose-built to scrutinize and juxtapose cryptocurrency pairs on Uniswap and Sushiswap. It is specifically developed to compute the reserves and prices of ETH/USDC pairs across both exchanges and pinpoint prospective arbitrage possibilities. -## Background +## Features +- Procures real-time reserve information for ETH/USDC pairs hailing from Uniswap and Sushiswap. +- Determines the prevailing value of WETH in terms of USDC on both exchanges. +- Discovers potential arbitrage prospects by contrasting prices. +- Leverages the robust async and concurrency support in Rust for efficient data maneuvering. +- Guarantees precision and security with Rust's stringent type system and ownership construct. -Cryptocurrency exchanges don't always have the same prices for the same assets. This difference is due to the supply and demand of each asset in each exchange. These discrepancies can create opportunities for what is known as arbitrage trading, which is the practice of buying an asset at a lower price in one market and selling it at a higher price in another. +## Usage +To leverage this tool, clone the repository and kickstart the application using `cargo run` command in Rust. Ensure Rust is set up on your system. -This code simulates a simple scenario where a trader has an initial amount of ETH and wants to see the potential profit from performing arbitrage trading between two exchanges. +## Dependencies +- [`ethers-rs`](https://github.com/gakonst/ethers-rs): A comprehensive Ethereum and Celo library and wallet crafted in Rust. +- Miscellaneous standard Rust libraries and ancillary async support. -## Implementation +## Contributions +Contributions are appreciated! Feel free to submit a pull request or initiate an issue for any enhancements or proposals. -The program calculates the profit that can be obtained by selling an increasing amount of ETH in the first exchange for USDC (a stablecoin pegged to the USD), and then using the USDC to buy back ETH in the second exchange. The maximum profit is achieved when the profit stops increasing. +## License +This project falls under the [MIT License](LICENSE). -The exchanges have a mechanism called "Automated Market Makers" (AMMs), which adjust the price of the assets according to their reserves. The code simulates the behavior of AMMs and calculates the new reserves after each transaction. - -The `reserve1_eth`, `reserve1_usdc`, `reserve2_eth`, and `reserve2_usdc` variables represent the initial reserves of ETH and USDC in the first and second exchanges, respectively. - -The `amount_eth_start` and `amount_eth_increment` variables control the increment of the amount of ETH to be sold in each iteration. The loop will stop once the profit stops increasing, indicating that the optimal amount of ETH to sell has been found. - -Finally, the maximum profit and the corresponding amount of ETH to sell are printed out. - -## How to Run - -To run the program, you will need to have Rust installed. After you have installed Rust, you can run the program by navigating to the project directory and using the command: - -```sh -cargo run -``` - -This will compile and run the program, outputting the maximum profit and corresponding amount of ETH to the console. +## Disclaimer +This tool is for educational objectives only. Users are urged to exercise due diligence and perform comprehensive research while trading or investigating cryptocurrency markets. \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 5c7ce24..1f68923 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,46 +1,90 @@ -fn main() { - // Reserves of ETH and USDC in the first exchange - let (reserve1_eth, reserve1_usdc) = (3586.0, 6454800.0); - // Reserves of ETH and USDC in the second exchange - let (reserve2_eth, reserve2_usdc) = (1123.0, 1998940.0); - - // Initial amount of ETH - let mut amount_eth_start = 0.0; - // Amount of ETH to be added in each iteration - let amount_eth_increment = 0.00001; - - // Maximum profit - let mut max_profit = 0.0; - - // Loop 500,000 times - for _ in 0..500000 { - // Increase the amount of ETH in each iteration - amount_eth_start += amount_eth_increment; - - // Calculate the new ETH reserves - let new_reserve1_eth = reserve1_eth - amount_eth_start; - // Calculate the new USDC reserves and the amount of USDC received - let new_reserve1_usdc = (reserve1_eth * reserve1_usdc) / (reserve1_eth + amount_eth_start); - let received_usdc = reserve1_usdc - new_reserve1_usdc; - - // Calculate the new USDC reserves - let new_reserve2_usdc = reserve2_usdc + received_usdc; - // Calculate the new ETH reserves and the amount of ETH received - let new_reserve2_eth = (reserve2_eth * reserve2_usdc) / (reserve2_usdc + received_usdc); - let received_eth = reserve2_eth - new_reserve2_eth; - - // Calculate the profit - let profit = received_eth - amount_eth_start; - - // If the profit is greater than the current maximum profit, update the maximum profit - if profit > max_profit { - max_profit = profit; - } else { - // If the profit stops increasing, stop the loop - break; - } +use ethers::{ + contract::abigen, + prelude::*, + providers::{Http, Provider}, +}; +use std::{error::Error, sync::Arc}; + +// Define the contract binding +abigen!( + IUniswapV2Pair, + r#"[ + function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) + ]"#, +); + +const USDC_DECIMAL: u128 = 1_000_000; // 6 decimals for USDC +const ETH_DECIMAL: u128 = 1_000_000_000_000_000_000; // 18 decimals for ETH + +#[tokio::main] +async fn main() -> Result<(), Box> { + let http_provider = Provider::::try_from("https://eth.llamarpc.com")?; + let shared_provider = Arc::new(http_provider); + + // Function to create a Uniswap pair + let create_pair = |address: &str| -> Result>>, Box> { + let pair_address = address.parse::
() + .map_err(|_| "Invalid address for pair")?; + Ok(Arc::new(IUniswapV2Pair::new(pair_address, Arc::clone(&shared_provider)))) + }; + + let uniswap_pair = create_pair("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc")?; + let sushiswap_pair = create_pair("0x397ff1542f962076d0bfe58ea045ffa2d347aca0")?; + + let print_reserves = |pair: Arc>>, name: String| async move { + let (reserve0, reserve1, _) = pair.get_reserves().call().await?; + println!( + "Reserves in {} (Token1, Token2): {}, {}", + name, reserve0, reserve1 + ); + Ok::<_, Box>((reserve0, reserve1)) + }; + + let (reserves_usdc_uniswap, reserves_weth_uniswap) = print_reserves(uniswap_pair, "Uniswap".to_string()).await?; + let (reserves_usdc_sushiswap, reserves_weth_sushiswap) = print_reserves(sushiswap_pair, "Sushiswap".to_string()).await?; + + let calculate_price = |reserves_usdc: u128, reserves_weth: u128| -> f64 { + (reserves_usdc as f64 / USDC_DECIMAL as f64) / (reserves_weth as f64 / ETH_DECIMAL as f64) + }; + + let uniswap_price = calculate_price(reserves_usdc_uniswap, reserves_weth_uniswap); + let sushiswap_price = calculate_price(reserves_usdc_sushiswap, reserves_weth_sushiswap); + println!( + "Uniswap WETH price: {} USDC \nSushiswap WETH price: {} USDC", + uniswap_price, sushiswap_price + ); + + let fee_ratio: f64 = 1.0; + if uniswap_price < sushiswap_price { + let exchange_amount_uniswap = reserves_weth_uniswap as f64 * reserves_usdc_sushiswap as f64 + / ((reserves_usdc_sushiswap as f64) + (reserves_usdc_uniswap as f64) * fee_ratio); + let exchange_amount_sushiswap = + fee_ratio * reserves_usdc_uniswap as f64 * reserves_weth_sushiswap as f64 + / ((reserves_usdc_sushiswap as f64) + (reserves_usdc_uniswap as f64) * fee_ratio); + + let optimal_delta = (exchange_amount_sushiswap * exchange_amount_uniswap * fee_ratio) + .sqrt() + - exchange_amount_sushiswap; + println!( + "Optimal Delta (Buy Uniswap, sell Sushiswap): {} WETH", + optimal_delta / fee_ratio / ETH_DECIMAL as f64 + ); + } else { + let exchange_amount_sushiswap = reserves_weth_sushiswap as f64 + * reserves_usdc_uniswap as f64 + / ((reserves_usdc_uniswap as f64) + (reserves_usdc_sushiswap as f64) * fee_ratio); + let exchange_amount_uniswap = + fee_ratio * reserves_usdc_sushiswap as f64 * reserves_weth_uniswap as f64 + / ((reserves_usdc_uniswap as f64) + (reserves_usdc_sushiswap as f64) * fee_ratio); + + let optimal_delta = (exchange_amount_uniswap * exchange_amount_sushiswap * fee_ratio) + .sqrt() + - exchange_amount_uniswap; + println!( + "Optimal Delta (Buy Sushiswap, sell Uniswap): {} WETH", + optimal_delta / fee_ratio / ETH_DECIMAL as f64 + ); } - // Print the maximum profit and the corresponding amount of ETH - println!("Maximum profit: {}, Corresponding amount of ETH: {}", max_profit, amount_eth_start); + Ok(()) }