@pafi-dev/issuer 0.5.9 → 0.5.11

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
@@ -1599,7 +1599,147 @@ interface IssuerService {
1599
1599
  */
1600
1600
  declare function createIssuerService(config: IssuerServiceConfig): IssuerService;
1601
1601
 
1602
+ /**
1603
+ * A pending UserOp serialized for persistent storage (Redis, Postgres, memory).
1604
+ *
1605
+ * All bigint fields are stored as decimal strings so the entry can be
1606
+ * JSON-serialized without precision loss. Convert back to bigint before
1607
+ * calling `computeUserOpHash` or `serializeUserOpToJsonRpc`.
1608
+ */
1609
+ interface PendingUserOpEntry {
1610
+ sender: Address;
1611
+ nonce: string;
1612
+ callData: Hex;
1613
+ callGasLimit: string;
1614
+ verificationGasLimit: string;
1615
+ preVerificationGas: string;
1616
+ maxFeePerGas: string;
1617
+ maxPriorityFeePerGas: string;
1618
+ paymaster?: Address;
1619
+ paymasterVerificationGasLimit?: string;
1620
+ paymasterPostOpGasLimit?: string;
1621
+ paymasterData?: Hex;
1622
+ chainId: number;
1623
+ /** Hex-encoded userOpHash — the value the user signed via personal_sign. */
1624
+ userOpHash: Hex;
1625
+ }
1626
+ /**
1627
+ * Storage backend for pending UserOps in the mobile prepare/submit pattern.
1628
+ *
1629
+ * Implement this interface and wire it into your issuer backend:
1630
+ * - `save()` — called by `POST /claim/prepare` and `POST /redeem/prepare`
1631
+ * - `get()` — called by `POST /claim/submit` and `POST /redeem/submit`
1632
+ * - `delete()` — called after successful submit or explicit cancellation
1633
+ *
1634
+ * The default implementation in the gg56 boilerplate uses Redis with
1635
+ * a short TTL matching the MintRequest / BurnRequest deadline.
1636
+ */
1637
+ interface IPendingUserOpStore {
1638
+ save(lockId: string, entry: PendingUserOpEntry, ttlSeconds: number): Promise<void>;
1639
+ get(lockId: string): Promise<PendingUserOpEntry | null>;
1640
+ delete(lockId: string): Promise<void>;
1641
+ }
1642
+
1643
+ /**
1644
+ * Convert a stored `PendingUserOpEntry` (decimal-string fields) plus a
1645
+ * signature into the JSON-RPC wire format for `eth_sendUserOperation`.
1646
+ *
1647
+ * Bridges the gap between the serialized storage format (decimal strings,
1648
+ * safe for JSON/Redis) and `serializeUserOpToJsonRpc` which expects bigints.
1649
+ */
1650
+ declare function serializeEntryToJsonRpc(entry: PendingUserOpEntry, signature: Hex): Record<string, string | null>;
1651
+
1652
+ interface IssuerRegistryRecord {
1653
+ issuerAddress: Address;
1654
+ signerAddress: Address;
1655
+ name: string;
1656
+ symbol: string;
1657
+ declaredTotalSupply: bigint;
1658
+ capBasisPoints: number;
1659
+ active: boolean;
1660
+ pointToken: Address;
1661
+ mintingOracle: Address;
1662
+ }
1663
+ interface PreValidateMintResult {
1664
+ /** Registry record read at pre-validation time. */
1665
+ issuer: IssuerRegistryRecord;
1666
+ /** Current on-chain PointToken.totalSupply(). */
1667
+ totalSupply: bigint;
1668
+ /** declaredTotalSupply × capBasisPoints / 10000. */
1669
+ hardCap: bigint;
1670
+ /** hardCap − totalSupply (clamped to 0). */
1671
+ remaining: bigint;
1672
+ }
1673
+ /**
1674
+ * Thrown by `IssuerStateValidator.preValidateMint()`.
1675
+ * `code` maps 1:1 to the HTTP error the issuer API surfaces to clients.
1676
+ */
1677
+ declare class IssuerStateError extends Error {
1678
+ readonly code: "ISSUER_NOT_REGISTERED" | "ISSUER_INACTIVE" | "MINT_CAP_EXCEEDED";
1679
+ readonly details?: Record<string, unknown> | undefined;
1680
+ constructor(code: "ISSUER_NOT_REGISTERED" | "ISSUER_INACTIVE" | "MINT_CAP_EXCEEDED", message: string, details?: Record<string, unknown> | undefined);
1681
+ }
1682
+
1683
+ /**
1684
+ * Pure (framework-agnostic) validator for issuer state.
1685
+ *
1686
+ * Reads IssuerRegistry + PointToken on-chain state and pre-validates
1687
+ * mint requests before the user submits a UserOp. Catching these
1688
+ * off-chain lets issuers fail fast with a clear error rather than
1689
+ * wasting gas on a revert.
1690
+ *
1691
+ * Caching:
1692
+ * - `PointToken.issuer()` — memoized for the process lifetime (immutable)
1693
+ * - Full state (registry + totalSupply) — 30s TTL per PointToken
1694
+ * - Burst calls while a fetch is in-flight share the same Promise
1695
+ * (thundering-herd protection)
1696
+ *
1697
+ * Usage in NestJS: wrap this in an `@Injectable()` service; pass
1698
+ * `PublicClient` and `registryAddress` from your DI container.
1699
+ */
1700
+ declare class IssuerStateValidator {
1701
+ private readonly provider;
1702
+ private readonly registryAddress;
1703
+ private readonly pointTokenIssuerCache;
1704
+ private readonly stateCache;
1705
+ private readonly inflight;
1706
+ constructor(provider: PublicClient, registryAddress: Address);
1707
+ /**
1708
+ * Convenience factory — reads `registryAddress` from the SDK
1709
+ * `CONTRACT_ADDRESSES` map for the given chain.
1710
+ */
1711
+ static forChain(provider: PublicClient, chainId: number): IssuerStateValidator;
1712
+ /**
1713
+ * Invalidate cached state for one PointToken, or everything if omitted.
1714
+ * Call after admin txs that change registry or cap settings.
1715
+ */
1716
+ invalidate(pointToken?: Address): void;
1717
+ /**
1718
+ * Resolve `PointToken.issuer()` once per token and memoize.
1719
+ * The issuer field is set at `initialize()` and never changes.
1720
+ */
1721
+ getIssuerAddressForPointToken(pointToken: Address): Promise<Address>;
1722
+ /**
1723
+ * Read registry record + totalSupply, with 30s cache and in-flight
1724
+ * deduplication. Does NOT throw on inactive/missing — returns raw state.
1725
+ */
1726
+ getIssuerState(pointToken: Address): Promise<PreValidateMintResult>;
1727
+ /**
1728
+ * Validate that `amount` PT can be minted on `pointToken` right now.
1729
+ *
1730
+ * Throws `IssuerStateError` with:
1731
+ * - `ISSUER_NOT_REGISTERED` — registry has no record for this issuer
1732
+ * - `ISSUER_INACTIVE` — issuer.active is false
1733
+ * - `MINT_CAP_EXCEEDED` — totalSupply + amount would exceed hardCap
1734
+ *
1735
+ * Returns the fetched state on success so callers can log without a
1736
+ * second RPC round-trip.
1737
+ */
1738
+ preValidateMint(pointToken: Address, amount: bigint): Promise<PreValidateMintResult>;
1739
+ private fetchIssuerState;
1740
+ }
1741
+
1602
1742
  /** SDK package version — bumped on every release */
1603
1743
  declare const PAFI_ISSUER_SDK_VERSION = "0.4.0";
1604
1744
 
1605
- export { type ApiClaimRequest, type ApiClaimResponse, type ApiConfigResponse, type ApiGasFeeResponse, type ApiLoginRequest, type ApiLoginResponse, type ApiNonceResponse, type ApiPoolsRequest, type ApiPoolsResponse, type ApiRedeemRequest, type ApiRedeemResponse, type ApiTopUpRequest, type ApiTopUpResponse, 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 IPointLedger, type IPolicyEngine, type ISessionStore, InMemoryCursorStore, IssuerApiHandlers, type IssuerApiHandlersConfig, type IssuerService, type IssuerServiceConfig, type LockedMintRequest, type LoginResult, MemorySessionStore, type MemorySessionStoreOptions, type MintEvent, type MintingStatus, NonceManager, 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, type PrepareBurnDirectParams, type PrepareBurnParams, type PrepareBurnWithSigParams, type PrepareMintParams, RelayError, type RelayErrorCode, RelayService, type RelayUserOpRequest, type RelayUserOpResponse, type RetryConfig, type Session, type SponsorshipRequest, type SponsorshipResponse, type SponsorshipTarget, type SponsorshipUserOp, type SubgraphNativeUsdtQuoterConfig, type SubgraphPoolsProviderConfig, TopUpRedemptionError, TopUpRedemptionHandler, type TopUpRedemptionHandlerConfig, type TopUpRedemptionRequest, type TopUpRedemptionResponse, authenticateRequest, createIssuerService, createSubgraphNativeUsdtQuoter, createSubgraphPoolsProvider };
1745
+ export { type ApiClaimRequest, type ApiClaimResponse, type ApiConfigResponse, type ApiGasFeeResponse, type ApiLoginRequest, type ApiLoginResponse, type ApiNonceResponse, type ApiPoolsRequest, type ApiPoolsResponse, type ApiRedeemRequest, type ApiRedeemResponse, type ApiTopUpRequest, type ApiTopUpResponse, 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 IPendingUserOpStore, type IPointLedger, type IPolicyEngine, type ISessionStore, InMemoryCursorStore, IssuerApiHandlers, type IssuerApiHandlersConfig, type IssuerRegistryRecord, type IssuerService, type IssuerServiceConfig, IssuerStateError, IssuerStateValidator, type LockedMintRequest, type LoginResult, MemorySessionStore, type MemorySessionStoreOptions, type MintEvent, type MintingStatus, NonceManager, PAFI_ISSUER_SDK_VERSION, PTRedeemError, PTRedeemHandler, type PTRedeemHandlerConfig, type PTRedeemRequest, type PTRedeemResponse, PafiBackendClient, type PafiBackendConfig, PafiBackendError, type PafiBackendErrorCode, type PendingUserOpEntry, PointIndexer, type PointIndexerConfig, type PolicyDecision, type PolicyEvalRequest, type PoolsProvider, type PreValidateMintResult, type PrepareBurnDirectParams, type PrepareBurnParams, type PrepareBurnWithSigParams, type PrepareMintParams, RelayError, type RelayErrorCode, RelayService, type RelayUserOpRequest, type RelayUserOpResponse, type RetryConfig, type Session, type SponsorshipRequest, type SponsorshipResponse, type SponsorshipTarget, type SponsorshipUserOp, type SubgraphNativeUsdtQuoterConfig, type SubgraphPoolsProviderConfig, TopUpRedemptionError, TopUpRedemptionHandler, type TopUpRedemptionHandlerConfig, type TopUpRedemptionRequest, type TopUpRedemptionResponse, authenticateRequest, createIssuerService, createSubgraphNativeUsdtQuoter, createSubgraphPoolsProvider, serializeEntryToJsonRpc };
package/dist/index.d.ts CHANGED
@@ -1599,7 +1599,147 @@ interface IssuerService {
1599
1599
  */
1600
1600
  declare function createIssuerService(config: IssuerServiceConfig): IssuerService;
1601
1601
 
1602
+ /**
1603
+ * A pending UserOp serialized for persistent storage (Redis, Postgres, memory).
1604
+ *
1605
+ * All bigint fields are stored as decimal strings so the entry can be
1606
+ * JSON-serialized without precision loss. Convert back to bigint before
1607
+ * calling `computeUserOpHash` or `serializeUserOpToJsonRpc`.
1608
+ */
1609
+ interface PendingUserOpEntry {
1610
+ sender: Address;
1611
+ nonce: string;
1612
+ callData: Hex;
1613
+ callGasLimit: string;
1614
+ verificationGasLimit: string;
1615
+ preVerificationGas: string;
1616
+ maxFeePerGas: string;
1617
+ maxPriorityFeePerGas: string;
1618
+ paymaster?: Address;
1619
+ paymasterVerificationGasLimit?: string;
1620
+ paymasterPostOpGasLimit?: string;
1621
+ paymasterData?: Hex;
1622
+ chainId: number;
1623
+ /** Hex-encoded userOpHash — the value the user signed via personal_sign. */
1624
+ userOpHash: Hex;
1625
+ }
1626
+ /**
1627
+ * Storage backend for pending UserOps in the mobile prepare/submit pattern.
1628
+ *
1629
+ * Implement this interface and wire it into your issuer backend:
1630
+ * - `save()` — called by `POST /claim/prepare` and `POST /redeem/prepare`
1631
+ * - `get()` — called by `POST /claim/submit` and `POST /redeem/submit`
1632
+ * - `delete()` — called after successful submit or explicit cancellation
1633
+ *
1634
+ * The default implementation in the gg56 boilerplate uses Redis with
1635
+ * a short TTL matching the MintRequest / BurnRequest deadline.
1636
+ */
1637
+ interface IPendingUserOpStore {
1638
+ save(lockId: string, entry: PendingUserOpEntry, ttlSeconds: number): Promise<void>;
1639
+ get(lockId: string): Promise<PendingUserOpEntry | null>;
1640
+ delete(lockId: string): Promise<void>;
1641
+ }
1642
+
1643
+ /**
1644
+ * Convert a stored `PendingUserOpEntry` (decimal-string fields) plus a
1645
+ * signature into the JSON-RPC wire format for `eth_sendUserOperation`.
1646
+ *
1647
+ * Bridges the gap between the serialized storage format (decimal strings,
1648
+ * safe for JSON/Redis) and `serializeUserOpToJsonRpc` which expects bigints.
1649
+ */
1650
+ declare function serializeEntryToJsonRpc(entry: PendingUserOpEntry, signature: Hex): Record<string, string | null>;
1651
+
1652
+ interface IssuerRegistryRecord {
1653
+ issuerAddress: Address;
1654
+ signerAddress: Address;
1655
+ name: string;
1656
+ symbol: string;
1657
+ declaredTotalSupply: bigint;
1658
+ capBasisPoints: number;
1659
+ active: boolean;
1660
+ pointToken: Address;
1661
+ mintingOracle: Address;
1662
+ }
1663
+ interface PreValidateMintResult {
1664
+ /** Registry record read at pre-validation time. */
1665
+ issuer: IssuerRegistryRecord;
1666
+ /** Current on-chain PointToken.totalSupply(). */
1667
+ totalSupply: bigint;
1668
+ /** declaredTotalSupply × capBasisPoints / 10000. */
1669
+ hardCap: bigint;
1670
+ /** hardCap − totalSupply (clamped to 0). */
1671
+ remaining: bigint;
1672
+ }
1673
+ /**
1674
+ * Thrown by `IssuerStateValidator.preValidateMint()`.
1675
+ * `code` maps 1:1 to the HTTP error the issuer API surfaces to clients.
1676
+ */
1677
+ declare class IssuerStateError extends Error {
1678
+ readonly code: "ISSUER_NOT_REGISTERED" | "ISSUER_INACTIVE" | "MINT_CAP_EXCEEDED";
1679
+ readonly details?: Record<string, unknown> | undefined;
1680
+ constructor(code: "ISSUER_NOT_REGISTERED" | "ISSUER_INACTIVE" | "MINT_CAP_EXCEEDED", message: string, details?: Record<string, unknown> | undefined);
1681
+ }
1682
+
1683
+ /**
1684
+ * Pure (framework-agnostic) validator for issuer state.
1685
+ *
1686
+ * Reads IssuerRegistry + PointToken on-chain state and pre-validates
1687
+ * mint requests before the user submits a UserOp. Catching these
1688
+ * off-chain lets issuers fail fast with a clear error rather than
1689
+ * wasting gas on a revert.
1690
+ *
1691
+ * Caching:
1692
+ * - `PointToken.issuer()` — memoized for the process lifetime (immutable)
1693
+ * - Full state (registry + totalSupply) — 30s TTL per PointToken
1694
+ * - Burst calls while a fetch is in-flight share the same Promise
1695
+ * (thundering-herd protection)
1696
+ *
1697
+ * Usage in NestJS: wrap this in an `@Injectable()` service; pass
1698
+ * `PublicClient` and `registryAddress` from your DI container.
1699
+ */
1700
+ declare class IssuerStateValidator {
1701
+ private readonly provider;
1702
+ private readonly registryAddress;
1703
+ private readonly pointTokenIssuerCache;
1704
+ private readonly stateCache;
1705
+ private readonly inflight;
1706
+ constructor(provider: PublicClient, registryAddress: Address);
1707
+ /**
1708
+ * Convenience factory — reads `registryAddress` from the SDK
1709
+ * `CONTRACT_ADDRESSES` map for the given chain.
1710
+ */
1711
+ static forChain(provider: PublicClient, chainId: number): IssuerStateValidator;
1712
+ /**
1713
+ * Invalidate cached state for one PointToken, or everything if omitted.
1714
+ * Call after admin txs that change registry or cap settings.
1715
+ */
1716
+ invalidate(pointToken?: Address): void;
1717
+ /**
1718
+ * Resolve `PointToken.issuer()` once per token and memoize.
1719
+ * The issuer field is set at `initialize()` and never changes.
1720
+ */
1721
+ getIssuerAddressForPointToken(pointToken: Address): Promise<Address>;
1722
+ /**
1723
+ * Read registry record + totalSupply, with 30s cache and in-flight
1724
+ * deduplication. Does NOT throw on inactive/missing — returns raw state.
1725
+ */
1726
+ getIssuerState(pointToken: Address): Promise<PreValidateMintResult>;
1727
+ /**
1728
+ * Validate that `amount` PT can be minted on `pointToken` right now.
1729
+ *
1730
+ * Throws `IssuerStateError` with:
1731
+ * - `ISSUER_NOT_REGISTERED` — registry has no record for this issuer
1732
+ * - `ISSUER_INACTIVE` — issuer.active is false
1733
+ * - `MINT_CAP_EXCEEDED` — totalSupply + amount would exceed hardCap
1734
+ *
1735
+ * Returns the fetched state on success so callers can log without a
1736
+ * second RPC round-trip.
1737
+ */
1738
+ preValidateMint(pointToken: Address, amount: bigint): Promise<PreValidateMintResult>;
1739
+ private fetchIssuerState;
1740
+ }
1741
+
1602
1742
  /** SDK package version — bumped on every release */
1603
1743
  declare const PAFI_ISSUER_SDK_VERSION = "0.4.0";
1604
1744
 
1605
- export { type ApiClaimRequest, type ApiClaimResponse, type ApiConfigResponse, type ApiGasFeeResponse, type ApiLoginRequest, type ApiLoginResponse, type ApiNonceResponse, type ApiPoolsRequest, type ApiPoolsResponse, type ApiRedeemRequest, type ApiRedeemResponse, type ApiTopUpRequest, type ApiTopUpResponse, 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 IPointLedger, type IPolicyEngine, type ISessionStore, InMemoryCursorStore, IssuerApiHandlers, type IssuerApiHandlersConfig, type IssuerService, type IssuerServiceConfig, type LockedMintRequest, type LoginResult, MemorySessionStore, type MemorySessionStoreOptions, type MintEvent, type MintingStatus, NonceManager, 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, type PrepareBurnDirectParams, type PrepareBurnParams, type PrepareBurnWithSigParams, type PrepareMintParams, RelayError, type RelayErrorCode, RelayService, type RelayUserOpRequest, type RelayUserOpResponse, type RetryConfig, type Session, type SponsorshipRequest, type SponsorshipResponse, type SponsorshipTarget, type SponsorshipUserOp, type SubgraphNativeUsdtQuoterConfig, type SubgraphPoolsProviderConfig, TopUpRedemptionError, TopUpRedemptionHandler, type TopUpRedemptionHandlerConfig, type TopUpRedemptionRequest, type TopUpRedemptionResponse, authenticateRequest, createIssuerService, createSubgraphNativeUsdtQuoter, createSubgraphPoolsProvider };
1745
+ export { type ApiClaimRequest, type ApiClaimResponse, type ApiConfigResponse, type ApiGasFeeResponse, type ApiLoginRequest, type ApiLoginResponse, type ApiNonceResponse, type ApiPoolsRequest, type ApiPoolsResponse, type ApiRedeemRequest, type ApiRedeemResponse, type ApiTopUpRequest, type ApiTopUpResponse, 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 IPendingUserOpStore, type IPointLedger, type IPolicyEngine, type ISessionStore, InMemoryCursorStore, IssuerApiHandlers, type IssuerApiHandlersConfig, type IssuerRegistryRecord, type IssuerService, type IssuerServiceConfig, IssuerStateError, IssuerStateValidator, type LockedMintRequest, type LoginResult, MemorySessionStore, type MemorySessionStoreOptions, type MintEvent, type MintingStatus, NonceManager, PAFI_ISSUER_SDK_VERSION, PTRedeemError, PTRedeemHandler, type PTRedeemHandlerConfig, type PTRedeemRequest, type PTRedeemResponse, PafiBackendClient, type PafiBackendConfig, PafiBackendError, type PafiBackendErrorCode, type PendingUserOpEntry, PointIndexer, type PointIndexerConfig, type PolicyDecision, type PolicyEvalRequest, type PoolsProvider, type PreValidateMintResult, type PrepareBurnDirectParams, type PrepareBurnParams, type PrepareBurnWithSigParams, type PrepareMintParams, RelayError, type RelayErrorCode, RelayService, type RelayUserOpRequest, type RelayUserOpResponse, type RetryConfig, type Session, type SponsorshipRequest, type SponsorshipResponse, type SponsorshipTarget, type SponsorshipUserOp, type SubgraphNativeUsdtQuoterConfig, type SubgraphPoolsProviderConfig, TopUpRedemptionError, TopUpRedemptionHandler, type TopUpRedemptionHandlerConfig, type TopUpRedemptionRequest, type TopUpRedemptionResponse, authenticateRequest, createIssuerService, createSubgraphNativeUsdtQuoter, createSubgraphPoolsProvider, serializeEntryToJsonRpc };
package/dist/index.js CHANGED
@@ -2056,6 +2056,202 @@ function createIssuerService(config) {
2056
2056
  };
2057
2057
  }
2058
2058
 
2059
+ // src/userop-store/serialize.ts
2060
+ import { serializeUserOpToJsonRpc } from "@pafi-dev/core";
2061
+ function serializeEntryToJsonRpc(entry, signature) {
2062
+ return serializeUserOpToJsonRpc(
2063
+ {
2064
+ sender: entry.sender,
2065
+ nonce: BigInt(entry.nonce),
2066
+ callData: entry.callData,
2067
+ callGasLimit: BigInt(entry.callGasLimit),
2068
+ verificationGasLimit: BigInt(entry.verificationGasLimit),
2069
+ preVerificationGas: BigInt(entry.preVerificationGas),
2070
+ maxFeePerGas: BigInt(entry.maxFeePerGas),
2071
+ maxPriorityFeePerGas: BigInt(entry.maxPriorityFeePerGas),
2072
+ paymaster: entry.paymaster,
2073
+ paymasterVerificationGasLimit: entry.paymasterVerificationGasLimit != null ? BigInt(entry.paymasterVerificationGasLimit) : void 0,
2074
+ paymasterPostOpGasLimit: entry.paymasterPostOpGasLimit != null ? BigInt(entry.paymasterPostOpGasLimit) : void 0,
2075
+ paymasterData: entry.paymasterData
2076
+ },
2077
+ signature
2078
+ );
2079
+ }
2080
+
2081
+ // src/issuer-state/validator.ts
2082
+ import { getAddress as getAddress9 } from "viem";
2083
+ import {
2084
+ POINT_TOKEN_V2_ABI as POINT_TOKEN_V2_ABI3,
2085
+ issuerRegistryAbi,
2086
+ getContractAddresses as getContractAddresses2
2087
+ } from "@pafi-dev/core";
2088
+
2089
+ // src/issuer-state/types.ts
2090
+ var IssuerStateError = class extends Error {
2091
+ constructor(code, message, details) {
2092
+ super(message);
2093
+ this.code = code;
2094
+ this.details = details;
2095
+ this.name = "IssuerStateError";
2096
+ }
2097
+ code;
2098
+ details;
2099
+ };
2100
+
2101
+ // src/issuer-state/validator.ts
2102
+ var ISSUER_RECORD_TTL_MS = 3e4;
2103
+ var IssuerStateValidator = class _IssuerStateValidator {
2104
+ constructor(provider, registryAddress) {
2105
+ this.provider = provider;
2106
+ this.registryAddress = registryAddress;
2107
+ }
2108
+ provider;
2109
+ registryAddress;
2110
+ pointTokenIssuerCache = /* @__PURE__ */ new Map();
2111
+ stateCache = /* @__PURE__ */ new Map();
2112
+ inflight = /* @__PURE__ */ new Map();
2113
+ /**
2114
+ * Convenience factory — reads `registryAddress` from the SDK
2115
+ * `CONTRACT_ADDRESSES` map for the given chain.
2116
+ */
2117
+ static forChain(provider, chainId) {
2118
+ const { issuerRegistry } = getContractAddresses2(chainId);
2119
+ return new _IssuerStateValidator(provider, issuerRegistry);
2120
+ }
2121
+ /**
2122
+ * Invalidate cached state for one PointToken, or everything if omitted.
2123
+ * Call after admin txs that change registry or cap settings.
2124
+ */
2125
+ invalidate(pointToken) {
2126
+ if (pointToken) {
2127
+ const key = getAddress9(pointToken);
2128
+ this.pointTokenIssuerCache.delete(key);
2129
+ this.stateCache.delete(key);
2130
+ this.inflight.delete(key);
2131
+ } else {
2132
+ this.pointTokenIssuerCache.clear();
2133
+ this.stateCache.clear();
2134
+ this.inflight.clear();
2135
+ }
2136
+ }
2137
+ /**
2138
+ * Resolve `PointToken.issuer()` once per token and memoize.
2139
+ * The issuer field is set at `initialize()` and never changes.
2140
+ */
2141
+ async getIssuerAddressForPointToken(pointToken) {
2142
+ const key = getAddress9(pointToken);
2143
+ const cached = this.pointTokenIssuerCache.get(key);
2144
+ if (cached) return cached;
2145
+ const issuer = await this.provider.readContract({
2146
+ address: key,
2147
+ abi: POINT_TOKEN_V2_ABI3,
2148
+ functionName: "issuer"
2149
+ });
2150
+ this.pointTokenIssuerCache.set(key, getAddress9(issuer));
2151
+ return getAddress9(issuer);
2152
+ }
2153
+ /**
2154
+ * Read registry record + totalSupply, with 30s cache and in-flight
2155
+ * deduplication. Does NOT throw on inactive/missing — returns raw state.
2156
+ */
2157
+ async getIssuerState(pointToken) {
2158
+ const tokenAddr = getAddress9(pointToken);
2159
+ const now = Date.now();
2160
+ const cached = this.stateCache.get(tokenAddr);
2161
+ if (cached && cached.expiresAt > now) return cached.value;
2162
+ const existing = this.inflight.get(tokenAddr);
2163
+ if (existing) return existing;
2164
+ const promise = this.fetchIssuerState(tokenAddr).then((state) => {
2165
+ this.stateCache.set(tokenAddr, {
2166
+ value: state,
2167
+ expiresAt: Date.now() + ISSUER_RECORD_TTL_MS
2168
+ });
2169
+ return state;
2170
+ }).finally(() => {
2171
+ this.inflight.delete(tokenAddr);
2172
+ });
2173
+ this.inflight.set(tokenAddr, promise);
2174
+ return promise;
2175
+ }
2176
+ /**
2177
+ * Validate that `amount` PT can be minted on `pointToken` right now.
2178
+ *
2179
+ * Throws `IssuerStateError` with:
2180
+ * - `ISSUER_NOT_REGISTERED` — registry has no record for this issuer
2181
+ * - `ISSUER_INACTIVE` — issuer.active is false
2182
+ * - `MINT_CAP_EXCEEDED` — totalSupply + amount would exceed hardCap
2183
+ *
2184
+ * Returns the fetched state on success so callers can log without a
2185
+ * second RPC round-trip.
2186
+ */
2187
+ async preValidateMint(pointToken, amount) {
2188
+ let state;
2189
+ try {
2190
+ state = await this.getIssuerState(pointToken);
2191
+ } catch (err) {
2192
+ if (err.message.includes("IssuerNotFound")) {
2193
+ throw new IssuerStateError(
2194
+ "ISSUER_NOT_REGISTERED",
2195
+ `IssuerRegistry has no record for PointToken ${pointToken}`,
2196
+ { pointToken }
2197
+ );
2198
+ }
2199
+ throw err;
2200
+ }
2201
+ const { issuer, totalSupply, hardCap, remaining } = state;
2202
+ if (!issuer.active) {
2203
+ throw new IssuerStateError(
2204
+ "ISSUER_INACTIVE",
2205
+ `Issuer ${issuer.issuerAddress} is deactivated on IssuerRegistry`,
2206
+ { issuer: issuer.issuerAddress, pointToken: issuer.pointToken }
2207
+ );
2208
+ }
2209
+ if (totalSupply + amount > hardCap) {
2210
+ throw new IssuerStateError(
2211
+ "MINT_CAP_EXCEEDED",
2212
+ `Requested ${amount} PT would exceed mint cap. Cap=${hardCap}, minted=${totalSupply}, remaining=${remaining}`,
2213
+ {
2214
+ requested: amount.toString(),
2215
+ cap: hardCap.toString(),
2216
+ minted: totalSupply.toString(),
2217
+ remaining: remaining.toString()
2218
+ }
2219
+ );
2220
+ }
2221
+ return state;
2222
+ }
2223
+ async fetchIssuerState(tokenAddr) {
2224
+ const issuerAddr = await this.getIssuerAddressForPointToken(tokenAddr);
2225
+ const [tuple, totalSupply] = await Promise.all([
2226
+ this.provider.readContract({
2227
+ address: this.registryAddress,
2228
+ abi: issuerRegistryAbi,
2229
+ functionName: "getIssuer",
2230
+ args: [issuerAddr]
2231
+ }),
2232
+ this.provider.readContract({
2233
+ address: tokenAddr,
2234
+ abi: POINT_TOKEN_V2_ABI3,
2235
+ functionName: "totalSupply"
2236
+ })
2237
+ ]);
2238
+ const issuer = {
2239
+ issuerAddress: tuple[0],
2240
+ signerAddress: tuple[1],
2241
+ name: tuple[2],
2242
+ symbol: tuple[3],
2243
+ declaredTotalSupply: tuple[4],
2244
+ capBasisPoints: tuple[5],
2245
+ active: tuple[6],
2246
+ pointToken: tuple[7],
2247
+ mintingOracle: tuple[8]
2248
+ };
2249
+ const hardCap = issuer.declaredTotalSupply * BigInt(issuer.capBasisPoints) / 10000n;
2250
+ const remaining = hardCap > totalSupply ? hardCap - totalSupply : 0n;
2251
+ return { issuer, totalSupply, hardCap, remaining };
2252
+ }
2253
+ };
2254
+
2059
2255
  // src/index.ts
2060
2256
  var PAFI_ISSUER_SDK_VERSION = "0.4.0";
2061
2257
  export {
@@ -2067,6 +2263,8 @@ export {
2067
2263
  FeeManager,
2068
2264
  InMemoryCursorStore,
2069
2265
  IssuerApiHandlers,
2266
+ IssuerStateError,
2267
+ IssuerStateValidator,
2070
2268
  MemorySessionStore,
2071
2269
  NonceManager,
2072
2270
  PAFI_ISSUER_SDK_VERSION,
@@ -2083,6 +2281,7 @@ export {
2083
2281
  authenticateRequest,
2084
2282
  createIssuerService,
2085
2283
  createSubgraphNativeUsdtQuoter,
2086
- createSubgraphPoolsProvider
2284
+ createSubgraphPoolsProvider,
2285
+ serializeEntryToJsonRpc
2087
2286
  };
2088
2287
  //# sourceMappingURL=index.js.map