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

@alcorexchange/orderbook-sdk

v0.1.1

Published

Client SDK for the Alcor orderbook contract: units, actions, reads, events, signing.

Readme

@alcorexchange/orderbook-sdk

Client SDK for the Alcor orderbook contract on Antelope chains (Telos). Exact unit conversions, action builders for any wallet, table and read-only reads, transaction signing for bots, event decoding and a local order book kept current by events.

npm install @alcorexchange/orderbook-sdk @wharfkit/antelope

ESM only: Node 20.10+ or any modern bundler (it imports JSON with an import attribute). Every 64-bit value is a bigint.

Quick start

import { OrderbookClient, OrderbookActions, KeySigner, Rpc, Side, OrderFlag, priceToUnits, baseToLots } from '@alcorexchange/orderbook-sdk';

const rpc = new Rpc('https://telos.example');
const client = new OrderbookClient({ rpc, contract: 'orderbook' });
const actions = new OrderbookActions('orderbook');

const m = await client.market(1n);                       // lot size, tick, tokens, fees
const order = actions.placeOrder({
  owner: 'alice', marketId: m.id, side: Side.BUY,
  price: priceToUnits(m, '0.0500'), qty: baseToLots(m, '100'), flags: OrderFlag.POST_ONLY,
});

// Wallet users: session.transact({ actions: [order] }). Bots sign with a key:
const signer = new KeySigner({ rpc, privateKey: process.env.KEY! });
const { results, events } = await signer.transact([order]);

Units

A market trades qty lots of lot_size minimal base units. price is minimal quote units per lot, on a grid of tick_size. An order of qty lots at price moves qty * price quote units. Parsing is exact: a value off the token precision, the lot size or the tick grid throws instead of rounding. unitsToPrice floors only when asked for fewer decimals.

| helper | from → to | |---|---| | priceToUnits(m, '0.05'), unitsToPrice(m, units) | human price ↔ contract price | | baseToLots(m, '100'), lotsToBase(m, lots) | base amount ↔ lots | | quoteToUnits(m, '12.5'), unitsToQuote(m, units) | quote amount ↔ minimal units | | parseUnits, formatUnits, assetString | any token amount |

Funds

Funds live in an internal ledger. Deposit with a plain token transfer to the contract (actions.deposit). Orders lock what they need: a sell locks its base, a buy locks qty * price plus the taker fee (buyReserve). actions.withdraw returns two actions: the token's open for the recipient, paid by the withdrawer, and the withdraw itself, because the contract only pays out to an existing token row.

Actions

OrderbookActions builds action JSON for any wallet (wharfkit Session, Anchor, a key):

  • deposit, withdraw
  • placeOrder with OrderFlag.POST_ONLY, IOC, FOK or POST_ONLY_SKIP and an optional expiresAt (seconds). POST_ONLY_SKIP is a post-only that, where it would trade, places nothing and does not fail (order_id = 0, rested = 0, no event), so a batch of cancels and new quotes survives a quote the price ran over. Other errors (funds, tick, min_notional) still fail the transaction.
  • buyQuote spends at most a quote amount, fees included; nothing rests
  • cancel (anyone may cancel an expired order; its funds go to its owner), reduceOrder, cancelAll
  • placeTrigger, placeOco, cancelTrigger, crank
  • swap trades straight from the wallet, see below

A remainder below the market's min_notional never rests in the book (isDust).

Swap

A transfer to the contract with memo swap#<market_id>#<min_out>[#<recipient>] trades at once and leaves nothing on the exchange: base in sells whole lots, quote in buys for the whole amount, fees included, both without a price limit. The output goes to the recipient (the sender by default) and whatever did not trade, including a part below one lot, comes back to the sender in the same transaction. If the output is below min_out (minimal units of the output token) the whole transaction fails.

const book = new BookState(m.id, [
  ...(await client.book(m.id, Side.BUY, { includeExpired: true })),
  ...(await client.book(m.id, Side.SELL, { includeExpired: true })),
]);
const q = quoteSwap(book, m, { owner: 'alice', side: Side.SELL, units: 5_5000n, now: Math.floor(Date.now() / 1000) });
const minOut = (q.received * 997n) / 1000n;  // 0.3% slippage
await session.transact({ actions: actions.swap({ from: 'alice', marketId: m.id, token: base, out: quote, units: 5_5000n, minOut }) });

actions.swap returns the token's open for the recipient's output row (paid by the sender, a no-op when it exists) and the transfer. quoteSwap runs the contract's arithmetic on a book copy; give it expired orders too, they cost work. toSwapEvent reads the swap event: who, to whom, side, input spent, input returned, output sent.

Reads

OrderbookClient reads any API node:

  • markets(), market(id), tokens(), config()
  • book(marketId, side) (expired orders hidden), depth(marketId, side, levels)
  • balances(owner), ordersOf(owner), triggersOf(owner)
  • triggerQueue(marketId, op), referencePrice(marketId)
  • readOnly(name, data) for the contract's read-only actions

Triggers

Stop and take-profit orders lock their funds when placed. They fire when the market's reference price reaches the trigger price. The reference is the median of the last trade prices of the last three blocks that traded. A trade fires due triggers on its own; crank fires the rest (triggerDue, referencePrice mirror the contract).

Events

The contract logs every change as an events action. KeySigner.transact returns the events of its own transaction (eventsFromTraces); decodeEvents decodes them from state history.

BookState keeps a local order book from a snapshot and events. It throws BookGapError when an event seq is missing; take a new snapshot then. With the Alcor orderbook indexer, the snapshot is GET <api>/markets/:id/book and the events come over <api>/ws, where <api> is https://telos.alcor.exchange/api/v2/orderbook on Telos; toOrder and toEvent turn their JSON (64-bit values as strings) into SDK types:

import { BookState, Side, toEvent, toOrder } from '@alcorexchange/orderbook-sdk';

const api = 'https://telos.alcor.exchange/api/v2/orderbook';
const snap = await fetch(`${api}/markets/1/book`).then((r) => r.json());
const book = new BookState(1n, snap.orders.map(toOrder), BigInt(snap.seq));

const ws = new WebSocket(`${api.replace('https', 'wss')}/ws`);
ws.onopen = () => ws.send(JSON.stringify({ op: 'subscribe', channel: 'market:1' }));
ws.onmessage = (msg) => {
  const { events } = JSON.parse(msg.data);
  for (const e of events ?? []) book.apply(toEvent(e));   // BookGapError: reload the snapshot
  render(book.levels(Side.BUY, 20), book.levels(Side.SELL, 20));
};

Events at or below the snapshot's seq are skipped. A block that lands between the snapshot and the subscription shows up as a BookGapError on the next event, never as a wrong book.

Contract math

buyReserve, feeOf, affordableLots, orderLock, isDust, referencePrice, triggerDue, quoteSwap compute exactly what the contract does, for previews before signing.