eip712.js 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  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.solidityPackedKeccak256(
  41. ['bytes', 'bytes32', 'bytes32'],
  42. ['0x1901', ethers.TypedDataEncoder.hashDomain(domain), structHash],
  43. );
  44. }
  45. module.exports = {
  46. Permit,
  47. getDomain,
  48. domainType,
  49. domainSeparator: ethers.TypedDataEncoder.hashDomain,
  50. hashTypedData,
  51. };