How does a contract interact with the GSN?

I have been checking out the Sending Gasless Transactions tutorial.

As discussed in the tutorial, we have a Counter contract that implements the GSNRecipient.

I’m trying to see how the react-app that we made in the tutorial, is interacting with the Relayer that we deployed locally.

The App.js file contains an increase() function:

  const increase = async () => {
    await counterInstance.methods.increase().send({ from: accounts[0] });

which sends a transaction to the deployed Counter contract.

Here is the Counter contract.

// contracts/Counter.sol
pragma solidity ^0.5.0;

import "@openzeppelin/contracts-ethereum-package/contracts/GSN/GSNRecipient.sol";

contract Counter is GSNRecipient {
    uint256 public value;

    function increase() public {
        value += 1;

    function acceptRelayedCall(
        address relay,
        address from,
        bytes calldata encodedFunction,
        uint256 transactionFee,
        uint256 gasPrice,
        uint256 gasLimit,
        uint256 nonce,
        bytes calldata approvalData,
        uint256 maxPossibleCharge
    ) external view returns (uint256, bytes memory) {
        return _approveRelayedCall();

    // We won't do any pre or post processing, so leave _preRelayedCall and _postRelayedCall empty
    function _preRelayedCall(bytes memory context) internal returns (bytes32) {}

    function _postRelayedCall(
        bytes memory context,
        uint256 actualCharge,
    ) internal {}

Question: I can’t figure out, how calling the increase() function triggers the Relayer? I mean I can’t find anything interacting with the HTTP interface of the Relayer.

1 Like

Hi @vasa-develop,

In our App.js we use OpenZeppelin Network.js and specify that we want to use the GSN.

  const context = useWeb3Network(PROVIDER_URL, {
    gsn: { dev: true }

OpenZeppelin Network.js uses OpenZeppelin GSN Provider where transactions sent to contracts will then be automatically routed through the GSN.

1 Like

Hey @abcoathup!

Just wanted to check if I understood the flow correctly:

  • There is a RelayHub Contract.
  • There are a number of Relays(or Relayers) with owners, all registered on the RelayHub Contract.
  • We have a GSN compatible Recipient Contract that has a function named increase() that we want to execute. This Recipient Contract is funded and is charged by the Relay for fueling the transactions.
  • We have a react app(to interact with the dapp) that uses OpenZeppelin Network.js which uses OpenZeppelin GSN Provider .
  • The OpenZeppelin GSN Provider selects the best Relay from the available relays.
  • It contacts the winner relayer via the relay’s HTTP interface to send the required data.
  • The relayer gets the required data via the HTTP interface and signs the transaction.
  • The Relay submits the transaction to the RelayHub contract.
  • The RelayHub publishes the transaction to the Network.
  • The Recipient Contract is charged a fee according to the Relayer’s fee structure.

Is this right?

P.S. I have omitted the details like stakes etc. and assumed that all the conditions of the Relay to filter an eligible transaction are met, and nothing messes up.

1 Like

Hi @vasa-develop

That flow is correct. Though it is the Relayer (not the RelayHub) that publishes the transaction to the Network.

In addition, a recipient contract will generally use a GSN Strategy to decide whether or not to accept a requested relayed call.

We can see the available relays using the following website with injected web3 (e.g. MetaMask) and setting the desired network in injected web3.

Feel free to ask all the questions that you need.

1 Like