1#![cfg_attr(not(feature = "std"), no_std)]
19#![warn(unused_crate_dependencies)]
20
21extern crate alloc;
22
23use alloc::string::{String, ToString};
24use core::fmt;
25
26use scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
27use scale_info::TypeInfo;
28use sp_core::{crypto::AccountId32, ecdsa, RuntimeDebug, H160, H256};
30use sp_io::hashing::keccak_256;
31use sp_runtime::MultiSignature;
32
33use xcm::latest::{Junction, Location};
35
36#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
40#[derive(Encode, Decode, DecodeWithMemTracking, MaxEncodedLen, TypeInfo)]
41pub struct AccountId20(pub [u8; 20]);
42
43#[cfg(feature = "serde")]
44impl_serde::impl_fixed_hash_serde!(AccountId20, 20);
45
46#[cfg(feature = "std")]
47impl std::str::FromStr for AccountId20 {
48 type Err = &'static str;
49
50 fn from_str(s: &str) -> Result<Self, Self::Err> {
51 H160::from_str(s)
52 .map(Into::into)
53 .map_err(|_| "invalid hex address.")
54 }
55}
56
57impl fmt::Display for AccountId20 {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 let address = hex::encode(self.0).trim_start_matches("0x").to_lowercase();
60 let address_hash = hex::encode(keccak_256(address.as_bytes()));
61
62 let checksum: String =
63 address
64 .char_indices()
65 .fold(String::from("0x"), |mut acc, (index, address_char)| {
66 let n = u16::from_str_radix(&address_hash[index..index + 1], 16)
67 .expect("Keccak256 hashed; qed");
68
69 if n > 7 {
70 acc.push_str(&address_char.to_uppercase().to_string())
72 } else {
73 acc.push(address_char)
75 }
76
77 acc
78 });
79 write!(f, "{checksum}")
80 }
81}
82
83impl fmt::Debug for AccountId20 {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 write!(f, "{:?}", H160(self.0))
86 }
87}
88
89impl From<[u8; 20]> for AccountId20 {
90 fn from(bytes: [u8; 20]) -> Self {
91 Self(bytes)
92 }
93}
94
95impl<'a> TryFrom<&'a [u8]> for AccountId20 {
96 type Error = ();
97 fn try_from(x: &'a [u8]) -> Result<AccountId20, ()> {
98 if x.len() == 20 {
99 let mut data = [0; 20];
100 data.copy_from_slice(x);
101 Ok(AccountId20(data))
102 } else {
103 Err(())
104 }
105 }
106}
107
108impl From<AccountId20> for [u8; 20] {
109 fn from(val: AccountId20) -> Self {
110 val.0
111 }
112}
113
114impl From<H160> for AccountId20 {
115 fn from(h160: H160) -> Self {
116 Self(h160.0)
117 }
118}
119
120impl From<AccountId20> for H160 {
121 fn from(val: AccountId20) -> Self {
122 H160(val.0)
123 }
124}
125
126impl AsRef<[u8]> for AccountId20 {
127 fn as_ref(&self) -> &[u8] {
128 &self.0[..]
129 }
130}
131
132impl AsMut<[u8]> for AccountId20 {
133 fn as_mut(&mut self) -> &mut [u8] {
134 &mut self.0[..]
135 }
136}
137
138impl AsRef<[u8; 20]> for AccountId20 {
139 fn as_ref(&self) -> &[u8; 20] {
140 &self.0
141 }
142}
143
144impl AsMut<[u8; 20]> for AccountId20 {
145 fn as_mut(&mut self) -> &mut [u8; 20] {
146 &mut self.0
147 }
148}
149
150impl From<ecdsa::Public> for AccountId20 {
151 fn from(pk: ecdsa::Public) -> Self {
152 let decompressed = libsecp256k1::PublicKey::parse_compressed(&pk.0)
153 .expect("Wrong compressed public key provided")
154 .serialize();
155 let mut m = [0u8; 64];
156 m.copy_from_slice(&decompressed[1..65]);
157 let account = H160::from(H256::from(keccak_256(&m)));
158 Self(account.into())
159 }
160}
161
162impl From<[u8; 32]> for AccountId20 {
163 fn from(bytes: [u8; 32]) -> Self {
164 let mut buffer = [0u8; 20];
165 buffer.copy_from_slice(&bytes[..20]);
166 Self(buffer)
167 }
168}
169
170impl From<AccountId32> for AccountId20 {
171 fn from(account: AccountId32) -> Self {
172 let bytes: &[u8; 32] = account.as_ref();
173 Self::from(*bytes)
174 }
175}
176
177impl From<AccountId20> for Location {
178 fn from(id: AccountId20) -> Self {
179 Junction::AccountKey20 {
180 network: None,
181 key: id.into(),
182 }
183 .into()
184 }
185}
186
187#[derive(Clone, Eq, PartialEq)]
188#[derive(
189 RuntimeDebug,
190 Encode,
191 Decode,
192 DecodeWithMemTracking,
193 MaxEncodedLen,
194 TypeInfo
195)]
196#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
197pub struct EthereumSignature(ecdsa::Signature);
198
199impl sp_runtime::traits::Verify for EthereumSignature {
200 type Signer = EthereumSigner;
201 fn verify<L: sp_runtime::traits::Lazy<[u8]>>(&self, mut msg: L, signer: &AccountId20) -> bool {
202 let m = keccak_256(msg.get());
203 match sp_io::crypto::secp256k1_ecdsa_recover(self.0.as_ref(), &m) {
204 Ok(pubkey) => AccountId20(H160::from(H256::from(keccak_256(&pubkey))).0) == *signer,
205 Err(sp_io::EcdsaVerifyError::BadRS) => {
206 log::error!(target: "evm", "Error recovering: Incorrect value of R or S");
207 false
208 }
209 Err(sp_io::EcdsaVerifyError::BadV) => {
210 log::error!(target: "evm", "Error recovering: Incorrect value of V");
211 false
212 }
213 Err(sp_io::EcdsaVerifyError::BadSignature) => {
214 log::error!(target: "evm", "Error recovering: Invalid signature");
215 false
216 }
217 }
218 }
219}
220
221impl From<MultiSignature> for EthereumSignature {
222 fn from(signature: MultiSignature) -> Self {
223 match signature {
224 MultiSignature::Ed25519(_) => {
225 panic!("Ed25519 not supported for EthereumSignature")
226 }
227 MultiSignature::Sr25519(_) => {
228 panic!("Sr25519 not supported for EthereumSignature")
229 }
230 MultiSignature::Ecdsa(sig) => Self(sig),
231 }
232 }
233}
234
235impl EthereumSignature {
236 pub fn new(s: ecdsa::Signature) -> Self {
237 Self(s)
238 }
239}
240
241#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
242#[derive(RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)]
243#[repr(transparent)]
244pub struct EthereumSigner([u8; 20]);
245
246impl From<[u8; 20]> for EthereumSigner {
247 fn from(x: [u8; 20]) -> Self {
248 EthereumSigner(x)
249 }
250}
251
252impl sp_runtime::traits::IdentifyAccount for EthereumSigner {
253 type AccountId = AccountId20;
254 fn into_account(self) -> AccountId20 {
255 AccountId20(self.0)
256 }
257}
258
259impl fmt::Display for EthereumSigner {
260 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
261 write!(fmt, "{:?}", H160::from(self.0))
262 }
263}
264
265impl From<ecdsa::Public> for EthereumSigner {
266 fn from(pk: ecdsa::Public) -> Self {
267 let decompressed = libsecp256k1::PublicKey::parse_compressed(&pk.0)
268 .expect("Wrong compressed public key provided")
269 .serialize();
270 let mut m = [0u8; 64];
271 m.copy_from_slice(&decompressed[1..65]);
272 let account = H160::from(H256::from(keccak_256(&m)));
273 EthereumSigner(account.into())
274 }
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280 use sp_core::{ecdsa, Pair, H256};
281 use sp_runtime::traits::IdentifyAccount;
282
283 #[test]
284 fn test_derive_from_secret_key() {
285 let sk = hex::decode("eb3d6b0b0c794f6fd8964b4a28df99d4baa5f9c8d33603c4cc62504daa259358")
286 .unwrap();
287 let hex_acc: [u8; 20] = hex::decode("98fa2838ee6471ae87135880f870a785318e6787")
288 .unwrap()
289 .try_into()
290 .unwrap();
291 let acc = AccountId20::from(hex_acc);
292
293 let pk = ecdsa::Pair::from_seed_slice(&sk).unwrap().public();
294 let signer: EthereumSigner = pk.into();
295
296 assert_eq!(signer.into_account(), acc);
297 }
298
299 #[test]
300 fn test_from_h160() {
301 let m = hex::decode("28490327ff4e60d44b8aadf5478266422ed01232cc712c2d617e5c650ca15b85")
302 .unwrap();
303 let old: AccountId20 = H160::from(H256::from(keccak_256(&m))).into();
304 let new: AccountId20 = H160::from_slice(&keccak_256(&m)[12..32]).into();
305 assert_eq!(new, old);
306 }
307
308 #[test]
309 fn test_account_display() {
310 let pk = ecdsa::Pair::from_string("//Alice", None)
311 .expect("static values are valid; qed")
312 .public();
313 let signer: EthereumSigner = pk.into();
314 let account: AccountId20 = signer.into_account();
315 let account_fmt = format!("{account}");
316 assert_eq!(account_fmt, "0xE04CC55ebEE1cBCE552f250e85c57B70B2E2625b");
317 }
318}