@aastar/sdk 0.24.2 → 0.26.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 (126) hide show
  1. package/dist/UserClient-5PQP6APK.js +6 -0
  2. package/dist/{UserClient-DPJ6E2XL.js.map → UserClient-5PQP6APK.js.map} +1 -1
  3. package/dist/UserClient-CD7R3335.cjs +15 -0
  4. package/dist/{UserClient-4MRK2D7W.cjs.map → UserClient-CD7R3335.cjs.map} +1 -1
  5. package/dist/account.cjs +8 -8
  6. package/dist/account.js +3 -3
  7. package/dist/addresses-D12T3kLs.d.cts +210 -0
  8. package/dist/addresses-D12T3kLs.d.ts +210 -0
  9. package/dist/admin.cjs +4 -4
  10. package/dist/admin.js +3 -3
  11. package/dist/airaccount.cjs +135 -103
  12. package/dist/airaccount.d.cts +1 -1
  13. package/dist/airaccount.d.ts +1 -1
  14. package/dist/airaccount.js +3 -3
  15. package/dist/channel.cjs +7 -7
  16. package/dist/channel.js +3 -3
  17. package/dist/{chunk-S7IUUQ5E.cjs → chunk-2RHBOBL7.cjs} +6 -6
  18. package/dist/{chunk-S7IUUQ5E.cjs.map → chunk-2RHBOBL7.cjs.map} +1 -1
  19. package/dist/{chunk-BPAAWQQA.js → chunk-4GJSK7E6.js} +557 -115
  20. package/dist/chunk-4GJSK7E6.js.map +1 -0
  21. package/dist/{chunk-EEWLL7GE.js → chunk-6DZCDV4Q.js} +2137 -13
  22. package/dist/chunk-6DZCDV4Q.js.map +1 -0
  23. package/dist/{chunk-MCDFQ5JH.cjs → chunk-7HTUDNH3.cjs} +11 -11
  24. package/dist/{chunk-MCDFQ5JH.cjs.map → chunk-7HTUDNH3.cjs.map} +1 -1
  25. package/dist/{chunk-UJPW54CK.js → chunk-7JVL5CU3.js} +3 -3
  26. package/dist/{chunk-UJPW54CK.js.map → chunk-7JVL5CU3.js.map} +1 -1
  27. package/dist/{chunk-7FLPD3V4.js → chunk-A4FO6FKN.js} +3 -3
  28. package/dist/{chunk-7FLPD3V4.js.map → chunk-A4FO6FKN.js.map} +1 -1
  29. package/dist/{chunk-MANVOQY7.cjs → chunk-CI4UJW5Y.cjs} +5 -5
  30. package/dist/{chunk-MANVOQY7.cjs.map → chunk-CI4UJW5Y.cjs.map} +1 -1
  31. package/dist/{chunk-PUE5GEKK.js → chunk-COTHBCR2.js} +3 -3
  32. package/dist/{chunk-PUE5GEKK.js.map → chunk-COTHBCR2.js.map} +1 -1
  33. package/dist/{chunk-TQIRRSGL.cjs → chunk-FIMXPANS.cjs} +4 -4
  34. package/dist/{chunk-TQIRRSGL.cjs.map → chunk-FIMXPANS.cjs.map} +1 -1
  35. package/dist/{chunk-MXJEULSE.cjs → chunk-G33MXEHU.cjs} +29 -2
  36. package/dist/chunk-G33MXEHU.cjs.map +1 -0
  37. package/dist/{chunk-FUY4MHPM.cjs → chunk-GASCTLKR.cjs} +9 -9
  38. package/dist/{chunk-FUY4MHPM.cjs.map → chunk-GASCTLKR.cjs.map} +1 -1
  39. package/dist/{chunk-W73Y6JWZ.js → chunk-IG4BG25C.js} +6 -6
  40. package/dist/{chunk-W73Y6JWZ.js.map → chunk-IG4BG25C.js.map} +1 -1
  41. package/dist/{chunk-TGEVD7OR.cjs → chunk-J3UAXGNP.cjs} +16 -16
  42. package/dist/{chunk-TGEVD7OR.cjs.map → chunk-J3UAXGNP.cjs.map} +1 -1
  43. package/dist/{chunk-Y5QM4LI4.js → chunk-JCEUTCFZ.js} +4 -4
  44. package/dist/{chunk-Y5QM4LI4.js.map → chunk-JCEUTCFZ.js.map} +1 -1
  45. package/dist/{chunk-IB3KOSHW.cjs → chunk-KOWTQJIX.cjs} +2177 -49
  46. package/dist/chunk-KOWTQJIX.cjs.map +1 -0
  47. package/dist/chunk-L6D2AGTF.js +500 -0
  48. package/dist/chunk-L6D2AGTF.js.map +1 -0
  49. package/dist/{chunk-KYXXIKEI.cjs → chunk-LRPAX5AG.cjs} +32 -32
  50. package/dist/{chunk-KYXXIKEI.cjs.map → chunk-LRPAX5AG.cjs.map} +1 -1
  51. package/dist/{chunk-UCLK6LTB.js → chunk-MBWBHKUE.js} +28 -3
  52. package/dist/chunk-MBWBHKUE.js.map +1 -0
  53. package/dist/{chunk-3FRNYRWI.cjs → chunk-NHDZQPDE.cjs} +26 -26
  54. package/dist/{chunk-3FRNYRWI.cjs.map → chunk-NHDZQPDE.cjs.map} +1 -1
  55. package/dist/{chunk-HP44S5U5.cjs → chunk-OBPTMV5W.cjs} +5 -5
  56. package/dist/{chunk-HP44S5U5.cjs.map → chunk-OBPTMV5W.cjs.map} +1 -1
  57. package/dist/{chunk-SX5GUCTF.js → chunk-QTXPAGNX.js} +9 -9
  58. package/dist/{chunk-SX5GUCTF.js.map → chunk-QTXPAGNX.js.map} +1 -1
  59. package/dist/{chunk-PTVXBXZX.js → chunk-UANSP3OK.js} +3 -3
  60. package/dist/{chunk-PTVXBXZX.js.map → chunk-UANSP3OK.js.map} +1 -1
  61. package/dist/{chunk-P3B6UTED.js → chunk-UTSFTWFC.js} +3 -3
  62. package/dist/{chunk-P3B6UTED.js.map → chunk-UTSFTWFC.js.map} +1 -1
  63. package/dist/{chunk-4Q6FADF6.cjs → chunk-UZE7IPOK.cjs} +571 -121
  64. package/dist/chunk-UZE7IPOK.cjs.map +1 -0
  65. package/dist/chunk-WTURYJEA.cjs +504 -0
  66. package/dist/chunk-WTURYJEA.cjs.map +1 -0
  67. package/dist/{chunk-XBZGVJ5K.js → chunk-YR7CTWY6.js} +3 -3
  68. package/dist/{chunk-XBZGVJ5K.js.map → chunk-YR7CTWY6.js.map} +1 -1
  69. package/dist/{contract-addresses-RABD77VP.cjs → contract-addresses-6K6IB5OB.cjs} +13 -13
  70. package/dist/{contract-addresses-RABD77VP.cjs.map → contract-addresses-6K6IB5OB.cjs.map} +1 -1
  71. package/dist/{contract-addresses-TVXSRQ7I.js → contract-addresses-CHZ7PK5H.js} +3 -3
  72. package/dist/{contract-addresses-TVXSRQ7I.js.map → contract-addresses-CHZ7PK5H.js.map} +1 -1
  73. package/dist/core.cjs +285 -261
  74. package/dist/core.d.cts +6 -175
  75. package/dist/core.d.ts +6 -175
  76. package/dist/core.js +2 -2
  77. package/dist/dapp.cjs +6 -6
  78. package/dist/dapp.js +3 -3
  79. package/dist/enduser.cjs +7 -7
  80. package/dist/enduser.js +4 -4
  81. package/dist/identity.cjs +6 -6
  82. package/dist/identity.js +3 -3
  83. package/dist/index.cjs +406 -374
  84. package/dist/index.d.cts +3 -2
  85. package/dist/index.d.ts +3 -2
  86. package/dist/index.js +17 -17
  87. package/dist/kms.cjs +135 -103
  88. package/dist/kms.d.cts +330 -26
  89. package/dist/kms.d.ts +330 -26
  90. package/dist/kms.js +3 -3
  91. package/dist/operator.cjs +7 -7
  92. package/dist/operator.js +3 -3
  93. package/dist/paymaster.cjs +16 -16
  94. package/dist/paymaster.js +3 -3
  95. package/dist/{src-VO7TXJPG.cjs → src-DNURNUIA.cjs} +287 -263
  96. package/dist/src-DNURNUIA.cjs.map +1 -0
  97. package/dist/{src-RM6DDR7K.cjs → src-DZDH3BSU.cjs} +18 -18
  98. package/dist/src-DZDH3BSU.cjs.map +1 -0
  99. package/dist/{src-HKOFZ4V3.js → src-EVM7OESP.js} +5 -5
  100. package/dist/src-EVM7OESP.js.map +1 -0
  101. package/dist/src-FY3KAPPC.js +5 -0
  102. package/dist/src-FY3KAPPC.js.map +1 -0
  103. package/dist/tokens.cjs +12 -4
  104. package/dist/tokens.d.cts +133 -1
  105. package/dist/tokens.d.ts +133 -1
  106. package/dist/tokens.js +3 -3
  107. package/dist/x402.cjs +26 -26
  108. package/dist/x402.js +3 -3
  109. package/package.json +1 -1
  110. package/dist/UserClient-4MRK2D7W.cjs +0 -15
  111. package/dist/UserClient-DPJ6E2XL.js +0 -6
  112. package/dist/chunk-4Q6FADF6.cjs.map +0 -1
  113. package/dist/chunk-BPAAWQQA.js.map +0 -1
  114. package/dist/chunk-EEWLL7GE.js.map +0 -1
  115. package/dist/chunk-IB3KOSHW.cjs.map +0 -1
  116. package/dist/chunk-MXJEULSE.cjs.map +0 -1
  117. package/dist/chunk-O2CN77MV.js +0 -226
  118. package/dist/chunk-O2CN77MV.js.map +0 -1
  119. package/dist/chunk-UCLK6LTB.js.map +0 -1
  120. package/dist/chunk-V23XPVHO.cjs +0 -228
  121. package/dist/chunk-V23XPVHO.cjs.map +0 -1
  122. package/dist/src-HKOFZ4V3.js.map +0 -1
  123. package/dist/src-L2BLX34S.js +0 -5
  124. package/dist/src-L2BLX34S.js.map +0 -1
  125. package/dist/src-RM6DDR7K.cjs.map +0 -1
  126. package/dist/src-VO7TXJPG.cjs.map +0 -1
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var chunkXQROKLZI_cjs = require('./chunk-XQROKLZI.cjs');
4
- var chunkIB3KOSHW_cjs = require('./chunk-IB3KOSHW.cjs');
5
- var chunkMXJEULSE_cjs = require('./chunk-MXJEULSE.cjs');
4
+ var chunkKOWTQJIX_cjs = require('./chunk-KOWTQJIX.cjs');
5
+ var chunkG33MXEHU_cjs = require('./chunk-G33MXEHU.cjs');
6
6
  var viem = require('viem');
7
7
  var axios = require('axios');
8
8
  var crypto = require('crypto');
@@ -13,7 +13,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
13
  var axios__default = /*#__PURE__*/_interopDefault(axios);
14
14
 
15
15
  // ../airaccount/src/server/constants/entrypoint.ts
16
- var CORE_SEPOLIA = chunkMXJEULSE_cjs.CANONICAL_ADDRESSES[11155111];
16
+ var CORE_SEPOLIA = chunkG33MXEHU_cjs.CANONICAL_ADDRESSES[11155111];
17
17
  var EntryPointVersion = /* @__PURE__ */ ((EntryPointVersion2) => {
18
18
  EntryPointVersion2["V0_6"] = "0.6";
19
19
  EntryPointVersion2["V0_7"] = "0.7";
@@ -728,7 +728,7 @@ function toGuardianSpecs(p) {
728
728
  return specs;
729
729
  }
730
730
  function buildFullInitConfig(p) {
731
- return chunkIB3KOSHW_cjs.buildInitConfig({
731
+ return chunkKOWTQJIX_cjs.buildInitConfig({
732
732
  guardians: toGuardianSpecs(p),
733
733
  dailyLimit: p.dailyLimit,
734
734
  ...p.approvedAlgIds ? { approvedAlgIds: p.approvedAlgIds } : {},
@@ -761,7 +761,7 @@ function initConfigFromRecord(record) {
761
761
  const guardians = record.guardianSpecs.map(
762
762
  (s) => "p256" in s ? { p256: { x: s.p256.x, y: s.p256.y } } : { ecdsa: s.ecdsa }
763
763
  );
764
- return chunkIB3KOSHW_cjs.buildInitConfig({
764
+ return chunkKOWTQJIX_cjs.buildInitConfig({
765
765
  guardians,
766
766
  dailyLimit: record.dailyLimit ? BigInt(record.dailyLimit) : 0n,
767
767
  ...record.approvedAlgIds ? { approvedAlgIds: record.approvedAlgIds } : {},
@@ -1109,7 +1109,7 @@ var AccountManager = class {
1109
1109
  this.logger.log(
1110
1110
  `[AccountManager] account created with ${params.p256Guardians.length} P-256 guardian(s): ${accountAddress}`
1111
1111
  );
1112
- if (chunkIB3KOSHW_cjs.needsValidatorRouter(config.approvedAlgIds)) {
1112
+ if (chunkKOWTQJIX_cjs.needsValidatorRouter(config.approvedAlgIds)) {
1113
1113
  this.logger.log(
1114
1114
  `[AccountManager] account ${accountAddress} approved a router-delegated algorithm (approvedAlgIds=[${config.approvedAlgIds.join(", ")}]); use deployAndWireValidator(userId, { walletClient }) to deploy + setValidator(router) in one call (or ensureValidatorRouter(userId) after a manual deploy) \u2014 required for those algIds to validate.`
1115
1115
  );
@@ -1146,11 +1146,11 @@ var AccountManager = class {
1146
1146
  if (!approvedAlgIds || approvedAlgIds.length === 0) {
1147
1147
  return { set: false, reason: "no approvedAlgIds / not router-delegated" };
1148
1148
  }
1149
- if (!chunkIB3KOSHW_cjs.needsValidatorRouter(approvedAlgIds)) {
1149
+ if (!chunkKOWTQJIX_cjs.needsValidatorRouter(approvedAlgIds)) {
1150
1150
  return { set: false, reason: "no router-delegated algorithm" };
1151
1151
  }
1152
1152
  const chainId = this.ethereum.getChainId();
1153
- const canonicalRouter = chunkMXJEULSE_cjs.getCanonicalAddresses(chainId)?.aaStarValidator;
1153
+ const canonicalRouter = chunkG33MXEHU_cjs.getCanonicalAddresses(chainId)?.aaStarValidator;
1154
1154
  const router = opts?.router ?? canonicalRouter;
1155
1155
  if (!router || router.toLowerCase() === viem.zeroAddress) {
1156
1156
  return { set: false, reason: `no canonical validator router for chain ${chainId}` };
@@ -1176,7 +1176,7 @@ var AccountManager = class {
1176
1176
  router
1177
1177
  };
1178
1178
  }
1179
- const tx = await chunkIB3KOSHW_cjs.airAccountActions(account.address)(walletClient).setValidator({
1179
+ const tx = await chunkKOWTQJIX_cjs.airAccountActions(account.address)(walletClient).setValidator({
1180
1180
  validator: router,
1181
1181
  account: walletClient.account
1182
1182
  });
@@ -1212,7 +1212,7 @@ var AccountManager = class {
1212
1212
  }
1213
1213
  if (!code || code === "0x") {
1214
1214
  const config = initConfigFromRecord(account);
1215
- deployTx = await chunkIB3KOSHW_cjs.airAccountFactoryActions(account.factoryAddress)(walletClient).createAccount({
1215
+ deployTx = await chunkKOWTQJIX_cjs.airAccountFactoryActions(account.factoryAddress)(walletClient).createAccount({
1216
1216
  owner: account.signerAddress,
1217
1217
  salt: BigInt(account.salt),
1218
1218
  config,
@@ -1616,7 +1616,12 @@ var TransferManager = class {
1616
1616
  );
1617
1617
  const userOpHash = await this.ethereum.getUserOpHash(userOp, version);
1618
1618
  await this.signer.ensureSigner(userId);
1619
- const assertionCtx = params.passkeyAssertion ? { assertion: params.passkeyAssertion } : void 0;
1619
+ if (params.webAuthnAssertion && params.passkeyAssertion) {
1620
+ throw new Error(
1621
+ "Provide either webAuthnAssertion (preferred) or passkeyAssertion, not both."
1622
+ );
1623
+ }
1624
+ const assertionCtx = params.webAuthnAssertion ? { webAuthnAssertion: params.webAuthnAssertion } : params.passkeyAssertion ? { assertion: params.passkeyAssertion } : void 0;
1620
1625
  let useECDSA = false;
1621
1626
  let isCompositeValidator = false;
1622
1627
  if (version === "0.7" /* V0_7 */ || version === "0.8" /* V0_8 */) {
@@ -1626,6 +1631,11 @@ var TransferManager = class {
1626
1631
  account.address
1627
1632
  ));
1628
1633
  }
1634
+ if (assertionCtx && "webAuthnAssertion" in assertionCtx && !useECDSA && !(params.useAirAccountTiering && this.guardChecker)) {
1635
+ throw new Error(
1636
+ "A one-time webAuthnAssertion cannot authorize the legacy non-tiered BLS dual-sign (two owner signatures, one spent challenge). Use useAirAccountTiering:true (single owner signature), or supply two assertions via the legacy path."
1637
+ );
1638
+ }
1629
1639
  if (useECDSA) {
1630
1640
  const ecdsaSig = await this.signer.signMessage(
1631
1641
  userId,
@@ -2122,7 +2132,7 @@ var BLSSignatureService = class {
2122
2132
  }
2123
2133
  return nodes;
2124
2134
  }
2125
- async generateBLSSignature(userId, userOpHash, ctx) {
2135
+ async generateBLSSignature(userId, userOpHash, ctx, options) {
2126
2136
  const manager = await this.ensureInitialized();
2127
2137
  const activeNodes = await this.getActiveSignerNodes();
2128
2138
  if (activeNodes.length < 1) {
@@ -2181,11 +2191,7 @@ var BLSSignatureService = class {
2181
2191
  `Wallet address mismatch! Wallet: ${walletAddress}, Expected: ${account.signerAddress}`
2182
2192
  );
2183
2193
  }
2184
- const aaSignature = await this.signer.signMessage(
2185
- userId,
2186
- viem.hexToBytes(userOpHash),
2187
- ctx
2188
- );
2194
+ const aaSignature = options?.skipOwnerOpSignature ? "0x" : await this.signer.signMessage(userId, viem.hexToBytes(userOpHash), ctx);
2189
2195
  const messagePointHash = chunkXQROKLZI_cjs.keccak256(messagePoint);
2190
2196
  const messagePointSignature = await this.signer.signMessage(
2191
2197
  userId,
@@ -2202,6 +2208,11 @@ var BLSSignatureService = class {
2202
2208
  };
2203
2209
  }
2204
2210
  async packSignature(blsData) {
2211
+ if (!blsData.aaSignature || blsData.aaSignature === "0x") {
2212
+ throw new Error(
2213
+ "packSignature requires aaSignature; this BLSSignatureData was generated with skipOwnerOpSignature (Tier-2/3 only). Use packCumulativeT2/T3Signature instead."
2214
+ );
2215
+ }
2205
2216
  const manager = await this.ensureInitialized();
2206
2217
  return manager.packSignature(blsData);
2207
2218
  }
@@ -2231,7 +2242,9 @@ var BLSSignatureService = class {
2231
2242
  if (!p256Signature) {
2232
2243
  throw new Error(`P256 signature required for Tier ${tier}`);
2233
2244
  }
2234
- const blsData = await this.generateBLSSignature(userId, userOpHash, ctx);
2245
+ const blsData = await this.generateBLSSignature(userId, userOpHash, ctx, {
2246
+ skipOwnerOpSignature: true
2247
+ });
2235
2248
  if (tier === 2) {
2236
2249
  const t2Data = {
2237
2250
  p256Signature,
@@ -2259,6 +2272,84 @@ var BLSSignatureService = class {
2259
2272
  return manager.packCumulativeT3Signature(t3Data);
2260
2273
  }
2261
2274
  };
2275
+ var ALG_NAMES = {
2276
+ [chunkXQROKLZI_cjs.ALG_BLS]: "BLS (0x01)",
2277
+ [chunkXQROKLZI_cjs.ALG_ECDSA]: "ECDSA (0x02)",
2278
+ [chunkXQROKLZI_cjs.ALG_P256]: "P256 (0x03)",
2279
+ [chunkXQROKLZI_cjs.ALG_CUMULATIVE_T2]: "Cumulative T2 (0x04)",
2280
+ [chunkXQROKLZI_cjs.ALG_CUMULATIVE_T3]: "Cumulative T3 (0x05)"
2281
+ };
2282
+ var GuardChecker = class {
2283
+ constructor(ethereum, logger) {
2284
+ this.ethereum = ethereum;
2285
+ this.logger = logger ?? new ConsoleLogger("[GuardChecker]");
2286
+ }
2287
+ logger;
2288
+ /**
2289
+ * Fetch tier limits from an AirAccount contract.
2290
+ */
2291
+ async fetchTierConfig(accountAddress) {
2292
+ const account = this.ethereum.getAccountContract(accountAddress);
2293
+ return readAccountTierLimits(account);
2294
+ }
2295
+ /**
2296
+ * Fetch guard status from the account's GlobalGuard.
2297
+ */
2298
+ async fetchGuardStatus(accountAddress) {
2299
+ const account = this.ethereum.getAccountContract(accountAddress);
2300
+ const guardAddress = await readAccountGuardAddress(account);
2301
+ if (guardAddress === viem.zeroAddress) {
2302
+ return {
2303
+ hasGuard: false,
2304
+ guardAddress: viem.zeroAddress,
2305
+ dailyLimit: 0n,
2306
+ dailyRemaining: 0n
2307
+ };
2308
+ }
2309
+ const guard = viem.getContract({
2310
+ address: guardAddress,
2311
+ abi: viem.parseAbi(GLOBAL_GUARD_ABI),
2312
+ client: this.ethereum.getProvider()
2313
+ });
2314
+ const { dailyLimit, dailyRemaining } = await readGuardDailyAllowance(guard);
2315
+ return {
2316
+ hasGuard: true,
2317
+ guardAddress,
2318
+ dailyLimit,
2319
+ dailyRemaining
2320
+ };
2321
+ }
2322
+ /**
2323
+ * Pre-check a transaction: determine tier, check guard limits and algorithm approval.
2324
+ * Returns errors array (empty = OK to proceed).
2325
+ */
2326
+ async preCheck(accountAddress, value) {
2327
+ const errors = [];
2328
+ const tierConfig = await this.fetchTierConfig(accountAddress);
2329
+ const tier = chunkXQROKLZI_cjs.resolveTier(value, tierConfig);
2330
+ const algId = chunkXQROKLZI_cjs.algIdForTier(tier);
2331
+ const guard = await this.fetchGuardStatus(accountAddress);
2332
+ if (!guard.hasGuard) {
2333
+ return { ok: true, errors: [], tier, algId };
2334
+ }
2335
+ if (guard.dailyLimit > 0n && value > guard.dailyRemaining) {
2336
+ errors.push(
2337
+ `Daily limit exceeded: requesting ${value} wei but only ${guard.dailyRemaining} remaining (limit: ${guard.dailyLimit})`
2338
+ );
2339
+ }
2340
+ const accountContract = this.ethereum.getAccountContract(accountAddress);
2341
+ const isApproved = await readAlgorithmApproved(accountContract, algId);
2342
+ if (!isApproved) {
2343
+ errors.push(
2344
+ `Algorithm ${ALG_NAMES[algId] ?? `0x${algId.toString(16)}`} is not approved by the account`
2345
+ );
2346
+ }
2347
+ if (errors.length > 0) {
2348
+ this.logger.warn(`Pre-check failed for ${accountAddress}: ${errors.join("; ")}`);
2349
+ }
2350
+ return { ok: errors.length === 0, errors, tier, algId };
2351
+ }
2352
+ };
2262
2353
  var ERC20_ABI_PARSED = viem.parseAbi(ERC20_ABI);
2263
2354
  var TokenService = class {
2264
2355
  constructor(ethereum) {
@@ -2385,7 +2476,8 @@ var AirAccountServerClient = class {
2385
2476
  this.tokens,
2386
2477
  config.storage,
2387
2478
  config.signer,
2388
- logger
2479
+ logger,
2480
+ new GuardChecker(this.ethereum, logger)
2389
2481
  );
2390
2482
  }
2391
2483
  };
@@ -2920,84 +3012,6 @@ async function isOapdDeployed(provider, config) {
2920
3012
  const code = await provider.getCode({ address });
2921
3013
  return code !== void 0 && code !== "0x";
2922
3014
  }
2923
- var ALG_NAMES = {
2924
- [chunkXQROKLZI_cjs.ALG_BLS]: "BLS (0x01)",
2925
- [chunkXQROKLZI_cjs.ALG_ECDSA]: "ECDSA (0x02)",
2926
- [chunkXQROKLZI_cjs.ALG_P256]: "P256 (0x03)",
2927
- [chunkXQROKLZI_cjs.ALG_CUMULATIVE_T2]: "Cumulative T2 (0x04)",
2928
- [chunkXQROKLZI_cjs.ALG_CUMULATIVE_T3]: "Cumulative T3 (0x05)"
2929
- };
2930
- var GuardChecker = class {
2931
- constructor(ethereum, logger) {
2932
- this.ethereum = ethereum;
2933
- this.logger = logger ?? new ConsoleLogger("[GuardChecker]");
2934
- }
2935
- logger;
2936
- /**
2937
- * Fetch tier limits from an AirAccount contract.
2938
- */
2939
- async fetchTierConfig(accountAddress) {
2940
- const account = this.ethereum.getAccountContract(accountAddress);
2941
- return readAccountTierLimits(account);
2942
- }
2943
- /**
2944
- * Fetch guard status from the account's GlobalGuard.
2945
- */
2946
- async fetchGuardStatus(accountAddress) {
2947
- const account = this.ethereum.getAccountContract(accountAddress);
2948
- const guardAddress = await readAccountGuardAddress(account);
2949
- if (guardAddress === viem.zeroAddress) {
2950
- return {
2951
- hasGuard: false,
2952
- guardAddress: viem.zeroAddress,
2953
- dailyLimit: 0n,
2954
- dailyRemaining: 0n
2955
- };
2956
- }
2957
- const guard = viem.getContract({
2958
- address: guardAddress,
2959
- abi: viem.parseAbi(GLOBAL_GUARD_ABI),
2960
- client: this.ethereum.getProvider()
2961
- });
2962
- const { dailyLimit, dailyRemaining } = await readGuardDailyAllowance(guard);
2963
- return {
2964
- hasGuard: true,
2965
- guardAddress,
2966
- dailyLimit,
2967
- dailyRemaining
2968
- };
2969
- }
2970
- /**
2971
- * Pre-check a transaction: determine tier, check guard limits and algorithm approval.
2972
- * Returns errors array (empty = OK to proceed).
2973
- */
2974
- async preCheck(accountAddress, value) {
2975
- const errors = [];
2976
- const tierConfig = await this.fetchTierConfig(accountAddress);
2977
- const tier = chunkXQROKLZI_cjs.resolveTier(value, tierConfig);
2978
- const algId = chunkXQROKLZI_cjs.algIdForTier(tier);
2979
- const guard = await this.fetchGuardStatus(accountAddress);
2980
- if (!guard.hasGuard) {
2981
- return { ok: true, errors: [], tier, algId };
2982
- }
2983
- if (guard.dailyLimit > 0n && value > guard.dailyRemaining) {
2984
- errors.push(
2985
- `Daily limit exceeded: requesting ${value} wei but only ${guard.dailyRemaining} remaining (limit: ${guard.dailyLimit})`
2986
- );
2987
- }
2988
- const accountContract = this.ethereum.getAccountContract(accountAddress);
2989
- const isApproved = await readAlgorithmApproved(accountContract, algId);
2990
- if (!isApproved) {
2991
- errors.push(
2992
- `Algorithm ${ALG_NAMES[algId] ?? `0x${algId.toString(16)}`} is not approved by the account`
2993
- );
2994
- }
2995
- if (errors.length > 0) {
2996
- this.logger.warn(`Pre-check failed for ${accountAddress}: ${errors.join("; ")}`);
2997
- }
2998
- return { ok: errors.length === 0, errors, tier, algId };
2999
- }
3000
- };
3001
3015
  var FORCE_EXIT_ABI = [
3002
3016
  // ERC-7579 module lifecycle
3003
3017
  "function onInstall(bytes calldata data) external",
@@ -4187,6 +4201,9 @@ function hexToBytes4(hex) {
4187
4201
  if (clean.length % 2 !== 0) {
4188
4202
  throw new Error("hexToBytes: odd-length hex string");
4189
4203
  }
4204
+ if (clean.length > 0 && !/^[0-9a-fA-F]+$/.test(clean)) {
4205
+ throw new Error("hexToBytes: non-hex characters in input");
4206
+ }
4190
4207
  const out = new Uint8Array(clean.length / 2);
4191
4208
  for (let i = 0; i < out.length; i++) {
4192
4209
  out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
@@ -4221,11 +4238,14 @@ function buildClientDataJSON(challenge, origin = DEFAULT_ORIGIN) {
4221
4238
  return new TextEncoder().encode(json);
4222
4239
  }
4223
4240
  function buildAuthenticatorData(rpId = DEFAULT_RP_ID, signCount = 1) {
4241
+ if (!Number.isInteger(signCount) || signCount < 0 || signCount > 4294967295) {
4242
+ throw new Error(`buildAuthenticatorData: signCount must be a uint32 (0..2^32-1), got ${signCount}`);
4243
+ }
4224
4244
  const rpIdHash = crypto.createHash("sha256").update(rpId).digest();
4225
4245
  const out = new Uint8Array(37);
4226
4246
  out.set(rpIdHash, 0);
4227
4247
  out[32] = 5;
4228
- new DataView(out.buffer).setUint32(33, signCount >>> 0, false);
4248
+ new DataView(out.buffer).setUint32(33, signCount, false);
4229
4249
  return out;
4230
4250
  }
4231
4251
  async function buildAuthenticationCredential(opts) {
@@ -4250,23 +4270,42 @@ async function buildAuthenticationCredential(opts) {
4250
4270
  }
4251
4271
  };
4252
4272
  }
4273
+ function commitChallenge(nonceBase64Url, payload) {
4274
+ const nonce = base64UrlDecode(nonceBase64Url);
4275
+ const payloadBytes = typeof payload === "string" ? hexToBytes4(payload) : payload;
4276
+ if (payloadBytes.length !== 32) {
4277
+ throw new Error(`commitChallenge: payload must be a 32-byte digest, got ${payloadBytes.length} bytes`);
4278
+ }
4279
+ const committed = crypto.createHash("sha256").update(nonce).update(payloadBytes).digest();
4280
+ return base64UrlEncode(new Uint8Array(committed));
4281
+ }
4253
4282
  async function runWebAuthnCeremony(begin, options) {
4254
4283
  const begun = await begin();
4255
- const challenge = begun?.Options?.challenge;
4256
- if (!begun?.ChallengeId || !challenge) {
4284
+ const nonce = begun?.Options?.challenge;
4285
+ if (!begun?.ChallengeId || !nonce) {
4257
4286
  throw new Error(
4258
4287
  "WebAuthn ceremony: begin endpoint did not return a ChallengeId + Options.challenge"
4259
4288
  );
4260
4289
  }
4290
+ const challenge = options.payload ? commitChallenge(nonce, options.payload) : nonce;
4261
4291
  const credential = await buildAuthenticationCredential({
4262
4292
  challenge,
4263
4293
  signer: options.signer,
4264
4294
  rpId: options.rpId,
4265
4295
  origin: options.origin,
4266
- signCount: options.signCount
4296
+ // The KMS enforces a strictly-increasing authenticator signCount (anti-clone). A
4297
+ // server-held signer (P256PasskeySigner) has no native counter, so default to a
4298
+ // monotonic value — else a second signature on the same key fails
4299
+ // "signCount not incremented". A real device passkey passes its own counter.
4300
+ signCount: options.signCount ?? nextSignCount()
4267
4301
  });
4268
4302
  return { ChallengeId: begun.ChallengeId, Credential: credential };
4269
4303
  }
4304
+ var _signCountCounter = Math.floor(Date.now() / 1e3);
4305
+ function nextSignCount() {
4306
+ _signCountCounter = _signCountCounter + 1 >>> 0;
4307
+ return _signCountCounter;
4308
+ }
4270
4309
  function beginAuthenticationChallenge(http2, keyId) {
4271
4310
  return http2.post("/BeginAuthentication", { KeyId: keyId });
4272
4311
  }
@@ -4289,6 +4328,133 @@ function runGrantSessionCeremony(http2, keyId, signer, options) {
4289
4328
  }
4290
4329
 
4291
4330
  // ../airaccount/src/server/services/kms-signer.ts
4331
+ function eip712Digest(params) {
4332
+ const types = Object.fromEntries(
4333
+ params.types.filter((t) => t.name !== "EIP712Domain").map((t) => [t.name, t.fields])
4334
+ );
4335
+ const message = Object.fromEntries(params.message.map((f) => [f.name, f.value]));
4336
+ return viem.hashTypedData({
4337
+ domain: params.domain,
4338
+ types,
4339
+ primaryType: params.primaryType,
4340
+ message
4341
+ });
4342
+ }
4343
+ function u256(x) {
4344
+ if (typeof x === "number" && !Number.isSafeInteger(x)) {
4345
+ throw new Error(`u256: number ${x} exceeds safe-integer range \u2014 pass a bigint or string`);
4346
+ }
4347
+ return BigInt(x);
4348
+ }
4349
+ var MINT_TAGS = { agent: "AA-AGENT-MINT-v1", p256: "AA-P256-SESSION-MINT-v1" };
4350
+ function mintDigest(p) {
4351
+ const hex = p.walletId.replace(/-/g, "");
4352
+ if (hex.length !== 32 || !/^[0-9a-fA-F]+$/.test(hex)) {
4353
+ throw new Error("mintDigest: walletId must be a 16-byte UUID");
4354
+ }
4355
+ if (!Number.isInteger(p.index) || p.index < 0 || p.index > 4294967295) {
4356
+ throw new Error(`mintDigest: index must be a uint32, got ${p.index}`);
4357
+ }
4358
+ if (typeof p.ttlSecs === "number" && !Number.isInteger(p.ttlSecs)) {
4359
+ throw new Error(`mintDigest: ttlSecs must be an integer, got ${p.ttlSecs}`);
4360
+ }
4361
+ const ttlBig = BigInt(p.ttlSecs);
4362
+ if (ttlBig < -(1n << 63n) || ttlBig > (1n << 63n) - 1n) {
4363
+ throw new Error(`mintDigest: ttlSecs out of int64 range: ${ttlBig}`);
4364
+ }
4365
+ const sha2562 = (b) => new Uint8Array(crypto.createHash("sha256").update(b).digest());
4366
+ const utf8 = (s) => new TextEncoder().encode(s);
4367
+ const walletBytes = new Uint8Array(16);
4368
+ for (let i = 0; i < 16; i++) walletBytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
4369
+ const idx = new Uint8Array(4);
4370
+ new DataView(idx.buffer).setUint32(0, p.index, false);
4371
+ const ttl = new Uint8Array(8);
4372
+ new DataView(ttl.buffer).setBigInt64(0, ttlBig, false);
4373
+ const parts = [utf8(MINT_TAGS[p.kind]), walletBytes, idx, ttl, sha2562(utf8(p.subject))];
4374
+ const total = parts.reduce((n, a) => n + a.length, 0);
4375
+ const buf = new Uint8Array(total);
4376
+ let off = 0;
4377
+ for (const a of parts) {
4378
+ buf.set(a, off);
4379
+ off += a.length;
4380
+ }
4381
+ return "0x" + Buffer.from(sha2562(buf)).toString("hex");
4382
+ }
4383
+ function grantSessionFinalHash(p) {
4384
+ const callTargetsHash = viem.keccak256(viem.encodePacked(["address[]"], [p.callTargets]));
4385
+ const selectorsHash = viem.keccak256(viem.encodePacked(["bytes4[]"], [p.selectorAllowlist]));
4386
+ const isP256 = "keyX" in p;
4387
+ const inner = isP256 ? viem.keccak256(
4388
+ viem.encodeAbiParameters(
4389
+ [
4390
+ { type: "string" },
4391
+ { type: "uint256" },
4392
+ { type: "address" },
4393
+ { type: "address" },
4394
+ { type: "bytes32" },
4395
+ { type: "bytes32" },
4396
+ { type: "uint48" },
4397
+ { type: "address" },
4398
+ { type: "bytes4" },
4399
+ { type: "uint16" },
4400
+ { type: "uint32" },
4401
+ { type: "bytes32" },
4402
+ { type: "bytes32" },
4403
+ { type: "uint256" }
4404
+ ],
4405
+ [
4406
+ "GRANT_P256_SESSION_V2",
4407
+ u256(p.chainId),
4408
+ p.verifyingContract,
4409
+ p.account,
4410
+ p.keyX,
4411
+ p.keyY,
4412
+ p.expiry,
4413
+ p.contractScope,
4414
+ p.selectorScope,
4415
+ p.velocityLimit,
4416
+ p.velocityWindow,
4417
+ callTargetsHash,
4418
+ selectorsHash,
4419
+ u256(p.nonce)
4420
+ ]
4421
+ )
4422
+ ) : viem.keccak256(
4423
+ viem.encodeAbiParameters(
4424
+ [
4425
+ { type: "string" },
4426
+ { type: "uint256" },
4427
+ { type: "address" },
4428
+ { type: "address" },
4429
+ { type: "address" },
4430
+ { type: "uint48" },
4431
+ { type: "address" },
4432
+ { type: "bytes4" },
4433
+ { type: "uint16" },
4434
+ { type: "uint32" },
4435
+ { type: "bytes32" },
4436
+ { type: "bytes32" },
4437
+ { type: "uint256" }
4438
+ ],
4439
+ [
4440
+ "GRANT_SESSION_V2",
4441
+ u256(p.chainId),
4442
+ p.verifyingContract,
4443
+ p.account,
4444
+ p.sessionKey,
4445
+ p.expiry,
4446
+ p.contractScope,
4447
+ p.selectorScope,
4448
+ p.velocityLimit,
4449
+ p.velocityWindow,
4450
+ callTargetsHash,
4451
+ selectorsHash,
4452
+ u256(p.nonce)
4453
+ ]
4454
+ )
4455
+ );
4456
+ return viem.hashMessage({ raw: inner });
4457
+ }
4292
4458
  var KmsManager = class {
4293
4459
  client;
4294
4460
  logger;
@@ -4378,6 +4544,29 @@ var KmsManager = class {
4378
4544
  this.ensureEnabled();
4379
4545
  return this.amzPost("/ChangePasskey", "TrentService.ChangePasskey", params);
4380
4546
  }
4547
+ // ── Ceremony wrappers for non-signing passkey ops (strict-readiness #135 item 2) ──
4548
+ // These are NON-signing ops, so the challenge is the raw nonce (no payload commitment),
4549
+ // but they MUST go through the ceremony (clientDataJSON present) — strict mode hard-rejects
4550
+ // any assertion without clientDataJSON. Run the ceremony internally so callers never reach
4551
+ // for the deprecated legacy `Passkey` field.
4552
+ /** Schedule key deletion, running the WebAuthn ceremony internally (raw-nonce). */
4553
+ async deleteKeyWithCeremony(params, signer, options) {
4554
+ this.ensureEnabled();
4555
+ const WebAuthn = await this.runAuthenticationCeremony(params.KeyId, signer, options);
4556
+ return this.deleteKey({ ...params, WebAuthn });
4557
+ }
4558
+ /** Unfreeze a dormant key, running the WebAuthn ceremony internally (raw-nonce). */
4559
+ async unfreezeKeyWithCeremony(params, signer, options) {
4560
+ this.ensureEnabled();
4561
+ const WebAuthn = await this.runAuthenticationCeremony(params.KeyId, signer, options);
4562
+ return this.unfreezeKey({ ...params, WebAuthn });
4563
+ }
4564
+ /** Rotate the bound passkey, running the WebAuthn ceremony internally (raw-nonce). */
4565
+ async changePasskeyWithCeremony(params, signer, options) {
4566
+ this.ensureEnabled();
4567
+ const WebAuthn = await this.runAuthenticationCeremony(params.KeyId, signer, options);
4568
+ return this.changePasskey({ ...params, WebAuthn });
4569
+ }
4381
4570
  /**
4382
4571
  * Sign a message or an EIP-155 transaction (WebAuthn-gated).
4383
4572
  * Provide exactly one of `Message` (hex) or `Transaction`. For a raw 32-byte
@@ -4519,24 +4708,50 @@ var KmsManager = class {
4519
4708
  return this.deriveAddress({ ...params, WebAuthn });
4520
4709
  }
4521
4710
  /**
4522
- * Sign a message or EIP-155 transaction, running the challenge-binding ceremony
4523
- * internally. `params.KeyId` is required (it identifies the wallet to challenge).
4711
+ * Sign a message or EIP-155 transaction via `/Sign`, running the ceremony internally.
4712
+ * `params.KeyId` is required.
4713
+ *
4714
+ * ⚠️ STRICT MODE: unlike {@link signHashWithCeremony} / {@link signTypedDataWithCeremony},
4715
+ * this does NOT auto-bind a payload commitment, because the TA derives the signed digest
4716
+ * from `Message` / `Transaction` host-side (EIP-191 / RLP) and the SDK can't reproduce it
4717
+ * byte-exactly for every input. So it sends the RAW nonce by default — which the KMS will
4718
+ * REJECT once strict mode (#63) is on. For strict-safe signing either:
4719
+ * - pass `options.payload` = the exact digest the TA will sign (you computed it), or
4720
+ * - prefer {@link signHashWithCeremony} (commits to a known 32-byte hash).
4524
4721
  */
4525
4722
  async signWithCeremony(params, signer, options) {
4526
4723
  this.ensureEnabled();
4527
4724
  const WebAuthn = await this.runAuthenticationCeremony(params.KeyId, signer, options);
4528
4725
  return this.sign({ ...params, WebAuthn });
4529
4726
  }
4530
- /** Sign a 32-byte digest, running the challenge-binding ceremony internally. */
4727
+ /**
4728
+ * Sign a 32-byte digest, running the challenge-binding ceremony internally.
4729
+ * Binds the challenge to `hash` (WYSIWYS commitment, #68) by default — pass an
4730
+ * explicit `options.payload` only to override.
4731
+ */
4531
4732
  async signHashWithCeremony(hash, target, signer, options) {
4532
4733
  this.ensureEnabled();
4533
- const assertion = await this.runAuthenticationCeremony(target.KeyId, signer, options);
4734
+ const assertion = await this.runAuthenticationCeremony(target.KeyId, signer, {
4735
+ ...options,
4736
+ payload: options?.payload ?? hash
4737
+ });
4534
4738
  return this.signHashWithWebAuthn(hash, assertion.ChallengeId, assertion.Credential, target);
4535
4739
  }
4536
- /** Sign EIP-712 typed data, running the challenge-binding ceremony internally. */
4740
+ /**
4741
+ * Sign EIP-712 typed data, running the challenge-binding ceremony internally.
4742
+ * Auto-binds the WYSIWYS commitment (#68): the ceremony challenge is
4743
+ * `SHA-256(nonce ‖ eip712Digest)`, where `eip712Digest` is the standard EIP-712
4744
+ * digest the KMS hashes host-side — computed here via {@link eip712Digest} so the
4745
+ * user's signature commits to the exact typed-data payload. Pass an explicit
4746
+ * `options.payload` only to override.
4747
+ */
4537
4748
  async signTypedDataWithCeremony(params, signer, options) {
4538
4749
  this.ensureEnabled();
4539
- const webAuthnAssertion = await this.runAuthenticationCeremony(params.keyId, signer, options);
4750
+ const payload = options?.payload ?? eip712Digest(params);
4751
+ const webAuthnAssertion = await this.runAuthenticationCeremony(params.keyId, signer, {
4752
+ ...options,
4753
+ payload
4754
+ });
4540
4755
  return this.signTypedDataWithWebAuthn({ ...params, webAuthnAssertion });
4541
4756
  }
4542
4757
  /**
@@ -4545,7 +4760,10 @@ var KmsManager = class {
4545
4760
  */
4546
4761
  async signGrantSessionWithCeremony(params, signer, options) {
4547
4762
  this.ensureEnabled();
4548
- const webAuthnAssertion = await this.runGrantSessionCeremony(params.keyId, signer, options);
4763
+ const webAuthnAssertion = await this.runGrantSessionCeremony(params.keyId, signer, {
4764
+ ...options,
4765
+ payload: options?.payload ?? grantSessionFinalHash(params)
4766
+ });
4549
4767
  return this.signGrantSession({ ...params, webAuthnAssertion });
4550
4768
  }
4551
4769
  /**
@@ -4554,7 +4772,10 @@ var KmsManager = class {
4554
4772
  */
4555
4773
  async signP256GrantSessionWithCeremony(params, signer, options) {
4556
4774
  this.ensureEnabled();
4557
- const webAuthnAssertion = await this.runGrantSessionCeremony(params.keyId, signer, options);
4775
+ const webAuthnAssertion = await this.runGrantSessionCeremony(params.keyId, signer, {
4776
+ ...options,
4777
+ payload: options?.payload ?? grantSessionFinalHash(params)
4778
+ });
4558
4779
  return this.signP256GrantSession({ ...params, webAuthnAssertion });
4559
4780
  }
4560
4781
  // ── WebAuthn Ceremonies ─────────────────────────────────────────
@@ -4583,27 +4804,100 @@ var KmsManager = class {
4583
4804
  return this.client.post("/BeginAuthentication", { KeyId: keyId });
4584
4805
  }
4585
4806
  // ── Factory ─────────────────────────────────────────────────────
4807
+ /**
4808
+ * Create a KMS signer that authorizes each signature with a LEGACY raw passkey
4809
+ * assertion (reusable, no challenge consumption).
4810
+ *
4811
+ * @deprecated The KMS (v0.20.0+) rejects legacy raw passkey assertions for
4812
+ * signing/mutating operations (`/SignHash` → 400, "no challenge binding —
4813
+ * replayable"), unless `KMS_ALLOW_LEGACY_PASSKEY=1` is set on the KMS (test
4814
+ * only). Prefer {@link createKmsSignerWithCeremony}, which runs a one-time
4815
+ * challenge-bound WebAuthn ceremony per signature.
4816
+ */
4586
4817
  createKmsSigner(keyId, address, assertionProvider) {
4587
4818
  this.ensureEnabled();
4588
- return new KmsSigner(keyId, address, this, assertionProvider);
4819
+ return new KmsSigner(keyId, address, this, { mode: "legacy", assertionProvider });
4820
+ }
4821
+ /**
4822
+ * Create a KMS signer that authorizes each signature with a one-time,
4823
+ * challenge-bound WebAuthn ceremony (production-safe; replay-protected).
4824
+ *
4825
+ * Every `signMessage` call runs a FRESH ceremony (BeginAuthentication →
4826
+ * authenticator assertion → `/SignHash` with the `WebAuthn` field), because the
4827
+ * KMS consumes the challenge atomically (one challenge ⇒ one signature). A
4828
+ * Tier-2/3 BLS transfer that needs N owner signatures therefore triggers N
4829
+ * ceremonies — see {@link BLSSignatureService} (which now skips the unused
4830
+ * userOpHash owner-ECDSA for tiered signatures, so Tier-2 needs only one).
4831
+ *
4832
+ * @param ceremonySigner authenticator that signs the WebAuthn challenge
4833
+ * (a browser passkey on the client, or {@link P256PasskeySigner} server-side).
4834
+ */
4835
+ createKmsSignerWithCeremony(keyId, address, ceremonySigner, ceremonyOptions, commitPayload = true) {
4836
+ this.ensureEnabled();
4837
+ return new KmsSigner(keyId, address, this, {
4838
+ mode: "ceremony",
4839
+ ceremonySigner,
4840
+ ceremonyOptions,
4841
+ commitPayload
4842
+ });
4589
4843
  }
4590
4844
  };
4591
4845
  var KmsSigner = class {
4592
- constructor(keyId, _address, kmsManager, assertionProvider) {
4846
+ constructor(keyId, _address, kmsManager, auth) {
4593
4847
  this.keyId = keyId;
4594
4848
  this._address = _address;
4595
4849
  this.kmsManager = kmsManager;
4596
- this.assertionProvider = assertionProvider;
4850
+ this.auth = auth;
4597
4851
  }
4598
4852
  async getAddress() {
4599
4853
  return this._address;
4600
4854
  }
4601
- async signMessage(message) {
4855
+ /**
4856
+ * EIP-191 personal-sign over a digest. A string is hashed as UTF-8 text, a byte
4857
+ * array as raw bytes — byte-identical to ethers `hashMessage`.
4858
+ *
4859
+ * @param webAuthnAssertion OPTIONAL pre-built, one-time ceremony assertion. Use
4860
+ * this in server flows where the passkey lives on the USER's device: the
4861
+ * frontend runs the BeginAuthentication ceremony and the backend forwards the
4862
+ * resulting `{ ChallengeId, Credential }` here. When supplied it takes
4863
+ * precedence over the signer's baked-in auth mode. Each assertion is one-time
4864
+ * (the KMS consumes the challenge), so a caller that needs N signatures must
4865
+ * supply N distinct assertions.
4866
+ *
4867
+ * WYSIWYS (AirAccount #68): the frontend MUST build the assertion over the
4868
+ * payload-committed challenge `commitChallenge(nonce, hashOf(message))`, not the
4869
+ * raw nonce — otherwise a compromised host could swap the signed payload. The
4870
+ * raw-nonce assertion only works while the KMS runs in transition mode. (The
4871
+ * signer's own ceremony mode does this automatically.)
4872
+ */
4873
+ async signMessage(message, webAuthnAssertion) {
4602
4874
  const messageHash = hashMessage(message);
4603
- const assertion = await this.assertionProvider();
4604
- const signResponse = await this.kmsManager.signHash(messageHash, assertion, {
4605
- Address: this._address
4606
- });
4875
+ const target = { Address: this._address };
4876
+ if (webAuthnAssertion) {
4877
+ const signResponse2 = await this.kmsManager.signHashWithWebAuthn(
4878
+ messageHash,
4879
+ webAuthnAssertion.ChallengeId,
4880
+ webAuthnAssertion.Credential,
4881
+ target
4882
+ );
4883
+ return "0x" + signResponse2.Signature;
4884
+ }
4885
+ if (this.auth.mode === "ceremony") {
4886
+ const assertion2 = await this.kmsManager.runAuthenticationCeremony(
4887
+ this.keyId,
4888
+ this.auth.ceremonySigner,
4889
+ this.auth.commitPayload ? { ...this.auth.ceremonyOptions, payload: messageHash } : this.auth.ceremonyOptions
4890
+ );
4891
+ const signResponse2 = await this.kmsManager.signHashWithWebAuthn(
4892
+ messageHash,
4893
+ assertion2.ChallengeId,
4894
+ assertion2.Credential,
4895
+ target
4896
+ );
4897
+ return "0x" + signResponse2.Signature;
4898
+ }
4899
+ const assertion = await this.auth.assertionProvider();
4900
+ const signResponse = await this.kmsManager.signHash(messageHash, assertion, target);
4607
4901
  return "0x" + signResponse.Signature;
4608
4902
  }
4609
4903
  };
@@ -4666,7 +4960,15 @@ var KmsAgentService = class {
4666
4960
  // challenge bound to the HUMAN key. These helpers run the full ceremony
4667
4961
  // (begin → clientDataJSON → assertion) via the shared
4668
4962
  // {@link runAuthenticationCeremony} helper, then invoke the endpoint.
4669
- /** Mint an agent key, running the challenge-binding ceremony internally. */
4963
+ /**
4964
+ * Mint an agent key, running the challenge-binding ceremony internally.
4965
+ *
4966
+ * STRICT MODE (AirAccount #115): bind the mint params by passing `options.payload =
4967
+ * mintDigest({ kind: "agent", walletId, index, ttlSecs, subject })` — `index` is the
4968
+ * agent_index the KMS will assign (query it first), `subject` the JWT sub (human key id),
4969
+ * `ttlSecs` the JWT lifetime. Without a payload the ceremony sends the raw nonce, which
4970
+ * strict mode rejects.
4971
+ */
4670
4972
  async createAgentKeyWithCeremony(params, signer, options) {
4671
4973
  this.http.ensureEnabled();
4672
4974
  const webAuthnAssertion = await runAuthenticationCeremony(
@@ -4753,7 +5055,15 @@ var KmsSessionService = class {
4753
5055
  // Create + revoke gate on the generic purpose="authentication" challenge bound
4754
5056
  // to the HUMAN key. These helpers run the full ceremony (begin → clientDataJSON
4755
5057
  // → assertion) via the shared {@link runAuthenticationCeremony} helper.
4756
- /** Create a P-256 session key, running the challenge-binding ceremony internally. */
5058
+ /**
5059
+ * Create a P-256 session key, running the challenge-binding ceremony internally.
5060
+ *
5061
+ * STRICT MODE (AirAccount #115): bind the mint params by passing `options.payload =
5062
+ * mintDigest({ kind: "p256", walletId, index, ttlSecs, subject })` — `index` is the
5063
+ * session_index the KMS will assign (query it first), `subject` the JWT sub (human key
5064
+ * id), `ttlSecs` the JWT lifetime. Without a payload the ceremony sends the raw nonce,
5065
+ * which strict mode rejects.
5066
+ */
4757
5067
  async createP256SessionKeyWithCeremony(params, signer, options) {
4758
5068
  this.http.ensureEnabled();
4759
5069
  const webAuthnAssertion = await runAuthenticationCeremony(
@@ -4817,7 +5127,108 @@ var KmsPaymentSigner = class {
4817
5127
  this.http.ensureEnabled();
4818
5128
  return this.signWithAuth("/kms/SignX402Payment", { ...params }, auth);
4819
5129
  }
5130
+ // ── Ceremony-internal variants with WYSIWYS payload commitment (#68 / #135 item 1) ──
5131
+ // Each payment endpoint is a fixed-schema SignTypedData host-side, so the commitment
5132
+ // payload is the EIP-712 digest of that schema. We compute it SDK-side (digest helpers
5133
+ // below, schemas mirrored from kms/host/src/api_server.rs) and bind the ceremony
5134
+ // challenge to it: challenge = SHA-256(nonce ‖ eip712Digest). Live-verified against KMS.
5135
+ /** Sign a MicroPaymentChannel voucher, running the committed ceremony internally. */
5136
+ async signMicropaymentVoucherWithCeremony(params, signer, options) {
5137
+ this.http.ensureEnabled();
5138
+ const webAuthnAssertion = await runAuthenticationCeremony(this.http, params.keyId, signer, {
5139
+ ...options,
5140
+ payload: micropaymentVoucherDigest(params)
5141
+ });
5142
+ return this.signMicropaymentVoucher(params, { webAuthnAssertion });
5143
+ }
5144
+ /** Sign a GToken EIP-3009 authorization, running the committed ceremony internally. */
5145
+ async signGTokenAuthorizationWithCeremony(params, signer, options) {
5146
+ this.http.ensureEnabled();
5147
+ const webAuthnAssertion = await runAuthenticationCeremony(this.http, params.keyId, signer, {
5148
+ ...options,
5149
+ payload: gTokenAuthorizationDigest(params)
5150
+ });
5151
+ return this.signGTokenAuthorization(params, { webAuthnAssertion });
5152
+ }
5153
+ /** Sign an x402 payment, running the committed ceremony internally. */
5154
+ async signX402PaymentWithCeremony(params, signer, options) {
5155
+ this.http.ensureEnabled();
5156
+ const webAuthnAssertion = await runAuthenticationCeremony(this.http, params.keyId, signer, {
5157
+ ...options,
5158
+ payload: x402PaymentDigest(params)
5159
+ });
5160
+ return this.signX402Payment(params, { webAuthnAssertion });
5161
+ }
4820
5162
  };
5163
+ function micropaymentVoucherDigest(p) {
5164
+ return eip712Digest({
5165
+ domain: { name: "MicroPaymentChannel", version: "1.0.0", chainId: p.chainId, verifyingContract: p.verifyingContract },
5166
+ primaryType: "Voucher",
5167
+ types: [
5168
+ {
5169
+ name: "Voucher",
5170
+ fields: [
5171
+ { name: "channelId", type: "bytes32" },
5172
+ { name: "cumulativeAmount", type: "uint256" }
5173
+ ]
5174
+ }
5175
+ ],
5176
+ message: [
5177
+ { name: "channelId", value: p.channelId },
5178
+ { name: "cumulativeAmount", value: p.cumulativeAmount }
5179
+ ]
5180
+ });
5181
+ }
5182
+ function gTokenAuthorizationDigest(p) {
5183
+ return eip712Digest({
5184
+ domain: { name: "GToken", version: "1", chainId: p.chainId, verifyingContract: p.gTokenAddress },
5185
+ primaryType: "TransferWithAuthorization",
5186
+ types: [
5187
+ {
5188
+ name: "TransferWithAuthorization",
5189
+ fields: [
5190
+ { name: "from", type: "address" },
5191
+ { name: "to", type: "address" },
5192
+ { name: "value", type: "uint256" },
5193
+ { name: "validAfter", type: "uint256" },
5194
+ { name: "validBefore", type: "uint256" },
5195
+ { name: "nonce", type: "bytes32" }
5196
+ ]
5197
+ }
5198
+ ],
5199
+ message: [
5200
+ { name: "from", value: p.from },
5201
+ { name: "to", value: p.to },
5202
+ { name: "value", value: p.value },
5203
+ { name: "validAfter", value: p.validAfter },
5204
+ { name: "validBefore", value: p.validBefore },
5205
+ { name: "nonce", value: p.nonce }
5206
+ ]
5207
+ });
5208
+ }
5209
+ function x402PaymentDigest(p) {
5210
+ return eip712Digest({
5211
+ domain: { name: "SuperPaymaster", version: "1", chainId: p.chainId, verifyingContract: p.verifyingContract },
5212
+ primaryType: "PaymentPayload",
5213
+ types: [
5214
+ {
5215
+ name: "PaymentPayload",
5216
+ fields: [
5217
+ { name: "paymentId", type: "bytes32" },
5218
+ { name: "amount", type: "uint256" },
5219
+ { name: "recipient", type: "address" },
5220
+ { name: "deadline", type: "uint256" }
5221
+ ]
5222
+ }
5223
+ ],
5224
+ message: [
5225
+ { name: "paymentId", value: p.paymentId },
5226
+ { name: "amount", value: p.amount },
5227
+ { name: "recipient", value: p.recipient },
5228
+ { name: "deadline", value: p.deadline }
5229
+ ]
5230
+ });
5231
+ }
4821
5232
 
4822
5233
  // ../airaccount/src/server/services/kms-monitor-service.ts
4823
5234
  var KmsMonitorService = class {
@@ -4989,6 +5400,37 @@ var LocalWalletSigner = class {
4989
5400
  return { address: this.account.address };
4990
5401
  }
4991
5402
  };
5403
+
5404
+ // ../airaccount/src/server/adapters/kms-signer-adapter.ts
5405
+ var KmsSignerAdapter = class {
5406
+ constructor(kms, resolveKey) {
5407
+ this.kms = kms;
5408
+ this.resolveKey = resolveKey;
5409
+ }
5410
+ async getAddress(userId) {
5411
+ return (await this.resolveKey(userId)).address;
5412
+ }
5413
+ async ensureSigner(userId) {
5414
+ return { address: (await this.resolveKey(userId)).address };
5415
+ }
5416
+ async signMessage(userId, message, ctx) {
5417
+ const { address } = await this.resolveKey(userId);
5418
+ const hash = hashMessage(message);
5419
+ const target = { Address: address };
5420
+ if (ctx && "webAuthnAssertion" in ctx) {
5421
+ const { ChallengeId, Credential } = ctx.webAuthnAssertion;
5422
+ const res = await this.kms.signHashWithWebAuthn(hash, ChallengeId, Credential, target);
5423
+ return "0x" + res.Signature;
5424
+ }
5425
+ if (ctx && "assertion" in ctx) {
5426
+ const res = await this.kms.signHash(hash, ctx.assertion, target);
5427
+ return "0x" + res.Signature;
5428
+ }
5429
+ throw new Error(
5430
+ "KmsSignerAdapter: KMS signing requires an auth context \u2014 pass a one-time WebAuthnCeremonyContext { webAuthnAssertion } (preferred)."
5431
+ );
5432
+ }
5433
+ };
4992
5434
  /*! Bundled license information:
4993
5435
 
4994
5436
  @noble/curves/nist.js:
@@ -5041,6 +5483,7 @@ exports.KmsMonitorService = KmsMonitorService;
5041
5483
  exports.KmsPaymentSigner = KmsPaymentSigner;
5042
5484
  exports.KmsSessionService = KmsSessionService;
5043
5485
  exports.KmsSigner = KmsSigner;
5486
+ exports.KmsSignerAdapter = KmsSignerAdapter;
5044
5487
  exports.L2_TYPE = L2_TYPE;
5045
5488
  exports.LocalWalletSigner = LocalWalletSigner;
5046
5489
  exports.MAX_GUARDIANS = MAX_GUARDIANS;
@@ -5076,15 +5519,21 @@ exports.buildClientDataJSON = buildClientDataJSON;
5076
5519
  exports.buildFullInitConfig = buildFullInitConfig;
5077
5520
  exports.buildInstallModuleHash = buildInstallModuleHash;
5078
5521
  exports.buildUninstallModuleHash = buildUninstallModuleHash;
5522
+ exports.commitChallenge = commitChallenge;
5079
5523
  exports.computeOapdSalt = computeOapdSalt;
5524
+ exports.eip712Digest = eip712Digest;
5080
5525
  exports.erc8004AddressesForChain = erc8004AddressesForChain;
5526
+ exports.gTokenAuthorizationDigest = gTokenAuthorizationDigest;
5081
5527
  exports.getOapdAddress = getOapdAddress;
5082
5528
  exports.getOapdAddressWithChainId = getOapdAddressWithChainId;
5529
+ exports.grantSessionFinalHash = grantSessionFinalHash;
5083
5530
  exports.initConfigFromRecord = initConfigFromRecord;
5084
5531
  exports.initConfigToTuple = initConfigToTuple;
5085
5532
  exports.isExecuteUserOpWrapped = isExecuteUserOpWrapped;
5086
5533
  exports.isOapdDeployed = isOapdDeployed;
5087
5534
  exports.isPendingConfirmation = isPendingConfirmation;
5535
+ exports.micropaymentVoucherDigest = micropaymentVoucherDigest;
5536
+ exports.mintDigest = mintDigest;
5088
5537
  exports.packP256SessionSignature = packP256SessionSignature;
5089
5538
  exports.packSecp256k1SessionSignature = packSecp256k1SessionSignature;
5090
5539
  exports.runAuthenticationCeremony = runAuthenticationCeremony;
@@ -5095,5 +5544,6 @@ exports.serializeGuardianSpecs = serializeGuardianSpecs;
5095
5544
  exports.toGuardianSpecs = toGuardianSpecs;
5096
5545
  exports.validateConfig = validateConfig;
5097
5546
  exports.wrapExecuteUserOp = wrapExecuteUserOp;
5098
- //# sourceMappingURL=chunk-4Q6FADF6.cjs.map
5099
- //# sourceMappingURL=chunk-4Q6FADF6.cjs.map
5547
+ exports.x402PaymentDigest = x402PaymentDigest;
5548
+ //# sourceMappingURL=chunk-UZE7IPOK.cjs.map
5549
+ //# sourceMappingURL=chunk-UZE7IPOK.cjs.map