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
  • Note:
  • /api/v2/meta-tx/native

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 API

Use our APIs to easily implement meta transactions!

Note:

Before using this API, make sure you have Trusted Forwarder support in your smart contracts i.e., you have removed the dependency on msg.sender property from your smart contracts and trusted forwarder is added.

/api/v2/meta-tx/native

POST https://api.biconomy.io/api/v2/meta-tx/native

Our API lets you relay transactions directly to your smart contract without your end users having to pay any transaction/gas fee. Just register your dApp on the developer dashboard, upload your smart contracts as meta transaction type as Trusted Forwarder and select your methods in which you want to enable native meta transaction support.

Headers

Name
Type
Description

x-api-key

string

API key present on your dashboard for your DApp after DApp registration. This is specific to DApp registered.

Request Body

Name
Type
Description

signatureType

string

Signature type chosen by the developer to sign the transaction message. Accepted values are EIP712_SIGN and PERSONAL_SIGN. If omitted personal signature will be assumed by the server and will expect only two parameters (signature and request) in params.

gasLimit

string

Gas limit to be set in the transaction. It can be a decimal number or hexadecimal string. If omitted web3 estimateGas method will be used to calculate the gasLimit for the transaction.

from

string

User client wallet public address who is supposed to be sending the transaction eg. metamask wallet address or portis wallet address.

params

array

Array of all the parameters required to call the execute methods of the trusted forwarder depending on the signature type. Read more about this in below section

apiId

string

API id corresponding to the method you want to call in your smart contract. It can be found on the dashboard under 'Manage APIs' section.

to

string

Target Contract Address.

 {
    "txHash": "0x84bc6f25b964f794f90c59b4f97a16aadc878ce53187703124b5e0ee52e15af9",
    "message": "Meta transaction sent to blockchain",
    "retryDuration": 158, 
    "flag": 200
}
//retryDuration: time in seconds after which you 
//can check resubmitted endpoint for new hash in case of
//potential resubmits.
{
    "message": "Api does not exist",
    "code": 404
}
{
  "code": 150,
  "message": "DApp limit reached",
  "responseCode": 409,
  "limit": {
    "allowed": false,
    "type": 1,
    "limitLeft": -6,
    "resetTime": 1608940800000
  },
  "allowed": false
}
{
    "message":"Error while gas estimation with message Returned error: The execution failed due to an exception.",
    "code":417
}

Example Curl Request

curl 
--request POST 'https://api.biconomy.io/api/v2/meta-tx/native'  
--header 'x-api-key: <api_key_from_dashboard>'  
--header 'Content-Type: application/json'  
--data-raw '{ 
"from": "<user_public_address>",
"apiId": "<api_id_from_dashboard>", 
"params": [<param1>,<param2>,...... ],
"to": "<recipient_contract_address>",
"gasLimit":"0xF4240",
"signatureType":"EIP712Sign"
}'

If signature type is personal sign, (assumed default if signatureType parameter is omitted in API request body) params are [request, signature]. params = [request, sig];

For EIP2771, below is an example code on how to use Biconomy helpers JS to build request, domain separator and data to sign for each signature type and then send API request to the Biconomy servers where our relayer infrastructure will process your transaction.

Sample code

import {
    helperAttributes,
    getDomainSeperator,
    getDataToSignForPersonalSign,
    getDataToSignForEIP712,
    buildForwardTxRequest,
    getBiconomyForwarderConfig
  } from './biconomyForwarderHelpers';
  
let sigUtil = require("eth-sig-util"); // additional dependency 

// This web3 instance is used to get user signature from connected wallet
let walletWeb3 = new Web3(window.ethereum);


let userAddress = <selected address>;
let networkId = <your provider networkId here>;

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

let functionSignature = contract.methods
                  .setQuote(newQuote)
                  .encodeABI();
let txGas = await contract.methods
                  .setQuote(newQuote)
                  .estimateGas({ from: userAddress });
                  
let forwarder = await getBiconomyForwarderConfig(networkId);
let forwarderContract = new web3.eth.Contract(
          forwarder.abi,
          forwarder.address
        );

//const batchId = await forwarderContract.methods.getBatch(userAddress).call();
const batchNonce = await forwarderContract.methods.getNonce(address,0).call();
const gasLimitNum = Number(txGas);
const to = <CONTRACT_ADDRESS>;

const request = await buildForwardTxRequest({account:userAddress,to,gasLimitNum,batchId,batchNonce,data:functionSignature});

/* If you wish to use EIP712 Signature type check below code*/


const hashToSign = getDataToSignForPersonalSign(request);
const sig = await walletWeb3.eth.personal.sign("0x" + hashToSign.toString("hex"), userAddress);
sendTransaction({userAddress, request, sig, signatureType:biconomy.PERSONAL_SIGN});
// notice domain seperator is not passed here

///////////////////////////////////////////////////////////

 // If you wish to use EIP712 Signature type  
 //build the request as mentioned above
   const domainSeparator = await getDomainSeperator(42);
   console.log(domainSeparator);
   const dataToSign =  await getDataToSignForEIP712(request,networkId);
   

 walletWeb3.currentProvider.send(
                    {
                        jsonrpc: "2.0",
                        id: 999999999999,
                        method: "eth_signTypedData_v4",
                        params: [userAddress, dataToSign]
                    },
                    function (error, response) {
                        console.info(`User signature is ${response.result}`);
                        if (error || (response && response.error)) {
                            showErrorMessage("Could not get user signature");
                        } else if (response && response.result) {
                            let sig = response.result;
                            sendTransaction({userAddress, request, domainSeparator, sig, signatureType:biconomy.EIP712_SIGN});
                        }
                    }
                );
 
  
import {
    helperAttributes,
    getDomainSeperator,
    getDataToSignForPersonalSign,
    getDataToSignForEIP712,
    buildForwardTxRequest,
    getBiconomyForwarderConfig
  } from './biconomyForwarderHelpers';

// Extra Dependencies
import abi from "ethereumjs-abi";
import {toBuffer} from "ethereumjs-util";

let walletProvider, walletSigner;

walletProvider = new ethers.providers.Web3Provider(window.ethereum);
walletSigner = walletProvider.getSigner();

// Initialize Constants

let userAddress = <selected address>;
let networkId = <your provider networkId here>;

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

let functionSignature = contractInterface.encodeFunctionData("setQuote", [newQuote]);
let gasPrice = await ethersProvider.getGasPrice();
let gasLimit = await ethersProvider.estimateGas({
              to: contract.address,
              from: address,
              data: functionSignature
            });
                      
let forwarder = await getBiconomyForwarderConfig(networkId);
let forwarderContract = new ethers.Contract(
          forwarder.address,
          forwarder.abi,
          biconomy.getSignerByAddress(userAddress)
        );

const batchNonce = await forwarderContract.getNonce(userAddress,0);
//const batchId = await forwarderContract.getBatch(userAddress);
const to = <CONTRACT_ADDRESS>;
const gasLimitNum = Number(gasLimit.toNumber().toString());
const request = await buildForwardTxRequest({account:userAddress,to,gasLimitNum,batchId,batchNonce,data});

/* If you wish to use EIP712 Signature type */
const domainSeparator = getDomainSeperator(networkId);
const dataToSign = await getDataToSignForEIP712(request,networkId);

let sig;
// get the user's signature
walletProvider.send("eth_signTypedData_v3", [userAddress, dataToSign])
        .then(function(sig){
          sendTransaction({userAddress, request, domainSeparator, sig, signatureType:biconomy.EIP712_SIGN});
        })
        .catch(function(error) {
	        console.log(error)
	      });
	
/////////////////////////////	

/** If you wish to use Personal Signature type 
 *  //domain seperator is not required
 *  //build the request as mentioned above
 *  const hashToSign =  getDataToSignForPersonalSign(request);
 */
 
 /*   walletSigner.signMessage(hashToSign)
        .then(function(sig){
          console.log('signature ' + sig);
          // make API call
          //sendTransaction({userAddress, request, sig, signatureType:biconomy.PERSONAL_SIGN});
        })
        .catch(function(error) {
	        console.log(error)
	      });
 */

Great! Once your parameters are built you are ready to make the API call to send gasless transactions!

const sendTransaction = async ({userAddress, request, sig, domainSeparator, signatureType}) => {
        if (web3 && contract) {
          let params;
          if (domainSeparator) {
            params = [request, domainSeparator, sig];
          } else {
            params = [request, sig];
          }
          try {
            fetch(`https://api.biconomy.io/api/v2/meta-tx/native`, {
              method: "POST",
              headers: {
                "x-api-key": <YOUR_DAPP_API_KEY>,
                "Content-Type": "application/json;charset=utf-8",
              },
              body: JSON.stringify({
                to: <CONTRACT_ADDRESS>,
                apiId: <METHOD_API_ID>,
                params: params,
                from: userAddress,
                signatureType: signatureType
              }),
            })
              .then((response) => response.json())
              .then(async function (result) {
                console.log(result);
                showInfoMessage(
                  `Transaction sent by relayer with hash ${result.txHash}`
                );

                let receipt = await getTransactionReceiptMined(
                  result.txHash,
                  2000
                );
                setTransactionHash(result.txHash);
                showSuccessMessage("Transaction confirmed on chain");
                getQuoteFromNetwork();
              })
              .catch(function (error) {
                console.log(error);
              });
          } catch (error) {
            console.log(error);
          }
        }
    };
    
  ////helper///

  //for web3  
  const getTransactionReceiptMined = (txHash, interval) => {
        const self = this;
        const transactionReceiptAsync = async function(resolve, reject) {
          var receipt = await web3.eth.getTransactionReceipt(txHash);
          if (receipt == null) {
              setTimeout(
                  () => transactionReceiptAsync(resolve, reject),
                  interval ? interval : 500);
          } else {
              resolve(receipt);
          }
        };
    
        if (typeof txHash === "string") {
            return new Promise(transactionReceiptAsync);
        } else {
            throw new Error("Invalid Type: " + txHash);
        }
      };

Congratulations 👏

You're now ready to use the trusted forwarder approach and enable gasless transactions in your dApp using SDK and/or APIs. Check out other implementations and in-depth technical details in the following sections.

PreviousUsing SDKNextCustom Implementation Approach

Last updated 3 years ago

Was this helpful?

If the signature type is , params are [request, domainSeperator, signature] params = [request, domainSeparator, sig];

Biconomy has available to build above mentioned parameters from your dapp transaction.

for complete example code

for complete example code

💸
EIP712
helpers
Check the repository here
Check the repository here