Skip to main content

polyoxide_relay/
config.rs

1use alloy::primitives::Address;
2use polyoxide_core::{current_timestamp, Base64Format, Signer};
3use reqwest::header::{HeaderMap, HeaderValue};
4use std::str::FromStr;
5
6#[derive(Clone, Debug)]
7pub struct ContractConfig {
8    pub safe_factory: Address,
9    pub safe_multisend: Address,
10    pub proxy_factory: Option<Address>,
11    pub relay_hub: Option<Address>,
12    pub rpc_url: &'static str,
13}
14
15pub fn get_contract_config(chain_id: u64) -> Option<ContractConfig> {
16    match chain_id {
17        137 => Some(ContractConfig {
18            safe_factory: Address::from_str("0xaacFeEa03eb1561C4e67d661e40682Bd20E3541b").unwrap(),
19            safe_multisend: Address::from_str("0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761")
20                .unwrap(),
21            proxy_factory: Some(
22                Address::from_str("0xaB45c5A4B0c941a2F231C04C3f49182e1A254052").unwrap(),
23            ),
24            relay_hub: Some(
25                Address::from_str("0xD216153c06E857cD7f72665E0aF1d7D82172F494").unwrap(),
26            ),
27            rpc_url: "https://polygon.drpc.org",
28        }),
29        80002 => Some(ContractConfig {
30            safe_factory: Address::from_str("0xaacFeEa03eb1561C4e67d661e40682Bd20E3541b").unwrap(),
31            safe_multisend: Address::from_str("0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761")
32                .unwrap(),
33            proxy_factory: None, // Proxy not supported on Amoy testnet
34            relay_hub: None,
35            rpc_url: "https://rpc-amoy.polygon.technology",
36        }),
37        _ => None,
38    }
39}
40
41#[derive(Clone, Debug)]
42pub struct BuilderConfig {
43    pub key: String,
44    pub secret: String,
45    pub passphrase: Option<String>,
46}
47
48impl BuilderConfig {
49    pub fn new(key: String, secret: String, passphrase: Option<String>) -> Self {
50        Self {
51            key,
52            secret,
53            passphrase,
54        }
55    }
56
57    pub fn generate_headers(
58        &self,
59        method: &str,
60        path: &str,
61        body: Option<&str>,
62    ) -> Result<HeaderMap, String> {
63        let mut headers = HeaderMap::new();
64        let timestamp = current_timestamp();
65
66        // Create signer from raw string secret (Relay v1 uses raw secrets)
67        let signer = Signer::from_raw(&self.secret);
68        let message = Signer::create_message(timestamp, method, path, body);
69        let signature = signer.sign(&message, Base64Format::Standard)?;
70
71        headers.insert("POLY-API-KEY", HeaderValue::from_str(&self.key).unwrap());
72        headers.insert(
73            "POLY-TIMESTAMP",
74            HeaderValue::from_str(&timestamp.to_string()).unwrap(),
75        );
76        headers.insert("POLY-SIGNATURE", HeaderValue::from_str(&signature).unwrap());
77
78        if let Some(passphrase) = &self.passphrase {
79            headers.insert(
80                "POLY-PASSPHRASE",
81                HeaderValue::from_str(passphrase).unwrap(),
82            );
83        }
84
85        Ok(headers)
86    }
87
88    pub fn generate_relayer_v2_headers(
89        &self,
90        method: &str,
91        path: &str,
92        body: Option<&str>,
93    ) -> Result<HeaderMap, String> {
94        let mut headers = HeaderMap::new();
95        let timestamp = current_timestamp();
96
97        // Create signer from base64-encoded secret (Relay v2 uses base64 secrets)
98        let signer = Signer::new(&self.secret)?;
99        let message = Signer::create_message(timestamp, method, path, body);
100        let signature = signer.sign(&message, Base64Format::UrlSafe)?;
101
102        headers.insert(
103            "POLY_BUILDER_API_KEY",
104            HeaderValue::from_str(&self.key).unwrap(),
105        );
106        headers.insert(
107            "POLY_BUILDER_TIMESTAMP",
108            HeaderValue::from_str(&timestamp.to_string()).unwrap(),
109        );
110        headers.insert(
111            "POLY_BUILDER_SIGNATURE",
112            HeaderValue::from_str(&signature).unwrap(),
113        );
114
115        if let Some(passphrase) = &self.passphrase {
116            headers.insert(
117                "POLY_BUILDER_PASSPHRASE",
118                HeaderValue::from_str(passphrase).unwrap(),
119            );
120        }
121
122        Ok(headers)
123    }
124}