Regarding the EVM gas fee used for calling precompile functions, how can I set that fee to zero so that the MetaMask will show zero fee at invoking those precompile functions?
I saw a demonstration of that zero gas transaction from Moombeam's tutorial https://youtu.be/V9KfvhoqLJ4?t=5348 and its original code is here https://github.com/PureStake/substrate-node-template/commit/142fe9a5ca9ca787925d3bd51c55db44caf444cd
But that video was posted about 1 year ago, so now the code has changed quite a lot...
I can achieve zero fee on MetaMask as the video above did by setting FixedGasPrice and GasWeightMapping below to return zeros in pallet_evm::Config:
impl pallet_evm::Config for Runtime {
type FeeCalculator = FixedGasPrice;
type GasWeightMapping = GasWeightMapping;
...
}
BUT that makes ALL transactions gasless! Not good. And in my parachain, that makes such feeless transactions not to be accepted by the validators somehow...
Here is Moonbeam recent code on precompile https://github.com/PureStake/moonbeam/blob/v0.26.0/precompiles/balances-erc20/src/lib.rs
My file structure:
project/precompiles
|- balances-erc20 -> src/lib.rs
|- utils -> src/lib.rs
From Parallel Finance's transfer()
function in precompiles/balances-erc20/src/lib.rs:
fn transfer(handle: &mut impl PrecompileHandle) -> EvmResult<PrecompileOutput> {
handle.record_log_costs_manual(3, 32)?;
// Parse input.
let mut input = handle.read_input()?;
input.expect_arguments(2)?;
let to: H160 = input.read::<Address>()?.into();
let amount: U256 = input.read()?;
// Build call with origin.
{
let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
let to = Runtime::AddressMapping::into_account_id(to);
let amount = Self::u256_to_amount(amount)?;
// Dispatch call (if enough gas).
RuntimeHelper::<Runtime>::try_dispatch(
handle,
Some(origin).into(),
pallet_balances::Call::<Runtime, Instance>::transfer {
dest: Runtime::Lookup::unlookup(to),
value: amount,
},
)?;
}
LogsBuilder::new(handle.context().address)
.log3(
SELECTOR_LOG_TRANSFER,
handle.context().caller,
to,
EvmDataWriter::new().write(amount).build(),
)
.record(handle)?;
// Build output.
Ok(succeed(EvmDataWriter::new().write(true).build()))
}
I found out this RuntimeHelper::<Runtime>::try_dispatch()
function was imported from my precompiles/utils/src/lib.rs:
inside try_dispatch() in precompiles/utils/src/lib.rs ... see https://github.com/parallel-finance/parallel/blob/master/precompiles/utils/src/lib.rs#L171:
pub fn try_dispatch<Call>(...){
let call = Runtime::Call::from(call);
let dispatch_info = call.get_dispatch_info();
let required_gas = Runtime::GasWeightMapping::weight_to_gas(dispatch_info.weight);
let used_weight = call.dispatch(origin)
.map_err(|e| revert(alloc::format!("Dispatched call failed with error: {:?}", e)))?
.actual_weight;
so I tried to set that required_gas to 0 in my precompiles/balances-erc20/src/lib.rs:
let mut call = pallet_balances::Call::<Runtime, Instance>::transfer {
dest: Runtime::Lookup::unlookup(to),
value: amount,
};
call.get_dispatch_info().weight= 0;
RuntimeHelper::<Runtime>::try_dispatch(
handle,
Some(origin).into(),
call,
)?;
But that does not change the gas fee!??
This post talks briefly about base_fee but not very clear on how to do it... How to set base_fee and len_fee to zero?
And docs talking about base fee and length fee, etc... https://docs.substrate.io/build/tx-weights-fees/
Now, I have made a simple feeless_transfer()
function from the above transfer()
function. And my feeless_transfer()
calls another feeless_transfer()
that is in my pallet.
This Ok(Pays::No.into())
in the pallet functions will make the actual_weight
to become None
inside precompiles/utils/src/lib.rs: dispatch()
:
let actual_weight = call
.dispatch(origin)
.map_err(|e| revert(alloc::format!("Dispatched call failed with error: {:?}", e)))?
.actual_weight;
And setting the
#[pallet::weight(0)]
above the pallet functions will make call.get_dispatch_info().weight
to produce zero weight_fee.
Still, how can I get zero fee on MetaMask ?
send_raw_transaction
EVM call here. Want to know if there is a clean way to bypass this for certain precompiles.