foundry_common/transactions/
broadcast.rs1use alloy_consensus::Transaction;
2use alloy_eips::eip7702::SignedAuthorization;
3use alloy_network::{Network, TransactionBuilder};
4use alloy_primitives::{Address, Bytes, U256};
5use foundry_common_fmt::UIfmt;
6use serde::{Deserialize, Serialize};
7
8use super::FoundryTransactionBuilder;
9
10#[derive(Clone, Debug, Serialize, Deserialize)]
14#[serde(untagged)]
15pub enum TransactionMaybeSigned<N: Network> {
16 Signed {
17 #[serde(flatten)]
18 tx: N::TxEnvelope,
19 from: Address,
20 },
21 Unsigned(N::TransactionRequest),
22}
23
24impl<N: Network> TransactionMaybeSigned<N> {
25 pub fn new(tx: N::TransactionRequest) -> Self {
27 Self::Unsigned(tx)
28 }
29
30 pub fn is_unsigned(&self) -> bool {
31 matches!(self, Self::Unsigned(_))
32 }
33
34 pub fn as_unsigned_mut(&mut self) -> Option<&mut N::TransactionRequest> {
35 match self {
36 Self::Unsigned(tx) => Some(tx),
37 _ => None,
38 }
39 }
40
41 pub fn from(&self) -> Option<Address> {
42 match self {
43 Self::Signed { from, .. } => Some(*from),
44 Self::Unsigned(tx) => tx.from(),
45 }
46 }
47
48 pub fn input(&self) -> Option<&Bytes> {
49 match self {
50 Self::Signed { tx, .. } => Some(tx.input()),
51 Self::Unsigned(tx) => tx.input(),
52 }
53 }
54
55 pub fn to(&self) -> Option<Address> {
56 match self {
57 Self::Signed { tx, .. } => tx.to(),
58 Self::Unsigned(tx) => tx.to(),
59 }
60 }
61
62 pub fn value(&self) -> Option<U256> {
63 match self {
64 Self::Signed { tx, .. } => Some(tx.value()),
65 Self::Unsigned(tx) => tx.value(),
66 }
67 }
68
69 pub fn gas(&self) -> Option<u128> {
70 match self {
71 Self::Signed { tx, .. } => Some(tx.gas_limit() as u128),
72 Self::Unsigned(tx) => tx.gas_limit().map(|g| g as u128),
73 }
74 }
75
76 pub fn nonce(&self) -> Option<u64> {
77 match self {
78 Self::Signed { tx, .. } => Some(tx.nonce()),
79 Self::Unsigned(tx) => tx.nonce(),
80 }
81 }
82
83 pub fn authorization_list(&self) -> Option<Vec<SignedAuthorization>>
84 where
85 N::TransactionRequest: FoundryTransactionBuilder<N>,
86 {
87 match self {
88 Self::Signed { tx, .. } => tx.authorization_list().map(|auths| auths.to_vec()),
89 Self::Unsigned(tx) => tx.authorization_list().cloned(),
90 }
91 .filter(|auths| !auths.is_empty())
92 }
93}
94
95impl<N: Network> UIfmt for TransactionMaybeSigned<N>
96where
97 N::TxEnvelope: UIfmt,
98 N::TransactionRequest: FoundryTransactionBuilder<N>,
99{
100 fn pretty(&self) -> String {
101 match self {
102 Self::Signed { tx, .. } => tx.pretty(),
103 Self::Unsigned(tx) => format!(
104 "
105accessList {}
106chainId {}
107gasLimit {}
108gasPrice {}
109input {}
110maxFeePerBlobGas {}
111maxFeePerGas {}
112maxPriorityFeePerGas {}
113nonce {}
114to {}
115type {}
116value {}",
117 tx.access_list()
118 .as_ref()
119 .map(|a| a.iter().collect::<Vec<_>>())
120 .unwrap_or_default()
121 .pretty(),
122 tx.chain_id().pretty(),
123 tx.gas_limit().unwrap_or_default(),
124 tx.gas_price().pretty(),
125 tx.input().pretty(),
126 tx.max_fee_per_blob_gas().pretty(),
127 tx.max_fee_per_gas().pretty(),
128 tx.max_priority_fee_per_gas().pretty(),
129 tx.nonce().pretty(),
130 tx.to().pretty(),
131 tx.output_tx_type(),
132 tx.value().pretty(),
133 ),
134 }
135 }
136}