1use serde::{Deserialize, Serialize};
2use std::collections::btree_map::BTreeMap as Map;
3
4use rust_decimal::Decimal;
5use std::path::Path;
6
7use crate::err_custom_create;
8use crate::error::*;
9use erc20_payment_lib_common::err_create;
10use tokio::fs;
11use web3::types::Address;
12
13#[derive(Debug, Clone)]
14pub struct AdditionalOptions {
15 pub keep_running: bool,
17 pub skip_service_loop: bool,
19 pub generate_tx_only: bool,
21 pub skip_multi_contract_check: bool,
23 pub contract_use_direct_method: bool,
24 pub contract_use_unpacked_method: bool,
25 pub use_transfer_for_single_payment: bool,
26}
27
28impl Default for AdditionalOptions {
29 fn default() -> Self {
30 AdditionalOptions {
31 keep_running: true,
32 generate_tx_only: false,
33 skip_multi_contract_check: false,
34 contract_use_direct_method: false,
35 contract_use_unpacked_method: false,
36 use_transfer_for_single_payment: true,
37 skip_service_loop: false,
38 }
39 }
40}
41
42impl AdditionalOptions {
43 pub fn keep_running(&mut self, keep_running: bool) -> &mut Self {
44 self.keep_running = keep_running;
45 self
46 }
47}
48
49#[derive(Deserialize, Serialize, Debug, Clone)]
50#[serde(rename_all = "kebab-case")]
51pub struct Engine {
52 pub process_interval: u64,
53 pub process_interval_after_error: u64,
54 pub process_interval_after_no_gas_or_token_start: u64,
55 pub process_interval_after_no_gas_or_token_max: u64,
56 pub process_interval_after_no_gas_or_token_increase: f64,
57 pub process_interval_after_send: u64,
58 pub report_alive_interval: u64,
59 pub gather_interval: u64,
60 pub mark_as_unrecoverable_after_seconds: Option<u64>,
61 pub gather_at_start: bool,
62 pub automatic_recover: bool,
63 pub ignore_deadlines: bool,
64}
65
66#[derive(Deserialize, Serialize, Debug, Clone)]
67pub struct Config {
68 pub chain: Map<String, Chain>,
69 pub engine: Engine,
70}
71
72#[derive(Deserialize, Serialize, Debug, Clone)]
73#[serde(rename_all = "kebab-case")]
74pub struct MultiContractSettings {
75 pub address: Address,
76 pub max_at_once: usize,
77}
78
79#[derive(Deserialize, Serialize, Debug, Clone)]
80#[serde(rename_all = "kebab-case")]
81pub struct WrapperContractSettings {
82 pub address: Address,
83}
84
85#[derive(Deserialize, Serialize, Debug, Clone)]
86#[serde(rename_all = "kebab-case")]
87pub struct MintContractSettings {
88 pub address: Address,
89 pub max_glm_allowed: Decimal,
90}
91
92#[derive(Deserialize, Serialize, Debug, Clone)]
93#[serde(rename_all = "kebab-case")]
94pub struct LockContractSettings {
95 pub address: Address,
96}
97
98#[derive(Deserialize, Serialize, Debug, Clone)]
99#[serde(rename_all = "kebab-case")]
100pub struct DistributorContractSettings {
101 pub address: Address,
102}
103
104#[derive(Deserialize, Serialize, Debug, Clone)]
105#[serde(rename_all = "kebab-case")]
106pub struct EasContractSettings {
107 pub address: Address,
108}
109
110#[derive(Deserialize, Serialize, Debug, Clone)]
111#[serde(rename_all = "kebab-case")]
112pub struct EasSchemaRegistrySettings {
113 pub address: Address,
114}
115
116#[derive(Deserialize, Serialize, Debug, Clone)]
117#[serde(rename_all = "kebab-case")]
118pub struct FaucetClientSettings {
119 pub max_eth_allowed: Decimal,
120 pub faucet_srv: String,
121 pub faucet_host: String,
122 pub faucet_srv_port: u16,
123 pub faucet_lookup_domain: String,
124}
125
126#[derive(Deserialize, Serialize, Debug, Clone)]
127#[serde(rename_all = "kebab-case")]
128pub struct RpcSettings {
129 pub names: Option<String>,
130 pub endpoints: Option<String>,
131 pub dns_source: Option<String>,
132 pub json_source: Option<String>,
133 pub skip_validation: Option<bool>,
134 pub backup_level: Option<i64>,
135 pub verify_interval_secs: Option<u64>,
136 pub min_interval_ms: Option<u64>,
137 pub max_timeout_ms: Option<u64>,
138 pub allowed_head_behind_secs: Option<i64>,
139 pub max_consecutive_errors: Option<u64>,
140}
141
142#[derive(Deserialize, Serialize, Debug, Clone)]
143#[serde(rename_all = "kebab-case")]
144pub struct Chain {
145 pub chain_name: String,
146 pub chain_id: i64,
147 pub rpc_endpoints: Vec<RpcSettings>,
148 pub currency_symbol: String,
149 pub priority_fee: Decimal,
150 pub max_fee_per_gas: Decimal,
151 pub token: Token,
152 pub multi_contract: Option<MultiContractSettings>,
153 pub wrapper_contract: Option<WrapperContractSettings>,
154 pub mint_contract: Option<MintContractSettings>,
155 pub lock_contract: Option<LockContractSettings>,
156 pub distributor_contract: Option<DistributorContractSettings>,
157 pub attestation_contract: Option<EasContractSettings>,
158 pub schema_registry_contract: Option<EasSchemaRegistrySettings>,
159 pub faucet_client: Option<FaucetClientSettings>,
160 pub transaction_timeout: u64,
161 pub confirmation_blocks: u64,
162 pub faucet_eth_amount: Option<Decimal>,
163 pub faucet_glm_amount: Option<Decimal>,
164 pub block_explorer_url: Option<String>,
165 pub replacement_timeout: Option<f64>,
166 pub external_source_check_interval: Option<u64>,
167}
168
169#[derive(Deserialize, Serialize, Debug, Clone)]
170pub struct Token {
171 pub symbol: String,
172 pub address: Address,
173 pub faucet: Option<Address>,
174}
175
176impl Config {
177 pub fn default_config_str() -> &'static str {
178 let config = include_str!("../config-payments.toml");
180 config
181 }
182
183 pub fn default_config() -> Self {
184 Self::load_from_str(Self::default_config_str()).unwrap()
186 }
187
188 pub fn load_from_str(str: &str) -> Result<Self, PaymentError> {
189 match toml::from_str(str) {
190 Ok(config) => Ok(config),
191 Err(e) => Err(err_custom_create!("Failed to parse toml {}: {}", str, e)),
192 }
193 }
194
195 pub async fn load<P: AsRef<Path>>(path: P) -> Result<Self, PaymentError> {
196 match toml::from_str(&String::from_utf8_lossy(&fs::read(&path).await.map_err(
197 |e| match e.kind() {
198 std::io::ErrorKind::NotFound => {
199 err_create!(e)
200 }
201 _ => {
202 err_custom_create!(
203 "Failed to read config file {}. Error {}",
204 path.as_ref().display(),
205 e
206 )
207 }
208 },
209 )?)) {
210 Ok(config) => Ok(config),
211 Err(e) => Err(err_custom_create!(
212 "Failed to parse toml {}: {}",
213 path.as_ref().display(),
214 e
215 )),
216 }
217 }
218
219 pub async fn change_rpc_endpoints(
220 &mut self,
221 chain: &str,
222 rpc_endpoints: Vec<RpcSettings>,
223 ) -> Result<(), PaymentError> {
224 self.chain
225 .get_mut(chain)
226 .ok_or(err_custom_create!("Chain {} not found", chain))?
227 .rpc_endpoints = rpc_endpoints;
228 Ok(())
229 }
230
231 pub async fn change_max_fee(
232 &mut self,
233 chain: &str,
234 max_fee_per_gas: Decimal,
235 ) -> Result<(), PaymentError> {
236 self.chain
237 .get_mut(chain)
238 .ok_or(err_custom_create!("Chain {} not found", chain))?
239 .max_fee_per_gas = max_fee_per_gas;
240 Ok(())
241 }
242}