Skip to main content

Overview

The kraken-book crate compiles to WebAssembly. The same orderbook logic powering Rust backends runs in browser tabs. WASM handles:
  • Orderbook state management
  • Delta application
  • CRC32 checksum validation
  • Spread/mid-price calculations
JavaScript handles:
  • WebSocket connection
  • DOM updates
  • User interaction

Setup

1

Build WASM

cd crates/kraken-wasm
wasm-pack build --target web
2

Copy to project

cp -r pkg/ your-app/src/wasm/
3

Configure bundler

For Vite:
// vite.config.js
import wasm from 'vite-plugin-wasm';
import topLevelAwait from 'vite-plugin-top-level-await';

export default {
  plugins: [wasm(), topLevelAwait()]
}

Basic Usage

import init, { WasmOrderbook } from './wasm/kraken_wasm.js';

async function main() {
  // Initialize WASM (once)
  await init();

  // Create orderbook
  const book = WasmOrderbook.with_depth("BTC/USD", 25);
  book.set_precision(1, 8);

  // Connect to Kraken
  const ws = new WebSocket('wss://ws.kraken.com/v2');

  ws.onopen = () => {
    ws.send(JSON.stringify({
      method: 'subscribe',
      params: { channel: 'book', symbol: ['BTC/USD'], depth: 25 }
    }));
  };

  ws.onmessage = (event) => {
    const result = book.apply_and_get(event.data, 10);
    if (result) {
      console.log('Spread:', result.spread);
      console.log('Top Bid:', result.bids[0]);
      console.log('Top Ask:', result.asks[0]);
    }
  };
}

React Integration

import { useState, useEffect, useRef } from 'react';
import init, { WasmOrderbook } from '../wasm/kraken_wasm.js';

function OrderbookDisplay({ symbol }) {
  const [orderbook, setOrderbook] = useState({ bids: [], asks: [], spread: null });
  const bookRef = useRef(null);
  const wsRef = useRef(null);

  useEffect(() => {
    let mounted = true;

    async function setup() {
      await init();

      bookRef.current = WasmOrderbook.with_depth(symbol, 25);
      bookRef.current.set_precision(1, 8);

      wsRef.current = new WebSocket('wss://ws.kraken.com/v2');

      wsRef.current.onopen = () => {
        wsRef.current.send(JSON.stringify({
          method: 'subscribe',
          params: { channel: 'book', symbol: [symbol], depth: 25 }
        }));
      };

      wsRef.current.onmessage = (event) => {
        if (!mounted) return;

        const result = bookRef.current.apply_and_get(event.data, 10);
        if (result) {
          setOrderbook({
            bids: result.bids,
            asks: result.asks,
            spread: result.spread,
          });
        }
      };
    }

    setup();

    return () => {
      mounted = false;
      wsRef.current?.close();
      bookRef.current?.free();
    };
  }, [symbol]);

  return (
    <div className="orderbook">
      <div className="spread">Spread: {orderbook.spread}</div>
      <div className="levels">
        <div className="bids">
          {orderbook.bids.map(([price, qty]) => (
            <div key={price}>{price} | {qty}</div>
          ))}
        </div>
        <div className="asks">
          {orderbook.asks.map(([price, qty]) => (
            <div key={price}>{price} | {qty}</div>
          ))}
        </div>
      </div>
    </div>
  );
}

Message Queue Pattern

Prevent WASM borrow conflicts with sequential processing:
const queue = [];
let processing = false;

ws.onmessage = (event) => {
  queue.push(event.data);
  processQueue();
};

function processQueue() {
  if (processing || queue.length === 0) return;

  processing = true;
  while (queue.length > 0) {
    const msg = queue.shift();
    const result = book.apply_and_get(msg, 10);
    if (result) updateUI(result);
  }
  processing = false;
}
Don’t call WASM functions from multiple async contexts simultaneously.

Symbol Precision

SymbolPrice DecimalsQty Decimals
BTC/USD18
ETH/USD28
SOL/USD28
XRP/USD58
ADA/USD68

Tips

Limit Depth

Request only what you need. 10-25 levels is enough for most UIs.

Batch Updates

Use requestAnimationFrame for DOM updates, not every message.

Reuse Instances

One WasmOrderbook per symbol. Don’t recreate on each message.

Cleanup

Call book.free() when unmounting to release WASM memory.