@pafi-dev/issuer 0.28.1 → 0.30.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 +66 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -2
- package/dist/index.d.ts +43 -2
- package/dist/index.js +66 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1884,6 +1884,27 @@ interface PTRedeemHandlerConfig {
|
|
|
1884
1884
|
* provisioning time. Typically HSM/KMS-backed in prod.
|
|
1885
1885
|
*/
|
|
1886
1886
|
burnerSignerWallet: WalletClient;
|
|
1887
|
+
/**
|
|
1888
|
+
* Issuer's allow-listed PointToken contracts (checksummed EIP-55).
|
|
1889
|
+
* Every `handle()` call validates the request's `pointTokenAddress`
|
|
1890
|
+
* against this set BEFORE any chain read, signer call, or pending
|
|
1891
|
+
* credit reservation.
|
|
1892
|
+
*
|
|
1893
|
+
* Audit PACI5-18 (redeem twin of the claim-side finding) — the read
|
|
1894
|
+
* surface (`IssuerApiHandlers.handleUser` / `handleRedemptionEvaluate`)
|
|
1895
|
+
* enforces this allowlist, but the write surface previously skipped
|
|
1896
|
+
* it. The asymmetry meant an issuer burner signer whitelisted on
|
|
1897
|
+
* multiple PointTokens could be coerced into signing a valid
|
|
1898
|
+
* `BurnRequest` for an off-allowlist token where no BurnIndexer is
|
|
1899
|
+
* running — the on-chain burn would succeed but the off-chain
|
|
1900
|
+
* pending credit would stay PENDING forever (or worse, resolve via
|
|
1901
|
+
* the bundler-receipt fallback against an unbacked credit balance).
|
|
1902
|
+
*
|
|
1903
|
+
* Pass the SAME set used to construct `IssuerApiHandlers` and
|
|
1904
|
+
* `PTClaimHandler` so the read, claim, and redeem paths agree on
|
|
1905
|
+
* what this issuer is willing to sign for.
|
|
1906
|
+
*/
|
|
1907
|
+
supportedTokens: ReadonlySet<Address>;
|
|
1887
1908
|
/**
|
|
1888
1909
|
* Optional — when wired, used to estimate the PT gas-reimbursement
|
|
1889
1910
|
* fee. The handler self-computes `feeAmount` + `feeRecipient` so the
|
|
@@ -1977,7 +1998,7 @@ interface PTRedeemResponse {
|
|
|
1977
1998
|
/** The BurnRequest deadline (unix seconds) — FE uses this to surface a countdown. */
|
|
1978
1999
|
signatureDeadline: bigint;
|
|
1979
2000
|
}
|
|
1980
|
-
type PTRedeemErrorCode = "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED" | "REDEMPTION_POLICY_DENIED";
|
|
2001
|
+
type PTRedeemErrorCode = "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED" | "REDEMPTION_POLICY_DENIED" | "UNSUPPORTED_POINT_TOKEN";
|
|
1981
2002
|
declare class PTRedeemError extends PafiSdkError {
|
|
1982
2003
|
readonly httpStatus: "unprocessable";
|
|
1983
2004
|
readonly code: PTRedeemErrorCode;
|
|
@@ -1995,6 +2016,7 @@ declare class PTRedeemHandler {
|
|
|
1995
2016
|
private readonly chainId;
|
|
1996
2017
|
private readonly domainResolver;
|
|
1997
2018
|
private readonly burnerSignerWallet;
|
|
2019
|
+
private readonly supportedTokens;
|
|
1998
2020
|
private readonly redeemLockDurationMs;
|
|
1999
2021
|
private readonly signatureDeadlineSeconds;
|
|
2000
2022
|
private readonly now;
|
|
@@ -2732,7 +2754,7 @@ interface IssuerStateValidatorLike {
|
|
|
2732
2754
|
* own composer — gg56 uses a timestamp-key 2D nonce). Caller layers
|
|
2733
2755
|
* paymaster sponsorship + sponsorAuth on top of the returned UserOps.
|
|
2734
2756
|
*/
|
|
2735
|
-
type PTClaimErrorCode = "INVALID_AMOUNT" | "VALIDATION_FAILED" | "BUILD_FAILED" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT";
|
|
2757
|
+
type PTClaimErrorCode = "INVALID_AMOUNT" | "VALIDATION_FAILED" | "BUILD_FAILED" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT" | "UNSUPPORTED_POINT_TOKEN";
|
|
2736
2758
|
declare class PTClaimError extends PafiSdkError {
|
|
2737
2759
|
readonly httpStatus: "unprocessable";
|
|
2738
2760
|
readonly code: PTClaimErrorCode;
|
|
@@ -2754,6 +2776,25 @@ interface PTClaimHandlerConfig {
|
|
|
2754
2776
|
* `chainId` + `pointTokenAddress` respectively.
|
|
2755
2777
|
*/
|
|
2756
2778
|
domainResolver: PointTokenDomainResolver;
|
|
2779
|
+
/**
|
|
2780
|
+
* Issuer's allow-listed PointToken contracts (checksummed EIP-55).
|
|
2781
|
+
* Every `handle()` call validates the request's `pointTokenAddress`
|
|
2782
|
+
* against this set BEFORE any chain read or signer call.
|
|
2783
|
+
*
|
|
2784
|
+
* Audit PACI5-18 — the read surface (`IssuerApiHandlers.handleUser`,
|
|
2785
|
+
* `handleRedemptionEvaluate`) enforces this allowlist, but the
|
|
2786
|
+
* write surface (claim/redeem) previously skipped it. The asymmetry
|
|
2787
|
+
* meant an issuer signer whitelisted as minter on PointTokens
|
|
2788
|
+
* outside the configured indexer set could be coerced into signing
|
|
2789
|
+
* a valid `MintForRequest` for an off-set token — the on-chain
|
|
2790
|
+
* mint would succeed, but no PointIndexer was watching to debit the
|
|
2791
|
+
* off-chain ledger. Silent supply-invariant violation.
|
|
2792
|
+
*
|
|
2793
|
+
* Pass the SAME set used to construct `IssuerApiHandlers` so the
|
|
2794
|
+
* read and write paths agree on what this issuer is willing to
|
|
2795
|
+
* sign for.
|
|
2796
|
+
*/
|
|
2797
|
+
supportedTokens: ReadonlySet<Address>;
|
|
2757
2798
|
/** Optional — when wired, used to estimate the PT gas-reimbursement fee. */
|
|
2758
2799
|
feeService?: FeeManager;
|
|
2759
2800
|
/** Optional — pre-validates issuer status + cap before locking balance. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1884,6 +1884,27 @@ interface PTRedeemHandlerConfig {
|
|
|
1884
1884
|
* provisioning time. Typically HSM/KMS-backed in prod.
|
|
1885
1885
|
*/
|
|
1886
1886
|
burnerSignerWallet: WalletClient;
|
|
1887
|
+
/**
|
|
1888
|
+
* Issuer's allow-listed PointToken contracts (checksummed EIP-55).
|
|
1889
|
+
* Every `handle()` call validates the request's `pointTokenAddress`
|
|
1890
|
+
* against this set BEFORE any chain read, signer call, or pending
|
|
1891
|
+
* credit reservation.
|
|
1892
|
+
*
|
|
1893
|
+
* Audit PACI5-18 (redeem twin of the claim-side finding) — the read
|
|
1894
|
+
* surface (`IssuerApiHandlers.handleUser` / `handleRedemptionEvaluate`)
|
|
1895
|
+
* enforces this allowlist, but the write surface previously skipped
|
|
1896
|
+
* it. The asymmetry meant an issuer burner signer whitelisted on
|
|
1897
|
+
* multiple PointTokens could be coerced into signing a valid
|
|
1898
|
+
* `BurnRequest` for an off-allowlist token where no BurnIndexer is
|
|
1899
|
+
* running — the on-chain burn would succeed but the off-chain
|
|
1900
|
+
* pending credit would stay PENDING forever (or worse, resolve via
|
|
1901
|
+
* the bundler-receipt fallback against an unbacked credit balance).
|
|
1902
|
+
*
|
|
1903
|
+
* Pass the SAME set used to construct `IssuerApiHandlers` and
|
|
1904
|
+
* `PTClaimHandler` so the read, claim, and redeem paths agree on
|
|
1905
|
+
* what this issuer is willing to sign for.
|
|
1906
|
+
*/
|
|
1907
|
+
supportedTokens: ReadonlySet<Address>;
|
|
1887
1908
|
/**
|
|
1888
1909
|
* Optional — when wired, used to estimate the PT gas-reimbursement
|
|
1889
1910
|
* fee. The handler self-computes `feeAmount` + `feeRecipient` so the
|
|
@@ -1977,7 +1998,7 @@ interface PTRedeemResponse {
|
|
|
1977
1998
|
/** The BurnRequest deadline (unix seconds) — FE uses this to surface a countdown. */
|
|
1978
1999
|
signatureDeadline: bigint;
|
|
1979
2000
|
}
|
|
1980
|
-
type PTRedeemErrorCode = "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED" | "REDEMPTION_POLICY_DENIED";
|
|
2001
|
+
type PTRedeemErrorCode = "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED" | "REDEMPTION_POLICY_DENIED" | "UNSUPPORTED_POINT_TOKEN";
|
|
1981
2002
|
declare class PTRedeemError extends PafiSdkError {
|
|
1982
2003
|
readonly httpStatus: "unprocessable";
|
|
1983
2004
|
readonly code: PTRedeemErrorCode;
|
|
@@ -1995,6 +2016,7 @@ declare class PTRedeemHandler {
|
|
|
1995
2016
|
private readonly chainId;
|
|
1996
2017
|
private readonly domainResolver;
|
|
1997
2018
|
private readonly burnerSignerWallet;
|
|
2019
|
+
private readonly supportedTokens;
|
|
1998
2020
|
private readonly redeemLockDurationMs;
|
|
1999
2021
|
private readonly signatureDeadlineSeconds;
|
|
2000
2022
|
private readonly now;
|
|
@@ -2732,7 +2754,7 @@ interface IssuerStateValidatorLike {
|
|
|
2732
2754
|
* own composer — gg56 uses a timestamp-key 2D nonce). Caller layers
|
|
2733
2755
|
* paymaster sponsorship + sponsorAuth on top of the returned UserOps.
|
|
2734
2756
|
*/
|
|
2735
|
-
type PTClaimErrorCode = "INVALID_AMOUNT" | "VALIDATION_FAILED" | "BUILD_FAILED" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT";
|
|
2757
|
+
type PTClaimErrorCode = "INVALID_AMOUNT" | "VALIDATION_FAILED" | "BUILD_FAILED" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT" | "UNSUPPORTED_POINT_TOKEN";
|
|
2736
2758
|
declare class PTClaimError extends PafiSdkError {
|
|
2737
2759
|
readonly httpStatus: "unprocessable";
|
|
2738
2760
|
readonly code: PTClaimErrorCode;
|
|
@@ -2754,6 +2776,25 @@ interface PTClaimHandlerConfig {
|
|
|
2754
2776
|
* `chainId` + `pointTokenAddress` respectively.
|
|
2755
2777
|
*/
|
|
2756
2778
|
domainResolver: PointTokenDomainResolver;
|
|
2779
|
+
/**
|
|
2780
|
+
* Issuer's allow-listed PointToken contracts (checksummed EIP-55).
|
|
2781
|
+
* Every `handle()` call validates the request's `pointTokenAddress`
|
|
2782
|
+
* against this set BEFORE any chain read or signer call.
|
|
2783
|
+
*
|
|
2784
|
+
* Audit PACI5-18 — the read surface (`IssuerApiHandlers.handleUser`,
|
|
2785
|
+
* `handleRedemptionEvaluate`) enforces this allowlist, but the
|
|
2786
|
+
* write surface (claim/redeem) previously skipped it. The asymmetry
|
|
2787
|
+
* meant an issuer signer whitelisted as minter on PointTokens
|
|
2788
|
+
* outside the configured indexer set could be coerced into signing
|
|
2789
|
+
* a valid `MintForRequest` for an off-set token — the on-chain
|
|
2790
|
+
* mint would succeed, but no PointIndexer was watching to debit the
|
|
2791
|
+
* off-chain ledger. Silent supply-invariant violation.
|
|
2792
|
+
*
|
|
2793
|
+
* Pass the SAME set used to construct `IssuerApiHandlers` so the
|
|
2794
|
+
* read and write paths agree on what this issuer is willing to
|
|
2795
|
+
* sign for.
|
|
2796
|
+
*/
|
|
2797
|
+
supportedTokens: ReadonlySet<Address>;
|
|
2757
2798
|
/** Optional — when wired, used to estimate the PT gas-reimbursement fee. */
|
|
2758
2799
|
feeService?: FeeManager;
|
|
2759
2800
|
/** Optional — pre-validates issuer status + cap before locking balance. */
|
package/dist/index.js
CHANGED
|
@@ -2108,6 +2108,7 @@ var PTRedeemHandler = class {
|
|
|
2108
2108
|
chainId;
|
|
2109
2109
|
domainResolver;
|
|
2110
2110
|
burnerSignerWallet;
|
|
2111
|
+
supportedTokens;
|
|
2111
2112
|
redeemLockDurationMs;
|
|
2112
2113
|
signatureDeadlineSeconds;
|
|
2113
2114
|
now;
|
|
@@ -2147,6 +2148,13 @@ var PTRedeemHandler = class {
|
|
|
2147
2148
|
this.chainId = config.chainId;
|
|
2148
2149
|
this.domainResolver = config.domainResolver;
|
|
2149
2150
|
this.burnerSignerWallet = config.burnerSignerWallet;
|
|
2151
|
+
if (!config.supportedTokens) {
|
|
2152
|
+
throw new PTRedeemError(
|
|
2153
|
+
"UNSUPPORTED_POINT_TOKEN",
|
|
2154
|
+
"PTRedeemHandler requires `supportedTokens` (issuer's allow-listed PointToken contracts). See audit PACI5-18."
|
|
2155
|
+
);
|
|
2156
|
+
}
|
|
2157
|
+
this.supportedTokens = config.supportedTokens;
|
|
2150
2158
|
if (this.burnerSignerWallet?.account?.type === "local") {
|
|
2151
2159
|
console.warn("[PAFI] PTRedeemHandler: burnerSignerWallet uses a local (private key) account. Use a KMS-backed signer in production.");
|
|
2152
2160
|
}
|
|
@@ -2175,6 +2183,12 @@ var PTRedeemHandler = class {
|
|
|
2175
2183
|
throw new PTRedeemError("INVALID_AMOUNT", "redeem amount must be positive");
|
|
2176
2184
|
}
|
|
2177
2185
|
const pointTokenAddress = getAddress7(request.pointTokenAddress);
|
|
2186
|
+
if (!this.supportedTokens.has(pointTokenAddress)) {
|
|
2187
|
+
throw new PTRedeemError(
|
|
2188
|
+
"UNSUPPORTED_POINT_TOKEN",
|
|
2189
|
+
`redeem: pointTokenAddress ${pointTokenAddress} is not in the issuer's supported-token allowlist. Check IssuerApiHandlers.supportedTokens and PTRedeemHandler.config.supportedTokens point at the same set.`
|
|
2190
|
+
);
|
|
2191
|
+
}
|
|
2178
2192
|
if (this.redemptionService) {
|
|
2179
2193
|
const decision = await this.redemptionService.evaluate(
|
|
2180
2194
|
request.userAddress,
|
|
@@ -2424,13 +2438,43 @@ async function handleClaimStatus(params) {
|
|
|
2424
2438
|
lock.userOpHash
|
|
2425
2439
|
);
|
|
2426
2440
|
if (receipt) {
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2441
|
+
if (receipt.success && receipt.txHash) {
|
|
2442
|
+
if (!lock.tokenAddress) {
|
|
2443
|
+
params.onWarning?.(
|
|
2444
|
+
`handleClaimStatus: lock ${lock.lockId} has no tokenAddress; falling back to status-only flip (PACI5-24 defence degraded). Migrate the ledger to the multi-token schema.`
|
|
2445
|
+
);
|
|
2446
|
+
await params.ledger.updateMintStatus(lock.lockId, "MINTED", receipt.txHash).catch((err) => {
|
|
2447
|
+
params.onWarning?.(
|
|
2448
|
+
`handleClaimStatus: ledger updateMintStatus failed for lock ${lock.lockId}: ${err}`
|
|
2449
|
+
);
|
|
2450
|
+
});
|
|
2451
|
+
status = "MINTED";
|
|
2452
|
+
txHash = receipt.txHash;
|
|
2453
|
+
} else {
|
|
2454
|
+
try {
|
|
2455
|
+
await params.ledger.deductBalance(
|
|
2456
|
+
lock.userAddress,
|
|
2457
|
+
lock.amount,
|
|
2458
|
+
receipt.txHash,
|
|
2459
|
+
lock.tokenAddress
|
|
2460
|
+
);
|
|
2461
|
+
status = "MINTED";
|
|
2462
|
+
txHash = receipt.txHash;
|
|
2463
|
+
} catch (deductErr) {
|
|
2464
|
+
params.onWarning?.(
|
|
2465
|
+
`handleClaimStatus: deductBalance failed for lock ${lock.lockId}: ${deductErr}`
|
|
2466
|
+
);
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
} else {
|
|
2470
|
+
await params.ledger.updateMintStatus(lock.lockId, "FAILED", receipt.txHash).catch((err) => {
|
|
2471
|
+
params.onWarning?.(
|
|
2472
|
+
`handleClaimStatus: ledger updateMintStatus failed for lock ${lock.lockId}: ${err}`
|
|
2473
|
+
);
|
|
2474
|
+
});
|
|
2475
|
+
status = "FAILED";
|
|
2476
|
+
txHash = receipt.txHash;
|
|
2477
|
+
}
|
|
2434
2478
|
}
|
|
2435
2479
|
} catch (err) {
|
|
2436
2480
|
params.onWarning?.(
|
|
@@ -2912,6 +2956,12 @@ var PTClaimHandler = class {
|
|
|
2912
2956
|
cfg;
|
|
2913
2957
|
inFlightNonces = /* @__PURE__ */ new Map();
|
|
2914
2958
|
constructor(config) {
|
|
2959
|
+
if (!config.supportedTokens) {
|
|
2960
|
+
throw new PTClaimError(
|
|
2961
|
+
"UNSUPPORTED_POINT_TOKEN",
|
|
2962
|
+
"PTClaimHandler requires `supportedTokens` (issuer's allow-listed PointToken contracts). See audit PACI5-18."
|
|
2963
|
+
);
|
|
2964
|
+
}
|
|
2915
2965
|
const lockDurationMs = config.lockDurationMs ?? DEFAULT_LOCK_MS;
|
|
2916
2966
|
const signatureDeadlineSeconds = config.signatureDeadlineSeconds ?? DEFAULT_SIG_DEADLINE_SEC2;
|
|
2917
2967
|
const maxAllowedSignatureMs = lockDurationMs - M11_SAFETY_MARGIN_MS2;
|
|
@@ -2943,6 +2993,14 @@ var PTClaimHandler = class {
|
|
|
2943
2993
|
if (request.amount <= 0n) {
|
|
2944
2994
|
throw new PTClaimError("INVALID_AMOUNT", "claim amount must be positive");
|
|
2945
2995
|
}
|
|
2996
|
+
const pointTokenAddress = getAddress9(request.pointTokenAddress);
|
|
2997
|
+
if (!this.cfg.supportedTokens.has(pointTokenAddress)) {
|
|
2998
|
+
throw new PTClaimError(
|
|
2999
|
+
"UNSUPPORTED_POINT_TOKEN",
|
|
3000
|
+
`claim: pointTokenAddress ${pointTokenAddress} is not in the issuer's supported-token allowlist. Check IssuerApiHandlers.supportedTokens and PTClaimHandler.config.supportedTokens point at the same set.`,
|
|
3001
|
+
{ requested: pointTokenAddress }
|
|
3002
|
+
);
|
|
3003
|
+
}
|
|
2946
3004
|
if (this.cfg.issuerStateValidator) {
|
|
2947
3005
|
try {
|
|
2948
3006
|
await this.cfg.issuerStateValidator.preValidateMint(
|
|
@@ -5029,7 +5087,7 @@ var MemoryRedemptionHistoryStore = class {
|
|
|
5029
5087
|
};
|
|
5030
5088
|
|
|
5031
5089
|
// src/index.ts
|
|
5032
|
-
var PAFI_ISSUER_SDK_VERSION = true ? "0.
|
|
5090
|
+
var PAFI_ISSUER_SDK_VERSION = true ? "0.30.0" : "dev";
|
|
5033
5091
|
export {
|
|
5034
5092
|
AdapterMisconfiguredError,
|
|
5035
5093
|
AuthError,
|