From dd6562e39b5f3bbea1b7210213e748421cfedcbe Mon Sep 17 00:00:00 2001 From: dvisacker Date: Sun, 13 Oct 2024 22:15:49 +0900 Subject: [PATCH] feat - implement leverage function on the CLI --- Makefile | 2 +- contracts/script/Leverage.s.sol | 2 +- contracts/src/AaveLooper.sol | 16 ++++++------- src/bot.rs | 41 ++++++++++++++++++++++++++++++++- src/cli.rs | 34 +++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index fca66ec..9747a5e 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ forge-clean: # This command will generate an error (no cargo.toml) that can be ignored because we are generating the bindings in a subcrate of the src folder forge-bind: @echo "Generating Rust bindings for Solidity contracts..." - @cd $(CONTRACTS_DIR) && forge bind --alloy --bindings-path ../src/bindings --crate-name bindings --alloy-version 0.3.3 --module + @cd $(CONTRACTS_DIR) && forge bind --alloy --bindings-path ../src/bindings --alloy-version 0.3.3 --module deploy: @echo "Deploying AaveLooper..." diff --git a/contracts/script/Leverage.s.sol b/contracts/script/Leverage.s.sol index 2fb5376..2af7a59 100644 --- a/contracts/script/Leverage.s.sol +++ b/contracts/script/Leverage.s.sol @@ -28,7 +28,7 @@ contract Leverage is Script { vm.startBroadcast(); ERC20(supplyAsset).approve(aaveLooper, initialAmount); - uint256 liquidity = looper.enterPosition(supplyAsset, borrowAsset, initialAmount, iterations, 500); + uint256 liquidity = looper.leverage(supplyAsset, borrowAsset, initialAmount, iterations, 500); vm.stopBroadcast(); console2.log("Entered position. Final liquidity:", liquidity); diff --git a/contracts/src/AaveLooper.sol b/contracts/src/AaveLooper.sol index 5a2d1fb..895fffa 100644 --- a/contracts/src/AaveLooper.sol +++ b/contracts/src/AaveLooper.sol @@ -177,12 +177,12 @@ contract AaveLooper is ImmutableOwnable { * @param iterations - Loop count * @return Liquidity at end of the loop */ - function enterPositionFully(address supplyAsset, address borrowAsset, uint256 iterations, uint24 feeTier) + function leverageFully(address supplyAsset, address borrowAsset, uint256 iterations, uint24 feeTier) external onlyOwner returns (uint256) { - return enterPosition(supplyAsset, borrowAsset, ERC20(supplyAsset).balanceOf(msg.sender), iterations, feeTier); + return leverage(supplyAsset, borrowAsset, ERC20(supplyAsset).balanceOf(msg.sender), iterations, feeTier); } function getBestFeeTier(address factory, address tokenIn, address tokenOut, uint256 amountIn) @@ -211,13 +211,11 @@ contract AaveLooper is ImmutableOwnable { * @param feeTier - Fee tier for the swap * @return Liquidity at end of the loop */ - function enterPosition( - address supplyAsset, - address borrowAsset, - uint256 principal, - uint256 iterations, - uint24 feeTier - ) public onlyOwner returns (uint256) { + function leverage(address supplyAsset, address borrowAsset, uint256 principal, uint256 iterations, uint24 feeTier) + public + onlyOwner + returns (uint256) + { if (principal > 0) { ERC20(supplyAsset).transferFrom(msg.sender, address(this), principal); } diff --git a/src/bot.rs b/src/bot.rs index e0cda6f..9d6ffa4 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -1,11 +1,13 @@ use crate::provider::SignerProvider; use alloy::sol; use alloy::{providers::WalletProvider, transports::BoxTransport}; +use alloy_primitives::aliases::U24; use alloy_primitives::{Address, U256}; use std::error::Error; use std::sync::Arc; use std::time::Duration; use tokio::time; +use AaveLooper::AaveLooperInstance; use ILendingPool::ILendingPoolInstance; use IERC20::IERC20Instance; @@ -26,8 +28,16 @@ sol! { } } +sol!( + #[sol(rpc)] + #[derive(Debug, PartialEq, Eq)] + AaveLooper, + "./contracts/out/AaveLooper.sol/AaveLooper.json" +); + type Token = IERC20Instance>; type LendingPool = ILendingPoolInstance>; +type Looper = AaveLooperInstance>; pub struct AaveBot { provider: Arc, @@ -35,6 +45,7 @@ pub struct AaveBot { asset_address: Address, lending_pool: LendingPool, asset: Token, + looper: Looper, max_amount: U256, leverage: u8, threshold: U256, @@ -56,13 +67,18 @@ impl AaveBot { let lending_pool = ILendingPool::new(aave_address, provider.clone()); let asset = IERC20::new(asset_address, provider.clone()); let signer_address = provider.default_signer_address(); - // let telegram_bot = Bot::new(telegram_token); + + // Initialize the AaveLooper contract + // Note: You'll need to deploy this contract and get its address + let looper_address = Address::from_str("YOUR_DEPLOYED_AAVELOOPER_ADDRESS_HERE")?; + let looper = AaveLooper::new(looper_address, provider.clone()); Ok(Arc::new(Self { provider, signer_address, lending_pool, asset, + looper, asset_address, max_amount, leverage, @@ -236,4 +252,27 @@ impl AaveBot { // .await?; Ok(()) } + + pub async fn leverage( + &self, + asset_address: Address, + amount: U256, + ) -> Result<(), Box> { + // First, approve the AaveLooper contract to spend tokens on our behalf + self.approve_tokens(asset_address, amount).await?; + + // Call the leverage function on the AaveLooper contract + let tx = self.looper.leverage( + asset_address, // supplyAsset + asset_address, // borrowAsset (same as supply in this case) + amount, // principal + U256::from(1), // iterations (you can adjust this as needed) + U24::from(500), // feeTier (0.3% fee tier for Uniswap V3, adjust if needed) + ); + + let receipt = tx.send().await?.get_receipt().await?; + println!("Increased leverage: {:?}", receipt); + + Ok(()) + } } diff --git a/src/cli.rs b/src/cli.rs index 85c4ecc..48083b2 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -51,6 +51,12 @@ enum Commands { #[arg(short, long)] token: String, }, + Leverage { + #[arg(short, long)] + amount: u64, + #[arg(short, long)] + token: String, + }, } pub async fn run_cli(provider: Arc) -> Result<(), Box> { @@ -201,6 +207,34 @@ pub async fn run_cli(provider: Arc) -> Result<(), Box bot.repay_tokens(asset_address, amount_wei).await?; println!("Repay successful!"); } + Commands::Leverage { amount, token } => { + let aave_address = get_aave_lending_pool_address(chain).ok_or_else(|| { + Box::::from("Aave lending pool address not found for this chain") + })?; + let asset_address = get_token_address(chain, token).ok_or_else(|| { + Box::::from(format!("{} address not found for this chain", token)) + })?; + let amount_wei = U256::from(*amount) * U256::from(10).pow(U256::from(6)); // Assuming 6 decimals, adjust if needed + + let bot = AaveBot::new( + provider.clone(), + aave_address, + asset_address, + amount_wei, + 1, // Leverage not used for this operation + U256::from(0), // Threshold not used for this operation + String::new(), + 0, + ) + .await?; + + println!( + "Increasing leverage by borrowing {} {} and supplying it back...", + amount, token + ); + bot.leverage(asset_address, amount_wei).await?; + println!("Leverage increased successfully!"); + } } Ok(())