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<U256>,
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<U256>, 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 = signature.r().into();
125 let mut s: U256 = signature.s().into();
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(t.transaction.transaction.rlp_bytes())),
152 public_key: t.public().map(Into::into),
153 chain_id: t.chain_id().map(|x| U64::from(x as u64)),
154 standard_v: Some(signature.v().into()),
155 v,
156 r,
157 s,
158 status: exec_info.0,
159 access_list: t.access_list().cloned(),
160 max_fee_per_gas: t.after_1559().then_some(*t.gas_price()),
161 max_priority_fee_per_gas: t
162 .after_1559()
163 .then_some(*t.max_priority_gas_price()),
164 y_parity,
165 transaction_type: Some(U64::from(t.type_id())),
166 authorization_list: t.authorization_list().map(|list| {
167 list.iter()
168 .map(|item| SignedAuthorization::from(item.clone()))
169 .collect()
170 }),
171 }
172 }
173
174 pub fn deployed_contract_address(t: &SignedTransaction) -> Option<H160> {
175 t.cal_created_address().map(|t| t.address)
176 }
177}
178
179#[derive(Debug, Clone, PartialEq, Serialize)]
180#[serde(rename_all = "camelCase")]
181pub enum WrapTransaction {
182 NativeTransaction(CfxTransaction),
183 EthTransaction(Transaction),
184}