@pafi-dev/issuer 0.6.1 → 0.7.1

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.js CHANGED
@@ -13,6 +13,26 @@ var PafiSdkError = class extends Error {
13
13
  this.name = new.target.name;
14
14
  }
15
15
  };
16
+ var ValidationError = class extends PafiSdkError {
17
+ httpStatus = "unprocessable";
18
+ code;
19
+ details;
20
+ constructor(code, message, details) {
21
+ super(message);
22
+ this.code = code;
23
+ this.details = details;
24
+ }
25
+ };
26
+ var ConfigurationError = class extends PafiSdkError {
27
+ httpStatus = "service_unavailable";
28
+ code;
29
+ details;
30
+ constructor(code, message, details) {
31
+ super(message);
32
+ this.code = code;
33
+ this.details = details;
34
+ }
35
+ };
16
36
 
17
37
  // src/policy/defaultPolicy.ts
18
38
  var DefaultPolicyEngine = class {
@@ -183,12 +203,32 @@ import { getAddress as getAddress2 } from "viem";
183
203
  import { parseLoginMessage, verifyLoginMessage } from "@pafi-dev/core";
184
204
 
185
205
  // src/auth/errors.ts
186
- var AuthError = class extends Error {
206
+ function statusForCode(code) {
207
+ switch (code) {
208
+ case "INVALID_MESSAGE":
209
+ case "DOMAIN_MISMATCH":
210
+ case "CHAIN_MISMATCH":
211
+ case "MESSAGE_EXPIRED":
212
+ case "MESSAGE_NOT_YET_VALID":
213
+ case "MALFORMED_TOKEN":
214
+ return "unprocessable";
215
+ case "NONCE_INVALID":
216
+ case "SIGNATURE_INVALID":
217
+ case "MISSING_TOKEN":
218
+ case "TOKEN_INVALID":
219
+ case "TOKEN_EXPIRED":
220
+ return "forbidden";
221
+ case "SESSION_REVOKED":
222
+ return "not_found";
223
+ }
224
+ }
225
+ var AuthError = class extends PafiSdkError {
187
226
  code;
227
+ httpStatus;
188
228
  constructor(code, message) {
189
229
  super(message);
190
- this.name = "AuthError";
191
230
  this.code = code;
231
+ this.httpStatus = statusForCode(code);
192
232
  }
193
233
  };
194
234
 
@@ -385,14 +425,15 @@ async function authenticateRequest(authHeader, authService) {
385
425
  }
386
426
 
387
427
  // src/relay/types.ts
388
- var RelayError = class extends Error {
428
+ var RelayError = class extends PafiSdkError {
429
+ httpStatus = "unprocessable";
389
430
  code;
390
- cause;
391
431
  constructor(code, message, cause) {
392
432
  super(message);
393
- this.name = "RelayError";
394
433
  this.code = code;
395
- if (cause !== void 0) this.cause = cause;
434
+ if (cause !== void 0) {
435
+ this.cause = cause;
436
+ }
396
437
  }
397
438
  };
398
439
 
@@ -1107,13 +1148,16 @@ var IssuerApiHandlers = class {
1107
1148
  /** `POST /auth/login` */
1108
1149
  async handleLogin(body) {
1109
1150
  if (!body || typeof body.message !== "string" || body.message.length === 0 || typeof body.signature !== "string" || body.signature.length <= 2) {
1110
- throw new Error("handleLogin: message and signature are required");
1151
+ throw new ValidationError(
1152
+ "INVALID_LOGIN_BODY",
1153
+ "handleLogin: message and signature are required"
1154
+ );
1111
1155
  }
1112
1156
  if (body.message.length > 4096) {
1113
- throw new Error("message too long");
1157
+ throw new ValidationError("MESSAGE_TOO_LONG", "message too long");
1114
1158
  }
1115
1159
  if (body.signature.length > 260) {
1116
- throw new Error("signature too long");
1160
+ throw new ValidationError("SIGNATURE_TOO_LONG", "signature too long");
1117
1161
  }
1118
1162
  const result = await this.authService.login(body.message, body.signature);
1119
1163
  return {
@@ -1130,11 +1174,15 @@ var IssuerApiHandlers = class {
1130
1174
  */
1131
1175
  async handleConfig(chainId) {
1132
1176
  if (!Number.isInteger(chainId) || chainId <= 0) {
1133
- throw new Error("invalid chainId");
1177
+ throw new ValidationError("INVALID_CHAIN_ID", "invalid chainId", {
1178
+ chainId
1179
+ });
1134
1180
  }
1135
1181
  if (chainId !== this.chainId) {
1136
- throw new Error(
1137
- `handleConfig: unsupported chainId ${chainId}`
1182
+ throw new ValidationError(
1183
+ "UNSUPPORTED_CHAIN_ID",
1184
+ `handleConfig: unsupported chainId ${chainId}`,
1185
+ { requested: chainId, supported: this.chainId }
1138
1186
  );
1139
1187
  }
1140
1188
  const contracts = {
@@ -1151,7 +1199,8 @@ var IssuerApiHandlers = class {
1151
1199
  /** `GET /gas-fee` — quoted in USDT (6-decimal base units). */
1152
1200
  async handleGasFee() {
1153
1201
  if (!this.feeManager) {
1154
- throw new Error(
1202
+ throw new ConfigurationError(
1203
+ "FEE_MANAGER_NOT_CONFIGURED",
1155
1204
  "handleGasFee: feeManager is not configured on this issuer"
1156
1205
  );
1157
1206
  }
@@ -1173,13 +1222,16 @@ var IssuerApiHandlers = class {
1173
1222
  */
1174
1223
  async handlePools(_userAddress, request) {
1175
1224
  if (!this.poolsProvider) {
1176
- throw new Error(
1225
+ throw new ConfigurationError(
1226
+ "POOLS_PROVIDER_NOT_CONFIGURED",
1177
1227
  "handlePools: poolsProvider is not configured on this issuer"
1178
1228
  );
1179
1229
  }
1180
1230
  if (request.chainId !== this.chainId) {
1181
- throw new Error(
1182
- `handlePools: unsupported chainId ${request.chainId}`
1231
+ throw new ValidationError(
1232
+ "UNSUPPORTED_CHAIN_ID",
1233
+ `handlePools: unsupported chainId ${request.chainId}`,
1234
+ { requested: request.chainId, supported: this.chainId }
1183
1235
  );
1184
1236
  }
1185
1237
  return this.poolsProvider(request);
@@ -1193,21 +1245,27 @@ var IssuerApiHandlers = class {
1193
1245
  */
1194
1246
  async handleUser(userAddress, request) {
1195
1247
  if (request.chainId !== this.chainId) {
1196
- throw new Error(
1197
- `handleUser: unsupported chainId ${request.chainId}`
1248
+ throw new ValidationError(
1249
+ "UNSUPPORTED_CHAIN_ID",
1250
+ `handleUser: unsupported chainId ${request.chainId}`,
1251
+ { requested: request.chainId, supported: this.chainId }
1198
1252
  );
1199
1253
  }
1200
1254
  const normalizedAuthed = getAddress5(userAddress);
1201
1255
  const normalizedRequest = getAddress5(request.userAddress);
1202
1256
  if (normalizedAuthed !== normalizedRequest) {
1203
- throw new Error(
1204
- "handleUser: request userAddress must match authenticated user"
1257
+ throw new ValidationError(
1258
+ "USER_ADDRESS_MISMATCH",
1259
+ "handleUser: request userAddress must match authenticated user",
1260
+ { authenticated: normalizedAuthed, requested: normalizedRequest }
1205
1261
  );
1206
1262
  }
1207
1263
  const pointToken = getAddress5(request.pointTokenAddress);
1208
1264
  if (!this.supportedTokens.has(pointToken)) {
1209
- throw new Error(
1210
- `handleUser: unsupported pointToken ${pointToken}`
1265
+ throw new ValidationError(
1266
+ "UNSUPPORTED_POINT_TOKEN",
1267
+ `handleUser: unsupported pointToken ${pointToken}`,
1268
+ { requested: pointToken }
1211
1269
  );
1212
1270
  }
1213
1271
  const [mintRequestNonce, receiverConsentNonce, offChainBalance, onChainBalance, minter] = await Promise.all([
@@ -1408,69 +1466,82 @@ var PTRedeemHandler = class {
1408
1466
  this.redeemLockDurationMs,
1409
1467
  this.pointTokenAddress
1410
1468
  );
1411
- const sponsoredUserOp = await this.relayService.prepareBurn({
1412
- mode: "burnWithSig",
1413
- userAddress: request.userAddress,
1414
- aaNonce: request.aaNonce,
1415
- pointTokenAddress: this.pointTokenAddress,
1416
- batchExecutorAddress: this.batchExecutorAddress,
1417
- burnRequest: sponsoredBurnRequest,
1418
- burnerSignature: sponsoredSig,
1419
- feeAmount: fee,
1420
- feeRecipient
1421
- });
1422
- let fallback = void 0;
1423
- if (fee > 0n) {
1424
- const fallbackBurnRequest = {
1425
- from: request.userAddress,
1426
- amount: request.amount,
1427
- nonce: burnNonce,
1428
- deadline
1429
- };
1430
- let fallbackSig;
1431
- try {
1432
- fallbackSig = (await signBurnRequest(this.burnerSignerWallet, domain, fallbackBurnRequest)).serialized;
1433
- } catch (err) {
1434
- throw new PTRedeemError(
1435
- "SIGNING_FAILED",
1436
- `failed to sign fallback BurnRequest: ${err instanceof Error ? err.message : String(err)}`
1437
- );
1438
- }
1439
- const fallbackLockId = await this.ledger.reservePendingCredit(
1440
- request.userAddress,
1441
- request.amount,
1442
- this.redeemLockDurationMs,
1443
- this.pointTokenAddress
1444
- );
1445
- const fallbackUserOp = await this.relayService.prepareBurn({
1469
+ try {
1470
+ const sponsoredUserOp = await this.relayService.prepareBurn({
1446
1471
  mode: "burnWithSig",
1447
1472
  userAddress: request.userAddress,
1448
1473
  aaNonce: request.aaNonce,
1449
1474
  pointTokenAddress: this.pointTokenAddress,
1450
1475
  batchExecutorAddress: this.batchExecutorAddress,
1451
- burnRequest: fallbackBurnRequest,
1452
- burnerSignature: fallbackSig,
1453
- // Explicit 0n — fallback is fee-free regardless of how
1454
- // RelayService is configured. Without this, an
1455
- // auto-quoting RelayService would try to quote a fee here
1456
- // and re-add the PT.transfer we're trying to strip.
1457
- feeAmount: 0n
1476
+ burnRequest: sponsoredBurnRequest,
1477
+ burnerSignature: sponsoredSig,
1478
+ feeAmount: fee,
1479
+ feeRecipient
1458
1480
  });
1459
- fallback = {
1460
- lockId: fallbackLockId,
1461
- userOp: fallbackUserOp,
1462
- netCreditAmount: request.amount
1481
+ let fallback = void 0;
1482
+ if (fee > 0n) {
1483
+ const fallbackBurnRequest = {
1484
+ from: request.userAddress,
1485
+ amount: request.amount,
1486
+ nonce: burnNonce,
1487
+ deadline
1488
+ };
1489
+ let fallbackSig;
1490
+ try {
1491
+ fallbackSig = (await signBurnRequest(this.burnerSignerWallet, domain, fallbackBurnRequest)).serialized;
1492
+ } catch (err) {
1493
+ throw new PTRedeemError(
1494
+ "SIGNING_FAILED",
1495
+ `failed to sign fallback BurnRequest: ${err instanceof Error ? err.message : String(err)}`
1496
+ );
1497
+ }
1498
+ const fallbackLockId = await this.ledger.reservePendingCredit(
1499
+ request.userAddress,
1500
+ request.amount,
1501
+ this.redeemLockDurationMs,
1502
+ this.pointTokenAddress
1503
+ );
1504
+ let fallbackUserOp;
1505
+ try {
1506
+ fallbackUserOp = await this.relayService.prepareBurn({
1507
+ mode: "burnWithSig",
1508
+ userAddress: request.userAddress,
1509
+ aaNonce: request.aaNonce,
1510
+ pointTokenAddress: this.pointTokenAddress,
1511
+ batchExecutorAddress: this.batchExecutorAddress,
1512
+ burnRequest: fallbackBurnRequest,
1513
+ burnerSignature: fallbackSig,
1514
+ // Explicit 0n — fallback is fee-free regardless of how
1515
+ // RelayService is configured. Without this, an
1516
+ // auto-quoting RelayService would try to quote a fee here
1517
+ // and re-add the PT.transfer we're trying to strip.
1518
+ feeAmount: 0n
1519
+ });
1520
+ } catch (err) {
1521
+ await this.ledger.releaseLock(fallbackLockId).catch(() => {
1522
+ });
1523
+ throw err;
1524
+ }
1525
+ fallback = {
1526
+ lockId: fallbackLockId,
1527
+ userOp: fallbackUserOp,
1528
+ netCreditAmount: request.amount
1529
+ };
1530
+ }
1531
+ return {
1532
+ lockId: sponsoredLockId,
1533
+ userOp: sponsoredUserOp,
1534
+ netCreditAmount: sponsoredBurnAmount,
1535
+ feeAmount: fee,
1536
+ fallback,
1537
+ expiresInSeconds: Math.floor(this.redeemLockDurationMs / 1e3),
1538
+ signatureDeadline: deadline
1463
1539
  };
1540
+ } catch (err) {
1541
+ await this.ledger.releaseLock(sponsoredLockId).catch(() => {
1542
+ });
1543
+ throw err;
1464
1544
  }
1465
- return {
1466
- lockId: sponsoredLockId,
1467
- userOp: sponsoredUserOp,
1468
- netCreditAmount: sponsoredBurnAmount,
1469
- feeAmount: fee,
1470
- fallback,
1471
- expiresInSeconds: Math.floor(this.redeemLockDurationMs / 1e3),
1472
- signatureDeadline: deadline
1473
- };
1474
1545
  }
1475
1546
  };
1476
1547
 
@@ -1744,6 +1815,41 @@ async function prepareMobileUserOp(params) {
1744
1815
  };
1745
1816
  }
1746
1817
 
1818
+ // src/pafi-backend/types.ts
1819
+ var PafiBackendError = class extends Error {
1820
+ constructor(code, message, httpStatus, details, opts) {
1821
+ super(message);
1822
+ this.code = code;
1823
+ this.httpStatus = httpStatus;
1824
+ this.details = details;
1825
+ this.name = "PafiBackendError";
1826
+ if (opts?.retryAfter !== void 0) this.retryAfter = opts.retryAfter;
1827
+ if (opts?.safeToRetry !== void 0) this.serverSafeToRetry = opts.safeToRetry;
1828
+ }
1829
+ code;
1830
+ httpStatus;
1831
+ details;
1832
+ retryAfter;
1833
+ serverSafeToRetry;
1834
+ get safeToRetry() {
1835
+ if (this.serverSafeToRetry !== void 0) return this.serverSafeToRetry;
1836
+ switch (this.code) {
1837
+ case "RATE_LIMITER_UNAVAILABLE":
1838
+ case "INTERNAL_ERROR":
1839
+ case "TIMEOUT":
1840
+ case "NETWORK_ERROR":
1841
+ return true;
1842
+ case "RATE_LIMIT_EXCEEDED":
1843
+ case "RATE_LIMIT_EXCEEDED_DAILY":
1844
+ case "RATE_LIMIT_EXCEEDED_PER_USER":
1845
+ case "ISSUER_BUDGET_EXCEEDED":
1846
+ return true;
1847
+ default:
1848
+ return false;
1849
+ }
1850
+ }
1851
+ };
1852
+
1747
1853
  // src/pafi-backend/helpers.ts
1748
1854
  var BundlerNotConfiguredError = class extends PafiSdkError {
1749
1855
  code = "BUNDLER_NOT_CONFIGURED";
@@ -1779,8 +1885,23 @@ async function requestPaymaster(params) {
1779
1885
  });
1780
1886
  } catch (err) {
1781
1887
  const msg = err instanceof Error ? err.message : String(err);
1782
- params.onWarning?.(`Paymaster sponsorship declined: ${msg}`);
1783
- return void 0;
1888
+ if (err instanceof PafiBackendError && isTransientPaymasterError(err.code)) {
1889
+ params.onWarning?.(`Paymaster sponsorship declined (transient): ${msg}`);
1890
+ return void 0;
1891
+ }
1892
+ throw err;
1893
+ }
1894
+ }
1895
+ function isTransientPaymasterError(code) {
1896
+ switch (code) {
1897
+ case "NETWORK_ERROR":
1898
+ case "TIMEOUT":
1899
+ case "PAYMASTER_UNAVAILABLE":
1900
+ case "RATE_LIMITER_UNAVAILABLE":
1901
+ case "INTERNAL_ERROR":
1902
+ return true;
1903
+ default:
1904
+ return false;
1784
1905
  }
1785
1906
  }
1786
1907
  function defaultFunctionForScenario(scenario) {
@@ -1964,39 +2085,19 @@ var PTClaimHandler = class {
1964
2085
  this.cfg.lockDurationMs,
1965
2086
  request.pointTokenAddress
1966
2087
  );
1967
- const signatureDeadline = BigInt(
1968
- Math.floor(this.cfg.now() / 1e3) + this.cfg.signatureDeadlineSeconds
1969
- );
1970
- const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
1971
- const domain = {
1972
- name: this.cfg.pointTokenDomainName,
1973
- chainId: request.chainId,
1974
- verifyingContract: request.pointTokenAddress
1975
- };
1976
- let userOp;
1977
2088
  try {
1978
- userOp = await this.cfg.relayService.prepareMint({
1979
- userAddress: request.userAddress,
1980
- aaNonce: request.aaNonce,
1981
- batchExecutorAddress,
1982
- pointTokenAddress: request.pointTokenAddress,
1983
- amount: request.amount,
1984
- issuerSignerWallet: this.cfg.issuerSignerWallet,
1985
- domain,
1986
- mintRequestNonce: request.mintRequestNonce,
1987
- deadline: signatureDeadline
1988
- // No feeAmount/feeRecipient — RelayService auto-resolves.
1989
- });
1990
- } catch (err) {
1991
- throw new PTClaimError(
1992
- "BUILD_FAILED",
1993
- `prepareMint failed: ${err instanceof Error ? err.message : String(err)}`
2089
+ const signatureDeadline = BigInt(
2090
+ Math.floor(this.cfg.now() / 1e3) + this.cfg.signatureDeadlineSeconds
1994
2091
  );
1995
- }
1996
- let fallback;
1997
- if (feeAmount > 0n) {
2092
+ const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
2093
+ const domain = {
2094
+ name: this.cfg.pointTokenDomainName,
2095
+ chainId: request.chainId,
2096
+ verifyingContract: request.pointTokenAddress
2097
+ };
2098
+ let userOp;
1998
2099
  try {
1999
- fallback = await this.cfg.relayService.prepareMint({
2100
+ userOp = await this.cfg.relayService.prepareMint({
2000
2101
  userAddress: request.userAddress,
2001
2102
  aaNonce: request.aaNonce,
2002
2103
  batchExecutorAddress,
@@ -2005,28 +2106,54 @@ var PTClaimHandler = class {
2005
2106
  issuerSignerWallet: this.cfg.issuerSignerWallet,
2006
2107
  domain,
2007
2108
  mintRequestNonce: request.mintRequestNonce,
2008
- deadline: signatureDeadline,
2009
- feeAmount: 0n
2109
+ deadline: signatureDeadline
2110
+ // No feeAmount/feeRecipient — RelayService auto-resolves.
2010
2111
  });
2011
2112
  } catch (err) {
2012
2113
  throw new PTClaimError(
2013
2114
  "BUILD_FAILED",
2014
- `prepareMint (fallback) failed: ${err instanceof Error ? err.message : String(err)}`
2115
+ `prepareMint failed: ${err instanceof Error ? err.message : String(err)}`
2015
2116
  );
2016
2117
  }
2118
+ let fallback;
2119
+ if (feeAmount > 0n) {
2120
+ try {
2121
+ fallback = await this.cfg.relayService.prepareMint({
2122
+ userAddress: request.userAddress,
2123
+ aaNonce: request.aaNonce,
2124
+ batchExecutorAddress,
2125
+ pointTokenAddress: request.pointTokenAddress,
2126
+ amount: request.amount,
2127
+ issuerSignerWallet: this.cfg.issuerSignerWallet,
2128
+ domain,
2129
+ mintRequestNonce: request.mintRequestNonce,
2130
+ deadline: signatureDeadline,
2131
+ feeAmount: 0n
2132
+ });
2133
+ } catch (err) {
2134
+ throw new PTClaimError(
2135
+ "BUILD_FAILED",
2136
+ `prepareMint (fallback) failed: ${err instanceof Error ? err.message : String(err)}`
2137
+ );
2138
+ }
2139
+ }
2140
+ const calls = decodeBatchExecuteCalls(userOp.callData);
2141
+ const callsFallback = fallback ? decodeBatchExecuteCalls(fallback.callData) : void 0;
2142
+ return {
2143
+ userOp,
2144
+ fallback,
2145
+ lockId,
2146
+ feeAmount,
2147
+ signatureDeadline,
2148
+ expiresInSeconds: Math.floor(this.cfg.lockDurationMs / 1e3),
2149
+ calls,
2150
+ callsFallback
2151
+ };
2152
+ } catch (err) {
2153
+ await this.cfg.ledger.releaseLock(lockId).catch(() => {
2154
+ });
2155
+ throw err;
2017
2156
  }
2018
- const calls = decodeBatchExecuteCalls(userOp.callData);
2019
- const callsFallback = fallback ? decodeBatchExecuteCalls(fallback.callData) : void 0;
2020
- return {
2021
- userOp,
2022
- fallback,
2023
- lockId,
2024
- feeAmount,
2025
- signatureDeadline,
2026
- expiresInSeconds: Math.floor(this.cfg.lockDurationMs / 1e3),
2027
- calls,
2028
- callsFallback
2029
- };
2030
2157
  }
2031
2158
  };
2032
2159
 
@@ -2040,7 +2167,8 @@ import {
2040
2167
  buildPerpDepositViaRelay,
2041
2168
  computeAccountId,
2042
2169
  decodeBatchExecuteCalls as decodeBatchExecuteCalls2,
2043
- getContractAddresses as getContractAddresses4
2170
+ getContractAddresses as getContractAddresses4,
2171
+ quoteOperatorFeeUsdt
2044
2172
  } from "@pafi-dev/core";
2045
2173
  var PerpDepositError = class extends PafiSdkError {
2046
2174
  httpStatus = "unprocessable";
@@ -2103,14 +2231,19 @@ var PerpDepositHandler = class {
2103
2231
  totalAmount: request.amount,
2104
2232
  maxFee: 0n
2105
2233
  };
2106
- const [relayTokenFee, ptGasFee] = await Promise.all([
2234
+ const [relayTokenFee, usdcGasFee] = await Promise.all([
2107
2235
  this.cfg.provider.readContract({
2108
2236
  address: relayAddress,
2109
2237
  abi: ORDERLY_RELAY_ABI,
2110
2238
  functionName: "quoteTokenFee",
2111
2239
  args: [requestForQuote]
2112
2240
  }),
2113
- this.cfg.feeService ? this.cfg.feeService.estimateGasFee() : Promise.resolve(0n)
2241
+ quoteOperatorFeeUsdt({
2242
+ provider: this.cfg.provider,
2243
+ chainId: request.chainId,
2244
+ gasUnits: this.cfg.gasUnits,
2245
+ premiumBps: this.cfg.gasPremiumBps
2246
+ })
2114
2247
  ]);
2115
2248
  if (relayTokenFee >= request.amount) {
2116
2249
  throw new PerpDepositError(
@@ -2118,6 +2251,12 @@ var PerpDepositHandler = class {
2118
2251
  `Relay quoted fee ${relayTokenFee} >= deposit amount ${request.amount}`
2119
2252
  );
2120
2253
  }
2254
+ if (usdcGasFee > 0n && usdcGasFee >= request.amount) {
2255
+ throw new PerpDepositError(
2256
+ "FEE_EXCEEDS_AMOUNT",
2257
+ `USDC gas fee ${usdcGasFee} >= deposit amount ${request.amount}`
2258
+ );
2259
+ }
2121
2260
  const maxFee = relayTokenFee * BigInt(1e4 + this.cfg.maxFeePremiumBps) / 10000n;
2122
2261
  const depositReq = {
2123
2262
  token: usdcAddress,
@@ -2131,11 +2270,10 @@ var PerpDepositHandler = class {
2131
2270
  aaNonce: request.aaNonce,
2132
2271
  relayAddress,
2133
2272
  request: depositReq,
2134
- pointTokenAddress: this.cfg.pointTokenAddress,
2135
- gasFeePt: ptGasFee,
2136
- gasFeePtRecipient: pafiFeeRecipient
2273
+ gasFeeUsdc: usdcGasFee,
2274
+ gasFeeUsdcRecipient: pafiFeeRecipient
2137
2275
  });
2138
- const fallbackOp = ptGasFee > 0n ? buildPerpDepositViaRelay({
2276
+ const fallbackOp = usdcGasFee > 0n ? buildPerpDepositViaRelay({
2139
2277
  userAddress: request.userAddress,
2140
2278
  aaNonce: request.aaNonce,
2141
2279
  relayAddress,
@@ -2144,7 +2282,7 @@ var PerpDepositHandler = class {
2144
2282
  return {
2145
2283
  userOp: sponsoredOp,
2146
2284
  fallback: fallbackOp,
2147
- feeAmount: ptGasFee,
2285
+ feeAmount: usdcGasFee,
2148
2286
  relayTokenFee,
2149
2287
  maxFee,
2150
2288
  netDeposit: request.amount - relayTokenFee,
@@ -2270,9 +2408,45 @@ import {
2270
2408
  getContractAddresses as getContractAddresses6,
2271
2409
  parseEip7702DelegatedAddress as parseEip7702DelegatedAddress2
2272
2410
  } from "@pafi-dev/core";
2411
+ var AdapterMisconfiguredError = class extends Error {
2412
+ code = "ADAPTER_MISCONFIGURED";
2413
+ constructor(message) {
2414
+ super(message);
2415
+ this.name = "AdapterMisconfiguredError";
2416
+ }
2417
+ };
2273
2418
  var IssuerApiAdapter = class {
2274
2419
  cfg;
2275
2420
  constructor(config) {
2421
+ if (config.ptClaimHandler) {
2422
+ if (typeof config.ledger.bindMintUserOpHash !== "function") {
2423
+ throw new AdapterMisconfiguredError(
2424
+ "ledger.bindMintUserOpHash is required when ptClaimHandler is wired (mobile claim flow). Implement it on your IPointLedger or omit ptClaimHandler from IssuerApiAdapter config."
2425
+ );
2426
+ }
2427
+ if (typeof config.ledger.getMintLock !== "function") {
2428
+ throw new AdapterMisconfiguredError(
2429
+ "ledger.getMintLock is required when ptClaimHandler is wired \u2014 claimStatus uses it to look up the lock."
2430
+ );
2431
+ }
2432
+ }
2433
+ if (config.ptRedeemHandler) {
2434
+ if (typeof config.ledger.reservePendingCredit !== "function") {
2435
+ throw new AdapterMisconfiguredError(
2436
+ "ledger.reservePendingCredit is required when ptRedeemHandler is wired (burn/redeem reverse flow). PTRedeemHandler also enforces this at construction; see ledger/types.ts comments."
2437
+ );
2438
+ }
2439
+ if (typeof config.ledger.bindCreditUserOpHash !== "function") {
2440
+ throw new AdapterMisconfiguredError(
2441
+ "ledger.bindCreditUserOpHash is required when ptRedeemHandler is wired (mobile redeem flow)."
2442
+ );
2443
+ }
2444
+ if (typeof config.ledger.getPendingCredit !== "function") {
2445
+ throw new AdapterMisconfiguredError(
2446
+ "ledger.getPendingCredit is required when ptRedeemHandler is wired \u2014 redeemStatus uses it to look up the credit."
2447
+ );
2448
+ }
2449
+ }
2276
2450
  this.cfg = config;
2277
2451
  }
2278
2452
  // ------------------------------ Read endpoints ---------------------------
@@ -2573,6 +2747,11 @@ var IssuerApiAdapter = class {
2573
2747
  /**
2574
2748
  * Build + sign a SponsorAuth payload. Returns `undefined` when no
2575
2749
  * issuer id is configured, so the controller can skip the field.
2750
+ *
2751
+ * v0.7.1 — `scenario` typed as `SponsorshipScenario` (was `string`).
2752
+ * Previously a typo (`"perp_deposit"` vs `"perp-deposit"`) compiled
2753
+ * fine but rejected at L1 by sponsor-relayer's IntentValidator. See
2754
+ * SDK_ISSUER_AUDIT.md N5.
2576
2755
  */
2577
2756
  async buildSponsorAuth(authenticatedAddress, callData, chainId, scenario) {
2578
2757
  if (!this.cfg.pafiIssuerId) return void 0;
@@ -3033,41 +3212,6 @@ var BalanceAggregator = class {
3033
3212
  }
3034
3213
  };
3035
3214
 
3036
- // src/pafi-backend/types.ts
3037
- var PafiBackendError = class extends Error {
3038
- constructor(code, message, httpStatus, details, opts) {
3039
- super(message);
3040
- this.code = code;
3041
- this.httpStatus = httpStatus;
3042
- this.details = details;
3043
- this.name = "PafiBackendError";
3044
- if (opts?.retryAfter !== void 0) this.retryAfter = opts.retryAfter;
3045
- if (opts?.safeToRetry !== void 0) this.serverSafeToRetry = opts.safeToRetry;
3046
- }
3047
- code;
3048
- httpStatus;
3049
- details;
3050
- retryAfter;
3051
- serverSafeToRetry;
3052
- get safeToRetry() {
3053
- if (this.serverSafeToRetry !== void 0) return this.serverSafeToRetry;
3054
- switch (this.code) {
3055
- case "RATE_LIMITER_UNAVAILABLE":
3056
- case "INTERNAL_ERROR":
3057
- case "TIMEOUT":
3058
- case "NETWORK_ERROR":
3059
- return true;
3060
- case "RATE_LIMIT_EXCEEDED":
3061
- case "RATE_LIMIT_EXCEEDED_DAILY":
3062
- case "RATE_LIMIT_EXCEEDED_PER_USER":
3063
- case "ISSUER_BUDGET_EXCEEDED":
3064
- return true;
3065
- default:
3066
- return false;
3067
- }
3068
- }
3069
- };
3070
-
3071
3215
  // src/pafi-backend/client.ts
3072
3216
  function serializeBigInt(_key, value) {
3073
3217
  return typeof value === "bigint" ? value.toString(10) : value;
@@ -3512,14 +3656,16 @@ var IssuerStateValidator = class _IssuerStateValidator {
3512
3656
  };
3513
3657
 
3514
3658
  // src/index.ts
3515
- var PAFI_ISSUER_SDK_VERSION = "0.4.0";
3659
+ var PAFI_ISSUER_SDK_VERSION = true ? "0.7.1" : "dev";
3516
3660
  export {
3661
+ AdapterMisconfiguredError,
3517
3662
  AuthError,
3518
3663
  AuthService,
3519
3664
  BalanceAggregator,
3520
3665
  BundlerNotConfiguredError,
3521
3666
  BundlerRejectedError,
3522
3667
  BurnIndexer,
3668
+ ConfigurationError,
3523
3669
  DefaultPolicyEngine,
3524
3670
  FeeManager,
3525
3671
  InMemoryCursorStore,
@@ -3547,6 +3693,7 @@ export {
3547
3693
  PointIndexer,
3548
3694
  RelayError,
3549
3695
  RelayService,
3696
+ ValidationError,
3550
3697
  authenticateRequest,
3551
3698
  createIssuerService,
3552
3699
  createNativePtQuoter,