Created
October 1, 2020 15:07
-
-
Save tomarsachin2271/2e9ece19d5dabb98bb430c74669d4763 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// To enable meta transaction, let create a generic method that calls executeMetaTransaction by taking the user signature | |
// and then execute transaction via Biconomy | |
// Dependencies | |
import {toBuffer} from "ethereumjs-util"; | |
import abi from "ethereumjs-abi"; | |
import events from "events"; | |
// Initialization of web3 | |
let web3 = new Web3(window.ethereum); | |
// Lets first create a method that takes user address, actual method encoded ABI (eg transfer method of ERC20 token) and | |
// the smart contract instance | |
// Add some helper methods also we'll create to make the code modular | |
const executeMetaTransaciton = async (userAddress, functionSignature, contract, contractAddress, chainId) => { | |
var eventEmitter = new events.EventEmitter(); | |
if(contract && userAddress && functionSignature, chainId, contractAddress) { | |
let nonce = await contract.methods.getNonce(userAddress).call(); | |
let messageToSign = constructMetaTransactionMessage(nonce, chainId, functionSignature, contractAddress); | |
const signature = await web3.eth.personal.sign( | |
"0x" + messageToSign.toString("hex"), | |
userAddress | |
); | |
console.info(`User signature is ${signature}`); | |
let { r, s, v } = getSignatureParameters(signature); | |
console.log("before transaction listener"); | |
// No need to calculate gas limit or gas price here | |
let transactionListener = contract.methods.executeMetaTransaction(userAddress, functionSignature, r, s, v).send({ | |
from: userAddress | |
}); | |
transactionListener.on("transactionHash", (hash)=>{ | |
eventEmitter.emit("transactionHash", hash); | |
}).once("confirmation", (confirmation, recipet) => { | |
eventEmitter.emit("confirmation", confirmation, recipet); | |
}).on("error", error => { | |
eventEmitter.emit("error", error); | |
}); | |
return eventEmitter; | |
} else { | |
console.log("All params userAddress, functionSignature, chainId, contract address and contract object are mandatory"); | |
} | |
} | |
const constructMetaTransactionMessage = (nonce, chainId, functionSignature, contractAddress) => { | |
return abi.soliditySHA3( | |
["uint256","address","uint256","bytes"], | |
[nonce, contractAddress, chainId, toBuffer(functionSignature)] | |
); | |
} | |
const getSignatureParameters = signature => { | |
if (!web3.utils.isHexStrict(signature)) { | |
throw new Error( | |
'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; | |
return { | |
r: r, | |
s: s, | |
v: v | |
}; | |
}; | |
// Now all you need is to call this executeMetaTransaciton method with required parameters from where you are calling your | |
// actual function eg transfer or mint | |
/******** BEFORE ********/ | |
let result = contract.methods.transfer(recipientAddress, tokenToTransfer.toString()).send({ | |
from: selectedAddress | |
}); | |
result.on("transactionHash", (hash)=>{ | |
// On transacion Hash | |
}).once("confirmation", (confirmation, recipet) => { | |
// On Confirmation | |
}).on("error", error => { | |
// On Error | |
}) | |
/******* AFTER *******/ | |
let functionSignature = contract.methods.transfer(recipientAddress, tokenToTransfer.toString()).encodeABI(); | |
let result = await executeMetaTransaciton(userAddress, functionSignature, contract, contractAddress, "42"); | |
result.on("transactionHash", (hash)=>{ | |
// On transacion Hash | |
}).once("confirmation", (confirmation, recipet) => { | |
// On Confirmation | |
}).on("error", error => { | |
// On Error | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment