erc4337.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. const { ethers } = require('hardhat');
  2. const SIG_VALIDATION_SUCCESS = '0x0000000000000000000000000000000000000000';
  3. const SIG_VALIDATION_FAILURE = '0x0000000000000000000000000000000000000001';
  4. function getAddress(account) {
  5. return account.target ?? account.address ?? account;
  6. }
  7. function pack(left, right) {
  8. return ethers.solidityPacked(['uint128', 'uint128'], [left, right]);
  9. }
  10. function packValidationData(validAfter, validUntil, authorizer) {
  11. return ethers.solidityPacked(
  12. ['uint48', 'uint48', 'address'],
  13. [
  14. validAfter,
  15. validUntil,
  16. typeof authorizer == 'boolean'
  17. ? authorizer
  18. ? SIG_VALIDATION_SUCCESS
  19. : SIG_VALIDATION_FAILURE
  20. : getAddress(authorizer),
  21. ],
  22. );
  23. }
  24. function packPaymasterData(paymaster, verificationGasLimit, postOpGasLimit) {
  25. return ethers.solidityPacked(
  26. ['address', 'uint128', 'uint128'],
  27. [getAddress(paymaster), verificationGasLimit, postOpGasLimit],
  28. );
  29. }
  30. /// Represent one user operation
  31. class UserOperation {
  32. constructor(params) {
  33. this.sender = getAddress(params.sender);
  34. this.nonce = params.nonce;
  35. this.initCode = params.initCode ?? '0x';
  36. this.callData = params.callData ?? '0x';
  37. this.verificationGas = params.verificationGas ?? 10_000_000n;
  38. this.callGas = params.callGas ?? 100_000n;
  39. this.preVerificationGas = params.preVerificationGas ?? 100_000n;
  40. this.maxPriorityFee = params.maxPriorityFee ?? 100_000n;
  41. this.maxFeePerGas = params.maxFeePerGas ?? 100_000n;
  42. this.paymasterAndData = params.paymasterAndData ?? '0x';
  43. this.signature = params.signature ?? '0x';
  44. }
  45. get packed() {
  46. return {
  47. sender: this.sender,
  48. nonce: this.nonce,
  49. initCode: this.initCode,
  50. callData: this.callData,
  51. accountGasLimits: pack(this.verificationGas, this.callGas),
  52. preVerificationGas: this.preVerificationGas,
  53. gasFees: pack(this.maxPriorityFee, this.maxFeePerGas),
  54. paymasterAndData: this.paymasterAndData,
  55. signature: this.signature,
  56. };
  57. }
  58. hash(entrypoint, chainId) {
  59. const p = this.packed;
  60. const h = ethers.keccak256(
  61. ethers.AbiCoder.defaultAbiCoder().encode(
  62. ['address', 'uint256', 'bytes32', 'bytes32', 'uint256', 'uint256', 'uint256', 'uint256'],
  63. [
  64. p.sender,
  65. p.nonce,
  66. ethers.keccak256(p.initCode),
  67. ethers.keccak256(p.callData),
  68. p.accountGasLimits,
  69. p.preVerificationGas,
  70. p.gasFees,
  71. ethers.keccak256(p.paymasterAndData),
  72. ],
  73. ),
  74. );
  75. return ethers.keccak256(
  76. ethers.AbiCoder.defaultAbiCoder().encode(['bytes32', 'address', 'uint256'], [h, getAddress(entrypoint), chainId]),
  77. );
  78. }
  79. }
  80. module.exports = {
  81. SIG_VALIDATION_SUCCESS,
  82. SIG_VALIDATION_FAILURE,
  83. packValidationData,
  84. packPaymasterData,
  85. UserOperation,
  86. };