1use ethereum::{eip2930, legacy, TransactionV3 as EthereumTransaction};
20use ethereum_types::{H160, H256};
21use jsonrpsee::types::ErrorObjectOwned;
22use sp_core::hashing::keccak_256;
24use fc_rpc_core::types::TransactionMessage;
26
27use crate::internal_err;
28
29pub trait EthSigner: Send + Sync {
31 fn accounts(&self) -> Vec<H160>;
33 fn sign(
35 &self,
36 message: TransactionMessage,
37 address: &H160,
38 ) -> Result<EthereumTransaction, ErrorObjectOwned>;
39}
40
41pub struct EthDevSigner {
42 keys: Vec<libsecp256k1::SecretKey>,
43}
44
45impl EthDevSigner {
46 pub fn new() -> Self {
47 Self {
48 keys: vec![libsecp256k1::SecretKey::parse(&[
49 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
50 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
51 0x11, 0x11, 0x11, 0x11,
52 ])
53 .expect("Test key is valid; qed")],
54 }
55 }
56}
57
58fn secret_key_address(secret: &libsecp256k1::SecretKey) -> H160 {
59 let public = libsecp256k1::PublicKey::from_secret_key(secret);
60 public_key_address(&public)
61}
62
63fn public_key_address(public: &libsecp256k1::PublicKey) -> H160 {
64 let mut res = [0u8; 64];
65 res.copy_from_slice(&public.serialize()[1..65]);
66 H160::from(H256::from(keccak_256(&res)))
67}
68
69impl EthSigner for EthDevSigner {
70 fn accounts(&self) -> Vec<H160> {
71 self.keys.iter().map(secret_key_address).collect()
72 }
73
74 fn sign(
75 &self,
76 message: TransactionMessage,
77 address: &H160,
78 ) -> Result<EthereumTransaction, ErrorObjectOwned> {
79 let mut transaction = None;
80
81 for secret in &self.keys {
82 let key_address = secret_key_address(secret);
83
84 if &key_address == address {
85 match message {
86 TransactionMessage::Legacy(m) => {
87 let signing_message = libsecp256k1::Message::parse_slice(&m.hash()[..])
88 .map_err(|_| internal_err("invalid signing message"))?;
89 let (signature, recid) = libsecp256k1::sign(&signing_message, secret);
90 let v = match m.chain_id {
91 None => 27 + recid.serialize() as u64,
92 Some(chain_id) => 2 * chain_id + 35 + recid.serialize() as u64,
93 };
94 let rs = signature.serialize();
95 let r = H256::from_slice(&rs[0..32]);
96 let s = H256::from_slice(&rs[32..64]);
97 transaction =
98 Some(EthereumTransaction::Legacy(ethereum::LegacyTransaction {
99 nonce: m.nonce,
100 gas_price: m.gas_price,
101 gas_limit: m.gas_limit,
102 action: m.action,
103 value: m.value,
104 input: m.input,
105 signature: legacy::TransactionSignature::new(v, r, s).ok_or_else(
106 || internal_err("signer generated invalid signature"),
107 )?,
108 }));
109 }
110 TransactionMessage::EIP2930(m) => {
111 let signing_message = libsecp256k1::Message::parse_slice(&m.hash()[..])
112 .map_err(|_| internal_err("invalid signing message"))?;
113 let (signature, recid) = libsecp256k1::sign(&signing_message, secret);
114 let rs = signature.serialize();
115 let r = H256::from_slice(&rs[0..32]);
116 let s = H256::from_slice(&rs[32..64]);
117 transaction =
118 Some(EthereumTransaction::EIP2930(ethereum::EIP2930Transaction {
119 chain_id: m.chain_id,
120 nonce: m.nonce,
121 gas_price: m.gas_price,
122 gas_limit: m.gas_limit,
123 action: m.action,
124 value: m.value,
125 input: m.input.clone(),
126 access_list: m.access_list,
127 signature: eip2930::TransactionSignature::new(
128 recid.serialize() != 0,
129 r,
130 s,
131 )
132 .ok_or(internal_err("Invalid transaction signature format"))?,
133 }));
134 }
135 TransactionMessage::EIP1559(m) => {
136 let signing_message = libsecp256k1::Message::parse_slice(&m.hash()[..])
137 .map_err(|_| internal_err("invalid signing message"))?;
138 let (signature, recid) = libsecp256k1::sign(&signing_message, secret);
139 let rs = signature.serialize();
140 let r = H256::from_slice(&rs[0..32]);
141 let s = H256::from_slice(&rs[32..64]);
142 transaction =
143 Some(EthereumTransaction::EIP1559(ethereum::EIP1559Transaction {
144 chain_id: m.chain_id,
145 nonce: m.nonce,
146 max_priority_fee_per_gas: m.max_priority_fee_per_gas,
147 max_fee_per_gas: m.max_fee_per_gas,
148 gas_limit: m.gas_limit,
149 action: m.action,
150 value: m.value,
151 input: m.input.clone(),
152 access_list: m.access_list,
153 signature: eip2930::TransactionSignature::new(
154 recid.serialize() != 0,
155 r,
156 s,
157 )
158 .ok_or(internal_err("Invalid transaction signature format"))?,
159 }));
160 }
161 TransactionMessage::EIP7702(m) => {
162 let signing_message = libsecp256k1::Message::parse_slice(&m.hash()[..])
163 .map_err(|_| internal_err("invalid signing message"))?;
164 let (signature, recid) = libsecp256k1::sign(&signing_message, secret);
165 let rs = signature.serialize();
166 let r = H256::from_slice(&rs[0..32]);
167 let s = H256::from_slice(&rs[32..64]);
168 transaction =
169 Some(EthereumTransaction::EIP7702(ethereum::EIP7702Transaction {
170 chain_id: m.chain_id,
171 nonce: m.nonce,
172 max_priority_fee_per_gas: m.max_priority_fee_per_gas,
173 max_fee_per_gas: m.max_fee_per_gas,
174 gas_limit: m.gas_limit,
175 destination: m.destination,
176 value: m.value,
177 data: m.data.clone(),
178 access_list: m.access_list,
179 authorization_list: m.authorization_list,
180 signature: eip2930::TransactionSignature::new(
181 recid.serialize() != 0,
182 r,
183 s,
184 )
185 .ok_or(internal_err("Invalid transaction signature format"))?,
186 }));
187 }
188 }
189 break;
190 }
191 }
192
193 transaction.ok_or_else(|| internal_err("signer not available"))
194 }
195}