1use crate::{Bytes, SignedAuthorization};
22use cfx_rpc_cfx_types::Transaction as CfxTransaction;
23use cfx_types::{H160, H256, H512, U256, U64};
24use primitives::{
25 transaction::eth_transaction::eip155_signature, AccessList, Action,
26 SignedTransaction,
27};
28use rlp::Encodable;
29use serde::{Deserialize, Serialize};
30
31#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
33#[serde(rename_all = "camelCase")]
34pub struct Transaction {
35 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
37 pub transaction_type: Option<U64>,
38 pub hash: H256,
40 pub nonce: U256,
42 pub block_hash: Option<H256>,
44 pub block_number: Option<U64>,
46 pub transaction_index: Option<U256>,
48 pub from: H160,
50 pub to: Option<H160>,
52 pub value: U256,
54 pub gas_price: Option<U256>,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub max_fee_per_gas: Option<U256>,
59 pub gas: U256,
61 pub input: Bytes,
63 pub creates: Option<H160>,
65 pub raw: Option<Bytes>,
67 pub public_key: Option<H512>,
69 pub chain_id: Option<U64>,
71 #[serde(skip_serializing_if = "Option::is_none")]
74 pub standard_v: Option<U256>,
75 pub v: U64,
77 pub r: U256,
79 pub s: U256,
81 pub status: Option<U64>,
83 #[serde(skip_serializing_if = "Option::is_none")]
85 pub access_list: Option<AccessList>,
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub max_priority_fee_per_gas: Option<U256>,
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub y_parity: Option<U64>,
91 #[serde(skip_serializing_if = "Option::is_none")]
95 pub authorization_list: Option<Vec<SignedAuthorization>>,
96}
97
98impl Transaction {
99 pub fn from_signed(
101 t: &SignedTransaction,
102 block_info: (Option<H256>, Option<U64>, Option<U256>),
103 exec_info: (Option<U64>, Option<H160>),
104 ) -> Transaction {
105 let signature = t.signature();
106
107 let (v, y_parity) = if t.is_2718() {
109 (U64::from(signature.v()), Some(U64::from(signature.v())))
110 } else {
111 (
112 eip155_signature::add_chain_replay_protection(
113 signature.v(),
114 t.chain_id().map(|x| x as u64),
115 )
116 .into(),
117 None,
118 )
119 };
120
121 let mut r: U256 = U256::from_big_endian(signature.r());
125 let mut s: U256 = U256::from_big_endian(signature.s());
126 if r == U256::zero() || s == U256::zero() {
127 let chain_id = t
128 .chain_id()
129 .map(|x| U256::from(x as u64))
130 .expect("should have chain_id");
131 r = chain_id;
132 s = chain_id;
133 }
134
135 Transaction {
136 hash: t.hash(),
137 nonce: *t.nonce(),
138 block_hash: block_info.0,
139 block_number: block_info.1,
140 transaction_index: block_info.2,
141 from: t.sender().address,
142 to: match t.action() {
143 Action::Create => None,
144 Action::Call(ref address) => Some(*address),
145 },
146 value: *t.value(),
147 gas_price: Some(*t.gas_price()),
148 gas: *t.gas(),
149 input: Bytes::new(t.data().clone()),
150 creates: exec_info.1,
151 raw: Some(Bytes::new(
152 t.transaction.transaction.rlp_bytes().to_vec(),
153 )),
154 public_key: t.public().map(Into::into),
155 chain_id: t.chain_id().map(|x| U64::from(x as u64)),
156 standard_v: Some(signature.v().into()),
157 v,
158 r,
159 s,
160 status: exec_info.0,
161 access_list: t.access_list().cloned(),
162 max_fee_per_gas: t.after_1559().then_some(*t.gas_price()),
163 max_priority_fee_per_gas: t
164 .after_1559()
165 .then_some(*t.max_priority_gas_price()),
166 y_parity,
167 transaction_type: Some(U64::from(t.type_id())),
168 authorization_list: t.authorization_list().map(|list| {
169 list.iter()
170 .map(|item| SignedAuthorization::from(item.clone()))
171 .collect()
172 }),
173 }
174 }
175
176 pub fn deployed_contract_address(t: &SignedTransaction) -> Option<H160> {
177 t.cal_created_address().map(|t| t.address)
178 }
179}
180
181#[derive(Debug, Clone, PartialEq, Serialize)]
182#[serde(rename_all = "camelCase")]
183pub enum WrapTransaction {
184 NativeTransaction(CfxTransaction),
185 EthTransaction(Transaction),
186}