Skip to content

Commit 93615ab

Browse files
authored
feat: FromEnv & FromEnvVar for SignetConstants types (#25)
* feat: FromEnvVar for SignetConstants types * feat: impl FromEnv for SignetConstants types (#26) * feat: impl FromEnv for SignetConstants types * feat: full implementation * comments * docs, import * fix: fmt * fix: add alloy feature
1 parent 7a693c0 commit 93615ab

File tree

4 files changed

+362
-2
lines changed

4 files changed

+362
-2
lines changed

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ repository = "https://github.com/init4tech/bin-base"
1515
[dependencies]
1616
init4-from-env-derive = "0.1.0"
1717

18+
19+
# Signet
20+
signet-constants = { git = "https://github.com/init4tech/signet-sdk.git", branch = "main" }
21+
1822
# Tracing
1923
tracing = "0.1.40"
2024
tracing-core = "0.1.33"
@@ -45,7 +49,6 @@ alloy = { version = "0.12.6", optional = true, default-features = false, feature
4549
serde = { version = "1", features = ["derive"] }
4650
async-trait = { version = "0.1.80", optional = true }
4751

48-
4952
# AWS
5053
aws-config = { version = "1.1.7", optional = true }
5154
aws-sdk-kms = { version = "1.15.0", optional = true }

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ pub mod utils {
2828
/// [`FromEnvVar`]: from_env::FromEnvVar
2929
pub mod from_env;
3030

31+
#[cfg(feature = "alloy")]
32+
/// SignetConstants variables FromEnv
33+
pub mod constants_from_env;
34+
3135
/// Prometheus metrics utilities.
3236
pub mod metrics;
3337

src/utils/constants_from_env.rs

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
use crate::utils::from_env::{EnvItemInfo, FromEnv, FromEnvErr, FromEnvVar};
2+
use alloy::primitives::{hex::FromHexError, Address};
3+
use signet_constants::{
4+
HostConstants, ParseChainError, PredeployTokens, RollupConstants, SignetConstants,
5+
SignetEnvironmentConstants, SignetSystemConstants,
6+
};
7+
use std::{borrow::Cow, num::ParseIntError};
8+
9+
/// EnvItemInfo for .env variable holding chain name
10+
/// Used to implement FromEnv for SignetConstants type structs
11+
/// that can be instantiated from a single chain name
12+
const CHAIN_NAME: EnvItemInfo = EnvItemInfo {
13+
var: "CHAIN_NAME",
14+
description: "The name of the chain, e.g. `pecorino`. If CHAIN_NAME is present, the known, hard-coded constants for the chain will be loaded from the SDK. If CHAIN_NAME is not present, each constant will be loaded from environment variables.",
15+
optional: true,
16+
};
17+
18+
// --- RollupConstants ---
19+
const ROLLUP_CHAIN_ID: &str = "ROLLUP_CHAIN_ID";
20+
const ROLLUP_BASE_FEE_RECIPIENT: &str = "ROLLUP_BASE_FEE_RECIPIENT";
21+
const ROLLUP_ORDERS: &str = "ROLLUP_ORDERS";
22+
const ROLLUP_PASSAGE: &str = "ROLLUP_PASSAGE";
23+
const ROLLUP_USDC: &str = "ROLLUP_USDC";
24+
const ROLLUP_USDT: &str = "ROLLUP_USDT";
25+
const ROLLUP_WBTC: &str = "ROLLUP_WBTC";
26+
// --- HostConstants ---
27+
const HOST_CHAIN_ID: &str = "HOST_CHAIN_ID";
28+
const HOST_DEPLOY_HEIGHT: &str = "HOST_DEPLOY_HEIGHT";
29+
const HOST_ZENITH: &str = "HOST_ZENITH";
30+
const HOST_ORDERS: &str = "HOST_ORDERS";
31+
const HOST_PASSAGE: &str = "HOST_PASSAGE";
32+
const HOST_TRANSACTOR: &str = "HOST_TRANSACTOR";
33+
const HOST_USDC: &str = "HOST_USDC";
34+
const HOST_USDT: &str = "HOST_USDT";
35+
const HOST_WBTC: &str = "HOST_WBTC";
36+
// --- SignetEnvironmentConstants ---
37+
const SIGNET_HOST_NAME: &str = "SIGNET_HOST_NAME";
38+
const SIGNET_ROLLUP_NAME: &str = "SIGNET_ROLLUP_NAME";
39+
const SIGNET_TRANSACTION_CACHE: &str = "SIGNET_TRANSACTION_CACHE";
40+
41+
/// Error type for parsing SignetConstants from environment variables.
42+
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
43+
pub enum ConstantsFromEnvError {
44+
/// Error parsing a chain name.
45+
#[error(transparent)]
46+
ParseChainError(#[from] ParseChainError),
47+
/// Error parsing a u64.
48+
#[error(transparent)]
49+
ParseIntError(#[from] ParseIntError),
50+
/// Error parsing a hex string.
51+
#[error(transparent)]
52+
FromHexError(#[from] FromHexError),
53+
}
54+
55+
impl From<FromEnvErr<ParseChainError>> for FromEnvErr<ConstantsFromEnvError> {
56+
fn from(e: FromEnvErr<ParseChainError>) -> Self {
57+
match e {
58+
FromEnvErr::ParseError(i) => FromEnvErr::ParseError(i.into()),
59+
FromEnvErr::Empty(i) => FromEnvErr::Empty(i),
60+
FromEnvErr::EnvError(var, err) => FromEnvErr::EnvError(var, err),
61+
}
62+
}
63+
}
64+
65+
impl From<FromEnvErr<ParseIntError>> for FromEnvErr<ConstantsFromEnvError> {
66+
fn from(e: FromEnvErr<ParseIntError>) -> Self {
67+
match e {
68+
FromEnvErr::ParseError(i) => FromEnvErr::ParseError(i.into()),
69+
FromEnvErr::Empty(i) => FromEnvErr::Empty(i),
70+
FromEnvErr::EnvError(var, err) => FromEnvErr::EnvError(var, err),
71+
}
72+
}
73+
}
74+
75+
impl From<FromEnvErr<FromHexError>> for FromEnvErr<ConstantsFromEnvError> {
76+
fn from(e: FromEnvErr<FromHexError>) -> Self {
77+
match e {
78+
FromEnvErr::ParseError(i) => FromEnvErr::ParseError(i.into()),
79+
FromEnvErr::Empty(i) => FromEnvErr::Empty(i),
80+
FromEnvErr::EnvError(var, err) => FromEnvErr::EnvError(var, err),
81+
}
82+
}
83+
}
84+
85+
impl FromEnv for RollupConstants {
86+
type Error = ConstantsFromEnvError;
87+
88+
fn inventory() -> Vec<&'static EnvItemInfo> {
89+
vec![
90+
&CHAIN_NAME,
91+
&EnvItemInfo {
92+
var: ROLLUP_CHAIN_ID,
93+
description: "Rollup chain ID.",
94+
optional: false,
95+
},
96+
&EnvItemInfo {
97+
var: ROLLUP_BASE_FEE_RECIPIENT,
98+
description: "Rollup address of the base fee recipient.",
99+
optional: false,
100+
},
101+
&EnvItemInfo {
102+
var: ROLLUP_ORDERS,
103+
description: "Rollup address of the orders contract.",
104+
optional: false,
105+
},
106+
&EnvItemInfo {
107+
var: ROLLUP_PASSAGE,
108+
description: "Rollup address of the passage contract.",
109+
optional: false,
110+
},
111+
&EnvItemInfo {
112+
var: ROLLUP_USDC,
113+
description: "Rollup address of usdc token.",
114+
optional: false,
115+
},
116+
&EnvItemInfo {
117+
var: ROLLUP_USDT,
118+
description: "Rollup address of usdt token.",
119+
optional: false,
120+
},
121+
&EnvItemInfo {
122+
var: ROLLUP_WBTC,
123+
description: "Rollup address of wbtc token.",
124+
optional: false,
125+
},
126+
]
127+
}
128+
129+
fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
130+
match Self::from_env_var(CHAIN_NAME.var) {
131+
Ok(c) => Ok(c),
132+
Err(e) => {
133+
match e {
134+
// if chain name is present but malformed, propagate the error
135+
FromEnvErr::ParseError(_) => Err(e.into()),
136+
// if the chain name is empty or missing,
137+
// instantiate each prop from env vars
138+
FromEnvErr::EnvError(_, _) | FromEnvErr::Empty(_) => Ok(RollupConstants::new(
139+
u64::from_env_var(ROLLUP_CHAIN_ID)?,
140+
Address::from_env_var(ROLLUP_ORDERS)?,
141+
Address::from_env_var(ROLLUP_PASSAGE)?,
142+
Address::from_env_var(ROLLUP_BASE_FEE_RECIPIENT)?,
143+
PredeployTokens::new(
144+
Address::from_env_var(ROLLUP_USDC)?,
145+
Address::from_env_var(ROLLUP_USDT)?,
146+
Address::from_env_var(ROLLUP_WBTC)?,
147+
),
148+
)),
149+
}
150+
}
151+
}
152+
}
153+
}
154+
155+
impl FromEnv for HostConstants {
156+
type Error = ConstantsFromEnvError;
157+
158+
fn inventory() -> Vec<&'static EnvItemInfo> {
159+
vec![
160+
&CHAIN_NAME,
161+
&EnvItemInfo {
162+
var: HOST_CHAIN_ID,
163+
description: "Host chain ID.",
164+
optional: false,
165+
},
166+
&EnvItemInfo {
167+
var: HOST_DEPLOY_HEIGHT,
168+
description: "Height at which the host chain deployed the rollup contracts.",
169+
optional: false,
170+
},
171+
&EnvItemInfo {
172+
var: HOST_ZENITH,
173+
description: "Host address for the zenith contract",
174+
optional: false,
175+
},
176+
&EnvItemInfo {
177+
var: HOST_ORDERS,
178+
description: "Host address for the orders contract",
179+
optional: false,
180+
},
181+
&EnvItemInfo {
182+
var: HOST_PASSAGE,
183+
description: "Host address for the passage contract",
184+
optional: false,
185+
},
186+
&EnvItemInfo {
187+
var: HOST_TRANSACTOR,
188+
description: "Host address for the transactor contract",
189+
optional: false,
190+
},
191+
&EnvItemInfo {
192+
var: HOST_USDC,
193+
description: "Host address for the USDC token",
194+
optional: false,
195+
},
196+
&EnvItemInfo {
197+
var: HOST_USDT,
198+
description: "Host address for the USDT token",
199+
optional: false,
200+
},
201+
&EnvItemInfo {
202+
var: HOST_WBTC,
203+
description: "Host address for the WBTC token",
204+
optional: false,
205+
},
206+
]
207+
}
208+
209+
fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
210+
match Self::from_env_var(CHAIN_NAME.var) {
211+
Ok(c) => Ok(c),
212+
Err(e) => {
213+
match e {
214+
// if chain name is present but malformed, propagate the error
215+
FromEnvErr::ParseError(_) => Err(e.into()),
216+
// if the chain name is empty or missing,
217+
// instantiate each prop from env vars
218+
FromEnvErr::EnvError(_, _) | FromEnvErr::Empty(_) => Ok(HostConstants::new(
219+
u64::from_env_var(HOST_CHAIN_ID)?,
220+
u64::from_env_var(HOST_DEPLOY_HEIGHT)?,
221+
Address::from_env_var(HOST_ZENITH)?,
222+
Address::from_env_var(HOST_ORDERS)?,
223+
Address::from_env_var(HOST_PASSAGE)?,
224+
Address::from_env_var(HOST_TRANSACTOR)?,
225+
PredeployTokens::new(
226+
Address::from_env_var(HOST_USDC)?,
227+
Address::from_env_var(HOST_USDT)?,
228+
Address::from_env_var(HOST_WBTC)?,
229+
),
230+
)),
231+
}
232+
}
233+
}
234+
}
235+
}
236+
237+
impl FromEnv for SignetEnvironmentConstants {
238+
type Error = ConstantsFromEnvError;
239+
240+
fn inventory() -> Vec<&'static EnvItemInfo> {
241+
vec![
242+
&CHAIN_NAME,
243+
&EnvItemInfo {
244+
var: SIGNET_HOST_NAME,
245+
description: "Name of the host chain.",
246+
optional: false,
247+
},
248+
&EnvItemInfo {
249+
var: SIGNET_ROLLUP_NAME,
250+
description: "Name of the rollup.",
251+
optional: false,
252+
},
253+
&EnvItemInfo {
254+
var: SIGNET_TRANSACTION_CACHE,
255+
description: "URL of the Transaction Cache",
256+
optional: false,
257+
},
258+
]
259+
}
260+
261+
fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
262+
match Self::from_env_var(CHAIN_NAME.var) {
263+
Ok(c) => Ok(c),
264+
Err(e) => {
265+
match e {
266+
// if chain name is present but malformed, propagate the error
267+
FromEnvErr::ParseError(_) => Err(e.into()),
268+
// if the chain name is empty or missing,
269+
// instantiate each prop from env vars
270+
FromEnvErr::EnvError(_, _) | FromEnvErr::Empty(_) => {
271+
Ok(SignetEnvironmentConstants::new(
272+
Cow::from_env_var(SIGNET_HOST_NAME)
273+
.map_err(|e| e.infallible_into::<ConstantsFromEnvError>())?,
274+
Cow::from_env_var(SIGNET_ROLLUP_NAME)
275+
.map_err(|e| e.infallible_into::<ConstantsFromEnvError>())?,
276+
Cow::from_env_var(SIGNET_TRANSACTION_CACHE)
277+
.map_err(|e| e.infallible_into::<ConstantsFromEnvError>())?,
278+
))
279+
}
280+
}
281+
}
282+
}
283+
}
284+
}
285+
286+
impl FromEnv for SignetSystemConstants {
287+
type Error = ConstantsFromEnvError;
288+
289+
fn inventory() -> Vec<&'static EnvItemInfo> {
290+
let mut inventory = Vec::new();
291+
inventory.extend_from_slice(&HostConstants::inventory());
292+
inventory.extend_from_slice(&RollupConstants::inventory()[1..]);
293+
inventory
294+
}
295+
296+
fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
297+
match Self::from_env_var(CHAIN_NAME.var) {
298+
Ok(c) => Ok(c),
299+
Err(e) => {
300+
match e {
301+
// if chain name is present but malformed, propagate the error
302+
FromEnvErr::ParseError(_) => Err(e.into()),
303+
// if the chain name is empty or missing,
304+
// instantiate each prop from env vars
305+
FromEnvErr::EnvError(_, _) | FromEnvErr::Empty(_) => {
306+
Ok(SignetSystemConstants::new(
307+
HostConstants::from_env()?,
308+
RollupConstants::from_env()?,
309+
))
310+
}
311+
}
312+
}
313+
}
314+
}
315+
}
316+
317+
impl FromEnv for SignetConstants {
318+
type Error = ConstantsFromEnvError;
319+
320+
fn inventory() -> Vec<&'static EnvItemInfo> {
321+
let mut inventory = Vec::new();
322+
inventory.extend_from_slice(&SignetSystemConstants::inventory());
323+
inventory.extend_from_slice(&SignetEnvironmentConstants::inventory()[1..]);
324+
inventory
325+
}
326+
327+
fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
328+
match Self::from_env_var(CHAIN_NAME.var) {
329+
Ok(c) => Ok(c),
330+
Err(e) => {
331+
match e {
332+
// if chain name is present but malformed, propagate the error
333+
FromEnvErr::ParseError(_) => Err(e.into()),
334+
// if the chain name is empty or missing,
335+
// instantiate each prop from env vars
336+
FromEnvErr::EnvError(_, _) | FromEnvErr::Empty(_) => Ok(SignetConstants::new(
337+
SignetSystemConstants::from_env()?,
338+
SignetEnvironmentConstants::from_env()?,
339+
)),
340+
}
341+
}
342+
}
343+
}
344+
}

src/utils/from_env.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
use signet_constants::{
2+
HostConstants, RollupConstants, SignetConstants, SignetEnvironmentConstants,
3+
SignetSystemConstants,
4+
};
15
use std::{convert::Infallible, env::VarError, num::ParseIntError, str::FromStr};
26

37
/// The `derive(FromEnv)` macro.
@@ -609,7 +613,12 @@ impl_for_parseable!(
609613
i128,
610614
isize,
611615
url::Url,
612-
tracing::Level
616+
tracing::Level,
617+
SignetConstants,
618+
SignetEnvironmentConstants,
619+
SignetSystemConstants,
620+
HostConstants,
621+
RollupConstants
613622
);
614623

615624
#[cfg(feature = "alloy")]

0 commit comments

Comments
 (0)