1#![warn(missing_docs)]
2pub mod arena;
6
7pub mod config;
9
10pub mod feed;
12
13pub mod strategy;
15
16pub mod engine;
18
19pub 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
45pub 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#[derive(Debug, Clone)]
70pub struct Signal {
71 pub lex_price: Uint<256, 4>,
73
74 pub step: Option<usize>,
76
77 pub tick: Signed<24, 1>,
79
80 pub sqrt_price_x96: Uint<160, 3>,
82
83 pub manager: Address,
85
86 pub pool: PoolKey,
88
89 pub fetcher: Address,
91
92 pub current_value: f64,
94
95 pub controller: Address,
97}
98
99impl Signal {
100 #[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}