@zkp2p/sdk 0.2.4 → 0.3.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 CHANGED
@@ -73,13 +73,13 @@ const client = new Zkp2pClient({
73
73
  - Supported runtime environments: `'production'`, `'preproduction'`, `'staging'`
74
74
  - `runtimeEnv` default: `'production'`
75
75
  - `rpcUrl`: optional RPC URL override (defaults to wallet's chain RPC)
76
- - `apiKey`: optional curator API key — enhances some responses (e.g. `getQuote` returns `depositData` when authenticated) but is **not required** for any SDK method
76
+ - `apiKey`: optional curator-issued API key — used when the SDK auto-fetches `signalIntent()` gating signatures and enables richer authenticated `getQuote()` responses with maker `depositData`; curator may also attach `skipTierEnforce` to trusted keys on hybrid intent-signing endpoints
77
77
  - `authorizationToken` / `getAuthorizationToken`: optional bearer auth for hybrid client and indexer flows
78
78
  - `indexerApiKey`: optional `x-api-key` for indexer proxy auth
79
79
  - `indexerUrl` and `baseApiUrl`: override defaults when you are targeting custom deployments
80
80
  - `timeouts`: `{ api?: number }` — API timeout in milliseconds (default 15000)
81
81
 
82
- **No API key is required to get started.** `createDeposit`, `registerPayeeDetails`, `getQuote`, `getTakerTier`, and all other SDK methods work without `apiKey` or `authorizationToken`. Auth credentials are optional and only affect response richness (e.g. authenticated quotes include maker `depositData`).
82
+ **No API key is required to get started.** `createDeposit`, `registerPayeeDetails`, `getQuote`, `getTakerTier`, and the rest of the SDK work without `apiKey` or `authorizationToken`. The main tradeoff is that `signalIntent()` only auto-fetches a gating service signature from curator `/v3/intent` when `apiKey` or `authorizationToken` is available; otherwise provide both `gatingServiceSignature` and `signatureExpiration` manually if your integration needs one. Authenticated quotes also include richer maker `depositData`, and curator-issued API keys may carry `skipTierEnforce` on hybrid intent-signing endpoints.
83
83
 
84
84
  Indexer defaults by environment:
85
85
 
package/dist/index.cjs CHANGED
@@ -1099,15 +1099,9 @@ var init_protocolViewerParsers = __esm({
1099
1099
 
1100
1100
  // src/client/clientUtils.ts
1101
1101
  init_bigint();
1102
+
1103
+ // src/utils/address.ts
1102
1104
  var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
1103
- var MIN_ORACLE_SPREAD_BPS = -32768;
1104
- var MAX_ORACLE_SPREAD_BPS = 32767;
1105
- var EMPTY_ORACLE_RATE_CONFIG = {
1106
- adapter: ZERO_ADDRESS,
1107
- adapterConfig: "0x",
1108
- spreadBps: 0,
1109
- maxStaleness: 0
1110
- };
1111
1105
  var isValidHexAddress = (addr) => {
1112
1106
  if (typeof addr !== "string") return false;
1113
1107
  return /^0x[0-9a-fA-F]{40}$/.test(addr);
@@ -1116,6 +1110,16 @@ var normalizeAddress = (addr) => {
1116
1110
  if (!isValidHexAddress(addr)) return void 0;
1117
1111
  return addr;
1118
1112
  };
1113
+
1114
+ // src/client/clientUtils.ts
1115
+ var MIN_ORACLE_SPREAD_BPS = -32768;
1116
+ var MAX_ORACLE_SPREAD_BPS = 32767;
1117
+ var EMPTY_ORACLE_RATE_CONFIG = {
1118
+ adapter: ZERO_ADDRESS,
1119
+ adapterConfig: "0x",
1120
+ spreadBps: 0,
1121
+ maxStaleness: 0
1122
+ };
1119
1123
  var parseEscrowAddressFromCompositeDepositId = (depositId) => {
1120
1124
  if (typeof depositId !== "string") return void 0;
1121
1125
  const parts = depositId.split("_");
@@ -1422,9 +1426,6 @@ function parseAPIError(response, responseText) {
1422
1426
  } catch {
1423
1427
  if (responseText && responseText.length < 200) message = responseText;
1424
1428
  }
1425
- if (response.status === 429) {
1426
- message = "Too many requests. Please try again later.";
1427
- }
1428
1429
  return new exports.APIError(message, response.status, { url: response.url });
1429
1430
  }
1430
1431
  async function withRetry(fn, maxRetries = 3, delayMs = 1e3, timeoutMs) {
@@ -1488,11 +1489,13 @@ async function apiSignIntentV3(request, opts) {
1488
1489
  const sig = json?.responseObject?.signedIntent;
1489
1490
  const expStr = json?.responseObject?.intentData?.signatureExpiration ?? json?.responseObject?.signatureExpiration;
1490
1491
  const preIntentHookData = json?.responseObject?.intentData?.preIntentHookData ?? json?.responseObject?.preIntentHookData;
1492
+ const referralFees = json?.responseObject?.intentData?.referralFees ?? json?.responseObject?.referralFees;
1491
1493
  if (!sig || !expStr) throw new Error("v3/intent missing signature or expiration");
1492
1494
  return {
1493
1495
  signature: sig,
1494
1496
  signatureExpiration: BigInt(expStr),
1495
- preIntentHookData
1497
+ preIntentHookData,
1498
+ referralFees
1496
1499
  };
1497
1500
  }
1498
1501
 
@@ -1919,7 +1922,7 @@ var IntentOperations = class {
1919
1922
  const depositId = parseRawDepositId(params.depositId);
1920
1923
  const amount = typeof params.amount === "bigint" ? params.amount : BigInt(params.amount);
1921
1924
  const conversionRate = typeof params.conversionRate === "bigint" ? params.conversionRate : BigInt(params.conversionRate);
1922
- const referralFees = referrerFeeConfig !== void 0 ? [
1925
+ let referralFees = referrerFeeConfig !== void 0 ? [
1923
1926
  {
1924
1927
  recipient: referrerFeeConfig.recipient,
1925
1928
  fee: referrerFeeConfigToPreciseUnits(referrerFeeConfig)
@@ -1961,6 +1964,23 @@ var IntentOperations = class {
1961
1964
  gatingServiceSignature = response.signature;
1962
1965
  signatureExpiration = response.signatureExpiration;
1963
1966
  preIntentHookData = response.preIntentHookData ?? preIntentHookData;
1967
+ if (response.referralFees !== void 0) {
1968
+ referralFees = response.referralFees.map((referralFee) => {
1969
+ if (!isValidReferrerFeeRecipient(referralFee.recipient)) {
1970
+ throw new Error("v3/intent returned invalid referral fee recipient");
1971
+ }
1972
+ let fee;
1973
+ try {
1974
+ fee = BigInt(referralFee.fee);
1975
+ } catch {
1976
+ throw new Error("v3/intent returned non-integer referral fee value");
1977
+ }
1978
+ return {
1979
+ recipient: referralFee.recipient,
1980
+ fee
1981
+ };
1982
+ });
1983
+ }
1964
1984
  }
1965
1985
  if (!gatingServiceSignature || !signatureExpiration) {
1966
1986
  throw new Error("Missing gatingServiceSignature/signatureExpiration");
@@ -4590,9 +4610,10 @@ function convertIndexerDepositToEscrowView(deposit, _chainId, _escrowAddress) {
4590
4610
  verifiers
4591
4611
  };
4592
4612
  }
4593
- function convertDepositsForLiquidity(deposits, chainId, escrowAddress) {
4613
+ function convertDepositsForLiquidity(deposits, chainId, escrowAddress, options = {}) {
4614
+ const { includePrivateOrderbooks = false } = options;
4594
4615
  return deposits.filter(
4595
- (d) => d.depositor && d.depositor.toLowerCase() !== ZERO && normalizeAddress2(d.whitelistHookAddress).toLowerCase() === ZERO && d.acceptingIntents && toBigInt(d.remainingDeposits) > 0n && d.status === "ACTIVE"
4616
+ (d) => d.depositor && d.depositor.toLowerCase() !== ZERO && (includePrivateOrderbooks || normalizeAddress2(d.whitelistHookAddress).toLowerCase() === ZERO) && d.acceptingIntents && toBigInt(d.remainingDeposits) > 0n && d.status === "ACTIVE"
4596
4617
  ).map((d) => convertIndexerDepositToEscrowView(d));
4597
4618
  }
4598
4619
  function convertIndexerIntentsToEscrowViews(intents, depositViewsById) {
@@ -5927,13 +5948,11 @@ function convertIndexerDepositToLegacyApiDeposit(deposit) {
5927
5948
  verifiers
5928
5949
  };
5929
5950
  }
5930
- async function apiPostDepositDetails(req, baseApiUrl, timeoutMs, apiKey, authToken) {
5951
+ async function apiPostDepositDetails(req, baseApiUrl, timeoutMs, _apiKey, _authToken) {
5931
5952
  return apiFetch({
5932
5953
  url: `${withApiBase(baseApiUrl)}/v1/makers/create`,
5933
5954
  method: "POST",
5934
5955
  body: req,
5935
- apiKey,
5936
- authToken,
5937
5956
  timeoutMs
5938
5957
  });
5939
5958
  }
@@ -5943,13 +5962,25 @@ async function apiGetQuote(req, baseApiUrl, timeoutMs, apiKey, authToken) {
5943
5962
  throw new exports.ValidationError("quotesToReturn must be a positive integer", "quotesToReturn");
5944
5963
  }
5945
5964
  }
5965
+ if (!isValidHexAddress(req.user)) {
5966
+ throw new exports.ValidationError("user must be a valid Ethereum address", "user");
5967
+ }
5968
+ if (!isValidHexAddress(req.recipient)) {
5969
+ throw new exports.ValidationError("recipient must be a valid Ethereum address", "recipient");
5970
+ }
5971
+ if (!isValidHexAddress(req.destinationToken)) {
5972
+ throw new exports.ValidationError(
5973
+ "destinationToken must be a valid Ethereum address",
5974
+ "destinationToken"
5975
+ );
5976
+ }
5946
5977
  const isExactFiat = req.isExactFiat !== false;
5947
5978
  const endpoint = isExactFiat ? "exact-fiat" : "exact-token";
5948
5979
  let url = `${withApiBase(baseApiUrl)}/v2/quote/${endpoint}`;
5949
5980
  if (req.quotesToReturn) url += `?quotesToReturn=${req.quotesToReturn}`;
5950
5981
  const requestBody = {
5951
5982
  ...req,
5952
- [isExactFiat ? "exactFiatAmount" : "exactTokenAmount"]: req.amount,
5983
+ [isExactFiat ? "exactFiatAmount" : "exactTokenAmount"]: String(req.amount),
5953
5984
  amount: void 0,
5954
5985
  isExactFiat: void 0,
5955
5986
  quotesToReturn: void 0
@@ -5964,6 +5995,29 @@ async function apiGetQuote(req, baseApiUrl, timeoutMs, apiKey, authToken) {
5964
5995
  timeoutMs
5965
5996
  });
5966
5997
  }
5998
+ async function apiGetQuotesBestByPlatform(req, baseApiUrl, timeoutMs, apiKey, authToken) {
5999
+ const isExactFiat = req.isExactFiat !== false;
6000
+ const endpoint = isExactFiat ? "best-by-platform" : "best-by-platform-exact-token";
6001
+ const url = `${withApiBase(baseApiUrl)}/v2/quote/${endpoint}`;
6002
+ const requestBody = {
6003
+ ...req,
6004
+ [isExactFiat ? "exactFiatAmount" : "exactTokenAmount"]: String(req.amount),
6005
+ amount: void 0,
6006
+ isExactFiat: void 0,
6007
+ referrerFeeConfig: void 0
6008
+ };
6009
+ Object.keys(requestBody).forEach(
6010
+ (key) => requestBody[key] === void 0 && delete requestBody[key]
6011
+ );
6012
+ return apiFetch({
6013
+ url,
6014
+ method: "POST",
6015
+ body: requestBody,
6016
+ apiKey,
6017
+ authToken,
6018
+ timeoutMs
6019
+ });
6020
+ }
5967
6021
  async function apiGetPayeeDetails(req, apiKey, baseApiUrl, authToken, timeoutMs) {
5968
6022
  return apiFetch({
5969
6023
  url: `${baseApiUrl.replace(/\/$/, "")}/v1/makers/${req.processorName}/${req.hashedOnchainId}`,
@@ -6030,7 +6084,6 @@ async function apiGetTakerTier(req, apiKey, baseApiUrl, timeoutMs) {
6030
6084
  return apiFetch({
6031
6085
  url: `${withApiBase(baseApiUrl)}${endpoint}`,
6032
6086
  method: "GET",
6033
- apiKey,
6034
6087
  timeoutMs
6035
6088
  });
6036
6089
  }
@@ -6132,6 +6185,23 @@ var appendReferrerFeeDisplayFields = (quoteResponse, referrerFeeConfig) => {
6132
6185
  }
6133
6186
  };
6134
6187
  };
6188
+ var appendReferrerFeeDisplayFieldsToBestByPlatform = (quoteResponse, referrerFeeConfig) => {
6189
+ if (!referrerFeeConfig) {
6190
+ return quoteResponse;
6191
+ }
6192
+ const decimals = quoteResponse.responseObject?.token?.decimals ?? 6;
6193
+ const enrichedPlatformQuotes = (quoteResponse.responseObject?.platformQuotes ?? []).map((platformQuote) => ({
6194
+ ...platformQuote,
6195
+ bestQuote: platformQuote.available && platformQuote.bestQuote ? applyReferrerFeeDisplayFieldsToQuote(platformQuote.bestQuote, referrerFeeConfig, decimals) : platformQuote.bestQuote
6196
+ }));
6197
+ return {
6198
+ ...quoteResponse,
6199
+ responseObject: {
6200
+ ...quoteResponse.responseObject,
6201
+ platformQuotes: enrichedPlatformQuotes
6202
+ }
6203
+ };
6204
+ };
6135
6205
 
6136
6206
  // src/utils/erc20.ts
6137
6207
  var ERC20_ABI = [
@@ -6704,7 +6774,9 @@ var Zkp2pClient = class {
6704
6774
  * sending fiat payment to the deposit's payee.
6705
6775
  *
6706
6776
  * If `gatingServiceSignature` is not provided, the SDK will automatically
6707
- * fetch one from the API (requires `apiKey` or `authorizationToken`).
6777
+ * fetch one from curator `/v3/intent` when `apiKey` or `authorizationToken`
6778
+ * is available. Otherwise you must provide `gatingServiceSignature` and
6779
+ * `signatureExpiration` yourself.
6708
6780
  *
6709
6781
  * **Prepare Mode**: Use `.prepare()` to get the transaction calldata without sending:
6710
6782
  * ```typescript
@@ -8043,15 +8115,7 @@ var Zkp2pClient = class {
8043
8115
  })
8044
8116
  );
8045
8117
  const apiResponses = await Promise.all(
8046
- depositDetails.map(
8047
- (req) => apiPostDepositDetails(
8048
- req,
8049
- baseApiUrl,
8050
- this.apiTimeoutMs,
8051
- this.apiKey,
8052
- this.authorizationToken
8053
- )
8054
- )
8118
+ depositDetails.map((req) => apiPostDepositDetails(req, baseApiUrl, this.apiTimeoutMs))
8055
8119
  );
8056
8120
  if (!apiResponses.every((r) => r?.success)) {
8057
8121
  const failed = apiResponses.find((r) => !r?.success);
@@ -8178,15 +8242,7 @@ var Zkp2pClient = class {
8178
8242
  } else {
8179
8243
  const baseApiUrl = (this.baseApiUrl ?? "https://api.zkp2p.xyz").replace(/\/$/, "");
8180
8244
  const apiResponses = await Promise.all(
8181
- depositDetails.map(
8182
- (req) => apiPostDepositDetails(
8183
- req,
8184
- baseApiUrl,
8185
- this.apiTimeoutMs,
8186
- this.apiKey,
8187
- this.authorizationToken
8188
- )
8189
- )
8245
+ depositDetails.map((req) => apiPostDepositDetails(req, baseApiUrl, this.apiTimeoutMs))
8190
8246
  );
8191
8247
  if (!apiResponses.every((r) => r?.success)) {
8192
8248
  const failed = apiResponses.find((r) => !r?.success);
@@ -8389,6 +8445,57 @@ var Zkp2pClient = class {
8389
8445
  }
8390
8446
  return appendReferrerFeeDisplayFields(quote, referrerFeeConfig);
8391
8447
  }
8448
+ /**
8449
+ * **Supporting Method** - Fetches the best available quote per supported payment platform.
8450
+ *
8451
+ * Returns one quote per platform when available. When authenticated, the API
8452
+ * returns payee details in each platform's best quote.
8453
+ *
8454
+ * @param req - Best-by-platform quote request parameters
8455
+ * @param opts - Optional overrides for API URL and timeout
8456
+ * @returns Best-by-platform quote response
8457
+ */
8458
+ async getQuotesBestByPlatform(req, opts) {
8459
+ const referrerFeeConfig = assertValidReferrerFeeConfig(
8460
+ req.referrerFeeConfig,
8461
+ "getQuotesBestByPlatform"
8462
+ );
8463
+ const baseApiUrl = (opts?.baseApiUrl ?? this.baseApiUrl ?? "https://api.zkp2p.xyz").replace(
8464
+ /\/$/,
8465
+ ""
8466
+ );
8467
+ const timeoutMs = opts?.timeoutMs ?? this.apiTimeoutMs;
8468
+ const reqWithEscrow = { ...req };
8469
+ if (!reqWithEscrow.escrowAddresses || reqWithEscrow.escrowAddresses.length === 0) {
8470
+ const configuredEscrows = this.escrowAddresses.length > 0 ? [...this.escrowAddresses] : this.escrowAddress ? [this.escrowAddress] : [];
8471
+ if (configuredEscrows.length > 0) {
8472
+ reqWithEscrow.escrowAddresses = configuredEscrows;
8473
+ }
8474
+ }
8475
+ const quote = await apiGetQuotesBestByPlatform(
8476
+ reqWithEscrow,
8477
+ baseApiUrl,
8478
+ timeoutMs,
8479
+ this.apiKey,
8480
+ this.authorizationToken
8481
+ );
8482
+ const enrichedQuote = quote ? {
8483
+ ...quote,
8484
+ responseObject: {
8485
+ ...quote.responseObject,
8486
+ platformQuotes: (quote.responseObject?.platformQuotes ?? []).map((platformQuote) => {
8487
+ const bestQuote = platformQuote?.bestQuote;
8488
+ const makerDepositData = bestQuote?.maker?.depositData;
8489
+ if (!bestQuote || !makerDepositData) return platformQuote;
8490
+ return {
8491
+ ...platformQuote,
8492
+ bestQuote: { ...bestQuote, payeeData: makerDepositData }
8493
+ };
8494
+ })
8495
+ }
8496
+ } : quote;
8497
+ return appendReferrerFeeDisplayFieldsToBestByPlatform(enrichedQuote, referrerFeeConfig);
8498
+ }
8392
8499
  // ───────────────────────────────────────────────────────────────────────────
8393
8500
  // SUPPORTING: TAKER TIER
8394
8501
  // (Used by frontends to display taker limits)
@@ -8408,7 +8515,7 @@ var Zkp2pClient = class {
8408
8515
  ""
8409
8516
  );
8410
8517
  const timeoutMs = opts?.timeoutMs ?? this.apiTimeoutMs;
8411
- return apiGetTakerTier(req, this.apiKey, baseApiUrl, timeoutMs);
8518
+ return apiGetTakerTier(req, void 0, baseApiUrl, timeoutMs);
8412
8519
  }
8413
8520
  // ╔═══════════════════════════════════════════════════════════════════════════╗
8414
8521
  // ║ CORE: ON-CHAIN DEPOSIT VIEWS ║
@@ -8838,6 +8945,7 @@ exports.ZKP2P_IOS_REFERRER = ZKP2P_IOS_REFERRER;
8838
8945
  exports.Zkp2pClient = Zkp2pClient;
8839
8946
  exports.apiGetOwnerDeposits = apiGetOwnerDeposits;
8840
8947
  exports.apiGetPayeeDetails = apiGetPayeeDetails;
8948
+ exports.apiGetQuotesBestByPlatform = apiGetQuotesBestByPlatform;
8841
8949
  exports.apiGetTakerTier = apiGetTakerTier;
8842
8950
  exports.apiPostDepositDetails = apiPostDepositDetails;
8843
8951
  exports.apiValidatePayeeDetails = apiValidatePayeeDetails;