arena_core/
lib.rs

1#![warn(missing_docs)]
2//! Arena
3
4/// Defines the main simulation runtime.
5pub mod arena;
6
7/// Contains configuration types for the simulation.
8pub mod config;
9
10/// Contains the types for various price processes.
11pub mod feed;
12
13/// Defines the base strategy trait.
14pub mod strategy;
15
16/// Defines core simulation logic types, such as an [`Arbitrageur`].
17pub mod engine;
18
19/// Contains error types for Arena.
20pub mod error;
21use alloy::{
22    network::{Ethereum, EthereumWallet},
23    node_bindings::{Anvil, AnvilInstance},
24    primitives::{Address, Bytes, Signed, Uint},
25    providers::{
26        fillers::{ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, WalletFiller},
27        Identity, RootProvider,
28    },
29    transports::http::{Client, Http},
30};
31
32use crate::types::controller::ArenaController::PoolKey;
33pub use crate::{
34    arena::{Arena, ArenaBuilder},
35    config::Config,
36    engine::{
37        arbitrageur::{Arbitrageur, EmptyArbitrageur},
38        inspector::{EmptyInspector, Inspector, LogMessage, Logger},
39        Engine,
40    },
41    feed::{Feed, GeometricBrownianMotion, OrnsteinUhlenbeck},
42    strategy::Strategy,
43};
44
45/// Provider type that includes all necessary fillers to execute transactions on an [`Anvil`] node.
46pub type AnvilProvider = FillProvider<
47    JoinFill<
48        JoinFill<JoinFill<JoinFill<Identity, GasFiller>, NonceFiller>, ChainIdFiller>,
49        WalletFiller<EthereumWallet>,
50    >,
51    RootProvider<Http<Client>>,
52    Http<Client>,
53    Ethereum,
54>;
55
56mod types {
57    pub mod controller {
58        use alloy_sol_macro::sol;
59        sol! {
60            #[sol(rpc)]
61            #[derive(Debug)]
62            ArenaController,
63            "src/artifacts/ArenaController.json"
64        }
65    }
66}
67
68/// A signal that is passed to a [`Strategy`] to provide information about the current state of the pool.
69#[derive(Debug, Clone)]
70pub struct Signal {
71    /// Current theoretical value of the pool.
72    pub lex_price: Uint<256, 4>,
73
74    /// Current step of the simulation.
75    pub step: Option<usize>,
76
77    /// Current tick of the pool.
78    pub tick: Signed<24, 1>,
79
80    /// Current price of the pool.
81    pub sqrt_price_x96: Uint<160, 3>,
82
83    /// Pool manager.
84    pub manager: Address,
85
86    /// Pool key.
87    pub pool: PoolKey,
88
89    /// Fetcher.
90    pub fetcher: Address,
91
92    /// Current value of the price feed.
93    pub current_value: f64,
94
95    /// The arena controller.
96    pub controller: Address,
97}
98
99impl Signal {
100    /// Public constructor function for a new [`Signal`].
101    #[allow(clippy::too_many_arguments)]
102    pub fn new(
103        lex_price: Uint<256, 4>,
104        step: Option<usize>,
105        tick: Signed<24, 1>,
106        sqrt_price_x96: Uint<160, 3>,
107        manager: Address,
108        pool: PoolKey,
109        fetcher: Address,
110        current_value: f64,
111        controller: Address,
112    ) -> Self {
113        Self {
114            lex_price,
115            step,
116            tick,
117            sqrt_price_x96,
118            manager,
119            pool,
120            fetcher,
121            current_value,
122            controller,
123        }
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use alloy::primitives::{Signed, Uint, I256};
130    use async_trait::async_trait;
131    use rug::{ops::Pow, Float};
132
133    use super::*;
134    use crate::{
135        arena::{Arena, ArenaBuilder},
136        config::Config,
137        engine::{arbitrageur::FixedArbitrageur, inspector::EmptyInspector},
138        feed::OrnsteinUhlenbeck,
139        strategy::Strategy,
140    };
141
142    struct StrategyMock;
143
144    #[async_trait]
145    impl<T> Strategy<T> for StrategyMock {
146        async fn init(
147            &self,
148            provider: AnvilProvider,
149            _signal: Signal,
150            _inspector: &mut Box<dyn Inspector<T>>,
151            engine: Engine,
152        ) {
153            engine
154                .modify_liquidity(
155                    I256::try_from(10000000).unwrap(),
156                    Signed::try_from(-887272).unwrap(),
157                    Signed::try_from(887272).unwrap(),
158                    Bytes::new(),
159                    provider,
160                )
161                .await
162                .unwrap();
163        }
164        async fn process(
165            &self,
166            _provider: AnvilProvider,
167            _signal: Signal,
168            _inspector: &mut Box<dyn Inspector<T>>,
169            _engine: Engine,
170        ) {
171        }
172    }
173
174    #[tokio::test]
175    async fn test_arena() {
176        let builder: ArenaBuilder<_> = ArenaBuilder::new();
177
178        let mut arena: Arena<_> = builder
179            .with_strategy(Box::new(StrategyMock))
180            .with_feed(Box::new(OrnsteinUhlenbeck::new(1.0, 0.1, 1.0, 0.1, 0.1)))
181            .with_inspector(Box::new(EmptyInspector {}))
182            .with_arbitrageur(Box::new(FixedArbitrageur {
183                depth: Signed::try_from(10000).unwrap(),
184            }))
185            .build();
186
187        arena
188            .run(Config::new(
189                100,
190                Uint::from(0),
191                Signed::try_from(2).unwrap(),
192                Bytes::new(),
193                Uint::from(79228162514264337593543950336_u128),
194                Uint::from(0),
195                Uint::from(1),
196                Address::ZERO,
197            ))
198            .await
199            .unwrap();
200    }
201}