@pafi-dev/issuer 0.5.5 → 0.5.7

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
@@ -1,5 +1,6 @@
1
1
  import { Address, Hex, PublicClient, WalletClient } from 'viem';
2
2
  import { PointTokenDomainConfig, PartialUserOperation, BurnRequest, PoolKey } from '@pafi-dev/core';
3
+ export { PAFI_SUBGRAPH_URL } from '@pafi-dev/core';
3
4
 
4
5
  /**
5
6
  * Lifecycle of a minting request as tracked by the issuer's point ledger.
@@ -1124,8 +1125,8 @@ interface PTRedeemResponse {
1124
1125
  signatureDeadline: bigint;
1125
1126
  }
1126
1127
  declare class PTRedeemError extends Error {
1127
- code: "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED";
1128
- constructor(code: "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED", message: string);
1128
+ code: "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED";
1129
+ constructor(code: "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED", message: string);
1129
1130
  }
1130
1131
  declare class PTRedeemHandler {
1131
1132
  private readonly ledger;
@@ -1139,8 +1140,23 @@ declare class PTRedeemHandler {
1139
1140
  private readonly redeemLockDurationMs;
1140
1141
  private readonly signatureDeadlineSeconds;
1141
1142
  private readonly now;
1143
+ /**
1144
+ * Per-user in-flight nonce guard (single-process only).
1145
+ *
1146
+ * Prevents two concurrent requests from reading the same on-chain
1147
+ * burnRequestNonce before either has completed, which would produce two
1148
+ * signed UserOps with the same nonce — only one succeeds on-chain; the
1149
+ * other leaves an orphaned pending credit and a wasted signer call.
1150
+ *
1151
+ * NOTE: This guard is effective only within a single Node.js process. For
1152
+ * multi-instance deployments (k8s, PM2 cluster), enforce mutual exclusion
1153
+ * via a distributed lock (Redis SETNX / Postgres advisory lock) keyed on
1154
+ * `(userAddress, pointTokenAddress)` BEFORE calling `handle()`.
1155
+ */
1156
+ private readonly inFlightNonces;
1142
1157
  constructor(config: PTRedeemHandlerConfig);
1143
1158
  handle(request: PTRedeemRequest): Promise<PTRedeemResponse>;
1159
+ private _handleAfterNonceLock;
1144
1160
  }
1145
1161
 
1146
1162
  /**
@@ -1207,8 +1223,6 @@ declare class TopUpRedemptionHandler {
1207
1223
  handle(request: TopUpRedemptionRequest): Promise<TopUpRedemptionResponse>;
1208
1224
  }
1209
1225
 
1210
- /** PAFI-hosted subgraph endpoint. Used as the default for all subgraph helpers. */
1211
- declare const PAFI_SUBGRAPH_URL = "https://graph-base-mainnet.pacificfinance.org/subgraphs/name/pafi-subgraph-v2";
1212
1226
  /**
1213
1227
  * Config for `createSubgraphPoolsProvider`.
1214
1228
  */
@@ -1412,6 +1426,21 @@ declare class PafiBackendError extends Error {
1412
1426
  get safeToRetry(): boolean;
1413
1427
  }
1414
1428
 
1429
+ interface RelayUserOpRequest {
1430
+ userOp: Record<string, string | null>;
1431
+ entryPoint: string;
1432
+ eip7702Auth?: {
1433
+ chainId: string;
1434
+ address: string;
1435
+ nonce: string;
1436
+ r: string;
1437
+ s: string;
1438
+ yParity: string;
1439
+ };
1440
+ }
1441
+ interface RelayUserOpResponse {
1442
+ userOpHash: Hex;
1443
+ }
1415
1444
  interface SponsorshipUserOp {
1416
1445
  sender: Address;
1417
1446
  nonce: bigint;
@@ -1444,6 +1473,7 @@ declare class PafiBackendClient {
1444
1473
  private readonly config;
1445
1474
  constructor(config: PafiBackendConfig);
1446
1475
  requestSponsorship(request: SponsorshipRequest): Promise<SponsorshipResponse>;
1476
+ relayUserOperation(request: RelayUserOpRequest): Promise<RelayUserOpResponse>;
1447
1477
  private _doRequest;
1448
1478
  }
1449
1479
 
@@ -1572,4 +1602,4 @@ declare function createIssuerService(config: IssuerServiceConfig): IssuerService
1572
1602
  /** SDK package version — bumped on every release */
1573
1603
  declare const PAFI_ISSUER_SDK_VERSION = "0.4.0";
1574
1604
 
1575
- 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, PAFI_SUBGRAPH_URL, 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 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 };
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 };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Address, Hex, PublicClient, WalletClient } from 'viem';
2
2
  import { PointTokenDomainConfig, PartialUserOperation, BurnRequest, PoolKey } from '@pafi-dev/core';
3
+ export { PAFI_SUBGRAPH_URL } from '@pafi-dev/core';
3
4
 
4
5
  /**
5
6
  * Lifecycle of a minting request as tracked by the issuer's point ledger.
@@ -1124,8 +1125,8 @@ interface PTRedeemResponse {
1124
1125
  signatureDeadline: bigint;
1125
1126
  }
1126
1127
  declare class PTRedeemError extends Error {
1127
- code: "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED";
1128
- constructor(code: "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED", message: string);
1128
+ code: "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED";
1129
+ constructor(code: "UNAUTHORIZED" | "INVALID_AMOUNT" | "NONCE_READ_FAILED" | "NONCE_IN_FLIGHT" | "LEDGER_NOT_SUPPORTED" | "SIGNING_FAILED", message: string);
1129
1130
  }
1130
1131
  declare class PTRedeemHandler {
1131
1132
  private readonly ledger;
@@ -1139,8 +1140,23 @@ declare class PTRedeemHandler {
1139
1140
  private readonly redeemLockDurationMs;
1140
1141
  private readonly signatureDeadlineSeconds;
1141
1142
  private readonly now;
1143
+ /**
1144
+ * Per-user in-flight nonce guard (single-process only).
1145
+ *
1146
+ * Prevents two concurrent requests from reading the same on-chain
1147
+ * burnRequestNonce before either has completed, which would produce two
1148
+ * signed UserOps with the same nonce — only one succeeds on-chain; the
1149
+ * other leaves an orphaned pending credit and a wasted signer call.
1150
+ *
1151
+ * NOTE: This guard is effective only within a single Node.js process. For
1152
+ * multi-instance deployments (k8s, PM2 cluster), enforce mutual exclusion
1153
+ * via a distributed lock (Redis SETNX / Postgres advisory lock) keyed on
1154
+ * `(userAddress, pointTokenAddress)` BEFORE calling `handle()`.
1155
+ */
1156
+ private readonly inFlightNonces;
1142
1157
  constructor(config: PTRedeemHandlerConfig);
1143
1158
  handle(request: PTRedeemRequest): Promise<PTRedeemResponse>;
1159
+ private _handleAfterNonceLock;
1144
1160
  }
1145
1161
 
1146
1162
  /**
@@ -1207,8 +1223,6 @@ declare class TopUpRedemptionHandler {
1207
1223
  handle(request: TopUpRedemptionRequest): Promise<TopUpRedemptionResponse>;
1208
1224
  }
1209
1225
 
1210
- /** PAFI-hosted subgraph endpoint. Used as the default for all subgraph helpers. */
1211
- declare const PAFI_SUBGRAPH_URL = "https://graph-base-mainnet.pacificfinance.org/subgraphs/name/pafi-subgraph-v2";
1212
1226
  /**
1213
1227
  * Config for `createSubgraphPoolsProvider`.
1214
1228
  */
@@ -1412,6 +1426,21 @@ declare class PafiBackendError extends Error {
1412
1426
  get safeToRetry(): boolean;
1413
1427
  }
1414
1428
 
1429
+ interface RelayUserOpRequest {
1430
+ userOp: Record<string, string | null>;
1431
+ entryPoint: string;
1432
+ eip7702Auth?: {
1433
+ chainId: string;
1434
+ address: string;
1435
+ nonce: string;
1436
+ r: string;
1437
+ s: string;
1438
+ yParity: string;
1439
+ };
1440
+ }
1441
+ interface RelayUserOpResponse {
1442
+ userOpHash: Hex;
1443
+ }
1415
1444
  interface SponsorshipUserOp {
1416
1445
  sender: Address;
1417
1446
  nonce: bigint;
@@ -1444,6 +1473,7 @@ declare class PafiBackendClient {
1444
1473
  private readonly config;
1445
1474
  constructor(config: PafiBackendConfig);
1446
1475
  requestSponsorship(request: SponsorshipRequest): Promise<SponsorshipResponse>;
1476
+ relayUserOperation(request: RelayUserOpRequest): Promise<RelayUserOpResponse>;
1447
1477
  private _doRequest;
1448
1478
  }
1449
1479
 
@@ -1572,4 +1602,4 @@ declare function createIssuerService(config: IssuerServiceConfig): IssuerService
1572
1602
  /** SDK package version — bumped on every release */
1573
1603
  declare const PAFI_ISSUER_SDK_VERSION = "0.4.0";
1574
1604
 
1575
- 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, PAFI_SUBGRAPH_URL, 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 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 };
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 };
package/dist/index.js CHANGED
@@ -1263,6 +1263,20 @@ var PTRedeemHandler = class {
1263
1263
  redeemLockDurationMs;
1264
1264
  signatureDeadlineSeconds;
1265
1265
  now;
1266
+ /**
1267
+ * Per-user in-flight nonce guard (single-process only).
1268
+ *
1269
+ * Prevents two concurrent requests from reading the same on-chain
1270
+ * burnRequestNonce before either has completed, which would produce two
1271
+ * signed UserOps with the same nonce — only one succeeds on-chain; the
1272
+ * other leaves an orphaned pending credit and a wasted signer call.
1273
+ *
1274
+ * NOTE: This guard is effective only within a single Node.js process. For
1275
+ * multi-instance deployments (k8s, PM2 cluster), enforce mutual exclusion
1276
+ * via a distributed lock (Redis SETNX / Postgres advisory lock) keyed on
1277
+ * `(userAddress, pointTokenAddress)` BEFORE calling `handle()`.
1278
+ */
1279
+ inFlightNonces = /* @__PURE__ */ new Map();
1266
1280
  constructor(config) {
1267
1281
  if (!config.ledger.reservePendingCredit) {
1268
1282
  throw new PTRedeemError(
@@ -1315,6 +1329,27 @@ var PTRedeemHandler = class {
1315
1329
  `failed to read burnRequestNonces(${request.userAddress}): ${err instanceof Error ? err.message : String(err)}`
1316
1330
  );
1317
1331
  }
1332
+ const userKey = getAddress6(request.userAddress).toLowerCase();
1333
+ let userNonces = this.inFlightNonces.get(userKey);
1334
+ if (!userNonces) {
1335
+ userNonces = /* @__PURE__ */ new Set();
1336
+ this.inFlightNonces.set(userKey, userNonces);
1337
+ }
1338
+ if (userNonces.has(burnNonce)) {
1339
+ throw new PTRedeemError(
1340
+ "NONCE_IN_FLIGHT",
1341
+ `A burn request for nonce ${burnNonce} is already in progress for ${request.userAddress}. Retry after the current request completes.`
1342
+ );
1343
+ }
1344
+ userNonces.add(burnNonce);
1345
+ try {
1346
+ return await this._handleAfterNonceLock(request, burnNonce);
1347
+ } finally {
1348
+ userNonces.delete(burnNonce);
1349
+ if (userNonces.size === 0) this.inFlightNonces.delete(userKey);
1350
+ }
1351
+ }
1352
+ async _handleAfterNonceLock(request, burnNonce) {
1318
1353
  const onChainBalance = await getPointTokenBalance2(
1319
1354
  this.provider,
1320
1355
  this.pointTokenAddress,
@@ -1444,7 +1479,7 @@ var TopUpRedemptionHandler = class {
1444
1479
 
1445
1480
  // src/pools/subgraphPoolsProvider.ts
1446
1481
  import { isAddress } from "viem";
1447
- var PAFI_SUBGRAPH_URL = "https://graph-base-mainnet.pacificfinance.org/subgraphs/name/pafi-subgraph-v2";
1482
+ import { PAFI_SUBGRAPH_URL } from "@pafi-dev/core";
1448
1483
  var DEFAULT_CACHE_TTL_MS = 3e4;
1449
1484
  var POOL_QUERY = `
1450
1485
  query GetPoolForPointToken($id: ID!) {
@@ -1821,6 +1856,40 @@ var PafiBackendClient = class {
1821
1856
  }
1822
1857
  throw lastError;
1823
1858
  }
1859
+ async relayUserOperation(request) {
1860
+ const fetchFn = this.config.fetchImpl ?? fetch;
1861
+ const url = `${this.config.url}/bundler/relay`;
1862
+ let response;
1863
+ try {
1864
+ response = await fetchFn(url, {
1865
+ method: "POST",
1866
+ headers: {
1867
+ "Content-Type": "application/json",
1868
+ Authorization: `Bearer ${this.config.apiKey}`,
1869
+ "X-Issuer-Id": this.config.issuerId
1870
+ },
1871
+ body: JSON.stringify(request)
1872
+ });
1873
+ } catch (err) {
1874
+ throw new PafiBackendError(
1875
+ "NETWORK_ERROR",
1876
+ `Network error: ${err instanceof Error ? err.message : String(err)}`,
1877
+ 0
1878
+ );
1879
+ }
1880
+ const text = await response.text();
1881
+ let json = {};
1882
+ try {
1883
+ json = JSON.parse(text);
1884
+ } catch {
1885
+ }
1886
+ if (!response.ok) {
1887
+ const code = json.code ?? "INTERNAL_ERROR";
1888
+ const message = json.message ?? `HTTP ${response.status}`;
1889
+ throw new PafiBackendError(code, message, response.status, json);
1890
+ }
1891
+ return { userOpHash: json.userOpHash };
1892
+ }
1824
1893
  async _doRequest(request) {
1825
1894
  const fetchFn = this.config.fetchImpl ?? fetch;
1826
1895
  const url = `${this.config.url}/paymaster/sponsor`;