From bdacbb30b789553c7733b9503b0e30e0581ef87f Mon Sep 17 00:00:00 2001 From: ts0yu <120932697+ts0yu@users.noreply.github.com> Date: Wed, 4 Sep 2024 12:34:49 +0000 Subject: [PATCH] feat: wip engine --- src/arena.rs | 14 +++++++ src/engine/arbitrageur.rs | 9 ++--- src/engine/mod.rs | 84 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 49 +++++++++++++++++++++-- src/strategy.rs | 14 ++++++- 5 files changed, 160 insertions(+), 10 deletions(-) diff --git a/src/arena.rs b/src/arena.rs index 0fc095f..edd3aca 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -15,6 +15,7 @@ use crate::{ strategy::Strategy, types::{ fetcher::Fetcher, + modify_liquidity::PoolModifyLiquidityTest, pool_manager::{PoolManager, PoolManager::PoolKey}, ArenaToken, LiquidExchange, }, @@ -56,6 +57,17 @@ impl Arena { .await .map_err(ArenaError::ContractError)?; + let lp_manager = + PoolModifyLiquidityTest::deploy(admin_provider.clone(), *pool_manager.address()) + .await + .map_err(ArenaError::ContractError)?; + + let engine = Engine { + pool: self.pool.clone().into(), + provider: admin_provider.clone(), + liquidity_manager: *lp_manager.address(), + }; + let currency_0 = ArenaToken::deploy( admin_provider.clone(), String::from("Currency 0"), @@ -136,6 +148,7 @@ impl Arena { self.providers[&(idx + 1)].clone(), signal.clone(), &mut self.inspector, + engine.clone(), ); } @@ -191,6 +204,7 @@ impl Arena { self.providers[&(idx + 1)].clone(), signal.clone(), &mut self.inspector, + engine.clone(), ); } diff --git a/src/engine/arbitrageur.rs b/src/engine/arbitrageur.rs index 3a3d1d8..7ee78bf 100644 --- a/src/engine/arbitrageur.rs +++ b/src/engine/arbitrageur.rs @@ -48,11 +48,10 @@ impl Arbitrageur for DefaultArbitrageur { let target_tick = price.log10() / base.log10(); let current_tick = Float::with_val(53, signal.tick.as_i64()); - let (start, end) = if current_tick < target_tick { - (current_tick.clone(), target_tick.clone()) - } else { - (target_tick.clone(), current_tick.clone()) - }; + let (start, end) = ( + current_tick.clone().min(&target_tick), + current_tick.clone().max(&target_tick), + ); let (a, b) = self .get_tick_range_liquidity( diff --git a/src/engine/mod.rs b/src/engine/mod.rs index c629583..83824de 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -1,5 +1,89 @@ +use alloy::{ + primitives::{Address, Signed, Uint, U256}, + providers::{Provider, WalletProvider}, +}; + +use super::*; +use crate::{ + error::ArenaError, + types::{ + fetcher::Fetcher, + modify_liquidity::{IPoolManager::ModifyLiquidityParams, PoolModifyLiquidityTest}, + pool_manager::{PoolManager, PoolManager::PoolKey}, + ArenaToken, + }, +}; /// Defines a trait for custom arbitrage strategies. pub mod arbitrageur; /// Defines a trait that allows custom strategy logging and telemetry. pub mod inspector; + +/// Type that allows the parameters of a Uniswap v4 pool to be set. +#[derive(Default, Debug, Clone)] +pub struct PoolParameters { + /// Pool fee. + pub fee: Uint<24, 1>, + + /// Pool tick spacing. + pub tick_spacing: Signed<24, 1>, + + /// Pool hooks. + pub hooks: Address, +} + +impl From for PoolParameters { + fn from(key: PoolKey) -> Self { + Self { + fee: key.fee, + tick_spacing: key.tickSpacing, + hooks: key.hooks, + } + } +} + +impl PoolParameters { + /// Public constructor function to instantiate a new `PoolParameters` struct. + pub fn new(hooks: Address, tick_spacing: Signed<24, 1>, fee: Uint<24, 1>) -> Self { + Self { + fee, + tick_spacing, + hooks, + } + } +} + +#[derive(Debug, Clone)] +pub struct Engine { + pub pool: PoolParameters, + pub(crate) provider: AnvilProvider, + pub(crate) liquidity_manager: Address, +} + +impl Engine { + pub async fn modify_liquidity( + &self, + key: PoolKey, + params: ModifyLiquidityParams, + hook_data: Bytes, + ) -> Result<(), ArenaError> { + let lp_manager = + PoolModifyLiquidityTest::new(self.liquidity_manager, self.provider.clone()); + + lp_manager + .modifyLiquidity_0(key.into(), params, hook_data, false, false) + .nonce( + self.provider + .get_transaction_count(self.provider.default_signer_address()) + .await + .unwrap(), + ) + .send() + .await + .map_err(ArenaError::ContractError)? + .watch() + .await + .map_err(|e| ArenaError::PendingTransactionError(e))?; + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index a9d69c9..f3e9ff4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,7 @@ pub use crate::{ engine::{ arbitrageur::{Arbitrageur, DefaultArbitrageur, EmptyArbitrageur}, inspector::{EmptyInspector, Inspector, LogMessage, Logger}, + Engine, PoolParameters, }, feed::{Feed, GeometricBrownianMotion, OrnsteinUhlenbeck}, strategy::Strategy, @@ -58,6 +59,7 @@ mod types { use crate::types::{ fetcher::Fetcher::PoolKey as FetcherPoolKey, + modify_liquidity::PoolModifyLiquidityTest::PoolKey as ModifyLiquidityPoolKey, pool_manager::PoolManager::PoolKey as ManagerPoolKey, swap::PoolSwapTest::PoolKey as SwapPoolKey, }; @@ -163,6 +165,30 @@ mod types { } } } + + impl From for ManagerPoolKey { + fn from(swap: ModifyLiquidityPoolKey) -> Self { + ManagerPoolKey { + currency0: swap.currency0, + currency1: swap.currency1, + fee: swap.fee, + tickSpacing: swap.tickSpacing, + hooks: swap.hooks, + } + } + } + + impl From for ModifyLiquidityPoolKey { + fn from(manager: ManagerPoolKey) -> Self { + ModifyLiquidityPoolKey { + currency0: manager.currency0, + currency1: manager.currency1, + fee: manager.fee, + tickSpacing: manager.tickSpacing, + hooks: manager.hooks, + } + } + } } /// A signal that is passed to a [`Strategy`] to provide information about the current state of the pool. @@ -216,6 +242,7 @@ impl Signal { #[cfg(test)] mod tests { use alloy::primitives::{Signed, Uint}; + use async_trait::async_trait; use super::*; use crate::{ @@ -227,23 +254,39 @@ mod tests { }, feed::OrnsteinUhlenbeck, strategy::Strategy, + types::modify_liquidity::IPoolManager::ModifyLiquidityParams, }; + use alloy::primitives::FixedBytes; struct StrategyMock; + #[async_trait] impl Strategy for StrategyMock { - fn init( + async fn init( &self, _provider: AnvilProvider, - _signal: Signal, + signal: Signal, _inspector: &mut Box>, + engine: Engine, ) { + let params = ModifyLiquidityParams { + tickLower: Signed::try_from(-2).unwrap(), + tickUpper: Signed::try_from(2).unwrap(), + liquidityDelta: Signed::try_from(1000).unwrap(), + salt: FixedBytes::ZERO, + }; + + engine + .modify_liquidity(signal.pool, params, Bytes::new()) + .await + .unwrap(); } - fn process( + async fn process( &self, _provider: AnvilProvider, _signal: Signal, _inspector: &mut Box>, + _engine: Engine, ) { } } diff --git a/src/strategy.rs b/src/strategy.rs index 10fe6de..4163ddc 100644 --- a/src/strategy.rs +++ b/src/strategy.rs @@ -1,15 +1,25 @@ +use async_trait::async_trait; + use super::*; /// Represents a strategy that can be run in an [`Arena`]. +#[async_trait] pub trait Strategy { /// Initialization function for ths strategy to be run upon simulation startup. - fn init(&self, provider: AnvilProvider, signal: Signal, inspector: &mut Box>); + async fn init( + &self, + provider: AnvilProvider, + signal: Signal, + inspector: &mut Box>, + engine: Engine, + ); /// Processing function for the strategy to be run each simulation step. - fn process( + async fn process( &self, provider: AnvilProvider, signal: Signal, inspector: &mut Box>, + engine: Engine, ); }