1use crate::{Bytes, SignedAuthorization};
22use cfx_types::{
23 cal_contract_address, CreateContractAddressType, H160, H256, H512, U256,
24 U64,
25};
26use primitives::{
27 transaction::eth_transaction::eip155_signature, AccessList, Action,
28 SignedTransaction,
29};
30use rlp::Encodable;
31use serde::{Deserialize, Serialize};
32
33#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
35#[serde(rename_all = "camelCase")]
36pub struct Transaction {
37 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
39 pub transaction_type: Option<U64>,
40 pub hash: H256,
42 pub nonce: U256,
44 pub block_hash: Option<H256>,
46 pub block_number: Option<U256>,
48 pub transaction_index: Option<U256>,
50 pub from: H160,
52 pub to: Option<H160>,
54 pub value: U256,
56 pub gas_price: Option<U256>,
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub max_fee_per_gas: Option<U256>,
61 pub gas: U256,
63 pub input: Bytes,
65 pub creates: Option<H160>,
67 pub raw: Option<Bytes>,
69 pub public_key: Option<H512>,
71 pub chain_id: Option<U64>,
73 #[serde(skip_serializing_if = "Option::is_none")]
76 pub standard_v: Option<U256>,
77 pub v: U64,
79 pub r: U256,
81 pub s: U256,
83 pub status: Option<U64>,
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub access_list: Option<AccessList>,
88 #[serde(skip_serializing_if = "Option::is_none")]
90 pub max_priority_fee_per_gas: Option<U256>,
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub y_parity: Option<U64>,
93 #[serde(skip_serializing_if = "Option::is_none")]
97 pub authorization_list: Option<Vec<SignedAuthorization>>,
98}
99
100impl Transaction {
101 pub fn from_signed(
103 t: &SignedTransaction,
104 block_info: (Option<H256>, Option<U256>, Option<U256>),
105 exec_info: (Option<U64>, Option<H160>),
106 ) -> Transaction {
107 let signature = t.signature();
108
109 let (v, y_parity) = if t.is_2718() {
111 (U64::from(signature.v()), Some(U64::from(signature.v())))
112 } else {
113 (
114 eip155_signature::add_chain_replay_protection(
115 signature.v(),
116 t.chain_id().map(|x| x as u64),
117 )
118 .into(),
119 None,
120 )
121 };
122
123 let mut r: U256 = signature.r().into();
127 let mut s: U256 = signature.s().into();
128 if r == U256::zero() || s == U256::zero() {
129 let chain_id = t
130 .chain_id()
131 .map(|x| U256::from(x as u64))
132 .expect("should have chain_id");
133 r = chain_id;
134 s = chain_id;
135 }
136
137 Transaction {
138 hash: t.hash(),
139 nonce: *t.nonce(),
140 block_hash: block_info.0,
141 block_number: block_info.1,
142 transaction_index: block_info.2,
143 from: t.sender().address,
144 to: match t.action() {
145 Action::Create => None,
146 Action::Call(ref address) => Some(*address),
147 },
148 value: *t.value(),
149 gas_price: Some(*t.gas_price()),
150 gas: *t.gas(),
151 input: Bytes::new(t.data().clone()),
152 creates: exec_info.1,
153 raw: Some(Bytes::new(t.transaction.transaction.rlp_bytes())),
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 match t.action() {
178 Action::Create => {
179 let (new_contract_address, _) = cal_contract_address(
180 CreateContractAddressType::FromSenderNonce,
181 0,
182 &t.sender().address,
183 t.nonce(),
184 t.data(),
185 );
186 Some(new_contract_address)
187 }
188 Action::Call(_) => None,
189 }
190 }
191}