1use alloy::{
2 network::EthereumWallet,
3 primitives::{Address, B256, U256},
4 providers::{DynProvider, Provider, ProviderBuilder},
5 signers::local::PrivateKeySigner,
6};
7use clap::Args;
8use tempo_alloy::{TempoNetwork, provider::ext::TempoProviderBuilderExt};
9
10#[derive(Debug, Clone, Default, Args, PartialEq, Eq)]
12#[command(next_help_heading = "Faucet")]
13pub struct FaucetArgs {
14 #[arg(
16 id = "faucet.enabled",
17 long = "faucet.enabled",
18 default_value_t = false
19 )]
20 pub enabled: bool,
21
22 #[arg(
24 long = "faucet.private-key",
25 requires = "faucet.enabled",
26 required_if_eq("faucet.enabled", "true")
27 )]
28 pub private_key: Option<B256>,
29
30 #[arg(
32 long = "faucet.amount",
33 requires = "faucet.enabled",
34 required_if_eq("faucet.enabled", "true")
35 )]
36 pub amount: Option<U256>,
37
38 #[arg(
40 long = "faucet.address",
41 requires = "faucet.enabled",
42 required_if_eq("faucet.enabled", "true"),
43 num_args(0..)
44 )]
45 pub token_addresses: Option<Vec<Address>>,
46
47 #[arg(
48 long = "faucet.node-address",
49 default_value = "http://localhost:8545",
50 requires = "faucet.enabled"
51 )]
52 pub node_address: String,
53}
54
55impl FaucetArgs {
56 pub fn wallet(&self) -> EthereumWallet {
57 let signer: PrivateKeySigner = PrivateKeySigner::from_bytes(
58 &self.private_key.expect("No faucet private key provided"),
59 )
60 .expect("Failed to decode private key");
61 EthereumWallet::new(signer)
62 }
63
64 pub fn addresses(&self) -> Vec<Address> {
65 self.token_addresses
66 .clone()
67 .expect("No TIP20 token addresses provided")
68 }
69
70 pub fn amount(&self) -> U256 {
71 self.amount.expect("No TIP20 token amount provided")
72 }
73
74 pub fn provider(&self) -> DynProvider<TempoNetwork> {
75 ProviderBuilder::new_with_network::<TempoNetwork>()
76 .with_expiring_nonces()
77 .wallet(self.wallet())
78 .connect_http(
79 self.node_address
80 .parse()
81 .expect("Failed to parse node address"),
82 )
83 .erased()
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use clap::Parser;
91
92 #[derive(Parser)]
94 struct CommandParser {
95 #[command(flatten)]
96 args: FaucetArgs,
97 }
98
99 #[test]
100 fn faucet_args_default_sanity_test() {
101 assert!(CommandParser::try_parse_from(["tempo"]).is_ok());
102 }
103}