AccountERC7702WithModulesMock.test.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. const { ethers, predeploy } = require('hardhat');
  2. const { loadFixture, setBalance } = require('@nomicfoundation/hardhat-network-helpers');
  3. const { getDomain } = require('../../helpers/eip712');
  4. const { ERC4337Helper } = require('../../helpers/erc4337');
  5. const { PackedUserOperation } = require('../../helpers/eip712-types');
  6. const { shouldBehaveLikeAccountCore, shouldBehaveLikeAccountHolder } = require('../Account.behavior');
  7. const { shouldBehaveLikeAccountERC7579 } = require('../extensions/AccountERC7579.behavior');
  8. const { shouldBehaveLikeERC1271 } = require('../../utils/cryptography/ERC1271.behavior');
  9. const { shouldBehaveLikeERC7821 } = require('../extensions/ERC7821.behavior');
  10. const { MODULE_TYPE_VALIDATOR } = require('../../helpers/erc7579');
  11. async function fixture() {
  12. // EOAs and environment
  13. const [beneficiary, other] = await ethers.getSigners();
  14. const target = await ethers.deployContract('CallReceiverMock');
  15. const anotherTarget = await ethers.deployContract('CallReceiverMock');
  16. // Signer with EIP-7702 support + funding
  17. const eoa = ethers.Wallet.createRandom(ethers.provider);
  18. await setBalance(eoa.address, ethers.WeiPerEther);
  19. // ERC-7579 validator module
  20. const validator = await ethers.deployContract('$ERC7579ValidatorMock');
  21. // ERC-4337 account
  22. const helper = new ERC4337Helper();
  23. const mock = await helper.newAccount('$AccountERC7702WithModulesMock', ['AccountERC7702WithModulesMock', '1'], {
  24. erc7702signer: eoa,
  25. });
  26. // ERC-4337 Entrypoint domain
  27. const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
  28. // domain cannot be fetched using getDomain(mock) before the mock is deployed
  29. const domain = {
  30. name: 'AccountERC7702WithModulesMock',
  31. version: '1',
  32. chainId: entrypointDomain.chainId,
  33. verifyingContract: mock.address,
  34. };
  35. return { helper, validator, mock, domain, entrypointDomain, eoa, target, anotherTarget, beneficiary, other };
  36. }
  37. describe('AccountERC7702WithModules: ERC-7702 account with ERC-7579 modules supports', function () {
  38. beforeEach(async function () {
  39. Object.assign(this, await loadFixture(fixture));
  40. });
  41. describe('using ERC-7702 signer', function () {
  42. beforeEach(async function () {
  43. this.signer = this.eoa;
  44. this.signUserOp = userOp =>
  45. this.signer
  46. .signTypedData(this.entrypointDomain, { PackedUserOperation }, userOp.packed)
  47. .then(signature => Object.assign(userOp, { signature }));
  48. });
  49. shouldBehaveLikeAccountCore();
  50. shouldBehaveLikeAccountHolder();
  51. shouldBehaveLikeERC7821({ deployable: false });
  52. shouldBehaveLikeERC1271({ erc7739: true });
  53. });
  54. describe('using ERC-7579 validator', function () {
  55. beforeEach(async function () {
  56. // signer that adds a prefix to all signatures (except the userOp ones)
  57. this.signer = ethers.Wallet.createRandom();
  58. this.signer.signMessage = message =>
  59. ethers.Wallet.prototype.signMessage
  60. .bind(this.signer)(message)
  61. .then(sign => ethers.concat([this.validator.target, sign]));
  62. this.signer.signTypedData = (domain, types, values) =>
  63. ethers.Wallet.prototype.signTypedData
  64. .bind(this.signer)(domain, types, values)
  65. .then(sign => ethers.concat([this.validator.target, sign]));
  66. this.signUserOp = userOp =>
  67. ethers.Wallet.prototype.signTypedData
  68. .bind(this.signer)(this.entrypointDomain, { PackedUserOperation }, userOp.packed)
  69. .then(signature => Object.assign(userOp, { signature }));
  70. // Use the first 20 bytes from the nonce key (24 bytes) to identify the validator module
  71. this.userOp = { nonce: ethers.zeroPadBytes(ethers.hexlify(this.validator.target), 32) };
  72. // Deploy (using ERC-7702) and add the validator module using EOA
  73. await this.mock.deploy();
  74. await this.mock.connect(this.eoa).installModule(MODULE_TYPE_VALIDATOR, this.validator, this.signer.address);
  75. });
  76. shouldBehaveLikeAccountCore();
  77. shouldBehaveLikeAccountHolder();
  78. shouldBehaveLikeAccountERC7579();
  79. shouldBehaveLikeERC1271({ erc7739: false });
  80. });
  81. });