-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
111 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<dyn Error>> { | ||
let http_provider = Provider::<Http>::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<Arc<IUniswapV2Pair<Provider<Http>>>, Box<dyn Error>> { | ||
let pair_address = address.parse::<Address>() | ||
.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<IUniswapV2Pair<Provider<Http>>>, name: String| async move { | ||
let (reserve0, reserve1, _) = pair.get_reserves().call().await?; | ||
println!( | ||
"Reserves in {} (Token1, Token2): {}, {}", | ||
name, reserve0, reserve1 | ||
); | ||
Ok::<_, Box<dyn Error>>((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(()) | ||
} |