@pafi-dev/issuer 0.31.0 → 0.33.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 +150 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -10
- package/dist/index.d.ts +62 -10
- package/dist/index.js +142 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -2414,11 +2414,23 @@ var PTRedeemHandler = class {
|
|
|
2414
2414
|
);
|
|
2415
2415
|
}
|
|
2416
2416
|
if (this.redemptionService) {
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2417
|
+
let decision;
|
|
2418
|
+
try {
|
|
2419
|
+
decision = await this.redemptionService.evaluate(
|
|
2420
|
+
request.userAddress,
|
|
2421
|
+
request.amount,
|
|
2422
|
+
pointTokenAddress
|
|
2423
|
+
);
|
|
2424
|
+
} catch (err) {
|
|
2425
|
+
const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
|
|
2426
|
+
if (code === "POLICY_PROVIDER_UNAVAILABLE") {
|
|
2427
|
+
throw new PTRedeemError(
|
|
2428
|
+
"REDEMPTION_POLICY_UNAVAILABLE",
|
|
2429
|
+
"Redemption policy temporarily unavailable \u2014 please try again shortly."
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
throw err;
|
|
2433
|
+
}
|
|
2422
2434
|
if (!decision.allowed) {
|
|
2423
2435
|
const denial = decision.denial;
|
|
2424
2436
|
throw new PTRedeemError(
|
|
@@ -2634,6 +2646,45 @@ var PTRedeemHandler = class {
|
|
|
2634
2646
|
};
|
|
2635
2647
|
|
|
2636
2648
|
// src/api/statusHandlers.ts
|
|
2649
|
+
var DEFAULT_STATUS_CONFIRMATIONS = 3;
|
|
2650
|
+
async function isReceiptPastConfirmations(receipt, provider, confirmations, onWarning, handlerName) {
|
|
2651
|
+
if (!provider) {
|
|
2652
|
+
onWarning?.(
|
|
2653
|
+
`${handlerName}: provider missing \u2014 cannot enforce confirmation depth; deferring receipt fallback to on-chain indexer (audit PACI5-13).`
|
|
2654
|
+
);
|
|
2655
|
+
return false;
|
|
2656
|
+
}
|
|
2657
|
+
if (!receipt.blockNumber) {
|
|
2658
|
+
onWarning?.(
|
|
2659
|
+
`${handlerName}: receipt has no blockNumber \u2014 cannot enforce confirmation depth; deferring to indexer (audit PACI5-13).`
|
|
2660
|
+
);
|
|
2661
|
+
return false;
|
|
2662
|
+
}
|
|
2663
|
+
const requiredConfs = BigInt(confirmations ?? DEFAULT_STATUS_CONFIRMATIONS);
|
|
2664
|
+
let receiptBlock;
|
|
2665
|
+
try {
|
|
2666
|
+
receiptBlock = BigInt(receipt.blockNumber);
|
|
2667
|
+
} catch {
|
|
2668
|
+
onWarning?.(
|
|
2669
|
+
`${handlerName}: malformed receipt blockNumber (${receipt.blockNumber}) \u2014 deferring to indexer (audit PACI5-13).`
|
|
2670
|
+
);
|
|
2671
|
+
return false;
|
|
2672
|
+
}
|
|
2673
|
+
let head;
|
|
2674
|
+
try {
|
|
2675
|
+
head = await provider.getBlockNumber();
|
|
2676
|
+
} catch (err) {
|
|
2677
|
+
onWarning?.(
|
|
2678
|
+
`${handlerName}: getBlockNumber failed (${err instanceof Error ? err.message : String(err)}) \u2014 deferring to indexer (audit PACI5-13).`
|
|
2679
|
+
);
|
|
2680
|
+
return false;
|
|
2681
|
+
}
|
|
2682
|
+
const depth = head - receiptBlock;
|
|
2683
|
+
if (depth < requiredConfs) {
|
|
2684
|
+
return false;
|
|
2685
|
+
}
|
|
2686
|
+
return true;
|
|
2687
|
+
}
|
|
2637
2688
|
var LockNotFoundError = class extends import_core.PafiSdkError {
|
|
2638
2689
|
code = "LOCK_NOT_FOUND";
|
|
2639
2690
|
httpStatus = "not_found";
|
|
@@ -2662,6 +2713,23 @@ async function handleClaimStatus(params) {
|
|
|
2662
2713
|
lock.userOpHash
|
|
2663
2714
|
);
|
|
2664
2715
|
if (receipt) {
|
|
2716
|
+
const passesConfirmationDepth = await isReceiptPastConfirmations(
|
|
2717
|
+
receipt,
|
|
2718
|
+
params.provider,
|
|
2719
|
+
params.confirmations,
|
|
2720
|
+
params.onWarning,
|
|
2721
|
+
"handleClaimStatus"
|
|
2722
|
+
);
|
|
2723
|
+
if (!passesConfirmationDepth) {
|
|
2724
|
+
return {
|
|
2725
|
+
lockId: lock.lockId,
|
|
2726
|
+
status: "PENDING",
|
|
2727
|
+
txHash: lock.txHash ?? null,
|
|
2728
|
+
amount: lock.amount.toString(),
|
|
2729
|
+
createdAt: new Date(lock.createdAt).toISOString(),
|
|
2730
|
+
expiresAt: new Date(lock.expiresAt).toISOString()
|
|
2731
|
+
};
|
|
2732
|
+
}
|
|
2665
2733
|
if (receipt.success && receipt.txHash) {
|
|
2666
2734
|
if (!lock.tokenAddress) {
|
|
2667
2735
|
params.onWarning?.(
|
|
@@ -2736,14 +2804,23 @@ async function handleRedeemStatus(params) {
|
|
|
2736
2804
|
credit.userOpHash
|
|
2737
2805
|
);
|
|
2738
2806
|
if (receipt && receipt.success) {
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2807
|
+
const passesConfirmationDepth = await isReceiptPastConfirmations(
|
|
2808
|
+
receipt,
|
|
2809
|
+
params.provider,
|
|
2810
|
+
params.confirmations,
|
|
2811
|
+
params.onWarning,
|
|
2812
|
+
"handleRedeemStatus"
|
|
2813
|
+
);
|
|
2814
|
+
if (passesConfirmationDepth) {
|
|
2815
|
+
status = "RESOLVED";
|
|
2816
|
+
txHash = receipt.txHash;
|
|
2817
|
+
if (params.ledger.resolveCreditByBurnTx) {
|
|
2818
|
+
await params.ledger.resolveCreditByBurnTx(credit.lockId, receipt.txHash).catch((err) => {
|
|
2819
|
+
params.onWarning?.(
|
|
2820
|
+
`handleRedeemStatus: resolveCreditByBurnTx failed for lock ${credit.lockId}: ${err}`
|
|
2821
|
+
);
|
|
2822
|
+
});
|
|
2823
|
+
}
|
|
2747
2824
|
}
|
|
2748
2825
|
}
|
|
2749
2826
|
} catch (err) {
|
|
@@ -3872,10 +3949,6 @@ var IssuerApiAdapter = class {
|
|
|
3872
3949
|
pointTokenAddress,
|
|
3873
3950
|
redeemResponse.expiresInSeconds,
|
|
3874
3951
|
input.eip7702Auth,
|
|
3875
|
-
// Audit PACI5-21 — fallback path reserves a separate
|
|
3876
|
-
// PendingCredit row for the full `amount`. Surface its lockId so
|
|
3877
|
-
// mobile FE can poll the correct row + `handleMobileSubmit`
|
|
3878
|
-
// routes the userOpHash bind to it on fallback submit.
|
|
3879
3952
|
redeemResponse.fallback?.lockId
|
|
3880
3953
|
);
|
|
3881
3954
|
return {
|
|
@@ -3911,6 +3984,9 @@ var IssuerApiAdapter = class {
|
|
|
3911
3984
|
userAddress: authenticatedAddress,
|
|
3912
3985
|
ledger: this.cfg.ledger,
|
|
3913
3986
|
pafiBackendClient: this.cfg.pafiBackendClient,
|
|
3987
|
+
// Audit PACI5-13 — pass the same provider the indexers use so
|
|
3988
|
+
// the receipt fallback gates on the same reorg depth.
|
|
3989
|
+
provider: this.cfg.provider,
|
|
3914
3990
|
onWarning: this.cfg.onWarning
|
|
3915
3991
|
});
|
|
3916
3992
|
}
|
|
@@ -3920,6 +3996,8 @@ var IssuerApiAdapter = class {
|
|
|
3920
3996
|
userAddress: authenticatedAddress,
|
|
3921
3997
|
ledger: this.cfg.ledger,
|
|
3922
3998
|
pafiBackendClient: this.cfg.pafiBackendClient,
|
|
3999
|
+
// Audit PACI5-13 — see claimStatus comment.
|
|
4000
|
+
provider: this.cfg.provider,
|
|
3923
4001
|
onWarning: this.cfg.onWarning
|
|
3924
4002
|
});
|
|
3925
4003
|
}
|
|
@@ -4454,7 +4532,9 @@ var PafiBackendClient = class {
|
|
|
4454
4532
|
if (!config.issuerId) throw new Error("PafiBackendClient: issuerId is required");
|
|
4455
4533
|
if (!config.apiKey) throw new Error("PafiBackendClient: apiKey is required");
|
|
4456
4534
|
this.config = config;
|
|
4457
|
-
this.baseUrl = (0, import_core16.getPafiServiceUrls)(config.chainId
|
|
4535
|
+
this.baseUrl = (0, import_core16.getPafiServiceUrls)(config.chainId, {
|
|
4536
|
+
sponsorRelayer: config.baseUrl
|
|
4537
|
+
}).sponsorRelayer;
|
|
4458
4538
|
}
|
|
4459
4539
|
async requestSponsorship(request) {
|
|
4460
4540
|
const maxAttempts = this.config.retry?.maxAttempts ?? 1;
|
|
@@ -4615,7 +4695,7 @@ var PafiBackendClient = class {
|
|
|
4615
4695
|
|
|
4616
4696
|
// src/config.ts
|
|
4617
4697
|
var import_viem15 = require("viem");
|
|
4618
|
-
var
|
|
4698
|
+
var import_core19 = require("@pafi-dev/core");
|
|
4619
4699
|
|
|
4620
4700
|
// src/redemption/evaluator.ts
|
|
4621
4701
|
var SECONDS_PER_DAY = 24 * 60 * 60;
|
|
@@ -4719,6 +4799,9 @@ function nextBlackoutEndAfter(windows, nowUnixSec) {
|
|
|
4719
4799
|
}
|
|
4720
4800
|
var REDEMPTION_HISTORY_WINDOW_SEC = SECONDS_PER_DAY;
|
|
4721
4801
|
|
|
4802
|
+
// src/redemption/policyProvider.ts
|
|
4803
|
+
var import_core18 = require("@pafi-dev/core");
|
|
4804
|
+
|
|
4722
4805
|
// src/redemption/settlementClient.ts
|
|
4723
4806
|
var import_core17 = require("@pafi-dev/core");
|
|
4724
4807
|
var DEFAULT_TIMEOUT_MS = 1e3;
|
|
@@ -4729,7 +4812,9 @@ var SettlementClient = class {
|
|
|
4729
4812
|
if (!config.issuerId) throw new Error("SettlementClient: issuerId is required");
|
|
4730
4813
|
if (!config.apiKey) throw new Error("SettlementClient: apiKey is required");
|
|
4731
4814
|
this.config = {
|
|
4732
|
-
baseUrl: (0, import_core17.getPafiServiceUrls)(config.chainId
|
|
4815
|
+
baseUrl: (0, import_core17.getPafiServiceUrls)(config.chainId, {
|
|
4816
|
+
issuerApi: config.baseUrl
|
|
4817
|
+
}).issuerApi.replace(/\/+$/, ""),
|
|
4733
4818
|
issuerId: config.issuerId,
|
|
4734
4819
|
apiKey: config.apiKey,
|
|
4735
4820
|
fetchTimeoutMs: config.fetchTimeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
@@ -4833,10 +4918,23 @@ function defaultPolicyFor(issuerId) {
|
|
|
4833
4918
|
|
|
4834
4919
|
// src/redemption/policyProvider.ts
|
|
4835
4920
|
var DEFAULT_CACHE_TTL_MS3 = 5 * 60 * 1e3;
|
|
4921
|
+
var PolicyProviderUnavailableError = class extends import_core18.PafiSdkError {
|
|
4922
|
+
code = "POLICY_PROVIDER_UNAVAILABLE";
|
|
4923
|
+
httpStatus = "service_unavailable";
|
|
4924
|
+
details;
|
|
4925
|
+
constructor(issuerId, reason) {
|
|
4926
|
+
super(
|
|
4927
|
+
`Redemption policy provider unavailable for issuer ${issuerId}: ${reason}. Pre-flight redeem limit cannot be enforced \u2014 refusing to sign BurnRequest. Mobile FE: surface "try again shortly" and retry with backoff.`
|
|
4928
|
+
);
|
|
4929
|
+
this.details = { issuerId, reason };
|
|
4930
|
+
}
|
|
4931
|
+
};
|
|
4836
4932
|
var PolicyProvider = class {
|
|
4837
4933
|
client;
|
|
4838
4934
|
issuerId;
|
|
4839
4935
|
cacheTtlMs;
|
|
4936
|
+
onFetchFailure;
|
|
4937
|
+
onWarning;
|
|
4840
4938
|
now;
|
|
4841
4939
|
cache = null;
|
|
4842
4940
|
inflight = null;
|
|
@@ -4844,6 +4942,8 @@ var PolicyProvider = class {
|
|
|
4844
4942
|
this.client = new SettlementClient(config);
|
|
4845
4943
|
this.issuerId = config.issuerId;
|
|
4846
4944
|
this.cacheTtlMs = config.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS3;
|
|
4945
|
+
this.onFetchFailure = config.onFetchFailure ?? "fail-closed";
|
|
4946
|
+
this.onWarning = config.onWarning;
|
|
4847
4947
|
this.now = config.now ?? (() => Date.now());
|
|
4848
4948
|
}
|
|
4849
4949
|
async getPolicy() {
|
|
@@ -4876,7 +4976,19 @@ var PolicyProvider = class {
|
|
|
4876
4976
|
};
|
|
4877
4977
|
return { policy: result.policy, source: "settlement" };
|
|
4878
4978
|
}
|
|
4879
|
-
|
|
4979
|
+
const reason = "reason" in result && typeof result.reason === "string" ? result.reason : "unknown";
|
|
4980
|
+
if (this.onFetchFailure === "permissive-default") {
|
|
4981
|
+
this.onWarning?.(
|
|
4982
|
+
"PolicyProvider: settlement-api unreachable, falling back to permissive default. Pre-flight redeem limit is DEGRADED until settlement-api recovers.",
|
|
4983
|
+
{
|
|
4984
|
+
event: "policy_provider_fallback",
|
|
4985
|
+
issuerId: this.issuerId,
|
|
4986
|
+
reason
|
|
4987
|
+
}
|
|
4988
|
+
);
|
|
4989
|
+
return { policy: defaultPolicyFor(this.issuerId), source: "default" };
|
|
4990
|
+
}
|
|
4991
|
+
throw new PolicyProviderUnavailableError(this.issuerId, reason);
|
|
4880
4992
|
}
|
|
4881
4993
|
};
|
|
4882
4994
|
|
|
@@ -4966,7 +5078,7 @@ async function createIssuerService(config) {
|
|
|
4966
5078
|
provider: config.provider
|
|
4967
5079
|
});
|
|
4968
5080
|
}
|
|
4969
|
-
const sdkWrapperAddress = (0,
|
|
5081
|
+
const sdkWrapperAddress = (0, import_core19.getContractAddresses)(config.chainId).mintFeeWrapper;
|
|
4970
5082
|
const wrapperOverride = config.indexer?.mintFeeWrapperAddress;
|
|
4971
5083
|
const resolvedWrapperAddress = wrapperOverride !== void 0 ? wrapperOverride : sdkWrapperAddress;
|
|
4972
5084
|
const baseCursorStore = config.indexer?.cursorStore;
|
|
@@ -5005,7 +5117,7 @@ async function createIssuerService(config) {
|
|
|
5005
5117
|
}
|
|
5006
5118
|
indexers.set(tokenAddress, new PointIndexer(indexerConfig));
|
|
5007
5119
|
}
|
|
5008
|
-
const chainAddresses = (0,
|
|
5120
|
+
const chainAddresses = (0, import_core19.getContractAddresses)(config.chainId);
|
|
5009
5121
|
const resolvedContracts = {
|
|
5010
5122
|
batchExecutor: chainAddresses.batchExecutor,
|
|
5011
5123
|
usdt: chainAddresses.usdt,
|
|
@@ -5023,6 +5135,15 @@ async function createIssuerService(config) {
|
|
|
5023
5135
|
issuerId: config.redemption.issuerId,
|
|
5024
5136
|
apiKey: config.redemption.apiKey
|
|
5025
5137
|
};
|
|
5138
|
+
if (config.redemption.baseUrl) {
|
|
5139
|
+
policyConfig.baseUrl = config.redemption.baseUrl;
|
|
5140
|
+
}
|
|
5141
|
+
if (config.redemption.onFetchFailure) {
|
|
5142
|
+
policyConfig.onFetchFailure = config.redemption.onFetchFailure;
|
|
5143
|
+
}
|
|
5144
|
+
if (config.redemption.onPolicyWarning) {
|
|
5145
|
+
policyConfig.onWarning = config.redemption.onPolicyWarning;
|
|
5146
|
+
}
|
|
5026
5147
|
if (config.redemption.fetchImpl) policyConfig.fetchImpl = config.redemption.fetchImpl;
|
|
5027
5148
|
if (config.redemption.fetchTimeoutMs !== void 0) {
|
|
5028
5149
|
policyConfig.fetchTimeoutMs = config.redemption.fetchTimeoutMs;
|
|
@@ -5088,7 +5209,7 @@ async function createIssuerService(config) {
|
|
|
5088
5209
|
|
|
5089
5210
|
// src/issuer-state/validator.ts
|
|
5090
5211
|
var import_viem16 = require("viem");
|
|
5091
|
-
var
|
|
5212
|
+
var import_core20 = require("@pafi-dev/core");
|
|
5092
5213
|
var ISSUER_RECORD_TTL_MS = 3e4;
|
|
5093
5214
|
var IssuerStateValidator = class _IssuerStateValidator {
|
|
5094
5215
|
constructor(provider, registryAddress) {
|
|
@@ -5105,7 +5226,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
5105
5226
|
* `CONTRACT_ADDRESSES` map for the given chain.
|
|
5106
5227
|
*/
|
|
5107
5228
|
static forChain(provider, chainId) {
|
|
5108
|
-
const { issuerRegistry } = (0,
|
|
5229
|
+
const { issuerRegistry } = (0, import_core20.getContractAddresses)(chainId);
|
|
5109
5230
|
return new _IssuerStateValidator(provider, issuerRegistry);
|
|
5110
5231
|
}
|
|
5111
5232
|
/**
|
|
@@ -5134,7 +5255,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
5134
5255
|
if (cached) return cached;
|
|
5135
5256
|
const issuer = await this.provider.readContract({
|
|
5136
5257
|
address: key,
|
|
5137
|
-
abi:
|
|
5258
|
+
abi: import_core20.POINT_TOKEN_ABI,
|
|
5138
5259
|
functionName: "issuer"
|
|
5139
5260
|
});
|
|
5140
5261
|
this.pointTokenIssuerCache.set(key, (0, import_viem16.getAddress)(issuer));
|
|
@@ -5214,7 +5335,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
5214
5335
|
const issuerAddr = await this.getIssuerAddressForPointToken(tokenAddr);
|
|
5215
5336
|
const issuerStruct = await this.provider.readContract({
|
|
5216
5337
|
address: this.registryAddress,
|
|
5217
|
-
abi:
|
|
5338
|
+
abi: import_core20.issuerRegistryAbi,
|
|
5218
5339
|
functionName: "getIssuer",
|
|
5219
5340
|
args: [issuerAddr]
|
|
5220
5341
|
});
|
|
@@ -5227,7 +5348,7 @@ var IssuerStateValidator = class _IssuerStateValidator {
|
|
|
5227
5348
|
};
|
|
5228
5349
|
const equitySupply = await this.provider.readContract({
|
|
5229
5350
|
address: tokenAddr,
|
|
5230
|
-
abi:
|
|
5351
|
+
abi: import_core20.POINT_TOKEN_ABI,
|
|
5231
5352
|
functionName: "equitySupply"
|
|
5232
5353
|
});
|
|
5233
5354
|
const hardCap = issuer.capitalBase * BigInt(issuer.basisPoints) / 10000n;
|
|
@@ -5283,7 +5404,7 @@ var MemoryRedemptionHistoryStore = class {
|
|
|
5283
5404
|
};
|
|
5284
5405
|
|
|
5285
5406
|
// src/index.ts
|
|
5286
|
-
var PAFI_ISSUER_SDK_VERSION = true ? "0.
|
|
5407
|
+
var PAFI_ISSUER_SDK_VERSION = true ? "0.33.0" : "dev";
|
|
5287
5408
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5288
5409
|
0 && (module.exports = {
|
|
5289
5410
|
AdapterMisconfiguredError,
|