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

Was this helpful?

  1. Products
  2. Gasless Transactions

Gasless SDK (EOA) 3

The new TypeScript Gasless SDK (EOA) is here!

PreviousConditional WhitelistingNextNetworks Supported

Last updated 2 years ago

Was this helpful?

Changes in the new SDK:

  1. Typescript based SDK

  2. Using event listeners you can monitor the state change of a transaction. One can get notified on transaction hash creation, transaction being mined or on any error.

How to build and send transaction with Ethers:

const provider = await biconomy.provider;
const contractInstance = new ethers.Contract(
  config.contract.address,
  config.contract.abi,
  biconomy.ethersProvider
);
let { data } = await contractInstance.populateTransaction.setQuote(arg);
let txParams = {
  data: data,
  to: config.contract.address,
  from: userAddress,
  signatureType: "EIP712_SIGN",
};
await provider.send("eth_sendTransaction", [txParams]);
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
  console.log(data);
  showSuccessMessage(`tx hash ${data.hash}`);
});

biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
  console.log(data);
});

biconomy.on("onError", (data: {error: any; transactionId: string}) => {
  console.log(data);
});

bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
  console.log(data);
});
const provider = await biconomy.provider;
const contractInstance = new ethers.Contract(
  config.contract.address,
  config.contract.abi,
  biconomy.ethersProvider
);
let { data } = await contractInstance.populateTransaction.setQuote(arg);
let txParams = {
  data: data,
  to: config.contract.address,
  from: userAddress,
  signatureType: "PERSONAL_SIGN",
};
await provider.send("eth_sendTransaction", [txParams]);
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
  console.log(data);
  showSuccessMessage(`tx hash ${data.hash}`);
});

biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
  console.log(data);
});

biconomy.on("onError", (data: {error: any; transactionId: string}) => {
  console.log(data);
});

bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
  console.log(data);
});
// Getting the signatures based on EIP 712 Signature Scheme:
const domainType = [
  { name: "name", type: "string" },
  { name: "version", type: "string" },
  { name: "verifyingContract", type: "address" },
  { name: "salt", type: "bytes32" },
];
const metaTransactionType = [
  { name: "nonce", type: "uint256" },
  { name: "from", type: "address" },
  { name: "functionSignature", type: "bytes" },
];
let domainData = {
  name: "TestContract",
  version: "1",
  verifyingContract: config.contract.address,
  salt: "0x" + (42).toString(16).padStart(64, "0"),
};

const contractInstance = new ethers.Contract(
        config.contract.address,
        config.contract.abi as ContractInterface,
        signer!
      );
let nonce = await contractInstance.getNonce(userAddress);
const contractInterface = new ethers.utils.Interface(config.contract.abi);
let functionSignature = contractInterface.encodeFunctionData("setQuote", [
  newQuote,
]);
let message = {
  nonce: parseInt(nonce),
  from: userAddress,
  functionSignature: functionSignature,
};

const dataToSign = JSON.stringify({
  types: {
    EIP712Domain: domainType,
    MetaTransaction: metaTransactionType,
  },
  domain: domainData,
  primaryType: "MetaTransaction",
  message: message,
});

let signature = await ethersProvider.send("eth_signTypedData_v3", [
  userAddress,
  dataToSign,
]);

let { r, s, v } = (signature: any) => {
    if (!ethers.utils.isHexString(signature)) {
      throw new Error(
        'Given value "'.concat(signature, '" is not a valid hex string.')
      );
    }
    const r = signature.slice(0, 66);
    const s = "0x".concat(signature.slice(66, 130));
    let v = "0x".concat(signature.slice(130, 132));
    v = ethers.BigNumber.from(v).toString();
    if (![27, 28].includes(Number(v))) v += 27;
    return {
      r: r,
      s: s,
      v: Number(v),
    };
};

const provider = await biconomy.provider;
let { data } =
  await contractInstance.populateTransaction.executeMetaTransaction(
    userAddress,
    functionData,
    r,
    s,
    v
  );
let txParams = {
  data: data,
  to: contractAddress,
  from: userAddress,
  signatureType: "EIP712_SIGN",
};
await provider.send("eth_sendTransaction", [txParams]);
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
  console.log(data);
  showSuccessMessage(`tx hash ${data.hash}`);
});

biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
  console.log(data);
});

biconomy.on("onError", (data: {error: any; transactionId: string}) => {
  console.log(data);
});

bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
  console.log(data);
});
const contractInstance = await new web3.eth.Contract(
    abi,
    contractAddress
  );
const nonce = await contractInstance.methods.getNonce(address).call();
let functionSignature = await contractInstance.methods
  .setQuote('test')
  .encodeABI();
let messageToSign = (
    nonce: number,
    chainId: number,
    functionSignature: string,
    contractAddress: string
  ) => {
    return abi.soliditySHA3(
      ["uint256", "address", "uint256", "bytes"],
      [nonce, contractAddress, chainId, toBuffer(functionSignature)]
    );
  };
const signature = await walletProvider.signMessage(messageToSign);

let { r, s, v } = (signature: any) => {
    if (!ethers.utils.isHexString(signature)) {
      throw new Error(
        'Given value "'.concat(signature, '" is not a valid hex string.')
      );
    }
    const r = signature.slice(0, 66);
    const s = "0x".concat(signature.slice(66, 130));
    let v = "0x".concat(signature.slice(130, 132));
    v = ethers.BigNumber.from(v).toString();
    if (![27, 28].includes(Number(v))) v += 27;
    return {
      r: r,
      s: s,
      v: Number(v),
    };
};

const provider = await biconomy.provider;

let { data } =
  await contractInstance.populateTransaction.executeMetaTransaction(
    userAddress,
    functionData,
    r,
    s,
    v
  );
let txParams = {
  data: data,
  to: config.contract.address,
  from: userAddress,
  signatureType: "PERSONAL_SIGN",
};
await provider.send("eth_sendTransaction", [txParams]);

// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
  console.log(data);
  showSuccessMessage(`tx hash ${data.hash}`);
});

biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
  console.log(data);
});

biconomy.on("onError", (data: {error: any; transactionId: string}) => {
  console.log(data);
});

bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
  console.log(data);
});

How to build and send transactions with Web3:

const web3 = new Web3(biconomy.provider);
const contractInstance = new web3.eth.Contract(
  abi
  contractAddress
);
await contractInstance.methods.setQuote(newQuote).send({
  from: address,
  signatureType: "EIP712_SIGN",
});
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
  console.log(data);
  showSuccessMessage(`tx hash ${data.hash}`);
});

biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
  console.log(data);
});

biconomy.on("onError", (data: {error: any; transactionId: string}) => {
  console.log(data);
});

bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
  console.log(data);
});
const web3 = new Web3(biconomy.provider as any);
const contractInstance = new web3.eth.Contract(
  config.contract.abi as AbiItem[],
  config.contract.address
);

await contractInstance.methods
  .setQuote(newQuote)
  .send("eth_sendTransaction", {
    from: address,
    signatureType: "PERSONAL_SIGN",
  });
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
  console.log(data);
  showSuccessMessage(`tx hash ${data.hash}`);
});

biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
  console.log(data);
});

biconomy.on("onError", (data: {error: any; transactionId: string}) => {
  console.log(data);
});

bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
  console.log(data);
});
const domainType = [
  { name: "name", type: "string" },
  { name: "version", type: "string" },
  { name: "verifyingContract", type: "address" },
  { name: "salt", type: "bytes32" },
];
const metaTransactionType = [
  { name: "nonce", type: "uint256" },
  { name: "from", type: "address" },
  { name: "functionSignature", type: "bytes" },
];
let domainData = {
  name: "TestContract",
  version: "1",
  verifyingContract: config.contract.address,
  salt: "0x" + (42).toString(16).padStart(64, "0"),
};

const contractInstance = await new web3.eth.Contract(
  config.contract.abi as AbiItem[],
  config.contract.address
);

const web3 = new Web3(biconomy.provider);  
let nonce = await contractInstance.methods.getNonce(address).call();
let functionSignature = await contractInstance.methods
  .setQuote(newQuote)
  .encodeABI();
let message = {
  nonce: parseInt(nonce),
  from: address,
  functionSignature: functionSignature,
};

const dataToSign = JSON.stringify({
  types: {
    EIP712Domain: domainType,
    MetaTransaction: metaTransactionType,
  },
  domain: domainData,
  primaryType: "MetaTransaction",
  message: message,
});

web3.currentProvider.send(
  {
    jsonrpc: "2.0",
    id: 999999999999,
    method: "eth_signTypedData_v4",
    params: [address, dataToSign],
  },
  
let { r, s, v } = (signature: any) => {
    if (!ethers.utils.isHexString(signature)) {
      throw new Error(
        'Given value "'.concat(signature, '" is not a valid hex string.')
      );
    }
    const r = signature.slice(0, 66);
    const s = "0x".concat(signature.slice(66, 130));
    let v = "0x".concat(signature.slice(130, 132));
    v = ethers.BigNumber.from(v).toString();
    if (![27, 28].includes(Number(v))) v += 27;
    return {
      r: r,
      s: s,
      v: Number(v),
    };
};

const contractInstance = new web3.eth.Contract(
  abi
  contractAddress
);

await contractInstance.methods
  .executeMetaTransaction(userAddress, functionData, r, s, v)
  .send({
    from: userAddress,
  });
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
  console.log(data);
  showSuccessMessage(`tx hash ${data.hash}`);
});

biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
  console.log(data);
});

biconomy.on("onError", (data: {error: any; transactionId: string}) => {
  console.log(data);
});

bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
  console.log(data);
});

const web3 = new Web3(biconomy.provider);
const contractInstance = await new web3.eth.Contract(
    abi,
    contractAddress
  );
const nonce = await contractInstance.methods.getNonce(address).call();
let functionSignature = await contractInstance.methods
  .setQuote('test')
  .encodeABI();
let messageToSign = (
    nonce: number,
    chainId: number,
    functionSignature: string,
    contractAddress: string
  ) => {
    return abi.soliditySHA3(
      ["uint256", "address", "uint256", "bytes"],
      [nonce, contractAddress, chainId, toBuffer(functionSignature)]
    );
  };
const signature = await walletProvider.signMessage(messageToSign);

const signature = await web3.eth.personal.sign(
  "0x" + messageToSign.toString("hex"),
  address
);

let { r, s, v } = (signature: any) => {
    if (!ethers.utils.isHexString(signature)) {
      throw new Error(
        'Given value "'.concat(signature, '" is not a valid hex string.')
      );
    }
    const r = signature.slice(0, 66);
    const s = "0x".concat(signature.slice(66, 130));
    let v = "0x".concat(signature.slice(130, 132));
    v = ethers.BigNumber.from(v).toString();
    if (![27, 28].includes(Number(v))) v += 27;
    return {
      r: r,
      s: s,
      v: Number(v),
    };
};


const tx = await contractInstance.methods
  .executeMetaTransaction(userAddress, functionData, r, s, v)
  .send({
           from: userAddress,
  });
  
// Listen to transaction updates:
biconomy.on("txHashGenerated", data: { transactionId: string; transactionHash: string; }) => {
  console.log(data);
  showSuccessMessage(`tx hash ${data.hash}`);
});

biconomy.on("txMined", (data: {msg: string; id: string; hash: string; receipt: string}) => {
  console.log(data);
});

biconomy.on("onError", (data: {error: any; transactionId: string}) => {
  console.log(data);
});

bicnomy.on("txHashChanged", (data: {transactionId: string, transactionHash: string}) => {
  console.log(data);
});

💸
EIP 1193 provider
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Ethers_EIP2771_EIP712Sign.tsx
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Ethers_EIP2771_PersonalSign.tsx
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Ethers_Custom_EIP712Sign.tsx
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Ethers_Custom_PersonalSign.tsx
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Web3_EIP2771_EIP712Sign.tsx
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Web3_EIP2771_PersonalSign.tsx
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Web3_Custom_EIP712Sign.tsx
https://github.com/bcnmy/gasless-playground/blob/master/src/components/Web3_Custom_PersonalSign.tsx