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
  • Passing extra information using web3
  • Passing extra information using ethers

Was this helpful?

  1. Products
  2. Gasless Transactions
  3. Choose An Approach to Enable Gasless
  4. Standard EIP 2771 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 SDK is a typescript 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/typescript 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 repository

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();

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 the project running at the backend where a raw transaction is signed by the user's private key.

Integration Steps

  1. There is no change in the way you send the transactions from the backend except adding the extra information about the signature type.

The developer can choose to take the user’s signatures with any signature type they wish to.

Passing extra information using web3

web3.eth.sendSignedTransaction(data, callback) will be used here but with parameters mentioned below

Parameters

callback Optional callback, returns an error object as first parameter and the result as second.

Returns

Passing extra information using ethers

provider.send("eth_sendRawTransaction", [data], callback) will be used here but with parameters mentioned below

Parameters

callback Optional callback, returns an error object as first parameter and the result as second.

Returns

Promise A promise which will not resolve until the transaction hash is mined. Promise resolves with transaction hash. One can use the event emitter method of ethers provider to get the mined transaction receipts.

Based on your Meta Transaction Type on the recipient contract (registered as Trusted Forwarder) Mexa will prepare the data to sign in the EIP712 format as well as personal signature format (default)

Example Code

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

// Initialize constants
let contract = new web3.eth.Contract(
            <CONTRACT_ABI>,
            <CONTRACT_ADDRESS>
          );

let userAddress = <selected address>;
let privateKey = <PRIVATE_KEY>;

let txParams = {
    "from": userAddress,
    //gasLimit is optional or can be pre estimated for your method call before passing
    "gasLimit": web3.utils.toHex(300000), 
    "to": <CONTRACT_ADDRESS>,
    //optional. Note: Native meta transactions would not work if your method call is expecting ether value transfer and has checkes on msg.value
    "value": "0x0", 
    //Call your target method. here we are calling setQuote() method of our contract
    "data": contract.methods.setQuote(newQuote).encodeABI(), 
};

const signedTx = await web3.eth.accounts.signTransaction(txParams, `0x${privateKey}`);
const forwardData = await biconomy.getForwardRequestAndMessageToSign(signedTx.rawTransaction);
const signature = sigUtil.signTypedMessage(new Buffer.from(privateKey, 'hex'),
                  { data: forwardData.eip712Format }, 'V4');
// forwardData has personalSignatureFormat available as well. Check the next tab on the right
 
let rawTransaction = signedTx.rawTransaction;

let data = {
    signature: signature,
    forwardRequest: forwardData.request,
    rawTransaction: rawTransaction,
    signatureType: biconomy.EIP712_SIGN
};

// Get the transaction Hash using the Event Emitter returned
web3.eth.sendSignedTransaction(data)
.on('transactionHash', (hash)=> {
    console.log(`Transaction hash is ${hash}`)
})
.once('confirmation', (confirmation, receipt)=> {
    console.log(`Transaction Confirmed.`);
    console.log(receipt);
    //do Something
});

/********* OR *********/

// Use any one of the methods below to check for transaction confirmation
// USING PROMISE
let receipt = await web3.eth.sendSignedTransaction(data, (error, txHash)=>{
    if(error) {
        return console.error(error);
    }
    console.log(txHash);
});
let sigUtil = require("eth-sig-util"); // additional dependency 

// Initialize constants
let contract = new web3.eth.Contract(
            <CONTRACT_ABI>,
            <CONTRACT_ADDRESS>
          );

let userAddress = <selected address>;
let privateKey = <PRIVATE_KEY>;

let txParams = {
    "from": userAddress,
    //gasLimit is optional or can be pre estimated for your method call before passing
    "gasLimit": web3.utils.toHex(300000), 
    "to": <CONTRACT_ADDRESS>,
    //optional. Note: Native meta transactions would not work if your method call is expecting ether value transfer and has checkes on msg.value
    "value": "0x0", 
    //Call your target method. here we are calling setQuote() method of our contract
    "data": contract.methods.setQuote(newQuote).encodeABI(), 
};

const signedTx = await web3.eth.accounts.signTransaction(txParams, `0x${privateKey}`);
const forwardData = await biconomy.getForwardRequestAndMessageToSign(signedTx.rawTransaction);

// const signature = sigUtil.personalSign(new Buffer.from(privateKey, 'hex'), { data: forwardData.personalSignatureFormat });
let {signature} = web3.eth.accounts.sign("0x" + forwardData.personalSignatureFormat.toString("hex"), privateKey);
 
let rawTransaction = signedTx.rawTransaction;

let data = {
    signature: signature,
    forwardRequest: forwardData.request,
    rawTransaction: rawTransaction,
    signatureType: biconomy.PERSONAL_SIGN //optional. mexa will assume personal signature by default if this is omitted
};

// Get the transaction Hash using the Event Emitter returned
web3.eth.sendSignedTransaction(data)
.on('transactionHash', (hash)=> {
    console.log(`Transaction hash is ${hash}`)
})
.once('confirmation', (confirmation, receipt)=> {
    console.log(`Transaction Confirmed.`);
    console.log(receipt);
    //do Something
});

/********* OR *********/

// Use any one of the methods below to check for transaction confirmation
// USING PROMISE
let receipt = await web3.eth.sendSignedTransaction(data, (error, txHash)=>{
    if(error) {
        return console.error(error);
    }
    console.log(txHash);
});
let sigUtil = require("eth-sig-util"); // additional dependency 

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

let userAddress = <Selected Address>;
let privateKey = <PRIVATE_KEY>;

let userSigner = new ethers.Wallet(privateKey);

// Create your target method signature.. here we are calling setQuote() method of our contract
let functionSignature = contractInterface.encodeFunctionData("setQuote", [newQuote]);

let rawTx = {
              to: <CONTRACT_ADDRESS>,
              data: functionSignature,
              from: userAddress
            };

let signedTx = await userSigner.signTransaction(rawTx);
// should get user message to sign for EIP712 or personal signature types
const forwardData = await biconomy.getForwardRequestAndMessageToSign(signedTx);
console.log(forwardData);      

// optionally one can sign using sigUtil
const signature = sigUtil.signTypedMessage(new Buffer.from(privateKey, 'hex'), { data: forwardData.eip712Format }, 'V3');                                                                    

let data = {
    signature: signature,
    forwardRequest: forwardData.request,
    rawTransaction: signedTx,
    signatureType: biconomy.EIP712_SIGN
};

let provider = biconomy.getEthersProvider();
// send signed transaction with ethers
// promise resolves to transaction hash                  
let txHash = await provider.send("eth_sendRawTransaction", [data]);

let receipt = await provider.waitForTransaction(txHash);
//do something
let sigUtil = require("eth-sig-util"); // additional dependency 

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

let userAddress = <Selected Address>;
let privateKey = <PRIVATE_KEY>;

let userSigner = new ethers.Wallet(privateKey);

// Create your target method signature.. here we are calling setQuote() method of our contract
let functionSignature = contractInterface.encodeFunctionData("setQuote", [newQuote]);

let rawTx = {
              to: <CONTRACT_ADDRESS>,
              data: functionSignature,
              from: userAddress
            };

let signedTx = await userSigner.signTransaction(rawTx);
// should get user message to sign for EIP712 or personal signature types
const forwardData = await biconomy.getForwardRequestAndMessageToSign(signedTx);
console.log(forwardData);      

// optionally one can sign using sigUtil
const signature = await userSigner.signMessage(forwardData.personalSignatureFormat);

let data = {
    signature: signature,
    forwardRequest: forwardData.request,
    rawTransaction: signedTx,
    signatureType: biconomy.PERSONAL_SIGN //optional. as mexa will assume personal signature by default this can be omitted
};

let provider = biconomy.getEthersProvider();
// send signed transaction with ethers
// promise resolves to transaction hash                  
let txHash = await provider.send("eth_sendRawTransaction", [data]);

let receipt = await provider.waitForTransaction(txHash);
//do something

Done! Interact with Web3/Ethers the same way you have been doing before! Now, whenever a contract call is made () Gasless SDK will ask for the user's signature and handle the transaction - rather than sending a signed transaction directly to the blockchain from the user's wallet. The message the user will be prompted to sign will be in an eth_personalsign format by default.

If you wish to get type structured message signature just include signatureType:”EIP712_SIGN” in your transaction parameters and SDK will take care of taking the signature and execution through the trusted forwarder.

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

Initialize the Gasless SDK in the same way as mentioned .

data A JSON object containing the user's signature, the raw transaction, forward request object and . Data to be signed can be generated using the methodgetForwardRequestAndMessageToSign(rawTransaction)

PromiEvent A . Will be resolved when the transaction receipt is available

data A JSON object containing the user's signature, the raw transaction, forward request object and . Data to be signed can be generated using the methodgetForwardRequestAndMessageToSign(rawTransaction)

for complete example code

for complete example code

for complete example code

for complete example code

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

💸
provided that it is registered in the Dashboard
EIP712
link
signature type
promise combined event emitter
signature type
Check the repository here
Check the repository here
Check the repository here
Check the repository here
Biconomy's API
above
Web3.js
Ethers.js
how to get API key