From 123c2b0527edb08e40db0cb9bedbf8bff949cade Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Tue, 23 Jan 2024 16:57:55 +0100 Subject: [PATCH] Added dispatch lockdrop precompile --- Cargo.lock | 26 ++ Cargo.toml | 1 + precompiles/dispatch-lockdrop/Cargo.toml | 53 +++++ precompiles/dispatch-lockdrop/src/lib.rs | 219 +++++++++++++++++ precompiles/dispatch-lockdrop/src/mock.rs | 261 +++++++++++++++++++++ precompiles/dispatch-lockdrop/src/tests.rs | 80 +++++++ runtime/local/Cargo.toml | 2 + runtime/local/src/precompiles.rs | 12 +- 8 files changed, 652 insertions(+), 2 deletions(-) create mode 100644 precompiles/dispatch-lockdrop/Cargo.toml create mode 100644 precompiles/dispatch-lockdrop/src/lib.rs create mode 100644 precompiles/dispatch-lockdrop/src/mock.rs create mode 100644 precompiles/dispatch-lockdrop/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 6678b9d47e..a1095a2c5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6074,6 +6074,7 @@ dependencies = [ "pallet-evm-precompile-bn128", "pallet-evm-precompile-dapp-staking-v3", "pallet-evm-precompile-dispatch", + "pallet-evm-precompile-dispatch-lockdrop", "pallet-evm-precompile-ed25519", "pallet-evm-precompile-modexp", "pallet-evm-precompile-rescue-lockdrop", @@ -8036,6 +8037,31 @@ dependencies = [ "pallet-evm", ] +[[package]] +name = "pallet-evm-precompile-dispatch-lockdrop" +version = "0.1.0" +dependencies = [ + "astar-primitives", + "ethers", + "fp-evm", + "frame-support", + "frame-system", + "libsecp256k1", + "log", + "pallet-balances", + "pallet-evm", + "pallet-evm-precompile-dispatch", + "pallet-timestamp", + "pallet-unified-accounts", + "parity-scale-codec", + "precompile-utils", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-evm-precompile-ed25519" version = "2.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 032aef60a7..e6d32066b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -300,6 +300,7 @@ pallet-evm-precompile-dapps-staking = { path = "./precompiles/dapps-staking", de pallet-evm-precompile-dapp-staking-v3 = { path = "./precompiles/dapp-staking-v3", default-features = false } pallet-evm-precompile-unified-accounts = { path = "./precompiles/unified-accounts", default-features = false } pallet-evm-precompile-rescue-lockdrop = { path = "./precompiles/rescue-lockdrop", default-features = false } +pallet-evm-precompile-dispatch-lockdrop = { path = "./precompiles/dispatch-lockdrop", default-features = false } pallet-chain-extension-xvm = { path = "./chain-extensions/xvm", default-features = false } pallet-chain-extension-assets = { path = "./chain-extensions/pallet-assets", default-features = false } diff --git a/precompiles/dispatch-lockdrop/Cargo.toml b/precompiles/dispatch-lockdrop/Cargo.toml new file mode 100644 index 0000000000..acb30deebc --- /dev/null +++ b/precompiles/dispatch-lockdrop/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "pallet-evm-precompile-dispatch-lockdrop" +description = "Evm Precompile to dispatch calls for lockdrop accounts" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +frame-support = { workspace = true } +fp-evm = { workspace = true } +pallet-evm = { workspace = true } +libsecp256k1 = { workspace = true, features = ["hmac", "static-context"] } +log = { workspace = true } +precompile-utils = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-std = { workspace = true } +pallet-unified-accounts = { workspace = true } +pallet-evm-precompile-dispatch = { workspace = true } + +[dev-dependencies] +ethers = { workspace = true } +parity-scale-codec = { package = "parity-scale-codec", workspace = true } +scale-info = { workspace = true } +frame-system = { workspace = true } +pallet-balances = { workspace = true } +pallet-timestamp = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-std = { workspace = true } +sp-runtime = { workspace = true } +precompile-utils = { workspace = true, features = ["testing"] } +astar-primitives = { workspace = true } + +[features] +default = ["std"] +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", + "libsecp256k1/std", + "pallet-evm/std", + "pallet-evm-precompile-dispatch/std", +] \ No newline at end of file diff --git a/precompiles/dispatch-lockdrop/src/lib.rs b/precompiles/dispatch-lockdrop/src/lib.rs new file mode 100644 index 0000000000..4956c15357 --- /dev/null +++ b/precompiles/dispatch-lockdrop/src/lib.rs @@ -0,0 +1,219 @@ +// 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)] + +extern crate alloc; + +use core::marker::PhantomData; +use fp_evm::PrecompileHandle; +use frame_support::pallet_prelude::IsType; +use frame_support::{codec::DecodeLimit as _, dispatch::Pays, traits::Get}; +use frame_support::{ + dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo}, + traits::ConstU32, +}; +use frame_system::Config; +use pallet_evm::GasWeightMapping; +use precompile_utils::prelude::{BoundedBytes, UnboundedBytes}; +use precompile_utils::EvmResult; +use sp_core::ecdsa; +use sp_core::ecdsa::Signature; +use sp_core::{crypto::AccountId32, H160, H256}; +use sp_io::hashing::keccak_256; +use sp_std::vec::Vec; +use pallet_evm_precompile_dispatch::DispatchValidateT; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +// ECDSA signature bytes +type ECDSASignatureBytes = ConstU32<65>; + +// `DecodeLimit` specifies the max depth a call can use when decoding, as unbounded depth +// can be used to overflow the stack. +// Default value is 8, which is the same as in XCM call decoding. +pub struct DispatchLockdrop>( + PhantomData<(Runtime, DispatchValidator, DecodeLimit)>, +); + +#[precompile_utils::precompile] +impl + DispatchLockdrop +where + Runtime: pallet_evm::Config + pallet_unified_accounts::Config, + ::RuntimeOrigin: From>, + Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, + ::AccountId: IsType, + ::AccountId: From<[u8; 32]>, + DispatchValidator: DispatchValidateT<::AccountId, ::RuntimeCall>, + DecodeLimit: Get, +{ + #[precompile::public("dispatch_lockdrop_call(bytes,bytes32,bytes)")] + fn dispatch_lockdrop_call( + handle: &mut impl PrecompileHandle, + call: UnboundedBytes, + account_id: H256, + signature: BoundedBytes, + ) -> EvmResult { + log::trace!( + target: "dispatch-lockdrop", + "raw arguments: call: {:?}, account_id: {:?}, signature: {:?}", + call, + account_id, + signature + ); + + let target_gas = handle.gas_limit(); + + let caller: H160 = handle.context().caller.into(); + let input: Vec = call.into(); + let signature_bytes: Vec = signature.into(); + let account_id = AccountId32::new(account_id.into()).into(); + + // 1. Decode the call + let call = + match Runtime::RuntimeCall::decode_with_depth_limit(DecodeLimit::get(), &mut &*input) { + Ok(c) => c, + Err(_) => { + log::trace!( + target: "dispatch-lockdrop", + "Error: could not decode call" + ); + return Ok(false); + } + }; + + // 2. Check that gas limit is not exceeded + let info = call.get_dispatch_info(); + if let Some(gas) = target_gas { + let valid_weight = info.weight.ref_time() + <= Runtime::GasWeightMapping::gas_to_weight(gas, false).ref_time(); + if !valid_weight { + log::trace!( + target: "dispatch-lockdrop", + "Error: gas limit exceeded" + ); + return Ok(false); + } + } + + // 3. Recover the ECDSA Public key from the signature + let signature_opt = match Self::parse_signature(&signature_bytes) { + Some(s) => s, + None => { + log::trace!( + target: "dispatch-lockdrop", + "Error: could not parse signature" + ); + return Ok(false); + } + }; + let pubkey = match >::recover_pubkey( + &account_id, + signature_opt.as_ref(), + ) { + Some(k) => k, + None => { + log::trace!( + target: "dispatch-lockdrop", + "Error: could not recover pubkey from signature" + ); + return Ok(false); + } + }; + + // 4. Ensure that the caller matches the recovered EVM address from the signature + if caller != Self::get_evm_address_from_pubkey(&pubkey) { + log::trace!( + target: "dispatch-lockdrop", + "Error: caller does not match calculated EVM address" + ); + return Ok(false); + } + + // 5. Derive the AccountId from the ECDSA compressed Public key + let origin = match Self::get_account_id_from_pubkey(pubkey) { + Some(a) => a, + None => { + log::trace!( + target: "dispatch-lockdrop", + "Error: could not derive AccountId from pubkey" + ); + return Ok(false); + } + }; + + // 6. validate the call + if let Some(_) = DispatchValidator::validate_before_dispatch(&origin, &call) { + return Ok(false); + } + + handle + .record_external_cost(Some(info.weight.ref_time()), Some(info.weight.proof_size()))?; + + match call.dispatch(Some(origin).into()) { + Ok(post_info) => { + if post_info.pays_fee(&info) == Pays::Yes { + let actual_weight = post_info.actual_weight.unwrap_or(info.weight); + let cost = Runtime::GasWeightMapping::weight_to_gas(actual_weight); + handle.record_cost(cost)?; + + handle.refund_external_cost( + Some( + info.weight + .ref_time() + .saturating_sub(actual_weight.ref_time()), + ), + Some( + info.weight + .proof_size() + .saturating_sub(actual_weight.proof_size()), + ), + ); + } + + Ok(true) + } + Err(e) => { + log::trace!( + target: "rescue-lockdrop-precompile:claim_lock_drop_account", + "Error: {:?}", + e + ); + Ok(false) + } + } + } + + fn get_account_id_from_pubkey(pubkey: [u8; 64]) -> Option<::AccountId> { + libsecp256k1::PublicKey::parse_slice(&pubkey, None) + .map(|k| sp_io::hashing::blake2_256(k.serialize_compressed().as_ref()).into()) + .ok() + } + + fn parse_signature(signature_bytes: &Vec) -> Option { + ecdsa::Signature::from_slice(&signature_bytes[..]) + } + + fn get_evm_address_from_pubkey(pubkey: &[u8]) -> H160 { + H160::from(H256::from_slice(&keccak_256(pubkey))) + } +} diff --git a/precompiles/dispatch-lockdrop/src/mock.rs b/precompiles/dispatch-lockdrop/src/mock.rs new file mode 100644 index 0000000000..bb4f3b2402 --- /dev/null +++ b/precompiles/dispatch-lockdrop/src/mock.rs @@ -0,0 +1,261 @@ +// 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 std::marker::PhantomData; + +use fp_evm::{IsPrecompileResult, Precompile}; +use frame_support::{construct_runtime, parameter_types, traits::ConstU64, weights::Weight}; +pub use pallet_evm::{ + AddressMapping, EnsureAddressNever, EnsureAddressRoot, PrecompileResult, PrecompileSet, +}; +use parity_scale_codec::Encode; +use sp_core::{keccak_256, H160, H256}; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, ConstU32, IdentityLookup}, + AccountId32, +}; + +use ethers::contract::{Eip712, EthAbiType}; +use ethers::prelude::transaction::eip712::Eip712; + +use frame_support::traits::Contains; + +use astar_primitives::evm::HashedDefaultMappings; +use astar_primitives::precompiles::DispatchFilterValidate; +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 ONE: u128 = 1_000_000_000_000_000_000; +pub const ALICE: AccountId32 = AccountId32::new([1u8; 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, + ) +} + +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>; +} + +pub struct WhitelistedCalls(PhantomData); + +impl Contains for WhitelistedCalls { + fn contains(_t: &T) -> bool { + true + } +} + +#[derive(Debug, Clone, Copy)] +pub struct TestPrecompileSet(PhantomData); + +impl PrecompileSet for TestPrecompileSet +where + R: pallet_evm::Config, + DispatchLockdrop>>: + Precompile, +{ + fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { + match handle.code_address() { + a if a == PRECOMPILE_ADDRESS => Some(DispatchLockdrop::< + R, + DispatchFilterValidate>, + >::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); +} + +pub type PrecompileCall = DispatchLockdropCall< + TestRuntime, + DispatchFilterValidate< + ::RuntimeCall, + WhitelistedCalls<::RuntimeCall>, + >, + ConstU32<8>, +>; + +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/dispatch-lockdrop/src/tests.rs b/precompiles/dispatch-lockdrop/src/tests.rs new file mode 100644 index 0000000000..258dd39840 --- /dev/null +++ b/precompiles/dispatch-lockdrop/src/tests.rs @@ -0,0 +1,80 @@ +// 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 ethers::prelude::H256; +use frame_support::traits::Currency; +use sp_core::crypto::AccountId32; + +use crate::mock::*; + +use parity_scale_codec::Encode; +use precompile_utils::testing::*; +use sp_core::ecdsa; + +fn precompiles() -> TestPrecompileSet { + PrecompilesValue::get() +} + +#[test] +fn unify_lockdrop_account_works() { + ExtBuilder::default().build().execute_with(|| { + // Transfer balance to Alice + let call = RuntimeCall::Balances(pallet_balances::Call::transfer { + dest: ALICE, + value: 15 * ONE, + }); + // Sanity check - Alice holds no Balance + assert_eq!(Balances::free_balance(ALICE), 0); + + // Get Alice EVM address based on the Public Key + let alice_eth = UnifiedAccounts::eth_address(&alice_secret()); + // Get derived AccountId from the Blake2b hash of the compressed ECDSA Public key + let account_id = account_id(&alice_secret()); + // Fund this account (fund the lockdrop account) + let _ = Balances::deposit_creating(&account_id, ONE * 20); + // Sign the EIP712 payload + let sig = get_evm_signature(&account_id, &alice_secret()); + + precompiles() + .prepare_test( + alice_eth, + PRECOMPILE_ADDRESS, + PrecompileCall::dispatch_lockdrop_call { + call: call.encode().into(), + account_id: H256::from_slice(account_id.as_ref()), + signature: sig.into(), + }, + ) + .expect_no_logs() + .execute_returns(true); + + // Get Balance of ALICE in pallet balances + assert_eq!(Balances::free_balance(ALICE), 15 * ONE); + }); +} + +fn account_id(secret: &libsecp256k1::SecretKey) -> AccountId32 { + sp_io::hashing::blake2_256( + ecdsa::Public::from_full( + &libsecp256k1::PublicKey::from_secret_key(secret).serialize()[1..65], + ) + .unwrap() + .as_ref(), + ) + .into() +} diff --git a/runtime/local/Cargo.toml b/runtime/local/Cargo.toml index 96e6138426..119396c8c5 100644 --- a/runtime/local/Cargo.toml +++ b/runtime/local/Cargo.toml @@ -75,6 +75,7 @@ pallet-dapp-staking-v3 = { workspace = true } pallet-dapps-staking = { workspace = true } pallet-dynamic-evm-base-fee = { workspace = true } pallet-evm-precompile-assets-erc20 = { workspace = true } +pallet-evm-precompile-dispatch-lockdrop = { workspace = true } pallet-evm-precompile-dapp-staking-v3 = { workspace = true } pallet-evm-precompile-rescue-lockdrop = { workspace = true } pallet-evm-precompile-sr25519 = { workspace = true } @@ -149,6 +150,7 @@ std = [ "pallet-evm-precompile-unified-accounts/std", "pallet-evm-precompile-xvm/std", "pallet-evm-precompile-rescue-lockdrop/std", + "pallet-evm-precompile-dispatch-lockdrop/std", "pallet-grandpa/std", "pallet-insecure-randomness-collective-flip/std", "pallet-preimage/std", diff --git a/runtime/local/src/precompiles.rs b/runtime/local/src/precompiles.rs index 5e73e99277..ffe45fdd62 100644 --- a/runtime/local/src/precompiles.rs +++ b/runtime/local/src/precompiles.rs @@ -21,11 +21,13 @@ use crate::{RuntimeCall, UnifiedAccounts}; use astar_primitives::precompiles::DispatchFilterValidate; use frame_support::{parameter_types, traits::Contains}; +use frame_support::pallet_prelude::ConstU32; use pallet_evm_precompile_assets_erc20::Erc20AssetsPrecompileSet; use pallet_evm_precompile_blake2::Blake2F; use pallet_evm_precompile_bn128::{Bn128Add, Bn128Mul, Bn128Pairing}; use pallet_evm_precompile_dapp_staking_v3::DappStakingV3Precompile; use pallet_evm_precompile_dispatch::Dispatch; +use pallet_evm_precompile_dispatch_lockdrop::DispatchLockdrop; use pallet_evm_precompile_ed25519::Ed25519Verify; use pallet_evm_precompile_modexp::Modexp; use pallet_evm_precompile_rescue_lockdrop::UnifyLockdropPrecompile; @@ -118,6 +120,12 @@ pub type LocalPrecompilesSetAt = ( (CallableByContract, CallableByPrecompile), >, PrecompileAt, UnifyLockdropPrecompile, ()>, + PrecompileAt< + AddressU64<20488>, + DispatchLockdrop, ConstU32<8>>, + // Not callable from smart contract nor precompiled, only EOA accounts + (), + >, ); pub type LocalPrecompiles = PrecompileSetBuilder< @@ -125,8 +133,8 @@ pub type LocalPrecompiles = PrecompileSetBuilder< ( // Skip precompiles if out of range. PrecompilesInRangeInclusive< - // We take range as last precompile index, UPDATE this once new prcompile is added - (AddressU64<1>, AddressU64<20486>), + // We take range as last precompile index, UPDATE this once new precompile is added + (AddressU64<1>, AddressU64<20488>), LocalPrecompilesSetAt, >, // Prefixed precompile sets (XC20)