@pafi-dev/issuer 0.22.1 → 0.24.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.d.cts CHANGED
@@ -967,12 +967,37 @@ interface BurnEvent {
967
967
  * number it is about to process so the caller can write it to Redis /
968
968
  * Postgres / a file. The SDK does not own persistence because every
969
969
  * issuer has their own storage stack.
970
+ *
971
+ * **Per-token keying (audit finding H-05).** When multiple PointTokens
972
+ * are wired through a single `createIssuerService` call, each
973
+ * `PointIndexer` MUST get its own cursor — otherwise token A advances
974
+ * the shared cursor past token B's events and token B's mints are
975
+ * never finalized (off-chain balance never deducts → on-chain PT
976
+ * supply for token B exceeds off-chain backing). Combined with the
977
+ * H-04 monotonic-save fix this becomes a catastrophic-and-stable
978
+ * state where token B's cursor can never catch up. Implementations
979
+ * SHOULD expose `forKey(key)` returning a derived store keyed under
980
+ * a distinct namespace; the SDK factory calls it once per token.
981
+ *
982
+ * When `forKey` is absent, the SDK falls back to the bare store and
983
+ * emits a runtime warning if more than one token is configured. New
984
+ * implementations are strongly encouraged to add `forKey`.
970
985
  */
971
986
  interface IIndexerCursorStore {
972
987
  /** Return the last persisted cursor (`undefined` on first run). */
973
988
  load(): Promise<bigint | undefined>;
974
989
  /** Persist a new cursor value. Called after each successful batch. */
975
990
  save(blockNumber: bigint): Promise<void>;
991
+ /**
992
+ * Return a derived store keyed under `key`. The returned store is
993
+ * an independent `IIndexerCursorStore` so the same persistence
994
+ * backend can serve N indexers with N distinct cursors.
995
+ *
996
+ * Optional for backwards compatibility, but REQUIRED in practice
997
+ * whenever more than one PointToken is wired through the SDK
998
+ * factory (see H-05).
999
+ */
1000
+ forKey?(key: string): IIndexerCursorStore;
976
1001
  }
977
1002
  /**
978
1003
  * No-op cursor store. Useful when the caller wants to drive the cursor
@@ -980,49 +1005,19 @@ interface IIndexerCursorStore {
980
1005
  */
981
1006
  declare class InMemoryCursorStore implements IIndexerCursorStore {
982
1007
  private cursor;
1008
+ /**
1009
+ * Child stores keyed by `forKey()`. Each child has its own cursor
1010
+ * (the H-05 fix), so a single InMemoryCursorStore can back N
1011
+ * PointIndexers in tests / single-process callers.
1012
+ */
1013
+ private readonly children;
983
1014
  load(): Promise<bigint | undefined>;
984
1015
  save(blockNumber: bigint): Promise<void>;
1016
+ forKey(key: string): IIndexerCursorStore;
985
1017
  }
986
- /**
987
- * Lock handle returned by a successful `ISingletonLock.acquire()`.
988
- *
989
- * The holder is the leader for the keyed indexer; non-holders MUST NOT
990
- * call `indexer.start()` (else they race against the leader's polling
991
- * loop and last-writer-wins cursor save corrupts replay state).
992
- *
993
- * `release()` is called by the leader on graceful shutdown. If the
994
- * leader crashes without calling release, the lock implementation
995
- * MUST drop the lock automatically (e.g. Postgres advisory locks
996
- * auto-release on connection close).
997
- */
998
1018
  interface SingletonLockHandle {
999
1019
  release(): Promise<void>;
1000
1020
  }
1001
- /**
1002
- * Leader-election primitive for indexer singletons.
1003
- *
1004
- * **Why this exists (audit finding H-04):** the `BurnIndexer` and
1005
- * `PointIndexer` classes are stateful polling loops with a cursor
1006
- * stored in an external store. Running them on multiple replicas
1007
- * simultaneously causes:
1008
- *
1009
- * 1. Double-credit — both replicas see the same Transfer event
1010
- * and call `ledger.resolveCreditByBurnTx` twice.
1011
- * 2. Cursor rewind — last-writer-wins `save()` causes the newer
1012
- * cursor to be overwritten by a lagging replica's older value,
1013
- * causing the next poll to replay events.
1014
- * 3. Skipped blocks — chunked range reads can leave gaps when two
1015
- * replicas race-advance the cursor.
1016
- *
1017
- * **Adoption:** pass `singletonLock` into `IssuerServiceConfig.indexer`
1018
- * (or wire it directly in your provider). The factory will only call
1019
- * `indexer.start()` on the indexers it successfully acquires a lock
1020
- * for; the rest stay idle and take over instantly on lock release.
1021
- *
1022
- * **Implementations:** `makePostgresSingletonLock(dataSource)` (recommended
1023
- * — uses `pg_try_advisory_lock`, auto-releases on connection close).
1024
- * You can also bring your own: Redis SETNX with TTL, etcd lease, etc.
1025
- */
1026
1021
  interface ISingletonLock {
1027
1022
  /**
1028
1023
  * Attempt to acquire the lock for `key`. Returns a handle on success
@@ -1034,6 +1029,23 @@ interface ISingletonLock {
1034
1029
  acquire(key: string): Promise<SingletonLockHandle | null>;
1035
1030
  }
1036
1031
 
1032
+ declare class PointIndexerFinalizeError extends Error {
1033
+ readonly context: {
1034
+ pointToken: Address;
1035
+ to: Address;
1036
+ amount: bigint;
1037
+ txHash: `0x${string}`;
1038
+ blockNumber: bigint;
1039
+ };
1040
+ readonly cause: unknown;
1041
+ constructor(message: string, context: {
1042
+ pointToken: Address;
1043
+ to: Address;
1044
+ amount: bigint;
1045
+ txHash: `0x${string}`;
1046
+ blockNumber: bigint;
1047
+ }, cause: unknown);
1048
+ }
1037
1049
  interface PointIndexerConfig {
1038
1050
  provider: PublicClient;
1039
1051
  pointTokenAddress: Address;
@@ -1184,6 +1196,33 @@ declare class PointIndexer {
1184
1196
  private finalize;
1185
1197
  }
1186
1198
 
1199
+ /**
1200
+ * Mirror of `PointIndexerFinalizeError` — raised when
1201
+ * `ledger.resolveCreditByBurnTx` rejects. See audit M-12: pre-fix this
1202
+ * was silently swallowed and the cursor advanced regardless,
1203
+ * permanently dropping confirmed on-chain burns from the off-chain
1204
+ * credit pipeline. Post-fix the error propagates, the chunk's cursor
1205
+ * save is skipped, and the next tick retries.
1206
+ */
1207
+ declare class BurnIndexerFinalizeError extends Error {
1208
+ readonly context: {
1209
+ pointToken: Address;
1210
+ from: Address;
1211
+ amount: bigint;
1212
+ txHash: `0x${string}`;
1213
+ blockNumber: bigint;
1214
+ lockId: string;
1215
+ };
1216
+ readonly cause: unknown;
1217
+ constructor(message: string, context: {
1218
+ pointToken: Address;
1219
+ from: Address;
1220
+ amount: bigint;
1221
+ txHash: `0x${string}`;
1222
+ blockNumber: bigint;
1223
+ lockId: string;
1224
+ }, cause: unknown);
1225
+ }
1187
1226
  interface BurnIndexerConfig {
1188
1227
  provider: PublicClient;
1189
1228
  pointTokenAddress: Address;
@@ -1242,7 +1281,7 @@ declare class BurnIndexer {
1242
1281
  private readonly provider;
1243
1282
  /**
1244
1283
  * The PointToken this indexer watches. Exposed so callers can key
1245
- * leader-election locks / cursor stores by token (audit H-04 fix).
1284
+ * leader-election locks / cursor stores by token
1246
1285
  */
1247
1286
  readonly pointTokenAddress: Address;
1248
1287
  private readonly ledger;
@@ -3651,34 +3690,48 @@ declare function relayUserOp(params: RelayUserOpParams): Promise<{
3651
3690
  userOpHash: Hex;
3652
3691
  }>;
3653
3692
 
3693
+ /**
3694
+ * Registry record returned by `IssuerRegistry.getIssuer()` in V2
3695
+ * dual-bucket. Schema reshape from V1:
3696
+ *
3697
+ * V1: { issuerAddress, signerAddress, name, symbol, active, pointToken, mintingOracle }
3698
+ * V2: { signerAddress, name, active, capitalBase, basisPoints }
3699
+ *
3700
+ * `issuerAddress` is the lookup key the caller passed; we don't
3701
+ * re-emit it here because the caller already has it. `capitalBase` +
3702
+ * `basisPoints` drive the EQUITY-bucket cap (`capitalBase *
3703
+ * basisPoints / 10000`).
3704
+ */
3654
3705
  interface IssuerRegistryRecord {
3655
- issuerAddress: Address;
3656
3706
  signerAddress: Address;
3657
3707
  name: string;
3658
- symbol: string;
3659
3708
  active: boolean;
3660
- pointToken: Address;
3661
- mintingOracle: Address;
3709
+ capitalBase: bigint;
3710
+ basisPoints: number;
3662
3711
  }
3663
3712
  /**
3664
- * Per-token cap config read from `MintingOracle.tokenCaps()`. Caps
3665
- * live per PointToken (not per issuer), so a single issuer can run
3666
- * many PointTokens with different supply policies.
3713
+ * Equity-bucket cap snapshot computed from the `IssuerRegistryRecord`.
3714
+ *
3715
+ * V1 had a separate `TokenCapRecord` sourced from
3716
+ * `MintingOracle.tokenCaps`; in V2 the oracle is stateless and the
3717
+ * EQUITY cap derives from the registry's `capitalBase` + `basisPoints`.
3718
+ * Kept as a distinct shape (rather than inlining into
3719
+ * `PreValidateMintResult`) so admin tooling can read it without
3720
+ * re-deriving the multiplication.
3667
3721
  */
3668
- interface TokenCapRecord {
3669
- declaredTotalSupply: bigint;
3670
- capBasisPoints: number;
3722
+ interface EquityCapRecord {
3723
+ capitalBase: bigint;
3724
+ basisPoints: number;
3725
+ hardCap: bigint;
3671
3726
  }
3672
3727
  interface PreValidateMintResult {
3673
3728
  /** Registry record read at pre-validation time. */
3674
3729
  issuer: IssuerRegistryRecord;
3675
- /** Per-token cap config from MintingOracle. */
3676
- tokenCap: TokenCapRecord;
3677
- /** Current on-chain PointToken.totalSupply(). */
3678
- totalSupply: bigint;
3679
- /** declaredTotalSupply × capBasisPoints / 10000. */
3680
- hardCap: bigint;
3681
- /** hardCap − totalSupply (clamped to 0). */
3730
+ /** Equity-bucket cap derived from issuer.capitalBase × basisPoints. */
3731
+ equityCap: EquityCapRecord;
3732
+ /** Current on-chain `PointToken.equitySupply()`. */
3733
+ equitySupply: bigint;
3734
+ /** equityCap.hardCap equitySupply (clamped to 0). */
3682
3735
  remaining: bigint;
3683
3736
  }
3684
3737
  /**
@@ -3832,4 +3885,4 @@ declare class MemoryRedemptionHistoryStore implements IRedemptionHistoryStore {
3832
3885
 
3833
3886
  declare const PAFI_ISSUER_SDK_VERSION: string;
3834
3887
 
3835
- export { AdapterMisconfiguredError, type ApiConfigResponse, type ApiGasFeeResponse, type ApiLoginRequest, type ApiLoginResponse, type ApiNonceResponse, type ApiPoolsRequest, type ApiPoolsResponse, type ApiRedemptionEvaluateRequest, type ApiRedemptionEvaluateResponse, type ApiRedemptionPreviewRequest, type ApiRedemptionPreviewResponse, type ApiUserRequest, type ApiUserResponse, type AuthContext, AuthError, type AuthErrorCode, AuthService, type AuthServiceConfig, type BundlerEstimatorClient, BundlerNotConfiguredError, BundlerRejectedError, type BurnEvent, BurnIndexer, type BurnIndexerConfig, type BurnStatusParams, type BurnStatusResponse, type ClaimDto, type ConfigDto, ConfigurationError, DEFAULT_REDEMPTION_POLICY, type DecodedCallDto, DefaultPolicyEngine, type DefaultPolicyEngineOptions, type DelegatePrepareDto, type DelegateStatusDto, type EstimateGasFeeOptions, type EvaluateInput, FeeManager, type FeeManagerConfig, type FeeManagerMetrics, type FetchFailureReason, type FetchImpl, type FetchResult, type GasFeeDto, type GasFeeSource, type HandleDelegateSubmitParams, type HandleDelegateSubmitResult, type HandleMobilePrepareParams, type HandleMobilePrepareResult, type HandleMobileSubmitParams, type IIndexerCursorStore, type IPendingUserOpStore, type IPointLedger, type IPolicyEngine, type IRateLimiter, type IRedemptionHistoryStore, type ISessionStore, type ISingletonLock, InMemoryCursorStore, IssuerApiAdapter, type IssuerApiAdapterConfig, IssuerApiHandlers, type IssuerApiHandlersConfig, type IssuerRegistryRecord, type IssuerService, type IssuerServiceConfig, IssuerStateError, IssuerStateValidator, LockNotFoundError, type LockedMintRequest, type LoginResult, MemoryPendingUserOpStore, MemoryRateLimiter, MemoryRedemptionHistoryStore, MemorySessionStore, type MemorySessionStoreOptions, type MintEvent, type MintStatusParams, type MintStatusResponse, type MintingStatus, type MobilePrepareDto, type MobileSubmitDto, type NativePtQuoterConfig, NonceManager, NoopRateLimiter, PAFI_ISSUER_SDK_VERSION, PTClaimError, PTClaimHandler, type PTClaimHandlerConfig, type PTClaimRequest, type PTClaimResponse, PTRedeemError, PTRedeemHandler, type PTRedeemHandlerConfig, type PTRedeemRequest, type PTRedeemResponse, PafiBackendClient, type PafiBackendConfig, PafiBackendError, type PafiBackendErrorCode, type PafiEstimatorClientConfig, PafiEstimatorHttpError, type PaymasterGasEstimates, type PendingCredit, type PendingUserOpEntry, PendingUserOpForbiddenError, PendingUserOpNotFoundError, type PerpDepositDto, PerpDepositError, PerpDepositHandler, type PerpDepositHandlerConfig, type PerpDepositRequest, type PerpDepositResponse, PointIndexer, type PointIndexerConfig, PointTokenDomainResolver, type PointTokenDomainResolverConfig, type PolicyDecision, type PolicyEvalRequest, PolicyProvider, type PolicyProviderConfig, type PoolsDto, type PoolsProvider, type PostgresQueryRunner, type PreValidateMintResult, type PrepareBurnParams, type PrepareMintParams, type PrepareMobileUserOpParams, type PrepareMobileUserOpResult, type PreparedUserOp, type PreviewBurnParams, type PreviewMintParams, REDEMPTION_HISTORY_WINDOW_SEC, type RateLimitAction, type RateLimiterConfig, type RedeemDto, type RedeemPrepareDto, RedemptionService, type RedemptionServiceConfig, RelayError, type RelayErrorCode, RelayService, type RelayUserOpParams, type RelayUserOpRequest, type RelayUserOpResponse, type RequestPaymasterParams, type ResolvedPolicy, type RetryConfig, type SdkErrorBody, type SdkErrorMapperFactories, type SdkErrorStatus, type SerializedUserOpTypedData, type Session, SettlementClient, type SettlementClientConfig, type SingletonLockHandle, type SponsorshipRequest, type SponsorshipResponse, type SponsorshipTarget, type SponsorshipUserOp, type SubgraphNativeUsdtQuoterConfig, type SubgraphPoolsProviderConfig, type UserDto, type UserHistory, applyPaymasterGasEstimates, authenticateRequest, buildSdkErrorBody, createIssuerService, createNativePtQuoter, createPafiEstimatorClient, createSdkErrorMapper, createSubgraphNativeUsdtQuoter, createSubgraphPoolsProvider, defaultPolicyFor, evaluateRedemption, handleClaimStatus, handleDelegateSubmit, handleMobilePrepare, handleMobileSubmit, handleRedeemStatus, makePostgresSingletonLock, mergePaymasterFields, prepareMobileUserOp, relayUserOp, requestPaymaster, serializeEntryToJsonRpc, serializeUserOpTypedData };
3888
+ export { AdapterMisconfiguredError, type ApiConfigResponse, type ApiGasFeeResponse, type ApiLoginRequest, type ApiLoginResponse, type ApiNonceResponse, type ApiPoolsRequest, type ApiPoolsResponse, type ApiRedemptionEvaluateRequest, type ApiRedemptionEvaluateResponse, type ApiRedemptionPreviewRequest, type ApiRedemptionPreviewResponse, type ApiUserRequest, type ApiUserResponse, type AuthContext, AuthError, type AuthErrorCode, AuthService, type AuthServiceConfig, type BundlerEstimatorClient, BundlerNotConfiguredError, BundlerRejectedError, type BurnEvent, BurnIndexer, type BurnIndexerConfig, BurnIndexerFinalizeError, type BurnStatusParams, type BurnStatusResponse, type ClaimDto, type ConfigDto, ConfigurationError, DEFAULT_REDEMPTION_POLICY, type DecodedCallDto, DefaultPolicyEngine, type DefaultPolicyEngineOptions, type DelegatePrepareDto, type DelegateStatusDto, type EstimateGasFeeOptions, type EvaluateInput, FeeManager, type FeeManagerConfig, type FeeManagerMetrics, type FetchFailureReason, type FetchImpl, type FetchResult, type GasFeeDto, type GasFeeSource, type HandleDelegateSubmitParams, type HandleDelegateSubmitResult, type HandleMobilePrepareParams, type HandleMobilePrepareResult, type HandleMobileSubmitParams, type IIndexerCursorStore, type IPendingUserOpStore, type IPointLedger, type IPolicyEngine, type IRateLimiter, type IRedemptionHistoryStore, type ISessionStore, type ISingletonLock, InMemoryCursorStore, IssuerApiAdapter, type IssuerApiAdapterConfig, IssuerApiHandlers, type IssuerApiHandlersConfig, type IssuerRegistryRecord, type IssuerService, type IssuerServiceConfig, IssuerStateError, IssuerStateValidator, LockNotFoundError, type LockedMintRequest, type LoginResult, MemoryPendingUserOpStore, MemoryRateLimiter, MemoryRedemptionHistoryStore, MemorySessionStore, type MemorySessionStoreOptions, type MintEvent, type MintStatusParams, type MintStatusResponse, type MintingStatus, type MobilePrepareDto, type MobileSubmitDto, type NativePtQuoterConfig, NonceManager, NoopRateLimiter, PAFI_ISSUER_SDK_VERSION, PTClaimError, PTClaimHandler, type PTClaimHandlerConfig, type PTClaimRequest, type PTClaimResponse, PTRedeemError, PTRedeemHandler, type PTRedeemHandlerConfig, type PTRedeemRequest, type PTRedeemResponse, PafiBackendClient, type PafiBackendConfig, PafiBackendError, type PafiBackendErrorCode, type PafiEstimatorClientConfig, PafiEstimatorHttpError, type PaymasterGasEstimates, type PendingCredit, type PendingUserOpEntry, PendingUserOpForbiddenError, PendingUserOpNotFoundError, type PerpDepositDto, PerpDepositError, PerpDepositHandler, type PerpDepositHandlerConfig, type PerpDepositRequest, type PerpDepositResponse, PointIndexer, type PointIndexerConfig, PointIndexerFinalizeError, PointTokenDomainResolver, type PointTokenDomainResolverConfig, type PolicyDecision, type PolicyEvalRequest, PolicyProvider, type PolicyProviderConfig, type PoolsDto, type PoolsProvider, type PostgresQueryRunner, type PreValidateMintResult, type PrepareBurnParams, type PrepareMintParams, type PrepareMobileUserOpParams, type PrepareMobileUserOpResult, type PreparedUserOp, type PreviewBurnParams, type PreviewMintParams, REDEMPTION_HISTORY_WINDOW_SEC, type RateLimitAction, type RateLimiterConfig, type RedeemDto, type RedeemPrepareDto, RedemptionService, type RedemptionServiceConfig, RelayError, type RelayErrorCode, RelayService, type RelayUserOpParams, type RelayUserOpRequest, type RelayUserOpResponse, type RequestPaymasterParams, type ResolvedPolicy, type RetryConfig, type SdkErrorBody, type SdkErrorMapperFactories, type SdkErrorStatus, type SerializedUserOpTypedData, type Session, SettlementClient, type SettlementClientConfig, type SingletonLockHandle, type SponsorshipRequest, type SponsorshipResponse, type SponsorshipTarget, type SponsorshipUserOp, type SubgraphNativeUsdtQuoterConfig, type SubgraphPoolsProviderConfig, type UserDto, type UserHistory, applyPaymasterGasEstimates, authenticateRequest, buildSdkErrorBody, createIssuerService, createNativePtQuoter, createPafiEstimatorClient, createSdkErrorMapper, createSubgraphNativeUsdtQuoter, createSubgraphPoolsProvider, defaultPolicyFor, evaluateRedemption, handleClaimStatus, handleDelegateSubmit, handleMobilePrepare, handleMobileSubmit, handleRedeemStatus, makePostgresSingletonLock, mergePaymasterFields, prepareMobileUserOp, relayUserOp, requestPaymaster, serializeEntryToJsonRpc, serializeUserOpTypedData };
package/dist/index.d.ts CHANGED
@@ -967,12 +967,37 @@ interface BurnEvent {
967
967
  * number it is about to process so the caller can write it to Redis /
968
968
  * Postgres / a file. The SDK does not own persistence because every
969
969
  * issuer has their own storage stack.
970
+ *
971
+ * **Per-token keying (audit finding H-05).** When multiple PointTokens
972
+ * are wired through a single `createIssuerService` call, each
973
+ * `PointIndexer` MUST get its own cursor — otherwise token A advances
974
+ * the shared cursor past token B's events and token B's mints are
975
+ * never finalized (off-chain balance never deducts → on-chain PT
976
+ * supply for token B exceeds off-chain backing). Combined with the
977
+ * H-04 monotonic-save fix this becomes a catastrophic-and-stable
978
+ * state where token B's cursor can never catch up. Implementations
979
+ * SHOULD expose `forKey(key)` returning a derived store keyed under
980
+ * a distinct namespace; the SDK factory calls it once per token.
981
+ *
982
+ * When `forKey` is absent, the SDK falls back to the bare store and
983
+ * emits a runtime warning if more than one token is configured. New
984
+ * implementations are strongly encouraged to add `forKey`.
970
985
  */
971
986
  interface IIndexerCursorStore {
972
987
  /** Return the last persisted cursor (`undefined` on first run). */
973
988
  load(): Promise<bigint | undefined>;
974
989
  /** Persist a new cursor value. Called after each successful batch. */
975
990
  save(blockNumber: bigint): Promise<void>;
991
+ /**
992
+ * Return a derived store keyed under `key`. The returned store is
993
+ * an independent `IIndexerCursorStore` so the same persistence
994
+ * backend can serve N indexers with N distinct cursors.
995
+ *
996
+ * Optional for backwards compatibility, but REQUIRED in practice
997
+ * whenever more than one PointToken is wired through the SDK
998
+ * factory (see H-05).
999
+ */
1000
+ forKey?(key: string): IIndexerCursorStore;
976
1001
  }
977
1002
  /**
978
1003
  * No-op cursor store. Useful when the caller wants to drive the cursor
@@ -980,49 +1005,19 @@ interface IIndexerCursorStore {
980
1005
  */
981
1006
  declare class InMemoryCursorStore implements IIndexerCursorStore {
982
1007
  private cursor;
1008
+ /**
1009
+ * Child stores keyed by `forKey()`. Each child has its own cursor
1010
+ * (the H-05 fix), so a single InMemoryCursorStore can back N
1011
+ * PointIndexers in tests / single-process callers.
1012
+ */
1013
+ private readonly children;
983
1014
  load(): Promise<bigint | undefined>;
984
1015
  save(blockNumber: bigint): Promise<void>;
1016
+ forKey(key: string): IIndexerCursorStore;
985
1017
  }
986
- /**
987
- * Lock handle returned by a successful `ISingletonLock.acquire()`.
988
- *
989
- * The holder is the leader for the keyed indexer; non-holders MUST NOT
990
- * call `indexer.start()` (else they race against the leader's polling
991
- * loop and last-writer-wins cursor save corrupts replay state).
992
- *
993
- * `release()` is called by the leader on graceful shutdown. If the
994
- * leader crashes without calling release, the lock implementation
995
- * MUST drop the lock automatically (e.g. Postgres advisory locks
996
- * auto-release on connection close).
997
- */
998
1018
  interface SingletonLockHandle {
999
1019
  release(): Promise<void>;
1000
1020
  }
1001
- /**
1002
- * Leader-election primitive for indexer singletons.
1003
- *
1004
- * **Why this exists (audit finding H-04):** the `BurnIndexer` and
1005
- * `PointIndexer` classes are stateful polling loops with a cursor
1006
- * stored in an external store. Running them on multiple replicas
1007
- * simultaneously causes:
1008
- *
1009
- * 1. Double-credit — both replicas see the same Transfer event
1010
- * and call `ledger.resolveCreditByBurnTx` twice.
1011
- * 2. Cursor rewind — last-writer-wins `save()` causes the newer
1012
- * cursor to be overwritten by a lagging replica's older value,
1013
- * causing the next poll to replay events.
1014
- * 3. Skipped blocks — chunked range reads can leave gaps when two
1015
- * replicas race-advance the cursor.
1016
- *
1017
- * **Adoption:** pass `singletonLock` into `IssuerServiceConfig.indexer`
1018
- * (or wire it directly in your provider). The factory will only call
1019
- * `indexer.start()` on the indexers it successfully acquires a lock
1020
- * for; the rest stay idle and take over instantly on lock release.
1021
- *
1022
- * **Implementations:** `makePostgresSingletonLock(dataSource)` (recommended
1023
- * — uses `pg_try_advisory_lock`, auto-releases on connection close).
1024
- * You can also bring your own: Redis SETNX with TTL, etcd lease, etc.
1025
- */
1026
1021
  interface ISingletonLock {
1027
1022
  /**
1028
1023
  * Attempt to acquire the lock for `key`. Returns a handle on success
@@ -1034,6 +1029,23 @@ interface ISingletonLock {
1034
1029
  acquire(key: string): Promise<SingletonLockHandle | null>;
1035
1030
  }
1036
1031
 
1032
+ declare class PointIndexerFinalizeError extends Error {
1033
+ readonly context: {
1034
+ pointToken: Address;
1035
+ to: Address;
1036
+ amount: bigint;
1037
+ txHash: `0x${string}`;
1038
+ blockNumber: bigint;
1039
+ };
1040
+ readonly cause: unknown;
1041
+ constructor(message: string, context: {
1042
+ pointToken: Address;
1043
+ to: Address;
1044
+ amount: bigint;
1045
+ txHash: `0x${string}`;
1046
+ blockNumber: bigint;
1047
+ }, cause: unknown);
1048
+ }
1037
1049
  interface PointIndexerConfig {
1038
1050
  provider: PublicClient;
1039
1051
  pointTokenAddress: Address;
@@ -1184,6 +1196,33 @@ declare class PointIndexer {
1184
1196
  private finalize;
1185
1197
  }
1186
1198
 
1199
+ /**
1200
+ * Mirror of `PointIndexerFinalizeError` — raised when
1201
+ * `ledger.resolveCreditByBurnTx` rejects. See audit M-12: pre-fix this
1202
+ * was silently swallowed and the cursor advanced regardless,
1203
+ * permanently dropping confirmed on-chain burns from the off-chain
1204
+ * credit pipeline. Post-fix the error propagates, the chunk's cursor
1205
+ * save is skipped, and the next tick retries.
1206
+ */
1207
+ declare class BurnIndexerFinalizeError extends Error {
1208
+ readonly context: {
1209
+ pointToken: Address;
1210
+ from: Address;
1211
+ amount: bigint;
1212
+ txHash: `0x${string}`;
1213
+ blockNumber: bigint;
1214
+ lockId: string;
1215
+ };
1216
+ readonly cause: unknown;
1217
+ constructor(message: string, context: {
1218
+ pointToken: Address;
1219
+ from: Address;
1220
+ amount: bigint;
1221
+ txHash: `0x${string}`;
1222
+ blockNumber: bigint;
1223
+ lockId: string;
1224
+ }, cause: unknown);
1225
+ }
1187
1226
  interface BurnIndexerConfig {
1188
1227
  provider: PublicClient;
1189
1228
  pointTokenAddress: Address;
@@ -1242,7 +1281,7 @@ declare class BurnIndexer {
1242
1281
  private readonly provider;
1243
1282
  /**
1244
1283
  * The PointToken this indexer watches. Exposed so callers can key
1245
- * leader-election locks / cursor stores by token (audit H-04 fix).
1284
+ * leader-election locks / cursor stores by token
1246
1285
  */
1247
1286
  readonly pointTokenAddress: Address;
1248
1287
  private readonly ledger;
@@ -3651,34 +3690,48 @@ declare function relayUserOp(params: RelayUserOpParams): Promise<{
3651
3690
  userOpHash: Hex;
3652
3691
  }>;
3653
3692
 
3693
+ /**
3694
+ * Registry record returned by `IssuerRegistry.getIssuer()` in V2
3695
+ * dual-bucket. Schema reshape from V1:
3696
+ *
3697
+ * V1: { issuerAddress, signerAddress, name, symbol, active, pointToken, mintingOracle }
3698
+ * V2: { signerAddress, name, active, capitalBase, basisPoints }
3699
+ *
3700
+ * `issuerAddress` is the lookup key the caller passed; we don't
3701
+ * re-emit it here because the caller already has it. `capitalBase` +
3702
+ * `basisPoints` drive the EQUITY-bucket cap (`capitalBase *
3703
+ * basisPoints / 10000`).
3704
+ */
3654
3705
  interface IssuerRegistryRecord {
3655
- issuerAddress: Address;
3656
3706
  signerAddress: Address;
3657
3707
  name: string;
3658
- symbol: string;
3659
3708
  active: boolean;
3660
- pointToken: Address;
3661
- mintingOracle: Address;
3709
+ capitalBase: bigint;
3710
+ basisPoints: number;
3662
3711
  }
3663
3712
  /**
3664
- * Per-token cap config read from `MintingOracle.tokenCaps()`. Caps
3665
- * live per PointToken (not per issuer), so a single issuer can run
3666
- * many PointTokens with different supply policies.
3713
+ * Equity-bucket cap snapshot computed from the `IssuerRegistryRecord`.
3714
+ *
3715
+ * V1 had a separate `TokenCapRecord` sourced from
3716
+ * `MintingOracle.tokenCaps`; in V2 the oracle is stateless and the
3717
+ * EQUITY cap derives from the registry's `capitalBase` + `basisPoints`.
3718
+ * Kept as a distinct shape (rather than inlining into
3719
+ * `PreValidateMintResult`) so admin tooling can read it without
3720
+ * re-deriving the multiplication.
3667
3721
  */
3668
- interface TokenCapRecord {
3669
- declaredTotalSupply: bigint;
3670
- capBasisPoints: number;
3722
+ interface EquityCapRecord {
3723
+ capitalBase: bigint;
3724
+ basisPoints: number;
3725
+ hardCap: bigint;
3671
3726
  }
3672
3727
  interface PreValidateMintResult {
3673
3728
  /** Registry record read at pre-validation time. */
3674
3729
  issuer: IssuerRegistryRecord;
3675
- /** Per-token cap config from MintingOracle. */
3676
- tokenCap: TokenCapRecord;
3677
- /** Current on-chain PointToken.totalSupply(). */
3678
- totalSupply: bigint;
3679
- /** declaredTotalSupply × capBasisPoints / 10000. */
3680
- hardCap: bigint;
3681
- /** hardCap − totalSupply (clamped to 0). */
3730
+ /** Equity-bucket cap derived from issuer.capitalBase × basisPoints. */
3731
+ equityCap: EquityCapRecord;
3732
+ /** Current on-chain `PointToken.equitySupply()`. */
3733
+ equitySupply: bigint;
3734
+ /** equityCap.hardCap equitySupply (clamped to 0). */
3682
3735
  remaining: bigint;
3683
3736
  }
3684
3737
  /**
@@ -3832,4 +3885,4 @@ declare class MemoryRedemptionHistoryStore implements IRedemptionHistoryStore {
3832
3885
 
3833
3886
  declare const PAFI_ISSUER_SDK_VERSION: string;
3834
3887
 
3835
- export { AdapterMisconfiguredError, type ApiConfigResponse, type ApiGasFeeResponse, type ApiLoginRequest, type ApiLoginResponse, type ApiNonceResponse, type ApiPoolsRequest, type ApiPoolsResponse, type ApiRedemptionEvaluateRequest, type ApiRedemptionEvaluateResponse, type ApiRedemptionPreviewRequest, type ApiRedemptionPreviewResponse, type ApiUserRequest, type ApiUserResponse, type AuthContext, AuthError, type AuthErrorCode, AuthService, type AuthServiceConfig, type BundlerEstimatorClient, BundlerNotConfiguredError, BundlerRejectedError, type BurnEvent, BurnIndexer, type BurnIndexerConfig, type BurnStatusParams, type BurnStatusResponse, type ClaimDto, type ConfigDto, ConfigurationError, DEFAULT_REDEMPTION_POLICY, type DecodedCallDto, DefaultPolicyEngine, type DefaultPolicyEngineOptions, type DelegatePrepareDto, type DelegateStatusDto, type EstimateGasFeeOptions, type EvaluateInput, FeeManager, type FeeManagerConfig, type FeeManagerMetrics, type FetchFailureReason, type FetchImpl, type FetchResult, type GasFeeDto, type GasFeeSource, type HandleDelegateSubmitParams, type HandleDelegateSubmitResult, type HandleMobilePrepareParams, type HandleMobilePrepareResult, type HandleMobileSubmitParams, type IIndexerCursorStore, type IPendingUserOpStore, type IPointLedger, type IPolicyEngine, type IRateLimiter, type IRedemptionHistoryStore, type ISessionStore, type ISingletonLock, InMemoryCursorStore, IssuerApiAdapter, type IssuerApiAdapterConfig, IssuerApiHandlers, type IssuerApiHandlersConfig, type IssuerRegistryRecord, type IssuerService, type IssuerServiceConfig, IssuerStateError, IssuerStateValidator, LockNotFoundError, type LockedMintRequest, type LoginResult, MemoryPendingUserOpStore, MemoryRateLimiter, MemoryRedemptionHistoryStore, MemorySessionStore, type MemorySessionStoreOptions, type MintEvent, type MintStatusParams, type MintStatusResponse, type MintingStatus, type MobilePrepareDto, type MobileSubmitDto, type NativePtQuoterConfig, NonceManager, NoopRateLimiter, PAFI_ISSUER_SDK_VERSION, PTClaimError, PTClaimHandler, type PTClaimHandlerConfig, type PTClaimRequest, type PTClaimResponse, PTRedeemError, PTRedeemHandler, type PTRedeemHandlerConfig, type PTRedeemRequest, type PTRedeemResponse, PafiBackendClient, type PafiBackendConfig, PafiBackendError, type PafiBackendErrorCode, type PafiEstimatorClientConfig, PafiEstimatorHttpError, type PaymasterGasEstimates, type PendingCredit, type PendingUserOpEntry, PendingUserOpForbiddenError, PendingUserOpNotFoundError, type PerpDepositDto, PerpDepositError, PerpDepositHandler, type PerpDepositHandlerConfig, type PerpDepositRequest, type PerpDepositResponse, PointIndexer, type PointIndexerConfig, PointTokenDomainResolver, type PointTokenDomainResolverConfig, type PolicyDecision, type PolicyEvalRequest, PolicyProvider, type PolicyProviderConfig, type PoolsDto, type PoolsProvider, type PostgresQueryRunner, type PreValidateMintResult, type PrepareBurnParams, type PrepareMintParams, type PrepareMobileUserOpParams, type PrepareMobileUserOpResult, type PreparedUserOp, type PreviewBurnParams, type PreviewMintParams, REDEMPTION_HISTORY_WINDOW_SEC, type RateLimitAction, type RateLimiterConfig, type RedeemDto, type RedeemPrepareDto, RedemptionService, type RedemptionServiceConfig, RelayError, type RelayErrorCode, RelayService, type RelayUserOpParams, type RelayUserOpRequest, type RelayUserOpResponse, type RequestPaymasterParams, type ResolvedPolicy, type RetryConfig, type SdkErrorBody, type SdkErrorMapperFactories, type SdkErrorStatus, type SerializedUserOpTypedData, type Session, SettlementClient, type SettlementClientConfig, type SingletonLockHandle, type SponsorshipRequest, type SponsorshipResponse, type SponsorshipTarget, type SponsorshipUserOp, type SubgraphNativeUsdtQuoterConfig, type SubgraphPoolsProviderConfig, type UserDto, type UserHistory, applyPaymasterGasEstimates, authenticateRequest, buildSdkErrorBody, createIssuerService, createNativePtQuoter, createPafiEstimatorClient, createSdkErrorMapper, createSubgraphNativeUsdtQuoter, createSubgraphPoolsProvider, defaultPolicyFor, evaluateRedemption, handleClaimStatus, handleDelegateSubmit, handleMobilePrepare, handleMobileSubmit, handleRedeemStatus, makePostgresSingletonLock, mergePaymasterFields, prepareMobileUserOp, relayUserOp, requestPaymaster, serializeEntryToJsonRpc, serializeUserOpTypedData };
3888
+ export { AdapterMisconfiguredError, type ApiConfigResponse, type ApiGasFeeResponse, type ApiLoginRequest, type ApiLoginResponse, type ApiNonceResponse, type ApiPoolsRequest, type ApiPoolsResponse, type ApiRedemptionEvaluateRequest, type ApiRedemptionEvaluateResponse, type ApiRedemptionPreviewRequest, type ApiRedemptionPreviewResponse, type ApiUserRequest, type ApiUserResponse, type AuthContext, AuthError, type AuthErrorCode, AuthService, type AuthServiceConfig, type BundlerEstimatorClient, BundlerNotConfiguredError, BundlerRejectedError, type BurnEvent, BurnIndexer, type BurnIndexerConfig, BurnIndexerFinalizeError, type BurnStatusParams, type BurnStatusResponse, type ClaimDto, type ConfigDto, ConfigurationError, DEFAULT_REDEMPTION_POLICY, type DecodedCallDto, DefaultPolicyEngine, type DefaultPolicyEngineOptions, type DelegatePrepareDto, type DelegateStatusDto, type EstimateGasFeeOptions, type EvaluateInput, FeeManager, type FeeManagerConfig, type FeeManagerMetrics, type FetchFailureReason, type FetchImpl, type FetchResult, type GasFeeDto, type GasFeeSource, type HandleDelegateSubmitParams, type HandleDelegateSubmitResult, type HandleMobilePrepareParams, type HandleMobilePrepareResult, type HandleMobileSubmitParams, type IIndexerCursorStore, type IPendingUserOpStore, type IPointLedger, type IPolicyEngine, type IRateLimiter, type IRedemptionHistoryStore, type ISessionStore, type ISingletonLock, InMemoryCursorStore, IssuerApiAdapter, type IssuerApiAdapterConfig, IssuerApiHandlers, type IssuerApiHandlersConfig, type IssuerRegistryRecord, type IssuerService, type IssuerServiceConfig, IssuerStateError, IssuerStateValidator, LockNotFoundError, type LockedMintRequest, type LoginResult, MemoryPendingUserOpStore, MemoryRateLimiter, MemoryRedemptionHistoryStore, MemorySessionStore, type MemorySessionStoreOptions, type MintEvent, type MintStatusParams, type MintStatusResponse, type MintingStatus, type MobilePrepareDto, type MobileSubmitDto, type NativePtQuoterConfig, NonceManager, NoopRateLimiter, PAFI_ISSUER_SDK_VERSION, PTClaimError, PTClaimHandler, type PTClaimHandlerConfig, type PTClaimRequest, type PTClaimResponse, PTRedeemError, PTRedeemHandler, type PTRedeemHandlerConfig, type PTRedeemRequest, type PTRedeemResponse, PafiBackendClient, type PafiBackendConfig, PafiBackendError, type PafiBackendErrorCode, type PafiEstimatorClientConfig, PafiEstimatorHttpError, type PaymasterGasEstimates, type PendingCredit, type PendingUserOpEntry, PendingUserOpForbiddenError, PendingUserOpNotFoundError, type PerpDepositDto, PerpDepositError, PerpDepositHandler, type PerpDepositHandlerConfig, type PerpDepositRequest, type PerpDepositResponse, PointIndexer, type PointIndexerConfig, PointIndexerFinalizeError, PointTokenDomainResolver, type PointTokenDomainResolverConfig, type PolicyDecision, type PolicyEvalRequest, PolicyProvider, type PolicyProviderConfig, type PoolsDto, type PoolsProvider, type PostgresQueryRunner, type PreValidateMintResult, type PrepareBurnParams, type PrepareMintParams, type PrepareMobileUserOpParams, type PrepareMobileUserOpResult, type PreparedUserOp, type PreviewBurnParams, type PreviewMintParams, REDEMPTION_HISTORY_WINDOW_SEC, type RateLimitAction, type RateLimiterConfig, type RedeemDto, type RedeemPrepareDto, RedemptionService, type RedemptionServiceConfig, RelayError, type RelayErrorCode, RelayService, type RelayUserOpParams, type RelayUserOpRequest, type RelayUserOpResponse, type RequestPaymasterParams, type ResolvedPolicy, type RetryConfig, type SdkErrorBody, type SdkErrorMapperFactories, type SdkErrorStatus, type SerializedUserOpTypedData, type Session, SettlementClient, type SettlementClientConfig, type SingletonLockHandle, type SponsorshipRequest, type SponsorshipResponse, type SponsorshipTarget, type SponsorshipUserOp, type SubgraphNativeUsdtQuoterConfig, type SubgraphPoolsProviderConfig, type UserDto, type UserHistory, applyPaymasterGasEstimates, authenticateRequest, buildSdkErrorBody, createIssuerService, createNativePtQuoter, createPafiEstimatorClient, createSdkErrorMapper, createSubgraphNativeUsdtQuoter, createSubgraphPoolsProvider, defaultPolicyFor, evaluateRedemption, handleClaimStatus, handleDelegateSubmit, handleMobilePrepare, handleMobileSubmit, handleRedeemStatus, makePostgresSingletonLock, mergePaymasterFields, prepareMobileUserOp, relayUserOp, requestPaymaster, serializeEntryToJsonRpc, serializeUserOpTypedData };