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

@provable-games/ekubo-sdk

v0.1.17

Published

Standalone TypeScript SDK for Ekubo DEX routing and quotes on Starknet

Downloads

1,062

Readme

Ekubo SDK

A standalone TypeScript SDK for Ekubo DEX routing and quotes on Starknet.

Features

  • Quote fetching with retry logic, timeout, and abort support
  • Symbol or address input - Accept "ETH" or "0x049d36..." interchangeably
  • Configurable polling for real-time quote updates
  • Swap call generation for multihop_swap and multi_multihop_swap
  • Dynamic token list - Fetch tokens from API or use built-in registry
  • Protocol statistics - TVL, volume, top pairs
  • Multi-chain support - Mainnet and Sepolia
  • Tree-shakeable - Import only what you need

Installation

npm install ekubo-sdk
# or
pnpm add ekubo-sdk

Quick Start

Using EkuboClient (Recommended)

import { createEkuboClient } from 'ekubo-sdk';

const client = createEkuboClient({ chain: 'mainnet' });

// Fetch a quote using symbols
const quote = await client.getQuote({
  amount: 1000000000000000000n, // 1 ETH
  tokenFrom: 'ETH',
  tokenTo: 'STRK',
});

console.log('Expected STRK:', quote.total);
console.log('Price impact:', quote.impact);

// Generate swap calls
const { allCalls } = client.generateSwapCalls({
  sellToken: 'ETH',
  buyToken: 'STRK',
  minimumReceived: quote.total * 99n / 100n, // 1% slippage
  quote,
});

// Execute with starknet.js or your wallet
await account.execute(allCalls);

Direct Function Imports (Tree-Shakeable)

import {
  fetchSwapQuote,
  generateSwapCalls,
  CHAIN_IDS
} from 'ekubo-sdk';

// Fetch quote
const quote = await fetchSwapQuote({
  amount: 1000000000000000000n,
  tokenFrom: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
  tokenTo: '0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d',
  chainId: CHAIN_IDS.MAINNET,
});

// Generate calls
const { allCalls } = generateSwapCalls({
  sellToken: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
  buyToken: '0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d',
  minimumReceived: quote.total * 99n / 100n,
  quote,
  chainId: CHAIN_IDS.MAINNET,
});

React Hooks

The SDK provides React hooks for easy integration with React applications.

npm install ekubo-sdk react

EkuboProvider

Wrap your app with EkuboProvider to share a single client instance:

import { EkuboProvider } from '@provable-games/ekubo-sdk/react';

function App() {
  return (
    <EkuboProvider config={{ chain: 'mainnet' }}>
      <YourApp />
    </EkuboProvider>
  );
}

useEkuboSwap

Fetch swap quotes with automatic polling:

import { useEkuboSwap } from '@provable-games/ekubo-sdk/react';

function SwapForm() {
  const { state, generateCalls, refetch } = useEkuboSwap({
    sellToken: 'ETH',
    buyToken: 'USDC',
    amount: 1000000000000000000n, // 1 ETH
    pollingInterval: 5000, // Poll every 5 seconds
  });

  if (state.loading) return <div>Loading quote...</div>;
  if (state.error) return <div>Error: {state.error.message}</div>;
  if (state.insufficientLiquidity) return <div>Insufficient liquidity</div>;

  const handleSwap = () => {
    const calls = generateCalls(5n); // 5% slippage
    if (calls) {
      // Execute calls with your wallet
    }
  };

  return (
    <div>
      <p>You will receive: {state.quote?.total}</p>
      <p>Price impact: {state.priceImpact}%</p>
      <button onClick={handleSwap}>Swap</button>
    </div>
  );
}

useEkuboPrices

Fetch USD prices for multiple tokens:

import { useEkuboPrices } from '@provable-games/ekubo-sdk/react';

const ETH_ADDRESS = '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7';
const STRK_ADDRESS = '0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d';

function TokenPrices() {
  const { prices, isLoading, getPrice, isTokenAvailable } = useEkuboPrices({
    tokens: [ETH_ADDRESS, STRK_ADDRESS],
  });

  if (isLoading) return <div>Loading prices...</div>;

  return (
    <div>
      <p>ETH: ${isTokenAvailable(ETH_ADDRESS) ? getPrice(ETH_ADDRESS)?.toFixed(2) : 'N/A'}</p>
      <p>STRK: ${isTokenAvailable(STRK_ADDRESS) ? getPrice(STRK_ADDRESS)?.toFixed(2) : 'N/A'}</p>
    </div>
  );
}

useEkuboTokens

Fetch the list of available tokens:

import { useEkuboTokens } from '@provable-games/ekubo-sdk/react';

function TokenList() {
  const { tokens, isLoading, getTokenBySymbol } = useEkuboTokens();

  if (isLoading) return <div>Loading tokens...</div>;

  const eth = getTokenBySymbol('ETH');

  return (
    <ul>
      {tokens.map(token => (
        <li key={token.address}>{token.symbol}: {token.name}</li>
      ))}
    </ul>
  );
}

useEkuboStats

Fetch protocol statistics:

import { useEkuboStats } from '@provable-games/ekubo-sdk/react';

function ProtocolStats() {
  const { tvl, volume, topPairs, isLoading } = useEkuboStats();

  if (isLoading) return <div>Loading stats...</div>;

  return (
    <div>
      {tvl && <p>TVL: ${tvl.total.toLocaleString()}</p>}
      {volume && <p>24h Volume: ${volume.total.toLocaleString()}</p>}
      <h3>Top Pairs</h3>
      <ul>
        {topPairs.slice(0, 5).map((pair, i) => (
          <li key={i}>{pair.token0Symbol}/{pair.token1Symbol}</li>
        ))}
      </ul>
    </div>
  );
}

useEkuboPriceHistory

Fetch historical price data:

import { useEkuboPriceHistory } from '@provable-games/ekubo-sdk/react';

function PriceChart() {
  const { data, isLoading } = useEkuboPriceHistory({
    token: 'ETH',
    quoteToken: 'USDC',
    interval: 3600, // 1 hour intervals
  });

  if (isLoading) return <div>Loading price history...</div>;

  return (
    <div>
      {data.map((point) => (
        <div key={point.timestamp}>
          {new Date(point.timestamp * 1000).toLocaleDateString()}: ${point.price}
        </div>
      ))}
    </div>
  );
}

Using Hooks Without Provider

Hooks work without EkuboProvider by creating a singleton client:

import { useEkuboSwap } from '@provable-games/ekubo-sdk/react';

function SwapForm() {
  // Works without EkuboProvider - uses default mainnet config
  const { state } = useEkuboSwap({
    sellToken: 'ETH',
    buyToken: 'USDC',
    amount: 1000000000000000000n,
    config: { chain: 'mainnet' }, // Optional: customize the singleton
  });

  // ...
}

Quote Polling

For real-time quote updates:

const client = createEkuboClient({ chain: 'mainnet' });

const poller = client.createQuotePoller(
  { amount: 1n * 10n ** 18n, tokenFrom: 'ETH', tokenTo: 'STRK' },
  {
    onQuote: (quote) => {
      console.log('New quote:', quote.total);
    },
    onError: (err) => {
      console.error('Quote error:', err);
    },
    onStop: (reason) => {
      console.log('Polling stopped:', reason);
    },
  },
  { interval: 5000 } // Poll every 5 seconds
);

poller.start();

// Later...
poller.stop();

Token Management

Static Registry (Built-in)

import { resolveToken, MAINNET_TOKENS, TokenRegistry } from 'ekubo-sdk';

// Resolve symbol to address
const ethAddress = resolveToken('ETH');
const strkAddress = resolveToken('strk'); // case-insensitive

// Use custom tokens
const registry = new TokenRegistry([
  { symbol: 'MYTOKEN', address: '0x123...', decimals: 18 }
]);

const address = resolveToken('MYTOKEN', registry);

Dynamic Token List (From API)

const client = createEkuboClient({ chain: 'mainnet' });

// Fetch all tokens from Ekubo API
const tokens = await client.fetchTokens();
console.log(`Found ${tokens.length} tokens`);

// Fetch specific token metadata
const ethInfo = await client.fetchToken('ETH');
console.log(ethInfo?.name, ethInfo?.decimals);

// Sync API tokens to local registry for symbol resolution
await client.syncTokensFromApi();

// Now you can use any token symbol from the API
const quote = await client.getQuote({
  amount: 1n * 10n ** 18n,
  tokenFrom: 'SOME_NEW_TOKEN',
  tokenTo: 'USDC',
});

Built-in Tokens

ETH, STRK, USDC, USDC.e, USDT, DAI, WBTC, LORDS, wstETH, EKUBO, ZEND, NSTR

Protocol Statistics

const client = createEkuboClient({ chain: 'mainnet' });

// Protocol-wide stats
const tvl = await client.getTvl();
console.log('Total TVL:', tvl.tvl_usd);

const volume = await client.getVolume();
console.log('24h Volume:', volume.volume_24h_usd);

// Top trading pairs
const pairs = await client.getTopPairs();
for (const pair of pairs.slice(0, 5)) {
  console.log(`${pair.token0}/${pair.token1}: $${pair.volume_24h_usd}`);
}

// Pair-specific stats
const ethStrkTvl = await client.getPairTvl('ETH', 'STRK');
const ethStrkVolume = await client.getPairVolume('ETH', 'STRK');
const ethStrkPools = await client.getPairPools('ETH', 'STRK');

Configuration

const client = createEkuboClient({
  // Chain selection
  chain: 'mainnet', // or 'sepolia'

  // Or use custom chain ID
  chainId: '23448594291968334',

  // Custom API URLs
  quoterApiUrl: 'https://prod-api-quoter.ekubo.org',
  apiUrl: 'https://prod-api.ekubo.org',

  // Custom router address
  routerAddress: '0x...',

  // Default slippage (5%)
  defaultSlippagePercent: 5n,

  // Fetch configuration
  fetch: {
    timeout: 10000,
    maxRetries: 3,
    baseBackoff: 1000,
    maxBackoff: 5000,
  },

  // Polling configuration
  polling: {
    interval: 5000,
    maxConsecutiveErrors: 3,
  },

  // Custom tokens (added to built-in registry)
  customTokens: [
    { symbol: 'MYTOKEN', address: '0x...', decimals: 18 }
  ],
});

Error Handling

import {
  InsufficientLiquidityError,
  RateLimitError,
  TokenNotFoundError,
} from 'ekubo-sdk';

try {
  const quote = await client.getQuote({
    amount: 1n * 10n ** 30n, // Very large amount
    tokenFrom: 'ETH',
    tokenTo: 'STRK',
  });
} catch (error) {
  if (error instanceof InsufficientLiquidityError) {
    console.log('Not enough liquidity for this swap');
  } else if (error instanceof RateLimitError) {
    console.log('Rate limited, try again later');
  } else if (error instanceof TokenNotFoundError) {
    console.log('Unknown token symbol');
  }
}

API Reference

EkuboClient Methods

Swap Quotes

| Method | Description | |--------|-------------| | getQuote(params) | Fetch a swap quote | | getUsdcPrice(token, amount) | Get token price in USDC | | getPriceHistory(token, otherToken) | Fetch price history |

Swap Execution

| Method | Description | |--------|-------------| | generateSwapCalls(params) | Generate swap transaction calls | | prepareSwapCalls(params) | Generate calls with ERC20 approval |

Polling

| Method | Description | |--------|-------------| | createQuotePoller(params, callbacks) | Create a quote polling instance |

Token Management

| Method | Description | |--------|-------------| | resolveToken(identifier) | Resolve symbol/address to address | | registerToken(token) | Register a custom token locally | | fetchTokens() | Fetch all tokens from API | | fetchToken(address) | Fetch single token metadata | | fetchTokensBatch(addresses) | Fetch multiple tokens | | syncTokensFromApi() | Sync API tokens to local registry |

Protocol Statistics

| Method | Description | |--------|-------------| | getTvl() | Fetch protocol TVL | | getVolume() | Fetch protocol volume | | getTopPairs() | Fetch top trading pairs | | getPairTvl(tokenA, tokenB) | Fetch pair TVL history | | getPairVolume(tokenA, tokenB) | Fetch pair volume history | | getPairPools(tokenA, tokenB) | Fetch pools for a pair |

Standalone Functions

| Function | Description | |----------|-------------| | fetchSwapQuote(params) | Fetch quote from Ekubo API | | fetchSwapQuoteInUsdc(params) | Fetch token price in USDC | | getPriceHistory(params) | Fetch price history | | fetchTokens(params) | Fetch all tokens | | fetchToken(params) | Fetch single token | | fetchTokensBatch(params) | Fetch multiple tokens | | fetchTopPairs(params) | Fetch top pairs | | fetchTvl(params) | Fetch protocol TVL | | fetchVolume(params) | Fetch protocol volume | | fetchPairTvl(params) | Fetch pair TVL | | fetchPairVolume(params) | Fetch pair volume | | fetchPairPools(params) | Fetch pair pools | | generateSwapCalls(params) | Generate swap calls | | prepareSwapCalls(params) | Generate calls with approval | | resolveToken(identifier, registry?) | Resolve token identifier |

React Hooks

Import from @provable-games/ekubo-sdk/react:

| Hook | Description | |------|-------------| | EkuboProvider | Context provider for sharing client | | useEkuboClient() | Access the client from context | | useEkuboSwap(props) | Swap quotes with polling | | useEkuboPrices(props) | USD prices for multiple tokens | | useEkuboTokens(props) | Fetch available tokens | | useEkuboStats(props) | Protocol TVL, volume, top pairs | | useEkuboPriceHistory(props) | Historical price data |

Chain IDs

import { CHAIN_IDS, STARKNET_CHAIN_IDS } from 'ekubo-sdk';

// Ekubo API format (decimal)
CHAIN_IDS.MAINNET  // "23448594291968334"
CHAIN_IDS.SEPOLIA  // "393402133025997798000961"

// Starknet.js format (hex)
STARKNET_CHAIN_IDS.SN_MAIN    // "0x534e5f4d41494e"
STARKNET_CHAIN_IDS.SN_SEPOLIA // "0x534e5f5345504f4c4941"

API URLs

import { API_URLS } from 'ekubo-sdk';

API_URLS.QUOTER  // "https://prod-api-quoter.ekubo.org" - Swap quotes
API_URLS.API     // "https://prod-api.ekubo.org" - Tokens, prices, stats

License

MIT