1#![cfg_attr(not(feature = "std"), no_std)]
22
23use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
24use scale_info::TypeInfo;
25use sha3::{Digest, Keccak256};
26use sp_core::{ecdsa, H160};
27
28pub use serde::{de::DeserializeOwned, Deserialize, Serialize};
29
30pub const SYSTEM_ACCOUNT_SIZE: u64 = 148;
37
38#[derive(
44 Eq,
45 PartialEq,
46 Copy,
47 Clone,
48 Encode,
49 Decode,
50 TypeInfo,
51 MaxEncodedLen,
52 Default,
53 PartialOrd,
54 Ord,
55 DecodeWithMemTracking,
56)]
57pub struct AccountId20(pub [u8; 20]);
58
59impl_serde::impl_fixed_hash_serde!(AccountId20, 20);
60
61#[cfg(feature = "std")]
62impl std::fmt::Display for AccountId20 {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(f, "{:?}", self.0)
68 }
69}
70
71impl core::fmt::Debug for AccountId20 {
72 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
73 write!(f, "{:?}", H160(self.0))
74 }
75}
76
77impl From<[u8; 20]> for AccountId20 {
78 fn from(bytes: [u8; 20]) -> Self {
79 Self(bytes)
80 }
81}
82
83impl From<AccountId20> for [u8; 20] {
84 fn from(value: AccountId20) -> Self {
85 value.0
86 }
87}
88
89impl From<[u8; 32]> for AccountId20 {
94 fn from(bytes: [u8; 32]) -> Self {
95 let mut buffer = [0u8; 20];
96 buffer.copy_from_slice(&bytes[..20]);
97 Self(buffer)
98 }
99}
100impl From<sp_runtime::AccountId32> for AccountId20 {
101 fn from(account: sp_runtime::AccountId32) -> Self {
102 let bytes: &[u8; 32] = account.as_ref();
103 Self::from(*bytes)
104 }
105}
106
107impl From<H160> for AccountId20 {
108 fn from(h160: H160) -> Self {
109 Self(h160.0)
110 }
111}
112
113impl From<AccountId20> for H160 {
114 fn from(value: AccountId20) -> Self {
115 H160(value.0)
116 }
117}
118
119#[cfg(feature = "std")]
120impl std::str::FromStr for AccountId20 {
121 type Err = &'static str;
122 fn from_str(input: &str) -> Result<Self, Self::Err> {
123 H160::from_str(input)
124 .map(Into::into)
125 .map_err(|_| "invalid hex address.")
126 }
127}
128
129#[derive(
130 Eq,
131 PartialEq,
132 Clone,
133 Encode,
134 Decode,
135 sp_core::RuntimeDebug,
136 TypeInfo,
137 Serialize,
138 Deserialize,
139 DecodeWithMemTracking,
140)]
141
142pub struct EthereumSignature(ecdsa::Signature);
146
147impl From<ecdsa::Signature> for EthereumSignature {
148 fn from(x: ecdsa::Signature) -> Self {
149 EthereumSignature(x)
150 }
151}
152
153impl From<sp_runtime::MultiSignature> for EthereumSignature {
154 fn from(signature: sp_runtime::MultiSignature) -> Self {
155 match signature {
156 sp_runtime::MultiSignature::Ed25519(_) => {
157 panic!("Ed25519 not supported for EthereumSignature")
158 }
159 sp_runtime::MultiSignature::Sr25519(_) => {
160 panic!("Sr25519 not supported for EthereumSignature")
161 }
162 sp_runtime::MultiSignature::Ecdsa(sig) => Self(sig),
163 sp_runtime::MultiSignature::Eth(sig) => Self(ecdsa::Signature::from(sig.0)),
165 }
166 }
167}
168
169impl sp_runtime::traits::Verify for EthereumSignature {
170 type Signer = EthereumSigner;
171 fn verify<L: sp_runtime::traits::Lazy<[u8]>>(&self, mut msg: L, signer: &AccountId20) -> bool {
172 let mut m = [0u8; 32];
173 m.copy_from_slice(Keccak256::digest(msg.get()).as_slice());
174 match sp_io::crypto::secp256k1_ecdsa_recover(self.0.as_ref(), &m) {
175 Ok(pubkey) => {
176 AccountId20(H160::from_slice(&Keccak256::digest(pubkey).as_slice()[12..32]).0)
177 == *signer
178 }
179 Err(sp_io::EcdsaVerifyError::BadRS) => {
180 log::error!(target: "evm", "Error recovering: Incorrect value of R or S");
181 false
182 }
183 Err(sp_io::EcdsaVerifyError::BadV) => {
184 log::error!(target: "evm", "Error recovering: Incorrect value of V");
185 false
186 }
187 Err(sp_io::EcdsaVerifyError::BadSignature) => {
188 log::error!(target: "evm", "Error recovering: Invalid signature");
189 false
190 }
191 }
192 }
193}
194
195#[derive(
197 Eq,
198 PartialEq,
199 Ord,
200 PartialOrd,
201 Clone,
202 Encode,
203 Decode,
204 sp_core::RuntimeDebug,
205 TypeInfo,
206 DecodeWithMemTracking,
207)]
208#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
209pub struct EthereumSigner([u8; 20]);
210
211impl sp_runtime::traits::IdentifyAccount for EthereumSigner {
212 type AccountId = AccountId20;
213 fn into_account(self) -> AccountId20 {
214 AccountId20(self.0)
215 }
216}
217
218impl From<[u8; 20]> for EthereumSigner {
219 fn from(x: [u8; 20]) -> Self {
220 EthereumSigner(x)
221 }
222}
223
224impl From<ecdsa::Public> for EthereumSigner {
225 fn from(x: ecdsa::Public) -> Self {
226 let decompressed = libsecp256k1::PublicKey::parse_slice(
227 &x.0,
228 Some(libsecp256k1::PublicKeyFormat::Compressed),
229 )
230 .expect("Wrong compressed public key provided")
231 .serialize();
232 let mut m = [0u8; 64];
233 m.copy_from_slice(&decompressed[1..65]);
234 let account = H160::from_slice(&Keccak256::digest(m).as_slice()[12..32]);
235 EthereumSigner(account.into())
236 }
237}
238
239impl From<libsecp256k1::PublicKey> for EthereumSigner {
240 fn from(x: libsecp256k1::PublicKey) -> Self {
241 let mut m = [0u8; 64];
242 m.copy_from_slice(&x.serialize()[1..65]);
243 let account = H160::from_slice(&Keccak256::digest(m).as_slice()[12..32]);
244 EthereumSigner(account.into())
245 }
246}
247
248#[cfg(feature = "std")]
249impl std::fmt::Display for EthereumSigner {
250 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
251 write!(fmt, "ethereum signature: {:?}", H160::from_slice(&self.0))
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258 use sp_core::{ecdsa, Pair, H256};
259 use sp_runtime::traits::IdentifyAccount;
260
261 #[test]
262 fn test_account_derivation_1() {
263 let secret_key =
265 hex::decode("502f97299c472b88754accd412b7c9a6062ef3186fba0c0388365e1edec24875")
266 .unwrap();
267 let mut expected_hex_account = [0u8; 20];
268 hex::decode_to_slice(
269 "976f8456e4e2034179b284a23c0e0c8f6d3da50c",
270 &mut expected_hex_account,
271 )
272 .expect("example data is 20 bytes of valid hex");
273
274 let public_key = ecdsa::Pair::from_seed_slice(&secret_key).unwrap().public();
275 let account: EthereumSigner = public_key.into();
276 let expected_account = AccountId20::from(expected_hex_account);
277 assert_eq!(account.into_account(), expected_account);
278 }
279 #[test]
280 fn test_account_derivation_2() {
281 let secret_key =
283 hex::decode("0f02ba4d7f83e59eaa32eae9c3c4d99b68ce76decade21cdab7ecce8f4aef81a")
284 .unwrap();
285 let mut expected_hex_account = [0u8; 20];
286 hex::decode_to_slice(
287 "420e9f260b40af7e49440cead3069f8e82a5230f",
288 &mut expected_hex_account,
289 )
290 .expect("example data is 20 bytes of valid hex");
291
292 let public_key = ecdsa::Pair::from_seed_slice(&secret_key).unwrap().public();
293 let account: EthereumSigner = public_key.into();
294 let expected_account = AccountId20::from(expected_hex_account);
295 assert_eq!(account.into_account(), expected_account);
296 }
297 #[test]
298 fn test_account_derivation_3() {
299 let m = hex::decode("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
300 .unwrap();
301 let old = AccountId20(H160::from(H256::from_slice(Keccak256::digest(&m).as_slice())).0);
302 let new = AccountId20(H160::from_slice(&Keccak256::digest(&m).as_slice()[12..32]).0);
303 assert_eq!(new, old);
304 }
305}