Gasless/Meta transactions on Matic using Biconomy

Sameep singhania
Ginete Technologies
8 min readJun 14, 2020

Matic Network is a blockchain scalability platform that provides secure, scalable, and instant transactions powered by PoS side chains and an adapted version of Plasma. You can learn more about Matic here

Biconomy is a relayer infrastructure network and transaction platform enabling you to build applications easily and reduce the friction between your applications built on the blockchain and your end-users. You can learn more about biconomy here

In this article, we will learn how to enable gasless/meta transactions in a DApp deployed on Matic using Biconomy.

Ginete Technologies Private Limited

In this article, we will create a simple Token Transfer DApp.

This post is divided into the following 5sections-:

  1. Setting up the development environment
  2. Developing the Smart Contract
  3. Deploying the smart contract to Matic
  4. Registering contracts on Biconomy
  5. Developing the front-end with gasless transactions

1. Setting up the development environment

The setup instructions are tested on Ubuntu 16.04 LTS. But they should work fine for macOS as well.

Open a new terminal.

> sudo apt-get update
> curl -sL https://deb.nodesource.com/setup_8.x -o nodesource_setup.sh
> sudo bash nodesource_setup.sh
> sudo apt-get install nodejs
> npm install -g truffle

This will install nodejs and truffle.

Open a new terminal and perform these steps

> cd ~
> mkdir tutorial
> cd tutorial
> npx create-react-app meta-tx
> cd meta-tx
> truffle init
> npm i --save web3 openzeppelin-solidity@2.5.1 truffle-hdwallet-provider dotenv @biconomy/mexa eth-sig-util

The above commands will do the following-:

  1. Create a new directory tutorial/meta-tx. From now we will call this directory our working directory
  2. Initialize the create-react-app project inside our working directory
  3. Initialize truffle project inside our working directory
  4. Install web3.js, openzeppelin-solidity, dotenv, eth-sig-util, @biconomy/mexa and truffle-hdwallet-provider node packages

Your working directory should have the following directory structure after executing above commands

> meta-tx
> contracts
> migrations
> public
> src
> test
> package.json
> truffle-config.js

2. Developing the Smart Contract

We will be using EIP712 standard to enable gasless/meta transactions in our DApp.

Now create EIP712Base.sol file in the contracts folder in your working directory with the below contents.

EIP712Base contract contains base functionalities to support EIP712

Now create EIP712MetaTransaction.sol in the contracts folder in your working directory with the below contents.

EIP712MetaTransaction contract contains functionality to support meta transactions. It does the following operations-:

  1. Calculating meta transaction hash
  2. User signature verification as per EIP712
  3. Executing meta transaction

Now create GineteToken.sol in the contracts folder in your working directory with the below contents.

GineteToken is a simple ERC20 token that inherits openzeppelin’s ERC20, ERC20Detailed and EIP712MetaTransaction created in the previous step.

3. Deploying the smart contract to the Matic testnet

To deploy GineteToken smart contract we will have to follow these steps-:

  1. Compile the contract
  2. Add environment variable
  3. Update truffle’s migration file
  4. Create migration file for GineteToken
  5. Deploy the contract on the matic testnet using truffle migration

Now let’s compile our contract. Follow the commands below to compile GineteToken contract.

Open a new terminal and perform these steps

> cd ~/tutorials/meta-tx
> truffle compile

The above command will compile your GineteToken contract and the generated artifacts will be saved inside build/contracts folder within your working directory.

Now let’s add required environment variables in our project.

Create .env file in your working directory with the below contents.

The content of the .env file is the private key associated with the account(0x46CFAE95AA3172B1E30E0F7103A09A1DabC60941) which will be used to deploy the GineteToken contract on matic testnet

NOTE: Please do not use the above mentioned private key in production.

Now let’s update our truffle migration file.

Please replace the contents of the truffle-config.js file in your working directory with the below contents.

Now let’s create the migration file for the GineteToken.

Please create 2_GineteToken_migration.js inside the migrations folder in your working directory with the below contents.

Now let’s deploy our compiled contract on the blockchain, in our case matic testnet. Before running the next steps please ensure that you have completed the above steps successfully.

Open a new terminal and perform the following steps

> cd ~/tutorials/meta-tx
> truffle migrate --network matic --reset

The above commands will deploy GineteToken on the matic testnet using truffle’s migration.

The output of the above command should look similar to this image

The output should contain the address of the GineteToken deployed on matic testnet. In above image the address of the GineteToken is 0xc9fa015042CE672ffAC9761206504967A128fb59.

Please keep this address safe somewhere. We will be needing this address in upcoming steps.

4. Registering contracts on Biconomy

To register contracts on thebiconomy we will have to follow these steps-:

  1. Create an account on the biconomy
  2. Register our DApp on the biconomy dashboard
  3. Add GineteToken Contract in your DApp
  4. Add executeMetaTransaction API for the GineteToken contract

Go to biconomy dashboard and create your account.

Now let’s register our DApp on biconomy. Goto biconomy dashboard and click on Register in Your Dapps section.

Enter the following information while registering your dapp-:

  1. Enter Dapp name
  2. Select Matic Testnet 3 in Network dropdown

Click on Create

The above step will register a GineteToken dapp in your biconomy dashboard

Now let’s add our GineteToken contract in our recently registered dapp.

Note- Please copy API Key from the newly created DApp. We will be needing in upcoming steps.

Click on the View Dapp button. It should open a screen like this.

Click on Add Contract button in Smart Contracts section. Please enter the following information-:

  1. Name- GineteToken
  2. Address- Address of the GineteToken deployed in Step 3
  3. ABI- Copy and paste this abi

Click on Add.

Now let’s add executeMetaTransaction API for our GineteToken contract.

Click on Manage APIs button in DAPP APIs section

Now click on New API button. Please enter the following information-:

  1. Smart Contract- GineteToken
  2. Method- ExecuteMetaTransaction
  3. Name- executeMetaTransaction
  4. Enable Native meta-tx- True
  5. Click on Add

Click on Save.

5. Developing the front-end with gasless transactions

Now we will develop a front-end to interact with our deployed GineteToken using meta/gasless transactions

Now let’s create GineteToken.json inside the src folder in your working directory with the below contents.

This file contains the ABI for the GineteToken. We will be needing it to interact with the token in upcoming steps.

Now let’s edit App.js inside the src folder in your working directory. Please replace the contents of the file with this one.

  1. Add the necessary imports
// src/App.jsimport React from "react";
import Biconomy from "@biconomy/mexa";

2. Initialize constants

const abi = require("./GineteToken.json").abi;
const Web3 = require("web3");
const sigUtil = require("eth-sig-util");
// GineteToken contract address
const contractAddress = "0xc9fa015042CE672ffAC9761206504967A128fb59";
const biconomyAPIKey = ''; // Biconomy api key from the dashboard const parentChainId = '3'; // chain id of the network
const maticProvider = 'https://testnetv3.matic.network'

3. Define EIP712 domain params

const domainType = [     
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
];
const metaTransactionType = [
{ name: "nonce", type: "uint256" },
{ name: "from", type: "address" },
{ name: "functionSignature", type: "bytes" }
];
let domainData = {
name: "GineteToken",
version: "1",
chainId: parentChainId,
verifyingContract: contractAddress
};

4. Enable metamask & initialize Web3 providers (metamask in page provider for web3 and biconomy provider for getWeb3)

window.ethereum.enable().catch(error => {
console.log(error);
});
const web3 = new Web3(window.ethereum);
const biconomy = new Biconomy(
new Web3.providers.HttpProvider(maticProvider),
{
apiKey: biconomyAPIKey,
debug: true
}
);
const getWeb3 = new Web3(biconomy);
biconomy
.onEvent(biconomy.READY, () => {
console.log("Mexa is Ready");
})
.onEvent(biconomy.ERROR, (error, message) => {
console.error(error);
});

5. Initialize contract object and define params

const contract = new getWeb3.eth.Contract(abi, contractAddress); const amount = "1000000000000000000";
const recipient = "Add your recipient address here";

6. Define functions to execute the transaction

const metaTransfer = async () => {
let functionSignature = contract.methods
.transfer(recipient, amount)
.encodeABI();
executeMetaTransaction(functionSignature);
};
const executeMetaTransaction = async functionSignature => {
const accounts = await web3.eth.getAccounts();
let userAddress = accounts[0];
let nonce = await contract.methods.getNonce(userAddress).call();
let message = {};
message.nonce = parseInt(nonce);
message.from = userAddress;
message.functionSignature = functionSignature;
const dataToSign = JSON.stringify({
types: {
EIP712Domain: domainType,
MetaTransaction: metaTransactionType
},
domain: domainData,
primaryType: "MetaTransaction",
message: message
});
web3.eth.currentProvider.send(
{
jsonrpc: "2.0",
id: 999999999999,
method: "eth_signTypedData_v4",
params: [userAddress, dataToSign]
},
function(error, response) {

let { r, s, v } = getSignatureParameters(response.result);

const recovered = sigUtil.recoverTypedSignature_v4({
data: JSON.parse(dataToSign),
sig: response.result
});
let tx = contract.methods
.executeMetaTransaction(userAddress, functionSignature,
r, s, v)
.send({
from: userAddress
});
}
);
};
const getSignatureParameters = signature => {
if (!web3.utils.isHexStrict(signature)) {
throw new Error(
'Given value "'.concat(signature, '" is not a valid hex
string.')
);
}
var r = signature.slice(0, 66);
var s = "0x".concat(signature.slice(66, 130));
var v = "0x".concat(signature.slice(130, 132));
v = web3.utils.hexToNumber(v);
if (![27, 28].includes(v)) v += 27;
return {
r: r,
s: s,
v: v
};
};

7. Define App() function

function App() {
return (
<div>
<h3> MetaToken </h3>
<React.Fragment>
{""}
<button onClick={() => metaTransfer()} size="small">
Transfer
</button>
</React.Fragment>
</div>
);
}
export default App;

You can find the App.js code here

8. Run your application

Open a new console and perform the following steps.

> cd ~/tutorials/meta-tx
> npm start

Now your app should be running on http://localhost:3000

Thanks for reading the article. I hope it was useful for you.

If you are looking out for Blockchain consulting or development services then reach out to us at info@ginete.in or drop your query on our website.

--

--