kabu_backtest_runner/test_config/
mod.rs

1use alloy_primitives::{Address, TxHash};
2use eyre::Result;
3use kabu::types::market::PoolClass;
4use serde::Deserialize;
5use std::collections::HashMap;
6use tokio::fs;
7
8#[derive(Deserialize, Debug)]
9pub struct TestConfig {
10    pub modules: Modules,
11    pub settings: Settings,
12    pub pools: HashMap<String, PoolConfig>,
13    pub txs: HashMap<String, TransactionConfig>,
14    pub tokens: HashMap<String, TokenConfig>,
15    pub assertions: AssertionsConfig,
16}
17
18fn default_true() -> bool {
19    true
20}
21fn default_false() -> bool {
22    false
23}
24
25#[allow(dead_code)]
26#[derive(Default, Deserialize, Debug, Clone)]
27pub struct AssertionsConfig {
28    pub swaps_encoded: Option<usize>,
29    pub swaps_ok: Option<usize>,
30    pub best_profit_eth: Option<f64>,
31}
32
33#[allow(dead_code)]
34#[derive(Deserialize, Debug)]
35pub struct Modules {
36    #[serde(default = "default_true")]
37    pub price: bool,
38    #[serde(default = "default_true")]
39    pub signer: bool,
40    #[serde(default = "default_true")]
41    pub encoder: bool,
42    #[serde(default = "default_true")]
43    pub arb_path_merger: bool,
44    #[serde(default = "default_true")]
45    pub same_path_merger: bool,
46    #[serde(default = "default_true")]
47    pub diff_path_merger: bool,
48    #[serde(default)]
49    pub arb_block: bool,
50    #[serde(default = "default_true")]
51    pub arb_mempool: bool,
52    #[serde(default = "default_false")]
53    pub flashbots: bool,
54}
55
56#[allow(dead_code)]
57#[derive(Deserialize, Debug)]
58pub struct Settings {
59    pub block: u64,
60    pub coinbase: Option<Address>,
61    pub multicaller: Option<Address>,
62    #[serde(default = "default_false")]
63    pub disabled: bool,
64}
65
66#[derive(Deserialize, Debug)]
67pub struct PoolConfig {
68    #[allow(dead_code)]
69    pub address: Address,
70    pub class: PoolClass,
71}
72
73#[derive(Deserialize, Debug)]
74pub struct TransactionConfig {
75    pub hash: TxHash,
76    pub send: String,
77}
78
79#[derive(Deserialize, Debug)]
80pub struct TokenConfig {
81    pub address: Address,
82    pub symbol: Option<String>,
83    pub name: Option<String>,
84    pub decimals: Option<u8>,
85    pub basic: Option<bool>,
86    pub middle: Option<bool>,
87    pub price: Option<f64>,
88}
89
90impl TestConfig {
91    pub async fn from_file(filename: String) -> Result<TestConfig> {
92        let toml_content = fs::read_to_string(filename.as_str()).await?;
93        let config: TestConfig = toml::from_str(&toml_content)?;
94        Ok(config)
95    }
96}
97
98#[cfg(test)]
99mod test {
100    use crate::test_config::TestConfig;
101
102    #[test]
103    fn test_deserialization() {
104        let cfg = r#"
105[settings]
106block = 19101579
107coinbase = "0x1dd35b4da6534230ff53048f7477f17f7f4e7a70"
108multicaller = "0x3dd35b4da6534230ff53048f7477f17f7f4e7a70"
109
110[modules]
111
112[pools]
113a = { address = "0x2dd35b4da6534230ff53048f7477f17f7f4e7a70", class = "uniswap2" }
114
115[txs]
116tx_1 = { hash = "0xf9fb98fe76dc5f4e836cdc3d80cd7902150a8609c617064f1447c3980fd6776b", send = "mempool" }
117tx_2 = { hash = "0x1ec982c2d4eb5475192b26f7208b797328eab88f8e5be053f797f74bcb87a20c", send = "mempool" }
118
119[tokens]
120weth = { address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", symbol = "WETH", decimals = 18, basic = true, middle = false }
121
122[assertions]
123swaps_encoded = 14
124swaps_ok = 11
125best_profit_eth = 181.37
126        "#;
127        let config: TestConfig = toml::from_str(cfg).unwrap();
128        assert_eq!(config.settings.block, 19101579);
129        assert_eq!(config.assertions.swaps_encoded.unwrap_or_default(), 14);
130        assert_eq!(config.assertions.swaps_ok.unwrap_or_default(), 11);
131        assert_eq!(config.assertions.best_profit_eth.unwrap_or_default(), 181.37);
132    }
133}