1use super::auth::confirm_auth_rpc_disclosure;
2use crate::{
3 Cast,
4 tx::{CastTxBuilder, SenderKind},
5};
6use alloy_ens::NameOrAddress;
7use alloy_network::{Ethereum, Network};
8use alloy_rpc_types::BlockId;
9use clap::Parser;
10use eyre::Result;
11use foundry_cli::{
12 opts::{RpcOpts, TransactionOpts},
13 utils::LoadConfig,
14};
15use foundry_common::{FoundryTransactionBuilder, provider::ProviderBuilder};
16use foundry_wallets::{BrowserWalletOpts, 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 #[arg(long)]
56 force: bool,
57
58 #[command(flatten)]
59 rpc: RpcOpts,
60
61 #[command(flatten)]
62 wallet: WalletOpts,
63
64 #[command(flatten)]
65 browser: BrowserWalletOpts,
66}
67
68impl AccessListArgs {
69 pub async fn run(self) -> Result<()> {
70 if self.tx.tempo.is_tempo() {
71 self.run_with_network::<TempoNetwork>().await
72 } else {
73 self.run_with_network::<Ethereum>().await
74 }
75 }
76
77 pub async fn run_with_network<N: Network + Unpin>(self) -> Result<()>
78 where
79 N::TransactionRequest: FoundryTransactionBuilder<N>,
80 {
81 let Self { to, mut sig, args, data, tx, force, rpc, wallet, browser, block } = self;
82
83 if let Some(data) = data {
84 sig = Some(data);
85 }
86
87 let config = rpc.load_config()?;
88 let provider = ProviderBuilder::<N>::from_config(&config)?.build()?;
89 let sender = if let Some(browser) = browser.run::<N>().await? {
90 browser.address().into()
91 } else {
92 SenderKind::from_wallet_opts(wallet).await?
93 };
94
95 let builder = CastTxBuilder::new(&provider, tx, &config)
96 .await?
97 .with_to(to)
98 .await?
99 .with_code_sig_and_args(None, sig, args)
100 .await?
101 .raw();
102 if builder.has_auth() && !confirm_auth_rpc_disclosure(&builder, &sender, force)? {
103 return Ok(());
104 }
105 let (tx, _) = builder.build(sender).await?;
106
107 let access_list: String = Cast::new(&provider).access_list(&tx, block).await?;
108
109 sh_println!("{access_list}")?;
110
111 Ok(())
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use alloy_primitives::hex;
119 use clap::error::ErrorKind;
120
121 #[test]
122 fn can_parse_access_list_data() {
123 let data = hex::encode("hello");
124 let args = AccessListArgs::parse_from(["foundry-cli", "--data", data.as_str()]);
125 assert_eq!(args.data, Some(data));
126
127 let data = hex::encode_prefixed("hello");
128 let args = AccessListArgs::parse_from(["foundry-cli", "--data", data.as_str()]);
129 assert_eq!(args.data, Some(data));
130 }
131
132 #[test]
133 fn data_conflicts_with_sig_and_args() {
134 let err = AccessListArgs::try_parse_from([
135 "foundry-cli",
136 "0x0000000000000000000000000000000000000001",
137 "transfer(address,uint256)",
138 "0x0000000000000000000000000000000000000002",
139 "1",
140 "--data",
141 "0x1234",
142 ])
143 .unwrap_err();
144
145 assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
146 }
147}