sign.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. function toEthSignedMessageHash (messageHex) {
  2. const messageBuffer = Buffer.from(messageHex.substring(2), 'hex');
  3. const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${messageBuffer.length}`);
  4. return web3.utils.sha3(Buffer.concat([prefix, messageBuffer]));
  5. }
  6. function fixSignature (signature) {
  7. // in geth its always 27/28, in ganache its 0/1. Change to 27/28 to prevent
  8. // signature malleability if version is 0/1
  9. // see https://github.com/ethereum/go-ethereum/blob/v1.8.23/internal/ethapi/api.go#L465
  10. let v = parseInt(signature.slice(130, 132), 16);
  11. if (v < 27) {
  12. v += 27;
  13. }
  14. const vHex = v.toString(16);
  15. return signature.slice(0, 130) + vHex;
  16. }
  17. // signs message in node (ganache auto-applies "Ethereum Signed Message" prefix)
  18. async function signMessage (signer, messageHex = '0x') {
  19. return fixSignature(await web3.eth.sign(messageHex, signer));
  20. };
  21. /**
  22. * Create a signer between a contract and a signer for a voucher of method, args, and redeemer
  23. * Note that `method` is the web3 method, not the truffle-contract method
  24. * @param contract TruffleContract
  25. * @param signer address
  26. * @param redeemer address
  27. * @param methodName string
  28. * @param methodArgs any[]
  29. */
  30. const getSignFor = (contract, signer) => (redeemer, methodName, methodArgs = []) => {
  31. const parts = [
  32. contract.address,
  33. redeemer,
  34. ];
  35. const REAL_SIGNATURE_SIZE = 2 * 65; // 65 bytes in hexadecimal string length
  36. const PADDED_SIGNATURE_SIZE = 2 * 96; // 96 bytes in hexadecimal string length
  37. const DUMMY_SIGNATURE = `0x${web3.utils.padLeft('', REAL_SIGNATURE_SIZE)}`;
  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. };