And I learned about how to wrap a pallet to make a precompile for Ethereum users to call those pallet functions ... see the video at https://www.youtube.com/watch?v=V9KfvhoqLJ4&t=1004s (time = 01:10:15), and code at https://github.com/PureStake/substrate-node-template/commits/frontier-workshop-2021
in this precompile function at https://github.com/PureStake/substrate-node-template/commit/142fe9a5ca9ca787925d3bd51c55db44caf444cd:
impl<Runtime> PalletTemplatePrecompile<Runtime>
where
Runtime: pallet_template::Config + pallet_evm::Config,
Runtime::Call: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo,
<Runtime::Call as Dispatchable>::Origin: From<Option<Runtime::AccountId>>,
Runtime::Call: From<pallet_template::Call<Runtime>>,
{
fn do_something(
mut input: EvmDataReader,
target_gas: Option<u64>,
context: &Context,
) -> EvmResult<PrecompileOutput> {
// This gasometer is a handy utility that will help us account for gas as we go.
let mut gasometer = Gasometer::new(target_gas);
// Bound check. We expect a single argument passed in.
input.expect_arguments(1)?;
// Parse the u32 value that will be dispatched to the pallet.
let value = input.read::<u32>()?.into();
// Use pallet-evm's account mapping to determine what AccountId to dispatch from.
let origin = Runtime::AddressMapping::into_account_id(context.caller);
let call =
pallet_template::Call::<Runtime>::do_something{something: value};
// Dispatch the call into the runtime.
// The RuntimeHelper tells how much gas was actually used.
let used_gas = RuntimeHelper::<Runtime>::try_dispatch(
Some(origin).into(),
call,
gasometer.remaining_gas()?,
)?;
// Record the gas used in the gasometer
gasometer.record_cost(used_gas)?;
Ok(PrecompileOutput {
exit_status: ExitSucceed::Stopped,
cost: gasometer.used_gas(),
output: Default::default(),
logs: Default::default(),
})
}
in my pallet_template
:
pub fn do_something(
origin: OriginFor<T>,
call: Box<<T as Config>::Call>,
) -> DispatchResultWithPostInfo {
let sender = ensure_signed(origin.clone())?;
let special_accounts = <SepecialList<T>>::get();
// check if this sender can send feeless txn
// Dispatch the call.
let result = call.dispatch(origin);
if special_accounts.contains(sender) {
Ok(Pays::No.into())
} else {
Ok(Pays::Yes.into())
}
}
Now. How can I specify which function from an Ethereum smart contract(deployed into the EVM in my parachain) to invoke?
How can I pass this call: Box<<T as Config>::Call>
argument in the precompile to the do_something()
in my pallet_template
?