diff --git a/Cargo.lock b/Cargo.lock index 51f6a415b..8a6b4f46a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6050,6 +6050,7 @@ dependencies = [ "pallet-evm-precompile-simple", "pallet-evm-precompile-sr25519", "pallet-evm-precompile-substrate-ecdsa", + "pallet-evm-precompile-unified-accounts", "pallet-evm-precompile-xvm", "pallet-grandpa", "pallet-insecure-randomness-collective-flip", @@ -8063,6 +8064,35 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-evm-precompile-unified-accounts" +version = "0.1.0" +dependencies = [ + "astar-primitives", + "derive_more", + "ethers", + "fp-evm", + "frame-support", + "frame-system", + "hex", + "hex-literal", + "libsecp256k1", + "log", + "num_enum 0.5.11", + "pallet-balances", + "pallet-evm", + "pallet-timestamp", + "pallet-unified-accounts", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-evm-precompile-xcm" version = "0.11.0" @@ -13163,6 +13193,7 @@ dependencies = [ "pallet-evm-precompile-simple", "pallet-evm-precompile-sr25519", "pallet-evm-precompile-substrate-ecdsa", + "pallet-evm-precompile-unified-accounts", "pallet-evm-precompile-xcm", "pallet-evm-precompile-xvm", "pallet-identity", diff --git a/Cargo.toml b/Cargo.toml index e451b0309..4bedb6497 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -291,6 +291,7 @@ pallet-evm-precompile-substrate-ecdsa = { path = "./precompiles/substrate-ecdsa" pallet-evm-precompile-xcm = { path = "./precompiles/xcm", default-features = false } pallet-evm-precompile-xvm = { path = "./precompiles/xvm", default-features = false } pallet-evm-precompile-dapps-staking = { path = "./precompiles/dapps-staking", default-features = false } +pallet-evm-precompile-unified-accounts = { path = "./precompiles/unified-accounts", default-features = false } pallet-chain-extension-dapps-staking = { path = "./chain-extensions/dapps-staking", default-features = false } pallet-chain-extension-xvm = { path = "./chain-extensions/xvm", default-features = false } diff --git a/precompiles/unified-accounts/Cargo.toml b/precompiles/unified-accounts/Cargo.toml new file mode 100644 index 000000000..30842e065 --- /dev/null +++ b/precompiles/unified-accounts/Cargo.toml @@ -0,0 +1,62 @@ +[package] +name = "pallet-evm-precompile-unified-accounts" +description = "Evm Precompile for AU" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +hex = { workspace = true } +log = { workspace = true } +num_enum = { workspace = true } +precompile-utils = { workspace = true } + +# Substrate +frame-support = { workspace = true } +frame-system = { workspace = true } +parity-scale-codec = { workspace = true, features = ["max-encoded-len"] } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +# Frontier +fp-evm = { workspace = true } +pallet-evm = { workspace = true } +pallet-unified-accounts = { workspace = true } + +# Astar +astar-primitives = { workspace = true } + +[dev-dependencies] +derive_more = { workspace = true } +hex-literal = { workspace = true } +scale-info = { workspace = true } +serde = { workspace = true } + +precompile-utils = { workspace = true, features = ["testing"] } + +ethers = { workspace = true } +libsecp256k1 = { workspace = true, features = ["hmac", "static-context"] } +pallet-balances = { workspace = true, features = ["std"] } +pallet-timestamp = { workspace = true } +sp-runtime = { workspace = true } + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "pallet-unified-accounts/std", + "fp-evm/std", + "frame-support/std", + "frame-system/std", + "pallet-evm/std", + "precompile-utils/std", + "sp-core/std", + "sp-std/std", + "sp-io/std", + "sp-runtime/std", + "astar-primitives/std", +] diff --git a/precompiles/unified-accounts/UnifiedAccounts.sol b/precompiles/unified-accounts/UnifiedAccounts.sol new file mode 100644 index 000000000..9569af44e --- /dev/null +++ b/precompiles/unified-accounts/UnifiedAccounts.sol @@ -0,0 +1,28 @@ +pragma solidity ^0.8.0; + +/** + * @title UA interface. + */ + +/// Interface to the precompiled contract +/// Predeployed at the address 0x0000000000000000000000000000000000005006 +/// For better understanding check the source code: +/// repo: https://github.com/AstarNetwork/astar +/// code: pallets/unified-accounts/src/lib.rs +interface UnifiedAccounts { + /// Gets the evm address associated with given account id. If no mapping exists, + /// then return the default account id. + /// @param accountId: The account id for which you want the evm address for. + /// @return (mapped_address, true) if there is a mapping found otherwise (default_address, false) + function get_evm_address_or_default( + bytes32 accountId + ) external view returns (address, bool); + + /// Gets the account id associated with given evm address. If no mapping exists, + /// then return the default evm address. + /// @param evmAddress: The evm address for which you want the account id for. + /// @return (mapped_account, true) if there is a mapping found otherwise (default_account, false) + function get_native_address_or_default( + address evmAddress + ) external view returns (bytes32, bool); +} diff --git a/precompiles/unified-accounts/src/lib.rs b/precompiles/unified-accounts/src/lib.rs new file mode 100644 index 000000000..d1dbf3dbf --- /dev/null +++ b/precompiles/unified-accounts/src/lib.rs @@ -0,0 +1,106 @@ +// 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::evm::{UnifiedAddress, UnifiedAddressMapper}; +use core::marker::PhantomData; +use fp_evm::Precompile; +use fp_evm::{PrecompileHandle, PrecompileOutput}; +use frame_support::dispatch::Dispatchable; +use frame_support::traits::IsType; +use precompile_utils::{ + succeed, Address, EvmDataWriter, EvmResult, FunctionModifier, PrecompileHandleExt, +}; +use sp_core::{crypto::AccountId32, H256}; +use sp_std::prelude::*; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +#[precompile_utils::generate_function_selector] +#[derive(Debug, PartialEq)] +pub enum Action { + GetEvmAddressOrDefault = "get_evm_address_or_default(bytes32)", + GetNativeAddressOrDefault = "get_native_address_or_default(address)", +} + +/// A precompile that expose AU related functions. +pub struct UnifiedAccountsPrecompile(PhantomData<(T, UA)>); + +impl Precompile for UnifiedAccountsPrecompile +where + R: pallet_evm::Config + pallet_unified_accounts::Config, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + From>, + ::AccountId: IsType, + UA: UnifiedAddressMapper, +{ + fn execute(handle: &mut impl PrecompileHandle) -> EvmResult { + log::trace!(target: "au-precompile", "Execute input = {:?}", handle.input()); + + let selector = handle.read_selector()?; + + handle.check_function_modifier(FunctionModifier::View)?; + + match selector { + // Dispatchables + Action::GetEvmAddressOrDefault => Self::get_evm_address_or_default(handle), + Action::GetNativeAddressOrDefault => Self::get_native_address_or_default(handle), + } + } +} + +impl UnifiedAccountsPrecompile +where + R: pallet_evm::Config + pallet_unified_accounts::Config, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + From>, + ::AccountId: IsType, + UA: UnifiedAddressMapper, +{ + fn get_evm_address_or_default( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = handle.read_input()?; + input.expect_arguments(1)?; + let account_id = AccountId32::new(input.read::()?.into()).into(); + + let output: (Address, bool) = match UA::to_h160_or_default(&account_id) { + UnifiedAddress::Mapped(address) => (address.into(), true), + UnifiedAddress::Default(address) => (address.into(), false), + }; + Ok(succeed(EvmDataWriter::new().write(output).build())) + } + + fn get_native_address_or_default( + handle: &mut impl PrecompileHandle, + ) -> EvmResult { + let mut input = handle.read_input()?; + input.expect_arguments(1)?; + let evm_address = input.read::
()?; + + let output: (H256, bool) = match UA::to_account_id_or_default(&evm_address.into()) { + UnifiedAddress::Mapped(account_id) => (H256::from(account_id.into().as_ref()), true), + UnifiedAddress::Default(account_id) => (H256::from(account_id.into().as_ref()), false), + }; + Ok(succeed(EvmDataWriter::new().write(output).build())) + } +} diff --git a/precompiles/unified-accounts/src/mock.rs b/precompiles/unified-accounts/src/mock.rs new file mode 100644 index 000000000..9b1eeb3a3 --- /dev/null +++ b/precompiles/unified-accounts/src/mock.rs @@ -0,0 +1,275 @@ +// 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 super::*; + +use fp_evm::IsPrecompileResult; +use frame_support::{construct_runtime, parameter_types, traits::ConstU64, weights::Weight}; +pub use pallet_evm::{ + AddressMapping, EnsureAddressNever, EnsureAddressRoot, PrecompileResult, PrecompileSet, +}; +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; +use sp_core::{keccak_256, H160, H256}; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, ConstU32, IdentityLookup}, + AccountId32, +}; + +use ethers::{ + contract::{Eip712, EthAbiType}, + core::types::transaction::eip712::Eip712, +}; + +use astar_primitives::evm::HashedDefaultMappings; +pub type AccountId = AccountId32; +pub type Balance = u128; +pub type BlockNumber = u64; +pub type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +pub type Block = frame_system::mocking::MockBlock; + +pub const PRECOMPILE_ADDRESS: H160 = H160::repeat_byte(0x7B); + +pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); + +pub fn alice_secret() -> libsecp256k1::SecretKey { + libsecp256k1::SecretKey::parse(&keccak_256(b"Alice")).unwrap() +} +/// 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: ethers::core::types::Bytes, +} + +/// Build the signature payload for given native account and eth private key +pub fn get_evm_signature(who: &AccountId32, secret: &libsecp256k1::SecretKey) -> [u8; 65] { + // sign the payload + UnifiedAccounts::eth_sign_prehash( + &Claim { + substrate_address: who.encode().into(), + } + .encode_eip712() + .unwrap(), + secret, + ) +} + +#[derive( + Eq, + PartialEq, + Ord, + PartialOrd, + Clone, + Encode, + Decode, + Debug, + MaxEncodedLen, + Serialize, + Deserialize, + derive_more::Display, + TypeInfo, +)] +pub enum TestAccount { + Viktor, + Precompile, +} +impl Default for TestAccount { + fn default() -> Self { + Self::Viktor + } +} +impl From for H160 { + fn from(value: TestAccount) -> H160 { + match value { + TestAccount::Viktor => H160::repeat_byte(0xAA), + TestAccount::Precompile => PRECOMPILE_ADDRESS, + } + } +} + +parameter_types! { + pub const BlockHashCount: u64 = 250; + 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 = AccountId32; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + 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>; +} +#[derive(Debug, Clone, Copy)] +pub struct TestPrecompileSet(PhantomData); + +impl PrecompileSet for TestPrecompileSet +where + R: pallet_evm::Config, + UnifiedAccountsPrecompile>: Precompile, +{ + fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { + match handle.code_address() { + a if a == PRECOMPILE_ADDRESS => Some(UnifiedAccountsPrecompile::< + R, + pallet_unified_accounts::Pallet, + >::execute(handle)), + _ => None, + } + } + + fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult { + IsPrecompileResult::Answer { + is_precompile: address == PRECOMPILE_ADDRESS, + extra_cost: 0, + } + } +} + +parameter_types! { + pub const ExistentialDeposit: u128 = 1; +} + +impl pallet_balances::Config for TestRuntime { + type MaxReserves = (); + type ReserveIdentifier = (); + type MaxLocks = (); + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + pub const MinimumPeriod: u64 = 5; +} + +impl pallet_timestamp::Config for TestRuntime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +parameter_types! { + pub const PrecompilesValue: TestPrecompileSet = + TestPrecompileSet(PhantomData); + pub WeightPerGas: Weight = Weight::from_parts(1, 0); +} + +impl pallet_evm::Config for TestRuntime { + type FeeCalculator = (); + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type CallOrigin = EnsureAddressRoot; + type WithdrawOrigin = EnsureAddressNever; + type AddressMapping = UnifiedAccounts; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = TestPrecompileSet; + type PrecompilesValue = PrecompilesValue; + type Timestamp = Timestamp; + type ChainId = ChainId; + type OnChargeTransaction = (); + type BlockGasLimit = (); + type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; + type FindAuthor = (); + type OnCreate = (); + type WeightInfo = (); + type GasLimitPovSizeRatio = ConstU64<4>; +} + +parameter_types! { + // 2 storage items with value size 20 and 32 + pub const AccountMappingStorageFee: u128 = 0; + pub ChainId: u64 = 1024; +} + +impl pallet_unified_accounts::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type DefaultMappings = HashedDefaultMappings; + type ChainId = ChainId; + type AccountMappingStorageFee = AccountMappingStorageFee; + type WeightInfo = pallet_unified_accounts::weights::SubstrateWeight; +} + +// Configure a mock runtime to test the pallet. +construct_runtime!( + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Evm: pallet_evm, + UnifiedAccounts: pallet_unified_accounts, + Balances : pallet_balances, + Timestamp: pallet_timestamp, + } +); + +#[derive(Default)] +pub(crate) struct ExtBuilder; + +impl ExtBuilder { + pub(crate) fn build(self) -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::default() + .build_storage::() + .expect("Frame system builds valid default genesis config"); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } +} diff --git a/precompiles/unified-accounts/src/tests.rs b/precompiles/unified-accounts/src/tests.rs new file mode 100644 index 000000000..598f38d8b --- /dev/null +++ b/precompiles/unified-accounts/src/tests.rs @@ -0,0 +1,133 @@ +// 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::mock::*; +use crate::*; + +use frame_support::assert_ok; +use precompile_utils::testing::*; +use precompile_utils::EvmDataWriter; + +fn precompiles() -> TestPrecompileSet { + PrecompilesValue::get() +} + +#[test] +fn test_get_evm_address() { + // Case 1 : Address Not Mapped + ExtBuilder::default().build().execute_with(|| { + let alice_default_evm = + ::DefaultMappings::to_default_h160( + &ALICE, + ); + + let res: (Address, bool) = (alice_default_evm.into(), false); + precompiles() + .prepare_test( + TestAccount::Viktor, + PRECOMPILE_ADDRESS, + EvmDataWriter::new_with_selector(Action::GetEvmAddressOrDefault) + .write(H256::zero()) // Alice's Address + .build(), + ) + .expect_no_logs() + .execute_returns(EvmDataWriter::new().write(res).build()); + }); + + // Case 2 : Address Mapped + ExtBuilder::default().build().execute_with(|| { + let alice_eth = UnifiedAccounts::eth_address(&alice_secret()); + let signature = get_evm_signature(&ALICE, &alice_secret()); + + // claim the account + assert_ok!(UnifiedAccounts::claim_evm_address( + RuntimeOrigin::signed(ALICE), + alice_eth, + signature + )); + + let res: (Address, bool) = (alice_eth.into(), true); + precompiles() + .prepare_test( + TestAccount::Viktor, + PRECOMPILE_ADDRESS, + EvmDataWriter::new_with_selector(Action::GetEvmAddressOrDefault) + .write(H256::zero()) // Alice's Address + .build(), + ) + .expect_no_logs() + .execute_returns(EvmDataWriter::new().write(res).build()); + }); +} + +#[test] +fn test_get_native_address() { + // Case 1: not mapped native address (default address) + ExtBuilder::default().build().execute_with(|| { + let alice_eth = UnifiedAccounts::eth_address(&alice_secret()); + let alice_eth_address: Address = alice_eth.into(); + + // default ss58 account associated with eth address + let alice_eth_old_account = + ::DefaultMappings::to_default_account_id( + &alice_eth, + ); + + // for let binding + let alice_eth_old_account_converted: &[u8; 32] = alice_eth_old_account.as_ref(); + let res: (H256, bool) = (alice_eth_old_account_converted.into(), false); + precompiles() + .prepare_test( + TestAccount::Viktor, + PRECOMPILE_ADDRESS, + EvmDataWriter::new_with_selector(Action::GetNativeAddressOrDefault) + .write(alice_eth_address) // Alice's Address + .build(), + ) + .expect_no_logs() + .execute_returns(EvmDataWriter::new().write(res).build()); + }); + + // Case 2 : mapped address + ExtBuilder::default().build().execute_with(|| { + // claiming address + let alice_eth: Address = UnifiedAccounts::eth_address(&alice_secret()).into(); + let signature = get_evm_signature(&ALICE, &alice_secret()); + + // claim the account + assert_ok!(UnifiedAccounts::claim_evm_address( + RuntimeOrigin::signed(ALICE), + alice_eth.into(), + signature + )); + + let alice_converted: &[u8; 32] = ALICE.as_ref(); + + let res: (H256, bool) = (alice_converted.into(), true); + precompiles() + .prepare_test( + TestAccount::Viktor, + PRECOMPILE_ADDRESS, + EvmDataWriter::new_with_selector(Action::GetNativeAddressOrDefault) + .write(alice_eth) // Alice's Address + .build(), + ) + .expect_no_logs() + .execute_returns(EvmDataWriter::new().write(res).build()); + }); +} diff --git a/runtime/local/Cargo.toml b/runtime/local/Cargo.toml index 2cbbb0733..56163524a 100644 --- a/runtime/local/Cargo.toml +++ b/runtime/local/Cargo.toml @@ -75,6 +75,7 @@ pallet-evm-precompile-assets-erc20 = { workspace = true } pallet-evm-precompile-dapps-staking = { workspace = true } pallet-evm-precompile-sr25519 = { workspace = true } pallet-evm-precompile-substrate-ecdsa = { workspace = true } +pallet-evm-precompile-unified-accounts = { workspace = true } pallet-evm-precompile-xvm = { workspace = true } pallet-unified-accounts = { workspace = true } pallet-xvm = { workspace = true } @@ -131,6 +132,7 @@ std = [ "pallet-evm-precompile-dapps-staking/std", "pallet-evm-precompile-sr25519/std", "pallet-evm-precompile-substrate-ecdsa/std", + "pallet-evm-precompile-unified-accounts/std", "pallet-evm-precompile-xvm/std", "pallet-grandpa/std", "pallet-insecure-randomness-collective-flip/std", diff --git a/runtime/local/src/precompiles.rs b/runtime/local/src/precompiles.rs index 3efe471c3..4eca364f7 100644 --- a/runtime/local/src/precompiles.rs +++ b/runtime/local/src/precompiles.rs @@ -36,6 +36,7 @@ use pallet_evm_precompile_sha3fips::Sha3FIPS256; use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; use pallet_evm_precompile_sr25519::Sr25519Precompile; use pallet_evm_precompile_substrate_ecdsa::SubstrateEcdsaPrecompile; +use pallet_evm_precompile_unified_accounts::UnifiedAccountsPrecompile; use pallet_evm_precompile_xvm::XvmPrecompile; use sp_core::H160; use sp_std::fmt::Debug; @@ -74,9 +75,11 @@ impl LocalNetworkPrecompiles { /// Return all addresses that contain precompiles. This can be used to populate dummy code /// under the precompile. pub fn used_addresses() -> impl Iterator { - sp_std::vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 1024, 1025, 1026, 1027, 20481, 20482, 20483, 20485,] - .into_iter() - .map(hash) + sp_std::vec![ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 1024, 1025, 1026, 1027, 20481, 20482, 20483, 20485, 20486 + ] + .into_iter() + .map(hash) } } @@ -89,9 +92,11 @@ where DappsStakingWrapper: Precompile, XvmPrecompile>: Precompile, Dispatch>: Precompile, + UnifiedAccountsPrecompile>: Precompile, R: pallet_evm::Config + pallet_xvm::Config + pallet_assets::Config + + pallet_unified_accounts::Config + AddressToAssetId<::AssetId>, { fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { @@ -136,6 +141,10 @@ where a if a == hash(20485) => { Some(XvmPrecompile::>::execute(handle)) } + a if a == hash(20486) => Some(UnifiedAccountsPrecompile::< + R, + pallet_unified_accounts::Pallet, + >::execute(handle)), // If the address matches asset prefix, the we route through the asset precompile set a if &a.to_fixed_bytes()[0..4] == ASSET_PRECOMPILE_ADDRESS_PREFIX => { Erc20AssetsPrecompileSet::::new().execute(handle) diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml index b97c54bd6..ac4e21cf4 100644 --- a/runtime/shibuya/Cargo.toml +++ b/runtime/shibuya/Cargo.toml @@ -107,6 +107,7 @@ pallet-evm-precompile-assets-erc20 = { workspace = true } pallet-evm-precompile-dapps-staking = { workspace = true } pallet-evm-precompile-sr25519 = { workspace = true } pallet-evm-precompile-substrate-ecdsa = { workspace = true } +pallet-evm-precompile-unified-accounts = { workspace = true } pallet-evm-precompile-xcm = { workspace = true } pallet-evm-precompile-xvm = { workspace = true } pallet-unified-accounts = { workspace = true } @@ -182,6 +183,7 @@ std = [ "pallet-evm-precompile-assets-erc20/std", "pallet-evm-precompile-xcm/std", "pallet-evm-precompile-xvm/std", + "pallet-evm-precompile-unified-accounts/std", "pallet-dapps-staking/std", "pallet-identity/std", "pallet-multisig/std", diff --git a/runtime/shibuya/src/precompiles.rs b/runtime/shibuya/src/precompiles.rs index 11c32ff77..520a6dabb 100644 --- a/runtime/shibuya/src/precompiles.rs +++ b/runtime/shibuya/src/precompiles.rs @@ -36,6 +36,7 @@ use pallet_evm_precompile_sha3fips::Sha3FIPS256; use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; use pallet_evm_precompile_sr25519::Sr25519Precompile; use pallet_evm_precompile_substrate_ecdsa::SubstrateEcdsaPrecompile; +use pallet_evm_precompile_unified_accounts::UnifiedAccountsPrecompile; use pallet_evm_precompile_xcm::XcmPrecompile; use pallet_evm_precompile_xvm::XvmPrecompile; use sp_core::H160; @@ -79,6 +80,7 @@ impl ShibuyaNetworkPrecompiles { pub fn used_addresses() -> impl Iterator { sp_std::vec![ 1, 2, 3, 4, 5, 6, 7, 8, 9, 1024, 1025, 1026, 1027, 20481, 20482, 20483, 20484, 20485, + 20486 ] .into_iter() .map(hash) @@ -95,10 +97,12 @@ where XcmPrecompile: Precompile, XvmPrecompile>: Precompile, Dispatch>: Precompile, + UnifiedAccountsPrecompile>: Precompile, R: pallet_evm::Config + pallet_assets::Config + pallet_xcm::Config + pallet_xvm::Config + + pallet_unified_accounts::Config + AddressToAssetId<::AssetId>, C: xcm_executor::traits::Convert::AssetId>, { @@ -146,6 +150,11 @@ where a if a == hash(20485) => { Some(XvmPrecompile::>::execute(handle)) } + // UnifiedAccounts 0x5006 + a if a == hash(20486) => Some(UnifiedAccountsPrecompile::< + R, + pallet_unified_accounts::Pallet, + >::execute(handle)), // If the address matches asset prefix, the we route through the asset precompile set a if &a.to_fixed_bytes()[0..4] == ASSET_PRECOMPILE_ADDRESS_PREFIX => { Erc20AssetsPrecompileSet::::new().execute(handle)