@pafi-dev/issuer 0.2.0 → 0.3.0-beta.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/README.md +58 -0
- package/dist/index.cjs +870 -85
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +624 -79
- package/dist/index.d.ts +624 -79
- package/dist/index.js +862 -82
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Address, Hex, PublicClient, Chain } from 'viem';
|
|
2
|
-
import { PointTokenDomainConfig, MintRequest, EIP712Signature, MintParams, SwapParams, ReceiverConsent, PathKey, PoolKey } from '@pafi-dev/core';
|
|
2
|
+
import { PointTokenDomainConfig, MintRequest, EIP712Signature, MintParams, SwapParams, MintRequestV2, SignatureStruct, PartialUserOperation, BurnConsent, ReceiverConsent, PathKey, PoolKey, SponsorshipScenario } from '@pafi-dev/core';
|
|
3
3
|
export { encodeExtData } from '@pafi-dev/core';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -78,6 +78,24 @@ interface IPointLedger {
|
|
|
78
78
|
* supplied when the status is `MINTED`.
|
|
79
79
|
*/
|
|
80
80
|
updateMintStatus(lockId: string, status: MintingStatus, txHash?: Hex): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Reserve a pending off-chain credit before the burn tx is submitted.
|
|
83
|
+
*
|
|
84
|
+
* Returns a lockId that the burn indexer uses to correlate the
|
|
85
|
+
* on-chain burn event back to this credit request.
|
|
86
|
+
*
|
|
87
|
+
* Throws if the ledger doesn't support the reverse flow (legacy
|
|
88
|
+
* implementations) — callers should catch and fall back.
|
|
89
|
+
*/
|
|
90
|
+
reservePendingCredit?(userAddress: Address, amount: bigint, durationMs: number, tokenAddress?: Address): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Finalize a reserved credit when the on-chain Burn event is seen by
|
|
93
|
+
* the BurnIndexer. Idempotent — safe to call multiple times with the
|
|
94
|
+
* same txHash (no double-credit).
|
|
95
|
+
*
|
|
96
|
+
* Throws if the lockId is unknown or already resolved.
|
|
97
|
+
*/
|
|
98
|
+
resolveCreditByBurnTx?(lockId: string, txHash: Hex): Promise<void>;
|
|
81
99
|
}
|
|
82
100
|
|
|
83
101
|
/**
|
|
@@ -109,6 +127,10 @@ declare class MemoryPointLedger implements IPointLedger {
|
|
|
109
127
|
releaseLock(lockId: string): Promise<void>;
|
|
110
128
|
deductBalance(userAddress: Address, amount: bigint, txHash: Hex, tokenAddress?: Address): Promise<void>;
|
|
111
129
|
updateMintStatus(lockId: string, status: MintingStatus, txHash?: Hex): Promise<void>;
|
|
130
|
+
private pendingCredits;
|
|
131
|
+
private nextCreditId;
|
|
132
|
+
reservePendingCredit(userAddress: Address, amount: bigint, durationMs: number, tokenAddress?: Address): Promise<string>;
|
|
133
|
+
resolveCreditByBurnTx(lockId: string, txHash: Hex): Promise<void>;
|
|
112
134
|
/**
|
|
113
135
|
* Auto-expire any PENDING lock past its expiry. Called lazily on every
|
|
114
136
|
* read/write so the in-memory state stays self-cleaning without a timer.
|
|
@@ -536,93 +558,145 @@ declare class RelayService {
|
|
|
536
558
|
* decide whether to release the ledger lock (`SUBMIT_FAILED` and
|
|
537
559
|
* `SIMULATION_FAILED` are safe to release; `TX_REVERTED` and `TIMEOUT`
|
|
538
560
|
* need manual review because the tx may still land).
|
|
561
|
+
*
|
|
562
|
+
* @deprecated Since 0.3.0 — will be replaced by `prepareMint()` +
|
|
563
|
+
* `prepareBurn()` in the v1.4 sponsored-UserOp flow. The SC team
|
|
564
|
+
* still needs to finalize Relayer v2 ABI before the replacements
|
|
565
|
+
* can ship (blocker B1). Kept for v0.2.x consumers. Removed in 2.0.
|
|
539
566
|
*/
|
|
540
567
|
submitMintAndSwap(params: SubmitMintAndSwapParams): Promise<RelayResult>;
|
|
568
|
+
/**
|
|
569
|
+
* Build an unsigned UserOp for Scenario 1 (Mint).
|
|
570
|
+
*
|
|
571
|
+
* Flow:
|
|
572
|
+
* 1. Encode `Relayer.mint(request, userSig, issuerSig)` as the inner call
|
|
573
|
+
* 2. Optionally append a PT fee transfer from user → feeRecipient
|
|
574
|
+
* (fee recovery happens on-chain via BatchExecutor, not via an
|
|
575
|
+
* operator wallet)
|
|
576
|
+
* 3. Wrap all inner calls into `BatchExecutor.execute(calls[])`
|
|
577
|
+
* 4. Return a `PartialUserOperation` ready for:
|
|
578
|
+
* - gas estimation (Bundler)
|
|
579
|
+
* - paymaster sponsorship (PAFI Backend)
|
|
580
|
+
* - user signature (Privy)
|
|
581
|
+
*/
|
|
582
|
+
prepareMint(params: PrepareMintParams): PartialUserOperation;
|
|
583
|
+
/**
|
|
584
|
+
* Build an unsigned UserOp for Scenario 2 (Burn/Redeem).
|
|
585
|
+
*
|
|
586
|
+
* Two modes:
|
|
587
|
+
* - `mode: 'burn'` — direct `PointToken.burn(amount)`; `msg.sender`
|
|
588
|
+
* via EIP-7702 delegation is the user, so no signature needed
|
|
589
|
+
* on-chain (the BurnConsent was already verified off-chain by
|
|
590
|
+
* the issuer backend before we got here)
|
|
591
|
+
* - `mode: 'burnWithSig'` — `PointToken.burnWithSig(consent, sig)`;
|
|
592
|
+
* used when the issuer hasn't verified the consent and the
|
|
593
|
+
* contract has to do it on-chain
|
|
594
|
+
*/
|
|
595
|
+
prepareBurn(params: PrepareBurnParams): PartialUserOperation;
|
|
596
|
+
}
|
|
597
|
+
interface PrepareMintParams {
|
|
598
|
+
/** User EOA that will send the UserOp (via EIP-7702 delegation). */
|
|
599
|
+
userAddress: Address;
|
|
600
|
+
/** ERC-4337 account nonce (not the MintRequest nonce — different namespace). */
|
|
601
|
+
aaNonce: bigint;
|
|
602
|
+
/** Deployed Relayer v2 contract address (chain-specific). */
|
|
603
|
+
relayerAddress: Address;
|
|
604
|
+
/** BatchExecutor delegation target (chain-specific). */
|
|
605
|
+
batchExecutorAddress: Address;
|
|
606
|
+
/** PointToken being minted — used for optional fee transfer call. */
|
|
607
|
+
pointTokenAddress: Address;
|
|
608
|
+
/** EIP-712-signed MintRequest fields. */
|
|
609
|
+
mintRequest: MintRequestV2;
|
|
610
|
+
/** User's EIP-712 signature over `mintRequest`. */
|
|
611
|
+
userSignature: SignatureStruct;
|
|
612
|
+
/** Issuer's EIP-712 signature over `mintRequest`. */
|
|
613
|
+
issuerSignature: SignatureStruct;
|
|
614
|
+
/** Gas limits — defaults are conservative; caller can tighten. */
|
|
615
|
+
callGasLimit?: bigint;
|
|
616
|
+
verificationGasLimit?: bigint;
|
|
617
|
+
preVerificationGas?: bigint;
|
|
618
|
+
}
|
|
619
|
+
type PrepareBurnParams = PrepareBurnDirectParams | PrepareBurnWithSigParams;
|
|
620
|
+
interface PrepareBurnCommonParams {
|
|
621
|
+
userAddress: Address;
|
|
622
|
+
aaNonce: bigint;
|
|
623
|
+
pointTokenAddress: Address;
|
|
624
|
+
batchExecutorAddress: Address;
|
|
625
|
+
callGasLimit?: bigint;
|
|
626
|
+
verificationGasLimit?: bigint;
|
|
627
|
+
preVerificationGas?: bigint;
|
|
628
|
+
}
|
|
629
|
+
interface PrepareBurnDirectParams extends PrepareBurnCommonParams {
|
|
630
|
+
mode: "burn";
|
|
631
|
+
amount: bigint;
|
|
632
|
+
}
|
|
633
|
+
interface PrepareBurnWithSigParams extends PrepareBurnCommonParams {
|
|
634
|
+
mode: "burnWithSig";
|
|
635
|
+
burnConsent: BurnConsent;
|
|
636
|
+
consentSignature: SignatureStruct;
|
|
541
637
|
}
|
|
542
638
|
|
|
543
639
|
interface FeeManagerConfig {
|
|
544
|
-
/** Provider used for gas price
|
|
640
|
+
/** Provider used for gas price reads. */
|
|
545
641
|
provider: PublicClient;
|
|
546
|
-
/** Operator wallet whose native balance the manager monitors. */
|
|
547
|
-
operatorWallet: OperatorWalletLike;
|
|
548
|
-
/** USDT token address on the target chain (used for rebalance swaps). */
|
|
549
|
-
usdtAddress: Address;
|
|
550
|
-
/** Wrapped-native token address (WETH on Base/Ethereum, WMATIC, etc). */
|
|
551
|
-
nativeWrappedAddress: Address;
|
|
552
642
|
/**
|
|
553
|
-
* Typical gas used by a
|
|
554
|
-
* manager multiplies this by current gas price to get
|
|
555
|
-
* then converts
|
|
643
|
+
* Typical gas used by a single sponsored UserOp. Default: 500_000.
|
|
644
|
+
* The manager multiplies this by current gas price to get native
|
|
645
|
+
* cost, then converts via the injected `quoteNativeToFee`.
|
|
556
646
|
*/
|
|
557
|
-
|
|
647
|
+
gasUnits?: bigint;
|
|
558
648
|
/**
|
|
559
|
-
* Safety margin applied
|
|
560
|
-
*
|
|
649
|
+
* Safety margin applied before charging the user, as basis points.
|
|
650
|
+
* 12_000 = 120%. Default: 12_000.
|
|
561
651
|
*/
|
|
562
652
|
gasPremiumBps?: number;
|
|
563
653
|
/**
|
|
564
|
-
*
|
|
565
|
-
* equivalent amount
|
|
566
|
-
*
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
*
|
|
571
|
-
* `rebalanceThresholdWei`, `rebalanceIfNeeded()` swaps `rebalanceUsdtAmount`
|
|
572
|
-
* worth of USDT into native. Both optional — omit to disable rebalancing.
|
|
573
|
-
*/
|
|
574
|
-
rebalanceThresholdWei?: bigint;
|
|
575
|
-
rebalanceUsdtAmount?: bigint;
|
|
576
|
-
/**
|
|
577
|
-
* Actual swap executor — the manager calls this when a rebalance is
|
|
578
|
-
* triggered. Injected so the SDK does not hard-code a DEX choice; the
|
|
579
|
-
* issuer wires it to the UniversalRouter (via `@pafi/core swap/`) or
|
|
580
|
-
* whatever liquidity venue they trust. Required iff the rebalance
|
|
581
|
-
* fields above are set.
|
|
654
|
+
* Quote function — given an amount of native wei, return the
|
|
655
|
+
* equivalent amount in the fee currency (PT raw units in v1.4,
|
|
656
|
+
* USDT 6-decimal in legacy v1.2 flows).
|
|
657
|
+
*
|
|
658
|
+
* Injected so the manager stays chain- and token-agnostic. Issuers
|
|
659
|
+
* wire it to `@pafi-dev/core` V4 quoting, a subgraph query, or an
|
|
660
|
+
* oracle feed.
|
|
582
661
|
*/
|
|
583
|
-
|
|
662
|
+
quoteNativeToFee: (amountNative: bigint) => Promise<bigint>;
|
|
584
663
|
}
|
|
585
664
|
/**
|
|
586
|
-
*
|
|
665
|
+
* Computes how much fee to collect from the user to cover the gas cost
|
|
666
|
+
* of a sponsored UserOp.
|
|
667
|
+
*
|
|
668
|
+
* ## v1.4 scope change
|
|
587
669
|
*
|
|
588
|
-
*
|
|
589
|
-
*
|
|
590
|
-
* 2. `rebalanceIfNeeded()` — when the operator's native balance gets
|
|
591
|
-
* low, swap some of the accumulated USDT fee back into native gas
|
|
592
|
-
* token so the operator never runs dry.
|
|
670
|
+
* The fee is now expressed in the **fee currency** chosen by the caller
|
|
671
|
+
* (PT for mint/burn, USDT for swap/perp_deposit) — not hardcoded to USDT.
|
|
593
672
|
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
596
|
-
*
|
|
673
|
+
* **Operator rebalancing is gone.** In v1.4 the operator no longer holds
|
|
674
|
+
* ETH directly — gas is paid by Coinbase Paymaster via the paymaster-proxy
|
|
675
|
+
* (see [SPONSORED_PATH_FLOW.md]). The fee collected here is an
|
|
676
|
+
* application-level ERC-20 transfer inside the same UserOp batch, not a
|
|
677
|
+
* reimbursement to a wallet that needs topping up.
|
|
678
|
+
*
|
|
679
|
+
* `rebalanceIfNeeded()` and `swapUsdtToNative` were removed in 0.3.0.
|
|
597
680
|
*/
|
|
598
681
|
declare class FeeManager {
|
|
599
682
|
private readonly provider;
|
|
600
|
-
private readonly
|
|
601
|
-
private readonly mintAndSwapGasUnits;
|
|
683
|
+
private readonly gasUnits;
|
|
602
684
|
private readonly gasPremiumBps;
|
|
603
|
-
private readonly
|
|
604
|
-
private readonly rebalanceThresholdWei?;
|
|
605
|
-
private readonly rebalanceUsdtAmount?;
|
|
606
|
-
private readonly swapUsdtToNative?;
|
|
685
|
+
private readonly quoteNativeToFee;
|
|
607
686
|
constructor(config: FeeManagerConfig);
|
|
608
687
|
/**
|
|
609
|
-
* Estimate the
|
|
610
|
-
*
|
|
688
|
+
* Estimate the fee (in the caller's fee currency) to charge for the
|
|
689
|
+
* next sponsored UserOp:
|
|
611
690
|
*
|
|
612
|
-
* nativeCost
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*/
|
|
616
|
-
estimateGasFee(): Promise<bigint>;
|
|
617
|
-
/**
|
|
618
|
-
* Check the operator's native balance and, if it has dropped below the
|
|
619
|
-
* configured threshold, trigger a USDT→native rebalance via the injected
|
|
620
|
-
* `swapUsdtToNative` function.
|
|
691
|
+
* nativeCost = gasUnits × gasPrice
|
|
692
|
+
* withPremium = nativeCost × premiumBps / 10_000
|
|
693
|
+
* fee = quoteNativeToFee(withPremium)
|
|
621
694
|
*
|
|
622
|
-
*
|
|
623
|
-
*
|
|
695
|
+
* For backward compatibility with v0.2.x code that reads `gasFeeUsdt`
|
|
696
|
+
* from the response, the name `estimateGasFee` is kept — but the
|
|
697
|
+
* currency depends on how the caller wired `quoteNativeToFee`.
|
|
624
698
|
*/
|
|
625
|
-
|
|
699
|
+
estimateGasFee(): Promise<bigint>;
|
|
626
700
|
}
|
|
627
701
|
|
|
628
702
|
/**
|
|
@@ -751,6 +825,12 @@ declare class MintingGateway {
|
|
|
751
825
|
private readonly now;
|
|
752
826
|
private readonly defaultLockBufferMs;
|
|
753
827
|
constructor(config: MintingGatewayConfig);
|
|
828
|
+
/**
|
|
829
|
+
* @deprecated Since 0.3.0 — will be renamed to `processMint()` once
|
|
830
|
+
* the SC team finalizes Relayer v2 ABI. The new flow drops the
|
|
831
|
+
* swap steps entirely (no more single-call mint+swap); users swap
|
|
832
|
+
* separately on PAFI Web. Kept here for v0.2.x consumers. Removed in 2.0.
|
|
833
|
+
*/
|
|
754
834
|
processMintAndCashOut(request: MintAndCashOutRequest): Promise<MintAndCashOutResponse>;
|
|
755
835
|
private computeLockDurationMs;
|
|
756
836
|
/**
|
|
@@ -782,6 +862,16 @@ interface MintEvent {
|
|
|
782
862
|
/** Log index within the tx, for deterministic ordering */
|
|
783
863
|
logIndex: number;
|
|
784
864
|
}
|
|
865
|
+
/** Decoded Transfer(from=user → 0x0) event used to finalize a burn-for-credit. */
|
|
866
|
+
interface BurnEvent {
|
|
867
|
+
/** The burner — user whose PT was burned. */
|
|
868
|
+
from: Address;
|
|
869
|
+
/** Amount burned. */
|
|
870
|
+
amount: bigint;
|
|
871
|
+
blockNumber: bigint;
|
|
872
|
+
txHash: Hex;
|
|
873
|
+
logIndex: number;
|
|
874
|
+
}
|
|
785
875
|
/**
|
|
786
876
|
* Cursor persistence interface — the indexer reports the next block
|
|
787
877
|
* number it is about to process so the caller can write it to Redis /
|
|
@@ -901,10 +991,102 @@ declare class PointIndexer {
|
|
|
901
991
|
private finalize;
|
|
902
992
|
}
|
|
903
993
|
|
|
994
|
+
interface BurnIndexerConfig {
|
|
995
|
+
provider: PublicClient;
|
|
996
|
+
pointTokenAddress: Address;
|
|
997
|
+
ledger: IPointLedger;
|
|
998
|
+
/** Block to start from on first run. Ignored if cursor store has value. */
|
|
999
|
+
fromBlock?: bigint;
|
|
1000
|
+
cursorStore?: IIndexerCursorStore;
|
|
1001
|
+
/**
|
|
1002
|
+
* Reorg safety — only treat events as final after this many
|
|
1003
|
+
* confirmations. Default: 3.
|
|
1004
|
+
*/
|
|
1005
|
+
confirmations?: number;
|
|
1006
|
+
/** Blocks per getLogs call. Default: 2000. */
|
|
1007
|
+
batchSize?: number;
|
|
1008
|
+
/** Polling interval (ms). Default: 5000. */
|
|
1009
|
+
pollIntervalMs?: number;
|
|
1010
|
+
now?: () => number;
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Mirror of `PointIndexer` for the reverse direction — watches
|
|
1014
|
+
* `Transfer(user → 0x0)` events (ERC-20 burns) on the PointToken
|
|
1015
|
+
* contract and finalizes pending off-chain credits.
|
|
1016
|
+
*
|
|
1017
|
+
* Finalization flow:
|
|
1018
|
+
* 1. For each Burn event at `{from, amount, txHash}`:
|
|
1019
|
+
* 2. Call `ledger.resolveCreditByBurnTx(lockId, txHash)` where `lockId`
|
|
1020
|
+
* is resolved by the caller's `onMatchCredit` hook or a
|
|
1021
|
+
* ledger-specific lookup. The SDK does not prescribe the matching
|
|
1022
|
+
* strategy — issuers with a Postgres ledger can JOIN by
|
|
1023
|
+
* `(from, amount, status=PENDING)`; the in-memory ledger matches
|
|
1024
|
+
* by `lockId` supplied out-of-band.
|
|
1025
|
+
*
|
|
1026
|
+
* When no pending credit matches an observed Burn event, the indexer
|
|
1027
|
+
* logs + skips — **it never credits off-chain** from a Burn that was
|
|
1028
|
+
* not first reserved via `reservePendingCredit()`. This prevents
|
|
1029
|
+
* spurious credits from one-off admin burns or direct burn calls
|
|
1030
|
+
* outside the issuer SDK.
|
|
1031
|
+
*/
|
|
1032
|
+
declare class BurnIndexer {
|
|
1033
|
+
private readonly provider;
|
|
1034
|
+
private readonly pointTokenAddress;
|
|
1035
|
+
private readonly ledger;
|
|
1036
|
+
private readonly cursorStore;
|
|
1037
|
+
private readonly startBlock;
|
|
1038
|
+
private readonly confirmations;
|
|
1039
|
+
private readonly batchSize;
|
|
1040
|
+
private readonly pollIntervalMs;
|
|
1041
|
+
/**
|
|
1042
|
+
* Caller-supplied matcher. Return the lockId to resolve for a given
|
|
1043
|
+
* burn event, or `undefined` to skip. Runs synchronously via the
|
|
1044
|
+
* ledger's query path.
|
|
1045
|
+
*
|
|
1046
|
+
* Default: try `ledger.resolveCreditByBurnTx` keyed on a synthetic
|
|
1047
|
+
* lock id `burn-${from}-${amount}` — the in-memory ledger assigns
|
|
1048
|
+
* incrementing IDs so callers with the memory ledger must provide a
|
|
1049
|
+
* custom matcher. Real DB-backed ledgers override this to JOIN on
|
|
1050
|
+
* their `pending_credits` table.
|
|
1051
|
+
*/
|
|
1052
|
+
matchLockId: (event: BurnEvent) => Promise<string | undefined>;
|
|
1053
|
+
private running;
|
|
1054
|
+
private timer;
|
|
1055
|
+
constructor(config: BurnIndexerConfig);
|
|
1056
|
+
start(): void;
|
|
1057
|
+
stop(): void;
|
|
1058
|
+
tick(): Promise<void>;
|
|
1059
|
+
private scheduleNext;
|
|
1060
|
+
/**
|
|
1061
|
+
* Scan `[from, to]` inclusive for burn events. Callers can drive this
|
|
1062
|
+
* directly to backfill a specific range without `start()`. Cursor is
|
|
1063
|
+
* advanced to `to + 1` on completion.
|
|
1064
|
+
*/
|
|
1065
|
+
processBlockRange(from: bigint, to: bigint): Promise<void>;
|
|
1066
|
+
private decodeBurnEvents;
|
|
1067
|
+
/**
|
|
1068
|
+
* Resolve a matching pending credit for this burn event and call
|
|
1069
|
+
* `ledger.resolveCreditByBurnTx(lockId, txHash)`. If no match found,
|
|
1070
|
+
* log + skip.
|
|
1071
|
+
*/
|
|
1072
|
+
private finalize;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
904
1075
|
interface ApiConfigResponse {
|
|
905
1076
|
chainId: number;
|
|
906
1077
|
contracts: {
|
|
1078
|
+
/**
|
|
1079
|
+
* Legacy single-token field — kept for backward compat with v0.1.x
|
|
1080
|
+
* frontends. Prefer `pointTokens` for multi-token issuers.
|
|
1081
|
+
*/
|
|
907
1082
|
pointToken?: Address;
|
|
1083
|
+
/**
|
|
1084
|
+
* All supported PointToken addresses (v0.2.0+). Single-token issuers
|
|
1085
|
+
* will have one entry that matches `pointToken`. Multi-token
|
|
1086
|
+
* issuers expose the full list here so the frontend can render a
|
|
1087
|
+
* token picker.
|
|
1088
|
+
*/
|
|
1089
|
+
pointTokens?: Address[];
|
|
908
1090
|
relay?: Address;
|
|
909
1091
|
issuerRegistry?: Address;
|
|
910
1092
|
pointTokenFactory?: Address;
|
|
@@ -912,6 +1094,17 @@ interface ApiConfigResponse {
|
|
|
912
1094
|
poolManager?: Address;
|
|
913
1095
|
usdt?: Address;
|
|
914
1096
|
};
|
|
1097
|
+
/**
|
|
1098
|
+
* Absolute URL that the Issuer App opens after a successful claim to
|
|
1099
|
+
* let the user swap PT → USDT or deposit into the perp DEX on PAFI
|
|
1100
|
+
* Web. Mobile opens this in an in-app browser
|
|
1101
|
+
* (SFSafariViewController / Chrome Custom Tabs). Desktop opens in a
|
|
1102
|
+
* popup. See [MOBILE_SDK_INTEGRATION.md] "PAFI Web Handoff" section.
|
|
1103
|
+
*
|
|
1104
|
+
* Optional — if omitted, the Issuer App should hide the "Open PAFI"
|
|
1105
|
+
* button.
|
|
1106
|
+
*/
|
|
1107
|
+
pafiWebUrl?: string;
|
|
915
1108
|
}
|
|
916
1109
|
interface ApiNonceResponse {
|
|
917
1110
|
nonce: string;
|
|
@@ -967,6 +1160,7 @@ interface ApiUserResponse {
|
|
|
967
1160
|
balance: bigint;
|
|
968
1161
|
isMinter: boolean;
|
|
969
1162
|
}
|
|
1163
|
+
/** @deprecated Since 0.3.0 — use `ApiClaimRequest` (mint-only) instead. Removed in 2.0. */
|
|
970
1164
|
interface ApiClaimAndSwapRequest {
|
|
971
1165
|
chainId: number;
|
|
972
1166
|
pointTokenAddress: Address;
|
|
@@ -985,6 +1179,7 @@ interface ApiClaimAndSwapRequest {
|
|
|
985
1179
|
/** Unix seconds. */
|
|
986
1180
|
swapDeadline: bigint;
|
|
987
1181
|
}
|
|
1182
|
+
/** @deprecated Since 0.3.0 — use `ApiClaimResponse` instead. Removed in 2.0. */
|
|
988
1183
|
interface ApiClaimAndSwapResponse {
|
|
989
1184
|
txHash: Hex;
|
|
990
1185
|
lockId: string;
|
|
@@ -1032,6 +1227,12 @@ interface IssuerApiHandlersConfig {
|
|
|
1032
1227
|
pointTokenAddresses?: Address[];
|
|
1033
1228
|
chainId: number;
|
|
1034
1229
|
contracts: ApiConfigResponse["contracts"];
|
|
1230
|
+
/**
|
|
1231
|
+
* Optional — URL that the Issuer App opens for PT→USDT swap or perp
|
|
1232
|
+
* deposit after a successful claim. Surfaced in `/config` response.
|
|
1233
|
+
* See [MOBILE_SDK_INTEGRATION.md] "PAFI Web Handoff".
|
|
1234
|
+
*/
|
|
1235
|
+
pafiWebUrl?: string;
|
|
1035
1236
|
/** Required by `handleGasFee`; omit to disable the endpoint. */
|
|
1036
1237
|
feeManager?: FeeManager;
|
|
1037
1238
|
/** Required by `handlePools`; omit to disable the endpoint. */
|
|
@@ -1065,6 +1266,7 @@ declare class IssuerApiHandlers {
|
|
|
1065
1266
|
private readonly defaultToken;
|
|
1066
1267
|
private readonly chainId;
|
|
1067
1268
|
private readonly contracts;
|
|
1269
|
+
private readonly pafiWebUrl?;
|
|
1068
1270
|
private readonly feeManager?;
|
|
1069
1271
|
private readonly poolsProvider?;
|
|
1070
1272
|
constructor(config: IssuerApiHandlersConfig);
|
|
@@ -1115,12 +1317,155 @@ declare class IssuerApiHandlers {
|
|
|
1115
1317
|
/**
|
|
1116
1318
|
* `POST /claim-and-swap`
|
|
1117
1319
|
*
|
|
1118
|
-
*
|
|
1119
|
-
*
|
|
1320
|
+
* @deprecated Since 0.3.0 — the single-call mint-then-swap flow is
|
|
1321
|
+
* retired in v1.4. Use the new `handleClaim()` (mint only) and let
|
|
1322
|
+
* the user swap separately on PAFI Web. See
|
|
1323
|
+
* [V1.4_V1.5_OVERVIEW.md §4] for the new scenario model. Will be
|
|
1324
|
+
* removed in 2.0.
|
|
1325
|
+
*
|
|
1326
|
+
* Legacy behavior: the terminal handler forwards the verified
|
|
1327
|
+
* consent to the MintingGateway, which runs the 11-step flow.
|
|
1120
1328
|
*/
|
|
1121
1329
|
handleClaimAndSwap(userAddress: Address, request: ApiClaimAndSwapRequest): Promise<ApiClaimAndSwapResponse>;
|
|
1122
1330
|
}
|
|
1123
1331
|
|
|
1332
|
+
/**
|
|
1333
|
+
* v1.4 reverse flow — **Variant A**: user-initiated PT redeem.
|
|
1334
|
+
*
|
|
1335
|
+
* User has on-chain PT, wants to convert back to off-chain points. They
|
|
1336
|
+
* sign a `BurnConsent`, the issuer backend verifies it, reserves an
|
|
1337
|
+
* off-chain credit, and returns an unsigned UserOp that the frontend
|
|
1338
|
+
* submits via the Bundler. When the burn lands, the `BurnIndexer`
|
|
1339
|
+
* (elsewhere) resolves the credit.
|
|
1340
|
+
*
|
|
1341
|
+
* **Mocked SC contracts** — this handler compiles + wires end-to-end
|
|
1342
|
+
* against `@pafi-dev/core/contracts` mock ABIs. When SC ships real
|
|
1343
|
+
* ABIs, no changes here — only `contracts/index.ts` re-export flips.
|
|
1344
|
+
*/
|
|
1345
|
+
interface PTRedeemHandlerConfig {
|
|
1346
|
+
ledger: IPointLedger;
|
|
1347
|
+
relayService: RelayService;
|
|
1348
|
+
provider: PublicClient;
|
|
1349
|
+
/** PointToken contract address (chain-specific). */
|
|
1350
|
+
pointTokenAddress: Address;
|
|
1351
|
+
/** BatchExecutor delegation target (chain-specific). */
|
|
1352
|
+
batchExecutorAddress: Address;
|
|
1353
|
+
/** Chain id — used for domain separator when verifying BurnConsent. */
|
|
1354
|
+
chainId: number;
|
|
1355
|
+
/**
|
|
1356
|
+
* EIP-712 domain fields. Must match the on-chain PointToken's domain
|
|
1357
|
+
* separator exactly, or signature verification fails. `name` is
|
|
1358
|
+
* typically the PointToken's ERC-20 name (e.g. "PAFI Starbucks
|
|
1359
|
+
* Points"). `verifyingContract` defaults to `pointTokenAddress`.
|
|
1360
|
+
*/
|
|
1361
|
+
domain: {
|
|
1362
|
+
name: string;
|
|
1363
|
+
verifyingContract?: Address;
|
|
1364
|
+
};
|
|
1365
|
+
/**
|
|
1366
|
+
* How long the pending credit stays reserved if the burn never lands.
|
|
1367
|
+
* Default: 15 min — long enough for a bundler submission + confirmation.
|
|
1368
|
+
*/
|
|
1369
|
+
redeemLockDurationMs?: number;
|
|
1370
|
+
/** Clock injection for tests; defaults to `Date.now`. */
|
|
1371
|
+
now?: () => number;
|
|
1372
|
+
}
|
|
1373
|
+
interface PTRedeemRequest {
|
|
1374
|
+
userAddress: Address;
|
|
1375
|
+
amount: bigint;
|
|
1376
|
+
/** Serialized EIP-712 signature over the BurnConsent. */
|
|
1377
|
+
consentSignature: Hex;
|
|
1378
|
+
consent: BurnConsent;
|
|
1379
|
+
/** ERC-4337 account nonce for the user's EOA. */
|
|
1380
|
+
aaNonce: bigint;
|
|
1381
|
+
}
|
|
1382
|
+
interface PTRedeemResponse {
|
|
1383
|
+
/** Lock id from the ledger — client polls status with this. */
|
|
1384
|
+
lockId: string;
|
|
1385
|
+
/** Unsigned UserOp — FE attaches paymaster + user signature + submits. */
|
|
1386
|
+
userOp: PartialUserOperation;
|
|
1387
|
+
/** Seconds until the lock expires if the burn doesn't land. */
|
|
1388
|
+
expiresInSeconds: number;
|
|
1389
|
+
}
|
|
1390
|
+
declare class PTRedeemError extends Error {
|
|
1391
|
+
code: "INVALID_CONSENT" | "SIGNATURE_MISMATCH" | "AMOUNT_MISMATCH" | "EXPIRED_CONSENT" | "LEDGER_NOT_SUPPORTED";
|
|
1392
|
+
constructor(code: "INVALID_CONSENT" | "SIGNATURE_MISMATCH" | "AMOUNT_MISMATCH" | "EXPIRED_CONSENT" | "LEDGER_NOT_SUPPORTED", message: string);
|
|
1393
|
+
}
|
|
1394
|
+
declare class PTRedeemHandler {
|
|
1395
|
+
private readonly ledger;
|
|
1396
|
+
private readonly relayService;
|
|
1397
|
+
private readonly pointTokenAddress;
|
|
1398
|
+
private readonly batchExecutorAddress;
|
|
1399
|
+
private readonly chainId;
|
|
1400
|
+
private readonly domain;
|
|
1401
|
+
private readonly redeemLockDurationMs;
|
|
1402
|
+
private readonly now;
|
|
1403
|
+
constructor(config: PTRedeemHandlerConfig);
|
|
1404
|
+
handle(request: PTRedeemRequest): Promise<PTRedeemResponse>;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
/**
|
|
1408
|
+
* v1.4 reverse flow — **Variant B**: auto top-up on voucher redemption.
|
|
1409
|
+
*
|
|
1410
|
+
* User tries to redeem a voucher for `requiredAmount` off-chain points
|
|
1411
|
+
* but their off-chain balance is short. If their on-chain PT balance is
|
|
1412
|
+
* enough to cover the shortfall, this handler auto-triggers a burn for
|
|
1413
|
+
* exactly the shortfall amount so the voucher can proceed.
|
|
1414
|
+
*
|
|
1415
|
+
* Required off-chain: 500
|
|
1416
|
+
* Available off-chain: 300
|
|
1417
|
+
* Shortfall: 200
|
|
1418
|
+
* On-chain PT: 250 ← enough, top-up fires
|
|
1419
|
+
* → burn 200 PT, credit 200 off-chain, voucher proceeds with 500
|
|
1420
|
+
*
|
|
1421
|
+
* Delegates the actual burn construction to {@link PTRedeemHandler}
|
|
1422
|
+
* — this handler is pure business logic (calculating shortfall +
|
|
1423
|
+
* checking on-chain balance) on top.
|
|
1424
|
+
*/
|
|
1425
|
+
interface TopUpRedemptionHandlerConfig {
|
|
1426
|
+
ledger: IPointLedger;
|
|
1427
|
+
ptRedeemHandler: PTRedeemHandler;
|
|
1428
|
+
provider: PublicClient;
|
|
1429
|
+
/** PointToken contract address (chain-specific). */
|
|
1430
|
+
pointTokenAddress: Address;
|
|
1431
|
+
}
|
|
1432
|
+
interface TopUpRedemptionRequest {
|
|
1433
|
+
userAddress: Address;
|
|
1434
|
+
/** Total points the voucher redemption requires off-chain. */
|
|
1435
|
+
requiredAmount: bigint;
|
|
1436
|
+
/**
|
|
1437
|
+
* The user's pre-signed `BurnConsent` + signature, prepared by the FE
|
|
1438
|
+
* with amount set to a worst-case upper bound. Handler inspects the
|
|
1439
|
+
* shortfall and uses the consent if the shortfall ≤ consent.amount.
|
|
1440
|
+
*/
|
|
1441
|
+
redeemRequest: Pick<PTRedeemRequest, "consent" | "consentSignature" | "aaNonce">;
|
|
1442
|
+
}
|
|
1443
|
+
type TopUpRedemptionResponse = {
|
|
1444
|
+
action: "NO_TOP_UP_NEEDED";
|
|
1445
|
+
offChainBalance: bigint;
|
|
1446
|
+
} | {
|
|
1447
|
+
action: "INSUFFICIENT_ONCHAIN";
|
|
1448
|
+
offChainBalance: bigint;
|
|
1449
|
+
onChainBalance: bigint;
|
|
1450
|
+
shortfall: bigint;
|
|
1451
|
+
} | {
|
|
1452
|
+
action: "TOP_UP_STARTED";
|
|
1453
|
+
shortfall: bigint;
|
|
1454
|
+
redeem: PTRedeemResponse;
|
|
1455
|
+
};
|
|
1456
|
+
declare class TopUpRedemptionError extends Error {
|
|
1457
|
+
code: "INSUFFICIENT_ONCHAIN_BALANCE" | "CONSENT_AMOUNT_TOO_LOW" | "LEDGER_NOT_SUPPORTED";
|
|
1458
|
+
constructor(code: "INSUFFICIENT_ONCHAIN_BALANCE" | "CONSENT_AMOUNT_TOO_LOW" | "LEDGER_NOT_SUPPORTED", message: string);
|
|
1459
|
+
}
|
|
1460
|
+
declare class TopUpRedemptionHandler {
|
|
1461
|
+
private readonly ledger;
|
|
1462
|
+
private readonly ptRedeemHandler;
|
|
1463
|
+
private readonly provider;
|
|
1464
|
+
private readonly pointTokenAddress;
|
|
1465
|
+
constructor(config: TopUpRedemptionHandlerConfig);
|
|
1466
|
+
handle(request: TopUpRedemptionRequest): Promise<TopUpRedemptionResponse>;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1124
1469
|
/**
|
|
1125
1470
|
* Config for `createSubgraphPoolsProvider`.
|
|
1126
1471
|
*/
|
|
@@ -1219,26 +1564,29 @@ interface SubgraphNativeUsdtQuoterConfig {
|
|
|
1219
1564
|
now?: () => number;
|
|
1220
1565
|
}
|
|
1221
1566
|
/**
|
|
1222
|
-
* Create a
|
|
1223
|
-
* `Bundle.ethPriceUSD`.
|
|
1567
|
+
* Create a native→USDT quoter backed by the PAFI subgraph's
|
|
1568
|
+
* `Bundle.ethPriceUSD`. The returned function has the shape
|
|
1569
|
+
* `(amountNative: bigint) => Promise<bigint>` and can be passed as
|
|
1570
|
+
* `quoteNativeToFee` to `FeeManager` — in v1.4 the fee currency
|
|
1571
|
+
* is configured at the integration layer, not hardcoded here.
|
|
1224
1572
|
*
|
|
1225
|
-
* Used by `FeeManager.estimateGasFee()` to convert the
|
|
1226
|
-
*
|
|
1227
|
-
* precision is not critical
|
|
1228
|
-
* the
|
|
1573
|
+
* Used by `FeeManager.estimateGasFee()` to convert the gas cost into
|
|
1574
|
+
* an ERC-20 amount charged as part of the sponsored UserOp batch.
|
|
1575
|
+
* Price precision is not critical — a 1-2% drift is acceptable since
|
|
1576
|
+
* the fee manager applies a `gasPremiumBps` buffer.
|
|
1229
1577
|
*
|
|
1230
|
-
* The result is cached in-process with a short TTL (default 30s). If
|
|
1231
|
-
* subgraph is unreachable, falls back to `fallbackEthPriceUsd` so
|
|
1232
|
-
* estimation doesn't block
|
|
1578
|
+
* The result is cached in-process with a short TTL (default 30s). If
|
|
1579
|
+
* the subgraph is unreachable, falls back to `fallbackEthPriceUsd` so
|
|
1580
|
+
* gas estimation doesn't block user flow during a subgraph outage.
|
|
1233
1581
|
*
|
|
1234
1582
|
* @example
|
|
1235
1583
|
* ```ts
|
|
1236
|
-
* import { createSubgraphNativeUsdtQuoter, createIssuerService } from "@pafi/issuer";
|
|
1584
|
+
* import { createSubgraphNativeUsdtQuoter, createIssuerService } from "@pafi-dev/issuer";
|
|
1237
1585
|
*
|
|
1238
1586
|
* const service = createIssuerService({
|
|
1239
1587
|
* // ...other config
|
|
1240
1588
|
* fee: {
|
|
1241
|
-
*
|
|
1589
|
+
* quoteNativeToFee: createSubgraphNativeUsdtQuoter({
|
|
1242
1590
|
* subgraphUrl: "https://graph.pacificfinance.org/subgraphs/name/pafi",
|
|
1243
1591
|
* }),
|
|
1244
1592
|
* },
|
|
@@ -1247,6 +1595,204 @@ interface SubgraphNativeUsdtQuoterConfig {
|
|
|
1247
1595
|
*/
|
|
1248
1596
|
declare function createSubgraphNativeUsdtQuoter(config: SubgraphNativeUsdtQuoterConfig): (amountNative: bigint) => Promise<bigint>;
|
|
1249
1597
|
|
|
1598
|
+
/**
|
|
1599
|
+
* Combined off-chain + on-chain balance for a single user / token pair.
|
|
1600
|
+
*
|
|
1601
|
+
* - `offChain` — the issuer's ledger balance (available, excluding locks)
|
|
1602
|
+
* - `onChain` — the user's ERC-20 balance from `PointToken.balanceOf`
|
|
1603
|
+
* - `total` — `offChain + onChain` (what the Issuer App displays)
|
|
1604
|
+
*/
|
|
1605
|
+
interface CombinedBalance {
|
|
1606
|
+
offChain: bigint;
|
|
1607
|
+
onChain: bigint;
|
|
1608
|
+
total: bigint;
|
|
1609
|
+
}
|
|
1610
|
+
interface BalanceAggregatorConfig {
|
|
1611
|
+
provider: PublicClient;
|
|
1612
|
+
ledger: IPointLedger;
|
|
1613
|
+
}
|
|
1614
|
+
/**
|
|
1615
|
+
* v1.4 utility — aggregates off-chain + on-chain point balances into a
|
|
1616
|
+
* single view for the "combined balance" UI in the Issuer App.
|
|
1617
|
+
*
|
|
1618
|
+
* The `/user` API handler uses this internally; the helper is exposed
|
|
1619
|
+
* publicly so Issuer Apps can call it directly without going through
|
|
1620
|
+
* the HTTP layer (e.g., for server-rendered pages or admin dashboards).
|
|
1621
|
+
*
|
|
1622
|
+
* See [REQUIREMENTS_V2.md] §1 — "The Issuer App displays a combined
|
|
1623
|
+
* balance (off-chain points + on-chain PT) and does not surface USDT."
|
|
1624
|
+
*/
|
|
1625
|
+
declare class BalanceAggregator {
|
|
1626
|
+
private readonly provider;
|
|
1627
|
+
private readonly ledger;
|
|
1628
|
+
constructor(config: BalanceAggregatorConfig);
|
|
1629
|
+
/**
|
|
1630
|
+
* Combined balance for a single (user, token) pair. Fetches off-chain
|
|
1631
|
+
* + on-chain in parallel.
|
|
1632
|
+
*/
|
|
1633
|
+
getCombinedBalance(user: Address, pointToken: Address): Promise<CombinedBalance>;
|
|
1634
|
+
/**
|
|
1635
|
+
* Combined balance for multiple tokens owned by the same user. Runs
|
|
1636
|
+
* all lookups in parallel. Returns a Map keyed by the token address
|
|
1637
|
+
* (same casing as supplied — caller should normalize if needed).
|
|
1638
|
+
*/
|
|
1639
|
+
getCombinedBalanceMulti(user: Address, pointTokens: Address[]): Promise<Map<Address, CombinedBalance>>;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
interface RetryConfig {
|
|
1643
|
+
/**
|
|
1644
|
+
* Max total attempts including the first try. Default: 1 (no retry).
|
|
1645
|
+
* Set to 3 to get 2 retries after the initial call.
|
|
1646
|
+
*
|
|
1647
|
+
* Only applies when the server error body carries `safeToRetry: true`
|
|
1648
|
+
* or the failure is a transient network/timeout error.
|
|
1649
|
+
*/
|
|
1650
|
+
maxAttempts?: number;
|
|
1651
|
+
/**
|
|
1652
|
+
* Initial backoff delay in ms. Default: 500. Each subsequent retry
|
|
1653
|
+
* doubles this (exponential backoff) and adds ±20% jitter.
|
|
1654
|
+
*/
|
|
1655
|
+
initialDelayMs?: number;
|
|
1656
|
+
/**
|
|
1657
|
+
* Hard ceiling for a single backoff (ms). Default: 10_000.
|
|
1658
|
+
*/
|
|
1659
|
+
maxDelayMs?: number;
|
|
1660
|
+
/**
|
|
1661
|
+
* Upper bound on `retryAfter` from the server. If the server asks us
|
|
1662
|
+
* to wait longer than this (e.g. rate limit until UTC midnight), the
|
|
1663
|
+
* client gives up rather than blocking. Default: 30_000.
|
|
1664
|
+
*/
|
|
1665
|
+
maxRetryAfterMs?: number;
|
|
1666
|
+
}
|
|
1667
|
+
interface PafiBackendConfig {
|
|
1668
|
+
/**
|
|
1669
|
+
* PAFI Backend API base URL. Example:
|
|
1670
|
+
* https://api.pacificfinance.org
|
|
1671
|
+
* https://staging-api.pacificfinance.org
|
|
1672
|
+
*/
|
|
1673
|
+
url: string;
|
|
1674
|
+
/** PAFI-assigned issuer ID (e.g., "gg56"). Sent in X-Issuer-Id header. */
|
|
1675
|
+
issuerId: string;
|
|
1676
|
+
/** Per-issuer API key (or JWT) for the Authorization header. */
|
|
1677
|
+
apiKey: string;
|
|
1678
|
+
/** Optional fetch override for tests. */
|
|
1679
|
+
fetchImpl?: typeof fetch;
|
|
1680
|
+
/**
|
|
1681
|
+
* Timeout (ms) for each request. Default: 10_000. PAFI Backend should
|
|
1682
|
+
* respond in <1s for the happy path; this is just the sanity bound.
|
|
1683
|
+
*/
|
|
1684
|
+
timeoutMs?: number;
|
|
1685
|
+
/**
|
|
1686
|
+
* Retry policy for transient failures (5xx, 429, timeouts, network).
|
|
1687
|
+
* Omit or pass `{ maxAttempts: 1 }` to disable retry entirely.
|
|
1688
|
+
*/
|
|
1689
|
+
retry?: RetryConfig;
|
|
1690
|
+
}
|
|
1691
|
+
/** Paired with `POST /paymaster/sponsor`. See SPONSORED_PATH_FLOW.md §4.1 */
|
|
1692
|
+
interface SponsorshipRequest {
|
|
1693
|
+
chainId: number;
|
|
1694
|
+
scenario: SponsorshipScenario;
|
|
1695
|
+
userOp: PartialUserOperation;
|
|
1696
|
+
target: {
|
|
1697
|
+
/** The allowlisted contract this batch call targets. */
|
|
1698
|
+
contract: Address;
|
|
1699
|
+
/** Function selector / name — validated against allowlist. */
|
|
1700
|
+
function: string;
|
|
1701
|
+
/** The PointToken involved (for scenario context). */
|
|
1702
|
+
pointToken?: Address;
|
|
1703
|
+
};
|
|
1704
|
+
}
|
|
1705
|
+
interface SponsorshipResponse {
|
|
1706
|
+
paymaster: Address;
|
|
1707
|
+
paymasterData: Hex;
|
|
1708
|
+
paymasterVerificationGasLimit: bigint;
|
|
1709
|
+
paymasterPostOpGasLimit: bigint;
|
|
1710
|
+
/** Unix seconds when this sponsorship expires. Re-request after. */
|
|
1711
|
+
expiresAt: number;
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Machine-readable error codes returned by PAFI Backend.
|
|
1715
|
+
*
|
|
1716
|
+
* Source of truth: `apps/paymaster-proxy` `CalldataValidationError`,
|
|
1717
|
+
* `RateLimitError`, `CoinbaseClientError`. Keep in sync.
|
|
1718
|
+
*/
|
|
1719
|
+
type PafiBackendErrorCode = "MISSING_ISSUER_ID" | "MISSING_API_KEY" | "ISSUER_UNAUTHORIZED" | "CALLDATA_INVALID" | "CALLDATA_EMPTY_BATCH" | "TARGET_NOT_ALLOWLISTED" | "FUNCTION_NOT_ALLOWED" | "SCENARIO_MISMATCH" | "SCENARIO_DISABLED" | "RATE_LIMIT_EXCEEDED" | "RATE_LIMIT_EXCEEDED_DAILY" | "RATE_LIMIT_EXCEEDED_PER_USER" | "RATE_LIMITER_UNAVAILABLE" | "PAYMASTER_REJECTED" | "PAYMASTER_UNAVAILABLE" | "PAYMASTER_TIMEOUT" | "BAD_REQUEST" | "INTERNAL_ERROR" | "TIMEOUT" | "NETWORK_ERROR";
|
|
1720
|
+
declare class PafiBackendError extends Error {
|
|
1721
|
+
code: PafiBackendErrorCode;
|
|
1722
|
+
httpStatus: number;
|
|
1723
|
+
details?: unknown | undefined;
|
|
1724
|
+
/**
|
|
1725
|
+
* Seconds to wait before retry. Populated from the server body
|
|
1726
|
+
* (e.g. rate limit returns the number of seconds until UTC midnight).
|
|
1727
|
+
*/
|
|
1728
|
+
readonly retryAfter?: number;
|
|
1729
|
+
/**
|
|
1730
|
+
* `safeToRetry` as reported by the server body. Prefer this over the
|
|
1731
|
+
* code-based heuristic when available — the server knows more about
|
|
1732
|
+
* whether the same request will succeed on retry.
|
|
1733
|
+
*/
|
|
1734
|
+
private readonly serverSafeToRetry?;
|
|
1735
|
+
constructor(code: PafiBackendErrorCode, message: string, httpStatus: number, details?: unknown | undefined, opts?: {
|
|
1736
|
+
retryAfter?: number;
|
|
1737
|
+
safeToRetry?: boolean;
|
|
1738
|
+
});
|
|
1739
|
+
/**
|
|
1740
|
+
* Whether the caller can safely retry the same request.
|
|
1741
|
+
*
|
|
1742
|
+
* If the server provided `safeToRetry` in the body, trust that.
|
|
1743
|
+
* Otherwise fall back to a code-based heuristic.
|
|
1744
|
+
*/
|
|
1745
|
+
get safeToRetry(): boolean;
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
/**
|
|
1749
|
+
* HTTP client for the PAFI Backend paymaster proxy service. See
|
|
1750
|
+
* [SPONSORED_PATH_FLOW.md] for the full flow + API contract.
|
|
1751
|
+
*
|
|
1752
|
+
* This client sits between `@pafi/issuer`'s RelayService and the
|
|
1753
|
+
* PAFI Backend. It does NOT talk to Coinbase Paymaster directly —
|
|
1754
|
+
* PAFI Backend holds that integration.
|
|
1755
|
+
*/
|
|
1756
|
+
declare class PafiBackendClient {
|
|
1757
|
+
private readonly url;
|
|
1758
|
+
private readonly issuerId;
|
|
1759
|
+
private readonly apiKey;
|
|
1760
|
+
private readonly fetchImpl;
|
|
1761
|
+
private readonly timeoutMs;
|
|
1762
|
+
private readonly retry;
|
|
1763
|
+
constructor(config: PafiBackendConfig);
|
|
1764
|
+
/**
|
|
1765
|
+
* Request paymaster sponsorship for a pre-built UserOperation.
|
|
1766
|
+
* See [SPONSORED_PATH_FLOW.md §4.1] for the API contract.
|
|
1767
|
+
*
|
|
1768
|
+
* Retries automatically on transient failures (5xx, timeouts, network
|
|
1769
|
+
* errors, and errors the server flags with `safeToRetry: true`) up to
|
|
1770
|
+
* `retry.maxAttempts`. 4xx errors that are not `safeToRetry` fail fast.
|
|
1771
|
+
*
|
|
1772
|
+
* @throws PafiBackendError on final failure after exhausting retries
|
|
1773
|
+
*/
|
|
1774
|
+
requestSponsorship(req: SponsorshipRequest): Promise<SponsorshipResponse>;
|
|
1775
|
+
private postWithRetry;
|
|
1776
|
+
/**
|
|
1777
|
+
* Pick the delay before the next retry.
|
|
1778
|
+
* - If the server sent `retryAfter` (seconds), honor it (capped by
|
|
1779
|
+
* `maxRetryAfterMs`) — returns null if the server wait exceeds the
|
|
1780
|
+
* cap, signalling the caller should give up.
|
|
1781
|
+
* - Otherwise: exponential backoff with ±20% jitter, capped at
|
|
1782
|
+
* `maxDelayMs`.
|
|
1783
|
+
*/
|
|
1784
|
+
private computeBackoff;
|
|
1785
|
+
private sleep;
|
|
1786
|
+
private post;
|
|
1787
|
+
/** JSON replacer that stringifies bigints. Paired with bigintReviver. */
|
|
1788
|
+
private bigintReplacer;
|
|
1789
|
+
/**
|
|
1790
|
+
* JSON reviver that coerces specific numeric-string fields back to
|
|
1791
|
+
* bigint. The server must send these fields as decimal strings.
|
|
1792
|
+
*/
|
|
1793
|
+
private bigintReviver;
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1250
1796
|
/**
|
|
1251
1797
|
* Top-level configuration for `createIssuerService`. Everything except
|
|
1252
1798
|
* the chain metadata, wallets, auth secret, and `signer` is optional and
|
|
@@ -1304,10 +1850,9 @@ interface IssuerServiceConfig {
|
|
|
1304
1850
|
/**
|
|
1305
1851
|
* Fee management config. If omitted the `handleGasFee` endpoint will
|
|
1306
1852
|
* throw "not configured" at request time. Pass any subset of fields
|
|
1307
|
-
* to opt in — provider
|
|
1308
|
-
* config automatically.
|
|
1853
|
+
* to opt in — `provider` is inherited from the outer config.
|
|
1309
1854
|
*/
|
|
1310
|
-
fee?: Omit<FeeManagerConfig, "provider"
|
|
1855
|
+
fee?: Omit<FeeManagerConfig, "provider">;
|
|
1311
1856
|
/**
|
|
1312
1857
|
* Pool discovery function for `handlePools`. If omitted the endpoint
|
|
1313
1858
|
* throws "not configured" at request time.
|
|
@@ -1377,4 +1922,4 @@ declare function createIssuerService(config: IssuerServiceConfig): IssuerService
|
|
|
1377
1922
|
/** SDK package version — bumped on every release */
|
|
1378
1923
|
declare const PAFI_ISSUER_SDK_VERSION = "0.1.0";
|
|
1379
1924
|
|
|
1380
|
-
export { type ApiBuildConsentTypedDataRequest, type ApiBuildConsentTypedDataResponse, type ApiClaimAndSwapRequest, type ApiClaimAndSwapResponse, type ApiConfigResponse, type ApiGasFeeResponse, type ApiLoginRequest, type ApiLoginResponse, type ApiNonceResponse, type ApiPoolsRequest, type ApiPoolsResponse, type ApiUserRequest, type ApiUserResponse, type AuthContext, AuthError, type AuthErrorCode, AuthService, type AuthServiceConfig, DefaultPolicyEngine, type DefaultPolicyEngineOptions, FeeManager, type FeeManagerConfig, type IIndexerCursorStore, type IIssuerSigner, type IPointLedger, type IPolicyEngine, type ISessionStore, InMemoryCursorStore, IssuerApiHandlers, type IssuerApiHandlersConfig, type IssuerService, type IssuerServiceConfig, type LockedMintRequest, type LoginResult, MemoryPointLedger, MemorySessionStore, type MemorySessionStoreOptions, type MintAndCashOutRequest, type MintAndCashOutResponse, type MintEvent, MintingGateway, type MintingGatewayConfig, MintingGatewayError, type MintingGatewayErrorCode, type MintingStatus, NonceManager, type OperatorWalletLike, PAFI_ISSUER_SDK_VERSION, PointIndexer, type PointIndexerConfig, type PolicyDecision, type PolicyEvalRequest, type PoolsProvider, PrivateKeySigner, type PrivateKeySignerOptions, RelayError, type RelayErrorCode, type RelayResult, RelayService, type RelayServiceConfig, type Session, type SubgraphNativeUsdtQuoterConfig, type SubgraphPoolsProviderConfig, type SubmitMintAndSwapParams, authenticateRequest, createIssuerService, createSubgraphNativeUsdtQuoter, createSubgraphPoolsProvider };
|
|
1925
|
+
export { type ApiBuildConsentTypedDataRequest, type ApiBuildConsentTypedDataResponse, type ApiClaimAndSwapRequest, type ApiClaimAndSwapResponse, type ApiConfigResponse, type ApiGasFeeResponse, type ApiLoginRequest, type ApiLoginResponse, type ApiNonceResponse, type ApiPoolsRequest, type ApiPoolsResponse, type ApiUserRequest, type ApiUserResponse, type AuthContext, AuthError, type AuthErrorCode, AuthService, type AuthServiceConfig, BalanceAggregator, type BalanceAggregatorConfig, type BurnEvent, BurnIndexer, type BurnIndexerConfig, type CombinedBalance, DefaultPolicyEngine, type DefaultPolicyEngineOptions, FeeManager, type FeeManagerConfig, type IIndexerCursorStore, type IIssuerSigner, type IPointLedger, type IPolicyEngine, type ISessionStore, InMemoryCursorStore, IssuerApiHandlers, type IssuerApiHandlersConfig, type IssuerService, type IssuerServiceConfig, type LockedMintRequest, type LoginResult, MemoryPointLedger, MemorySessionStore, type MemorySessionStoreOptions, type MintAndCashOutRequest, type MintAndCashOutResponse, type MintEvent, MintingGateway, type MintingGatewayConfig, MintingGatewayError, type MintingGatewayErrorCode, type MintingStatus, NonceManager, type OperatorWalletLike, PAFI_ISSUER_SDK_VERSION, PTRedeemError, PTRedeemHandler, type PTRedeemHandlerConfig, type PTRedeemRequest, type PTRedeemResponse, PafiBackendClient, type PafiBackendConfig, PafiBackendError, type PafiBackendErrorCode, PointIndexer, type PointIndexerConfig, type PolicyDecision, type PolicyEvalRequest, type PoolsProvider, PrivateKeySigner, type PrivateKeySignerOptions, RelayError, type RelayErrorCode, type RelayResult, RelayService, type RelayServiceConfig, type Session, type SponsorshipRequest, type SponsorshipResponse, type SubgraphNativeUsdtQuoterConfig, type SubgraphPoolsProviderConfig, type SubmitMintAndSwapParams, TopUpRedemptionError, TopUpRedemptionHandler, type TopUpRedemptionHandlerConfig, type TopUpRedemptionRequest, type TopUpRedemptionResponse, authenticateRequest, createIssuerService, createSubgraphNativeUsdtQuoter, createSubgraphPoolsProvider };
|