@pafi-dev/issuer 0.29.0 → 0.31.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
@@ -2332,6 +2332,7 @@ var PTRedeemHandler = class {
2332
2332
  chainId;
2333
2333
  domainResolver;
2334
2334
  burnerSignerWallet;
2335
+ supportedTokens;
2335
2336
  redeemLockDurationMs;
2336
2337
  signatureDeadlineSeconds;
2337
2338
  now;
@@ -2371,6 +2372,13 @@ var PTRedeemHandler = class {
2371
2372
  this.chainId = config.chainId;
2372
2373
  this.domainResolver = config.domainResolver;
2373
2374
  this.burnerSignerWallet = config.burnerSignerWallet;
2375
+ if (!config.supportedTokens) {
2376
+ throw new PTRedeemError(
2377
+ "UNSUPPORTED_POINT_TOKEN",
2378
+ "PTRedeemHandler requires `supportedTokens` (issuer's allow-listed PointToken contracts). See audit PACI5-18."
2379
+ );
2380
+ }
2381
+ this.supportedTokens = config.supportedTokens;
2374
2382
  if (this.burnerSignerWallet?.account?.type === "local") {
2375
2383
  console.warn("[PAFI] PTRedeemHandler: burnerSignerWallet uses a local (private key) account. Use a KMS-backed signer in production.");
2376
2384
  }
@@ -2399,6 +2407,12 @@ var PTRedeemHandler = class {
2399
2407
  throw new PTRedeemError("INVALID_AMOUNT", "redeem amount must be positive");
2400
2408
  }
2401
2409
  const pointTokenAddress = (0, import_viem8.getAddress)(request.pointTokenAddress);
2410
+ if (!this.supportedTokens.has(pointTokenAddress)) {
2411
+ throw new PTRedeemError(
2412
+ "UNSUPPORTED_POINT_TOKEN",
2413
+ `redeem: pointTokenAddress ${pointTokenAddress} is not in the issuer's supported-token allowlist. Check IssuerApiHandlers.supportedTokens and PTRedeemHandler.config.supportedTokens point at the same set.`
2414
+ );
2415
+ }
2402
2416
  if (this.redemptionService) {
2403
2417
  const decision = await this.redemptionService.evaluate(
2404
2418
  request.userAddress,
@@ -2889,7 +2903,10 @@ async function prepareMobileUserOp(params) {
2889
2903
  callGasLimit: fallback.userOp.callGasLimit.toString(),
2890
2904
  verificationGasLimit: fallback.userOp.verificationGasLimit.toString(),
2891
2905
  preVerificationGas: fallback.userOp.preVerificationGas.toString(),
2892
- userOpHash: fallback.userOpHash
2906
+ userOpHash: fallback.userOpHash,
2907
+ // Audit PACI5-21 — carry the fallback-specific lockId so submit
2908
+ // can bind the fallback userOpHash to the correct ledger row.
2909
+ lockId: params.lockIdFallback
2893
2910
  };
2894
2911
  }
2895
2912
  const entry = {
@@ -3082,6 +3099,7 @@ async function handleMobilePrepare(params) {
3082
3099
  lockId: params.lockId,
3083
3100
  partialUserOp: sponsoredOp,
3084
3101
  partialUserOpFallback: params.partialUserOpFallback,
3102
+ lockIdFallback: params.lockIdFallback,
3085
3103
  paymasterFields,
3086
3104
  chainId: params.chainId,
3087
3105
  store: params.store,
@@ -3110,7 +3128,8 @@ async function handleMobileSubmit(params) {
3110
3128
  entryPoint: params.entryPoint ?? import_core10.ENTRY_POINT_V08,
3111
3129
  eip7702Auth: entry.eip7702Auth
3112
3130
  });
3113
- await params.bindUserOpHash(params.lockId, result.userOpHash);
3131
+ const targetLockId = variant === "fallback" && entry.fallback?.lockId ? entry.fallback.lockId : params.lockId;
3132
+ await params.bindUserOpHash(targetLockId, result.userOpHash);
3114
3133
  await params.store.delete(params.lockId);
3115
3134
  return { userOpHash: result.userOpHash };
3116
3135
  }
@@ -3156,6 +3175,12 @@ var PTClaimHandler = class {
3156
3175
  cfg;
3157
3176
  inFlightNonces = /* @__PURE__ */ new Map();
3158
3177
  constructor(config) {
3178
+ if (!config.supportedTokens) {
3179
+ throw new PTClaimError(
3180
+ "UNSUPPORTED_POINT_TOKEN",
3181
+ "PTClaimHandler requires `supportedTokens` (issuer's allow-listed PointToken contracts). See audit PACI5-18."
3182
+ );
3183
+ }
3159
3184
  const lockDurationMs = config.lockDurationMs ?? DEFAULT_LOCK_MS;
3160
3185
  const signatureDeadlineSeconds = config.signatureDeadlineSeconds ?? DEFAULT_SIG_DEADLINE_SEC2;
3161
3186
  const maxAllowedSignatureMs = lockDurationMs - M11_SAFETY_MARGIN_MS2;
@@ -3187,6 +3212,14 @@ var PTClaimHandler = class {
3187
3212
  if (request.amount <= 0n) {
3188
3213
  throw new PTClaimError("INVALID_AMOUNT", "claim amount must be positive");
3189
3214
  }
3215
+ const pointTokenAddress = (0, import_viem10.getAddress)(request.pointTokenAddress);
3216
+ if (!this.cfg.supportedTokens.has(pointTokenAddress)) {
3217
+ throw new PTClaimError(
3218
+ "UNSUPPORTED_POINT_TOKEN",
3219
+ `claim: pointTokenAddress ${pointTokenAddress} is not in the issuer's supported-token allowlist. Check IssuerApiHandlers.supportedTokens and PTClaimHandler.config.supportedTokens point at the same set.`,
3220
+ { requested: pointTokenAddress }
3221
+ );
3222
+ }
3190
3223
  if (this.cfg.issuerStateValidator) {
3191
3224
  try {
3192
3225
  await this.cfg.issuerStateValidator.preValidateMint(
@@ -3838,10 +3871,16 @@ var IssuerApiAdapter = class {
3838
3871
  "burn",
3839
3872
  pointTokenAddress,
3840
3873
  redeemResponse.expiresInSeconds,
3841
- input.eip7702Auth
3874
+ input.eip7702Auth,
3875
+ // Audit PACI5-21 — fallback path reserves a separate
3876
+ // PendingCredit row for the full `amount`. Surface its lockId so
3877
+ // mobile FE can poll the correct row + `handleMobileSubmit`
3878
+ // routes the userOpHash bind to it on fallback submit.
3879
+ redeemResponse.fallback?.lockId
3842
3880
  );
3843
3881
  return {
3844
3882
  lockId: redeemResponse.lockId,
3883
+ lockIdFallback: redeemResponse.fallback?.lockId,
3845
3884
  userOpHash: prepared.sponsored.userOpHash,
3846
3885
  typedData: prepared.sponsored.typedData,
3847
3886
  userOpHashFallback: prepared.fallback?.userOpHash,
@@ -3972,13 +4011,14 @@ var IssuerApiAdapter = class {
3972
4011
  issuerSignerWallet: this.cfg.issuerSignerWallet
3973
4012
  });
3974
4013
  }
3975
- async runMobilePrepare(authenticatedAddress, chainId, lockId, partialUserOp, partialUserOpFallback, scenario, pointTokenAddress, ttlSeconds, eip7702Auth) {
4014
+ async runMobilePrepare(authenticatedAddress, chainId, lockId, partialUserOp, partialUserOpFallback, scenario, pointTokenAddress, ttlSeconds, eip7702Auth, lockIdFallback) {
3976
4015
  return await handleMobilePrepare({
3977
4016
  userAddress: authenticatedAddress,
3978
4017
  chainId,
3979
4018
  lockId,
3980
4019
  partialUserOp,
3981
4020
  partialUserOpFallback,
4021
+ lockIdFallback,
3982
4022
  scenario,
3983
4023
  pointTokenAddress,
3984
4024
  ttlSeconds,
@@ -5243,7 +5283,7 @@ var MemoryRedemptionHistoryStore = class {
5243
5283
  };
5244
5284
 
5245
5285
  // src/index.ts
5246
- var PAFI_ISSUER_SDK_VERSION = true ? "0.28.1" : "dev";
5286
+ var PAFI_ISSUER_SDK_VERSION = true ? "0.31.0" : "dev";
5247
5287
  // Annotate the CommonJS export names for ESM import in node:
5248
5288
  0 && (module.exports = {
5249
5289
  AdapterMisconfiguredError,