@pafi-dev/issuer 0.5.38 → 0.5.39

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
@@ -43,6 +43,8 @@ __export(index_exports, {
43
43
  PTRedeemHandler: () => PTRedeemHandler,
44
44
  PafiBackendClient: () => PafiBackendClient,
45
45
  PafiBackendError: () => PafiBackendError,
46
+ PafiSdkError: () => PafiSdkError,
47
+ PendingUserOpForbiddenError: () => PendingUserOpForbiddenError,
46
48
  PendingUserOpNotFoundError: () => PendingUserOpNotFoundError,
47
49
  PerpDepositError: () => PerpDepositError,
48
50
  PerpDepositHandler: () => PerpDepositHandler,
@@ -74,6 +76,22 @@ __export(index_exports, {
74
76
  });
75
77
  module.exports = __toCommonJS(index_exports);
76
78
 
79
+ // src/errors.ts
80
+ var PafiSdkError = class extends Error {
81
+ /**
82
+ * `true` when the FE should consider a retry safe — typically because
83
+ * the failure is transient (`MINT_CAP_EXCEEDED` may free up,
84
+ * `RELAY_FEE_EXCEEDS_AMOUNT` may drop on next quote). Defaults to
85
+ * `false` — subclasses opt in per-code.
86
+ */
87
+ safeToRetry = false;
88
+ details;
89
+ constructor(message) {
90
+ super(message);
91
+ this.name = new.target.name;
92
+ }
93
+ };
94
+
77
95
  // src/policy/defaultPolicy.ts
78
96
  var DefaultPolicyEngine = class {
79
97
  ledger;
@@ -1375,18 +1393,19 @@ var import_viem7 = require("viem");
1375
1393
  var import_core4 = require("@pafi-dev/core");
1376
1394
  var DEFAULT_REDEEM_LOCK_MS = 15 * 60 * 1e3;
1377
1395
  var DEFAULT_SIG_DEADLINE_SEC = 15 * 60;
1378
- var PTRedeemError = class extends Error {
1396
+ var PTRedeemError = class extends PafiSdkError {
1397
+ httpStatus = "unprocessable";
1398
+ code;
1379
1399
  constructor(code, message) {
1380
1400
  super(message);
1381
1401
  this.code = code;
1382
- this.name = "PTRedeemError";
1383
1402
  }
1384
- code;
1385
1403
  };
1386
1404
  var PTRedeemHandler = class {
1387
1405
  ledger;
1388
1406
  relayService;
1389
1407
  provider;
1408
+ feeService;
1390
1409
  pointTokenAddress;
1391
1410
  batchExecutorAddress;
1392
1411
  chainId;
@@ -1425,6 +1444,7 @@ var PTRedeemHandler = class {
1425
1444
  this.ledger = config.ledger;
1426
1445
  this.relayService = config.relayService;
1427
1446
  this.provider = config.provider;
1447
+ this.feeService = config.feeService;
1428
1448
  this.pointTokenAddress = (0, import_viem7.getAddress)(config.pointTokenAddress);
1429
1449
  this.batchExecutorAddress = (0, import_viem7.getAddress)(config.batchExecutorAddress);
1430
1450
  this.chainId = config.chainId;
@@ -1482,7 +1502,15 @@ var PTRedeemHandler = class {
1482
1502
  }
1483
1503
  }
1484
1504
  async _handleAfterNonceLock(request, burnNonce) {
1485
- const fee = request.feeAmount && request.feeAmount > 0n ? request.feeAmount : 0n;
1505
+ let fee;
1506
+ if (request.feeAmount !== void 0) {
1507
+ fee = request.feeAmount > 0n ? request.feeAmount : 0n;
1508
+ } else if (this.feeService) {
1509
+ fee = await this.feeService.estimateGasFee();
1510
+ } else {
1511
+ fee = 0n;
1512
+ }
1513
+ const feeRecipient = request.feeRecipient ?? (request.chainId !== void 0 ? (0, import_core4.getContractAddresses)(request.chainId).pafiFeeRecipient : (0, import_core4.getContractAddresses)(this.chainId).pafiFeeRecipient);
1486
1514
  if (fee > 0n && fee >= request.amount) {
1487
1515
  throw new PTRedeemError(
1488
1516
  "INVALID_AMOUNT",
@@ -1539,7 +1567,7 @@ var PTRedeemHandler = class {
1539
1567
  burnRequest: sponsoredBurnRequest,
1540
1568
  burnerSignature: sponsoredSig,
1541
1569
  feeAmount: fee,
1542
- feeRecipient: request.feeRecipient
1570
+ feeRecipient
1543
1571
  });
1544
1572
  let fallback = void 0;
1545
1573
  if (fee > 0n) {
@@ -1588,6 +1616,7 @@ var PTRedeemHandler = class {
1588
1616
  lockId: sponsoredLockId,
1589
1617
  userOp: sponsoredUserOp,
1590
1618
  netCreditAmount: sponsoredBurnAmount,
1619
+ feeAmount: fee,
1591
1620
  fallback,
1592
1621
  expiresInSeconds: Math.floor(this.redeemLockDurationMs / 1e3),
1593
1622
  signatureDeadline: deadline
@@ -1660,11 +1689,11 @@ var TopUpRedemptionHandler = class {
1660
1689
  };
1661
1690
 
1662
1691
  // src/api/statusHandlers.ts
1663
- var LockNotFoundError = class extends Error {
1692
+ var LockNotFoundError = class extends PafiSdkError {
1664
1693
  code = "LOCK_NOT_FOUND";
1694
+ httpStatus = "not_found";
1665
1695
  constructor() {
1666
1696
  super("Lock not found or does not belong to authenticated user");
1667
- this.name = "LockNotFoundError";
1668
1697
  }
1669
1698
  };
1670
1699
  async function handleClaimStatus(params) {
@@ -1760,6 +1789,7 @@ async function handleRedeemStatus(params) {
1760
1789
  }
1761
1790
 
1762
1791
  // src/api/mobileHandlers.ts
1792
+ var import_viem9 = require("viem");
1763
1793
  var import_core8 = require("@pafi-dev/core");
1764
1794
 
1765
1795
  // src/userop-store/serialize.ts
@@ -1896,21 +1926,21 @@ async function prepareMobileUserOp(params) {
1896
1926
  }
1897
1927
 
1898
1928
  // src/pafi-backend/helpers.ts
1899
- var BundlerNotConfiguredError = class extends Error {
1929
+ var BundlerNotConfiguredError = class extends PafiSdkError {
1900
1930
  code = "BUNDLER_NOT_CONFIGURED";
1931
+ httpStatus = "service_unavailable";
1901
1932
  constructor() {
1902
1933
  super(
1903
1934
  "PAFI backend client not configured \u2014 set PAFI_BACKEND_URL, PAFI_ISSUER_ID, PAFI_API_KEY to enable mobile submit."
1904
1935
  );
1905
- this.name = "BundlerNotConfiguredError";
1906
1936
  }
1907
1937
  };
1908
- var BundlerRejectedError = class extends Error {
1938
+ var BundlerRejectedError = class extends PafiSdkError {
1909
1939
  code = "BUNDLER_REJECTED";
1940
+ httpStatus = "unprocessable";
1910
1941
  cause;
1911
1942
  constructor(message, cause) {
1912
1943
  super(message);
1913
- this.name = "BundlerRejectedError";
1914
1944
  this.cause = cause;
1915
1945
  }
1916
1946
  };
@@ -1966,13 +1996,22 @@ async function relayUserOp(params) {
1966
1996
  }
1967
1997
 
1968
1998
  // src/api/mobileHandlers.ts
1969
- var PendingUserOpNotFoundError = class extends Error {
1999
+ var PendingUserOpNotFoundError = class extends PafiSdkError {
1970
2000
  code = "PENDING_USEROP_NOT_FOUND";
2001
+ httpStatus = "not_found";
1971
2002
  constructor(lockId) {
1972
2003
  super(
1973
2004
  `No pending UserOp found for lockId ${lockId} \u2014 it may have expired or already been submitted.`
1974
2005
  );
1975
- this.name = "PendingUserOpNotFoundError";
2006
+ }
2007
+ };
2008
+ var PendingUserOpForbiddenError = class extends PafiSdkError {
2009
+ code = "PENDING_USEROP_FORBIDDEN";
2010
+ httpStatus = "forbidden";
2011
+ constructor(lockId) {
2012
+ super(
2013
+ `Pending UserOp ${lockId} does not belong to the authenticated user.`
2014
+ );
1976
2015
  }
1977
2016
  };
1978
2017
  async function handleMobilePrepare(params) {
@@ -2014,6 +2053,9 @@ async function handleMobileSubmit(params) {
2014
2053
  if (!entry) {
2015
2054
  throw new PendingUserOpNotFoundError(params.lockId);
2016
2055
  }
2056
+ if ((0, import_viem9.getAddress)(entry.sender) !== (0, import_viem9.getAddress)(params.authenticatedAddress)) {
2057
+ throw new PendingUserOpForbiddenError(params.lockId);
2058
+ }
2017
2059
  const variant = params.variant ?? "sponsored";
2018
2060
  const userOpJson = serializeEntryToJsonRpc(entry, params.signature, variant);
2019
2061
  const result = await relayUserOp({
@@ -2027,31 +2069,33 @@ async function handleMobileSubmit(params) {
2027
2069
  }
2028
2070
 
2029
2071
  // src/api/handlers/ptClaimHandler.ts
2030
- var import_viem9 = require("viem");
2072
+ var import_viem10 = require("viem");
2031
2073
  var import_core9 = require("@pafi-dev/core");
2032
2074
 
2033
2075
  // src/issuer-state/types.ts
2034
- var IssuerStateError = class extends Error {
2076
+ var IssuerStateError = class extends PafiSdkError {
2077
+ httpStatus = "unprocessable";
2078
+ code;
2079
+ details;
2080
+ safeToRetry;
2035
2081
  constructor(code, message, details) {
2036
2082
  super(message);
2037
2083
  this.code = code;
2038
2084
  this.details = details;
2039
- this.name = "IssuerStateError";
2085
+ this.safeToRetry = code === "MINT_CAP_EXCEEDED";
2040
2086
  }
2041
- code;
2042
- details;
2043
2087
  };
2044
2088
 
2045
2089
  // src/api/handlers/ptClaimHandler.ts
2046
- var PTClaimError = class extends Error {
2090
+ var PTClaimError = class extends PafiSdkError {
2091
+ httpStatus = "unprocessable";
2092
+ code;
2093
+ details;
2047
2094
  constructor(code, message, details) {
2048
2095
  super(message);
2049
2096
  this.code = code;
2050
2097
  this.details = details;
2051
- this.name = "PTClaimError";
2052
2098
  }
2053
- code;
2054
- details;
2055
2099
  };
2056
2100
  var DEFAULT_LOCK_MS = 15 * 60 * 1e3;
2057
2101
  var DEFAULT_SIG_DEADLINE_SEC2 = 15 * 60;
@@ -2066,7 +2110,7 @@ var PTClaimHandler = class {
2066
2110
  };
2067
2111
  }
2068
2112
  async handle(request) {
2069
- if ((0, import_viem9.getAddress)(request.authenticatedAddress) !== (0, import_viem9.getAddress)(request.userAddress)) {
2113
+ if ((0, import_viem10.getAddress)(request.authenticatedAddress) !== (0, import_viem10.getAddress)(request.userAddress)) {
2070
2114
  throw new PTClaimError(
2071
2115
  "VALIDATION_FAILED",
2072
2116
  `userAddress (${request.userAddress}) does not match authenticated session (${request.authenticatedAddress})`
@@ -2166,13 +2210,13 @@ var PTClaimHandler = class {
2166
2210
 
2167
2211
  // src/api/handlers/swapHandler.ts
2168
2212
  var import_core10 = require("@pafi-dev/core");
2169
- var SwapError = class extends Error {
2213
+ var SwapError = class extends PafiSdkError {
2214
+ httpStatus = "unprocessable";
2215
+ code;
2170
2216
  constructor(code, message) {
2171
2217
  super(message);
2172
2218
  this.code = code;
2173
- this.name = "SwapError";
2174
2219
  }
2175
- code;
2176
2220
  };
2177
2221
  var DEFAULT_SLIPPAGE_BPS = 50;
2178
2222
  var DEFAULT_SWAP_DEADLINE_SEC = 5 * 60;
@@ -2298,13 +2342,15 @@ var SwapHandler = class {
2298
2342
 
2299
2343
  // src/api/handlers/perpDepositHandler.ts
2300
2344
  var import_core11 = require("@pafi-dev/core");
2301
- var PerpDepositError = class extends Error {
2345
+ var PerpDepositError = class extends PafiSdkError {
2346
+ httpStatus = "unprocessable";
2347
+ code;
2348
+ safeToRetry;
2302
2349
  constructor(code, message) {
2303
2350
  super(message);
2304
2351
  this.code = code;
2305
- this.name = "PerpDepositError";
2352
+ this.safeToRetry = code === "RELAY_FEE_EXCEEDS_AMOUNT";
2306
2353
  }
2307
- code;
2308
2354
  };
2309
2355
  var DEFAULT_MAX_FEE_PREMIUM_BPS = 5e3;
2310
2356
  var PerpDepositHandler = class {
@@ -2550,49 +2596,30 @@ async function quotePointTokenToUsdt(params) {
2550
2596
  // src/api/errorMapper.ts
2551
2597
  function createSdkErrorMapper(factories) {
2552
2598
  return (err) => {
2553
- if (err instanceof PendingUserOpNotFoundError) {
2554
- throw factories.notFound({
2555
- code: err.code,
2556
- message: err.message,
2557
- safeToRetry: false
2558
- });
2559
- }
2560
- if (err instanceof BundlerNotConfiguredError) {
2561
- throw factories.serviceUnavailable({
2562
- code: err.code,
2563
- message: err.message,
2564
- safeToRetry: false
2565
- });
2566
- }
2567
- if (err instanceof IssuerStateError) {
2568
- throw factories.unprocessable({
2569
- code: err.code,
2570
- message: err.message,
2571
- details: err.details,
2572
- safeToRetry: err.code === "MINT_CAP_EXCEEDED"
2573
- });
2574
- }
2575
- if (err instanceof PerpDepositError) {
2576
- throw factories.unprocessable({
2577
- code: err.code,
2578
- message: err.message,
2579
- safeToRetry: err.code === "RELAY_FEE_EXCEEDS_AMOUNT"
2580
- });
2599
+ if (!(err instanceof PafiSdkError)) {
2600
+ throw err;
2581
2601
  }
2582
- if (err instanceof PTClaimError || err instanceof PTRedeemError || err instanceof SwapError || err instanceof BundlerRejectedError) {
2583
- throw factories.unprocessable({
2584
- code: err.code,
2585
- message: err.message,
2586
- details: "details" in err ? err.details : void 0,
2587
- safeToRetry: false
2588
- });
2602
+ const body = {
2603
+ code: err.code,
2604
+ message: err.message,
2605
+ details: err.details,
2606
+ safeToRetry: err.safeToRetry
2607
+ };
2608
+ switch (err.httpStatus) {
2609
+ case "not_found":
2610
+ throw factories.notFound(body);
2611
+ case "forbidden":
2612
+ throw factories.forbidden(body);
2613
+ case "unprocessable":
2614
+ throw factories.unprocessable(body);
2615
+ case "service_unavailable":
2616
+ throw factories.serviceUnavailable(body);
2589
2617
  }
2590
- throw err;
2591
2618
  };
2592
2619
  }
2593
2620
 
2594
2621
  // src/pools/subgraphPoolsProvider.ts
2595
- var import_viem10 = require("viem");
2622
+ var import_viem11 = require("viem");
2596
2623
  var import_core14 = require("@pafi-dev/core");
2597
2624
  var DEFAULT_CACHE_TTL_MS = 3e4;
2598
2625
  var POOL_QUERY = `
@@ -2693,7 +2720,7 @@ async function fetchPoolsFromSubgraph(fetchImpl, subgraphUrl, pointTokenAddress)
2693
2720
  return [];
2694
2721
  }
2695
2722
  const { pool } = token;
2696
- if (!(0, import_viem10.isAddress)(pool.hooks)) {
2723
+ if (!(0, import_viem11.isAddress)(pool.hooks)) {
2697
2724
  console.error(
2698
2725
  "[PAFI] SubgraphPoolsProvider: invalid hooks address in response:",
2699
2726
  pool.hooks,
@@ -2701,7 +2728,7 @@ async function fetchPoolsFromSubgraph(fetchImpl, subgraphUrl, pointTokenAddress)
2701
2728
  );
2702
2729
  return [];
2703
2730
  }
2704
- if (!(0, import_viem10.isAddress)(pool.token0.id) || !(0, import_viem10.isAddress)(pool.token1.id)) {
2731
+ if (!(0, import_viem11.isAddress)(pool.token0.id) || !(0, import_viem11.isAddress)(pool.token1.id)) {
2705
2732
  console.error(
2706
2733
  "[PAFI] SubgraphPoolsProvider: invalid token address in response \u2014 skipping pool"
2707
2734
  );
@@ -2851,8 +2878,8 @@ function toUsdtPerNative(priceFloat, usdtDecimals) {
2851
2878
  }
2852
2879
 
2853
2880
  // src/pools/nativePtQuoter.ts
2854
- var import_viem11 = require("viem");
2855
- var CHAINLINK_ABI = (0, import_viem11.parseAbi)([
2881
+ var import_viem12 = require("viem");
2882
+ var CHAINLINK_ABI = (0, import_viem12.parseAbi)([
2856
2883
  "function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)"
2857
2884
  ]);
2858
2885
  var CHAINLINK_MAX_AGE_S = 3600n;
@@ -3209,7 +3236,7 @@ var PafiBackendClient = class {
3209
3236
  };
3210
3237
 
3211
3238
  // src/config.ts
3212
- var import_viem12 = require("viem");
3239
+ var import_viem13 = require("viem");
3213
3240
  var import_core16 = require("@pafi-dev/core");
3214
3241
  function createIssuerService(config) {
3215
3242
  if (!config.provider) {
@@ -3230,7 +3257,7 @@ function createIssuerService(config) {
3230
3257
  "createIssuerService: at least one of pointTokenAddress / pointTokenAddresses is required"
3231
3258
  );
3232
3259
  }
3233
- const tokenAddresses = rawAddresses.map((a) => (0, import_viem12.getAddress)(a));
3260
+ const tokenAddresses = rawAddresses.map((a) => (0, import_viem13.getAddress)(a));
3234
3261
  const ledger = config.ledger;
3235
3262
  const sessionStore = config.sessionStore ?? new MemorySessionStore();
3236
3263
  const policy = config.policy ?? new DefaultPolicyEngine({ ledger });
@@ -3328,7 +3355,7 @@ function createIssuerService(config) {
3328
3355
  }
3329
3356
 
3330
3357
  // src/issuer-state/validator.ts
3331
- var import_viem13 = require("viem");
3358
+ var import_viem14 = require("viem");
3332
3359
  var import_core17 = require("@pafi-dev/core");
3333
3360
  var ISSUER_RECORD_TTL_MS = 3e4;
3334
3361
  var IssuerStateValidator = class _IssuerStateValidator {
@@ -3355,7 +3382,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
3355
3382
  */
3356
3383
  invalidate(pointToken) {
3357
3384
  if (pointToken) {
3358
- const key = (0, import_viem13.getAddress)(pointToken);
3385
+ const key = (0, import_viem14.getAddress)(pointToken);
3359
3386
  this.pointTokenIssuerCache.delete(key);
3360
3387
  this.stateCache.delete(key);
3361
3388
  this.inflight.delete(key);
@@ -3370,7 +3397,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
3370
3397
  * The issuer field is set at `initialize()` and never changes.
3371
3398
  */
3372
3399
  async getIssuerAddressForPointToken(pointToken) {
3373
- const key = (0, import_viem13.getAddress)(pointToken);
3400
+ const key = (0, import_viem14.getAddress)(pointToken);
3374
3401
  const cached = this.pointTokenIssuerCache.get(key);
3375
3402
  if (cached) return cached;
3376
3403
  const issuer = await this.provider.readContract({
@@ -3378,15 +3405,15 @@ var IssuerStateValidator = class _IssuerStateValidator {
3378
3405
  abi: import_core17.POINT_TOKEN_V2_ABI,
3379
3406
  functionName: "issuer"
3380
3407
  });
3381
- this.pointTokenIssuerCache.set(key, (0, import_viem13.getAddress)(issuer));
3382
- return (0, import_viem13.getAddress)(issuer);
3408
+ this.pointTokenIssuerCache.set(key, (0, import_viem14.getAddress)(issuer));
3409
+ return (0, import_viem14.getAddress)(issuer);
3383
3410
  }
3384
3411
  /**
3385
3412
  * Read registry record + totalSupply, with 30s cache and in-flight
3386
3413
  * deduplication. Does NOT throw on inactive/missing — returns raw state.
3387
3414
  */
3388
3415
  async getIssuerState(pointToken) {
3389
- const tokenAddr = (0, import_viem13.getAddress)(pointToken);
3416
+ const tokenAddr = (0, import_viem14.getAddress)(pointToken);
3390
3417
  const now = Date.now();
3391
3418
  const cached = this.stateCache.get(tokenAddr);
3392
3419
  if (cached && cached.expiresAt > now) return cached.value;
@@ -3510,6 +3537,8 @@ var PAFI_ISSUER_SDK_VERSION = "0.4.0";
3510
3537
  PTRedeemHandler,
3511
3538
  PafiBackendClient,
3512
3539
  PafiBackendError,
3540
+ PafiSdkError,
3541
+ PendingUserOpForbiddenError,
3513
3542
  PendingUserOpNotFoundError,
3514
3543
  PerpDepositError,
3515
3544
  PerpDepositHandler,