diff --git a/Cargo.lock b/Cargo.lock
index a13fd5143..059beaad2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -528,6 +528,7 @@ dependencies = [
"pallet-assets",
"pallet-evm",
"pallet-evm-precompile-assets-erc20",
+ "pallet-evm-precompile-dispatch",
"pallet-xc-asset-config",
"parity-scale-codec",
"scale-info",
@@ -4936,6 +4937,7 @@ dependencies = [
"pallet-ethereum-checked",
"pallet-evm",
"pallet-evm-precompile-assets-erc20",
+ "pallet-evm-precompile-dispatch",
"pallet-proxy",
"pallet-unified-accounts",
"pallet-utility",
diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml
index 8f0effb94..737ff4306 100644
--- a/primitives/Cargo.toml
+++ b/primitives/Cargo.toml
@@ -39,6 +39,7 @@ pallet-evm = { workspace = true }
# Astar pallets & dependencies
pallet-evm-precompile-assets-erc20 = { workspace = true }
+pallet-evm-precompile-dispatch = { workspace = true }
pallet-xc-asset-config = { workspace = true }
[features]
@@ -64,5 +65,6 @@ std = [
"pallet-assets/std",
"pallet-evm/std",
"pallet-evm-precompile-assets-erc20/std",
+ "pallet-evm-precompile-dispatch/std",
]
runtime-benchmarks = ["xcm-builder/runtime-benchmarks", "pallet-assets/runtime-benchmarks"]
diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs
index 9cf71cb37..010feba29 100644
--- a/primitives/src/lib.rs
+++ b/primitives/src/lib.rs
@@ -32,6 +32,9 @@ pub mod xvm;
/// EVM primitives.
pub mod evm;
+/// Precompiles
+pub mod precompiles;
+
/// Benchmark primitives
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarks;
diff --git a/primitives/src/precompiles.rs b/primitives/src/precompiles.rs
new file mode 100644
index 000000000..26e5abef5
--- /dev/null
+++ b/primitives/src/precompiles.rs
@@ -0,0 +1,57 @@
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Astar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Astar. If not, see .
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+use core::marker::PhantomData;
+
+use fp_evm::{ExitError, PrecompileFailure};
+use frame_support::{
+ dispatch::{DispatchClass, GetDispatchInfo, Pays},
+ traits::Contains,
+};
+use pallet_evm_precompile_dispatch::DispatchValidateT;
+
+/// Struct that allows only calls based on `Filter` to pass through.
+pub struct DispatchFilterValidate>(
+ PhantomData<(RuntimeCall, Filter)>,
+);
+
+impl>
+ DispatchValidateT for DispatchFilterValidate
+{
+ fn validate_before_dispatch(
+ _origin: &AccountId,
+ call: &RuntimeCall,
+ ) -> Option {
+ let info = call.get_dispatch_info();
+ let paid_normal_call = info.pays_fee == Pays::Yes && info.class == DispatchClass::Normal;
+ if !paid_normal_call {
+ return Some(PrecompileFailure::Error {
+ exit_status: ExitError::Other("invalid call".into()),
+ });
+ }
+ if Filter::contains(call) {
+ None
+ } else {
+ Some(PrecompileFailure::Error {
+ exit_status: ExitError::Other("call filtered out".into()),
+ })
+ }
+ }
+}
diff --git a/runtime/astar/src/lib.rs b/runtime/astar/src/lib.rs
index 92578b231..5ac39086f 100644
--- a/runtime/astar/src/lib.rs
+++ b/runtime/astar/src/lib.rs
@@ -22,6 +22,7 @@
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"]
+pub use crate::precompiles::WhitelistedCalls;
pub use astar_primitives::{
evm::EvmRevertCodeHandler, xcm::AssetLocationIdConverter, AccountId, Address, AssetId, Balance,
BlockNumber, Hash, Header, Index, Signature,
diff --git a/runtime/astar/src/precompiles.rs b/runtime/astar/src/precompiles.rs
index cc0d81180..ffe0e2cbd 100644
--- a/runtime/astar/src/precompiles.rs
+++ b/runtime/astar/src/precompiles.rs
@@ -18,6 +18,9 @@
//! The Astar Network EVM precompiles. This can be compiled with ``#[no_std]`, ready for Wasm.
+use crate::RuntimeCall;
+use astar_primitives::precompiles::DispatchFilterValidate;
+use frame_support::traits::Contains;
use pallet_evm::{
ExitRevert, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
PrecompileResult, PrecompileSet,
@@ -45,6 +48,23 @@ use xcm::latest::prelude::MultiLocation;
/// to Erc20AssetsPrecompileSet
pub const ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4];
+/// Filter that only allows whitelisted runtime call to pass through dispatch precompile
+
+pub struct WhitelistedCalls;
+
+impl Contains for WhitelistedCalls {
+ fn contains(t: &RuntimeCall) -> bool {
+ match t {
+ RuntimeCall::Utility(pallet_utility::Call::batch { calls })
+ | RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => {
+ calls.iter().all(|call| WhitelistedCalls::contains(call))
+ }
+ RuntimeCall::DappsStaking(_) => true,
+ RuntimeCall::Assets(pallet_assets::Call::transfer { .. }) => true,
+ _ => false,
+ }
+ }
+}
/// The PrecompileSet installed in the Astar runtime.
#[derive(Debug, Default, Clone, Copy)]
pub struct AstarNetworkPrecompiles(PhantomData<(R, C)>);
@@ -74,7 +94,7 @@ where
DappsStakingWrapper: Precompile,
BatchPrecompile: Precompile,
XcmPrecompile: Precompile,
- Dispatch: Precompile,
+ Dispatch>: Precompile,
R: pallet_evm::Config
+ pallet_assets::Config
+ pallet_xcm::Config
@@ -106,7 +126,10 @@ where
a if a == hash(9) => Some(Blake2F::execute(handle)),
// nor Ethereum precompiles :
a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)),
- a if a == hash(1025) => Some(Dispatch::::execute(handle)),
+ a if a == hash(1025) => Some(Dispatch::<
+ R,
+ DispatchFilterValidate,
+ >::execute(handle)),
a if a == hash(1026) => Some(ECRecoverPublicKey::execute(handle)),
a if a == hash(1027) => Some(Ed25519Verify::execute(handle)),
// Astar precompiles (starts from 0x5000):
diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs
index f183bc7c5..be79454ca 100644
--- a/runtime/local/src/lib.rs
+++ b/runtime/local/src/lib.rs
@@ -63,6 +63,7 @@ pub use astar_primitives::{
Balance, BlockNumber, Hash, Header, Index, Signature,
};
+pub use crate::precompiles::WhitelistedCalls;
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
diff --git a/runtime/local/src/precompiles.rs b/runtime/local/src/precompiles.rs
index 8520a7522..b2ccb203b 100644
--- a/runtime/local/src/precompiles.rs
+++ b/runtime/local/src/precompiles.rs
@@ -18,6 +18,9 @@
//! The Local EVM precompiles. This can be compiled with ``#[no_std]`, ready for Wasm.
+use crate::RuntimeCall;
+use astar_primitives::precompiles::DispatchFilterValidate;
+use frame_support::traits::Contains;
use pallet_evm::{
ExitRevert, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
PrecompileResult, PrecompileSet,
@@ -43,6 +46,23 @@ use sp_std::marker::PhantomData;
/// to Erc20AssetsPrecompileSet
pub const ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4];
+/// Filter that only allows whitelisted runtime call to pass through dispatch precompile
+pub struct WhitelistedCalls;
+
+impl Contains for WhitelistedCalls {
+ fn contains(t: &RuntimeCall) -> bool {
+ match t {
+ RuntimeCall::Utility(pallet_utility::Call::batch { calls })
+ | RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => {
+ calls.iter().all(|call| WhitelistedCalls::contains(call))
+ }
+ RuntimeCall::Assets(pallet_assets::Call::transfer { .. }) => true,
+ RuntimeCall::DappsStaking(_) => true,
+ _ => false,
+ }
+ }
+}
+
/// The PrecompileSet installed in the Local runtime.
#[derive(Debug, Default, Clone, Copy)]
pub struct LocalNetworkPrecompiles(PhantomData);
@@ -72,7 +92,7 @@ where
DappsStakingWrapper: Precompile,
BatchPrecompile: Precompile,
XvmPrecompile>: Precompile,
- Dispatch: Precompile,
+ Dispatch>: Precompile,
R: pallet_evm::Config
+ pallet_xvm::Config
+ pallet_assets::Config
@@ -103,7 +123,10 @@ where
a if a == hash(9) => Some(Blake2F::execute(handle)),
// nor Ethereum precompiles :
a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)),
- a if a == hash(1025) => Some(Dispatch::::execute(handle)),
+ a if a == hash(1025) => Some(Dispatch::<
+ R,
+ DispatchFilterValidate,
+ >::execute(handle)),
a if a == hash(1026) => Some(ECRecoverPublicKey::execute(handle)),
a if a == hash(1027) => Some(Ed25519Verify::execute(handle)),
// Astar precompiles (starts from 0x5000):
diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs
index cbe0283f8..26908d4b7 100644
--- a/runtime/shibuya/src/lib.rs
+++ b/runtime/shibuya/src/lib.rs
@@ -73,6 +73,8 @@ pub use astar_primitives::{
AccountId, Address, AssetId, Balance, BlockNumber, Hash, Header, Index, Signature,
};
+pub use crate::precompiles::WhitelistedCalls;
+
use pallet_evm_precompile_assets_erc20::AddressToAssetId;
#[cfg(any(feature = "std", test))]
diff --git a/runtime/shibuya/src/precompiles.rs b/runtime/shibuya/src/precompiles.rs
index 3761e33ff..d87b7e31f 100644
--- a/runtime/shibuya/src/precompiles.rs
+++ b/runtime/shibuya/src/precompiles.rs
@@ -18,6 +18,9 @@
//! The Shibuya Network EVM precompiles. This can be compiled with ``#[no_std]`, ready for Wasm.
+use crate::RuntimeCall;
+use astar_primitives::precompiles::DispatchFilterValidate;
+use frame_support::traits::Contains;
use pallet_evm::{
ExitRevert, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
PrecompileResult, PrecompileSet,
@@ -46,6 +49,23 @@ use xcm::latest::prelude::MultiLocation;
/// to Erc20AssetsPrecompileSet
pub const ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4];
+/// Filter that only allows whitelisted runtime call to pass through dispatch precompile
+pub struct WhitelistedCalls;
+
+impl Contains for WhitelistedCalls {
+ fn contains(t: &RuntimeCall) -> bool {
+ match t {
+ RuntimeCall::Utility(pallet_utility::Call::batch { calls })
+ | RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => {
+ calls.iter().all(|call| WhitelistedCalls::contains(call))
+ }
+ RuntimeCall::Assets(pallet_assets::Call::transfer { .. }) => true,
+ RuntimeCall::DappsStaking(_) => true,
+ _ => false,
+ }
+ }
+}
+
/// The PrecompileSet installed in the Shiden runtime.
#[derive(Debug, Default, Clone, Copy)]
pub struct ShibuyaNetworkPrecompiles(PhantomData<(R, C)>);
@@ -77,7 +97,7 @@ where
XcmPrecompile: Precompile,
BatchPrecompile: Precompile,
XvmPrecompile>: Precompile,
- Dispatch: Precompile,
+ Dispatch>: Precompile,
R: pallet_evm::Config
+ pallet_assets::Config
+ pallet_xcm::Config
@@ -110,7 +130,10 @@ where
a if a == hash(9) => Some(Blake2F::execute(handle)),
// nor Ethereum precompiles :
a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)),
- a if a == hash(1025) => Some(Dispatch::::execute(handle)),
+ a if a == hash(1025) => Some(Dispatch::<
+ R,
+ DispatchFilterValidate,
+ >::execute(handle)),
a if a == hash(1026) => Some(ECRecoverPublicKey::execute(handle)),
a if a == hash(1027) => Some(Ed25519Verify::execute(handle)),
// Astar precompiles (starts from 0x5000):
diff --git a/runtime/shiden/src/lib.rs b/runtime/shiden/src/lib.rs
index ecb37a6bc..e49698d88 100644
--- a/runtime/shiden/src/lib.rs
+++ b/runtime/shiden/src/lib.rs
@@ -65,6 +65,7 @@ use sp_runtime::{
};
use sp_std::prelude::*;
+pub use crate::precompiles::WhitelistedCalls;
pub use astar_primitives::{
evm::EvmRevertCodeHandler, xcm::AssetLocationIdConverter, AccountId, Address, AssetId, Balance,
BlockNumber, Hash, Header, Index, Signature,
diff --git a/runtime/shiden/src/precompiles.rs b/runtime/shiden/src/precompiles.rs
index 62b1023e5..9e714eceb 100644
--- a/runtime/shiden/src/precompiles.rs
+++ b/runtime/shiden/src/precompiles.rs
@@ -18,6 +18,9 @@
//! The Shiden Network EVM precompiles. This can be compiled with ``#[no_std]`, ready for Wasm.
+use crate::RuntimeCall;
+use astar_primitives::precompiles::DispatchFilterValidate;
+use frame_support::traits::Contains;
use pallet_evm::{
ExitRevert, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
PrecompileResult, PrecompileSet,
@@ -45,6 +48,23 @@ use xcm::latest::prelude::MultiLocation;
/// to Erc20AssetsPrecompileSet
pub const ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4];
+/// Filter that only allows whitelisted runtime call to pass through dispatch precompile
+pub struct WhitelistedCalls;
+
+impl Contains for WhitelistedCalls {
+ fn contains(t: &RuntimeCall) -> bool {
+ match t {
+ RuntimeCall::Utility(pallet_utility::Call::batch { calls })
+ | RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => {
+ calls.iter().all(|call| WhitelistedCalls::contains(call))
+ }
+ RuntimeCall::DappsStaking(_) => true,
+ RuntimeCall::Assets(pallet_assets::Call::transfer { .. }) => true,
+ _ => false,
+ }
+ }
+}
+
/// The PrecompileSet installed in the Shiden runtime.
#[derive(Debug, Default, Clone, Copy)]
pub struct ShidenNetworkPrecompiles(PhantomData<(R, C)>);
@@ -74,7 +94,7 @@ where
DappsStakingWrapper: Precompile,
BatchPrecompile: Precompile,
XcmPrecompile: Precompile,
- Dispatch: Precompile,
+ Dispatch>: Precompile,
R: pallet_evm::Config
+ pallet_assets::Config
+ pallet_xcm::Config
@@ -106,7 +126,10 @@ where
a if a == hash(9) => Some(Blake2F::execute(handle)),
// nor Ethereum precompiles :
a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)),
- a if a == hash(1025) => Some(Dispatch::::execute(handle)),
+ a if a == hash(1025) => Some(Dispatch::<
+ R,
+ DispatchFilterValidate,
+ >::execute(handle)),
a if a == hash(1026) => Some(ECRecoverPublicKey::execute(handle)),
a if a == hash(1027) => Some(Ed25519Verify::execute(handle)),
// Astar precompiles (starts from 0x5000):
diff --git a/tests/integration/Cargo.toml b/tests/integration/Cargo.toml
index 091dff78b..22779b38b 100644
--- a/tests/integration/Cargo.toml
+++ b/tests/integration/Cargo.toml
@@ -35,6 +35,7 @@ sp-runtime = { workspace = true }
# astar dependencies
pallet-ethereum-checked = { workspace = true }
pallet-evm-precompile-assets-erc20 = { workspace = true }
+pallet-evm-precompile-dispatch = { workspace = true }
pallet-unified-accounts = { workspace = true }
precompile-utils = { workspace = true }
diff --git a/tests/integration/src/dispatch_precompile_filter.rs b/tests/integration/src/dispatch_precompile_filter.rs
new file mode 100644
index 000000000..1099d592f
--- /dev/null
+++ b/tests/integration/src/dispatch_precompile_filter.rs
@@ -0,0 +1,223 @@
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Astar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Astar. If not, see .
+#![cfg(test)]
+
+use crate::setup::*;
+use astar_primitives::precompiles::DispatchFilterValidate;
+use fp_evm::{ExitError, PrecompileFailure};
+use frame_support::{
+ dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays},
+ traits::Contains,
+};
+use pallet_evm_precompile_dispatch::DispatchValidateT;
+use parity_scale_codec::Compact;
+
+/// Whitelisted Calls are defined in the runtime
+#[test]
+fn filter_accepts_batch_call_with_whitelisted_calls() {
+ ExtBuilder::default().build().execute_with(|| {
+ let contract = SmartContract::Evm(H160::repeat_byte(0x01));
+ let inner_call = RuntimeCall::DappsStaking(DappStakingCall::Call::claim_staker {
+ contract_id: contract.clone(),
+ });
+ let call = RuntimeCall::Utility(UtilityCall::batch {
+ calls: vec![inner_call],
+ });
+ assert!(WhitelistedCalls::contains(&call));
+ });
+}
+
+#[test]
+fn filter_rejects_non_whitelisted_batch_calls() {
+ ExtBuilder::default().build().execute_with(|| {
+ // CASE1 - only non whitelisted calls
+ let transfer_call = RuntimeCall::Balances(BalancesCall::transfer {
+ dest: MultiAddress::Id(CAT),
+ value: 100_000_000_000,
+ });
+ let transfer = Box::new(transfer_call);
+ let call = Box::new(RuntimeCall::Utility(UtilityCall::batch {
+ calls: vec![*transfer.clone()],
+ }));
+
+ // Utility call containing Balances Call
+ assert!(!WhitelistedCalls::contains(&call));
+
+ // CASE 2 - now whitelisted mixed with whitelisted calls
+
+ let contract = SmartContract::Evm(H160::repeat_byte(0x01));
+ let staking_call = RuntimeCall::DappsStaking(DappStakingCall::Call::claim_staker {
+ contract_id: contract.clone(),
+ });
+ let staking = Box::new(staking_call);
+
+ let call = Box::new(RuntimeCall::Utility(UtilityCall::batch {
+ calls: vec![*transfer, *staking.clone()],
+ }));
+
+ // Utility call containing Balances Call and Dappsstaking Call Fails filter
+ assert!(!WhitelistedCalls::contains(&call));
+ });
+}
+
+#[test]
+fn filter_accepts_whitelisted_calls() {
+ ExtBuilder::default().build().execute_with(|| {
+ // Dappstaking call works
+ let contract = SmartContract::Evm(H160::repeat_byte(0x01));
+ let stake_call = RuntimeCall::DappsStaking(DappStakingCall::Call::claim_staker {
+ contract_id: contract.clone(),
+ });
+ assert!(WhitelistedCalls::contains(&stake_call));
+
+ // Pallet::Assets transfer call works
+ let transfer_call = RuntimeCall::Assets(pallet_assets::Call::transfer {
+ id: Compact(0),
+ target: MultiAddress::Address20(H160::repeat_byte(0x01).into()),
+ amount: 100,
+ });
+ assert!(WhitelistedCalls::contains(&transfer_call));
+ });
+}
+
+#[test]
+fn filter_rejects_non_whitelisted_calls() {
+ ExtBuilder::default().build().execute_with(|| {
+ // Random call from non whitelisted pallet doesn't work
+ let transfer_call = RuntimeCall::Balances(BalancesCall::transfer {
+ dest: MultiAddress::Id(CAT),
+ value: 100_000_000_000,
+ });
+ assert!(!WhitelistedCalls::contains(&transfer_call));
+
+ // Only `transfer` call from pallet assets work
+ // Other random call from Pallet Assets doesn't work
+ let thaw_asset_call =
+ RuntimeCall::Assets(pallet_assets::Call::thaw_asset { id: Compact(0) });
+ assert!(!WhitelistedCalls::contains(&thaw_asset_call));
+ })
+}
+
+#[test]
+fn filter_accepts_whitelisted_batch_all_calls() {
+ ExtBuilder::default().build().execute_with(|| {
+ let contract = SmartContract::Evm(H160::repeat_byte(0x01));
+ let inner_call1 = RuntimeCall::DappsStaking(DappStakingCall::Call::claim_staker {
+ contract_id: contract.clone(),
+ });
+ let inner_call2 = RuntimeCall::DappsStaking(DappStakingCall::Call::claim_staker {
+ contract_id: contract.clone(),
+ });
+ let transfer_call = RuntimeCall::Assets(pallet_assets::Call::transfer {
+ id: Compact(0),
+ target: MultiAddress::Address20(H160::repeat_byte(0x01).into()),
+ amount: 100,
+ });
+ let call = RuntimeCall::Utility(UtilityCall::batch_all {
+ calls: vec![inner_call1, inner_call2, transfer_call],
+ });
+ assert!(WhitelistedCalls::contains(&call));
+ });
+}
+
+#[test]
+fn test_correct_dispatch_info_works() {
+ ExtBuilder::default().build().execute_with(|| {
+ // Mock implementation
+ struct Filter;
+ struct AccountId;
+ enum RuntimeCall {
+ System,
+ DappsStaking,
+ }
+ impl GetDispatchInfo for RuntimeCall {
+ fn get_dispatch_info(&self) -> DispatchInfo {
+ // Default is Pays::Yes and DispatchCall::Normal
+ DispatchInfo::default()
+ }
+ }
+ impl Contains for Filter {
+ fn contains(t: &RuntimeCall) -> bool {
+ match t {
+ RuntimeCall::DappsStaking => true,
+ _ => false,
+ }
+ }
+ }
+ // Case 1: Whitelisted Call with correct Dispatch info
+ assert_eq!(
+ DispatchFilterValidate::::validate_before_dispatch(
+ &AccountId,
+ &RuntimeCall::DappsStaking
+ ),
+ Option::None
+ );
+ // Case 2: Non-Whitelisted Call with correct Dispatch Info
+ assert_eq!(
+ DispatchFilterValidate::::validate_before_dispatch(
+ &AccountId,
+ &RuntimeCall::System
+ ),
+ Option::Some(PrecompileFailure::Error {
+ exit_status: ExitError::Other("call filtered out".into()),
+ })
+ );
+ });
+}
+
+#[test]
+fn test_incorrect_dispatch_info_fails() {
+ ExtBuilder::default().build().execute_with(|| {
+ // Mock implementation
+ struct Filter;
+ struct AccountId;
+ enum RuntimeCall {
+ System,
+ DappsStaking,
+ }
+ impl GetDispatchInfo for RuntimeCall {
+ fn get_dispatch_info(&self) -> DispatchInfo {
+ DispatchInfo {
+ weight: Weight::default(),
+ class: DispatchClass::Normal,
+ // Should have been Pays::Yes for call to pass
+ pays_fee: Pays::No,
+ }
+ }
+ }
+ impl Contains for Filter {
+ fn contains(t: &RuntimeCall) -> bool {
+ match t {
+ RuntimeCall::DappsStaking => true,
+ _ => false,
+ }
+ }
+ }
+
+ // WhiteListed Call fails because of incorrect DispatchInfo
+ assert_eq!(
+ DispatchFilterValidate::::validate_before_dispatch(
+ &AccountId,
+ &RuntimeCall::DappsStaking
+ ),
+ Option::Some(PrecompileFailure::Error {
+ exit_status: ExitError::Other("invalid call".into()),
+ })
+ );
+ })
+}
diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs
index 9b599b80f..d43b84541 100644
--- a/tests/integration/src/lib.rs
+++ b/tests/integration/src/lib.rs
@@ -34,3 +34,5 @@ mod xvm;
#[cfg(feature = "shibuya")]
mod account;
+#[cfg(any(feature = "shibuya", feature = "shiden", feature = "astar"))]
+mod dispatch_precompile_filter;