polyoxide_relay/
config.rs1use alloy::primitives::Address;
2use base64::{
3 engine::general_purpose::{STANDARD, URL_SAFE},
4 Engine as _,
5};
6use hmac::{Hmac, Mac};
7use reqwest::header::{HeaderMap, HeaderValue};
8use sha2::Sha256;
9use std::str::FromStr;
10use std::time::{SystemTime, UNIX_EPOCH};
11
12#[derive(Clone, Debug)]
13pub struct ContractConfig {
14 pub safe_factory: Address,
15 pub safe_multisend: Address,
16 pub proxy_factory: Option<Address>,
17 pub relay_hub: Option<Address>,
18 pub rpc_url: &'static str,
19}
20
21pub fn get_contract_config(chain_id: u64) -> Option<ContractConfig> {
22 match chain_id {
23 137 => Some(ContractConfig {
24 safe_factory: Address::from_str("0xaacFeEa03eb1561C4e67d661e40682Bd20E3541b").unwrap(),
25 safe_multisend: Address::from_str("0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761")
26 .unwrap(),
27 proxy_factory: Some(
28 Address::from_str("0xaB45c5A4B0c941a2F231C04C3f49182e1A254052").unwrap(),
29 ),
30 relay_hub: Some(
31 Address::from_str("0xD216153c06E857cD7f72665E0aF1d7D82172F494").unwrap(),
32 ),
33 rpc_url: "https://polygon.drpc.org",
34 }),
35 80002 => Some(ContractConfig {
36 safe_factory: Address::from_str("0xaacFeEa03eb1561C4e67d661e40682Bd20E3541b").unwrap(),
37 safe_multisend: Address::from_str("0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761")
38 .unwrap(),
39 proxy_factory: None, relay_hub: None,
41 rpc_url: "https://rpc-amoy.polygon.technology",
42 }),
43 _ => None,
44 }
45}
46
47#[derive(Clone, Debug)]
48pub struct BuilderConfig {
49 pub key: String,
50 pub secret: String,
51 pub passphrase: Option<String>,
52}
53
54impl BuilderConfig {
55 pub fn new(key: String, secret: String, passphrase: Option<String>) -> Self {
56 Self {
57 key,
58 secret,
59 passphrase,
60 }
61 }
62
63 pub fn generate_headers(
64 &self,
65 method: &str,
66 path: &str,
67 body: Option<&str>,
68 ) -> Result<HeaderMap, String> {
69 let mut headers = HeaderMap::new();
70 let timestamp = SystemTime::now()
71 .duration_since(UNIX_EPOCH)
72 .unwrap()
73 .as_secs()
74 .to_string();
75
76 let body_str = body.unwrap_or("");
77 let message = format!("{}{}{}{}", timestamp, method, path, body_str);
78
79 let mut mac = Hmac::<Sha256>::new_from_slice(self.secret.as_bytes())
80 .map_err(|e| format!("Invalid secret: {}", e))?;
81 mac.update(message.as_bytes());
82 let result = mac.finalize();
83 let signature = STANDARD.encode(result.into_bytes());
84
85 headers.insert("POLY-API-KEY", HeaderValue::from_str(&self.key).unwrap());
86 headers.insert("POLY-TIMESTAMP", HeaderValue::from_str(×tamp).unwrap());
87 headers.insert("POLY-SIGNATURE", HeaderValue::from_str(&signature).unwrap());
88
89 if let Some(passphrase) = &self.passphrase {
90 headers.insert(
91 "POLY-PASSPHRASE",
92 HeaderValue::from_str(passphrase).unwrap(),
93 );
94 }
95
96 Ok(headers)
97 }
98
99 pub fn generate_relayer_v2_headers(
100 &self,
101 method: &str,
102 path: &str,
103 body: Option<&str>,
104 ) -> Result<HeaderMap, String> {
105 let mut headers = HeaderMap::new();
106 let timestamp = SystemTime::now()
107 .duration_since(UNIX_EPOCH)
108 .unwrap()
109 .as_secs()
110 .to_string();
111
112 let body_str = body.unwrap_or("");
113 let message = format!("{}{}{}{}", timestamp, method, path, body_str);
115
116 let secret_bytes = URL_SAFE
118 .decode(&self.secret)
119 .or_else(|_| STANDARD.decode(&self.secret))
120 .map_err(|e| format!("Invalid base64 secret: {}", e))?;
121
122 let mut mac = Hmac::<Sha256>::new_from_slice(&secret_bytes)
123 .map_err(|e| format!("Invalid secret: {}", e))?;
124 mac.update(message.as_bytes());
125 let result = mac.finalize();
126 let signature = URL_SAFE.encode(result.into_bytes());
128
129 headers.insert(
130 "POLY_BUILDER_API_KEY",
131 HeaderValue::from_str(&self.key).unwrap(),
132 );
133 headers.insert(
134 "POLY_BUILDER_TIMESTAMP",
135 HeaderValue::from_str(×tamp).unwrap(),
136 );
137 headers.insert(
138 "POLY_BUILDER_SIGNATURE",
139 HeaderValue::from_str(&signature).unwrap(),
140 );
141
142 if let Some(passphrase) = &self.passphrase {
143 headers.insert(
144 "POLY_BUILDER_PASSPHRASE",
145 HeaderValue::from_str(passphrase).unwrap(),
146 );
147 }
148
149 Ok(headers)
150 }
151}