eip712.js 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. const { ethers } = require('ethers');
  2. const EIP712Domain = [
  3. { name: 'name', type: 'string' },
  4. { name: 'version', type: 'string' },
  5. { name: 'chainId', type: 'uint256' },
  6. { name: 'verifyingContract', type: 'address' },
  7. { name: 'salt', type: 'bytes32' },
  8. ];
  9. const Permit = [
  10. { name: 'owner', type: 'address' },
  11. { name: 'spender', type: 'address' },
  12. { name: 'value', type: 'uint256' },
  13. { name: 'nonce', type: 'uint256' },
  14. { name: 'deadline', type: 'uint256' },
  15. ];
  16. async function getDomain(contract) {
  17. const { fields, name, version, chainId, verifyingContract, salt, extensions } = await contract.eip712Domain();
  18. if (extensions.length > 0) {
  19. throw Error('Extensions not implemented');
  20. }
  21. const domain = {
  22. name,
  23. version,
  24. // TODO: remove check when contracts are all migrated to ethers
  25. chainId: web3.utils.isBN(chainId) ? chainId.toNumber() : chainId,
  26. verifyingContract,
  27. salt,
  28. };
  29. for (const [i, { name }] of EIP712Domain.entries()) {
  30. if (!(fields & (1 << i))) {
  31. delete domain[name];
  32. }
  33. }
  34. return domain;
  35. }
  36. function domainType(domain) {
  37. return EIP712Domain.filter(({ name }) => domain[name] !== undefined);
  38. }
  39. function hashTypedData(domain, structHash) {
  40. return ethers.keccak256(
  41. Buffer.concat(['0x1901', ethers.TypedDataEncoder.hashDomain(domain), structHash].map(ethers.toBeArray)),
  42. );
  43. }
  44. module.exports = {
  45. Permit,
  46. getDomain,
  47. domainType,
  48. domainSeparator: ethers.TypedDataEncoder.hashDomain,
  49. hashTypedData,
  50. };