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
//! Network configuration — Mainnet, Sepolia, and Devnet.
use std::str::FromStr;
use starknet::core::types::Felt;
/// The Starknet network to connect to.
///
/// Mirrors starkzap's `network: "mainnet" | "sepolia" | "devnet"` preset system.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Network {
/// Starknet Mainnet (production — real funds).
Mainnet,
/// Starknet Sepolia testnet (staging — test tokens).
Sepolia,
/// Local starknet-devnet instance (development — no tokens needed).
///
/// Defaults to `http://127.0.0.1:5050`. Override via
/// [`crate::sdk::StarkZapConfig::with_rpc`] if you use a different port.
Devnet,
}
impl Network {
/// Read `STARKZAP_NETWORK` from the environment.
///
/// Defaults to Sepolia when the variable is unset.
pub fn from_env() -> Self {
std::env::var("STARKZAP_NETWORK")
.ok()
.and_then(|value| value.parse().ok())
.unwrap_or(Self::Sepolia)
}
/// Default public JSON-RPC endpoint for this network.
///
/// For production always pass your own URL via
/// [`crate::sdk::StarkZapConfig::with_rpc`].
pub fn default_rpc_url(&self) -> &'static str {
match self {
Network::Mainnet => "https://starknet.drpc.org",
Network::Sepolia => "https://starknet-sepolia.drpc.org",
Network::Devnet => "http://127.0.0.1:5050/rpc",
}
}
/// Chain ID felt used when building `SingleOwnerAccount`.
pub fn chain_id(&self) -> Felt {
match self {
// "SN_MAIN"
Network::Mainnet => Felt::from_hex_unchecked("0x534e5f4d41494e"),
// "SN_SEPOLIA"
Network::Sepolia => Felt::from_hex_unchecked("0x534e5f5345504f4c4941"),
// Devnet mirrors Sepolia by default
Network::Devnet => Felt::from_hex_unchecked("0x534e5f5345504f4c4941"),
}
}
/// Returns `true` if this is mainnet.
pub fn is_mainnet(&self) -> bool {
matches!(self, Network::Mainnet)
}
/// Returns `true` if this is a local devnet instance.
pub fn is_devnet(&self) -> bool {
matches!(self, Network::Devnet)
}
/// AVNU paymaster JSON-RPC base URL.
///
/// This mirrors StarkZap TS / `starknet.js` `PaymasterRpc`.
pub fn avnu_paymaster_url(&self) -> &'static str {
match self {
Network::Mainnet => "https://starknet.paymaster.avnu.fi",
Network::Sepolia => "https://sepolia.paymaster.avnu.fi",
Network::Devnet => "http://localhost:0", // intentionally invalid
}
}
/// AVNU swap/exchange REST API base URL.
pub fn avnu_base_url(&self) -> &'static str {
match self {
Network::Mainnet => "https://starknet.api.avnu.fi",
Network::Sepolia => "https://sepolia.api.avnu.fi",
Network::Devnet => "http://localhost:0",
}
}
/// Universal Deployer Contract (UDC) address — same across all networks.
pub fn udc_address(&self) -> Felt {
Felt::from_hex_unchecked(
"0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf",
)
}
/// Starknet native staking contract address.
///
/// Returns `Felt::ZERO` for devnet — staking is not available locally.
pub fn staking_contract(&self) -> Felt {
match self {
Network::Mainnet => Felt::from_hex_unchecked(
"0x00ca1702e64c81d9a07b86bd2c540188d92a2c73cf5cc0e508d949015e7e84a7",
),
Network::Sepolia => Felt::from_hex_unchecked(
"0x03745ab04a431fc02871a139be6b93d9260b0ff3e779ad9c8b377183b23109f1",
),
Network::Devnet => Felt::ZERO,
}
}
}
impl std::fmt::Display for Network {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Network::Mainnet => write!(f, "mainnet"),
Network::Sepolia => write!(f, "sepolia"),
Network::Devnet => write!(f, "devnet"),
}
}
}
impl FromStr for Network {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value.trim().to_ascii_lowercase().as_str() {
"mainnet" | "main" => Ok(Self::Mainnet),
"sepolia" | "testnet" => Ok(Self::Sepolia),
"devnet" | "local" => Ok(Self::Devnet),
other => Err(format!(
"unsupported network '{other}', expected mainnet, sepolia, or devnet"
)),
}
}
}