Expand description
§Meta Tx (Meta Transaction) Pezpallet
This pezpallet enables the dispatch of transactions that are authorized by one party (the signer) and executed by an untrusted third party (the relayer), who covers the transaction fees.
§Pezpallet API
See the pezpallet module for more information about the interfaces this pezpallet exposes,
including its configuration trait, dispatchables, storage items, events and errors.
§Overview
The pezpallet provides a client-level API, typically not meant for direct use by end users.
A meta transaction, constructed with the help of a wallet, contains a target call, necessary
extensions, and the signer’s signature. This transaction is then broadcast, and any interested
relayer can pick it up and execute it. The relayer submits a regular transaction via the
dispatch function, passing the meta transaction as an argument to
execute the target call on behalf of the signer while covering the fees.
§Example
#[test]
fn sign_and_execute_meta_tx() {
new_test_ext().execute_with(|| {
// meta tx signer
let alice_keyring = Sr25519Keyring::Alice;
// meta tx relayer
let bob_keyring = Sr25519Keyring::Bob;
let alice_account: AccountId = alice_keyring.public().into();
let bob_account: AccountId = bob_keyring.public().into();
let tx_fee: Balance = (2 * TX_FEE).into(); // base tx fee + weight fee
let alice_balance = force_set_balance(alice_account.clone());
let bob_balance = force_set_balance(bob_account.clone());
// Alice builds a meta transaction.
let remark_call =
RuntimeCall::System(pezframe_system::Call::remark_with_event { remark: vec![1] });
let meta_tx_bare_ext = create_meta_tx_bare_ext(alice_account.clone());
let meta_tx_sig =
create_signature(remark_call.clone(), meta_tx_bare_ext.clone(), alice_keyring);
let meta_tx_ext = (
VerifySignatureExt::new_with_signature(meta_tx_sig, alice_account.clone()),
// append signed part.
meta_tx_bare_ext,
);
let meta_tx = MetaTxFor::<Runtime>::new(
remark_call.clone(),
META_EXTENSION_VERSION,
meta_tx_ext.clone(),
);
// Encode and share with the world.
let meta_tx_encoded = meta_tx.encode();
// Bob acts as meta transaction relayer.
let meta_tx = MetaTxFor::<Runtime>::decode(&mut &meta_tx_encoded[..]).unwrap();
let call = RuntimeCall::MetaTx(Call::dispatch { meta_tx: Box::new(meta_tx.clone()) });
let tx_bare_ext = create_tx_bare_ext(bob_account.clone());
let tx_sig = create_signature(call.clone(), tx_bare_ext.clone(), bob_keyring);
let tx_ext = (
VerifySignatureExt::new_with_signature(tx_sig, bob_account.clone()),
// append signed part
tx_bare_ext,
);
let uxt = UncheckedExtrinsic::new_transaction(call.clone(), tx_ext.clone());
// Check Extrinsic validity and apply it.
let result = apply_extrinsic(uxt);
// Asserting the results and make sure the weight is correct.
let tx_weight = tx_ext.weight(&call) + <Runtime as Config>::WeightInfo::bare_dispatch();
let meta_tx_weight = remark_call
.get_dispatch_info()
.call_weight
.add(meta_tx_ext.weight(&remark_call));
assert_eq!(
result,
Ok(PostDispatchInfo {
actual_weight: Some(meta_tx_weight + tx_weight),
pays_fee: Pays::Yes,
})
);
System::assert_has_event(RuntimeEvent::MetaTx(crate::Event::Dispatched {
result: Ok(PostDispatchInfo {
actual_weight: Some(meta_tx_weight),
pays_fee: Pays::Yes,
}),
}));
System::assert_has_event(RuntimeEvent::System(pezframe_system::Event::Remarked {
sender: alice_account.clone(),
hash: <Runtime as pezframe_system::Config>::Hashing::hash(&[1]),
}));
// Alice balance is unchanged, Bob paid the transaction fee.
assert_eq!(alice_balance, Balances::free_balance(alice_account));
assert_eq!(bob_balance - tx_fee, Balances::free_balance(bob_account));
});
}§Low-Level / Implementation Details
The structure of a meta transaction is identical to the
General transaction.
It contains the target call along with a configurable set of extensions and its associated
version. Typically, these extensions include type like
pezpallet_verify_signature::VerifySignature, which provides the signer address
and the signature of the payload, encompassing the call and the meta-transaction’s
configurations, such as its mortality. The extensions follow the same TransactionExtension
contract, and common types such as pezframe_system::CheckGenesis,
pezframe_system::CheckMortality, pezframe_system::CheckNonce, etc., are applicable in
the context of meta transactions. Check the mock setup for the example.
Re-exports§
pub use weights::WeightInfo;pub use pezpallet::*;
Modules§
- pezpallet
- The
pezpalletmodule in each FRAME pezpallet hosts the most important items needed to construct this pezpallet. - weights
- Autogenerated weights for
pezpallet_meta_tx
Structs§
- MetaTx
- Meta Transaction type.
- Meta
TxMarker - This type serves as a marker extension to differentiate meta-transactions from regular
transactions. It implements the
TransactionExtensiontrait and carries constant implicit data (“_meta_tx”).