foundry_cli/opts/
transaction.rs

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