Gelato
  • Introduction
    • Gelato, The Web3 Cloud Platform
  • Smart Wallets
    • Introduction
      • Understanding EIP-7702
      • Understanding ERC-4337
      • ERC-4337 vs EIP-7702
    • Templates & Examples
    • How-To Guides
      • Sponsor gas for your users
      • Allow users to pay gas with erc20
      • Allow users to pay gas with native
      • Use Dynamic/Privy signers with React SDK
      • Estimate Gas for your transactions
    • React SDK
    • Demo
    • Supported Networks
  • Rollup As A Service
    • Introduction
    • Rollup Stacks
      • Arbitrum Orbit
        • Run a Full Orbit Node
      • OP Stack
        • Run OP Node
    • Deploy your Rollup
    • Customization
      • Data Availability
        • Celestia
        • Avail
        • Eigen DA
      • Custom Gas Token
      • Marketplace
        • Gelato Services
        • Data Indexers
        • Block Explorers
        • Oracles
        • Bridges
        • Account Abstraction
        • On & Off-ramp
        • Community
        • Identity & KYC
        • Others
      • Verifier Node Package
    • Public Testnet
  • RPC Nodes
    • Introduction
    • Compute Units
    • Using RPC Nodes
    • Supported Networks
    • Pricing and Plans
    • FAQ
  • Web3 Services
    • Web3 Functions
      • Understanding Web3 Functions
        • Trigger Types
        • Typescript Function
        • Solidity Function
        • Automated Transactions
      • Security Considerations
      • Template & Use Cases
      • Quick Start
        • Writing Typescript Functions
          • Event Trigger
          • Private Typescript Functions
          • Callbacks
        • Test, Deploy & Run Typescript functions
        • Writing Solidity Functions
        • Test, Deploy & Run Solidity Functions
        • Initiate an Automated Transaction
      • Create a Web3 Function Task
        • Using the UI
        • Using the Safe App
        • Using a Smart Contract
        • Using the Automate SDK
      • Analytics & Monitoring
      • Supported Networks
      • Subscription & Payments
      • Legacy Automate Migration Guide
    • Relay
      • What is Relaying?
      • Security Considerations
        • ERC-2771 Delegatecall Vulnerability
      • Templates
      • Quick Start
        • Sponsored Calls
        • Non-Sponsored Calls
      • ERC-2771 (recommended)
        • SponsoredCallERC2771
        • CallWithSyncFeeERC2771
          • Relay Context Contracts ERC2771
      • Non-ERC-2771
        • SponsoredCall
        • CallWithSyncFee
          • Relay Context Contracts
      • Relay API
      • Gelato's Fee Oracle
      • Tracking your Relay Request
      • Supported Networks
      • Subscriptions and Payments
        • 1Balance & Relay
        • SyncFee Payment Tokens
        • Relay Pricing
      • ERC2771 Migration Guide
    • VRF
      • Understanding VRF
      • How does Gelato VRF Work?
      • Security Considerations
      • Template
      • Quick Start
      • Create a VRF Task
        • Create a Fallback VRF
        • Migrating from Chainlink VRF
      • Supported Networks
      • Pricing & Rate Limits
    • Oracles
      • Understanding Gelato Oracles
      • Quick Start
      • Data Providers
        • Stork
        • Choas Labs
      • Migrating from Chainlink Oracles
      • Available Price Feeds
      • Supported Networks
      • Pricing & Rate Limits
    • Account Abstraction
      • Understanding ERC-4337
      • Introduction to Gelato Bundler
      • Templates & Examples
      • Quick Start
      • Supported Networks
      • Bundler API Endpoints
        • eth_sendUserOperation
        • eth_estimateUserOperationGas
        • eth_getUserOperationByHash
        • eth_getUserOperationReceipt
        • eth_supportedEntryPoints
        • eth_maxPriorityFeePerGas
        • eth_chainId
    • 1Balance
      • 1Balance Alerts
      • Subscription Plans
      • Subscription Notifications
      • USDC Addresses
    • AI Agents
    • Teams
  • GELATO DAO
    • DAO & Token (GEL)
    • GEL Token Contracts
    • Governance Process
  • Social Media
Powered by GitBook
On this page
  • Implementation Steps
  • 1. Deploy a GelatoRelayContext compatible contract
  • 2. Import GelatoRelaySDK into your front-end .js project
  • 3. Generate a payload for your target contract
  • 4. Send payload to Gelato
  1. Web3 Services
  2. Relay
  3. Quick Start

Non-Sponsored Calls

PreviousSponsored CallsNextERC-2771 (recommended)

Last updated 1 month ago

Non-Sponsored calls are also known as Sync fee Calls, It is the simplest way to pay, but it delegates all security (reentrancy/replay protection etc.) and payment logic to the target smart contract. You can use to achieve out-of-the-box security and authentication. Relay costs are covered in either native or ERC-20 tokens and they are paid synchronously during the relay call.

Implementation Steps

1. Deploy a GelatoRelayContext compatible contract

import GelatoRelayContext in your target contract to inherit callWithSyncFee functionalities.

import {
    GelatoRelayContext
} from "@gelatonetwork/relay-context/contracts/GelatoRelayContext.sol";

contract TargetContract is GelatoRelayContext {

    function example() external onlyGelatoRelay {
        // _yourAuthenticationLogic()

        // Payment to Gelato
        // NOTE: be very careful here!
        // if you do not use the onlyGelatoRelay modifier,
        // anyone could encode themselves as the fee collector
        // in the low-level data and drain tokens from this contract.
        _transferRelayFee();
    }

    function exampleFeeCapped(uint256 maxFee) external onlyGelatoRelay {
        // Remember to autheticate your call since you are not using ERC-2771
        // _yourAuthenticationLogic()

        // Payment to Gelato
        // NOTE: be very careful here!
        // if you do not use the onlyGelatoRelay modifier,
        // anyone could encode themselves as the fee collector
        // in the low-level data and drain tokens from this contract.
        _transferRelayFeeCapped(maxFee);
    }
}

For ERC2771 Sync Fee Calls (Recommended)

import {
    GelatoRelayContextERC2771
} from "@gelatonetwork/relay-context/contracts/GelatoRelayContextERC2771.sol";

contract TargetContractRelayContextERC2771 is GelatoRelayContextERC2771 {

    mapping (address=>bool) public caller;

    function increment() external onlyGelatoRelayERC2771 {

        // Payment to Gelato
        // NOTE: be very careful here!
        // if you do not use the onlyGelatoRelayERC2771 modifier,
        // anyone could encode themselves as the fee collector
        // in the low-level data and drain tokens from this contract.
        _transferRelayFee();
        // _getMsgSender() will fetch the original user who signed the relay request.
        caller[_getMsgSender()] = true;
    }
    
    function incrementFeeCapped(uint256 maxFee) external onlyGelatoRelayERC2771 {

        // Payment to Gelato
        // NOTE: be very careful here!
        // if you do not use the onlyGelatoRelayERC2771 modifier,
        // anyone could encode themselves as the fee collector
        // in the low-level data and drain tokens from this contract.
  
        _transferRelayFeeCapped(maxFee);
        // _getMsgSender() will fetch the original user who signed the relay request.
        caller[_getMsgSender()] = true;
    }
}

2. Import GelatoRelaySDK into your front-end .js project

import { GelatoRelay, CallWithSyncFeeRequest } from "@gelatonetwork/relay-sdk";
const relay = new GelatoRelay();

or

If you’re using the Viem library in your project, consider importing @gelatonetwork/relay-sdk-viem.

import { GelatoRelay, CallWithSyncFeeRequest } from "@gelatonetwork/relay-sdk-viem";
const relay = new GelatoRelay();

For ERC2771 Sync Fee Calls

import { GelatoRelay, CallWithSyncFeeERC2771Request } from "@gelatonetwork/relay-sdk-viem";
import { GelatoRelay, CallWithSyncFeeERC2771Request } from "@gelatonetwork/relay-sdk";

Once we have imported the GelatoRelay class, when using ERC2771 methods, we must initialize it with the appropriate trustedForwarder. The possible configurations are:

  contract: {
    relay1BalanceERC2771: "trustedForwarder for method sponsoredCallERC2771",
    relayERC2771: "trustedForwarder for method callWithSyncFeeERC2771",
    relay1BalanceConcurrentERC2771: "trustedForwarder for method concurrent sponsoredCallERC2771",
    relayConcurrentERC2771:"trustedForwarder for method concurrent callWithSyncFeeERC2771",
    relay1BalanceConcurrentERC2771zkSync: "trustedForwarder for method concurrent sponsoredCallERC2771 on zkSync",
    relay1BalanceERC2771zkSync: "trustedForwarder for method sponsoredCallERC2771 on zkSync",
    relayConcurrentERC2771zkSync: "trustedForwarder for method concurrent callWithSyncFeeERC2771 on zkSync",
    relayERC2771zkSync: "trustedForwarder for method callWithSyncFeeERC2771 on zkSync",
  },
const relay = new GelatoRelay({
contract: {
    relayERC2771:"0xb539068872230f20456CF38EC52EF2f91AF4AE49"
    }
});

3. Generate a payload for your target contract

// set up target address and function signature abi
const targetContractAddress = "<your target contract address>"; 
const abi = ["function example()","function exampleFeeCapped(uint256)"];

const [address] = await window.ethereum!.request({
      method: "eth_requestAccounts",
 });

// generate payload using front-end provider such as MetaMask
const client = createWalletClient({
      account: address,
      chain,
      transport: custom(window.ethereum!),
});

// address of the token to pay fees
const feeToken = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";

const chainId = await client.getChainId();

//encode function data
const data = encodeFunctionData({
    abi: abi,
    functionName: "example",
});

// -----------------------------------------------------------------
// the following is an alternative example using Gelato Fee Oracle, 
// setting maxFee, and calling the exampleFeeCapped(maxFee) method

// retrieve the estimate fee from the Gelato 
const fee = await relay.getEstimatedFee(
  BigInt(chainId),
  feeToken,
  gasLimit,
  false,
)

const maxFee = fee * 2 // you can use 2x or 3x to set your maxFee

//encode function data
const data = encodeFunctionData({
    abi: abi,
    functionName: "exampleFeeCapped",
    args : [maxFee]
});
// set up target address and function signature abi
const targetContractAddress = "<your target contract address>"; 
const abi = ["function example()","function exampleFeeCapped(uint256)"];

// generate payload using front-end provider such as MetaMask
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = provider.getSigner();
const user = await signer.getAddress();

// address of the token to pay fees
const feeToken = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";

// instantiate the target contract object
const contract = new ethers.Contract(targetContractAddress, abi, signer);

// example callig the example() method
const { data } = await contract.example.populateTransaction();

// -----------------------------------------------------------------
// the following is an alternative example using Gelato Fee Oracle, 
// setting maxFee, and calling the exampleFeeCapped(maxFee) method

// retrieve the estimate fee from the Gelato 
const fee = await relay.getEstimatedFee(
  (await provider.getNetwork()).chainId,
  feeToken,
  gasLimit,
  false,
)

const maxFee = fee * 2 // you can use 2x or 3x to set your maxFee

// example calling the exampleFeeCapped(maxFee) method
const { dataMaxFee } = await contract.exampleFeeCapped.populateTransaction(maxFee);

4. Send payload to Gelato

// populate the relay SDK request body
const request: CallWithSyncFeeRequest = {
  chainId: BigInt(chainId),
  target: targetContractAddress,
  data: data,
  feeToken: feeToken,
  isRelayContext: true,
};
  
// send relayRequest to Gelato Relay API
const relayResponse = await relay.callWithSyncFee(request);

// -----------------------------------------------------------------
// the following is an alternative example using Gelato Fee Oracle, 
// setting maxFee, and calling the exampleFeeCapped(maxFee) method

// populate the relay SDK request body
const requestMaxFee: CallWithSyncFeeRequest = {
  chainId: BigInt(chainId),
  target: targetContractAddress,
  data: dataMaxFee,
  feeToken: feeToken,
  isRelayContext: true,
};
  
// send relayRequest to Gelato Relay API
const relayResponse = await relay.callWithSyncFee(requestMaxFee);
// populate the relay SDK request body
const request: CallWithSyncFeeRequest = {
  chainId: (await provider.getNetwork()).chainId,
  target: targetContractAddress,
  data: data,
  feeToken: feeToken,
  isRelayContext: true,
};
  
// send relayRequest to Gelato Relay API
const relayResponse = await relay.callWithSyncFee(request);

// -----------------------------------------------------------------
// the following is an alternative example using Gelato Fee Oracle, 
// setting maxFee, and calling the exampleFeeCapped(maxFee) method

// populate the relay SDK request body
const requestMaxFee: CallWithSyncFeeRequest = {
  chainId: (await provider.getNetwork()).chainId,
  target: targetContractAddress,
  data: dataMaxFee,
  feeToken: feeToken,
  isRelayContext: true,
};
  
// send relayRequest to Gelato Relay API
const relayResponse = await relay.callWithSyncFee(requestMaxFee);

For ERC2771 Sync Fee Calls

// populate the relay SDK request body
const request: CallWithSyncFeeERC2771Request = {
  chainId: BigInt(chainId),
  target: targetContractAddress,
  data: data,
  user: address,
  feeToken: feeToken,
  isRelayContext: true,
};
  
// send relayRequest to Gelato Relay API
const relayResponse = await relay.callWithSyncFeeERC2771(request, client as any);

// -----------------------------------------------------------------
// the following is an alternative example using Gelato Fee Oracle, 
// setting maxFee, and calling the incrementFeeCapped(maxFee) method

// populate the relay SDK request body
const requestMaxFee: CallWithSyncFeeERC2771Request = {
  chainId:  BigInt(chainId),
  target: targetContractAddress,
  data: dataMaxFee,
  user: address,
  feeToken: feeToken,
  isRelayContext: true,
};
  
// send relayRequest to Gelato Relay API
const relayResponseMaxFee = await relay.callWithSyncFeeERC2771(requestMaxFee, client as any);
// populate the relay SDK request body
const request: CallWithSyncFeeERC2771Request = {
  chainId: (await provider.getNetwork()).chainId,
  target: targetContractAddress,
  data: data,
  user: user,
  feeToken: feeToken,
  isRelayContext: true,
};
  
// send relayRequest to Gelato Relay API
const relayResponse = await relay.callWithSyncFeeERC2771(request, provider);

// -----------------------------------------------------------------
// the following is an alternative example using Gelato Fee Oracle, 
// setting maxFee, and calling the incrementFeeCapped(maxFee) method

// populate the relay SDK request body
const requestMaxFee: CallWithSyncFeeERC2771Request = {
  chainId:  (await provider.getNetwork()).chainId,
  target: targetContractAddress,
  data: dataMaxFee,
  user: user,
  feeToken: feeToken,
  isRelayContext: true,
};
  
// send relayRequest to Gelato Relay API
const relayResponseMaxFee = await relay.callWithSyncFeeERC2771(requestMaxFee, provider);

import GelatoRelayContextERC2771 in your target contract to inherit ERC2771 functionalities with callWithSyncFee. Learn more about ERC2771 .

We will need to go to the and check the network and the contract addresses to identify the trustedForwarder associated with our method. In the example below, we are using the method callWithSyncFeeERC2771 on Sepolia, the trustedForwarder associated is 0xb539068872230f20456CF38EC52EF2f91AF4AE49. We will initialize GelatoRelay with the following config:

Note: The code below uses the Ethers library. Alternatively, if you want to use the services with Viem, check .

Learn more about Implementation of Non ERC2771 SyncFee Calls and ERC2771 SyncFee Calls .

ERC-2771
here
Supported Networks
here
here
here