Skip to main content

cast/cmd/
access_list.rs

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/// CLI arguments for `cast access-list`.
21#[derive(Debug, Parser)]
22pub struct AccessListArgs {
23    /// The destination of the transaction.
24    #[arg(
25        value_name = "TO",
26        value_parser = NameOrAddress::from_str
27    )]
28    to: Option<NameOrAddress>,
29
30    /// The signature of the function to call.
31    #[arg(value_name = "SIG")]
32    sig: Option<String>,
33
34    /// The arguments of the function to call.
35    #[arg(value_name = "ARGS", allow_negative_numbers = true)]
36    args: Vec<String>,
37
38    /// Raw hex-encoded data for the transaction. Used instead of `SIG` and `ARGS`.
39    #[arg(
40        long,
41        conflicts_with_all = &["sig", "args"]
42    )]
43    data: Option<String>,
44
45    /// The block height to query at.
46    ///
47    /// Can also be the tags earliest, finalized, safe, latest, or pending.
48    #[arg(long, short = 'B')]
49    block: Option<BlockId>,
50
51    #[command(flatten)]
52    tx: TransactionOpts,
53
54    /// Skip the EIP-7702 authorization disclosure confirmation.
55    #[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}