sign.js 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. const { sha3, soliditySha3 } = require('web3-utils');
  2. const REAL_SIGNATURE_SIZE = 2 * 65; // 65 bytes in hexadecimal string legnth
  3. const PADDED_SIGNATURE_SIZE = 2 * 96; // 96 bytes in hexadecimal string length
  4. const DUMMY_SIGNATURE = `0x${web3.padLeft('', REAL_SIGNATURE_SIZE)}`;
  5. // messageHex = '0xdeadbeef'
  6. function toEthSignedMessageHash (messageHex) {
  7. const messageBuffer = Buffer.from(messageHex.substring(2), 'hex');
  8. const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${messageBuffer.length}`);
  9. return sha3(Buffer.concat([prefix, messageBuffer]));
  10. }
  11. // signs message in node (ganache auto-applies "Ethereum Signed Message" prefix)
  12. // messageHex = '0xdeadbeef'
  13. const signMessage = (signer, messageHex = '0x') => {
  14. return web3.eth.sign(signer, messageHex); // actually personal_sign
  15. };
  16. // @TODO - remove this when we migrate to web3-1.0.0
  17. const transformToFullName = function (json) {
  18. if (json.name.indexOf('(') !== -1) {
  19. return json.name;
  20. }
  21. const typeName = json.inputs.map(function (i) { return i.type; }).join();
  22. return json.name + '(' + typeName + ')';
  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. * Well truffle is terrible, but luckily (?) so is web3 < 1.0, so we get to make our own method id
  28. * fetcher because the method on the contract isn't actually the SolidityFunction object ಠ_ಠ
  29. * @param contract TruffleContract
  30. * @param signer address
  31. * @param redeemer address
  32. * @param methodName string
  33. * @param methodArgs any[]
  34. */
  35. const getSignFor = (contract, signer) => (redeemer, methodName, methodArgs = []) => {
  36. const parts = [
  37. contract.address,
  38. redeemer,
  39. ];
  40. // if we have a method, add it to the parts that we're signing
  41. if (methodName) {
  42. if (methodArgs.length > 0) {
  43. parts.push(
  44. contract.contract[methodName].getData(...methodArgs.concat([DUMMY_SIGNATURE])).slice(
  45. 0,
  46. -1 * PADDED_SIGNATURE_SIZE
  47. )
  48. );
  49. } else {
  50. const abi = contract.abi.find(abi => abi.name === methodName);
  51. const name = transformToFullName(abi);
  52. const signature = sha3(name).slice(0, 10);
  53. parts.push(signature);
  54. }
  55. }
  56. // return the signature of the "Ethereum Signed Message" hash of the hash of `parts`
  57. const messageHex = soliditySha3(...parts);
  58. return signMessage(signer, messageHex);
  59. };
  60. module.exports = {
  61. signMessage,
  62. toEthSignedMessageHash,
  63. getSignFor,
  64. };