From e77b72cfecc23bdb15c9809bfd8def269dbc1a63 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Tue, 13 Feb 2024 17:44:34 +0100 Subject: [PATCH 01/16] evm accounts pallet implementation --- Cargo.lock | 30 +++ Cargo.toml | 3 + integration-tests/Cargo.toml | 3 +- integration-tests/src/evm.rs | 202 +++++++++++++++- integration-tests/src/lib.rs | 2 +- integration-tests/src/polkadot_test_net.rs | 9 +- pallets/circuit-breaker/src/benchmarking.rs | 4 +- pallets/evm-accounts/Cargo.toml | 57 +++++ pallets/evm-accounts/README.md | 25 ++ .../evm-accounts/rpc/runtime-api/Cargo.toml | 24 ++ .../evm-accounts/rpc/runtime-api/README.md | 1 + .../evm-accounts/rpc/runtime-api/src/lib.rs | 41 ++++ pallets/evm-accounts/src/benchmarking.rs | 41 ++++ pallets/evm-accounts/src/lib.rs | 222 ++++++++++++++++++ pallets/evm-accounts/src/mock.rs | 155 ++++++++++++ pallets/evm-accounts/src/tests.rs | 83 +++++++ pallets/evm-accounts/src/weights.rs | 45 ++++ runtime/hydradx/Cargo.toml | 5 + .../hydradx/src/evm/accounts_conversion.rs | 25 +- runtime/hydradx/src/evm/mod.rs | 15 ++ runtime/hydradx/src/lib.rs | 20 +- 21 files changed, 979 insertions(+), 33 deletions(-) create mode 100644 pallets/evm-accounts/Cargo.toml create mode 100644 pallets/evm-accounts/README.md create mode 100644 pallets/evm-accounts/rpc/runtime-api/Cargo.toml create mode 100644 pallets/evm-accounts/rpc/runtime-api/README.md create mode 100644 pallets/evm-accounts/rpc/runtime-api/src/lib.rs create mode 100644 pallets/evm-accounts/src/benchmarking.rs create mode 100644 pallets/evm-accounts/src/lib.rs create mode 100644 pallets/evm-accounts/src/mock.rs create mode 100644 pallets/evm-accounts/src/tests.rs create mode 100644 pallets/evm-accounts/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 65981c141..3a3eb362b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4673,6 +4673,8 @@ dependencies = [ "pallet-ema-oracle", "pallet-ethereum", "pallet-evm", + "pallet-evm-accounts", + "pallet-evm-accounts-rpc-runtime-api", "pallet-evm-chain-id", "pallet-evm-precompile-dispatch", "pallet-genesis-history", @@ -7609,6 +7611,33 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-evm-accounts" +version = "1.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "hex-literal 0.4.1", + "orml-tokens", + "orml-traits", + "parity-scale-codec", + "primitive-types", + "scale-info", + "sp-core", + "sp-io", + "sp-std", + "test-utils", +] + +[[package]] +name = "pallet-evm-accounts-rpc-runtime-api" +version = "1.0.0" +dependencies = [ + "parity-scale-codec", + "sp-api", +] + [[package]] name = "pallet-evm-chain-id" version = "1.0.0-dev" @@ -11273,6 +11302,7 @@ dependencies = [ "pallet-elections-phragmen", "pallet-ema-oracle", "pallet-evm", + "pallet-evm-accounts", "pallet-im-online", "pallet-lbp", "pallet-liquidity-mining", diff --git a/Cargo.toml b/Cargo.toml index a094fa340..ecd052fc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ members = [ 'pallets/democracy', 'runtime/hydradx/src/evm/evm-utility/macro', 'pallets/referrals', + 'pallets/evm-accounts', ] [workspace.dependencies] @@ -80,6 +81,8 @@ pallet-bonds = { path = "pallets/bonds", default-features = false} pallet-lbp = { path = "pallets/lbp", default-features = false} pallet-xyk = { path = "pallets/xyk", default-features = false} pallet-referrals = { path = "pallets/referrals", default-features = false} +pallet-evm-accounts = { path = "pallets/evm-accounts", default-features = false} +pallet-evm-accounts-rpc-runtime-api = { path = "pallets/evm-accounts/rpc/runtime-api", default-features = false} hydra-dx-build-script-utils = { path = "utils/build-script-utils", default-features = false } scraper = { path = "scraper", default-features = false } diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index c054c120d..e3302fe92 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -21,8 +21,6 @@ pallet-omnipool-liquidity-mining = { workspace = true } pallet-bonds = { workspace = true } pallet-stableswap = { workspace = true } pallet-referrals = { workspace = true } - -# Warehouse dependencies pallet-asset-registry = { workspace = true } hydradx-traits = { workspace = true } pallet-transaction-multi-payment = { workspace = true, features = ["evm"] } @@ -38,6 +36,7 @@ pallet-dynamic-fees = { workspace = true } pallet-staking = { workspace = true} pallet-lbp = { workspace = true} pallet-xyk = { workspace = true} +pallet-evm-accounts = { workspace = true} pallet-treasury = { workspace = true } pallet-democracy = { workspace = true } diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index f60a6eb6e..f92456279 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -12,7 +12,8 @@ use hydradx_runtime::{ multicurrency::{Action, MultiCurrencyPrecompile}, Address, Bytes, EvmAddress, HydraDXPrecompiles, }, - AssetRegistry, Balances, CallFilter, Currencies, RuntimeCall, RuntimeOrigin, Tokens, TransactionPause, EVM, + AssetRegistry, Balances, CallFilter, Currencies, EVMAccounts, RuntimeCall, RuntimeOrigin, Tokens, TransactionPause, + EVM, }; use orml_traits::MultiCurrency; use pallet_evm::*; @@ -24,6 +25,205 @@ use xcm_emulator::TestExt; const TREASURY_ACCOUNT_INIT_BALANCE: Balance = 1000 * UNITS; +mod account_conversion { + use super::*; + use frame_support::{assert_noop, assert_ok}; + use pretty_assertions::assert_eq; + + #[test] + fn eth_address_should_convert_to_truncated_address_when_not_bound() { + TestNet::reset(); + + Hydra::execute_with(|| { + let evm_address = EVMAccounts::evm_address(&Into::::into(ALICE)); + // truncated address + let substrate_address: AccountId = EVMAccounts::get_truncated_account_id(evm_address); + + assert_eq!(ExtendedAddressMapping::into_account_id(evm_address), substrate_address); + + assert_eq!(EVMAccounts::get_account_id(evm_address), substrate_address); + assert_eq!(EVMAccounts::bound_account_id(evm_address), None); + }); + } + + #[test] + fn eth_address_should_convert_to_full_address_when_bound() { + TestNet::reset(); + + Hydra::execute_with(|| { + let substrate_address: AccountId = Into::::into(ALICE); + let evm_address = EVMAccounts::evm_address(&substrate_address); + + assert_ok!(EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed( + substrate_address.clone() + ))); + + assert_eq!(ExtendedAddressMapping::into_account_id(evm_address), substrate_address); + + assert_eq!(EVMAccounts::get_account_id(evm_address), substrate_address); + assert_eq!(EVMAccounts::bound_account_id(evm_address), Some(substrate_address)); + }); + } + + #[test] + fn bind_address_should_fail_when_already_bound() { + TestNet::reset(); + + Hydra::execute_with(|| { + assert_ok!(EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed( + ALICE.into() + )),); + + assert_noop!( + EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed(ALICE.into())), + pallet_evm_accounts::Error::::AddressAlreadyBound, + ); + }); + } + + #[test] + fn bind_address_should_fail_when_nonce_is_not_zero() { + use pallet_evm_accounts::EvmNonceProvider; + TestNet::reset(); + + Hydra::execute_with(|| { + // Arrange + let evm_address = EVMAccounts::evm_address(&Into::::into(ALICE)); + let truncated_address = EVMAccounts::get_truncated_account_id(evm_address); + + assert_ok!(hydradx_runtime::Currencies::update_balance( + hydradx_runtime::RuntimeOrigin::root(), + truncated_address, + WETH, + 100 * UNITS as i128, + )); + + let data = + hex!["4d0045544800d1820d45118d78d091e685490c674d7596e62d1f0000000000000000140000000f0000c16ff28623"] + .to_vec(); + + // Act + assert_ok!(EVM::call( + evm_signed_origin(evm_address), + evm_address, + DISPATCH_ADDR, + data, + U256::from(0), + 1000000, + gas_price(), + None, + Some(U256::zero()), + [].into() + )); + + // Assert + assert!(hydradx_runtime::evm::EvmNonceProvider::get_nonce(evm_address) != U256::zero()); + + assert_noop!( + EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed(ALICE.into())), + pallet_evm_accounts::Error::::NonZeroNonce, + ); + }); + } + + #[test] + fn truncated_address_should_be_used_in_evm_precompile_when_not_bound() { + TestNet::reset(); + + Hydra::execute_with(|| { + //Arrange + let evm_address = EVMAccounts::evm_address(&Into::::into(ALICE)); + let truncated_address = EVMAccounts::get_truncated_account_id(evm_address); + + assert_ok!(hydradx_runtime::Currencies::update_balance( + hydradx_runtime::RuntimeOrigin::root(), + truncated_address, + HDX, + 100 * UNITS as i128, + )); + + let data = EvmDataWriter::new_with_selector(Action::BalanceOf) + .write(Address::from(evm_address)) + .build(); + + let mut handle = MockHandle { + input: data, + context: Context { + address: evm_address, + caller: evm_address, + apparent_value: U256::from(0), + }, + core_address: native_asset_ethereum_address(), + is_static: true, + }; + + //Act + let result = MultiCurrencyPrecompile::::execute(&mut handle); + + //Assert + + // 100 * UNITS, balance of truncated_address + let expected_output = hex! {" + 00000000000000000000000000000000 000000000000000000005AF3107A4000 + "}; + + assert_eq!( + result, + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: expected_output.to_vec() + }) + ); + }); + } + + #[test] + fn full_address_should_be_used_in_evm_precompile_when_bound() { + TestNet::reset(); + + Hydra::execute_with(|| { + //Arrange + let evm_address = EVMAccounts::evm_address(&Into::::into(ALICE)); + + let data = EvmDataWriter::new_with_selector(Action::BalanceOf) + .write(Address::from(evm_address)) + .build(); + + let mut handle = MockHandle { + input: data, + context: Context { + address: evm_address, + caller: evm_address, + apparent_value: U256::from(0), + }, + core_address: native_asset_ethereum_address(), + is_static: true, + }; + + //Act + assert_ok!(EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed( + ALICE.into() + )),); + + let result = MultiCurrencyPrecompile::::execute(&mut handle); + + //Assert + + // 1000 * UNITS, balance of ALICE + let expected_output = hex! {" + 00000000000000000000000000000000 000000000000000000038D7EA4C68000 + "}; + assert_eq!( + result, + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: expected_output.to_vec() + }) + ); + }); + } +} + mod currency_precompile { use super::*; use pretty_assertions::assert_eq; diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs index db957efce..241f661c6 100644 --- a/integration-tests/src/lib.rs +++ b/integration-tests/src/lib.rs @@ -23,6 +23,7 @@ mod transact_call_filter; mod vesting; mod xcm_defer; mod xcm_rate_limiter; +mod xyk; #[macro_export] macro_rules! assert_balance { @@ -37,4 +38,3 @@ macro_rules! assert_reserved_balance { assert_eq!(Currencies::reserved_balance($asset, &$who), $amount); }}; } -mod xyk; diff --git a/integration-tests/src/polkadot_test_net.rs b/integration-tests/src/polkadot_test_net.rs index 060c9ed0f..f2048c070 100644 --- a/integration-tests/src/polkadot_test_net.rs +++ b/integration-tests/src/polkadot_test_net.rs @@ -18,7 +18,6 @@ use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; pub use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use hex_literal::hex; use hydradx_runtime::{evm::WETH_ASSET_LOCATION, Referrals, RuntimeOrigin}; -use pallet_evm::AddressMapping; use pallet_referrals::{FeeDistribution, Level}; pub use polkadot_primitives::v5::{BlockNumber, MAX_CODE_SIZE, MAX_POV_SIZE}; use polkadot_runtime_parachains::configuration::HostConfiguration; @@ -33,18 +32,22 @@ pub const CHARLIE: [u8; 32] = [6u8; 32]; pub const DAVE: [u8; 32] = [7u8; 32]; pub const UNKNOWN: [u8; 32] = [8u8; 32]; +// Private key: 42d8d953e4f9246093a33e9ca6daa078501012f784adfe4bbed57918ff13be14 +// Address: 0x222222ff7Be76052e023Ec1a306fCca8F9659D80 +// Account Id: 45544800222222ff7be76052e023ec1a306fcca8f9659d800000000000000000 +// SS58(63): 7KATdGakyhfBGnAt3XVgXTL7cYjzRXeSZHezKNtENcbwWibb pub fn evm_address() -> H160 { hex!["222222ff7Be76052e023Ec1a306fCca8F9659D80"].into() } pub fn evm_account() -> AccountId { - ExtendedAddressMapping::into_account_id(evm_address()) + hydradx_runtime::EVMAccounts::get_truncated_account_id(evm_address()) } pub fn evm_address2() -> H160 { hex!["222222ff7Be76052e023Ec1a306fCca8F9659D81"].into() } pub fn evm_account2() -> AccountId { - ExtendedAddressMapping::into_account_id(evm_address2()) + hydradx_runtime::EVMAccounts::get_truncated_account_id(evm_address2()) } pub fn evm_signed_origin(address: H160) -> RuntimeOrigin { // account has to be truncated to spoof it as an origin diff --git a/pallets/circuit-breaker/src/benchmarking.rs b/pallets/circuit-breaker/src/benchmarking.rs index 2d66af78e..c153a950b 100644 --- a/pallets/circuit-breaker/src/benchmarking.rs +++ b/pallets/circuit-breaker/src/benchmarking.rs @@ -1,6 +1,4 @@ -// This file is part of Basilisk-node. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2020-2022 Intergalactic, Limited (GIB). // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pallets/evm-accounts/Cargo.toml b/pallets/evm-accounts/Cargo.toml new file mode 100644 index 000000000..0539baec5 --- /dev/null +++ b/pallets/evm-accounts/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "pallet-evm-accounts" +version = "1.0.0" +authors = ['GalacticCouncil'] +edition = "2021" +license = "Apache-2.0" +homepage = 'https://github.com/galacticcouncil/hydradx-node' +repository = 'https://github.com/galacticcouncil/hydradx-node' +description = "HydraDX EVM accounts pallet" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +# parity +scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.4.0" } + +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-std = { workspace = true } +sp-core = { workspace = true } + +orml-traits = { workspace = true } + +primitive-types = { version = "0.12.0", default-features = false } + +# Optional imports for benchmarking +frame-benchmarking = { workspace = true, optional = true } +sp-io = { workspace = true, optional = true } + +[dev-dependencies] +sp-core = { workspace = true } +sp-io = { workspace = true } +frame-benchmarking = { workspace = true } +orml-tokens = { workspace = true } +test-utils = { workspace = true } +hex-literal = "0.4.1" + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "sp-std/std", + "sp-core/std", + "sp-io/std", + "frame-support/std", + "frame-system/std", + "orml-tokens/std", + "frame-benchmarking/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "sp-io", +] diff --git a/pallets/evm-accounts/README.md b/pallets/evm-accounts/README.md new file mode 100644 index 000000000..4151f2e36 --- /dev/null +++ b/pallets/evm-accounts/README.md @@ -0,0 +1,25 @@ +# EVM accounts pallet + +## Terminology + +* **Truncated address:** * A substrate address created from an EVM address by prefixing it with "ETH\0" and appending with eight 0 bytes. +* **Full Substrate address:** * Original 32 bytes long native address (not a truncated address). +* **EVM address:** * First 20 bytes of a Substrate address. + +## Overview + +The pallet allows users to bind their Substrate account to the EVM address. +The purpose of this pallet is to make interaction with the EVM easier. +Binding an address is not necessary for interacting with the EVM. + +Without binding, we are unable to get the original Substrate address from the EVM address inside +of the EVM. Inside of the EVM, we have access only to the EVM address (first 20 bytes of a Substrate account). +In this case we create and use a truncated version of the original Substrate address that called the EVM. +The original and truncated address are two different Substrate addresses. + +With binding, we store the last 12 bytes of the Substrate address. Then we can get the original +Substrate address by concatenating these 12 bytes stored in the storage to the EVM address. + +### Dispatchable Functions + +* `bind_evm_address` - Binds a Substrate address to EVM address. \ No newline at end of file diff --git a/pallets/evm-accounts/rpc/runtime-api/Cargo.toml b/pallets/evm-accounts/rpc/runtime-api/Cargo.toml new file mode 100644 index 000000000..731980d10 --- /dev/null +++ b/pallets/evm-accounts/rpc/runtime-api/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "pallet-evm-accounts-rpc-runtime-api" +version = "1.0.0" +authors = ['GalacticCouncil'] +edition = "2021" +license = "Apache-2.0" +homepage = 'https://github.com/galacticcouncil/hydradx-node' +repository = 'https://github.com/galacticcouncil/hydradx-node' +description = "RPC runtime API for EVM accounts pallet" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +sp-api = { workspace = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-api/std", +] diff --git a/pallets/evm-accounts/rpc/runtime-api/README.md b/pallets/evm-accounts/rpc/runtime-api/README.md new file mode 100644 index 000000000..5969f05c4 --- /dev/null +++ b/pallets/evm-accounts/rpc/runtime-api/README.md @@ -0,0 +1 @@ +Runtime API definition for EVM accounts pallet. diff --git a/pallets/evm-accounts/rpc/runtime-api/src/lib.rs b/pallets/evm-accounts/rpc/runtime-api/src/lib.rs new file mode 100644 index 000000000..472e30de2 --- /dev/null +++ b/pallets/evm-accounts/rpc/runtime-api/src/lib.rs @@ -0,0 +1,41 @@ +// Copyright (C) 2020-2022 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Runtime API definition for the EVM accounts pallet. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; + +sp_api::decl_runtime_apis! { + /// The API to query EVM account conversions. + pub trait EvmAccountsApi where + AccountId: Codec, + EvmAddress: Codec, + { + /// get the EVM address from the substrate address. + fn get_evm_address(account_id: AccountId) -> EvmAddress; + + /// Get the truncated address from the EVM address. + fn get_truncated_account_id(evm_address: EvmAddress) -> AccountId; + + /// Return the Substrate address bound to the EVM account. If not bound, returns `None`. + fn query_bound_account_id(evm_address: EvmAddress) -> Option; + + /// Get the Substrate address from the EVM address. + /// Returns the truncated version of the address if the address wasn't bind. + fn query_account_id(evm_address: EvmAddress) -> AccountId; + } +} diff --git a/pallets/evm-accounts/src/benchmarking.rs b/pallets/evm-accounts/src/benchmarking.rs new file mode 100644 index 000000000..bac655c19 --- /dev/null +++ b/pallets/evm-accounts/src/benchmarking.rs @@ -0,0 +1,41 @@ +// Copyright (C) 2020-2022 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; + +use frame_benchmarking::{account, benchmarks}; +use frame_system::RawOrigin; +use sp_std::prelude::*; + +benchmarks! { + where_clause { + where T::AccountId: AsRef<[u8; 32]> + frame_support::pallet_prelude::IsType, + } + + bind_evm_address { + let user: T::AccountId = account("user", 0, 1); + let evm_address = Pallet::::evm_address(&user); + assert!(!BoundAccount::::contains_key(evm_address)); + + }: _(RawOrigin::Signed(user.clone())) + verify { + let evm_address = Pallet::::evm_address(&user); + assert!(BoundAccount::::contains_key(evm_address)); + } + + impl_benchmark_test_suite!(Pallet, crate::mock::ExtBuilder::default().build(), crate::mock::Test); +} diff --git a/pallets/evm-accounts/src/lib.rs b/pallets/evm-accounts/src/lib.rs new file mode 100644 index 000000000..e93e6e59c --- /dev/null +++ b/pallets/evm-accounts/src/lib.rs @@ -0,0 +1,222 @@ +// Copyright (C) 2020-2022 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # EVM accounts pallet +//! +//! ## Terminology +//! +//! * **Truncated address:** * A substrate address created from an EVM address by prefixing it with "ETH\0" and appending with eight 0 bytes. +//! * **Full Substrate address:** * Original 32 bytes long native address (not a truncated address). +//! * **EVM address:** * First 20 bytes of a Substrate address. +//! +//! ## Overview +//! +//! The pallet allows users to bind their Substrate account to the EVM address. +//! The purpose of this pallet is to make interaction with the EVM easier. +//! Binding an address is not necessary for interacting with the EVM. +//! +//! Without binding, we are unable to get the original Substrate address from the EVM address inside +//! of the EVM. Inside of the EVM, we have access only to the EVM address (first 20 bytes of a Substrate account). +//! In this case we create and use a truncated version of the original Substrate address that called the EVM. +//! The original and truncated address are two different Substrate addresses. +//! +//! With binding, we store the last 12 bytes of the Substrate address. Then we can get the original +//! Substrate address by concatenating these 12 bytes stored in the storage to the EVM address. +//! +//! ### Dispatchable Functions +//! +//! * `bind_evm_address` - Binds a Substrate address to EVM address. + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::ensure; +use frame_support::pallet_prelude::{DispatchResult, Get}; + +use scale_info::TypeInfo; +use sp_core::{crypto::AccountId32, H160, U256}; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +mod benchmarking; +pub mod weights; + +pub use pallet::*; +pub use weights::WeightInfo; + +pub type Balance = u128; +pub type EvmAddress = H160; +pub type AccountIdLast12Bytes = [u8; 12]; + +pub trait EvmNonceProvider { + fn get_nonce(evm_address: H160) -> U256; +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use codec::HasCompact; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Asset type. + type AssetId: Member + + Parameter + + Default + + Copy + + HasCompact + + MaybeSerializeDeserialize + + MaxEncodedLen + + TypeInfo; + + /// EVM nonce provider. + type EvmNonceProvider: EvmNonceProvider; + + /// Fee multiplier for the binding of addresses. + #[pallet::constant] + type FeeMultiplier: Get; + + /// Weight information for extrinsic in this pallet. + type WeightInfo: WeightInfo; + } + + /// Maps an EVM address to the last 12 bytes of a substrate account. + #[pallet::storage] + #[pallet::getter(fn account)] + pub(super) type BoundAccount = StorageMap<_, Blake2_128Concat, EvmAddress, AccountIdLast12Bytes>; + + #[pallet::event] + #[pallet::generate_deposit(pub(crate) fn deposit_event)] + pub enum Event { + /// Binding was created. + EvmAccountBounded { who: T::AccountId, evm_address: EvmAddress }, + } + + #[pallet::error] + #[cfg_attr(test, derive(PartialEq, Eq))] + pub enum Error { + /// Nonce is not zero + NonZeroNonce, + /// Address is already bound + AddressAlreadyBound, + /// Error occurred while converting AccountId to a different type + AccountConversionFailed, + } + + #[pallet::call] + impl Pallet + where + T::AccountId: AsRef<[u8; 32]> + frame_support::traits::IsType, + { + /// Binds a Substrate address to EVM address. + /// After binding, the EVM is able to convert an EVM address to the original Substrate address. + /// Without binding, the EVM converts an EVM address to a truncated Substrate address, which doesn't correspond + /// to the origin address. + /// + /// Binding an address is not necessary for interacting with the EVM. + /// + /// Parameters: + /// - `origin`: Substrate account binding an address + /// + /// Emits `EvmAccountBound` event when successful. + #[pallet::call_index(0)] + #[pallet::weight(::WeightInfo::bind_evm_address().saturating_mul(::FeeMultiplier::get() as u64))] + pub fn bind_evm_address(origin: OriginFor) -> DispatchResult { + let who = ensure_signed(origin)?; + + let evm_address = Self::evm_address(&who); + + // This check is not necessary. It prevents binding the same address multiple times. + // Without this check binding the address second time can have pass or fail, depending + // on the nonce. So it's better to prevent any confusion and throw an error when address is + // already bound. + ensure!( + !BoundAccount::::contains_key(evm_address), + Error::::AddressAlreadyBound + ); + + let nonce = T::EvmNonceProvider::get_nonce(evm_address); + ensure!(nonce.is_zero(), Error::::NonZeroNonce); + + let maybe_last_12_bytes: Result>::Error> = + who.as_ref()[20..32].try_into(); + let last_12_bytes = if let Ok(bytes) = maybe_last_12_bytes { + bytes + } else { + // this should never happen, but we can't get rid of try_into() when converting a slice to an array + return Err(Error::::AccountConversionFailed.into()); + }; + + >::insert(evm_address, last_12_bytes); + + Self::deposit_event(Event::EvmAccountBounded { who, evm_address }); + + Ok(()) + } + } +} + +impl Pallet +where + T::AccountId: frame_support::traits::IsType, +{ + /// get the EVM address from the substrate address. + pub fn evm_address(account_id: &impl AsRef<[u8; 32]>) -> EvmAddress { + let acc = account_id.as_ref(); + EvmAddress::from_slice(&acc[..20]) + } + + /// Get the truncated address from the EVM address. + pub fn get_truncated_account_id(evm_address: EvmAddress) -> T::AccountId { + let mut data: [u8; 32] = [0u8; 32]; + data[0..4].copy_from_slice(b"ETH\0"); + data[4..24].copy_from_slice(&evm_address[..]); + AccountId32::from(data).into() + } + + /// Return the Substrate address bound to the EVM account. If not bound, returns `None`. + pub fn bound_account_id(evm_address: EvmAddress) -> Option { + let maybe_last_12_bytes = BoundAccount::::get(evm_address); + match maybe_last_12_bytes { + Some(last_12_bytes) => { + let mut data: [u8; 32] = [0u8; 32]; + data[..20].copy_from_slice(evm_address.0.as_ref()); + data[20..32].copy_from_slice(&last_12_bytes[..]); + Some(AccountId32::from(data).into()) + } + _ => None, + } + } + + /// Get the Substrate address from the EVM address. + /// Returns the truncated version of the address if the address wasn't bind. + pub fn get_account_id(evm_address: EvmAddress) -> T::AccountId { + let maybe_bound_address = Self::bound_account_id(evm_address); + match maybe_bound_address { + Some(full_address) => full_address, + None => Self::get_truncated_account_id(evm_address), + } + } +} diff --git a/pallets/evm-accounts/src/mock.rs b/pallets/evm-accounts/src/mock.rs new file mode 100644 index 000000000..bbddcc2a9 --- /dev/null +++ b/pallets/evm-accounts/src/mock.rs @@ -0,0 +1,155 @@ +#![cfg(test)] +use super::*; + +use crate as pallet_evm_accounts; +use crate::{Balance, Config}; +use frame_support::parameter_types; +use frame_support::sp_runtime::{ + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + BuildStorage, MultiSignature, +}; +use frame_support::traits::Everything; +use orml_traits::parameter_type_with_key; +pub use sp_core::{H160, H256}; +use std::cell::RefCell; +use std::collections::HashMap; + +pub type AssetId = u32; +pub type Signature = MultiSignature; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; +type Block = frame_system::mocking::MockBlock; + +pub const ONE: Balance = 1_000_000_000_000; +pub const INITIAL_BALANCE: Balance = 1_000_000_000_000 * ONE; + +pub const ALICE: AccountId = AccountId::new([1; 32]); + +pub const HDX: AssetId = 0; + +thread_local! { + pub static NONCE: RefCell> = RefCell::new(HashMap::default()); +} + +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system, + EVMAccounts: pallet_evm_accounts, + Tokens: orml_tokens, + } + +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 63; + pub const NativeAssetId: AssetId = HDX; +} + +pub struct EvmNonceProviderMock; +impl EvmNonceProvider for EvmNonceProviderMock { + fn get_nonce(evm_address: H160) -> U256 { + NONCE + .with(|v| v.borrow().get(&evm_address).copied()) + .unwrap_or_default() + } +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type AssetId = AssetId; + type FeeMultiplier = sp_core::ConstU32<10>; + type EvmNonceProvider = EvmNonceProviderMock; + type WeightInfo = (); +} + +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Block = Block; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +parameter_type_with_key! { + pub ExistentialDeposits: |_asset_id: AssetId| -> Balance { + 1 + }; +} + +impl orml_tokens::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Amount = i128; + type CurrencyId = AssetId; + type WeightInfo = (); + type ExistentialDeposits = ExistentialDeposits; + type CurrencyHooks = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type DustRemovalWhitelist = Everything; +} + +pub struct ExtBuilder { + endowed_accounts: Vec<(AccountId, AssetId, Balance)>, +} + +impl Default for ExtBuilder { + fn default() -> Self { + NONCE.with(|v| { + v.borrow_mut().clear(); + }); + + Self { + endowed_accounts: vec![(ALICE, HDX, INITIAL_BALANCE)], + } + } +} + +impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + orml_tokens::GenesisConfig:: { + balances: self.endowed_accounts, + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut r: sp_io::TestExternalities = t.into(); + r.execute_with(|| System::set_block_number(1)); + r + } + + pub fn with_non_zero_nonce(self, account_id: AccountId) -> Self { + let evm_address = EVMAccounts::evm_address(&account_id); + NONCE.with(|v| { + let mut m = v.borrow_mut(); + m.insert(evm_address, U256::one()); + }); + self + } +} + +pub fn expect_events(e: Vec) { + test_utils::expect_events::(e); +} diff --git a/pallets/evm-accounts/src/tests.rs b/pallets/evm-accounts/src/tests.rs new file mode 100644 index 000000000..e8317dc4e --- /dev/null +++ b/pallets/evm-accounts/src/tests.rs @@ -0,0 +1,83 @@ +// This file is part of HydraDX-node. + +// Copyright (C) 2020-2022 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use mock::*; + +use frame_support::{assert_noop, assert_ok}; +use hex_literal::hex; + +#[test] +fn eth_address_should_convert_to_truncated_address_when_not_bound() { + ExtBuilder::default().build().execute_with(|| { + // Arrange + let evm_address = H160::from(hex!["222222ff7Be76052e023Ec1a306fCca8F9659D80"]); + let truncated_address = + AccountId::from(hex!["45544800222222ff7be76052e023ec1a306fcca8f9659d800000000000000000"]); + + assert_eq!(EVMAccounts::get_truncated_account_id(evm_address), truncated_address); + + // Act & Assert + assert_eq!(EVMAccounts::bound_account_id(evm_address), None); + assert_eq!(EVMAccounts::get_account_id(evm_address), truncated_address); + }); +} + +#[test] +fn eth_address_should_convert_to_full_address_when_bound() { + ExtBuilder::default().build().execute_with(|| { + // Arrange & Act + assert_ok!(EVMAccounts::bind_evm_address(RuntimeOrigin::signed(ALICE),)); + + // Assert + let evm_address = EVMAccounts::evm_address(&ALICE); + + assert_eq!(EVMAccounts::bound_account_id(evm_address), Some(ALICE)); + + assert_eq!(EVMAccounts::get_account_id(evm_address), ALICE); + + expect_events(vec![Event::EvmAccountBounded { + who: ALICE, + evm_address, + } + .into()]); + }); +} + +#[test] +fn bind_address_should_fail_when_nonce_is_not_zero() { + ExtBuilder::default() + .with_non_zero_nonce(ALICE) + .build() + .execute_with(|| { + assert_noop!( + EVMAccounts::bind_evm_address(RuntimeOrigin::signed(ALICE)), + Error::::NonZeroNonce + ); + }); +} + +#[test] +fn bind_address_should_fail_when_already_bound() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(EVMAccounts::bind_evm_address(RuntimeOrigin::signed(ALICE),)); + assert_noop!( + EVMAccounts::bind_evm_address(RuntimeOrigin::signed(ALICE)), + Error::::AddressAlreadyBound + ); + }); +} diff --git a/pallets/evm-accounts/src/weights.rs b/pallets/evm-accounts/src/weights.rs new file mode 100644 index 000000000..1dedd162c --- /dev/null +++ b/pallets/evm-accounts/src/weights.rs @@ -0,0 +1,45 @@ +// This file is part of HydraDX. + +// Copyright (C) 2020-2023 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(clippy::unnecessary_cast)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +pub trait WeightInfo { + fn bind_evm_address() -> Weight; +} + +pub struct HydraWeight(PhantomData); + +impl WeightInfo for HydraWeight { + fn bind_evm_address() -> Weight { + Weight::zero() + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn bind_evm_address() -> Weight { + Weight::zero() + } +} diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index 501190821..60931d90c 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -36,6 +36,8 @@ pallet-bonds = { workspace = true } pallet-lbp = { workspace = true } pallet-xyk = { workspace = true } pallet-referrals = { workspace = true } +pallet-evm-accounts = { workspace = true } +pallet-evm-accounts-rpc-runtime-api = { workspace = true } # pallets pallet-balances = { workspace = true } @@ -192,6 +194,7 @@ runtime-benchmarks = [ "pallet-xyk/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", "pallet-referrals/runtime-benchmarks", + "pallet-evm-accounts/runtime-benchmarks", ] std = [ "codec/std", @@ -286,6 +289,8 @@ std = [ "pallet-evm-precompile-dispatch/std", "pallet-xyk/std", "pallet-referrals/std", + "pallet-evm-accounts/std", + "pallet-evm-accounts-rpc-runtime-api/std", ] try-runtime= [ "frame-try-runtime", diff --git a/runtime/hydradx/src/evm/accounts_conversion.rs b/runtime/hydradx/src/evm/accounts_conversion.rs index 173aeaf26..6295b5512 100644 --- a/runtime/hydradx/src/evm/accounts_conversion.rs +++ b/runtime/hydradx/src/evm/accounts_conversion.rs @@ -21,27 +21,21 @@ #![allow(unused_imports)] use crate::{ evm::{ConsensusEngineId, FindAuthor}, - AccountId, Aura, + AccountId, Aura, EVMAccounts, }; use codec::{Decode, Encode}; use core::marker::PhantomData; +use frame_support::traits::IsType; use hex_literal::hex; use pallet_evm::AddressMapping; use sp_core::{crypto::ByteArray, H160}; use sp_runtime::traits::AccountIdConversion; -#[derive(Encode, Decode, Default)] -struct EthereumAccount(H160); - -impl sp_runtime::TypeId for EthereumAccount { - const TYPE_ID: [u8; 4] = *b"ETH\0"; -} - pub struct ExtendedAddressMapping; impl AddressMapping for ExtendedAddressMapping { fn into_account_id(address: H160) -> AccountId { - EthereumAccount(address).into_account_truncating() + EVMAccounts::get_account_id(address) } } @@ -60,16 +54,3 @@ impl> FindAuthor for FindAuthorTruncated { None } } - -#[cfg(test)] -#[test] -fn eth_address_should_convert_to_account_id() { - // Private key: 42d8d953e4f9246093a33e9ca6daa078501012f784adfe4bbed57918ff13be14 - // Address: 0x222222ff7Be76052e023Ec1a306fCca8F9659D80 - // Account Id: 45544800222222ff7be76052e023ec1a306fcca8f9659d800000000000000000 - // SS58(63): 7KATdGakyhfBGnAt3XVgXTL7cYjzRXeSZHezKNtENcbwWibb - assert_eq!( - ExtendedAddressMapping::into_account_id(H160::from(hex!["222222ff7Be76052e023Ec1a306fCca8F9659D80"])), - AccountId::from(hex!["45544800222222ff7be76052e023ec1a306fcca8f9659d800000000000000000"]) - ); -} diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index f9e84968b..60ce17d88 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -164,3 +164,18 @@ impl pallet_ethereum::Config for crate::Runtime { type PostLogContent = PostLogContent; type ExtraDataLength = sp_core::ConstU32<1>; } + +pub struct EvmNonceProvider; +impl pallet_evm_accounts::EvmNonceProvider for EvmNonceProvider { + fn get_nonce(evm_address: sp_core::H160) -> U256 { + crate::EVM::account_basic(&evm_address).0.nonce + } +} + +impl pallet_evm_accounts::Config for crate::Runtime { + type RuntimeEvent = crate::RuntimeEvent; + type AssetId = AssetId; + type FeeMultiplier = sp_core::ConstU32<10>; + type EvmNonceProvider = EvmNonceProvider; + type WeightInfo = pallet_evm_accounts::weights::HydraWeight; +} diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 9fdc47c1c..80d212250 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -181,10 +181,11 @@ construct_runtime!( Currencies: pallet_currencies = 79, Vesting: orml_vesting = 81, - // Frontier + // Frontier and EVM pallets EVM: pallet_evm = 90, EVMChainId: pallet_evm_chain_id = 91, Ethereum: pallet_ethereum = 92, + EVMAccounts: pallet_evm_accounts = 93, // Parachain ParachainSystem: cumulus_pallet_parachain_system exclude_parts { Config } = 103, @@ -583,6 +584,21 @@ impl_runtime_apis! { } } + impl pallet_evm_accounts_rpc_runtime_api::EvmAccountsApi for Runtime { + fn get_evm_address(account_id: AccountId) -> H160 { + EVMAccounts::evm_address(&account_id) + } + fn get_truncated_account_id(evm_address: H160) -> AccountId { + EVMAccounts::get_truncated_account_id(evm_address) + } + fn query_bound_account_id(evm_address: H160) -> Option { + EVMAccounts::bound_account_id(evm_address) + } + fn query_account_id(evm_address: H160) -> AccountId { + EVMAccounts::get_account_id(evm_address) + } + } + #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn benchmark_metadata(extra: bool) -> ( @@ -622,6 +638,7 @@ impl_runtime_apis! { list_benchmark!(list, extra, pallet_lbp, LBP); list_benchmark!(list, extra, pallet_xyk, XYK); list_benchmark!(list, extra, pallet_referrals, Referrals); + list_benchmark!(list, extra, pallet_evm_accounts, EVMAccounts); list_benchmark!(list, extra, cumulus_pallet_xcmp_queue, XcmpQueue); list_benchmark!(list, extra, pallet_transaction_pause, TransactionPause); @@ -703,6 +720,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_xyk, XYK); add_benchmark!(params, batches, pallet_stableswap, Stableswap); add_benchmark!(params, batches, pallet_referrals, Referrals); + add_benchmark!(params, batches, pallet_evm_accounts, EVMAccounts); add_benchmark!(params, batches, cumulus_pallet_xcmp_queue, XcmpQueue); add_benchmark!(params, batches, pallet_transaction_pause, TransactionPause); From 817db685d7a873a3acfcf74e4ddb23a416248a35 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Tue, 13 Feb 2024 18:01:20 +0100 Subject: [PATCH 02/16] rebenchmark evm accounts pallet --- pallets/evm-accounts/src/weights.rs | 58 +++++++++++++++- runtime/hydradx/src/evm/mod.rs | 2 +- runtime/hydradx/src/weights/evm_accounts.rs | 76 +++++++++++++++++++++ runtime/hydradx/src/weights/mod.rs | 1 + 4 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 runtime/hydradx/src/weights/evm_accounts.rs diff --git a/pallets/evm-accounts/src/weights.rs b/pallets/evm-accounts/src/weights.rs index 1dedd162c..e2d910360 100644 --- a/pallets/evm-accounts/src/weights.rs +++ b/pallets/evm-accounts/src/weights.rs @@ -15,6 +15,28 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Autogenerated weights for `pallet_evm_accounts` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-02-13, STEPS: `10`, REPEAT: `30`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bench-bot`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 + +// Executed Command: +// target/release/hydradx +// benchmark +// pallet +// --chain=dev +// --steps=10 +// --repeat=30 +// --wasm-execution=compiled +// --heap-pages=4096 +// --template=.maintain/pallet-weight-template-no-back.hbs +// --pallet=pallet-evm-accounts +// --output=weights-1.1.0/evm-accounts.rs +// --extrinsic=* + #![allow(unused_parens)] #![allow(unused_imports)] #![allow(clippy::unnecessary_cast)] @@ -32,14 +54,46 @@ pub trait WeightInfo { pub struct HydraWeight(PhantomData); impl WeightInfo for HydraWeight { + /// Storage: `EVMAccounts::BoundAccount` (r:1 w:1) + /// Proof: `EVMAccounts::BoundAccount` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::NextAssetId` (r:1 w:0) + /// Proof: `AssetRegistry::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::LocationAssets` (r:1 w:0) + /// Proof: `AssetRegistry::LocationAssets` (`max_values`: None, `max_size`: Some(622), added: 3097, mode: `MaxEncodedLen`) + /// Storage: `Tokens::Accounts` (r:1 w:0) + /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn bind_evm_address() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `479` + // Estimated: `4087` + // Minimum execution time: 35_419_000 picoseconds. + Weight::from_parts(35_955_000, 4087) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(1)) } } // For backwards compatibility and tests impl WeightInfo for () { + /// Storage: `EVMAccounts::BoundAccount` (r:1 w:1) + /// Proof: `EVMAccounts::BoundAccount` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::NextAssetId` (r:1 w:0) + /// Proof: `AssetRegistry::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::LocationAssets` (r:1 w:0) + /// Proof: `AssetRegistry::LocationAssets` (`max_values`: None, `max_size`: Some(622), added: 3097, mode: `MaxEncodedLen`) + /// Storage: `Tokens::Accounts` (r:1 w:0) + /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn bind_evm_address() -> Weight { - Weight::zero() + // Proof Size summary in bytes: + // Measured: `479` + // Estimated: `4087` + // Minimum execution time: 35_419_000 picoseconds. + Weight::from_parts(35_955_000, 4087) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(1)) } } diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index 60ce17d88..45a57ec58 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -177,5 +177,5 @@ impl pallet_evm_accounts::Config for crate::Runtime { type AssetId = AssetId; type FeeMultiplier = sp_core::ConstU32<10>; type EvmNonceProvider = EvmNonceProvider; - type WeightInfo = pallet_evm_accounts::weights::HydraWeight; + type WeightInfo = crate::weights::evm_accounts::HydraWeight; } diff --git a/runtime/hydradx/src/weights/evm_accounts.rs b/runtime/hydradx/src/weights/evm_accounts.rs new file mode 100644 index 000000000..69a0f04ad --- /dev/null +++ b/runtime/hydradx/src/weights/evm_accounts.rs @@ -0,0 +1,76 @@ +// This file is part of HydraDX. + +// Copyright (C) 2020-2023 Intergalactic, Limited (GIB). +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_evm_accounts` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-02-13, STEPS: `10`, REPEAT: `30`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `bench-bot`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 + +// Executed Command: +// target/release/hydradx +// benchmark +// pallet +// --chain=dev +// --steps=10 +// --repeat=30 +// --wasm-execution=compiled +// --heap-pages=4096 +// --template=.maintain/pallet-weight-template-no-back.hbs +// --pallet=pallet-evm-accounts +// --output=weights-1.1.0/evm-accounts.rs +// --extrinsic=* + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +use pallet_evm_accounts::weights::WeightInfo; + +/// Weights for pallet_evm_accounts using the hydraDX node and recommended hardware. +pub struct HydraWeight(PhantomData); + +impl WeightInfo for HydraWeight { + /// Storage: `EVMAccounts::BoundAccount` (r:1 w:1) + /// Proof: `EVMAccounts::BoundAccount` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::NextAssetId` (r:1 w:0) + /// Proof: `AssetRegistry::NextAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `AssetRegistry::LocationAssets` (r:1 w:0) + /// Proof: `AssetRegistry::LocationAssets` (`max_values`: None, `max_size`: Some(622), added: 3097, mode: `MaxEncodedLen`) + /// Storage: `Tokens::Accounts` (r:1 w:0) + /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + fn bind_evm_address() -> Weight { + // Proof Size summary in bytes: + // Measured: `479` + // Estimated: `4087` + // Minimum execution time: 35_419_000 picoseconds. + Weight::from_parts(35_955_000, 4087) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/runtime/hydradx/src/weights/mod.rs b/runtime/hydradx/src/weights/mod.rs index 1cd454e94..a171f5643 100644 --- a/runtime/hydradx/src/weights/mod.rs +++ b/runtime/hydradx/src/weights/mod.rs @@ -9,6 +9,7 @@ pub mod dca; pub mod democracy; pub mod duster; pub mod ema_oracle; +pub mod evm_accounts; pub mod identity; pub mod lbp; pub mod omnipool; From 55d6ad861b4443f64bd31476d1febd168c7c4112 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Tue, 13 Feb 2024 18:02:55 +0100 Subject: [PATCH 03/16] bump crate versions --- Cargo.lock | 4 ++-- integration-tests/Cargo.toml | 2 +- runtime/hydradx/Cargo.toml | 2 +- runtime/hydradx/src/lib.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa54e96a8..d5f5b2503 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4619,7 +4619,7 @@ dependencies = [ [[package]] name = "hydradx-runtime" -version = "207.0.0" +version = "208.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -11256,7 +11256,7 @@ dependencies = [ [[package]] name = "runtime-integration-tests" -version = "1.17.3" +version = "1.17.4" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 3a2336097..0abc85aed 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "runtime-integration-tests" -version = "1.17.3" +version = "1.17.4" description = "Integration tests" authors = ["GalacticCouncil"] edition = "2021" diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index 8f3c71424..ec6156edc 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-runtime" -version = "207.0.0" +version = "208.0.0" authors = ["GalacticCouncil"] edition = "2021" license = "Apache 2.0" diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 869043690..88efee3df 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -107,7 +107,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("hydradx"), impl_name: create_runtime_str!("hydradx"), authoring_version: 1, - spec_version: 207, + spec_version: 208, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From f0394e866f1b5ee63fd1ed6243445957390146ae Mon Sep 17 00:00:00 2001 From: Richard Roznovjak Date: Wed, 14 Feb 2024 11:01:07 +0100 Subject: [PATCH 04/16] Update pallets/evm-accounts/src/lib.rs Co-authored-by: Martin Hloska --- pallets/evm-accounts/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/evm-accounts/src/lib.rs b/pallets/evm-accounts/src/lib.rs index e93e6e59c..77555071e 100644 --- a/pallets/evm-accounts/src/lib.rs +++ b/pallets/evm-accounts/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2022 Intergalactic, Limited (GIB). +// Copyright (C) 2020-2024 Intergalactic, Limited (GIB). // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); From 6ca74f0350488caf4fe5398d39e0b5a736b54720 Mon Sep 17 00:00:00 2001 From: Richard Roznovjak Date: Wed, 14 Feb 2024 15:22:26 +0100 Subject: [PATCH 05/16] Update pallets/evm-accounts/src/lib.rs Co-authored-by: Martin Hloska --- pallets/evm-accounts/src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pallets/evm-accounts/src/lib.rs b/pallets/evm-accounts/src/lib.rs index 77555071e..8986bac2f 100644 --- a/pallets/evm-accounts/src/lib.rs +++ b/pallets/evm-accounts/src/lib.rs @@ -213,10 +213,6 @@ where /// Get the Substrate address from the EVM address. /// Returns the truncated version of the address if the address wasn't bind. pub fn get_account_id(evm_address: EvmAddress) -> T::AccountId { - let maybe_bound_address = Self::bound_account_id(evm_address); - match maybe_bound_address { - Some(full_address) => full_address, - None => Self::get_truncated_account_id(evm_address), - } + Self::bound_account_id(evm_address).unwrap_or_else(|| Self::get_truncated_account_id(evm_address)) } } From 4878d8b4999de86363f5586133942432d0e08971 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Wed, 14 Feb 2024 15:26:15 +0100 Subject: [PATCH 06/16] resolve comments --- Cargo.lock | 1 - pallets/evm-accounts/Cargo.toml | 5 +--- .../evm-accounts/rpc/runtime-api/src/lib.rs | 3 -- pallets/evm-accounts/src/lib.rs | 30 +++++-------------- pallets/evm-accounts/src/mock.rs | 1 - runtime/hydradx/src/evm/mod.rs | 1 - runtime/hydradx/src/lib.rs | 3 -- 7 files changed, 8 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5f5b2503..2ef6477cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7623,7 +7623,6 @@ dependencies = [ "orml-tokens", "orml-traits", "parity-scale-codec", - "primitive-types", "scale-info", "sp-core", "sp-io", diff --git a/pallets/evm-accounts/Cargo.toml b/pallets/evm-accounts/Cargo.toml index 0539baec5..01166711c 100644 --- a/pallets/evm-accounts/Cargo.toml +++ b/pallets/evm-accounts/Cargo.toml @@ -22,10 +22,6 @@ frame-system = { workspace = true } sp-std = { workspace = true } sp-core = { workspace = true } -orml-traits = { workspace = true } - -primitive-types = { version = "0.12.0", default-features = false } - # Optional imports for benchmarking frame-benchmarking = { workspace = true, optional = true } sp-io = { workspace = true, optional = true } @@ -35,6 +31,7 @@ sp-core = { workspace = true } sp-io = { workspace = true } frame-benchmarking = { workspace = true } orml-tokens = { workspace = true } +orml-traits = { workspace = true } test-utils = { workspace = true } hex-literal = "0.4.1" diff --git a/pallets/evm-accounts/rpc/runtime-api/src/lib.rs b/pallets/evm-accounts/rpc/runtime-api/src/lib.rs index 472e30de2..5550597cb 100644 --- a/pallets/evm-accounts/rpc/runtime-api/src/lib.rs +++ b/pallets/evm-accounts/rpc/runtime-api/src/lib.rs @@ -28,9 +28,6 @@ sp_api::decl_runtime_apis! { /// get the EVM address from the substrate address. fn get_evm_address(account_id: AccountId) -> EvmAddress; - /// Get the truncated address from the EVM address. - fn get_truncated_account_id(evm_address: EvmAddress) -> AccountId; - /// Return the Substrate address bound to the EVM account. If not bound, returns `None`. fn query_bound_account_id(evm_address: EvmAddress) -> Option; diff --git a/pallets/evm-accounts/src/lib.rs b/pallets/evm-accounts/src/lib.rs index 8986bac2f..59bd2465b 100644 --- a/pallets/evm-accounts/src/lib.rs +++ b/pallets/evm-accounts/src/lib.rs @@ -43,8 +43,6 @@ use frame_support::ensure; use frame_support::pallet_prelude::{DispatchResult, Get}; - -use scale_info::TypeInfo; use sp_core::{crypto::AccountId32, H160, U256}; #[cfg(test)] @@ -69,7 +67,6 @@ pub trait EvmNonceProvider { #[frame_support::pallet] pub mod pallet { use super::*; - use codec::HasCompact; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -81,16 +78,6 @@ pub mod pallet { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Asset type. - type AssetId: Member - + Parameter - + Default - + Copy - + HasCompact - + MaybeSerializeDeserialize - + MaxEncodedLen - + TypeInfo; - /// EVM nonce provider. type EvmNonceProvider: EvmNonceProvider; @@ -198,16 +185,13 @@ where /// Return the Substrate address bound to the EVM account. If not bound, returns `None`. pub fn bound_account_id(evm_address: EvmAddress) -> Option { - let maybe_last_12_bytes = BoundAccount::::get(evm_address); - match maybe_last_12_bytes { - Some(last_12_bytes) => { - let mut data: [u8; 32] = [0u8; 32]; - data[..20].copy_from_slice(evm_address.0.as_ref()); - data[20..32].copy_from_slice(&last_12_bytes[..]); - Some(AccountId32::from(data).into()) - } - _ => None, - } + let Some(last_12_bytes) = BoundAccount::::get(evm_address) else { + return None; + }; + let mut data: [u8; 32] = [0u8; 32]; + data[..20].copy_from_slice(evm_address.0.as_ref()); + data[20..32].copy_from_slice(&last_12_bytes); + Some(AccountId32::from(data).into()) } /// Get the Substrate address from the EVM address. diff --git a/pallets/evm-accounts/src/mock.rs b/pallets/evm-accounts/src/mock.rs index bbddcc2a9..13f1aae10 100644 --- a/pallets/evm-accounts/src/mock.rs +++ b/pallets/evm-accounts/src/mock.rs @@ -57,7 +57,6 @@ impl EvmNonceProvider for EvmNonceProviderMock { impl Config for Test { type RuntimeEvent = RuntimeEvent; - type AssetId = AssetId; type FeeMultiplier = sp_core::ConstU32<10>; type EvmNonceProvider = EvmNonceProviderMock; type WeightInfo = (); diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index 45a57ec58..ffadc2c5c 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -174,7 +174,6 @@ impl pallet_evm_accounts::EvmNonceProvider for EvmNonceProvider { impl pallet_evm_accounts::Config for crate::Runtime { type RuntimeEvent = crate::RuntimeEvent; - type AssetId = AssetId; type FeeMultiplier = sp_core::ConstU32<10>; type EvmNonceProvider = EvmNonceProvider; type WeightInfo = crate::weights::evm_accounts::HydraWeight; diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 88efee3df..599045fed 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -588,9 +588,6 @@ impl_runtime_apis! { fn get_evm_address(account_id: AccountId) -> H160 { EVMAccounts::evm_address(&account_id) } - fn get_truncated_account_id(evm_address: H160) -> AccountId { - EVMAccounts::get_truncated_account_id(evm_address) - } fn query_bound_account_id(evm_address: H160) -> Option { EVMAccounts::bound_account_id(evm_address) } From fab0aeaa56695f5377073b096679b92afa26ac7c Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Wed, 14 Feb 2024 18:21:22 +0100 Subject: [PATCH 07/16] increase fee multiplier --- integration-tests/src/evm.rs | 25 +++++++++++++++++++++++++ pallets/evm-accounts/src/lib.rs | 2 +- runtime/hydradx/src/evm/mod.rs | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index f92456279..14afadea5 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -222,6 +222,31 @@ mod account_conversion { ); }); } + + #[test] + fn bind_evm_address_tx_cost_should_be_increased_by_fee_multiplier() { + // the fee multiplier is in the pallet evm accounts config and the desired fee is 10 HDX + use primitives::constants::currency::UNITS; + use pallet_transaction_payment::{Multiplier, NextFeeMultiplier}; + use sp_runtime::FixedPointNumber; + + TestNet::reset(); + + Hydra::execute_with(|| { + let call = pallet_evm_accounts::Call::::bind_evm_address {}; + let info = call.get_dispatch_info(); + // convert to outer call + let call = hydradx_runtime::RuntimeCall::EVMAccounts(call); + let len = call.using_encoded(|e| e.len()) as u32; + + NextFeeMultiplier::::put(Multiplier::saturating_from_integer(1)); + let fee_raw = hydradx_runtime::TransactionPayment::compute_fee_details(len, &info, 0); + let fee = fee_raw.final_fee(); + + // simple test that the fee is approximately 10 HDX + assert!(fee / UNITS == 10); + }); + } } mod currency_precompile { diff --git a/pallets/evm-accounts/src/lib.rs b/pallets/evm-accounts/src/lib.rs index 59bd2465b..f2edc3515 100644 --- a/pallets/evm-accounts/src/lib.rs +++ b/pallets/evm-accounts/src/lib.rs @@ -197,6 +197,6 @@ where /// Get the Substrate address from the EVM address. /// Returns the truncated version of the address if the address wasn't bind. pub fn get_account_id(evm_address: EvmAddress) -> T::AccountId { - Self::bound_account_id(evm_address).unwrap_or_else(|| Self::get_truncated_account_id(evm_address)) + Self::bound_account_id(evm_address).unwrap_or_else(|| Self::get_truncated_account_id(evm_address)) } } diff --git a/runtime/hydradx/src/evm/mod.rs b/runtime/hydradx/src/evm/mod.rs index ffadc2c5c..0beab4083 100644 --- a/runtime/hydradx/src/evm/mod.rs +++ b/runtime/hydradx/src/evm/mod.rs @@ -174,7 +174,7 @@ impl pallet_evm_accounts::EvmNonceProvider for EvmNonceProvider { impl pallet_evm_accounts::Config for crate::Runtime { type RuntimeEvent = crate::RuntimeEvent; - type FeeMultiplier = sp_core::ConstU32<10>; + type FeeMultiplier = sp_core::ConstU32<50>; type EvmNonceProvider = EvmNonceProvider; type WeightInfo = crate::weights::evm_accounts::HydraWeight; } From fa70e01e891ac5c6fe9dcf3e513159871b52e9ba Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Thu, 15 Feb 2024 14:24:14 +0100 Subject: [PATCH 08/16] refactoring and integrity test --- integration-tests/src/evm.rs | 2 +- pallets/evm-accounts/src/lib.rs | 32 +++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index 14afadea5..f3a7280a0 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -226,8 +226,8 @@ mod account_conversion { #[test] fn bind_evm_address_tx_cost_should_be_increased_by_fee_multiplier() { // the fee multiplier is in the pallet evm accounts config and the desired fee is 10 HDX - use primitives::constants::currency::UNITS; use pallet_transaction_payment::{Multiplier, NextFeeMultiplier}; + use primitives::constants::currency::UNITS; use sp_runtime::FixedPointNumber; TestNet::reset(); diff --git a/pallets/evm-accounts/src/lib.rs b/pallets/evm-accounts/src/lib.rs index f2edc3515..dfc59b02b 100644 --- a/pallets/evm-accounts/src/lib.rs +++ b/pallets/evm-accounts/src/lib.rs @@ -43,7 +43,10 @@ use frame_support::ensure; use frame_support::pallet_prelude::{DispatchResult, Get}; -use sp_core::{crypto::AccountId32, H160, U256}; +use sp_core::{ + crypto::{AccountId32, ByteArray}, + H160, U256, +}; #[cfg(test)] mod mock; @@ -112,6 +115,23 @@ pub mod pallet { AccountConversionFailed, } + #[pallet::hooks] + impl Hooks> for Pallet + where + T::AccountId: frame_support::traits::IsType, + { + fn integrity_test() { + // implementation of this pallet expects that EvmAddress is 20 bytes and AccountId is 32 bytes long. + // If this is not true, `copy_from_slice` might panic. + assert_eq!( + EvmAddress::len_bytes(), + 20, + "EVM Address is expected to be 20 bytes long." + ); + assert_eq!(AccountId32::LEN, 32, "AccountId is expected to be 32 bytes long."); + } + } + #[pallet::call] impl Pallet where @@ -147,14 +167,8 @@ pub mod pallet { let nonce = T::EvmNonceProvider::get_nonce(evm_address); ensure!(nonce.is_zero(), Error::::NonZeroNonce); - let maybe_last_12_bytes: Result>::Error> = - who.as_ref()[20..32].try_into(); - let last_12_bytes = if let Ok(bytes) = maybe_last_12_bytes { - bytes - } else { - // this should never happen, but we can't get rid of try_into() when converting a slice to an array - return Err(Error::::AccountConversionFailed.into()); - }; + let mut last_12_bytes: [u8; 12] = [0; 12]; + last_12_bytes.copy_from_slice(&who.as_ref()[20..32]); >::insert(evm_address, last_12_bytes); From 14244b503a553eb6c64fcc3c3568c810214b4065 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Thu, 15 Feb 2024 14:25:17 +0100 Subject: [PATCH 09/16] revert change in circuit breaker --- pallets/circuit-breaker/src/benchmarking.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pallets/circuit-breaker/src/benchmarking.rs b/pallets/circuit-breaker/src/benchmarking.rs index c153a950b..2d66af78e 100644 --- a/pallets/circuit-breaker/src/benchmarking.rs +++ b/pallets/circuit-breaker/src/benchmarking.rs @@ -1,4 +1,6 @@ -// Copyright (C) 2020-2022 Intergalactic, Limited (GIB). +// This file is part of Basilisk-node. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); From dd2f40c66135bd43dbd53e676c195d4711dfa6b6 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Thu, 15 Feb 2024 14:43:53 +0100 Subject: [PATCH 10/16] remove unused error --- pallets/evm-accounts/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/pallets/evm-accounts/src/lib.rs b/pallets/evm-accounts/src/lib.rs index dfc59b02b..291296f04 100644 --- a/pallets/evm-accounts/src/lib.rs +++ b/pallets/evm-accounts/src/lib.rs @@ -111,8 +111,6 @@ pub mod pallet { NonZeroNonce, /// Address is already bound AddressAlreadyBound, - /// Error occurred while converting AccountId to a different type - AccountConversionFailed, } #[pallet::hooks] From 786e48c6038e911b23c1b93abd9e899c8778df19 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Fri, 16 Feb 2024 15:31:49 +0100 Subject: [PATCH 11/16] fix clippy --- pallets/evm-accounts/Cargo.toml | 1 + runtime/hydradx/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/pallets/evm-accounts/Cargo.toml b/pallets/evm-accounts/Cargo.toml index 01166711c..201561ef0 100644 --- a/pallets/evm-accounts/Cargo.toml +++ b/pallets/evm-accounts/Cargo.toml @@ -52,3 +52,4 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "sp-io", ] +try-runtime = [ "frame-support/try-runtime" ] diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index ec6156edc..5f13f3852 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -357,4 +357,5 @@ try-runtime= [ "pallet-evm-chain-id/try-runtime", "pallet-xyk/try-runtime", "pallet-referrals/try-runtime", + "pallet-evm-accounts/try-runtime", ] From 57c804f8faa48b16fc58ee034f9276cf212bf8f4 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Mon, 19 Feb 2024 11:35:35 +0100 Subject: [PATCH 12/16] resolve comments --- integration-tests/src/evm.rs | 12 ++++----- integration-tests/src/polkadot_test_net.rs | 4 +-- .../evm-accounts/rpc/runtime-api/src/lib.rs | 6 ++--- pallets/evm-accounts/src/benchmarking.rs | 4 +-- pallets/evm-accounts/src/lib.rs | 27 ++++++++++--------- pallets/evm-accounts/src/tests.rs | 14 +++++----- .../hydradx/src/evm/accounts_conversion.rs | 2 +- runtime/hydradx/src/lib.rs | 8 +++--- 8 files changed, 40 insertions(+), 37 deletions(-) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index f3a7280a0..8be3c49c9 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -37,11 +37,11 @@ mod account_conversion { Hydra::execute_with(|| { let evm_address = EVMAccounts::evm_address(&Into::::into(ALICE)); // truncated address - let substrate_address: AccountId = EVMAccounts::get_truncated_account_id(evm_address); + let substrate_address: AccountId = EVMAccounts::truncated_account_id(evm_address); assert_eq!(ExtendedAddressMapping::into_account_id(evm_address), substrate_address); - assert_eq!(EVMAccounts::get_account_id(evm_address), substrate_address); + assert_eq!(EVMAccounts::account_id(evm_address), substrate_address); assert_eq!(EVMAccounts::bound_account_id(evm_address), None); }); } @@ -60,7 +60,7 @@ mod account_conversion { assert_eq!(ExtendedAddressMapping::into_account_id(evm_address), substrate_address); - assert_eq!(EVMAccounts::get_account_id(evm_address), substrate_address); + assert_eq!(EVMAccounts::account_id(evm_address), substrate_address); assert_eq!(EVMAccounts::bound_account_id(evm_address), Some(substrate_address)); }); } @@ -89,7 +89,7 @@ mod account_conversion { Hydra::execute_with(|| { // Arrange let evm_address = EVMAccounts::evm_address(&Into::::into(ALICE)); - let truncated_address = EVMAccounts::get_truncated_account_id(evm_address); + let truncated_address = EVMAccounts::truncated_account_id(evm_address); assert_ok!(hydradx_runtime::Currencies::update_balance( hydradx_runtime::RuntimeOrigin::root(), @@ -121,7 +121,7 @@ mod account_conversion { assert_noop!( EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed(ALICE.into())), - pallet_evm_accounts::Error::::NonZeroNonce, + pallet_evm_accounts::Error::::TruncatedAccountAlreadyUsed, ); }); } @@ -133,7 +133,7 @@ mod account_conversion { Hydra::execute_with(|| { //Arrange let evm_address = EVMAccounts::evm_address(&Into::::into(ALICE)); - let truncated_address = EVMAccounts::get_truncated_account_id(evm_address); + let truncated_address = EVMAccounts::truncated_account_id(evm_address); assert_ok!(hydradx_runtime::Currencies::update_balance( hydradx_runtime::RuntimeOrigin::root(), diff --git a/integration-tests/src/polkadot_test_net.rs b/integration-tests/src/polkadot_test_net.rs index f2048c070..ed03d5d7e 100644 --- a/integration-tests/src/polkadot_test_net.rs +++ b/integration-tests/src/polkadot_test_net.rs @@ -40,14 +40,14 @@ pub fn evm_address() -> H160 { hex!["222222ff7Be76052e023Ec1a306fCca8F9659D80"].into() } pub fn evm_account() -> AccountId { - hydradx_runtime::EVMAccounts::get_truncated_account_id(evm_address()) + hydradx_runtime::EVMAccounts::truncated_account_id(evm_address()) } pub fn evm_address2() -> H160 { hex!["222222ff7Be76052e023Ec1a306fCca8F9659D81"].into() } pub fn evm_account2() -> AccountId { - hydradx_runtime::EVMAccounts::get_truncated_account_id(evm_address2()) + hydradx_runtime::EVMAccounts::truncated_account_id(evm_address2()) } pub fn evm_signed_origin(address: H160) -> RuntimeOrigin { // account has to be truncated to spoof it as an origin diff --git a/pallets/evm-accounts/rpc/runtime-api/src/lib.rs b/pallets/evm-accounts/rpc/runtime-api/src/lib.rs index 5550597cb..c26dcacf3 100644 --- a/pallets/evm-accounts/rpc/runtime-api/src/lib.rs +++ b/pallets/evm-accounts/rpc/runtime-api/src/lib.rs @@ -26,13 +26,13 @@ sp_api::decl_runtime_apis! { EvmAddress: Codec, { /// get the EVM address from the substrate address. - fn get_evm_address(account_id: AccountId) -> EvmAddress; + fn evm_address(account_id: AccountId) -> EvmAddress; /// Return the Substrate address bound to the EVM account. If not bound, returns `None`. - fn query_bound_account_id(evm_address: EvmAddress) -> Option; + fn bound_account_id(evm_address: EvmAddress) -> Option; /// Get the Substrate address from the EVM address. /// Returns the truncated version of the address if the address wasn't bind. - fn query_account_id(evm_address: EvmAddress) -> AccountId; + fn account_id(evm_address: EvmAddress) -> AccountId; } } diff --git a/pallets/evm-accounts/src/benchmarking.rs b/pallets/evm-accounts/src/benchmarking.rs index bac655c19..8f785f257 100644 --- a/pallets/evm-accounts/src/benchmarking.rs +++ b/pallets/evm-accounts/src/benchmarking.rs @@ -29,12 +29,12 @@ benchmarks! { bind_evm_address { let user: T::AccountId = account("user", 0, 1); let evm_address = Pallet::::evm_address(&user); - assert!(!BoundAccount::::contains_key(evm_address)); + assert!(!AccountExtension::::contains_key(evm_address)); }: _(RawOrigin::Signed(user.clone())) verify { let evm_address = Pallet::::evm_address(&user); - assert!(BoundAccount::::contains_key(evm_address)); + assert!(AccountExtension::::contains_key(evm_address)); } impl_benchmark_test_suite!(Pallet, crate::mock::ExtBuilder::default().build(), crate::mock::Test); diff --git a/pallets/evm-accounts/src/lib.rs b/pallets/evm-accounts/src/lib.rs index 291296f04..c4cfcf236 100644 --- a/pallets/evm-accounts/src/lib.rs +++ b/pallets/evm-accounts/src/lib.rs @@ -95,20 +95,20 @@ pub mod pallet { /// Maps an EVM address to the last 12 bytes of a substrate account. #[pallet::storage] #[pallet::getter(fn account)] - pub(super) type BoundAccount = StorageMap<_, Blake2_128Concat, EvmAddress, AccountIdLast12Bytes>; + pub(super) type AccountExtension = StorageMap<_, Blake2_128Concat, EvmAddress, AccountIdLast12Bytes>; #[pallet::event] #[pallet::generate_deposit(pub(crate) fn deposit_event)] pub enum Event { /// Binding was created. - EvmAccountBounded { who: T::AccountId, evm_address: EvmAddress }, + Bound { account: T::AccountId, address: EvmAddress }, } #[pallet::error] #[cfg_attr(test, derive(PartialEq, Eq))] pub enum Error { - /// Nonce is not zero - NonZeroNonce, + /// EVM Account's nonce is not zero + TruncatedAccountAlreadyUsed, /// Address is already bound AddressAlreadyBound, } @@ -158,19 +158,22 @@ pub mod pallet { // on the nonce. So it's better to prevent any confusion and throw an error when address is // already bound. ensure!( - !BoundAccount::::contains_key(evm_address), + !AccountExtension::::contains_key(evm_address), Error::::AddressAlreadyBound ); let nonce = T::EvmNonceProvider::get_nonce(evm_address); - ensure!(nonce.is_zero(), Error::::NonZeroNonce); + ensure!(nonce.is_zero(), Error::::TruncatedAccountAlreadyUsed); let mut last_12_bytes: [u8; 12] = [0; 12]; last_12_bytes.copy_from_slice(&who.as_ref()[20..32]); - >::insert(evm_address, last_12_bytes); + >::insert(evm_address, last_12_bytes); - Self::deposit_event(Event::EvmAccountBounded { who, evm_address }); + Self::deposit_event(Event::Bound { + account: who, + address: evm_address, + }); Ok(()) } @@ -188,7 +191,7 @@ where } /// Get the truncated address from the EVM address. - pub fn get_truncated_account_id(evm_address: EvmAddress) -> T::AccountId { + pub fn truncated_account_id(evm_address: EvmAddress) -> T::AccountId { let mut data: [u8; 32] = [0u8; 32]; data[0..4].copy_from_slice(b"ETH\0"); data[4..24].copy_from_slice(&evm_address[..]); @@ -197,7 +200,7 @@ where /// Return the Substrate address bound to the EVM account. If not bound, returns `None`. pub fn bound_account_id(evm_address: EvmAddress) -> Option { - let Some(last_12_bytes) = BoundAccount::::get(evm_address) else { + let Some(last_12_bytes) = AccountExtension::::get(evm_address) else { return None; }; let mut data: [u8; 32] = [0u8; 32]; @@ -208,7 +211,7 @@ where /// Get the Substrate address from the EVM address. /// Returns the truncated version of the address if the address wasn't bind. - pub fn get_account_id(evm_address: EvmAddress) -> T::AccountId { - Self::bound_account_id(evm_address).unwrap_or_else(|| Self::get_truncated_account_id(evm_address)) + pub fn account_id(evm_address: EvmAddress) -> T::AccountId { + Self::bound_account_id(evm_address).unwrap_or_else(|| Self::truncated_account_id(evm_address)) } } diff --git a/pallets/evm-accounts/src/tests.rs b/pallets/evm-accounts/src/tests.rs index e8317dc4e..a743e54b5 100644 --- a/pallets/evm-accounts/src/tests.rs +++ b/pallets/evm-accounts/src/tests.rs @@ -29,11 +29,11 @@ fn eth_address_should_convert_to_truncated_address_when_not_bound() { let truncated_address = AccountId::from(hex!["45544800222222ff7be76052e023ec1a306fcca8f9659d800000000000000000"]); - assert_eq!(EVMAccounts::get_truncated_account_id(evm_address), truncated_address); + assert_eq!(EVMAccounts::truncated_account_id(evm_address), truncated_address); // Act & Assert assert_eq!(EVMAccounts::bound_account_id(evm_address), None); - assert_eq!(EVMAccounts::get_account_id(evm_address), truncated_address); + assert_eq!(EVMAccounts::account_id(evm_address), truncated_address); }); } @@ -48,11 +48,11 @@ fn eth_address_should_convert_to_full_address_when_bound() { assert_eq!(EVMAccounts::bound_account_id(evm_address), Some(ALICE)); - assert_eq!(EVMAccounts::get_account_id(evm_address), ALICE); + assert_eq!(EVMAccounts::account_id(evm_address), ALICE); - expect_events(vec![Event::EvmAccountBounded { - who: ALICE, - evm_address, + expect_events(vec![Event::Bound { + account: ALICE, + address: evm_address, } .into()]); }); @@ -66,7 +66,7 @@ fn bind_address_should_fail_when_nonce_is_not_zero() { .execute_with(|| { assert_noop!( EVMAccounts::bind_evm_address(RuntimeOrigin::signed(ALICE)), - Error::::NonZeroNonce + Error::::TruncatedAccountAlreadyUsed ); }); } diff --git a/runtime/hydradx/src/evm/accounts_conversion.rs b/runtime/hydradx/src/evm/accounts_conversion.rs index 6295b5512..9c35d3903 100644 --- a/runtime/hydradx/src/evm/accounts_conversion.rs +++ b/runtime/hydradx/src/evm/accounts_conversion.rs @@ -35,7 +35,7 @@ pub struct ExtendedAddressMapping; impl AddressMapping for ExtendedAddressMapping { fn into_account_id(address: H160) -> AccountId { - EVMAccounts::get_account_id(address) + EVMAccounts::account_id(address) } } diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 599045fed..d8c20f955 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -585,14 +585,14 @@ impl_runtime_apis! { } impl pallet_evm_accounts_rpc_runtime_api::EvmAccountsApi for Runtime { - fn get_evm_address(account_id: AccountId) -> H160 { + fn evm_address(account_id: AccountId) -> H160 { EVMAccounts::evm_address(&account_id) } - fn query_bound_account_id(evm_address: H160) -> Option { + fn bound_account_id(evm_address: H160) -> Option { EVMAccounts::bound_account_id(evm_address) } - fn query_account_id(evm_address: H160) -> AccountId { - EVMAccounts::get_account_id(evm_address) + fn account_id(evm_address: H160) -> AccountId { + EVMAccounts::account_id(evm_address) } } From 4716e8ad9a3dc3e7542268c901d00a5a46f07150 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Mon, 19 Feb 2024 11:48:52 +0100 Subject: [PATCH 13/16] formatting --- integration-tests/src/evm.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index a72ba7a72..8437bc28d 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -12,7 +12,8 @@ use hydradx_runtime::{ multicurrency::{Action, MultiCurrencyPrecompile}, Address, Bytes, EvmAddress, HydraDXPrecompiles, }, - AssetRegistry, Balances, CallFilter, Currencies, RuntimeCall, RuntimeOrigin, Tokens, TransactionPause, EVM, EVMAccounts, + AssetRegistry, Balances, CallFilter, Currencies, EVMAccounts, RuntimeCall, RuntimeOrigin, Tokens, TransactionPause, + EVM, }; use orml_traits::MultiCurrency; use pallet_evm::*; @@ -1258,4 +1259,4 @@ impl PrecompileHandle for MockHandle { fn gas_limit(&self) -> Option { None } -} \ No newline at end of file +} From 72ae6a234f88594052ba779791bbbfad16f778a9 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Mon, 19 Feb 2024 12:53:03 +0100 Subject: [PATCH 14/16] bump crate versions --- Cargo.lock | 4 ++-- integration-tests/Cargo.toml | 2 +- runtime/hydradx/Cargo.toml | 2 +- runtime/hydradx/src/lib.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 286987ecf..69219d89f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4619,7 +4619,7 @@ dependencies = [ [[package]] name = "hydradx-runtime" -version = "208.0.0" +version = "209.0.0" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", @@ -11330,7 +11330,7 @@ dependencies = [ [[package]] name = "runtime-integration-tests" -version = "1.17.4" +version = "1.17.5" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 1cd8f93ad..808800428 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "runtime-integration-tests" -version = "1.17.4" +version = "1.17.5" description = "Integration tests" authors = ["GalacticCouncil"] edition = "2021" diff --git a/runtime/hydradx/Cargo.toml b/runtime/hydradx/Cargo.toml index 919e58abd..c56f86ac4 100644 --- a/runtime/hydradx/Cargo.toml +++ b/runtime/hydradx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hydradx-runtime" -version = "208.0.0" +version = "209.0.0" authors = ["GalacticCouncil"] edition = "2021" license = "Apache 2.0" diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index d8c20f955..46886ba69 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -107,7 +107,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("hydradx"), impl_name: create_runtime_str!("hydradx"), authoring_version: 1, - spec_version: 208, + spec_version: 209, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From f69e03e8281d13ca42292954b14cc8e98fdf2a5b Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Mon, 19 Feb 2024 14:37:57 +0100 Subject: [PATCH 15/16] do not allow Call from RPC and runtime API for bound accounts --- integration-tests/src/evm.rs | 62 +++++++++++++++++++++++++++++++++ pallets/evm-accounts/src/lib.rs | 2 ++ runtime/hydradx/src/lib.rs | 4 +++ 3 files changed, 68 insertions(+) diff --git a/integration-tests/src/evm.rs b/integration-tests/src/evm.rs index 8437bc28d..035832a79 100644 --- a/integration-tests/src/evm.rs +++ b/integration-tests/src/evm.rs @@ -2,6 +2,7 @@ use crate::{assert_balance, polkadot_test_net::*}; use fp_evm::{Context, Transfer}; +use fp_rpc::runtime_decl_for_ethereum_runtime_rpc_api::EthereumRuntimeRPCApi; use frame_support::{assert_ok, dispatch::GetDispatchInfo, sp_runtime::codec::Encode, traits::Contains}; use frame_system::RawOrigin; use hex_literal::hex; @@ -247,6 +248,67 @@ mod account_conversion { assert!(fee / UNITS == 10); }); } + + #[test] + fn evm_call_from_runtime_rpc_should_be_accepted_from_bound_addresses() { + TestNet::reset(); + + Hydra::execute_with(|| { + //Arrange + let data = + hex!["4d0045544800d1820d45118d78d091e685490c674d7596e62d1f0000000000000000140000000f0000c16ff28623"] + .to_vec(); + + //Act & Assert + assert_ok!(hydradx_runtime::Runtime::call( + evm_address(), // from + DISPATCH_ADDR, // to + data, // data + U256::from(1000u64), + U256::from(100000u64), + None, + None, + None, + false, + None, + )); + }); + } + + #[test] + fn evm_call_from_runtime_rpc_should_not_be_accepted_from_bound_addresses() { + TestNet::reset(); + + Hydra::execute_with(|| { + //Arrange + let data = + hex!["4d0045544800d1820d45118d78d091e685490c674d7596e62d1f0000000000000000140000000f0000c16ff28623"] + .to_vec(); + + assert_ok!(EVMAccounts::bind_evm_address(hydradx_runtime::RuntimeOrigin::signed( + ALICE.into() + )),); + + let evm_address = EVMAccounts::evm_address(&Into::::into(ALICE)); + + //Act & Assert + assert_noop!( + hydradx_runtime::Runtime::call( + evm_address, // from + DISPATCH_ADDR, // to + data, // data + U256::from(1000u64), + U256::from(100000u64), + None, + None, + None, + false, + None, + ), + pallet_evm_accounts::Error::::BoundAddressCannotBeUsed + ); + }); + } } mod standard_precompiles { diff --git a/pallets/evm-accounts/src/lib.rs b/pallets/evm-accounts/src/lib.rs index c4cfcf236..9a2e389c3 100644 --- a/pallets/evm-accounts/src/lib.rs +++ b/pallets/evm-accounts/src/lib.rs @@ -111,6 +111,8 @@ pub mod pallet { TruncatedAccountAlreadyUsed, /// Address is already bound AddressAlreadyBound, + /// Bound address cannot be used + BoundAddressCannotBeUsed, } #[pallet::hooks] diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 46886ba69..71e22c703 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -484,6 +484,10 @@ impl_runtime_apis! { _ => (None, None), }; + if EVMAccounts::bound_account_id(from).is_some() { + return Err(pallet_evm_accounts::Error::::BoundAddressCannotBeUsed.into()) + }; + ::Runner::call( from, to, From ffe0780a0e2b47124a99aad34372b921c8da8408 Mon Sep 17 00:00:00 2001 From: Roznovjak Date: Mon, 19 Feb 2024 23:36:42 +0100 Subject: [PATCH 16/16] add comment --- runtime/hydradx/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/hydradx/src/lib.rs b/runtime/hydradx/src/lib.rs index 71e22c703..d1bd56142 100644 --- a/runtime/hydradx/src/lib.rs +++ b/runtime/hydradx/src/lib.rs @@ -484,6 +484,7 @@ impl_runtime_apis! { _ => (None, None), }; + // don't allow calling EVM RPC or Runtime API from a bound address if EVMAccounts::bound_account_id(from).is_some() { return Err(pallet_evm_accounts::Error::::BoundAddressCannotBeUsed.into()) };