How DApp users can interact with your Smart Contracts with ZERO ETH
By: Lukas Lukac
Tags: Meta Transactions, Smart Contracts, Ethereum, Blockchain, Solidity

How DApp users can interact with your Smart Contracts with ZERO ETH

Lightstreams RelayServer on Sirius Test Network

The problem is well known. In order to perform a transfer transaction or interact with a specific application smart contract, you need to pay the infrastructure cost (gas) in Ether. No user, especially new to the blockchain ecosystem, is going to be willing to do so. There is a reason why FREEMIUM model is so widely implemented in the current Web2 stack. Taste before you buy.

In this article, you will learn how to pay transactions on behalf of your users by implementing a new Ethereum concept called GSN into your DApp in 5 steps.

Gas Station Network

GSN is a concept designed and developed by a cyber security firm TabooKey. TabooKey submitted an official EIP-1613 design draft in December 2018.

Complicated?

No worries. The concept was later adopted and enhanced by established Ethereum auditing company OpenZeppelin (OZ) who developed a friendly set of JS helper tools to ease the GSN usage.

STEP 0: Choose your Ethereum-compatible blockchain network

I will demonstrate the usage on Lightstream’s PoA Ethereum compatible blockchain powered by Tendermint consensus.

Why?

Addressing gas issues is just part of the solution. Mainstream apps need to be responsive. Ethereum’s 15s blocks without a guarantee a TX won’t be reverted is unfortunately insufficient for any user facing, interactive DApp. Lightstreams provides instant finality in 3s blocks.

Already deployed RelayHub and active RelayServer means you don’t have to worry about half of the previously visualised complicated GSN diagram and can ONLY FOCUS on your app business-case.

Pre-deployed Lightstream’s RelayServer

STEP 1: Take YOUR existing Smart Contract

E.g, given you, have a simple Voter.sol smart contract and your users can either up-vote or down-vote some arbitrary value.

contract Voter {

uint256 public count;



event Voted(uint256 newCount, address account);



function upVote() public {

address lastVoter = _msgSender();

count++;



emit Voted(count, lastVoter);

}



function downVote() public {

address lastVoter = _msgSender();

count--;



emit Voted(count, lastVoter);

}

}

STEP 2: Inherit the Gas Free feature

Inherit GSN.sol to convert your traditional SC to a GSN compatible one. The GSN.sol is extending the official OpenZeppelin, TabooKey contracts.

npm i --save lightstreams-js-sdk

import "@lightstreams-js-sdk/contracts/utils/GSN.sol";



contract Voter is GSN {

STEP 3: Register the Voter.sol SC in a global RelayHub

Deploy the Voter.sol and call the initialize method. As RELAY_HUB argument specify “0xECf278654f73000F9cB3b05858158AC49c29ed68”.

This is a official RelayHub deployed on Lightstream’s Sirius test network.

voter.initialize(RELAY_HUB)

STEP 4: Pay for your users transactions

The users transactions will be free but the voting application still has to pay for it. This is done by pre-funding the SC you want to be gas-free in RelayHub.

Install OZ GSN Helpers:

"@openzeppelin/gsn-helpers": "0.1.9",

Import the fundRecipient method:

const { fundRecipient } = require('@openzeppelin/gsn-helpers');

Fund the Voter.sol with as many PHTs you are willing to pay for your users transactions gas costs:

await fundRecipient(web3, {

recipient: voter.address,

relayHubAddress: RELAY_HUB,

amount: web3.utils.toWei("10", "ether"),

from: YOUR_PHT_ACCOUNT

});

STEP 5: Let users perform FREE transactions

In order to do this, you will need a special Web3 lib decorated with HTTP Relay functionality. Why? Because the users gas-free transactions will be now submitted to previously mentioned HTTP Relayer Server https://gsn.sirius.lightstreams.io/getaddr and decorated before they are broadcasted to blockchain.

Require the Lightstream’s adjusted OZ Network library:

const { fromConnection } = require('@lightstreams-js-sdk/node_modules/openzeppelin/network');

Create a new GSN powered Web3 object:

gsnCtx = await fromConnection(

web3.eth.currentProvider.host, {

gsn: {

dev: false,

signKey: emptyAcc.privateKey

}

}); web3 = gsnCtx.lib;

Execute the gas-free TX!