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);
{ 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" }
// replace the chainId 42 if network is not kovan
verifyingContract: config.contract.address,
// converts Number to bytes32. pass your chainId instead of 42 if network is not Kovan
salt : '0x' + (42).toString(16).padStart(64, '0')
let userAddress = <selected address>;
let contract = new web3.eth.Contract(
let nonce = await contract.methods.getNonce(userAddress).call();
// Create your target method signature.. here we are calling setQuote() method of our contract
let functionSignature = contract.methods.setQuote(newQuote).encodeABI();
message.nonce = parseInt(nonce);
message.from = userAddress;
message.functionSignature = functionSignature;
const dataToSign = JSON.stringify({
EIP712Domain: domainType,
MetaTransaction: metaTransactionType
primaryType: "MetaTransaction",
web3.currentProvider.send(
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 { r, s, v } = getSignatureParameters(response.result);
sendTransaction(userAddress, functionSignature, r, s, v);
const sendTransaction = async (userAddress, functionData, r, s, v) => {
fetch(`https://api.biconomy.io/api/v2/meta-tx/native`, {
"x-api-key" : <BICONOMY_DAPP_API_KEY>,
'Content-Type': 'application/json;charset=utf-8'
"to": config.contract.address,
"apiId": <METHOD_API_ID>,
"params": [userAddress, functionData, r, s, v],
.then(response=>response.json())
.then(async function(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");
}).catch(function(error) {
const getTransactionReceiptMined = (txHash, interval) => {
const transactionReceiptAsync = async function(resolve, reject) {
var receipt = await web3.eth.getTransactionReceipt(txHash);
() => transactionReceiptAsync(resolve, reject),
interval ? interval : 500);
if (typeof txHash === "string") {
return new Promise(transactionReceiptAsync);
throw new Error("Invalid Type: " + txHash);
const getSignatureParameters = signature => {
if (!web3.utils.isHexStrict(signature)) {
'Given value "'.concat(signature, '" is not a valid hex string.')
var r = signature.slice(0, 66);
var s = "0x".concat(signature.slice(66, 130));
var v = "0x".concat(signature.slice(130, 132));
v = web3.utils.hexToNumber(v);
if (![27, 28].includes(v)) v += 27;