-
Notifications
You must be signed in to change notification settings - Fork 83
/
file.rs
153 lines (130 loc) · 5.02 KB
/
file.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! Configuration parameters that get shared across all dex solvers.
use {
crate::{
boundary::rate_limiter::RateLimitingStrategy,
domain::{dex::slippage, eth, Risk},
infra::{blockchain, config::unwrap_or_log, contracts},
util::serialize,
},
bigdecimal::BigDecimal,
serde::{de::DeserializeOwned, Deserialize},
serde_with::serde_as,
std::{fmt::Debug, num::NonZeroUsize, path::Path, time::Duration},
tokio::fs,
};
#[serde_as]
#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
struct Config {
/// The node URL to use for simulations.
#[serde_as(as = "serde_with::DisplayFromStr")]
node_url: reqwest::Url,
/// Optional CoW Protocol Settlement contract address. If not specified,
/// the default Settlement contract address will be used.
settlement: Option<eth::H160>,
/// The relative slippage allowed by the solver.
#[serde(default = "default_relative_slippage")]
#[serde_as(as = "serde_with::DisplayFromStr")]
relative_slippage: BigDecimal,
/// The absolute slippage allowed by the solver.
#[serde_as(as = "Option<serialize::U256>")]
absolute_slippage: Option<eth::U256>,
/// The number of concurrent requests to make to the DEX aggregator API.
#[serde(default = "default_concurrent_requests")]
concurrent_requests: NonZeroUsize,
/// The amount of Ether a partially fillable order should be filled for at
/// least.
#[serde(default = "default_smallest_partial_fill")]
#[serde_as(as = "serialize::U256")]
smallest_partial_fill: eth::U256,
/// Parameters used to calculate the revert risk of a solution.
/// (gas_amount_factor, gas_price_factor, nmb_orders_factor, intercept)
risk_parameters: (f64, f64, f64, f64),
/// Back-off growth factor for rate limiting.
#[serde(default = "default_back_off_growth_factor")]
back_off_growth_factor: f64,
/// Minimum back-off time in seconds for rate limiting.
#[serde(default = "default_min_back_off")]
min_back_off: u64,
/// Maximum back-off time in seconds for rate limiting.
#[serde(default = "default_max_back_off")]
max_back_off: u64,
/// Settings specific to the wrapped dex API.
dex: toml::Value,
}
fn default_relative_slippage() -> BigDecimal {
BigDecimal::new(1.into(), 2) // 1%
}
fn default_concurrent_requests() -> NonZeroUsize {
NonZeroUsize::new(1).unwrap()
}
fn default_smallest_partial_fill() -> eth::U256 {
eth::U256::exp10(16) // 0.01 ETH
}
fn default_back_off_growth_factor() -> f64 {
2.0
}
fn default_min_back_off() -> u64 {
1
}
fn default_max_back_off() -> u64 {
8
}
/// Loads the base solver configuration from a TOML file.
///
/// # Panics
///
/// This method panics if the config is invalid or on I/O errors.
pub async fn load<T: DeserializeOwned>(path: &Path) -> (super::Config, T) {
let data = fs::read_to_string(path)
.await
.unwrap_or_else(|e| panic!("I/O error while reading {path:?}: {e:?}"));
// Not printing detailed error because it could potentially leak secrets.
let config = unwrap_or_log(toml::de::from_str::<Config>(&data), &path);
let dex: T = unwrap_or_log(config.dex.try_into(), &path);
// Take advantage of the fact that deterministic deployment means that all
// CoW Protocol contracts have the same address.
let contracts = contracts::Contracts::for_chain(eth::ChainId::Mainnet);
let (settlement, authenticator) = if let Some(settlement) = config.settlement {
let authenticator = eth::ContractAddress({
let web3 = blockchain::rpc(&config.node_url);
let settlement = ::contracts::GPv2Settlement::at(&web3, settlement);
settlement
.methods()
.authenticator()
.call()
.await
.unwrap_or_else(|e| panic!("error reading authenticator contract address: {e:?}"))
});
(eth::ContractAddress(settlement), authenticator)
} else {
(contracts.settlement, contracts.authenticator)
};
let config = super::Config {
node_url: config.node_url,
contracts: super::Contracts {
settlement,
authenticator,
},
slippage: slippage::Limits::new(
config.relative_slippage,
config.absolute_slippage.map(eth::Ether),
)
.expect("invalid slippage limits"),
concurrent_requests: config.concurrent_requests,
smallest_partial_fill: eth::Ether(config.smallest_partial_fill),
risk: Risk {
gas_amount_factor: config.risk_parameters.0,
gas_price_factor: config.risk_parameters.1,
nmb_orders_factor: config.risk_parameters.2,
intercept: config.risk_parameters.3,
},
rate_limiting_strategy: RateLimitingStrategy::try_new(
config.back_off_growth_factor,
Duration::from_secs(config.min_back_off),
Duration::from_secs(config.max_back_off),
)
.unwrap(),
};
(config, dex)
}