diff --git a/Cargo.lock b/Cargo.lock index a2e6ef26d0..f2be80a72a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4925,7 +4925,6 @@ dependencies = [ "frame-support", "frame-system", "hex", - "pallet-account", "pallet-assets", "pallet-balances", "pallet-contracts", @@ -4935,6 +4934,7 @@ dependencies = [ "pallet-evm", "pallet-evm-precompile-assets-erc20", "pallet-proxy", + "pallet-unified-accounts", "pallet-utility", "parity-scale-codec", "shibuya-runtime", @@ -5981,7 +5981,6 @@ dependencies = [ "moonbeam-evm-tracer", "moonbeam-rpc-primitives-debug", "moonbeam-rpc-primitives-txpool", - "pallet-account", "pallet-assets", "pallet-aura", "pallet-balances", @@ -6022,6 +6021,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", + "pallet-unified-accounts", "pallet-utility", "pallet-vesting", "pallet-xvm", @@ -7202,31 +7202,6 @@ dependencies = [ "libm 0.1.4", ] -[[package]] -name = "pallet-account" -version = "0.1.0" -dependencies = [ - "astar-primitives", - "ethers", - "frame-benchmarking", - "frame-support", - "frame-system", - "hex", - "libsecp256k1", - "log", - "pallet-balances", - "pallet-ethereum", - "pallet-evm", - "pallet-timestamp", - "parity-scale-codec", - "precompile-utils", - "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-assets" version = "4.0.0-dev" @@ -8708,6 +8683,31 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-unified-accounts" +version = "0.1.0" +dependencies = [ + "astar-primitives", + "ethers", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "libsecp256k1", + "log", + "pallet-balances", + "pallet-ethereum", + "pallet-evm", + "pallet-timestamp", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-utility" version = "4.0.0-dev" @@ -13052,7 +13052,6 @@ dependencies = [ "moonbeam-rpc-primitives-txpool", "orml-xcm-support", "orml-xtokens", - "pallet-account", "pallet-assets", "pallet-aura", "pallet-authorship", @@ -13099,6 +13098,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", + "pallet-unified-accounts", "pallet-utility", "pallet-vesting", "pallet-xc-asset-config", diff --git a/Cargo.toml b/Cargo.toml index 8dd39e5b6a..b13062e82f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -278,7 +278,7 @@ pallet-xc-asset-config = { path = "./pallets/xc-asset-config", default-features pallet-xvm = { path = "./pallets/xvm", default-features = false } pallet-xcm = { path = "./pallets/pallet-xcm", default-features = false } pallet-ethereum-checked = { path = "./pallets/ethereum-checked", default-features = false } -pallet-account = { path = "./pallets/account", default-features = false } +pallet-unified-accounts = { path = "./pallets/account", default-features = false } astar-primitives = { path = "./primitives", default-features = false } diff --git a/pallets/account/Cargo.toml b/pallets/account/Cargo.toml index b89996c4f0..c74c5ac954 100644 --- a/pallets/account/Cargo.toml +++ b/pallets/account/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pallet-account" +name = "pallet-unified-accounts" version = "0.1.0" description = "Pallet for mapping VM accounts with native accounts" authors.workspace = true diff --git a/pallets/account/src/benchmarking.rs b/pallets/account/src/benchmarking.rs index e75a75904e..fed54a699e 100644 --- a/pallets/account/src/benchmarking.rs +++ b/pallets/account/src/benchmarking.rs @@ -28,18 +28,18 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { } #[benchmarks( - where <::ClaimSignature as ClaimSignature>::Signature: IsType<[u8;65]> + where <::SignatureHelper as SignatureHelper>::Signature: IsType<[u8;65]> )] mod benchmarks { use super::*; #[benchmark] - fn claim_evm_account() { + fn claim_evm_address() { let caller: T::AccountId = whitelisted_caller(); let eth_secret_key = libsecp256k1::SecretKey::parse(&[0xff; 32]).unwrap(); let evm_address = Pallet::::eth_address(ð_secret_key); let signature = Pallet::::eth_sign_prehash( - &T::ClaimSignature::build_signing_payload(&caller), + &T::SignatureHelper::build_signing_payload(&caller), ð_secret_key, ) .into(); @@ -59,7 +59,7 @@ mod benchmarks { } #[benchmark] - fn claim_default_evm_account() { + fn claim_default_evm_address() { let caller: T::AccountId = whitelisted_caller(); let caller_clone = caller.clone(); let evm_address = T::DefaultAccountMapping::into_h160(caller.clone()); diff --git a/pallets/account/src/impls.rs b/pallets/account/src/impls.rs index c9099451e5..c49fcb652d 100644 --- a/pallets/account/src/impls.rs +++ b/pallets/account/src/impls.rs @@ -31,43 +31,43 @@ use sp_std::marker::PhantomData; use crate::*; -/// AddressManager implementation -impl AddressManager for Pallet { - fn to_account_id(address: &EvmAddress) -> Option { - NativeAccounts::::get(address) +/// UnifiedAddressMapper implementation +impl UnifiedAddressMapper for Pallet { + fn to_account_id(evm_address: &EvmAddress) -> Option { + NativeToEvm::::get(evm_address) } - fn to_account_id_or_default(address: &EvmAddress) -> T::AccountId { - NativeAccounts::::get(address).unwrap_or_else(|| { + 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(address.clone()) + T::DefaultAddressMapping::into_account_id(evm_address.clone()) }) } - fn to_default_account_id(address: &EvmAddress) -> T::AccountId { - T::DefaultAddressMapping::into_account_id(address.clone()) + fn to_default_account_id(evm_address: &EvmAddress) -> T::AccountId { + T::DefaultAddressMapping::into_account_id(evm_address.clone()) } - fn to_address(account_id: &T::AccountId) -> Option { - EvmAccounts::::get(account_id) + fn to_h160(account_id: &T::AccountId) -> Option { + EvmToNative::::get(account_id) } - fn to_address_or_default(account_id: &T::AccountId) -> EvmAddress { - EvmAccounts::::get(account_id).unwrap_or_else(|| { + 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_address(account_id: &T::AccountId) -> EvmAddress { + fn to_default_h160(account_id: &T::AccountId) -> EvmAddress { T::DefaultAccountMapping::into_h160(account_id.clone()) } } -/// AccountMapping wrapper implementation over AddressManager +/// AccountMapping wrapper implementation impl AccountMapping for Pallet { fn into_h160(account: T::AccountId) -> H160 { - >::to_address_or_default(&account) + >::to_h160_or_default(&account) } } @@ -80,10 +80,10 @@ impl> AccountMapping for HashedAccountMapping AddressMapping for Pallet { - fn into_account_id(address: H160) -> T::AccountId { - >::to_account_id_or_default(&address) + fn into_account_id(evm_address: H160) -> T::AccountId { + >::to_account_id_or_default(&evm_address) } } @@ -93,9 +93,9 @@ 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) = EvmAccounts::::get(who) { - NativeAccounts::::remove(evm_addr); - EvmAccounts::::remove(who); + if let Some(evm_addr) = EvmToNative::::take(who) { + NativeToEvm::::remove(evm_addr); + EvmToNative::::remove(who); } } } @@ -108,7 +108,7 @@ impl StaticLookup for Pallet { fn lookup(a: Self::Source) -> Result { match a { MultiAddress::Address20(i) => Ok( - >::to_account_id_or_default( + >::to_account_id_or_default( &EvmAddress::from_slice(&i), ), ), @@ -122,12 +122,13 @@ impl StaticLookup for Pallet { } /// 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> ClaimSignature for EIP712Signature { +impl> SignatureHelper for EIP712Signature { type AccountId = T::AccountId; - /// EVM address type + /// evm address type type Address = EvmAddress; /// A signature (a 512-bit value, plus 8 bits for recovery ID). type Signature = [u8; 65]; diff --git a/pallets/account/src/lib.rs b/pallets/account/src/lib.rs index 3109656fd3..b4bc22e64b 100644 --- a/pallets/account/src/lib.rs +++ b/pallets/account/src/lib.rs @@ -26,33 +26,33 @@ //! //! ## Overview //! -//! The Accounts module provide functionality for native account holders to -//! connect their EVM accounts to have a unified experence across the different VMs. -//! - Connect EVM address you control +//! The Unified Accounts module provide functionality for native account holders to +//! connect their evm address to have a unified experence across the different VMs. +//! - Connect evm address you control //! - Connect default evm address //! //! ## Interface //! -//! * `claim_evm_account`: Creates the double mappings for the provided evm address with caller +//! * `claim_evm_address`: Creates the double mappings for the provided evm address with caller //! account id given that no prior mapping exists for both and signature provided is valid. -//! * `claim_default_evm_account`: Creates the double mapping with default evm address given that +//! * `claim_default_evm_address`: Creates the double mapping with default evm address given that //! no prior mapping exists. //! //! ## Traits //! -//! * `AddressManager`: Interface to access pallet's mappings with defaults -//! * `ClaimSignature`: Signature verification scheme for proving address ownership +//! * `UnifiedAddressMapper`: Interface to access pallet's mappings with defaults +//! * `SignatureHelper`: Signature verification scheme for proving address ownership //! //! ## Implementations //! //! * [`StaticLookup`](sp_runtime::traits::StaticLookup): Lookup implementations for accepting H160 -//! * [`AddressMapping`](pallet_evm::AddressMapping): Wrapper over `AddressManager` for evm address mapping +//! * [`AddressMapping`](pallet_evm::AddressMapping): Wrapper over `UnifiedAddressMapper` for evm address mapping //! to account id. -//! * [`AccountMapping`](astar_primitives::ethereum_checked::AccountMapping): Wrapper over `AddressManager` +//! * [`AccountMapping`](astar_primitives::ethereum_checked::AccountMapping): Wrapper over `UnifiedAddressMapper` //! for account id mappings to h160. //! * `KillAccountMapping`: [`OnKilledAccount`](frame_support::traits::OnKilledAccount) implementation to remove //! the mappings from storage after account is reaped. -//! * `EIP712Signature`: EIP712 signature implementation for [`ClaimSignature`](crate::ClaimSignature) +//! * `EIP712Signature`: EIP712 signature implementation for [`SignatureHelper`](crate::SignatureHelper) #![cfg_attr(not(feature = "std"), no_std)] @@ -80,29 +80,29 @@ mod tests; mod impls; pub use impls::*; -type SignatureOf = <::ClaimSignature as ClaimSignature>::Signature; - -/// Mapping between Native(AccountId) and EVM Address(H160) -pub trait AddressManager { - /// Gets the account id associated with given address, if mapped else None. - fn to_account_id(address: &Address) -> Option; - /// Gets the account id associated with given address. - /// If no mapping exists, then return the default address. - fn to_account_id_or_default(address: &Address) -> AccountId; - /// Gets the default account which is associated with given address. - fn to_default_account_id(address: &Address) -> AccountId; - - /// Gets the address associated with given account id, if mapped else None. - fn to_address(account_id: &AccountId) -> Option
; - /// Gets the address associated with given account id. +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_address_or_default(account_id: &AccountId) -> Address; - /// Gets the default address which is associated with given account id. - fn to_default_address(account_id: &AccountId) -> Address; + 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 ClaimSignature { +pub trait SignatureHelper { type AccountId; type Address; /// Signature type, ideally a 512-bit value for ECDSA signatures @@ -125,7 +125,7 @@ pub mod pallet { pub trait Config: frame_system::Config { /// The overarching event type type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The Currency for managing Evm account assets + /// The Currency for managing evm address assets type Currency: Mutate; /// Default evm address to account id conversion type DefaultAddressMapping: AddressMapping; @@ -133,7 +133,7 @@ pub mod pallet { type DefaultAccountMapping: AccountMapping; /// The Signature verification implementation to use for checking claims /// Note: the signature type defined by this will be used as parameter in pallet's extrinsic - type ClaimSignature: ClaimSignature; + type SignatureHelper: SignatureHelper; // /// Weight information for the extrinsics in this module // type WeightInfo: WeightInfo; @@ -141,20 +141,18 @@ pub mod pallet { #[pallet::error] pub enum Error { - /// AccountId has mapped - AccountIdHasMapped, - /// Eth address has mapped - EthAddressHasMapped, - /// Bad signature + /// AccountId or EvmAddress already mapped + AlreadyMapped, + /// The signature is malformed BadSignature, - /// Invalid signature + /// The signature verification failed due to mismatch evm address InvalidSignature, } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// EVM Account claimed. + /// Evm Address claimed. /// Double Mapping b/w native and evm address created AccountClaimed { account_id: T::AccountId, @@ -162,28 +160,28 @@ pub mod pallet { }, } - /// Native accounts for EVM address - /// NativeAccounts: EvmAddress => Option + /// Native accounts for evm address + /// NativeToEvm: EvmAddress => Option #[pallet::storage] - pub type NativeAccounts = - StorageMap<_, Twox64Concat, EvmAddress, T::AccountId, OptionQuery>; + pub type NativeToEvm = + StorageMap<_, Blake2_128Concat, EvmAddress, T::AccountId, OptionQuery>; - /// EVM Addresses for native accounts - /// EvmAccounts: AccountId => Option + /// evm addresses for native accounts + /// EvmToNative: AccountId => Option #[pallet::storage] - pub type EvmAccounts = - StorageMap<_, Twox64Concat, T::AccountId, EvmAddress, OptionQuery>; + pub type EvmToNative = + StorageMap<_, Blake2_128Concat, T::AccountId, EvmAddress, OptionQuery>; #[pallet::call] impl Pallet { - /// Claim account mapping between Substrate accounts and EVM accounts. + /// Claim account mapping between Substrate account and Evm address. /// Ensure no prior mapping exists for evm address. /// - /// - `evm_address`: The address to bind to the caller's account + /// - `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)] - pub fn claim_evm_account( + pub fn claim_evm_address( origin: OriginFor, evm_address: EvmAddress, signature: SignatureOf, @@ -191,62 +189,65 @@ pub mod pallet { let who = ensure_signed(origin)?; // make sure no prior mapping exists Self::enure_no_mapping(&who, &Some(evm_address))?; - // claim the address - Self::do_claim_address(who, evm_address, signature) + // claim the evm address + Self::do_claim_evm_address(who, evm_address, signature) } /// Claim default evm address for given account id /// Ensure no prior mapping exists for the account #[pallet::call_index(1)] - pub fn claim_default_evm_account(origin: OriginFor) -> DispatchResult { + 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 address - let _ = Self::do_claim_default_address(who)?; + // claim default evm address + let _ = Self::do_claim_default_evm_address(who)?; Ok(()) } } } impl Pallet { - /// Ensure no mappings exists for given pair of account/address - fn enure_no_mapping(account_id: &T::AccountId, address: &Option) -> DispatchResult { - // ensure account_id and address has not been mapped + /// 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!( - !EvmAccounts::::contains_key(&account_id), - Error::::AccountIdHasMapped + !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) = address { + if let Some(addr) = evm_address { ensure!( - !NativeAccounts::::contains_key(addr), - Error::::EthAddressHasMapped + !NativeToEvm::::contains_key(addr), + Error::::AlreadyMapped ); } Ok(()) } /// Add the given pair to create double mappings - fn add_mappings(account_id: T::AccountId, address: EvmAddress) { - NativeAccounts::::insert(&address, &account_id); - EvmAccounts::::insert(&account_id, &address); + fn add_mappings(account_id: T::AccountId, evm_address: EvmAddress) { + NativeToEvm::::insert(&evm_address, &account_id); + EvmToNative::::insert(&account_id, &evm_address); Self::deposit_event(Event::AccountClaimed { account_id, - evm_address: address, + evm_address, }); } /// Claim the given evm address by providing claim signature - fn do_claim_address( + fn do_claim_evm_address( account_id: T::AccountId, evm_address: EvmAddress, signature: SignatureOf, ) -> DispatchResult { // recover evm address from signature - let address = T::ClaimSignature::verify_signature(&account_id, &signature) + let address = T::SignatureHelper::verify_signature(&account_id, &signature) .ok_or(Error::::BadSignature)?; log::trace!( target: "account::do_claim_address", @@ -254,7 +255,7 @@ impl Pallet { ); ensure!(evm_address == address, Error::::InvalidSignature); - // Check if the default account id already exists for this eth address + // 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 @@ -274,17 +275,17 @@ impl Pallet { } /// Claim the default evm address - fn do_claim_default_address(account_id: T::AccountId) -> Result { + fn do_claim_default_evm_address(account_id: T::AccountId) -> Result { // get the default evm address - let address = T::DefaultAccountMapping::into_h160(account_id.clone()); + let evm_address = T::DefaultAccountMapping::into_h160(account_id.clone()); // create double mappings for the pair with default evm address - Self::add_mappings(account_id, address.clone()); - Ok(address) + Self::add_mappings(account_id, evm_address.clone()); + Ok(evm_address) } } +#[cfg(any(feature = "std", feature = "runtime-benchmarks"))] impl Pallet { - #[cfg(any(feature = "std", feature = "runtime-benchmarks"))] 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]; @@ -293,14 +294,12 @@ impl Pallet { r } - #[cfg(any(feature = "std", feature = "runtime-benchmarks"))] pub fn eth_address(secret: &libsecp256k1::SecretKey) -> EvmAddress { EvmAddress::from_slice( &sp_io::hashing::keccak_256(&Self::eth_public(secret).serialize()[1..65])[12..], ) } - #[cfg(any(feature = "std", feature = "runtime-benchmarks"))] // 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) diff --git a/pallets/account/src/mock.rs b/pallets/account/src/mock.rs index 4508c3cae9..4b3d1f5442 100644 --- a/pallets/account/src/mock.rs +++ b/pallets/account/src/mock.rs @@ -19,7 +19,7 @@ #![cfg(test)] use super::*; -use crate as pallet_account; +use crate as pallet_unified_accounts; use frame_support::{ construct_runtime, parameter_types, sp_io::TestExternalities, @@ -51,7 +51,7 @@ impl frame_system::Config for TestRuntime { type Hash = H256; type Hashing = BlakeTwo256; type AccountId = AccountId; - type Lookup = (AccountIdLookup, Accounts); + type Lookup = (AccountIdLookup, UnifiedAccounts); type Header = Header; type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; @@ -120,7 +120,7 @@ impl pallet_evm::Config for TestRuntime { type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type CallOrigin = pallet_evm::EnsureAddressRoot; type WithdrawOrigin = pallet_evm::EnsureAddressTruncated; - type AddressMapping = Accounts; + type AddressMapping = UnifiedAccounts; type Currency = Balances; type RuntimeEvent = RuntimeEvent; type Runner = pallet_evm::runner::stack::Runner; @@ -151,12 +151,12 @@ parameter_types! { pub TxWeightLimit: Weight = Weight::from_parts(u64::max_value(), 0); } -impl pallet_account::Config for TestRuntime { +impl pallet_unified_accounts::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type DefaultAddressMapping = HashedAddressMapping; type DefaultAccountMapping = HashedAccountMapping; - type ClaimSignature = EIP712Signature; + type SignatureHelper = EIP712Signature; } pub(crate) type AccountId = AccountId32; @@ -190,7 +190,7 @@ construct_runtime!( Balances: pallet_balances, Evm: pallet_evm, Ethereum: pallet_ethereum, - Accounts: pallet_account, + UnifiedAccounts: pallet_unified_accounts, } ); @@ -226,14 +226,4 @@ impl ExtBuilder { ext.execute_with(|| System::set_block_number(1)); ext } - - pub fn with_alice_mapping() -> TestExternalities { - let mut ext = Self::default().build(); - ext.execute_with(|| { - let alice_eth = Accounts::eth_address(&alice_secret()); - EvmAccounts::::set(ALICE, Some(alice_eth.clone())); - NativeAccounts::::set(alice_eth, Some(ALICE)); - }); - ext - } } diff --git a/pallets/account/src/tests.rs b/pallets/account/src/tests.rs index 3a303b8365..888afd2f3f 100644 --- a/pallets/account/src/tests.rs +++ b/pallets/account/src/tests.rs @@ -42,9 +42,10 @@ struct Claim { substrate_address: Bytes, } -fn claim_signature(who: &AccountId32, secret: &libsecp256k1::SecretKey) -> [u8; 65] { +/// Build the signature payload for given native account and eth private key +fn get_evm_signature(who: &AccountId32, secret: &libsecp256k1::SecretKey) -> [u8; 65] { // sign the payload - Accounts::eth_sign_prehash( + UnifiedAccounts::eth_sign_prehash( &Claim { substrate_address: who.encode().into(), } @@ -54,6 +55,15 @@ fn claim_signature(who: &AccountId32, secret: &libsecp256k1::SecretKey) -> [u8; ) } +/// Create the mappings for the accounts +fn connect_accounts(who: &AccountId32, secret: &libsecp256k1::SecretKey) { + assert_ok!(UnifiedAccounts::claim_evm_address( + RuntimeOrigin::signed(who.clone()), + UnifiedAccounts::eth_address(&alice_secret()), + get_evm_signature(who, secret) + )); +} + #[test] fn eip712_signature_verify_works() { ExtBuilder::default().build().execute_with(|| { @@ -70,9 +80,9 @@ fn eip712_signature_verify_works() { ); // sign the payload - let sig = Accounts::eth_sign_prehash(&claim_hash, &alice_secret()); + let sig = UnifiedAccounts::eth_sign_prehash(&claim_hash, &alice_secret()); assert_eq!( - Some(Accounts::eth_address(&alice_secret())), + Some(UnifiedAccounts::eth_address(&alice_secret())), EIP712Signature::::verify_signature(&ALICE, &sig), "signature verification should work" ); @@ -81,21 +91,24 @@ fn eip712_signature_verify_works() { #[test] fn static_lookup_works() { - ExtBuilder::with_alice_mapping().execute_with(|| { - let alice_eth = Accounts::eth_address(&alice_secret()); - let bob_eth = Accounts::eth_address(&bob_secret()); + ExtBuilder::default().build().execute_with(|| { + let alice_eth = UnifiedAccounts::eth_address(&alice_secret()); + let bob_eth = UnifiedAccounts::eth_address(&bob_secret()); let bob_default_account_id = - >::to_default_account_id(&bob_eth); + >::to_default_account_id(&bob_eth); + + // create mappings for alice + connect_accounts(&ALICE, &alice_secret()); // mapping should work if available assert_eq!( - ::lookup(MultiAddress::Address20(alice_eth.into())).unwrap(), + ::lookup(MultiAddress::Address20(alice_eth.into())).unwrap(), ALICE ); // should use default if not mapping assert_eq!( - ::lookup(MultiAddress::Address20(bob_eth.into())).unwrap(), + ::lookup(MultiAddress::Address20(bob_eth.into())).unwrap(), bob_default_account_id ); }); @@ -103,8 +116,11 @@ fn static_lookup_works() { #[test] fn on_killed_account_hook() { - ExtBuilder::with_alice_mapping().execute_with(|| { - let alice_eth = Accounts::eth_address(&alice_secret()); + ExtBuilder::default().build().execute_with(|| { + let alice_eth = UnifiedAccounts::eth_address(&alice_secret()); + + // create the mappings + connect_accounts(&ALICE, &alice_secret()); // kill alice by transfering everything to bob Balances::set_balance(&ALICE, 0); @@ -116,18 +132,18 @@ fn on_killed_account_hook() { ))); // make sure mapping is removed - assert_eq!(EvmAccounts::::get(ALICE), None); - assert_eq!(NativeAccounts::::get(alice_eth), None); + assert_eq!(EvmToNative::::get(ALICE), None); + assert_eq!(NativeToEvm::::get(alice_eth), None); }); } #[test] fn account_claim_should_work() { ExtBuilder::default().build().execute_with(|| { - let alice_eth = Accounts::eth_address(&alice_secret()); + let alice_eth = UnifiedAccounts::eth_address(&alice_secret()); // default ss58 account associated with eth address let alice_eth_old_account = ::DefaultAddressMapping::into_account_id(alice_eth.clone()); - let signature = claim_signature(&ALICE, &alice_secret()); + let signature = get_evm_signature(&ALICE, &alice_secret()); // transfer some funds to alice_eth (H160) assert_ok!(Balances::transfer_allow_death( @@ -137,7 +153,7 @@ fn account_claim_should_work() { )); // claim the account - assert_ok!(Accounts::claim_evm_account( + assert_ok!(UnifiedAccounts::claim_evm_address( RuntimeOrigin::signed(ALICE), alice_eth, signature @@ -152,14 +168,16 @@ fn account_claim_should_work() { // check for claim account event System::assert_last_event( - RuntimeEvent::Accounts(crate::Event::AccountClaimed { account_id: ALICE.clone(), evm_address: alice_eth.clone()}) + RuntimeEvent::UnifiedAccounts(crate::Event::AccountClaimed { account_id: ALICE.clone(), evm_address: alice_eth.clone()}) ); // make sure mappings are in place - assert!( - NativeAccounts::::contains_key(alice_eth) - && EvmAccounts::::contains_key(ALICE) + assert_eq!( + NativeToEvm::::get(alice_eth).unwrap(), ALICE ); + assert_eq!( + EvmToNative::::get(ALICE).unwrap(), alice_eth + ) }); } @@ -168,44 +186,44 @@ fn account_claim_should_not_work() { ExtBuilder::default().build().execute_with(|| { // invald signature assert_noop!( - Accounts::claim_evm_account( + UnifiedAccounts::claim_evm_address( RuntimeOrigin::signed(ALICE), - Accounts::eth_address(&bob_secret()), - claim_signature(&BOB, &bob_secret()) + UnifiedAccounts::eth_address(&bob_secret()), + get_evm_signature(&BOB, &bob_secret()) ), Error::::InvalidSignature ); assert_noop!( - Accounts::claim_evm_account( + UnifiedAccounts::claim_evm_address( RuntimeOrigin::signed(ALICE), - Accounts::eth_address(&bob_secret()), - claim_signature(&ALICE, &alice_secret()) + UnifiedAccounts::eth_address(&bob_secret()), + get_evm_signature(&ALICE, &alice_secret()) ), Error::::InvalidSignature ); - assert_ok!(Accounts::claim_evm_account( + assert_ok!(UnifiedAccounts::claim_evm_address( RuntimeOrigin::signed(ALICE), - Accounts::eth_address(&alice_secret()), - claim_signature(&ALICE, &alice_secret()) + UnifiedAccounts::eth_address(&alice_secret()), + get_evm_signature(&ALICE, &alice_secret()) )); // AccountId already mapped assert_noop!( - Accounts::claim_evm_account( + UnifiedAccounts::claim_evm_address( RuntimeOrigin::signed(ALICE), - Accounts::eth_address(&alice_secret()), - claim_signature(&ALICE, &alice_secret()) + UnifiedAccounts::eth_address(&alice_secret()), + get_evm_signature(&ALICE, &alice_secret()) ), - Error::::AccountIdHasMapped + Error::::AlreadyMapped ); // eth address already mapped assert_noop!( - Accounts::claim_evm_account( + UnifiedAccounts::claim_evm_address( RuntimeOrigin::signed(BOB), - Accounts::eth_address(&alice_secret()), - claim_signature(&ALICE, &alice_secret()) + UnifiedAccounts::eth_address(&alice_secret()), + get_evm_signature(&ALICE, &alice_secret()) ), - Error::::EthAddressHasMapped + Error::::AlreadyMapped ); }); } @@ -217,32 +235,32 @@ fn account_default_claim_works() { ::DefaultAccountMapping::into_h160(ALICE.into()); // claim default account - assert_ok!(Accounts::claim_default_evm_account(RuntimeOrigin::signed( + assert_ok!(UnifiedAccounts::claim_default_evm_address(RuntimeOrigin::signed( ALICE ))); - System::assert_last_event(RuntimeEvent::Accounts(crate::Event::AccountClaimed { + System::assert_last_event(RuntimeEvent::UnifiedAccounts(crate::Event::AccountClaimed { account_id: ALICE.clone(), evm_address: alice_default_evm.clone(), })); - // check AddressManager mapping works + // check UnifiedAddressMapper's mapping works assert_eq!( - >::to_address(&ALICE), + >::to_h160(&ALICE), Some(alice_default_evm) ); assert_eq!( - >::to_account_id(&alice_default_evm), + >::to_account_id(&alice_default_evm), Some(ALICE) ); // should not allow to claim afterwards assert_noop!( - Accounts::claim_evm_account( + UnifiedAccounts::claim_evm_address( RuntimeOrigin::signed(ALICE), - Accounts::eth_address(&alice_secret()), - claim_signature(&ALICE, &alice_secret()) + UnifiedAccounts::eth_address(&alice_secret()), + get_evm_signature(&ALICE, &alice_secret()) ), - Error::::AccountIdHasMapped + Error::::AlreadyMapped ); }); } diff --git a/rpc-tests/claim.mjs b/rpc-tests/claim.mjs index 9d56a75d13..a452c2e1c7 100644 --- a/rpc-tests/claim.mjs +++ b/rpc-tests/claim.mjs @@ -56,7 +56,7 @@ async function main() { const hash = await claimEvmAccount(alice, ethSigner.address, sig, api); console.log(`Claim Extrisic - ${hash}`); - console.log(`Claimed Account ${await api.query.accounts.evmAccounts(alice.address)}, EVM Account: ${ethSigner.address}`); + console.log(`Claimed Account ${await api.query.accounts.EvmToNative(alice.address)}, EVM Account: ${ethSigner.address}`); api.disconnect(); } diff --git a/runtime/local/Cargo.toml b/runtime/local/Cargo.toml index 2eb7ec6615..8d59813740 100644 --- a/runtime/local/Cargo.toml +++ b/runtime/local/Cargo.toml @@ -66,7 +66,7 @@ pallet-transaction-payment-rpc-runtime-api = { workspace = true } # Astar pallets astar-primitives = { workspace = true } -pallet-account = { 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 } @@ -162,7 +162,7 @@ std = [ "pallet-scheduler/std", "pallet-treasury/std", "pallet-xvm/std", - "pallet-account/std", + "pallet-unified-accounts/std", "pallet-ethereum-checked/std", "moonbeam-evm-tracer/std", "moonbeam-rpc-primitives-debug/std", @@ -185,7 +185,7 @@ runtime-benchmarks = [ "pallet-collective/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-ethereum-checked/runtime-benchmarks", - "pallet-account/runtime-benchmarks", + "pallet-unified-accounts/runtime-benchmarks", "astar-primitives/runtime-benchmarks", "pallet-assets/runtime-benchmarks", ] @@ -210,7 +210,7 @@ try-runtime = [ "pallet-utility/try-runtime", "pallet-vesting/try-runtime", "pallet-xvm/try-runtime", - "pallet-account/try-runtime", + "pallet-unified-accounts/try-runtime", "pallet-ethereum/try-runtime", "pallet-assets/try-runtime", "pallet-scheduler/try-runtime", diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index f67b7bf5ce..cbcac0a080 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -201,7 +201,7 @@ impl frame_system::Config for Runtime { /// The aggregated dispatch type that is available for extrinsics. type RuntimeCall = RuntimeCall; /// The lookup mechanism to get account ID from whatever is passed in dispatchers. - type Lookup = (AccountIdLookup, Accounts); + type Lookup = (AccountIdLookup, UnifiedAccounts); /// The index type for storing how many extrinsics an account has signed. type Index = Index; /// The index type for blocks. @@ -229,7 +229,7 @@ impl frame_system::Config for Runtime { /// What to do if a new account is created. type OnNewAccount = (); /// What to do if an account is fully reaped from the system. - type OnKilledAccount = pallet_account::KillAccountMapping; + type OnKilledAccount = pallet_unified_accounts::KillAccountMapping; /// The data to be stored in an account. type AccountData = pallet_balances::AccountData; /// Weight information for the extrinsics of this pallet. @@ -446,12 +446,12 @@ impl pallet_utility::Config for Runtime { type WeightInfo = pallet_utility::weights::SubstrateWeight; } -impl pallet_account::Config for Runtime { +impl pallet_unified_accounts::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type DefaultAddressMapping = pallet_evm::HashedAddressMapping; - type DefaultAccountMapping = pallet_account::HashedAccountMapping; - type ClaimSignature = pallet_account::EIP712Signature; + type DefaultAccountMapping = pallet_unified_accounts::HashedAccountMapping; + type SignatureHelper = pallet_unified_accounts::EIP712Signature; } parameter_types! { @@ -465,14 +465,14 @@ impl pallet_ethereum_checked::Config for Runtime { type XvmTxWeightLimit = XvmTxWeightLimit; type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; - type AccountMapping = Accounts; + type AccountMapping = UnifiedAccounts; type XcmTransactOrigin = pallet_ethereum_checked::EnsureXcmEthereumTx; type WeightInfo = pallet_ethereum_checked::weights::SubstrateWeight; } impl pallet_xvm::Config for Runtime { type GasWeightMapping = pallet_evm::FixedGasWeightMapping; - type AccountMapping = Accounts; + type AccountMapping = UnifiedAccounts; type EthereumTransact = EthereumChecked; type WeightInfo = pallet_xvm::weights::SubstrateWeight; } @@ -558,7 +558,7 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type CallOrigin = pallet_evm::EnsureAddressRoot; type WithdrawOrigin = pallet_evm::EnsureAddressTruncated; - type AddressMapping = Accounts; + type AddressMapping = UnifiedAccounts; type Currency = Balances; type RuntimeEvent = RuntimeEvent; type Runner = pallet_evm::runner::stack::Runner; @@ -1022,7 +1022,7 @@ construct_runtime!( Proxy: pallet_proxy, Preimage: pallet_preimage, EthereumChecked: pallet_ethereum_checked, - Accounts: pallet_account, + UnifiedAccounts: pallet_unified_accounts, } ); diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml index e997bab06e..60a82668f4 100644 --- a/runtime/shibuya/Cargo.toml +++ b/runtime/shibuya/Cargo.toml @@ -96,7 +96,7 @@ orml-xtokens = { workspace = true } # Astar pallets astar-primitives = { workspace = true } -pallet-account = { 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 } @@ -207,7 +207,7 @@ std = [ "pallet-xcm/std", "pallet-xc-asset-config/std", "pallet-xvm/std", - "pallet-account/std", + "pallet-unified-accounts/std", "pallet-ethereum-checked/std", "pallet-scheduler/std", "parachain-info/std", @@ -255,7 +255,7 @@ runtime-benchmarks = [ "pallet-preimage/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-ethereum-checked/runtime-benchmarks", - "pallet-account/runtime-benchmarks", + "pallet-unified-accounts/runtime-benchmarks", "pallet-xvm/runtime-benchmarks", "polkadot-runtime/runtime-benchmarks", "orml-xtokens/runtime-benchmarks", @@ -306,7 +306,7 @@ try-runtime = [ "pallet-preimage/try-runtime", "pallet-base-fee/try-runtime", "pallet-evm/try-runtime", - "pallet-account/try-runtime", + "pallet-unified-accounts/try-runtime", "pallet-ethereum-checked/try-runtime", "orml-xtokens/try-runtime", ] diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 9ffbb60329..7a1a2003e0 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -256,7 +256,7 @@ impl frame_system::Config for Runtime { /// The aggregated dispatch type that is available for extrinsics. type RuntimeCall = RuntimeCall; /// The lookup mechanism to get account ID from whatever is passed in dispatchers. - type Lookup = (AccountIdLookup, Accounts); + type Lookup = (AccountIdLookup, UnifiedAccounts); /// The index type for storing how many extrinsics an account has signed. type Index = Index; /// The index type for blocks. @@ -279,7 +279,7 @@ impl frame_system::Config for Runtime { type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; type OnNewAccount = (); - type OnKilledAccount = pallet_account::KillAccountMapping; + type OnKilledAccount = pallet_unified_accounts::KillAccountMapping; type DbWeight = RocksDbWeight; type BaseCallFilter = BaseFilter; type SystemWeightInfo = frame_system::weights::SubstrateWeight; @@ -775,14 +775,14 @@ impl pallet_ethereum_checked::Config for Runtime { type XvmTxWeightLimit = XvmTxWeightLimit; type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; - type AccountMapping = Accounts; + type AccountMapping = UnifiedAccounts; type XcmTransactOrigin = pallet_ethereum_checked::EnsureXcmEthereumTx; type WeightInfo = pallet_ethereum_checked::weights::SubstrateWeight; } impl pallet_xvm::Config for Runtime { type GasWeightMapping = pallet_evm::FixedGasWeightMapping; - type AccountMapping = Accounts; + type AccountMapping = UnifiedAccounts; type EthereumTransact = EthereumChecked; type WeightInfo = pallet_xvm::weights::SubstrateWeight; } @@ -862,7 +862,7 @@ impl pallet_evm::Config for Runtime { type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type CallOrigin = pallet_evm::EnsureAddressRoot; type WithdrawOrigin = pallet_evm::EnsureAddressTruncated; - type AddressMapping = Accounts; + type AddressMapping = UnifiedAccounts; type Currency = Balances; type RuntimeEvent = RuntimeEvent; type Runner = pallet_evm::runner::stack::Runner; @@ -1223,12 +1223,12 @@ impl pallet_xc_asset_config::Config for Runtime { type WeightInfo = pallet_xc_asset_config::weights::SubstrateWeight; } -impl pallet_account::Config for Runtime { +impl pallet_unified_accounts::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; type DefaultAddressMapping = pallet_evm::HashedAddressMapping; - type DefaultAccountMapping = pallet_account::HashedAccountMapping; - type ClaimSignature = pallet_account::EIP712Signature; + type DefaultAccountMapping = pallet_unified_accounts::HashedAccountMapping; + type SignatureHelper = pallet_unified_accounts::EIP712Signature; } construct_runtime!( @@ -1275,7 +1275,7 @@ construct_runtime!( BaseFee: pallet_base_fee = 62, EVMChainId: pallet_evm_chain_id = 63, EthereumChecked: pallet_ethereum_checked = 64, - Accounts: pallet_account = 65, + UnifiedAccounts: pallet_unified_accounts = 65, Contracts: pallet_contracts = 70, @@ -1420,7 +1420,7 @@ mod benches { [pallet_xcm, PolkadotXcm] [pallet_ethereum_checked, EthereumChecked] [pallet_xvm, Xvm] - [pallet_account, Accounts] + [pallet_unified_accounts, UnifiedAccounts] ); } diff --git a/tests/integration/Cargo.toml b/tests/integration/Cargo.toml index cd7e43b119..54ac446226 100644 --- a/tests/integration/Cargo.toml +++ b/tests/integration/Cargo.toml @@ -29,7 +29,7 @@ sp-io = { workspace = true } sp-runtime = { workspace = true } # astar dependencies -pallet-account = { workspace = true } +pallet-unified-accounts = { workspace = true } pallet-ethereum-checked = { workspace = true } pallet-evm-precompile-assets-erc20 = { workspace = true } diff --git a/tests/integration/src/account.rs b/tests/integration/src/account.rs index 84e5f58844..5c1e55a1cb 100644 --- a/tests/integration/src/account.rs +++ b/tests/integration/src/account.rs @@ -17,12 +17,12 @@ // along with Astar. If not, see . use crate::setup::*; -use std::str::FromStr; +pub use sp_io::hashing::keccak_256; #[test] fn transfer_to_h160_via_lookup() { new_test_ext().execute_with(|| { - let eth_address = H160::from_str("0xaaafB3972B05630fCceE866eC69CdADd9baC2771").unwrap(); + let eth_address = H160::from_slice(&keccak_256(b"Alice")[0..20]); // make sure account is empty assert!(EVM::is_account_empty(ð_address)); diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs index 77807a3484..5f5f5c2758 100644 --- a/tests/integration/src/setup.rs +++ b/tests/integration/src/setup.rs @@ -23,7 +23,7 @@ pub use frame_support::{ traits::{OnFinalize, OnIdle, OnInitialize}, weights::Weight, }; -pub use pallet_account::AddressManager; +pub use pallet_unified_accounts::UnifiedAddressMapper; pub use pallet_evm::AddressMapping; pub use sp_core::{H160, H256, U256}; pub use sp_runtime::{AccountId32, MultiAddress}; @@ -107,11 +107,11 @@ mod shibuya { } pub fn claim_default_accounts(account: AccountId) { - let default_h160 = Accounts::to_default_address(&account); - assert_ok!(Accounts::claim_default_evm_account(RuntimeOrigin::signed( + let default_h160 = UnifiedAccounts::to_default_h160(&account); + assert_ok!(UnifiedAccounts::claim_default_evm_address(RuntimeOrigin::signed( account.clone() ))); - assert_eq!(Accounts::to_address(&account).unwrap(), default_h160); + assert_eq!(UnifiedAccounts::to_h160(&account).unwrap(), default_h160); } } @@ -176,8 +176,6 @@ impl ExtBuilder { let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); - #[cfg(feature = "shibuya")] - ext.execute_with(|| claim_default_accounts(ALICE)); ext } } diff --git a/tests/integration/src/xvm.rs b/tests/integration/src/xvm.rs index 8e9c58fbab..b52ee6f39c 100644 --- a/tests/integration/src/xvm.rs +++ b/tests/integration/src/xvm.rs @@ -157,6 +157,9 @@ const CALL_EVM_PAYBLE_NAME: &'static str = "call_xvm_payable"; #[test] fn evm_payable_call_via_xvm_works() { new_test_ext().execute_with(|| { + // create account mappings + claim_default_accounts(ALICE); + let evm_payable_addr = deploy_evm_contract(EVM_PAYABLE); let value = UNIT; @@ -225,6 +228,9 @@ fn wasm_payable_call_via_xvm_works() { #[test] fn calling_wasm_payable_from_evm_fails_if_caller_contract_balance_below_ed() { new_test_ext().execute_with(|| { + // create account mappings + claim_default_accounts(ALICE); + let wasm_payable_addr = deploy_wasm_contract(WASM_PAYABLE_NAME); let call_wasm_payable_addr = deploy_evm_contract(CALL_WASM_PAYBLE); @@ -264,6 +270,9 @@ fn calling_wasm_payable_from_evm_fails_if_caller_contract_balance_below_ed() { #[test] fn calling_wasm_payable_from_evm_works() { new_test_ext().execute_with(|| { + // create account mappings + claim_default_accounts(ALICE); + let wasm_payable_addr = deploy_wasm_contract(WASM_PAYABLE_NAME); let call_wasm_payable_addr = deploy_evm_contract(CALL_WASM_PAYBLE); @@ -294,6 +303,9 @@ fn calling_wasm_payable_from_evm_works() { #[test] fn calling_evm_payable_from_wasm_works() { new_test_ext().execute_with(|| { + // create account mappings + claim_default_accounts(ALICE); + let evm_payable_addr = deploy_evm_contract(EVM_PAYABLE); let wasm_address = deploy_wasm_contract(CALL_EVM_PAYBLE_NAME); @@ -335,6 +347,9 @@ fn calling_evm_payable_from_wasm_works() { #[test] fn reentrance_not_allowed() { new_test_ext().execute_with(|| { + // create account mappings + claim_default_accounts(ALICE); + // Call path: WASM -> EVM -> WASM let call_evm_payable_address = deploy_wasm_contract(CALL_EVM_PAYBLE_NAME); let call_wasm_payable_addr = deploy_evm_contract(CALL_WASM_PAYBLE);