@zkp2p/sdk 0.2.4 → 0.3.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/README.md +6 -6
- package/dist/index.cjs +279 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +10 -6
- package/dist/index.d.ts +10 -6
- package/dist/index.mjs +278 -77
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +4 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.mts +4 -10
- package/dist/react.d.ts +4 -10
- package/dist/react.mjs +4 -1
- package/dist/react.mjs.map +1 -1
- package/dist/{vaultUtils-C2wT1ZYY.d.mts → vaultUtils-DATqc35J.d.mts} +125 -40
- package/dist/{vaultUtils-C2wT1ZYY.d.ts → vaultUtils-DATqc35J.d.ts} +125 -40
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Stable TypeScript SDK for trustless fiat-to-crypto on Base. ZKP2P combines escrowed on-chain settlement, TLS attestations for payment verification, and API/indexer helpers so makers, takers, wallets, and embedded ramps can ship production-grade fiat liquidity flows without building their own contract or indexing stack.
|
|
8
8
|
|
|
9
|
-
Current version: `0.
|
|
9
|
+
Current version: `0.3.1`
|
|
10
10
|
|
|
11
11
|
## Why This SDK
|
|
12
12
|
|
|
@@ -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 —
|
|
76
|
+
- `apiKey`: optional curator-issued API key — used when the SDK auto-fetches `signalIntent()` gating signatures and enables richer authenticated `getQuote()` responses with resolved maker payee details (`offchainId`, `telegramUsername`, `metadata`)
|
|
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
|
|
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/sign` when `apiKey` or `authorizationToken` is available; otherwise provide both `gatingServiceSignature` and `signatureExpiration` manually if your integration needs one. Authenticated quotes also include resolved maker payee details (`offchainId`, `telegramUsername`, `metadata`).
|
|
83
83
|
|
|
84
84
|
Indexer defaults by environment:
|
|
85
85
|
|
|
@@ -95,7 +95,7 @@ Indexer defaults by environment:
|
|
|
95
95
|
| Payment methods and currencies | `addPaymentMethods`, `removePaymentMethod`, `setPaymentMethodActive`, `addCurrencies`, `removeCurrency`, `deactivateCurrency`, `pruneExpiredIntents` |
|
|
96
96
|
| Intents | `signalIntent`, `fulfillIntent`, `cancelIntent`, `releaseFundsToPayer`, `getFulfillIntentInputs` |
|
|
97
97
|
| Prepared transactions | `client.prepareCreateDeposit(...)`, `client.signalIntent.prepare(...)`, `client.fulfillIntent.prepare(...)`, `client.setVaultFee.prepare(...)`, and equivalent prepare flows across the rest of the prepareable write surface |
|
|
98
|
-
| Payee and quote APIs | `registerPayeeDetails`, `resolvePayeeHash`, `getQuote`, `getTakerTier`
|
|
98
|
+
| Payee and quote APIs | `registerPayeeDetails`, `resolvePayeeHash`, `getQuote`, `getQuotesBestByPlatform`, `getTakerTier` |
|
|
99
99
|
| Delegation and hooks | `setDelegate`, `removeDelegate`, `setRateManager`, `clearRateManager`, `setDepositRateManager`, `clearDepositRateManager`, `setDepositPreIntentHook`, `setDepositWhitelistHook` |
|
|
100
100
|
| Vault / DRM | `createRateManager`, `setVaultMinRate`, `setVaultMinRatesBatch`, `setVaultFee`, `setVaultConfig`, `getDepositRateManager`, `getManagerFee`, `getEffectiveRate` |
|
|
101
101
|
| Oracle config | `setOracleRateConfig`, `setOracleRateConfigBatch`, `removeOracleRateConfig`, `updateCurrencyConfigBatch`, `deactivateCurrenciesBatch`, `supportsInlineOracleRateConfig`, `validateOracleFeedsOnChain` |
|
|
@@ -156,7 +156,7 @@ const payeeHash = await client.resolvePayeeHash(
|
|
|
156
156
|
);
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
-
`getQuote()` returns available liquidity plus payee details when authenticated. `getTakerTier()` returns limits and cooldown data for taker UX.
|
|
159
|
+
`getQuote()` returns available liquidity plus payee details when authenticated. Use `getQuotesBestByPlatform()` to fetch the best quote per supported payment platform in a single call (handy for cross-platform comparison UIs). `getTakerTier()` returns limits and cooldown data for taker UX.
|
|
160
160
|
|
|
161
161
|
## Signal, Fulfill, and Release Intents
|
|
162
162
|
|
|
@@ -519,7 +519,7 @@ The SDK ships currency metadata for 34 fiat currencies:
|
|
|
519
519
|
|
|
520
520
|
## Supported Payment Platforms
|
|
521
521
|
|
|
522
|
-
`wise`, `venmo`, `revolut`, `cashapp`, `mercadopago`, `zelle`, `paypal`, `monzo`, `chime`, `luxon`, `n26`
|
|
522
|
+
`wise`, `venmo`, `revolut`, `cashapp`, `mercadopago`, `zelle`, `paypal`, `monzo`, `chime`, `luxon`, `n26`, `alipay`
|
|
523
523
|
|
|
524
524
|
## Attribution (ERC-8021)
|
|
525
525
|
|
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) {
|
|
@@ -1459,7 +1460,7 @@ function createHeaders(apiKey, authorizationToken) {
|
|
|
1459
1460
|
return headers2;
|
|
1460
1461
|
}
|
|
1461
1462
|
async function apiSignIntentV3(request, opts) {
|
|
1462
|
-
const url = `${opts.baseApiUrl.replace(/\/$/, "")}/v3/intent`;
|
|
1463
|
+
const url = `${opts.baseApiUrl.replace(/\/$/, "")}/v3/intent/sign`;
|
|
1463
1464
|
const json = await withRetry(
|
|
1464
1465
|
async () => {
|
|
1465
1466
|
let res;
|
|
@@ -1471,7 +1472,7 @@ async function apiSignIntentV3(request, opts) {
|
|
|
1471
1472
|
});
|
|
1472
1473
|
} catch (error) {
|
|
1473
1474
|
throw new exports.NetworkError("Failed to connect to API server", {
|
|
1474
|
-
endpoint: "/v3/intent",
|
|
1475
|
+
endpoint: "/v3/intent/sign",
|
|
1475
1476
|
error
|
|
1476
1477
|
});
|
|
1477
1478
|
}
|
|
@@ -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;
|
|
1491
|
-
|
|
1492
|
+
const referralFees = json?.responseObject?.intentData?.referralFees ?? json?.responseObject?.referralFees;
|
|
1493
|
+
if (!sig || !expStr) throw new Error("v3/intent/sign 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
|
-
|
|
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/sign returned invalid referral fee recipient");
|
|
1971
|
+
}
|
|
1972
|
+
let fee;
|
|
1973
|
+
try {
|
|
1974
|
+
fee = BigInt(referralFee.fee);
|
|
1975
|
+
} catch {
|
|
1976
|
+
throw new Error("v3/intent/sign 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,
|
|
5951
|
+
async function apiPostDepositDetails(req, baseApiUrl, timeoutMs, _apiKey, _authToken) {
|
|
5931
5952
|
return apiFetch({
|
|
5932
|
-
url: `${withApiBase(baseApiUrl)}/
|
|
5953
|
+
url: `${withApiBase(baseApiUrl)}/v2/makers/create`,
|
|
5933
5954
|
method: "POST",
|
|
5934
5955
|
body: req,
|
|
5935
|
-
apiKey,
|
|
5936
|
-
authToken,
|
|
5937
5956
|
timeoutMs
|
|
5938
5957
|
});
|
|
5939
5958
|
}
|
|
@@ -5943,16 +5962,29 @@ 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
|
-
quotesToReturn: void 0
|
|
5986
|
+
quotesToReturn: void 0,
|
|
5987
|
+
includePrivateOrderbooks: req.includePrivateOrderbooks
|
|
5956
5988
|
};
|
|
5957
5989
|
Object.keys(requestBody).forEach((k) => requestBody[k] === void 0 && delete requestBody[k]);
|
|
5958
5990
|
return apiFetch({
|
|
@@ -5964,9 +5996,32 @@ async function apiGetQuote(req, baseApiUrl, timeoutMs, apiKey, authToken) {
|
|
|
5964
5996
|
timeoutMs
|
|
5965
5997
|
});
|
|
5966
5998
|
}
|
|
5999
|
+
async function apiGetQuotesBestByPlatform(req, baseApiUrl, timeoutMs, apiKey, authToken) {
|
|
6000
|
+
const isExactFiat = req.isExactFiat !== false;
|
|
6001
|
+
const endpoint = isExactFiat ? "best-by-platform" : "best-by-platform-exact-token";
|
|
6002
|
+
const url = `${withApiBase(baseApiUrl)}/v2/quote/${endpoint}`;
|
|
6003
|
+
const requestBody = {
|
|
6004
|
+
...req,
|
|
6005
|
+
[isExactFiat ? "exactFiatAmount" : "exactTokenAmount"]: String(req.amount),
|
|
6006
|
+
amount: void 0,
|
|
6007
|
+
isExactFiat: void 0,
|
|
6008
|
+
referrerFeeConfig: void 0
|
|
6009
|
+
};
|
|
6010
|
+
Object.keys(requestBody).forEach(
|
|
6011
|
+
(key) => requestBody[key] === void 0 && delete requestBody[key]
|
|
6012
|
+
);
|
|
6013
|
+
return apiFetch({
|
|
6014
|
+
url,
|
|
6015
|
+
method: "POST",
|
|
6016
|
+
body: requestBody,
|
|
6017
|
+
apiKey,
|
|
6018
|
+
authToken,
|
|
6019
|
+
timeoutMs
|
|
6020
|
+
});
|
|
6021
|
+
}
|
|
5967
6022
|
async function apiGetPayeeDetails(req, apiKey, baseApiUrl, authToken, timeoutMs) {
|
|
5968
6023
|
return apiFetch({
|
|
5969
|
-
url: `${baseApiUrl.replace(/\/$/, "")}/
|
|
6024
|
+
url: `${baseApiUrl.replace(/\/$/, "")}/v2/makers/${req.processorName}/${req.hashedOnchainId}`,
|
|
5970
6025
|
method: "GET",
|
|
5971
6026
|
apiKey,
|
|
5972
6027
|
authToken,
|
|
@@ -5975,7 +6030,7 @@ async function apiGetPayeeDetails(req, apiKey, baseApiUrl, authToken, timeoutMs)
|
|
|
5975
6030
|
}
|
|
5976
6031
|
async function apiValidatePayeeDetails(req, baseApiUrl, timeoutMs) {
|
|
5977
6032
|
const data = await apiFetch({
|
|
5978
|
-
url: `${baseApiUrl.replace(/\/$/, "")}/
|
|
6033
|
+
url: `${baseApiUrl.replace(/\/$/, "")}/v2/makers/validate`,
|
|
5979
6034
|
method: "POST",
|
|
5980
6035
|
body: req,
|
|
5981
6036
|
timeoutMs
|
|
@@ -6030,7 +6085,6 @@ async function apiGetTakerTier(req, apiKey, baseApiUrl, timeoutMs) {
|
|
|
6030
6085
|
return apiFetch({
|
|
6031
6086
|
url: `${withApiBase(baseApiUrl)}${endpoint}`,
|
|
6032
6087
|
method: "GET",
|
|
6033
|
-
apiKey,
|
|
6034
6088
|
timeoutMs
|
|
6035
6089
|
});
|
|
6036
6090
|
}
|
|
@@ -6132,6 +6186,23 @@ var appendReferrerFeeDisplayFields = (quoteResponse, referrerFeeConfig) => {
|
|
|
6132
6186
|
}
|
|
6133
6187
|
};
|
|
6134
6188
|
};
|
|
6189
|
+
var appendReferrerFeeDisplayFieldsToBestByPlatform = (quoteResponse, referrerFeeConfig) => {
|
|
6190
|
+
if (!referrerFeeConfig) {
|
|
6191
|
+
return quoteResponse;
|
|
6192
|
+
}
|
|
6193
|
+
const decimals = quoteResponse.responseObject?.token?.decimals ?? 6;
|
|
6194
|
+
const enrichedPlatformQuotes = (quoteResponse.responseObject?.platformQuotes ?? []).map((platformQuote) => ({
|
|
6195
|
+
...platformQuote,
|
|
6196
|
+
bestQuote: platformQuote.available && platformQuote.bestQuote ? applyReferrerFeeDisplayFieldsToQuote(platformQuote.bestQuote, referrerFeeConfig, decimals) : platformQuote.bestQuote
|
|
6197
|
+
}));
|
|
6198
|
+
return {
|
|
6199
|
+
...quoteResponse,
|
|
6200
|
+
responseObject: {
|
|
6201
|
+
...quoteResponse.responseObject,
|
|
6202
|
+
platformQuotes: enrichedPlatformQuotes
|
|
6203
|
+
}
|
|
6204
|
+
};
|
|
6205
|
+
};
|
|
6135
6206
|
|
|
6136
6207
|
// src/utils/erc20.ts
|
|
6137
6208
|
var ERC20_ABI = [
|
|
@@ -6158,6 +6229,95 @@ var ERC20_ABI = [
|
|
|
6158
6229
|
];
|
|
6159
6230
|
|
|
6160
6231
|
// src/client/Zkp2pClient.ts
|
|
6232
|
+
function isStringRecord(value) {
|
|
6233
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6234
|
+
return false;
|
|
6235
|
+
}
|
|
6236
|
+
return Object.values(value).every((entry) => typeof entry === "string");
|
|
6237
|
+
}
|
|
6238
|
+
function normalizeTelegramUsername(value) {
|
|
6239
|
+
if (typeof value !== "string") {
|
|
6240
|
+
return value === null ? null : null;
|
|
6241
|
+
}
|
|
6242
|
+
const normalized = value.trim();
|
|
6243
|
+
return normalized.length > 0 ? normalized : null;
|
|
6244
|
+
}
|
|
6245
|
+
function extractLegacyQuotePayeeData(depositData) {
|
|
6246
|
+
if (!depositData || typeof depositData !== "object" || Array.isArray(depositData)) {
|
|
6247
|
+
return void 0;
|
|
6248
|
+
}
|
|
6249
|
+
const stringEntries = Object.entries(depositData).filter(
|
|
6250
|
+
(entry) => typeof entry[1] === "string" && entry[1].trim().length > 0
|
|
6251
|
+
);
|
|
6252
|
+
const telegramUsername = stringEntries.find(([key]) => key === "telegramUsername")?.[1] ?? null;
|
|
6253
|
+
const identifierEntries = stringEntries.filter(([key]) => key !== "telegramUsername");
|
|
6254
|
+
const [primaryEntry, ...metadataEntries] = identifierEntries;
|
|
6255
|
+
if (!primaryEntry) {
|
|
6256
|
+
return void 0;
|
|
6257
|
+
}
|
|
6258
|
+
return {
|
|
6259
|
+
offchainId: primaryEntry[1],
|
|
6260
|
+
telegramUsername,
|
|
6261
|
+
metadata: metadataEntries.length > 0 ? Object.fromEntries(metadataEntries) : null
|
|
6262
|
+
};
|
|
6263
|
+
}
|
|
6264
|
+
function normalizeQuotePayeeData(maker) {
|
|
6265
|
+
const legacy = extractLegacyQuotePayeeData(maker?.depositData);
|
|
6266
|
+
const offchainId = typeof maker?.offchainId === "string" && maker.offchainId.trim().length > 0 ? maker.offchainId : legacy?.offchainId;
|
|
6267
|
+
if (!offchainId) {
|
|
6268
|
+
return void 0;
|
|
6269
|
+
}
|
|
6270
|
+
return {
|
|
6271
|
+
offchainId,
|
|
6272
|
+
telegramUsername: normalizeTelegramUsername(maker?.telegramUsername) ?? legacy?.telegramUsername ?? null,
|
|
6273
|
+
metadata: isStringRecord(maker?.metadata) ? maker.metadata : legacy?.metadata ?? null
|
|
6274
|
+
};
|
|
6275
|
+
}
|
|
6276
|
+
function normalizePayeeDataInputItem(raw) {
|
|
6277
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
6278
|
+
return null;
|
|
6279
|
+
}
|
|
6280
|
+
const candidate = raw;
|
|
6281
|
+
if (typeof candidate.offchainId === "string" && candidate.offchainId.trim().length > 0) {
|
|
6282
|
+
return candidate;
|
|
6283
|
+
}
|
|
6284
|
+
const legacy = extractLegacyQuotePayeeData(raw);
|
|
6285
|
+
if (!legacy) {
|
|
6286
|
+
return null;
|
|
6287
|
+
}
|
|
6288
|
+
return {
|
|
6289
|
+
offchainId: legacy.offchainId,
|
|
6290
|
+
telegramUsername: legacy.telegramUsername,
|
|
6291
|
+
metadata: legacy.metadata
|
|
6292
|
+
};
|
|
6293
|
+
}
|
|
6294
|
+
function resolvePayeeDataInput(params, methodName) {
|
|
6295
|
+
const payeeData = params.payeeData ?? params.depositData;
|
|
6296
|
+
if (!Array.isArray(payeeData)) {
|
|
6297
|
+
throw new Error(`${methodName} requires payeeData`);
|
|
6298
|
+
}
|
|
6299
|
+
const normalized = payeeData.map((item, index) => {
|
|
6300
|
+
const result = normalizePayeeDataInputItem(item);
|
|
6301
|
+
if (!result) {
|
|
6302
|
+
throw new Error(
|
|
6303
|
+
`${methodName}: payeeData[${index}] must include a non-empty offchainId or a recognizable legacy identifier`
|
|
6304
|
+
);
|
|
6305
|
+
}
|
|
6306
|
+
return result;
|
|
6307
|
+
});
|
|
6308
|
+
return normalized;
|
|
6309
|
+
}
|
|
6310
|
+
function toPostDepositDetailsRequest(processorName, payeeData, index) {
|
|
6311
|
+
if (!payeeData || typeof payeeData.offchainId !== "string" || payeeData.offchainId.length === 0) {
|
|
6312
|
+
throw new Error(`payeeData[${index}] must include a non-empty offchainId`);
|
|
6313
|
+
}
|
|
6314
|
+
return {
|
|
6315
|
+
processorName,
|
|
6316
|
+
offchainId: payeeData.offchainId,
|
|
6317
|
+
telegramUsername: payeeData.telegramUsername,
|
|
6318
|
+
metadata: payeeData.metadata
|
|
6319
|
+
};
|
|
6320
|
+
}
|
|
6161
6321
|
var Zkp2pClient = class {
|
|
6162
6322
|
/**
|
|
6163
6323
|
* Creates a new Zkp2pClient instance.
|
|
@@ -6704,7 +6864,9 @@ var Zkp2pClient = class {
|
|
|
6704
6864
|
* sending fiat payment to the deposit's payee.
|
|
6705
6865
|
*
|
|
6706
6866
|
* If `gatingServiceSignature` is not provided, the SDK will automatically
|
|
6707
|
-
* fetch one from
|
|
6867
|
+
* fetch one from curator `/v3/intent/sign` when `apiKey` or `authorizationToken`
|
|
6868
|
+
* is available. Otherwise you must provide `gatingServiceSignature` and
|
|
6869
|
+
* `signatureExpiration` yourself.
|
|
6708
6870
|
*
|
|
6709
6871
|
* **Prepare Mode**: Use `.prepare()` to get the transaction calldata without sending:
|
|
6710
6872
|
* ```typescript
|
|
@@ -8016,42 +8178,32 @@ var Zkp2pClient = class {
|
|
|
8016
8178
|
* register maker payment details with the curator service.
|
|
8017
8179
|
*
|
|
8018
8180
|
* @param params.processorNames - Payment platforms (e.g., ['wise', 'revolut'])
|
|
8019
|
-
* @param params.
|
|
8181
|
+
* @param params.payeeData - Payee details per processor (e.g., [{ offchainId: 'you@example.com' }]). Required when the SDK needs to register payee details with the curator.
|
|
8020
8182
|
* @returns The posted deposit details and their corresponding hashed on-chain IDs
|
|
8021
8183
|
*
|
|
8022
8184
|
* @example
|
|
8023
8185
|
* ```typescript
|
|
8024
8186
|
* const { hashedOnchainIds } = await client.registerPayeeDetails({
|
|
8025
8187
|
* processorNames: ['wise'],
|
|
8026
|
-
*
|
|
8188
|
+
* payeeData: [{ offchainId: 'you@example.com' }],
|
|
8027
8189
|
* });
|
|
8028
8190
|
* // Then pass hashedOnchainIds to createDeposit
|
|
8029
8191
|
* ```
|
|
8030
8192
|
*/
|
|
8031
8193
|
async registerPayeeDetails(params) {
|
|
8194
|
+
const payeeData = resolvePayeeDataInput(params, "registerPayeeDetails");
|
|
8032
8195
|
if (!Array.isArray(params.processorNames) || params.processorNames.length === 0) {
|
|
8033
8196
|
throw new Error("processorNames must be a non-empty array");
|
|
8034
8197
|
}
|
|
8035
|
-
if (params.processorNames.length !==
|
|
8036
|
-
throw new Error("processorNames and
|
|
8198
|
+
if (params.processorNames.length !== payeeData.length) {
|
|
8199
|
+
throw new Error("processorNames and payeeData length mismatch");
|
|
8037
8200
|
}
|
|
8038
8201
|
const baseApiUrl = (this.baseApiUrl ?? "https://api.zkp2p.xyz").replace(/\/$/, "");
|
|
8039
8202
|
const depositDetails = params.processorNames.map(
|
|
8040
|
-
(processorName, index) => (
|
|
8041
|
-
processorName,
|
|
8042
|
-
depositData: params.depositData[index] || {}
|
|
8043
|
-
})
|
|
8203
|
+
(processorName, index) => toPostDepositDetailsRequest(processorName, payeeData[index], index)
|
|
8044
8204
|
);
|
|
8045
8205
|
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
|
-
)
|
|
8206
|
+
depositDetails.map((req) => apiPostDepositDetails(req, baseApiUrl, this.apiTimeoutMs))
|
|
8055
8207
|
);
|
|
8056
8208
|
if (!apiResponses.every((r) => r?.success)) {
|
|
8057
8209
|
const failed = apiResponses.find((r) => !r?.success);
|
|
@@ -8075,16 +8227,17 @@ var Zkp2pClient = class {
|
|
|
8075
8227
|
* @param params.amount - Total deposit amount in token units (6 decimals for USDC)
|
|
8076
8228
|
* @param params.intentAmountRange - Min/max amount per intent
|
|
8077
8229
|
* @param params.processorNames - Payment platforms to accept (e.g., ['wise', 'revolut'])
|
|
8078
|
-
* @param params.
|
|
8230
|
+
* @param params.payeeData - Payee details per processor (e.g., [{ offchainId: 'you@example.com' }])
|
|
8079
8231
|
* @param params.conversionRates - Conversion rates per processor, grouped by currency
|
|
8080
8232
|
* @param params.payeeDetailsHashes - Pre-computed hashed on-chain IDs (from registerPayeeDetails). When provided, skips the curator API call entirely.
|
|
8081
8233
|
* @param params.delegate - Optional delegate address that can manage the deposit
|
|
8082
8234
|
* @param params.intentGuardian - Optional guardian for intent approval
|
|
8083
8235
|
* @param params.retainOnEmpty - Keep deposit active when balance reaches zero
|
|
8084
8236
|
* @param params.txOverrides - Optional viem transaction overrides
|
|
8085
|
-
* @returns The deposit details posted to API and the transaction hash
|
|
8237
|
+
* @returns The deposit details posted to API (empty when payee registration is skipped) and the transaction hash
|
|
8086
8238
|
*
|
|
8087
|
-
* @throws Error if processorNames,
|
|
8239
|
+
* @throws Error if processorNames, payeeData, and conversionRates lengths don't match
|
|
8240
|
+
* @throws Error if payeeData is missing and neither payeeDetailsHashes nor full payment method overrides are provided
|
|
8088
8241
|
* @throws Error if a currency is not supported by the specified processor
|
|
8089
8242
|
*
|
|
8090
8243
|
* @example
|
|
@@ -8095,7 +8248,7 @@ var Zkp2pClient = class {
|
|
|
8095
8248
|
* amount: 1000_000000n,
|
|
8096
8249
|
* intentAmountRange: { min: 10_000000n, max: 500_000000n },
|
|
8097
8250
|
* processorNames: ['wise'],
|
|
8098
|
-
*
|
|
8251
|
+
* payeeData: [{ offchainId: 'you@example.com' }],
|
|
8099
8252
|
* conversionRates: [[
|
|
8100
8253
|
* { currency: 'USD', conversionRate: '1020000000000000000' }, // 1.02
|
|
8101
8254
|
* { currency: 'EUR', conversionRate: '1100000000000000000' }, // 1.10
|
|
@@ -8128,24 +8281,30 @@ var Zkp2pClient = class {
|
|
|
8128
8281
|
};
|
|
8129
8282
|
}
|
|
8130
8283
|
async prepareCreateDepositInternal(params) {
|
|
8284
|
+
const hasOverrides = Boolean(
|
|
8285
|
+
params.paymentMethodsOverride || params.paymentMethodDataOverride || params.currenciesOverride
|
|
8286
|
+
);
|
|
8287
|
+
const payeeDetailsHashes = params.payeeDetailsHashes;
|
|
8288
|
+
const hasPayeeHashes = payeeDetailsHashes !== void 0;
|
|
8289
|
+
const shouldResolvePayeeData = params.payeeData !== void 0 || params.depositData !== void 0;
|
|
8290
|
+
const payeeData = shouldResolvePayeeData ? resolvePayeeDataInput(params, "createDeposit") : null;
|
|
8131
8291
|
if (!Array.isArray(params.processorNames) || params.processorNames.length === 0) {
|
|
8132
8292
|
throw new Error("processorNames must be a non-empty array");
|
|
8133
8293
|
}
|
|
8134
8294
|
if (params.processorNames.length !== params.conversionRates.length) {
|
|
8135
8295
|
throw new Error("processorNames and conversionRates length mismatch");
|
|
8136
8296
|
}
|
|
8137
|
-
if (params.processorNames.length !==
|
|
8138
|
-
throw new Error("processorNames and
|
|
8297
|
+
if (payeeData && params.processorNames.length !== payeeData.length) {
|
|
8298
|
+
throw new Error("processorNames and payeeData length mismatch");
|
|
8139
8299
|
}
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
);
|
|
8300
|
+
if (!hasOverrides && !hasPayeeHashes && !payeeData) {
|
|
8301
|
+
throw new Error(
|
|
8302
|
+
"createDeposit requires payeeData unless payeeDetailsHashes or full payment method overrides are provided"
|
|
8303
|
+
);
|
|
8304
|
+
}
|
|
8305
|
+
const depositDetails = payeeData ? params.processorNames.map(
|
|
8306
|
+
(processorName, index) => toPostDepositDetailsRequest(processorName, payeeData[index], index)
|
|
8307
|
+
) : [];
|
|
8149
8308
|
let paymentMethods;
|
|
8150
8309
|
let paymentMethodData;
|
|
8151
8310
|
let currencies;
|
|
@@ -8170,23 +8329,15 @@ var Zkp2pClient = class {
|
|
|
8170
8329
|
);
|
|
8171
8330
|
const intentGatingService = getGatingServiceAddress(this.chainId, this.runtimeEnv);
|
|
8172
8331
|
let hashedOnchainIds;
|
|
8173
|
-
if (
|
|
8174
|
-
if (
|
|
8332
|
+
if (payeeDetailsHashes !== void 0) {
|
|
8333
|
+
if (payeeDetailsHashes.length !== params.processorNames.length) {
|
|
8175
8334
|
throw new Error("payeeDetailsHashes length must match processorNames length");
|
|
8176
8335
|
}
|
|
8177
|
-
hashedOnchainIds =
|
|
8336
|
+
hashedOnchainIds = payeeDetailsHashes;
|
|
8178
8337
|
} else {
|
|
8179
8338
|
const baseApiUrl = (this.baseApiUrl ?? "https://api.zkp2p.xyz").replace(/\/$/, "");
|
|
8180
8339
|
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
|
-
)
|
|
8340
|
+
depositDetails.map((req) => apiPostDepositDetails(req, baseApiUrl, this.apiTimeoutMs))
|
|
8190
8341
|
);
|
|
8191
8342
|
if (!apiResponses.every((r) => r?.success)) {
|
|
8192
8343
|
const failed = apiResponses.find((r) => !r?.success);
|
|
@@ -8383,12 +8534,64 @@ var Zkp2pClient = class {
|
|
|
8383
8534
|
const quotes = quote?.responseObject?.quotes ?? [];
|
|
8384
8535
|
for (const q of quotes) {
|
|
8385
8536
|
const maker = q?.maker;
|
|
8386
|
-
|
|
8387
|
-
|
|
8537
|
+
const payeeData = normalizeQuotePayeeData(maker);
|
|
8538
|
+
if (payeeData && typeof q === "object") {
|
|
8539
|
+
q.payeeData = payeeData;
|
|
8388
8540
|
}
|
|
8389
8541
|
}
|
|
8390
8542
|
return appendReferrerFeeDisplayFields(quote, referrerFeeConfig);
|
|
8391
8543
|
}
|
|
8544
|
+
/**
|
|
8545
|
+
* **Supporting Method** - Fetches the best available quote per supported payment platform.
|
|
8546
|
+
*
|
|
8547
|
+
* Returns one quote per platform when available. When authenticated, the API
|
|
8548
|
+
* returns payee details in each platform's best quote.
|
|
8549
|
+
*
|
|
8550
|
+
* @param req - Best-by-platform quote request parameters
|
|
8551
|
+
* @param opts - Optional overrides for API URL and timeout
|
|
8552
|
+
* @returns Best-by-platform quote response
|
|
8553
|
+
*/
|
|
8554
|
+
async getQuotesBestByPlatform(req, opts) {
|
|
8555
|
+
const referrerFeeConfig = assertValidReferrerFeeConfig(
|
|
8556
|
+
req.referrerFeeConfig,
|
|
8557
|
+
"getQuotesBestByPlatform"
|
|
8558
|
+
);
|
|
8559
|
+
const baseApiUrl = (opts?.baseApiUrl ?? this.baseApiUrl ?? "https://api.zkp2p.xyz").replace(
|
|
8560
|
+
/\/$/,
|
|
8561
|
+
""
|
|
8562
|
+
);
|
|
8563
|
+
const timeoutMs = opts?.timeoutMs ?? this.apiTimeoutMs;
|
|
8564
|
+
const reqWithEscrow = { ...req };
|
|
8565
|
+
if (!reqWithEscrow.escrowAddresses || reqWithEscrow.escrowAddresses.length === 0) {
|
|
8566
|
+
const configuredEscrows = this.escrowAddresses.length > 0 ? [...this.escrowAddresses] : this.escrowAddress ? [this.escrowAddress] : [];
|
|
8567
|
+
if (configuredEscrows.length > 0) {
|
|
8568
|
+
reqWithEscrow.escrowAddresses = configuredEscrows;
|
|
8569
|
+
}
|
|
8570
|
+
}
|
|
8571
|
+
const quote = await apiGetQuotesBestByPlatform(
|
|
8572
|
+
reqWithEscrow,
|
|
8573
|
+
baseApiUrl,
|
|
8574
|
+
timeoutMs,
|
|
8575
|
+
this.apiKey,
|
|
8576
|
+
this.authorizationToken
|
|
8577
|
+
);
|
|
8578
|
+
const enrichedQuote = quote ? {
|
|
8579
|
+
...quote,
|
|
8580
|
+
responseObject: {
|
|
8581
|
+
...quote.responseObject,
|
|
8582
|
+
platformQuotes: (quote.responseObject?.platformQuotes ?? []).map((platformQuote) => {
|
|
8583
|
+
const bestQuote = platformQuote?.bestQuote;
|
|
8584
|
+
const payeeData = normalizeQuotePayeeData(bestQuote?.maker);
|
|
8585
|
+
if (!bestQuote || !payeeData) return platformQuote;
|
|
8586
|
+
return {
|
|
8587
|
+
...platformQuote,
|
|
8588
|
+
bestQuote: { ...bestQuote, payeeData }
|
|
8589
|
+
};
|
|
8590
|
+
})
|
|
8591
|
+
}
|
|
8592
|
+
} : quote;
|
|
8593
|
+
return appendReferrerFeeDisplayFieldsToBestByPlatform(enrichedQuote, referrerFeeConfig);
|
|
8594
|
+
}
|
|
8392
8595
|
// ───────────────────────────────────────────────────────────────────────────
|
|
8393
8596
|
// SUPPORTING: TAKER TIER
|
|
8394
8597
|
// (Used by frontends to display taker limits)
|
|
@@ -8408,7 +8611,7 @@ var Zkp2pClient = class {
|
|
|
8408
8611
|
""
|
|
8409
8612
|
);
|
|
8410
8613
|
const timeoutMs = opts?.timeoutMs ?? this.apiTimeoutMs;
|
|
8411
|
-
return apiGetTakerTier(req,
|
|
8614
|
+
return apiGetTakerTier(req, void 0, baseApiUrl, timeoutMs);
|
|
8412
8615
|
}
|
|
8413
8616
|
// ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
8414
8617
|
// ║ CORE: ON-CHAIN DEPOSIT VIEWS ║
|
|
@@ -8838,6 +9041,7 @@ exports.ZKP2P_IOS_REFERRER = ZKP2P_IOS_REFERRER;
|
|
|
8838
9041
|
exports.Zkp2pClient = Zkp2pClient;
|
|
8839
9042
|
exports.apiGetOwnerDeposits = apiGetOwnerDeposits;
|
|
8840
9043
|
exports.apiGetPayeeDetails = apiGetPayeeDetails;
|
|
9044
|
+
exports.apiGetQuotesBestByPlatform = apiGetQuotesBestByPlatform;
|
|
8841
9045
|
exports.apiGetTakerTier = apiGetTakerTier;
|
|
8842
9046
|
exports.apiPostDepositDetails = apiPostDepositDetails;
|
|
8843
9047
|
exports.apiValidatePayeeDetails = apiValidatePayeeDetails;
|