From 7b4662aa7dbd4086707c710ecb8deceb460caad5 Mon Sep 17 00:00:00 2001 From: ts0yu <120932697+ts0yu@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:40:21 +0000 Subject: [PATCH] chore(refactor): docs --- src/arena.rs | 48 +++++++++++++++++++++++++++++++++++-- src/config.rs | 3 +++ src/feed.rs | 10 ++++---- src/lib.rs | 63 +++++++++++++++++++++++++++++++++++++++++++------ src/strategy.rs | 8 +++++-- src/types.rs | 21 ----------------- 6 files changed, 117 insertions(+), 36 deletions(-) delete mode 100644 src/types.rs diff --git a/src/arena.rs b/src/arena.rs index 483f440..902310a 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -10,16 +10,25 @@ use crate::{ types::{PoolManager, PoolManager::PoolKey}, }; +/// Represents an [`Arena`] that can be used to run a simulation and execute strategies. pub struct Arena { + /// The underlying Anvil execution environment. pub env: AnvilInstance, + + /// The strategies that are to be run in the simulation. pub strategies: Vec>, + + /// The pool that the strategies are to be run against, and the arbitrageur to peg. pub pool: PoolKey, + + /// The feed that provides the current, theoretical value of the pool. pub feed: Box, providers: HashMap, } impl Arena { + /// Run all strategies in the simulation with a given configuration. pub async fn run(&mut self, config: Config) { let admin_provider = self.providers[&0].clone(); @@ -38,12 +47,28 @@ impl Arena { .unwrap(); for (idx, strategy) in self.strategies.iter_mut().enumerate() { - strategy.init(self.providers[&(idx + 1)].clone()); + strategy.init( + self.providers[&(idx + 1)].clone(), + Signal::new( + *pool_manager.address(), + self.pool.clone(), + self.feed.current_value(), + None, + ), + ); } for step in 0..config.steps { for (idx, strategy) in self.strategies.iter_mut().enumerate() { - strategy.process(self.providers[&(idx + 1)].clone()); + strategy.process( + self.providers[&(idx + 1)].clone(), + Signal::new( + *pool_manager.address(), + self.pool.clone(), + self.feed.current_value(), + Some(step), + ), + ); } self.feed.step(); @@ -51,16 +76,31 @@ impl Arena { } } +/// A builder for an [`Arena`] that can be used to configure the simulation. pub struct ArenaBuilder { + /// [`Arena::env`] pub env: AnvilInstance, + + /// [`Arena::strategies`] pub strategies: Vec>, + + /// [`Arena::pool`] pub pool: Option, + + /// [`Arena::feed`] pub feed: Option>, providers: Option>, } +impl Default for ArenaBuilder { + fn default() -> Self { + Self::new() + } +} + impl ArenaBuilder { + /// Public constructor function for a new [`ArenaBuilder`]. pub fn new() -> Self { ArenaBuilder { env: Anvil::default().spawn(), @@ -71,21 +111,25 @@ impl ArenaBuilder { } } + /// Add a strategy to the simulation. pub fn with_strategy(mut self, strategy: Box) -> Self { self.strategies.push(strategy); self } + /// Set the pool that the strategies are to be run against. pub fn with_pool(mut self, pool: PoolKey) -> Self { self.pool = Some(pool); self } + /// Set the feed that provides the current, theoretical value of the pool. pub fn with_feed(mut self, feed: Box) -> Self { self.feed = Some(feed); self } + /// Build the [`Arena`] with the given configuration. pub fn build(self) -> Arena { let mut providers = HashMap::new(); diff --git a/src/config.rs b/src/config.rs index 6648244..135d271 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,8 +1,11 @@ +/// Configuration for the simulation. pub struct Config { + /// Number of steps to run the simulation for. pub steps: usize, } impl Config { + /// Public constructor function for a new [`Config`]. pub fn new(steps: usize) -> Self { Config { steps } } diff --git a/src/feed.rs b/src/feed.rs index 654ce4a..1e2015e 100644 --- a/src/feed.rs +++ b/src/feed.rs @@ -11,23 +11,25 @@ pub trait Feed { } #[derive(Debug)] +/// Implementation of an Ornstein-Uhlenbeck process using a Euler-Maruyama discretization scheme. pub struct OrnsteinUhlenbeck { current_value: f64, - /// Mean reversion rate + /// Mean reversion rate. theta: f64, - /// Long-term mean + /// Long-term mean. mu: f64, - // Volatility + /// Volatility. sigma: f64, - // Time step + /// Time step. dt: f64, } impl OrnsteinUhlenbeck { + /// Public constructor function for a new [`OrnsteinUhlenbeck`]. pub fn new(initial_value: f64, theta: f64, mu: f64, sigma: f64, dt: f64) -> Self { OrnsteinUhlenbeck { current_value: initial_value, diff --git a/src/lib.rs b/src/lib.rs index 9b7e70b..40968ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,18 @@ +#![warn(missing_docs)] +#[doc = include_str!("../README.md")] + +/// Defines the main simulation runtime. pub mod arena; + +/// Contains configuration types for the simulation. pub mod config; + +/// Contains the types for various price processes. pub mod feed; + +/// Defines the base strategy trait. pub mod strategy; -pub mod types; + use alloy::{ network::{Ethereum, EthereumWallet}, node_bindings::{Anvil, AnvilInstance}, @@ -14,11 +24,9 @@ use alloy::{ transports::http::{Client, Http}, }; -use crate::{ - arena::ArenaBuilder, config::Config, feed::OrnsteinUhlenbeck, strategy::Strategy, - types::PoolManager::PoolKey, -}; +use crate::types::PoolManager::PoolKey; +/// Provider type that includes all necessary fillers to execute transactions on an [`Anvil`] node. pub type AnvilProvider = FillProvider< JoinFill< JoinFill, NonceFiller>, ChainIdFiller>, @@ -29,15 +37,56 @@ pub type AnvilProvider = FillProvider< Ethereum, >; +mod types { + use alloy_sol_macro::sol; + + #[allow(missing_docs)] + sol! { + #[sol(rpc)] + #[derive(Debug)] + PoolManager, + "contracts/v4-core/out/PoolManager.sol/PoolManager.json" + } +} + +/// A signal that is passed to a [`Strategy`] to provide information about the current state of the pool. +#[derive(Debug, Clone)] +pub struct Signal { + /// Address of the pool manager. + pub manager: Address, + + /// Key of the pool. + pub pool: PoolKey, + + /// Current theoretical value of the pool. + pub current_value: f64, + + /// Current step of the simulation. + pub step: Option, +} + +impl Signal { + /// Public constructor function for a new [`Signal`]. + pub fn new(manager: Address, pool: PoolKey, current_value: f64, step: Option) -> Self { + Self { + manager, + pool, + current_value, + step, + } + } +} + #[cfg(test)] mod tests { use super::*; + use crate::{arena::ArenaBuilder, config::Config, feed::OrnsteinUhlenbeck, strategy::Strategy}; struct StrategyMock; impl Strategy for StrategyMock { - fn init(&self, _provider: AnvilProvider) {} - fn process(&self, _provider: AnvilProvider) {} + fn init(&self, _provider: AnvilProvider, _signal: Signal) {} + fn process(&self, _provider: AnvilProvider, _signal: Signal) {} } #[tokio::test] diff --git a/src/strategy.rs b/src/strategy.rs index 933d4f0..31f0bc7 100644 --- a/src/strategy.rs +++ b/src/strategy.rs @@ -1,6 +1,10 @@ use super::*; +/// Represents a strategy that can be run in an [`Arena`]. pub trait Strategy { - fn init(&self, provider: AnvilProvider); - fn process(&self, provider: AnvilProvider); + /// Initialization function for ths strategy to be run upon simulation startup. + fn init(&self, provider: AnvilProvider, signal: Signal); + + /// Processing function for the strategy to be run each simulation step. + fn process(&self, provider: AnvilProvider, signal: Signal); } diff --git a/src/types.rs b/src/types.rs deleted file mode 100644 index 247f1c9..0000000 --- a/src/types.rs +++ /dev/null @@ -1,21 +0,0 @@ -use alloy_sol_macro::sol; - -sol! { - type Currency is address; - - #[derive(Debug)] - struct PoolKey { - Currency currency0; - Currency currency1; - uint24 fee; - int24 tickSpacing; - address hooks; - } -} - -sol! { - #[sol(rpc)] - #[derive(Debug)] - PoolManager, - "contracts/v4-core/out/PoolManager.sol/PoolManager.json" -}