Biconomy - Win your customer's heart with Gasless Transactions
Published: 2022-12-05 03:32:41

Gas Price is a necessary evil in the world of Web3. Although it plays a vital role in terms of rewarding the “Miners” and making smart contract execution more secure, it creates an awful user experience. Even from a purely business perspective, it makes much more sense in having a fixed billing system for the users, while the execution costs are covered by the service provider. With the traditional approach, it’s impossible to build such a system without introducing a centralized entity into the system. 

## 💡Biconomy - A ray of hope

Among other features, Biconomy makes it possible for developers to provide “Gasless Transactions” with the least amount of effort. This is a fully decentralized solution powered by smart contracts and no compromise is made in terms of security and stability.

Biconomy is based on the simple concept that the service provider pays the gas on behalf of the users. The users are only required to sign a particular message while interacting with the smart contract. This signature is then validated by Biconomy and if sufficient funds are available to sponsor the transaction, the gas is paid, and the transaction details are forwarded to the Dapp smart contract.

The important point to note is that there is nothing like a transaction without gas fees, however, Biconomy just enables us to maintain a special account where we deposit enough funds to pay for the gas price for all users. The gas price gets paid from this “*special*” account and it’s up to us or the project admin to ensure that sufficient funds are always available for sponsoring transactions. To make this even simpler, Biconomy provides an intuitive Dashboard for managing everything.

## 🎯Scope of this article

This article will act as a beginner-friendly tutorial for getting started with Biconomy. For the sake of simplicity, we will be focusing only on *[Gasless Transactions](https://docs.biconomy.io/products/enable-gasless-transactions)*, specifically *[Gasless Transactions using EIP 2771-based approach](https://docs.biconomy.io/products/enable-gasless-transactions/choose-an-approach-to-enable-gasless/eip-2771)*. This article won’t discuss the architecture used by Biconomy nor the various other jaw-dropping features provided. To learn about them I recommend giving their [official documentation](https://docs.biconomy.io/) a read. 

In this tutorial we will:

- Write a simple Smart Contract using `EIP 2771` to make it compatible with Biconomy.
- Deploy and test our smart contract on the Polygon Testnet (Mumbai).
- Build a very simple front end using React to interact with our smart contract.

I follow a “*code-first-explanation-next”* approach. Please let me know if this is helpful or if I should try any different approach in the comment section.

## ⚠️Disclaimer

At the point of writing this article, Biconomy is transitioning to a newer SDK-based approach that brings yet more to the table, however here we will be using the older approach which is much simpler and sufficient for our needs. Documentation of the latest SDK can be found [here](https://biconomy.gitbook.io/sdk/introduction/overview). The new SDK is still WIP and not polished enough for developers to use. Once ready, I plan to cover it in my future articles. 

## 🎒Pre-requisites

I know you all are excited to get started, but before we dive in, make sure you got the following pre-requisites sorted:

- [Remix IDE](https://remix.ethereum.org/#optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.7+commit.e28d00a7.js): For developing smart contracts
- [Metamask](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn): Metamask is a popular non-custodial wallet used for interacting with the blockchain.
- Connected with Testnet: Although you can use any network of your choice, I will be using Polygon’s Mumbai Testnet. If you want to follow along, make sure you have added Mumbai Testnet in Metamask following [this article](https://medium.com/stakingbits/how-to-connect-polygon-mumbai-testnet-to-metamask-fc3487a3871f), and then fund your account using [this faucet](https://www.notion.so/Write-ups-620aeda4ab7649908b58b692a6de981c).

## 💻Writing the Smart Contract

Let’s get started with the crux of our project, i.e., the smart contract. In your Remix IDE create a new file named `Greetings.sol` and paste the following code.

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

contract Greetings {
    mapping (address => string) public greetings;

    function setGreeting(string memory newGreeting) public {
        greetings[msg.sender] = newGreeting;
    }
}
```

This is a very simple smart contract that stores a string each corresponding to each address that called the `setGreeting`function. The string to be stored is passed as an argument to the function. The important point to note here is `msg.sender` is used for finding the account address that invoked the `setGreeting` function.

Let’s try to understand the challenge of using the above contract with Biconomy. Refer to the following diagram to understand how Biconomy forwards transactions:
![Biconomy TrustedForwarder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/js90t7eqqp8qnijvc21q.png)
If you look closely, you will understand that a “*TrustedForwarder*” contract is used to invoke our smart contract. In this scenario, regardless of which account initiates the call, the `msg.sender` will always return the address of the caller, i.e., the *TrustedForwarder’s* address. To solve this issue, we have to make the following changes to our smart contract:

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/metatx/ERC2771Context.sol";

contract Greetings is ERC2771Context {

    constructor(address trustedForwarderAddress) ERC2771Context(trustedForwarderAddress) {}

    mapping (address => string) public greetings;

    function setGreeting(string memory newGreeting) public {
        greetings[_msgSender()] = newGreeting;
    }
}
```

Here we are doing the following:

- We are using the `ERC2771Context` contract from OpenZeppelin contracts. It provides us with the `_msgSender()` function that will be very important to us.
- The `trustedForwarderAddress` is the contract that we expect to call our smart contract. This forwarder is responsible for signature verification and protection against replay attacks. Before forwarding the transaction, the signer (our user’s address) is appended to the *calldata and* passed to the smart contact. The `_msgSender()` function returns this address.
    
    You can find the list of Biconomy’s TrustedForwarder’s addresses [here](https://docs.biconomy.io/misc/contract-addresses).
    
- Inside our code we replace `msg.sender` with `_msgSender()` to reflect the correct user.

*And with that our smart contract is ready for gasless transactions!!*

### Deployment and Biconomy Setup

Now that our smart contract is ready, it’s time to deploy our smart contract. Let’s deploy it to Mumbai Testnet (You can choose any other network of your choice).

- In the deploy section of Remix, select `Injected Provider - MetaMask` as the Environment. Also, make sure your Metamask is connected with your desired chain.
- For your chosen chain, find the respective TrustedForwarder address [here](https://docs.biconomy.io/misc/contract-addresses). Since I am using Mumbai Testnet, mine is 0x69015912AA33720b842dCD6aC059Ed623F28d9f7. You must pass this address as a constructor argument while deploying the contract.
- Finally, click on `transact` and confirm the MetaMask popup to deploy the smart contract.
![Deploying Smart Contract](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9iq6dmvdulgyag0m4qrs.png)
Now to set up Biconomy, sign in to your Biconomy Dashboard. Next, you have to register a new Dapp and mention the chain in which your smart contract is deployed.
![Register new Dapp in Biconomy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ifqf3scv3r42hwan0vmy.png)
Once registered, click on the card corresponding to your Dapp and this will open the respective Dapp’s dashboard. Here you can see the various details associated with your Dapp.
![Newly registered Dapp](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6uepfvayoquftiyhvbmk.png)
For a freshly created Dapp, the Gas Balance would be 0. Before you can let users enjoy gasless transactions, you have to load crypto (native token) into this Dapp to pay for the gas on behalf of the users. Click on the `Fill Gas` button, enter the amount of token you want to deposit, and click `Fill Me Up`. A MetaMask popup will ask you to send the required amount of tokens and confirm it to deposit the funds. It should be reflected on your Dapp promptly under `GAS BALANCE`.

A single Dapp can be associated with multiple smart contracts. Head to the `Smart Contract` section in your dashboard. Enter the Name, address, and ABI of your smart contract. All these details can be found in Remix. Make sure that `Meta Transaction Type` is set to `Trusted Forwarder`. Click on `Add` to add the smart contract to your Dapp.
![Adding Smart Contract](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vkcqbiscpykqpbcn6z4h.png)
Now the final step is to create API Endpoints for the function we want to invoke. Head to the `Dapp APIs` section.

- Click on the white `Add` Button
- Enter a suitable name for your API.
- Choose the corresponding Smart Contract and Method to be invoked.
- Click on the orange `Add` button to create a new API endpoint.
![Creating new Endpoint](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/21zzx6yzk9dw2uhrov7t.png)
Hurray!! Finally, we are ready for gasless transactions 👏👏👏.

## 🌐Building a basic website

Now that we are ready for gasless transactions, it’s time to build a simple website for interacting with our smart contract. In this tutorial, we are going to use React for building our demo website.

Use the following command to create a new react project:

```bash
npx create-react-app biconomy_tutorial
```

I have named my project `biconomy_tutorial`, however, feel free to choose any name of your liking. Once the project is initialized, move inside the newly created project folder. Next, we will be using the `biconomy/mexa` package for interacting with our smart contract. Use the following command for installing it:

```bash
npm install @biconomy/mexa
```

### 🚫Known Issue

In case you have used any other libraries like `web3.js`, you must be already familiar with the [Webpack Error](https://github.com/bcnmy/gasless-playground/issues/2). For those who are new, whenever you try to import the `biconomy/mexa` package in your React code, you would get an error message similar to the following:
![Webpack Error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cdeytes3bqwjbz44w9zn.png)
To resolve this we will need `react-app-rewired`. First, install the required dependencies using the following command:

```bash
npm install react-app-rewired crypto-browserify stream-browserify assert stream-http https-browserify os-browserify url path-browserify browserify-zlib process buffer util
```

Now create a new file called `config-overrides.js` and paste in the following code:

```jsx
const webpack = require('webpack');
module.exports = function override(config) {
  config.ignoreWarnings = [/Failed to parse source map/];
  const fallback = config.resolve.fallback || {};
  Object.assign(fallback, {
    crypto: require.resolve("crypto-browserify"),
    stream: require.resolve("stream-browserify"),
    assert: require.resolve("assert"),
    http: require.resolve("stream-http"),
    https: require.resolve("https-browserify"),
    os: require.resolve("os-browserify"),
    url: require.resolve("url"),
    path: require.resolve("path-browserify"),
    zlib: require.resolve("browserify-zlib"),
    process: require.resolve("process/browser"),
    buffer: require.resolve("buffer"),
    util: require.resolve("util"),
    fs: false,
    tls: false,
    net: false,
  });
  config.resolve.fallback = fallback;
  config.plugins = (config.plugins || []).concat([
    new webpack.ProvidePlugin({
      process: 'process/browser',
      Buffer: ['buffer', 'Buffer'],
    })
  ])
  return config;
}
```

Finally in the `package.json` file change the `start` task to `react-app-wired start`. Finally, close and restart the react app. Now this problem should be resolved.

### Building the website

Open the `App.js` file in our react project in any code editor of your choice and make the following modifications:

```jsx
import './App.css';
import { Biconomy } from "@biconomy/mexa";
import { ethers } from 'ethers';

function App() {

  const setMessage = async (message) => {
  }

  return (
    <div className="App">
      <header className="App-header">
        <button onClick={() => setMessage("Hello World")}>Set Message</button>
      </header>
    </div>
  );
}

export default App;
```

Here we added a simple button that calls the `setMessage` function. This function takes a string as input and passes it to the smart contract function. For simplicity, here we are hardcoding the string to be “*Hello World*”. To simplify our project even further, we will implement the complete logic of using Biconomy inside the `setMessage` function, however, an experienced React developer would prefer to use proper state management.

Before using Biconomy, we have to first initialize it. The code for initializing Biconomy is as follows:

```jsx
const setMessage = async (message) => {
  const biconomy = new Biconomy(window.ethereum, {
    apiKey: "5hUl....1a87",
    debug: true,
    contractAddresses: [
      "0x160d3a01bf31cabbb6fcb60b5573bbad859e46c7"
    ]
  })
  await biconomy.init();
}
```

In the above code snippet note that:

- As the Ethereum provider, we are using `window.ethereum`, i.e., the Ethereum object injected by the Metamask wallet. In case you want to use a different wallet, you have to modify it respectively. (Let me know in the comments if you want an example of using a different wallet).
- Make sure you enter your own API Key for Biconomy that you will find in the Biconomy Dashboard. Needless to say, instead of hardcoding it, it’s recommended to use environment variables.
- We also have to pass a list of contract addresses that we want to interact with. Ideally, this list will contain only those contract addresses that we want to interact with, and not all the contract addresses added to our dashboard.

The next step is to create a contract instance. The beauty of Biconomy is from here on, the process of interacting with the smart contract is similar to the traditional approach. I am using `ethers`, however, in the official documentation, you will also find how to use `web3.js`.

```jsx
const setMessage = async(message) => {
  ...
	const contractInstance = new ethers.Contract(
		CONTRACT_ADDRESS,
		CONTRACT_ABI,
		biconomy.ethersProvider
	)

	const ethersProvider = new ethers.providers.Web3Provider(window.ethereum);
	const connectedAddress = (await ethersProvider.listAccounts())[0];

	const tx = await contractInstance.populateTransaction.setGreeting(message, {
		gasLimit: 1000000,
		gasPrice: 1000000000
	})
	const txDetails = {
		from: contractAddress,
		to: CONTRACT_ADDRESS,
		data: tx.data,
		signatureType: "PERSONAL_SIGN"
	}

	const provider = await biconomy.provider
	await provider.send("eth_sendTransaction", [txDetails])
}
```

Here we are performing the following tasks:

- Creating an instance of the smart contract.
- We get and store the current connected Metamask account in the `connectedAddress` variable.
- Next, we define the transaction and store it in `tx` variable. Note that here we are not sending the transaction to the blockchain. Rather we are using the `populateTransaction` method because we want to generate the calldata that would be sent to the blockchain.
- Any function invocation in the blockchain is also recorded in form of a transaction. Without getting into the complexities, you can assume that what differentiates a transfer of native tokens (also called transaction) and calling a function is that in the latter, a signed payload containing the function signature and the arguments are passed which is also termed as the `calldata`. We generate these transaction details and store them in the `txDetails` variable.
- Next, we obtain the `provider` from the defined `Biconomy` object.
- Finally, we send the transaction for verification to the blockchain. Here we use the `eth_sendTransaction` function. This is where the users receive a Metamask popup asking them to sign a specific payload. Behind the hood, this transaction payload is actually passed by the *Biconomy Relay* to the *TrustedForwarder* contract, and it also pays for the required gas.

With this, you are now ready to make Gasless transactions 😎. Go ahead and give your newly created website a try. I have a small task for you: 

```
👉Try to make a gasless transaction. Verify whether the message was set properly and
whether the user had to pay any gas.

👉Let me know your findings in the comment section
```

In case you run into errors or feel I was not able to explain the topic properly, please let me know and I will try my best to clear every doubt.

## 👨‍💻About Me

Hi, I am [Bhaskar Dutta](https://www.linkedin.com/in/itsbhaskardutta/), a Software Developer here at [Xenabler](https://xenabler.digital/) where we try to bring technology and people together, one commit at a time.

If you have read so far, I feel we are going to be partners in an otherwise long journey of exploring the ever-changing world of technology. I would really want to connect with my readers and know them a bit more and if you want something similar, do send a connect request on [LinkedIn](https://www.linkedin.com/in/itsbhaskardutta/).

Before saying goodbye, remember to take care of yourself and let the special people in your life know you *Love Them*. We will soon meet again in a different tutorial, till then *Take Care of Yourself*, let the special people in your life know you *Love Them*, and *Keep Building*.