1
2use super::common::{
3 compute_v, compute_y_parity, encode_blob_hashes,
4 AbiEncodeResult,
5};
6use alloy::{
7 consensus::{
8 Signed, Transaction as ConsensusTransaction, TxEip1559, TxEip2930,
9 TxEip4844Variant, TxEip7702, TxEnvelope, TxLegacy,
10 }, dyn_abi::DynSolValue, eips::eip7702::SignedAuthorization, primitives::{Address, B256, U256}, rpc::types::{AccessListItem, Transaction, TransactionReceipt}
11};
12use thiserror::Error;
13
14#[derive(Debug, Error)]
15pub enum EncodeError {
16 #[error("Custom error: {0}")]
17 Custom(String),
18}
19
20pub fn encode_transaction_type_0(tx: Transaction, signed_tx: Signed<TxLegacy>) -> Vec<DynSolValue> {
21
22 let signature = signed_tx.signature();
24 let chain_id = tx.chain_id();
25 let v = compute_v(signature, chain_id);
26
27 let values: Vec<DynSolValue> = vec![
28 DynSolValue::Uint(U256::from(0), 8), DynSolValue::Uint(U256::from(signed_tx.tx().nonce), 64), DynSolValue::Uint(U256::from(signed_tx.tx().gas_price), 128), DynSolValue::Uint(U256::from(signed_tx.tx().gas_limit), 64), DynSolValue::Address(tx.from), DynSolValue::Address(tx.to().unwrap_or(Address::ZERO)), DynSolValue::Uint(tx.value(), 256), DynSolValue::Bytes(tx.input().to_vec()), DynSolValue::Uint(U256::from(v), 256), DynSolValue::FixedBytes(B256::from(signature.r()), 32), DynSolValue::FixedBytes(B256::from(signature.s()), 32) ];
40
41 values
42}
43
44pub fn encode_transaction_type_1(
45 tx: Transaction,
46 signed_tx: Signed<TxEip2930>,
47) -> Vec<DynSolValue> {
48 let signature = signed_tx.signature();
50 let y_parity: u8 = compute_y_parity(signature);
51 let access_list = encode_access_list(signed_tx.tx().access_list.0.clone());
52
53 let values: Vec<DynSolValue> = vec![
54 DynSolValue::Uint(U256::from(1), 8), DynSolValue::Uint(U256::from(signed_tx.tx().chain_id), 64),
56 DynSolValue::Uint(U256::from(signed_tx.tx().nonce), 64), DynSolValue::Uint(U256::from(signed_tx.tx().gas_price), 128), DynSolValue::Uint(U256::from(signed_tx.tx().gas_limit), 64), DynSolValue::Address(tx.from), DynSolValue::Address(tx.to().unwrap_or(Address::ZERO)), DynSolValue::Uint(tx.value(), 256), DynSolValue::Bytes(tx.input().to_vec()), access_list,
64 DynSolValue::Uint(U256::from(y_parity), 8), DynSolValue::FixedBytes(B256::from(signature.r()), 32), DynSolValue::FixedBytes(B256::from(signature.s()), 32), ];
68
69 values
70}
71
72pub fn encode_transaction_type_2(
73 tx: Transaction,
74 signed_tx: Signed<TxEip1559>,
75) -> Vec<DynSolValue> {
76 let signature = signed_tx.signature();
78 let y_parity = compute_y_parity(signature);
79 let access_list = encode_access_list(signed_tx.tx().access_list.0.clone());
80
81 let values: Vec<DynSolValue> = vec![
82 DynSolValue::Uint(U256::from(2), 8),
83 DynSolValue::Uint(U256::from(signed_tx.tx().chain_id), 64),
84 DynSolValue::Uint(U256::from(signed_tx.tx().nonce), 64),
85 DynSolValue::Uint(U256::from(tx.max_priority_fee_per_gas().unwrap_or(0)), 128),
86 DynSolValue::Uint(U256::from(tx.max_fee_per_gas()), 128),
87 DynSolValue::Uint(U256::from(signed_tx.tx().gas_limit), 64),
88 DynSolValue::Address(tx.from),
89 DynSolValue::Address(tx.to().unwrap_or(Address::ZERO)),
90 DynSolValue::Uint(tx.value(), 256),
91 DynSolValue::Bytes(tx.input().to_vec()),
92 access_list,
93 DynSolValue::Uint(U256::from(y_parity), 8),
94 DynSolValue::FixedBytes(B256::from(signature.r()), 32),
95 DynSolValue::FixedBytes(B256::from(signature.s()), 32),
96 ];
97
98 values
99}
100
101pub fn encode_transaction_type_3(
102 tx: Transaction,
103 signed_tx: Signed<TxEip4844Variant>,
104) -> Vec<DynSolValue> {
105 let signature = signed_tx.signature();
107 let y_parity = compute_y_parity(signature);
108
109 let access_list_item_vector = match tx.access_list() {
110 Some(access_list) => access_list.0.clone(),
111 None => Vec::new(),
112 };
113 let access_list = encode_access_list(access_list_item_vector);
114 let blob_version_hashes = tx.blob_versioned_hashes().unwrap_or_default();
115 let blob_hashes = encode_blob_hashes(blob_version_hashes.to_vec());
116
117 let chain_id = tx.chain_id().unwrap_or(0);
120
121 let values: Vec<DynSolValue> = vec![
122 DynSolValue::Uint(U256::from(3), 8),
123 DynSolValue::Uint(U256::from(chain_id), 64),
124 DynSolValue::Uint(U256::from(signed_tx.tx().nonce()), 64),
125 DynSolValue::Uint(U256::from(tx.max_priority_fee_per_gas().unwrap_or(0)), 128),
126 DynSolValue::Uint(U256::from(tx.max_fee_per_gas()), 128),
127 DynSolValue::Uint(U256::from(signed_tx.tx().gas_limit()), 64),
128 DynSolValue::Address(tx.from),
129 DynSolValue::Address(tx.to().unwrap_or(Address::ZERO)),
130 DynSolValue::Uint(tx.value(), 256),
131 DynSolValue::Bytes(tx.input().to_vec()),
132 access_list,
133 DynSolValue::Uint(
134 U256::from(signed_tx.tx().max_fee_per_blob_gas().unwrap_or(0u128)),
135 128,
136 ),
137 blob_hashes,
138 DynSolValue::Uint(U256::from(y_parity), 8),
139 DynSolValue::FixedBytes(B256::from(signature.r()), 32),
140 DynSolValue::FixedBytes(B256::from(signature.s()), 32),
141 ];
142
143 values
144}
145
146pub fn encode_transaction_type_4(
147 tx: Transaction,
148 signed_tx: Signed<TxEip7702>,
149) -> Vec<DynSolValue> {
150 let signature = signed_tx.signature();
152 let y_parity = compute_y_parity(signature);
153 let access_list = encode_access_list(signed_tx.tx().access_list.0.clone());
154 let authorization_list = encode_authorization_list(signed_tx.tx().authorization_list.clone());
155
156 let chain_id = tx.chain_id().unwrap_or(0);
159
160 let values: Vec<DynSolValue> = vec![
161 DynSolValue::Uint(U256::from(3), 8),
162 DynSolValue::Uint(U256::from(chain_id), 64),
163 DynSolValue::Uint(U256::from(signed_tx.tx().nonce()), 64),
164 DynSolValue::Uint(U256::from(tx.max_priority_fee_per_gas().unwrap_or(0)), 128),
165 DynSolValue::Uint(U256::from(tx.max_fee_per_gas()), 128),
166 DynSolValue::Uint(U256::from(signed_tx.tx().gas_limit()), 64),
167 DynSolValue::Address(tx.from),
168 DynSolValue::Address(tx.to().unwrap_or(Address::ZERO)),
169 DynSolValue::Uint(tx.value(), 256),
170 DynSolValue::Bytes(tx.input().to_vec()),
171 access_list,
172 authorization_list,
173 DynSolValue::Uint(U256::from(y_parity), 8),
174 DynSolValue::FixedBytes(B256::from(signature.r()), 32),
175 DynSolValue::FixedBytes(B256::from(signature.s()), 32),
176 ];
177
178 values
179}
180
181pub fn encode_transaction(tx: Transaction) -> Vec<DynSolValue> {
182 match tx.inner.clone() {
183 TxEnvelope::Legacy(signed_tx) => encode_transaction_type_0(tx, signed_tx),
184 TxEnvelope::Eip2930(signed_tx) => encode_transaction_type_1(tx, signed_tx),
185 TxEnvelope::Eip1559(signed_tx) => encode_transaction_type_2(tx, signed_tx),
186 TxEnvelope::Eip4844(signed_tx) => encode_transaction_type_3(tx, signed_tx),
187 TxEnvelope::Eip7702(signed_tx) => encode_transaction_type_4(tx, signed_tx)
188 }
189}
190
191fn encode_receipt(rx: TransactionReceipt) -> Vec<DynSolValue> {
192
193 let log_blooms = rx.inner.logs_bloom().0.to_vec();
194 let result = vec![
195 DynSolValue::Uint(U256::from(rx.status()), 8),
196 DynSolValue::Uint(U256::from(rx.gas_used), 64),
197 DynSolValue::Array(
198 rx.inner.logs().into_iter().map(|log| {
199
200 let topics = DynSolValue::Array(log.topics().into_iter().map(|topic| {
201 DynSolValue::FixedBytes(topic.clone(), 32)
202 }).collect());
203
204 DynSolValue::Tuple(vec![
205 DynSolValue::Address(log.address()),
206 topics,
207 DynSolValue::Bytes(log.data().data.to_vec())
208 ])
209 }).collect()
210 ),
211 DynSolValue::Bytes(log_blooms),
212 ];
213
214 result
215}
216
217pub fn encode_authorization_list(signed_authorizations: Vec<SignedAuthorization>) -> DynSolValue {
218 let mut result = Vec::new();
219 for signed_authorization in signed_authorizations {
220
221 let signed_authorization_tuple = DynSolValue::Tuple(vec![
222 DynSolValue::Uint(U256::from(signed_authorization.chain_id().clone()), 256),
223 DynSolValue::Address(signed_authorization.address().clone()),
224 DynSolValue::Uint(U256::from(signed_authorization.nonce()), 64),
225 DynSolValue::Uint(U256::from(signed_authorization.y_parity()), 8),
226 DynSolValue::Uint(U256::from(signed_authorization.r()), 256),
227 DynSolValue::Uint(U256::from(signed_authorization.s()), 256)
228 ]);
229
230 result.push(signed_authorization_tuple);
232 }
233
234 DynSolValue::Array(result)
235}
236
237pub fn encode_access_list(access_list: Vec<AccessListItem>) -> DynSolValue {
238
239 let mut list = Vec::new();
240 for access_list_item in access_list {
241
242 let mut storage_keys = Vec::new();
243 for storage_item in access_list_item.storage_keys {
244 storage_keys.push(DynSolValue::FixedBytes(storage_item, 32));
245 }
246
247 let access_list_tuple = DynSolValue::Tuple(vec![
249 DynSolValue::Address(access_list_item.address), DynSolValue::Array(storage_keys)
251 ]);
252
253 list.push(access_list_tuple);
254 }
255
256 DynSolValue::Array(list)
258}
259
260pub fn abi_encode(
261 tx: Transaction,
262 rx: TransactionReceipt,
263) -> Result<AbiEncodeResult, Box<dyn std::error::Error>> {
264
265 let transaction_fields = encode_transaction(tx);
266 let receipt_fields = encode_receipt(rx);
267 let mut all_fields = Vec::new();
268 all_fields.extend(transaction_fields);
269 all_fields.extend(receipt_fields);
270 let tuple = DynSolValue::Tuple(all_fields.clone());
271 let final_bytes = match tuple.abi_encode_sequence() {
272 Some(final_bytes) => {
273 final_bytes
274 },
275 None => {
276 return Err(Box::new(EncodeError::Custom("Failed to encode sequence".into())));
277 }
278 };
279
280 let field_types: Vec<String> = all_fields.into_iter().map(|field| {
281
282 match field.as_type() {
283 Some(sol_type) => {
284 sol_type.sol_type_name().into_owned()
285 },
286 None => "unknown".into()
287 }
288
289 }).collect();
290
291 Ok(AbiEncodeResult {
292 types: field_types,
293 abi: final_bytes,
294 })
295}