What are meta transactions?
This page describes the meta transactions that are used in the Market.
Meta transaction allow a wallet to do contract executions on behalf of another wallet and (most importantly) thus pay for the gas fee of that transaction.
So for example if wallet A owns an NFT, the owner of wallet A could allow wallet B to transfer that NFT to wherever necessary and letting wallet B pay for the gas fee.
- Meta transactions can only be used on contracts and thus cannot be used with native tokens (e.g. Ether, Matic, …)
- The (token) contract needs an
executeMetaTransaction
(write) and agetNonce
(read) function
- 1.an EIP712 JSON document is generated specifying the contract, method and parameters that are allowed to be executed on the source wallet’s behalf
- 2.the source wallet signs this JSON document using our widget and supplies the signature to the owner of the executor wallet (gas fee payer)
- 3.using the executor wallet, the
executeMetaTransaction
function on the contract needs to be called supplying the signature of the EIP712 document - 4.the method specified in step 1 will be executed using the parameters also supplied in step 1
- The executer wallet pays for the GAS fees of the transaction
An example of how this could look like for an NFT transfer:

Meta transactions flow
The EIP712 standard defines a way to structure a document that needs a signature in such a way that wallets can parse and show it in a readable way to their end users that need to sign.
Below you can find an example of such a EIP712 document, calling
safeTransferFrom
on contract 0x0096100f27d5ed9a3455b54af3934df07b58b506
{
"types": {
"EIP712Domain": [
{
"name": "name",
"type": "string"
},
{
"name": "version",
"type": "string"
},
{
"name": "verifyingContract",
"type": "address"
},
{
"name": "salt",
"type": "bytes32"
}
],
"MetaTransaction": [
{
"name": "nonce",
"type": "uint256"
},
{
"name": "from",
"type": "address"
},
{
"name": "functionSignature",
"type": "bytes"
}
]
},
"domain": {
"name": "Digimon",
"version": "1",
"verifyingContract": "0x0096100f27d5ed9a3455b54af3934df07b58b506",
"salt": "0x0000000000000000000000000000000000000000000000000000000000013881"
},
"primaryType": "MetaTransaction",
"message": {
"nonce": 0,
"from": "0xeB947ED047020F3C2982d35Ac2a8EbE8A7330282",
"functionSignature": "0xf242432a000000000000000000000000eb947ed047020f3c2982d35ac2a8ebe8a73302820000000000000000000000008fe26c6ff544bee01f41e6f87e6d0ead0ad274050000000000000000000000000000000000000000000000000000000000000065000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000"
}
}
types
is about defining the structure and data types of the document. This part you should basically take as is.domain
is about describing the contract you want to interact with. Here some customisation needs to be done:Property | Description |
---|---|
name | The name of the (NFT) contract you want to interact with |
version | This should always be 1 |
verifyingContract | The contract address you want to interact with e.g. the NFT contract address |
salt | Hex value of the chainId, left padded with 0 until it’s length equals 64 chars, then prepended with 0x . In this case 80001 = Polygon Mumbai Testnet, an overview can be found at https://chainlist.org/ |
primaryType
needs to be MetaTransaction
message
is about defining which contract call to execute and what parameters should be used.Property | Description |
---|---|
nonce | This is a contract + wallet specific sequence number that needs to be fetched from the contract. This can be done by calling the getNonce(address user) function and supplying it with the wallet address that needs to sign the message (wallet A) |
from | The address of the signer |
functionSignature | The encoded function + parameters that need to be executed. This depends on which contract call you want to do. Below you will find a breakdown on how to build this signature for calling safeTransferFrom(address,address,uint256,uint256,bytes) |
The
functionSignature
defines what the signer allows to be executed by a third party. To explain how it is build we’ll work with an example:0xf242432a000000000000000000000000eb947ed047020f3c2982d35ac2a8ebe8a73302820000000000000000000000008fe26c6ff544bee01f41e6f87e6d0ead0ad274050000000000000000000000000000000000000000000000000000000000000065000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000
This is the
functionSignature
for safeTransferFrom(address,address,uint256,uint256,bytes)
+ input data and is build as follows:0xf242432a
: this is the method ID of the function you want to call. You can get this in several ways, but to make it easy we’ve created a jsFiddle that can help you with that:https://jsfiddle.net/nipee/sanjmtu7/. In the fiddle you can input your function signature e.g.safeTransferFrom(address,address,uint256,uint256,bytes)
and it will return you the method ID (0xf242432a
for the above)- next is the input data for each of the inputs. These always need to be 64 chars long and to achieve this, they are pre-padded with
0
until 64 chars000000000000000000000000eb947ed047020f3c2982d35ac2a8ebe8a7330282
: the “from address” (input 1) of the transfer (0x
stripped).0000000000000000000000008fe26c6ff544bee01f41e6f87e6d0ead0ad27405
: the “to address” (input 2) of the transfer (0x
stripped).0000000000000000000000000000000000000000000000000000000000000065
: the token id (input 3) that needs to be transferred as a hex value (101 dec = 65 hex)0000000000000000000000000000000000000000000000000000000000000001
: the amount of tokens (input 4) that need to be transferred. Also as a hex value, but that remains 1 in this case00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000
: empty calldata bytes (input 5)
This has to be done by the source wallet!
Signing is done off chain, so no gas fee has to be paid
Signing the EIP712 JSON document can be done very easily either by using the Venly API or by using the Venly Widget.
This has to be done by the executor wallet (who will be paying for the gas fee)!
After the source wallet has signed the EIP712 document, they need to provide the signature to the executor wallet which can then use it as input to call the
executeMetaTransaction
method. Calling this is again easy using the Venly API or the Venly Widget.function executeMetaTransaction(
address userAddress,
bytes memory functionSignature,
bytes32 sigR,
bytes32 sigS,
uint8 sigV
)
The
executeMetaTransaction
method looks like this:where:
userAddress
= the address from which the transaction must appear to be originating. I.e. the address of the wallet who signed the EIP712 documentfunctionSignature
= thefunctionSignature
that was also included in the EIP712 documentsigR
= ther
value of the signature from step 2sigS
= thes
value of the signature from step 2sigV
= thev
value of the signature from step 2
Last modified 6mo ago