I am currently implementing a mock for our EVM precompiles but ran into the following error when building the tests
error[E0277]: the trait bound `currencies::MultiCurrencyPrecompile<TestRuntime>: Precompile` is not satisfied
--> runtime/common/src/mock.rs:205:25
|
205 | type PrecompilesType = Precompiles;
| ^^^^^^^^^^^ the trait `Precompile` is not implemented for `currencies::MultiCurrencyPrecompile<TestRuntime>`
|
= help: the following implementations were found:
<currencies::MultiCurrencyPrecompile<Runtime> as Precompile>
However, the precompile trait is already implemented for MultiCurrencyPrecompile
.
Here is the implementation:
pub struct MultiCurrencyPrecompile<Runtime>(PhantomData<Runtime>);
impl<Runtime> Precompile for MultiCurrencyPrecompile<Runtime>
where
Runtime: currencies::Config + pallet_evm::Config + frame_system::Config,
Runtime: Erc20Mapping,
currencies::Pallet<Runtime>:
MultiCurrencyTrait<Runtime::AccountId, CurrencyId = FungibleTokenId, Balance = Balance>,
U256: From<
<<Runtime as currencies::Config>::MultiSocialCurrency as MultiCurrencyTrait<
<Runtime as frame_system::Config>::AccountId,
>>::Balance,
>,
BalanceOf<Runtime>: TryFrom<U256> + Into<U256> + EvmData,
<<Runtime as frame_system::Config>::Call as Dispatchable>::Origin: OriginTrait,
{
fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
let address = handle.code_address();
if let Some(currency_id) = Runtime::decode_evm_address(address) {
log::debug!(target: "evm", "multicurrency: currency id: {:?}", currency_id);
let result = {
let selector = match handle.read_selector() {
Ok(selector) => selector,
Err(e) => return Err(e),
};
if let Err(err) = handle.check_function_modifier(match selector {
Action::Approve | Action::Transfer | Action::TransferFrom => FunctionModifier::NonPayable,
_ => FunctionModifier::View,
}) {
return Err(err);
}
match selector {
// Local and Foreign common
Action::TotalSupply => Self::total_supply(currency_id, handle),
Action::BalanceOf => Self::balance_of(currency_id, handle),
Action::Allowance => Self::total_supply(currency_id, handle),
Action::Transfer => Self::transfer(currency_id, handle),
Action::Approve => Self::total_supply(currency_id, handle),
Action::TransferFrom => Self::total_supply(currency_id, handle),
Action::Name => Self::total_supply(currency_id, handle),
Action::Symbol => Self::total_supply(currency_id, handle),
Action::Decimals => Self::total_supply(currency_id, handle),
}
};
}
Err(PrecompileFailure::Revert {
exit_status: ExitRevert::Reverted,
output: "invalid currency id".into(),
})
}
}
Also here is the implementation of the MetaverseNetworkPrecompiles
used as Precompiles
value:
impl<R> PrecompileSet for MetaverseNetworkPrecompiles<R>
where
R: pallet_evm::Config + currencies::Config,
MultiCurrencyPrecompile<R>: Precompile,
Dispatch<R>: Precompile,
{
fn execute(&self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
let address = handle.code_address();
// if self.is_precompile(address) && address > hash(9) && handle.context().address != address {
// return Some(Err(PrecompileFailure::Revert {
// exit_status: ExitRevert::Reverted,
// output: b"cannot be called with DELEGATECALL or CALLCODE".to_vec(),
// }));
// }
match address {
// Ethereum precompiles :
a if a == hash(1) => Some(ECRecover::execute(handle)),
a if a == hash(2) => Some(Sha256::execute(handle)),
a if a == hash(3) => Some(Ripemd160::execute(handle)),
a if a == hash(4) => Some(Identity::execute(handle)),
a if a == hash(5) => Some(Modexp::execute(handle)),
a if a == hash(6) => Some(Bn128Add::execute(handle)),
a if a == hash(7) => Some(Bn128Mul::execute(handle)),
a if a == hash(8) => Some(Bn128Pairing::execute(handle)),
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::<R>::execute(handle)),
a if a == hash(1026) => Some(ECRecoverPublicKey::execute(handle)),
a if a == hash(1027) => Some(Ed25519Verify::execute(handle)),
// Metaverse Network precompiles
// If the address matches asset prefix, the we route through the asset precompile set
a if &a.to_fixed_bytes()[0..9] == ASSET_PRECOMPILE_ADDRESS_PREFIX => {
Some(MultiCurrencyPrecompile::<R>::execute(handle))
}
// Default
_ => None,
}
}
fn is_precompile(&self, address: H160) -> bool {
// sp_std::vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 1024, 1025, 1026, 1027, 400]
// .into_iter()
// .map(hash)
// .any(|x| x == address)
true
}
}
Here is also the part of the mock file which gives the build error
pub type Precompiles = MetaverseNetworkPrecompiles<TestRuntime>;
parameter_types! {
pub NetworkContractSource: H160 = H160::from_low_u64_be(1);
pub const ChainId: u64 = 2042;
pub BlockGasLimit: U256 = U256::from(u32::max_value());
pub PrecompilesValue: Precompiles = MetaverseNetworkPrecompiles::<_>::new();
}
impl pallet_evm::Config for TestRuntime {
type Event = Event;
type Currency = Balances;
type BlockGasLimit = BlockGasLimit;
type ChainId = ChainId;
type BlockHashMapping = EthereumBlockHashMapping<Self>;
type Runner = pallet_evm::runner::stack::Runner<Self>;
type CallOrigin = EnsureAddressRoot<AccountId>;
type WithdrawOrigin = EnsureAddressNever<AccountId>;
type AddressMapping = HashedAddressMapping<BlakeTwo256>;
type FeeCalculator = ();
type GasWeightMapping = ();
type OnChargeTransaction = ();
type FindAuthor = ();
type PrecompilesType = Precompiles;
type PrecompilesValue = PrecompilesValue;
//type WeightInfo = pallet_evm::weights::SubstrateWeight<Self>;
}
Full implementation can be found here