1#![allow(clippy::expect_used)]
11#![allow(clippy::enum_variant_names)]
13
14use crate::common::{Address, Amount};
15use crate::contract::merkle_payment_vault::error::Error as MerklePaymentError;
16use crate::contract::merkle_payment_vault::handler::MerklePaymentVaultHandler;
17use crate::merkle_batch_payment::PoolCommitment;
18use crate::utils::{get_evm_network, http_provider};
19use alloy::primitives::address;
20use alloy::transports::http::reqwest;
21use serde::{Deserialize, Serialize};
22use serde_with::{DisplayFromStr, serde_as};
23use std::str::FromStr;
24use std::sync::LazyLock;
25
26#[macro_use]
27extern crate tracing;
28
29pub mod common;
30pub mod contract;
31pub mod cryptography;
32#[cfg(feature = "external-signer")]
33pub mod external_signer;
34pub mod merkle_batch_payment;
35pub mod quoting_metrics;
36mod retry;
37pub mod testnet;
38pub mod transaction_config;
39pub mod utils;
40pub mod wallet;
41
42pub use retry::GasInfo;
44
45const TX_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(24); static PUBLIC_ARBITRUM_ONE_HTTP_RPC_URL: LazyLock<reqwest::Url> = LazyLock::new(|| {
49 "https://arb1.arbitrum.io/rpc"
50 .parse()
51 .expect("Invalid RPC URL")
52});
53
54static PUBLIC_ARBITRUM_SEPOLIA_HTTP_RPC_URL: LazyLock<reqwest::Url> = LazyLock::new(|| {
55 "https://sepolia-rollup.arbitrum.io/rpc"
56 .parse()
57 .expect("Invalid RPC URL")
58});
59
60const ARBITRUM_ONE_PAYMENT_TOKEN_ADDRESS: Address =
61 address!("a78d8321B20c4Ef90eCd72f2588AA985A4BDb684");
62
63const ARBITRUM_SEPOLIA_TEST_PAYMENT_TOKEN_ADDRESS: Address =
64 address!("4bc1aCE0E66170375462cB4E6Af42Ad4D5EC689C");
65
66const ARBITRUM_ONE_DATA_PAYMENTS_ADDRESS: Address =
67 address!("B1b5219f8Aaa18037A2506626Dd0406a46f70BcC");
68
69const ARBITRUM_SEPOLIA_TEST_DATA_PAYMENTS_ADDRESS: Address =
70 address!("7f0842a78f7d4085d975ba91d630d680f91b1295");
71
72const ARBITRUM_ONE_MERKLE_PAYMENTS_ADDRESS: Address =
73 address!("0x8c20E9A6e5e2aA038Ed463460E412B669fE712Aa");
74
75const ARBITRUM_SEPOLIA_TEST_MERKLE_PAYMENTS_ADDRESS: Address =
76 address!("0x393F6825C248a29295A7f9Bfa03e475decb44dc0");
77
78#[serde_as]
79#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
80pub struct CustomNetwork {
81 #[serde_as(as = "DisplayFromStr")]
82 pub rpc_url_http: reqwest::Url,
83 pub payment_token_address: Address,
84 pub data_payments_address: Address,
85 pub merkle_payments_address: Option<Address>,
86}
87
88impl CustomNetwork {
89 pub fn new(
90 rpc_url: &str,
91 payment_token_addr: &str,
92 data_payments_addr: &str,
93 merkle_payments_addr: Option<&str>,
94 ) -> Self {
95 Self {
96 rpc_url_http: reqwest::Url::parse(rpc_url).expect("Invalid RPC URL"),
97 payment_token_address: Address::from_str(payment_token_addr)
98 .expect("Invalid payment token address"),
99 data_payments_address: Address::from_str(data_payments_addr)
100 .expect("Invalid chunk payments address"),
101 merkle_payments_address: merkle_payments_addr
102 .map(|addr| Address::from_str(addr).expect("Invalid merkle payments address")),
103 }
104 }
105}
106
107#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
108pub enum Network {
109 #[default]
110 ArbitrumOne,
111 ArbitrumSepoliaTest,
112 Custom(CustomNetwork),
113}
114
115impl std::fmt::Display for Network {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 match self {
118 Network::ArbitrumOne => write!(f, "evm-arbitrum-one"),
119 Network::ArbitrumSepoliaTest => write!(f, "evm-arbitrum-sepolia-test"),
120 Network::Custom(_) => write!(f, "evm-custom"),
121 }
122 }
123}
124
125impl std::str::FromStr for Network {
126 type Err = ();
127
128 fn from_str(s: &str) -> Result<Self, Self::Err> {
129 match s {
130 "evm-arbitrum-one" => Ok(Network::ArbitrumOne),
131 "evm-arbitrum-sepolia-test" => Ok(Network::ArbitrumSepoliaTest),
132 _ => Err(()),
133 }
134 }
135}
136
137impl Network {
138 pub fn new(local: bool) -> Result<Self, utils::Error> {
139 get_evm_network(local, None).inspect_err(|err| {
140 warn!("Failed to select EVM network from ENV: {err}");
141 })
142 }
143
144 pub fn new_custom(
145 rpc_url: &str,
146 payment_token_addr: &str,
147 chunk_payments_addr: &str,
148 merkle_payments_addr: Option<&str>,
149 ) -> Self {
150 Self::Custom(CustomNetwork::new(
151 rpc_url,
152 payment_token_addr,
153 chunk_payments_addr,
154 merkle_payments_addr,
155 ))
156 }
157
158 pub fn identifier(&self) -> &str {
159 match self {
160 Network::ArbitrumOne => "arbitrum-one",
161 Network::ArbitrumSepoliaTest => "arbitrum-sepolia-test",
162 Network::Custom(_) => "custom",
163 }
164 }
165
166 pub fn rpc_url(&self) -> &reqwest::Url {
167 match self {
168 Network::ArbitrumOne => &PUBLIC_ARBITRUM_ONE_HTTP_RPC_URL,
169 Network::ArbitrumSepoliaTest => &PUBLIC_ARBITRUM_SEPOLIA_HTTP_RPC_URL,
170 Network::Custom(custom) => &custom.rpc_url_http,
171 }
172 }
173
174 pub fn payment_token_address(&self) -> &Address {
175 match self {
176 Network::ArbitrumOne => &ARBITRUM_ONE_PAYMENT_TOKEN_ADDRESS,
177 Network::ArbitrumSepoliaTest => &ARBITRUM_SEPOLIA_TEST_PAYMENT_TOKEN_ADDRESS,
178 Network::Custom(custom) => &custom.payment_token_address,
179 }
180 }
181
182 pub fn data_payments_address(&self) -> &Address {
183 match self {
184 Network::ArbitrumOne => &ARBITRUM_ONE_DATA_PAYMENTS_ADDRESS,
185 Network::ArbitrumSepoliaTest => &ARBITRUM_SEPOLIA_TEST_DATA_PAYMENTS_ADDRESS,
186 Network::Custom(custom) => &custom.data_payments_address,
187 }
188 }
189
190 pub fn merkle_payments_address(&self) -> Option<&Address> {
191 match self {
192 Network::ArbitrumOne => Some(&ARBITRUM_ONE_MERKLE_PAYMENTS_ADDRESS),
193 Network::ArbitrumSepoliaTest => Some(&ARBITRUM_SEPOLIA_TEST_MERKLE_PAYMENTS_ADDRESS),
194 Network::Custom(custom) => custom.merkle_payments_address.as_ref(),
195 }
196 }
197
198 pub async fn estimate_merkle_payment_cost(
212 &self,
213 depth: u8,
214 pool_commitments: &[PoolCommitment],
215 merkle_payment_timestamp: u64,
216 ) -> Result<Amount, MerklePaymentError> {
217 if pool_commitments.is_empty() {
218 return Ok(Amount::ZERO);
219 }
220
221 let provider = http_provider(self.rpc_url().clone());
223
224 let merkle_vault_address = *self
226 .merkle_payments_address()
227 .ok_or(MerklePaymentError::MerklePaymentsAddressNotConfigured)?;
228
229 let handler = MerklePaymentVaultHandler::new(merkle_vault_address, provider);
231 let total_amount = handler
232 .estimate_merkle_tree_cost(depth, pool_commitments.to_vec(), merkle_payment_timestamp)
233 .await?;
234
235 Ok(total_amount)
236 }
237}