sign.js 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. const REAL_SIGNATURE_SIZE = 2 * 65; // 65 bytes in hexadecimal string legnth
  2. const PADDED_SIGNATURE_SIZE = 2 * 96; // 96 bytes in hexadecimal string length
  3. const DUMMY_SIGNATURE = `0x${web3.utils.padLeft('', REAL_SIGNATURE_SIZE)}`;
  4. function toEthSignedMessageHash (messageHex) {
  5. const messageBuffer = Buffer.from(messageHex.substring(2), 'hex');
  6. const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${messageBuffer.length}`);
  7. return web3.utils.sha3(Buffer.concat([prefix, messageBuffer]));
  8. }
  9. function fixSignature (signature) {
  10. // in geth its always 27/28, in ganache its 0/1. Change to 27/28 to prevent
  11. // signature malleability if version is 0/1
  12. // see https://github.com/ethereum/go-ethereum/blob/v1.8.23/internal/ethapi/api.go#L465
  13. let v = parseInt(signature.slice(130, 132), 16);
  14. if (v < 27) {
  15. v += 27;
  16. }
  17. const vHex = v.toString(16);
  18. return signature.slice(0, 130) + vHex;
  19. }
  20. // signs message in node (ganache auto-applies "Ethereum Signed Message" prefix)
  21. async function signMessage (signer, messageHex = '0x') {
  22. return fixSignature(await web3.eth.sign(messageHex, signer));
  23. };
  24. /**
  25. * Create a signer between a contract and a signer for a voucher of method, args, and redeemer
  26. * Note that `method` is the web3 method, not the truffle-contract method
  27. * @param contract TruffleContract
  28. * @param signer address
  29. * @param redeemer address
  30. * @param methodName string
  31. * @param methodArgs any[]
  32. */
  33. const getSignFor = (contract, signer) => (redeemer, methodName, methodArgs = []) => {
  34. const parts = [
  35. contract.address,
  36. redeemer,
  37. ];
  38. // if we have a method, add it to the parts that we're signing
  39. if (methodName) {
  40. if (methodArgs.length > 0) {
  41. parts.push(
  42. contract.contract.methods[methodName](...methodArgs.concat([DUMMY_SIGNATURE])).encodeABI()
  43. .slice(0, -1 * PADDED_SIGNATURE_SIZE)
  44. );
  45. } else {
  46. const abi = contract.abi.find(abi => abi.name === methodName);
  47. parts.push(abi.signature);
  48. }
  49. }
  50. // return the signature of the "Ethereum Signed Message" hash of the hash of `parts`
  51. const messageHex = web3.utils.soliditySha3(...parts);
  52. return signMessage(signer, messageHex);
  53. };
  54. module.exports = {
  55. signMessage,
  56. toEthSignedMessageHash,
  57. fixSignature,
  58. getSignFor,
  59. };