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