@zkp2p/sdk
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.
Current version: 0.5.2
Why This SDK
- Build maker, taker, vault, and embedded ramp flows from one client.
- Read live protocol state directly from ProtocolViewer instead of waiting on indexer sync.
- Route against the EscrowV2/OrchestratorV2 stack — legacy V1 resolution has been removed.
- Use prepareable write methods for smart accounts, relayers, gas estimation, and batching.
- Keep advanced analytics, fund activity history, and vault stats behind
client.indexer.*.
Who This Is For
- maker and liquidity-provider applications
- wallets and embedded onramp/offramp products
- backends that need contract-safe deposit and intent operations
- dashboards and analytics services that query
client.indexer.* - React apps that want first-party hooks instead of writing transaction glue
Architecture
- RPC-first reads: primary reads use ProtocolViewer and on-chain fallbacks, so
getDeposits(),getDeposit(),getIntents(),getIntent(), and thegetPv*methods are not blocked on indexer lag. - Indexer for history and filtering: use
client.indexer.*for pagination, historical volumes, fund activities, daily snapshots, and vault analytics. - V2-only routing: the client resolves against EscrowV2 and OrchestratorV2. Legacy V1 escrow/orchestrator fallbacks have been removed from both read and write paths.
- Modular internals: intent, vault, and ProtocolViewer logic are extracted into
IntentOperations,VaultOperations, andProtocolViewerReader, keepingZkp2pClientfocused on orchestration. - App-level rollout control: the SDK is capability-based. Product gating and phase flags belong in your app layer, not inside transaction helpers.
Installation
npm install @zkp2p/sdk viem
# or
pnpm add @zkp2p/sdk viem
# or
bun add @zkp2p/sdk viemIf you use React hooks, add React as well:
pnpm add reactQuick Start
import { Zkp2pClient } from '@zkp2p/sdk';
import { createWalletClient, custom } from 'viem';
import { base } from 'viem/chains';
const walletClient = createWalletClient({
chain: base,
transport: custom(window.ethereum),
});
const client = new Zkp2pClient({
walletClient,
chainId: base.id,
});runtimeEnv defaults to 'production'. Use 'preproduction' or 'staging' when you want to point the SDK at those deployments.
Environment and Authentication
- Supported runtime environments:
'production','preproduction','staging' runtimeEnvdefault:'production'rpcUrl: optional RPC URL override (defaults to wallet's chain RPC)apiKey: optional internal curator API key for internal seller verification onlyauthorizationToken/getAuthorizationToken: optional bearer auth for indexer flowsindexerApiKey: optionalx-api-keyfor indexer proxy authindexerUrlandbaseApiUrl: override defaults when you are targeting custom deploymentstimeouts:{ api?: number }— API timeout in milliseconds (default 15000)
No external API key is required. createDeposit, registerPayeeDetails, getQuote, getTakerTier, signalIntent, and the rest of the public SDK flows work without apiKey or authorizationToken. When baseApiUrl is configured, signalIntent() can auto-fetch a gating service signature from curator /v3/intent/sign without auth. Quote responses include resolved maker payee details (offchainId, telegramUsername, metadata) when curator has them.
Indexer defaults by environment:
production:https://indexer.zkp2p.xyz/v1/graphqlpreproduction:https://indexer-preprod.zkp2p.xyz/v1/graphqlstaging:https://indexer-staging.zkp2p.xyz/v1/graphql
Core Capabilities
| Area | Stable surface |
|---|---|
| Deposits | createDeposit, addFunds, removeFunds, withdrawDeposit, ensureAllowance, setAcceptingIntents, setIntentRange, setCurrencyMinRate, setRetainOnEmpty |
| Payment methods and currencies | addPaymentMethods, removePaymentMethod, setPaymentMethodActive, addCurrencies, removeCurrency, deactivateCurrency, pruneExpiredIntents |
| Intents | signalIntent, fulfillIntent, cancelIntent, releaseFundsToPayer, getFulfillIntentInputs |
| 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 |
| Payee and quote APIs | registerPayeeDetails, resolvePayeeHash, getQuote, getQuotesBestByPlatform, getTakerTier |
| Seller automated release | uploadSellerCredential, getSellerCredentialStatus, verifySellerPayment |
| Delegation and hooks | setDelegate, removeDelegate, setRateManager, clearRateManager, setDepositRateManager, clearDepositRateManager, setDepositPreIntentHook, setDepositWhitelistHook |
| Vault / DRM | createRateManager, setVaultMinRate, setVaultMinRatesBatch, setVaultFee, setVaultConfig, getDepositRateManager, getManagerFee, getEffectiveRate |
| Oracle config | setOracleRateConfig, setOracleRateConfigBatch, removeOracleRateConfig, updateCurrencyConfigBatch, deactivateCurrenciesBatch, supportsInlineOracleRateConfig, validateOracleFeedsOnChain |
| RPC reads | getDeposits, getDeposit, getDepositsById, getIntents, getIntent, getPvDepositById, getPvDepositsFromIds, getPvAccountDeposits, getPvAccountIntents, getPvIntent |
| Indexer | client.indexer.getDeposits, getDepositsWithRelations, getDepositById, getDepositsByIds, getDepositsByIdsWithRelations, getDepositsByPayeeHash, getIntentsForDeposits, getOwnerIntents, getIntentsByRateManager, getIntentByHash, getExpiredIntents, getFulfilledIntentEvents, getIntentFulfillmentAmounts, getFulfillmentAndPayment, getDepositFundActivities, getMakerFundActivities, getDepositDailySnapshots, getProfitSnapshotsByDeposits, getRateManagers, getRateManagerDetail, getRateManagerDelegations, getDelegationForDeposit, getManagerDailySnapshots, getManualRateUpdates, getOracleConfigUpdates, query |
| React hooks | @zkp2p/sdk/react exports hooks for deposits, intents, delegation, vaults, payment methods, and taker tier |
| Attribution | ERC-8021 helpers like sendTransactionWithAttribution, encodeWithAttribution, and txOverrides.referrer support |
Extension Metadata Bridge
Use createPeerExtensionSdk() when a page needs the Peer extension to open a
provider auth tab and interact with the Peer TEE protocol. The extension owns
provider-tab capture and Buyer TEE session encryption. For seller automated
release, the extension captures seller session material, creates the encrypted
attestation-service bundle, and returns only that bundle plus the maker
offchainId. The page owns maker payee registration and curator credential
storage.
import { createPeerExtensionSdk } from '@zkp2p/sdk';
const peer = createPeerExtensionSdk();
if ((await peer.getState()) === 'needs_connection') {
await peer.requestConnection();
}
const unsubscribe = peer.onMetadataMessage((message) => {
if (message.sarCredentialCapture) {
console.log('SAR credential bundle captured', message.sarCredentialCapture.credentialBundle);
return;
}
console.log('captured payment metadata', message.metadata);
});
peer.authenticate({
actionType: 'transfer_venmo',
captureMode: 'buyerTee',
platform: 'venmo',
attestationServiceUrl: 'https://attestation.zkp2p.xyz',
});requestConnection() is required for third-party origins. authenticate()
accepts an optional inline providerConfig object; otherwise the extension
fetches the default template from https://api.zkp2p.xyz/providers/. Buyer TEE
is API/template driven: pass captureMode: "buyerTee" plus
attestationServiceUrl, and the extension returns encrypted session material.
For SAR, pass captureMode: "sellerCredential" and optionally pass
attestationServiceUrl only when overriding the extension's production
attestation default. The extension returns sarCredentialCapture.credentialBundle
plus offchainId. The page should call apiUploadSellerCredentialBundle() to
register maker payee details with curator, compare the registered hash to the
bundle payeeIdHash, and store the encrypted bundle with curator. Plaintext
seller session material is never returned to the page.
Zkp2pClient.uploadSellerCredential() remains the backwards-compatible
plaintext convenience path for mobile and React Native callers. Internally it
creates the encrypted bundle, then uses the same
apiUploadSellerCredentialBundle() storage helper.
Create a Deposit
import { Currency } from '@zkp2p/sdk';
const result = await client.createDeposit({
token: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
amount: 10_000_000n,
intentAmountRange: { min: 100_000n, max: 5_000_000n },
processorNames: ['wise'],
depositData: [{ email: 'maker@example.com' }],
conversionRates: [[{ currency: Currency.USD, conversionRate: '1020000000000000000' }]],
});
console.log(result.hash);
console.log(result.depositDetails);If you do not pass payeeDetailsHashes, createDeposit() can register the payee details for you. If you want to pre-register or reuse hashes across deposits, use registerPayeeDetails() first.
Payee Registration, Quotes, and Taker Tier
import { resolvePaymentMethodHash } from '@zkp2p/sdk';
const { hashedOnchainIds } = await client.registerPayeeDetails({
processorNames: ['wise'],
depositData: [{ email: 'maker@example.com' }],
});
const quote = await client.getQuote({
paymentPlatforms: ['wise'],
fiatCurrency: 'USD',
user: '0xBuyer',
recipient: '0xBuyer',
destinationChainId: 8453,
destinationToken: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
amount: '250',
isExactFiat: true,
});
const takerTier = await client.getTakerTier({
owner: '0xBuyer',
chainId: 8453,
});
const payeeHash = await client.resolvePayeeHash(
42n,
resolvePaymentMethodHash('wise', { env: 'production' }),
);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.
Seller Credential Status
await client.uploadSellerCredential({
platform: 'venmo',
offchainId: 'alice',
payeeId: '123456',
sessionMaterial: {
recipientUsername: 'alice',
accountId: '123456',
sessionCookie: 'session-cookie',
},
});const status = await client.getSellerCredentialStatus({
processorName: 'venmo',
payeeDetails: '0xPAYEE_DETAILS_HASH',
});payeeDetails is the hashed payee details bytes32 used by maker registration, quotes, and on-chain intents. The public status endpoint returns { platform, payeeIdHash, status, credentialType }; maker row ids are intentionally not returned by status or upload responses.
Signal, Fulfill, and Release Intents
const intentHash = await client.signalIntent({
depositId: 42n,
amount: 250_000n,
toAddress: '0xBuyer',
processorName: 'wise',
payeeDetails: '0xPAYEE_DETAILS_HASH',
fiatCurrencyCode: 'USD',
conversionRate: 1_020_000_000_000_000_000n,
referralFees: [
{ recipient: '0xPlatformFeeRecipient', fee: 2_500n },
{ recipient: '0xPartnerFeeRecipient', fee: 1_250n },
],
});
await client.fulfillIntent({
intentHash,
proof: {
proofType: 'buyerTee',
encryptedSessionMaterial,
params: buyerTeePaymentParams,
},
});
await client.releaseFundsToPayer({
intentHash,
});Use referralFees[] for multi-recipient fee distribution on OrchestratorV2.
Prepared Transactions
Most write methods expose .prepare(params) and return a PreparedTransaction without sending the transaction. createDeposit() is the main exception and uses client.prepareCreateDeposit(params), which returns { depositDetails, prepared }. This is the stable pattern for smart accounts, batched user-ops, relayers, gas estimation, and custom senders.
const prepared = await client.signalIntent.prepare({
depositId: 42n,
amount: 250_000n,
toAddress: '0xBuyer',
processorName: 'wise',
payeeDetails: '0xPAYEE_DETAILS_HASH',
fiatCurrencyCode: 'USD',
conversionRate: 1_020_000_000_000_000_000n,
});
console.log(prepared);
// { to, data, value, chainId }React hooks mirror this where useful. For example, useSignalIntent() returns prepareSignalIntent() and prepared.
Error Handling
The SDK exports a normalized error model:
ZKP2PErrorValidationErrorNetworkErrorAPIErrorContractErrorErrorCode
import { APIError, ErrorCode, ValidationError, ZKP2PError } from '@zkp2p/sdk';
try {
await client.createDeposit({
token: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
amount: 10_000_000n,
intentAmountRange: { min: 100_000n, max: 5_000_000n },
processorNames: ['wise'],
depositData: [{ email: 'maker@example.com' }],
conversionRates: [[{ currency: 'USD', conversionRate: '1020000000000000000' }]],
});
} catch (error) {
if (error instanceof ValidationError) {
console.error('Invalid field:', error.field, error.message);
} else if (error instanceof APIError) {
console.error('HTTP status:', error.status, error.message);
} else if (error instanceof ZKP2PError) {
console.error('SDK error:', error.code ?? ErrorCode.UNKNOWN, error.details);
} else {
console.error('Unknown error:', error);
}
}You should still handle generic Error for lower-level transport or wallet failures that originate outside the normalized SDK wrappers.
Oracle Configuration
The SDK exports Chainlink and Pyth adapter helpers, plus a Chainlink-first getSpreadOracleConfig() resolver for bundled feed metadata.
import {
getSpreadOracleConfig,
resolveFiatCurrencyBytes32,
resolvePaymentMethodHash,
validateOracleFeedsOnChain,
} from '@zkp2p/sdk';
const paymentMethodHash = resolvePaymentMethodHash('wise', { env: 'production' });
const currencyHash = resolveFiatCurrencyBytes32('USD');
const oracle = getSpreadOracleConfig('USD');
if (!oracle) throw new Error('No bundled oracle config for USD');
await client.setOracleRateConfig({
depositId: 42n,
paymentMethodHash,
currencyHash,
config: {
adapter: oracle.adapter,
adapterConfig: oracle.adapterConfig,
spreadBps: -50,
maxStaleness: oracle.maxStaleness,
},
});
await client.updateCurrencyConfigBatch({
depositId: 42n,
paymentMethods: [paymentMethodHash],
updates: [
[
{
code: currencyHash,
minConversionRate: 1_020_000_000_000_000_000n,
updateOracle: true,
oracleRateConfig: {
adapter: oracle.adapter,
adapterConfig: oracle.adapterConfig,
spreadBps: -50,
maxStaleness: oracle.maxStaleness,
},
},
],
],
});
const availableFeeds = await validateOracleFeedsOnChain(client.publicClient);
console.log([...availableFeeds].sort());Useful helpers and methods in this area:
CHAINLINK_ORACLE_ADAPTERPYTH_ORACLE_ADAPTERencodeSpreadOracleAdapterConfigencodePythAdapterConfiggetSpreadOracleConfigsetOracleRateConfigBatchupdateCurrencyConfigBatchdeactivateCurrenciesBatch
Delegation and Hooks
await client.setDelegate({
depositId: 42n,
delegate: '0xDelegate',
});
await client.setRateManager({
depositId: 42n,
rateManagerAddress: '0xVaultAddress',
rateManagerId: '0xVaultId',
});
await client.setDepositPreIntentHook({
depositId: 42n,
preIntentHook: '0xHookAddress',
});
await client.setDepositWhitelistHook({
depositId: 42n,
whitelistHook: '0xHookAddress',
});Use removeDelegate() and clearRateManager() to unwind delegation. Hook methods are part of the current V2 surface; still validate target contract support before assuming a deployment exposes every hook.
Vault / DRM
const createHash = await client.createRateManager({
config: {
manager: '0xManager',
feeRecipient: '0xFeeRecipient',
maxFee: 50_000_000_000_000_000n,
fee: 10_000_000_000_000_000n,
name: 'My Vault',
uri: 'ipfs://vault-metadata',
},
});
await client.setVaultFee({
rateManagerId: '0xVaultId',
newFee: 20_000_000_000_000_000n,
});
await client.setVaultMinRate({
rateManagerId: '0xVaultId',
paymentMethodHash: resolvePaymentMethodHash('wise', { env: 'production' }),
currencyHash: resolveFiatCurrencyBytes32('USD'),
rate: 1_010_000_000_000_000_000n,
});
await client.setVaultConfig({
rateManagerId: '0xVaultId',
newManager: '0xNewManager',
newFeeRecipient: '0xNewFeeRecipient',
newName: 'Updated Vault',
newUri: 'ipfs://updated-vault-metadata',
});Protocol Viewer (RPC) Reads
ProtocolViewer methods bypass indexer lag and are the right default for primary user-facing reads.
const deposit = await client.getPvDepositById(42n);
const deposits = await client.getPvDepositsFromIds([42n, 43n]);
const makerDeposits = await client.getPvAccountDeposits('0xMaker');
const takerIntents = await client.getPvAccountIntents('0xTaker');
const intent = await client.getPvIntent('0xIntentHash');You can also use the convenience wrappers getDeposits(), getDeposit(), getIntents(), and getIntent() for common flows.
Indexer Queries
Use the indexer for filtered queries, pagination, fund activity history, snapshots, and vault analytics. All methods live on the flat client.indexer.* namespace.
// Deposit queries
const deposits = await client.indexer.getDeposits(
{ status: 'ACTIVE', depositor: '0xMaker' },
{ limit: 25, orderBy: 'updatedAt', orderDirection: 'desc' },
);
const depositsWithRelations = await client.indexer.getDepositsWithRelations(
{ status: 'ACTIVE' },
{ limit: 10 },
{ includeIntents: true },
);
const deposit = await client.indexer.getDepositById('8453_0xEscrowAddress_42', {
includeIntents: true,
});
const depositsByIds = await client.indexer.getDepositsByIds(['8453_0xEscrow_42']);
const depositsByIdsWithRelations = await client.indexer.getDepositsByIdsWithRelations(
['8453_0xEscrow_42'],
{ includeIntents: true },
);
const depositsByPayee = await client.indexer.getDepositsByPayeeHash('0xPayeeHash', {
paymentMethodHash: '0x...',
limit: 10,
includeIntents: true,
});
// Intent queries
const intentsForDeposits = await client.indexer.getIntentsForDeposits(
['8453_0xEscrow_42'],
['SIGNALED'],
);
const ownerIntents = await client.indexer.getOwnerIntents('0xTaker', ['SIGNALED', 'FULFILLED']);
const intentsByVault = await client.indexer.getIntentsByRateManager('0xVaultId');
const intent = await client.indexer.getIntentByHash('0xIntentHash');
const expiredIntents = await client.indexer.getExpiredIntents({
now: BigInt(Math.floor(Date.now() / 1000)),
depositIds: ['8453_0xEscrow_42'],
});
const fulfilledEvents = await client.indexer.getFulfilledIntentEvents(['0xIntentHash']);
const fulfillment = await client.indexer.getIntentFulfillmentAmounts('0xIntentHash');
const fulfillmentAndPayment = await client.indexer.getFulfillmentAndPayment('0xIntentHash');
// Received USDC:
// - fulfilledEvents[0].amount is the net USDC transferred to the taker.
// - fulfillment.takerAmountNetFees is the same net taker amount from the Intent row.
// - fulfillment.releasedAmount is gross USDC released from the deposit before fees.
// Fund activity and snapshots
const fundActivities = await client.indexer.getDepositFundActivities('8453_0xEscrowAddress_42');
const makerActivities = await client.indexer.getMakerFundActivities('0xMaker', 50);
const snapshots = await client.indexer.getDepositDailySnapshots('8453_0xEscrowAddress_42', 30);
const profitSnapshots = await client.indexer.getProfitSnapshotsByDeposits(['8453_0xEscrow_42']);
// Rate manager (vault) queries
const managers = await client.indexer.getRateManagers({
limit: 10,
orderBy: 'currentDelegatedBalance',
orderDirection: 'desc',
});
const managerDetail = await client.indexer.getRateManagerDetail('0xVaultId', {
rateManagerAddress: '0xVaultAddress',
statsLimit: 30,
});
const delegations = await client.indexer.getRateManagerDelegations('0xVaultId');
const delegation = await client.indexer.getDelegationForDeposit('8453_0xEscrow_42');
const managerSnapshots = await client.indexer.getManagerDailySnapshots('0xVaultId');
const manualRates = await client.indexer.getManualRateUpdates('0xVaultId');
const oracleUpdates = await client.indexer.getOracleConfigUpdates('0xVaultId');
// Raw GraphQL
const custom = await client.indexer.query<MyType>({
query: '{ deposits(limit: 5) { id } }',
});React Hooks
Install React and import hooks from @zkp2p/sdk/react. React is an optional peer dependency of the SDK.
Most mutation hooks return a named action plus status fields such as isLoading, error, and txHash. Hooks with prepare support expose dedicated prepare... helpers, and some of them also store the latest prepared transaction in hook state. Every hook exports a matching Use*Options type.
import {
useCreateDeposit,
useSignalIntent,
useCreateVault,
useVaultDelegation,
useGetTakerTier,
} from '@zkp2p/sdk/react';
const createDeposit = useCreateDeposit({ client });
const signalIntent = useSignalIntent({ client });
const createVault = useCreateVault({ client, sendTransaction });
const vaultDelegation = useVaultDelegation({ client, sendTransaction, sendBatch });
const takerTier = useGetTakerTier({ client, owner, chainId, autoFetch: true });Hook groups:
- Deposit lifecycle:
useCreateDeposit,useAddFunds,useRemoveFunds,useWithdrawDeposit,useSetAcceptingIntents,useSetIntentRange,useSetCurrencyMinRate,useSetRetainOnEmpty - Payment and currency management:
useAddPaymentMethods,useRemovePaymentMethod,useSetPaymentMethodActive,useAddCurrencies,useRemoveCurrency,useDeactivateCurrency - Intent lifecycle:
useSignalIntent,useFulfillIntent,useReleaseFundsToPayer,usePruneExpiredIntents - Delegation:
useSetDelegate,useRemoveDelegate - Vault / DRM:
useCreateVault,useVaultDelegation,useSetVaultFee,useSetVaultMinRate,useSetVaultConfig - Taker tier:
useGetTakerTier, plusgetTierDisplayInfo()andgetNextTierCap()helpers
useVaultDelegation() is the batching-oriented hook. It returns delegateDeposit, delegateDeposits, clearDelegation, and clearDelegations.
Contracts and Catalog Helpers
import {
getContracts,
getPaymentMethodsCatalog,
getRateManagerContracts,
resolveFiatCurrencyBytes32,
resolvePaymentMethodHash,
} from '@zkp2p/sdk';
const contracts = getContracts(8453, 'production');
const rateManagerContracts = getRateManagerContracts(8453, 'production');
const paymentMethods = getPaymentMethodsCatalog(8453, 'production');
const usdHash = resolveFiatCurrencyBytes32('USD');
const wiseHash = resolvePaymentMethodHash('wise', { env: 'production' });Supported Currencies
The SDK ships currency metadata for 34 fiat currencies:
AED, ARS, AUD, BRL, CAD, CHF, CNY, CZK, DKK, EUR, GBP, HKD, HUF, IDR, ILS, INR, JPY, KES, MXN, MYR, NOK, NZD, PHP, PLN, RON, SAR, SEK, SGD, THB, TRY, UGX, USD, VND, ZAR
Supported Payment Platforms
wise, venmo, revolut, cashapp, mercadopago, zelle, paypal, monzo, chime, luxon, n26, alipay
Attribution (ERC-8021)
The SDK includes builder-code attribution helpers and transaction overrides for partner attribution:
const hash = await client.signalIntent({
depositId: 42n,
amount: 250_000n,
toAddress: '0xBuyer',
processorName: 'wise',
payeeDetails: '0xPAYEE_DETAILS_HASH',
fiatCurrencyCode: 'USD',
conversionRate: 1_020_000_000_000_000_000n,
txOverrides: {
referrer: ['my-app', 'campaign-42'],
},
});Lower-level helpers are also exported: BASE_BUILDER_CODE, ZKP2P_IOS_REFERRER, ZKP2P_ANDROID_REFERRER, getAttributionDataSuffix(), appendAttributionToCalldata(), encodeWithAttribution(), and sendTransactionWithAttribution().
TypeDoc API Reference
The package already includes TypeDoc configuration. Generate the full API reference locally with:
pnpm --filter @zkp2p/sdk docsThis writes documentation to packages/sdk/docs and now includes the React entry point as well as the main SDK and extension surfaces.
Debug Logging
Use setLogLevel() when you want verbose SDK logging during local development or integration debugging.
import { setLogLevel } from '@zkp2p/sdk';
setLogLevel('debug');Supported log levels: 'error', 'info', 'debug'
Development
cd packages/sdk
pnpm build
pnpm test
pnpm typecheck
pnpm lint
pnpm docsLinks
- NPM: https://www.npmjs.com/package/@zkp2p/sdk
- Docs: https://docs.zkp2p.xyz
- Monorepo: https://github.com/zkp2p/zkp2p-clients
- TypeDoc output:
packages/sdk/docs