From bd16dfdff2d8f9500edc419b7a21fa98b4c89579 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Wed, 23 Aug 2023 09:14:02 +0530 Subject: [PATCH 01/29] wip --- Cargo.lock | 13 +++++++++++++ Cargo.toml | 1 + pallets/account/Cargo.toml | 40 ++++++++++++++++++++++++++++++++++++++ pallets/account/src/lib.rs | 34 ++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 pallets/account/Cargo.toml create mode 100644 pallets/account/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 49ee57f0b1..bf29b99701 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8300,6 +8300,19 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet_account" +version = "0.1.0" +dependencies = [ + "astar-primitives", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "parachain-info" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 6e3948a47f..e82204ef88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -277,6 +277,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 } astar-primitives = { path = "./primitives", default-features = false } diff --git a/pallets/account/Cargo.toml b/pallets/account/Cargo.toml new file mode 100644 index 0000000000..538bebfa23 --- /dev/null +++ b/pallets/account/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "pallet_account" +version = "0.1.0" +description = "Pallet for mapping VM accounts with native accounts" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +parity-scale-codec = { workspace = true } +scale-info = { workspace = true } + +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +astar-primitives = { workspace = true } + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "scale-info/std", + "sp-std/std", + "sp-runtime/std", + "frame-support/std", + "frame-system/std", + "astar-primitives/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "astar-primitives/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/account/src/lib.rs b/pallets/account/src/lib.rs new file mode 100644 index 0000000000..f6c62fd03d --- /dev/null +++ b/pallets/account/src/lib.rs @@ -0,0 +1,34 @@ +// 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 . + +//! # Pallet Account + +#![cfg_attr(not(feature = "std"), no_std)] + +use sp_std::marker::PhantomData; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::config] + pub trait Config: frame_system::Config {} +} From d5e60cdcc423e4809265370f44f9ccd6ee462b75 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Wed, 30 Aug 2023 17:07:55 +0530 Subject: [PATCH 02/29] feat: add initial implementation for `pallet_account` --- Cargo.lock | 9 + pallets/account/Cargo.toml | 29 ++- pallets/account/src/lib.rs | 355 ++++++++++++++++++++++++++++++++++- pallets/account/src/mock.rs | 260 +++++++++++++++++++++++++ pallets/account/src/tests.rs | 36 ++++ primitives/src/evm.rs | 3 + rpc-tests/package.json | 3 +- 7 files changed, 691 insertions(+), 4 deletions(-) create mode 100644 pallets/account/src/mock.rs create mode 100644 pallets/account/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index bf29b99701..10761a72f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8307,8 +8307,17 @@ dependencies = [ "astar-primitives", "frame-support", "frame-system", + "hex", + "log", + "pallet-balances", + "pallet-ethereum", + "pallet-evm", + "pallet-timestamp", "parity-scale-codec", + "precompile-utils", "scale-info", + "sp-core", + "sp-io", "sp-runtime", "sp-std", ] diff --git a/pallets/account/Cargo.toml b/pallets/account/Cargo.toml index 538bebfa23..83a739eb16 100644 --- a/pallets/account/Cargo.toml +++ b/pallets/account/Cargo.toml @@ -10,31 +10,58 @@ repository.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +log = { workspace = true } parity-scale-codec = { workspace = true } scale-info = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } +precompile-utils = { workspace = true } + +# frontier +pallet-evm = { workspace = true } + +# Astar astar-primitives = { workspace = true } +[dev-dependencies] +hex = { workspace = true} +pallet-balances = { workspace = true } +pallet-ethereum = { workspace = true } +pallet-evm = { workspace = true } +pallet-timestamp = { workspace = true } + [features] default = ["std"] std = [ + "hex/std", + "log/std", "parity-scale-codec/std", "scale-info/std", "sp-std/std", + "sp-core/std", + "sp-io/std", "sp-runtime/std", "frame-support/std", "frame-system/std", "astar-primitives/std", + "precompile-utils/std", + "pallet-evm/std", + "pallet-balances/std", + "pallet-timestamp/std", + "pallet-ethereum/std", ] runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "astar-primitives/runtime-benchmarks", + "pallet-ethereum/runtime-benchmarks", + "pallet-evm/runtime-benchmarks", ] -try-runtime = ["frame-support/try-runtime"] +try-runtime = ["frame-support/try-runtime", "pallet-evm/try-runtime"] diff --git a/pallets/account/src/lib.rs b/pallets/account/src/lib.rs index f6c62fd03d..5157a16be8 100644 --- a/pallets/account/src/lib.rs +++ b/pallets/account/src/lib.rs @@ -20,9 +20,62 @@ #![cfg_attr(not(feature = "std"), no_std)] +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::{Currency, ExistenceRequirement::*, Get, IsType}, +}; +use frame_system::{ensure_signed, pallet_prelude::*}; +use pallet_evm::AddressMapping; +use precompile_utils::keccak256; +use sp_core::{keccak_256, Hasher, H160, H256, U256}; +use sp_runtime::traits::{LookupError, StaticLookup, Zero}; +use sp_runtime::MultiAddress; use sp_std::marker::PhantomData; -#[frame_support::pallet] +use pallet::*; + +mod mock; +mod tests; + +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. + /// 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; +} + +/// Signature verification scheme for proving address ownership +pub trait ClaimSignature { + type AccountId; + type Address; + /// Signature type, ideally a 512-bit value for ECDSA signatures + type Signature: Parameter; + + /// Build raw payload (pre-hash) that user will sign. + fn build_signing_payload(who: &Self::AccountId) -> Vec; + /// Verify the provided signature against the given account. + fn verify_signature(who: &Self::AccountId, sig: &Self::Signature) -> Option; +} + +#[frame_support::pallet(dev_mode)] pub mod pallet { use super::*; @@ -30,5 +83,303 @@ pub mod pallet { pub struct Pallet(PhantomData); #[pallet::config] - pub trait Config: frame_system::Config {} + pub trait Config: frame_system::Config { + /// The overarching event type + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// The Currency for managing Evm account assets + type Currency: Currency; + /// Default evm address to account id conversion + type DefaultAddressMapping: AddressMapping; + /// Default account id to evm address conversion + 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; + /// Chain ID of EVM + /// TODO: remove this and make it generic parameter of EIP712Signature struct + #[pallet::constant] + type ChainId: Get; + + // TODO: benchmarks + // /// Weight information for the extrinsics in this module + // type WeightInfo: WeightInfo; + } + + #[pallet::error] + pub enum Error { + /// AccountId has mapped + AccountIdHasMapped, + /// Eth address has mapped + EthAddressHasMapped, + /// Bad signature + BadSignature, + /// Invalid signature + InvalidSignature, + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// EVM Account claimed. + /// Double Mapping b/w native and evm address created + AccountClaimed { + account_id: T::AccountId, + evm_address: EvmAddress, + }, + } + + /// Native accounts for EVM address + /// NativeAccounts: EvmAddress => Option + #[pallet::storage] + pub type NativeAccounts = + StorageMap<_, Twox64Concat, EvmAddress, T::AccountId, OptionQuery>; + + /// EVM Addresses for native accounts + /// EvmAccounts: AccountId => Option + #[pallet::storage] + pub type EvmAccounts = + StorageMap<_, Twox64Concat, T::AccountId, EvmAddress, OptionQuery>; + + #[pallet::call] + impl Pallet { + /// Claim account mapping between Substrate accounts and EVM accounts. + /// Ensure no prior mapping exists for evm address. + /// + /// - `evm_address`: The 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( + origin: OriginFor, + evm_address: EvmAddress, + signature: SignatureOf, + ) -> DispatchResult { + 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 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 { + 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)?; + 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!( + !EvmAccounts::::contains_key(&account_id), + Error::::AccountIdHasMapped + ); + // This is not required since checking one mapping is sufficent + // but this is just for sanity check + if let Some(addr) = address { + ensure!( + !NativeAccounts::::contains_key(addr), + Error::::EthAddressHasMapped + ); + } + 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); + + Self::deposit_event(Event::AccountClaimed { + account_id, + evm_address: address, + }); + } + + /// Claim the given evm address by providing claim signature + fn do_claim_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) + .ok_or(Error::::BadSignature)?; + ensure!(evm_address == address, Error::::InvalidSignature); + + // Check if the default account id already exists for this eth 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::free_balance(&default_account_id), + AllowDeath, + )?; + } + + // create double mappings for the pair + Self::add_mappings(account_id, evm_address); + Ok(()) + } + + /// Claim the default evm address + fn do_claim_default_address(account_id: T::AccountId) -> Result { + // get the default evm address + let 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) + } +} + +impl AddressManager for Pallet { + fn to_account_id(address: &EvmAddress) -> Option { + NativeAccounts::::get(address) + } + + fn to_account_id_or_default(address: &EvmAddress) -> T::AccountId { + NativeAccounts::::get(address).unwrap_or_else(|| { + // fallback to default account_id + T::DefaultAddressMapping::into_account_id(address.clone()) + }) + } + + fn to_default_account_id(address: &EvmAddress) -> T::AccountId { + T::DefaultAddressMapping::into_account_id(address.clone()) + } + + fn to_address(account_id: &T::AccountId) -> Option { + EvmAccounts::::get(account_id) + } + + fn to_address_or_default(account_id: &T::AccountId) -> EvmAddress { + EvmAccounts::::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 { + T::DefaultAccountMapping::into_h160(account_id.clone()) + } +} + +impl AccountMapping for Pallet { + fn into_h160(account: T::AccountId) -> H160 { + >::to_address_or_default(&account) + } +} +impl AddressMapping for Pallet { + fn into_account_id(address: H160) -> T::AccountId { + >::to_account_id_or_default(&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) = EvmAccounts::::get(who) { + NativeAccounts::::remove(evm_addr); + EvmAccounts::::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 +/// +/// Raw Data = Domain Separator + Type Hash + keccak256(AccountId) +pub struct EIP712Signature(PhantomData); +impl ClaimSignature 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) -> Vec { + 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); + payload + } + + fn verify_signature(who: &Self::AccountId, sig: &Self::Signature) -> Option { + let payload = Self::build_signing_payload(who); + let payload_hash = keccak_256(&payload); + + sp_io::crypto::secp256k1_ecdsa_recover(sig, &payload_hash) + .map(|pubkey| H160::from(H256::from_slice(&keccak_256(&pubkey)))) + .ok() + } +} + +impl EIP712Signature { + /// TODO: 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(T::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()) + } +} + +/// 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/pallets/account/src/mock.rs b/pallets/account/src/mock.rs new file mode 100644 index 0000000000..8ee1370ff4 --- /dev/null +++ b/pallets/account/src/mock.rs @@ -0,0 +1,260 @@ +// 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 . + +#![cfg(test)] + +use super::*; +use crate as pallet_account; +use astar_primitives::ethereum_checked::AccountMapping; +use frame_support::{ + construct_runtime, parameter_types, + sp_io::TestExternalities, + traits::{ConstU128, ConstU64, FindAuthor}, + weights::Weight, +}; +use pallet_ethereum::PostLogContent; +use pallet_evm::FeeCalculator; +use sp_io::hashing::blake2_256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, ConsensusEngineId, +}; + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, 0)); +} + +impl frame_system::Config for TestRuntime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = BlockNumber; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_balances::Config for TestRuntime { + type MaxLocks = ConstU32<4>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ConstU128<2>; + type AccountStore = System; + type WeightInfo = (); + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +impl pallet_timestamp::Config for TestRuntime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<3>; + type WeightInfo = (); +} + +pub struct MockFeeCalculator; +impl FeeCalculator for MockFeeCalculator { + fn min_gas_price() -> (U256, Weight) { + (U256::one(), Weight::zero()) + } +} + +pub struct MockFindAuthor; +impl FindAuthor for MockFindAuthor { + fn find_author<'a, I>(_digests: I) -> Option + where + I: 'a + IntoIterator, + { + Some(H160::from_low_u64_be(1)) + } +} + +pub struct MockAddressMapping; +impl AddressMapping for MockAddressMapping { + fn into_account_id(address: H160) -> AccountId32 { + if address == ALICE_H160 { + return ALICE; + } + if address == BOB_H160 { + return BOB; + } + if address == CHARLIE_H160 { + return CHARLIE; + } + + return pallet_evm::HashedAddressMapping::::into_account_id(address); + } +} + +pub struct MockAccountMapping; +impl AccountMapping for MockAccountMapping { + fn into_h160(account_id: AccountId) -> H160 { + if account_id == ALICE { + return ALICE_H160; + } + if account_id == BOB { + return BOB_H160; + } + if account_id == CHARLIE { + return CHARLIE_H160; + } + + let data = (b"evm:", account_id); + return H160::from_slice(&data.using_encoded(blake2_256)[0..20]); + } +} + +parameter_types! { + pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub const BlockGasLimit: U256 = U256::MAX; +} + +impl pallet_evm::Config for TestRuntime { + type FeeCalculator = MockFeeCalculator; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; + type CallOrigin = pallet_evm::EnsureAddressRoot; + type WithdrawOrigin = pallet_evm::EnsureAddressTruncated; + type AddressMapping = MockAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = (); + type PrecompilesValue = (); + type ChainId = ConstU64<1024>; + type OnChargeTransaction = (); + type BlockGasLimit = BlockGasLimit; + type OnCreate = (); + type FindAuthor = MockFindAuthor; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; + type GasLimitPovSizeRatio = ConstU64<4>; +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +parameter_types! { + pub TxWeightLimit: Weight = Weight::from_parts(u64::max_value(), 0); +} + +impl pallet_account::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type DefaultAddressMapping = MockAddressMapping; + type DefaultAccountMapping = HashedAccountMapping; + type ChainId = ConstU64<1024>; + type ClaimSignature = EIP712Signature; +} + +pub(crate) type AccountId = AccountId32; +pub(crate) type BlockNumber = u64; +pub(crate) type Balance = u128; + +pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); +pub const CHARLIE: AccountId32 = AccountId32::new([2u8; 32]); + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub struct TestRuntime + where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Evm: pallet_evm, + Ethereum: pallet_ethereum, + Accounts: pallet_account, + } +); + +pub const ALICE_H160: H160 = H160::repeat_byte(1); +pub const BOB_H160: H160 = H160::repeat_byte(2); +pub const CHARLIE_H160: H160 = H160::repeat_byte(3); + +pub struct ExtBuilder { + balances: Vec<(AccountId, Balance)>, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + balances: vec![ + (ALICE, 1_000_000_000_000), + (BOB, 1_000_000_000_000), + (CHARLIE, 1_000_000_000_000), + ], + } + } +} + +impl ExtBuilder { + pub fn build(self) -> TestExternalities { + let mut t = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.balances, + } + .assimilate_storage(&mut t) + .unwrap(); + + let ext = TestExternalities::from(t); + ext + } +} diff --git a/pallets/account/src/tests.rs b/pallets/account/src/tests.rs new file mode 100644 index 0000000000..a4369e95bf --- /dev/null +++ b/pallets/account/src/tests.rs @@ -0,0 +1,36 @@ +// 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 . + +#![cfg(test)] + +use super::*; +use mock::*; + +#[test] +fn test() { + ExtBuilder::default().build().execute_with(|| { + println!( + "0x{}", + hex::encode( + ::ClaimSignature::build_signing_payload( + &ALICE + ) + ) + ); + }); +} diff --git a/primitives/src/evm.rs b/primitives/src/evm.rs index 25d1599219..ce6c483ac5 100644 --- a/primitives/src/evm.rs +++ b/primitives/src/evm.rs @@ -19,11 +19,14 @@ use crate::{AccountId, AssetId}; use frame_support::ensure; +use sp_core::H160; use sp_std::marker::PhantomData; use pallet_assets::AssetsCallback; use pallet_evm_precompile_assets_erc20::AddressToAssetId; +pub type EvmAddress = H160; + /// Revert opt code. It's inserted at the precompile addresses, to make them functional in EVM. pub const EVM_REVERT_CODE: &[u8] = &[0x60, 0x00, 0x60, 0x00, 0xfd]; diff --git a/rpc-tests/package.json b/rpc-tests/package.json index ad51a9a26d..105a59aabb 100644 --- a/rpc-tests/package.json +++ b/rpc-tests/package.json @@ -10,6 +10,7 @@ "dependencies": { "@polkadot/util-crypto": "^10.4.2", "solc": "^0.8.18", - "web3": "^1.8.2" + "web3": "^1.8.2", + "ethers": "6" } } From cff5b2a0264d082bacc7427edc88a999772908f3 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Thu, 31 Aug 2023 15:15:19 +0530 Subject: [PATCH 03/29] feat: add test helpers and refactor --- Cargo.lock | 887 +++++++++++++++++++++++++++++++---- Cargo.toml | 3 +- pallets/account/Cargo.toml | 7 +- pallets/account/src/impls.rs | 175 +++++++ pallets/account/src/lib.rs | 162 +------ 5 files changed, 1008 insertions(+), 226 deletions(-) create mode 100644 pallets/account/src/impls.rs diff --git a/Cargo.lock b/Cargo.lock index 10761a72f2..c46eb51234 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -300,6 +300,15 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b1c5a481ec30a5abd8dfbd94ab5cf1bb4e9a66be7f1b3b322f2f1170c200fd" +[[package]] +name = "array-init" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" +dependencies = [ + "nodrop", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -606,7 +615,7 @@ dependencies = [ "polkadot-runtime", "polkadot-runtime-common", "scale-info", - "smallvec", + "smallvec 1.11.0", "sp-api", "sp-block-builder", "sp-consensus-aura", @@ -679,15 +688,26 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.71" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", "syn 2.0.25", ] +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures 0.3.28", + "pharos", + "rustc_version 0.4.0", +] + [[package]] name = "asynchronous-codec" version = "0.6.1" @@ -698,7 +718,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", ] [[package]] @@ -787,6 +807,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "beef" version = "0.5.2" @@ -986,6 +1012,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "sha2 0.10.7", + "tinyvec", +] + [[package]] name = "bstr" version = "0.2.17" @@ -1051,6 +1087,9 @@ name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +dependencies = [ + "serde", +] [[package]] name = "bzip2-sys" @@ -1095,6 +1134,20 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cargo_metadata" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7daec1a2a2129eeba1644b220b4647ec537b0b5d4bfd6876fcc5a540056b592" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.17", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.79" @@ -1130,7 +1183,7 @@ version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "215c0072ecc28f92eeb0eea38ba63ddfcb65c2828c46311d646f1a3ff5f9841c" dependencies = [ - "smallvec", + "smallvec 1.11.0", ] [[package]] @@ -1309,6 +1362,58 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58 0.5.0", + "coins-core", + "digest 0.10.7", + "hmac 0.12.1", + "k256", + "serde", + "sha2 0.10.7", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac 0.12.1", + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "sha2 0.10.7", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.2", + "bech32", + "bs58 0.5.0", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.7", + "sha3", + "thiserror", +] + [[package]] name = "colorchoice" version = "1.0.0" @@ -1321,8 +1426,8 @@ version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e959d788268e3bf9d35ace83e81b124190378e4c91c9067524675e33394b8ba" dependencies = [ - "strum", - "strum_macros", + "strum 0.24.1", + "strum_macros 0.24.3", "unicode-width", ] @@ -1348,6 +1453,18 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "const-hex" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08849ed393c907c90016652a01465a12d86361cd38ad2a7de026c56a520cc259" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "serde", +] + [[package]] name = "const-oid" version = "0.9.3" @@ -1450,7 +1567,7 @@ dependencies = [ "hashbrown 0.13.2", "log", "regalloc2", - "smallvec", + "smallvec 1.11.0", "target-lexicon", ] @@ -1486,7 +1603,7 @@ checksum = "64a25d9d0a0ae3079c463c34115ec59507b4707175454f0eee0891e83e30e82d" dependencies = [ "cranelift-codegen", "log", - "smallvec", + "smallvec 1.11.0", "target-lexicon", ] @@ -1518,7 +1635,7 @@ dependencies = [ "cranelift-frontend", "itertools", "log", - "smallvec", + "smallvec 1.11.0", "wasmparser", "wasmtime-types", ] @@ -2582,6 +2699,12 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "519b83cd10f5f6e969625a409f735182bea5558cd8b64c655806ceaae36f1999" +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + [[package]] name = "dyn-clonable" version = "0.9.0" @@ -2725,6 +2848,34 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enr" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be7b2ac146c1f99fe245c02d16af0696450d8e06c135db75e10eeb9e642c20d" +dependencies = [ + "base64 0.21.2", + "bytes", + "hex", + "k256", + "log", + "rand 0.8.5", + "rlp", + "serde", + "serde-hex", + "sha3", + "zeroize", +] + [[package]] name = "enum-as-inner" version = "0.5.1" @@ -2827,6 +2978,45 @@ dependencies = [ "libc", ] +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes 0.8.3", + "ctr 0.9.2", + "digest 0.10.7", + "hex", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.7", + "sha3", + "thiserror", + "uuid 0.8.2", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + [[package]] name = "ethbloom" version = "0.13.0" @@ -2876,6 +3066,217 @@ dependencies = [ "uint", ] +[[package]] +name = "ethers" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba3fd516c15a9a587135229466dbbfc85796de55c5660afbbb1b1c78517d85c" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0245617f11b8178fa50b52e433e2c34ac69f39116b62c8be2437decf2edf1986" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bb80fd2c22631a5eb8a02cbf373cc5fd86937fc966bb670b9a884580c8e71c" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22c54db0d393393e732a5b20273e4f8ab89f0cce501c84e75fab9c126799a6e6" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "eyre", + "prettyplease 0.2.10", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.25", + "toml 0.7.6", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ee4f216184a1304b707ed258f4f70aa40bf7e1522ab8963d127a8d516eaa1a" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.25", +] + +[[package]] +name = "ethers-core" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c29523f73c12753165781c6e5dc11c84d3e44c080a15f7c6cfbd70b514cb6f1" +dependencies = [ + "arrayvec 0.7.4", + "bytes", + "cargo_metadata 0.17.0", + "chrono", + "const-hex", + "elliptic-curve 0.13.5", + "ethabi", + "generic-array 0.14.7", + "k256", + "num_enum 0.7.0", + "once_cell", + "open-fastrlp", + "rand 0.8.5", + "rlp", + "serde", + "serde_json", + "strum 0.25.0", + "syn 2.0.25", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-etherscan" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aab5af432b3fe5b7756b60df5c9ddeb85a13414575ad8a9acd707c24f0a77a5" +dependencies = [ + "ethers-core", + "reqwest", + "semver 1.0.17", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "356151d5ded56d4918146366abc9dfc9df367cf0096492a7a5477b21b7693615" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00c84664b294e47fc2860d6db0db0246f79c4c724e552549631bb9505b834bee" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.2", + "bytes", + "const-hex", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http", + "instant", + "jsonwebtoken", + "once_cell", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170b299698702ef1f53d2275af7d6d97409cfa4f9398ee9ff518f6bc9102d0ad" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve 0.13.5", + "eth-keystore", + "ethers-core", + "rand 0.8.5", + "sha2 0.10.7", + "thiserror", + "tracing", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -3009,6 +3410,16 @@ dependencies = [ "syn 2.0.25", ] +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -3036,6 +3447,12 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + [[package]] name = "fatality" version = "0.0.6" @@ -3090,7 +3507,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "sc-client-db", - "smallvec", + "smallvec 1.11.0", "sp-blockchain", "sp-core", "sp-database", @@ -3604,7 +4021,7 @@ dependencies = [ "paste", "scale-info", "serde", - "smallvec", + "smallvec 1.11.0", "sp-api", "sp-arithmetic", "sp-core", @@ -3807,15 +4224,25 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ - "fastrand", + "fastrand 1.9.0", "futures-core", "futures-io", "memchr", "parking", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", "waker-fn", ] +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + [[package]] name = "futures-macro" version = "0.3.28" @@ -3855,6 +4282,10 @@ name = "futures-timer" version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] [[package]] name = "futures-util" @@ -3870,7 +4301,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", "pin-utils", "slab", ] @@ -3986,6 +4417,18 @@ dependencies = [ "regex", ] +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "group" version = "0.12.1" @@ -4086,6 +4529,15 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + [[package]] name = "heck" version = "0.4.1" @@ -4201,7 +4653,7 @@ checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", ] [[package]] @@ -4244,7 +4696,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", "socket2 0.4.9", "tokio", "tower-service", @@ -4385,6 +4837,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "1.9.3" @@ -4727,6 +5185,20 @@ dependencies = [ "jsonrpsee-types", ] +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.2", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "k256" version = "0.13.1" @@ -4738,6 +5210,7 @@ dependencies = [ "elliptic-curve 0.13.5", "once_cell", "sha2 0.10.7", + "signature 2.1.0", ] [[package]] @@ -4822,7 +5295,7 @@ dependencies = [ "scale-info", "serde", "serde_derive", - "smallvec", + "smallvec 1.11.0", "sp-api", "sp-arithmetic", "sp-authority-discovery", @@ -4856,7 +5329,7 @@ dependencies = [ "frame-support", "polkadot-primitives", "polkadot-runtime-common", - "smallvec", + "smallvec 1.11.0", "sp-core", "sp-runtime", "sp-weights", @@ -4868,7 +5341,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7d770dcb02bf6835887c3a979b5107a04ff4bbde97a5f0928d27404a155add9" dependencies = [ - "smallvec", + "smallvec 1.11.0", ] [[package]] @@ -4892,7 +5365,7 @@ dependencies = [ "parking_lot 0.12.1", "regex", "rocksdb", - "smallvec", + "smallvec 1.11.0", ] [[package]] @@ -5018,7 +5491,7 @@ dependencies = [ "quick-protobuf", "rand 0.8.5", "rw-stream-sink", - "smallvec", + "smallvec 1.11.0", "thiserror", "unsigned-varint", "void", @@ -5034,7 +5507,7 @@ dependencies = [ "libp2p-core", "log", "parking_lot 0.12.1", - "smallvec", + "smallvec 1.11.0", "trust-dns-resolver", ] @@ -5055,7 +5528,7 @@ dependencies = [ "lru 0.10.1", "quick-protobuf", "quick-protobuf-codec", - "smallvec", + "smallvec 1.11.0", "thiserror", "void", ] @@ -5066,7 +5539,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e2d584751cecb2aabaa56106be6be91338a60a0f4e420cf2af639204f596fc1" dependencies = [ - "bs58", + "bs58 0.4.0", "ed25519-dalek", "log", "multiaddr", @@ -5099,7 +5572,7 @@ dependencies = [ "quick-protobuf", "rand 0.8.5", "sha2 0.10.7", - "smallvec", + "smallvec 1.11.0", "thiserror", "uint", "unsigned-varint", @@ -5120,7 +5593,7 @@ dependencies = [ "libp2p-swarm", "log", "rand 0.8.5", - "smallvec", + "smallvec 1.11.0", "socket2 0.4.9", "tokio", "trust-dns-proto", @@ -5216,7 +5689,7 @@ dependencies = [ "libp2p-identity", "libp2p-swarm", "rand 0.8.5", - "smallvec", + "smallvec 1.11.0", ] [[package]] @@ -5235,7 +5708,7 @@ dependencies = [ "libp2p-swarm-derive", "log", "rand 0.8.5", - "smallvec", + "smallvec 1.11.0", "tokio", "void", ] @@ -5685,6 +6158,12 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + [[package]] name = "md-5" version = "0.10.5" @@ -5783,6 +6262,12 @@ dependencies = [ "thrift", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -6169,7 +6654,7 @@ dependencies = [ "futures 0.3.28", "log", "pin-project", - "smallvec", + "smallvec 1.11.0", "unsigned-varint", ] @@ -6293,6 +6778,12 @@ dependencies = [ "memoffset 0.6.5", ] +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -6429,6 +6920,15 @@ dependencies = [ "num_enum_derive 0.6.1", ] +[[package]] +name = "num_enum" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb" +dependencies = [ + "num_enum_derive 0.7.0", +] + [[package]] name = "num_enum_derive" version = "0.5.11" @@ -6453,6 +6953,18 @@ dependencies = [ "syn 2.0.25", ] +[[package]] +name = "num_enum_derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.25", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -6516,6 +7028,31 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.4", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -7015,7 +7552,7 @@ dependencies = [ "rand_pcg", "scale-info", "serde", - "smallvec", + "smallvec 1.11.0", "sp-api", "sp-core", "sp-io", @@ -7161,7 +7698,7 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-std", - "strum", + "strum 0.24.1", ] [[package]] @@ -8305,9 +8842,11 @@ name = "pallet_account" version = "0.1.0" dependencies = [ "astar-primitives", + "ethers", "frame-support", "frame-system", "hex", + "libsecp256k1", "log", "pallet-balances", "pallet-ethereum", @@ -8430,7 +8969,7 @@ dependencies = [ "instant", "libc", "redox_syscall 0.2.16", - "smallvec", + "smallvec 1.11.0", "winapi", ] @@ -8443,7 +8982,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall 0.3.5", - "smallvec", + "smallvec 1.11.0", "windows-targets 0.48.1", ] @@ -8477,6 +9016,16 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", +] + [[package]] name = "peeking_take_while" version = "0.1.2" @@ -8561,6 +9110,16 @@ dependencies = [ "indexmap 1.9.3", ] +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures 0.3.28", + "rustc_version 0.4.0", +] + [[package]] name = "pin-project" version = "1.1.2" @@ -8589,9 +9148,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -9216,7 +9775,7 @@ name = "polkadot-node-metrics" version = "0.9.43" source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.43#ba42b9ce51d25bdaf52d2c61e0763a6e3da50d25" dependencies = [ - "bs58", + "bs58 0.4.0", "futures 0.3.28", "futures-timer", "log", @@ -9248,7 +9807,7 @@ dependencies = [ "rand 0.8.5", "sc-authority-discovery", "sc-network", - "strum", + "strum 0.24.1", "thiserror", "tracing-gum", ] @@ -9300,7 +9859,7 @@ dependencies = [ "polkadot-primitives", "polkadot-statement-table", "sc-network", - "smallvec", + "smallvec 1.11.0", "sp-api", "sp-authority-discovery", "sp-consensus-babe", @@ -9526,7 +10085,7 @@ dependencies = [ "scale-info", "serde", "serde_derive", - "smallvec", + "smallvec 1.11.0", "sp-api", "sp-arithmetic", "sp-authority-discovery", @@ -9606,7 +10165,7 @@ dependencies = [ "frame-support", "polkadot-primitives", "polkadot-runtime-common", - "smallvec", + "smallvec 1.11.0", "sp-core", "sp-runtime", "sp-weights", @@ -9617,7 +10176,7 @@ name = "polkadot-runtime-metrics" version = "0.9.43" source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.43#ba42b9ce51d25bdaf52d2c61e0763a6e3da50d25" dependencies = [ - "bs58", + "bs58 0.4.0", "parity-scale-codec", "polkadot-primitives", "sp-std", @@ -9821,7 +10380,7 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", "windows-sys 0.48.0", ] @@ -10422,7 +10981,7 @@ dependencies = [ "fxhash", "log", "slice-group-by", - "smallvec", + "smallvec 1.11.0", ] [[package]] @@ -10469,6 +11028,40 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" +[[package]] +name = "reqwest" +version = "0.11.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +dependencies = [ + "base64 0.21.2", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite 0.2.13", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -10619,7 +11212,7 @@ dependencies = [ "scale-info", "serde", "serde_derive", - "smallvec", + "smallvec 1.11.0", "sp-api", "sp-authority-discovery", "sp-block-builder", @@ -10651,7 +11244,7 @@ dependencies = [ "frame-support", "polkadot-primitives", "polkadot-runtime-common", - "smallvec", + "smallvec 1.11.0", "sp-core", "sp-runtime", "sp-weights", @@ -10891,6 +11484,15 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "same-file" version = "1.0.6" @@ -11478,7 +12080,7 @@ dependencies = [ "sc-utils", "serde", "serde_json", - "smallvec", + "smallvec 1.11.0", "snow", "sp-arithmetic", "sp-blockchain", @@ -11530,7 +12132,7 @@ dependencies = [ "sc-peerset", "sc-utils", "serde", - "smallvec", + "smallvec 1.11.0", "sp-blockchain", "sp-consensus", "sp-consensus-grandpa", @@ -11606,7 +12208,7 @@ dependencies = [ "sc-network-common", "sc-peerset", "sc-utils", - "smallvec", + "smallvec 1.11.0", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -12108,6 +12710,18 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "764cad9e7e1ca5fe15b552859ff5d96a314e6ed2934f2260168cd5dfa5891409" +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac 0.12.1", + "pbkdf2 0.11.0", + "salsa20", + "sha2 0.10.7", +] + [[package]] name = "sct" version = "0.6.1" @@ -12251,6 +12865,18 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "serde" version = "1.0.171" @@ -12260,6 +12886,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-hex" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca37e3e4d1b39afd7ff11ee4e947efae85adfddf4841787bfa47c470e96dc26d" +dependencies = [ + "array-init", + "serde", + "smallvec 0.6.14", +] + [[package]] name = "serde_derive" version = "1.0.171" @@ -12291,6 +12928,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha-1" version = "0.9.8" @@ -12458,7 +13107,7 @@ dependencies = [ "polkadot-runtime", "polkadot-runtime-common", "scale-info", - "smallvec", + "smallvec 1.11.0", "sp-api", "sp-block-builder", "sp-consensus-aura", @@ -12554,7 +13203,7 @@ dependencies = [ "polkadot-runtime", "polkadot-runtime-common", "scale-info", - "smallvec", + "smallvec 1.11.0", "sp-api", "sp-block-builder", "sp-consensus-aura", @@ -12642,6 +13291,18 @@ dependencies = [ "similar", ] +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time 0.3.23", +] + [[package]] name = "siphasher" version = "0.3.10" @@ -12696,6 +13357,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "smallvec" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +dependencies = [ + "maybe-uninit", +] + [[package]] name = "smallvec" version = "1.11.0" @@ -12936,7 +13606,7 @@ dependencies = [ "sp-mmr-primitives", "sp-runtime", "sp-std", - "strum", + "strum 0.24.1", ] [[package]] @@ -12978,7 +13648,7 @@ dependencies = [ "bitflags 1.3.2", "blake2", "bounded-collections", - "bs58", + "bs58 0.4.0", "dyn-clonable", "ed25519-zebra", "futures 0.3.28", @@ -13117,7 +13787,7 @@ dependencies = [ "lazy_static", "sp-core", "sp-runtime", - "strum", + "strum 0.24.1", ] [[package]] @@ -13305,7 +13975,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", "rand 0.8.5", - "smallvec", + "smallvec 1.11.0", "sp-core", "sp-externalities", "sp-panic-handler", @@ -13476,7 +14146,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "smallvec", + "smallvec 1.11.0", "sp-arithmetic", "sp-core", "sp-debug-derive", @@ -13503,7 +14173,7 @@ checksum = "08615eea740067d9899969bc2891c68a19c315cb1f66640af9a9ecb91b13bcab" dependencies = [ "lazy_static", "maplit", - "strum", + "strum 0.24.1", ] [[package]] @@ -13618,7 +14288,16 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "strum_macros", + "strum_macros 0.24.3", +] + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros 0.25.2", ] [[package]] @@ -13634,6 +14313,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.25", +] + [[package]] name = "stun" version = "0.4.4" @@ -13757,10 +14449,10 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.43#5e dependencies = [ "ansi_term", "build-helper", - "cargo_metadata", + "cargo_metadata 0.15.4", "filetime", "sp-maybe-compressed-blob", - "strum", + "strum 0.24.1", "tempfile", "toml 0.7.6", "walkdir", @@ -13851,15 +14543,14 @@ checksum = "1b1c7f239eb94671427157bd93b3694320f3668d4e1eff08c7285366fd777fac" [[package]] name = "tempfile" -version = "3.6.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ - "autocfg", "cfg-if", - "fastrand", + "fastrand 2.0.0", "redox_syscall 0.3.5", - "rustix 0.37.23", + "rustix 0.38.3", "windows-sys 0.48.0", ] @@ -14050,20 +14741,19 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", "signal-hook-registry", - "socket2 0.4.9", + "socket2 0.5.3", "tokio-macros", "windows-sys 0.48.0", ] @@ -14108,7 +14798,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", "tokio", "tokio-util", ] @@ -14123,7 +14813,7 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", "tokio", "tracing", ] @@ -14195,7 +14885,7 @@ dependencies = [ "http", "http-body", "http-range-header", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", "tower-layer", "tower-service", ] @@ -14220,7 +14910,7 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "log", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.13", "tracing-attributes", "tracing-core", ] @@ -14315,7 +15005,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec", + "smallvec 1.11.0", "thread_local", "tracing", "tracing-core", @@ -14333,7 +15023,7 @@ dependencies = [ "hashbrown 0.13.2", "log", "rustc-hex", - "smallvec", + "smallvec 1.11.0", ] [[package]] @@ -14372,7 +15062,7 @@ dependencies = [ "ipnet", "lazy_static", "rand 0.8.5", - "smallvec", + "smallvec 1.11.0", "socket2 0.4.9", "thiserror", "tinyvec", @@ -14394,7 +15084,7 @@ dependencies = [ "lru-cache", "parking_lot 0.12.1", "resolv-conf", - "smallvec", + "smallvec 1.11.0", "thiserror", "tokio", "tracing", @@ -14599,6 +15289,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.10", + "serde", +] + [[package]] name = "uuid" version = "1.4.0" @@ -14776,8 +15476,8 @@ checksum = "87fef6d0d508f08334e0ab0e6877feb4c0ecb3956bcf2cb950699b22fedf3e9c" dependencies = [ "anyhow", "libc", - "strum", - "strum_macros", + "strum 0.24.1", + "strum_macros 0.24.3", "tempfile", "thiserror", "wasm-opt-cxx-sys", @@ -15254,7 +15954,7 @@ dependencies = [ "tokio", "turn", "url", - "uuid", + "uuid 1.4.0", "waitgroup", "webrtc-mdns", "webrtc-util", @@ -15416,7 +16116,7 @@ dependencies = [ "scale-info", "serde", "serde_derive", - "smallvec", + "smallvec 1.11.0", "sp-api", "sp-authority-discovery", "sp-block-builder", @@ -15449,7 +16149,7 @@ dependencies = [ "frame-support", "polkadot-primitives", "polkadot-runtime-common", - "smallvec", + "smallvec 1.11.0", "sp-core", "sp-runtime", "sp-weights", @@ -15716,6 +16416,25 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures 0.3.28", + "js-sys", + "log", + "pharos", + "rustc_version 0.4.0", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wyz" version = "0.5.1" @@ -15901,7 +16620,7 @@ dependencies = [ "polkadot-primitives", "polkadot-runtime-parachains", "scale-info", - "smallvec", + "smallvec 1.11.0", "sp-core", "sp-io", "sp-runtime", diff --git a/Cargo.toml b/Cargo.toml index e82204ef88..8a87a5eb36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,6 +88,7 @@ derive_more = { version = "0.99" } proc-macro2 = "1.0" quote = "1.0" syn = { version = "1.0" } +ethers = { version = "2.0.9", default_features = false } # Substrate # (wasm) @@ -277,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-account = { 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 83a739eb16..6e416cc987 100644 --- a/pallets/account/Cargo.toml +++ b/pallets/account/Cargo.toml @@ -10,6 +10,7 @@ repository.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +libsecp256k1 = { workspace = true, optional = true } log = { workspace = true } parity-scale-codec = { workspace = true } scale-info = { workspace = true } @@ -30,7 +31,8 @@ pallet-evm = { workspace = true } astar-primitives = { workspace = true } [dev-dependencies] -hex = { workspace = true} +ethers = { workspace = true } +hex = { workspace = true } pallet-balances = { workspace = true } pallet-ethereum = { workspace = true } pallet-evm = { workspace = true } @@ -41,6 +43,8 @@ default = ["std"] std = [ "hex/std", "log/std", + "libsecp256k1", + "libsecp256k1/std", "parity-scale-codec/std", "scale-info/std", "sp-std/std", @@ -57,6 +61,7 @@ std = [ "pallet-ethereum/std", ] runtime-benchmarks = [ + "libsecp256k1/hmac", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/pallets/account/src/impls.rs b/pallets/account/src/impls.rs new file mode 100644 index 0000000000..3efd6641f7 --- /dev/null +++ b/pallets/account/src/impls.rs @@ -0,0 +1,175 @@ +// 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 . + +#![cfg_attr(not(feature = "std"), no_std)] + +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::{keccak_256, Hasher, H160, H256, U256}; +use sp_runtime::traits::{LookupError, StaticLookup, Zero}; +use sp_runtime::MultiAddress; +use sp_std::marker::PhantomData; + +use crate::*; + +/// AddressManager implementation +impl AddressManager for Pallet { + fn to_account_id(address: &EvmAddress) -> Option { + NativeAccounts::::get(address) + } + + fn to_account_id_or_default(address: &EvmAddress) -> T::AccountId { + NativeAccounts::::get(address).unwrap_or_else(|| { + // fallback to default account_id + T::DefaultAddressMapping::into_account_id(address.clone()) + }) + } + + fn to_default_account_id(address: &EvmAddress) -> T::AccountId { + T::DefaultAddressMapping::into_account_id(address.clone()) + } + + fn to_address(account_id: &T::AccountId) -> Option { + EvmAccounts::::get(account_id) + } + + fn to_address_or_default(account_id: &T::AccountId) -> EvmAddress { + EvmAccounts::::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 { + T::DefaultAccountMapping::into_h160(account_id.clone()) + } +} + +/// AccountMapping wrapper implementation over AddressManager +impl AccountMapping for Pallet { + fn into_h160(account: T::AccountId) -> H160 { + >::to_address_or_default(&account) + } +} + +/// AddresstMapping wrapper implementation over AddressManager +impl AddressMapping for Pallet { + fn into_account_id(address: H160) -> T::AccountId { + >::to_account_id_or_default(&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) = EvmAccounts::::get(who) { + NativeAccounts::::remove(evm_addr); + EvmAccounts::::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 +/// +/// Raw Data = Domain Separator + Type Hash + keccak256(AccountId) +pub struct EIP712Signature(PhantomData); +impl ClaimSignature 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: 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(T::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()) + } +} + +/// 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/pallets/account/src/lib.rs b/pallets/account/src/lib.rs index 5157a16be8..c878269439 100644 --- a/pallets/account/src/lib.rs +++ b/pallets/account/src/lib.rs @@ -22,18 +22,12 @@ 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::{Currency, ExistenceRequirement::*, Get, IsType}, }; use frame_system::{ensure_signed, pallet_prelude::*}; use pallet_evm::AddressMapping; -use precompile_utils::keccak256; -use sp_core::{keccak_256, Hasher, H160, H256, U256}; -use sp_runtime::traits::{LookupError, StaticLookup, Zero}; -use sp_runtime::MultiAddress; use sp_std::marker::PhantomData; use pallet::*; @@ -41,6 +35,9 @@ use pallet::*; mod mock; mod tests; +mod impls; +pub use impls::*; + type SignatureOf = <::ClaimSignature as ClaimSignature>::Signature; /// Mapping between Native(AccountId) and EVM Address(H160) @@ -69,8 +66,8 @@ pub trait ClaimSignature { /// Signature type, ideally a 512-bit value for ECDSA signatures type Signature: Parameter; - /// Build raw payload (pre-hash) that user will sign. - fn build_signing_payload(who: &Self::AccountId) -> Vec; + /// Build raw payload that user will sign (keccack hashed). + fn build_signing_payload(who: &Self::AccountId) -> [u8; 32]; /// Verify the provided signature against the given account. fn verify_signature(who: &Self::AccountId, sig: &Self::Signature) -> Option; } @@ -245,141 +242,26 @@ impl Pallet { } } -impl AddressManager for Pallet { - fn to_account_id(address: &EvmAddress) -> Option { - NativeAccounts::::get(address) - } - - fn to_account_id_or_default(address: &EvmAddress) -> T::AccountId { - NativeAccounts::::get(address).unwrap_or_else(|| { - // fallback to default account_id - T::DefaultAddressMapping::into_account_id(address.clone()) - }) - } - - fn to_default_account_id(address: &EvmAddress) -> T::AccountId { - T::DefaultAddressMapping::into_account_id(address.clone()) - } - - fn to_address(account_id: &T::AccountId) -> Option { - EvmAccounts::::get(account_id) - } - - fn to_address_or_default(account_id: &T::AccountId) -> EvmAddress { - EvmAccounts::::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 { - T::DefaultAccountMapping::into_h160(account_id.clone()) - } -} - -impl AccountMapping for Pallet { - fn into_h160(account: T::AccountId) -> H160 { - >::to_address_or_default(&account) - } -} -impl AddressMapping for Pallet { - fn into_account_id(address: H160) -> T::AccountId { - >::to_account_id_or_default(&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) = EvmAccounts::::get(who) { - NativeAccounts::::remove(evm_addr); - EvmAccounts::::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 -/// -/// Raw Data = Domain Separator + Type Hash + keccak256(AccountId) -pub struct EIP712Signature(PhantomData); -impl ClaimSignature 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) -> Vec { - 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); - payload - } - - fn verify_signature(who: &Self::AccountId, sig: &Self::Signature) -> Option { - let payload = Self::build_signing_payload(who); - let payload_hash = keccak_256(&payload); - - sp_io::crypto::secp256k1_ecdsa_recover(sig, &payload_hash) - .map(|pubkey| H160::from(H256::from_slice(&keccak_256(&pubkey)))) - .ok() - } -} - -impl EIP712Signature { - /// TODO: 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(T::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()) +impl Pallet { + #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] + 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]; + r[0..64].copy_from_slice(&sig.serialize()[..]); + r[64] = recovery_id.serialize(); + r } - 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()) + #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] + pub fn eth_address(secret: &libsecp256k1::SecretKey) -> EvmAddress { + EvmAddress::from_slice( + &sp_core::keccak_256(&Self::eth_public(secret).serialize()[1..65])[12..], + ) } -} -/// 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]) + #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] + // 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) } } From 28a53aa3d4edeb8563833f1a0712bbaf8f115f49 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Thu, 31 Aug 2023 15:16:26 +0530 Subject: [PATCH 04/29] feat: setup mock and add tests for eip712 sig --- pallets/account/src/mock.rs | 66 +++++++++++------------------------- pallets/account/src/tests.rs | 46 ++++++++++++++++++++----- 2 files changed, 57 insertions(+), 55 deletions(-) diff --git a/pallets/account/src/mock.rs b/pallets/account/src/mock.rs index 8ee1370ff4..7caccfc3c6 100644 --- a/pallets/account/src/mock.rs +++ b/pallets/account/src/mock.rs @@ -20,7 +20,6 @@ use super::*; use crate as pallet_account; -use astar_primitives::ethereum_checked::AccountMapping; use frame_support::{ construct_runtime, parameter_types, sp_io::TestExternalities, @@ -28,11 +27,11 @@ use frame_support::{ weights::Weight, }; use pallet_ethereum::PostLogContent; -use pallet_evm::FeeCalculator; -use sp_io::hashing::blake2_256; +use pallet_evm::{FeeCalculator, HashedAddressMapping}; +use sp_core::{keccak_256, H160, H256, U256}; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{AccountIdLookup, BlakeTwo256}, AccountId32, ConsensusEngineId, }; @@ -52,7 +51,7 @@ impl frame_system::Config for TestRuntime { type Hash = H256; type Hashing = BlakeTwo256; type AccountId = AccountId; - type Lookup = IdentityLookup; + type Lookup = (AccountIdLookup, Accounts); type Header = Header; type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; @@ -61,7 +60,7 @@ impl frame_system::Config for TestRuntime { type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; type OnNewAccount = (); - type OnKilledAccount = (); + type OnKilledAccount = KillAccountMapping; type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); @@ -108,41 +107,6 @@ impl FindAuthor for MockFindAuthor { } } -pub struct MockAddressMapping; -impl AddressMapping for MockAddressMapping { - fn into_account_id(address: H160) -> AccountId32 { - if address == ALICE_H160 { - return ALICE; - } - if address == BOB_H160 { - return BOB; - } - if address == CHARLIE_H160 { - return CHARLIE; - } - - return pallet_evm::HashedAddressMapping::::into_account_id(address); - } -} - -pub struct MockAccountMapping; -impl AccountMapping for MockAccountMapping { - fn into_h160(account_id: AccountId) -> H160 { - if account_id == ALICE { - return ALICE_H160; - } - if account_id == BOB { - return BOB_H160; - } - if account_id == CHARLIE { - return CHARLIE_H160; - } - - let data = (b"evm:", account_id); - return H160::from_slice(&data.using_encoded(blake2_256)[0..20]); - } -} - parameter_types! { pub WeightPerGas: Weight = Weight::from_parts(1, 0); pub const BlockGasLimit: U256 = U256::MAX; @@ -155,7 +119,7 @@ impl pallet_evm::Config for TestRuntime { type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type CallOrigin = pallet_evm::EnsureAddressRoot; type WithdrawOrigin = pallet_evm::EnsureAddressTruncated; - type AddressMapping = MockAddressMapping; + type AddressMapping = Accounts; type Currency = Balances; type RuntimeEvent = RuntimeEvent; type Runner = pallet_evm::runner::stack::Runner; @@ -189,7 +153,7 @@ parameter_types! { impl pallet_account::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type DefaultAddressMapping = MockAddressMapping; + type DefaultAddressMapping = HashedAddressMapping; type DefaultAccountMapping = HashedAccountMapping; type ChainId = ConstU64<1024>; type ClaimSignature = EIP712Signature; @@ -203,6 +167,18 @@ pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); pub const CHARLIE: AccountId32 = AccountId32::new([2u8; 32]); +pub fn alice_secret() -> libsecp256k1::SecretKey { + libsecp256k1::SecretKey::parse(&keccak_256(b"Alice")).unwrap() +} + +// pub fn bob_secret() -> libsecp256k1::SecretKey { +// libsecp256k1::SecretKey::parse(&keccak_256(b"Bob")).unwrap() +// } + +// pub fn charlie_secret() -> libsecp256k1::SecretKey { +// libsecp256k1::SecretKey::parse(&keccak_256(b"Charlie")).unwrap() +// } + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -222,10 +198,6 @@ construct_runtime!( } ); -pub const ALICE_H160: H160 = H160::repeat_byte(1); -pub const BOB_H160: H160 = H160::repeat_byte(2); -pub const CHARLIE_H160: H160 = H160::repeat_byte(3); - pub struct ExtBuilder { balances: Vec<(AccountId, Balance)>, } diff --git a/pallets/account/src/tests.rs b/pallets/account/src/tests.rs index a4369e95bf..4020fab220 100644 --- a/pallets/account/src/tests.rs +++ b/pallets/account/src/tests.rs @@ -21,16 +21,46 @@ use super::*; use mock::*; +use ethers::{ + contract::{Eip712, EthAbiType}, + core::types::{transaction::eip712::Eip712, Bytes}, +}; +use parity_scale_codec::Encode; + #[test] -fn test() { +fn eip712_signature_verify_works() { + /// EIP712 Payload struct + #[derive(Eip712, EthAbiType, Clone)] + #[eip712( + name = "Astar EVM Claim", + version = "1", + chain_id = 1024, + // mock genisis hash + raw_salt = "0x4545454545454545454545454545454545454545454545454545454545454545" + )] + struct Claim { + substrate_address: Bytes, + } + ExtBuilder::default().build().execute_with(|| { - println!( - "0x{}", - hex::encode( - ::ClaimSignature::build_signing_payload( - &ALICE - ) - ) + let claim = Claim { + substrate_address: ALICE.encode().into(), + }; + + let claim_hash = EIP712Signature::::build_signing_payload(&ALICE); + // assert signing payload is correct + assert_eq!( + claim.encode_eip712().unwrap(), + claim_hash, + "signing payload should match" + ); + + // sign the payload + let sig = Accounts::eth_sign_prehash(&claim_hash, &alice_secret()); + assert_eq!( + Some(Accounts::eth_address(&alice_secret())), + EIP712Signature::::verify_signature(&ALICE, &sig), + "signature verification should work" ); }); } From 1a6b8b07ec7fc2f4cc6b0a3394fd728ad0442eef Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Thu, 31 Aug 2023 21:07:34 +0530 Subject: [PATCH 05/29] feat: add `pallet_account` to local runtime --- Cargo.lock | 49 ++++++++++++++++++------------------ pallets/account/Cargo.toml | 2 +- pallets/account/src/impls.rs | 3 ++- pallets/account/src/lib.rs | 2 +- runtime/local/Cargo.toml | 4 +++ runtime/local/src/lib.rs | 23 +++++++++-------- 6 files changed, 45 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c46eb51234..f4749c619b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5980,6 +5980,7 @@ dependencies = [ "moonbeam-evm-tracer", "moonbeam-rpc-primitives-debug", "moonbeam-rpc-primitives-txpool", + "pallet-account", "pallet-assets", "pallet-aura", "pallet-balances", @@ -7200,6 +7201,30 @@ dependencies = [ "libm 0.1.4", ] +[[package]] +name = "pallet-account" +version = "0.1.0" +dependencies = [ + "astar-primitives", + "ethers", + "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" @@ -8837,30 +8862,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet_account" -version = "0.1.0" -dependencies = [ - "astar-primitives", - "ethers", - "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 = "parachain-info" version = "0.1.0" diff --git a/pallets/account/Cargo.toml b/pallets/account/Cargo.toml index 6e416cc987..3ab9d5db57 100644 --- a/pallets/account/Cargo.toml +++ b/pallets/account/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pallet_account" +name = "pallet-account" version = "0.1.0" description = "Pallet for mapping VM accounts with native accounts" authors.workspace = true diff --git a/pallets/account/src/impls.rs b/pallets/account/src/impls.rs index 3efd6641f7..5a875e2505 100644 --- a/pallets/account/src/impls.rs +++ b/pallets/account/src/impls.rs @@ -25,7 +25,8 @@ use frame_support::traits::OnKilledAccount; use frame_support::{pallet_prelude::*, traits::Get}; use pallet_evm::AddressMapping; use precompile_utils::keccak256; -use sp_core::{keccak_256, Hasher, H160, H256, U256}; +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; diff --git a/pallets/account/src/lib.rs b/pallets/account/src/lib.rs index c878269439..b8aab9f3fc 100644 --- a/pallets/account/src/lib.rs +++ b/pallets/account/src/lib.rs @@ -30,7 +30,7 @@ use frame_system::{ensure_signed, pallet_prelude::*}; use pallet_evm::AddressMapping; use sp_std::marker::PhantomData; -use pallet::*; +pub use pallet::*; mod mock; mod tests; diff --git a/runtime/local/Cargo.toml b/runtime/local/Cargo.toml index e7733bebd4..2eb7ec6615 100644 --- a/runtime/local/Cargo.toml +++ b/runtime/local/Cargo.toml @@ -66,6 +66,7 @@ pallet-transaction-payment-rpc-runtime-api = { workspace = true } # Astar pallets astar-primitives = { workspace = true } +pallet-account = { workspace = true } pallet-block-reward = { workspace = true } pallet-chain-extension-dapps-staking = { workspace = true } pallet-chain-extension-xvm = { workspace = true } @@ -161,6 +162,7 @@ std = [ "pallet-scheduler/std", "pallet-treasury/std", "pallet-xvm/std", + "pallet-account/std", "pallet-ethereum-checked/std", "moonbeam-evm-tracer/std", "moonbeam-rpc-primitives-debug/std", @@ -183,6 +185,7 @@ runtime-benchmarks = [ "pallet-collective/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-ethereum-checked/runtime-benchmarks", + "pallet-account/runtime-benchmarks", "astar-primitives/runtime-benchmarks", "pallet-assets/runtime-benchmarks", ] @@ -207,6 +210,7 @@ try-runtime = [ "pallet-utility/try-runtime", "pallet-vesting/try-runtime", "pallet-xvm/try-runtime", + "pallet-account/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 40c1e7e9a3..96d12e605f 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; + type Lookup = (AccountIdLookup, Accounts); /// 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 = (); + type OnKilledAccount = pallet_account::KillAccountMapping; /// The data to be stored in an account. type AccountData = pallet_balances::AccountData; /// Weight information for the extrinsics of this pallet. @@ -446,13 +446,13 @@ impl pallet_utility::Config for Runtime { type WeightInfo = pallet_utility::weights::SubstrateWeight; } -///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. -pub struct HashedAccountMapping; -impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { - fn into_h160(account_id: AccountId) -> H160 { - let data = (b"evm:", account_id); - return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); - } +impl pallet_account::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type DefaultAddressMapping = pallet_evm::HashedAddressMapping; + type DefaultAccountMapping = pallet_account::HashedAccountMapping; + type ChainId = ChainId; + type ClaimSignature = pallet_account::EIP712Signature; } parameter_types! { @@ -466,14 +466,14 @@ impl pallet_ethereum_checked::Config for Runtime { type XvmTxWeightLimit = XvmTxWeightLimit; type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; - type AccountMapping = HashedAccountMapping; + type AccountMapping = Accounts; 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 = HashedAccountMapping; + type AccountMapping = Accounts; type EthereumTransact = EthereumChecked; type WeightInfo = pallet_xvm::weights::SubstrateWeight; } @@ -1023,6 +1023,7 @@ construct_runtime!( Proxy: pallet_proxy, Preimage: pallet_preimage, EthereumChecked: pallet_ethereum_checked, + Accounts: pallet_account, } ); From 570cd51dbe5fa87d2542d3ea32f54b1d0efbcd17 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Sat, 2 Sep 2023 02:25:30 +0530 Subject: [PATCH 06/29] fix: runtime-benchmarks build --- pallets/account/Cargo.toml | 1 - pallets/account/src/lib.rs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pallets/account/Cargo.toml b/pallets/account/Cargo.toml index 3ab9d5db57..30d29f6691 100644 --- a/pallets/account/Cargo.toml +++ b/pallets/account/Cargo.toml @@ -61,7 +61,6 @@ std = [ "pallet-ethereum/std", ] runtime-benchmarks = [ - "libsecp256k1/hmac", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/pallets/account/src/lib.rs b/pallets/account/src/lib.rs index b8aab9f3fc..5ab5f0fee1 100644 --- a/pallets/account/src/lib.rs +++ b/pallets/account/src/lib.rs @@ -243,7 +243,7 @@ impl Pallet { } impl Pallet { - #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] + #[cfg(feature = "std")] 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]; @@ -252,14 +252,14 @@ impl Pallet { r } - #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] + #[cfg(feature = "std")] pub fn eth_address(secret: &libsecp256k1::SecretKey) -> EvmAddress { EvmAddress::from_slice( &sp_core::keccak_256(&Self::eth_public(secret).serialize()[1..65])[12..], ) } - #[cfg(any(feature = "runtime-benchmarks", feature = "std"))] + #[cfg(feature = "std")] // 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) From d8826acab94f73e9bd4fbd0f475751f4e581a803 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Sat, 2 Sep 2023 02:43:08 +0530 Subject: [PATCH 07/29] feat: add claim js script --- rpc-tests/claim.mjs | 58 ++++ rpc-tests/package.json | 2 +- rpc-tests/yarn.lock | 664 +++++++++++++++++++++++++++++++---------- 3 files changed, 567 insertions(+), 157 deletions(-) create mode 100644 rpc-tests/claim.mjs diff --git a/rpc-tests/claim.mjs b/rpc-tests/claim.mjs new file mode 100644 index 0000000000..a2a5988220 --- /dev/null +++ b/rpc-tests/claim.mjs @@ -0,0 +1,58 @@ +/// TODO: make this into a rpc test + +import { JsonRpcProvider, Wallet } from "ethers" +import { WsProvider, ApiPromise, Keyring } from '@polkadot/api'; + +async function waitForTx(tx, signer, api) { + return new Promise((resolve, reject) => { + tx.signAndSend(signer, (result) => { + if (result.status.isInBlock) { + console.log(`\t Transaction included at blockHash ${result.status.asInBlock}`); + } else if (result.status.isFinalized) { + console.log(`\t Transaction finalized at blockHash ${result.status.asFinalized}`); + resolve(result.txHash) + } else if (result.isError) { + reject(); + } + }) + }) +} + +async function buildSignature(signer, substrateAddress, api) { + return await signer.signTypedData({ + chainId: api.consts.accounts.chainId.toNumber(), + name: "Astar EVM Claim", + version: "1", + salt: await api.query.system.blockHash(0) // genisis hash + }, { + Claim: [ + { name: 'substrateAddress', type: 'bytes' } + ], + }, { + substrateAddress + }) +} + +async function claimEvmAccount(account, evmAddress, signature, api) { + await waitForTx(api.tx.accounts.claimEvmAccount(evmAddress, signature), account) +} + +async function main() { + const api = await ApiPromise.create({ provider: new WsProvider('ws://127.0.0.1:9944') }); + await api.isReady; + + const keyring = new Keyring({ type: 'sr25519' }); + const alice = keyring.addFromUri('//Alice', { name: 'Alice default' }) + + const provider = new JsonRpcProvider("http://127.0.0.1:9944"); + const ethSigner = new Wallet("0x01ab6e801c06e59ca97a14fc0a1978b27fa366fc87450e0b65459dd3515b7391", provider); + + const sig = await buildSignature(ethSigner, alice.publicKey, api); + console.log(`Signature - ${sig}`) + const hash = await claimEvmAccount(alice, ethSigner.address, sig, api); + console.log(`Claim Extrisic - ${hash}`); + + api.disconnect(); +} + +await main() diff --git a/rpc-tests/package.json b/rpc-tests/package.json index 105a59aabb..636f5b90f8 100644 --- a/rpc-tests/package.json +++ b/rpc-tests/package.json @@ -8,7 +8,7 @@ "author": "AstarNetwork", "license": "ISC", "dependencies": { - "@polkadot/util-crypto": "^10.4.2", + "@polkadot/api": "^10.9.1", "solc": "^0.8.18", "web3": "^1.8.2", "ethers": "6" diff --git a/rpc-tests/yarn.lock b/rpc-tests/yarn.lock index d5b7eca9fa..a735b485da 100644 --- a/rpc-tests/yarn.lock +++ b/rpc-tests/yarn.lock @@ -2,12 +2,10 @@ # yarn lockfile v1 -"@babel/runtime@^7.20.13", "@babel/runtime@^7.20.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" - integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== - dependencies: - regenerator-runtime "^0.13.11" +"@adraffy/ens-normalize@1.9.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz#60111a5d9db45b2e5cbb6231b0bb8d97e8659316" + integrity sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg== "@ethereumjs/common@2.5.0": version "2.5.0" @@ -210,144 +208,352 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@noble/hashes@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" - integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== +"@noble/curves@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" + integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA== + dependencies: + "@noble/hashes" "1.3.1" + +"@noble/hashes@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" + integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== + +"@noble/hashes@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" + integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== "@noble/secp256k1@1.7.1": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== -"@polkadot/networks@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-10.4.2.tgz#d7878c6aad8173c800a21140bfe5459261724456" - integrity sha512-FAh/znrEvWBiA/LbcT5GXHsCFUl//y9KqxLghSr/CreAmAergiJNT0MVUezC7Y36nkATgmsr4ylFwIxhVtuuCw== - dependencies: - "@babel/runtime" "^7.20.13" - "@polkadot/util" "10.4.2" - "@substrate/ss58-registry" "^1.38.0" +"@polkadot/api-augment@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/api-augment/-/api-augment-10.9.1.tgz#9fc81b81903229bb23b0b16783e97ec52a5d4f1b" + integrity sha512-kRZZvCFVcN4hAH4dJ+Qzfdy27/4EEq3oLDf3ihj0LTVrAezSWcKPGE3EVFy+Mn6Lo4SUc7RVyoKvIUhSk2l4Dg== + dependencies: + "@polkadot/api-base" "10.9.1" + "@polkadot/rpc-augment" "10.9.1" + "@polkadot/types" "10.9.1" + "@polkadot/types-augment" "10.9.1" + "@polkadot/types-codec" "10.9.1" + "@polkadot/util" "^12.3.1" + tslib "^2.5.3" + +"@polkadot/api-base@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/api-base/-/api-base-10.9.1.tgz#27f63c4950814c2f10535f794121fa1384dc2207" + integrity sha512-Q3m2KzlceMK2kX8bhnUZWk3RT6emmijeeFZZQgCePpEcrSeNjnqG4qjuTPgkveaOkUT8MAoDc5Avuzcc2jlW9g== + dependencies: + "@polkadot/rpc-core" "10.9.1" + "@polkadot/types" "10.9.1" + "@polkadot/util" "^12.3.1" + rxjs "^7.8.1" + tslib "^2.5.3" + +"@polkadot/api-derive@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-10.9.1.tgz#04a4ca3285fd215c4cd50cfb3f4791d38dd90050" + integrity sha512-mRud1UZCFIc4Z63qAoGSIHh/foyUYADfy1RQYCmPpeFKfIdCIrHpd7xFdJXTOMYOS0BwlM6u4qli/ZT4XigezQ== + dependencies: + "@polkadot/api" "10.9.1" + "@polkadot/api-augment" "10.9.1" + "@polkadot/api-base" "10.9.1" + "@polkadot/rpc-core" "10.9.1" + "@polkadot/types" "10.9.1" + "@polkadot/types-codec" "10.9.1" + "@polkadot/util" "^12.3.1" + "@polkadot/util-crypto" "^12.3.1" + rxjs "^7.8.1" + tslib "^2.5.3" + +"@polkadot/api@10.9.1", "@polkadot/api@^10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-10.9.1.tgz#156b3436f45ef18218960804988c1f552d2c4e46" + integrity sha512-ND/2UqZBWvtt4PfV03OStTKg0mxmPk4UpMAgJKutdgsz/wP9CYJ1KbjwFgPNekL9JnzbKQsWyQNPVrcw7kQk8A== + dependencies: + "@polkadot/api-augment" "10.9.1" + "@polkadot/api-base" "10.9.1" + "@polkadot/api-derive" "10.9.1" + "@polkadot/keyring" "^12.3.1" + "@polkadot/rpc-augment" "10.9.1" + "@polkadot/rpc-core" "10.9.1" + "@polkadot/rpc-provider" "10.9.1" + "@polkadot/types" "10.9.1" + "@polkadot/types-augment" "10.9.1" + "@polkadot/types-codec" "10.9.1" + "@polkadot/types-create" "10.9.1" + "@polkadot/types-known" "10.9.1" + "@polkadot/util" "^12.3.1" + "@polkadot/util-crypto" "^12.3.1" + eventemitter3 "^5.0.1" + rxjs "^7.8.1" + tslib "^2.5.3" + +"@polkadot/keyring@^12.3.1": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-12.4.2.tgz#ff66c531ff29c1c9cb7c0f8411930bc18c76e2d3" + integrity sha512-VH91feSL6GiVVLcJ6V8h6jIAuq62bfvhM75AMcjTFol6MDqFl25jdjkHfZ2bQhig330LIhLw89nKdYr2/OfwjA== + dependencies: + "@polkadot/util" "12.4.2" + "@polkadot/util-crypto" "12.4.2" + tslib "^2.6.2" + +"@polkadot/networks@12.4.2", "@polkadot/networks@^12.3.1": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-12.4.2.tgz#6b3dcbdd016beb0ea585009fd61b048b99b17d1c" + integrity sha512-dd7vss+86kpOyy/C+DuCWChGfhwHBHtrzJ9ArbbpY75qc8SqdP90lj/c13ZCHr5I1l+coy31gyyMj5i6ja1Dpg== + dependencies: + "@polkadot/util" "12.4.2" + "@substrate/ss58-registry" "^1.43.0" + tslib "^2.6.2" + +"@polkadot/rpc-augment@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/rpc-augment/-/rpc-augment-10.9.1.tgz#214ec3ee145d20caa61ea204041a3aadb89c6b0f" + integrity sha512-MaLHkNlyqN20ZRYr6uNd1BZr1OsrnX9qLAmsl0mcrri1vPGRH6VHjfFH1RBLkikpWD82v17g0l2hLwdV1ZHMcw== + dependencies: + "@polkadot/rpc-core" "10.9.1" + "@polkadot/types" "10.9.1" + "@polkadot/types-codec" "10.9.1" + "@polkadot/util" "^12.3.1" + tslib "^2.5.3" + +"@polkadot/rpc-core@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-10.9.1.tgz#798c514dbed6f6c2e43098a494c9f51fb144dc31" + integrity sha512-ZtA8B8SfXSAwVkBlCcKRHw0eSM7ec/sbiNOM5GasXPeRujUgT7lOwSH2GbUZSqe9RfRDMp6DvO9c2JoGc3LLWw== + dependencies: + "@polkadot/rpc-augment" "10.9.1" + "@polkadot/rpc-provider" "10.9.1" + "@polkadot/types" "10.9.1" + "@polkadot/util" "^12.3.1" + rxjs "^7.8.1" + tslib "^2.5.3" + +"@polkadot/rpc-provider@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-10.9.1.tgz#de3a474bbcd26d28d9cd3134acdb3b5ce92b680b" + integrity sha512-4QzT2QzD+320+eT6b79sGAA85Tt3Bb8fQvse4r5Mom2iiBd2SO81vOhxSAOaIe4GUsw25VzFJmsbe7+OObItdg== + dependencies: + "@polkadot/keyring" "^12.3.1" + "@polkadot/types" "10.9.1" + "@polkadot/types-support" "10.9.1" + "@polkadot/util" "^12.3.1" + "@polkadot/util-crypto" "^12.3.1" + "@polkadot/x-fetch" "^12.3.1" + "@polkadot/x-global" "^12.3.1" + "@polkadot/x-ws" "^12.3.1" + eventemitter3 "^5.0.1" + mock-socket "^9.2.1" + nock "^13.3.1" + tslib "^2.5.3" + optionalDependencies: + "@substrate/connect" "0.7.26" + +"@polkadot/types-augment@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/types-augment/-/types-augment-10.9.1.tgz#5f1c1225c04ffbfe243629a46087c9c9de25a6b3" + integrity sha512-OY9/jTMFRFqYdkUnfcGwqMLC64A0Q25bjvCuVQCVjsPFKE3wl0Kt5rNT01eV2UmLXrR6fY0xWbR2w80bLA7CIQ== + dependencies: + "@polkadot/types" "10.9.1" + "@polkadot/types-codec" "10.9.1" + "@polkadot/util" "^12.3.1" + tslib "^2.5.3" + +"@polkadot/types-codec@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/types-codec/-/types-codec-10.9.1.tgz#f30026d3dfeaa69c07c45fa66d1c39318fd232cc" + integrity sha512-mJ5OegKGraY1FLvEa8FopRCr3pQrhDkcn5RNOjmgJQozENVeRaxhk0NwxYz7IojFvSDnKnc6lNQfKaaSe5pLHg== + dependencies: + "@polkadot/util" "^12.3.1" + "@polkadot/x-bigint" "^12.3.1" + tslib "^2.5.3" + +"@polkadot/types-create@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/types-create/-/types-create-10.9.1.tgz#087d7e2af51cce558b67e3859613b932a3bdc0a3" + integrity sha512-OVz50MGTTuiuVnRP/zAx4CTuLioc0hsiwNwqN2lNhmIJGtnQ4Vy/7mQRsIWehiYz6g0Vzzm5B3qWkTXO1NSN5w== + dependencies: + "@polkadot/types-codec" "10.9.1" + "@polkadot/util" "^12.3.1" + tslib "^2.5.3" + +"@polkadot/types-known@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-10.9.1.tgz#fe0c7e55191aa843119edcaf9abb5d2471463a7d" + integrity sha512-zCMVWc4pJtkbMFPu72bD4IhvV/gkHXPX3C5uu92WdmCfnn0vEIEsMKWlVXVVvQQZKAqvs/awpqIfrUtEViOGEA== + dependencies: + "@polkadot/networks" "^12.3.1" + "@polkadot/types" "10.9.1" + "@polkadot/types-codec" "10.9.1" + "@polkadot/types-create" "10.9.1" + "@polkadot/util" "^12.3.1" + tslib "^2.5.3" + +"@polkadot/types-support@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/types-support/-/types-support-10.9.1.tgz#17a861aab8e5a225a4e20cefa2d16076ddd51baf" + integrity sha512-XsieuLDsszvMZQlleacQBfx07i/JkwQV/UxH9q8Hz7Okmaz9pEVEW1h3ka2/cPuC7a4l32JhaORBUYshBZNdJg== + dependencies: + "@polkadot/util" "^12.3.1" + tslib "^2.5.3" + +"@polkadot/types@10.9.1": + version "10.9.1" + resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-10.9.1.tgz#f111d00f7278ad3be95deba3d701fafefe080cb2" + integrity sha512-AG33i2ZGGfq7u+5rkAdGrXAQHHl844/Yv+junH5ZzX69xiCoWO1bH/yzDUNBdpki2GlACWvF9nLYh3F2tVF93w== + dependencies: + "@polkadot/keyring" "^12.3.1" + "@polkadot/types-augment" "10.9.1" + "@polkadot/types-codec" "10.9.1" + "@polkadot/types-create" "10.9.1" + "@polkadot/util" "^12.3.1" + "@polkadot/util-crypto" "^12.3.1" + rxjs "^7.8.1" + tslib "^2.5.3" + +"@polkadot/util-crypto@12.4.2", "@polkadot/util-crypto@^12.3.1": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-12.4.2.tgz#e19258dab5f2d4fe49f2d074d36d33a445e50b74" + integrity sha512-JP7OrEKYx35P3wWc2Iu9F6BfYMIkywXik908zQqPxwoQhr8uDLP1Qoyu9Sws+hE97Yz1O4jBVvryS2le0yusog== + dependencies: + "@noble/curves" "1.1.0" + "@noble/hashes" "1.3.1" + "@polkadot/networks" "12.4.2" + "@polkadot/util" "12.4.2" + "@polkadot/wasm-crypto" "^7.2.2" + "@polkadot/wasm-util" "^7.2.2" + "@polkadot/x-bigint" "12.4.2" + "@polkadot/x-randomvalues" "12.4.2" + "@scure/base" "1.1.1" + tslib "^2.6.2" -"@polkadot/util-crypto@^10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-10.4.2.tgz#871fb69c65768bd48c57bb5c1f76a85d979fb8b5" - integrity sha512-RxZvF7C4+EF3fzQv8hZOLrYCBq5+wA+2LWv98nECkroChY3C2ZZvyWDqn8+aonNULt4dCVTWDZM0QIY6y4LUAQ== +"@polkadot/util@12.4.2", "@polkadot/util@^12.3.1": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-12.4.2.tgz#65759f4b366c2a787fd21abacab8cf8ab1aebbf9" + integrity sha512-NcTCbnIzMb/3TvJNEbaiu/9EvYIBuzDwZfqQ4hzL0GAptkF8aDkKMDCfQ/j3FI38rR+VTPQHNky9fvWglGKGRw== dependencies: - "@babel/runtime" "^7.20.13" - "@noble/hashes" "1.2.0" - "@noble/secp256k1" "1.7.1" - "@polkadot/networks" "10.4.2" - "@polkadot/util" "10.4.2" - "@polkadot/wasm-crypto" "^6.4.1" - "@polkadot/x-bigint" "10.4.2" - "@polkadot/x-randomvalues" "10.4.2" - "@scure/base" "1.1.1" - ed2curve "^0.3.0" - tweetnacl "^1.0.3" - -"@polkadot/util@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-10.4.2.tgz#df41805cb27f46b2b4dad24c371fa2a68761baa1" - integrity sha512-0r5MGICYiaCdWnx+7Axlpvzisy/bi1wZGXgCSw5+ZTyPTOqvsYRqM2X879yxvMsGfibxzWqNzaiVjToz1jvUaA== - dependencies: - "@babel/runtime" "^7.20.13" - "@polkadot/x-bigint" "10.4.2" - "@polkadot/x-global" "10.4.2" - "@polkadot/x-textdecoder" "10.4.2" - "@polkadot/x-textencoder" "10.4.2" + "@polkadot/x-bigint" "12.4.2" + "@polkadot/x-global" "12.4.2" + "@polkadot/x-textdecoder" "12.4.2" + "@polkadot/x-textencoder" "12.4.2" "@types/bn.js" "^5.1.1" bn.js "^5.2.1" - -"@polkadot/wasm-bridge@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-bridge/-/wasm-bridge-6.4.1.tgz#e97915dd67ba543ec3381299c2a5b9330686e27e" - integrity sha512-QZDvz6dsUlbYsaMV5biZgZWkYH9BC5AfhT0f0/knv8+LrbAoQdP3Asbvddw8vyU9sbpuCHXrd4bDLBwUCRfrBQ== - dependencies: - "@babel/runtime" "^7.20.6" - -"@polkadot/wasm-crypto-asmjs@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-6.4.1.tgz#3cc76bbda5ea4a7a860982c64f9565907b312253" - integrity sha512-UxZTwuBZlnODGIQdCsE2Sn/jU0O2xrNQ/TkhRFELfkZXEXTNu4lw6NpaKq7Iey4L+wKd8h4lT3VPVkMcPBLOvA== - dependencies: - "@babel/runtime" "^7.20.6" - -"@polkadot/wasm-crypto-init@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-init/-/wasm-crypto-init-6.4.1.tgz#4d9ab0030db52cf177bf707ef8e77aa4ca721668" - integrity sha512-1ALagSi/nfkyFaH6JDYfy/QbicVbSn99K8PV9rctDUfxc7P06R7CoqbjGQ4OMPX6w1WYVPU7B4jPHGLYBlVuMw== - dependencies: - "@babel/runtime" "^7.20.6" - "@polkadot/wasm-bridge" "6.4.1" - "@polkadot/wasm-crypto-asmjs" "6.4.1" - "@polkadot/wasm-crypto-wasm" "6.4.1" - -"@polkadot/wasm-crypto-wasm@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-6.4.1.tgz#97180f80583b18f6a13c1054fa5f7e8da40b1028" - integrity sha512-3VV9ZGzh0ZY3SmkkSw+0TRXxIpiO0nB8lFwlRgcwaCihwrvLfRnH9GI8WE12mKsHVjWTEVR3ogzILJxccAUjDA== - dependencies: - "@babel/runtime" "^7.20.6" - "@polkadot/wasm-util" "6.4.1" - -"@polkadot/wasm-crypto@^6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-6.4.1.tgz#79310e23ad1ca62362ba893db6a8567154c2536a" - integrity sha512-FH+dcDPdhSLJvwL0pMLtn/LIPd62QDPODZRCmDyw+pFjLOMaRBc7raomWUOqyRWJTnqVf/iscc2rLVLNMyt7ag== - dependencies: - "@babel/runtime" "^7.20.6" - "@polkadot/wasm-bridge" "6.4.1" - "@polkadot/wasm-crypto-asmjs" "6.4.1" - "@polkadot/wasm-crypto-init" "6.4.1" - "@polkadot/wasm-crypto-wasm" "6.4.1" - "@polkadot/wasm-util" "6.4.1" - -"@polkadot/wasm-util@6.4.1": - version "6.4.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-util/-/wasm-util-6.4.1.tgz#74aecc85bec427a9225d9874685944ea3dc3ab76" - integrity sha512-Uwo+WpEsDmFExWC5kTNvsVhvqXMZEKf4gUHXFn4c6Xz4lmieRT5g+1bO1KJ21pl4msuIgdV3Bksfs/oiqMFqlw== - dependencies: - "@babel/runtime" "^7.20.6" - -"@polkadot/x-bigint@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-bigint/-/x-bigint-10.4.2.tgz#7eb2ec732259df48b5a00f07879a1331e05606ec" - integrity sha512-awRiox+/XSReLzimAU94fPldowiwnnMUkQJe8AebYhNocAj6SJU00GNoj6j6tAho6yleOwrTJXZaWFBaQVJQNg== - dependencies: - "@babel/runtime" "^7.20.13" - "@polkadot/x-global" "10.4.2" - -"@polkadot/x-global@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-10.4.2.tgz#5662366e3deda0b4c8f024b2d902fa838f9e60a4" - integrity sha512-g6GXHD/ykZvHap3M6wh19dO70Zm43l4jEhlxf5LtTo5/0/UporFCXr2YJYZqfbn9JbQwl1AU+NroYio+vtJdiA== - dependencies: - "@babel/runtime" "^7.20.13" - -"@polkadot/x-randomvalues@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-10.4.2.tgz#895f1220d5a4522a83d8d5014e3c1e03b129893e" - integrity sha512-mf1Wbpe7pRZHO0V3V89isPLqZOy5XGX2bCqsfUWHgb1NvV1MMx5TjVjdaYyNlGTiOkAmJKlOHshcfPU2sYWpNg== - dependencies: - "@babel/runtime" "^7.20.13" - "@polkadot/x-global" "10.4.2" - -"@polkadot/x-textdecoder@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-10.4.2.tgz#93202f3e5ad0e7f75a3fa02d2b8a3343091b341b" - integrity sha512-d3ADduOKUTU+cliz839+KCFmi23pxTlabH7qh7Vs1GZQvXOELWdqFOqakdiAjtMn68n1KVF4O14Y+OUm7gp/zA== - dependencies: - "@babel/runtime" "^7.20.13" - "@polkadot/x-global" "10.4.2" - -"@polkadot/x-textencoder@10.4.2": - version "10.4.2" - resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-10.4.2.tgz#cd2e6c8a66b0b400a73f0164e99c510fb5c83501" - integrity sha512-mxcQuA1exnyv74Kasl5vxBq01QwckG088lYjc3KwmND6+pPrW2OWagbxFX5VFoDLDAE+UJtnUHsjdWyOTDhpQA== - dependencies: - "@babel/runtime" "^7.20.13" - "@polkadot/x-global" "10.4.2" + tslib "^2.6.2" + +"@polkadot/wasm-bridge@7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-bridge/-/wasm-bridge-7.2.2.tgz#957b82b17927fe080729e8930b5b5c554f77b8df" + integrity sha512-CgNENd65DVYtackOVXXRA0D1RPoCv5+77IdBCf7kNqu6LeAnR4nfTI6qjaApUdN1xRweUsQjSH7tu7VjkMOA0A== + dependencies: + "@polkadot/wasm-util" "7.2.2" + tslib "^2.6.1" + +"@polkadot/wasm-crypto-asmjs@7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-7.2.2.tgz#25243a4d5d8d997761141b616623cacff4329f13" + integrity sha512-wKg+cpsWQCTSVhjlHuNeB/184rxKqY3vaklacbLOMbUXieIfuDBav5PJdzS3yeiVE60TpYaHW4iX/5OYHS82gg== + dependencies: + tslib "^2.6.1" + +"@polkadot/wasm-crypto-init@7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-init/-/wasm-crypto-init-7.2.2.tgz#ffd105b87fc1b679c06c85c0848183c27bc539e3" + integrity sha512-vD4iPIp9x+SssUIWUenxWLPw4BVIwhXHNMpsV81egK990tvpyIxL205/EF5QRb1mKn8WfWcNFm5tYwwh9NdnnA== + dependencies: + "@polkadot/wasm-bridge" "7.2.2" + "@polkadot/wasm-crypto-asmjs" "7.2.2" + "@polkadot/wasm-crypto-wasm" "7.2.2" + "@polkadot/wasm-util" "7.2.2" + tslib "^2.6.1" + +"@polkadot/wasm-crypto-wasm@7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-7.2.2.tgz#9e49a1565bda2bc830708693b491b37ad8a2144d" + integrity sha512-3efoIB6jA3Hhv6k0YIBwCtlC8gCSWCk+R296yIXRLLr3cGN415KM/PO/d1JIXYI64lbrRzWRmZRhllw3jf6Atg== + dependencies: + "@polkadot/wasm-util" "7.2.2" + tslib "^2.6.1" + +"@polkadot/wasm-crypto@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-7.2.2.tgz#3c4b300c0997f4f7e2ddcdf8101d97fa1f5d1a7f" + integrity sha512-1ZY1rxUTawYm0m1zylvBMFovNIHYgG2v/XoASNp/EMG5c8FQIxCbhJRaTBA983GVq4lN/IAKREKEp9ZbLLqssA== + dependencies: + "@polkadot/wasm-bridge" "7.2.2" + "@polkadot/wasm-crypto-asmjs" "7.2.2" + "@polkadot/wasm-crypto-init" "7.2.2" + "@polkadot/wasm-crypto-wasm" "7.2.2" + "@polkadot/wasm-util" "7.2.2" + tslib "^2.6.1" + +"@polkadot/wasm-util@7.2.2", "@polkadot/wasm-util@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-util/-/wasm-util-7.2.2.tgz#f8aa62eba9a35466aa23f3c5634f3e8dbd398bbf" + integrity sha512-N/25960ifCc56sBlJZ2h5UBpEPvxBmMLgwYsl7CUuT+ea2LuJW9Xh8VHDN/guYXwmm92/KvuendYkEUykpm/JQ== + dependencies: + tslib "^2.6.1" + +"@polkadot/x-bigint@12.4.2", "@polkadot/x-bigint@^12.3.1": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/x-bigint/-/x-bigint-12.4.2.tgz#a63c9c926443231206726103d06c117ac2248de8" + integrity sha512-VRbkhdIf7CyWiUSyHemYi2fFWjBetUGyqpzsIHEclmzvqhKPfs7Kd2ZRdoXKU5QM56eD0sV2pyJxL34dv36/rw== + dependencies: + "@polkadot/x-global" "12.4.2" + tslib "^2.6.2" + +"@polkadot/x-fetch@^12.3.1": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-12.4.2.tgz#c5b70aacf7491ec9e51b0b14a7dbda44e9f3a11c" + integrity sha512-QEtYIUO6q6LupYkOl+vRwAkbBSSNHbALG8Y3+L/tFDubeXQl79vCkJFmsjhLewpsDIwTFTPNOwzA0ZEyb+0HZw== + dependencies: + "@polkadot/x-global" "12.4.2" + node-fetch "^3.3.2" + tslib "^2.6.2" + +"@polkadot/x-global@12.4.2", "@polkadot/x-global@^12.3.1": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-12.4.2.tgz#cc6ed596698678f98a53547b9adb712eadfd5175" + integrity sha512-CwbjSt1Grmn56xAj+hGC8ZB0uZxMl92K+VkBH0KxjgcbAX/D24ZD/0ds8pAnUYrO4aYHYq2j2MAGVSMdHcMBAQ== + dependencies: + tslib "^2.6.2" + +"@polkadot/x-randomvalues@12.4.2": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-12.4.2.tgz#399a7f831e465e6cd5aea64f8220693b07be86fa" + integrity sha512-HVlXRWY9RfN54RgfDroDy2itWmtTUtr119DfPl3wjnBf9i4wl/M+848OYlmCZCTpViTJrvWVSEJH9zVgchlNnw== + dependencies: + "@polkadot/x-global" "12.4.2" + tslib "^2.6.2" + +"@polkadot/x-textdecoder@12.4.2": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-12.4.2.tgz#fea941decbe32d24aa3f951a511bf576dc104826" + integrity sha512-cyUoKwdSIiBXAaWnGdMYqnaNHc5NV9skQh/fITis3ufKKi3pMwxJ5IwhhfDZpuKDl/3fDXF40Z3fqtTeUnoRXA== + dependencies: + "@polkadot/x-global" "12.4.2" + tslib "^2.6.2" + +"@polkadot/x-textencoder@12.4.2": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-12.4.2.tgz#a717fe2701ade5648600ff3a34d4d1224d916ee3" + integrity sha512-xrcwx55B2K7j9CnVucGLFl0qd5sb7W5Ei6dOsWgDnZNjZPBqsx9jTBQSBv9HmyHE4GEnF4z0rpO0msy3S7Sj9Q== + dependencies: + "@polkadot/x-global" "12.4.2" + tslib "^2.6.2" + +"@polkadot/x-ws@^12.3.1": + version "12.4.2" + resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-12.4.2.tgz#675e2d7effd6cafebc43783484a6ae55afb58f20" + integrity sha512-dYUtpbPa/JNd94tPAM9iHMzhR8MZ4wtOPh8gvueQRRYC8ZYQ9NPwjbBImY2FRfx7wCG1tFLAR6OEw4ToLLJNsA== + dependencies: + "@polkadot/x-global" "12.4.2" + tslib "^2.6.2" + ws "^8.13.0" "@scure/base@1.1.1": version "1.1.1" @@ -359,10 +565,24 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== -"@substrate/ss58-registry@^1.38.0": - version "1.39.0" - resolved "https://registry.yarnpkg.com/@substrate/ss58-registry/-/ss58-registry-1.39.0.tgz#eb916ff5fea7fa02e77745823fde21af979273d2" - integrity sha512-qZYpuE6n+mwew+X71dOur/CbMXj6rNW27o63JeJwdQH/GvcSKm3JLNhd+bGzwUKg0D/zD30Qc6p4JykArzM+tA== +"@substrate/connect-extension-protocol@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@substrate/connect-extension-protocol/-/connect-extension-protocol-1.0.1.tgz#fa5738039586c648013caa6a0c95c43265dbe77d" + integrity sha512-161JhCC1csjH3GE5mPLEd7HbWtwNSPJBg3p1Ksz9SFlTzj/bgEwudiRN2y5i0MoLGCIJRYKyKGMxVnd29PzNjg== + +"@substrate/connect@0.7.26": + version "0.7.26" + resolved "https://registry.yarnpkg.com/@substrate/connect/-/connect-0.7.26.tgz#a0ee5180c9cb2f29250d1219a32f7b7e7dea1196" + integrity sha512-uuGSiroGuKWj1+38n1kY5HReer5iL9bRwPCzuoLtqAOmI1fGI0hsSI2LlNQMAbfRgr7VRHXOk5MTuQf5ulsFRw== + dependencies: + "@substrate/connect-extension-protocol" "^1.0.1" + eventemitter3 "^4.0.7" + smoldot "1.0.4" + +"@substrate/ss58-registry@^1.43.0": + version "1.43.0" + resolved "https://registry.yarnpkg.com/@substrate/ss58-registry/-/ss58-registry-1.43.0.tgz#93108e45cb7ef6d82560c153e3692c2aa1c711b3" + integrity sha512-USEkXA46P9sqClL7PZv0QFsit4S8Im97wchKG0/H/9q3AT/S76r40UHfCr4Un7eBJPE23f7fU9BZ0ITpP9MCsA== "@szmarczak/http-timer@^4.0.5": version "4.0.6" @@ -419,6 +639,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/node@^12.12.6": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" @@ -458,6 +683,11 @@ accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + ajv@^6.12.3: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -828,6 +1058,11 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +data-uri-to-buffer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" + integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== + debug@2.6.9, debug@^2.2.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -835,6 +1070,13 @@ debug@2.6.9, debug@^2.2.0: dependencies: ms "2.0.0" +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + decode-uri-component@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" @@ -887,13 +1129,6 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" -ed2curve@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/ed2curve/-/ed2curve-0.3.0.tgz#322b575152a45305429d546b071823a93129a05d" - integrity sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ== - dependencies: - tweetnacl "1.x.x" - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -1033,6 +1268,19 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereum ethereum-cryptography "^0.1.3" rlp "^2.2.4" +ethers@6: + version "6.7.1" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.7.1.tgz#9c65e8b5d8e9ad77b7e8cf1c46099892cfafad49" + integrity sha512-qX5kxIFMfg1i+epfgb0xF4WM7IqapIIu50pOJ17aebkxxa4BacW5jFrQRmCJpDEg2ZK2oNtR5QjrQ1WDBF29dA== + dependencies: + "@adraffy/ens-normalize" "1.9.2" + "@noble/hashes" "1.1.2" + "@noble/secp256k1" "1.7.1" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -1046,6 +1294,16 @@ eventemitter3@4.0.4: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== +eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" @@ -1123,6 +1381,14 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + finalhandler@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" @@ -1167,6 +1433,13 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -1496,7 +1769,7 @@ json-schema@0.4.0: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== -json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== @@ -1534,6 +1807,11 @@ keyv@^4.0.0: dependencies: json-buffer "3.0.1" +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lowercase-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" @@ -1661,11 +1939,21 @@ mock-fs@^4.1.0: resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== +mock-socket@^9.2.1: + version "9.2.1" + resolved "https://registry.yarnpkg.com/mock-socket/-/mock-socket-9.2.1.tgz#cc9c0810aa4d0afe02d721dcb2b7e657c00e2282" + integrity sha512-aw9F9T9G2zpGipLLhSNh6ZpgUyUl4frcVmRN08uE1NWPWg43Wx6+sGPDbQ7E5iFZZDJW5b5bypMeAEHqTbIFag== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + ms@2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -1726,11 +2014,26 @@ next-tick@^1.1.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== +nock@^13.3.1: + version "13.3.3" + resolved "https://registry.yarnpkg.com/nock/-/nock-13.3.3.tgz#179759c07d3f88ad3e794ace885629c1adfd3fe7" + integrity sha512-z+KUlILy9SK/RjpeXDiDUEAq4T94ADPHE3qaRkf66mpEhzc/ytOMm3Bwdrbq6k1tMWkbdujiKim3G2tfQARuJw== + dependencies: + debug "^4.1.0" + json-stringify-safe "^5.0.1" + lodash "^4.17.21" + propagate "^2.0.0" + node-addon-api@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== +node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + node-fetch@2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -1738,6 +2041,15 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" +node-fetch@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b" + integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + node-gyp-build@^4.2.0: version "4.6.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" @@ -1812,6 +2124,11 @@ p-cancelable@^3.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== +pako@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" + integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== + parse-headers@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" @@ -1848,6 +2165,11 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== +propagate@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" + integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -1936,11 +2258,6 @@ readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - request@^2.79.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" @@ -1994,6 +2311,13 @@ rlp@^2.2.4: dependencies: bn.js "^5.2.0" +rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -2109,6 +2433,14 @@ simple-get@^2.7.0: once "^1.3.1" simple-concat "^1.0.0" +smoldot@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/smoldot/-/smoldot-1.0.4.tgz#e4c38cedad68d699a11b5b9ce72bb75c891bfd98" + integrity sha512-N3TazI1C4GGrseFH/piWyZCCCRJTRx2QhDfrUKRT4SzILlW5m8ayZ3QTKICcz1C/536T9cbHHJyP7afxI6Mi1A== + dependencies: + pako "^2.0.4" + ws "^8.8.1" + solc@^0.8.18: version "0.8.19" resolved "https://registry.yarnpkg.com/solc/-/solc-0.8.19.tgz#cac6541106ae3cff101c740042c7742aa56a2ed3" @@ -2221,6 +2553,16 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + +tslib@^2.1.0, tslib@^2.5.3, tslib@^2.6.1, tslib@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -2228,11 +2570,6 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -tweetnacl@1.x.x, tweetnacl@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" @@ -2352,6 +2689,11 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +web-streams-polyfill@^3.0.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" + integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== + web3-bzz@1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.8.2.tgz#67ea1c775874056250eece551ded22905ed08784" @@ -2623,6 +2965,11 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -2632,6 +2979,11 @@ ws@^3.0.0: safe-buffer "~5.1.0" ultron "~1.1.0" +ws@^8.13.0, ws@^8.8.1: + version "8.13.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== + xhr-request-promise@^0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" From cf86aba1448a0c59d39de60cf8abc8f5dfd8767e Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Fri, 8 Sep 2023 09:42:52 +0200 Subject: [PATCH 08/29] feat: add tests for lookup and on kill --- pallets/account/src/impls.rs | 18 ++++++------- pallets/account/src/lib.rs | 13 ++++++--- pallets/account/src/mock.rs | 19 ++++++++++--- pallets/account/src/tests.rs | 52 ++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 17 deletions(-) diff --git a/pallets/account/src/impls.rs b/pallets/account/src/impls.rs index 5a875e2505..11fc896080 100644 --- a/pallets/account/src/impls.rs +++ b/pallets/account/src/impls.rs @@ -73,6 +73,15 @@ impl AccountMapping for Pallet { } } +/// 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]) + } +} + /// AddresstMapping wrapper implementation over AddressManager impl AddressMapping for Pallet { fn into_account_id(address: H160) -> T::AccountId { @@ -165,12 +174,3 @@ impl EIP712Signature { keccak_256(args_hash.as_slice()) } } - -/// 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/pallets/account/src/lib.rs b/pallets/account/src/lib.rs index 5ab5f0fee1..3fa1f3d085 100644 --- a/pallets/account/src/lib.rs +++ b/pallets/account/src/lib.rs @@ -24,7 +24,11 @@ use astar_primitives::ethereum_checked::AccountMapping; use astar_primitives::evm::EvmAddress; use frame_support::{ pallet_prelude::*, - traits::{Currency, ExistenceRequirement::*, Get, IsType}, + traits::{ + fungible::{Inspect, Mutate}, + tokens::{Fortitude::*, Preservation::*}, + Get, IsType, + }, }; use frame_system::{ensure_signed, pallet_prelude::*}; use pallet_evm::AddressMapping; @@ -74,6 +78,7 @@ pub trait ClaimSignature { #[frame_support::pallet(dev_mode)] pub mod pallet { + use super::*; #[pallet::pallet] @@ -84,7 +89,7 @@ pub mod pallet { /// The overarching event type type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The Currency for managing Evm account assets - type Currency: Currency; + type Currency: Mutate; /// Default evm address to account id conversion type DefaultAddressMapping: AddressMapping; /// Default account id to evm address conversion @@ -222,8 +227,8 @@ impl Pallet { T::Currency::transfer( &default_account_id, &account_id, - T::Currency::free_balance(&default_account_id), - AllowDeath, + T::Currency::reducible_balance(&default_account_id, Expendable, Polite), + Expendable, )?; } diff --git a/pallets/account/src/mock.rs b/pallets/account/src/mock.rs index 7caccfc3c6..4d267128e8 100644 --- a/pallets/account/src/mock.rs +++ b/pallets/account/src/mock.rs @@ -171,9 +171,9 @@ pub fn alice_secret() -> libsecp256k1::SecretKey { libsecp256k1::SecretKey::parse(&keccak_256(b"Alice")).unwrap() } -// pub fn bob_secret() -> libsecp256k1::SecretKey { -// libsecp256k1::SecretKey::parse(&keccak_256(b"Bob")).unwrap() -// } +pub fn bob_secret() -> libsecp256k1::SecretKey { + libsecp256k1::SecretKey::parse(&keccak_256(b"Bob")).unwrap() +} // pub fn charlie_secret() -> libsecp256k1::SecretKey { // libsecp256k1::SecretKey::parse(&keccak_256(b"Charlie")).unwrap() @@ -226,7 +226,18 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); - let ext = TestExternalities::from(t); + let mut ext = TestExternalities::from(t); + 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 4020fab220..e2f56a779b 100644 --- a/pallets/account/src/tests.rs +++ b/pallets/account/src/tests.rs @@ -26,6 +26,7 @@ use ethers::{ core::types::{transaction::eip712::Eip712, Bytes}, }; use parity_scale_codec::Encode; +use sp_runtime::{traits::StaticLookup, MultiAddress}; #[test] fn eip712_signature_verify_works() { @@ -64,3 +65,54 @@ 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()); + let bob_default_account_id = + >::to_default_account_id(&bob_eth); + + // mapping should work if available + assert_eq!( + ::lookup(MultiAddress::Address20(alice_eth.into())).unwrap(), + ALICE + ); + + // should use default if not mapping + assert_eq!( + ::lookup(MultiAddress::Address20(bob_eth.into())).unwrap(), + bob_default_account_id + ); + }); +} + +#[test] +fn on_killed_account_hook() { + ExtBuilder::with_alice_mapping().execute_with(|| { + let alice_eth = Accounts::eth_address(&alice_secret()); + + // kill alice by transfering everything to bob + Balances::set_balance(&ALICE, 0); + + // check killed account events + assert!(System::events().iter().any(|r| matches!( + &r.event, + RuntimeEvent::System(frame_system::Event::KilledAccount { account }) if account == &ALICE + ))); + + // make sure mapping is removed + assert_eq!(EvmAccounts::::get(ALICE), None); + assert_eq!(NativeAccounts::::get(alice_eth), None); + }); +} + +#[test] +fn account_claim_correct_signature_should_work() {} + +#[test] +fn account_claim_wrong_signature_should_not_work() {} + +#[test] +fn account_default_claim_works() {} From 51e00b751db2ff703ec7c39d5bf9cac3fa8b24dc Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Mon, 11 Sep 2023 15:54:14 +0200 Subject: [PATCH 09/29] feat: add more tests --- pallets/account/src/impls.rs | 10 +-- pallets/account/src/mock.rs | 12 +-- pallets/account/src/tests.rs | 158 +++++++++++++++++++++++++++++++---- 3 files changed, 153 insertions(+), 27 deletions(-) diff --git a/pallets/account/src/impls.rs b/pallets/account/src/impls.rs index 11fc896080..edb9208ff3 100644 --- a/pallets/account/src/impls.rs +++ b/pallets/account/src/impls.rs @@ -126,8 +126,8 @@ impl StaticLookup for Pallet { /// EIP-712 compatible signature scheme for verifying ownership of EVM Address /// /// Raw Data = Domain Separator + Type Hash + keccak256(AccountId) -pub struct EIP712Signature(PhantomData); -impl ClaimSignature for EIP712Signature { +pub struct EIP712Signature>(PhantomData<(T, ChainId)>); +impl> ClaimSignature for EIP712Signature { type AccountId = T::AccountId; /// EVM address type type Address = EvmAddress; @@ -153,15 +153,15 @@ impl ClaimSignature for EIP712Signature { } } -impl EIP712Signature { - /// TODO: use hardcoded bytes, configurable via generics +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(T::ChainId::get())))); // chain id + 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 diff --git a/pallets/account/src/mock.rs b/pallets/account/src/mock.rs index 4d267128e8..4508c3cae9 100644 --- a/pallets/account/src/mock.rs +++ b/pallets/account/src/mock.rs @@ -110,6 +110,7 @@ impl FindAuthor for MockFindAuthor { parameter_types! { pub WeightPerGas: Weight = Weight::from_parts(1, 0); pub const BlockGasLimit: U256 = U256::MAX; + pub ChainId: u64 = 1024; } impl pallet_evm::Config for TestRuntime { @@ -125,7 +126,7 @@ impl pallet_evm::Config for TestRuntime { type Runner = pallet_evm::runner::stack::Runner; type PrecompilesType = (); type PrecompilesValue = (); - type ChainId = ConstU64<1024>; + type ChainId = ChainId; type OnChargeTransaction = (); type BlockGasLimit = BlockGasLimit; type OnCreate = (); @@ -155,8 +156,7 @@ impl pallet_account::Config for TestRuntime { type Currency = Balances; type DefaultAddressMapping = HashedAddressMapping; type DefaultAccountMapping = HashedAccountMapping; - type ChainId = ConstU64<1024>; - type ClaimSignature = EIP712Signature; + type ClaimSignature = EIP712Signature; } pub(crate) type AccountId = AccountId32; @@ -172,13 +172,9 @@ pub fn alice_secret() -> libsecp256k1::SecretKey { } pub fn bob_secret() -> libsecp256k1::SecretKey { - libsecp256k1::SecretKey::parse(&keccak_256(b"Bob")).unwrap() + libsecp256k1::SecretKey::parse(&keccak_256(b"Bob")).unwrap() } -// pub fn charlie_secret() -> libsecp256k1::SecretKey { -// libsecp256k1::SecretKey::parse(&keccak_256(b"Charlie")).unwrap() -// } - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; diff --git a/pallets/account/src/tests.rs b/pallets/account/src/tests.rs index e2f56a779b..3a303b8365 100644 --- a/pallets/account/src/tests.rs +++ b/pallets/account/src/tests.rs @@ -19,6 +19,7 @@ #![cfg(test)] use super::*; +use frame_support::{assert_noop, assert_ok}; use mock::*; use ethers::{ @@ -26,29 +27,41 @@ use ethers::{ core::types::{transaction::eip712::Eip712, Bytes}, }; use parity_scale_codec::Encode; -use sp_runtime::{traits::StaticLookup, MultiAddress}; +use sp_runtime::{traits::StaticLookup, AccountId32, MultiAddress}; -#[test] -fn eip712_signature_verify_works() { - /// EIP712 Payload struct - #[derive(Eip712, EthAbiType, Clone)] - #[eip712( +/// EIP712 Payload struct +#[derive(Eip712, EthAbiType, Clone)] +#[eip712( name = "Astar EVM Claim", version = "1", chain_id = 1024, // mock genisis hash raw_salt = "0x4545454545454545454545454545454545454545454545454545454545454545" )] - struct Claim { - substrate_address: Bytes, - } +struct Claim { + substrate_address: Bytes, +} + +fn claim_signature(who: &AccountId32, secret: &libsecp256k1::SecretKey) -> [u8; 65] { + // sign the payload + Accounts::eth_sign_prehash( + &Claim { + substrate_address: who.encode().into(), + } + .encode_eip712() + .unwrap(), + secret, + ) +} +#[test] +fn eip712_signature_verify_works() { ExtBuilder::default().build().execute_with(|| { let claim = Claim { substrate_address: ALICE.encode().into(), }; - let claim_hash = EIP712Signature::::build_signing_payload(&ALICE); + let claim_hash = EIP712Signature::::build_signing_payload(&ALICE); // assert signing payload is correct assert_eq!( claim.encode_eip712().unwrap(), @@ -60,7 +73,7 @@ fn eip712_signature_verify_works() { let sig = Accounts::eth_sign_prehash(&claim_hash, &alice_secret()); assert_eq!( Some(Accounts::eth_address(&alice_secret())), - EIP712Signature::::verify_signature(&ALICE, &sig), + EIP712Signature::::verify_signature(&ALICE, &sig), "signature verification should work" ); }); @@ -109,10 +122,127 @@ fn on_killed_account_hook() { } #[test] -fn account_claim_correct_signature_should_work() {} +fn account_claim_should_work() { + ExtBuilder::default().build().execute_with(|| { + let alice_eth = Accounts::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()); + + // transfer some funds to alice_eth (H160) + assert_ok!(Balances::transfer_allow_death( + RuntimeOrigin::signed(BOB), + alice_eth_old_account.clone().into(), + 1001 + )); + + // claim the account + assert_ok!(Accounts::claim_evm_account( + RuntimeOrigin::signed(ALICE), + alice_eth, + signature + )); + + // check if all of balances is transfered to new account (ALICE) from + // old account (alice_eth_old_account) + assert!(System::events().iter().any(|r| matches!( + &r.event, + RuntimeEvent::System(frame_system::Event::KilledAccount { account }) if account == &alice_eth_old_account + ))); + + // check for claim account event + System::assert_last_event( + RuntimeEvent::Accounts(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) + ); + }); +} #[test] -fn account_claim_wrong_signature_should_not_work() {} +fn account_claim_should_not_work() { + ExtBuilder::default().build().execute_with(|| { + // invald signature + assert_noop!( + Accounts::claim_evm_account( + RuntimeOrigin::signed(ALICE), + Accounts::eth_address(&bob_secret()), + claim_signature(&BOB, &bob_secret()) + ), + Error::::InvalidSignature + ); + assert_noop!( + Accounts::claim_evm_account( + RuntimeOrigin::signed(ALICE), + Accounts::eth_address(&bob_secret()), + claim_signature(&ALICE, &alice_secret()) + ), + Error::::InvalidSignature + ); + + assert_ok!(Accounts::claim_evm_account( + RuntimeOrigin::signed(ALICE), + Accounts::eth_address(&alice_secret()), + claim_signature(&ALICE, &alice_secret()) + )); + // AccountId already mapped + assert_noop!( + Accounts::claim_evm_account( + RuntimeOrigin::signed(ALICE), + Accounts::eth_address(&alice_secret()), + claim_signature(&ALICE, &alice_secret()) + ), + Error::::AccountIdHasMapped + ); + // eth address already mapped + assert_noop!( + Accounts::claim_evm_account( + RuntimeOrigin::signed(BOB), + Accounts::eth_address(&alice_secret()), + claim_signature(&ALICE, &alice_secret()) + ), + Error::::EthAddressHasMapped + ); + }); +} #[test] -fn account_default_claim_works() {} +fn account_default_claim_works() { + ExtBuilder::default().build().execute_with(|| { + let alice_default_evm = + ::DefaultAccountMapping::into_h160(ALICE.into()); + + // claim default account + assert_ok!(Accounts::claim_default_evm_account(RuntimeOrigin::signed( + ALICE + ))); + System::assert_last_event(RuntimeEvent::Accounts(crate::Event::AccountClaimed { + account_id: ALICE.clone(), + evm_address: alice_default_evm.clone(), + })); + + // check AddressManager mapping works + assert_eq!( + >::to_address(&ALICE), + Some(alice_default_evm) + ); + assert_eq!( + >::to_account_id(&alice_default_evm), + Some(ALICE) + ); + + // should not allow to claim afterwards + assert_noop!( + Accounts::claim_evm_account( + RuntimeOrigin::signed(ALICE), + Accounts::eth_address(&alice_secret()), + claim_signature(&ALICE, &alice_secret()) + ), + Error::::AccountIdHasMapped + ); + }); +} From 9cfb4293ba84cb0681760f3b0f6b3390def65ed8 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Mon, 11 Sep 2023 15:55:51 +0200 Subject: [PATCH 10/29] feat: add benchmarks --- Cargo.lock | 1 + pallets/account/Cargo.toml | 5 ++ pallets/account/src/benchmarking.rs | 78 +++++++++++++++++++++++++++++ pallets/account/src/lib.rs | 15 +++--- 4 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 pallets/account/src/benchmarking.rs diff --git a/Cargo.lock b/Cargo.lock index f4749c619b..81ddb96c67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7207,6 +7207,7 @@ version = "0.1.0" dependencies = [ "astar-primitives", "ethers", + "frame-benchmarking", "frame-support", "frame-system", "hex", diff --git a/pallets/account/Cargo.toml b/pallets/account/Cargo.toml index 30d29f6691..10ff752647 100644 --- a/pallets/account/Cargo.toml +++ b/pallets/account/Cargo.toml @@ -22,6 +22,9 @@ sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } +# Benchmarks +frame-benchmarking = { workspace = true, optional = true } + precompile-utils = { workspace = true } # frontier @@ -41,6 +44,7 @@ pallet-timestamp = { workspace = true } [features] default = ["std"] std = [ + "runtime-benchmarks", "hex/std", "log/std", "libsecp256k1", @@ -61,6 +65,7 @@ std = [ "pallet-ethereum/std", ] runtime-benchmarks = [ + "frame-benchmarking", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/pallets/account/src/benchmarking.rs b/pallets/account/src/benchmarking.rs new file mode 100644 index 0000000000..e75a75904e --- /dev/null +++ b/pallets/account/src/benchmarking.rs @@ -0,0 +1,78 @@ +// 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 . + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use frame_benchmarking::v2::*; +use frame_system::RawOrigin; + +/// Assert that the last event equals the provided one. +fn assert_last_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +#[benchmarks( + where <::ClaimSignature as ClaimSignature>::Signature: IsType<[u8;65]> +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn claim_evm_account() { + 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), + ð_secret_key, + ) + .into(); + + let caller_clone = caller.clone(); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), evm_address, signature); + + assert_last_event::( + Event::::AccountClaimed { + account_id: caller_clone, + evm_address, + } + .into(), + ); + } + + #[benchmark] + fn claim_default_evm_account() { + let caller: T::AccountId = whitelisted_caller(); + let caller_clone = caller.clone(); + let evm_address = T::DefaultAccountMapping::into_h160(caller.clone()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller)); + + assert_last_event::( + Event::::AccountClaimed { + account_id: caller_clone, + evm_address, + } + .into(), + ); + } +} diff --git a/pallets/account/src/lib.rs b/pallets/account/src/lib.rs index 3fa1f3d085..b9ce09ff90 100644 --- a/pallets/account/src/lib.rs +++ b/pallets/account/src/lib.rs @@ -27,7 +27,7 @@ use frame_support::{ traits::{ fungible::{Inspect, Mutate}, tokens::{Fortitude::*, Preservation::*}, - Get, IsType, + IsType, }, }; use frame_system::{ensure_signed, pallet_prelude::*}; @@ -36,6 +36,8 @@ use sp_std::marker::PhantomData; pub use pallet::*; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; mod mock; mod tests; @@ -97,12 +99,7 @@ pub mod pallet { /// 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; - /// Chain ID of EVM - /// TODO: remove this and make it generic parameter of EIP712Signature struct - #[pallet::constant] - type ChainId: Get; - // TODO: benchmarks // /// Weight information for the extrinsics in this module // type WeightInfo: WeightInfo; } @@ -248,7 +245,7 @@ impl Pallet { } impl Pallet { - #[cfg(feature = "std")] + #[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]; @@ -257,14 +254,14 @@ impl Pallet { r } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", feature = "runtime-benchmarks"))] pub fn eth_address(secret: &libsecp256k1::SecretKey) -> EvmAddress { EvmAddress::from_slice( &sp_core::keccak_256(&Self::eth_public(secret).serialize()[1..65])[12..], ) } - #[cfg(feature = "std")] + #[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) From cb5bef7ba9cefac48c4f44f0db5c499c566021c8 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Mon, 11 Sep 2023 16:49:01 +0200 Subject: [PATCH 11/29] fix: build issues --- Cargo.toml | 2 +- pallets/account/Cargo.toml | 4 ++-- pallets/account/src/impls.rs | 2 -- pallets/account/src/lib.rs | 2 +- runtime/local/src/lib.rs | 3 +-- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8a87a5eb36..8dd39e5b6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,7 +81,7 @@ rlp = "0.5" tracing = "0.1.34" similar-asserts = { version = "1.1.0" } assert_matches = "1.3.0" -libsecp256k1 = "0.7.0" +libsecp256k1 = { version = "0.7.0", default-features = false } impl-trait-for-tuples = "0.2.2" slices = "0.2.0" derive_more = { version = "0.99" } diff --git a/pallets/account/Cargo.toml b/pallets/account/Cargo.toml index 10ff752647..b89996c4f0 100644 --- a/pallets/account/Cargo.toml +++ b/pallets/account/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libsecp256k1 = { workspace = true, optional = true } +libsecp256k1 = { workspace = true, optional = true, features = ["hmac", "static-context"] } log = { workspace = true } parity-scale-codec = { workspace = true } scale-info = { workspace = true } @@ -44,7 +44,6 @@ pallet-timestamp = { workspace = true } [features] default = ["std"] std = [ - "runtime-benchmarks", "hex/std", "log/std", "libsecp256k1", @@ -65,6 +64,7 @@ std = [ "pallet-ethereum/std", ] runtime-benchmarks = [ + "libsecp256k1/hmac", "frame-benchmarking", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", diff --git a/pallets/account/src/impls.rs b/pallets/account/src/impls.rs index edb9208ff3..c9099451e5 100644 --- a/pallets/account/src/impls.rs +++ b/pallets/account/src/impls.rs @@ -16,8 +16,6 @@ // You should have received a copy of the GNU General Public License // along with Astar. If not, see . -#![cfg_attr(not(feature = "std"), no_std)] - use astar_primitives::ethereum_checked::AccountMapping; use astar_primitives::evm::EvmAddress; use astar_primitives::AccountId; diff --git a/pallets/account/src/lib.rs b/pallets/account/src/lib.rs index b9ce09ff90..8075d20d80 100644 --- a/pallets/account/src/lib.rs +++ b/pallets/account/src/lib.rs @@ -257,7 +257,7 @@ impl Pallet { #[cfg(any(feature = "std", feature = "runtime-benchmarks"))] pub fn eth_address(secret: &libsecp256k1::SecretKey) -> EvmAddress { EvmAddress::from_slice( - &sp_core::keccak_256(&Self::eth_public(secret).serialize()[1..65])[12..], + &sp_io::hashing::keccak_256(&Self::eth_public(secret).serialize()[1..65])[12..], ) } diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 96d12e605f..b486aad035 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -451,8 +451,7 @@ impl pallet_account::Config for Runtime { type Currency = Balances; type DefaultAddressMapping = pallet_evm::HashedAddressMapping; type DefaultAccountMapping = pallet_account::HashedAccountMapping; - type ChainId = ChainId; - type ClaimSignature = pallet_account::EIP712Signature; + type ClaimSignature = pallet_account::EIP712Signature; } parameter_types! { From dbffa3a1e5f9453bcf3efef7d93f4ddc87048fd4 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Wed, 13 Sep 2023 12:03:27 +0200 Subject: [PATCH 12/29] feat: add to shibuya --- Cargo.lock | 2 ++ pallets/account/src/lib.rs | 5 ++++- rpc-tests/claim.mjs | 20 +++++++++++++------- runtime/local/src/lib.rs | 2 +- runtime/shibuya/Cargo.toml | 4 ++++ runtime/shibuya/src/lib.rs | 27 ++++++++++++++------------- 6 files changed, 38 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81ddb96c67..a2e6ef26d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4925,6 +4925,7 @@ dependencies = [ "frame-support", "frame-system", "hex", + "pallet-account", "pallet-assets", "pallet-balances", "pallet-contracts", @@ -13051,6 +13052,7 @@ dependencies = [ "moonbeam-rpc-primitives-txpool", "orml-xcm-support", "orml-xtokens", + "pallet-account", "pallet-assets", "pallet-aura", "pallet-authorship", diff --git a/pallets/account/src/lib.rs b/pallets/account/src/lib.rs index 8075d20d80..85bd63bc69 100644 --- a/pallets/account/src/lib.rs +++ b/pallets/account/src/lib.rs @@ -80,7 +80,6 @@ pub trait ClaimSignature { #[frame_support::pallet(dev_mode)] pub mod pallet { - use super::*; #[pallet::pallet] @@ -213,6 +212,10 @@ impl Pallet { // recover evm address from signature let address = T::ClaimSignature::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 eth address diff --git a/rpc-tests/claim.mjs b/rpc-tests/claim.mjs index a2a5988220..9d56a75d13 100644 --- a/rpc-tests/claim.mjs +++ b/rpc-tests/claim.mjs @@ -1,4 +1,4 @@ -/// TODO: make this into a rpc test +/// TODO: make this into a rpc test when integrated in Shiden & Astar import { JsonRpcProvider, Wallet } from "ethers" import { WsProvider, ApiPromise, Keyring } from '@polkadot/api'; @@ -10,6 +10,9 @@ async function waitForTx(tx, signer, api) { console.log(`\t Transaction included at blockHash ${result.status.asInBlock}`); } else if (result.status.isFinalized) { console.log(`\t Transaction finalized at blockHash ${result.status.asFinalized}`); + result.events.forEach(({ phase, event: { data, method, section } }) => { + console.log(`\t' ${phase}: ${section}.${method}:: ${data}`); + }); resolve(result.txHash) } else if (result.isError) { reject(); @@ -18,9 +21,9 @@ async function waitForTx(tx, signer, api) { }) } -async function buildSignature(signer, substrateAddress, api) { +async function buildSignature(signer, substrateAddress, api, chainId) { return await signer.signTypedData({ - chainId: api.consts.accounts.chainId.toNumber(), + chainId, name: "Astar EVM Claim", version: "1", salt: await api.query.system.blockHash(0) // genisis hash @@ -34,24 +37,27 @@ async function buildSignature(signer, substrateAddress, api) { } async function claimEvmAccount(account, evmAddress, signature, api) { - await waitForTx(api.tx.accounts.claimEvmAccount(evmAddress, signature), account) + return await waitForTx(api.tx.accounts.claimEvmAccount(evmAddress, signature), account) } async function main() { - const api = await ApiPromise.create({ provider: new WsProvider('ws://127.0.0.1:9944') }); + const api = await ApiPromise.create({ provider: new WsProvider('ws://127.0.0.1:9945') }); await api.isReady; const keyring = new Keyring({ type: 'sr25519' }); const alice = keyring.addFromUri('//Alice', { name: 'Alice default' }) - const provider = new JsonRpcProvider("http://127.0.0.1:9944"); + const provider = new JsonRpcProvider("http://127.0.0.1:9945"); + const { chainId } = await provider.getNetwork(); const ethSigner = new Wallet("0x01ab6e801c06e59ca97a14fc0a1978b27fa366fc87450e0b65459dd3515b7391", provider); - const sig = await buildSignature(ethSigner, alice.publicKey, api); + const sig = await buildSignature(ethSigner, alice.publicKey, api, chainId); console.log(`Signature - ${sig}`) 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}`); + api.disconnect(); } diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index b486aad035..cfe6342464 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -449,7 +449,7 @@ impl pallet_utility::Config for Runtime { impl pallet_account::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type DefaultAddressMapping = pallet_evm::HashedAddressMapping; + type DefaultAddressMapping = ::AddressMapping; type DefaultAccountMapping = pallet_account::HashedAccountMapping; type ClaimSignature = pallet_account::EIP712Signature; } diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml index a62e030061..e997bab06e 100644 --- a/runtime/shibuya/Cargo.toml +++ b/runtime/shibuya/Cargo.toml @@ -96,6 +96,7 @@ orml-xtokens = { workspace = true } # Astar pallets astar-primitives = { workspace = true } +pallet-account = { workspace = true } pallet-block-reward = { workspace = true } pallet-chain-extension-dapps-staking = { workspace = true } pallet-chain-extension-xvm = { workspace = true } @@ -206,6 +207,7 @@ std = [ "pallet-xcm/std", "pallet-xc-asset-config/std", "pallet-xvm/std", + "pallet-account/std", "pallet-ethereum-checked/std", "pallet-scheduler/std", "parachain-info/std", @@ -253,6 +255,7 @@ runtime-benchmarks = [ "pallet-preimage/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-ethereum-checked/runtime-benchmarks", + "pallet-account/runtime-benchmarks", "pallet-xvm/runtime-benchmarks", "polkadot-runtime/runtime-benchmarks", "orml-xtokens/runtime-benchmarks", @@ -303,6 +306,7 @@ try-runtime = [ "pallet-preimage/try-runtime", "pallet-base-fee/try-runtime", "pallet-evm/try-runtime", + "pallet-account/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 5da4ebbc53..c93328816b 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; + type Lookup = (AccountIdLookup, Accounts); /// 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 = (); + type OnKilledAccount = pallet_account::KillAccountMapping; type DbWeight = RocksDbWeight; type BaseCallFilter = BaseFilter; type SystemWeightInfo = frame_system::weights::SubstrateWeight; @@ -765,15 +765,6 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; } -///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. -pub struct HashedAccountMapping; -impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { - fn into_h160(account_id: AccountId) -> H160 { - let data = (b"evm:", account_id); - return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); - } -} - parameter_types! { /// Equal to normal class dispatch weight limit. pub XvmTxWeightLimit: Weight = NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT; @@ -784,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 = HashedAccountMapping; + type AccountMapping = Accounts; 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 = HashedAccountMapping; + type AccountMapping = Accounts; type EthereumTransact = EthereumChecked; type WeightInfo = pallet_xvm::weights::SubstrateWeight; } @@ -1232,6 +1223,14 @@ impl pallet_xc_asset_config::Config for Runtime { type WeightInfo = pallet_xc_asset_config::weights::SubstrateWeight; } +impl pallet_account::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type DefaultAddressMapping = ::AddressMapping; + type DefaultAccountMapping = pallet_account::HashedAccountMapping; + type ClaimSignature = pallet_account::EIP712Signature; +} + construct_runtime!( pub struct Runtime where Block = Block, @@ -1276,6 +1275,7 @@ construct_runtime!( BaseFee: pallet_base_fee = 62, EVMChainId: pallet_evm_chain_id = 63, EthereumChecked: pallet_ethereum_checked = 64, + Accounts: pallet_account = 65, Contracts: pallet_contracts = 70, @@ -1420,6 +1420,7 @@ mod benches { [pallet_xcm, PolkadotXcm] [pallet_ethereum_checked, EthereumChecked] [pallet_xvm, Xvm] + [pallet_account, Accounts] ); } From 19dbd0aaf1045ebc8b50ba04cae8367c9b8fc3e1 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Wed, 13 Sep 2023 17:04:44 +0200 Subject: [PATCH 13/29] feat: update xvm integration tests --- runtime/local/src/lib.rs | 4 ++-- runtime/shibuya/src/lib.rs | 4 ++-- tests/integration/Cargo.toml | 1 + tests/integration/src/account.rs | 22 ++++++++++++++++++++++ tests/integration/src/lib.rs | 3 +++ tests/integration/src/setup.rs | 24 +++++++++++++----------- tests/integration/src/xvm.rs | 15 ++++++--------- 7 files changed, 49 insertions(+), 24 deletions(-) create mode 100644 tests/integration/src/account.rs diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index cfe6342464..f67b7bf5ce 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -449,7 +449,7 @@ impl pallet_utility::Config for Runtime { impl pallet_account::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type DefaultAddressMapping = ::AddressMapping; + type DefaultAddressMapping = pallet_evm::HashedAddressMapping; type DefaultAccountMapping = pallet_account::HashedAccountMapping; type ClaimSignature = pallet_account::EIP712Signature; } @@ -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 = pallet_evm::HashedAddressMapping; + type AddressMapping = Accounts; type Currency = Balances; type RuntimeEvent = RuntimeEvent; type Runner = pallet_evm::runner::stack::Runner; diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index c93328816b..9ffbb60329 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -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 = pallet_evm::HashedAddressMapping; + type AddressMapping = Accounts; type Currency = Balances; type RuntimeEvent = RuntimeEvent; type Runner = pallet_evm::runner::stack::Runner; @@ -1226,7 +1226,7 @@ impl pallet_xc_asset_config::Config for Runtime { impl pallet_account::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type DefaultAddressMapping = ::AddressMapping; + type DefaultAddressMapping = pallet_evm::HashedAddressMapping; type DefaultAccountMapping = pallet_account::HashedAccountMapping; type ClaimSignature = pallet_account::EIP712Signature; } diff --git a/tests/integration/Cargo.toml b/tests/integration/Cargo.toml index 834f6dd902..3bcb1c8831 100644 --- a/tests/integration/Cargo.toml +++ b/tests/integration/Cargo.toml @@ -30,6 +30,7 @@ sp-runtime = { workspace = true } # astar dependencies pallet-ethereum-checked = { workspace = true } +pallet-account = { workspace = true } pallet-evm-precompile-assets-erc20 = { workspace = true } astar-primitives = { workspace = true } diff --git a/tests/integration/src/account.rs b/tests/integration/src/account.rs new file mode 100644 index 0000000000..8f3024e59c --- /dev/null +++ b/tests/integration/src/account.rs @@ -0,0 +1,22 @@ +// 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 crate::setup::*; + +#[test] +fn account_transfer_to_h160_via_lookup() {} diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs index c36fc93edc..9b599b80f6 100644 --- a/tests/integration/src/lib.rs +++ b/tests/integration/src/lib.rs @@ -31,3 +31,6 @@ mod assets; #[cfg(feature = "shibuya")] mod xvm; + +#[cfg(feature = "shibuya")] +mod account; diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs index 594ca745b0..f188a505eb 100644 --- a/tests/integration/src/setup.rs +++ b/tests/integration/src/setup.rs @@ -23,6 +23,7 @@ pub use frame_support::{ traits::{OnFinalize, OnIdle, OnInitialize}, weights::Weight, }; +pub use pallet_account::AddressManager; pub use pallet_evm::AddressMapping; pub use sp_core::{H160, H256, U256}; pub use sp_runtime::{AccountId32, MultiAddress}; @@ -39,19 +40,11 @@ mod shibuya { /// 1 SBY. pub const UNIT: Balance = SBY; - // TODO: once Account Unification is finished, remove `alith` and `alicia`, - // which are mocks of two way account/address mapping. - - /// H160 address mapped from `ALICE`. + /// H160 address mapped to `ALICE`. pub fn alith() -> H160 { h160_from(ALICE) } - /// `AccountId32` mapped from `alith()`. - pub fn alicia() -> AccountId32 { - account_id_from(alith()) - } - /// Convert `H160` to `AccountId32`. pub fn account_id_from(address: H160) -> AccountId32 { ::AddressMapping::into_account_id(address) @@ -112,6 +105,16 @@ mod shibuya { assert_eq!(Balances::free_balance(&address), ExistentialDeposit::get(),); address } + + pub fn claim_default_accounts(account: AccountId) { + let default_h160 = Accounts::to_default_address(&account); + assert_ok!(Accounts::claim_default_evm_account(RuntimeOrigin::signed( + account.clone() + ))); + assert_eq!(Accounts::to_address(&account).unwrap(), default_h160); + // println!("{:?}", EVM::account_basic(&default_h160).0); + // println!("{} - {}", account_id_from(default_h160), ALICE); + } } #[cfg(feature = "shiden")] @@ -175,6 +178,7 @@ impl ExtBuilder { let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); + ext.execute_with(|| claim_default_accounts(ALICE)); ext } } @@ -185,8 +189,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { (ALICE, INITIAL_AMOUNT), (BOB, INITIAL_AMOUNT), (CAT, INITIAL_AMOUNT), - #[cfg(feature = "shibuya")] - (alicia(), INITIAL_AMOUNT), ]) .build() } diff --git a/tests/integration/src/xvm.rs b/tests/integration/src/xvm.rs index fb3ba9b72b..8e9c58fbab 100644 --- a/tests/integration/src/xvm.rs +++ b/tests/integration/src/xvm.rs @@ -299,11 +299,8 @@ fn calling_evm_payable_from_wasm_works() { let value = UNIT; - // TODO: after Account Unification finished, remove this mock account. - // It is needed now because currently the `AccountMapping` and `AddressMapping` are - // both one way mapping. - let mock_unified_wasm_account = account_id_from(h160_from(wasm_address.clone())); - let _ = Balances::deposit_creating(&mock_unified_wasm_account, value); + // claim the default mappings for wasm contract + claim_default_accounts(wasm_address.clone()); let evm_payable = evm_payable_addr.as_ref().to_vec(); let deposit_func = hex::decode("d0e30db0").expect("invalid deposit function hex"); @@ -328,10 +325,10 @@ fn calling_evm_payable_from_wasm_works() { value ); - // TODO: after Account Unification finished, enable the wasm address balance check - // and remove the mock account balance check. - // assert_eq!(Balances::free_balance(&wasm_address), ExistentialDeposit::get()); - assert_eq!(Balances::free_balance(&mock_unified_wasm_account), 0); + assert_eq!( + Balances::free_balance(&wasm_address), + ExistentialDeposit::get() + ); }); } From 10dfa241258ee0eeedd766b302ba062674cf0155 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Wed, 13 Sep 2023 17:35:55 +0200 Subject: [PATCH 14/29] feat: add intergration test for lookup --- tests/integration/src/account.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/integration/src/account.rs b/tests/integration/src/account.rs index 8f3024e59c..84e5f58844 100644 --- a/tests/integration/src/account.rs +++ b/tests/integration/src/account.rs @@ -16,7 +16,26 @@ // You should have received a copy of the GNU General Public License // along with Astar. If not, see . -// use crate::setup::*; +use crate::setup::*; +use std::str::FromStr; #[test] -fn account_transfer_to_h160_via_lookup() {} +fn transfer_to_h160_via_lookup() { + new_test_ext().execute_with(|| { + let eth_address = H160::from_str("0xaaafB3972B05630fCceE866eC69CdADd9baC2771").unwrap(); + + // make sure account is empty + assert!(EVM::is_account_empty(ð_address)); + + // tranfer to evm account + assert_ok!(Balances::transfer( + RuntimeOrigin::signed(ALICE), + MultiAddress::Address20(eth_address.clone().into()), + UNIT, + )); + + // evm account should have recieved the funds + let (account, _) = EVM::account_basic(ð_address); + assert_eq!(account.balance, (UNIT - ExistentialDeposit::get()).into()); + }); +} From b738fb0a28e640ad0782d49d5521a02b8df57939 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Wed, 13 Sep 2023 17:56:05 +0200 Subject: [PATCH 15/29] fix: formatting --- tests/integration/Cargo.toml | 2 +- tests/integration/src/setup.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/integration/Cargo.toml b/tests/integration/Cargo.toml index 3bcb1c8831..cd7e43b119 100644 --- a/tests/integration/Cargo.toml +++ b/tests/integration/Cargo.toml @@ -29,8 +29,8 @@ sp-io = { workspace = true } sp-runtime = { workspace = true } # astar dependencies -pallet-ethereum-checked = { workspace = true } pallet-account = { workspace = true } +pallet-ethereum-checked = { workspace = true } pallet-evm-precompile-assets-erc20 = { workspace = true } astar-primitives = { workspace = true } diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs index f188a505eb..b48604902d 100644 --- a/tests/integration/src/setup.rs +++ b/tests/integration/src/setup.rs @@ -112,8 +112,6 @@ mod shibuya { account.clone() ))); assert_eq!(Accounts::to_address(&account).unwrap(), default_h160); - // println!("{:?}", EVM::account_basic(&default_h160).0); - // println!("{} - {}", account_id_from(default_h160), ALICE); } } From 1de5d1623891aa6eaee5d05d1332cb4bc1d29e53 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Thu, 14 Sep 2023 15:12:56 +0200 Subject: [PATCH 16/29] fix: integration tests --- pallets/account/src/lib.rs | 36 ++++++++++++++++++++++++++++++++++ tests/integration/src/setup.rs | 1 + 2 files changed, 37 insertions(+) diff --git a/pallets/account/src/lib.rs b/pallets/account/src/lib.rs index 85bd63bc69..3109656fd3 100644 --- a/pallets/account/src/lib.rs +++ b/pallets/account/src/lib.rs @@ -17,6 +17,42 @@ // along with Astar. If not, see . //! # Pallet Account +//! +//! A simple module for managing mappings (both ways) between different +//! address schemes +//! +//! - [`Config`] +//! - [`Call`] +//! +//! ## 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 +//! - Connect default evm address +//! +//! ## Interface +//! +//! * `claim_evm_account`: 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 +//! no prior mapping exists. +//! +//! ## Traits +//! +//! * `AddressManager`: Interface to access pallet's mappings with defaults +//! * `ClaimSignature`: 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 +//! to account id. +//! * [`AccountMapping`](astar_primitives::ethereum_checked::AccountMapping): Wrapper over `AddressManager` +//! 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) #![cfg_attr(not(feature = "std"), no_std)] diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs index b48604902d..77807a3484 100644 --- a/tests/integration/src/setup.rs +++ b/tests/integration/src/setup.rs @@ -176,6 +176,7 @@ 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 } From 2dbc09bfec4d5c65339f7ff9c6158bdeb8df975c Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Thu, 21 Sep 2023 10:43:28 +0530 Subject: [PATCH 17/29] feat: apply code review suggestions --- Cargo.lock | 56 +++++------ Cargo.toml | 2 +- pallets/account/Cargo.toml | 2 +- pallets/account/src/benchmarking.rs | 8 +- pallets/account/src/impls.rs | 51 +++++----- pallets/account/src/lib.rs | 151 ++++++++++++++-------------- pallets/account/src/mock.rs | 22 ++-- pallets/account/src/tests.rs | 112 ++++++++++++--------- rpc-tests/claim.mjs | 2 +- runtime/local/Cargo.toml | 8 +- runtime/local/src/lib.rs | 18 ++-- runtime/shibuya/Cargo.toml | 8 +- runtime/shibuya/src/lib.rs | 20 ++-- tests/integration/Cargo.toml | 2 +- tests/integration/src/account.rs | 4 +- tests/integration/src/setup.rs | 10 +- tests/integration/src/xvm.rs | 15 +++ 17 files changed, 256 insertions(+), 235 deletions(-) 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); From f9014ed83250548677fc8541e590cc72f42589fe Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Thu, 21 Sep 2023 16:07:07 +0530 Subject: [PATCH 18/29] feat: update pallet directory name --- Cargo.toml | 2 +- .../{account => unified-accounts}/Cargo.toml | 0 .../src/benchmarking.rs | 0 .../src/impls.rs | 0 .../{account => unified-accounts}/src/lib.rs | 0 .../{account => unified-accounts}/src/mock.rs | 0 .../src/tests.rs | 22 +++++++++++-------- tests/integration/src/setup.rs | 8 +++---- 8 files changed, 18 insertions(+), 14 deletions(-) rename pallets/{account => unified-accounts}/Cargo.toml (100%) rename pallets/{account => unified-accounts}/src/benchmarking.rs (100%) rename pallets/{account => unified-accounts}/src/impls.rs (100%) rename pallets/{account => unified-accounts}/src/lib.rs (100%) rename pallets/{account => unified-accounts}/src/mock.rs (100%) rename pallets/{account => unified-accounts}/src/tests.rs (95%) diff --git a/Cargo.toml b/Cargo.toml index b13062e82f..645317cb4d 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-unified-accounts = { path = "./pallets/account", default-features = false } +pallet-unified-accounts = { path = "./pallets/unified-accounts", default-features = false } astar-primitives = { path = "./primitives", default-features = false } diff --git a/pallets/account/Cargo.toml b/pallets/unified-accounts/Cargo.toml similarity index 100% rename from pallets/account/Cargo.toml rename to pallets/unified-accounts/Cargo.toml diff --git a/pallets/account/src/benchmarking.rs b/pallets/unified-accounts/src/benchmarking.rs similarity index 100% rename from pallets/account/src/benchmarking.rs rename to pallets/unified-accounts/src/benchmarking.rs diff --git a/pallets/account/src/impls.rs b/pallets/unified-accounts/src/impls.rs similarity index 100% rename from pallets/account/src/impls.rs rename to pallets/unified-accounts/src/impls.rs diff --git a/pallets/account/src/lib.rs b/pallets/unified-accounts/src/lib.rs similarity index 100% rename from pallets/account/src/lib.rs rename to pallets/unified-accounts/src/lib.rs diff --git a/pallets/account/src/mock.rs b/pallets/unified-accounts/src/mock.rs similarity index 100% rename from pallets/account/src/mock.rs rename to pallets/unified-accounts/src/mock.rs diff --git a/pallets/account/src/tests.rs b/pallets/unified-accounts/src/tests.rs similarity index 95% rename from pallets/account/src/tests.rs rename to pallets/unified-accounts/src/tests.rs index 888afd2f3f..30f3c40eb2 100644 --- a/pallets/account/src/tests.rs +++ b/pallets/unified-accounts/src/tests.rs @@ -102,13 +102,15 @@ fn static_lookup_works() { // 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 ); }); @@ -235,13 +237,15 @@ fn account_default_claim_works() { ::DefaultAccountMapping::into_h160(ALICE.into()); // claim default account - assert_ok!(UnifiedAccounts::claim_default_evm_address(RuntimeOrigin::signed( - ALICE - ))); - System::assert_last_event(RuntimeEvent::UnifiedAccounts(crate::Event::AccountClaimed { - account_id: ALICE.clone(), - evm_address: alice_default_evm.clone(), - })); + assert_ok!(UnifiedAccounts::claim_default_evm_address( + RuntimeOrigin::signed(ALICE) + )); + System::assert_last_event(RuntimeEvent::UnifiedAccounts( + crate::Event::AccountClaimed { + account_id: ALICE.clone(), + evm_address: alice_default_evm.clone(), + }, + )); // check UnifiedAddressMapper's mapping works assert_eq!( diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs index 5f5f5c2758..97d0b74fc9 100644 --- a/tests/integration/src/setup.rs +++ b/tests/integration/src/setup.rs @@ -23,8 +23,8 @@ pub use frame_support::{ traits::{OnFinalize, OnIdle, OnInitialize}, weights::Weight, }; -pub use pallet_unified_accounts::UnifiedAddressMapper; pub use pallet_evm::AddressMapping; +pub use pallet_unified_accounts::UnifiedAddressMapper; pub use sp_core::{H160, H256, U256}; pub use sp_runtime::{AccountId32, MultiAddress}; @@ -108,9 +108,9 @@ mod shibuya { pub fn claim_default_accounts(account: AccountId) { let default_h160 = UnifiedAccounts::to_default_h160(&account); - assert_ok!(UnifiedAccounts::claim_default_evm_address(RuntimeOrigin::signed( - account.clone() - ))); + assert_ok!(UnifiedAccounts::claim_default_evm_address( + RuntimeOrigin::signed(account.clone()) + )); assert_eq!(UnifiedAccounts::to_h160(&account).unwrap(), default_h160); } } From 97bd0e13fbb0eda0997d412e1bf837a6543e170e Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Thu, 21 Sep 2023 20:16:25 +0530 Subject: [PATCH 19/29] feat: expand tests --- pallets/unified-accounts/src/tests.rs | 127 +++++++++++++++++--------- 1 file changed, 82 insertions(+), 45 deletions(-) diff --git a/pallets/unified-accounts/src/tests.rs b/pallets/unified-accounts/src/tests.rs index 30f3c40eb2..d6e3fd6203 100644 --- a/pallets/unified-accounts/src/tests.rs +++ b/pallets/unified-accounts/src/tests.rs @@ -184,83 +184,120 @@ fn account_claim_should_work() { } #[test] -fn account_claim_should_not_work() { +fn account_default_claim_works() { ExtBuilder::default().build().execute_with(|| { - // invald signature - assert_noop!( - UnifiedAccounts::claim_evm_address( - RuntimeOrigin::signed(ALICE), - UnifiedAccounts::eth_address(&bob_secret()), - get_evm_signature(&BOB, &bob_secret()) - ), - Error::::InvalidSignature + let alice_default_evm = + ::DefaultAccountMapping::into_h160(ALICE.into()); + + // claim default account + assert_ok!(UnifiedAccounts::claim_default_evm_address( + RuntimeOrigin::signed(ALICE) + )); + System::assert_last_event(RuntimeEvent::UnifiedAccounts( + crate::Event::AccountClaimed { + account_id: ALICE.clone(), + evm_address: alice_default_evm.clone(), + }, + )); + + // check UnifiedAddressMapper's mapping works + assert_eq!( + >::to_h160(&ALICE), + Some(alice_default_evm) ); + assert_eq!( + >::to_account_id(&alice_default_evm), + Some(ALICE) + ); + + // should not allow to claim afterwards assert_noop!( UnifiedAccounts::claim_evm_address( RuntimeOrigin::signed(ALICE), - UnifiedAccounts::eth_address(&bob_secret()), + UnifiedAccounts::eth_address(&alice_secret()), get_evm_signature(&ALICE, &alice_secret()) ), - Error::::InvalidSignature + Error::::AlreadyMapped ); + }); +} +#[test] +fn replay_attack_should_not_be_possible() { + ExtBuilder::default().build().execute_with(|| { + let alice_eth = UnifiedAccounts::eth_address(&alice_secret()); + let alice_signature = get_evm_signature(&ALICE, &alice_secret()); + + // alice claim her eth address first assert_ok!(UnifiedAccounts::claim_evm_address( RuntimeOrigin::signed(ALICE), - UnifiedAccounts::eth_address(&alice_secret()), - get_evm_signature(&ALICE, &alice_secret()) + alice_eth, + alice_signature )); - // AccountId already mapped + + // bob intercepted alice signature and tries to perform + // replay attack to claim alice eth address as his own, + // this should fail. assert_noop!( UnifiedAccounts::claim_evm_address( - RuntimeOrigin::signed(ALICE), - UnifiedAccounts::eth_address(&alice_secret()), - get_evm_signature(&ALICE, &alice_secret()) + RuntimeOrigin::signed(BOB), + alice_eth, + alice_signature ), Error::::AlreadyMapped ); - // eth address already mapped + }); +} + +#[test] +fn frontrun_attack_should_not_be_possible() { + ExtBuilder::default().build().execute_with(|| { + let alice_eth = UnifiedAccounts::eth_address(&alice_secret()); + let alice_signature = get_evm_signature(&ALICE, &alice_secret()); + + // bob intercepted alice signature and tries to perform + // frontrun attack to claim alice eth address as his own + // this should fail with InvalidSignature. assert_noop!( UnifiedAccounts::claim_evm_address( RuntimeOrigin::signed(BOB), - UnifiedAccounts::eth_address(&alice_secret()), - get_evm_signature(&ALICE, &alice_secret()) + alice_eth, + alice_signature ), - Error::::AlreadyMapped + Error::::InvalidSignature ); + + // alice can claim her eth address + assert_ok!(UnifiedAccounts::claim_evm_address( + RuntimeOrigin::signed(ALICE), + alice_eth, + alice_signature + )); }); } #[test] -fn account_default_claim_works() { +fn connecting_mapped_accounts_should_not_work() { ExtBuilder::default().build().execute_with(|| { - let alice_default_evm = - ::DefaultAccountMapping::into_h160(ALICE.into()); - - // claim default account - assert_ok!(UnifiedAccounts::claim_default_evm_address( - RuntimeOrigin::signed(ALICE) - )); - System::assert_last_event(RuntimeEvent::UnifiedAccounts( - crate::Event::AccountClaimed { - account_id: ALICE.clone(), - evm_address: alice_default_evm.clone(), - }, - )); + // connect ALICE accounts + connect_accounts(&ALICE, &alice_secret()); - // check UnifiedAddressMapper's mapping works - assert_eq!( - >::to_h160(&ALICE), - Some(alice_default_evm) - ); - assert_eq!( - >::to_account_id(&alice_default_evm), - Some(ALICE) + // AccountId already mapped + // ALICE attempts to connect another evm address + assert_noop!( + UnifiedAccounts::claim_evm_address( + RuntimeOrigin::signed(ALICE), + UnifiedAccounts::eth_address(&bob_secret()), + get_evm_signature(&BOB, &bob_secret()) + ), + Error::::AlreadyMapped ); - // should not allow to claim afterwards + // eth address already mapped + // BOB attempts to connect alice_eth that is already mapped assert_noop!( UnifiedAccounts::claim_evm_address( - RuntimeOrigin::signed(ALICE), + RuntimeOrigin::signed(BOB), UnifiedAccounts::eth_address(&alice_secret()), get_evm_signature(&ALICE, &alice_secret()) ), From 27ecc4c3e8d1a6404baabb8a4b73df5cdf235661 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Mon, 25 Sep 2023 14:18:10 +0530 Subject: [PATCH 20/29] fix: benchmarks and weights --- pallets/unified-accounts/src/benchmarking.rs | 2 +- pallets/unified-accounts/src/weights.rs | 127 +++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 pallets/unified-accounts/src/weights.rs diff --git a/pallets/unified-accounts/src/benchmarking.rs b/pallets/unified-accounts/src/benchmarking.rs index fed54a699e..e69aa8fa77 100644 --- a/pallets/unified-accounts/src/benchmarking.rs +++ b/pallets/unified-accounts/src/benchmarking.rs @@ -36,7 +36,7 @@ mod benchmarks { #[benchmark] fn claim_evm_address() { let caller: T::AccountId = whitelisted_caller(); - let eth_secret_key = libsecp256k1::SecretKey::parse(&[0xff; 32]).unwrap(); + let eth_secret_key = libsecp256k1::SecretKey::parse(&keccak_256(b"Alice")).unwrap(); let evm_address = Pallet::::eth_address(ð_secret_key); let signature = Pallet::::eth_sign_prehash( &T::SignatureHelper::build_signing_payload(&caller), diff --git a/pallets/unified-accounts/src/weights.rs b/pallets/unified-accounts/src/weights.rs new file mode 100644 index 0000000000..c0967f5b8a --- /dev/null +++ b/pallets/unified-accounts/src/weights.rs @@ -0,0 +1,127 @@ + +// 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 . + +//! Autogenerated weights for pallet_unified_accounts +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Ashutoshs-MacBook-Pro.local`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("shibuya-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/astar-collator +// benchmark +// pallet +// --chain=shibuya-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_unified_accounts +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./pallets/unified-accounts/src/weights.rs +// --template=./scripts/templates/weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for pallet_unified_accounts. +pub trait WeightInfo { + fn claim_evm_address() -> Weight; + fn claim_default_evm_address() -> Weight; +} + +/// Weights for pallet_unified_accounts using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: UnifiedAccounts EvmToNative (r:1 w:1) + /// Proof Skipped: UnifiedAccounts EvmToNative (max_values: None, max_size: None, mode: Measured) + /// Storage: UnifiedAccounts NativeToEvm (r:1 w:1) + /// Proof Skipped: UnifiedAccounts NativeToEvm (max_values: None, max_size: None, mode: Measured) + /// Storage: EVMChainId ChainId (r:1 w:0) + /// Proof: EVMChainId ChainId (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: System BlockHash (r:1 w:0) + /// Proof: System BlockHash (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn claim_evm_address() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `3721` + // Minimum execution time: 58_000_000 picoseconds. + Weight::from_parts(59_000_000, 3721) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: UnifiedAccounts EvmToNative (r:1 w:1) + /// Proof Skipped: UnifiedAccounts EvmToNative (max_values: None, max_size: None, mode: Measured) + /// Storage: UnifiedAccounts NativeToEvm (r:0 w:1) + /// Proof Skipped: UnifiedAccounts NativeToEvm (max_values: None, max_size: None, mode: Measured) + fn claim_default_evm_address() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3507` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3507) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: UnifiedAccounts EvmToNative (r:1 w:1) + /// Proof Skipped: UnifiedAccounts EvmToNative (max_values: None, max_size: None, mode: Measured) + /// Storage: UnifiedAccounts NativeToEvm (r:1 w:1) + /// Proof Skipped: UnifiedAccounts NativeToEvm (max_values: None, max_size: None, mode: Measured) + /// Storage: EVMChainId ChainId (r:1 w:0) + /// Proof: EVMChainId ChainId (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: System BlockHash (r:1 w:0) + /// Proof: System BlockHash (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn claim_evm_address() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `3721` + // Minimum execution time: 58_000_000 picoseconds. + Weight::from_parts(59_000_000, 3721) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: UnifiedAccounts EvmToNative (r:1 w:1) + /// Proof Skipped: UnifiedAccounts EvmToNative (max_values: None, max_size: None, mode: Measured) + /// Storage: UnifiedAccounts NativeToEvm (r:0 w:1) + /// Proof Skipped: UnifiedAccounts NativeToEvm (max_values: None, max_size: None, mode: Measured) + fn claim_default_evm_address() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `3507` + // Minimum execution time: 14_000_000 picoseconds. + Weight::from_parts(15_000_000, 3507) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } +} From 434e94057e6053e11967b939511a6d35f77e6cac Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Mon, 25 Sep 2023 14:18:57 +0530 Subject: [PATCH 21/29] feat: use claim account in integration tests --- tests/integration/Cargo.toml | 3 ++- tests/integration/src/setup.rs | 36 ++++++++++++++++++++++++++-------- tests/integration/src/xvm.rs | 10 +++++----- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/tests/integration/Cargo.toml b/tests/integration/Cargo.toml index 54ac446226..80470fee3e 100644 --- a/tests/integration/Cargo.toml +++ b/tests/integration/Cargo.toml @@ -9,6 +9,7 @@ repository.workspace = true [dependencies] hex = { workspace = true } +libsecp256k1 = { workspace = true, features = ["hmac", "static-context"] } parity-scale-codec = { workspace = true } # frontier @@ -29,9 +30,9 @@ sp-io = { workspace = true } sp-runtime = { workspace = true } # astar dependencies -pallet-unified-accounts = { workspace = true } pallet-ethereum-checked = { workspace = true } pallet-evm-precompile-assets-erc20 = { workspace = true } +pallet-unified-accounts = { workspace = true } astar-primitives = { workspace = true } astar-runtime = { workspace = true, features = ["std"], optional = true } diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs index 97d0b74fc9..026bf57fd0 100644 --- a/tests/integration/src/setup.rs +++ b/tests/integration/src/setup.rs @@ -24,25 +24,30 @@ pub use frame_support::{ weights::Weight, }; pub use pallet_evm::AddressMapping; -pub use pallet_unified_accounts::UnifiedAddressMapper; pub use sp_core::{H160, H256, U256}; +pub use sp_io::hashing::keccak_256; pub use sp_runtime::{AccountId32, MultiAddress}; -pub use astar_primitives::ethereum_checked::AccountMapping; +pub use astar_primitives::{ethereum_checked::AccountMapping, evm::UnifiedAddressMapper}; #[cfg(feature = "shibuya")] pub use shibuya::*; #[cfg(feature = "shibuya")] mod shibuya { use super::*; + pub use pallet_unified_accounts::SignatureHelper; pub use shibuya_runtime::*; /// 1 SBY. pub const UNIT: Balance = SBY; + pub fn alith_secret_key() -> libsecp256k1::SecretKey { + libsecp256k1::SecretKey::parse(&keccak_256(b"Alith")).unwrap() + } + /// H160 address mapped to `ALICE`. pub fn alith() -> H160 { - h160_from(ALICE) + UnifiedAccounts::eth_address(&alith_secret_key()) } /// Convert `H160` to `AccountId32`. @@ -50,11 +55,6 @@ mod shibuya { ::AddressMapping::into_account_id(address) } - /// Convert `AccountId32` to `H160`. - pub fn h160_from(account_id: AccountId32) -> H160 { - ::AccountMapping::into_h160(account_id) - } - /// Deploy an EVM contract with code. pub fn deploy_evm_contract(code: &str) -> H160 { assert_ok!(EVM::create2( @@ -106,6 +106,26 @@ mod shibuya { address } + /// 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 + UnifiedAccounts::eth_sign_prehash( + &::SignatureHelper::build_signing_payload( + who, + ), + secret, + ) + } + + /// Create the mappings for the accounts + pub fn connect_accounts(who: &AccountId32, secret: &libsecp256k1::SecretKey) { + assert_ok!(UnifiedAccounts::claim_evm_address( + RuntimeOrigin::signed(who.clone()), + UnifiedAccounts::eth_address(secret), + get_evm_signature(who, secret) + )); + } + pub fn claim_default_accounts(account: AccountId) { let default_h160 = UnifiedAccounts::to_default_h160(&account); assert_ok!(UnifiedAccounts::claim_default_evm_address( diff --git a/tests/integration/src/xvm.rs b/tests/integration/src/xvm.rs index b52ee6f39c..cc3031ad9c 100644 --- a/tests/integration/src/xvm.rs +++ b/tests/integration/src/xvm.rs @@ -158,7 +158,7 @@ const CALL_EVM_PAYBLE_NAME: &'static str = "call_xvm_payable"; fn evm_payable_call_via_xvm_works() { new_test_ext().execute_with(|| { // create account mappings - claim_default_accounts(ALICE); + connect_accounts(&ALICE, &alith_secret_key()); let evm_payable_addr = deploy_evm_contract(EVM_PAYABLE); @@ -229,7 +229,7 @@ fn wasm_payable_call_via_xvm_works() { 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); + connect_accounts(&ALICE, &alith_secret_key()); let wasm_payable_addr = deploy_wasm_contract(WASM_PAYABLE_NAME); let call_wasm_payable_addr = deploy_evm_contract(CALL_WASM_PAYBLE); @@ -271,7 +271,7 @@ fn calling_wasm_payable_from_evm_fails_if_caller_contract_balance_below_ed() { fn calling_wasm_payable_from_evm_works() { new_test_ext().execute_with(|| { // create account mappings - claim_default_accounts(ALICE); + connect_accounts(&ALICE, &alith_secret_key()); let wasm_payable_addr = deploy_wasm_contract(WASM_PAYABLE_NAME); let call_wasm_payable_addr = deploy_evm_contract(CALL_WASM_PAYBLE); @@ -304,7 +304,7 @@ fn calling_wasm_payable_from_evm_works() { fn calling_evm_payable_from_wasm_works() { new_test_ext().execute_with(|| { // create account mappings - claim_default_accounts(ALICE); + connect_accounts(&ALICE, &alith_secret_key()); let evm_payable_addr = deploy_evm_contract(EVM_PAYABLE); let wasm_address = deploy_wasm_contract(CALL_EVM_PAYBLE_NAME); @@ -348,7 +348,7 @@ fn calling_evm_payable_from_wasm_works() { fn reentrance_not_allowed() { new_test_ext().execute_with(|| { // create account mappings - claim_default_accounts(ALICE); + connect_accounts(&ALICE, &alith_secret_key()); // Call path: WASM -> EVM -> WASM let call_evm_payable_address = deploy_wasm_contract(CALL_EVM_PAYBLE_NAME); From 775f1b802c58fd6d8760049b574d86bfc2129cf0 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Mon, 25 Sep 2023 14:19:14 +0530 Subject: [PATCH 22/29] feat: apply code suggestions --- Cargo.lock | 1 + pallets/unified-accounts/src/impls.rs | 175 --------------- pallets/unified-accounts/src/lib.rs | 293 +++++++++++++++++--------- pallets/unified-accounts/src/mock.rs | 2 + pallets/unified-accounts/src/tests.rs | 2 +- primitives/src/ethereum_checked.rs | 12 ++ primitives/src/evm.rs | 19 ++ runtime/local/Cargo.toml | 2 +- runtime/local/src/lib.rs | 7 +- runtime/shibuya/Cargo.toml | 2 +- runtime/shibuya/src/lib.rs | 10 +- 11 files changed, 244 insertions(+), 281 deletions(-) delete mode 100644 pallets/unified-accounts/src/impls.rs 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!( From 74e83da1de41e3394f06e0eba440524c9245d7ff Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Tue, 26 Sep 2023 18:14:31 +0530 Subject: [PATCH 23/29] feat: remove `SignatureHelper` trait --- pallets/unified-accounts/src/lib.rs | 134 ++++++++++++-------------- pallets/unified-accounts/src/mock.rs | 2 +- pallets/unified-accounts/src/tests.rs | 4 +- runtime/local/src/lib.rs | 2 +- runtime/shibuya/src/lib.rs | 2 +- tests/integration/src/setup.rs | 8 +- 6 files changed, 66 insertions(+), 86 deletions(-) diff --git a/pallets/unified-accounts/src/lib.rs b/pallets/unified-accounts/src/lib.rs index 058cc29a23..77ec369349 100644 --- a/pallets/unified-accounts/src/lib.rs +++ b/pallets/unified-accounts/src/lib.rs @@ -90,20 +90,8 @@ mod benchmarking; mod mock; mod tests; -type SignatureOf = <::SignatureHelper as SignatureHelper>::Signature; - -/// Signature verification scheme for proving address ownership -pub trait SignatureHelper { - type AccountId; - type Address; - /// Signature type, ideally a 512-bit value for ECDSA signatures - type Signature: Parameter; - - /// Build raw payload that user will sign (keccack hashed). - fn build_signing_payload(who: &Self::AccountId) -> [u8; 32]; - /// Verify the provided signature against the given account. - fn verify_signature(who: &Self::AccountId, sig: &Self::Signature) -> Option; -} +/// ECDSA Signature type, with last bit for recovering address +type EvmSignature = [u8; 65]; #[frame_support::pallet] pub mod pallet { @@ -122,10 +110,8 @@ pub mod pallet { type DefaultAddressMapping: AddressMapping; /// Default account id to evm address conversion 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 SignatureHelper: SignatureHelper; - + /// EVM chain id + type ChainId: Get; /// Weight information for the extrinsics in this module type WeightInfo: WeightInfo; } @@ -157,7 +143,7 @@ pub mod pallet { pub type NativeToEvm = StorageMap<_, Blake2_128Concat, EvmAddress, T::AccountId, OptionQuery>; - /// evm addresses for native accounts + /// Evm addresses for native accounts /// EvmToNative: AccountId => Option #[pallet::storage] pub type EvmToNative = @@ -170,12 +156,18 @@ 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 + /// + /// WARNING: + /// - This extrisic only handles transfer of native balance, if your EVM + /// address contains any other native assets like XC20, DAppStaking unclaimed rewards, + /// etc you need to transfer them before hand, otherwise FUNDS WILL BE LOST FOREVER. + /// - Once connected user cannot change their mapping EVER. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::claim_evm_address())] pub fn claim_evm_address( origin: OriginFor, evm_address: EvmAddress, - signature: SignatureOf, + signature: EvmSignature, ) -> DispatchResult { let who = ensure_signed(origin)?; // make sure no prior mapping exists @@ -189,7 +181,7 @@ pub mod pallet { ); // recover evm address from signature - let address = T::SignatureHelper::verify_signature(&who, &signature) + let address = Self::verify_signature(&who, &signature) .ok_or(Error::::UnexpectedSignatureFormat)?; ensure!(evm_address == address, Error::::InvalidSignature); @@ -197,9 +189,10 @@ pub mod pallet { // 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 + // Transfer all the free native 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. + // For the reset of the assets types (like XC20, etc) that should be handled by UI. T::Currency::transfer( &default_account_id, &who, @@ -215,6 +208,8 @@ pub mod pallet { /// Claim default evm address for given account id /// Ensure no prior mapping exists for the account + /// + /// WARNINGS: Once connected user cannot change their mapping EVER. #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::claim_default_evm_address())] pub fn claim_default_evm_address(origin: OriginFor) -> DispatchResult { @@ -252,6 +247,49 @@ impl 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) +impl Pallet { + pub fn build_signing_payload(who: &T::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) + } + + pub fn verify_signature(who: &T::AccountId, sig: &EvmSignature) -> 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() + } + + 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(T::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()) + } + + 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()) + } +} + #[cfg(any(feature = "std", feature = "runtime-benchmarks"))] impl Pallet { /// Sign the given prehash with provided eth private key @@ -354,55 +392,3 @@ impl StaticLookup for Pallet { 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()) - } - - 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 524882caf6..60e81015ff 100644 --- a/pallets/unified-accounts/src/mock.rs +++ b/pallets/unified-accounts/src/mock.rs @@ -157,7 +157,7 @@ impl pallet_unified_accounts::Config for TestRuntime { type Currency = Balances; type DefaultAddressMapping = HashedAddressMapping; type DefaultAccountMapping = HashedAccountMapping; - type SignatureHelper = EIP712Signature; + type ChainId = ChainId; type WeightInfo = (); } diff --git a/pallets/unified-accounts/src/tests.rs b/pallets/unified-accounts/src/tests.rs index dd4cac821b..19724e368f 100644 --- a/pallets/unified-accounts/src/tests.rs +++ b/pallets/unified-accounts/src/tests.rs @@ -71,7 +71,7 @@ fn eip712_signature_verify_works() { substrate_address: ALICE.encode().into(), }; - let claim_hash = EIP712Signature::::build_signing_payload(&ALICE); + let claim_hash = UnifiedAccounts::build_signing_payload(&ALICE); // assert signing payload is correct assert_eq!( claim.encode_eip712().unwrap(), @@ -83,7 +83,7 @@ fn eip712_signature_verify_works() { let sig = UnifiedAccounts::eth_sign_prehash(&claim_hash, &alice_secret()); assert_eq!( Some(UnifiedAccounts::eth_address(&alice_secret())), - EIP712Signature::::verify_signature(&ALICE, &sig), + UnifiedAccounts::verify_signature(&ALICE, &sig), "signature verification should work" ); }); diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 4a881135c1..9b3e86ad60 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -449,7 +449,7 @@ impl pallet_unified_accounts::Config for Runtime { type Currency = Balances; type DefaultAddressMapping = pallet_evm::HashedAddressMapping; type DefaultAccountMapping = HashedAccountMapping; - type SignatureHelper = pallet_unified_accounts::EIP712Signature; + type ChainId = ChainId; type WeightInfo = pallet_unified_accounts::weights::SubstrateWeight; } diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index d3dcb95964..30092900e7 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -1208,7 +1208,7 @@ impl pallet_unified_accounts::Config for Runtime { type Currency = Balances; type DefaultAddressMapping = pallet_evm::HashedAddressMapping; type DefaultAccountMapping = HashedAccountMapping; - type SignatureHelper = pallet_unified_accounts::EIP712Signature; + type ChainId = EVMChainId; type WeightInfo = pallet_unified_accounts::weights::SubstrateWeight; } diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs index 4f785545db..aa46e80b12 100644 --- a/tests/integration/src/setup.rs +++ b/tests/integration/src/setup.rs @@ -35,7 +35,6 @@ pub use shibuya::*; #[cfg(feature = "shibuya")] mod shibuya { use super::*; - pub use pallet_unified_accounts::SignatureHelper; pub use shibuya_runtime::*; /// 1 SBY. @@ -109,12 +108,7 @@ mod shibuya { /// 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 - UnifiedAccounts::eth_sign_prehash( - &::SignatureHelper::build_signing_payload( - who, - ), - secret, - ) + UnifiedAccounts::eth_sign_prehash(&UnifiedAccounts::build_signing_payload(who), secret) } /// Create the mappings for the accounts From 5e9a0b8f104a8c8aa09672dd00034f249448c625 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Tue, 26 Sep 2023 18:14:50 +0530 Subject: [PATCH 24/29] feat: update claim script --- rpc-tests/claim.mjs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rpc-tests/claim.mjs b/rpc-tests/claim.mjs index a452c2e1c7..809752bb13 100644 --- a/rpc-tests/claim.mjs +++ b/rpc-tests/claim.mjs @@ -37,17 +37,17 @@ async function buildSignature(signer, substrateAddress, api, chainId) { } async function claimEvmAccount(account, evmAddress, signature, api) { - return await waitForTx(api.tx.accounts.claimEvmAccount(evmAddress, signature), account) + return await waitForTx(api.tx.unifiedAccounts.claimEvmAddress(evmAddress, signature), account) } async function main() { - const api = await ApiPromise.create({ provider: new WsProvider('ws://127.0.0.1:9945') }); + const api = await ApiPromise.create({ provider: new WsProvider('ws://127.0.0.1:9944') }); await api.isReady; const keyring = new Keyring({ type: 'sr25519' }); const alice = keyring.addFromUri('//Alice', { name: 'Alice default' }) - const provider = new JsonRpcProvider("http://127.0.0.1:9945"); + const provider = new JsonRpcProvider("http://127.0.0.1:9944"); const { chainId } = await provider.getNetwork(); const ethSigner = new Wallet("0x01ab6e801c06e59ca97a14fc0a1978b27fa366fc87450e0b65459dd3515b7391", provider); @@ -56,7 +56,8 @@ 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.EvmToNative(alice.address)}, EVM Account: ${ethSigner.address}`); + console.log(`Claimed Account ${await api.query.unifiedAccounts.evmToNative(alice.address)}, EVM Account: ${ethSigner.address}`); + console.log(`EVM Balance=${await provider.getBalance(ethSigner.address)}`) api.disconnect(); } From aa587d051bbc3b6c917acfc0c3933dfa9ee00be1 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Tue, 26 Sep 2023 18:29:17 +0530 Subject: [PATCH 25/29] feat: add check in default claim to manage collisions --- pallets/unified-accounts/src/lib.rs | 6 ++++++ pallets/unified-accounts/src/tests.rs | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/pallets/unified-accounts/src/lib.rs b/pallets/unified-accounts/src/lib.rs index 77ec369349..6ee0ad41c8 100644 --- a/pallets/unified-accounts/src/lib.rs +++ b/pallets/unified-accounts/src/lib.rs @@ -241,6 +241,12 @@ impl Pallet { ); // get the default evm address let evm_address = T::DefaultAccountMapping::into_h160(account_id.clone()); + // make sure default address is not already mapped, this should not + // happen but for sanity check. + ensure!( + !NativeToEvm::::contains_key(&evm_address), + Error::::AlreadyMapped + ); // create double mappings for the pair with default evm address Self::add_mappings(account_id, evm_address.clone()); Ok(evm_address) diff --git a/pallets/unified-accounts/src/tests.rs b/pallets/unified-accounts/src/tests.rs index 19724e368f..f3d8ff2ed9 100644 --- a/pallets/unified-accounts/src/tests.rs +++ b/pallets/unified-accounts/src/tests.rs @@ -222,6 +222,24 @@ fn account_default_claim_works() { }); } +#[test] +fn account_default_claim_should_not_work_if_collision() { + ExtBuilder::default().build().execute_with(|| { + let bob_default_h160 = >::to_default_h160(&BOB); + + // connect alice native with bob's default address + // in real world possibilty of this happening is minuscule + UnifiedAccounts::add_mappings(ALICE, bob_default_h160); + + // bob try claiming default h160 address, it should fail since alice already + // has mapping in place with it. + assert_noop!( + UnifiedAccounts::claim_default_evm_address(RuntimeOrigin::signed(BOB)), + Error::::AlreadyMapped + ); + }); +} + #[test] fn replay_attack_should_not_be_possible() { ExtBuilder::default().build().execute_with(|| { From 2609aecaee6958b67fbdaf63a61bda6ab4722428 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Tue, 26 Sep 2023 18:49:36 +0530 Subject: [PATCH 26/29] fix: benchmarks --- pallets/unified-accounts/src/benchmarking.rs | 6 ++---- pallets/unified-accounts/src/lib.rs | 8 ++++++-- pallets/unified-accounts/src/tests.rs | 10 ++++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/pallets/unified-accounts/src/benchmarking.rs b/pallets/unified-accounts/src/benchmarking.rs index e69aa8fa77..b86e3ad425 100644 --- a/pallets/unified-accounts/src/benchmarking.rs +++ b/pallets/unified-accounts/src/benchmarking.rs @@ -27,9 +27,7 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } -#[benchmarks( - where <::SignatureHelper as SignatureHelper>::Signature: IsType<[u8;65]> -)] +#[benchmarks] mod benchmarks { use super::*; @@ -39,7 +37,7 @@ mod benchmarks { let eth_secret_key = libsecp256k1::SecretKey::parse(&keccak_256(b"Alice")).unwrap(); let evm_address = Pallet::::eth_address(ð_secret_key); let signature = Pallet::::eth_sign_prehash( - &T::SignatureHelper::build_signing_payload(&caller), + &Pallet::::build_signing_payload(&caller), ð_secret_key, ) .into(); diff --git a/pallets/unified-accounts/src/lib.rs b/pallets/unified-accounts/src/lib.rs index 6ee0ad41c8..19dbced7ba 100644 --- a/pallets/unified-accounts/src/lib.rs +++ b/pallets/unified-accounts/src/lib.rs @@ -39,10 +39,15 @@ //! * `claim_default_evm_address`: Creates the double mapping with default evm address given that //! no prior mapping exists. //! +//! WARNINGS: +//! * This pallet only handles transfer of native balance only, for the rest of native assets +//! hold by evm address like XC20, DAppStaking unclaimed rewards, etc should be transferred +//! manually beforehand by user himself otherwise FUNDS WILL BE LOST FOREVER. +//! * Once mapping is created it cannot be changed. +//! //! ## Traits //! //! * `UnifiedAddressMapper`: Interface to access pallet's mappings with defaults -//! * `SignatureHelper`: Signature verification scheme for proving address ownership //! //! ## Implementations //! @@ -53,7 +58,6 @@ //! 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 [`SignatureHelper`](crate::SignatureHelper) #![cfg_attr(not(feature = "std"), no_std)] diff --git a/pallets/unified-accounts/src/tests.rs b/pallets/unified-accounts/src/tests.rs index f3d8ff2ed9..4e92a04322 100644 --- a/pallets/unified-accounts/src/tests.rs +++ b/pallets/unified-accounts/src/tests.rs @@ -237,6 +237,16 @@ fn account_default_claim_should_not_work_if_collision() { UnifiedAccounts::claim_default_evm_address(RuntimeOrigin::signed(BOB)), Error::::AlreadyMapped ); + + // check mappings are consistent + assert_eq!( + >::to_h160(&ALICE), + Some(bob_default_h160) + ); + assert_eq!( + >::to_account_id(&bob_default_h160), + Some(ALICE) + ); }); } From 037028a1bb07e96ecbc5c6ab8d03c4b680010da3 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Tue, 26 Sep 2023 20:27:48 +0530 Subject: [PATCH 27/29] feat: inline `add_mappings()` method --- pallets/unified-accounts/src/lib.rs | 27 ++++++++++++++------------- pallets/unified-accounts/src/tests.rs | 5 +++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/pallets/unified-accounts/src/lib.rs b/pallets/unified-accounts/src/lib.rs index 19dbced7ba..102c87c881 100644 --- a/pallets/unified-accounts/src/lib.rs +++ b/pallets/unified-accounts/src/lib.rs @@ -206,7 +206,13 @@ pub mod pallet { } // create double mappings for the pair - Self::add_mappings(who, evm_address); + NativeToEvm::::insert(&evm_address, &who); + EvmToNative::::insert(&who, &evm_address); + + Self::deposit_event(Event::AccountClaimed { + account_id: who, + evm_address, + }); Ok(()) } @@ -226,17 +232,6 @@ pub mod pallet { } impl Pallet { - /// Add the given pair to create double mappings - 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, - }); - } - /// Claim the default evm address fn do_claim_default_evm_address(account_id: T::AccountId) -> Result { ensure!( @@ -252,7 +247,13 @@ impl Pallet { Error::::AlreadyMapped ); // create double mappings for the pair with default evm address - Self::add_mappings(account_id, evm_address.clone()); + NativeToEvm::::insert(&evm_address, &account_id); + EvmToNative::::insert(&account_id, &evm_address); + + Self::deposit_event(Event::AccountClaimed { + account_id, + evm_address, + }); Ok(evm_address) } } diff --git a/pallets/unified-accounts/src/tests.rs b/pallets/unified-accounts/src/tests.rs index 4e92a04322..dfb96efc4e 100644 --- a/pallets/unified-accounts/src/tests.rs +++ b/pallets/unified-accounts/src/tests.rs @@ -227,9 +227,10 @@ fn account_default_claim_should_not_work_if_collision() { ExtBuilder::default().build().execute_with(|| { let bob_default_h160 = >::to_default_h160(&BOB); - // connect alice native with bob's default address + // create mapping of alice native with bob's default address // in real world possibilty of this happening is minuscule - UnifiedAccounts::add_mappings(ALICE, bob_default_h160); + NativeToEvm::::insert(&bob_default_h160, &ALICE); + EvmToNative::::insert(&ALICE, &bob_default_h160); // bob try claiming default h160 address, it should fail since alice already // has mapping in place with it. From 9fcc5a6c75da9fe8f1be9dd1ab2da8b5065126d1 Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Tue, 26 Sep 2023 20:29:33 +0530 Subject: [PATCH 28/29] feat: apply benchmarks weights & code suggestions --- pallets/unified-accounts/src/benchmarking.rs | 2 +- pallets/unified-accounts/src/lib.rs | 16 +++--- pallets/unified-accounts/src/mock.rs | 4 +- pallets/unified-accounts/src/tests.rs | 4 +- pallets/unified-accounts/src/weights.rs | 54 ++++++++++---------- runtime/local/src/lib.rs | 4 +- runtime/shibuya/src/lib.rs | 4 +- 7 files changed, 44 insertions(+), 44 deletions(-) diff --git a/pallets/unified-accounts/src/benchmarking.rs b/pallets/unified-accounts/src/benchmarking.rs index b86e3ad425..a4291e63c3 100644 --- a/pallets/unified-accounts/src/benchmarking.rs +++ b/pallets/unified-accounts/src/benchmarking.rs @@ -60,7 +60,7 @@ mod benchmarks { 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()); + let evm_address = T::DefaultNativeToEvm::into_h160(caller.clone()); #[extrinsic_call] _(RawOrigin::Signed(caller)); diff --git a/pallets/unified-accounts/src/lib.rs b/pallets/unified-accounts/src/lib.rs index 102c87c881..c2c53643e8 100644 --- a/pallets/unified-accounts/src/lib.rs +++ b/pallets/unified-accounts/src/lib.rs @@ -111,9 +111,9 @@ pub mod pallet { /// The Currency for managing evm address assets type Currency: Mutate; /// Default evm address to account id conversion - type DefaultAddressMapping: AddressMapping; + type DefaultEvmToNative: AddressMapping; /// Default account id to evm address conversion - type DefaultAccountMapping: AccountMapping; + type DefaultNativeToEvm: AccountMapping; /// EVM chain id type ChainId: Get; /// Weight information for the extrinsics in this module @@ -191,7 +191,7 @@ pub mod pallet { 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()); + let default_account_id = T::DefaultEvmToNative::into_account_id(evm_address.clone()); if frame_system::Pallet::::account_exists(&default_account_id) { // Transfer all the free native balance from old account id to the newly // since this `default_account_id` will no longer be connected to evm address @@ -239,7 +239,7 @@ impl Pallet { Error::::AlreadyMapped ); // get the default evm address - let evm_address = T::DefaultAccountMapping::into_h160(account_id.clone()); + let evm_address = T::DefaultNativeToEvm::into_h160(account_id.clone()); // make sure default address is not already mapped, this should not // happen but for sanity check. ensure!( @@ -332,12 +332,12 @@ impl UnifiedAddressMapper for Pallet { 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()) + T::DefaultEvmToNative::into_account_id(evm_address.clone()) }) } fn to_default_account_id(evm_address: &EvmAddress) -> T::AccountId { - T::DefaultAddressMapping::into_account_id(evm_address.clone()) + T::DefaultEvmToNative::into_account_id(evm_address.clone()) } fn to_h160(account_id: &T::AccountId) -> Option { @@ -347,12 +347,12 @@ impl UnifiedAddressMapper for Pallet { 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()) + T::DefaultNativeToEvm::into_h160(account_id.clone()) }) } fn to_default_h160(account_id: &T::AccountId) -> EvmAddress { - T::DefaultAccountMapping::into_h160(account_id.clone()) + T::DefaultNativeToEvm::into_h160(account_id.clone()) } } diff --git a/pallets/unified-accounts/src/mock.rs b/pallets/unified-accounts/src/mock.rs index 60e81015ff..1b0f4a4851 100644 --- a/pallets/unified-accounts/src/mock.rs +++ b/pallets/unified-accounts/src/mock.rs @@ -155,8 +155,8 @@ parameter_types! { impl pallet_unified_accounts::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type DefaultAddressMapping = HashedAddressMapping; - type DefaultAccountMapping = HashedAccountMapping; + type DefaultEvmToNative = HashedAddressMapping; + type DefaultNativeToEvm = HashedAccountMapping; type ChainId = ChainId; type WeightInfo = (); } diff --git a/pallets/unified-accounts/src/tests.rs b/pallets/unified-accounts/src/tests.rs index dfb96efc4e..93dd97937a 100644 --- a/pallets/unified-accounts/src/tests.rs +++ b/pallets/unified-accounts/src/tests.rs @@ -144,7 +144,7 @@ fn account_claim_should_work() { ExtBuilder::default().build().execute_with(|| { 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 alice_eth_old_account = ::DefaultEvmToNative::into_account_id(alice_eth.clone()); let signature = get_evm_signature(&ALICE, &alice_secret()); // transfer some funds to alice_eth (H160) @@ -187,7 +187,7 @@ fn account_claim_should_work() { fn account_default_claim_works() { ExtBuilder::default().build().execute_with(|| { let alice_default_evm = - ::DefaultAccountMapping::into_h160(ALICE.into()); + ::DefaultNativeToEvm::into_h160(ALICE.into()); // claim default account assert_ok!(UnifiedAccounts::claim_default_evm_address( diff --git a/pallets/unified-accounts/src/weights.rs b/pallets/unified-accounts/src/weights.rs index c0967f5b8a..81ea31fd29 100644 --- a/pallets/unified-accounts/src/weights.rs +++ b/pallets/unified-accounts/src/weights.rs @@ -20,9 +20,9 @@ //! Autogenerated weights for pallet_unified_accounts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Ashutoshs-MacBook-Pro.local`, CPU: `` +//! HOSTNAME: `devserver-01`, CPU: `Intel(R) Xeon(R) E-2236 CPU @ 3.40GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("shibuya-dev"), DB CACHE: 1024 // Executed Command: @@ -37,7 +37,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 -// --output=./pallets/unified-accounts/src/weights.rs +// --output=./benchmark-results/unified_accounts_weights.rs // --template=./scripts/templates/weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -57,9 +57,9 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: UnifiedAccounts EvmToNative (r:1 w:1) - /// Proof Skipped: UnifiedAccounts EvmToNative (max_values: None, max_size: None, mode: Measured) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) /// Storage: UnifiedAccounts NativeToEvm (r:1 w:1) - /// Proof Skipped: UnifiedAccounts NativeToEvm (max_values: None, max_size: None, mode: Measured) + /// Proof: UnifiedAccounts NativeToEvm (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) /// Storage: EVMChainId ChainId (r:1 w:0) /// Proof: EVMChainId ChainId (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) /// Storage: System BlockHash (r:1 w:0) @@ -69,23 +69,23 @@ impl WeightInfo for SubstrateWeight { fn claim_evm_address() -> Weight { // Proof Size summary in bytes: // Measured: `256` - // Estimated: `3721` - // Minimum execution time: 58_000_000 picoseconds. - Weight::from_parts(59_000_000, 3721) + // Estimated: `3593` + // Minimum execution time: 64_843_000 picoseconds. + Weight::from_parts(65_508_000, 3593) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: UnifiedAccounts EvmToNative (r:1 w:1) - /// Proof Skipped: UnifiedAccounts EvmToNative (max_values: None, max_size: None, mode: Measured) - /// Storage: UnifiedAccounts NativeToEvm (r:0 w:1) - /// Proof Skipped: UnifiedAccounts NativeToEvm (max_values: None, max_size: None, mode: Measured) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: UnifiedAccounts NativeToEvm (r:1 w:1) + /// Proof: UnifiedAccounts NativeToEvm (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn claim_default_evm_address() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `3507` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3507) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Estimated: `3533` + // Minimum execution time: 16_399_000 picoseconds. + Weight::from_parts(16_806_000, 3533) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } } @@ -93,9 +93,9 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { /// Storage: UnifiedAccounts EvmToNative (r:1 w:1) - /// Proof Skipped: UnifiedAccounts EvmToNative (max_values: None, max_size: None, mode: Measured) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) /// Storage: UnifiedAccounts NativeToEvm (r:1 w:1) - /// Proof Skipped: UnifiedAccounts NativeToEvm (max_values: None, max_size: None, mode: Measured) + /// Proof: UnifiedAccounts NativeToEvm (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) /// Storage: EVMChainId ChainId (r:1 w:0) /// Proof: EVMChainId ChainId (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) /// Storage: System BlockHash (r:1 w:0) @@ -105,23 +105,23 @@ impl WeightInfo for () { fn claim_evm_address() -> Weight { // Proof Size summary in bytes: // Measured: `256` - // Estimated: `3721` - // Minimum execution time: 58_000_000 picoseconds. - Weight::from_parts(59_000_000, 3721) + // Estimated: `3593` + // Minimum execution time: 64_843_000 picoseconds. + Weight::from_parts(65_508_000, 3593) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: UnifiedAccounts EvmToNative (r:1 w:1) - /// Proof Skipped: UnifiedAccounts EvmToNative (max_values: None, max_size: None, mode: Measured) - /// Storage: UnifiedAccounts NativeToEvm (r:0 w:1) - /// Proof Skipped: UnifiedAccounts NativeToEvm (max_values: None, max_size: None, mode: Measured) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + /// Storage: UnifiedAccounts NativeToEvm (r:1 w:1) + /// Proof: UnifiedAccounts NativeToEvm (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn claim_default_evm_address() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `3507` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(15_000_000, 3507) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Estimated: `3533` + // Minimum execution time: 16_399_000 picoseconds. + Weight::from_parts(16_806_000, 3533) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 9b3e86ad60..8bc54786ff 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -447,8 +447,8 @@ impl pallet_utility::Config for Runtime { impl pallet_unified_accounts::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type DefaultAddressMapping = pallet_evm::HashedAddressMapping; - type DefaultAccountMapping = HashedAccountMapping; + type DefaultEvmToNative = pallet_evm::HashedAddressMapping; + type DefaultNativeToEvm = HashedAccountMapping; type ChainId = ChainId; type WeightInfo = pallet_unified_accounts::weights::SubstrateWeight; } diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 30092900e7..70ac9fff64 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -1206,8 +1206,8 @@ impl pallet_xc_asset_config::Config for Runtime { impl pallet_unified_accounts::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type DefaultAddressMapping = pallet_evm::HashedAddressMapping; - type DefaultAccountMapping = HashedAccountMapping; + type DefaultEvmToNative = pallet_evm::HashedAddressMapping; + type DefaultNativeToEvm = HashedAccountMapping; type ChainId = EVMChainId; type WeightInfo = pallet_unified_accounts::weights::SubstrateWeight; } From 817ea7ec9e4621a7a6c2eab8d23d5c1cb6447e2e Mon Sep 17 00:00:00 2001 From: Ashutosh Varma Date: Tue, 26 Sep 2023 22:00:26 +0530 Subject: [PATCH 29/29] feat: re-run `pallet_balances` benchmarks --- runtime/local/src/lib.rs | 2 +- runtime/local/src/weights/mod.rs | 1 + runtime/local/src/weights/pallet_balances.rs | 153 ++++++++++++++++++ runtime/shibuya/src/lib.rs | 2 +- runtime/shibuya/src/weights/mod.rs | 1 + .../shibuya/src/weights/pallet_balances.rs | 153 ++++++++++++++++++ 6 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 runtime/local/src/weights/pallet_balances.rs create mode 100644 runtime/shibuya/src/weights/pallet_balances.rs diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs index 8bc54786ff..f183bc7c5a 100644 --- a/runtime/local/src/lib.rs +++ b/runtime/local/src/lib.rs @@ -290,7 +290,7 @@ impl pallet_balances::Config for Runtime { type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; + type WeightInfo = weights::pallet_balances::SubstrateWeight; type HoldIdentifier = (); type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; diff --git a/runtime/local/src/weights/mod.rs b/runtime/local/src/weights/mod.rs index 2db3ac12ab..cfb33e5fac 100644 --- a/runtime/local/src/weights/mod.rs +++ b/runtime/local/src/weights/mod.rs @@ -17,3 +17,4 @@ // along with Astar. If not, see . pub mod pallet_assets; +pub mod pallet_balances; diff --git a/runtime/local/src/weights/pallet_balances.rs b/runtime/local/src/weights/pallet_balances.rs new file mode 100644 index 0000000000..72416e77b7 --- /dev/null +++ b/runtime/local/src/weights/pallet_balances.rs @@ -0,0 +1,153 @@ + +// 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 . + +//! Autogenerated weights for pallet_balances +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `devserver-01`, CPU: `Intel(R) Xeon(R) E-2236 CPU @ 3.40GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("shibuya-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/astar-collator +// benchmark +// pallet +// --chain=shibuya-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_balances +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./benchmark-results/balances_weights.rs +// --template=./scripts/templates/weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weights for pallet_balances using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl pallet_balances::WeightInfo for SubstrateWeight { + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: UnifiedAccounts EvmToNative (r:1 w:0) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + fn transfer_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `94` + // Estimated: `3593` + // Minimum execution time: 54_598_000 picoseconds. + Weight::from_parts(55_039_000, 3593) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn transfer_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `52` + // Estimated: `3593` + // Minimum execution time: 39_626_000 picoseconds. + Weight::from_parts(40_238_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn force_set_balance_creating() -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `3593` + // Minimum execution time: 16_675_000 picoseconds. + Weight::from_parts(16_939_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: UnifiedAccounts EvmToNative (r:1 w:0) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + fn force_set_balance_killing() -> Weight { + // Proof Size summary in bytes: + // Measured: `182` + // Estimated: `3593` + // Minimum execution time: 26_023_000 picoseconds. + Weight::from_parts(26_587_000, 3593) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: UnifiedAccounts EvmToNative (r:1 w:0) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + fn force_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `197` + // Estimated: `6196` + // Minimum execution time: 57_231_000 picoseconds. + Weight::from_parts(58_030_000, 6196) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: UnifiedAccounts EvmToNative (r:1 w:0) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `94` + // Estimated: `3593` + // Minimum execution time: 51_686_000 picoseconds. + Weight::from_parts(52_193_000, 3593) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn force_unreserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `3593` + // Minimum execution time: 19_416_000 picoseconds. + Weight::from_parts(19_850_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:999 w:999) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + u * (136 ±0)` + // Estimated: `990 + u * (2603 ±0)` + // Minimum execution time: 19_161_000 picoseconds. + Weight::from_parts(19_253_000, 990) + // Standard Error: 8_562 + .saturating_add(Weight::from_parts(13_649_240, 0).saturating_mul(u.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) + } +} diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 70ac9fff64..cbe0283f8f 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -579,7 +579,7 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type ExistentialDeposit = ExistentialDeposit; type AccountStore = frame_system::Pallet; - type WeightInfo = pallet_balances::weights::SubstrateWeight; + type WeightInfo = weights::pallet_balances::SubstrateWeight; type HoldIdentifier = (); type FreezeIdentifier = (); type MaxHolds = ConstU32<0>; diff --git a/runtime/shibuya/src/weights/mod.rs b/runtime/shibuya/src/weights/mod.rs index 2db3ac12ab..cfb33e5fac 100644 --- a/runtime/shibuya/src/weights/mod.rs +++ b/runtime/shibuya/src/weights/mod.rs @@ -17,3 +17,4 @@ // along with Astar. If not, see . pub mod pallet_assets; +pub mod pallet_balances; diff --git a/runtime/shibuya/src/weights/pallet_balances.rs b/runtime/shibuya/src/weights/pallet_balances.rs new file mode 100644 index 0000000000..72416e77b7 --- /dev/null +++ b/runtime/shibuya/src/weights/pallet_balances.rs @@ -0,0 +1,153 @@ + +// 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 . + +//! Autogenerated weights for pallet_balances +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-09-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `devserver-01`, CPU: `Intel(R) Xeon(R) E-2236 CPU @ 3.40GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("shibuya-dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/astar-collator +// benchmark +// pallet +// --chain=shibuya-dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_balances +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./benchmark-results/balances_weights.rs +// --template=./scripts/templates/weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weights for pallet_balances using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl pallet_balances::WeightInfo for SubstrateWeight { + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: UnifiedAccounts EvmToNative (r:1 w:0) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + fn transfer_allow_death() -> Weight { + // Proof Size summary in bytes: + // Measured: `94` + // Estimated: `3593` + // Minimum execution time: 54_598_000 picoseconds. + Weight::from_parts(55_039_000, 3593) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn transfer_keep_alive() -> Weight { + // Proof Size summary in bytes: + // Measured: `52` + // Estimated: `3593` + // Minimum execution time: 39_626_000 picoseconds. + Weight::from_parts(40_238_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn force_set_balance_creating() -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `3593` + // Minimum execution time: 16_675_000 picoseconds. + Weight::from_parts(16_939_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: UnifiedAccounts EvmToNative (r:1 w:0) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + fn force_set_balance_killing() -> Weight { + // Proof Size summary in bytes: + // Measured: `182` + // Estimated: `3593` + // Minimum execution time: 26_023_000 picoseconds. + Weight::from_parts(26_587_000, 3593) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:2 w:2) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: UnifiedAccounts EvmToNative (r:1 w:0) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + fn force_transfer() -> Weight { + // Proof Size summary in bytes: + // Measured: `197` + // Estimated: `6196` + // Minimum execution time: 57_231_000 picoseconds. + Weight::from_parts(58_030_000, 6196) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: UnifiedAccounts EvmToNative (r:1 w:0) + /// Proof: UnifiedAccounts EvmToNative (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) + fn transfer_all() -> Weight { + // Proof Size summary in bytes: + // Measured: `94` + // Estimated: `3593` + // Minimum execution time: 51_686_000 picoseconds. + Weight::from_parts(52_193_000, 3593) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + fn force_unreserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `140` + // Estimated: `3593` + // Minimum execution time: 19_416_000 picoseconds. + Weight::from_parts(19_850_000, 3593) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:999 w:999) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// The range of component `u` is `[1, 1000]`. + fn upgrade_accounts(u: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + u * (136 ±0)` + // Estimated: `990 + u * (2603 ±0)` + // Minimum execution time: 19_161_000 picoseconds. + Weight::from_parts(19_253_000, 990) + // Standard Error: 8_562 + .saturating_add(Weight::from_parts(13_649_240, 0).saturating_mul(u.into())) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(u.into())) + } +}