@aastar/sdk 0.20.8 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/dist/BaseClient-CkBhQ1ou.d.cts +88 -0
  2. package/dist/UserClient-BDGP37PK.js +6 -0
  3. package/dist/{UserClient-AIIHB54I.js.map → UserClient-BDGP37PK.js.map} +1 -1
  4. package/dist/UserClient-FOAOBLGK.cjs +15 -0
  5. package/dist/UserClient-FOAOBLGK.cjs.map +1 -0
  6. package/dist/account.cjs +31 -0
  7. package/dist/account.cjs.map +1 -0
  8. package/dist/account.d.cts +48 -0
  9. package/dist/account.js +3 -3
  10. package/dist/admin.cjs +15 -0
  11. package/dist/admin.cjs.map +1 -0
  12. package/dist/admin.d.cts +62 -0
  13. package/dist/admin.js +3 -3
  14. package/dist/airaccount.cjs +452 -0
  15. package/dist/airaccount.cjs.map +1 -0
  16. package/dist/airaccount.d.cts +4 -0
  17. package/dist/airaccount.js +3 -3
  18. package/dist/channel-CkRRbzT8.d.cts +77 -0
  19. package/dist/channel.cjs +27 -0
  20. package/dist/channel.cjs.map +1 -0
  21. package/dist/channel.d.cts +64 -0
  22. package/dist/channel.js +3 -3
  23. package/dist/chunk-3HZEIFBW.cjs +118 -0
  24. package/dist/chunk-3HZEIFBW.cjs.map +1 -0
  25. package/dist/{chunk-7ARJ3OSU.js → chunk-57XLR2NT.js} +3 -3
  26. package/dist/{chunk-7ARJ3OSU.js.map → chunk-57XLR2NT.js.map} +1 -1
  27. package/dist/chunk-5JFYTJOE.cjs +448 -0
  28. package/dist/chunk-5JFYTJOE.cjs.map +1 -0
  29. package/dist/{chunk-KDH3UPKD.js → chunk-5NKU5NT5.js} +8 -8
  30. package/dist/{chunk-KDH3UPKD.js.map → chunk-5NKU5NT5.js.map} +1 -1
  31. package/dist/chunk-63JM67L7.cjs +435 -0
  32. package/dist/chunk-63JM67L7.cjs.map +1 -0
  33. package/dist/{chunk-IC3G6YM2.js → chunk-6OWZOTE7.js} +113 -9
  34. package/dist/chunk-6OWZOTE7.js.map +1 -0
  35. package/dist/chunk-CIEYY3A6.cjs +43259 -0
  36. package/dist/chunk-CIEYY3A6.cjs.map +1 -0
  37. package/dist/chunk-DEUBKZH5.cjs +421 -0
  38. package/dist/chunk-DEUBKZH5.cjs.map +1 -0
  39. package/dist/{chunk-TENYCMJ3.js → chunk-DF4WVR2H.js} +9 -9
  40. package/dist/{chunk-TENYCMJ3.js.map → chunk-DF4WVR2H.js.map} +1 -1
  41. package/dist/{chunk-BN5WY5GM.js → chunk-DQBKE4ND.js} +4 -4
  42. package/dist/{chunk-BN5WY5GM.js.map → chunk-DQBKE4ND.js.map} +1 -1
  43. package/dist/{chunk-4EZD7LPE.js → chunk-E4CQFW75.js} +3 -3
  44. package/dist/{chunk-4EZD7LPE.js.map → chunk-E4CQFW75.js.map} +1 -1
  45. package/dist/{chunk-LXWIPTPX.js → chunk-ENSMYCU6.js} +3 -3
  46. package/dist/{chunk-LXWIPTPX.js.map → chunk-ENSMYCU6.js.map} +1 -1
  47. package/dist/{chunk-FJ7XECC5.js → chunk-EY2AJTGV.js} +3 -3
  48. package/dist/{chunk-FJ7XECC5.js.map → chunk-EY2AJTGV.js.map} +1 -1
  49. package/dist/chunk-GAMSWXWI.cjs +1168 -0
  50. package/dist/chunk-GAMSWXWI.cjs.map +1 -0
  51. package/dist/chunk-IJN776TA.cjs +585 -0
  52. package/dist/chunk-IJN776TA.cjs.map +1 -0
  53. package/dist/{chunk-PKCHRXFR.js → chunk-KZERVPUR.js} +3 -3
  54. package/dist/{chunk-PKCHRXFR.js.map → chunk-KZERVPUR.js.map} +1 -1
  55. package/dist/{chunk-6QYXGMCR.js → chunk-M5WFKETT.js} +833 -47
  56. package/dist/chunk-M5WFKETT.js.map +1 -0
  57. package/dist/chunk-M7HXR7G5.cjs +128 -0
  58. package/dist/chunk-M7HXR7G5.cjs.map +1 -0
  59. package/dist/{chunk-PAABYXS6.js → chunk-MCALA6WM.js} +6 -6
  60. package/dist/{chunk-PAABYXS6.js.map → chunk-MCALA6WM.js.map} +1 -1
  61. package/dist/chunk-MXJEULSE.cjs +396 -0
  62. package/dist/chunk-MXJEULSE.cjs.map +1 -0
  63. package/dist/chunk-OVNOSAL3.cjs +4797 -0
  64. package/dist/chunk-OVNOSAL3.cjs.map +1 -0
  65. package/dist/chunk-Q7SFCCGT.cjs +11 -0
  66. package/dist/chunk-Q7SFCCGT.cjs.map +1 -0
  67. package/dist/{chunk-MVEWJIPY.js → chunk-RXPSL33E.js} +3 -3
  68. package/dist/{chunk-MVEWJIPY.js.map → chunk-RXPSL33E.js.map} +1 -1
  69. package/dist/{chunk-G3UJC4EL.js → chunk-UCLK6LTB.js} +39 -36
  70. package/dist/chunk-UCLK6LTB.js.map +1 -0
  71. package/dist/chunk-WR4OZUXR.cjs +115 -0
  72. package/dist/chunk-WR4OZUXR.cjs.map +1 -0
  73. package/dist/chunk-XQROKLZI.cjs +4521 -0
  74. package/dist/chunk-XQROKLZI.cjs.map +1 -0
  75. package/dist/chunk-Y4EJX7UA.cjs +228 -0
  76. package/dist/chunk-Y4EJX7UA.cjs.map +1 -0
  77. package/dist/chunk-Z4GZ6DQA.cjs +108 -0
  78. package/dist/chunk-Z4GZ6DQA.cjs.map +1 -0
  79. package/dist/contract-addresses-RABD77VP.cjs +49 -0
  80. package/dist/contract-addresses-RABD77VP.cjs.map +1 -0
  81. package/dist/{contract-addresses-N3TOL2WL.js → contract-addresses-TVXSRQ7I.js} +3 -3
  82. package/dist/{contract-addresses-N3TOL2WL.js.map → contract-addresses-TVXSRQ7I.js.map} +1 -1
  83. package/dist/core.cjs +898 -0
  84. package/dist/core.cjs.map +1 -0
  85. package/dist/core.d.cts +7048 -0
  86. package/dist/core.d.ts +130 -12
  87. package/dist/core.js +2 -2
  88. package/dist/dapp.cjs +289 -0
  89. package/dist/dapp.cjs.map +1 -0
  90. package/dist/dapp.d.cts +127 -0
  91. package/dist/dapp.js +3 -3
  92. package/dist/doc-types-471vSmPO.d.cts +16 -0
  93. package/dist/enduser.cjs +24 -0
  94. package/dist/enduser.cjs.map +1 -0
  95. package/dist/enduser.d.cts +261 -0
  96. package/dist/enduser.js +4 -4
  97. package/dist/identity.cjs +23 -0
  98. package/dist/identity.cjs.map +1 -0
  99. package/dist/identity.d.cts +81 -0
  100. package/dist/identity.js +3 -3
  101. package/dist/index-B6SfEQxo.d.cts +47 -0
  102. package/dist/index.cjs +2818 -0
  103. package/dist/index.cjs.map +1 -0
  104. package/dist/index.d.cts +656 -0
  105. package/dist/index.d.ts +1 -1
  106. package/dist/index.js +17 -17
  107. package/dist/kms.cjs +452 -0
  108. package/dist/kms.cjs.map +1 -0
  109. package/dist/kms.d.cts +3104 -0
  110. package/dist/kms.d.ts +62 -12
  111. package/dist/kms.js +3 -3
  112. package/dist/lib-FE4GR7TO.cjs +1865 -0
  113. package/dist/lib-FE4GR7TO.cjs.map +1 -0
  114. package/dist/operator.cjs +27 -0
  115. package/dist/operator.cjs.map +1 -0
  116. package/dist/operator.d.cts +164 -0
  117. package/dist/operator.js +3 -3
  118. package/dist/paymaster.cjs +63 -0
  119. package/dist/paymaster.cjs.map +1 -0
  120. package/dist/paymaster.d.cts +312 -0
  121. package/dist/paymaster.js +3 -3
  122. package/dist/src-CUHI6G6W.cjs +898 -0
  123. package/dist/src-CUHI6G6W.cjs.map +1 -0
  124. package/dist/src-KHCWIS4Q.cjs +63 -0
  125. package/dist/src-KHCWIS4Q.cjs.map +1 -0
  126. package/dist/{src-X5MIV3EB.js → src-RSN4U2T2.js} +5 -5
  127. package/dist/src-RSN4U2T2.js.map +1 -0
  128. package/dist/{src-L5SI5WNB.js → src-XCV6BTSV.js} +4 -4
  129. package/dist/{src-X5MIV3EB.js.map → src-XCV6BTSV.js.map} +1 -1
  130. package/dist/tier-router-DeeVg69O.d.cts +370 -0
  131. package/dist/tokens.cjs +15 -0
  132. package/dist/tokens.cjs.map +1 -0
  133. package/dist/tokens.d.cts +64 -0
  134. package/dist/tokens.js +3 -3
  135. package/dist/x402.cjs +103 -0
  136. package/dist/x402.cjs.map +1 -0
  137. package/dist/x402.d.cts +373 -0
  138. package/dist/x402.js +3 -3
  139. package/package.json +116 -32
  140. package/dist/UserClient-AIIHB54I.js +0 -6
  141. package/dist/chunk-6QYXGMCR.js.map +0 -1
  142. package/dist/chunk-G3UJC4EL.js.map +0 -1
  143. package/dist/chunk-IC3G6YM2.js.map +0 -1
  144. package/dist/src-L5SI5WNB.js.map +0 -1
@@ -0,0 +1,4797 @@
1
+ 'use strict';
2
+
3
+ var chunkXQROKLZI_cjs = require('./chunk-XQROKLZI.cjs');
4
+ var chunkMXJEULSE_cjs = require('./chunk-MXJEULSE.cjs');
5
+ var viem = require('viem');
6
+ var axios = require('axios');
7
+ var crypto = require('crypto');
8
+ var accounts = require('viem/accounts');
9
+
10
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
+
12
+ var axios__default = /*#__PURE__*/_interopDefault(axios);
13
+
14
+ // ../airaccount/src/server/constants/entrypoint.ts
15
+ var CORE_SEPOLIA = chunkMXJEULSE_cjs.CANONICAL_ADDRESSES[11155111];
16
+ var EntryPointVersion = /* @__PURE__ */ ((EntryPointVersion2) => {
17
+ EntryPointVersion2["V0_6"] = "0.6";
18
+ EntryPointVersion2["V0_7"] = "0.7";
19
+ EntryPointVersion2["V0_8"] = "0.8";
20
+ return EntryPointVersion2;
21
+ })(EntryPointVersion || {});
22
+ var ENTRYPOINT_ADDRESSES = {
23
+ ["0.6" /* V0_6 */]: {
24
+ sepolia: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
25
+ mainnet: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789",
26
+ optimism: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
27
+ },
28
+ ["0.7" /* V0_7 */]: {
29
+ sepolia: "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
30
+ mainnet: "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
31
+ optimism: "0x0000000071727De22E5E9d8BAf0edAc6f37da032"
32
+ },
33
+ ["0.8" /* V0_8 */]: {
34
+ sepolia: "0x0576a174D229E3cFA37253523E645A78A0C91B57",
35
+ mainnet: "0x0576a174D229E3cFA37253523E645A78A0C91B57",
36
+ optimism: "0x0576a174D229E3cFA37253523E645A78A0C91B57"
37
+ }
38
+ };
39
+ var ENTRYPOINT_ABI_V6 = [
40
+ "function simulateValidation((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes) userOp) external",
41
+ "function getNonce(address sender, uint192 key) external view returns (uint256 nonce)",
42
+ "function getUserOpHash((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes) userOp) external view returns (bytes32)",
43
+ "function handleOps((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[] ops, address payable beneficiary) external"
44
+ ];
45
+ var ENTRYPOINT_ABI_V7_V8 = [
46
+ "function simulateValidation((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes) packedUserOp) external",
47
+ "function getNonce(address sender, uint192 key) external view returns (uint256 nonce)",
48
+ "function getUserOpHash((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes) packedUserOp) external view returns (bytes32)",
49
+ "function handleOps((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes)[] ops, address payable beneficiary) external"
50
+ ];
51
+ var FACTORY_ABI_V6 = [
52
+ "function getAddress(address creator, address signer, address validator, bool useAAStarValidator, uint256 salt) view returns (address)",
53
+ "function createAccountWithAAStarValidator(address creator, address signer, address aaStarValidator, bool useAAStarValidator, uint256 salt) returns (address)"
54
+ ];
55
+ var FACTORY_ABI_V7_V8 = [
56
+ "function getAddress(address creator, address signer, address validator, bool useAAStarValidator, uint256 salt) view returns (address)",
57
+ "function createAccount(address creator, address signer, address aaStarValidator, bool useAAStarValidator, uint256 salt) returns (address)"
58
+ ];
59
+ var ACCOUNT_ABI = [
60
+ "function execute(address dest, uint256 value, bytes calldata func) external"
61
+ ];
62
+ var VALIDATOR_ABI = [
63
+ "function getGasEstimate(uint256 nodeCount) external pure returns (uint256 gasEstimate)"
64
+ ];
65
+ var AIRACCOUNT_ADDRESSES = {
66
+ sepolia: {
67
+ // M4 factory (legacy — 3-field InitConfig)
68
+ factoryM4: "0x914db0a849f55e68a726c72fd02b7114b1176d88",
69
+ // M5 factory r5 — 6-field InitConfig, guardian acceptance sigs required
70
+ factoryM5: "0xd72a236d84be6c388a8bc7deb64afd54704ae385",
71
+ /** @deprecated defaultCommunityGuardian was address(0); superseded by r6 and r4. Do not use for new accounts. */
72
+ factoryM7r5Prev: "0xa0007c5dB27548D8c1582773856dB1D123107383",
73
+ // ── Deprecated: r6 addresses (2026-03-29 deployment, superseded by r4 audit-final) ──────────
74
+ // Retain for legacy account lookups and historical event indexing ONLY.
75
+ // DO NOT use for new account creation — CREATE2 address will differ from r4.
76
+ /** @deprecated Use {@link factory} (r4 audit-final) for new accounts. */
77
+ factoryM7r6: "0x42f82d77f9cf940686b6a64a369245cb563e0e85",
78
+ /** @deprecated Use {@link accountImpl} (r4 audit-final). */
79
+ accountImplM7r6: "0x2F1B4EB63143D338bE78d0AF878B806f075080c1",
80
+ /** @deprecated Use {@link compositeValidator} (r4 audit-final). */
81
+ compositeValidatorM7r6: "0x4135c539fec5e200fe9762b721f6829b2315cbe1",
82
+ /** @deprecated Use {@link tierGuardHook} (r4 audit-final). */
83
+ tierGuardHookM7r6: "0x73572e9e6138fd53465ee243e2fb4842cf86a787",
84
+ /** @deprecated Use {@link agentSessionKeyValidator} (r4 audit-final). */
85
+ agentSessionKeyValidatorM7r6: "0xa3e52db4b6e0a9d7cd5dd1414a90eedcf950e029",
86
+ // ── Deprecated: r4 audit-final (v0.16.0 era — pre-beta). Retained for existing account recovery. ─
87
+ /** @deprecated Use factory (beta.4) for new accounts. */
88
+ factoryM7r4: "0x61bBAf9E1b8Fd78fF874776cFa50497dB9d43C3F",
89
+ /** @deprecated */
90
+ accountImplM7r4: "0xA674D308ce22230B70412b20Ee5a66fC6B24F49c",
91
+ /** @deprecated Use validatorRouter. */
92
+ validatorRouterM7r4: "0x730a162Ce3202b94cC5B74181B75b11eBB3045B1",
93
+ /** @deprecated */
94
+ compositeValidatorM7r4: "0xB65569950C48AA56dbe876915ca3605fD6FF2980",
95
+ /** @deprecated */
96
+ tierGuardHookM7r4: "0x67f878295cFF7451CBD2A775C4490607AF1b07d7",
97
+ /** @deprecated */
98
+ agentSessionKeyValidatorM7r4: "0x1F06961e133217801F92e1CF552187F594a32873",
99
+ // ── Current: derived from @aastar/core CANONICAL_ADDRESSES[11155111] ───────────
100
+ // SINGLE SOURCE OF TRUTH. Do NOT hand-copy hex here. core is synced on every
101
+ // protocol redeploy (currently AirAccount v0.20.0, Sepolia 2026-06-20),
102
+ // and these fields re-derive automatically. The key mapping (airaccount field ←
103
+ // core key) is asserted by entrypoint.addresses.test.ts so it can't silently drift.
104
+ factory: CORE_SEPOLIA.airAccountFactoryV7,
105
+ factoryM7: CORE_SEPOLIA.airAccountFactoryV7,
106
+ accountImpl: CORE_SEPOLIA.airAccountV7Impl,
107
+ validatorRouter: CORE_SEPOLIA.aaStarValidator,
108
+ blsAlgorithm: CORE_SEPOLIA.aaStarBLSAlgorithm,
109
+ blsAggregator: CORE_SEPOLIA.aaStarBLSAggregator,
110
+ // SuperPaymaster proxy — same concept as core's `superPaymaster` proxy.
111
+ superPaymaster: CORE_SEPOLIA.superPaymaster,
112
+ sessionKeyValidator: CORE_SEPOLIA.sessionKeyValidator,
113
+ forceExitModule: CORE_SEPOLIA.forceExitModule,
114
+ airAccountDelegate: CORE_SEPOLIA.airAccountDelegate,
115
+ airAccountExtension: CORE_SEPOLIA.airAccountExtension,
116
+ agentRegistry: CORE_SEPOLIA.agentRegistry,
117
+ calldataParserRegistry: CORE_SEPOLIA.calldataParserRegistry,
118
+ // uniswapV3Parser is airaccount-specific (not in core) — keep hardcoded.
119
+ uniswapV3Parser: "0x5671810ac8aa1857397870e60232579cfc519515"
120
+ }
121
+ };
122
+ var AIRACCOUNT_ABI = [
123
+ // ── Core execution ──
124
+ "function execute(address dest, uint256 value, bytes calldata func) external",
125
+ "function executeBatch(address[] calldata dest, uint256[] calldata value, bytes[] calldata func) external",
126
+ // ── ERC-7579 Module Management (M7.2) ──
127
+ "function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external",
128
+ "function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external",
129
+ "function executeFromExecutor(bytes32 mode, bytes calldata executionCalldata) external returns (bytes[] memory returnData)",
130
+ // ── ERC-7579 Introspection ──
131
+ "function accountId() external pure returns (string memory)",
132
+ "function supportsModule(uint256 moduleTypeId) external pure returns (bool)",
133
+ "function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext) external view returns (bool)",
134
+ // ── ERC-1271 / ERC-165 ──
135
+ "function isValidSignature(bytes32 hash, bytes calldata sig) external view returns (bytes4)",
136
+ "function validateCompositeSignature(bytes32 hash, bytes calldata sig) external returns (uint256)",
137
+ "function supportsInterface(bytes4 interfaceId) external pure returns (bool)",
138
+ // ── State readers ──
139
+ "function owner() external view returns (address)",
140
+ "function entryPoint() external view returns (address)",
141
+ "function validator() external view returns (address)",
142
+ "function guard() external view returns (address)",
143
+ "function guardianCount() external view returns (uint8)",
144
+ "function guardians(uint256 index) external view returns (address)",
145
+ "function p256KeyX() external view returns (bytes32)",
146
+ "function p256KeyY() external view returns (bytes32)",
147
+ // abitype/viem human-readable ABIs use a bare parenthesised tuple `(...)`, not the
148
+ // ethers-style `tuple(...)` keyword (which parseAbi rejects with "Invalid ABI parameter").
149
+ "function getConfigDescription() external view returns ((address accountOwner, address guardAddress, uint256 dailyLimit, uint256 dailyRemaining, uint256 tier1Limit, uint256 tier2Limit, address[3] guardianAddresses, uint8 guardianCount, bool hasP256Key, bool hasValidator, bool hasAggregator, bool hasActiveRecovery))",
150
+ // ── Owner / key management ──
151
+ "function setValidator(address _validator) external",
152
+ "function setP256Key(bytes32 _x, bytes32 _y) external",
153
+ "function setTierLimits(uint256 _tier1, uint256 _tier2) external",
154
+ "function modifyTierLimitsWithGuardians(uint256 _tier1, uint256 _tier2, uint256 deadline, bytes[] calldata guardianSigs) external",
155
+ // ── Algorithm whitelist (v0.17.2-beta.4: single source of truth on the ACCOUNT, not the guard) ──
156
+ "function approvedAlgorithms(uint8 algId) external view returns (bool)",
157
+ "function guardApproveAlgorithm(uint8 algId) external",
158
+ // ── Social / guardian recovery (F28) ──
159
+ // Guardian set: owner adds guardians (max 3); removal needs RECOVERY_THRESHOLD guardian sigs.
160
+ // Recovery lifecycle: a guardian proposes a new owner (starts the timelock), guardians
161
+ // approve to reach 2-of-3 threshold, then anyone executes after the timelock; guardians
162
+ // (not the owner) can vote to cancel. See RecoveryService for the full flow.
163
+ "function addGuardian(address _guardian) external",
164
+ "function removeGuardian(uint8 index, bytes[] calldata guardianSigs) external",
165
+ "function proposeRecovery(address _newOwner) external",
166
+ "function approveRecovery() external",
167
+ "function cancelRecovery() external",
168
+ "function executeRecovery() external",
169
+ "function activeRecovery() external view returns (address newOwner, uint256 proposedAt, uint256 approvalBitmap, uint256 cancellationBitmap)",
170
+ // ── Weighted-signature governance (algId 0x07) ──
171
+ // WeightConfig tuple = (passkeyWeight, ecdsaWeight, blsWeight, guardian0Weight,
172
+ // guardian1Weight, guardian2Weight, _padding, tier1Threshold, tier2Threshold, tier3Threshold)
173
+ "function setWeightConfig((uint8 passkeyWeight, uint8 ecdsaWeight, uint8 blsWeight, uint8 guardian0Weight, uint8 guardian1Weight, uint8 guardian2Weight, uint8 _padding, uint8 tier1Threshold, uint8 tier2Threshold, uint8 tier3Threshold) config) external",
174
+ "function proposeWeightChange((uint8 passkeyWeight, uint8 ecdsaWeight, uint8 blsWeight, uint8 guardian0Weight, uint8 guardian1Weight, uint8 guardian2Weight, uint8 _padding, uint8 tier1Threshold, uint8 tier2Threshold, uint8 tier3Threshold) proposed) external",
175
+ "function approveWeightChange() external",
176
+ "function cancelWeightChange() external",
177
+ "function executeWeightChange() external",
178
+ "function weightConfig() external view returns (uint8 passkeyWeight, uint8 ecdsaWeight, uint8 blsWeight, uint8 guardian0Weight, uint8 guardian1Weight, uint8 guardian2Weight, uint8 _padding, uint8 tier1Threshold, uint8 tier2Threshold, uint8 tier3Threshold)",
179
+ "function pendingWeightChange() external view returns ((uint8 passkeyWeight, uint8 ecdsaWeight, uint8 blsWeight, uint8 guardian0Weight, uint8 guardian1Weight, uint8 guardian2Weight, uint8 _padding, uint8 tier1Threshold, uint8 tier2Threshold, uint8 tier3Threshold) proposed, uint256 proposedAt, uint256 approvalBitmap)",
180
+ // ── ERC-4337 v0.7 bundler entrypoint (v0.17.2-beta.4) ──
181
+ // Routes a UserOp whose callData starts with the executeUserOp selector to the account,
182
+ // re-deriving the signature algId in-frame (fixes guard-account bundler gas estimation).
183
+ // Only an inner execute()/executeBatch() may be wrapped (else reverts UnsupportedInnerSelector).
184
+ "function executeUserOp((address sender, uint256 nonce, bytes initCode, bytes callData, bytes32 accountGasLimits, uint256 preVerificationGas, bytes32 gasFees, bytes paymasterAndData, bytes signature) userOp, bytes32 userOpHash) external",
185
+ // ── Events ──
186
+ "event ModuleInstalled(uint256 indexed moduleTypeId, address indexed module)",
187
+ "event ModuleUninstalled(uint256 indexed moduleTypeId, address indexed module)",
188
+ "event OwnerChanged(address indexed oldOwner, address indexed newOwner)",
189
+ // v0.20.0 (#120): recovery events gained a trailing `uint8 guardianIdx` naming the
190
+ // authorizing guardian slot (on P-256 relayer-submitted paths msg.sender is the relayer,
191
+ // not the guardian). topic0 of these three events changed — decoders must use the new shape.
192
+ "event RecoveryProposed(address indexed newOwner, address indexed proposedBy, uint8 guardianIdx)",
193
+ "event RecoveryApproved(address indexed newOwner, address indexed approvedBy, uint256 approvalCount, uint8 guardianIdx)",
194
+ "event RecoveryCancelVoted(address indexed votedBy, uint256 cancelCount, uint8 guardianIdx)",
195
+ "event RecoveryExecuted(address indexed oldOwner, address indexed newOwner)"
196
+ ];
197
+ var AIRACCOUNT_FACTORY_ABI = [
198
+ // Full config creation
199
+ "function createAccount(address owner, uint256 salt, (address[3] guardians, bytes32[3] guardianP256X, bytes32[3] guardianP256Y, uint256 dailyLimit, uint8[] approvedAlgIds, uint256 minDailyLimit, address[] initialTokens, (uint256 tier1Limit, uint256 tier2Limit, uint256 dailyLimit)[] initialTokenConfigs) config) external returns (address)",
200
+ "function getAddress(address owner, uint256 salt, (address[3] guardians, bytes32[3] guardianP256X, bytes32[3] guardianP256Y, uint256 dailyLimit, uint8[] approvedAlgIds, uint256 minDailyLimit, address[] initialTokens, (uint256 tier1Limit, uint256 tier2Limit, uint256 dailyLimit)[] initialTokenConfigs) config) external view returns (address)",
201
+ // Default guardian setup (requires guardian acceptance sigs — M5.3+)
202
+ "function createAccountWithDefaults(address owner, uint256 salt, address guardian1, bytes guardian1Sig, address guardian2, bytes guardian2Sig, uint256 dailyLimit) external returns (address)",
203
+ "function getAddressWithDefaults(address owner, uint256 salt, address guardian1, address guardian2, uint256 dailyLimit) external view returns (address)",
204
+ // Agent-account creation (V7: agentKey + human-guardian2 co-owned account, registered in AgentRegistry)
205
+ "function createAgentAccount(address agentKey, bytes32 agentId, address guardian2, bytes guardian2Sig, bytes agentKeySig, uint48 deadline, uint256 dailyLimit) external returns (address account)",
206
+ "function getAgentAddress(address humanOwner, address agentKey, bytes32 agentId) external view returns (address)",
207
+ "function setAgentRegistry(address _agentRegistry) external",
208
+ "function agentRegistry() external view returns (address)",
209
+ // M7 immutable state
210
+ "function implementation() external view returns (address)",
211
+ "function entryPoint() external view returns (address)",
212
+ "function defaultCommunityGuardian() external view returns (address)",
213
+ "function defaultValidatorModule() external view returns (address)",
214
+ "function defaultHookModule() external view returns (address)",
215
+ // M7.4 ERC-7828 chain-qualified address helpers
216
+ "function getChainQualifiedAddress(address account) external view returns (bytes32)",
217
+ "function getAddressWithChainId(address owner, uint256 salt, (address[3] guardians, bytes32[3] guardianP256X, bytes32[3] guardianP256Y, uint256 dailyLimit, uint8[] approvedAlgIds, uint256 minDailyLimit, address[] initialTokens, (uint256 tier1Limit, uint256 tier2Limit, uint256 dailyLimit)[] initialTokenConfigs) config) external view returns (address account, bytes32 chainQualified)",
218
+ // Events
219
+ "event AccountCreated(address indexed account, address indexed owner, uint256 salt)"
220
+ ];
221
+ var GLOBAL_GUARD_ABI = [
222
+ "function remainingDailyAllowance() external view returns (uint256)",
223
+ "function dailyLimit() external view returns (uint256)",
224
+ "function account() external view returns (address)",
225
+ // Spend accounting (record* — algId dropped from the ETH path; kept for per-token tier math)
226
+ "function recordSpend(uint256 value) external returns (bool)",
227
+ "function recordTokenSpend(address token, uint256 amount, uint8 algId) external returns (bool)"
228
+ ];
229
+ var ERC20_ABI = [
230
+ "function name() view returns (string)",
231
+ "function symbol() view returns (string)",
232
+ "function decimals() view returns (uint8)",
233
+ "function totalSupply() view returns (uint256)",
234
+ "function balanceOf(address owner) view returns (uint256)",
235
+ "function transfer(address to, uint256 amount) returns (bool)",
236
+ "function allowance(address owner, address spender) view returns (uint256)",
237
+ "function approve(address spender, uint256 amount) returns (bool)"
238
+ ];
239
+ var AGENT_SESSION_KEY_VALIDATOR_ABI = [
240
+ // ERC-7579 lifecycle
241
+ "function onInstall(bytes calldata data) external",
242
+ "function onUninstall(bytes calldata data) external",
243
+ "function isInitialized(address smartAccount) external view returns (bool)",
244
+ // Session management
245
+ "function grantAgentSession(address sessionKey, (uint48 expiry, uint16 velocityLimit, uint32 velocityWindow, bool revoked, address[] callTargets, bytes4[] selectorAllowlist) cfg) external",
246
+ "function delegateSession(address account, address subKey, (uint48 expiry, uint16 velocityLimit, uint32 velocityWindow, bool revoked, address[] callTargets, bytes4[] selectorAllowlist) subCfg) external",
247
+ "function revokeAgentSession(address sessionKey) external",
248
+ // Validation
249
+ "function validateUserOp((address sender, uint256 nonce, bytes initCode, bytes callData, bytes32 accountGasLimits, uint256 preVerificationGas, bytes32 gasFees, bytes paymasterAndData, bytes signature) userOp, bytes32 userOpHash) external returns (uint256 validationData)",
250
+ "function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata data) external pure returns (bytes4)",
251
+ // Enforcement
252
+ "function enforceSessionScope(address account, address sessionKey, address callTarget, bytes4 selector) external view",
253
+ // State readers
254
+ "function agentSessions(address account, address sessionKey) external view returns (uint48 expiry, uint16 velocityLimit, uint32 velocityWindow, bool revoked, address[] memory callTargets, bytes4[] memory selectorAllowlist)",
255
+ "function sessionStates(address account, address sessionKey) external view returns (uint256 callCount, uint256 windowStart)",
256
+ "function sessionKeyOwner(address sessionKey) external view returns (address)",
257
+ "function delegatedBy(address account, address subKey) external view returns (address parentKey)",
258
+ // Events
259
+ "event AgentSessionGranted(address indexed account, address indexed sessionKey, uint48 expiry)",
260
+ "event AgentSessionRevoked(address indexed account, address indexed sessionKey)",
261
+ "event AgentSessionDelegated(address indexed parentAccount, address indexed parentKey, address indexed subKey, uint48 expiry)"
262
+ ];
263
+ var TIER_GUARD_HOOK_ABI = [
264
+ // ERC-7579 lifecycle
265
+ "function onInstall(bytes calldata data) external",
266
+ "function onUninstall(bytes calldata data) external",
267
+ "function isInitialized(address smartAccount) external view returns (bool)",
268
+ // ERC-7579 Hook interface
269
+ "function preCheck(address msgSender, uint256 msgValue, bytes calldata msgData) external returns (bytes memory hookData)",
270
+ "function postCheck(bytes calldata hookData) external",
271
+ // State readers
272
+ "function accountGuard(address account) external view returns (address)",
273
+ "function accountTier1(address account) external view returns (uint256)",
274
+ "function accountTier2(address account) external view returns (uint256)"
275
+ ];
276
+ var AIR_ACCOUNT_COMPOSITE_VALIDATOR_ABI = [
277
+ // ERC-7579 lifecycle
278
+ "function onInstall(bytes calldata data) external",
279
+ "function onUninstall(bytes calldata data) external",
280
+ "function isInitialized(address smartAccount) external view returns (bool)",
281
+ // ERC-7579 Validator interface
282
+ "function validateUserOp((address sender, uint256 nonce, bytes initCode, bytes callData, bytes32 accountGasLimits, uint256 preVerificationGas, bytes32 gasFees, bytes paymasterAndData, bytes signature) userOp, bytes32 userOpHash) external returns (uint256 validationData)",
283
+ "function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata data) external view returns (bytes4 magicValue)"
284
+ ];
285
+ var FORCE_EXIT_MODULE_ABI = [
286
+ // ERC-7579 lifecycle
287
+ "function onInstall(bytes calldata data) external",
288
+ "function onUninstall(bytes calldata data) external",
289
+ "function isInitialized(address smartAccount) external view returns (bool)",
290
+ // Force exit flow
291
+ "function proposeForceExit(address target, uint256 value, bytes calldata data) external",
292
+ "function approveForceExit(address account, bytes calldata guardianSig) external",
293
+ "function executeForceExit(address account) external",
294
+ "function cancelForceExit(address account) external",
295
+ // State readers
296
+ "function accountL2Type(address account) external view returns (uint8)",
297
+ "function getPendingExit(address account) external view returns (address target, uint256 value, bytes memory data, uint256 proposedAt, uint256 approvalBitmap, address[3] memory guardians)",
298
+ // Events
299
+ "event ExitProposed(address indexed account, address indexed target, uint256 value)",
300
+ "event ExitApproved(address indexed account, address indexed guardian, uint256 bitmap)",
301
+ "event ExitExecuted(address indexed account, address indexed target, uint256 value)",
302
+ "event ExitCancelled(address indexed account)"
303
+ ];
304
+ var MODULE_TYPE = {
305
+ VALIDATOR: 1,
306
+ EXECUTOR: 2,
307
+ FALLBACK: 3,
308
+ HOOK: 4
309
+ };
310
+ var ALG_ID = {
311
+ BLS: 1,
312
+ ECDSA: 2,
313
+ P256: 3,
314
+ CUMULATIVE_T2: 4,
315
+ // P256 + BLS
316
+ CUMULATIVE_T3: 5,
317
+ // P256 + BLS + Guardian ECDSA
318
+ COMBINED_T1: 6,
319
+ // P256 AND ECDSA simultaneously
320
+ WEIGHTED: 7,
321
+ // Weighted multi-signature
322
+ SESSION_KEY: 8,
323
+ // Time-limited session key (SessionKeyValidator)
324
+ AGENT_SESSION_KEY: 9
325
+ // AI agent session key (AgentSessionKeyValidator)
326
+ };
327
+ var SESSION_KEY_VALIDATOR_ABI = [
328
+ // Session struct (8 fields) — authoritative tuple shape from
329
+ // airaccount-contract/src/validators/SessionKeyValidator.sol and
330
+ // packages/core/src/abis/SessionKeyValidator.json. The grant/build/read
331
+ // functions take/return this tuple as a single arg — NOT flat params.
332
+ // Canonical tuple type: (uint48,address,bytes4,bool,uint16,uint32,address[],bytes4[])
333
+ // ECDSA session key
334
+ "function grantSession(address account, address sessionKey, (uint48 expiry, address contractScope, bytes4 selectorScope, bool revoked, uint16 velocityLimit, uint32 velocityWindow, address[] callTargets, bytes4[] selectorAllowlist) cfg, bytes calldata ownerSig) external",
335
+ "function grantSessionDirect(address account, address sessionKey, (uint48 expiry, address contractScope, bytes4 selectorScope, bool revoked, uint16 velocityLimit, uint32 velocityWindow, address[] callTargets, bytes4[] selectorAllowlist) cfg) external",
336
+ "function revokeSession(address account, address sessionKey) external",
337
+ "function isSessionActive(address account, address sessionKey) external view returns (bool)",
338
+ "function getSession(address account, address sessionKey) external view returns ((uint48 expiry, address contractScope, bytes4 selectorScope, bool revoked, uint16 velocityLimit, uint32 velocityWindow, address[] callTargets, bytes4[] selectorAllowlist))",
339
+ "function buildGrantHash(address account, address sessionKey, (uint48 expiry, address contractScope, bytes4 selectorScope, bool revoked, uint16 velocityLimit, uint32 velocityWindow, address[] callTargets, bytes4[] selectorAllowlist) cfg) external view returns (bytes32)",
340
+ // P256 session key
341
+ "function grantP256Session(address account, bytes32 p256KeyX, bytes32 p256KeyY, (uint48 expiry, address contractScope, bytes4 selectorScope, bool revoked, uint16 velocityLimit, uint32 velocityWindow, address[] callTargets, bytes4[] selectorAllowlist) cfg, bytes calldata ownerSig) external",
342
+ "function grantP256SessionDirect(address account, bytes32 p256KeyX, bytes32 p256KeyY, (uint48 expiry, address contractScope, bytes4 selectorScope, bool revoked, uint16 velocityLimit, uint32 velocityWindow, address[] callTargets, bytes4[] selectorAllowlist) cfg) external",
343
+ "function revokeP256Session(address account, bytes32 p256KeyX, bytes32 p256KeyY) external",
344
+ "function isP256SessionActive(address account, bytes32 p256KeyX, bytes32 p256KeyY) external view returns (bool)",
345
+ "function getP256Session(address account, bytes32 p256KeyHash) external view returns ((uint48 expiry, address contractScope, bytes4 selectorScope, bool revoked, uint16 velocityLimit, uint32 velocityWindow, address[] callTargets, bytes4[] selectorAllowlist))",
346
+ "function buildP256GrantHash(address account, bytes32 p256KeyX, bytes32 p256KeyY, (uint48 expiry, address contractScope, bytes4 selectorScope, bool revoked, uint16 velocityLimit, uint32 velocityWindow, address[] callTargets, bytes4[] selectorAllowlist) cfg) external view returns (bytes32)",
347
+ // Events
348
+ "event SessionGranted(address indexed account, address indexed sessionKey, uint48 expiry, address contractScope, bytes4 selectorScope)",
349
+ "event SessionRevoked(address indexed account, address indexed sessionKey)",
350
+ "event P256SessionGranted(address indexed account, bytes32 indexed p256KeyHash, uint48 expiry)",
351
+ "event P256SessionRevoked(address indexed account, bytes32 indexed p256KeyHash)"
352
+ ];
353
+ var CALLDATA_PARSER_REGISTRY_ABI = [
354
+ "function registerParser(address dest, address parser) external",
355
+ "function getParser(address dest) external view returns (address)",
356
+ "function transferOwnership(address newOwner) external",
357
+ "function parserFor(address dest) external view returns (address)",
358
+ "event ParserRegistered(address indexed dest, address indexed parser)",
359
+ "event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)"
360
+ ];
361
+ var AIR_ACCOUNT_DELEGATE_ABI = [
362
+ // EIP-7702 初始化(仅限 EOA 自身调用)
363
+ "function initialize(address guardian1, bytes calldata g1Sig, address guardian2, bytes calldata g2Sig, uint256 dailyLimit) external",
364
+ // ERC-4337 执行
365
+ "function validateUserOp((address sender, uint256 nonce, bytes initCode, bytes callData, bytes32 accountGasLimits, uint256 preVerificationGas, bytes32 gasFees, bytes paymasterAndData, bytes signature) userOp, bytes32 userOpHash, uint256 missingAccountFunds) external returns (uint256)",
366
+ "function execute(address dest, uint256 value, bytes calldata data) external",
367
+ "function executeBatch(address[] calldata dest, uint256[] calldata value, bytes[] calldata data) external",
368
+ // 社会恢复(Rescue,EIP-7702 术语避免与 AirAccount Recovery 混淆)
369
+ "function initiateRescue(address rescueTo) external",
370
+ "function approveRescue() external",
371
+ "function executeRescue() external",
372
+ // Events
373
+ "event DelegateInitialized(address indexed eoa, address guard, address g1, address g2)",
374
+ "event RescueInitiated(address indexed eoa, address rescueTo, address indexed initiator)",
375
+ "event RescueApproved(address indexed eoa, address indexed guardian, uint8 approvals)",
376
+ "event RescueExecuted(address indexed eoa, address rescueTo, uint256 ethAmount)",
377
+ "event RescueCancelled(address indexed eoa)"
378
+ ];
379
+
380
+ // ../airaccount/src/server/config.ts
381
+ function sepoliaV07Config(version = "M7") {
382
+ const factoryAddress = version === "M5" ? AIRACCOUNT_ADDRESSES.sepolia.factoryM5 : version === "M7r6" ? AIRACCOUNT_ADDRESSES.sepolia.factoryM7r6 : AIRACCOUNT_ADDRESSES.sepolia.factory;
383
+ return {
384
+ entryPointAddress: ENTRYPOINT_ADDRESSES["0.7" /* V0_7 */].sepolia,
385
+ factoryAddress,
386
+ validatorAddress: AIRACCOUNT_ADDRESSES.sepolia.validatorRouter
387
+ };
388
+ }
389
+ function validateConfig(config) {
390
+ if (!config.rpcUrl) {
391
+ throw new Error("ServerConfig: rpcUrl is required");
392
+ }
393
+ if (!config.bundlerRpcUrl) {
394
+ throw new Error("ServerConfig: bundlerRpcUrl is required");
395
+ }
396
+ if (!config.chainId) {
397
+ throw new Error("ServerConfig: chainId is required");
398
+ }
399
+ const { entryPoints } = config;
400
+ if (!entryPoints || !entryPoints.v06 && !entryPoints.v07 && !entryPoints.v08) {
401
+ throw new Error("ServerConfig: at least one entryPoint version must be configured");
402
+ }
403
+ for (const [key, ep] of Object.entries(entryPoints)) {
404
+ if (ep) {
405
+ if (!ep.entryPointAddress) {
406
+ throw new Error(`ServerConfig: entryPoints.${key}.entryPointAddress is required`);
407
+ }
408
+ if (!ep.factoryAddress) {
409
+ throw new Error(`ServerConfig: entryPoints.${key}.factoryAddress is required`);
410
+ }
411
+ if (!ep.validatorAddress) {
412
+ throw new Error(`ServerConfig: entryPoints.${key}.validatorAddress is required`);
413
+ }
414
+ }
415
+ }
416
+ if (!config.storage) {
417
+ throw new Error("ServerConfig: storage adapter is required");
418
+ }
419
+ if (!config.signer) {
420
+ throw new Error("ServerConfig: signer adapter is required");
421
+ }
422
+ }
423
+
424
+ // ../airaccount/src/server/interfaces/logger.ts
425
+ var ConsoleLogger = class {
426
+ constructor(prefix = "[YAAA]") {
427
+ this.prefix = prefix;
428
+ }
429
+ debug(message, ...args) {
430
+ console.debug(`${this.prefix} ${message}`, ...args);
431
+ }
432
+ log(message, ...args) {
433
+ console.log(`${this.prefix} ${message}`, ...args);
434
+ }
435
+ warn(message, ...args) {
436
+ console.warn(`${this.prefix} ${message}`, ...args);
437
+ }
438
+ error(message, ...args) {
439
+ console.error(`${this.prefix} ${message}`, ...args);
440
+ }
441
+ };
442
+ var SilentLogger = class {
443
+ debug() {
444
+ }
445
+ log() {
446
+ }
447
+ warn() {
448
+ }
449
+ error() {
450
+ }
451
+ };
452
+ var EthereumProvider = class {
453
+ /** Main-network read client. Pass to viem getContract / readContract calls. */
454
+ provider;
455
+ /** Bundler client — used only for raw eth_ / pimlico_ userOp JSON-RPC. */
456
+ bundlerProvider;
457
+ config;
458
+ logger;
459
+ constructor(config) {
460
+ this.config = config;
461
+ this.logger = config.logger ?? new ConsoleLogger("[EthereumProvider]");
462
+ this.provider = viem.createPublicClient({ transport: viem.http(config.rpcUrl) });
463
+ this.bundlerProvider = viem.createPublicClient({ transport: viem.http(config.bundlerRpcUrl) });
464
+ }
465
+ /** Returns the viem PublicClient for the main network RPC. */
466
+ getProvider() {
467
+ return this.provider;
468
+ }
469
+ /** Returns the viem PublicClient bound to the bundler RPC (raw .request only). */
470
+ getBundlerProvider() {
471
+ return this.bundlerProvider;
472
+ }
473
+ /**
474
+ * Raw bundler JSON-RPC call. The bundler exposes non-standard methods
475
+ * (eth_sendUserOperation, pimlico_getUserOperationGasPrice, ...) that are not in
476
+ * viem's typed RPC schema, so we go through the transport's request fn untyped.
477
+ */
478
+ async bundlerRequest(method, params) {
479
+ return await this.bundlerProvider.request({
480
+ method,
481
+ params
482
+ });
483
+ }
484
+ // ── Config helpers ──────────────────────────────────────────────
485
+ getVersionConfig(version) {
486
+ const map = {
487
+ ["0.6" /* V0_6 */]: this.config.entryPoints.v06,
488
+ ["0.7" /* V0_7 */]: this.config.entryPoints.v07,
489
+ ["0.8" /* V0_8 */]: this.config.entryPoints.v08
490
+ };
491
+ const versionConfig = map[version];
492
+ if (!versionConfig) {
493
+ throw new Error(`EntryPoint version ${version} is not configured`);
494
+ }
495
+ return versionConfig;
496
+ }
497
+ getEntryPointAddress(version) {
498
+ return this.getVersionConfig(version).entryPointAddress;
499
+ }
500
+ getFactoryAddress(version) {
501
+ return this.getVersionConfig(version).factoryAddress;
502
+ }
503
+ getValidatorAddress(version) {
504
+ return this.getVersionConfig(version).validatorAddress;
505
+ }
506
+ getDefaultVersion() {
507
+ const v = this.config.defaultVersion;
508
+ if (v === "0.7") return "0.7" /* V0_7 */;
509
+ if (v === "0.8") return "0.8" /* V0_8 */;
510
+ return "0.6" /* V0_6 */;
511
+ }
512
+ // ── Contract factories ──────────────────────────────────────────
513
+ /** Build a read-only viem contract bound to the main-network PublicClient. */
514
+ contractAt(address, abi) {
515
+ return viem.getContract({
516
+ address,
517
+ abi: viem.parseAbi(abi),
518
+ client: this.provider
519
+ });
520
+ }
521
+ getFactoryContract(version = "0.6" /* V0_6 */) {
522
+ const address = this.getFactoryAddress(version);
523
+ const abi = version === "0.6" /* V0_6 */ ? FACTORY_ABI_V6 : AIRACCOUNT_FACTORY_ABI;
524
+ return this.contractAt(address, abi);
525
+ }
526
+ getEntryPointContract(version = "0.6" /* V0_6 */) {
527
+ const address = this.getEntryPointAddress(version);
528
+ const abi = version === "0.6" /* V0_6 */ ? ENTRYPOINT_ABI_V6 : ENTRYPOINT_ABI_V7_V8;
529
+ return this.contractAt(address, abi);
530
+ }
531
+ getValidatorContract(version = "0.6" /* V0_6 */) {
532
+ const address = this.getValidatorAddress(version);
533
+ return this.contractAt(address, VALIDATOR_ABI);
534
+ }
535
+ getAccountContract(address) {
536
+ return this.contractAt(address, AIRACCOUNT_ABI);
537
+ }
538
+ // ── M7 Module contracts ─────────────────────────────────────────
539
+ // M7 r4 module helpers — addresses renamed to *M7r4 suffix in beta.3 to avoid ambiguity.
540
+ // These methods are retained for backwards compatibility; callers should pass an explicit address.
541
+ getAgentSessionKeyValidatorContract(address = AIRACCOUNT_ADDRESSES.sepolia.agentSessionKeyValidatorM7r4) {
542
+ return this.contractAt(address, AGENT_SESSION_KEY_VALIDATOR_ABI);
543
+ }
544
+ getTierGuardHookContract(address = AIRACCOUNT_ADDRESSES.sepolia.tierGuardHookM7r4) {
545
+ return this.contractAt(address, TIER_GUARD_HOOK_ABI);
546
+ }
547
+ getCompositeValidatorContract(address = AIRACCOUNT_ADDRESSES.sepolia.compositeValidatorM7r4) {
548
+ return this.contractAt(address, AIR_ACCOUNT_COMPOSITE_VALIDATOR_ABI);
549
+ }
550
+ getForceExitModuleContract(address) {
551
+ return this.contractAt(address, FORCE_EXIT_MODULE_ABI);
552
+ }
553
+ // ── On-chain queries ────────────────────────────────────────────
554
+ async getBalance(address) {
555
+ const balance = await this.provider.getBalance({ address });
556
+ return viem.formatEther(balance);
557
+ }
558
+ async getNonce(accountAddress, key = 0, version = "0.6" /* V0_6 */) {
559
+ const entryPoint = this.getEntryPointContract(version);
560
+ return await entryPoint.read.getNonce([
561
+ accountAddress,
562
+ BigInt(key)
563
+ ]);
564
+ }
565
+ async getUserOpHash(userOp, version = "0.6" /* V0_6 */) {
566
+ const entryPoint = this.getEntryPointContract(version);
567
+ const read = entryPoint.read;
568
+ if (version === "0.6" /* V0_6 */) {
569
+ const op = userOp;
570
+ const userOpArray = [
571
+ op.sender,
572
+ BigInt(op.nonce),
573
+ op.initCode || "0x",
574
+ op.callData,
575
+ BigInt(op.callGasLimit),
576
+ BigInt(op.verificationGasLimit),
577
+ BigInt(op.preVerificationGas),
578
+ BigInt(op.maxFeePerGas),
579
+ BigInt(op.maxPriorityFeePerGas),
580
+ op.paymasterAndData || "0x",
581
+ "0x"
582
+ // Always use empty signature for hash calculation
583
+ ];
584
+ return await read.getUserOpHash([userOpArray]);
585
+ } else {
586
+ const packedOp = userOp;
587
+ const packedOpArray = [
588
+ packedOp.sender,
589
+ BigInt(packedOp.nonce),
590
+ packedOp.initCode || "0x",
591
+ packedOp.callData,
592
+ packedOp.accountGasLimits,
593
+ BigInt(packedOp.preVerificationGas),
594
+ packedOp.gasFees,
595
+ packedOp.paymasterAndData || "0x",
596
+ "0x"
597
+ ];
598
+ return await read.getUserOpHash([packedOpArray]);
599
+ }
600
+ }
601
+ // ── Bundler RPC ─────────────────────────────────────────────────
602
+ async estimateUserOperationGas(userOp, version = "0.6" /* V0_6 */) {
603
+ try {
604
+ return await this.bundlerRequest("eth_estimateUserOperationGas", [
605
+ userOp,
606
+ this.getEntryPointAddress(version)
607
+ ]);
608
+ } catch {
609
+ return {
610
+ callGasLimit: "0x249f0",
611
+ verificationGasLimit: "0x3d0900",
612
+ // 4M — enough for M4 factory deployment + BLS verification
613
+ preVerificationGas: "0x11170"
614
+ };
615
+ }
616
+ }
617
+ async sendUserOperation(userOp, version = "0.6" /* V0_6 */) {
618
+ return await this.bundlerRequest("eth_sendUserOperation", [
619
+ userOp,
620
+ this.getEntryPointAddress(version)
621
+ ]);
622
+ }
623
+ async getUserOperationReceipt(userOpHash) {
624
+ return await this.bundlerRequest("eth_getUserOperationReceipt", [userOpHash]);
625
+ }
626
+ async waitForUserOp(userOpHash, maxAttempts = 60) {
627
+ const pollInterval = 2e3;
628
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
629
+ try {
630
+ const receipt = await this.getUserOperationReceipt(userOpHash);
631
+ if (receipt) {
632
+ const txHash = receipt.transactionHash || receipt.receipt?.transactionHash;
633
+ if (txHash) return txHash;
634
+ }
635
+ } catch {
636
+ }
637
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
638
+ }
639
+ throw new Error(`UserOp timeout: ${userOpHash}`);
640
+ }
641
+ async getUserOperationGasPrice() {
642
+ try {
643
+ const gasPrice = await this.bundlerRequest("pimlico_getUserOperationGasPrice", []);
644
+ return {
645
+ maxFeePerGas: gasPrice.fast.maxFeePerGas,
646
+ maxPriorityFeePerGas: gasPrice.fast.maxPriorityFeePerGas
647
+ };
648
+ } catch {
649
+ try {
650
+ const feeData = await this.provider.estimateFeesPerGas();
651
+ const baseFee = feeData.maxFeePerGas || viem.parseUnits("20", 9);
652
+ const priorityFee = feeData.maxPriorityFeePerGas || viem.parseUnits("2", 9);
653
+ const maxFeePerGas = baseFee * 3n / 2n;
654
+ const maxPriorityFeePerGas = priorityFee * 3n / 2n;
655
+ return {
656
+ maxFeePerGas: "0x" + maxFeePerGas.toString(16),
657
+ maxPriorityFeePerGas: "0x" + maxPriorityFeePerGas.toString(16)
658
+ };
659
+ } catch {
660
+ return {
661
+ maxFeePerGas: "0x" + viem.parseUnits("3", 9).toString(16),
662
+ // gwei
663
+ maxPriorityFeePerGas: "0x" + viem.parseUnits("1", 9).toString(16)
664
+ // gwei
665
+ };
666
+ }
667
+ }
668
+ }
669
+ };
670
+
671
+ // ../airaccount/src/server/providers/typed-reads.ts
672
+ function readFn(contract, name) {
673
+ return contract.read[name];
674
+ }
675
+ function readValidatorGasEstimate(validator, nodeCount) {
676
+ return readFn(validator, "getGasEstimate")([nodeCount]);
677
+ }
678
+ function readPredictedAddress(factory, owner, salt, config) {
679
+ return readFn(factory, "getAddress")([owner, salt, config]);
680
+ }
681
+ function readPredictedAddressWithDefaults(factory, owner, salt, guardian1, guardian2, dailyLimit) {
682
+ return readFn(factory, "getAddressWithDefaults")([
683
+ owner,
684
+ salt,
685
+ guardian1,
686
+ guardian2,
687
+ dailyLimit
688
+ ]);
689
+ }
690
+ async function readAccountTierLimits(account) {
691
+ const [tier1Limit, tier2Limit] = await Promise.all([
692
+ readFn(account, "tier1Limit")([]),
693
+ readFn(account, "tier2Limit")([])
694
+ ]);
695
+ return { tier1Limit, tier2Limit };
696
+ }
697
+ function readAlgorithmApproved(account, algId) {
698
+ return readFn(account, "approvedAlgorithms")([algId]);
699
+ }
700
+ async function readAccountGuardAddress(account) {
701
+ const config = await readFn(account, "getConfigDescription")([]);
702
+ return config.guardAddress;
703
+ }
704
+ async function readGuardDailyAllowance(guard) {
705
+ const [dailyLimit, dailyRemaining] = await Promise.all([
706
+ readFn(guard, "dailyLimit")([]),
707
+ readFn(guard, "remainingDailyAllowance")([])
708
+ ]);
709
+ return { dailyLimit, dailyRemaining };
710
+ }
711
+ function readBuildGrantHash(validator, account, sessionKey, cfg) {
712
+ return readFn(validator, "buildGrantHash")([account, sessionKey, cfg]);
713
+ }
714
+ function readBuildP256GrantHash(validator, account, keyX, keyY, cfg) {
715
+ return readFn(validator, "buildP256GrantHash")([account, keyX, keyY, cfg]);
716
+ }
717
+
718
+ // ../airaccount/src/server/services/account-manager.ts
719
+ var ZERO32 = "0x" + "0".repeat(64);
720
+ var EMPTY_P256 = [ZERO32, ZERO32, ZERO32];
721
+ var AccountManager = class {
722
+ constructor(ethereum, storage, signer, logger) {
723
+ this.ethereum = ethereum;
724
+ this.storage = storage;
725
+ this.signer = signer;
726
+ this.logger = logger ?? new ConsoleLogger("[AccountManager]");
727
+ }
728
+ logger;
729
+ async createAccount(userId, options) {
730
+ const version = options?.entryPointVersion ?? this.ethereum.getDefaultVersion();
731
+ const versionStr = version;
732
+ const existingAccounts = await this.storage.getAccounts();
733
+ const existing = existingAccounts.find(
734
+ (a) => a.userId === userId && a.entryPointVersion === versionStr
735
+ );
736
+ if (existing) return existing;
737
+ const factory = this.ethereum.getFactoryContract(version);
738
+ const validatorAddress = this.ethereum.getValidatorContract(version).address || this.ethereum.getValidatorAddress(version);
739
+ const { address: signerAddress } = await this.signer.ensureSigner(userId);
740
+ const salt = options?.salt ?? Math.floor(Math.random() * 1e6);
741
+ const dailyLimitValue = options?.dailyLimit ?? 0n;
742
+ const minimalConfig = [
743
+ [viem.zeroAddress, viem.zeroAddress, viem.zeroAddress],
744
+ // guardians (address[3])
745
+ EMPTY_P256,
746
+ // guardianP256X (bytes32[3]) — v0.20.0
747
+ EMPTY_P256,
748
+ // guardianP256Y (bytes32[3]) — v0.20.0
749
+ dailyLimitValue,
750
+ // dailyLimit (0 = no guard)
751
+ [],
752
+ // approvedAlgIds
753
+ 0n,
754
+ // minDailyLimit
755
+ [],
756
+ // initialTokens
757
+ []
758
+ // initialTokenConfigs
759
+ ];
760
+ const accountAddress = await readPredictedAddress(
761
+ factory,
762
+ signerAddress,
763
+ BigInt(salt),
764
+ minimalConfig
765
+ );
766
+ let deployed = false;
767
+ try {
768
+ const code = await this.ethereum.getProvider().getCode({ address: accountAddress });
769
+ deployed = !!code && code !== "0x";
770
+ } catch {
771
+ }
772
+ const account = {
773
+ userId,
774
+ address: accountAddress,
775
+ signerAddress,
776
+ salt,
777
+ deployed,
778
+ deploymentTxHash: null,
779
+ validatorAddress,
780
+ entryPointVersion: versionStr,
781
+ factoryAddress: factory.address || this.ethereum.getFactoryAddress(version),
782
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
783
+ // Persist dailyLimit so buildUserOperation can reconstruct identical initCode at deploy time.
784
+ ...dailyLimitValue > 0n ? { dailyLimit: dailyLimitValue.toString() } : {}
785
+ };
786
+ await this.storage.saveAccount(account);
787
+ return account;
788
+ }
789
+ async getAccount(userId) {
790
+ const account = await this.storage.findAccountByUserId(userId);
791
+ if (!account) return null;
792
+ let balance = "0";
793
+ try {
794
+ balance = await this.ethereum.getBalance(account.address);
795
+ } catch {
796
+ }
797
+ const version = account.entryPointVersion || "0.6";
798
+ const nonce = await this.ethereum.getNonce(account.address, 0, version);
799
+ return { ...account, balance, nonce: nonce.toString() };
800
+ }
801
+ async getAccountAddress(userId) {
802
+ const account = await this.storage.findAccountByUserId(userId);
803
+ if (!account) throw new Error("Account not found");
804
+ return account.address;
805
+ }
806
+ async getAccountBalance(userId) {
807
+ const account = await this.storage.findAccountByUserId(userId);
808
+ if (!account) throw new Error("Account not found");
809
+ const balance = await this.ethereum.getBalance(account.address);
810
+ return {
811
+ address: account.address,
812
+ balance,
813
+ balanceInWei: viem.parseEther(balance).toString()
814
+ };
815
+ }
816
+ async getAccountNonce(userId) {
817
+ const account = await this.storage.findAccountByUserId(userId);
818
+ if (!account) throw new Error("Account not found");
819
+ const nonce = await this.ethereum.getNonce(account.address);
820
+ return { address: account.address, nonce: nonce.toString() };
821
+ }
822
+ async getAccountByUserId(userId) {
823
+ return this.storage.findAccountByUserId(userId);
824
+ }
825
+ /**
826
+ * Build the acceptance hash that guardian devices must sign before account creation.
827
+ *
828
+ * Encoding: keccak256(solidityPacked(
829
+ * ["string","uint256","address","address","uint256","uint256"],
830
+ * ["ACCEPT_GUARDIAN", chainId, factoryAddress, owner, salt, dailyLimit]
831
+ * ))
832
+ *
833
+ * dailyLimit is bound in the hash (PR #47 / C-3) to prevent a front-runner from
834
+ * replaying guardian sigs with a weaker limit on the same counterfactual address.
835
+ *
836
+ * Returns the RAW keccak256 hash (no EIP-191 prefix).
837
+ * Guardians MUST sign via personal_sign / ethers.signMessage(ethers.getBytes(hash)).
838
+ * Do NOT use eth_sign — the EIP-191 "\x19Ethereum Signed Message:\n32" prefix
839
+ * is applied inside the contract (toEthSignedMessageHash) before ecrecover, not here.
840
+ *
841
+ * @returns raw hex keccak256 hash — encode this into the QR code shown to guardian devices
842
+ */
843
+ buildGuardianAcceptanceHash(owner, salt, factoryAddress, chainId, dailyLimit) {
844
+ if (typeof salt === "number" && !Number.isSafeInteger(salt)) {
845
+ throw new Error(
846
+ `salt value ${salt} exceeds Number.MAX_SAFE_INTEGER; pass as bigint to avoid precision loss`
847
+ );
848
+ }
849
+ return chunkXQROKLZI_cjs.keccak256(
850
+ chunkXQROKLZI_cjs.solidityPacked(
851
+ ["string", "uint256", "address", "address", "uint256", "uint256"],
852
+ ["ACCEPT_GUARDIAN", BigInt(chainId), factoryAddress, owner, BigInt(salt), dailyLimit]
853
+ )
854
+ );
855
+ }
856
+ /**
857
+ * Encode calldata for modifyTierLimitsWithGuardians() — guardian-gated tier-limit change (PR #43).
858
+ *
859
+ * Both tier1 and tier2 can be raised or lowered, subject to guardian approval.
860
+ * Caller is responsible for building and submitting the resulting UserOp.
861
+ *
862
+ * @param tier1 New Tier-1 ceiling in wei (ECDSA-only spending; 0 = no limit)
863
+ * @param tier2 New Tier-2 ceiling in wei (dual-factor; 0 = no limit)
864
+ * @param deadline Unix timestamp — guardian sigs rejected after this
865
+ * @param guardianSigs 65-byte EIP-191 hex signatures from required guardians
866
+ */
867
+ encodeModifyTierLimits(tier1, tier2, deadline, guardianSigs) {
868
+ return viem.encodeFunctionData({
869
+ abi: viem.parseAbi(AIRACCOUNT_ABI),
870
+ functionName: "modifyTierLimitsWithGuardians",
871
+ args: [tier1, tier2, deadline, guardianSigs]
872
+ });
873
+ }
874
+ /**
875
+ * Create an AirAccount with 3 on-chain guardians:
876
+ * - guardian1 and guardian2: user's own devices (passkeys on phone 1 and phone 2)
877
+ * - guardian3: team Safe multisig (defaultCommunityGuardian, set in factory at deploy time)
878
+ *
879
+ * Both guardian1 and guardian2 must sign the acceptance hash produced by
880
+ * buildGuardianAcceptanceHash() before this method is called.
881
+ *
882
+ * Recovery: any 2-of-3 guardians can initiate social recovery after a 48h timelock.
883
+ */
884
+ async createAccountWithGuardians(userId, params) {
885
+ if (params.guardian1.toLowerCase() === params.guardian2.toLowerCase()) {
886
+ throw new Error("guardian1 and guardian2 must be different addresses");
887
+ }
888
+ if (params.dailyLimit <= 0n) {
889
+ throw new Error("Guardian accounts require dailyLimit > 0 (on-chain enforcement)");
890
+ }
891
+ const version = params.entryPointVersion ?? this.ethereum.getDefaultVersion();
892
+ if (version === "0.6" /* V0_6 */) {
893
+ throw new Error(
894
+ "createAccountWithGuardians requires EntryPoint v0.7 or v0.8; v0.6 factory does not support getAddressWithDefaults"
895
+ );
896
+ }
897
+ const versionStr = version;
898
+ const existingAccounts = await this.storage.getAccounts();
899
+ const existing = existingAccounts.find(
900
+ (a) => a.userId === userId && a.entryPointVersion === versionStr && a.guardian1
901
+ );
902
+ if (existing) return existing;
903
+ const { address: signerAddress } = await this.signer.ensureSigner(userId);
904
+ const salt = params.salt ?? Math.floor(Math.random() * 1e6);
905
+ const factory = this.ethereum.getFactoryContract(version);
906
+ const factoryAddress = factory.address ?? this.ethereum.getFactoryAddress(version);
907
+ const accountAddress = await readPredictedAddressWithDefaults(
908
+ factory,
909
+ signerAddress,
910
+ BigInt(salt),
911
+ params.guardian1,
912
+ params.guardian2,
913
+ params.dailyLimit
914
+ );
915
+ let deployed = false;
916
+ try {
917
+ const code = await this.ethereum.getProvider().getCode({ address: accountAddress });
918
+ deployed = !!code && code !== "0x";
919
+ } catch {
920
+ }
921
+ const validatorAddress = this.ethereum.getValidatorAddress(version);
922
+ const account = {
923
+ userId,
924
+ address: accountAddress,
925
+ signerAddress,
926
+ salt,
927
+ deployed,
928
+ deploymentTxHash: null,
929
+ validatorAddress,
930
+ entryPointVersion: versionStr,
931
+ factoryAddress,
932
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
933
+ // Persist dailyLimit so transfer-manager can reconstruct identical initCode at deploy time.
934
+ ...params.dailyLimit > 0n ? { dailyLimit: params.dailyLimit.toString() } : {},
935
+ // Persist guardian addresses and sigs so transfer-manager can use createAccountWithDefaults
936
+ // to reconstruct the correct initCode on first UserOp deployment.
937
+ guardian1: params.guardian1,
938
+ guardian1Sig: params.guardian1Sig,
939
+ guardian2: params.guardian2,
940
+ guardian2Sig: params.guardian2Sig
941
+ };
942
+ await this.storage.saveAccount(account);
943
+ this.logger.log(`[AccountManager] account created with guardians: ${accountAddress}`);
944
+ return account;
945
+ }
946
+ };
947
+ var EXECUTE_USER_OP_SELECTOR = chunkXQROKLZI_cjs.selectorFromId(
948
+ "executeUserOp((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes),bytes32)"
949
+ );
950
+ var EXECUTE_SELECTOR = chunkXQROKLZI_cjs.selectorFromId("execute(address,uint256,bytes)");
951
+ var EXECUTE_BATCH_SELECTOR = chunkXQROKLZI_cjs.selectorFromId(
952
+ "executeBatch(address[],uint256[],bytes[])"
953
+ );
954
+ function wrapExecuteUserOp(innerCallData) {
955
+ if (!/^0x[0-9a-fA-F]*$/.test(innerCallData) || innerCallData.length < 10) {
956
+ throw new Error("wrapExecuteUserOp: innerCallData must be 0x-prefixed calldata with a 4-byte selector");
957
+ }
958
+ const sel = innerCallData.slice(0, 10).toLowerCase();
959
+ if (sel !== EXECUTE_SELECTOR && sel !== EXECUTE_BATCH_SELECTOR) {
960
+ throw new Error(
961
+ `wrapExecuteUserOp: only execute()/executeBatch() may be wrapped (got selector ${sel}); the account reverts UnsupportedInnerSelector otherwise`
962
+ );
963
+ }
964
+ return viem.concat([EXECUTE_USER_OP_SELECTOR, innerCallData]);
965
+ }
966
+ function isExecuteUserOpWrapped(callData) {
967
+ return callData.slice(0, 10).toLowerCase() === EXECUTE_USER_OP_SELECTOR;
968
+ }
969
+ var PaymasterPriceStalenessError = class extends Error {
970
+ constructor(paymasterAddress, ageSeconds, thresholdSeconds) {
971
+ super(
972
+ `Paymaster ${paymasterAddress} price is stale (age: ${Math.floor(ageSeconds / 60)}min, threshold: ${Math.floor(thresholdSeconds / 60)}min). Call updatePrice() on the paymaster contract before retrying.`
973
+ );
974
+ this.paymasterAddress = paymasterAddress;
975
+ this.ageSeconds = ageSeconds;
976
+ this.thresholdSeconds = thresholdSeconds;
977
+ this.name = "PaymasterPriceStalenessError";
978
+ }
979
+ };
980
+ var PAYMASTER_PRICE_ABI = viem.parseAbi([
981
+ "function token() view returns (address)",
982
+ "function cachedPriceTimestamp() view returns (uint256)",
983
+ "function priceStalenessThreshold() view returns (uint256)",
984
+ "function updatePrice() external"
985
+ ]);
986
+ var SUPER_PAYMASTER_DETECT_ABI = viem.parseAbi([
987
+ "function owner() view returns (address)",
988
+ "function operators(address) view returns (bool,uint256,address,uint256)"
989
+ ]);
990
+ var PaymasterManager = class {
991
+ constructor(ethereum, storage, logger) {
992
+ this.ethereum = ethereum;
993
+ this.storage = storage;
994
+ this.logger = logger ?? new ConsoleLogger("[PaymasterManager]");
995
+ }
996
+ logger;
997
+ async getAvailablePaymasters(userId) {
998
+ const paymasters = await this.storage.getPaymasters(userId);
999
+ return paymasters.map((config) => ({
1000
+ name: config.name,
1001
+ address: config.address,
1002
+ configured: !!config.address && config.address !== "0x"
1003
+ }));
1004
+ }
1005
+ async addCustomPaymaster(userId, name, address, type = "custom", apiKey, endpoint) {
1006
+ const paymaster = {
1007
+ id: `${userId}-${name}-${Date.now()}`,
1008
+ name,
1009
+ address,
1010
+ type,
1011
+ apiKey,
1012
+ endpoint,
1013
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1014
+ };
1015
+ await this.storage.savePaymaster(userId, paymaster);
1016
+ }
1017
+ async removeCustomPaymaster(userId, name) {
1018
+ return this.storage.removePaymaster(userId, name);
1019
+ }
1020
+ /**
1021
+ * Check whether a paymaster's on-chain price cache is still fresh.
1022
+ * Returns `{ fresh, ageSeconds, thresholdSeconds }`.
1023
+ * Throws if the contract does not implement `cachedPriceTimestamp()` / `priceStalenessThreshold()`.
1024
+ */
1025
+ async checkPriceFreshness(paymasterAddress) {
1026
+ const provider = this.ethereum.getProvider();
1027
+ const contract = viem.getContract({
1028
+ address: paymasterAddress,
1029
+ abi: PAYMASTER_PRICE_ABI,
1030
+ client: provider
1031
+ });
1032
+ const [timestamp, threshold] = await Promise.all([
1033
+ contract.read.cachedPriceTimestamp(),
1034
+ contract.read.priceStalenessThreshold()
1035
+ ]);
1036
+ const nowSeconds = Math.floor(Date.now() / 1e3);
1037
+ const ageSeconds = nowSeconds - Number(timestamp);
1038
+ const thresholdSeconds = Number(threshold);
1039
+ return {
1040
+ fresh: ageSeconds <= thresholdSeconds,
1041
+ ageSeconds,
1042
+ thresholdSeconds
1043
+ };
1044
+ }
1045
+ /**
1046
+ * Call `updatePrice()` on a paymaster contract (permissionless).
1047
+ * Useful when `checkPriceFreshness()` reports stale price.
1048
+ *
1049
+ * @param walletClient - A viem WalletClient (with an account) that will send
1050
+ * the transaction (must have gas). Replaces the former ethers Signer param.
1051
+ */
1052
+ async updatePrice(paymasterAddress, walletClient) {
1053
+ const account = walletClient.account;
1054
+ if (!account) {
1055
+ throw new Error("updatePrice requires a WalletClient with a configured account");
1056
+ }
1057
+ const hash = await walletClient.writeContract({
1058
+ address: paymasterAddress,
1059
+ abi: PAYMASTER_PRICE_ABI,
1060
+ functionName: "updatePrice",
1061
+ args: [],
1062
+ gas: BigInt(3e5),
1063
+ account,
1064
+ chain: walletClient.chain
1065
+ });
1066
+ await this.ethereum.getProvider().waitForTransactionReceipt({ hash });
1067
+ this.logger.log(`Paymaster ${paymasterAddress} price updated, tx: ${hash}`);
1068
+ return hash;
1069
+ }
1070
+ async getPaymasterData(userId, paymasterName, userOp, entryPoint, customAddress, options) {
1071
+ if (paymasterName === "custom-user-provided" && customAddress) {
1072
+ const formattedAddress = customAddress.toLowerCase().startsWith("0x") ? customAddress : `0x${customAddress}`;
1073
+ if (!/^0x[a-fA-F0-9]{40}$/.test(formattedAddress)) {
1074
+ throw new Error(`Invalid paymaster address format: ${customAddress}`);
1075
+ }
1076
+ const isV07OrV08 = entryPoint.toLowerCase() === "0x0000000071727De22E5E9d8BAf0edAc6f37da032".toLowerCase() || entryPoint.toLowerCase() === "0x0576a174D229E3cFA37253523E645A78A0C91B57".toLowerCase();
1077
+ if (isV07OrV08) {
1078
+ const provider = this.ethereum.getProvider();
1079
+ let isSuperPaymaster = false;
1080
+ let operatorAddress = "0x";
1081
+ try {
1082
+ const spContract = viem.getContract({
1083
+ address: formattedAddress,
1084
+ abi: SUPER_PAYMASTER_DETECT_ABI,
1085
+ client: provider
1086
+ });
1087
+ const owner = await spContract.read.owner();
1088
+ const opInfo = await spContract.read.operators([owner]);
1089
+ if (opInfo && opInfo[0] === true) {
1090
+ isSuperPaymaster = true;
1091
+ operatorAddress = owner;
1092
+ this.logger.log(`SuperPaymaster detected, operator: ${operatorAddress}`);
1093
+ }
1094
+ } catch {
1095
+ }
1096
+ if (isSuperPaymaster) {
1097
+ const verGas = BigInt(8e4);
1098
+ const postGas = BigInt(3e5);
1099
+ const maxRate = (BigInt(1) << BigInt(256)) - BigInt(1);
1100
+ return viem.concat([
1101
+ formattedAddress,
1102
+ viem.numberToHex(verGas, { size: 16 }),
1103
+ viem.numberToHex(postGas, { size: 16 }),
1104
+ operatorAddress,
1105
+ viem.numberToHex(maxRate, { size: 32 })
1106
+ ]);
1107
+ }
1108
+ const paymasterVerificationGasLimit = BigInt(196608);
1109
+ const paymasterPostOpGasLimit = BigInt(196608);
1110
+ let tokenAddress = options?.tokenAddress ?? null;
1111
+ if (tokenAddress) {
1112
+ this.logger.log(`PaymasterV4 token from options: ${tokenAddress}`);
1113
+ } else {
1114
+ try {
1115
+ const pmContract = viem.getContract({
1116
+ address: formattedAddress,
1117
+ abi: PAYMASTER_PRICE_ABI,
1118
+ client: provider
1119
+ });
1120
+ tokenAddress = await pmContract.read.token();
1121
+ if (tokenAddress === viem.zeroAddress) tokenAddress = null;
1122
+ if (tokenAddress) {
1123
+ this.logger.log(`PaymasterV4 token auto-detected: ${tokenAddress}`);
1124
+ }
1125
+ } catch {
1126
+ this.logger.log(`PaymasterV4 token() not available, paymasterData will have no token`);
1127
+ }
1128
+ }
1129
+ const parts = [
1130
+ formattedAddress,
1131
+ viem.numberToHex(paymasterVerificationGasLimit, { size: 16 }),
1132
+ viem.numberToHex(paymasterPostOpGasLimit, { size: 16 })
1133
+ ];
1134
+ if (tokenAddress) {
1135
+ parts.push(tokenAddress);
1136
+ }
1137
+ return viem.concat(parts);
1138
+ }
1139
+ return formattedAddress;
1140
+ }
1141
+ const paymasters = await this.storage.getPaymasters(userId);
1142
+ const config = paymasters.find((p) => p.name === paymasterName);
1143
+ if (!config) {
1144
+ throw new Error(`Paymaster ${paymasterName} not found`);
1145
+ }
1146
+ switch (config.type) {
1147
+ case "pimlico":
1148
+ if (!config.apiKey) return "0x";
1149
+ return this.getPimlicoPaymasterData(config, userOp, entryPoint);
1150
+ case "stackup":
1151
+ if (!config.apiKey) return "0x";
1152
+ return this.getStackUpPaymasterData(config, userOp, entryPoint);
1153
+ case "alchemy":
1154
+ if (!config.apiKey) return "0x";
1155
+ return this.getAlchemyPaymasterData(config, userOp, entryPoint);
1156
+ case "custom":
1157
+ if (config.address.toLowerCase() === "0x0000000000325602a77416A16136FDafd04b299f".toLowerCase() && config.apiKey) {
1158
+ return this.getPimlicoPaymasterData(
1159
+ { ...config, type: "pimlico", endpoint: "https://api.pimlico.io/v2/11155111/rpc" },
1160
+ userOp,
1161
+ entryPoint
1162
+ );
1163
+ }
1164
+ return config.address;
1165
+ default:
1166
+ return "0x";
1167
+ }
1168
+ }
1169
+ async getPimlicoPaymasterData(config, userOp, entryPoint) {
1170
+ const url = `${config.endpoint}?apikey=${config.apiKey}`;
1171
+ const response = await globalThis.fetch(url, {
1172
+ method: "POST",
1173
+ headers: { "Content-Type": "application/json" },
1174
+ body: JSON.stringify({
1175
+ jsonrpc: "2.0",
1176
+ method: "pm_sponsorUserOperation",
1177
+ params: [userOp, entryPoint, {}],
1178
+ id: 1
1179
+ })
1180
+ });
1181
+ const result = await response.json();
1182
+ if (result.error) {
1183
+ throw new Error(
1184
+ `Pimlico sponsorship failed: ${result.error.message || JSON.stringify(result.error)}`
1185
+ );
1186
+ }
1187
+ if (result.result) {
1188
+ if (result.result.paymasterAndData) {
1189
+ return result.result.paymasterAndData;
1190
+ }
1191
+ if (result.result.paymaster) {
1192
+ return viem.concat([
1193
+ result.result.paymaster,
1194
+ viem.numberToHex(BigInt(result.result.paymasterVerificationGasLimit || "0x30000"), {
1195
+ size: 16
1196
+ }),
1197
+ viem.numberToHex(BigInt(result.result.paymasterPostOpGasLimit || "0x30000"), { size: 16 }),
1198
+ result.result.paymasterData || "0x"
1199
+ ]);
1200
+ }
1201
+ }
1202
+ throw new Error("Pimlico API did not return valid paymaster data");
1203
+ }
1204
+ async getStackUpPaymasterData(config, userOp, entryPoint) {
1205
+ try {
1206
+ const response = await globalThis.fetch(`${config.endpoint}/${config.apiKey}`, {
1207
+ method: "POST",
1208
+ headers: { "Content-Type": "application/json" },
1209
+ body: JSON.stringify({
1210
+ jsonrpc: "2.0",
1211
+ method: "pm_sponsorUserOperation",
1212
+ params: { userOperation: userOp, entryPoint, context: { type: "payg" } },
1213
+ id: 1
1214
+ })
1215
+ });
1216
+ const result = await response.json();
1217
+ if (result.error) return "0x";
1218
+ return result.result || "0x";
1219
+ } catch {
1220
+ return "0x";
1221
+ }
1222
+ }
1223
+ async getAlchemyPaymasterData(config, userOp, entryPoint) {
1224
+ try {
1225
+ const response = await globalThis.fetch(`${config.endpoint}/${config.apiKey}`, {
1226
+ method: "POST",
1227
+ headers: { "Content-Type": "application/json" },
1228
+ body: JSON.stringify({
1229
+ jsonrpc: "2.0",
1230
+ method: "alchemy_requestGasAndPaymasterAndData",
1231
+ params: [{ policyId: "default", entryPoint, userOperation: userOp }],
1232
+ id: 1
1233
+ })
1234
+ });
1235
+ const result = await response.json();
1236
+ if (result.error) return "0x";
1237
+ return result.result?.paymasterAndData || "0x";
1238
+ } catch {
1239
+ return "0x";
1240
+ }
1241
+ }
1242
+ };
1243
+
1244
+ // ../airaccount/src/server/services/transfer-manager.ts
1245
+ var ZERO322 = "0x" + "0".repeat(64);
1246
+ var EMPTY_P2562 = [ZERO322, ZERO322, ZERO322];
1247
+ var AIRACCOUNT_ABI_PARSED = viem.parseAbi(AIRACCOUNT_ABI);
1248
+ var AIRACCOUNT_FACTORY_ABI_PARSED = viem.parseAbi(AIRACCOUNT_FACTORY_ABI);
1249
+ var FACTORY_ABI_V6_PARSED = viem.parseAbi(FACTORY_ABI_V6);
1250
+ var VALIDATOR_GETTER_ABI = viem.parseAbi(["function validator() view returns (address)"]);
1251
+ function encodeFn(abi, functionName, args) {
1252
+ return viem.encodeFunctionData({ abi, functionName, args });
1253
+ }
1254
+ async function detectSignatureStrategy(provider, accountAddress) {
1255
+ try {
1256
+ const accountCode = await provider.getCode({ address: accountAddress });
1257
+ if (!accountCode || accountCode === "0x") {
1258
+ return { useECDSA: true, isCompositeValidator: true };
1259
+ }
1260
+ const v = await provider.readContract({
1261
+ address: accountAddress,
1262
+ abi: VALIDATOR_GETTER_ABI,
1263
+ functionName: "validator"
1264
+ });
1265
+ return { useECDSA: v === viem.zeroAddress, isCompositeValidator: true };
1266
+ } catch {
1267
+ return { useECDSA: true, isCompositeValidator: false };
1268
+ }
1269
+ }
1270
+ function generateId() {
1271
+ const hex = () => Math.random().toString(16).slice(2, 10);
1272
+ return `${hex()}${hex()}-${hex()}-${hex()}-${hex()}-${hex()}${hex()}${hex()}`;
1273
+ }
1274
+ var TransferManager = class {
1275
+ constructor(ethereum, accountManager, blsService, paymasterManager, tokenService, storage, signer, logger, guardChecker) {
1276
+ this.ethereum = ethereum;
1277
+ this.accountManager = accountManager;
1278
+ this.blsService = blsService;
1279
+ this.paymasterManager = paymasterManager;
1280
+ this.tokenService = tokenService;
1281
+ this.storage = storage;
1282
+ this.signer = signer;
1283
+ this.logger = logger ?? new ConsoleLogger("[TransferManager]");
1284
+ this.guardChecker = guardChecker ?? null;
1285
+ }
1286
+ logger;
1287
+ guardChecker;
1288
+ async executeTransfer(userId, params) {
1289
+ const account = await this.accountManager.getAccountByUserId(userId);
1290
+ if (!account) throw new Error("User account not found");
1291
+ const code = await this.ethereum.getProvider().getCode({ address: account.address });
1292
+ const needsDeployment = !code || code === "0x";
1293
+ if (needsDeployment) {
1294
+ this.logger.log("Account needs deployment, will deploy with first transaction");
1295
+ }
1296
+ const smartAccountBalance = parseFloat(await this.ethereum.getBalance(account.address));
1297
+ const isTokenTransfer = !!params.tokenAddress;
1298
+ const transferAmount = isTokenTransfer ? 0 : parseFloat(params.amount);
1299
+ if (!params.usePaymaster) {
1300
+ const minRequiredBalance = 2e-4;
1301
+ const totalNeeded = transferAmount + minRequiredBalance;
1302
+ if (smartAccountBalance < totalNeeded) {
1303
+ throw new Error(
1304
+ `Insufficient balance: Account has ${smartAccountBalance} ETH but needs ${totalNeeded} ETH`
1305
+ );
1306
+ }
1307
+ } else if (!isTokenTransfer && transferAmount > smartAccountBalance) {
1308
+ throw new Error(
1309
+ `Insufficient balance: Account has ${smartAccountBalance} ETH but trying to send ${transferAmount} ETH`
1310
+ );
1311
+ }
1312
+ const version = account.entryPointVersion || "0.6";
1313
+ const userOp = await this.buildUserOperation(
1314
+ userId,
1315
+ account.address,
1316
+ params.to,
1317
+ params.amount,
1318
+ params.data || "0x",
1319
+ params.usePaymaster,
1320
+ params.paymasterAddress,
1321
+ params.paymasterData,
1322
+ params.tokenAddress,
1323
+ version,
1324
+ params.paymasterTokenAddress,
1325
+ params.wrapExecuteUserOp ?? false
1326
+ );
1327
+ const userOpHash = await this.ethereum.getUserOpHash(userOp, version);
1328
+ await this.signer.ensureSigner(userId);
1329
+ const assertionCtx = params.passkeyAssertion ? { assertion: params.passkeyAssertion } : void 0;
1330
+ let useECDSA = false;
1331
+ let isCompositeValidator = false;
1332
+ if (version === "0.7" /* V0_7 */ || version === "0.8" /* V0_8 */) {
1333
+ const provider = this.ethereum.getProvider();
1334
+ ({ useECDSA, isCompositeValidator } = await detectSignatureStrategy(
1335
+ provider,
1336
+ account.address
1337
+ ));
1338
+ }
1339
+ if (useECDSA) {
1340
+ const ecdsaSig = await this.signer.signMessage(
1341
+ userId,
1342
+ viem.hexToBytes(userOpHash),
1343
+ assertionCtx
1344
+ );
1345
+ if (isCompositeValidator) {
1346
+ this.logger.log("ECDSA path for compositeValidator: prepending algId prefix");
1347
+ userOp.signature = viem.concat([
1348
+ viem.numberToHex(ALG_ID.ECDSA, { size: 1 }),
1349
+ ecdsaSig
1350
+ ]);
1351
+ } else {
1352
+ this.logger.log("ECDSA path for non-compositeValidator: raw signature");
1353
+ userOp.signature = ecdsaSig;
1354
+ }
1355
+ } else if (params.useAirAccountTiering && this.guardChecker) {
1356
+ const transferValue = params.tokenAddress ? 0n : viem.parseEther(params.amount);
1357
+ const preCheck = await this.guardChecker.preCheck(account.address, transferValue);
1358
+ if (!preCheck.ok) {
1359
+ throw new Error(`Guard pre-check failed: ${preCheck.errors.join("; ")}`);
1360
+ }
1361
+ this.logger.log(
1362
+ `Tier ${preCheck.tier} selected (algId=0x${preCheck.algId.toString(16).padStart(2, "0")})`
1363
+ );
1364
+ userOp.signature = await this.blsService.generateTieredSignature({
1365
+ tier: preCheck.tier,
1366
+ userId,
1367
+ userOpHash,
1368
+ p256Signature: params.p256Signature,
1369
+ guardianSigner: params.guardianSigner,
1370
+ ctx: assertionCtx
1371
+ });
1372
+ } else {
1373
+ const blsData = await this.blsService.generateBLSSignature(userId, userOpHash, assertionCtx);
1374
+ const packedBls = await this.blsService.packSignature(blsData);
1375
+ userOp.signature = viem.concat([
1376
+ viem.numberToHex(ALG_ID.BLS, { size: 1 }),
1377
+ packedBls
1378
+ ]);
1379
+ }
1380
+ const transferId = generateId();
1381
+ let tokenSymbol = "ETH";
1382
+ if (params.tokenAddress) {
1383
+ try {
1384
+ const tokenInfo = await this.tokenService.getTokenInfo(params.tokenAddress);
1385
+ tokenSymbol = tokenInfo.symbol;
1386
+ } catch {
1387
+ tokenSymbol = `${params.tokenAddress.slice(0, 6)}...${params.tokenAddress.slice(-4)}`;
1388
+ }
1389
+ }
1390
+ await this.storage.saveTransfer({
1391
+ id: transferId,
1392
+ userId,
1393
+ from: account.address,
1394
+ to: params.to,
1395
+ amount: params.amount,
1396
+ data: params.data,
1397
+ userOpHash,
1398
+ status: "pending",
1399
+ nodeIndices: [],
1400
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1401
+ tokenAddress: params.tokenAddress,
1402
+ tokenSymbol
1403
+ });
1404
+ this.processTransferAsync(transferId, userOp, account.address, version);
1405
+ return {
1406
+ success: true,
1407
+ transferId,
1408
+ userOpHash,
1409
+ status: "pending",
1410
+ message: "Transfer submitted successfully. Use transferId to check status.",
1411
+ from: account.address,
1412
+ to: params.to,
1413
+ amount: params.amount
1414
+ };
1415
+ }
1416
+ async processTransferAsync(transferId, userOp, from, version) {
1417
+ try {
1418
+ const formatted = this.formatUserOpForBundler(userOp, version);
1419
+ const bundlerUserOpHash = await this.ethereum.sendUserOperation(formatted, version);
1420
+ await this.storage.updateTransfer(transferId, {
1421
+ bundlerUserOpHash,
1422
+ status: "submitted",
1423
+ submittedAt: (/* @__PURE__ */ new Date()).toISOString()
1424
+ });
1425
+ const txHash = await this.ethereum.waitForUserOp(bundlerUserOpHash);
1426
+ await this.storage.updateTransfer(transferId, {
1427
+ transactionHash: txHash,
1428
+ status: "completed",
1429
+ completedAt: (/* @__PURE__ */ new Date()).toISOString()
1430
+ });
1431
+ const code = await this.ethereum.getProvider().getCode({ address: from });
1432
+ if (code && code !== "0x") {
1433
+ const account = (await this.storage.getAccounts()).find((a) => a.address === from);
1434
+ if (account && !account.deployed) {
1435
+ await this.storage.updateAccount(account.userId, {
1436
+ deployed: true,
1437
+ deploymentTxHash: txHash
1438
+ });
1439
+ }
1440
+ }
1441
+ } catch (error) {
1442
+ let message = error instanceof Error ? error.message : String(error);
1443
+ if (message.includes("expires too soon") || message.includes("AA32") || message.includes("paymaster deposit not locked")) {
1444
+ const validUntilMatch = message.match(/validUntil=(\d+)/);
1445
+ const hint = validUntilMatch ? ` (validUntil=${validUntilMatch[1]}, expired ${Math.floor(Date.now() / 1e3) - Number(validUntilMatch[1])}s ago)` : "";
1446
+ message = `Paymaster price is stale${hint}. Call paymasterManager.checkPriceFreshness(paymasterAddress) to diagnose, then paymasterManager.updatePrice(paymasterAddress, signer) to refresh. Original error: ${message}`;
1447
+ error = new PaymasterPriceStalenessError(
1448
+ "unknown",
1449
+ 0,
1450
+ 0
1451
+ );
1452
+ error.message = message;
1453
+ }
1454
+ await this.storage.updateTransfer(transferId, {
1455
+ status: "failed",
1456
+ error: message,
1457
+ failedAt: (/* @__PURE__ */ new Date()).toISOString()
1458
+ });
1459
+ this.logger.error(`Transfer ${transferId} failed: ${message}`);
1460
+ }
1461
+ }
1462
+ async estimateGas(userId, params) {
1463
+ const account = await this.accountManager.getAccountByUserId(userId);
1464
+ if (!account) throw new Error("User account not found");
1465
+ const version = account.entryPointVersion || "0.6";
1466
+ const userOp = await this.buildUserOperation(
1467
+ userId,
1468
+ account.address,
1469
+ params.to,
1470
+ params.amount,
1471
+ params.data || "0x",
1472
+ false,
1473
+ void 0,
1474
+ void 0,
1475
+ params.tokenAddress,
1476
+ version,
1477
+ void 0,
1478
+ params.wrapExecuteUserOp ?? false
1479
+ );
1480
+ const formatted = this.formatUserOpForBundler(userOp, version);
1481
+ const gasEstimates = await this.ethereum.estimateUserOperationGas(formatted, version);
1482
+ const gasPrices = await this.ethereum.getUserOperationGasPrice();
1483
+ const validatorContract = this.ethereum.getValidatorContract(version);
1484
+ const validatorGasEstimate = await readValidatorGasEstimate(validatorContract, 3n);
1485
+ return {
1486
+ callGasLimit: gasEstimates.callGasLimit,
1487
+ verificationGasLimit: gasEstimates.verificationGasLimit,
1488
+ preVerificationGas: gasEstimates.preVerificationGas,
1489
+ validatorGasEstimate: validatorGasEstimate.toString(),
1490
+ totalGasEstimate: (BigInt(gasEstimates.callGasLimit) + BigInt(gasEstimates.verificationGasLimit) + BigInt(gasEstimates.preVerificationGas)).toString(),
1491
+ maxFeePerGas: gasPrices.maxFeePerGas,
1492
+ maxPriorityFeePerGas: gasPrices.maxPriorityFeePerGas
1493
+ };
1494
+ }
1495
+ async getTransferStatus(userId, transferId) {
1496
+ const transfer = await this.storage.findTransferById(transferId);
1497
+ if (!transfer || transfer.userId !== userId) {
1498
+ throw new Error("Transfer not found");
1499
+ }
1500
+ const response = { ...transfer };
1501
+ if (transfer.status === "pending" || transfer.status === "submitted") {
1502
+ const elapsed = Math.floor((Date.now() - new Date(transfer.createdAt).getTime()) / 1e3);
1503
+ response.elapsedSeconds = elapsed;
1504
+ }
1505
+ if (transfer.transactionHash) {
1506
+ response.explorerUrl = `https://sepolia.etherscan.io/tx/${transfer.transactionHash}`;
1507
+ }
1508
+ const statusDescriptions = {
1509
+ pending: "Preparing transaction and generating signatures",
1510
+ submitted: "Transaction submitted to bundler, waiting for confirmation",
1511
+ completed: "Transaction confirmed on chain",
1512
+ failed: "Transaction failed"
1513
+ };
1514
+ response.statusDescription = statusDescriptions[transfer.status] || transfer.status;
1515
+ return response;
1516
+ }
1517
+ async getTransferHistory(userId, page = 1, limit = 10) {
1518
+ const transfers = await this.storage.findTransfersByUserId(userId);
1519
+ if (!transfers || transfers.length === 0) {
1520
+ return { transfers: [], total: 0, page, limit, totalPages: 0 };
1521
+ }
1522
+ transfers.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
1523
+ const start = (page - 1) * limit;
1524
+ const paginated = transfers.slice(start, start + limit);
1525
+ return {
1526
+ transfers: paginated,
1527
+ total: transfers.length,
1528
+ page,
1529
+ limit,
1530
+ totalPages: Math.ceil(transfers.length / limit)
1531
+ };
1532
+ }
1533
+ // ── Private helpers ─────────────────────────────────────────────
1534
+ async buildUserOperation(userId, sender, to, amount, data, usePaymaster, paymasterAddress, _paymasterData, tokenAddress, version = "0.6" /* V0_6 */, paymasterTokenAddress, wrapExecuteUserOpFlag = false) {
1535
+ const nonce = await this.ethereum.getNonce(sender, 0, version);
1536
+ const provider = this.ethereum.getProvider();
1537
+ const code = await provider.getCode({ address: sender });
1538
+ const needsDeployment = !code || code === "0x";
1539
+ let initCode = "0x";
1540
+ if (needsDeployment) {
1541
+ const accounts = await this.storage.getAccounts();
1542
+ const account = accounts.find((a) => a.address === sender);
1543
+ if (account) {
1544
+ const factory = this.ethereum.getFactoryContract(version);
1545
+ const factoryAddress = factory.address;
1546
+ let deployCalldata;
1547
+ if (version === "0.7" /* V0_7 */ || version === "0.8" /* V0_8 */) {
1548
+ const storedDailyLimit = account.dailyLimit ? BigInt(account.dailyLimit) : 0n;
1549
+ if (account.guardian1 && account.guardian2 && account.guardian1Sig && account.guardian2Sig) {
1550
+ const sig1 = account.guardian1Sig.startsWith("0x") ? account.guardian1Sig : `0x${account.guardian1Sig}`;
1551
+ const sig2 = account.guardian2Sig.startsWith("0x") ? account.guardian2Sig : `0x${account.guardian2Sig}`;
1552
+ deployCalldata = encodeFn(AIRACCOUNT_FACTORY_ABI_PARSED, "createAccountWithDefaults", [
1553
+ account.signerAddress,
1554
+ BigInt(account.salt),
1555
+ account.guardian1,
1556
+ sig1,
1557
+ account.guardian2,
1558
+ sig2,
1559
+ storedDailyLimit
1560
+ ]);
1561
+ } else {
1562
+ const minimalConfig = [
1563
+ [viem.zeroAddress, viem.zeroAddress, viem.zeroAddress],
1564
+ // guardians (address[3])
1565
+ EMPTY_P2562,
1566
+ // guardianP256X (bytes32[3]) — v0.20.0
1567
+ EMPTY_P2562,
1568
+ // guardianP256Y (bytes32[3]) — v0.20.0
1569
+ storedDailyLimit,
1570
+ [],
1571
+ // approvedAlgIds
1572
+ 0n,
1573
+ // minDailyLimit
1574
+ [],
1575
+ // initialTokens
1576
+ []
1577
+ // initialTokenConfigs
1578
+ ];
1579
+ deployCalldata = encodeFn(AIRACCOUNT_FACTORY_ABI_PARSED, "createAccount", [
1580
+ account.signerAddress,
1581
+ BigInt(account.salt),
1582
+ minimalConfig
1583
+ ]);
1584
+ }
1585
+ } else {
1586
+ deployCalldata = encodeFn(FACTORY_ABI_V6_PARSED, "createAccountWithAAStarValidator", [
1587
+ account.signerAddress,
1588
+ account.signerAddress,
1589
+ account.validatorAddress,
1590
+ true,
1591
+ BigInt(account.salt)
1592
+ ]);
1593
+ }
1594
+ initCode = viem.concat([factoryAddress, deployCalldata]);
1595
+ }
1596
+ }
1597
+ let callData;
1598
+ if (tokenAddress) {
1599
+ const tokenInfo = await this.tokenService.getTokenInfo(tokenAddress);
1600
+ const transferCalldata = this.tokenService.generateTransferCalldata(
1601
+ to,
1602
+ amount,
1603
+ tokenInfo.decimals
1604
+ );
1605
+ callData = encodeFn(AIRACCOUNT_ABI_PARSED, "execute", [tokenAddress, 0n, transferCalldata]);
1606
+ } else {
1607
+ callData = encodeFn(AIRACCOUNT_ABI_PARSED, "execute", [to, viem.parseEther(amount), data]);
1608
+ }
1609
+ if (wrapExecuteUserOpFlag) {
1610
+ callData = wrapExecuteUserOp(callData);
1611
+ }
1612
+ const gasPrices = await this.ethereum.getUserOperationGasPrice();
1613
+ const isV07 = version === "0.7" /* V0_7 */ || version === "0.8" /* V0_8 */;
1614
+ let baseUserOp;
1615
+ if (isV07) {
1616
+ let factory;
1617
+ let factoryData;
1618
+ if (initCode && initCode !== "0x" && initCode.length > 2) {
1619
+ factory = initCode.slice(0, 42);
1620
+ factoryData = initCode.length > 42 ? "0x" + initCode.slice(42) : "0x";
1621
+ }
1622
+ baseUserOp = {
1623
+ sender,
1624
+ nonce: "0x" + nonce.toString(16),
1625
+ ...factory ? { factory, factoryData } : {},
1626
+ callData,
1627
+ callGasLimit: "0x0",
1628
+ verificationGasLimit: "0x0",
1629
+ preVerificationGas: "0x0",
1630
+ maxFeePerGas: gasPrices.maxFeePerGas,
1631
+ maxPriorityFeePerGas: gasPrices.maxPriorityFeePerGas,
1632
+ signature: "0x"
1633
+ };
1634
+ } else {
1635
+ baseUserOp = {
1636
+ sender,
1637
+ nonce: "0x" + nonce.toString(16),
1638
+ initCode,
1639
+ callData,
1640
+ callGasLimit: "0x0",
1641
+ verificationGasLimit: "0x0",
1642
+ preVerificationGas: "0x0",
1643
+ maxFeePerGas: gasPrices.maxFeePerGas,
1644
+ maxPriorityFeePerGas: gasPrices.maxPriorityFeePerGas,
1645
+ paymasterAndData: "0x",
1646
+ signature: "0x"
1647
+ };
1648
+ }
1649
+ let paymasterAndData = "0x";
1650
+ if (usePaymaster) {
1651
+ if (paymasterAddress) {
1652
+ const entryPoint = this.ethereum.getEntryPointAddress(version);
1653
+ paymasterAndData = await this.paymasterManager.getPaymasterData(
1654
+ userId,
1655
+ "custom-user-provided",
1656
+ baseUserOp,
1657
+ entryPoint,
1658
+ paymasterAddress,
1659
+ paymasterTokenAddress ? { tokenAddress: paymasterTokenAddress } : void 0
1660
+ );
1661
+ } else {
1662
+ const available = await this.paymasterManager.getAvailablePaymasters(userId);
1663
+ const configured = available.find((pm) => pm.configured);
1664
+ if (configured) {
1665
+ const entryPoint = this.ethereum.getEntryPointAddress(version);
1666
+ paymasterAndData = await this.paymasterManager.getPaymasterData(
1667
+ userId,
1668
+ configured.name,
1669
+ baseUserOp,
1670
+ entryPoint
1671
+ );
1672
+ } else {
1673
+ throw new Error("No paymaster configured and no paymaster address provided");
1674
+ }
1675
+ }
1676
+ if (!paymasterAndData || paymasterAndData === "0x") {
1677
+ throw new Error(
1678
+ `Paymaster failed to provide sponsorship data. The paymaster at ${paymasterAddress} may not be configured correctly.`
1679
+ );
1680
+ }
1681
+ if (isV07) {
1682
+ baseUserOp.paymaster = paymasterAndData.slice(0, 42);
1683
+ if (paymasterAndData.length >= 74) {
1684
+ baseUserOp.paymasterVerificationGasLimit = "0x" + BigInt("0x" + paymasterAndData.slice(42, 74)).toString(16);
1685
+ }
1686
+ if (paymasterAndData.length >= 106) {
1687
+ baseUserOp.paymasterPostOpGasLimit = "0x" + BigInt("0x" + paymasterAndData.slice(74, 106)).toString(16);
1688
+ }
1689
+ if (paymasterAndData.length > 106) {
1690
+ baseUserOp.paymasterData = "0x" + paymasterAndData.slice(106);
1691
+ }
1692
+ } else {
1693
+ baseUserOp.paymasterAndData = paymasterAndData;
1694
+ }
1695
+ }
1696
+ const gasEstimates = await this.ethereum.estimateUserOperationGas(baseUserOp, version);
1697
+ const standardUserOp = {
1698
+ sender,
1699
+ nonce,
1700
+ initCode,
1701
+ callData,
1702
+ callGasLimit: BigInt(gasEstimates.callGasLimit),
1703
+ verificationGasLimit: BigInt(gasEstimates.verificationGasLimit),
1704
+ preVerificationGas: BigInt(gasEstimates.preVerificationGas),
1705
+ maxFeePerGas: BigInt(gasPrices.maxFeePerGas),
1706
+ maxPriorityFeePerGas: BigInt(gasPrices.maxPriorityFeePerGas),
1707
+ paymasterAndData,
1708
+ signature: "0x"
1709
+ };
1710
+ if (version === "0.7" /* V0_7 */ || version === "0.8" /* V0_8 */) {
1711
+ return chunkXQROKLZI_cjs.ERC4337Utils.packUserOperation(standardUserOp);
1712
+ }
1713
+ return standardUserOp;
1714
+ }
1715
+ formatUserOpForBundler(userOp, version = "0.6" /* V0_6 */) {
1716
+ if (version === "0.7" /* V0_7 */ || version === "0.8" /* V0_8 */) {
1717
+ const packedOp = userOp;
1718
+ const gasLimits = chunkXQROKLZI_cjs.ERC4337Utils.unpackAccountGasLimits(packedOp.accountGasLimits);
1719
+ const gasFees = chunkXQROKLZI_cjs.ERC4337Utils.unpackGasFees(packedOp.gasFees);
1720
+ let factory;
1721
+ let factoryData;
1722
+ if (packedOp.initCode && packedOp.initCode !== "0x" && packedOp.initCode.length > 2) {
1723
+ factory = packedOp.initCode.slice(0, 42);
1724
+ if (packedOp.initCode.length > 42) {
1725
+ factoryData = "0x" + packedOp.initCode.slice(42);
1726
+ }
1727
+ }
1728
+ let paymaster;
1729
+ let paymasterVerificationGasLimit;
1730
+ let paymasterPostOpGasLimit;
1731
+ let paymasterData;
1732
+ if (packedOp.paymasterAndData && packedOp.paymasterAndData !== "0x" && packedOp.paymasterAndData.length > 2) {
1733
+ paymaster = packedOp.paymasterAndData.slice(0, 42);
1734
+ if (packedOp.paymasterAndData.length >= 74) {
1735
+ paymasterVerificationGasLimit = "0x" + BigInt("0x" + packedOp.paymasterAndData.slice(42, 74)).toString(16);
1736
+ }
1737
+ if (packedOp.paymasterAndData.length >= 106) {
1738
+ paymasterPostOpGasLimit = "0x" + BigInt("0x" + packedOp.paymasterAndData.slice(74, 106)).toString(16);
1739
+ }
1740
+ if (packedOp.paymasterAndData.length > 106) {
1741
+ paymasterData = "0x" + packedOp.paymasterAndData.slice(106);
1742
+ }
1743
+ }
1744
+ const result = {
1745
+ sender: packedOp.sender,
1746
+ nonce: typeof packedOp.nonce === "bigint" ? "0x" + packedOp.nonce.toString(16) : packedOp.nonce.toString().startsWith("0x") ? packedOp.nonce.toString() : "0x" + BigInt(packedOp.nonce).toString(16),
1747
+ callData: packedOp.callData,
1748
+ callGasLimit: "0x" + gasLimits.callGasLimit.toString(16),
1749
+ verificationGasLimit: "0x" + gasLimits.verificationGasLimit.toString(16),
1750
+ preVerificationGas: typeof packedOp.preVerificationGas === "bigint" ? "0x" + packedOp.preVerificationGas.toString(16) : packedOp.preVerificationGas.toString().startsWith("0x") ? packedOp.preVerificationGas.toString() : "0x" + BigInt(packedOp.preVerificationGas).toString(16),
1751
+ maxFeePerGas: "0x" + gasFees.maxFeePerGas.toString(16),
1752
+ maxPriorityFeePerGas: "0x" + gasFees.maxPriorityFeePerGas.toString(16),
1753
+ signature: packedOp.signature || "0x"
1754
+ };
1755
+ if (factory) result.factory = factory;
1756
+ if (factoryData) result.factoryData = factoryData;
1757
+ if (paymaster) {
1758
+ result.paymaster = paymaster;
1759
+ result.paymasterVerificationGasLimit = paymasterVerificationGasLimit || "0x30000";
1760
+ result.paymasterPostOpGasLimit = paymasterPostOpGasLimit || "0x30000";
1761
+ if (paymasterData && paymasterData !== "0x") {
1762
+ result.paymasterData = paymasterData;
1763
+ }
1764
+ }
1765
+ return result;
1766
+ }
1767
+ const op = userOp;
1768
+ return {
1769
+ sender: op.sender,
1770
+ nonce: "0x" + op.nonce.toString(16),
1771
+ initCode: op.initCode,
1772
+ callData: op.callData,
1773
+ callGasLimit: "0x" + op.callGasLimit.toString(16),
1774
+ verificationGasLimit: "0x" + op.verificationGasLimit.toString(16),
1775
+ preVerificationGas: "0x" + op.preVerificationGas.toString(16),
1776
+ maxFeePerGas: "0x" + op.maxFeePerGas.toString(16),
1777
+ maxPriorityFeePerGas: "0x" + op.maxPriorityFeePerGas.toString(16),
1778
+ paymasterAndData: op.paymasterAndData,
1779
+ signature: op.signature
1780
+ };
1781
+ }
1782
+ };
1783
+ var DvtPendingConfirmationError = class extends Error {
1784
+ constructor(userOpHash, nodeEndpoint) {
1785
+ super(
1786
+ `DVT node ${nodeEndpoint} withheld its co-signature pending out-of-band confirmation for userOpHash ${userOpHash}; release it via POST /signature/confirm.`
1787
+ );
1788
+ this.userOpHash = userOpHash;
1789
+ this.nodeEndpoint = nodeEndpoint;
1790
+ this.name = "DvtPendingConfirmationError";
1791
+ }
1792
+ };
1793
+ function isPendingConfirmation(data) {
1794
+ return typeof data === "object" && data !== null && data.status === "pending_confirmation";
1795
+ }
1796
+ var BLSSignatureService = class {
1797
+ constructor(config, ethereum, storage, signer, logger) {
1798
+ this.config = config;
1799
+ this.ethereum = ethereum;
1800
+ this.storage = storage;
1801
+ this.signer = signer;
1802
+ this.logger = logger ?? new ConsoleLogger("[BLSSignatureService]");
1803
+ }
1804
+ blsManager = null;
1805
+ logger;
1806
+ /** Lazy-initialize BLSManager on first use. */
1807
+ async ensureInitialized() {
1808
+ if (this.blsManager) return this.blsManager;
1809
+ const blsConfig = await this.storage.getBlsConfig();
1810
+ const seedNodes = this.config.blsSeedNodes ?? blsConfig?.discovery?.seedNodes?.map((n) => n.endpoint) ?? [];
1811
+ this.blsManager = new chunkXQROKLZI_cjs.BLSManager({
1812
+ seedNodes,
1813
+ discoveryTimeout: this.config.blsDiscoveryTimeout ?? 1e4
1814
+ });
1815
+ return this.blsManager;
1816
+ }
1817
+ async getActiveSignerNodes() {
1818
+ const manager = await this.ensureInitialized();
1819
+ const nodes = await manager.getAvailableNodes();
1820
+ if (nodes.length > 0) {
1821
+ try {
1822
+ await this.storage.updateSignerNodesCache(nodes);
1823
+ } catch {
1824
+ }
1825
+ }
1826
+ return nodes;
1827
+ }
1828
+ async generateBLSSignature(userId, userOpHash, ctx) {
1829
+ const manager = await this.ensureInitialized();
1830
+ const activeNodes = await this.getActiveSignerNodes();
1831
+ if (activeNodes.length < 1) {
1832
+ throw new Error("No active BLS signer nodes available");
1833
+ }
1834
+ const selectedNodes = activeNodes.slice(0, Math.min(3, activeNodes.length));
1835
+ const signerNodeSignatures = [];
1836
+ const signerNodeIds = [];
1837
+ for (const node of selectedNodes) {
1838
+ try {
1839
+ const response = await axios__default.default.post(`${node.apiEndpoint}/signature/sign`, {
1840
+ message: userOpHash
1841
+ });
1842
+ if (isPendingConfirmation(response.data)) {
1843
+ throw new DvtPendingConfirmationError(response.data.userOpHash ?? userOpHash, node.apiEndpoint);
1844
+ }
1845
+ const signatureForAggregation = response.data.signatureCompact || response.data.signature;
1846
+ const formatted = signatureForAggregation.startsWith("0x") ? signatureForAggregation : `0x${signatureForAggregation}`;
1847
+ signerNodeSignatures.push(formatted);
1848
+ signerNodeIds.push(response.data.nodeId);
1849
+ } catch (err) {
1850
+ if (err instanceof DvtPendingConfirmationError) throw err;
1851
+ }
1852
+ }
1853
+ if (signerNodeSignatures.length === 0) {
1854
+ throw new Error("Failed to get signatures from any BLS signer nodes");
1855
+ }
1856
+ let aggregatedSignature;
1857
+ if (signerNodeSignatures.length > 1) {
1858
+ const aggregateResponse = await axios__default.default.post(
1859
+ `${selectedNodes[0].apiEndpoint}/signature/aggregate`,
1860
+ { signatures: signerNodeSignatures }
1861
+ );
1862
+ aggregatedSignature = aggregateResponse.data.signature.startsWith("0x") ? aggregateResponse.data.signature : `0x${aggregateResponse.data.signature}`;
1863
+ } else {
1864
+ const singleSignResponse = await axios__default.default.post(
1865
+ `${selectedNodes[0].apiEndpoint}/signature/sign`,
1866
+ { message: userOpHash }
1867
+ );
1868
+ if (isPendingConfirmation(singleSignResponse.data)) {
1869
+ throw new DvtPendingConfirmationError(
1870
+ singleSignResponse.data.userOpHash ?? userOpHash,
1871
+ selectedNodes[0].apiEndpoint
1872
+ );
1873
+ }
1874
+ aggregatedSignature = singleSignResponse.data.signature.startsWith("0x") ? singleSignResponse.data.signature : `0x${singleSignResponse.data.signature}`;
1875
+ }
1876
+ const messagePoint = await manager.generateMessagePoint(userOpHash);
1877
+ const account = await this.storage.findAccountByUserId(userId);
1878
+ if (!account) {
1879
+ throw new Error(`User account not found for userId: ${userId}`);
1880
+ }
1881
+ const walletAddress = await this.signer.getAddress(userId);
1882
+ if (walletAddress.toLowerCase() !== account.signerAddress.toLowerCase()) {
1883
+ throw new Error(
1884
+ `Wallet address mismatch! Wallet: ${walletAddress}, Expected: ${account.signerAddress}`
1885
+ );
1886
+ }
1887
+ const aaSignature = await this.signer.signMessage(
1888
+ userId,
1889
+ viem.hexToBytes(userOpHash),
1890
+ ctx
1891
+ );
1892
+ const messagePointHash = chunkXQROKLZI_cjs.keccak256(messagePoint);
1893
+ const messagePointSignature = await this.signer.signMessage(
1894
+ userId,
1895
+ viem.hexToBytes(messagePointHash),
1896
+ ctx
1897
+ );
1898
+ return {
1899
+ nodeIds: signerNodeIds,
1900
+ signature: aggregatedSignature,
1901
+ messagePoint,
1902
+ aaAddress: account.signerAddress,
1903
+ aaSignature,
1904
+ messagePointSignature
1905
+ };
1906
+ }
1907
+ async packSignature(blsData) {
1908
+ const manager = await this.ensureInitialized();
1909
+ return manager.packSignature(blsData);
1910
+ }
1911
+ // ── Tiered Signature Support (M4) ─────────────────────────────
1912
+ /**
1913
+ * Generate a tiered signature based on the required tier level.
1914
+ *
1915
+ * - Tier 1: raw 65-byte ECDSA (no algId prefix, backwards-compat)
1916
+ * - Tier 2: algId 0x04 — P256 + BLS aggregate + messagePoint ECDSA
1917
+ * - Tier 3: algId 0x05 — P256 + BLS + messagePoint ECDSA + Guardian ECDSA
1918
+ *
1919
+ * @param tier - Required tier level (1, 2, or 3)
1920
+ * @param userId - User ID for account lookup
1921
+ * @param userOpHash - The UserOp hash to sign
1922
+ * @param p256Signature - P256 passkey signature (64 bytes, required for tier 2/3)
1923
+ * @param guardianSigner - Guardian signer (required for tier 3)
1924
+ * @param ctx - Optional passkey assertion context for KMS signing
1925
+ */
1926
+ async generateTieredSignature(params) {
1927
+ const { tier, userId, userOpHash, p256Signature, guardianSigner, ctx } = params;
1928
+ const manager = await this.ensureInitialized();
1929
+ if (tier === 1) {
1930
+ const account = await this.storage.findAccountByUserId(userId);
1931
+ if (!account) throw new Error(`User account not found for userId: ${userId}`);
1932
+ return this.signer.signMessage(userId, viem.hexToBytes(userOpHash), ctx);
1933
+ }
1934
+ if (!p256Signature) {
1935
+ throw new Error(`P256 signature required for Tier ${tier}`);
1936
+ }
1937
+ const blsData = await this.generateBLSSignature(userId, userOpHash, ctx);
1938
+ if (tier === 2) {
1939
+ const t2Data = {
1940
+ p256Signature,
1941
+ nodeIds: blsData.nodeIds,
1942
+ blsSignature: blsData.signature,
1943
+ messagePoint: blsData.messagePoint,
1944
+ messagePointSignature: blsData.messagePointSignature
1945
+ };
1946
+ return manager.packCumulativeT2Signature(t2Data);
1947
+ }
1948
+ if (!guardianSigner) {
1949
+ throw new Error("Guardian signer required for Tier 3");
1950
+ }
1951
+ const guardianSignature = await guardianSigner.signMessage(
1952
+ viem.hexToBytes(userOpHash)
1953
+ );
1954
+ const t3Data = {
1955
+ p256Signature,
1956
+ nodeIds: blsData.nodeIds,
1957
+ blsSignature: blsData.signature,
1958
+ messagePoint: blsData.messagePoint,
1959
+ messagePointSignature: blsData.messagePointSignature,
1960
+ guardianSignature
1961
+ };
1962
+ return manager.packCumulativeT3Signature(t3Data);
1963
+ }
1964
+ };
1965
+ var ERC20_ABI_PARSED = viem.parseAbi(ERC20_ABI);
1966
+ var TokenService = class {
1967
+ constructor(ethereum) {
1968
+ this.ethereum = ethereum;
1969
+ }
1970
+ async getTokenInfo(tokenAddress) {
1971
+ const client = this.ethereum.getProvider();
1972
+ const address = tokenAddress;
1973
+ const [name, symbol, decimals] = await Promise.all([
1974
+ client.readContract({ address, abi: ERC20_ABI_PARSED, functionName: "name" }),
1975
+ client.readContract({ address, abi: ERC20_ABI_PARSED, functionName: "symbol" }),
1976
+ client.readContract({ address, abi: ERC20_ABI_PARSED, functionName: "decimals" })
1977
+ ]);
1978
+ return {
1979
+ address: tokenAddress.toLowerCase(),
1980
+ name,
1981
+ symbol,
1982
+ decimals: Number(decimals)
1983
+ };
1984
+ }
1985
+ async getTokenBalance(tokenAddress, walletAddress) {
1986
+ const client = this.ethereum.getProvider();
1987
+ try {
1988
+ const balance = await client.readContract({
1989
+ address: tokenAddress,
1990
+ abi: ERC20_ABI_PARSED,
1991
+ functionName: "balanceOf",
1992
+ args: [walletAddress]
1993
+ });
1994
+ return balance.toString();
1995
+ } catch {
1996
+ return "0";
1997
+ }
1998
+ }
1999
+ async getFormattedTokenBalance(tokenAddress, walletAddress) {
2000
+ const tokenInfo = await this.getTokenInfo(tokenAddress);
2001
+ const rawBalance = await this.getTokenBalance(tokenAddress, walletAddress);
2002
+ const formattedBalance = viem.formatUnits(BigInt(rawBalance), tokenInfo.decimals);
2003
+ return { token: tokenInfo, balance: rawBalance, formattedBalance };
2004
+ }
2005
+ generateTransferCalldata(to, amount, decimals) {
2006
+ const parsedAmount = viem.parseUnits(amount, decimals);
2007
+ return viem.encodeFunctionData({
2008
+ abi: ERC20_ABI_PARSED,
2009
+ functionName: "transfer",
2010
+ args: [to, parsedAmount]
2011
+ });
2012
+ }
2013
+ async validateToken(tokenAddress) {
2014
+ try {
2015
+ const client = this.ethereum.getProvider();
2016
+ const address = tokenAddress;
2017
+ const [name, symbol, decimals] = await Promise.race([
2018
+ Promise.all([
2019
+ client.readContract({ address, abi: ERC20_ABI_PARSED, functionName: "name" }),
2020
+ client.readContract({ address, abi: ERC20_ABI_PARSED, functionName: "symbol" }),
2021
+ client.readContract({ address, abi: ERC20_ABI_PARSED, functionName: "decimals" })
2022
+ ]),
2023
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), 1e4))
2024
+ ]);
2025
+ return {
2026
+ isValid: true,
2027
+ token: {
2028
+ address: tokenAddress.toLowerCase(),
2029
+ name,
2030
+ symbol,
2031
+ decimals: Number(decimals)
2032
+ }
2033
+ };
2034
+ } catch (error) {
2035
+ return {
2036
+ isValid: false,
2037
+ error: error instanceof Error ? error.message : "Invalid ERC20 token"
2038
+ };
2039
+ }
2040
+ }
2041
+ };
2042
+
2043
+ // ../airaccount/src/server/services/wallet-manager.ts
2044
+ var WalletManager = class {
2045
+ constructor(signer) {
2046
+ this.signer = signer;
2047
+ }
2048
+ async getAddress(userId) {
2049
+ return this.signer.getAddress(userId);
2050
+ }
2051
+ async signMessage(userId, message, ctx) {
2052
+ return this.signer.signMessage(userId, message, ctx);
2053
+ }
2054
+ async ensureSigner(userId) {
2055
+ return this.signer.ensureSigner(userId);
2056
+ }
2057
+ };
2058
+
2059
+ // ../airaccount/src/server/server-client.ts
2060
+ var AirAccountServerClient = class {
2061
+ ethereum;
2062
+ accounts;
2063
+ transfers;
2064
+ bls;
2065
+ paymaster;
2066
+ tokens;
2067
+ wallets;
2068
+ constructor(config) {
2069
+ validateConfig(config);
2070
+ const logger = config.logger ?? new ConsoleLogger("[YAAA]");
2071
+ this.ethereum = new EthereumProvider(config);
2072
+ this.wallets = new WalletManager(config.signer);
2073
+ this.tokens = new TokenService(this.ethereum);
2074
+ this.paymaster = new PaymasterManager(this.ethereum, config.storage, logger);
2075
+ this.accounts = new AccountManager(this.ethereum, config.storage, config.signer, logger);
2076
+ this.bls = new BLSSignatureService(
2077
+ config,
2078
+ this.ethereum,
2079
+ config.storage,
2080
+ config.signer,
2081
+ logger
2082
+ );
2083
+ this.transfers = new TransferManager(
2084
+ this.ethereum,
2085
+ this.accounts,
2086
+ this.bls,
2087
+ this.paymaster,
2088
+ this.tokens,
2089
+ config.storage,
2090
+ config.signer,
2091
+ logger
2092
+ );
2093
+ }
2094
+ };
2095
+ var YAAAServerClient = AirAccountServerClient;
2096
+ function hashMessage(message) {
2097
+ if (typeof message === "string") return viem.hashMessage(message);
2098
+ return viem.hashMessage({ raw: message });
2099
+ }
2100
+ async function recoverAddress(hash, signature) {
2101
+ return viem.recoverAddress({ hash, signature });
2102
+ }
2103
+ function buildAuthorizationHash(chainId, nonce, delegateAddress) {
2104
+ const encoded = viem.toRlp([
2105
+ chainId === 0 ? "0x" : viem.numberToHex(chainId),
2106
+ delegateAddress,
2107
+ nonce === 0n ? "0x" : viem.numberToHex(nonce)
2108
+ ]);
2109
+ return viem.keccak256(viem.concatHex(["0x05", encoded]));
2110
+ }
2111
+ async function verifyAuthorization(eoa, chainId, nonce, signature, delegateAddress) {
2112
+ const hash = buildAuthorizationHash(chainId, nonce, delegateAddress);
2113
+ const recovered = await recoverAddress(hash, signature);
2114
+ return recovered.toLowerCase() === eoa.toLowerCase();
2115
+ }
2116
+
2117
+ // ../airaccount/src/server/services/module-manager.ts
2118
+ function buildInstallModuleHash(chainId, account, moduleTypeId, module, moduleInitData = "0x") {
2119
+ const moduleInitDataHash = chunkXQROKLZI_cjs.keccak256(moduleInitData);
2120
+ const raw = chunkXQROKLZI_cjs.keccak256(
2121
+ chunkXQROKLZI_cjs.solidityPacked(
2122
+ ["string", "uint256", "address", "uint256", "address", "bytes32"],
2123
+ ["INSTALL_MODULE", BigInt(chainId), account, BigInt(moduleTypeId), module, moduleInitDataHash]
2124
+ )
2125
+ );
2126
+ return hashMessage(viem.hexToBytes(raw));
2127
+ }
2128
+ function buildUninstallModuleHash(chainId, account, moduleTypeId, module) {
2129
+ const raw = chunkXQROKLZI_cjs.keccak256(
2130
+ chunkXQROKLZI_cjs.solidityPacked(
2131
+ ["string", "uint256", "address", "uint256", "address"],
2132
+ ["UNINSTALL_MODULE", BigInt(chainId), account, BigInt(moduleTypeId), module]
2133
+ )
2134
+ );
2135
+ return hashMessage(viem.hexToBytes(raw));
2136
+ }
2137
+ var ModuleManager = class {
2138
+ provider;
2139
+ chainId;
2140
+ constructor(provider, chainId) {
2141
+ this.provider = provider;
2142
+ this.chainId = chainId;
2143
+ }
2144
+ /**
2145
+ * Encode calldata for installModule().
2146
+ * Caller is responsible for submitting via UserOp (EntryPoint) or direct tx.
2147
+ */
2148
+ encodeInstall(params) {
2149
+ const sigs = params.guardianSigs ?? [];
2150
+ const initData = params.moduleInitData ?? "0x";
2151
+ const packed = sigs.length > 0 ? viem.concat([...sigs, initData]) : initData;
2152
+ return viem.encodeFunctionData({
2153
+ abi: viem.parseAbi(AIRACCOUNT_ABI),
2154
+ functionName: "installModule",
2155
+ args: [BigInt(params.moduleTypeId), params.module, packed]
2156
+ });
2157
+ }
2158
+ /**
2159
+ * Encode calldata for uninstallModule().
2160
+ * Always requires 2 guardian signatures.
2161
+ */
2162
+ encodeUninstall(params) {
2163
+ const deInitData = params.moduleDeInitData ?? "0x";
2164
+ const packed = viem.concat([
2165
+ params.guardianSig1,
2166
+ params.guardianSig2,
2167
+ deInitData
2168
+ ]);
2169
+ return viem.encodeFunctionData({
2170
+ abi: viem.parseAbi(AIRACCOUNT_ABI),
2171
+ functionName: "uninstallModule",
2172
+ args: [BigInt(params.moduleTypeId), params.module, packed]
2173
+ });
2174
+ }
2175
+ /** Check if a module is currently installed on the account. */
2176
+ async isInstalled(account, moduleTypeId, module) {
2177
+ return await this.provider.readContract({
2178
+ address: account,
2179
+ abi: viem.parseAbi(AIRACCOUNT_ABI),
2180
+ functionName: "isModuleInstalled",
2181
+ args: [BigInt(moduleTypeId), module, "0x"]
2182
+ });
2183
+ }
2184
+ /** Return the install hash for a guardian to sign (r5 format, includes moduleInitData hash). */
2185
+ installHash(account, moduleTypeId, module, moduleInitData = "0x") {
2186
+ return buildInstallModuleHash(this.chainId, account, moduleTypeId, module, moduleInitData);
2187
+ }
2188
+ /** Return the uninstall hash for guardians to sign. */
2189
+ uninstallHash(account, moduleTypeId, module) {
2190
+ return buildUninstallModuleHash(this.chainId, account, moduleTypeId, module);
2191
+ }
2192
+ /**
2193
+ * Convenience: build install calldata for the standard M7 module set.
2194
+ * Uses pre-deployed Sepolia addresses (r4 audit-final). No guardian sigs required when
2195
+ * account threshold <= 40 (default for newly created accounts).
2196
+ *
2197
+ * Note: beta.3 unifies these into SessionKeyValidator. This helper retains the r4
2198
+ * addresses for accounts already deployed on r4; new accounts use SessionKeyValidator.
2199
+ */
2200
+ encodeInstallDefaultModules(account) {
2201
+ const addresses = AIRACCOUNT_ADDRESSES.sepolia;
2202
+ return {
2203
+ compositeValidator: this.encodeInstall({
2204
+ account,
2205
+ moduleTypeId: MODULE_TYPE.VALIDATOR,
2206
+ module: addresses.compositeValidatorM7r4
2207
+ }),
2208
+ tierGuardHook: this.encodeInstall({
2209
+ account,
2210
+ moduleTypeId: MODULE_TYPE.HOOK,
2211
+ module: addresses.tierGuardHookM7r4
2212
+ })
2213
+ };
2214
+ }
2215
+ };
2216
+ var SESSION_KEY_VALIDATOR_VIEM_ABI = viem.parseAbi(SESSION_KEY_VALIDATOR_ABI);
2217
+ var AGENT_SESSION_KEY_VALIDATOR_VIEM_ABI = viem.parseAbi(AGENT_SESSION_KEY_VALIDATOR_ABI);
2218
+ function buildSessionStruct(params) {
2219
+ return {
2220
+ expiry: params.expiry,
2221
+ contractScope: params.contractScope ?? viem.zeroAddress,
2222
+ selectorScope: params.selectorScope ?? "0x00000000",
2223
+ revoked: false,
2224
+ velocityLimit: params.velocityLimit ?? 0,
2225
+ velocityWindow: params.velocityWindow ?? 0,
2226
+ callTargets: params.callTargets ?? [],
2227
+ selectorAllowlist: params.selectorAllowlist ?? []
2228
+ };
2229
+ }
2230
+ function decodeSessionInfo(session) {
2231
+ const s = session;
2232
+ const expiry = Number(s.expiry);
2233
+ const now = Math.floor(Date.now() / 1e3);
2234
+ return {
2235
+ expiry,
2236
+ contractScope: s.contractScope,
2237
+ selectorScope: s.selectorScope,
2238
+ revoked: s.revoked,
2239
+ velocityLimit: Number(s.velocityLimit),
2240
+ velocityWindow: Number(s.velocityWindow),
2241
+ callTargets: [...s.callTargets ?? []],
2242
+ selectorAllowlist: [...s.selectorAllowlist ?? []],
2243
+ active: expiry > now && !s.revoked
2244
+ };
2245
+ }
2246
+ var SessionKeyService = class {
2247
+ skValidator;
2248
+ askValidator;
2249
+ constructor(provider, sessionKeyValidatorAddress, agentSessionKeyValidatorAddress) {
2250
+ this.skValidator = viem.getContract({
2251
+ address: sessionKeyValidatorAddress,
2252
+ abi: SESSION_KEY_VALIDATOR_VIEM_ABI,
2253
+ client: provider
2254
+ });
2255
+ this.askValidator = viem.getContract({
2256
+ address: agentSessionKeyValidatorAddress,
2257
+ abi: AGENT_SESSION_KEY_VALIDATOR_VIEM_ABI,
2258
+ client: provider
2259
+ });
2260
+ }
2261
+ // ── M6: Basic Session Keys ────────────────────────────────────
2262
+ /**
2263
+ * Build the hash that the account owner must sign to grant a session key.
2264
+ * Use grantSession() with this sig, or grantSessionDirect() from the account itself.
2265
+ */
2266
+ async buildGrantHash(params) {
2267
+ return readBuildGrantHash(
2268
+ this.skValidator,
2269
+ params.account,
2270
+ params.sessionKey,
2271
+ buildSessionStruct(params)
2272
+ );
2273
+ }
2274
+ /** Query an ECDSA session key state (decodes the 8-field Session tuple). */
2275
+ async getSession(account, sessionKey) {
2276
+ const session = await this.skValidator.read.getSession([account, sessionKey]);
2277
+ return decodeSessionInfo(session);
2278
+ }
2279
+ /** Check if an ECDSA session is currently active. */
2280
+ async isSessionActive(account, sessionKey) {
2281
+ return this.skValidator.read.isSessionActive([account, sessionKey]);
2282
+ }
2283
+ /**
2284
+ * Encode calldata for session grant.
2285
+ *
2286
+ * - **With ownerSig** → `grantSession()` — for gasless/UserOp flows.
2287
+ * Owner signs the GRANT_SESSION_V2 typed hash via KMS `sign-grant-session`,
2288
+ * then the relayer calls `grantSession(account, key, cfg, ownerSig)` on-chain.
2289
+ * This is the ONLY path for ERC-4337 sponsored / gasless grant flows.
2290
+ *
2291
+ * - **Without ownerSig** → `grantSessionDirect()` — **owner EOA direct-send only**.
2292
+ * Since v0.17.2 round 3, `grantSessionDirect` requires `msg.sender == ownerOf(account)`.
2293
+ * It does NOT accept `msg.sender == account` (removed in round 3 — confused-deputy fix).
2294
+ * Do NOT encode this for a UserOp callData; the EntryPoint is not the owner EOA.
2295
+ */
2296
+ encodeGrantSession(params) {
2297
+ const cfg = buildSessionStruct(params);
2298
+ if (params.ownerSig) {
2299
+ return viem.encodeFunctionData({
2300
+ abi: SESSION_KEY_VALIDATOR_VIEM_ABI,
2301
+ functionName: "grantSession",
2302
+ args: [params.account, params.sessionKey, cfg, params.ownerSig]
2303
+ });
2304
+ }
2305
+ return viem.encodeFunctionData({
2306
+ abi: SESSION_KEY_VALIDATOR_VIEM_ABI,
2307
+ functionName: "grantSessionDirect",
2308
+ args: [params.account, params.sessionKey, cfg]
2309
+ });
2310
+ }
2311
+ /** Encode calldata for revokeSession(). */
2312
+ encodeRevokeSession(account, sessionKey) {
2313
+ return viem.encodeFunctionData({
2314
+ abi: SESSION_KEY_VALIDATOR_VIEM_ABI,
2315
+ functionName: "revokeSession",
2316
+ args: [account, sessionKey]
2317
+ });
2318
+ }
2319
+ // ── M6: P256 / Passkey Session Keys ───────────────────────────
2320
+ /**
2321
+ * Build the hash that the account owner must sign to grant a P256/passkey session key.
2322
+ * Use grantP256Session() with this sig, or grantP256SessionDirect() from the owner EOA itself.
2323
+ * The owner/KMS signs this hash to authorize a gasless grantP256Session().
2324
+ */
2325
+ async buildP256GrantHash(params) {
2326
+ return readBuildP256GrantHash(
2327
+ this.skValidator,
2328
+ params.account,
2329
+ params.keyX,
2330
+ params.keyY,
2331
+ buildSessionStruct(params)
2332
+ );
2333
+ }
2334
+ /**
2335
+ * Query a P256 session key state (decodes the 8-field Session tuple).
2336
+ * @param keyHash The keccak256 hash of (keyX, keyY) used as the on-chain session id.
2337
+ */
2338
+ async getP256Session(account, keyHash) {
2339
+ const session = await this.skValidator.read.getP256Session([account, keyHash]);
2340
+ return decodeSessionInfo(session);
2341
+ }
2342
+ /** Check if a P256 session is currently active. */
2343
+ async isP256SessionActive(account, keyX, keyY) {
2344
+ return this.skValidator.read.isP256SessionActive([account, keyX, keyY]);
2345
+ }
2346
+ /**
2347
+ * Encode calldata for a P256/passkey session grant.
2348
+ *
2349
+ * - **With ownerSig** → `grantP256Session()` — for gasless/UserOp flows.
2350
+ * Owner signs the buildP256GrantHash() digest via KMS `sign-p256-grant-session`,
2351
+ * then the relayer calls `grantP256Session(account, keyX, keyY, cfg, ownerSig)` on-chain.
2352
+ * This is the ONLY path for ERC-4337 sponsored / gasless P256 grant flows.
2353
+ *
2354
+ * - **Without ownerSig** → `grantP256SessionDirect()` — **owner EOA direct-send only**.
2355
+ * Since v0.17.2 round 3, `grantP256SessionDirect` requires `msg.sender == ownerOf(account)`.
2356
+ * It does NOT accept `msg.sender == account` (removed in round 3 — confused-deputy fix).
2357
+ * Do NOT encode this for a UserOp callData; the EntryPoint is not the owner EOA.
2358
+ */
2359
+ encodeGrantP256Session(params) {
2360
+ const cfg = buildSessionStruct(params);
2361
+ if (params.ownerSig) {
2362
+ return viem.encodeFunctionData({
2363
+ abi: SESSION_KEY_VALIDATOR_VIEM_ABI,
2364
+ functionName: "grantP256Session",
2365
+ args: [params.account, params.keyX, params.keyY, cfg, params.ownerSig]
2366
+ });
2367
+ }
2368
+ return viem.encodeFunctionData({
2369
+ abi: SESSION_KEY_VALIDATOR_VIEM_ABI,
2370
+ functionName: "grantP256SessionDirect",
2371
+ args: [params.account, params.keyX, params.keyY, cfg]
2372
+ });
2373
+ }
2374
+ /** Encode calldata for revokeP256Session(). */
2375
+ encodeRevokeP256Session(account, keyX, keyY) {
2376
+ return viem.encodeFunctionData({
2377
+ abi: SESSION_KEY_VALIDATOR_VIEM_ABI,
2378
+ functionName: "revokeP256Session",
2379
+ args: [account, keyX, keyY]
2380
+ });
2381
+ }
2382
+ // ── M7: Agent Session Keys ────────────────────────────────────
2383
+ /**
2384
+ * Encode calldata for grantAgentSession().
2385
+ * Must be called from the account (via UserOp or direct execute).
2386
+ * The contract uses msg.sender as the account — no account param needed.
2387
+ */
2388
+ encodeGrantAgentSession(sessionKey, cfg) {
2389
+ return viem.encodeFunctionData({
2390
+ abi: AGENT_SESSION_KEY_VALIDATOR_VIEM_ABI,
2391
+ functionName: "grantAgentSession",
2392
+ args: [
2393
+ sessionKey,
2394
+ {
2395
+ expiry: cfg.expiry,
2396
+ velocityLimit: cfg.velocityLimit,
2397
+ velocityWindow: cfg.velocityWindow,
2398
+ revoked: false,
2399
+ callTargets: cfg.callTargets,
2400
+ selectorAllowlist: cfg.selectorAllowlist
2401
+ }
2402
+ ]
2403
+ });
2404
+ }
2405
+ /**
2406
+ * Encode calldata for delegateSession() — sub-agent delegation.
2407
+ * The sub-agent config must be a strict subset of the parent session's scope.
2408
+ * Called by the parent session key (not the account owner).
2409
+ * @param account The smart account under which the parent session was granted.
2410
+ */
2411
+ encodeDelegateSession(account, subKey, subCfg) {
2412
+ return viem.encodeFunctionData({
2413
+ abi: AGENT_SESSION_KEY_VALIDATOR_VIEM_ABI,
2414
+ functionName: "delegateSession",
2415
+ args: [
2416
+ account,
2417
+ subKey,
2418
+ {
2419
+ expiry: subCfg.expiry,
2420
+ velocityLimit: subCfg.velocityLimit,
2421
+ velocityWindow: subCfg.velocityWindow,
2422
+ revoked: false,
2423
+ callTargets: subCfg.callTargets,
2424
+ selectorAllowlist: subCfg.selectorAllowlist
2425
+ }
2426
+ ]
2427
+ });
2428
+ }
2429
+ /** Encode calldata for revokeAgentSession(). */
2430
+ encodeRevokeAgentSession(sessionKey) {
2431
+ return viem.encodeFunctionData({
2432
+ abi: AGENT_SESSION_KEY_VALIDATOR_VIEM_ABI,
2433
+ functionName: "revokeAgentSession",
2434
+ args: [sessionKey]
2435
+ });
2436
+ }
2437
+ /** Query agent session config + runtime state. */
2438
+ async getAgentSession(account, sessionKey) {
2439
+ const [expiry, velocityLimit, velocityWindow, revoked, callTargets, selectorAllowlist] = await this.askValidator.read.agentSessions([account, sessionKey]);
2440
+ const [callCount, windowStart] = await this.askValidator.read.sessionStates([account, sessionKey]);
2441
+ return {
2442
+ expiry: Number(expiry),
2443
+ velocityLimit: Number(velocityLimit),
2444
+ velocityWindow: Number(velocityWindow),
2445
+ callTargets,
2446
+ selectorAllowlist,
2447
+ revoked,
2448
+ callCount: BigInt(callCount),
2449
+ windowStart: BigInt(windowStart)
2450
+ };
2451
+ }
2452
+ /** Check if an agent session is active (not expired, not revoked). */
2453
+ async isAgentSessionActive(account, sessionKey) {
2454
+ const session = await this.getAgentSession(account, sessionKey);
2455
+ return session.expiry > Math.floor(Date.now() / 1e3) && !session.revoked;
2456
+ }
2457
+ /** Return the parent account of a delegated session key. */
2458
+ async getSessionKeyOwner(sessionKey) {
2459
+ return this.askValidator.read.sessionKeyOwner([sessionKey]);
2460
+ }
2461
+ /** Return the parent key that delegated to subKey, or ZeroAddress if not delegated. */
2462
+ async getDelegatedBy(account, subKey) {
2463
+ return this.askValidator.read.delegatedBy([account, subKey]);
2464
+ }
2465
+ };
2466
+ function packSecp256k1SessionSignature(account, sessionKey, signature) {
2467
+ const acc = account.startsWith("0x") ? account.slice(2) : account;
2468
+ const key = sessionKey.startsWith("0x") ? sessionKey.slice(2) : sessionKey;
2469
+ const sig = signature.startsWith("0x") ? signature.slice(2) : signature;
2470
+ if (acc.length !== 40) throw new Error("account must be 20 bytes (40 hex chars)");
2471
+ if (key.length !== 40) throw new Error("sessionKey must be 20 bytes (40 hex chars)");
2472
+ if (sig.length !== 130) throw new Error("signature must be 65 bytes (130 hex chars)");
2473
+ return `0x08${acc}${key}${sig}`;
2474
+ }
2475
+ function packP256SessionSignature(account, keyX, keyY, signature) {
2476
+ const acc = account.startsWith("0x") ? account.slice(2) : account;
2477
+ const x = keyX.startsWith("0x") ? keyX.slice(2) : keyX;
2478
+ const y = keyY.startsWith("0x") ? keyY.slice(2) : keyY;
2479
+ const sig = signature.startsWith("0x") ? signature.slice(2) : signature;
2480
+ if (acc.length !== 40) throw new Error("account must be 20 bytes (40 hex chars)");
2481
+ if (x.length !== 64) throw new Error("keyX must be 32 bytes (64 hex chars)");
2482
+ if (y.length !== 64) throw new Error("keyY must be 32 bytes (64 hex chars)");
2483
+ if (sig.length !== 128) throw new Error("P256 signature must be 64 bytes (128 hex chars, R||S)");
2484
+ return `0x08${acc}${x}${y}${sig}`;
2485
+ }
2486
+ var EXTENDED_GUARD_ABI = [
2487
+ ...GLOBAL_GUARD_ABI,
2488
+ "function todaySpent() external view returns (uint256)",
2489
+ "function tokenTodaySpent(address token) external view returns (uint256)",
2490
+ // approvedAlgorithms removed from the guard in v0.17.2-beta.4 — now read from the account.
2491
+ "function tier1Limit() external view returns (uint256)",
2492
+ "function tier2Limit() external view returns (uint256)",
2493
+ "function minDailyLimit() external view returns (uint256)"
2494
+ ];
2495
+ var GuardStateReader = class {
2496
+ provider;
2497
+ constructor(provider) {
2498
+ this.provider = provider;
2499
+ }
2500
+ accountContract(accountAddress) {
2501
+ return viem.getContract({
2502
+ address: accountAddress,
2503
+ abi: viem.parseAbi(AIRACCOUNT_ABI),
2504
+ client: this.provider
2505
+ });
2506
+ }
2507
+ guardContract(guardAddress) {
2508
+ return viem.getContract({
2509
+ address: guardAddress,
2510
+ abi: viem.parseAbi(EXTENDED_GUARD_ABI),
2511
+ client: this.provider
2512
+ });
2513
+ }
2514
+ /**
2515
+ * Read the full ETH guard state for an account.
2516
+ * Returns null if the account has no guard (dailyLimit=0).
2517
+ */
2518
+ async getGuardState(accountAddress) {
2519
+ const account = this.accountContract(accountAddress).read;
2520
+ const guardAddress = await account.guard([]);
2521
+ if (guardAddress === viem.zeroAddress) return null;
2522
+ const guard = this.guardContract(guardAddress).read;
2523
+ const [dailyLimit, remaining, todaySpent, tier1Limit, tier2Limit, minDailyLimit] = await Promise.all([
2524
+ guard.dailyLimit([]),
2525
+ guard.remainingDailyAllowance([]),
2526
+ guard.todaySpent([]),
2527
+ guard.tier1Limit([]).catch(() => 0n),
2528
+ guard.tier2Limit([]).catch(() => 0n),
2529
+ guard.minDailyLimit([]).catch(() => 0n)
2530
+ ]);
2531
+ return {
2532
+ dailyLimit: BigInt(dailyLimit),
2533
+ todaySpent: BigInt(todaySpent),
2534
+ remaining: BigInt(remaining),
2535
+ currentTier: resolveTierFromSpend(
2536
+ BigInt(todaySpent),
2537
+ BigInt(tier1Limit),
2538
+ BigInt(tier2Limit)
2539
+ ),
2540
+ tier1Limit: BigInt(tier1Limit),
2541
+ tier2Limit: BigInt(tier2Limit),
2542
+ minDailyLimit: BigInt(minDailyLimit),
2543
+ guardAddress
2544
+ };
2545
+ }
2546
+ /**
2547
+ * Read per-token guard state.
2548
+ * Returns null if the token is not configured on the guard.
2549
+ */
2550
+ async getTokenGuardState(accountAddress, token) {
2551
+ const account = this.accountContract(accountAddress).read;
2552
+ const guardAddress = await account.guard([]);
2553
+ if (guardAddress === viem.zeroAddress) return null;
2554
+ const guard = this.guardContract(guardAddress).read;
2555
+ try {
2556
+ const todaySpent = await guard.tokenTodaySpent([token]);
2557
+ return {
2558
+ token,
2559
+ todaySpent: BigInt(todaySpent),
2560
+ dailyLimit: 0n,
2561
+ // token daily limit not directly exposed
2562
+ remaining: 0n,
2563
+ currentTier: 1,
2564
+ tier1Limit: 0n,
2565
+ tier2Limit: 0n
2566
+ };
2567
+ } catch {
2568
+ return null;
2569
+ }
2570
+ }
2571
+ /**
2572
+ * Determine the minimum tier required to send a given ETH amount.
2573
+ * Useful for showing "this transfer needs 2 signatures" before submission.
2574
+ */
2575
+ async requiredTierForAmount(accountAddress, amountWei) {
2576
+ const state = await this.getGuardState(accountAddress);
2577
+ if (!state) return 1;
2578
+ const projectedSpend = state.todaySpent + amountWei;
2579
+ return resolveTierFromSpend(projectedSpend, state.tier1Limit, state.tier2Limit);
2580
+ }
2581
+ /**
2582
+ * Check if a given algorithm ID is approved on the guard.
2583
+ */
2584
+ async isAlgorithmApproved(accountAddress, algId) {
2585
+ const account = this.accountContract(accountAddress).read;
2586
+ return await account.approvedAlgorithms([BigInt(algId)]);
2587
+ }
2588
+ };
2589
+ function resolveTierFromSpend(spent, tier1Limit, tier2Limit) {
2590
+ if (tier1Limit === 0n) return 1;
2591
+ if (spent < tier1Limit) return 1;
2592
+ if (tier2Limit === 0n || spent < tier2Limit) return 2;
2593
+ return 3;
2594
+ }
2595
+ var FACTORY_ABI = viem.parseAbi(AIRACCOUNT_FACTORY_ABI);
2596
+ function computeOapdSalt(owner, dappId) {
2597
+ const packed = chunkXQROKLZI_cjs.solidityPacked(["address", "string"], [owner, dappId]);
2598
+ return BigInt(chunkXQROKLZI_cjs.keccak256(packed));
2599
+ }
2600
+ async function getOapdAddress(provider, config) {
2601
+ const factoryAddress = config.factoryAddress ?? AIRACCOUNT_ADDRESSES.sepolia.factory;
2602
+ const salt = computeOapdSalt(config.owner, config.dappId);
2603
+ return provider.readContract({
2604
+ address: factoryAddress,
2605
+ abi: FACTORY_ABI,
2606
+ functionName: "getAddress",
2607
+ args: [config.owner, salt, config.initConfig]
2608
+ });
2609
+ }
2610
+ async function getOapdAddressWithChainId(provider, config) {
2611
+ const factoryAddress = config.factoryAddress ?? AIRACCOUNT_ADDRESSES.sepolia.factory;
2612
+ const salt = computeOapdSalt(config.owner, config.dappId);
2613
+ const result = await provider.readContract({
2614
+ address: factoryAddress,
2615
+ abi: FACTORY_ABI,
2616
+ functionName: "getAddressWithChainId",
2617
+ args: [config.owner, salt, config.initConfig]
2618
+ });
2619
+ return { address: result[0], chainQualified: result[1] };
2620
+ }
2621
+ async function isOapdDeployed(provider, config) {
2622
+ const address = await getOapdAddress(provider, config);
2623
+ const code = await provider.getCode({ address });
2624
+ return code !== void 0 && code !== "0x";
2625
+ }
2626
+ var ALG_NAMES = {
2627
+ [chunkXQROKLZI_cjs.ALG_BLS]: "BLS (0x01)",
2628
+ [chunkXQROKLZI_cjs.ALG_ECDSA]: "ECDSA (0x02)",
2629
+ [chunkXQROKLZI_cjs.ALG_P256]: "P256 (0x03)",
2630
+ [chunkXQROKLZI_cjs.ALG_CUMULATIVE_T2]: "Cumulative T2 (0x04)",
2631
+ [chunkXQROKLZI_cjs.ALG_CUMULATIVE_T3]: "Cumulative T3 (0x05)"
2632
+ };
2633
+ var GuardChecker = class {
2634
+ constructor(ethereum, logger) {
2635
+ this.ethereum = ethereum;
2636
+ this.logger = logger ?? new ConsoleLogger("[GuardChecker]");
2637
+ }
2638
+ logger;
2639
+ /**
2640
+ * Fetch tier limits from an AirAccount contract.
2641
+ */
2642
+ async fetchTierConfig(accountAddress) {
2643
+ const account = this.ethereum.getAccountContract(accountAddress);
2644
+ return readAccountTierLimits(account);
2645
+ }
2646
+ /**
2647
+ * Fetch guard status from the account's GlobalGuard.
2648
+ */
2649
+ async fetchGuardStatus(accountAddress) {
2650
+ const account = this.ethereum.getAccountContract(accountAddress);
2651
+ const guardAddress = await readAccountGuardAddress(account);
2652
+ if (guardAddress === viem.zeroAddress) {
2653
+ return {
2654
+ hasGuard: false,
2655
+ guardAddress: viem.zeroAddress,
2656
+ dailyLimit: 0n,
2657
+ dailyRemaining: 0n
2658
+ };
2659
+ }
2660
+ const guard = viem.getContract({
2661
+ address: guardAddress,
2662
+ abi: viem.parseAbi(GLOBAL_GUARD_ABI),
2663
+ client: this.ethereum.getProvider()
2664
+ });
2665
+ const { dailyLimit, dailyRemaining } = await readGuardDailyAllowance(guard);
2666
+ return {
2667
+ hasGuard: true,
2668
+ guardAddress,
2669
+ dailyLimit,
2670
+ dailyRemaining
2671
+ };
2672
+ }
2673
+ /**
2674
+ * Pre-check a transaction: determine tier, check guard limits and algorithm approval.
2675
+ * Returns errors array (empty = OK to proceed).
2676
+ */
2677
+ async preCheck(accountAddress, value) {
2678
+ const errors = [];
2679
+ const tierConfig = await this.fetchTierConfig(accountAddress);
2680
+ const tier = chunkXQROKLZI_cjs.resolveTier(value, tierConfig);
2681
+ const algId = chunkXQROKLZI_cjs.algIdForTier(tier);
2682
+ const guard = await this.fetchGuardStatus(accountAddress);
2683
+ if (!guard.hasGuard) {
2684
+ return { ok: true, errors: [], tier, algId };
2685
+ }
2686
+ if (guard.dailyLimit > 0n && value > guard.dailyRemaining) {
2687
+ errors.push(
2688
+ `Daily limit exceeded: requesting ${value} wei but only ${guard.dailyRemaining} remaining (limit: ${guard.dailyLimit})`
2689
+ );
2690
+ }
2691
+ const accountContract = this.ethereum.getAccountContract(accountAddress);
2692
+ const isApproved = await readAlgorithmApproved(accountContract, algId);
2693
+ if (!isApproved) {
2694
+ errors.push(
2695
+ `Algorithm ${ALG_NAMES[algId] ?? `0x${algId.toString(16)}`} is not approved by the account`
2696
+ );
2697
+ }
2698
+ if (errors.length > 0) {
2699
+ this.logger.warn(`Pre-check failed for ${accountAddress}: ${errors.join("; ")}`);
2700
+ }
2701
+ return { ok: errors.length === 0, errors, tier, algId };
2702
+ }
2703
+ };
2704
+ var FORCE_EXIT_ABI = [
2705
+ // ERC-7579 module lifecycle
2706
+ "function onInstall(bytes calldata data) external",
2707
+ "function onUninstall(bytes calldata data) external",
2708
+ "function isInitialized(address smartAccount) external view returns (bool)",
2709
+ // Proposal lifecycle
2710
+ "function proposeForceExit(address target, uint256 value, bytes calldata data) external",
2711
+ "function approveForceExit(address account, bytes calldata guardianSig) external",
2712
+ "function executeForceExit(address account) external",
2713
+ "function cancelForceExit(address account) external",
2714
+ // State readers
2715
+ "function getPendingExit(address account) external view returns (address target, uint256 value, bytes memory data, uint256 proposedAt, uint256 approvalBitmap, address[3] memory guardians)",
2716
+ "function accountL2Type(address account) external view returns (uint8)",
2717
+ // Constants
2718
+ "function APPROVAL_THRESHOLD() external view returns (uint8)",
2719
+ "function MODULE_VERSION() external view returns (string)",
2720
+ // Errors (for decoding reverts)
2721
+ "error AlreadyApproved()",
2722
+ "error AlreadyProposed()",
2723
+ "error ForceExitCallFailed()",
2724
+ "error IncompatibleAccount()",
2725
+ "error InvalidGuardianSig()",
2726
+ "error NoProposal()",
2727
+ "error NotEnoughApprovals()",
2728
+ "error NotInstalled()",
2729
+ "error NotOwner()",
2730
+ "error SignerNoLongerGuardian()",
2731
+ "error UnsupportedL2Type()"
2732
+ ];
2733
+ var FORCE_EXIT_PARSED_ABI = viem.parseAbi(FORCE_EXIT_ABI);
2734
+ var L2_TYPE = {
2735
+ OPTIMISM: 1,
2736
+ ARBITRUM: 2
2737
+ };
2738
+ var ForceExitService = class {
2739
+ constructor(moduleAddress, client) {
2740
+ this.moduleAddress = moduleAddress;
2741
+ this.contract = viem.getContract({
2742
+ address: moduleAddress,
2743
+ abi: FORCE_EXIT_PARSED_ABI,
2744
+ // viem inspects the client's actions at runtime to expose read/write; the
2745
+ // cast only satisfies the static union — a wallet client still yields writes.
2746
+ client
2747
+ });
2748
+ }
2749
+ contract;
2750
+ // ── On-chain reads ──────────────────────────────────────────────
2751
+ async isInitialized(smartAccount) {
2752
+ return await this.contract.read.isInitialized([smartAccount]);
2753
+ }
2754
+ async getPendingExit(account) {
2755
+ const [target, value, data, proposedAt, approvalBitmap, guardians] = await this.contract.read.getPendingExit([account]);
2756
+ return {
2757
+ target,
2758
+ value: BigInt(value),
2759
+ data,
2760
+ proposedAt: BigInt(proposedAt),
2761
+ approvalBitmap: BigInt(approvalBitmap),
2762
+ guardians
2763
+ };
2764
+ }
2765
+ async getAccountL2Type(account) {
2766
+ return Number(await this.contract.read.accountL2Type([account]));
2767
+ }
2768
+ async getApprovalThreshold() {
2769
+ return Number(await this.contract.read.APPROVAL_THRESHOLD([]));
2770
+ }
2771
+ async getModuleVersion() {
2772
+ return await this.contract.read.MODULE_VERSION([]);
2773
+ }
2774
+ // ── Calldata encoders (for UserOp or direct tx submission) ─────
2775
+ /**
2776
+ * Encode onInstall calldata for installModule() call on the smart account.
2777
+ * Must be submitted by the account owner, with moduleTypeId=2 (EXECUTOR).
2778
+ *
2779
+ * @param l2Type - L2_TYPE.OPTIMISM (1) or L2_TYPE.ARBITRUM (2)
2780
+ * @example
2781
+ * const calldata = forceExit.encodeOnInstall(L2_TYPE.OPTIMISM);
2782
+ * // account.installModule(2, forceExitModuleAddress, calldata)
2783
+ */
2784
+ encodeOnInstall(l2Type) {
2785
+ return viem.encodeFunctionData({
2786
+ abi: FORCE_EXIT_PARSED_ABI,
2787
+ functionName: "onInstall",
2788
+ args: [chunkXQROKLZI_cjs.encodeAbiParams(["uint8"], [l2Type])]
2789
+ });
2790
+ }
2791
+ encodeOnUninstall() {
2792
+ return viem.encodeFunctionData({
2793
+ abi: FORCE_EXIT_PARSED_ABI,
2794
+ functionName: "onUninstall",
2795
+ args: ["0x"]
2796
+ });
2797
+ }
2798
+ /**
2799
+ * Encode calldata for proposeForceExit — the exit payload to bridge out of L2.
2800
+ * `target` is the L2→L1 bridge contract; `data` is the bridge call payload.
2801
+ */
2802
+ encodeProposeForceExit(target, value, data) {
2803
+ return viem.encodeFunctionData({
2804
+ abi: FORCE_EXIT_PARSED_ABI,
2805
+ functionName: "proposeForceExit",
2806
+ args: [target, value, data]
2807
+ });
2808
+ }
2809
+ /**
2810
+ * Encode calldata for approveForceExit — guardian signs off on the pending proposal.
2811
+ * `guardianSig` must be an EIP-191 personal_sign over the proposal hash.
2812
+ */
2813
+ encodeApproveForceExit(account, guardianSig) {
2814
+ return viem.encodeFunctionData({
2815
+ abi: FORCE_EXIT_PARSED_ABI,
2816
+ functionName: "approveForceExit",
2817
+ args: [account, guardianSig]
2818
+ });
2819
+ }
2820
+ encodeExecuteForceExit(account) {
2821
+ return viem.encodeFunctionData({
2822
+ abi: FORCE_EXIT_PARSED_ABI,
2823
+ functionName: "executeForceExit",
2824
+ args: [account]
2825
+ });
2826
+ }
2827
+ encodeCancelForceExit(account) {
2828
+ return viem.encodeFunctionData({
2829
+ abi: FORCE_EXIT_PARSED_ABI,
2830
+ functionName: "cancelForceExit",
2831
+ args: [account]
2832
+ });
2833
+ }
2834
+ // ── Convenience: send transactions (requires a WalletClient) ──────────
2835
+ async proposeForceExit(target, value, data) {
2836
+ return await this.contract.write.proposeForceExit([
2837
+ target,
2838
+ value,
2839
+ data
2840
+ ]);
2841
+ }
2842
+ async approveForceExit(account, guardianSig) {
2843
+ return await this.contract.write.approveForceExit([
2844
+ account,
2845
+ guardianSig
2846
+ ]);
2847
+ }
2848
+ async executeForceExit(account) {
2849
+ return await this.contract.write.executeForceExit([account]);
2850
+ }
2851
+ async cancelForceExit(account) {
2852
+ return await this.contract.write.cancelForceExit([account]);
2853
+ }
2854
+ };
2855
+ var AIRACCOUNT_ABI_PARSED2 = viem.parseAbi(AIRACCOUNT_ABI);
2856
+ var RECOVERY_THRESHOLD = 2;
2857
+ var MAX_GUARDIANS = 3;
2858
+ var RECOVERY_TIMELOCK_SECONDS = 2n * 24n * 60n * 60n;
2859
+ var GUARDIAN_SIG_VERSION = 4;
2860
+ function popcount(value) {
2861
+ let v = value;
2862
+ let count = 0;
2863
+ while (v > 0n) {
2864
+ count += Number(v & 1n);
2865
+ v >>= 1n;
2866
+ }
2867
+ return count;
2868
+ }
2869
+ var RecoveryService = class {
2870
+ /**
2871
+ * @param client viem read client (was `ethers.Provider | ethers.Signer`). Only
2872
+ * on-chain reads are performed here; calldata encoders are pure and never
2873
+ * touch the client.
2874
+ */
2875
+ constructor(client) {
2876
+ this.client = client;
2877
+ }
2878
+ // ── Calldata encoders (submit TO the account address) ─────────────
2879
+ /**
2880
+ * Encode `addGuardian(guardian)` calldata. **Owner only.**
2881
+ * Registers a recovery guardian; reverts once 3 guardians are set, or if the
2882
+ * guardian is `address(0)`, the owner, or already registered.
2883
+ */
2884
+ encodeAddGuardian(guardian) {
2885
+ return viem.encodeFunctionData({
2886
+ abi: AIRACCOUNT_ABI_PARSED2,
2887
+ functionName: "addGuardian",
2888
+ args: [guardian]
2889
+ });
2890
+ }
2891
+ /**
2892
+ * Encode `removeGuardian(index, guardianSigs)` calldata. **Owner only**, and
2893
+ * requires >= {@link RECOVERY_THRESHOLD} guardian signatures over the removal
2894
+ * hash. Cannot remove while a recovery is active, nor drop below 2 guardians.
2895
+ *
2896
+ * @param index Guardian slot to remove (0-indexed).
2897
+ * @param guardianSigs EIP-191 guardian signatures over the removal hash.
2898
+ */
2899
+ encodeRemoveGuardian(index, guardianSigs) {
2900
+ return viem.encodeFunctionData({
2901
+ abi: AIRACCOUNT_ABI_PARSED2,
2902
+ functionName: "removeGuardian",
2903
+ args: [index, guardianSigs]
2904
+ });
2905
+ }
2906
+ /**
2907
+ * Build the RAW (un-prefixed) challenge hash that each guardian must sign to
2908
+ * authorize `removeGuardian(index, ...)` / `removeGuardianWithMixedSigs(...)`.
2909
+ *
2910
+ * ## v0.20.0 breaking change (#120 final-review [HIGH], spec §6.4)
2911
+ * The signed `opData` changed from `abi.encode(nonce, guardianToRemove)` to
2912
+ * `abi.encode(nonce, index, guardianToRemove, p256X, p256Y)` — it now binds the
2913
+ * SLOT INDEX and the slot's P-256 key. Because P-256 guardians all share the
2914
+ * sentinel address, the old 2-field payload was identical for every P-256 slot,
2915
+ * so a signature collected to remove slot A could be replayed to remove slot B
2916
+ * (or survive a key rotation). The new 5-field payload affects EVERY removal,
2917
+ * including the plain ECDSA path: for an ECDSA slot `p256X`/`p256Y` are both
2918
+ * `bytes32(0)`, but the payload STRUCTURE (extra `index` + two key words) still
2919
+ * changed, so the ECDSA `removeGuardian` signing payload MUST use this encoding.
2920
+ *
2921
+ * Hash construction (matches `AAStarAirAccountBase._guardianOpHash`):
2922
+ * ```
2923
+ * opData = abi.encode(uint256 nonce, uint8 index, address guardianToRemove,
2924
+ * bytes32 p256X, bytes32 p256Y)
2925
+ * challenge = keccak256(abi.encode(uint8 GUARDIAN_SIG_VERSION, uint256 chainId,
2926
+ * address account, "REMOVE_GUARDIAN", bytes opData))
2927
+ * ```
2928
+ * The contract additionally applies `toEthSignedMessageHash()` before
2929
+ * `ecrecover`, so this returns the RAW inner hash and each guardian signs it via
2930
+ * `personal_sign` / `signMessage({ raw: hash })` (which adds the EIP-191 prefix).
2931
+ * Do NOT pre-apply the prefix here (mirrors `buildGuardianAcceptanceHash`).
2932
+ *
2933
+ * @param account The AirAccount address whose guardian is being removed.
2934
+ * @param chainId EVM chain id (bound into the challenge).
2935
+ * @param removalNonce Current `_guardianRemovalNonce` — there is no on-chain
2936
+ * getter (internal storage slot 15), so the caller tracks
2937
+ * it (starts at 0, increments once per successful removal).
2938
+ * @param index Guardian slot being removed (0-indexed, < guardianCount).
2939
+ * @param guardianToRemove Address stored in that slot (a P-256 slot stores
2940
+ * {@link P256_GUARDIAN_SENTINEL}; an ECDSA slot stores the EOA).
2941
+ * @param p256X Slot's P-256 x coordinate; `bytes32(0)` for an ECDSA slot (default).
2942
+ * @param p256Y Slot's P-256 y coordinate; `bytes32(0)` for an ECDSA slot (default).
2943
+ * @returns raw hex keccak256 challenge — guardians sign it with `personal_sign`.
2944
+ */
2945
+ buildRemoveGuardianHash(args) {
2946
+ const ZERO323 = "0x0000000000000000000000000000000000000000000000000000000000000000";
2947
+ const opData = viem.encodeAbiParameters(
2948
+ [
2949
+ { type: "uint256" },
2950
+ // _guardianRemovalNonce
2951
+ { type: "uint8" },
2952
+ // index
2953
+ { type: "address" },
2954
+ // guardianToRemove
2955
+ { type: "bytes32" },
2956
+ // p256X (0 for ECDSA slot)
2957
+ { type: "bytes32" }
2958
+ // p256Y (0 for ECDSA slot)
2959
+ ],
2960
+ [
2961
+ args.removalNonce,
2962
+ args.index,
2963
+ args.guardianToRemove,
2964
+ args.p256X ?? ZERO323,
2965
+ args.p256Y ?? ZERO323
2966
+ ]
2967
+ );
2968
+ return viem.keccak256(
2969
+ viem.encodeAbiParameters(
2970
+ [
2971
+ { type: "uint8" },
2972
+ // GUARDIAN_SIG_VERSION
2973
+ { type: "uint256" },
2974
+ // chainId
2975
+ { type: "address" },
2976
+ // address(this) — the account
2977
+ { type: "string" },
2978
+ // opLabel
2979
+ { type: "bytes" }
2980
+ // opData
2981
+ ],
2982
+ [
2983
+ GUARDIAN_SIG_VERSION,
2984
+ BigInt(args.chainId),
2985
+ args.account,
2986
+ "REMOVE_GUARDIAN",
2987
+ opData
2988
+ ]
2989
+ )
2990
+ );
2991
+ }
2992
+ /**
2993
+ * Encode `proposeRecovery(newOwner)` calldata. **Any guardian** may call.
2994
+ * Starts the {@link RECOVERY_TIMELOCK_SECONDS} timelock and records the
2995
+ * proposer's approval (1 of {@link RECOVERY_THRESHOLD}).
2996
+ */
2997
+ encodeProposeRecovery(newOwner) {
2998
+ return viem.encodeFunctionData({
2999
+ abi: AIRACCOUNT_ABI_PARSED2,
3000
+ functionName: "proposeRecovery",
3001
+ args: [newOwner]
3002
+ });
3003
+ }
3004
+ /**
3005
+ * Encode `approveRecovery()` calldata. **Another guardian** approves the
3006
+ * active proposal, setting its bit in `approvalBitmap`.
3007
+ */
3008
+ encodeApproveRecovery() {
3009
+ return viem.encodeFunctionData({
3010
+ abi: AIRACCOUNT_ABI_PARSED2,
3011
+ functionName: "approveRecovery",
3012
+ args: []
3013
+ });
3014
+ }
3015
+ /**
3016
+ * Encode `cancelRecovery()` calldata. **Guardians only** — each call is one
3017
+ * vote; recovery is dropped once {@link RECOVERY_THRESHOLD} cancel votes are
3018
+ * reached. The owner cannot cancel.
3019
+ */
3020
+ encodeCancelRecovery() {
3021
+ return viem.encodeFunctionData({
3022
+ abi: AIRACCOUNT_ABI_PARSED2,
3023
+ functionName: "cancelRecovery",
3024
+ args: []
3025
+ });
3026
+ }
3027
+ /**
3028
+ * Encode `executeRecovery()` calldata. **Anyone** may call, but it only
3029
+ * succeeds once the timelock has elapsed and the approval threshold is met.
3030
+ * Rotates the account owner to the proposed `newOwner`.
3031
+ */
3032
+ encodeExecuteRecovery() {
3033
+ return viem.encodeFunctionData({
3034
+ abi: AIRACCOUNT_ABI_PARSED2,
3035
+ functionName: "executeRecovery",
3036
+ args: []
3037
+ });
3038
+ }
3039
+ // ── On-chain reads (against the account address) ──────────────────
3040
+ /**
3041
+ * Read and decode the account's `activeRecovery()` struct.
3042
+ * Returns derived `approvalCount`, `cancellationCount`, `executeAfter`, and
3043
+ * `isActive` alongside the raw fields.
3044
+ *
3045
+ * @param account The AirAccount address to query.
3046
+ */
3047
+ async getActiveRecovery(account) {
3048
+ const [newOwner, proposedAt, approvalBitmap, cancellationBitmap] = await this.client.readContract({
3049
+ address: account,
3050
+ abi: AIRACCOUNT_ABI_PARSED2,
3051
+ functionName: "activeRecovery"
3052
+ });
3053
+ const proposedAtBn = BigInt(proposedAt);
3054
+ const approvalBitmapBn = BigInt(approvalBitmap);
3055
+ const cancellationBitmapBn = BigInt(cancellationBitmap);
3056
+ return {
3057
+ newOwner,
3058
+ proposedAt: proposedAtBn,
3059
+ approvalBitmap: approvalBitmapBn,
3060
+ cancellationBitmap: cancellationBitmapBn,
3061
+ approvalCount: popcount(approvalBitmapBn),
3062
+ cancellationCount: popcount(cancellationBitmapBn),
3063
+ executeAfter: proposedAtBn + RECOVERY_TIMELOCK_SECONDS,
3064
+ isActive: newOwner.toLowerCase() !== viem.zeroAddress
3065
+ };
3066
+ }
3067
+ /**
3068
+ * Read the number of registered guardians via `guardianCount()`.
3069
+ *
3070
+ * @param account The AirAccount address to query.
3071
+ */
3072
+ async getGuardianCount(account) {
3073
+ const count = await this.client.readContract({
3074
+ address: account,
3075
+ abi: AIRACCOUNT_ABI_PARSED2,
3076
+ functionName: "guardianCount"
3077
+ });
3078
+ return Number(count);
3079
+ }
3080
+ /**
3081
+ * Read the full guardian address list.
3082
+ *
3083
+ * The V7 account exposes positional `guardians(uint256 i)` (3 packed slots) plus
3084
+ * `guardianCount()` — there is no single `getGuardians()` getter on the account
3085
+ * (that exists only on `AirAccountDelegate`, the EIP-7702 path). This reads slots
3086
+ * `0..guardianCount-1` and returns the non-zero guardian addresses.
3087
+ *
3088
+ * @param account The AirAccount address to query.
3089
+ */
3090
+ async getGuardians(account) {
3091
+ const count = Number(
3092
+ await this.client.readContract({
3093
+ address: account,
3094
+ abi: AIRACCOUNT_ABI_PARSED2,
3095
+ functionName: "guardianCount"
3096
+ })
3097
+ );
3098
+ const guardians = [];
3099
+ for (let i = 0; i < count; i++) {
3100
+ const g = await this.client.readContract({
3101
+ address: account,
3102
+ abi: AIRACCOUNT_ABI_PARSED2,
3103
+ functionName: "guardians",
3104
+ args: [BigInt(i)]
3105
+ });
3106
+ if (g.toLowerCase() !== viem.zeroAddress) guardians.push(g);
3107
+ }
3108
+ return guardians;
3109
+ }
3110
+ };
3111
+ var DELEGATE_ABI = [
3112
+ "function initialize(address guardian1, bytes calldata g1Sig, address guardian2, bytes calldata g2Sig, uint256 dailyLimit) external",
3113
+ "function owner() external view returns (address)",
3114
+ "function isInitialized() external view returns (bool)",
3115
+ "function entryPoint() external view returns (address)",
3116
+ "function getGuardians() external view returns (address[3] memory)",
3117
+ "function getDeposit() external view returns (uint256)",
3118
+ "function execute(address dest, uint256 value, bytes calldata data) external",
3119
+ "function executeBatch(address[] calldata dest, uint256[] calldata value, bytes[] calldata data) external",
3120
+ "function validateUserOp((address sender, uint256 nonce, bytes initCode, bytes callData, bytes32 accountGasLimits, uint256 preVerificationGas, bytes32 gasFees, bytes paymasterAndData, bytes signature) calldata userOp, bytes32 userOpHash, uint256 missingFunds) external returns (uint256)",
3121
+ "function initiateRescue(address rescueTo) external",
3122
+ "function approveRescue() external",
3123
+ "function cancelRescue() external",
3124
+ "function executeRescue() external",
3125
+ "function addDeposit() external payable",
3126
+ "function withdrawDepositTo(address to, uint256 amount) external",
3127
+ "error AlreadyInitialized()",
3128
+ "error NotInitialized()",
3129
+ "error InvalidAddress()",
3130
+ "error InvalidGuardianSignature()"
3131
+ ];
3132
+ var AIR_ACCOUNT_DELEGATE_ADDRESS = "0x8603AAF6C3f07fdae810B323c95a198D796EC52E";
3133
+ var EIP7702DelegateService = class {
3134
+ constructor(delegateAddress = AIR_ACCOUNT_DELEGATE_ADDRESS, client) {
3135
+ this.delegateAddress = delegateAddress;
3136
+ this.abi = viem.parseAbi(DELEGATE_ABI);
3137
+ this.client = client;
3138
+ }
3139
+ /** Parsed ABI (loose viem `Abi` shape) used for encoding calldata and on-chain reads. */
3140
+ abi;
3141
+ /** Optional viem read client (was `ethers.Provider | ethers.Signer`). Required only for on-chain reads. */
3142
+ client;
3143
+ // ── Calldata encoders ─────────────────────────────────────────
3144
+ /**
3145
+ * Encode initialize() calldata for the first post-delegation UserOp.
3146
+ * Must be the callData of a UserOp sent immediately after the SET_CODE delegation activates.
3147
+ * Guardian acceptance sigs follow the same EIP-712 scheme as AirAccountV7 createAccount.
3148
+ */
3149
+ encodeInitialize(params) {
3150
+ return viem.encodeFunctionData({
3151
+ abi: this.abi,
3152
+ functionName: "initialize",
3153
+ args: [
3154
+ params.guardian1,
3155
+ params.guardian1Sig,
3156
+ params.guardian2,
3157
+ params.guardian2Sig,
3158
+ params.dailyLimit
3159
+ ]
3160
+ });
3161
+ }
3162
+ encodeExecute(dest, value, data) {
3163
+ return viem.encodeFunctionData({
3164
+ abi: this.abi,
3165
+ functionName: "execute",
3166
+ args: [dest, value, data]
3167
+ });
3168
+ }
3169
+ encodeExecuteBatch(dests, values, datas) {
3170
+ return viem.encodeFunctionData({
3171
+ abi: this.abi,
3172
+ functionName: "executeBatch",
3173
+ args: [dests, values, datas]
3174
+ });
3175
+ }
3176
+ // ── EIP-7702 authorization hash construction ──────────────────
3177
+ /**
3178
+ * Compute the EIP-7702 SET_CODE authorization hash that the EOA must sign.
3179
+ *
3180
+ * Hash = keccak256(0x05 || RLP([chainId, address, nonce]))
3181
+ *
3182
+ * This is the hash the private key signs to delegate code execution to
3183
+ * AirAccountDelegate. Use this hash with your KMS sign-hash endpoint or
3184
+ * local viem account.
3185
+ *
3186
+ * @param chainId - Target chain ID (11155111 for Sepolia)
3187
+ * @param nonce - EOA's current transaction nonce
3188
+ * @returns 32-byte hash (0x-prefixed) ready for signing
3189
+ */
3190
+ buildAuthorizationHash(chainId, nonce) {
3191
+ return buildAuthorizationHash(chainId, nonce, this.delegateAddress);
3192
+ }
3193
+ /**
3194
+ * Build the full EIP-7702 authorization object for relay submission.
3195
+ * The caller must sign `buildAuthorizationHash()` externally and pass the result here.
3196
+ *
3197
+ * @param chainId - Target chain ID
3198
+ * @param nonce - EOA's current nonce
3199
+ * @param signature - 65-byte ECDSA signature (R||S||V) over the authorization hash
3200
+ */
3201
+ buildAuthorization(chainId, nonce, signature) {
3202
+ return {
3203
+ chainId,
3204
+ address: this.delegateAddress,
3205
+ nonce,
3206
+ signature
3207
+ };
3208
+ }
3209
+ /**
3210
+ * Verify that a signature is a valid EIP-7702 authorization for the given EOA address.
3211
+ * Recovers the signer from the authorization hash and checks it matches `eoa`.
3212
+ *
3213
+ * NOTE: now async — viem's `recoverAddress` is asynchronous (ethers' was sync).
3214
+ */
3215
+ verifyAuthorization(eoa, chainId, nonce, signature) {
3216
+ return verifyAuthorization(
3217
+ eoa,
3218
+ chainId,
3219
+ nonce,
3220
+ signature,
3221
+ this.delegateAddress
3222
+ );
3223
+ }
3224
+ // ── On-chain reads (requires provider) ───────────────────────
3225
+ async isInitialized(eoa) {
3226
+ if (!this.client) throw new Error("EIP7702DelegateService: provider required for on-chain reads");
3227
+ return await this.client.readContract({
3228
+ address: eoa,
3229
+ abi: this.abi,
3230
+ functionName: "isInitialized"
3231
+ });
3232
+ }
3233
+ async getOwner(eoa) {
3234
+ if (!this.client) throw new Error("EIP7702DelegateService: provider required for on-chain reads");
3235
+ return await this.client.readContract({
3236
+ address: eoa,
3237
+ abi: this.abi,
3238
+ functionName: "owner"
3239
+ });
3240
+ }
3241
+ async getGuardians(eoa) {
3242
+ if (!this.client) throw new Error("EIP7702DelegateService: provider required for on-chain reads");
3243
+ return await this.client.readContract({
3244
+ address: eoa,
3245
+ abi: this.abi,
3246
+ functionName: "getGuardians"
3247
+ });
3248
+ }
3249
+ };
3250
+ var WEIGHTED_SIGNATURE_ABI = [
3251
+ // Direct owner set (first-time / strengthening only)
3252
+ "function setWeightConfig((uint8 passkeyWeight, uint8 ecdsaWeight, uint8 blsWeight, uint8 guardian0Weight, uint8 guardian1Weight, uint8 guardian2Weight, uint8 _padding, uint8 tier1Threshold, uint8 tier2Threshold, uint8 tier3Threshold) config) external",
3253
+ // Guardian-governed change flow (required for any weakening)
3254
+ "function proposeWeightChange((uint8 passkeyWeight, uint8 ecdsaWeight, uint8 blsWeight, uint8 guardian0Weight, uint8 guardian1Weight, uint8 guardian2Weight, uint8 _padding, uint8 tier1Threshold, uint8 tier2Threshold, uint8 tier3Threshold) proposed) external",
3255
+ "function approveWeightChange() external",
3256
+ "function cancelWeightChange() external",
3257
+ "function executeWeightChange() external",
3258
+ // State readers
3259
+ "function weightConfig() external view returns (uint8 passkeyWeight, uint8 ecdsaWeight, uint8 blsWeight, uint8 guardian0Weight, uint8 guardian1Weight, uint8 guardian2Weight, uint8 _padding, uint8 tier1Threshold, uint8 tier2Threshold, uint8 tier3Threshold)",
3260
+ "function pendingWeightChange() external view returns ((uint8 passkeyWeight, uint8 ecdsaWeight, uint8 blsWeight, uint8 guardian0Weight, uint8 guardian1Weight, uint8 guardian2Weight, uint8 _padding, uint8 tier1Threshold, uint8 tier2Threshold, uint8 tier3Threshold) proposed, uint256 proposedAt, uint256 approvalBitmap)",
3261
+ // Errors (for decoding reverts)
3262
+ "error InsecureWeightConfig()",
3263
+ "error WeakeningRequiresProposal()",
3264
+ "error WeightChangePending()",
3265
+ "error NoWeightChangeProposal()",
3266
+ "error WeightChangeAlreadyApproved()",
3267
+ "error WeightChangeNotApproved()",
3268
+ "error WeightChangeTimelockNotExpired()"
3269
+ ];
3270
+ var WEIGHTED_SIGNATURE_ABI_PARSED = viem.parseAbi(WEIGHTED_SIGNATURE_ABI);
3271
+ var WEIGHT_CHANGE_TIMELOCK_SECONDS = 2 * 24 * 60 * 60;
3272
+ var WEIGHT_CHANGE_THRESHOLD = 2;
3273
+ var WEIGHT_CHANGE_EXPIRY_SECONDS = 30 * 24 * 60 * 60;
3274
+ var WEIGHT_CONFIG_FIELDS = [
3275
+ "passkeyWeight",
3276
+ "ecdsaWeight",
3277
+ "blsWeight",
3278
+ "guardian0Weight",
3279
+ "guardian1Weight",
3280
+ "guardian2Weight",
3281
+ "_padding",
3282
+ "tier1Threshold",
3283
+ "tier2Threshold",
3284
+ "tier3Threshold"
3285
+ ];
3286
+ function toConfigTuple(config) {
3287
+ return WEIGHT_CONFIG_FIELDS.map((f) => config[f]);
3288
+ }
3289
+ function fromConfigResult(result) {
3290
+ const r = result;
3291
+ const pick = (name, idx) => Number(r[name] ?? r[idx]);
3292
+ return {
3293
+ passkeyWeight: pick("passkeyWeight", 0),
3294
+ ecdsaWeight: pick("ecdsaWeight", 1),
3295
+ blsWeight: pick("blsWeight", 2),
3296
+ guardian0Weight: pick("guardian0Weight", 3),
3297
+ guardian1Weight: pick("guardian1Weight", 4),
3298
+ guardian2Weight: pick("guardian2Weight", 5),
3299
+ _padding: pick("_padding", 6),
3300
+ tier1Threshold: pick("tier1Threshold", 7),
3301
+ tier2Threshold: pick("tier2Threshold", 8),
3302
+ tier3Threshold: pick("tier3Threshold", 9)
3303
+ };
3304
+ }
3305
+ var WeightedSignatureService = class {
3306
+ constructor(accountAddress, client) {
3307
+ this.accountAddress = accountAddress;
3308
+ this.client = client;
3309
+ this.address = accountAddress;
3310
+ }
3311
+ address;
3312
+ // ── On-chain reads ──────────────────────────────────────────────
3313
+ /** Read the account's current active WeightConfig. */
3314
+ async getWeightConfig() {
3315
+ const result = await this.client.readContract({
3316
+ address: this.address,
3317
+ abi: WEIGHTED_SIGNATURE_ABI_PARSED,
3318
+ functionName: "weightConfig"
3319
+ });
3320
+ return fromConfigResult(result);
3321
+ }
3322
+ /**
3323
+ * Read the pending weight-change proposal. When `proposedAt === 0n` there is no
3324
+ * active proposal (the returned `proposed` config will be all zeros).
3325
+ */
3326
+ async getPendingWeightChange() {
3327
+ const [proposed, proposedAt, approvalBitmap] = await this.client.readContract({
3328
+ address: this.address,
3329
+ abi: WEIGHTED_SIGNATURE_ABI_PARSED,
3330
+ functionName: "pendingWeightChange"
3331
+ });
3332
+ return {
3333
+ proposed: fromConfigResult(proposed),
3334
+ proposedAt: BigInt(proposedAt),
3335
+ approvalBitmap: BigInt(approvalBitmap)
3336
+ };
3337
+ }
3338
+ // ── Calldata encoders (for UserOp or direct tx submission) ─────
3339
+ /**
3340
+ * Encode setWeightConfig calldata. OWNER only; for first-time setup or strengthening.
3341
+ * Weakening an existing config must go through encodeProposeWeightChange instead.
3342
+ */
3343
+ encodeSetWeightConfig(config) {
3344
+ return viem.encodeFunctionData({
3345
+ abi: WEIGHTED_SIGNATURE_ABI_PARSED,
3346
+ functionName: "setWeightConfig",
3347
+ args: [toConfigTuple(config)]
3348
+ });
3349
+ }
3350
+ /**
3351
+ * Encode proposeWeightChange calldata. OWNER only; opens a guardian-governed proposal
3352
+ * (required for any weakening). Subject to 2-of-3 approval + 2-day timelock before execute.
3353
+ */
3354
+ encodeProposeWeightChange(config) {
3355
+ return viem.encodeFunctionData({
3356
+ abi: WEIGHTED_SIGNATURE_ABI_PARSED,
3357
+ functionName: "proposeWeightChange",
3358
+ args: [toConfigTuple(config)]
3359
+ });
3360
+ }
3361
+ /** Encode approveWeightChange calldata. GUARDIAN only; each guardian may approve once. */
3362
+ encodeApproveWeightChange() {
3363
+ return viem.encodeFunctionData({
3364
+ abi: WEIGHTED_SIGNATURE_ABI_PARSED,
3365
+ functionName: "approveWeightChange"
3366
+ });
3367
+ }
3368
+ /** Encode cancelWeightChange calldata. OWNER or any GUARDIAN may cancel a pending proposal. */
3369
+ encodeCancelWeightChange() {
3370
+ return viem.encodeFunctionData({
3371
+ abi: WEIGHTED_SIGNATURE_ABI_PARSED,
3372
+ functionName: "cancelWeightChange"
3373
+ });
3374
+ }
3375
+ /**
3376
+ * Encode executeWeightChange calldata. Callable by anyone, but only succeeds once the
3377
+ * threshold (2-of-3) and timelock (2 days) are both satisfied and the proposal has not expired.
3378
+ */
3379
+ encodeExecuteWeightChange() {
3380
+ return viem.encodeFunctionData({
3381
+ abi: WEIGHTED_SIGNATURE_ABI_PARSED,
3382
+ functionName: "executeWeightChange"
3383
+ });
3384
+ }
3385
+ };
3386
+ var AGENT_REGISTRY_ABI = [
3387
+ // ── Writes ──
3388
+ "function registerAgent(address agentWallet, bytes agentWalletSig) external",
3389
+ "function revokeAgent(address agentWallet) external",
3390
+ "function deregisterAgent(address agentWallet) external",
3391
+ // ── Reads ──
3392
+ "function isRegisteredAgent(address agentWallet) external view returns (bool)",
3393
+ "function isValidAccount(address account) external view returns (bool)",
3394
+ "function getHumanOwner(address agentWallet) external view returns (address)",
3395
+ "function getAgentCount(address owner) external view returns (uint256)",
3396
+ "function getAgentByIndex(address owner, uint256 index) external view returns (address)",
3397
+ "function getAgents(address humanOwner) external view returns (address[])",
3398
+ "function getAgentsPage(address owner, uint256 start, uint256 count) external view returns (address[] page)",
3399
+ "function agentWalletOwner(address agentWallet) external view returns (address)",
3400
+ "function ownerAgents(address owner, uint256 index) external view returns (address)",
3401
+ "function balanceOf(address humanOwner) external view returns (uint256)",
3402
+ // ── Errors (for decoding reverts) ──
3403
+ "error AgentAlreadyRegistered()",
3404
+ "error CallerNotAirAccount()",
3405
+ "error InvalidAddress()",
3406
+ "error InvalidAgentSignature()",
3407
+ "error NotAgentOwner()",
3408
+ "error SelfRegistrationForbidden()"
3409
+ ];
3410
+ var REGISTRY_ABI = viem.parseAbi(AGENT_REGISTRY_ABI);
3411
+ var FACTORY_ABI2 = viem.parseAbi(AIRACCOUNT_FACTORY_ABI);
3412
+ var ACCOUNT_ABI3 = viem.parseAbi(AIRACCOUNT_ABI);
3413
+ var AgentRegistryService = class {
3414
+ /**
3415
+ * @param client viem PublicClient for on-chain reads (e.g. `ethereum.getProvider()`).
3416
+ * @param registryAddress deployed AgentRegistry contract address.
3417
+ */
3418
+ constructor(client, registryAddress) {
3419
+ this.registryAddress = registryAddress;
3420
+ this.client = client;
3421
+ }
3422
+ client;
3423
+ // ── Composed register/revoke-via-account scenario encoders ──────────────────
3424
+ // registerAgent/revokeAgent require msg.sender == the agent account, so they are delivered
3425
+ // through the account's execute(registry, 0, calldata). These return the FULL execute
3426
+ // calldata to submit TO the agent account (owner-signed) — the scenario-level entry point.
3427
+ /** Encode `account.execute(registry, 0, registerAgent(agentWallet, agentWalletSig))`. */
3428
+ encodeRegisterAgentViaAccount(agentWallet, agentWalletSig) {
3429
+ return viem.encodeFunctionData({
3430
+ abi: ACCOUNT_ABI3,
3431
+ functionName: "execute",
3432
+ args: [
3433
+ this.registryAddress,
3434
+ 0n,
3435
+ this.encodeRegisterAgent(agentWallet, agentWalletSig)
3436
+ ]
3437
+ });
3438
+ }
3439
+ /** Encode `account.execute(registry, 0, revokeAgent(agentWallet))`. */
3440
+ encodeRevokeAgentViaAccount(agentWallet) {
3441
+ return viem.encodeFunctionData({
3442
+ abi: ACCOUNT_ABI3,
3443
+ functionName: "execute",
3444
+ args: [this.registryAddress, 0n, this.encodeRevokeAgent(agentWallet)]
3445
+ });
3446
+ }
3447
+ // ── AgentRegistry calldata encoders ─────────────────────────────────────────
3448
+ /**
3449
+ * Encode calldata for `registerAgent(agentWallet, agentWalletSig)`.
3450
+ *
3451
+ * Binds `agentWallet` to the caller (the human owner). `agentWalletSig` must be the agent
3452
+ * wallet's EIP-191 signature proving control of the key. Reverts with
3453
+ * `SelfRegistrationForbidden` if the caller registers itself, or `AgentAlreadyRegistered`
3454
+ * if the wallet is already bound.
3455
+ */
3456
+ encodeRegisterAgent(agentWallet, agentWalletSig) {
3457
+ return viem.encodeFunctionData({
3458
+ abi: REGISTRY_ABI,
3459
+ functionName: "registerAgent",
3460
+ args: [agentWallet, agentWalletSig]
3461
+ });
3462
+ }
3463
+ /**
3464
+ * Encode calldata for `revokeAgent(agentWallet)`.
3465
+ *
3466
+ * Owner-initiated revocation of a previously registered agent wallet. Caller must be the
3467
+ * agent's human owner (else `NotAgentOwner`).
3468
+ */
3469
+ encodeRevokeAgent(agentWallet) {
3470
+ return viem.encodeFunctionData({
3471
+ abi: REGISTRY_ABI,
3472
+ functionName: "revokeAgent",
3473
+ args: [agentWallet]
3474
+ });
3475
+ }
3476
+ /**
3477
+ * Encode calldata for `deregisterAgent(agentWallet)`.
3478
+ *
3479
+ * Removes the agent wallet from the registry (full deregistration, distinct from the
3480
+ * lighter-weight `revokeAgent`). Caller must be the agent's human owner.
3481
+ */
3482
+ encodeDeregisterAgent(agentWallet) {
3483
+ return viem.encodeFunctionData({
3484
+ abi: REGISTRY_ABI,
3485
+ functionName: "deregisterAgent",
3486
+ args: [agentWallet]
3487
+ });
3488
+ }
3489
+ // ── AgentRegistry on-chain reads ────────────────────────────────────────────
3490
+ /** Whether `agentWallet` is currently registered in the registry. */
3491
+ async isRegisteredAgent(agentWallet) {
3492
+ return await this.client.readContract({
3493
+ address: this.registryAddress,
3494
+ abi: REGISTRY_ABI,
3495
+ functionName: "isRegisteredAgent",
3496
+ args: [agentWallet]
3497
+ });
3498
+ }
3499
+ /** Whether `account` has been marked valid (e.g. an AirAccount minted by the bound factory). */
3500
+ async isValidAccount(account) {
3501
+ return await this.client.readContract({
3502
+ address: this.registryAddress,
3503
+ abi: REGISTRY_ABI,
3504
+ functionName: "isValidAccount",
3505
+ args: [account]
3506
+ });
3507
+ }
3508
+ /** The human owner bound to `agentWallet` (ZeroAddress if unregistered). */
3509
+ async getHumanOwner(agentWallet) {
3510
+ return await this.client.readContract({
3511
+ address: this.registryAddress,
3512
+ abi: REGISTRY_ABI,
3513
+ functionName: "getHumanOwner",
3514
+ args: [agentWallet]
3515
+ });
3516
+ }
3517
+ /** Number of agents registered under `owner`. */
3518
+ async getAgentCount(owner) {
3519
+ return BigInt(
3520
+ await this.client.readContract({
3521
+ address: this.registryAddress,
3522
+ abi: REGISTRY_ABI,
3523
+ functionName: "getAgentCount",
3524
+ args: [owner]
3525
+ })
3526
+ );
3527
+ }
3528
+ /** The agent wallet at `index` in `owner`'s agent list. */
3529
+ async getAgentByIndex(owner, index) {
3530
+ return await this.client.readContract({
3531
+ address: this.registryAddress,
3532
+ abi: REGISTRY_ABI,
3533
+ functionName: "getAgentByIndex",
3534
+ args: [owner, BigInt(index)]
3535
+ });
3536
+ }
3537
+ /** Full list of agent wallets registered under `humanOwner`. */
3538
+ async getAgents(humanOwner) {
3539
+ const result = await this.client.readContract({
3540
+ address: this.registryAddress,
3541
+ abi: REGISTRY_ABI,
3542
+ functionName: "getAgents",
3543
+ args: [humanOwner]
3544
+ });
3545
+ return Array.from(result);
3546
+ }
3547
+ /**
3548
+ * Paginated slice of `owner`'s agent wallets: `count` entries starting at `start`.
3549
+ * The contract clamps `count` to the remaining length, so the returned array may be shorter.
3550
+ */
3551
+ async getAgentsPage(owner, start, count) {
3552
+ const result = await this.client.readContract({
3553
+ address: this.registryAddress,
3554
+ abi: REGISTRY_ABI,
3555
+ functionName: "getAgentsPage",
3556
+ args: [owner, BigInt(start), BigInt(count)]
3557
+ });
3558
+ return Array.from(result);
3559
+ }
3560
+ /** Raw `agentWalletOwner` mapping read (agentWallet → owner). */
3561
+ async agentWalletOwner(agentWallet) {
3562
+ return await this.client.readContract({
3563
+ address: this.registryAddress,
3564
+ abi: REGISTRY_ABI,
3565
+ functionName: "agentWalletOwner",
3566
+ args: [agentWallet]
3567
+ });
3568
+ }
3569
+ /** Raw `ownerAgents` array read (owner, index → agentWallet). */
3570
+ async ownerAgents(owner, index) {
3571
+ return await this.client.readContract({
3572
+ address: this.registryAddress,
3573
+ abi: REGISTRY_ABI,
3574
+ functionName: "ownerAgents",
3575
+ args: [owner, BigInt(index)]
3576
+ });
3577
+ }
3578
+ // ── Factory agent-account helpers (AAStarAirAccountFactoryV7) ───────────────
3579
+ /**
3580
+ * Encode calldata for the factory's `createAgentAccount(...)`.
3581
+ *
3582
+ * Targets the AAStarAirAccountFactoryV7, NOT the AgentRegistry. The factory deploys the agent
3583
+ * AirAccount and registers it in the bound AgentRegistry in one transaction. Submit this
3584
+ * calldata to the factory address (direct tx or via a relayer).
3585
+ */
3586
+ encodeCreateAgentAccount(params) {
3587
+ return viem.encodeFunctionData({
3588
+ abi: FACTORY_ABI2,
3589
+ functionName: "createAgentAccount",
3590
+ args: [
3591
+ params.agentKey,
3592
+ params.agentId,
3593
+ params.guardian2,
3594
+ params.guardian2Sig,
3595
+ params.agentKeySig,
3596
+ BigInt(params.deadline),
3597
+ params.dailyLimit
3598
+ ]
3599
+ });
3600
+ }
3601
+ /**
3602
+ * Encode calldata for the factory's `setAgentRegistry(_agentRegistry)` (factory-admin only).
3603
+ */
3604
+ encodeSetAgentRegistry(agentRegistry) {
3605
+ return viem.encodeFunctionData({
3606
+ abi: FACTORY_ABI2,
3607
+ functionName: "setAgentRegistry",
3608
+ args: [agentRegistry]
3609
+ });
3610
+ }
3611
+ /**
3612
+ * Predict the CREATE2 address of an agent account via the factory's `getAgentAddress(...)`.
3613
+ *
3614
+ * @param factoryAddress AAStarAirAccountFactoryV7 address.
3615
+ * @param humanOwner the human guardian/owner co-owning the agent account.
3616
+ * @param agentKey the agent's signing key.
3617
+ * @param agentId the bytes32 agent identifier.
3618
+ */
3619
+ async getAgentAccountAddress(factoryAddress, humanOwner, agentKey, agentId) {
3620
+ return await this.client.readContract({
3621
+ address: factoryAddress,
3622
+ abi: FACTORY_ABI2,
3623
+ functionName: "getAgentAddress",
3624
+ args: [humanOwner, agentKey, agentId]
3625
+ });
3626
+ }
3627
+ /** Read the AgentRegistry address currently bound to the factory. */
3628
+ async getFactoryAgentRegistry(factoryAddress) {
3629
+ return await this.client.readContract({
3630
+ address: factoryAddress,
3631
+ abi: FACTORY_ABI2,
3632
+ functionName: "agentRegistry",
3633
+ args: []
3634
+ });
3635
+ }
3636
+ };
3637
+ var ERC8004_ABI = [
3638
+ "function setAgentWallet(uint256 agentId, address agentWallet, address agentRegistry, bytes agentWalletSig) external",
3639
+ "function mintAgentIdentity(address identityRegistry, string agentURI) external returns (uint256 agentId)",
3640
+ "function bindERC8004AgentWallet(address identityRegistry, uint256 agentId, address agentWallet, uint256 deadline, bytes signature) external",
3641
+ "function submitAgentReputation(address reputationRegistry, uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2, string endpoint, string feedbackURI, bytes32 feedbackHash) external",
3642
+ "function queryAgentReputation(address reputationRegistry, uint256 agentId, address[] clientAddresses, string tag1, string tag2) external view returns (uint64 count, int128 summaryValue, uint8 summaryDecimals)",
3643
+ "function agentExtension() external view returns (address)"
3644
+ ];
3645
+ var ERC8004_ADDRESSES = {
3646
+ mainnet: {
3647
+ identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
3648
+ reputationRegistry: "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63",
3649
+ validationRegistry: "0x8004Cc8439f36fd5F9F049D9fF86523Df6dAAB58"
3650
+ },
3651
+ testnet: {
3652
+ identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
3653
+ reputationRegistry: "0x8004B663056A597Dffe9eCcC1965A193B7388713",
3654
+ validationRegistry: "0x8004Cb1BF31DAf7788923b405b754f57acEB4272"
3655
+ }
3656
+ };
3657
+ var MAINNET_CHAIN_IDS = /* @__PURE__ */ new Set([1, 10, 137, 8453, 42161, 43114, 56, 534352, 100, 42220, 59144, 5e3, 167e3, 360]);
3658
+ var TESTNET_CHAIN_IDS = /* @__PURE__ */ new Set([11155111, 11155420, 84532, 421614, 80002]);
3659
+ function erc8004AddressesForChain(chainId) {
3660
+ if (MAINNET_CHAIN_IDS.has(chainId)) return ERC8004_ADDRESSES.mainnet;
3661
+ if (TESTNET_CHAIN_IDS.has(chainId)) return ERC8004_ADDRESSES.testnet;
3662
+ throw new Error(`ERC-8004: unsupported chain ${chainId}`);
3663
+ }
3664
+ var ERC8004Service = class {
3665
+ abi;
3666
+ provider;
3667
+ constructor(provider) {
3668
+ this.abi = viem.parseAbi(ERC8004_ABI);
3669
+ this.provider = provider;
3670
+ }
3671
+ /**
3672
+ * Build a read-only viem contract bound to the account address. The ABI is loaded from
3673
+ * human-readable signatures via `parseAbi` (loose `Abi`), so `read` methods are indexed by
3674
+ * name and return `unknown` — cast at the call site. Mirrors the dynamic surface that
3675
+ * `ethers.Contract` previously exposed. Caller must ensure `this.provider` is set.
3676
+ */
3677
+ contractAt(accountAddress) {
3678
+ return viem.getContract({
3679
+ address: accountAddress,
3680
+ abi: this.abi,
3681
+ client: this.provider
3682
+ });
3683
+ }
3684
+ // ── AAStar AgentRegistry path ─────────────────────────────────────────────
3685
+ /**
3686
+ * Encode calldata for `setAgentWallet`.
3687
+ *
3688
+ * Registers `agentWallet` in the AAStar AgentRegistry (SuperPaymaster-facing). This is the
3689
+ * correct path when the goal is SuperPaymaster gasless sponsorship for the agent.
3690
+ *
3691
+ * **Not** a call to the official ERC-8004 IdentityRegistry. Use `encodeMintAgentIdentity`
3692
+ * + `encodeBindERC8004AgentWallet` for the ERC-8004 standard path.
3693
+ *
3694
+ * Callable: owner EOA direct tx OR via UserOp (gasless).
3695
+ */
3696
+ encodeSetAgentWallet(params) {
3697
+ return viem.encodeFunctionData({
3698
+ abi: this.abi,
3699
+ functionName: "setAgentWallet",
3700
+ args: [params.agentId, params.agentWallet, params.agentRegistry, params.agentWalletSig]
3701
+ });
3702
+ }
3703
+ // ── Official ERC-8004 identity path ──────────────────────────────────────
3704
+ /**
3705
+ * Encode calldata for `mintAgentIdentity`.
3706
+ *
3707
+ * Mints an ERC-721 agent identity NFT in the official ERC-8004 IdentityRegistry and returns
3708
+ * the new `agentId` (decoded from the tx receipt). The `identityRegistry` must be
3709
+ * `erc8004AddressesForChain(chainId).identityRegistry` — the contract reverts otherwise.
3710
+ *
3711
+ * Callable: owner EOA direct tx OR via UserOp (gasless).
3712
+ */
3713
+ encodeMintAgentIdentity(params) {
3714
+ return viem.encodeFunctionData({
3715
+ abi: this.abi,
3716
+ functionName: "mintAgentIdentity",
3717
+ args: [params.identityRegistry, params.agentURI]
3718
+ });
3719
+ }
3720
+ /**
3721
+ * Encode calldata for `bindERC8004AgentWallet`.
3722
+ *
3723
+ * Binds an execution wallet to an existing ERC-8004 agent identity NFT. Requires a
3724
+ * deadline-bounded signature from the expected signer (see the IdentityRegistry contract).
3725
+ * The `identityRegistry` must be the official chain-specific address.
3726
+ *
3727
+ * Callable: owner EOA direct tx OR via UserOp (gasless).
3728
+ */
3729
+ encodeBindERC8004AgentWallet(params) {
3730
+ return viem.encodeFunctionData({
3731
+ abi: this.abi,
3732
+ functionName: "bindERC8004AgentWallet",
3733
+ args: [
3734
+ params.identityRegistry,
3735
+ params.agentId,
3736
+ params.agentWallet,
3737
+ params.deadline,
3738
+ params.signature
3739
+ ]
3740
+ });
3741
+ }
3742
+ // ── Reputation ────────────────────────────────────────────────────────────
3743
+ /**
3744
+ * Encode calldata for `submitAgentReputation`.
3745
+ *
3746
+ * Submits a reputation feedback entry to the official ERC-8004 ReputationRegistry.
3747
+ * `reputationRegistry` must be `erc8004AddressesForChain(chainId).reputationRegistry`.
3748
+ *
3749
+ * Callable: owner EOA direct tx OR via UserOp (gasless).
3750
+ */
3751
+ encodeSubmitAgentReputation(params) {
3752
+ return viem.encodeFunctionData({
3753
+ abi: this.abi,
3754
+ functionName: "submitAgentReputation",
3755
+ args: [
3756
+ params.reputationRegistry,
3757
+ params.agentId,
3758
+ params.value,
3759
+ params.valueDecimals,
3760
+ params.tag1,
3761
+ params.tag2,
3762
+ params.endpoint,
3763
+ params.feedbackURI,
3764
+ params.feedbackHash
3765
+ ]
3766
+ });
3767
+ }
3768
+ /**
3769
+ * Query aggregated reputation for an agent from the official ERC-8004 ReputationRegistry.
3770
+ * Returns `null` when no provider was supplied at construction.
3771
+ */
3772
+ async queryAgentReputation(accountAddress, params) {
3773
+ if (!this.provider) throw new Error("ERC8004Service: provider required for on-chain reads");
3774
+ const contract = this.contractAt(accountAddress);
3775
+ const [count, summaryValue, summaryDecimals] = await contract.read.queryAgentReputation([
3776
+ params.reputationRegistry,
3777
+ params.agentId,
3778
+ params.clientAddresses,
3779
+ params.tag1,
3780
+ params.tag2
3781
+ ]);
3782
+ return { count: BigInt(count), summaryValue: BigInt(summaryValue), summaryDecimals: Number(summaryDecimals) };
3783
+ }
3784
+ /**
3785
+ * Encode calldata for `queryAgentReputation` (for static-call or eth_call without a signer).
3786
+ */
3787
+ encodeQueryAgentReputation(params) {
3788
+ return viem.encodeFunctionData({
3789
+ abi: this.abi,
3790
+ functionName: "queryAgentReputation",
3791
+ args: [
3792
+ params.reputationRegistry,
3793
+ params.agentId,
3794
+ params.clientAddresses,
3795
+ params.tag1,
3796
+ params.tag2
3797
+ ]
3798
+ });
3799
+ }
3800
+ /**
3801
+ * Read the agentExtension implementation address from a deployed AirAccount.
3802
+ */
3803
+ async getAgentExtensionAddress(accountAddress) {
3804
+ if (!this.provider) throw new Error("ERC8004Service: provider required for on-chain reads");
3805
+ const contract = this.contractAt(accountAddress);
3806
+ const extension = await contract.read.agentExtension([]);
3807
+ return extension;
3808
+ }
3809
+ };
3810
+ var DEFAULT_KMS_ENDPOINT = "https://kms.aastar.io";
3811
+ var KmsHttpClient = class {
3812
+ endpoint;
3813
+ enabled;
3814
+ logger;
3815
+ apiKey;
3816
+ http;
3817
+ constructor(options) {
3818
+ this.endpoint = options.kmsEndpoint ?? DEFAULT_KMS_ENDPOINT;
3819
+ this.enabled = options.kmsEnabled === true;
3820
+ this.apiKey = options.kmsApiKey;
3821
+ this.logger = options.logger ?? new ConsoleLogger("[KmsHttpClient]");
3822
+ const headers = { "Content-Type": "application/json" };
3823
+ if (this.apiKey) {
3824
+ headers["x-api-key"] = this.apiKey;
3825
+ }
3826
+ this.http = axios__default.default.create({ baseURL: this.endpoint, headers });
3827
+ }
3828
+ /** Throw if KMS is not enabled — every operation must call this first. */
3829
+ ensureEnabled() {
3830
+ if (!this.enabled) {
3831
+ throw new Error("KMS service is not enabled");
3832
+ }
3833
+ }
3834
+ /**
3835
+ * Plain JSON POST. The axios `config` arg is only forwarded when defined, so a
3836
+ * config-less call results in `http.post(path, body)` (2 args) — preserving the
3837
+ * exact call shape the existing unit tests assert against.
3838
+ */
3839
+ async post(path, body, config) {
3840
+ const response = config === void 0 ? await this.http.post(path, body) : await this.http.post(path, body, config);
3841
+ return response.data;
3842
+ }
3843
+ /** Plain JSON GET. */
3844
+ async get(path, config) {
3845
+ const response = config === void 0 ? await this.http.get(path) : await this.http.get(path, config);
3846
+ return response.data;
3847
+ }
3848
+ /** POST with AWS-KMS framing (x-amz-target header) — required for wallet/signing ops. */
3849
+ async amzPost(path, target, body) {
3850
+ return this.post(path, body, {
3851
+ headers: {
3852
+ "Content-Type": "application/x-amz-json-1.1",
3853
+ "x-amz-target": target
3854
+ }
3855
+ });
3856
+ }
3857
+ /** POST authenticated with a TEE-issued agent/session JWT (Authorization: Bearer). */
3858
+ async postWithBearer(path, body, jwt) {
3859
+ return this.post(path, body, {
3860
+ headers: { authorization: `Bearer ${jwt}` }
3861
+ });
3862
+ }
3863
+ };
3864
+
3865
+ // ../../node_modules/.pnpm/@noble+curves@2.0.1/node_modules/@noble/curves/nist.js
3866
+ var p256_CURVE = /* @__PURE__ */ (() => ({
3867
+ p: BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"),
3868
+ n: BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"),
3869
+ h: BigInt(1),
3870
+ a: BigInt("0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc"),
3871
+ b: BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"),
3872
+ Gx: BigInt("0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"),
3873
+ Gy: BigInt("0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")
3874
+ }))();
3875
+ var p256_Point = /* @__PURE__ */ chunkXQROKLZI_cjs.weierstrass(p256_CURVE);
3876
+ var p256 = /* @__PURE__ */ chunkXQROKLZI_cjs.ecdsa(p256_Point, chunkXQROKLZI_cjs.sha256);
3877
+
3878
+ // ../airaccount/src/server/services/webauthn-ceremony.ts
3879
+ var DEFAULT_RP_ID = "aastar.io";
3880
+ var DEFAULT_ORIGIN = "https://aastar.io";
3881
+ var DEFAULT_CREDENTIAL_ID = "dGVzdC1jcmVkZW50aWFs";
3882
+ function base64UrlEncode(bytes) {
3883
+ return Buffer.from(bytes).toString("base64url");
3884
+ }
3885
+ function base64UrlDecode(value) {
3886
+ return new Uint8Array(Buffer.from(value, "base64url"));
3887
+ }
3888
+ function hexToBytes4(hex) {
3889
+ const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
3890
+ if (clean.length % 2 !== 0) {
3891
+ throw new Error("hexToBytes: odd-length hex string");
3892
+ }
3893
+ const out = new Uint8Array(clean.length / 2);
3894
+ for (let i = 0; i < out.length; i++) {
3895
+ out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
3896
+ }
3897
+ return out;
3898
+ }
3899
+ var P256PasskeySigner = class {
3900
+ credentialId;
3901
+ privateKey;
3902
+ /**
3903
+ * @param privateKey raw 32-byte P-256 scalar (Uint8Array or hex, 0x optional).
3904
+ * @param credentialId base64url credential id (defaults to the reference fixture).
3905
+ */
3906
+ constructor(privateKey, credentialId = DEFAULT_CREDENTIAL_ID) {
3907
+ this.privateKey = typeof privateKey === "string" ? hexToBytes4(privateKey) : privateKey;
3908
+ this.credentialId = credentialId;
3909
+ }
3910
+ /**
3911
+ * Uncompressed (0x04…, 65-byte) P-256 public key hex. Register this with the
3912
+ * KMS via CreateKey `PasskeyPublicKey` (or ChangePasskey) so the TA can verify
3913
+ * assertions produced by this signer.
3914
+ */
3915
+ get publicKeyHex() {
3916
+ return "0x" + Buffer.from(p256.getPublicKey(this.privateKey, false)).toString("hex");
3917
+ }
3918
+ sign(message) {
3919
+ return p256.sign(message, this.privateKey, { prehash: true, format: "der" });
3920
+ }
3921
+ };
3922
+ function buildClientDataJSON(challenge, origin = DEFAULT_ORIGIN) {
3923
+ const json = JSON.stringify({ type: "webauthn.get", challenge, origin });
3924
+ return new TextEncoder().encode(json);
3925
+ }
3926
+ function buildAuthenticatorData(rpId = DEFAULT_RP_ID, signCount = 1) {
3927
+ const rpIdHash = crypto.createHash("sha256").update(rpId).digest();
3928
+ const out = new Uint8Array(37);
3929
+ out.set(rpIdHash, 0);
3930
+ out[32] = 5;
3931
+ new DataView(out.buffer).setUint32(33, signCount >>> 0, false);
3932
+ return out;
3933
+ }
3934
+ async function buildAuthenticationCredential(opts) {
3935
+ const origin = opts.origin ?? DEFAULT_ORIGIN;
3936
+ const rpId = opts.rpId ?? DEFAULT_RP_ID;
3937
+ const signCount = opts.signCount ?? 1;
3938
+ const clientDataJSON = buildClientDataJSON(opts.challenge, origin);
3939
+ const authenticatorData = buildAuthenticatorData(rpId, signCount);
3940
+ const clientDataHash = crypto.createHash("sha256").update(clientDataJSON).digest();
3941
+ const message = new Uint8Array(authenticatorData.length + clientDataHash.length);
3942
+ message.set(authenticatorData, 0);
3943
+ message.set(clientDataHash, authenticatorData.length);
3944
+ const signature = await opts.signer.sign(message);
3945
+ return {
3946
+ id: opts.signer.credentialId,
3947
+ rawId: opts.signer.credentialId,
3948
+ type: "public-key",
3949
+ response: {
3950
+ clientDataJSON: base64UrlEncode(clientDataJSON),
3951
+ authenticatorData: base64UrlEncode(authenticatorData),
3952
+ signature: base64UrlEncode(signature)
3953
+ }
3954
+ };
3955
+ }
3956
+ async function runWebAuthnCeremony(begin, options) {
3957
+ const begun = await begin();
3958
+ const challenge = begun?.Options?.challenge;
3959
+ if (!begun?.ChallengeId || !challenge) {
3960
+ throw new Error(
3961
+ "WebAuthn ceremony: begin endpoint did not return a ChallengeId + Options.challenge"
3962
+ );
3963
+ }
3964
+ const credential = await buildAuthenticationCredential({
3965
+ challenge,
3966
+ signer: options.signer,
3967
+ rpId: options.rpId,
3968
+ origin: options.origin,
3969
+ signCount: options.signCount
3970
+ });
3971
+ return { ChallengeId: begun.ChallengeId, Credential: credential };
3972
+ }
3973
+ function beginAuthenticationChallenge(http2, keyId) {
3974
+ return http2.post("/BeginAuthentication", { KeyId: keyId });
3975
+ }
3976
+ function beginGrantSessionChallenge(http2, keyId) {
3977
+ return http2.get("/kms/begin-grant-session-auth", {
3978
+ params: { keyId }
3979
+ });
3980
+ }
3981
+ function runAuthenticationCeremony(http2, keyId, signer, options) {
3982
+ return runWebAuthnCeremony(() => beginAuthenticationChallenge(http2, keyId), {
3983
+ signer,
3984
+ ...options
3985
+ });
3986
+ }
3987
+ function runGrantSessionCeremony(http2, keyId, signer, options) {
3988
+ return runWebAuthnCeremony(() => beginGrantSessionChallenge(http2, keyId), {
3989
+ signer,
3990
+ ...options
3991
+ });
3992
+ }
3993
+
3994
+ // ../airaccount/src/server/services/kms-signer.ts
3995
+ var KmsManager = class {
3996
+ client;
3997
+ logger;
3998
+ constructor(options) {
3999
+ this.client = new KmsHttpClient(options);
4000
+ this.logger = this.client.logger;
4001
+ }
4002
+ isKmsEnabled() {
4003
+ return this.client.enabled;
4004
+ }
4005
+ /** Shared HTTP transport — pass to KmsAgentService / KmsSessionService / etc. */
4006
+ get httpClient() {
4007
+ return this.client;
4008
+ }
4009
+ ensureEnabled() {
4010
+ this.client.ensureEnabled();
4011
+ }
4012
+ /** POST with x-amz-target header (required for wallet/signing operations). */
4013
+ async amzPost(path, target, body) {
4014
+ return this.client.amzPost(path, target, body);
4015
+ }
4016
+ // ── Key Management ──────────────────────────────────────────────
4017
+ async createKey(description, passkeyPublicKey) {
4018
+ this.ensureEnabled();
4019
+ return this.amzPost("/CreateKey", "TrentService.CreateKey", {
4020
+ Description: description,
4021
+ KeyUsage: "SIGN_VERIFY",
4022
+ KeySpec: "ECC_SECG_P256K1",
4023
+ Origin: "EXTERNAL_KMS",
4024
+ PasskeyPublicKey: passkeyPublicKey
4025
+ });
4026
+ }
4027
+ async getKeyStatus(keyId) {
4028
+ this.ensureEnabled();
4029
+ return this.client.get("/KeyStatus", {
4030
+ params: { KeyId: keyId }
4031
+ });
4032
+ }
4033
+ async describeKey(keyId) {
4034
+ this.ensureEnabled();
4035
+ return this.amzPost("/DescribeKey", "TrentService.DescribeKey", { KeyId: keyId });
4036
+ }
4037
+ /** Get a key's public key (uncompressed). Not WebAuthn-gated. */
4038
+ async getPublicKey(target) {
4039
+ this.ensureEnabled();
4040
+ return this.amzPost("/GetPublicKey", "TrentService.GetPublicKey", target);
4041
+ }
4042
+ /**
4043
+ * Derive an Ethereum address at a BIP-44 path (WebAuthn-gated).
4044
+ * Provide a WebAuthn ceremony assertion (preferred) or a Legacy passkey assertion.
4045
+ */
4046
+ async deriveAddress(params) {
4047
+ this.ensureEnabled();
4048
+ return this.amzPost("/DeriveAddress", "TrentService.DeriveAddress", params);
4049
+ }
4050
+ /** List keys (paginated). Not WebAuthn-gated. */
4051
+ async listKeys(params = {}) {
4052
+ this.ensureEnabled();
4053
+ return this.amzPost("/ListKeys", "TrentService.ListKeys", params);
4054
+ }
4055
+ /**
4056
+ * Schedule key deletion (AWS-KMS action ScheduleKeyDeletion; WebAuthn-gated).
4057
+ * RPMB-bound on the TEE — requires a passkey/WebAuthn assertion on the normal path.
4058
+ */
4059
+ async deleteKey(params) {
4060
+ this.ensureEnabled();
4061
+ return this.amzPost("/DeleteKey", "TrentService.ScheduleKeyDeletion", params);
4062
+ }
4063
+ /**
4064
+ * Unfreeze a dormant (frozen) key (issue #42; WebAuthn-gated).
4065
+ * A key auto-frozen by the dormant-key sweep rejects signing until unfrozen.
4066
+ * The TEE verifies the owner via the same strict WebAuthn ceremony as
4067
+ * {@link deleteKey}; ownership is checked even when the key is already active,
4068
+ * so this cannot be used as an unauthenticated key-state probe. Unlike DeleteKey
4069
+ * this endpoint takes no `x-amz-target` header — it authenticates via the default
4070
+ * API key plus the WebAuthn assertion in the body.
4071
+ */
4072
+ async unfreezeKey(params) {
4073
+ this.ensureEnabled();
4074
+ return this.client.post("/UnfreezeKey", params);
4075
+ }
4076
+ /**
4077
+ * Rotate the WebAuthn passkey bound to a key (WebAuthn-gated, RPMB-bound).
4078
+ * `PasskeyPublicKey` is the NEW P-256 public key (0x04… 65-byte uncompressed).
4079
+ */
4080
+ async changePasskey(params) {
4081
+ this.ensureEnabled();
4082
+ return this.amzPost("/ChangePasskey", "TrentService.ChangePasskey", params);
4083
+ }
4084
+ /**
4085
+ * Sign a message or an EIP-155 transaction (WebAuthn-gated).
4086
+ * Provide exactly one of `Message` (hex) or `Transaction`. For a raw 32-byte
4087
+ * digest use {@link signHash} / {@link signHashWithWebAuthn} instead.
4088
+ */
4089
+ async sign(params) {
4090
+ this.ensureEnabled();
4091
+ return this.amzPost("/Sign", "TrentService.Sign", params);
4092
+ }
4093
+ /**
4094
+ * Poll KeyStatus until the key is ready (address derived) or timeout.
4095
+ * STM32 key derivation takes 60-75 seconds on first creation.
4096
+ */
4097
+ async pollUntilReady(keyId, timeoutMs = 12e4, intervalMs = 3e3) {
4098
+ this.ensureEnabled();
4099
+ const deadline = Date.now() + timeoutMs;
4100
+ while (Date.now() < deadline) {
4101
+ const status = await this.getKeyStatus(keyId);
4102
+ this.logger.debug(`Key ${keyId} status: ${status.Status}`);
4103
+ if (status.Status === "ready") {
4104
+ return status;
4105
+ }
4106
+ if (status.Status === "error") {
4107
+ throw new Error(`KMS key derivation failed: ${status.Error ?? "unknown error"}`);
4108
+ }
4109
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
4110
+ }
4111
+ throw new Error(`KMS key derivation timed out after ${timeoutMs}ms`);
4112
+ }
4113
+ // ── Signing ─────────────────────────────────────────────────────
4114
+ /**
4115
+ * Sign a hash using Legacy Passkey assertion (reusable for BLS dual-signing).
4116
+ */
4117
+ async signHash(hash, assertion, target) {
4118
+ this.ensureEnabled();
4119
+ const formattedHash = hash.startsWith("0x") ? hash : `0x${hash}`;
4120
+ const body = {
4121
+ Hash: formattedHash,
4122
+ Passkey: assertion
4123
+ };
4124
+ if (target.Address) {
4125
+ body.Address = target.Address;
4126
+ }
4127
+ if (target.KeyId) {
4128
+ body.KeyId = target.KeyId;
4129
+ }
4130
+ return this.amzPost("/SignHash", "TrentService.SignHash", body);
4131
+ }
4132
+ /**
4133
+ * Sign a hash using a WebAuthn ceremony assertion (one-time use).
4134
+ */
4135
+ async signHashWithWebAuthn(hash, challengeId, credential, target) {
4136
+ this.ensureEnabled();
4137
+ const formattedHash = hash.startsWith("0x") ? hash : `0x${hash}`;
4138
+ const body = {
4139
+ Hash: formattedHash,
4140
+ WebAuthn: { ChallengeId: challengeId, Credential: credential }
4141
+ };
4142
+ if (target.Address) {
4143
+ body.Address = target.Address;
4144
+ }
4145
+ if (target.KeyId) {
4146
+ body.KeyId = target.KeyId;
4147
+ }
4148
+ return this.amzPost("/SignHash", "TrentService.SignHash", body);
4149
+ }
4150
+ // ── Sign Typed Data (v0.19.0+) ─────────────────────────────────
4151
+ /**
4152
+ * Sign arbitrary EIP-712 typed data via `POST /kms/SignTypedData` (v0.20.0).
4153
+ *
4154
+ * The KMS hashes the typed data host-side, so the FULL EIP-712 structure
4155
+ * (domain / primaryType / types / message) is sent — not a pre-hashed
4156
+ * domainSeparator/structHash. The `webAuthnAssertion` challenge comes from a
4157
+ * generic {@link beginAuthentication} ceremony (purpose="authentication").
4158
+ *
4159
+ * Alternatively, agents authenticate with a Bearer JWT — see KmsAgentService.
4160
+ */
4161
+ async signTypedDataWithWebAuthn(params) {
4162
+ this.ensureEnabled();
4163
+ return this.client.post("/kms/SignTypedData", params);
4164
+ }
4165
+ // ── Grant Session Off-chain Signing (v0.19.0+) ─────────────────
4166
+ /**
4167
+ * Begin a grant-session WebAuthn challenge.
4168
+ * The returned challengeId can ONLY be used with sign-grant-session, not sign-typed-data.
4169
+ */
4170
+ async beginGrantSessionAuth(params) {
4171
+ this.ensureEnabled();
4172
+ return this.client.get("/kms/begin-grant-session-auth", {
4173
+ params: { keyId: params.keyId }
4174
+ });
4175
+ }
4176
+ /**
4177
+ * Sign a GRANT_SESSION_V2 hash off-chain inside the TEE (secp256k1 session key).
4178
+ * Returns a 65-byte signature (R||S||V, V=27/28) for use in grantSessionWithSig().
4179
+ */
4180
+ async signGrantSession(params) {
4181
+ this.ensureEnabled();
4182
+ return this.client.post("/kms/sign-grant-session", params);
4183
+ }
4184
+ /**
4185
+ * Sign a GRANT_P256_SESSION_V2 hash off-chain inside the TEE (P256 session key).
4186
+ * Returns a 65-byte signature for use in grantP256SessionWithSig().
4187
+ */
4188
+ async signP256GrantSession(params) {
4189
+ this.ensureEnabled();
4190
+ return this.client.post("/kms/sign-p256-grant-session", params);
4191
+ }
4192
+ // ── Challenge-binding ceremonies (#49 / Beta3) ──────────────────
4193
+ //
4194
+ // These run the full WebAuthn challenge-binding ceremony in one call:
4195
+ // fetch the TA one-time nonce, embed it in clientDataJSON, build + sign the
4196
+ // assertion, then invoke the signing endpoint with the resulting
4197
+ // `WebAuthn` / `webAuthnAssertion`. They share the
4198
+ // {@link runAuthenticationCeremony} / {@link runGrantSessionCeremony} helper,
4199
+ // so every path produces an identical, replay-protected assertion structure.
4200
+ /**
4201
+ * Run a generic authentication ceremony (purpose="authentication") bound to a
4202
+ * fresh TA challenge. The returned assertion is valid for DeriveAddress / Sign
4203
+ * / SignHash / SignTypedData / agent-key / p256-session signing.
4204
+ */
4205
+ async runAuthenticationCeremony(keyId, signer, options) {
4206
+ this.ensureEnabled();
4207
+ return runAuthenticationCeremony(this.client, keyId, signer, options);
4208
+ }
4209
+ /**
4210
+ * Run a grant-session ceremony (purpose="grant-session") bound to a fresh TA
4211
+ * challenge — required by {@link signGrantSession} / {@link signP256GrantSession}
4212
+ * (the generic 'authentication' challenge is rejected there for replay safety).
4213
+ */
4214
+ async runGrantSessionCeremony(keyId, signer, options) {
4215
+ this.ensureEnabled();
4216
+ return runGrantSessionCeremony(this.client, keyId, signer, options);
4217
+ }
4218
+ /** Derive an address, running the challenge-binding ceremony internally. */
4219
+ async deriveAddressWithCeremony(params, signer, options) {
4220
+ this.ensureEnabled();
4221
+ const WebAuthn = await this.runAuthenticationCeremony(params.KeyId, signer, options);
4222
+ return this.deriveAddress({ ...params, WebAuthn });
4223
+ }
4224
+ /**
4225
+ * Sign a message or EIP-155 transaction, running the challenge-binding ceremony
4226
+ * internally. `params.KeyId` is required (it identifies the wallet to challenge).
4227
+ */
4228
+ async signWithCeremony(params, signer, options) {
4229
+ this.ensureEnabled();
4230
+ const WebAuthn = await this.runAuthenticationCeremony(params.KeyId, signer, options);
4231
+ return this.sign({ ...params, WebAuthn });
4232
+ }
4233
+ /** Sign a 32-byte digest, running the challenge-binding ceremony internally. */
4234
+ async signHashWithCeremony(hash, target, signer, options) {
4235
+ this.ensureEnabled();
4236
+ const assertion = await this.runAuthenticationCeremony(target.KeyId, signer, options);
4237
+ return this.signHashWithWebAuthn(hash, assertion.ChallengeId, assertion.Credential, target);
4238
+ }
4239
+ /** Sign EIP-712 typed data, running the challenge-binding ceremony internally. */
4240
+ async signTypedDataWithCeremony(params, signer, options) {
4241
+ this.ensureEnabled();
4242
+ const webAuthnAssertion = await this.runAuthenticationCeremony(params.keyId, signer, options);
4243
+ return this.signTypedDataWithWebAuthn({ ...params, webAuthnAssertion });
4244
+ }
4245
+ /**
4246
+ * Sign a GRANT_SESSION_V2 hash, running the grant-session ceremony internally
4247
+ * (uses the purpose-bound `begin-grant-session-auth` challenge).
4248
+ */
4249
+ async signGrantSessionWithCeremony(params, signer, options) {
4250
+ this.ensureEnabled();
4251
+ const webAuthnAssertion = await this.runGrantSessionCeremony(params.keyId, signer, options);
4252
+ return this.signGrantSession({ ...params, webAuthnAssertion });
4253
+ }
4254
+ /**
4255
+ * Sign a GRANT_P256_SESSION_V2 hash, running the grant-session ceremony
4256
+ * internally (uses the purpose-bound `begin-grant-session-auth` challenge).
4257
+ */
4258
+ async signP256GrantSessionWithCeremony(params, signer, options) {
4259
+ this.ensureEnabled();
4260
+ const webAuthnAssertion = await this.runGrantSessionCeremony(params.keyId, signer, options);
4261
+ return this.signP256GrantSession({ ...params, webAuthnAssertion });
4262
+ }
4263
+ // ── WebAuthn Ceremonies ─────────────────────────────────────────
4264
+ async beginRegistration(params) {
4265
+ this.ensureEnabled();
4266
+ return this.client.post("/BeginRegistration", params);
4267
+ }
4268
+ async completeRegistration(params) {
4269
+ this.ensureEnabled();
4270
+ return this.client.post("/CompleteRegistration", params);
4271
+ }
4272
+ async beginAuthentication(params) {
4273
+ this.ensureEnabled();
4274
+ return this.client.post("/BeginAuthentication", params);
4275
+ }
4276
+ /**
4277
+ * Begin a generic WebAuthn authentication ceremony for a key, returning a
4278
+ * challenge usable for SignHash / SignTypedData (purpose="authentication").
4279
+ *
4280
+ * NOTE: there is no dedicated `begin-webauthn-auth` endpoint — this delegates
4281
+ * to `POST /BeginAuthentication`. (Grant-session signing needs a purpose-bound
4282
+ * challenge from {@link beginGrantSessionAuth} instead.)
4283
+ */
4284
+ async beginWebAuthnAuth(keyId) {
4285
+ this.ensureEnabled();
4286
+ return this.client.post("/BeginAuthentication", { KeyId: keyId });
4287
+ }
4288
+ // ── Factory ─────────────────────────────────────────────────────
4289
+ createKmsSigner(keyId, address, assertionProvider) {
4290
+ this.ensureEnabled();
4291
+ return new KmsSigner(keyId, address, this, assertionProvider);
4292
+ }
4293
+ };
4294
+ var KmsSigner = class {
4295
+ constructor(keyId, _address, kmsManager, assertionProvider) {
4296
+ this.keyId = keyId;
4297
+ this._address = _address;
4298
+ this.kmsManager = kmsManager;
4299
+ this.assertionProvider = assertionProvider;
4300
+ }
4301
+ async getAddress() {
4302
+ return this._address;
4303
+ }
4304
+ async signMessage(message) {
4305
+ const messageHash = hashMessage(message);
4306
+ const assertion = await this.assertionProvider();
4307
+ const signResponse = await this.kmsManager.signHash(messageHash, assertion, {
4308
+ Address: this._address
4309
+ });
4310
+ return "0x" + signResponse.Signature;
4311
+ }
4312
+ };
4313
+
4314
+ // ../airaccount/src/server/services/kms-agent-service.ts
4315
+ var KmsAgentService = class {
4316
+ constructor(http2) {
4317
+ this.http = http2;
4318
+ }
4319
+ /**
4320
+ * Mint a new agent key under an existing human key (WebAuthn-gated).
4321
+ *
4322
+ * The WebAuthn challenge is obtained from a generic
4323
+ * {@link KmsManager.beginAuthentication} ceremony (purpose="authentication");
4324
+ * the caller supplies the resulting assertion in the request.
4325
+ */
4326
+ async createAgentKey(params) {
4327
+ this.http.ensureEnabled();
4328
+ return this.http.post("/kms/create-agent-key", params);
4329
+ }
4330
+ /**
4331
+ * Sign a userOpHash with an agent key, authenticated by the agent's TEE-JWT
4332
+ * credential (`jwt`, the `agentCredential` from {@link createAgentKey}).
4333
+ * Returns the 106-byte packed signature for ERC-4337 sponsorship.
4334
+ */
4335
+ async signAgent(params, jwt) {
4336
+ this.http.ensureEnabled();
4337
+ return this.http.postWithBearer("/kms/sign-agent", params, jwt);
4338
+ }
4339
+ /**
4340
+ * Refresh (re-mint) an agent credential before it expires. Authenticated with
4341
+ * the existing credential (`jwt`, Bearer) plus a human WebAuthn / passkey
4342
+ * assertion in the request.
4343
+ */
4344
+ async refreshAgentCredential(params, jwt) {
4345
+ this.http.ensureEnabled();
4346
+ return this.http.postWithBearer(
4347
+ "/kms/refresh-agent-credential",
4348
+ params,
4349
+ jwt
4350
+ );
4351
+ }
4352
+ /**
4353
+ * Revoke an agent's credential (WebAuthn-gated).
4354
+ *
4355
+ * The WebAuthn challenge is obtained from a generic
4356
+ * {@link KmsManager.beginAuthentication} ceremony (purpose="authentication");
4357
+ * the caller supplies the resulting assertion in the request.
4358
+ */
4359
+ async revokeAgentCredential(params) {
4360
+ this.http.ensureEnabled();
4361
+ return this.http.post(
4362
+ "/kms/revoke-agent-credential",
4363
+ params
4364
+ );
4365
+ }
4366
+ // ── Challenge-binding ceremony variants (#49 / Beta3) ────────────
4367
+ //
4368
+ // All agent-key WebAuthn gates use the generic purpose="authentication"
4369
+ // challenge bound to the HUMAN key. These helpers run the full ceremony
4370
+ // (begin → clientDataJSON → assertion) via the shared
4371
+ // {@link runAuthenticationCeremony} helper, then invoke the endpoint.
4372
+ /** Mint an agent key, running the challenge-binding ceremony internally. */
4373
+ async createAgentKeyWithCeremony(params, signer, options) {
4374
+ this.http.ensureEnabled();
4375
+ const webAuthnAssertion = await runAuthenticationCeremony(
4376
+ this.http,
4377
+ params.humanKeyId,
4378
+ signer,
4379
+ options
4380
+ );
4381
+ return this.createAgentKey({ ...params, webAuthnAssertion });
4382
+ }
4383
+ /**
4384
+ * Refresh an agent credential, running the challenge-binding ceremony
4385
+ * internally. `humanKeyId` is the owning human key challenged by the ceremony
4386
+ * (distinct from the agent `keyId` in `params`); `jwt` is the existing credential.
4387
+ */
4388
+ async refreshAgentCredentialWithCeremony(params, humanKeyId, jwt, signer, options) {
4389
+ this.http.ensureEnabled();
4390
+ const webAuthnAssertion = await runAuthenticationCeremony(this.http, humanKeyId, signer, options);
4391
+ return this.refreshAgentCredential({ ...params, webAuthnAssertion }, jwt);
4392
+ }
4393
+ /**
4394
+ * Revoke an agent credential, running the challenge-binding ceremony internally.
4395
+ * `humanKeyId` is the owning human key challenged by the ceremony (distinct from
4396
+ * the agent `keyId` in `params`).
4397
+ */
4398
+ async revokeAgentCredentialWithCeremony(params, humanKeyId, signer, options) {
4399
+ this.http.ensureEnabled();
4400
+ const webAuthnAssertion = await runAuthenticationCeremony(this.http, humanKeyId, signer, options);
4401
+ return this.revokeAgentCredential({ ...params, webAuthnAssertion });
4402
+ }
4403
+ };
4404
+
4405
+ // ../airaccount/src/server/services/kms-session-service.ts
4406
+ var KmsSessionService = class {
4407
+ constructor(http2) {
4408
+ this.http = http2;
4409
+ }
4410
+ /**
4411
+ * Create a P-256 session key under a human key (WebAuthn-gated).
4412
+ *
4413
+ * `POST /kms/create-p256-session-key`. The `webAuthnAssertion` challenge comes
4414
+ * from a generic {@link KmsManager.beginAuthentication} ceremony supplied by
4415
+ * the caller. Returns the session key's public key plus an `agentCredential`
4416
+ * JWT used to authenticate subsequent {@link signP256UserOp} calls.
4417
+ */
4418
+ async createP256SessionKey(params) {
4419
+ this.http.ensureEnabled();
4420
+ return this.http.post(
4421
+ "/kms/create-p256-session-key",
4422
+ params
4423
+ );
4424
+ }
4425
+ /**
4426
+ * Sign an ERC-4337 UserOp hash with a P-256 session key (Bearer JWT auth).
4427
+ *
4428
+ * `POST /kms/sign-p256-user-op`, authenticated with the `agentCredential` JWT
4429
+ * returned by {@link createP256SessionKey}. Returns the 149-byte P256
4430
+ * session-key wire-format signature.
4431
+ */
4432
+ async signP256UserOp(params, jwt) {
4433
+ this.http.ensureEnabled();
4434
+ return this.http.postWithBearer(
4435
+ "/kms/sign-p256-user-op",
4436
+ params,
4437
+ jwt
4438
+ );
4439
+ }
4440
+ /**
4441
+ * Revoke a P-256 session key (WebAuthn-gated, idempotent).
4442
+ *
4443
+ * `POST /kms/revoke-p256-session-key`. The `webAuthnAssertion` challenge comes
4444
+ * from a generic {@link KmsManager.beginAuthentication} ceremony supplied by
4445
+ * the caller. Idempotent: revoking an already-revoked key still resolves.
4446
+ */
4447
+ async revokeP256SessionKey(params) {
4448
+ this.http.ensureEnabled();
4449
+ return this.http.post(
4450
+ "/kms/revoke-p256-session-key",
4451
+ params
4452
+ );
4453
+ }
4454
+ // ── Challenge-binding ceremony variants (#49 / Beta3) ────────────
4455
+ //
4456
+ // Create + revoke gate on the generic purpose="authentication" challenge bound
4457
+ // to the HUMAN key. These helpers run the full ceremony (begin → clientDataJSON
4458
+ // → assertion) via the shared {@link runAuthenticationCeremony} helper.
4459
+ /** Create a P-256 session key, running the challenge-binding ceremony internally. */
4460
+ async createP256SessionKeyWithCeremony(params, signer, options) {
4461
+ this.http.ensureEnabled();
4462
+ const webAuthnAssertion = await runAuthenticationCeremony(
4463
+ this.http,
4464
+ params.humanKeyId,
4465
+ signer,
4466
+ options
4467
+ );
4468
+ return this.createP256SessionKey({ ...params, webAuthnAssertion });
4469
+ }
4470
+ /**
4471
+ * Revoke a P-256 session key, running the challenge-binding ceremony internally.
4472
+ * `humanKeyId` is the owning human key challenged by the ceremony (distinct from
4473
+ * the session `keyId` in `params`).
4474
+ */
4475
+ async revokeP256SessionKeyWithCeremony(params, humanKeyId, signer, options) {
4476
+ this.http.ensureEnabled();
4477
+ const webAuthnAssertion = await runAuthenticationCeremony(this.http, humanKeyId, signer, options);
4478
+ return this.revokeP256SessionKey({ ...params, webAuthnAssertion });
4479
+ }
4480
+ };
4481
+
4482
+ // ../airaccount/src/server/services/kms-payment-signer.ts
4483
+ var KmsPaymentSigner = class {
4484
+ constructor(http2) {
4485
+ this.http = http2;
4486
+ }
4487
+ /**
4488
+ * Dispatch a payment-signing request with the chosen auth mode.
4489
+ * JWT auth uses `postWithBearer`; WebAuthn auth merges the assertion into the body.
4490
+ */
4491
+ async signWithAuth(path, body, auth) {
4492
+ if ("jwt" in auth) {
4493
+ return this.http.postWithBearer(path, body, auth.jwt);
4494
+ }
4495
+ return this.http.post(path, {
4496
+ ...body,
4497
+ webAuthnAssertion: auth.webAuthnAssertion
4498
+ });
4499
+ }
4500
+ /**
4501
+ * Sign a MicroPaymentChannel voucher (cumulative-amount EIP-712 message)
4502
+ * via `POST /kms/SignMicropaymentVoucher`.
4503
+ */
4504
+ async signMicropaymentVoucher(params, auth) {
4505
+ this.http.ensureEnabled();
4506
+ return this.signWithAuth("/kms/SignMicropaymentVoucher", { ...params }, auth);
4507
+ }
4508
+ /**
4509
+ * Sign an EIP-3009 TransferWithAuthorization for a GToken transfer
4510
+ * via `POST /kms/SignGTokenAuthorization`. `from` MUST equal the derived address.
4511
+ */
4512
+ async signGTokenAuthorization(params, auth) {
4513
+ this.http.ensureEnabled();
4514
+ return this.signWithAuth("/kms/SignGTokenAuthorization", { ...params }, auth);
4515
+ }
4516
+ /**
4517
+ * Sign an x402 payment authorization via `POST /kms/SignX402Payment`.
4518
+ */
4519
+ async signX402Payment(params, auth) {
4520
+ this.http.ensureEnabled();
4521
+ return this.signWithAuth("/kms/SignX402Payment", { ...params }, auth);
4522
+ }
4523
+ };
4524
+
4525
+ // ../airaccount/src/server/services/kms-monitor-service.ts
4526
+ var KmsMonitorService = class {
4527
+ constructor(http2) {
4528
+ this.http = http2;
4529
+ }
4530
+ /**
4531
+ * Liveness probe (`GET /health`, no auth). Does NOT require the KMS feature
4532
+ * flag to be enabled.
4533
+ */
4534
+ async health() {
4535
+ return this.http.get("/health");
4536
+ }
4537
+ /**
4538
+ * Version / capability descriptor (`GET /version`, no auth). Does NOT require
4539
+ * the KMS feature flag to be enabled.
4540
+ */
4541
+ async version() {
4542
+ return this.http.get("/version");
4543
+ }
4544
+ /**
4545
+ * Request-queue health and circuit-breaker state (`GET /QueueStatus`).
4546
+ */
4547
+ async queueStatus() {
4548
+ this.http.ensureEnabled();
4549
+ return this.http.get("/QueueStatus");
4550
+ }
4551
+ /**
4552
+ * RPMB anti-rollback monotonic counter (`GET /RollbackCounter`, diagnostic,
4553
+ * v0.20.0).
4554
+ */
4555
+ async rollbackCounter() {
4556
+ this.http.ensureEnabled();
4557
+ return this.http.get("/RollbackCounter");
4558
+ }
4559
+ /**
4560
+ * Machine-readable runtime statistics (`GET /stats`, v0.20.0) — wallets, tx,
4561
+ * queue, warnings.
4562
+ */
4563
+ async stats() {
4564
+ this.http.ensureEnabled();
4565
+ return this.http.get("/stats");
4566
+ }
4567
+ /**
4568
+ * TEE remote-attestation evidence bound to a caller nonce (`GET /attestation`,
4569
+ * #37). Public (no auth) — pass a fresh random `nonce` (hex, ≤64 bytes) to bind
4570
+ * the evidence + defeat replay, then verify the returned signed measurement.
4571
+ */
4572
+ async getAttestation(nonce) {
4573
+ return this.http.get("/attestation", { params: { nonce } });
4574
+ }
4575
+ /**
4576
+ * Ed25519-signed measurement manifest, version → ta_measurement
4577
+ * (`GET /.well-known/attestation-measurements.json`, #12). Public.
4578
+ */
4579
+ async getAttestationMeasurements() {
4580
+ return this.http.get("/.well-known/attestation-measurements.json");
4581
+ }
4582
+ /**
4583
+ * Sigsum transparency proof sidecar for the measurement manifest
4584
+ * (`GET /.well-known/attestation-measurements-proof.json`, #87). Public.
4585
+ */
4586
+ async getAttestationMeasurementsProof() {
4587
+ return this.http.get("/.well-known/attestation-measurements-proof.json");
4588
+ }
4589
+ /**
4590
+ * WARNING — DESTRUCTIVE, IRREVERSIBLE. Force-purges a key from both the TEE
4591
+ * and the SQLite store with NO passkey/WebAuthn check (`POST /admin/purge-key`,
4592
+ * v0.20.0). Operator-only: authorised solely by the `KMS_ADMIN_TOKEN` operator
4593
+ * secret sent as `Authorization: Bearer <adminToken>`. There is no recovery
4594
+ * once a key is purged.
4595
+ *
4596
+ * @internal Operator/break-glass tooling only — not part of the general SDK surface.
4597
+ * The endpoint is gated server-side and intentionally omitted from the public KMS
4598
+ * docs; do not expose it in application-facing flows.
4599
+ */
4600
+ async adminPurgeKey(params, adminToken) {
4601
+ this.http.ensureEnabled();
4602
+ return this.http.postWithBearer("/admin/purge-key", params, adminToken);
4603
+ }
4604
+ };
4605
+
4606
+ // ../airaccount/src/server/adapters/memory-storage.ts
4607
+ var MemoryStorage = class {
4608
+ accounts = [];
4609
+ transfers = [];
4610
+ paymasters = /* @__PURE__ */ new Map();
4611
+ blsConfig = null;
4612
+ // ── Accounts ─────────────────────────────────────────────────
4613
+ async getAccounts() {
4614
+ return [...this.accounts];
4615
+ }
4616
+ async saveAccount(account) {
4617
+ this.accounts.push({ ...account });
4618
+ }
4619
+ async findAccountByUserId(userId) {
4620
+ return this.accounts.find((a) => a.userId === userId) ?? null;
4621
+ }
4622
+ async updateAccount(userId, updates) {
4623
+ const index = this.accounts.findIndex((a) => a.userId === userId);
4624
+ if (index >= 0) {
4625
+ this.accounts[index] = { ...this.accounts[index], ...updates };
4626
+ }
4627
+ }
4628
+ // ── Transfers ────────────────────────────────────────────────
4629
+ async saveTransfer(transfer) {
4630
+ this.transfers.push({ ...transfer });
4631
+ }
4632
+ async findTransfersByUserId(userId) {
4633
+ return this.transfers.filter((t) => t.userId === userId);
4634
+ }
4635
+ async findTransferById(id) {
4636
+ return this.transfers.find((t) => t.id === id) ?? null;
4637
+ }
4638
+ async updateTransfer(id, updates) {
4639
+ const index = this.transfers.findIndex((t) => t.id === id);
4640
+ if (index >= 0) {
4641
+ this.transfers[index] = { ...this.transfers[index], ...updates };
4642
+ }
4643
+ }
4644
+ // ── Paymasters ───────────────────────────────────────────────
4645
+ async getPaymasters(userId) {
4646
+ return this.paymasters.get(userId) ?? [];
4647
+ }
4648
+ async savePaymaster(userId, paymaster) {
4649
+ const list = this.paymasters.get(userId) ?? [];
4650
+ const existingIndex = list.findIndex((p) => p.name === paymaster.name);
4651
+ if (existingIndex >= 0) {
4652
+ list[existingIndex] = { ...paymaster };
4653
+ } else {
4654
+ list.push({ ...paymaster });
4655
+ }
4656
+ this.paymasters.set(userId, list);
4657
+ }
4658
+ async removePaymaster(userId, name) {
4659
+ const list = this.paymasters.get(userId) ?? [];
4660
+ const filtered = list.filter((p) => p.name !== name);
4661
+ if (filtered.length < list.length) {
4662
+ this.paymasters.set(userId, filtered);
4663
+ return true;
4664
+ }
4665
+ return false;
4666
+ }
4667
+ // ── BLS Config ───────────────────────────────────────────────
4668
+ async getBlsConfig() {
4669
+ return this.blsConfig;
4670
+ }
4671
+ async updateSignerNodesCache(nodes) {
4672
+ this.blsConfig = {
4673
+ ...this.blsConfig,
4674
+ signerNodes: {
4675
+ nodes
4676
+ }
4677
+ };
4678
+ }
4679
+ };
4680
+ var LocalWalletSigner = class {
4681
+ account;
4682
+ constructor(privateKey) {
4683
+ this.account = accounts.privateKeyToAccount(privateKey);
4684
+ }
4685
+ async getAddress(_userId) {
4686
+ return this.account.address;
4687
+ }
4688
+ async signMessage(_userId, message, _ctx) {
4689
+ return this.account.signMessage({ message: { raw: message } });
4690
+ }
4691
+ async ensureSigner(_userId) {
4692
+ return { address: this.account.address };
4693
+ }
4694
+ };
4695
+ /*! Bundled license information:
4696
+
4697
+ @noble/curves/nist.js:
4698
+ (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
4699
+ */
4700
+
4701
+ exports.ACCOUNT_ABI = ACCOUNT_ABI;
4702
+ exports.AGENT_SESSION_KEY_VALIDATOR_ABI = AGENT_SESSION_KEY_VALIDATOR_ABI;
4703
+ exports.AIRACCOUNT_ABI = AIRACCOUNT_ABI;
4704
+ exports.AIRACCOUNT_ADDRESSES = AIRACCOUNT_ADDRESSES;
4705
+ exports.AIRACCOUNT_FACTORY_ABI = AIRACCOUNT_FACTORY_ABI;
4706
+ exports.AIR_ACCOUNT_COMPOSITE_VALIDATOR_ABI = AIR_ACCOUNT_COMPOSITE_VALIDATOR_ABI;
4707
+ exports.AIR_ACCOUNT_DELEGATE_ABI = AIR_ACCOUNT_DELEGATE_ABI;
4708
+ exports.AIR_ACCOUNT_DELEGATE_ADDRESS = AIR_ACCOUNT_DELEGATE_ADDRESS;
4709
+ exports.ALG_ID = ALG_ID;
4710
+ exports.AccountManager = AccountManager;
4711
+ exports.AgentRegistryService = AgentRegistryService;
4712
+ exports.AirAccountServerClient = AirAccountServerClient;
4713
+ exports.BLSSignatureService = BLSSignatureService;
4714
+ exports.CALLDATA_PARSER_REGISTRY_ABI = CALLDATA_PARSER_REGISTRY_ABI;
4715
+ exports.ConsoleLogger = ConsoleLogger;
4716
+ exports.DEFAULT_CREDENTIAL_ID = DEFAULT_CREDENTIAL_ID;
4717
+ exports.DEFAULT_KMS_ENDPOINT = DEFAULT_KMS_ENDPOINT;
4718
+ exports.DEFAULT_ORIGIN = DEFAULT_ORIGIN;
4719
+ exports.DEFAULT_RP_ID = DEFAULT_RP_ID;
4720
+ exports.DvtPendingConfirmationError = DvtPendingConfirmationError;
4721
+ exports.EIP7702DelegateService = EIP7702DelegateService;
4722
+ exports.ENTRYPOINT_ABI_V6 = ENTRYPOINT_ABI_V6;
4723
+ exports.ENTRYPOINT_ABI_V7_V8 = ENTRYPOINT_ABI_V7_V8;
4724
+ exports.ENTRYPOINT_ADDRESSES = ENTRYPOINT_ADDRESSES;
4725
+ exports.ERC20_ABI = ERC20_ABI;
4726
+ exports.ERC8004Service = ERC8004Service;
4727
+ exports.ERC8004_ADDRESSES = ERC8004_ADDRESSES;
4728
+ exports.EXECUTE_BATCH_SELECTOR = EXECUTE_BATCH_SELECTOR;
4729
+ exports.EXECUTE_SELECTOR = EXECUTE_SELECTOR;
4730
+ exports.EXECUTE_USER_OP_SELECTOR = EXECUTE_USER_OP_SELECTOR;
4731
+ exports.EntryPointVersion = EntryPointVersion;
4732
+ exports.EthereumProvider = EthereumProvider;
4733
+ exports.FACTORY_ABI_V6 = FACTORY_ABI_V6;
4734
+ exports.FACTORY_ABI_V7_V8 = FACTORY_ABI_V7_V8;
4735
+ exports.FORCE_EXIT_MODULE_ABI = FORCE_EXIT_MODULE_ABI;
4736
+ exports.ForceExitService = ForceExitService;
4737
+ exports.GLOBAL_GUARD_ABI = GLOBAL_GUARD_ABI;
4738
+ exports.GuardChecker = GuardChecker;
4739
+ exports.GuardStateReader = GuardStateReader;
4740
+ exports.KmsAgentService = KmsAgentService;
4741
+ exports.KmsHttpClient = KmsHttpClient;
4742
+ exports.KmsManager = KmsManager;
4743
+ exports.KmsMonitorService = KmsMonitorService;
4744
+ exports.KmsPaymentSigner = KmsPaymentSigner;
4745
+ exports.KmsSessionService = KmsSessionService;
4746
+ exports.KmsSigner = KmsSigner;
4747
+ exports.L2_TYPE = L2_TYPE;
4748
+ exports.LocalWalletSigner = LocalWalletSigner;
4749
+ exports.MAX_GUARDIANS = MAX_GUARDIANS;
4750
+ exports.MODULE_TYPE = MODULE_TYPE;
4751
+ exports.MemoryStorage = MemoryStorage;
4752
+ exports.ModuleManager = ModuleManager;
4753
+ exports.P256PasskeySigner = P256PasskeySigner;
4754
+ exports.PaymasterManager = PaymasterManager;
4755
+ exports.PaymasterPriceStalenessError = PaymasterPriceStalenessError;
4756
+ exports.RECOVERY_THRESHOLD = RECOVERY_THRESHOLD;
4757
+ exports.RECOVERY_TIMELOCK_SECONDS = RECOVERY_TIMELOCK_SECONDS;
4758
+ exports.RecoveryService = RecoveryService;
4759
+ exports.SESSION_KEY_VALIDATOR_ABI = SESSION_KEY_VALIDATOR_ABI;
4760
+ exports.SessionKeyService = SessionKeyService;
4761
+ exports.SilentLogger = SilentLogger;
4762
+ exports.TIER_GUARD_HOOK_ABI = TIER_GUARD_HOOK_ABI;
4763
+ exports.TokenService = TokenService;
4764
+ exports.TransferManager = TransferManager;
4765
+ exports.VALIDATOR_ABI = VALIDATOR_ABI;
4766
+ exports.WEIGHT_CHANGE_EXPIRY_SECONDS = WEIGHT_CHANGE_EXPIRY_SECONDS;
4767
+ exports.WEIGHT_CHANGE_THRESHOLD = WEIGHT_CHANGE_THRESHOLD;
4768
+ exports.WEIGHT_CHANGE_TIMELOCK_SECONDS = WEIGHT_CHANGE_TIMELOCK_SECONDS;
4769
+ exports.WalletManager = WalletManager;
4770
+ exports.WeightedSignatureService = WeightedSignatureService;
4771
+ exports.YAAAServerClient = YAAAServerClient;
4772
+ exports.base64UrlDecode = base64UrlDecode;
4773
+ exports.base64UrlEncode = base64UrlEncode;
4774
+ exports.beginAuthenticationChallenge = beginAuthenticationChallenge;
4775
+ exports.beginGrantSessionChallenge = beginGrantSessionChallenge;
4776
+ exports.buildAuthenticationCredential = buildAuthenticationCredential;
4777
+ exports.buildAuthenticatorData = buildAuthenticatorData;
4778
+ exports.buildClientDataJSON = buildClientDataJSON;
4779
+ exports.buildInstallModuleHash = buildInstallModuleHash;
4780
+ exports.buildUninstallModuleHash = buildUninstallModuleHash;
4781
+ exports.computeOapdSalt = computeOapdSalt;
4782
+ exports.erc8004AddressesForChain = erc8004AddressesForChain;
4783
+ exports.getOapdAddress = getOapdAddress;
4784
+ exports.getOapdAddressWithChainId = getOapdAddressWithChainId;
4785
+ exports.isExecuteUserOpWrapped = isExecuteUserOpWrapped;
4786
+ exports.isOapdDeployed = isOapdDeployed;
4787
+ exports.isPendingConfirmation = isPendingConfirmation;
4788
+ exports.packP256SessionSignature = packP256SessionSignature;
4789
+ exports.packSecp256k1SessionSignature = packSecp256k1SessionSignature;
4790
+ exports.runAuthenticationCeremony = runAuthenticationCeremony;
4791
+ exports.runGrantSessionCeremony = runGrantSessionCeremony;
4792
+ exports.runWebAuthnCeremony = runWebAuthnCeremony;
4793
+ exports.sepoliaV07Config = sepoliaV07Config;
4794
+ exports.validateConfig = validateConfig;
4795
+ exports.wrapExecuteUserOp = wrapExecuteUserOp;
4796
+ //# sourceMappingURL=chunk-OVNOSAL3.cjs.map
4797
+ //# sourceMappingURL=chunk-OVNOSAL3.cjs.map