1use crate::{
2 Cast,
3 tx::{CastTxBuilder, SenderKind},
4};
5use alloy_ens::NameOrAddress;
6use alloy_network::{Ethereum, Network};
7use alloy_rpc_types::BlockId;
8use clap::Parser;
9use eyre::Result;
10use foundry_cli::{
11 opts::{RpcOpts, TransactionOpts},
12 utils::LoadConfig,
13};
14use foundry_common::{FoundryTransactionBuilder, provider::ProviderBuilder};
15use foundry_wallets::WalletOpts;
16use std::str::FromStr;
17use tempo_alloy::TempoNetwork;
18
19#[derive(Debug, Parser)]
21pub struct AccessListArgs {
22 #[arg(
24 value_name = "TO",
25 value_parser = NameOrAddress::from_str
26 )]
27 to: Option<NameOrAddress>,
28
29 #[arg(value_name = "SIG")]
31 sig: Option<String>,
32
33 #[arg(value_name = "ARGS", allow_negative_numbers = true)]
35 args: Vec<String>,
36
37 #[arg(
39 long,
40 conflicts_with_all = &["sig", "args"]
41 )]
42 data: Option<String>,
43
44 #[arg(long, short = 'B')]
48 block: Option<BlockId>,
49
50 #[command(flatten)]
51 tx: TransactionOpts,
52
53 #[command(flatten)]
54 rpc: RpcOpts,
55
56 #[command(flatten)]
57 wallet: WalletOpts,
58}
59
60impl AccessListArgs {
61 pub async fn run(self) -> Result<()> {
62 if self.tx.tempo.is_tempo() {
63 self.run_with_network::<TempoNetwork>().await
64 } else {
65 self.run_with_network::<Ethereum>().await
66 }
67 }
68
69 pub async fn run_with_network<N: Network + Unpin>(self) -> Result<()>
70 where
71 N::TransactionRequest: FoundryTransactionBuilder<N>,
72 {
73 let Self { to, mut sig, args, data, tx, rpc, wallet, block } = self;
74
75 if let Some(data) = data {
76 sig = Some(data);
77 }
78
79 let config = rpc.load_config()?;
80 let provider = ProviderBuilder::<N>::from_config(&config)?.build()?;
81 let sender = SenderKind::from_wallet_opts(wallet).await?;
82
83 let (tx, _) = CastTxBuilder::new(&provider, tx, &config)
84 .await?
85 .with_to(to)
86 .await?
87 .with_code_sig_and_args(None, sig, args)
88 .await?
89 .raw()
90 .build(sender)
91 .await?;
92
93 let access_list: String = Cast::new(&provider).access_list(&tx, block).await?;
94
95 sh_println!("{access_list}")?;
96
97 Ok(())
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use alloy_primitives::hex;
105 use clap::error::ErrorKind;
106
107 #[test]
108 fn can_parse_access_list_data() {
109 let data = hex::encode("hello");
110 let args = AccessListArgs::parse_from(["foundry-cli", "--data", data.as_str()]);
111 assert_eq!(args.data, Some(data));
112
113 let data = hex::encode_prefixed("hello");
114 let args = AccessListArgs::parse_from(["foundry-cli", "--data", data.as_str()]);
115 assert_eq!(args.data, Some(data));
116 }
117
118 #[test]
119 fn data_conflicts_with_sig_and_args() {
120 let err = AccessListArgs::try_parse_from([
121 "foundry-cli",
122 "0x0000000000000000000000000000000000000001",
123 "transfer(address,uint256)",
124 "0x0000000000000000000000000000000000000002",
125 "1",
126 "--data",
127 "0x1234",
128 ])
129 .unwrap_err();
130
131 assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
132 }
133}