@pafi-dev/issuer 0.5.15 → 0.5.17
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 +70 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -2
- package/dist/index.d.ts +22 -2
- package/dist/index.js +70 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1129,10 +1129,30 @@ interface PTRedeemRequest {
|
|
|
1129
1129
|
feeRecipient?: Address;
|
|
1130
1130
|
}
|
|
1131
1131
|
interface PTRedeemResponse {
|
|
1132
|
-
/**
|
|
1132
|
+
/**
|
|
1133
|
+
* Sponsored path — UserOp with PT fee transfer. BurnRequest signed for
|
|
1134
|
+
* `request.amount - feeAmount`. User holds exactly `request.amount` PT
|
|
1135
|
+
* and the fee comes out of the redeem amount, NOT on top.
|
|
1136
|
+
*/
|
|
1133
1137
|
lockId: string;
|
|
1134
|
-
/** Unsigned UserOp — FE attaches paymaster + user signature + submits. */
|
|
1135
1138
|
userOp: PartialUserOperation;
|
|
1139
|
+
/** = request.amount - feeAmount. What BurnIndexer credits off-chain on sponsored fire. */
|
|
1140
|
+
netCreditAmount: bigint;
|
|
1141
|
+
/**
|
|
1142
|
+
* Fallback path — UserOp with NO fee transfer. BurnRequest signed for
|
|
1143
|
+
* full `request.amount`. User pays gas in ETH directly. Present only
|
|
1144
|
+
* when `feeAmount > 0`.
|
|
1145
|
+
*
|
|
1146
|
+
* Same nonce as sponsored: only one of the two can fire on-chain;
|
|
1147
|
+
* the other lock auto-expires after `expiresInSeconds`. BurnIndexer
|
|
1148
|
+
* matches by burn amount and resolves the correct lock.
|
|
1149
|
+
*/
|
|
1150
|
+
fallback?: {
|
|
1151
|
+
lockId: string;
|
|
1152
|
+
userOp: PartialUserOperation;
|
|
1153
|
+
/** = request.amount. Full credit when fallback fires. */
|
|
1154
|
+
netCreditAmount: bigint;
|
|
1155
|
+
};
|
|
1136
1156
|
/** Seconds until the lock expires if the burn doesn't land. */
|
|
1137
1157
|
expiresInSeconds: number;
|
|
1138
1158
|
/** The BurnRequest deadline (unix seconds) — FE uses this to surface a countdown. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1129,10 +1129,30 @@ interface PTRedeemRequest {
|
|
|
1129
1129
|
feeRecipient?: Address;
|
|
1130
1130
|
}
|
|
1131
1131
|
interface PTRedeemResponse {
|
|
1132
|
-
/**
|
|
1132
|
+
/**
|
|
1133
|
+
* Sponsored path — UserOp with PT fee transfer. BurnRequest signed for
|
|
1134
|
+
* `request.amount - feeAmount`. User holds exactly `request.amount` PT
|
|
1135
|
+
* and the fee comes out of the redeem amount, NOT on top.
|
|
1136
|
+
*/
|
|
1133
1137
|
lockId: string;
|
|
1134
|
-
/** Unsigned UserOp — FE attaches paymaster + user signature + submits. */
|
|
1135
1138
|
userOp: PartialUserOperation;
|
|
1139
|
+
/** = request.amount - feeAmount. What BurnIndexer credits off-chain on sponsored fire. */
|
|
1140
|
+
netCreditAmount: bigint;
|
|
1141
|
+
/**
|
|
1142
|
+
* Fallback path — UserOp with NO fee transfer. BurnRequest signed for
|
|
1143
|
+
* full `request.amount`. User pays gas in ETH directly. Present only
|
|
1144
|
+
* when `feeAmount > 0`.
|
|
1145
|
+
*
|
|
1146
|
+
* Same nonce as sponsored: only one of the two can fire on-chain;
|
|
1147
|
+
* the other lock auto-expires after `expiresInSeconds`. BurnIndexer
|
|
1148
|
+
* matches by burn amount and resolves the correct lock.
|
|
1149
|
+
*/
|
|
1150
|
+
fallback?: {
|
|
1151
|
+
lockId: string;
|
|
1152
|
+
userOp: PartialUserOperation;
|
|
1153
|
+
/** = request.amount. Full credit when fallback fires. */
|
|
1154
|
+
netCreditAmount: bigint;
|
|
1155
|
+
};
|
|
1136
1156
|
/** Seconds until the lock expires if the burn doesn't land. */
|
|
1137
1157
|
expiresInSeconds: number;
|
|
1138
1158
|
/** The BurnRequest deadline (unix seconds) — FE uses this to surface a countdown. */
|
package/dist/index.js
CHANGED
|
@@ -560,13 +560,7 @@ var RelayService = class {
|
|
|
560
560
|
err
|
|
561
561
|
);
|
|
562
562
|
}
|
|
563
|
-
const operations = [
|
|
564
|
-
{
|
|
565
|
-
target: params.pointTokenAddress,
|
|
566
|
-
value: 0n,
|
|
567
|
-
data: burnCallData
|
|
568
|
-
}
|
|
569
|
-
];
|
|
563
|
+
const operations = [];
|
|
570
564
|
if (params.feeAmount && params.feeAmount > 0n) {
|
|
571
565
|
if (!params.feeRecipient) {
|
|
572
566
|
throw new RelayError(
|
|
@@ -590,6 +584,11 @@ var RelayService = class {
|
|
|
590
584
|
})
|
|
591
585
|
});
|
|
592
586
|
}
|
|
587
|
+
operations.push({
|
|
588
|
+
target: params.pointTokenAddress,
|
|
589
|
+
value: 0n,
|
|
590
|
+
data: burnCallData
|
|
591
|
+
});
|
|
593
592
|
return buildPartialUserOperation({
|
|
594
593
|
sender: params.userAddress,
|
|
595
594
|
nonce: params.aaNonce,
|
|
@@ -1373,16 +1372,22 @@ var PTRedeemHandler = class {
|
|
|
1373
1372
|
}
|
|
1374
1373
|
}
|
|
1375
1374
|
async _handleAfterNonceLock(request, burnNonce) {
|
|
1375
|
+
const fee = request.feeAmount && request.feeAmount > 0n ? request.feeAmount : 0n;
|
|
1376
|
+
if (fee > 0n && fee >= request.amount) {
|
|
1377
|
+
throw new PTRedeemError(
|
|
1378
|
+
"INVALID_AMOUNT",
|
|
1379
|
+
`fee (${fee}) must be strictly less than redeem amount (${request.amount})`
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1376
1382
|
const onChainBalance = await getPointTokenBalance2(
|
|
1377
1383
|
this.provider,
|
|
1378
1384
|
this.pointTokenAddress,
|
|
1379
1385
|
request.userAddress
|
|
1380
1386
|
);
|
|
1381
|
-
|
|
1382
|
-
if (onChainBalance < totalRequired) {
|
|
1387
|
+
if (onChainBalance < request.amount) {
|
|
1383
1388
|
throw new PTRedeemError(
|
|
1384
1389
|
"INVALID_AMOUNT",
|
|
1385
|
-
`insufficient on-chain PT balance: have ${onChainBalance}, need ${
|
|
1390
|
+
`insufficient on-chain PT balance: have ${onChainBalance}, need ${request.amount}`
|
|
1386
1391
|
);
|
|
1387
1392
|
}
|
|
1388
1393
|
const deadline = BigInt(
|
|
@@ -1393,46 +1398,83 @@ var PTRedeemHandler = class {
|
|
|
1393
1398
|
chainId: this.chainId,
|
|
1394
1399
|
verifyingContract: this.domain.verifyingContract ?? this.pointTokenAddress
|
|
1395
1400
|
};
|
|
1396
|
-
const
|
|
1401
|
+
const sponsoredBurnAmount = request.amount - fee;
|
|
1402
|
+
const sponsoredBurnRequest = {
|
|
1397
1403
|
from: request.userAddress,
|
|
1398
|
-
amount:
|
|
1404
|
+
amount: sponsoredBurnAmount,
|
|
1399
1405
|
nonce: burnNonce,
|
|
1400
1406
|
deadline
|
|
1401
1407
|
};
|
|
1402
|
-
let
|
|
1408
|
+
let sponsoredSig;
|
|
1403
1409
|
try {
|
|
1404
|
-
|
|
1405
|
-
this.burnerSignerWallet,
|
|
1406
|
-
domain,
|
|
1407
|
-
burnRequest
|
|
1408
|
-
);
|
|
1409
|
-
burnerSignature = sig.serialized;
|
|
1410
|
+
sponsoredSig = (await signBurnRequest(this.burnerSignerWallet, domain, sponsoredBurnRequest)).serialized;
|
|
1410
1411
|
} catch (err) {
|
|
1411
1412
|
throw new PTRedeemError(
|
|
1412
1413
|
"SIGNING_FAILED",
|
|
1413
|
-
`failed to sign BurnRequest: ${err instanceof Error ? err.message : String(err)}`
|
|
1414
|
+
`failed to sign sponsored BurnRequest: ${err instanceof Error ? err.message : String(err)}`
|
|
1414
1415
|
);
|
|
1415
1416
|
}
|
|
1416
|
-
const
|
|
1417
|
+
const sponsoredLockId = await this.ledger.reservePendingCredit(
|
|
1417
1418
|
request.userAddress,
|
|
1418
|
-
|
|
1419
|
+
sponsoredBurnAmount,
|
|
1419
1420
|
this.redeemLockDurationMs,
|
|
1420
1421
|
this.pointTokenAddress
|
|
1421
1422
|
);
|
|
1422
|
-
const
|
|
1423
|
+
const sponsoredUserOp = this.relayService.prepareBurn({
|
|
1423
1424
|
mode: "burnWithSig",
|
|
1424
1425
|
userAddress: request.userAddress,
|
|
1425
1426
|
aaNonce: request.aaNonce,
|
|
1426
1427
|
pointTokenAddress: this.pointTokenAddress,
|
|
1427
1428
|
batchExecutorAddress: this.batchExecutorAddress,
|
|
1428
|
-
burnRequest,
|
|
1429
|
-
burnerSignature,
|
|
1430
|
-
feeAmount:
|
|
1429
|
+
burnRequest: sponsoredBurnRequest,
|
|
1430
|
+
burnerSignature: sponsoredSig,
|
|
1431
|
+
feeAmount: fee,
|
|
1431
1432
|
feeRecipient: request.feeRecipient
|
|
1432
1433
|
});
|
|
1434
|
+
let fallback = void 0;
|
|
1435
|
+
if (fee > 0n) {
|
|
1436
|
+
const fallbackBurnRequest = {
|
|
1437
|
+
from: request.userAddress,
|
|
1438
|
+
amount: request.amount,
|
|
1439
|
+
nonce: burnNonce,
|
|
1440
|
+
deadline
|
|
1441
|
+
};
|
|
1442
|
+
let fallbackSig;
|
|
1443
|
+
try {
|
|
1444
|
+
fallbackSig = (await signBurnRequest(this.burnerSignerWallet, domain, fallbackBurnRequest)).serialized;
|
|
1445
|
+
} catch (err) {
|
|
1446
|
+
throw new PTRedeemError(
|
|
1447
|
+
"SIGNING_FAILED",
|
|
1448
|
+
`failed to sign fallback BurnRequest: ${err instanceof Error ? err.message : String(err)}`
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
const fallbackLockId = await this.ledger.reservePendingCredit(
|
|
1452
|
+
request.userAddress,
|
|
1453
|
+
request.amount,
|
|
1454
|
+
this.redeemLockDurationMs,
|
|
1455
|
+
this.pointTokenAddress
|
|
1456
|
+
);
|
|
1457
|
+
const fallbackUserOp = this.relayService.prepareBurn({
|
|
1458
|
+
mode: "burnWithSig",
|
|
1459
|
+
userAddress: request.userAddress,
|
|
1460
|
+
aaNonce: request.aaNonce,
|
|
1461
|
+
pointTokenAddress: this.pointTokenAddress,
|
|
1462
|
+
batchExecutorAddress: this.batchExecutorAddress,
|
|
1463
|
+
burnRequest: fallbackBurnRequest,
|
|
1464
|
+
burnerSignature: fallbackSig
|
|
1465
|
+
// No feeAmount/feeRecipient — fallback is fee-free.
|
|
1466
|
+
});
|
|
1467
|
+
fallback = {
|
|
1468
|
+
lockId: fallbackLockId,
|
|
1469
|
+
userOp: fallbackUserOp,
|
|
1470
|
+
netCreditAmount: request.amount
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1433
1473
|
return {
|
|
1434
|
-
lockId,
|
|
1435
|
-
userOp,
|
|
1474
|
+
lockId: sponsoredLockId,
|
|
1475
|
+
userOp: sponsoredUserOp,
|
|
1476
|
+
netCreditAmount: sponsoredBurnAmount,
|
|
1477
|
+
fallback,
|
|
1436
1478
|
expiresInSeconds: Math.floor(this.redeemLockDurationMs / 1e3),
|
|
1437
1479
|
signatureDeadline: deadline
|
|
1438
1480
|
};
|