DEV Community

loading...

Ethereum Meta-Transactions 101

coinmonks profile image CoinMonks Originally published at Medium on ・6 min read

In the Ethereum world things happen thanks to transactions. These transactions, just like everything in life, don’t come for free. In order to create and execute a transaction you need to pay a fee in the form of “Gas” which costs ETH.

But what if you want to create a transaction and you have no money to pay for gas… this is where Meta-Transactions come to the rescue!

Meta Transactions are transactions who’s data is created and signed off-chain by one person and executed by another person who pays the gas fees.

Since meta transactions are not native to the system, you would need to either use a 3rd party setup (e.g. GSN), or create your own.

Setup

A very basic setup would consists of 3 entities:

  • Signer —  the address who has with 0 ether and is the creator of the transaction. This address is the one which signs the transaction data.
  • Sender— the address which has ether and is willing to send the transaction on your behalf, thus paying the gas.
  • Relay/Proxy —  a smart contract which would read the signed data, validate it against the provided signature and forward the call to the actual contract.

_Note that in this case the transaction sender would be the Proxy contract (e.g. the msg.sender). In the case of an ERC-20 transfer, the Signer needs to approve the Proxy contract to transfer tokens on it’s behalf (unless the ERC-20 contract supports meta transactions already. See [_EIP-1776](https://github.com/ethereum/EIPs/issues/1776)

Let’s look into a simple use case…

Use Case: Sending Tokens

(For the sake of simplifying the example consider that any approval of ERC-20 token transfers has been done in advance)

Imagine you have an ethereum address with 0 ether in it and a friendly blockchain buddy sends you 1000 DAI. You are unable to make use of them since you don’t have enough money to execute any transactions.

What you could do instead is make use of meta-transactions.

Step #1: Generate Meta Transaction

A meta transaction is basically a message with some data that has been signed by whoever wants to execute a transaction. That signed data is then verified and sent in a normal ethereum transaction by another party (the one paying the Gas fees).

Let’s consider that we want to transfer those tokens to another account which means that we need to create a transaction with the following data:

  • Receiver : 0x00007e87416D7328fC74663f37e0DF53777188fb
  • Amount : 1000000000000000000000 (1000 with 18 decimals)

Using web3js we can easily build the calldata for such a function call:

transferFrom(senderAddress, receiverAddress, 1000);

which is translated into the following bytecode:

0xa9059cbb
0000000000000000000000000000ef76331b59b1cc5e82ba1d2f840dbac1c73e
00000000000000000000000000007e87416d7328fc74663f37e0df53777188fb
00000000000000000000000000000000000000000000003635c9adc5dea00000
Enter fullscreen mode Exit fullscreen mode

Step #2: Sign the data

Now that you have the created the calldata of the action you want to perform, it’s time to sign it so that the Proxy contract can verify that this calldata has not been tampered along the way.

In addition to this data, we also want to ensure that the correct contract is being called so let’s add the target contract address to the data we want to sign. The easiest way to do that is to create a hash of all the data you want to sign, and sign the hash instead of the raw data.

// pack the DAI Token address and our "transferFrom()" calldata together and sign them.

let rawData = web3.eth.abi.encodeParameters(
  ['address','bytes'],
  [DaiTokenAddress,data]
);

// hash the data.
let hash = web3.utils.soliditySha3(rawData);

// sign the hash.
let signature = web3.eth.sign(hash, signer);
Enter fullscreen mode Exit fullscreen mode

Step #3: Hand over the data to the Gas payer

Once you have created and signed the data you hand it over to the service/address that will be executing the transaction on the chain.

Depending on how the Proxy contract is structured the Gas Payer might need differently structured data (and your signed data might need to be different as well). But for the sake of simplicity let’s consider that we have the following basic proxy contract functionality (NOTE! Not production safe):

In order to successfully execute the transaction, the gas payer needs to call our Proxy contract’s forward() function with the values supplied by the Signer.

  • _to: DAI Token contract address (this is our target contract).
  • _data: the generated calldata from the signer. (the one with the transferFrom(...) which we did).
  • _signature: the resulting signature from signing the data.

This would then make our Proxy contract call the DAI Token address and execute the transferFrom() function transferring 1000 DAI.

Things to consider

There are a lot of security improvements that could/should be added (such as adding a nonce in the signed message which would protect against replay attacks).

But the goal of this example was to show you how Person A can sign a message off-chain without paying gas and then be executed by Person B. From here on there are limitless improvements and changed that could be done to fit your needs.

Join Coinmonks Telegram group and learn about crypto trading and investing

Also, Read

Get Best Software Deals Directly In Your Inbox


Discussion (0)

pic
Editor guide