Skip to main content

cast/cmd/
access_list.rs

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/// 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    #[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}