Biconomy Gasless SDK (EOA)
DashboardMediumWebsite
  • 🚀Getting Started
  • Introduction
    • 🤘Why Biconomy?
    • 🙂How we simplify transactions
  • Products
    • 💸Gasless Transactions
      • Choose An Approach to Enable Gasless
        • Standard EIP 2771 Approach
          • 1. Register Artifacts on the Dashboard
          • 2. Code Changes
            • Using SDK
            • Using API
        • Custom Implementation Approach
          • 1. Register Artifacts on the Dashboard
          • 2. Code Changes
            • Using SDK
            • Using API
        • Smart Contract Wallet Approach
          • Gnosis
        • Network Agnostic Transactions
          • EIP-2771 Approach
          • Custom Approach
      • Conditional Whitelisting
      • Gasless SDK (EOA) 3
      • Networks Supported
    • ↔️Hyphen - Instant Cross-Chain Transfers
      • SDK
        • DepositManager
        • TransferManager
        • TokenManager
      • APIs
      • Helper Methods
      • Migrating from Hyphen V1
      • Contract Addresses
      • Hyphen Widget
  • Guides
    • 💻Dashboard
      • DApp Statistics
    • ⛽Gas Tank Deposits
      • Via Dashboard
      • Via Smart Contract
  • api
    • 🔧Native Meta Transaction
      • Get Retried Hashes
    • 🌎Dashboard APIs
    • ⚪Whitelist API
      • Whitelist Destination Address
      • Whitelist Proxy Contracts
    • 〰️ Check Limits
    • 💿Biconomy Data API
      • 👨‍🚀Unique User Data
      • 🧑‍🔧Per User Limits Data
      • ⛽Gas Tank Balance Data
  • SDK
    • 📙Gasless SDK (EOA)
      • Configuration
  • Tutorials
    • 🔰Native Meta Transactions
      • How To Build Your First DApp
        • Write Your First Smart Contract
        • Initialize Web3 on Client Side
        • Executing First Blockchain Transaction
      • Enable Native Meta Transactions
        • Smart Contract
          • Describe Your Structs
          • Declare Your Variables
          • Modify Respective Function
        • Client Side
          • Design Your JSON structure
          • Design Your Domain Separator
          • Design Data Types
          • Define Data To Sign
          • Generate Signatures
      • Integrate Biconomy
        • Register On Dashboard
        • Integrate Gasless SDK (EOA)
      • Summary
  • BICO Staking
    • 🪁Safety Module
  • Get in touch
    • 👥Contact Us
  • Misc
    • 🧩Projects on Biconomy
    • 🌐Supported Networks
    • 📫Contract Addresses
    • ✔︎ Smart Contracts Audit
    • ❓FAQs
Powered by GitBook
On this page
  • SDK Frontend Integration
  • SDK Backend Integration

Was this helpful?

  1. Products
  2. Gasless Transactions
  3. Choose An Approach to Enable Gasless
  4. Custom Implementation Approach
  5. 2. Code Changes

Using SDK

Gasless SDK (EOA), enables meta transactions or gasless transactions in your dApp out of the box.

Previous2. Code ChangesNextUsing API

Last updated 2 years ago

Was this helpful?

Biconomy's Gasless SDK (EOA) is a javascript based implementation that can be easily integrated into your dApp. The SDK can be used on client side code running in a browser or a javascript based dApp running on a backend server.

It works alongside your existing Web3/Ethers library by acting as a Web3/Ether provider that submits meta transactions to our relayer infrastructure - instead of directly to the network.

Get your API Key first

In order to integrate SDK, you will need an API Key. Check out from the dashboard.

This section is divided into Frontend and Backend integration of SDK. You can choose either of them based on your requirement.

SDK Frontend Integration

1. Installing and importing SDK

Biconomy Gasless SDK can be installed either via npm or yarn.

npm install @biconomy/mexa
yarn add @biconomy/mexa

You can use Gasless either with or library. It works with both libraries.

const biconomy = new Biconomy(window.ethereum as ExternalProvider, {
  apiKey: config.apiKey.prod,
  debug: true,
  contractAddresses: [<contractAddress1>, <contractAddress2>], // list of contract address you want to enable gasless on
});

// The first argument of the Biconomy class is an EIP 1193 type provider that has to be passed. 
// If there is a type mismatch you'll have to set the type of the provider as 
// External Provider
export type ExternalProvider = {
  isMetaMask?: boolean;
  isStatus?: boolean;
  host?: string;
  path?: string;
  sendAsync?: (request: { method: string, params?: Array<any> }, callback: (error: any, response: any) => void) => void
  send?: (request: { method: string, params?: Array<any> }, callback: (error: any, response: any) => void) => void
  request?: (request: { method: string, params?: Array<any> }) => Promise<any>
}

// To create contract instances you can do:
const contractInstance = new ethers.Contract(
  config.contract.address,
  config.contract.abi,
  biconomy.ethersProvider
);
const biconomy = new Biconomy(window.ethereum as ExternalProvider, {
  apiKey: config.apiKey.prod,
  debug: true,
  contractAddresses: [<contractAddress1>, <contractAddress2>], // list of contract address you want to enable gasless on
});

// The first argument of the Biconomy class is an EIP 1193 type provider that has to be passed. 
// If there is a type mismatch you'll have to set the type of the provider as 
// External Provider
export type ExternalProvider = {
  isMetaMask?: boolean;
  isStatus?: boolean;
  host?: string;
  path?: string;
  sendAsync?: (request: { method: string, params?: Array<any> }, callback: (error: any, response: any) => void) => void
  send?: (request: { method: string, params?: Array<any> }, callback: (error: any, response: any) => void) => void
  request?: (request: { method: string, params?: Array<any> }) => Promise<any>
}

const web3 = new Web3(biconomy.provider);
const contractInstance = new web3.eth.Contract(
  abi,
  contractAddress
);

If using SDK version 2.0.35 or earlier:

import { Biconomy } from "@biconomy/mexa";
const biconomyWithWeb3 = new Biconomy(<web3 provider>,{apiKey: <API Key>, debug: true});
web3 = new Web3(biconomyWithWeb3);

const biconomyWithEthers = new Biconomy(<ethers provider>,{apiKey: <API Key>, debug: true});
let ethersProvider = new ethers.providers.Web3Provider(biconomyWithEthers);

2. Initialize your dApp after SDK initialization

You need to call the init method. This method makes calls to the Biconomy backend to fetch data that you registered on the dashbaord.

await biconomy.init();

3. Example Code:

Since we have enabled native meta transaction in a custom way, instead of calling your smart contract methods directly, we will call executeMetaTransaction method and pass the target method info as a parameter to this function.

Congratulations 👏

You have now enabled meta transactions in your dApp.

SDK Backend Integration

For using the SDK in the backend, use SDK version 2.0.35 or earlier

Here, we provide more freedom to the developer in case you want to use Biconomy in your project running at the backend where a raw transaction is signed by the user's private key.

Integration Steps

  1. Call executeMetaTransaction method via web3 or ethers using a private key.

Checkout example code below. Need more reference? check repositories for complete code.

let sigUtil = require("eth-sig-util"); // additional dependency 

let privateKey = <PRIVATE_KEY>;
let nonce = await contract.methods.getNonce(userAddress).call();
let functionSignature = contract.methods.setQuote(newQuote).encodeABI();

let message = {};
message.nonce = parseInt(nonce);
message.from = userAddress;
message.functionSignature = functionSignature;

//please refer to SDK front end example for domainType and domainData
const dataToSign = JSON.stringify({
  types: {
    EIP712Domain: domainType,
    MetaTransaction: metaTransactionType
  },
  domain: domainData,
  primaryType: "MetaTransaction",
  message: message
});

/*Its important to use eth_signTypedData_v3 and not v4 to get EIP712 
signature because we have used salt in domain data instead of chainId*/
const signature = sigUtil.signTypedMessage(new Buffer.from(privateKey, 'hex'), { data: dataToSign }, 'V3');
let { r, s, v } = getSignatureParameters(signature); // same helper used in SDK frontend code
let executeMetaTransactionData = contract.methods.executeMetaTransaction(userAddress, functionSignature, r, s, v).encodeABI();

let txParams = {
                    "from": userAddress,
                    "to": config.contract.address,
                    "value": "0x0",
                    "gas": "100000", // (optional) your custom gas limit 
                    "data": executeMetaTransactionData
                };
                
const signedTx = await web3.eth.accounts.signTransaction(txParams, `0x${privateKey}`);                                                                

let receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction, (error, txHash) => {
                    if (error) {
                        return console.error(error);
                    }
                    console.log("Transaction hash is ", txHash);
                    // do something with transaction hash
                });
                
console.log(receipt.transactionHash);
let privateKey = <PRIVATE_KEY>;
let nonce = await contract.methods.getNonce(userAddress).call();
let functionSignature = contract.methods.setQuote(newQuote).encodeABI();
let chainId = 42;

//same helper constructMetaTransactionMessage used in SDK front end code
let messageToSign = constructMetaTransactionMessage(nonce, chainId, functionSignature, config.contract.address);

let {signature} = web3.eth.accounts.sign("0x" + messageToSign.toString("hex"), privateKey);
let { r, s, v } = getSignatureParameters(signature); // same helper used in SDK frontend code
let executeMetaTransactionData = contract.methods.executeMetaTransaction(userAddress, functionSignature, r, s, v).encodeABI();

let txParams = {
                    "from": userAddress,
                    "to": config.contract.address,
                    "value": "0x0",
                    "gas": "100000", // (optional) your custom gas limit 
                    "data": executeMetaTransactionData
                };
                
const signedTx = await web3.eth.accounts.signTransaction(txParams, `0x${privateKey}`);                                                                

let receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction, (error, txHash) => {
                    if (error) {
                        return console.error(error);
                    }
                    console.log("Transaction hash is ", txHash);
                    // do something with transaction hash
                });
                
console.log(receipt.transactionHash);
let sigUtil = require("eth-sig-util"); // additional dependency 

let contract = new ethers.Contract(<CONTRACT_ADDRESS>,
              <CONTRACT_ABI>, biconomy.getSignerByAddress(userAddress));
let contractInterface = new ethers.utils.Interface(<CONTRACT_ABI>);

let privateKey = <PRIVATE_KEY>;
let wallet = new ethers.Wallet(privateKey);
let nonce = await contract.getNonce(userAddress);
let functionSignature = contractInterface.encodeFunctionData("setQuote", [newQuote]);

let message = {};
message.nonce = parseInt(nonce);
message.from = userAddress;
message.functionSignature = functionSignature;

//please refer to SDK front end example for domainType and domainData
const dataToSign = JSON.stringify({
  types: {
    EIP712Domain: domainType,
    MetaTransaction: metaTransactionType
  },
  domain: domainData,
  primaryType: "MetaTransaction",
  message: message
});

/*Its important to use eth_signTypedData_v3 and not v4 to get EIP712 
signature because we have used salt in domain data instead of chainId*/
const signature = sigUtil.signTypedMessage(new Buffer.from(privateKey, 'hex'), { data: dataToSign }, 'V3');
let { r, s, v } = getSignatureParameters(signature); // same helper used in SDK frontend code


let rawTx, tx;
rawTx = {
            to: <YOUR_CONTRACT_ADDRESS>,
            data: contractInterface.encodeFunctionData("executeMetaTransaction", [userAddress, functionData, r, s, v]),
            from: userAddress
          };
tx = await wallet.signTransaction(rawTx);

let transactionHash;
try {
      let receipt = await ethersProvider.sendTransaction(tx);
      console.log(receipt);
    } catch (error) {
          /*Ethers check the hash from user's signed tx and hash returned from Biconomy
          Both hash are expected to be different as biconomy send the transaction from its relayers*/
          
          // You could also refer to https://github.com/bcnmy/metatx-standard/blob/kovan-demo-ethers-backend/example/react-ui/src/App.js
          if (error.returnedHash && error.expectedHash) {
            console.log("Transaction hash : ", error.returnedHash);
            transactionHash = error.returnedHash;
            } 
          else{
            console.log(error);
            showErrorMessage("Error while sending transaction");
              }
          }

if (transactionHash) {
      // display transactionHash
      let receipt = await ethersProvider.waitForTransaction(transactionHash);
      console.log(receipt);
      //show Success Message
    } else 
    {
     showErrorMessage("Could not get transaction hash");
    }
let contract = new ethers.Contract(<CONTRACT_ADDRESS>,
              <CONTRACT_ABI>, biconomy.getSignerByAddress(userAddress));
let contractInterface = new ethers.utils.Interface(<CONTRACT_ABI>);
let chainId = 42;

let privateKey = <PRIVATE_KEY>;
let wallet = new ethers.Wallet(privateKey);
let nonce = await contract.getNonce(userAddress);
let functionSignature = contractInterface.encodeFunctionData("setQuote", [newQuote]);

//same helper constructMetaTransactionMessage used in SDK front end code
let messageToSign = constructMetaTransactionMessage(nonce, chainId, functionSignature, config.contract.address);
const signature = await wallet.signMessage(messageToSign);

console.info(`User signature is ${signature}`);
let { r, s, v } = getSignatureParameters(signature); // same helper used in SDK frontend code

let rawTx, tx;
rawTx = {
            to: <YOUR_CONTRACT_ADDRESS>,
            data: contractInterface.encodeFunctionData("executeMetaTransaction", [userAddress, functionData, r, s, v]),
            from: userAddress
          };
tx = await wallet.signTransaction(rawTx);

let transactionHash;
try {
      let receipt = await ethersProvider.sendTransaction(tx);
      console.log(receipt);
    } catch (error) {
          /*Ethers check the hash from user's signed tx and hash returned from Biconomy
          Both hash are expected to be different as biconomy send the transaction from its relayers*/
          
          // You could also refer to https://github.com/bcnmy/metatx-standard/blob/kovan-demo-ethers-backend/example/react-ui/src/App.js
          if (error.returnedHash && error.expectedHash) {
            console.log("Transaction hash : ", error.returnedHash);
            transactionHash = error.returnedHash;
            } 
          else{
            console.log(error);
            showErrorMessage("Error while sending transaction");
              }
          }

if (transactionHash) {
      // display transactionHash
      let receipt = await ethersProvider.waitForTransaction(transactionHash);
      console.log(receipt);
      //show Success Message
    } else 
    {
     showErrorMessage("Could not get transaction hash");
    }

Refer to this for extensive code examples for you to interact with the SDK.

Initialize the Gasless SDK (EOA) in the same way as mentioned .

for complete example code with this approach

for complete example code with this approach

for complete example code with this approach

for complete example code with this approach

If you don't wish to use the Gasless SDK (EOA), gasless meta transactions can be directly sent using also. Check next section for implementation steps.

💸
link
Check the repository here
Check the repository here
Check the repository here
Check the repository here
Biconomy's APIs
above
Web3.js
Ethers.js
how to get API key