@pafi-dev/issuer 0.23.0 → 0.25.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.
package/dist/index.cjs CHANGED
@@ -26,6 +26,7 @@ __export(index_exports, {
26
26
  BundlerNotConfiguredError: () => BundlerNotConfiguredError,
27
27
  BundlerRejectedError: () => BundlerRejectedError,
28
28
  BurnIndexer: () => BurnIndexer,
29
+ BurnIndexerFinalizeError: () => BurnIndexerFinalizeError,
29
30
  ConfigurationError: () => ConfigurationError,
30
31
  DEFAULT_REDEMPTION_POLICY: () => DEFAULT_REDEMPTION_POLICY,
31
32
  DefaultPolicyEngine: () => DefaultPolicyEngine,
@@ -57,6 +58,7 @@ __export(index_exports, {
57
58
  PerpDepositError: () => PerpDepositError,
58
59
  PerpDepositHandler: () => PerpDepositHandler,
59
60
  PointIndexer: () => PointIndexer,
61
+ PointIndexerFinalizeError: () => PointIndexerFinalizeError,
60
62
  PointTokenDomainResolver: () => PointTokenDomainResolver,
61
63
  PolicyProvider: () => PolicyProvider,
62
64
  REDEMPTION_HISTORY_WINDOW_SEC: () => REDEMPTION_HISTORY_WINDOW_SEC,
@@ -908,6 +910,7 @@ var RelayService = class {
908
910
  "prepareMint: deadline exceeds maximum allowed window (1 hour)"
909
911
  );
910
912
  }
913
+ const MINT_SOURCE = import_core5.Source.EQUITY;
911
914
  const useWrapper = params.mintFeeWrapperAddress !== void 0;
912
915
  const receiverForSig = useWrapper ? params.mintFeeWrapperAddress : params.userAddress;
913
916
  let minterSig;
@@ -919,6 +922,7 @@ var RelayService = class {
919
922
  user: params.userAddress,
920
923
  receiver: receiverForSig,
921
924
  amount: params.amount,
925
+ source: MINT_SOURCE,
922
926
  nonce: params.mintRequestNonce,
923
927
  deadline: params.deadline
924
928
  }
@@ -949,9 +953,15 @@ var RelayService = class {
949
953
  mintTarget = params.mintFeeWrapperAddress;
950
954
  } else {
951
955
  mintCallData = (0, import_viem3.encodeFunctionData)({
952
- abi: import_core5.POINT_TOKEN_ABI,
956
+ abi: import_core5.POINT_TOKEN_MINT_SIG_ABI,
953
957
  functionName: "mint",
954
- args: [params.userAddress, params.amount, params.deadline, minterSig]
958
+ args: [
959
+ params.userAddress,
960
+ params.amount,
961
+ MINT_SOURCE,
962
+ params.deadline,
963
+ minterSig
964
+ ]
955
965
  });
956
966
  mintTarget = params.pointTokenAddress;
957
967
  }
@@ -1036,11 +1046,12 @@ var RelayService = class {
1036
1046
  let burnCallData;
1037
1047
  try {
1038
1048
  burnCallData = (0, import_viem3.encodeFunctionData)({
1039
- abi: import_core5.POINT_TOKEN_ABI,
1049
+ abi: import_core5.POINT_TOKEN_BURN_SIG_ABI,
1040
1050
  functionName: "burn",
1041
1051
  args: [
1042
1052
  params.burnRequest.from,
1043
1053
  params.burnRequest.amount,
1054
+ params.burnRequest.source,
1044
1055
  params.burnRequest.deadline,
1045
1056
  params.burnerSignature
1046
1057
  ]
@@ -1135,11 +1146,12 @@ var RelayService = class {
1135
1146
  mintTarget = params.mintFeeWrapperAddress;
1136
1147
  } else {
1137
1148
  mintCallData = (0, import_viem3.encodeFunctionData)({
1138
- abi: import_core5.POINT_TOKEN_ABI,
1149
+ abi: import_core5.POINT_TOKEN_MINT_SIG_ABI,
1139
1150
  functionName: "mint",
1140
1151
  args: [
1141
1152
  params.userAddress,
1142
1153
  params.amount,
1154
+ import_core5.Source.EQUITY,
1143
1155
  params.deadline,
1144
1156
  PLACEHOLDER_SIG_65
1145
1157
  ]
@@ -1161,11 +1173,12 @@ var RelayService = class {
1161
1173
  /** Burn-side mirror of `previewMintUserOp`. */
1162
1174
  previewBurnUserOp(params) {
1163
1175
  const burnCallData = (0, import_viem3.encodeFunctionData)({
1164
- abi: import_core5.POINT_TOKEN_ABI,
1176
+ abi: import_core5.POINT_TOKEN_BURN_SIG_ABI,
1165
1177
  functionName: "burn",
1166
1178
  args: [
1167
1179
  params.userAddress,
1168
1180
  params.amount,
1181
+ import_core5.Source.EQUITY,
1169
1182
  params.deadline,
1170
1183
  PLACEHOLDER_SIG_65
1171
1184
  ]
@@ -1383,6 +1396,16 @@ var InMemoryCursorStore = class _InMemoryCursorStore {
1383
1396
 
1384
1397
  // src/indexer/pointIndexer.ts
1385
1398
  var import_viem4 = require("viem");
1399
+ var PointIndexerFinalizeError = class extends Error {
1400
+ constructor(message, context, cause) {
1401
+ super(message);
1402
+ this.context = context;
1403
+ this.cause = cause;
1404
+ this.name = "PointIndexerFinalizeError";
1405
+ }
1406
+ context;
1407
+ cause;
1408
+ };
1386
1409
  var TRANSFER_EVENT = (0, import_viem4.parseAbiItem)(
1387
1410
  "event Transfer(address indexed from, address indexed to, uint256 value)"
1388
1411
  );
@@ -1608,8 +1631,18 @@ var PointIndexer = class {
1608
1631
  evt.txHash,
1609
1632
  this.pointTokenAddress
1610
1633
  );
1611
- } catch {
1612
- return;
1634
+ } catch (err) {
1635
+ throw new PointIndexerFinalizeError(
1636
+ `PointIndexer.deductBalance failed for tx ${evt.txHash} (to=${evt.to}, amount=${evt.amount}, block=${evt.blockNumber}); cursor will NOT advance, next tick retries.`,
1637
+ {
1638
+ pointToken: this.pointTokenAddress,
1639
+ to: evt.to,
1640
+ amount: evt.amount,
1641
+ txHash: evt.txHash,
1642
+ blockNumber: evt.blockNumber
1643
+ },
1644
+ err
1645
+ );
1613
1646
  }
1614
1647
  try {
1615
1648
  await this.ledger.updateMintStatus(match.lockId, "MINTED", evt.txHash);
@@ -1631,6 +1664,16 @@ function pickMatchingLock(locks, amount) {
1631
1664
 
1632
1665
  // src/indexer/burnIndexer.ts
1633
1666
  var import_viem5 = require("viem");
1667
+ var BurnIndexerFinalizeError = class extends Error {
1668
+ constructor(message, context, cause) {
1669
+ super(message);
1670
+ this.context = context;
1671
+ this.cause = cause;
1672
+ this.name = "BurnIndexerFinalizeError";
1673
+ }
1674
+ context;
1675
+ cause;
1676
+ };
1634
1677
  var TRANSFER_EVENT2 = (0, import_viem5.parseAbiItem)(
1635
1678
  "event Transfer(address indexed from, address indexed to, uint256 value)"
1636
1679
  );
@@ -1798,7 +1841,18 @@ var BurnIndexer = class {
1798
1841
  try {
1799
1842
  await this.ledger.resolveCreditByBurnTx(lockId, evt.txHash);
1800
1843
  } catch (err) {
1801
- console.error("[PAFI] BurnIndexer finalize error \u2014 credit may be lost:", err);
1844
+ throw new BurnIndexerFinalizeError(
1845
+ `BurnIndexer.resolveCreditByBurnTx failed for tx ${evt.txHash} (lockId=${lockId}, from=${evt.from}, amount=${evt.amount}, block=${evt.blockNumber}); cursor will NOT advance, next tick retries.`,
1846
+ {
1847
+ pointToken: this.pointTokenAddress,
1848
+ from: evt.from,
1849
+ amount: evt.amount,
1850
+ txHash: evt.txHash,
1851
+ blockNumber: evt.blockNumber,
1852
+ lockId
1853
+ },
1854
+ err
1855
+ );
1802
1856
  }
1803
1857
  }
1804
1858
  };
@@ -2113,14 +2167,12 @@ var IssuerApiHandlers = class _IssuerApiHandlers {
2113
2167
  { requested: pointToken }
2114
2168
  );
2115
2169
  }
2116
- const [mintRequestNonce, offChainBalance, onChainBalance, minter] = await Promise.all([
2117
- (0, import_core6.getMintRequestNonce)(this.provider, pointToken, normalizedAuthed),
2170
+ const [offChainBalance, onChainBalance, minter] = await Promise.all([
2118
2171
  this.ledger.getBalance(normalizedAuthed, pointToken),
2119
2172
  (0, import_core6.getPointTokenBalance)(this.provider, pointToken, normalizedAuthed),
2120
2173
  (0, import_core6.isMinter)(this.provider, pointToken, normalizedAuthed)
2121
2174
  ]);
2122
2175
  return {
2123
- mintRequestNonce,
2124
2176
  offChainBalance,
2125
2177
  onChainBalance,
2126
2178
  totalBalance: offChainBalance + onChainBalance,
@@ -2257,7 +2309,8 @@ var PointTokenDomainResolver = class {
2257
2309
  var import_viem8 = require("viem");
2258
2310
  var import_core7 = require("@pafi-dev/core");
2259
2311
  var DEFAULT_REDEEM_LOCK_MS = 15 * 60 * 1e3;
2260
- var DEFAULT_SIG_DEADLINE_SEC = 15 * 60;
2312
+ var M11_SAFETY_MARGIN_MS = 30 * 1e3;
2313
+ var DEFAULT_SIG_DEADLINE_SEC = (DEFAULT_REDEEM_LOCK_MS - M11_SAFETY_MARGIN_MS) / 1e3;
2261
2314
  var PTRedeemError = class extends import_core.PafiSdkError {
2262
2315
  httpStatus = "unprocessable";
2263
2316
  code;
@@ -2324,6 +2377,13 @@ var PTRedeemHandler = class {
2324
2377
  this.redeemLockDurationMs = config.redeemLockDurationMs ?? DEFAULT_REDEEM_LOCK_MS;
2325
2378
  this.signatureDeadlineSeconds = config.signatureDeadlineSeconds ?? DEFAULT_SIG_DEADLINE_SEC;
2326
2379
  this.now = config.now ?? (() => Date.now());
2380
+ const maxAllowedSignatureMs = this.redeemLockDurationMs - M11_SAFETY_MARGIN_MS;
2381
+ if (this.signatureDeadlineSeconds * 1e3 > maxAllowedSignatureMs) {
2382
+ throw new PTRedeemError(
2383
+ "INVALID_AMOUNT",
2384
+ `PTRedeemHandler config: signatureDeadlineSeconds (${this.signatureDeadlineSeconds}s) must be at most redeemLockDurationMs - safety margin = ${maxAllowedSignatureMs / 1e3}s (redeemLockDurationMs=${this.redeemLockDurationMs / 1e3}s, safety=${M11_SAFETY_MARGIN_MS / 1e3}s). See audit M-11.`
2385
+ );
2386
+ }
2327
2387
  if (config.redemptionService) {
2328
2388
  this.redemptionService = config.redemptionService;
2329
2389
  }
@@ -2389,8 +2449,14 @@ var PTRedeemHandler = class {
2389
2449
  }
2390
2450
  }
2391
2451
  async _handleAfterNonceLock(request, burnNonce, pointTokenAddress) {
2452
+ const referenceMs = this.now();
2453
+ const projectedLockExpiresAtMs = referenceMs + this.redeemLockDurationMs;
2454
+ const requestedDeadlineSec = Math.floor(referenceMs / 1e3) + this.signatureDeadlineSeconds;
2455
+ const lockBoundedDeadlineSec = Math.floor(
2456
+ (projectedLockExpiresAtMs - M11_SAFETY_MARGIN_MS) / 1e3
2457
+ );
2392
2458
  const previewDeadline = BigInt(
2393
- Math.floor(this.now() / 1e3) + this.signatureDeadlineSeconds
2459
+ Math.min(requestedDeadlineSec, lockBoundedDeadlineSec)
2394
2460
  );
2395
2461
  let fee;
2396
2462
  if (request.feeAmount !== void 0) {
@@ -2398,7 +2464,7 @@ var PTRedeemHandler = class {
2398
2464
  } else if (this.feeService) {
2399
2465
  const previewUserOp = this.relayService.previewBurnUserOp({
2400
2466
  userAddress: request.userAddress,
2401
- aaNonce: burnNonce,
2467
+ aaNonce: request.aaNonce,
2402
2468
  pointTokenAddress,
2403
2469
  amount: request.amount,
2404
2470
  deadline: previewDeadline
@@ -2440,10 +2506,12 @@ var PTRedeemHandler = class {
2440
2506
  chainId: this.chainId,
2441
2507
  verifyingContract: pointTokenAddress
2442
2508
  };
2509
+ const BURN_SOURCE = import_core7.Source.EQUITY;
2443
2510
  const sponsoredBurnAmount = request.amount - fee;
2444
2511
  const sponsoredBurnRequest = {
2445
2512
  from: request.userAddress,
2446
2513
  amount: sponsoredBurnAmount,
2514
+ source: BURN_SOURCE,
2447
2515
  nonce: burnNonce,
2448
2516
  deadline
2449
2517
  };
@@ -2479,6 +2547,7 @@ var PTRedeemHandler = class {
2479
2547
  const fallbackBurnRequest = {
2480
2548
  from: request.userAddress,
2481
2549
  amount: request.amount,
2550
+ source: BURN_SOURCE,
2482
2551
  nonce: burnNonce,
2483
2552
  deadline
2484
2553
  };
@@ -3047,14 +3116,30 @@ function isNoWrapper2(address) {
3047
3116
  return lower === "0x0000000000000000000000000000000000000000" || lower === "0x000000000000000000000000000000000000dead";
3048
3117
  }
3049
3118
  var DEFAULT_LOCK_MS = 15 * 60 * 1e3;
3050
- var DEFAULT_SIG_DEADLINE_SEC2 = 15 * 60;
3119
+ var M11_SAFETY_MARGIN_MS2 = 30 * 1e3;
3120
+ var DEFAULT_SIG_DEADLINE_SEC2 = (DEFAULT_LOCK_MS - M11_SAFETY_MARGIN_MS2) / 1e3;
3051
3121
  var PTClaimHandler = class {
3052
3122
  cfg;
3123
+ inFlightNonces = /* @__PURE__ */ new Map();
3053
3124
  constructor(config) {
3125
+ const lockDurationMs = config.lockDurationMs ?? DEFAULT_LOCK_MS;
3126
+ const signatureDeadlineSeconds = config.signatureDeadlineSeconds ?? DEFAULT_SIG_DEADLINE_SEC2;
3127
+ const maxAllowedSignatureMs = lockDurationMs - M11_SAFETY_MARGIN_MS2;
3128
+ if (signatureDeadlineSeconds * 1e3 > maxAllowedSignatureMs) {
3129
+ throw new PTClaimError(
3130
+ "VALIDATION_FAILED",
3131
+ `PTClaimHandler config: signatureDeadlineSeconds (${signatureDeadlineSeconds}s) must be at most lockDurationMs - safety margin = ${maxAllowedSignatureMs / 1e3}s (lockDurationMs=${lockDurationMs / 1e3}s, safety=${M11_SAFETY_MARGIN_MS2 / 1e3}s). See audit M-11.`,
3132
+ {
3133
+ lockDurationMs,
3134
+ signatureDeadlineSeconds,
3135
+ maxAllowedSignatureSec: maxAllowedSignatureMs / 1e3
3136
+ }
3137
+ );
3138
+ }
3054
3139
  this.cfg = {
3055
3140
  ...config,
3056
- lockDurationMs: config.lockDurationMs ?? DEFAULT_LOCK_MS,
3057
- signatureDeadlineSeconds: config.signatureDeadlineSeconds ?? DEFAULT_SIG_DEADLINE_SEC2,
3141
+ lockDurationMs,
3142
+ signatureDeadlineSeconds,
3058
3143
  now: config.now ?? (() => Date.now())
3059
3144
  };
3060
3145
  }
@@ -3084,77 +3169,82 @@ var PTClaimHandler = class {
3084
3169
  }
3085
3170
  const chainAddresses = (0, import_core11.getContractAddresses)(request.chainId);
3086
3171
  const { batchExecutor: batchExecutorAddress } = chainAddresses;
3172
+ let mintRequestNonce;
3173
+ try {
3174
+ mintRequestNonce = await this.cfg.provider.readContract({
3175
+ address: request.pointTokenAddress,
3176
+ abi: import_core11.POINT_TOKEN_ABI,
3177
+ functionName: "mintRequestNonces",
3178
+ args: [request.userAddress]
3179
+ });
3180
+ } catch (err) {
3181
+ throw new PTClaimError(
3182
+ "NONCE_READ_FAILED",
3183
+ `failed to read mintRequestNonces(${request.userAddress}): ${err instanceof Error ? err.message : String(err)}`
3184
+ );
3185
+ }
3186
+ const nonceKey = `${(0, import_viem10.getAddress)(request.userAddress).toLowerCase()}:${request.pointTokenAddress.toLowerCase()}`;
3187
+ let userNonces = this.inFlightNonces.get(nonceKey);
3188
+ if (!userNonces) {
3189
+ userNonces = /* @__PURE__ */ new Set();
3190
+ this.inFlightNonces.set(nonceKey, userNonces);
3191
+ }
3192
+ if (userNonces.has(mintRequestNonce)) {
3193
+ throw new PTClaimError(
3194
+ "NONCE_IN_FLIGHT",
3195
+ `concurrent claim for nonce ${mintRequestNonce} in progress; retry after the prior request completes`,
3196
+ { userAddress: request.userAddress, pointToken: request.pointTokenAddress, nonce: mintRequestNonce.toString() }
3197
+ );
3198
+ }
3199
+ userNonces.add(mintRequestNonce);
3087
3200
  const wrapperOverride = this.cfg.mintFeeWrapperAddress;
3088
3201
  const wrapperFromSdk = chainAddresses.mintFeeWrapper;
3089
3202
  const resolvedWrapper = wrapperOverride !== void 0 ? isNoWrapper2(wrapperOverride) ? void 0 : wrapperOverride : isNoWrapper2(wrapperFromSdk) ? void 0 : wrapperFromSdk;
3090
- const lockId = await this.cfg.ledger.lockForMinting(
3091
- request.userAddress,
3092
- request.amount,
3093
- this.cfg.lockDurationMs,
3094
- request.pointTokenAddress
3095
- );
3096
3203
  try {
3097
- const signatureDeadline = BigInt(
3098
- Math.floor(this.cfg.now() / 1e3) + this.cfg.signatureDeadlineSeconds
3099
- );
3100
- const previewUserOp = this.cfg.relayService.previewMintUserOp({
3101
- userAddress: request.userAddress,
3102
- aaNonce: request.aaNonce,
3103
- pointTokenAddress: request.pointTokenAddress,
3104
- amount: request.amount,
3105
- deadline: signatureDeadline,
3106
- mintFeeWrapperAddress: resolvedWrapper
3107
- });
3108
- const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee({
3109
- scenario: resolvedWrapper ? "mint-wrapped" : "mint",
3110
- contractAddress: request.pointTokenAddress,
3111
- partialUserOp: {
3112
- sender: previewUserOp.sender,
3113
- nonce: previewUserOp.nonce,
3114
- callData: previewUserOp.callData
3115
- }
3116
- }) : 0n;
3117
- const domainName = await this.cfg.domainResolver.resolve(
3204
+ const lockCreatedAtMs = this.cfg.now();
3205
+ const lockExpiresAtMs = lockCreatedAtMs + this.cfg.lockDurationMs;
3206
+ const lockId = await this.cfg.ledger.lockForMinting(
3207
+ request.userAddress,
3208
+ request.amount,
3209
+ this.cfg.lockDurationMs,
3118
3210
  request.pointTokenAddress
3119
3211
  );
3120
- const domain = {
3121
- name: domainName,
3122
- chainId: request.chainId,
3123
- verifyingContract: request.pointTokenAddress
3124
- };
3125
- let userOp;
3126
3212
  try {
3127
- userOp = await this.cfg.relayService.prepareMint({
3213
+ const requestedDeadlineSec = Math.floor(lockCreatedAtMs / 1e3) + this.cfg.signatureDeadlineSeconds;
3214
+ const lockBoundedDeadlineSec = Math.floor(
3215
+ (lockExpiresAtMs - M11_SAFETY_MARGIN_MS2) / 1e3
3216
+ );
3217
+ const signatureDeadline = BigInt(
3218
+ Math.min(requestedDeadlineSec, lockBoundedDeadlineSec)
3219
+ );
3220
+ const previewUserOp = this.cfg.relayService.previewMintUserOp({
3128
3221
  userAddress: request.userAddress,
3129
3222
  aaNonce: request.aaNonce,
3130
- batchExecutorAddress,
3131
3223
  pointTokenAddress: request.pointTokenAddress,
3132
3224
  amount: request.amount,
3133
- issuerSignerWallet: this.cfg.issuerSignerWallet,
3134
- domain,
3135
- mintRequestNonce: request.mintRequestNonce,
3136
3225
  deadline: signatureDeadline,
3137
- mintFeeWrapperAddress: resolvedWrapper,
3138
- // Pass the bundler-estimated `feeAmount` explicitly so the
3139
- // RelayService skips its legacy `quoteOperatorFeePt` path
3140
- // (which uses the SDK's old 12_000 bps premium default).
3141
- // Without this, the response's `feeAmount` (from FeeManager,
3142
- // 100% premium on top of PAFI's 110% server-side estimate)
3143
- // would diverge from the actual PT.transfer amount in the
3144
- // UserOp batch (`quoteOperatorFeePt`'s 120%), and the user
3145
- // would see one value while the wallet transferred another.
3146
- feeAmount
3226
+ mintFeeWrapperAddress: resolvedWrapper
3147
3227
  });
3148
- } catch (err) {
3149
- throw new PTClaimError(
3150
- "BUILD_FAILED",
3151
- `prepareMint failed: ${err instanceof Error ? err.message : String(err)}`
3228
+ const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee({
3229
+ scenario: resolvedWrapper ? "mint-wrapped" : "mint",
3230
+ contractAddress: request.pointTokenAddress,
3231
+ partialUserOp: {
3232
+ sender: previewUserOp.sender,
3233
+ nonce: previewUserOp.nonce,
3234
+ callData: previewUserOp.callData
3235
+ }
3236
+ }) : 0n;
3237
+ const domainName = await this.cfg.domainResolver.resolve(
3238
+ request.pointTokenAddress
3152
3239
  );
3153
- }
3154
- let fallback;
3155
- if (feeAmount > 0n) {
3240
+ const domain = {
3241
+ name: domainName,
3242
+ chainId: request.chainId,
3243
+ verifyingContract: request.pointTokenAddress
3244
+ };
3245
+ let userOp;
3156
3246
  try {
3157
- fallback = await this.cfg.relayService.prepareMint({
3247
+ userOp = await this.cfg.relayService.prepareMint({
3158
3248
  userAddress: request.userAddress,
3159
3249
  aaNonce: request.aaNonce,
3160
3250
  batchExecutorAddress,
@@ -3162,34 +3252,68 @@ var PTClaimHandler = class {
3162
3252
  amount: request.amount,
3163
3253
  issuerSignerWallet: this.cfg.issuerSignerWallet,
3164
3254
  domain,
3165
- mintRequestNonce: request.mintRequestNonce,
3255
+ mintRequestNonce,
3166
3256
  deadline: signatureDeadline,
3167
- feeAmount: 0n,
3168
- mintFeeWrapperAddress: resolvedWrapper
3257
+ mintFeeWrapperAddress: resolvedWrapper,
3258
+ // Pass the bundler-estimated `feeAmount` explicitly so the
3259
+ // RelayService skips its legacy `quoteOperatorFeePt` path
3260
+ // (which uses the SDK's old 12_000 bps premium default).
3261
+ // Without this, the response's `feeAmount` (from FeeManager,
3262
+ // 100% premium on top of PAFI's 110% server-side estimate)
3263
+ // would diverge from the actual PT.transfer amount in the
3264
+ // UserOp batch (`quoteOperatorFeePt`'s 120%), and the user
3265
+ // would see one value while the wallet transferred another.
3266
+ feeAmount
3169
3267
  });
3170
3268
  } catch (err) {
3171
3269
  throw new PTClaimError(
3172
3270
  "BUILD_FAILED",
3173
- `prepareMint (fallback) failed: ${err instanceof Error ? err.message : String(err)}`
3271
+ `prepareMint failed: ${err instanceof Error ? err.message : String(err)}`
3174
3272
  );
3175
3273
  }
3274
+ let fallback;
3275
+ if (feeAmount > 0n) {
3276
+ try {
3277
+ fallback = await this.cfg.relayService.prepareMint({
3278
+ userAddress: request.userAddress,
3279
+ aaNonce: request.aaNonce,
3280
+ batchExecutorAddress,
3281
+ pointTokenAddress: request.pointTokenAddress,
3282
+ amount: request.amount,
3283
+ issuerSignerWallet: this.cfg.issuerSignerWallet,
3284
+ domain,
3285
+ mintRequestNonce,
3286
+ deadline: signatureDeadline,
3287
+ feeAmount: 0n,
3288
+ mintFeeWrapperAddress: resolvedWrapper
3289
+ });
3290
+ } catch (err) {
3291
+ throw new PTClaimError(
3292
+ "BUILD_FAILED",
3293
+ `prepareMint (fallback) failed: ${err instanceof Error ? err.message : String(err)}`
3294
+ );
3295
+ }
3296
+ }
3297
+ const calls = (0, import_core11.decodeBatchExecuteCalls)(userOp.callData);
3298
+ const callsFallback = fallback ? (0, import_core11.decodeBatchExecuteCalls)(fallback.callData) : void 0;
3299
+ return {
3300
+ userOp,
3301
+ fallback,
3302
+ lockId,
3303
+ feeAmount,
3304
+ signatureDeadline,
3305
+ expiresInSeconds: Math.floor(this.cfg.lockDurationMs / 1e3),
3306
+ calls,
3307
+ callsFallback
3308
+ };
3309
+ } catch (err) {
3310
+ await this.cfg.ledger.releaseLock(lockId).catch(() => {
3311
+ });
3312
+ throw err;
3176
3313
  }
3177
- const calls = (0, import_core11.decodeBatchExecuteCalls)(userOp.callData);
3178
- const callsFallback = fallback ? (0, import_core11.decodeBatchExecuteCalls)(fallback.callData) : void 0;
3179
- return {
3180
- userOp,
3181
- fallback,
3182
- lockId,
3183
- feeAmount,
3184
- signatureDeadline,
3185
- expiresInSeconds: Math.floor(this.cfg.lockDurationMs / 1e3),
3186
- calls,
3187
- callsFallback
3188
- };
3189
- } catch (err) {
3190
- await this.cfg.ledger.releaseLock(lockId).catch(() => {
3191
- });
3192
- throw err;
3314
+ } finally {
3315
+ userNonces.delete(mintRequestNonce);
3316
+ if (userNonces.size === 0) this.inFlightNonces.delete(nonceKey);
3193
3317
  }
3194
3318
  }
3195
3319
  };
@@ -3504,7 +3628,6 @@ var IssuerApiAdapter = class {
3504
3628
  }
3505
3629
  );
3506
3630
  return {
3507
- mintRequestNonce: result.mintRequestNonce.toString(),
3508
3631
  offChainBalance: result.offChainBalance.toString(),
3509
3632
  onChainBalance: result.onChainBalance.toString(),
3510
3633
  totalBalance: result.totalBalance.toString(),
@@ -3528,8 +3651,7 @@ var IssuerApiAdapter = class {
3528
3651
  amount: input.amount,
3529
3652
  pointTokenAddress,
3530
3653
  chainId: input.chainId,
3531
- aaNonce: input.aaNonce,
3532
- mintRequestNonce: input.mintRequestNonce
3654
+ aaNonce: input.aaNonce
3533
3655
  });
3534
3656
  const sponsorAuth = await this.buildSponsorAuth(
3535
3657
  input.authenticatedAddress,
@@ -3625,8 +3747,7 @@ var IssuerApiAdapter = class {
3625
3747
  amount: input.amount,
3626
3748
  pointTokenAddress,
3627
3749
  chainId: input.chainId,
3628
- aaNonce: input.aaNonce,
3629
- mintRequestNonce: input.mintRequestNonce
3750
+ aaNonce: input.aaNonce
3630
3751
  });
3631
3752
  const prepared = await this.runMobilePrepare(
3632
3753
  input.authenticatedAddress,
@@ -4990,22 +5111,22 @@ var IssuerStateValidator = class _IssuerStateValidator {
4990
5111
  }
4991
5112
  throw err;
4992
5113
  }
4993
- const { issuer, totalSupply, hardCap, remaining } = state;
5114
+ const { issuer, equityCap, equitySupply, remaining } = state;
4994
5115
  if (!issuer.active) {
4995
5116
  throw new IssuerStateError(
4996
5117
  "ISSUER_INACTIVE",
4997
- `Issuer ${issuer.issuerAddress} is deactivated on IssuerRegistry`,
4998
- { issuer: issuer.issuerAddress, pointToken: issuer.pointToken }
5118
+ `Issuer "${issuer.name}" is deactivated on IssuerRegistry`,
5119
+ { pointToken }
4999
5120
  );
5000
5121
  }
5001
- if (totalSupply + amount > hardCap) {
5122
+ if (equitySupply + amount > equityCap.hardCap) {
5002
5123
  throw new IssuerStateError(
5003
5124
  "MINT_CAP_EXCEEDED",
5004
- `Requested ${amount} PT would exceed mint cap. Cap=${hardCap}, minted=${totalSupply}, remaining=${remaining}`,
5125
+ `Requested ${amount} PT would exceed EQUITY mint cap. Cap=${equityCap.hardCap}, equityMinted=${equitySupply}, remaining=${remaining}`,
5005
5126
  {
5006
5127
  requested: amount.toString(),
5007
- cap: hardCap.toString(),
5008
- minted: totalSupply.toString(),
5128
+ cap: equityCap.hardCap.toString(),
5129
+ equityMinted: equitySupply.toString(),
5009
5130
  remaining: remaining.toString()
5010
5131
  }
5011
5132
  );
@@ -5021,33 +5142,28 @@ var IssuerStateValidator = class _IssuerStateValidator {
5021
5142
  args: [issuerAddr]
5022
5143
  });
5023
5144
  const issuer = {
5024
- issuerAddress: issuerStruct.issuerAddress,
5025
5145
  signerAddress: issuerStruct.signerAddress,
5026
5146
  name: issuerStruct.name,
5027
- symbol: issuerStruct.symbol,
5028
5147
  active: issuerStruct.active,
5029
- pointToken: issuerStruct.pointToken,
5030
- mintingOracle: issuerStruct.mintingOracle
5148
+ capitalBase: issuerStruct.capitalBase,
5149
+ basisPoints: Number(issuerStruct.basisPoints)
5031
5150
  };
5032
- const [tokenCap, totalSupply] = await Promise.all([
5033
- (0, import_core19.getTokenCap)(this.provider, issuer.mintingOracle, tokenAddr),
5034
- this.provider.readContract({
5035
- address: tokenAddr,
5036
- abi: import_core19.POINT_TOKEN_ABI,
5037
- functionName: "totalSupply"
5038
- })
5039
- ]);
5040
- const tokenCapRecord = {
5041
- declaredTotalSupply: tokenCap.declaredTotalSupply,
5042
- capBasisPoints: tokenCap.capBasisPoints
5151
+ const equitySupply = await this.provider.readContract({
5152
+ address: tokenAddr,
5153
+ abi: import_core19.POINT_TOKEN_ABI,
5154
+ functionName: "equitySupply"
5155
+ });
5156
+ const hardCap = issuer.capitalBase * BigInt(issuer.basisPoints) / 10000n;
5157
+ const equityCap = {
5158
+ capitalBase: issuer.capitalBase,
5159
+ basisPoints: issuer.basisPoints,
5160
+ hardCap
5043
5161
  };
5044
- const hardCap = tokenCapRecord.declaredTotalSupply * BigInt(tokenCapRecord.capBasisPoints) / 10000n;
5045
- const remaining = hardCap > totalSupply ? hardCap - totalSupply : 0n;
5162
+ const remaining = hardCap > equitySupply ? hardCap - equitySupply : 0n;
5046
5163
  return {
5047
5164
  issuer,
5048
- tokenCap: tokenCapRecord,
5049
- totalSupply,
5050
- hardCap,
5165
+ equityCap,
5166
+ equitySupply,
5051
5167
  remaining
5052
5168
  };
5053
5169
  }
@@ -5090,7 +5206,7 @@ var MemoryRedemptionHistoryStore = class {
5090
5206
  };
5091
5207
 
5092
5208
  // src/index.ts
5093
- var PAFI_ISSUER_SDK_VERSION = true ? "0.23.0" : "dev";
5209
+ var PAFI_ISSUER_SDK_VERSION = true ? "0.25.0" : "dev";
5094
5210
  // Annotate the CommonJS export names for ESM import in node:
5095
5211
  0 && (module.exports = {
5096
5212
  AdapterMisconfiguredError,
@@ -5099,6 +5215,7 @@ var PAFI_ISSUER_SDK_VERSION = true ? "0.23.0" : "dev";
5099
5215
  BundlerNotConfiguredError,
5100
5216
  BundlerRejectedError,
5101
5217
  BurnIndexer,
5218
+ BurnIndexerFinalizeError,
5102
5219
  ConfigurationError,
5103
5220
  DEFAULT_REDEMPTION_POLICY,
5104
5221
  DefaultPolicyEngine,
@@ -5130,6 +5247,7 @@ var PAFI_ISSUER_SDK_VERSION = true ? "0.23.0" : "dev";
5130
5247
  PerpDepositError,
5131
5248
  PerpDepositHandler,
5132
5249
  PointIndexer,
5250
+ PointIndexerFinalizeError,
5133
5251
  PointTokenDomainResolver,
5134
5252
  PolicyProvider,
5135
5253
  REDEMPTION_HISTORY_WINDOW_SEC,