/* this exmaple is with DAI tokens */
// assuming permit is already obtained
// to see how to use permit client please refer to SDK front end example code or web3 example
// Import sigUtil for signing data - Optional
var sigUtil = require('eth-sig-util');
var ethers = require('ethers');
// ethersProvider is initialized with biconomy
let ethersProvider = new ethers.providers.Web3Provider(biconomy);
let signer = ethersProvider.getSigner();
let contract = new ethers.Contract(<CONTRACT_ADDRESS>,
<CONTRACT_ABI>, signer.connectUnchecked());
let contractInterface = new ethers.utils.Interface(<CONTRACT_ABI>);
let address = <wallet public address>;
let privateKey = <private key>;
let wallet = new ethers.Wallet(privateKey);
// Create your target method signature.. here we are calling addRating() method of our contract
let functionSignature = contractInterface.encodeFunctionData("setQuote", ["hello meta transactions"]);
let gasPrice = await ethersProvider.getGasPrice();
let gasLimit = await ethersProvider.estimateGas({
to: config.contract.address,
console.log(gasLimit.toString());
to: config.contract.address,
//gasLimit: web3.utils.toHex(gasLimit),
signedTx = await wallet.signTransaction(rawTx);
// should get user message to sign for EIP712 or personal signature types
const forwardRequestData = await biconomy.getForwardRequestAndMessageToSign(
console.log(forwardRequestData);
const signParams = forwardRequestData.eip712Format;
// returned data has personal signature format available as well
// data.personalSignatureFormat
// forward request that was created to prepare the data to sign
// you must pass the same request otherwise it would result in signature mistach
const request = forwardRequestData.request;
const cost = forwardRequestData.cost;
//show the fees in number of ERC20 tokens to be spent
//https://github.com/ethers-io/ethers.js/issues/687
/** ethers automatically appends EIP712 domain type.
* only need to remove for EIP712 format
* personal format is available as well by dataToSign.personalSignatureFormat
delete signParams.types.EIP712Domain;
const signature = await wallet._signTypedData(signParams.domain, signParams.types, signParams.message);
// optionally one can sign using sigUtil
//sigUtil works perfectly fine
const signature = sigUtil.signTypedMessage(new Buffer.from(privateKey, 'hex'),
{data: dataToSign.eip712Format}, 'V4');
rawTransaction: signedTx,
signatureType: biconomy.EIP712_SIGN,
// send signed transaction with ethers
// promise resolves to transaction hash
let tx = await ethersProvider.send("eth_sendRawTransaction", [data]);
console.log("Transaction hash : ", tx);
ethersProvider.once(tx, (transaction) => {
// Emitted when the transaction has been mined
console.log(transaction);