npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@oneswap/sdk

v0.2.8

Published

Official TypeScript SDK for the OneSwap API

Downloads

465

Readme

@oneswap/sdk

Official TypeScript SDK for the OneSwap API. Typed methods for pools, tokens, quotes, wallet auth, swaps, and wallet-scoped tracking — with built-in awaitable swap lifecycle. Works in Node.js and browsers.

Install

npm install @oneswap/sdk

Maintainers: see PUBLISHING.md for the release workflow and the local ignored npm auth-file setup used in this repo.

Quick Start

import { OneSwap } from '@oneswap/sdk'

const apiKey = 'os_live_...'
const authClient = new OneSwap({ apiKey })
const partyId = 'alice::12205a8c...'

const challenge = await authClient.walletAuth.requestChallenge(partyId)
const signature = await wallet.signMessage(challenge.message)

const verified = await authClient.walletAuth.verifyChallenge({
  partyId,
  nonce: challenge.nonce,
  signature,
  publicKey: wallet.publicKey,
})

const client = new OneSwap({
  apiKey,
  walletToken: verified.token,
})

// Get a traffic-aware quote for the same party that will deposit
const quote = await client.quotes.get({
  from: 'Amulet',
  to: 'USDCx',
  amount: '100',
  receiverParty: partyId,
})
console.log(`Output: ${quote.outputAmount} ${quote.outputToken}`)
console.log(`Traffic: ${quote.trafficFeeInInput ?? '0'} ${quote.inputToken}`)

// Create a swap and wait for completion
const intent = await client.swaps.create({
  fromToken: 'Amulet',
  toToken: 'USDCx',
  amount: '100',
  walletAddress: partyId,
})

console.log(`Deposit to: ${intent.depositAddress}`)
console.log(`Transfer reference: ${intent.depositReference}`)

// Listen for status changes
intent.on('processing', () => console.log('Deposit detected'))
intent.on('completed', (status) => console.log(`Swap done: ${status.actualOutput}`))

// Await final result
const result = await intent.wait()
console.log(`Received: ${result.actualOutput} ${result.outputToken}`)

Use os_live_... SDK keys for integrations. Pair the key with a verified wallet token from client.walletAuth.* for user-bound actions. SDK keys are created and managed through the wallet-authenticated OneSwap developer portal.

walletAddress is the user's actual Canton party ID. Deposits go directly to the pool party, and swap output returns directly to that same source party in the current execution flow. If your wallet flow supports Canton reason/reference metadata, pass through intent.depositReference for faster fallback matching. The SDK does not expose wallet registration, wallet balance lookup, LP add, LP withdraw, or other liquidity management.

If token names are unique across pools, name-only selection is still fine. If the same symbol exists under multiple admins, pass poolId or both token admins so the API cannot guess the wrong pool.

Environment Targeting

Mainnet remains the default:

const client = new OneSwap({ apiKey })

Devnet now has a built-in default backend too:

const client = new OneSwap({
  apiKey,
  environment: 'devnet',
})

Create and manage SDK keys from the matching developer portal:

  • Mainnet: https://oneswap.cc/developer/keys
  • Devnet: https://devnet.oneswap.cc/developer/keys

You can still override it with an explicit backend URL:

const client = new OneSwap({
  apiKey,
  environment: 'devnet',
  baseUrl: 'https://devnet-backend.example.com',
})

If you omit baseUrl, the SDK defaults to:

  • Mainnet: https://api.oneswap.cc
  • Devnet: https://devnet.api.oneswap.cc

Getting An SDK API Key

Developer access is wallet-authenticated. SDK developer auth and SDK swap execution do not require a site-access token or access code.

  1. Authenticate a Canton wallet with OneSwap.
  2. Exchange that wallet session on POST /api/sdk/wallet-login.
  3. Use the returned user JWT on /api/sdk/keys to create or rotate os_live_... keys.
  4. Use the resulting API key in new OneSwap({ apiKey }).

Portal entry points:

  • Mainnet SDK keys: https://oneswap.cc/developer/keys
  • Devnet SDK keys: https://devnet.oneswap.cc/developer/keys

Devnet SDK Keys

Use the devnet site when you want a devnet SDK key:

  1. Open https://devnet.oneswap.cc/developer/keys.
  2. Connect and authenticate the devnet wallet you want to use.
  3. Create or rotate the SDK key from the devnet developer portal.
  4. Use that key with:
const client = new OneSwap({
  apiKey: 'os_live_...',
  environment: 'devnet',
})

POST /api/sdk/register and POST /api/sdk/login are retired compatibility endpoints and now return 410 Gone.

API Reference

new OneSwap(config)

| Option | Type | Default | Description | |--------|------|---------|-------------| | apiKey | string | required | Your OneSwap SDK API key (os_live_...) | | environment | 'mainnet' \| 'devnet' | 'mainnet' | Logical target environment. | | baseUrl | string | Mainnet: https://api.oneswap.cc, Devnet: https://devnet.api.oneswap.cc | Override the API origin. Use this for alternate Devnet or self-hosted backends. | | walletToken | string \| (() => string \| Promise<string \| undefined> \| undefined) | none | Optional end-user wallet token, or a lazy getter, for wallet-authenticated requests | | timeout | number | 30000 | Request timeout (ms) |

Pools

| Method | Returns | Description | |--------|---------|-------------| | client.pools.list() | PoolListResponse | List all pools | | client.pools.get(poolId) | PoolDetail | Get pool details | | client.pools.getStats(poolId, { days? }) | PoolStats | Get pool APR/volume/TVL. Defaults to a 7-day annualized view. |

Tokens

| Method | Returns | Description | |--------|---------|-------------| | client.tokens.list() | TokenListResponse | List available tokens |

client.tokens.list() returns { name, admin } entries. Duplicate token names are allowed when admins differ.

Quotes

| Method | Returns | Description | |--------|---------|-------------| | client.quotes.get({ from, to, amount, receiverParty?, poolId?, fromAdmin?, toAdmin? }) | Quote | Get swap quote. Pass poolId or both admins when token names are ambiguous. amount is the exact deposit amount you want the user to send. |

Quotes are directional execution estimates, not inverse mid-prices.

  • OneSwap prices swaps with the current pool reserves, the configured swap fee, and constant-product slippage.
  • Traffic recovery is deducted from the deposit before pricing, and the 0.1% pool fee is deducted from the remainder, so outputAmount is based on the effective post-fee input rather than the raw requested deposit.
  • CC -> USDCx and USDCx -> CC therefore should not be exact reciprocals, and a round-trip loses value to fee, slippage, and possibly traffic recovery on both legs.
  • If receiverParty is provided, quote-time traffic estimation follows the current payout path. CC output and utility-token output can use different transfer machinery, so direction can matter even more.

For all-in comparisons, check these fields together:

  • inputAmount
  • totalInputAmount
  • networkFeeAmount
  • poolFeeAmount
  • trafficFeeInInput
  • inputAmountAfterPoolFee
  • outputAmount
  • rate

totalInputAmount currently echoes the exact deposit amount to send. rate is based on the effective post-fee input amount, not necessarily the original requested deposit.

Swaps

| Method | Returns | Description | |--------|---------|-------------| | client.swaps.create(params) | SwapIntent | Create swap intent | | client.swaps.getStatus(intentId) | SwapStatusResponse | Get swap status | | client.swaps.cancel(intentId) | { success: boolean } | Cancel a pending swap intent |

outputAddress is deprecated on client.swaps.create(...) and ignored by the SDK client. Current OneSwap execution always returns output to the same source party that makes the deposit.

SwapIntent includes depositReference. Treat it as optional metadata: pass it through when your wallet flow supports Canton reason/reference fields, but do not depend on it as the only way a swap will settle.

Disambiguating Duplicate Symbols

const tokens = await client.tokens.list()

const usdc = tokens.tokens.find(
  (token) => token.name === 'USDCx' && token.admin === 'admin::issuer-a'
)

const quote = await client.quotes.get({
  from: 'USDCx',
  to: 'Amulet',
  amount: '250',
  fromAdmin: usdc?.admin,
  toAdmin: 'DSO',
})

const intent = await client.swaps.create({
  fromToken: 'USDCx',
  toToken: 'Amulet',
  amount: '250',
  walletAddress: 'alice::12205a8c...',
  poolId: quote.poolId,
  fromAdmin: usdc?.admin,
  toAdmin: 'DSO',
})

If you omit those fields for an ambiguous pair, the API returns 409 ambiguous_pool_pair and the SDK throws AmbiguousPoolPairError.

SwapIntent (with event emitter):

  • .wait(opts?) — Polls until terminal state. Resolves with SwapStatusResponse, or throws a typed terminal error such as ManualReviewRequiredError.
  • .cancel() — Cancels a pending swap intent.
  • .on(event, handler) / .once(event, handler) — Listen for status changes.
  • Events: pending, matched, deposit_received, forwarded, processing, sending_output, completed, slippage_failed, price_impact_exceeded, insufficient_liquidity, insufficient_amount, output_failed, no_output_holdings, failed, refund_failed, manual_review, expired, cancelled

Track

| Method | Returns | Description | |--------|---------|-------------| | client.track(partyId) | TrackResponse | Get swap intents only for the currently authenticated wallet party |

client.track(...) does not return liquidity intents or LP positions. LP add and LP withdraw remain website-only and are intentionally absent from the SDK surface.

Error Handling

All errors extend OneSwapError so you can catch them uniformly:

import {
  OneSwap,
  AuthError,
  ValidationError,
  AmbiguousPoolPairError,
  SlippageError,
  PriceImpactError,
  InsufficientLiquidityError,
  InsufficientAmountError,
  OutputFailedError,
  SwapFailedError,
  RefundFailedError,
  ExpiredError,
  TimeoutError,
  NetworkError,
} from '@oneswap/sdk'

try {
  const intent = await client.swaps.create({ ... })
  const result = await intent.wait()
} catch (err) {
  if (err instanceof SlippageError) {
    console.log('Slippage exceeded, swap refunded')
  } else if (err instanceof PriceImpactError) {
    console.log('Price impact exceeded the server cap')
  } else if (err instanceof InsufficientLiquidityError) {
    console.log('Not enough liquidity in pool')
  } else if (err instanceof InsufficientAmountError) {
    console.log('Amount too low to cover traffic cost')
  } else if (err instanceof OutputFailedError) {
    console.log('Output transfer failed - contact support')
  } else if (err instanceof SwapFailedError) {
    console.log('Swap failed - retry after reviewing the pool state')
  } else if (err instanceof RefundFailedError) {
    console.log('Refund failed - manual intervention is required')
  } else if (err instanceof ExpiredError) {
    console.log('Intent expired before deposit')
  } else if (err instanceof TimeoutError) {
    console.log('Request timed out')
  } else if (err instanceof NetworkError) {
    console.log('Network connectivity issue')
  } else if (err instanceof AuthError) {
    console.log('Invalid API key')
  } else if (err instanceof ValidationError) {
    console.log('Invalid params:', err.message)
  } else if (err instanceof AmbiguousPoolPairError) {
    console.log('Specify poolId or token admins:', err.candidates)
  }
}

Quote-time or create-time price-impact rejections still arrive as ValidationError because the API responds with HTTP 400. PriceImpactError is reserved for an already-created intent that later reaches price_impact_exceeded while wait() is polling.

Wait Options

const result = await intent.wait({
  pollInterval: 5000,  // Poll every 5s (default: 3s)
  timeout: 600000,     // Timeout after 10min (default: 35min)
})

License

MIT