diff --git a/Cargo.lock b/Cargo.lock
index f2be80a72a..7336ca52c6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4925,6 +4925,7 @@ dependencies = [
"frame-support",
"frame-system",
"hex",
+ "libsecp256k1",
"pallet-assets",
"pallet-balances",
"pallet-contracts",
diff --git a/pallets/unified-accounts/src/impls.rs b/pallets/unified-accounts/src/impls.rs
deleted file mode 100644
index c49fcb652d..0000000000
--- a/pallets/unified-accounts/src/impls.rs
+++ /dev/null
@@ -1,175 +0,0 @@
-// This file is part of Astar.
-
-// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-// Astar is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Astar is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Astar. If not, see .
-
-use astar_primitives::ethereum_checked::AccountMapping;
-use astar_primitives::evm::EvmAddress;
-use astar_primitives::AccountId;
-use frame_support::traits::OnKilledAccount;
-use frame_support::{pallet_prelude::*, traits::Get};
-use pallet_evm::AddressMapping;
-use precompile_utils::keccak256;
-use sp_core::{Hasher, H160, H256, U256};
-use sp_io::hashing::keccak_256;
-use sp_runtime::traits::{LookupError, StaticLookup, Zero};
-use sp_runtime::MultiAddress;
-use sp_std::marker::PhantomData;
-
-use crate::*;
-
-/// UnifiedAddressMapper implementation
-impl UnifiedAddressMapper for Pallet {
- fn to_account_id(evm_address: &EvmAddress) -> Option {
- NativeToEvm::::get(evm_address)
- }
-
- fn to_account_id_or_default(evm_address: &EvmAddress) -> T::AccountId {
- NativeToEvm::::get(evm_address).unwrap_or_else(|| {
- // fallback to default account_id
- T::DefaultAddressMapping::into_account_id(evm_address.clone())
- })
- }
-
- fn to_default_account_id(evm_address: &EvmAddress) -> T::AccountId {
- T::DefaultAddressMapping::into_account_id(evm_address.clone())
- }
-
- fn to_h160(account_id: &T::AccountId) -> Option {
- EvmToNative::::get(account_id)
- }
-
- fn to_h160_or_default(account_id: &T::AccountId) -> EvmAddress {
- EvmToNative::::get(account_id).unwrap_or_else(|| {
- // fallback to default account_id
- T::DefaultAccountMapping::into_h160(account_id.clone())
- })
- }
-
- fn to_default_h160(account_id: &T::AccountId) -> EvmAddress {
- T::DefaultAccountMapping::into_h160(account_id.clone())
- }
-}
-
-/// AccountMapping wrapper implementation
-impl AccountMapping for Pallet {
- fn into_h160(account: T::AccountId) -> H160 {
- >::to_h160_or_default(&account)
- }
-}
-
-/// Hashed derive mapping for converting account id to evm address
-pub struct HashedAccountMapping(sp_std::marker::PhantomData);
-impl> AccountMapping for HashedAccountMapping {
- fn into_h160(account: AccountId) -> H160 {
- let payload = (b"evm:", account);
- H160::from_slice(&payload.using_encoded(H::hash)[0..20])
- }
-}
-
-/// AddressMapping wrapper implementation
-impl AddressMapping for Pallet {
- fn into_account_id(evm_address: H160) -> T::AccountId {
- >::to_account_id_or_default(&evm_address)
- }
-}
-
-/// OnKilledAccout hooks implementation for removing storage mapping
-/// for killed accounts
-pub struct KillAccountMapping(PhantomData);
-impl OnKilledAccount for KillAccountMapping {
- fn on_killed_account(who: &T::AccountId) {
- // remove mapping created by `claim_account` or `get_or_create_evm_address`
- if let Some(evm_addr) = EvmToNative::::take(who) {
- NativeToEvm::::remove(evm_addr);
- EvmToNative::::remove(who);
- }
- }
-}
-
-/// A lookup implementation returning the `AccountId` from `MultiAddress::Address20` (EVM Address).
-impl StaticLookup for Pallet {
- type Source = MultiAddress;
- type Target = T::AccountId;
-
- fn lookup(a: Self::Source) -> Result {
- match a {
- MultiAddress::Address20(i) => Ok(
- >::to_account_id_or_default(
- &EvmAddress::from_slice(&i),
- ),
- ),
- _ => Err(LookupError),
- }
- }
-
- fn unlookup(a: Self::Target) -> Self::Source {
- MultiAddress::Id(a)
- }
-}
-
-/// EIP-712 compatible signature scheme for verifying ownership of EVM Address
-/// https://eips.ethereum.org/EIPS/eip-712
-///
-/// Raw Data = Domain Separator + Type Hash + keccak256(AccountId)
-pub struct EIP712Signature>(PhantomData<(T, ChainId)>);
-impl> SignatureHelper for EIP712Signature {
- type AccountId = T::AccountId;
- /// evm address type
- type Address = EvmAddress;
- /// A signature (a 512-bit value, plus 8 bits for recovery ID).
- type Signature = [u8; 65];
-
- fn build_signing_payload(who: &Self::AccountId) -> [u8; 32] {
- let domain_separator = Self::build_domain_separator();
- let args_hash = Self::build_args_hash(who);
-
- let mut payload = b"\x19\x01".to_vec();
- payload.extend_from_slice(&domain_separator);
- payload.extend_from_slice(&args_hash);
- keccak_256(&payload)
- }
-
- fn verify_signature(who: &Self::AccountId, sig: &Self::Signature) -> Option {
- let payload_hash = Self::build_signing_payload(who);
-
- sp_io::crypto::secp256k1_ecdsa_recover(sig, &payload_hash)
- .map(|pubkey| H160::from(H256::from_slice(&keccak_256(&pubkey))))
- .ok()
- }
-}
-
-impl> EIP712Signature {
- /// TODO: minor, use hardcoded bytes, configurable via generics
- fn build_domain_separator() -> [u8; 32] {
- let mut hash =
- keccak256!("EIP712Domain(string name,string version,uint256 chainId,bytes32 salt)")
- .to_vec();
- hash.extend_from_slice(&keccak256!("Astar EVM Claim")); // name
- hash.extend_from_slice(&keccak256!("1")); // version
- hash.extend_from_slice(&(<[u8; 32]>::from(U256::from(ChainId::get())))); // chain id
- hash.extend_from_slice(
- frame_system::Pallet::::block_hash(T::BlockNumber::zero()).as_ref(),
- ); // genesis block hash
- keccak_256(hash.as_slice())
- }
-
- fn build_args_hash(account: &T::AccountId) -> [u8; 32] {
- let mut args_hash = keccak256!("Claim(bytes substrateAddress)").to_vec();
- args_hash.extend_from_slice(&keccak_256(&account.encode()));
- keccak_256(args_hash.as_slice())
- }
-}
diff --git a/pallets/unified-accounts/src/lib.rs b/pallets/unified-accounts/src/lib.rs
index b4bc22e64b..058cc29a23 100644
--- a/pallets/unified-accounts/src/lib.rs
+++ b/pallets/unified-accounts/src/lib.rs
@@ -16,10 +16,11 @@
// You should have received a copy of the GNU General Public License
// along with Astar. If not, see .
-//! # Pallet Account
+//! # Pallet Unified Account
//!
//! A simple module for managing mappings (both ways) between different
-//! address schemes
+//! address schemes, inspired from Acala's evm-accounts pallet
+//! https://github.com/AcalaNetwork/Acala/tree/master/modules/evm-accounts
//!
//! - [`Config`]
//! - [`Call`]
@@ -56,51 +57,41 @@
#![cfg_attr(not(feature = "std"), no_std)]
-use astar_primitives::ethereum_checked::AccountMapping;
-use astar_primitives::evm::EvmAddress;
+use astar_primitives::{
+ ethereum_checked::AccountMapping,
+ evm::{EvmAddress, UnifiedAddressMapper},
+};
use frame_support::{
pallet_prelude::*,
traits::{
fungible::{Inspect, Mutate},
tokens::{Fortitude::*, Preservation::*},
- IsType,
+ IsType, OnKilledAccount,
},
};
use frame_system::{ensure_signed, pallet_prelude::*};
use pallet_evm::AddressMapping;
+use precompile_utils::keccak256;
+use sp_core::{H160, H256, U256};
+use sp_io::hashing::keccak_256;
+use sp_runtime::{
+ traits::{LookupError, StaticLookup, Zero},
+ MultiAddress,
+};
use sp_std::marker::PhantomData;
pub use pallet::*;
+pub mod weights;
+pub use weights::WeightInfo;
+
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
mod mock;
mod tests;
-mod impls;
-pub use impls::*;
-
type SignatureOf = <::SignatureHelper as SignatureHelper>::Signature;
-/// Mapping between Native and EVM Addresses
-pub trait UnifiedAddressMapper {
- /// Gets the account id associated with given evm address, if mapped else None.
- fn to_account_id(evm_address: &EvmAddress) -> Option;
- /// Gets the account id associated with given evm address.
- /// If no mapping exists, then return the default evm address.
- fn to_account_id_or_default(evm_address: &EvmAddress) -> AccountId;
- /// Gets the default account id which is associated with given evm address.
- fn to_default_account_id(evm_address: &EvmAddress) -> AccountId;
-
- /// Gets the evm address associated with given account id, if mapped else None.
- fn to_h160(account_id: &AccountId) -> Option;
- /// Gets the evm address associated with given account id.
- /// If no mapping exists, then return the default account id.
- fn to_h160_or_default(account_id: &AccountId) -> EvmAddress;
- /// Gets the default evm address which is associated with given account id.
- fn to_default_h160(account_id: &AccountId) -> EvmAddress;
-}
-
/// Signature verification scheme for proving address ownership
pub trait SignatureHelper {
type AccountId;
@@ -114,7 +105,7 @@ pub trait SignatureHelper {
fn verify_signature(who: &Self::AccountId, sig: &Self::Signature) -> Option;
}
-#[frame_support::pallet(dev_mode)]
+#[frame_support::pallet]
pub mod pallet {
use super::*;
@@ -135,8 +126,8 @@ pub mod pallet {
/// Note: the signature type defined by this will be used as parameter in pallet's extrinsic
type SignatureHelper: SignatureHelper;
- // /// Weight information for the extrinsics in this module
- // type WeightInfo: WeightInfo;
+ /// Weight information for the extrinsics in this module
+ type WeightInfo: WeightInfo;
}
#[pallet::error]
@@ -144,7 +135,7 @@ pub mod pallet {
/// AccountId or EvmAddress already mapped
AlreadyMapped,
/// The signature is malformed
- BadSignature,
+ UnexpectedSignatureFormat,
/// The signature verification failed due to mismatch evm address
InvalidSignature,
}
@@ -180,7 +171,7 @@ pub mod pallet {
/// - `evm_address`: The evm address to bind to the caller's account
/// - `signature`: A signature generated by the address to prove ownership
#[pallet::call_index(0)]
- #[pallet::weight(0)]
+ #[pallet::weight(T::WeightInfo::claim_evm_address())]
pub fn claim_evm_address(
origin: OriginFor,
evm_address: EvmAddress,
@@ -188,18 +179,46 @@ pub mod pallet {
) -> DispatchResult {
let who = ensure_signed(origin)?;
// make sure no prior mapping exists
- Self::enure_no_mapping(&who, &Some(evm_address))?;
- // claim the evm address
- Self::do_claim_evm_address(who, evm_address, signature)
+ ensure!(
+ !EvmToNative::::contains_key(&who),
+ Error::::AlreadyMapped
+ );
+ ensure!(
+ !NativeToEvm::::contains_key(evm_address),
+ Error::::AlreadyMapped
+ );
+
+ // recover evm address from signature
+ let address = T::SignatureHelper::verify_signature(&who, &signature)
+ .ok_or(Error::::UnexpectedSignatureFormat)?;
+
+ ensure!(evm_address == address, Error::::InvalidSignature);
+
+ // Check if the default account id already exists for this evm address
+ let default_account_id = T::DefaultAddressMapping::into_account_id(evm_address.clone());
+ if frame_system::Pallet::::account_exists(&default_account_id) {
+ // Transfer all the free balance from old account id to the newly
+ // since this `default_account_id` will no longer be connected to evm address
+ // and users cannot access it.
+ T::Currency::transfer(
+ &default_account_id,
+ &who,
+ T::Currency::reducible_balance(&default_account_id, Expendable, Polite),
+ Expendable,
+ )?;
+ }
+
+ // create double mappings for the pair
+ Self::add_mappings(who, evm_address);
+ Ok(())
}
/// Claim default evm address for given account id
/// Ensure no prior mapping exists for the account
#[pallet::call_index(1)]
+ #[pallet::weight(T::WeightInfo::claim_default_evm_address())]
pub fn claim_default_evm_address(origin: OriginFor) -> DispatchResult {
let who = ensure_signed(origin)?;
- // make sure no prior mapping exists
- Self::enure_no_mapping(&who, &None)?;
// claim default evm address
let _ = Self::do_claim_default_evm_address(who)?;
Ok(())
@@ -208,27 +227,6 @@ pub mod pallet {
}
impl Pallet {
- /// Ensure no mappings exists for given pair of account/evm_address
- fn enure_no_mapping(
- account_id: &T::AccountId,
- evm_address: &Option,
- ) -> DispatchResult {
- // ensure account_id and evm address has not been mapped
- ensure!(
- !EvmToNative::::contains_key(&account_id),
- Error::::AlreadyMapped
- );
- // This is not required since checking one mapping is sufficent
- // but this is just for sanity check
- if let Some(addr) = evm_address {
- ensure!(
- !NativeToEvm::::contains_key(addr),
- Error::::AlreadyMapped
- );
- }
- Ok(())
- }
-
/// Add the given pair to create double mappings
fn add_mappings(account_id: T::AccountId, evm_address: EvmAddress) {
NativeToEvm::::insert(&evm_address, &account_id);
@@ -240,42 +238,12 @@ impl Pallet {
});
}
- /// Claim the given evm address by providing claim signature
- fn do_claim_evm_address(
- account_id: T::AccountId,
- evm_address: EvmAddress,
- signature: SignatureOf,
- ) -> DispatchResult {
- // recover evm address from signature
- let address = T::SignatureHelper::verify_signature(&account_id, &signature)
- .ok_or(Error::::BadSignature)?;
- log::trace!(
- target: "account::do_claim_address",
- "evm_address: {:#?}, recovered: {:#?}", evm_address, address
- );
- ensure!(evm_address == address, Error::::InvalidSignature);
-
- // Check if the default account id already exists for this evm address
- let default_account_id = T::DefaultAddressMapping::into_account_id(evm_address.clone());
- if frame_system::Pallet::::account_exists(&default_account_id) {
- // Transfer all the free balance from old account id to the newly
- // since this `default_account_id` will no longer be connected to evm address
- // and users cannot access it.
- T::Currency::transfer(
- &default_account_id,
- &account_id,
- T::Currency::reducible_balance(&default_account_id, Expendable, Polite),
- Expendable,
- )?;
- }
-
- // create double mappings for the pair
- Self::add_mappings(account_id, evm_address);
- Ok(())
- }
-
/// Claim the default evm address
fn do_claim_default_evm_address(account_id: T::AccountId) -> Result {
+ ensure!(
+ !EvmToNative::::contains_key(&account_id),
+ Error::::AlreadyMapped
+ );
// get the default evm address
let evm_address = T::DefaultAccountMapping::into_h160(account_id.clone());
// create double mappings for the pair with default evm address
@@ -286,6 +254,7 @@ impl Pallet {
#[cfg(any(feature = "std", feature = "runtime-benchmarks"))]
impl Pallet {
+ /// Sign the given prehash with provided eth private key
pub fn eth_sign_prehash(prehash: &[u8; 32], secret: &libsecp256k1::SecretKey) -> [u8; 65] {
let (sig, recovery_id) = libsecp256k1::sign(&libsecp256k1::Message::parse(prehash), secret);
let mut r = [0u8; 65];
@@ -294,14 +263,146 @@ impl Pallet {
r
}
+ /// Get the eth address for given eth private key
pub fn eth_address(secret: &libsecp256k1::SecretKey) -> EvmAddress {
EvmAddress::from_slice(
- &sp_io::hashing::keccak_256(&Self::eth_public(secret).serialize()[1..65])[12..],
+ &sp_io::hashing::keccak_256(
+ &libsecp256k1::PublicKey::from_secret_key(secret).serialize()[1..65],
+ )[12..],
)
}
+}
+
+/// UnifiedAddressMapper implementation using pallet's mapping
+/// and default address scheme from pallet's config
+impl UnifiedAddressMapper for Pallet {
+ fn to_account_id(evm_address: &EvmAddress) -> Option {
+ NativeToEvm::::get(evm_address)
+ }
+
+ fn to_account_id_or_default(evm_address: &EvmAddress) -> T::AccountId {
+ NativeToEvm::::get(evm_address).unwrap_or_else(|| {
+ // fallback to default account_id
+ T::DefaultAddressMapping::into_account_id(evm_address.clone())
+ })
+ }
+
+ fn to_default_account_id(evm_address: &EvmAddress) -> T::AccountId {
+ T::DefaultAddressMapping::into_account_id(evm_address.clone())
+ }
+
+ fn to_h160(account_id: &T::AccountId) -> Option {
+ EvmToNative::::get(account_id)
+ }
+
+ fn to_h160_or_default(account_id: &T::AccountId) -> EvmAddress {
+ EvmToNative::::get(account_id).unwrap_or_else(|| {
+ // fallback to default account_id
+ T::DefaultAccountMapping::into_h160(account_id.clone())
+ })
+ }
+
+ fn to_default_h160(account_id: &T::AccountId) -> EvmAddress {
+ T::DefaultAccountMapping::into_h160(account_id.clone())
+ }
+}
+
+/// AccountMapping wrapper implementation
+impl AccountMapping for Pallet {
+ fn into_h160(account: T::AccountId) -> H160 {
+ >::to_h160_or_default(&account)
+ }
+}
+
+/// AddressMapping wrapper implementation
+impl AddressMapping for Pallet {
+ fn into_account_id(evm_address: H160) -> T::AccountId {
+ >::to_account_id_or_default(&evm_address)
+ }
+}
+
+/// OnKilledAccout hooks implementation for removing storage mapping
+/// for killed accounts
+pub struct KillAccountMapping(PhantomData);
+impl OnKilledAccount for KillAccountMapping {
+ fn on_killed_account(who: &T::AccountId) {
+ // remove mapping created by `claim_account` or `get_or_create_evm_address`
+ if let Some(evm_addr) = EvmToNative::::take(who) {
+ NativeToEvm::::remove(evm_addr);
+ EvmToNative::::remove(who);
+ }
+ }
+}
+
+/// A lookup implementation returning the `AccountId` from `MultiAddress::Address20` (EVM Address).
+impl StaticLookup for Pallet {
+ type Source = MultiAddress;
+ type Target = T::AccountId;
+
+ fn lookup(a: Self::Source) -> Result {
+ match a {
+ MultiAddress::Address20(i) => Ok(
+ >::to_account_id_or_default(
+ &EvmAddress::from_slice(&i),
+ ),
+ ),
+ _ => Err(LookupError),
+ }
+ }
+
+ fn unlookup(a: Self::Target) -> Self::Source {
+ MultiAddress::Id(a)
+ }
+}
+
+/// EIP-712 compatible signature scheme for verifying ownership of EVM Address
+/// https://eips.ethereum.org/EIPS/eip-712
+///
+/// Raw Data = Domain Separator + Type Hash + keccak256(AccountId)
+pub struct EIP712Signature>(PhantomData<(T, ChainId)>);
+impl> SignatureHelper for EIP712Signature {
+ type AccountId = T::AccountId;
+ /// evm address type
+ type Address = EvmAddress;
+ /// A signature (a 512-bit value, plus 8 bits for recovery ID).
+ type Signature = [u8; 65];
+
+ fn build_signing_payload(who: &Self::AccountId) -> [u8; 32] {
+ let domain_separator = Self::build_domain_separator();
+ let args_hash = Self::build_args_hash(who);
+
+ let mut payload = b"\x19\x01".to_vec();
+ payload.extend_from_slice(&domain_separator);
+ payload.extend_from_slice(&args_hash);
+ keccak_256(&payload)
+ }
+
+ fn verify_signature(who: &Self::AccountId, sig: &Self::Signature) -> Option {
+ let payload_hash = Self::build_signing_payload(who);
+
+ sp_io::crypto::secp256k1_ecdsa_recover(sig, &payload_hash)
+ .map(|pubkey| H160::from(H256::from_slice(&keccak_256(&pubkey))))
+ .ok()
+ }
+}
+
+impl> EIP712Signature {
+ fn build_domain_separator() -> [u8; 32] {
+ let mut domain =
+ keccak256!("EIP712Domain(string name,string version,uint256 chainId,bytes32 salt)")
+ .to_vec();
+ domain.extend_from_slice(&keccak256!("Astar EVM Claim")); // name
+ domain.extend_from_slice(&keccak256!("1")); // version
+ domain.extend_from_slice(&(<[u8; 32]>::from(U256::from(ChainId::get())))); // chain id
+ domain.extend_from_slice(
+ frame_system::Pallet::::block_hash(T::BlockNumber::zero()).as_ref(),
+ ); // genesis block hash
+ keccak_256(domain.as_slice())
+ }
- // Returns an Ethereum public key derived from an Ethereum secret key.
- pub fn eth_public(secret: &libsecp256k1::SecretKey) -> libsecp256k1::PublicKey {
- libsecp256k1::PublicKey::from_secret_key(secret)
+ fn build_args_hash(account: &T::AccountId) -> [u8; 32] {
+ let mut args_hash = keccak256!("Claim(bytes substrateAddress)").to_vec();
+ args_hash.extend_from_slice(&keccak_256(&account.encode()));
+ keccak_256(args_hash.as_slice())
}
}
diff --git a/pallets/unified-accounts/src/mock.rs b/pallets/unified-accounts/src/mock.rs
index 4b3d1f5442..524882caf6 100644
--- a/pallets/unified-accounts/src/mock.rs
+++ b/pallets/unified-accounts/src/mock.rs
@@ -20,6 +20,7 @@
use super::*;
use crate as pallet_unified_accounts;
+use astar_primitives::ethereum_checked::HashedAccountMapping;
use frame_support::{
construct_runtime, parameter_types,
sp_io::TestExternalities,
@@ -157,6 +158,7 @@ impl pallet_unified_accounts::Config for TestRuntime {
type DefaultAddressMapping = HashedAddressMapping;
type DefaultAccountMapping = HashedAccountMapping;
type SignatureHelper = EIP712Signature;
+ type WeightInfo = ();
}
pub(crate) type AccountId = AccountId32;
diff --git a/pallets/unified-accounts/src/tests.rs b/pallets/unified-accounts/src/tests.rs
index d6e3fd6203..dd4cac821b 100644
--- a/pallets/unified-accounts/src/tests.rs
+++ b/pallets/unified-accounts/src/tests.rs
@@ -59,7 +59,7 @@ fn get_evm_signature(who: &AccountId32, secret: &libsecp256k1::SecretKey) -> [u8
fn connect_accounts(who: &AccountId32, secret: &libsecp256k1::SecretKey) {
assert_ok!(UnifiedAccounts::claim_evm_address(
RuntimeOrigin::signed(who.clone()),
- UnifiedAccounts::eth_address(&alice_secret()),
+ UnifiedAccounts::eth_address(secret),
get_evm_signature(who, secret)
));
}
diff --git a/primitives/src/ethereum_checked.rs b/primitives/src/ethereum_checked.rs
index 29af13c229..51eda15a0b 100644
--- a/primitives/src/ethereum_checked.rs
+++ b/primitives/src/ethereum_checked.rs
@@ -30,8 +30,11 @@ use frame_support::{
traits::ConstU32,
BoundedVec,
};
+use sp_core::Hasher;
use sp_std::{prelude::*, result::Result};
+use crate::AccountId;
+
/// Max Ethereum tx input size: 65_536 bytes
pub const MAX_ETHEREUM_TX_INPUT_SIZE: u32 = 2u32.pow(16);
@@ -101,3 +104,12 @@ pub trait CheckedEthereumTransact {
pub trait AccountMapping {
fn into_h160(account: AccountId) -> H160;
}
+
+/// Hashed derive mapping for converting account id to evm address
+pub struct HashedAccountMapping(sp_std::marker::PhantomData);
+impl> AccountMapping for HashedAccountMapping {
+ fn into_h160(account: AccountId) -> H160 {
+ let payload = (b"evm:", account);
+ H160::from_slice(&payload.using_encoded(H::hash)[0..20])
+ }
+}
diff --git a/primitives/src/evm.rs b/primitives/src/evm.rs
index ce6c483ac5..766f7bf7a8 100644
--- a/primitives/src/evm.rs
+++ b/primitives/src/evm.rs
@@ -57,3 +57,22 @@ where
Ok(())
}
}
+
+/// Mapping between Native and EVM Addresses
+pub trait UnifiedAddressMapper {
+ /// Gets the account id associated with given evm address, if mapped else None.
+ fn to_account_id(evm_address: &EvmAddress) -> Option;
+ /// Gets the account id associated with given evm address.
+ /// If no mapping exists, then return the default evm address.
+ fn to_account_id_or_default(evm_address: &EvmAddress) -> AccountId;
+ /// Gets the default account id which is associated with given evm address.
+ fn to_default_account_id(evm_address: &EvmAddress) -> AccountId;
+
+ /// Gets the evm address associated with given account id, if mapped else None.
+ fn to_h160(account_id: &AccountId) -> Option;
+ /// Gets the evm address associated with given account id.
+ /// If no mapping exists, then return the default account id.
+ fn to_h160_or_default(account_id: &AccountId) -> EvmAddress;
+ /// Gets the default evm address which is associated with given account id.
+ fn to_default_h160(account_id: &AccountId) -> EvmAddress;
+}
diff --git a/runtime/local/Cargo.toml b/runtime/local/Cargo.toml
index 8d59813740..664c90eed4 100644
--- a/runtime/local/Cargo.toml
+++ b/runtime/local/Cargo.toml
@@ -66,7 +66,6 @@ pallet-transaction-payment-rpc-runtime-api = { workspace = true }
# Astar pallets
astar-primitives = { workspace = true }
-pallet-unified-accounts = { workspace = true }
pallet-block-reward = { workspace = true }
pallet-chain-extension-dapps-staking = { workspace = true }
pallet-chain-extension-xvm = { workspace = true }
@@ -77,6 +76,7 @@ pallet-evm-precompile-dapps-staking = { workspace = true }
pallet-evm-precompile-sr25519 = { workspace = true }
pallet-evm-precompile-substrate-ecdsa = { workspace = true }
pallet-evm-precompile-xvm = { workspace = true }
+pallet-unified-accounts = { workspace = true }
pallet-xvm = { workspace = true }
# Moonbeam tracing
diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs
index cbcac0a080..2b85a26089 100644
--- a/runtime/local/src/lib.rs
+++ b/runtime/local/src/lib.rs
@@ -61,8 +61,8 @@ use sp_runtime::{
use sp_std::prelude::*;
pub use astar_primitives::{
- evm::EvmRevertCodeHandler, AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header,
- Index, Signature,
+ ethereum_checked::HashedAccountMapping, evm::EvmRevertCodeHandler, AccountId, Address, AssetId,
+ Balance, BlockNumber, Hash, Header, Index, Signature,
};
#[cfg(feature = "std")]
@@ -450,8 +450,9 @@ impl pallet_unified_accounts::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type DefaultAddressMapping = pallet_evm::HashedAddressMapping;
- type DefaultAccountMapping = pallet_unified_accounts::HashedAccountMapping;
+ type DefaultAccountMapping = HashedAccountMapping;
type SignatureHelper = pallet_unified_accounts::EIP712Signature;
+ type WeightInfo = pallet_unified_accounts::weights::SubstrateWeight;
}
parameter_types! {
diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml
index 60a82668f4..a8b76b1aef 100644
--- a/runtime/shibuya/Cargo.toml
+++ b/runtime/shibuya/Cargo.toml
@@ -96,7 +96,6 @@ orml-xtokens = { workspace = true }
# Astar pallets
astar-primitives = { workspace = true }
-pallet-unified-accounts = { workspace = true }
pallet-block-reward = { workspace = true }
pallet-chain-extension-dapps-staking = { workspace = true }
pallet-chain-extension-xvm = { workspace = true }
@@ -111,6 +110,7 @@ pallet-evm-precompile-sr25519 = { workspace = true }
pallet-evm-precompile-substrate-ecdsa = { workspace = true }
pallet-evm-precompile-xcm = { workspace = true }
pallet-evm-precompile-xvm = { workspace = true }
+pallet-unified-accounts = { workspace = true }
pallet-xc-asset-config = { workspace = true }
pallet-xcm = { workspace = true }
pallet-xvm = { workspace = true }
diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs
index 7a1a2003e0..b2bffc89ff 100644
--- a/runtime/shibuya/src/lib.rs
+++ b/runtime/shibuya/src/lib.rs
@@ -69,9 +69,10 @@ use sp_runtime::{
use sp_std::prelude::*;
pub use astar_primitives::{
- ethereum_checked::CheckedEthereumTransact, evm::EvmRevertCodeHandler,
- xcm::AssetLocationIdConverter, AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header,
- Index, Signature,
+ ethereum_checked::{CheckedEthereumTransact, HashedAccountMapping},
+ evm::EvmRevertCodeHandler,
+ xcm::AssetLocationIdConverter,
+ AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header, Index, Signature,
};
use pallet_evm_precompile_assets_erc20::AddressToAssetId;
@@ -1227,8 +1228,9 @@ impl pallet_unified_accounts::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type DefaultAddressMapping = pallet_evm::HashedAddressMapping;
- type DefaultAccountMapping = pallet_unified_accounts::HashedAccountMapping;
+ type DefaultAccountMapping = HashedAccountMapping;
type SignatureHelper = pallet_unified_accounts::EIP712Signature;
+ type WeightInfo = pallet_unified_accounts::weights::SubstrateWeight;
}
construct_runtime!(