foundry_cli/opts/
transaction.rs

1use std::str::FromStr;
2
3use super::TempoOpts;
4use crate::utils::{parse_ether_value, parse_json};
5use alloy_eips::{eip2930::AccessList, eip7702::SignedAuthorization};
6use alloy_primitives::{Address, U64, U256, hex};
7use alloy_rlp::Decodable;
8use clap::Parser;
9
10/// CLI helper to parse a EIP-7702 authorization list.
11/// Can be either a hex-encoded signed authorization or an address.
12#[derive(Clone, Debug)]
13pub enum CliAuthorizationList {
14    /// If an address is provided, we sign the authorization delegating to provided address.
15    Address(Address),
16    /// If RLP-encoded authorization is provided, we decode it and attach to transaction.
17    Signed(SignedAuthorization),
18}
19
20impl FromStr for CliAuthorizationList {
21    type Err = eyre::Error;
22
23    fn from_str(s: &str) -> Result<Self, Self::Err> {
24        if let Ok(addr) = Address::from_str(s) {
25            Ok(Self::Address(addr))
26        } else if let Ok(auth) = SignedAuthorization::decode(&mut hex::decode(s)?.as_ref()) {
27            Ok(Self::Signed(auth))
28        } else {
29            eyre::bail!("Failed to decode authorization")
30        }
31    }
32}
33
34#[derive(Clone, Debug, Parser)]
35#[command(next_help_heading = "Transaction options")]
36pub struct TransactionOpts {
37    /// Gas limit for the transaction.
38    #[arg(long, env = "ETH_GAS_LIMIT")]
39    pub gas_limit: Option<U256>,
40
41    /// Gas price for legacy transactions, or max fee per gas for EIP1559 transactions, either
42    /// specified in wei, or as a string with a unit type.
43    ///
44    /// Examples: 1ether, 10gwei, 0.01ether
45    #[arg(
46        long,
47        env = "ETH_GAS_PRICE",
48        value_parser = parse_ether_value,
49        value_name = "PRICE"
50    )]
51    pub gas_price: Option<U256>,
52
53    /// Max priority fee per gas for EIP1559 transactions.
54    #[arg(
55        long,
56        env = "ETH_PRIORITY_GAS_PRICE",
57        value_parser = parse_ether_value,
58        value_name = "PRICE"
59    )]
60    pub priority_gas_price: Option<U256>,
61
62    /// Ether to send in the transaction, either specified in wei, or as a string with a unit type.
63    ///
64    ///
65    ///
66    /// Examples: 1ether, 10gwei, 0.01ether
67    #[arg(long, value_parser = parse_ether_value)]
68    pub value: Option<U256>,
69
70    /// Nonce for the transaction.
71    #[arg(long)]
72    pub nonce: Option<U64>,
73
74    /// Send a legacy transaction instead of an EIP1559 transaction.
75    ///
76    /// This is automatically enabled for common networks without EIP1559.
77    #[arg(long)]
78    pub legacy: bool,
79
80    /// Send a blob transaction using EIP-7594 (PeerDAS) format.
81    ///
82    /// Note: Use with `--eip4844` for the legacy EIP-4844 format.
83    #[arg(long, conflicts_with = "legacy")]
84    pub blob: bool,
85
86    /// Send a blob transaction using EIP-4844 (legacy) format instead of EIP-7594. Must be used
87    /// with `--blob`.
88    #[arg(long, conflicts_with = "legacy", requires = "blob")]
89    pub eip4844: bool,
90
91    /// Gas price for EIP-7594/EIP-4844 blob transaction.
92    #[arg(long, conflicts_with = "legacy", value_parser = parse_ether_value, env = "ETH_BLOB_GAS_PRICE", value_name = "BLOB_PRICE")]
93    pub blob_gas_price: Option<U256>,
94
95    /// EIP-7702 authorization list.
96    ///
97    /// Can be either a hex-encoded signed authorization or an address.
98    #[arg(long, conflicts_with_all = &["legacy", "blob"])]
99    pub auth: Vec<CliAuthorizationList>,
100
101    /// EIP-2930 access list.
102    ///
103    /// Accepts either a JSON-encoded access list or an empty value to create the access list
104    /// via an RPC call to `eth_createAccessList`. To retrieve only the access list portion, use
105    /// the `cast access-list` command.
106    #[arg(long, value_parser = parse_json::<AccessList>)]
107    pub access_list: Option<Option<AccessList>>,
108
109    #[command(flatten)]
110    pub tempo: TempoOpts,
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn parse_priority_gas_tx_opts() {
119        let args: TransactionOpts =
120            TransactionOpts::parse_from(["foundry-cli", "--priority-gas-price", "100"]);
121        assert!(args.priority_gas_price.is_some());
122    }
123}