Getting Started with Gelato¶
Introduction¶
Gelato Network is a decentralized automation network for Web3, enabling developers to automate & relay arbitrary smart contract executions on and across EVM-based compatible blockchains. The network relies on a broad set of transaction relayers called executors that are rewarded for the infrastructure and automation services they provide. Gelato is designed to be a more robust, decentralized, and cost-efficient alternative to running your own bot infrastructure.
Gelato is live on both Moonbeam and Moonriver, enabling developers and end-users to automate smart contract interactions with Gelato Ops and the Gelato Relay SDK. First, this guide will demonstrate a step-by-step tutorial to automating a smart contract interaction with Gelato Ops. Next, you'll interact with the Gelato Relay SDK via a hands-on demo.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
Gelato Ops¶
Gelato Ops is a front-end for interacting with the Gelato network and managing your transaction automation. There's no sign up or registration step - your account is tied directly to your wallet. In this guide, you'll deploy a signature Gelato ice cream NFT that can be licked via a function call. Then, you'll automate the lick function according to specific parameters.
Create an Automated Task¶
To get started with this guide, you'll need to have some GLMR or MOVR in your free balance. Then, head to Gelato Ops and ensure that you have selected the Moonbeam or Moonriver network in your wallet and connected it to Gelato. To kick off the tutorial, press Start Tutorial, then press Mint NFT and confirm the transaction in MetaMask.
Then, take the following steps:
- Enter the amount of GLMR / MOVR you'd like to use to fund your Gelato Ops account. These funds will be used to pay for gas. Then press Deposit and confirm the transaction in MetaMask
- Press Create Task
- Copy the contract address of your ice cream NFT
- Paste the contract address to allow the ABI to be automatically fetched by Gelato
- Next, select the function you'd like to automate. For this example, choose the lick function
- The lick function takes a single parameter, namely, the tokenId of the NFT to lick. Enter the tokenId that corresponds to your ice cream NFT
- Next, choose how you'd like your automation scheduled. You can choose from a time-based schedule or Gelato can automatically execute the function whenever possible
- Select Gelato Balance to use your deposited funds to pay for the gas of the automated transactions
- Enter a task name
- Press Create Task and confirm the transaction in MetaMask. Then, sign the next pop-up in MetaMask to confirm your task name
And that's it! You've successfully set up your first recurring smart contract interaction with Gelato. Your automated smart contract interactions will continue according to the set schedule until the remaining funds for gas are drained or the automation is paused on Gelato Ops. This example was a simple demo, but you can automate much more complex interactions and build increasingly sophisticated logic into your automated tasks. Be sure to check out docs.gelato.network for more information.
Manage your Automated Tasks¶
On app.gelato.network, you'll see all of your automations and their associated statuses. You can click on an automation to see more details about the task and its execution history. Here you can also make any changes to the automated task, including pausing or resuming the task. To pause a task, press Pause in the upper right corner and confirm the transaction in your wallet. You can resume the automation at any time by pressing Restart and confirming the transaction in your wallet.
At the bottom of the page, you can see your task's execution history including the transaction status and the gas cost. You can click on the Task Logs tab to see a detailed debugging level history of your automated tasks, which may be especially helpful in the event a transaction failed or did not execute.
Manage your Gas Funds¶
To manage your gas funds on app.gelato.network, click on the Funds box in the upper left corner. Here, you can top up your balance of gas funds or withdraw them. You can also register be notified with low balance alerts.
To deposit funds for gas, take the following steps:
- Click on the Funds box in the upper left corner
- Enter the amount of funds you'd like to deposit
- Click Deposit and confirm the transaction in your wallet
You can follow a similar set of steps to withdraw your gas funds from Gelato.
Gelato Relay SDK¶
Gelato Relay SDK is a collection of functions that enable you to interact with the Gelato Relay API. Per Gelato Docs, Gelato Relay API is a service that allows users and developers to get transactions mined fast, reliably and securely, without having to deal with the low-level complexities of blockchains. A key feature of this offering is the ability to provide users with gasless transactions.
Send a Gasless Transaction with Gelato Relay SDK¶
Gasless transactions, also referred to as meta transactions, allow end-users to interact with smart contracts without paying for gas. Instead of confirming a transaction in a wallet, a user signs a message that enables a transaction to take place once a relayer submits the transaction and pays the associated gas fee. EIP-2771 is a common standard that enables meta transactions, and is implemented by the HelloWorld.sol
contract referenced later in the tutorial.
In this demo, you'll ask Gelato Relay SDK to call a HelloWorld.sol
contract on your behalf. The script being built is sourced from the quick start guide on Gelato's Docs. Note, there is no dependency on RPC providers - once the transaction and signature are built, you simply pass them along to the Gelato Relay API.
Get Started¶
Gelato Relay SDK is an NPM package that can be installed locally in the current directory with the following command:
npm install @gelatonetwork/gelato-relay-sdk
You'll also want to install the Ethers.js library with the following command:
npm install ethers
Next, you'll need to create a javascript file for your script. You can create a hello-world.js
file by running:
touch hello-world.js
Now you're ready to build. First, you need to import the Gelato Relay SDK and Ethers.js:
import { Wallet, utils } from "ethers";
import { GelatoRelaySDK } from "@gelatonetwork/gelato-relay-sdk";
Then, create a function to contain the logic of the script:
const forwardRequestExample = async () => {
}
Within the forwardRequestExample
function, define the chain ID and the HelloWorld.sol
contract that you want to interact with.
const chainId = 1284;
// `HelloWorld.sol` contract on Moonbeam
const target = "0x3456E168d2D7271847808463D6D383D079Bd5Eaa";
The HelloWorld.sol
contract, reproduced below, is configured to have gasless transaction support.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
/// @title HelloWorld with meta transaction support (EIP-2771)
contract HelloWorld is ERC2771Context {
event Success(
address indexed user,
address indexed feeToken,
string message
);
constructor(address _gelatoMetaBox) ERC2771Context(_gelatoMetaBox) {}
function sayHiVanilla(address _feeToken) external {
string memory message = "Hello World";
emit Success(msg.sender, _feeToken, message);
}
function sayHi(address _feeToken) external {
string memory message = "Hello World";
emit Success(_msgSender(), _feeToken, message);
}
}
Next, you'll create a new test account that will submit the gasless transaction. This account is insecure and should not be used in production. This example defines a test_token
with a default value for demonstration purposes, but you can specify any token here that you'd like.
const test_token = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
// Create mock wallet
const wallet = Wallet.createRandom();
const sponsor = await wallet.getAddress();
console.log(`Mock PK: ${await wallet._signingKey().privateKey}`);
console.log(`Mock wallet address: ${sponsor}`);
Add Request Data¶
In this step you have to provide the ABI-encoded call data for the function you want to interact with. You can generate this by taking the following steps:
- Navigate to the Write Contract heading of the
HelloWorld.sol
contract on Moonscan - Press Connect to Web3. After you accept the terms and conditions, you can connect your wallet
- Head to the
sayHiVanilla
function and provide the following default value for the_feeToken
parameter:0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
- Press Write
- Without confirming the transaction in MetaMask, click on the Hex tab
- Press Copy Raw Transaction Data
The resulting ABI-encodeded call data should look like 0x4b327067000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeaeeeeeeeeeeeeeeeee
The ABI-encoded call data specifies the contract function to call as well as any relevant parameters, and can be fetched via MetaMask or Remix. More commonly, you might fetch the ABI-encoded call data programmatically via Ethers.js or Web3.js. There are some additional parameters defined in the following example, such as paymentType
, maxFee
, and gas
. There are a variety of possible payment types you can choose from. For simplicity, replay protection has not been considered in this example.
// ABI encode for HelloWorld.sayHiVanilla(address _feeToken)
const data = `0x4b327067000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeaeeeeeeeeeeeeeeeee`;
const paymentType = 1;
// Maximum fee that sponsor is willing to pay worth of test_token
const maxFee = "1000000000000000000";
// Gas limit
const gas = "200000";
// Smart contract nonces are not enforced to simplify the example.
// In reality, this decision depends whether or not target
// address already implements replay protection. (More info in the docs)
const sponsorNonce = 0;
const enforceSponsorNonce = false;
// Only relevant when enforceSponsorNonce = true
const enforceSponsorNonceOrdering = false;
// Build ForwardRequest object
const forwardRequest = GelatoRelaySDK.forwardRequest(
chainId,
target,
data,
test_token,
paymentType,
maxFee,
gas,
sponsorNonce,
enforceSponsorNonce,
sponsor
);
Lastly, the forwardRequest
object is created with all of the relevant parameters defined in prior steps. In the final step, the forwardRequest
object will be sent to the Gelato Relay API with the required signature.
Send Request Data¶
The last few steps include hashing the request object and signing the resulting hash. The ultimate step is to submit the request and the signature to the Gelato Relay API. You can copy and paste the below code after the forwardRequest
object:
// Get EIP-712 hash (aka digest) of forwardRequest
const digest = GelatoRelaySDK.getForwardRequestDigestToSign(forwardRequest);
// Sign digest using mock private key
const sponsorSignature = utils.BytesLike = utils.joinSignature(
await wallet._signingKey().signDigest(digest)
);
// Send forwardRequest and its sponsorSignature to Gelato Relay API
await GelatoRelaySDK.sendForwardRequest(forwardRequest, sponsorSignature);
console.log("ForwardRequest submitted!");
The EIP-712 standard provides important context to users about the action they're authorizing. Instead of signing a long, unrecognizable bytestring (which is dangerous and could be exploited by bad actors), EIP-712 provides a framework for encoding and displaying the contents of the message in a readable manner, making it substantially safer for end-users.
To execute the script and dispatch the gasless transaction to Gelato Relay API, use the following command:
node hello-world.js
You should see a message logged to the console that says ForwardRequest submitted!
You can also verify your relayed transaction was successfully executed by checking the latest transactions of this Gelato contract on Moonscan.
Complete Script¶
The entire hello-world.js
file should contain the following:
import { Wallet, utils } from "ethers";
import { GelatoRelaySDK } from "@gelatonetwork/gelato-relay-sdk";
const forwardRequestExample = async () => {
const chainId = 1284;
// `HelloWorld.sol` contract on Moonbeam
const target = "0x3456E168d2D7271847808463D6D383D079Bd5Eaa";
const test_token = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
// Create mock wallet
const wallet = Wallet.createRandom();
const sponsor = await wallet.getAddress();
console.log(`Mock PK: ${await wallet._signingKey().privateKey}`);
console.log(`Mock wallet address: ${sponsor}`);
// ABI encode for HelloWorld.sayHiVanilla(address _feeToken)
const data = `0x4b327067000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeaeeeeeeeeeeeeeeeee`;
const paymentType = 1;
// Maximum fee that sponsor is willing to pay worth of test_token
const maxFee = "1000000000000000000";
// Gas limit
const gas = "200000";
// Smart contract nonces are not enforced to simplify the example.
// In reality, this decision depends whether or not target
// address already implements replay protection. (More info in the docs)
const sponsorNonce = 0;
const enforceSponsorNonce = false;
// Only relevant when enforceSponsorNonce = true
const enforceSponsorNonceOrdering = false;
// Build ForwardRequest object
const forwardRequest = GelatoRelaySDK.forwardRequest(
chainId,
target,
data,
test_token,
paymentType,
maxFee,
gas,
sponsorNonce,
enforceSponsorNonce,
sponsor
);
// Get EIP-712 hash (aka digest) of forwardRequest
const digest = GelatoRelaySDK.getForwardRequestDigestToSign(forwardRequest);
// Sign digest using mock private key
const sponsorSignature = utils.BytesLike = utils.joinSignature(
await wallet._signingKey().signDigest(digest)
);
// Send forwardRequest and its sponsorSignature to Gelato Relay API
await GelatoRelaySDK.sendForwardRequest(forwardRequest, sponsorSignature);
console.log("ForwardRequest submitted!");
};
forwardRequestExample();
| Created: March 23, 2022