Gelato Network
Search…
πŸ“š
Prerequisites
A few useful definitions to help you get started

In a standard Ethereum transaction, an ethereum user signs and sends the transaction themselves. This user controls the private key to an externally owned account (EOA) which they can use to sign a transaction and prove they have the right to spend the balance associated with that account address.
For each transaction a user sends, there is an associated transaction fee, known as gas. Since Ethereum executes computation, each unit of computation has an associated gas cost, which deters malicious actors from overloading the network by requiring them to pay heavily for a potential attack. This is excellent news for Ethereum's security and helps keep the network consistent under load, but it comes at a hidden cost for onboarding new users.

How does a new user start interacting with exciting on-chain applications like DeFi, NFTs, or gaming? They will always need the native token to pay for gas on every network, even if the network has very cheap gas fees like Polygon. This requires the user to open an account at a centralised exchange, go through KYC, and buy crypto using fiat. This can be quite a process, even for the most skilled of degens out there, and it can deter new users from being onboarded to a dApp by increasing the latency between their initial excitement and the time it takes to actually get started.
This is where relaying comes in! A relayer can help solve these issues by sending a transaction on behalf of the user.

We allow the user to send a transaction without a native token balance (it turns out relayers can be super nifty in loads of ways, for example, allowing a user who wants to swap a token to pay for the gas using the token being swapped!). Ideally, we would also like to still utilise the excellent security of a user signature, but for the transaction to be sent by a different EOA, one controlled by a relayer, who abstracts gas payment away from the user.
This is a very import context shift to understand. We have shifted from a user signing and sending a transaction themselves, to a user signing a standardised message and passing that on to a relayer. This relayer will, first, verify the user's signature for security, and then pass their message along on-chain. Gelato Relay does exactly this by taking a user's message off-chain and subsequently building a meta-transaction which is executed on chain.

A meta transaction is a regular ethereum transaction which contains the actual message to be delivered on-chain to a target contract within itself, hence the term meta. The outer transaction helps facilitate the first on-chain call which is sent by a relayer. The call is forwarded to the target contract using an intermediate smart contract (Gelato Relay), which in turn forwards the call using the inner transaction to deliver the relayed message.

To achieve gasless transactions securely, Gelato Relay makes use of the EIP-712 standard. EIP-712 allows for a standardised way to sign and hash typed structured data. This means the user can sign a message using their wallet without incurring a gas cost or interacting with the chain at all, and this signature can be verified on-chain, by the relayer, facilitating a gasless transaction with security built in. This message will include important information such as the transaction signer address, the target contract address, and the calldata payload used to target a specific function.

Using Gelato Relay, we relay your user's transactions on-chain (with optional ERC-2771 support), enabling secure gasless transactions for an ultra smooth UX for your dApp. This allows for a variety of new web3 experiences, as the user can now pay by only signing a message, or their transaction costs can be sponsored by the dApp developer. As long as the gas costs are covered in one of the multiple payment methods that Gelato supports, we handle the rest reliably, quickly and securely.

When relaying a message to a target smart contract function, the function needs to authenticate that the message was created by the correct party, and forwarded through the correct relayer. Otherwise, your target function is open to exploits. EIP-2771 uses clever data encoding to allow for a new _msgSender to be relayed from off-chain, and a trustedForwarder address to be set. Together, these two parameters protect against any foul play and allow for information to be sent from off-chain on-chain!

When relaying, the msg.sender loses its informational value. Whereas usually, the msg.sender would be the user initiating the transaction, with off-chain relaying, we lose this valuable information.
For example, how does the target smart contract permission who can call a specific function? In this case, the msg.sender will be the relayer, but whitelisting this address is both permissioned and still not enough to stop some one else using the same relayer from calling your function. This can be especially worrisome when low-level calls are involved.
  • The best option would be somehow to let the relay call originator specify an address and have this address relayed on-chain. The target smart contract can now authenticate a function call using this address.
  • But how do we successfully pass information (a specific address) through low-level calldata from off-chain to on-chain without interfering with the calldata?

There are four interested parties when it comes to Gelato relaying:
  • 1. The transaction signer, who signs the payload and sends the request off-chain to a Gelato Relay backend via the Gelato Relay SDK.
  • 2. The executor who takes this transaction and executes it on-chain sending it via a trusted forwarder.
  • 3. A trusted forwarder, in this case, the Gelato Relay contract. This trusted forwarder can also be whitelisted by the target contract for extra security. This trusted forwarder contract verifies the signature relayed from off-chain via the executor to verify the relay request.
  • 4. The target smart contract on a which a function is called by the calldata.
Here’s where the magic happens, the trusted forwarder encodes the from address i.e. the off-chain address into the calldata by appending it at the end:
1
(bool success, ) = to.call.value(value)(abi.encodePacked(data, from));
The target contract can now verify the from address by decoding the data in the same way, making sure this message has been passed through the trustedForwarder.
The required target contract function can be sure that the correct entity signed and requested this payload to be relayed, only via a trusted forwarder - in our case, Gelato Relay.

GelatoRelayContext allows you in just one line of Solidity code to create a Gelato Relay compatible contract, when using relayWithSyncFee.
1
import {
2
GelatoRelayContext
3
} from "@gelatonetwork/relay-context/contracts/GelatoRelayContext.sol";

GelatoRelayContext allows your smart contract to retrieve the following information from the relay calldata :
  1. 1.
    Gelato's fee collector address, a contract specifically for collecting relay fees securely. This allows a smart contract to transfer fees directly if you are using the syncFee payment method.
  2. 2.
    The fee token address specifying which address the fee will be paid in, which Gelato resolved from the original relay-SDK request body.
  3. 3.
    The fee itself, which includes the gas cost + Gelato's 10% fee on top.
Below is an example:
1
// SPDX-License-Identifier: MIT
2
pragma solidity 0.8.16;
3
​
4
import {
5
GelatoRelayContext
6
} from "@gelatonetwork/relay-context/contracts/GelatoRelayContext.sol";
7
​
8
contract Counter is GelatoRelayContext {
9
uint256 public counter;
10
​
11
event IncrementCounter();
12
​
13
function increment() external onlyGelatoRelay {
14
// payment to Gelato
15
_transferRelayFee();
16
​
17
// logic
18
counter += 1;
19
emit IncrementCounter();
20
}
21
}
Line 8 inherits the GelatoRelayContext contract, giving access to these features:
  • onlyGelatoRelay: a modifier which will only allow Gelato Relay to call this function.
  • _isGelatoRelay(address _forwarder): a function which returns true if the address matches Gelato Relay's address.

  • _getFeeCollector() : a function to retrieve the fee collector address.
  • _getFee(): a function to retrieve the fee that Gelato will charge.
  • _getFeeToken(): a function to retrieve the address of the token used for fee payment.

As you are using the relayWithSyncFee SDK method, you can use the below helper functions to pay directly to Gelato:
  • _transferRelayFee(): a function which transfers the fee amount to Gelato, with no cap.
  • _transferRelayFeeCapped(uint256 _maxFee): a function which transfers the fee amount to Gelato which a set cap from the argument maxFee in wei. This helps limit fees on function calls in case of gas volatility or just for general budgeting.

Copy link
On this page
Introduction to Relaying
Standard transactions
What is a relayer?
What is a meta transaction?
Why Gelato Relay?
ERC-2771
Gelato's Relay Context