1pub use ethereum::{
8 AccessListItem, BlockV2 as Block, LegacyTransactionMessage, Log, ReceiptV3 as Receipt,
9 TransactionAction, TransactionSignature, TransactionV2 as Transaction,
10};
11use frame_support::parameter_types;
12use rlp::RlpStream;
13use sp_core::crypto::AccountId32;
14use sp_core::{H160, H256, U256, keccak_256};
15
16parameter_types! {
17 pub const ChainId: u64 = 870;
19}
20
21#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct AccountInfo {
23 pub address: H160,
24 pub account_id: AccountId32,
25 pub private_key: H256,
26}
27
28pub fn address_build(mut seed: u128) -> AccountInfo {
31 seed += 1;
32
33 let mut seed_bytes = [0u8; 32];
34 seed_bytes[0..16].copy_from_slice(&seed.to_be_bytes());
35 let private_key = H256::from_slice(&seed_bytes);
36 let secret_key = libsecp256k1::SecretKey::parse_slice(&private_key[..]).unwrap();
40 let public_key = &libsecp256k1::PublicKey::from_secret_key(&secret_key).serialize()[1..65];
41 let address = H160::from(H256::from(keccak_256(public_key)));
42
43 let mut data = [0u8; 32];
44 data[0..20].copy_from_slice(&address[..]);
45
46 AccountInfo {
47 private_key,
48 account_id: AccountId32::from(Into::<[u8; 32]>::into(data)),
49 address,
50 }
51}
52
53pub fn contract_address(sender: H160, nonce: u64) -> H160 {
56 let mut rlp = RlpStream::new_list(2);
57 rlp.append(&sender);
58 rlp.append(&nonce);
59
60 H160::from_slice(&keccak_256(&rlp.out())[12..])
61}
62
63pub struct LegacyUnsignedTransaction {
64 pub nonce: U256,
65 pub gas_price: U256,
66 pub gas_limit: U256,
67 pub action: TransactionAction,
68 pub value: U256,
69 pub input: Vec<u8>,
70}
71
72impl LegacyUnsignedTransaction {
73 fn signing_rlp_append(&self, s: &mut RlpStream) {
74 s.begin_list(9);
75 s.append(&self.nonce);
76 s.append(&self.gas_price);
77 s.append(&self.gas_limit);
78 s.append(&self.action);
79 s.append(&self.value);
80 s.append(&self.input);
81 s.append(&ChainId::get());
82 s.append(&0u8);
83 s.append(&0u8);
84 }
85
86 fn signing_hash(&self) -> H256 {
87 let mut stream = RlpStream::new();
88 self.signing_rlp_append(&mut stream);
89 H256::from(keccak_256(&stream.out()))
90 }
91
92 pub fn sign(&self, key: &H256) -> Transaction {
93 self.sign_with_chain_id(key, ChainId::get())
94 }
95
96 pub fn sign_with_chain_id(&self, key: &H256, chain_id: u64) -> Transaction {
97 let hash = self.signing_hash();
98 let msg = libsecp256k1::Message::parse(hash.as_fixed_bytes());
99 let s = libsecp256k1::sign(
100 &msg,
101 &libsecp256k1::SecretKey::parse_slice(&key[..]).unwrap(),
102 );
103 let sig = s.0.serialize();
104
105 let sig = TransactionSignature::new(
106 s.1.serialize() as u64 % 2 + chain_id * 2 + 35,
107 H256::from_slice(&sig[0..32]),
108 H256::from_slice(&sig[32..64]),
109 )
110 .unwrap();
111
112 Transaction::Legacy(ethereum::LegacyTransaction {
113 nonce: self.nonce,
114 gas_price: self.gas_price,
115 gas_limit: self.gas_limit,
116 action: self.action,
117 value: self.value,
118 input: self.input.clone(),
119 signature: sig,
120 })
121 }
122}
123
124pub struct EIP2930UnsignedTransaction {
125 pub nonce: U256,
126 pub gas_price: U256,
127 pub gas_limit: U256,
128 pub action: TransactionAction,
129 pub value: U256,
130 pub input: Vec<u8>,
131}
132
133impl EIP2930UnsignedTransaction {
134 pub fn sign(&self, secret: &H256, chain_id: Option<u64>) -> Transaction {
135 let secret = {
136 let mut sk: [u8; 32] = [0u8; 32];
137 sk.copy_from_slice(&secret[0..]);
138 libsecp256k1::SecretKey::parse(&sk).unwrap()
139 };
140 let chain_id = chain_id.unwrap_or(ChainId::get());
141 let msg = ethereum::EIP2930TransactionMessage {
142 chain_id,
143 nonce: self.nonce,
144 gas_price: self.gas_price,
145 gas_limit: self.gas_limit,
146 action: self.action,
147 value: self.value,
148 input: self.input.clone(),
149 access_list: vec![],
150 };
151 let signing_message = libsecp256k1::Message::parse_slice(&msg.hash()[..]).unwrap();
152
153 let (signature, recid) = libsecp256k1::sign(&signing_message, &secret);
154 let rs = signature.serialize();
155 let r = H256::from_slice(&rs[0..32]);
156 let s = H256::from_slice(&rs[32..64]);
157 Transaction::EIP2930(ethereum::EIP2930Transaction {
158 chain_id: msg.chain_id,
159 nonce: msg.nonce,
160 gas_price: msg.gas_price,
161 gas_limit: msg.gas_limit,
162 action: msg.action,
163 value: msg.value,
164 input: msg.input.clone(),
165 access_list: msg.access_list,
166 odd_y_parity: recid.serialize() != 0,
167 r,
168 s,
169 })
170 }
171}
172
173pub struct EIP1559UnsignedTransaction {
174 pub nonce: U256,
175 pub max_priority_fee_per_gas: U256,
176 pub max_fee_per_gas: U256,
177 pub gas_limit: U256,
178 pub action: TransactionAction,
179 pub value: U256,
180 pub input: Vec<u8>,
181}
182
183impl EIP1559UnsignedTransaction {
184 pub fn sign(&self, secret: &H256, chain_id: Option<u64>) -> Transaction {
185 let secret = {
186 let mut sk: [u8; 32] = [0u8; 32];
187 sk.copy_from_slice(&secret[0..]);
188 libsecp256k1::SecretKey::parse(&sk).unwrap()
189 };
190 let chain_id = chain_id.unwrap_or(ChainId::get());
191 let msg = ethereum::EIP1559TransactionMessage {
192 chain_id,
193 nonce: self.nonce,
194 max_priority_fee_per_gas: self.max_priority_fee_per_gas,
195 max_fee_per_gas: self.max_fee_per_gas,
196 gas_limit: self.gas_limit,
197 action: self.action,
198 value: self.value,
199 input: self.input.clone(),
200 access_list: vec![],
201 };
202 let signing_message = libsecp256k1::Message::parse_slice(&msg.hash()[..]).unwrap();
203
204 let (signature, recid) = libsecp256k1::sign(&signing_message, &secret);
205 let rs = signature.serialize();
206 let r = H256::from_slice(&rs[0..32]);
207 let s = H256::from_slice(&rs[32..64]);
208 Transaction::EIP1559(ethereum::EIP1559Transaction {
209 chain_id: msg.chain_id,
210 nonce: msg.nonce,
211 max_priority_fee_per_gas: msg.max_priority_fee_per_gas,
212 max_fee_per_gas: msg.max_fee_per_gas,
213 gas_limit: msg.gas_limit,
214 action: msg.action,
215 value: msg.value,
216 input: msg.input.clone(),
217 access_list: msg.access_list,
218 odd_y_parity: recid.serialize() != 0,
219 r,
220 s,
221 })
222 }
223}