Starter Kits is deprecated. We are no longer developing new features nor addressing issues. Read here for more info.

GSN Starter Kit

OpenZeppelin GSN Starter Kit comes with everything you need to start using Gas Station Network contracts inside your applications. It also includes all the GSN & Web3 connection that you need to abstract gas for your users.


Ensure you are in a new and empty directory, and run the unpack command with the name of the starter kit you want to use. In this case, we’ll start our project using the kit with the name starter.

$ openzeppelin unpack OpenZeppelin/starter-kit-gsn

Why This Kit?

This kit leverages GSN to create dapps that are ready for mass adoption. Free your users from the initial burden of installing Metamask and obtaining Ether. Create blockchain applications that are indistinguishable from Web2.0 apps.

This document assumes familiarity with the Gas Station Network. Here are some resources about it:

How does it use Web3 with GSN?

This kit uses *Open Zeppelin Network JS to create the connection to Web3. Using a couple flags for development and production, you can see how the dapp obtains a context that is aware of the Gas Station Network.

// get GSN web3
const context = useWeb3Network('', {
  gsn: {
    dev: true,

How are the contracts modified to use GSN?

The Counter contract is modified to inherit from RelayRecipient. Also, the counter contract is going to naively pay for all the transactions that are submitted. Note how the acceptRelayedCall determines this by returning 0.

pragma solidity ^0.5.0;

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

contract Counter is Initializable, GSNRecipient {
  //it keeps a count to demonstrate stage changes
  uint private count;
  address private _owner;

  function initialize(uint num) public initializer {
    _owner = _msgSender();
    count = num;

// accept all requests
  function acceptRelayedCall(
    bytes calldata,
    bytes calldata,
    ) external view returns (uint256, bytes memory) {
    return _approveRelayedCall();
  }  ...

How will I know if my recipient has funds?

The frontend also has some functions to help you see how much remaining balance you have left. Once it runs out, transactions will stop working because your dapp won’t be able to pay the gas fee on behalf of its users.

const getDeploymentAndFunds = async () => {
  if (instance) {
    const isDeployed = await isRelayHubDeployedForRecipient(lib, _address);
    if (isDeployed) {
      const funds = await getRecipientFunds(lib, _address);

You can top your balance by sending funds to your contract using npx oz-gsn fund-recipient --recipient ADDRESS command or heading to the dapp tool.