0

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

1 Answer 1

0

The issue has been resolved by implementing Erc20Mapping mock implementation together with implementing both Precompile and PrecompileSet for the precompile + setting a mock PrecompileSet implementation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.