Building with Account Abstraction (Part 3) - Using the Paymaster Contract

Emmanuel Oaikhenan
Emmanuel Oaikhenan
Technical Writer
This installment of our Account Abstraction series focuses on using the Paymaster contract in preparation to create a gasless dapp!

Introduction

Continuing on with our Account Abstraction guide series, the next few parts will focus on Paymasters! Specifically, how the Paymaster smart contract and the Biconomy SDK can create a gasless experience for your app users. In this installment, we introduce the project and guide you through setting up the Paymaster, gas tank and policies for the two smart contracts we will interact with.

Understanding the Paymaster Smart Contract

The Paymaster smart contract is a key player in Web3's evolving landscape, especially in onboarding users. It addresses one of the most significant hurdles in user interaction with decentralized applications (dApps): the complexity and friction associated with gas fees. This contract simplifies the onboarding experience, allowing applications to sponsor gas fees, paving the way for the next billion users to enter web3.

Whether you are a developer looking to enhance user experience or an enthusiast curious about the latest advancements in decentralized technologies, this exploration of the Paymaster contract promises to be enlightening.

Prerequisites

Before we dive in, ensure you have:

  • Knowledge of the ERC-4337 proposal.

  • An understanding of what Node Operators do.

  • NodeJS (v18+ recommended) installed on your machine.

  • An IDE, such as VSCode.

  • Familiarity with previous articles in this series.

  • Understanding of Smart Contract ABIs.

  • Knowledge of the Biconomy SDK.

Understanding the Tipping Smart Contract

Our focus is on a Tipping smart contract. This contract allows users to send tips, with the contract owner being the only one able to withdraw them.

For a detailed step-by-step process, refer to my guide on building a tipping smart contract using Solidity. Here, the entire codebase and its methods will be shared rather than presenting a follow-along tutorial.

// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol";

This initial section specifies the Solidity version with the pragma statement and declares the MIT Open Source License. We utilize several Smart Contract Libraries from OpenZeppelin. The IERC20 Library provides access to ERC20 methods as an interface contract. SafeERC20 is used for methods like safeTransferFrom, and the Ownable Contract enables access control with the onlyOwner modifier.

contract Tip is Ownable { using SafeERC20 for IERC20; IERC20 public token; constructor(IERC20 _token) { token = _token; } }

Here, the contract is initialized, libraries are declared, and variables are assigned. The tipping contract operates with a native ERC-20 token for receiving tips. This functionality enables a demonstration of batch UserOperations for approve and send. The process involves approving the tipping smart contract to spend the native ERC-20 token owned by the address, followed by executing the transfer method in a single userOperation.

The following lines define emitted events.

event TipReceived(address sender, uint256 amount); event TipWithdrawn(uint256 amount);

This function enables the recieval of tips:

function receiveTips(uint256 _amount) public payable returns(uint256) { require(_amount > 0, "Amount must be greater than 0"); token.safeTransferFrom(msg.sender, address(this), _amount); emit TipReceived(msg.sender, _amount); return _amount; }

The following functions are for withdrawing tips. This can be called by only the owner who deployed the smart contract.

function getTokenBalance() public view onlyOwner returns(uint256) { return token.balanceOf(address(this)); } function withdrawTips(uint256 _amount) public onlyOwner returns(uint256) { require(_amount > 0, "Amount must be greater than 0"); token.safeTransfer(msg.sender, _amount); emit TipWithdrawn(_amount); return _amount; }

The deployed smart contracts are accessible at:

Interaction typically occurs with both the token contract and the tipping contract. We will mint tokens to the created smart contract account, then call the method to send tips to the tipping smart contract.

The next phase involves developing the user interface and integrating the Biconomy SDK.

Using the Biconomy SDK

The Biconomy Modular SDK is a toolkit designed for implementing common account abstraction scenarios. This SDK operates in a non-custodial manner, ensuring that Smart Contract Accounts created by users are fully owned by them. This grants developers flexibility in their implementation strategies using the SDK.

Before integrating the SDK into your user interface, it's essential to understand several key points:

  1. User Operations Without a Paymaster: It's important to note that you can send UserOperations without using a Paymaster, as per the ERC 4337 specification. However, implementing a Paymaster facilitates a Gasless experience for users.

  2. Dashboard Requirements on Biconomy: On the Biconomy Dashboard, you are required to:

    • Create a Biconomy Account: This provides you with a unique API key for accessing Biconomy's features. Create an account here.

    • Register a Paymaster: Biconomy offers two types of Paymasters:

      • Sponsorship Paymaster: Opt to pay the user’s gas fees.

      • Token Paymaster: Allows users to pay gas fees with any ERC20 native tokens supported by Biconomy.

    • Set Up a Gas Tank: Fund this with native tokens (e.g., MATIC on Polygon) for use in the Sponsorship Mode to pay for UserOperations.

    • Define Paymaster Policies: Specify which method calls in your smart contracts should be sponsored by the Paymaster. This process is similar to smart contract verification, requiring you to provide the ABI and list the specific methods for interaction in your dApp.

All these activities are performed on the Biconomy platform and are integrated into the UI build through libraries and URL paths.

Understanding these processes is crucial for the upcoming project steps. We will first develop the UI, followed by executing the above tasks.

Step 1 - Initialize Project

We'll be using Vite to build our dApp.

Open VSCode or your preferred IDE, create a new folder, and navigate into it:

mkdir gasless-bcnmy && cd gasless-bcnmy

Execute the following command:

yarn create vite

Select the framework as React, and choose TypeScript as the variant. Follow the subsequent instructions:

cd gasless-bcnmy yarn yarn dev

Your app should now be running at http://localhost:5173/.

The goal is to implement a login button and a UI where users can mint tokens and submit tips.

Step 2 - Set Up TailwindCSS

To enhance the app's appearance, we will integrate TailwindCSS with Vite.

Execute these commands in your terminal:

npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p

Update the content array in the tailwind.config.js file:

content: [ "./index.html", "./src/**/*.{js,ts,jsx,tsx}", ],

This step includes all your template files in the Tailwind configuration.

In index.css, insert the Tailwind directives at the top:

@tailwind base; @tailwind components; @tailwind utilities;

Remove specific styles from index.css and App.css as described:

  • In index.css, delete color-scheme and background-color.

  • In body, remove display and place-items.

  • In App.css, remove padding and text-align.

Restart your app server:

yarn run dev

TailwindCSS is now integrated. Remember to restart the server after these changes!

Modify App.tsx as follows:

import "./App.css"; function App() { return ( <> <nav className="flex items-center justify-between flex-wrap bg-teal-500 p-6"> <div className="flex items-center flex-shrink-0 text-white mr-6"> <span className="font-semibold text-xl tracking-tight">DEMO</span> </div> <div className="w-full block flex-grow lg:flex lg:items-center lg:w-auto"> <div className="text-sm lg:flex-grow"> <a href="#responsive-header" className="block mt-4 lg:inline-block lg:mt-0 text-teal-200 hover:text-white mr-4" > Welcome </a> </div> <div> <button //onClick={login} className="inline-block bg-teal-500 text-sm px-4 py-2 leading-none border rounded text-white border-white hover:border-transparent hover:text-teal-500 hover:bg-white mt-4 lg:mt-0" > Log in </button> </div> </div> </nav> <div className={`flex min-h-screen flex-col items-start p-24`}> <div className="text-gray-900"> Click the Button above to Connect your Wallet </div> </div> </> ); } export default App;

Reload your browser to view the changes.

With the UI in place, we'll next integrate Biconomy for user functionalities such as creating Smart Contract Accounts, minting tokens, and sending tips. This requires setting up an account on Biconomy to access the API Key and configuring the Paymaster and gas tank.

Step 3 - Set Up Paymaster and Fill Gas Tank

Head over to Biconomy.io and click on Get Started. You have two options to sign in with Developer Auth using GitHub or GitLab, and the option of using email. Sign up to create an account and head over to the dashboard. On the dashboard, we will create a Paymaster.

Click on Add paymaster.

Next, register the Paymaster. Give it a name, choose a version (currently 1.1.0), and select Polygon Mumbai as the chain we will be using.

Upon creation of the Paymaster, you will be able to find your unique API key and Paymaster URL. The next step is to fill the gas tank. You can get some MATIC test tokens from the Polygon Faucet or the GoldRush Faucet.

In the Overview section of the newly created Paymaster, select the option Sponsored in the mode section. The option ERC-20 is selected by default.

Switching the mode will open the Gas-Tank tab. You will be required to connect your wallet, and then deposit your chosen amount of MATIC tokens.

When you click Connect wallet, you will be required to sign a transaction by MetaMask.

After signing the message, Click on Set up gas tank.

You will be prompted again by MetaMask to sign a message.

Click on Go to deposit, enter the amount you wish to deposit and approve the deposit.

You can always withdraw the deposited tokens.

Now, the gas tank is set up! The next step will be to set up the policies.

Step 3B - Set up Policies

Click on Policies in the Tab.

Click on Add your first contract. You can enter a name for easy recall. Then enter the address of the deployed token contract on Polygon Mumbai. It will pull up the ABI and available contract methods:

For the deployed token contract, we will only call the mint and approve methods. Select those to be added to the policies.

Then click on Add Smart Contract and create additional policies for the tipping smart contract. It should be the same steps as above, aside from the smart contract address (0x8FA509aB0087755fdd5fb49DF1D5FaD95f9d9eB7) and the method we will call receiveTips.

Conclusion

There! We have successfully set up our Biconomy dashboard, and have access to the API Key. We have also set up the Paymaster, gas tank and policies for the two smart contracts that we will be interacting with. The next step is to add the scripts to the UI that will integrate functionalities for onboarding users and carrying out transactions without them paying gas fees or calling their MetaMask to approve UserOperations (i.e. Transactions). Keep engaged with the following parts to create a completely gasless dApp!

Read more