@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.cjs +316 -167
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +78 -13
- package/dist/index.d.ts +78 -13
- package/dist/index.js +315 -168
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -20,12 +20,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
AdapterMisconfiguredError: () => AdapterMisconfiguredError,
|
|
23
24
|
AuthError: () => AuthError,
|
|
24
25
|
AuthService: () => AuthService,
|
|
25
26
|
BalanceAggregator: () => BalanceAggregator,
|
|
26
27
|
BundlerNotConfiguredError: () => BundlerNotConfiguredError,
|
|
27
28
|
BundlerRejectedError: () => BundlerRejectedError,
|
|
28
29
|
BurnIndexer: () => BurnIndexer,
|
|
30
|
+
ConfigurationError: () => ConfigurationError,
|
|
29
31
|
DefaultPolicyEngine: () => DefaultPolicyEngine,
|
|
30
32
|
FeeManager: () => FeeManager,
|
|
31
33
|
InMemoryCursorStore: () => InMemoryCursorStore,
|
|
@@ -53,6 +55,7 @@ __export(index_exports, {
|
|
|
53
55
|
PointIndexer: () => PointIndexer,
|
|
54
56
|
RelayError: () => RelayError,
|
|
55
57
|
RelayService: () => RelayService,
|
|
58
|
+
ValidationError: () => ValidationError,
|
|
56
59
|
authenticateRequest: () => authenticateRequest,
|
|
57
60
|
createIssuerService: () => createIssuerService,
|
|
58
61
|
createNativePtQuoter: () => createNativePtQuoter,
|
|
@@ -88,6 +91,26 @@ var PafiSdkError = class extends Error {
|
|
|
88
91
|
this.name = new.target.name;
|
|
89
92
|
}
|
|
90
93
|
};
|
|
94
|
+
var ValidationError = class extends PafiSdkError {
|
|
95
|
+
httpStatus = "unprocessable";
|
|
96
|
+
code;
|
|
97
|
+
details;
|
|
98
|
+
constructor(code, message, details) {
|
|
99
|
+
super(message);
|
|
100
|
+
this.code = code;
|
|
101
|
+
this.details = details;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
var ConfigurationError = class extends PafiSdkError {
|
|
105
|
+
httpStatus = "service_unavailable";
|
|
106
|
+
code;
|
|
107
|
+
details;
|
|
108
|
+
constructor(code, message, details) {
|
|
109
|
+
super(message);
|
|
110
|
+
this.code = code;
|
|
111
|
+
this.details = details;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
91
114
|
|
|
92
115
|
// src/policy/defaultPolicy.ts
|
|
93
116
|
var DefaultPolicyEngine = class {
|
|
@@ -258,12 +281,32 @@ var import_viem2 = require("viem");
|
|
|
258
281
|
var import_core = require("@pafi-dev/core");
|
|
259
282
|
|
|
260
283
|
// src/auth/errors.ts
|
|
261
|
-
|
|
284
|
+
function statusForCode(code) {
|
|
285
|
+
switch (code) {
|
|
286
|
+
case "INVALID_MESSAGE":
|
|
287
|
+
case "DOMAIN_MISMATCH":
|
|
288
|
+
case "CHAIN_MISMATCH":
|
|
289
|
+
case "MESSAGE_EXPIRED":
|
|
290
|
+
case "MESSAGE_NOT_YET_VALID":
|
|
291
|
+
case "MALFORMED_TOKEN":
|
|
292
|
+
return "unprocessable";
|
|
293
|
+
case "NONCE_INVALID":
|
|
294
|
+
case "SIGNATURE_INVALID":
|
|
295
|
+
case "MISSING_TOKEN":
|
|
296
|
+
case "TOKEN_INVALID":
|
|
297
|
+
case "TOKEN_EXPIRED":
|
|
298
|
+
return "forbidden";
|
|
299
|
+
case "SESSION_REVOKED":
|
|
300
|
+
return "not_found";
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
var AuthError = class extends PafiSdkError {
|
|
262
304
|
code;
|
|
305
|
+
httpStatus;
|
|
263
306
|
constructor(code, message) {
|
|
264
307
|
super(message);
|
|
265
|
-
this.name = "AuthError";
|
|
266
308
|
this.code = code;
|
|
309
|
+
this.httpStatus = statusForCode(code);
|
|
267
310
|
}
|
|
268
311
|
};
|
|
269
312
|
|
|
@@ -460,14 +503,15 @@ async function authenticateRequest(authHeader, authService) {
|
|
|
460
503
|
}
|
|
461
504
|
|
|
462
505
|
// src/relay/types.ts
|
|
463
|
-
var RelayError = class extends
|
|
506
|
+
var RelayError = class extends PafiSdkError {
|
|
507
|
+
httpStatus = "unprocessable";
|
|
464
508
|
code;
|
|
465
|
-
cause;
|
|
466
509
|
constructor(code, message, cause) {
|
|
467
510
|
super(message);
|
|
468
|
-
this.name = "RelayError";
|
|
469
511
|
this.code = code;
|
|
470
|
-
if (cause !== void 0)
|
|
512
|
+
if (cause !== void 0) {
|
|
513
|
+
this.cause = cause;
|
|
514
|
+
}
|
|
471
515
|
}
|
|
472
516
|
};
|
|
473
517
|
|
|
@@ -1168,13 +1212,16 @@ var IssuerApiHandlers = class {
|
|
|
1168
1212
|
/** `POST /auth/login` */
|
|
1169
1213
|
async handleLogin(body) {
|
|
1170
1214
|
if (!body || typeof body.message !== "string" || body.message.length === 0 || typeof body.signature !== "string" || body.signature.length <= 2) {
|
|
1171
|
-
throw new
|
|
1215
|
+
throw new ValidationError(
|
|
1216
|
+
"INVALID_LOGIN_BODY",
|
|
1217
|
+
"handleLogin: message and signature are required"
|
|
1218
|
+
);
|
|
1172
1219
|
}
|
|
1173
1220
|
if (body.message.length > 4096) {
|
|
1174
|
-
throw new
|
|
1221
|
+
throw new ValidationError("MESSAGE_TOO_LONG", "message too long");
|
|
1175
1222
|
}
|
|
1176
1223
|
if (body.signature.length > 260) {
|
|
1177
|
-
throw new
|
|
1224
|
+
throw new ValidationError("SIGNATURE_TOO_LONG", "signature too long");
|
|
1178
1225
|
}
|
|
1179
1226
|
const result = await this.authService.login(body.message, body.signature);
|
|
1180
1227
|
return {
|
|
@@ -1191,11 +1238,15 @@ var IssuerApiHandlers = class {
|
|
|
1191
1238
|
*/
|
|
1192
1239
|
async handleConfig(chainId) {
|
|
1193
1240
|
if (!Number.isInteger(chainId) || chainId <= 0) {
|
|
1194
|
-
throw new
|
|
1241
|
+
throw new ValidationError("INVALID_CHAIN_ID", "invalid chainId", {
|
|
1242
|
+
chainId
|
|
1243
|
+
});
|
|
1195
1244
|
}
|
|
1196
1245
|
if (chainId !== this.chainId) {
|
|
1197
|
-
throw new
|
|
1198
|
-
|
|
1246
|
+
throw new ValidationError(
|
|
1247
|
+
"UNSUPPORTED_CHAIN_ID",
|
|
1248
|
+
`handleConfig: unsupported chainId ${chainId}`,
|
|
1249
|
+
{ requested: chainId, supported: this.chainId }
|
|
1199
1250
|
);
|
|
1200
1251
|
}
|
|
1201
1252
|
const contracts = {
|
|
@@ -1212,7 +1263,8 @@ var IssuerApiHandlers = class {
|
|
|
1212
1263
|
/** `GET /gas-fee` — quoted in USDT (6-decimal base units). */
|
|
1213
1264
|
async handleGasFee() {
|
|
1214
1265
|
if (!this.feeManager) {
|
|
1215
|
-
throw new
|
|
1266
|
+
throw new ConfigurationError(
|
|
1267
|
+
"FEE_MANAGER_NOT_CONFIGURED",
|
|
1216
1268
|
"handleGasFee: feeManager is not configured on this issuer"
|
|
1217
1269
|
);
|
|
1218
1270
|
}
|
|
@@ -1234,13 +1286,16 @@ var IssuerApiHandlers = class {
|
|
|
1234
1286
|
*/
|
|
1235
1287
|
async handlePools(_userAddress, request) {
|
|
1236
1288
|
if (!this.poolsProvider) {
|
|
1237
|
-
throw new
|
|
1289
|
+
throw new ConfigurationError(
|
|
1290
|
+
"POOLS_PROVIDER_NOT_CONFIGURED",
|
|
1238
1291
|
"handlePools: poolsProvider is not configured on this issuer"
|
|
1239
1292
|
);
|
|
1240
1293
|
}
|
|
1241
1294
|
if (request.chainId !== this.chainId) {
|
|
1242
|
-
throw new
|
|
1243
|
-
|
|
1295
|
+
throw new ValidationError(
|
|
1296
|
+
"UNSUPPORTED_CHAIN_ID",
|
|
1297
|
+
`handlePools: unsupported chainId ${request.chainId}`,
|
|
1298
|
+
{ requested: request.chainId, supported: this.chainId }
|
|
1244
1299
|
);
|
|
1245
1300
|
}
|
|
1246
1301
|
return this.poolsProvider(request);
|
|
@@ -1254,21 +1309,27 @@ var IssuerApiHandlers = class {
|
|
|
1254
1309
|
*/
|
|
1255
1310
|
async handleUser(userAddress, request) {
|
|
1256
1311
|
if (request.chainId !== this.chainId) {
|
|
1257
|
-
throw new
|
|
1258
|
-
|
|
1312
|
+
throw new ValidationError(
|
|
1313
|
+
"UNSUPPORTED_CHAIN_ID",
|
|
1314
|
+
`handleUser: unsupported chainId ${request.chainId}`,
|
|
1315
|
+
{ requested: request.chainId, supported: this.chainId }
|
|
1259
1316
|
);
|
|
1260
1317
|
}
|
|
1261
1318
|
const normalizedAuthed = (0, import_viem6.getAddress)(userAddress);
|
|
1262
1319
|
const normalizedRequest = (0, import_viem6.getAddress)(request.userAddress);
|
|
1263
1320
|
if (normalizedAuthed !== normalizedRequest) {
|
|
1264
|
-
throw new
|
|
1265
|
-
"
|
|
1321
|
+
throw new ValidationError(
|
|
1322
|
+
"USER_ADDRESS_MISMATCH",
|
|
1323
|
+
"handleUser: request userAddress must match authenticated user",
|
|
1324
|
+
{ authenticated: normalizedAuthed, requested: normalizedRequest }
|
|
1266
1325
|
);
|
|
1267
1326
|
}
|
|
1268
1327
|
const pointToken = (0, import_viem6.getAddress)(request.pointTokenAddress);
|
|
1269
1328
|
if (!this.supportedTokens.has(pointToken)) {
|
|
1270
|
-
throw new
|
|
1271
|
-
|
|
1329
|
+
throw new ValidationError(
|
|
1330
|
+
"UNSUPPORTED_POINT_TOKEN",
|
|
1331
|
+
`handleUser: unsupported pointToken ${pointToken}`,
|
|
1332
|
+
{ requested: pointToken }
|
|
1272
1333
|
);
|
|
1273
1334
|
}
|
|
1274
1335
|
const [mintRequestNonce, receiverConsentNonce, offChainBalance, onChainBalance, minter] = await Promise.all([
|
|
@@ -1464,69 +1525,82 @@ var PTRedeemHandler = class {
|
|
|
1464
1525
|
this.redeemLockDurationMs,
|
|
1465
1526
|
this.pointTokenAddress
|
|
1466
1527
|
);
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
userAddress: request.userAddress,
|
|
1470
|
-
aaNonce: request.aaNonce,
|
|
1471
|
-
pointTokenAddress: this.pointTokenAddress,
|
|
1472
|
-
batchExecutorAddress: this.batchExecutorAddress,
|
|
1473
|
-
burnRequest: sponsoredBurnRequest,
|
|
1474
|
-
burnerSignature: sponsoredSig,
|
|
1475
|
-
feeAmount: fee,
|
|
1476
|
-
feeRecipient
|
|
1477
|
-
});
|
|
1478
|
-
let fallback = void 0;
|
|
1479
|
-
if (fee > 0n) {
|
|
1480
|
-
const fallbackBurnRequest = {
|
|
1481
|
-
from: request.userAddress,
|
|
1482
|
-
amount: request.amount,
|
|
1483
|
-
nonce: burnNonce,
|
|
1484
|
-
deadline
|
|
1485
|
-
};
|
|
1486
|
-
let fallbackSig;
|
|
1487
|
-
try {
|
|
1488
|
-
fallbackSig = (await (0, import_core4.signBurnRequest)(this.burnerSignerWallet, domain, fallbackBurnRequest)).serialized;
|
|
1489
|
-
} catch (err) {
|
|
1490
|
-
throw new PTRedeemError(
|
|
1491
|
-
"SIGNING_FAILED",
|
|
1492
|
-
`failed to sign fallback BurnRequest: ${err instanceof Error ? err.message : String(err)}`
|
|
1493
|
-
);
|
|
1494
|
-
}
|
|
1495
|
-
const fallbackLockId = await this.ledger.reservePendingCredit(
|
|
1496
|
-
request.userAddress,
|
|
1497
|
-
request.amount,
|
|
1498
|
-
this.redeemLockDurationMs,
|
|
1499
|
-
this.pointTokenAddress
|
|
1500
|
-
);
|
|
1501
|
-
const fallbackUserOp = await this.relayService.prepareBurn({
|
|
1528
|
+
try {
|
|
1529
|
+
const sponsoredUserOp = await this.relayService.prepareBurn({
|
|
1502
1530
|
mode: "burnWithSig",
|
|
1503
1531
|
userAddress: request.userAddress,
|
|
1504
1532
|
aaNonce: request.aaNonce,
|
|
1505
1533
|
pointTokenAddress: this.pointTokenAddress,
|
|
1506
1534
|
batchExecutorAddress: this.batchExecutorAddress,
|
|
1507
|
-
burnRequest:
|
|
1508
|
-
burnerSignature:
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
// auto-quoting RelayService would try to quote a fee here
|
|
1512
|
-
// and re-add the PT.transfer we're trying to strip.
|
|
1513
|
-
feeAmount: 0n
|
|
1535
|
+
burnRequest: sponsoredBurnRequest,
|
|
1536
|
+
burnerSignature: sponsoredSig,
|
|
1537
|
+
feeAmount: fee,
|
|
1538
|
+
feeRecipient
|
|
1514
1539
|
});
|
|
1515
|
-
fallback =
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1540
|
+
let fallback = void 0;
|
|
1541
|
+
if (fee > 0n) {
|
|
1542
|
+
const fallbackBurnRequest = {
|
|
1543
|
+
from: request.userAddress,
|
|
1544
|
+
amount: request.amount,
|
|
1545
|
+
nonce: burnNonce,
|
|
1546
|
+
deadline
|
|
1547
|
+
};
|
|
1548
|
+
let fallbackSig;
|
|
1549
|
+
try {
|
|
1550
|
+
fallbackSig = (await (0, import_core4.signBurnRequest)(this.burnerSignerWallet, domain, fallbackBurnRequest)).serialized;
|
|
1551
|
+
} catch (err) {
|
|
1552
|
+
throw new PTRedeemError(
|
|
1553
|
+
"SIGNING_FAILED",
|
|
1554
|
+
`failed to sign fallback BurnRequest: ${err instanceof Error ? err.message : String(err)}`
|
|
1555
|
+
);
|
|
1556
|
+
}
|
|
1557
|
+
const fallbackLockId = await this.ledger.reservePendingCredit(
|
|
1558
|
+
request.userAddress,
|
|
1559
|
+
request.amount,
|
|
1560
|
+
this.redeemLockDurationMs,
|
|
1561
|
+
this.pointTokenAddress
|
|
1562
|
+
);
|
|
1563
|
+
let fallbackUserOp;
|
|
1564
|
+
try {
|
|
1565
|
+
fallbackUserOp = await this.relayService.prepareBurn({
|
|
1566
|
+
mode: "burnWithSig",
|
|
1567
|
+
userAddress: request.userAddress,
|
|
1568
|
+
aaNonce: request.aaNonce,
|
|
1569
|
+
pointTokenAddress: this.pointTokenAddress,
|
|
1570
|
+
batchExecutorAddress: this.batchExecutorAddress,
|
|
1571
|
+
burnRequest: fallbackBurnRequest,
|
|
1572
|
+
burnerSignature: fallbackSig,
|
|
1573
|
+
// Explicit 0n — fallback is fee-free regardless of how
|
|
1574
|
+
// RelayService is configured. Without this, an
|
|
1575
|
+
// auto-quoting RelayService would try to quote a fee here
|
|
1576
|
+
// and re-add the PT.transfer we're trying to strip.
|
|
1577
|
+
feeAmount: 0n
|
|
1578
|
+
});
|
|
1579
|
+
} catch (err) {
|
|
1580
|
+
await this.ledger.releaseLock(fallbackLockId).catch(() => {
|
|
1581
|
+
});
|
|
1582
|
+
throw err;
|
|
1583
|
+
}
|
|
1584
|
+
fallback = {
|
|
1585
|
+
lockId: fallbackLockId,
|
|
1586
|
+
userOp: fallbackUserOp,
|
|
1587
|
+
netCreditAmount: request.amount
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
return {
|
|
1591
|
+
lockId: sponsoredLockId,
|
|
1592
|
+
userOp: sponsoredUserOp,
|
|
1593
|
+
netCreditAmount: sponsoredBurnAmount,
|
|
1594
|
+
feeAmount: fee,
|
|
1595
|
+
fallback,
|
|
1596
|
+
expiresInSeconds: Math.floor(this.redeemLockDurationMs / 1e3),
|
|
1597
|
+
signatureDeadline: deadline
|
|
1519
1598
|
};
|
|
1599
|
+
} catch (err) {
|
|
1600
|
+
await this.ledger.releaseLock(sponsoredLockId).catch(() => {
|
|
1601
|
+
});
|
|
1602
|
+
throw err;
|
|
1520
1603
|
}
|
|
1521
|
-
return {
|
|
1522
|
-
lockId: sponsoredLockId,
|
|
1523
|
-
userOp: sponsoredUserOp,
|
|
1524
|
-
netCreditAmount: sponsoredBurnAmount,
|
|
1525
|
-
feeAmount: fee,
|
|
1526
|
-
fallback,
|
|
1527
|
-
expiresInSeconds: Math.floor(this.redeemLockDurationMs / 1e3),
|
|
1528
|
-
signatureDeadline: deadline
|
|
1529
|
-
};
|
|
1530
1604
|
}
|
|
1531
1605
|
};
|
|
1532
1606
|
|
|
@@ -1794,6 +1868,41 @@ async function prepareMobileUserOp(params) {
|
|
|
1794
1868
|
};
|
|
1795
1869
|
}
|
|
1796
1870
|
|
|
1871
|
+
// src/pafi-backend/types.ts
|
|
1872
|
+
var PafiBackendError = class extends Error {
|
|
1873
|
+
constructor(code, message, httpStatus, details, opts) {
|
|
1874
|
+
super(message);
|
|
1875
|
+
this.code = code;
|
|
1876
|
+
this.httpStatus = httpStatus;
|
|
1877
|
+
this.details = details;
|
|
1878
|
+
this.name = "PafiBackendError";
|
|
1879
|
+
if (opts?.retryAfter !== void 0) this.retryAfter = opts.retryAfter;
|
|
1880
|
+
if (opts?.safeToRetry !== void 0) this.serverSafeToRetry = opts.safeToRetry;
|
|
1881
|
+
}
|
|
1882
|
+
code;
|
|
1883
|
+
httpStatus;
|
|
1884
|
+
details;
|
|
1885
|
+
retryAfter;
|
|
1886
|
+
serverSafeToRetry;
|
|
1887
|
+
get safeToRetry() {
|
|
1888
|
+
if (this.serverSafeToRetry !== void 0) return this.serverSafeToRetry;
|
|
1889
|
+
switch (this.code) {
|
|
1890
|
+
case "RATE_LIMITER_UNAVAILABLE":
|
|
1891
|
+
case "INTERNAL_ERROR":
|
|
1892
|
+
case "TIMEOUT":
|
|
1893
|
+
case "NETWORK_ERROR":
|
|
1894
|
+
return true;
|
|
1895
|
+
case "RATE_LIMIT_EXCEEDED":
|
|
1896
|
+
case "RATE_LIMIT_EXCEEDED_DAILY":
|
|
1897
|
+
case "RATE_LIMIT_EXCEEDED_PER_USER":
|
|
1898
|
+
case "ISSUER_BUDGET_EXCEEDED":
|
|
1899
|
+
return true;
|
|
1900
|
+
default:
|
|
1901
|
+
return false;
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
};
|
|
1905
|
+
|
|
1797
1906
|
// src/pafi-backend/helpers.ts
|
|
1798
1907
|
var BundlerNotConfiguredError = class extends PafiSdkError {
|
|
1799
1908
|
code = "BUNDLER_NOT_CONFIGURED";
|
|
@@ -1829,8 +1938,23 @@ async function requestPaymaster(params) {
|
|
|
1829
1938
|
});
|
|
1830
1939
|
} catch (err) {
|
|
1831
1940
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1832
|
-
|
|
1833
|
-
|
|
1941
|
+
if (err instanceof PafiBackendError && isTransientPaymasterError(err.code)) {
|
|
1942
|
+
params.onWarning?.(`Paymaster sponsorship declined (transient): ${msg}`);
|
|
1943
|
+
return void 0;
|
|
1944
|
+
}
|
|
1945
|
+
throw err;
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
function isTransientPaymasterError(code) {
|
|
1949
|
+
switch (code) {
|
|
1950
|
+
case "NETWORK_ERROR":
|
|
1951
|
+
case "TIMEOUT":
|
|
1952
|
+
case "PAYMASTER_UNAVAILABLE":
|
|
1953
|
+
case "RATE_LIMITER_UNAVAILABLE":
|
|
1954
|
+
case "INTERNAL_ERROR":
|
|
1955
|
+
return true;
|
|
1956
|
+
default:
|
|
1957
|
+
return false;
|
|
1834
1958
|
}
|
|
1835
1959
|
}
|
|
1836
1960
|
function defaultFunctionForScenario(scenario) {
|
|
@@ -2011,39 +2135,19 @@ var PTClaimHandler = class {
|
|
|
2011
2135
|
this.cfg.lockDurationMs,
|
|
2012
2136
|
request.pointTokenAddress
|
|
2013
2137
|
);
|
|
2014
|
-
const signatureDeadline = BigInt(
|
|
2015
|
-
Math.floor(this.cfg.now() / 1e3) + this.cfg.signatureDeadlineSeconds
|
|
2016
|
-
);
|
|
2017
|
-
const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
|
|
2018
|
-
const domain = {
|
|
2019
|
-
name: this.cfg.pointTokenDomainName,
|
|
2020
|
-
chainId: request.chainId,
|
|
2021
|
-
verifyingContract: request.pointTokenAddress
|
|
2022
|
-
};
|
|
2023
|
-
let userOp;
|
|
2024
2138
|
try {
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
aaNonce: request.aaNonce,
|
|
2028
|
-
batchExecutorAddress,
|
|
2029
|
-
pointTokenAddress: request.pointTokenAddress,
|
|
2030
|
-
amount: request.amount,
|
|
2031
|
-
issuerSignerWallet: this.cfg.issuerSignerWallet,
|
|
2032
|
-
domain,
|
|
2033
|
-
mintRequestNonce: request.mintRequestNonce,
|
|
2034
|
-
deadline: signatureDeadline
|
|
2035
|
-
// No feeAmount/feeRecipient — RelayService auto-resolves.
|
|
2036
|
-
});
|
|
2037
|
-
} catch (err) {
|
|
2038
|
-
throw new PTClaimError(
|
|
2039
|
-
"BUILD_FAILED",
|
|
2040
|
-
`prepareMint failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2139
|
+
const signatureDeadline = BigInt(
|
|
2140
|
+
Math.floor(this.cfg.now() / 1e3) + this.cfg.signatureDeadlineSeconds
|
|
2041
2141
|
);
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2142
|
+
const feeAmount = this.cfg.feeService ? await this.cfg.feeService.estimateGasFee() : 0n;
|
|
2143
|
+
const domain = {
|
|
2144
|
+
name: this.cfg.pointTokenDomainName,
|
|
2145
|
+
chainId: request.chainId,
|
|
2146
|
+
verifyingContract: request.pointTokenAddress
|
|
2147
|
+
};
|
|
2148
|
+
let userOp;
|
|
2045
2149
|
try {
|
|
2046
|
-
|
|
2150
|
+
userOp = await this.cfg.relayService.prepareMint({
|
|
2047
2151
|
userAddress: request.userAddress,
|
|
2048
2152
|
aaNonce: request.aaNonce,
|
|
2049
2153
|
batchExecutorAddress,
|
|
@@ -2052,28 +2156,54 @@ var PTClaimHandler = class {
|
|
|
2052
2156
|
issuerSignerWallet: this.cfg.issuerSignerWallet,
|
|
2053
2157
|
domain,
|
|
2054
2158
|
mintRequestNonce: request.mintRequestNonce,
|
|
2055
|
-
deadline: signatureDeadline
|
|
2056
|
-
feeAmount
|
|
2159
|
+
deadline: signatureDeadline
|
|
2160
|
+
// No feeAmount/feeRecipient — RelayService auto-resolves.
|
|
2057
2161
|
});
|
|
2058
2162
|
} catch (err) {
|
|
2059
2163
|
throw new PTClaimError(
|
|
2060
2164
|
"BUILD_FAILED",
|
|
2061
|
-
`prepareMint
|
|
2165
|
+
`prepareMint failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2062
2166
|
);
|
|
2063
2167
|
}
|
|
2168
|
+
let fallback;
|
|
2169
|
+
if (feeAmount > 0n) {
|
|
2170
|
+
try {
|
|
2171
|
+
fallback = await this.cfg.relayService.prepareMint({
|
|
2172
|
+
userAddress: request.userAddress,
|
|
2173
|
+
aaNonce: request.aaNonce,
|
|
2174
|
+
batchExecutorAddress,
|
|
2175
|
+
pointTokenAddress: request.pointTokenAddress,
|
|
2176
|
+
amount: request.amount,
|
|
2177
|
+
issuerSignerWallet: this.cfg.issuerSignerWallet,
|
|
2178
|
+
domain,
|
|
2179
|
+
mintRequestNonce: request.mintRequestNonce,
|
|
2180
|
+
deadline: signatureDeadline,
|
|
2181
|
+
feeAmount: 0n
|
|
2182
|
+
});
|
|
2183
|
+
} catch (err) {
|
|
2184
|
+
throw new PTClaimError(
|
|
2185
|
+
"BUILD_FAILED",
|
|
2186
|
+
`prepareMint (fallback) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2187
|
+
);
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
const calls = (0, import_core8.decodeBatchExecuteCalls)(userOp.callData);
|
|
2191
|
+
const callsFallback = fallback ? (0, import_core8.decodeBatchExecuteCalls)(fallback.callData) : void 0;
|
|
2192
|
+
return {
|
|
2193
|
+
userOp,
|
|
2194
|
+
fallback,
|
|
2195
|
+
lockId,
|
|
2196
|
+
feeAmount,
|
|
2197
|
+
signatureDeadline,
|
|
2198
|
+
expiresInSeconds: Math.floor(this.cfg.lockDurationMs / 1e3),
|
|
2199
|
+
calls,
|
|
2200
|
+
callsFallback
|
|
2201
|
+
};
|
|
2202
|
+
} catch (err) {
|
|
2203
|
+
await this.cfg.ledger.releaseLock(lockId).catch(() => {
|
|
2204
|
+
});
|
|
2205
|
+
throw err;
|
|
2064
2206
|
}
|
|
2065
|
-
const calls = (0, import_core8.decodeBatchExecuteCalls)(userOp.callData);
|
|
2066
|
-
const callsFallback = fallback ? (0, import_core8.decodeBatchExecuteCalls)(fallback.callData) : void 0;
|
|
2067
|
-
return {
|
|
2068
|
-
userOp,
|
|
2069
|
-
fallback,
|
|
2070
|
-
lockId,
|
|
2071
|
-
feeAmount,
|
|
2072
|
-
signatureDeadline,
|
|
2073
|
-
expiresInSeconds: Math.floor(this.cfg.lockDurationMs / 1e3),
|
|
2074
|
-
calls,
|
|
2075
|
-
callsFallback
|
|
2076
|
-
};
|
|
2077
2207
|
}
|
|
2078
2208
|
};
|
|
2079
2209
|
|
|
@@ -2140,14 +2270,19 @@ var PerpDepositHandler = class {
|
|
|
2140
2270
|
totalAmount: request.amount,
|
|
2141
2271
|
maxFee: 0n
|
|
2142
2272
|
};
|
|
2143
|
-
const [relayTokenFee,
|
|
2273
|
+
const [relayTokenFee, usdcGasFee] = await Promise.all([
|
|
2144
2274
|
this.cfg.provider.readContract({
|
|
2145
2275
|
address: relayAddress,
|
|
2146
2276
|
abi: import_core9.ORDERLY_RELAY_ABI,
|
|
2147
2277
|
functionName: "quoteTokenFee",
|
|
2148
2278
|
args: [requestForQuote]
|
|
2149
2279
|
}),
|
|
2150
|
-
|
|
2280
|
+
(0, import_core9.quoteOperatorFeeUsdt)({
|
|
2281
|
+
provider: this.cfg.provider,
|
|
2282
|
+
chainId: request.chainId,
|
|
2283
|
+
gasUnits: this.cfg.gasUnits,
|
|
2284
|
+
premiumBps: this.cfg.gasPremiumBps
|
|
2285
|
+
})
|
|
2151
2286
|
]);
|
|
2152
2287
|
if (relayTokenFee >= request.amount) {
|
|
2153
2288
|
throw new PerpDepositError(
|
|
@@ -2155,6 +2290,12 @@ var PerpDepositHandler = class {
|
|
|
2155
2290
|
`Relay quoted fee ${relayTokenFee} >= deposit amount ${request.amount}`
|
|
2156
2291
|
);
|
|
2157
2292
|
}
|
|
2293
|
+
if (usdcGasFee > 0n && usdcGasFee >= request.amount) {
|
|
2294
|
+
throw new PerpDepositError(
|
|
2295
|
+
"FEE_EXCEEDS_AMOUNT",
|
|
2296
|
+
`USDC gas fee ${usdcGasFee} >= deposit amount ${request.amount}`
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2158
2299
|
const maxFee = relayTokenFee * BigInt(1e4 + this.cfg.maxFeePremiumBps) / 10000n;
|
|
2159
2300
|
const depositReq = {
|
|
2160
2301
|
token: usdcAddress,
|
|
@@ -2168,11 +2309,10 @@ var PerpDepositHandler = class {
|
|
|
2168
2309
|
aaNonce: request.aaNonce,
|
|
2169
2310
|
relayAddress,
|
|
2170
2311
|
request: depositReq,
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
gasFeePtRecipient: pafiFeeRecipient
|
|
2312
|
+
gasFeeUsdc: usdcGasFee,
|
|
2313
|
+
gasFeeUsdcRecipient: pafiFeeRecipient
|
|
2174
2314
|
});
|
|
2175
|
-
const fallbackOp =
|
|
2315
|
+
const fallbackOp = usdcGasFee > 0n ? (0, import_core9.buildPerpDepositViaRelay)({
|
|
2176
2316
|
userAddress: request.userAddress,
|
|
2177
2317
|
aaNonce: request.aaNonce,
|
|
2178
2318
|
relayAddress,
|
|
@@ -2181,7 +2321,7 @@ var PerpDepositHandler = class {
|
|
|
2181
2321
|
return {
|
|
2182
2322
|
userOp: sponsoredOp,
|
|
2183
2323
|
fallback: fallbackOp,
|
|
2184
|
-
feeAmount:
|
|
2324
|
+
feeAmount: usdcGasFee,
|
|
2185
2325
|
relayTokenFee,
|
|
2186
2326
|
maxFee,
|
|
2187
2327
|
netDeposit: request.amount - relayTokenFee,
|
|
@@ -2293,9 +2433,45 @@ function createSdkErrorMapper(factories) {
|
|
|
2293
2433
|
// src/api/issuerApiAdapter.ts
|
|
2294
2434
|
var import_viem10 = require("viem");
|
|
2295
2435
|
var import_core11 = require("@pafi-dev/core");
|
|
2436
|
+
var AdapterMisconfiguredError = class extends Error {
|
|
2437
|
+
code = "ADAPTER_MISCONFIGURED";
|
|
2438
|
+
constructor(message) {
|
|
2439
|
+
super(message);
|
|
2440
|
+
this.name = "AdapterMisconfiguredError";
|
|
2441
|
+
}
|
|
2442
|
+
};
|
|
2296
2443
|
var IssuerApiAdapter = class {
|
|
2297
2444
|
cfg;
|
|
2298
2445
|
constructor(config) {
|
|
2446
|
+
if (config.ptClaimHandler) {
|
|
2447
|
+
if (typeof config.ledger.bindMintUserOpHash !== "function") {
|
|
2448
|
+
throw new AdapterMisconfiguredError(
|
|
2449
|
+
"ledger.bindMintUserOpHash is required when ptClaimHandler is wired (mobile claim flow). Implement it on your IPointLedger or omit ptClaimHandler from IssuerApiAdapter config."
|
|
2450
|
+
);
|
|
2451
|
+
}
|
|
2452
|
+
if (typeof config.ledger.getMintLock !== "function") {
|
|
2453
|
+
throw new AdapterMisconfiguredError(
|
|
2454
|
+
"ledger.getMintLock is required when ptClaimHandler is wired \u2014 claimStatus uses it to look up the lock."
|
|
2455
|
+
);
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
if (config.ptRedeemHandler) {
|
|
2459
|
+
if (typeof config.ledger.reservePendingCredit !== "function") {
|
|
2460
|
+
throw new AdapterMisconfiguredError(
|
|
2461
|
+
"ledger.reservePendingCredit is required when ptRedeemHandler is wired (burn/redeem reverse flow). PTRedeemHandler also enforces this at construction; see ledger/types.ts comments."
|
|
2462
|
+
);
|
|
2463
|
+
}
|
|
2464
|
+
if (typeof config.ledger.bindCreditUserOpHash !== "function") {
|
|
2465
|
+
throw new AdapterMisconfiguredError(
|
|
2466
|
+
"ledger.bindCreditUserOpHash is required when ptRedeemHandler is wired (mobile redeem flow)."
|
|
2467
|
+
);
|
|
2468
|
+
}
|
|
2469
|
+
if (typeof config.ledger.getPendingCredit !== "function") {
|
|
2470
|
+
throw new AdapterMisconfiguredError(
|
|
2471
|
+
"ledger.getPendingCredit is required when ptRedeemHandler is wired \u2014 redeemStatus uses it to look up the credit."
|
|
2472
|
+
);
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2299
2475
|
this.cfg = config;
|
|
2300
2476
|
}
|
|
2301
2477
|
// ------------------------------ Read endpoints ---------------------------
|
|
@@ -2596,6 +2772,11 @@ var IssuerApiAdapter = class {
|
|
|
2596
2772
|
/**
|
|
2597
2773
|
* Build + sign a SponsorAuth payload. Returns `undefined` when no
|
|
2598
2774
|
* issuer id is configured, so the controller can skip the field.
|
|
2775
|
+
*
|
|
2776
|
+
* v0.7.1 — `scenario` typed as `SponsorshipScenario` (was `string`).
|
|
2777
|
+
* Previously a typo (`"perp_deposit"` vs `"perp-deposit"`) compiled
|
|
2778
|
+
* fine but rejected at L1 by sponsor-relayer's IntentValidator. See
|
|
2779
|
+
* SDK_ISSUER_AUDIT.md N5.
|
|
2599
2780
|
*/
|
|
2600
2781
|
async buildSponsorAuth(authenticatedAddress, callData, chainId, scenario) {
|
|
2601
2782
|
if (!this.cfg.pafiIssuerId) return void 0;
|
|
@@ -3056,41 +3237,6 @@ var BalanceAggregator = class {
|
|
|
3056
3237
|
}
|
|
3057
3238
|
};
|
|
3058
3239
|
|
|
3059
|
-
// src/pafi-backend/types.ts
|
|
3060
|
-
var PafiBackendError = class extends Error {
|
|
3061
|
-
constructor(code, message, httpStatus, details, opts) {
|
|
3062
|
-
super(message);
|
|
3063
|
-
this.code = code;
|
|
3064
|
-
this.httpStatus = httpStatus;
|
|
3065
|
-
this.details = details;
|
|
3066
|
-
this.name = "PafiBackendError";
|
|
3067
|
-
if (opts?.retryAfter !== void 0) this.retryAfter = opts.retryAfter;
|
|
3068
|
-
if (opts?.safeToRetry !== void 0) this.serverSafeToRetry = opts.safeToRetry;
|
|
3069
|
-
}
|
|
3070
|
-
code;
|
|
3071
|
-
httpStatus;
|
|
3072
|
-
details;
|
|
3073
|
-
retryAfter;
|
|
3074
|
-
serverSafeToRetry;
|
|
3075
|
-
get safeToRetry() {
|
|
3076
|
-
if (this.serverSafeToRetry !== void 0) return this.serverSafeToRetry;
|
|
3077
|
-
switch (this.code) {
|
|
3078
|
-
case "RATE_LIMITER_UNAVAILABLE":
|
|
3079
|
-
case "INTERNAL_ERROR":
|
|
3080
|
-
case "TIMEOUT":
|
|
3081
|
-
case "NETWORK_ERROR":
|
|
3082
|
-
return true;
|
|
3083
|
-
case "RATE_LIMIT_EXCEEDED":
|
|
3084
|
-
case "RATE_LIMIT_EXCEEDED_DAILY":
|
|
3085
|
-
case "RATE_LIMIT_EXCEEDED_PER_USER":
|
|
3086
|
-
case "ISSUER_BUDGET_EXCEEDED":
|
|
3087
|
-
return true;
|
|
3088
|
-
default:
|
|
3089
|
-
return false;
|
|
3090
|
-
}
|
|
3091
|
-
}
|
|
3092
|
-
};
|
|
3093
|
-
|
|
3094
3240
|
// src/pafi-backend/client.ts
|
|
3095
3241
|
function serializeBigInt(_key, value) {
|
|
3096
3242
|
return typeof value === "bigint" ? value.toString(10) : value;
|
|
@@ -3531,15 +3677,17 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
3531
3677
|
};
|
|
3532
3678
|
|
|
3533
3679
|
// src/index.ts
|
|
3534
|
-
var PAFI_ISSUER_SDK_VERSION = "0.
|
|
3680
|
+
var PAFI_ISSUER_SDK_VERSION = true ? "0.7.1" : "dev";
|
|
3535
3681
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3536
3682
|
0 && (module.exports = {
|
|
3683
|
+
AdapterMisconfiguredError,
|
|
3537
3684
|
AuthError,
|
|
3538
3685
|
AuthService,
|
|
3539
3686
|
BalanceAggregator,
|
|
3540
3687
|
BundlerNotConfiguredError,
|
|
3541
3688
|
BundlerRejectedError,
|
|
3542
3689
|
BurnIndexer,
|
|
3690
|
+
ConfigurationError,
|
|
3543
3691
|
DefaultPolicyEngine,
|
|
3544
3692
|
FeeManager,
|
|
3545
3693
|
InMemoryCursorStore,
|
|
@@ -3567,6 +3715,7 @@ var PAFI_ISSUER_SDK_VERSION = "0.4.0";
|
|
|
3567
3715
|
PointIndexer,
|
|
3568
3716
|
RelayError,
|
|
3569
3717
|
RelayService,
|
|
3718
|
+
ValidationError,
|
|
3570
3719
|
authenticateRequest,
|
|
3571
3720
|
createIssuerService,
|
|
3572
3721
|
createNativePtQuoter,
|