1use std::str::FromStr;
23use 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;
89/// 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.
14Address(Address),
15/// If RLP-encoded authorization is provided, we decode it and attach to transaction.
16Signed(SignedAuthorization),
17}
1819impl FromStrfor CliAuthorizationList {
20type Err = eyre::Error;
2122fn from_str(s: &str) -> Result<Self, Self::Err> {
23if let Ok(addr) = Address::from_str(s) {
24Ok(Self::Address(addr))
25 } else if let Ok(auth) = SignedAuthorization::decode(&mut hex::decode(s)?.as_ref()) {
26Ok(Self::Signed(auth))
27 } else {
28eyre::bail!("Failed to decode authorization")
29 }
30 }
31}
3233#[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")]
38pub gas_limit: Option<U256>,
3940/// 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)]
50pub gas_price: Option<U256>,
5152/// 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)]
59pub priority_gas_price: Option<U256>,
6061/// 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)]
67pub value: Option<U256>,
6869/// Nonce for the transaction.
70#[arg(long)]
71pub nonce: Option<U64>,
7273/// Send a legacy transaction instead of an EIP1559 transaction.
74 ///
75 /// This is automatically enabled for common networks without EIP1559.
76#[arg(long)]
77pub legacy: bool,
7879/// Send a EIP-4844 blob transaction.
80#[arg(long, conflicts_with = "legacy")]
81pub blob: bool,
8283/// 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")]
85pub blob_gas_price: Option<U256>,
8687/// 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"])]
91pub auth: Option<CliAuthorizationList>,
9293/// 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>)]
99pub access_list: Option<Option<AccessList>>,
100}
101102#[cfg(test)]
103mod tests {
104use super::*;
105106#[test]
107fn parse_priority_gas_tx_opts() {
108let args: TransactionOpts =
109 TransactionOpts::parse_from(["foundry-cli", "--priority-gas-price", "100"]);
110assert!(args.priority_gas_price.is_some());
111 }
112}