Skip to content

Bvvvp009/Extended-TS-SDK

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Extended TypeScript SDK

This is a community-maintained TypeScript SDK for Extended Exchange. It is not officially supported by Extended.

TypeScript client for Extended Exchange API.

✅ Works in Both Node.js and Browser

This SDK is production-ready for both backend and frontend applications:

  • Node.js (v18+) - Works immediately, no configuration needed
  • Browser (Chrome, Firefox, Safari, Edge) - Requires one-time bundler config
  • All Modern Bundlers (Vite, Webpack, Rollup, Next.js, Parcel)
  • Dual Package - Ships ESM + CommonJS for maximum compatibility
  • WASM Crypto - Pre-built for both Node.js and browser (no Rust needed)

Package Structure

extended-typescript-sdk/
├── dist/
│   ├── esm/          # ES Modules (import)
│   └── cjs/          # CommonJS (require)
└── wasm/
    ├── stark_crypto_wasm.js             # Node.js WASM
    ├── stark_crypto_wasm_bg.wasm        # Node.js binary
    ├── stark_crypto_wasm-web.js         # Browser WASM
    └── stark_crypto_wasm_bg-web.wasm    # Browser binary

About Extended Exchange

Extended is a perpetual DEX (Decentralized Exchange), built by an ex-Revolut team. As of now, Extended offers perpetual contracts on both crypto and TradFi assets, with USDC as collateral and leverage of up to 100x.

This SDK provides full type safety and modern async/await patterns for interacting with the Extended Exchange API.

Installation

npm install extended-typescript-sdk

Node.js Setup (Backend)

No configuration needed! Just install and use:

import { initWasm, TESTNET_CONFIG } from 'extended-typescript-sdk';

await initWasm(); // Automatically loads Node.js WASM
// Ready to trade!

Browser Setup (Frontend)

  1. Install the SDK:

    npm install extended-typescript-sdk
  2. Configure your bundler (one-time setup):

    • See bundler configuration below for Vite, Webpack, Next.js, etc.
  3. Use in your app:

    import { initWasm, TESTNET_CONFIG } from 'extended-typescript-sdk';
    
    await initWasm(); // Automatically loads browser WASM
    // Ready to trade!

✅ Node.js Backend: Works immediately - no configuration needed!

⚙️ Browser/Frontend: Requires one-time bundler configuration (see below)


Browser Bundler Setup

This SDK uses WebAssembly for cryptographic operations. Modern bundlers need minimal configuration to handle WASM files.

Quick Setup by Bundler

✅ Vite (Recommended)

Vite has excellent WASM support. Add this to vite.config.ts:

import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    exclude: ['extended-typescript-sdk']
  },
  assetsInclude: ['**/*.wasm'],
  build: {
    target: 'esnext'
  }
});

Optional: Copy WASM files to dist (for production deployments):

npm install --save-dev vite-plugin-static-copy
import { defineConfig } from 'vite';
import { viteStaticCopy } from 'vite-plugin-static-copy';

export default defineConfig({
  plugins: [
    viteStaticCopy({
      targets: [{
        src: 'node_modules/extended-typescript-sdk/wasm/*',
        dest: 'wasm'
      }]
    })
  ],
  optimizeDeps: {
    exclude: ['extended-typescript-sdk']
  }
});

✅ See vite.config.example.ts for a complete example

Webpack 5+

Enable async WebAssembly in webpack.config.js:

module.exports = {
  experiments: {
    asyncWebAssembly: true,
  },
  module: {
    rules: [
      {
        test: /\.wasm$/,
        type: 'webassembly/async',
      },
    ],
  },
};
Next.js

Add to next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config) => {
    config.experiments = {
      ...config.experiments,
      asyncWebAssembly: true,
    };
    return config;
  },
};

module.exports = nextConfig;
Rollup Configuration

Install plugin:

npm install --save-dev @rollup/plugin-wasm

Configure rollup.config.js:

import wasm from '@rollup/plugin-wasm';

export default {
  plugins: [
    wasm({
      maxFileSize: 10000000, // 10MB
      targetEnv: 'auto',
    }),
  ],
};

Troubleshooting Bundler Issues

Problem: Cannot find module 'extended-typescript-sdk/wasm/...'

Solution: Add to bundler config:

optimizeDeps: {
  exclude: ['extended-typescript-sdk']
}

Problem: WASM loading fails in production

Solution: Ensure WASM files are copied to your dist folder. Use vite-plugin-static-copy (Vite) or copy-webpack-plugin (Webpack).

Problem: WebAssembly module is included in initial chunk

Solution: Configure code splitting or external WASM:

build: {
  rollupOptions: {
    external: [/\.wasm$/]
  }
}

Problem: Works in dev but not production

Solution: Check that WASM files are included in your production build:

  • Vite: Check dist/wasm/ folder
  • Webpack: Verify WASM files in output bundle
  • Next.js: Check .next/static/ or public folder

📖 For detailed troubleshooting, see ENVIRONMENT_SUPPORT.md


Prerequisites

  • Node.js 18+ or TypeScript 5.3+
  • No Rust required - The SDK ships with pre-built WASM for both Node.js and browser

Environment Testing

The SDK includes comprehensive tests for both environments:

# Test Node.js CommonJS and ESM compatibility
npm run test:cjs-esm

# Test browser bundler compatibility (Vite)
npm run test:vite

# Test all compatibility scenarios
npm run test:compat

All tests pass in both Node.js and browser environments, confirming dual-environment support.

Quick Start

1. Initialize the SDK

The SDK ships with pre-built WASM signer - no build step required!

import {
  initWasm,
  TESTNET_CONFIG,
  StarkPerpetualAccount,
  PerpetualTradingClient,
} from 'extended-typescript-sdk';
import Decimal from 'decimal.js';

// Initialize WASM module (MUST be called before using any crypto functions)
// Automatically loads the correct WASM for Node.js or browser
await initWasm();

// Create a Stark account
const starkAccount = new StarkPerpetualAccount(
  vaultId,           // number
  privateKey,        // Hex string (e.g., "0x123...")
  publicKey,         // Hex string
  apiKey             // string
);

// Create trading client
const tradingClient = new PerpetualTradingClient(TESTNET_CONFIG, starkAccount);

2. Place an Order

import { OrderSide } from 'extended-typescript-sdk';
import Decimal from 'decimal.js';

const placedOrder = await tradingClient.placeOrder({
  marketName: 'BTC-USD',
  amountOfSynthetic: new Decimal('1'),
  price: new Decimal('63000.1'),
  side: OrderSide.SELL,
});

console.log('Placed order:', placedOrder);

// Cancel the order
await tradingClient.orders.cancelOrder(placedOrder.id);

3. Get Account Information

// Get balance
const balance = await tradingClient.account.getBalance();
console.log('Balance:', balance.toPrettyJson());

// Get positions
const positions = await tradingClient.account.getPositions();
console.log('Positions:', positions.toPrettyJson());

// Get open orders
const openOrders = await tradingClient.account.getOpenOrders();
console.log('Open orders:', openOrders.toPrettyJson());

4. Onboarding (User Client)

import { UserClient, TESTNET_CONFIG } from 'extended-typescript-sdk';

// Create user client
const userClient = new UserClient(TESTNET_CONFIG, () => ethPrivateKey);

// Onboard new account
const account = await userClient.onboard();

// Get API key
const apiKey = await userClient.createAccountApiKey(account.account, 'My trading key');

// Use the account
const starkAccount = new StarkPerpetualAccount(
  account.account.l2Vault,
  account.l2KeyPair.privateHex,
  account.l2KeyPair.publicHex,
  apiKey
);

const client = new PerpetualTradingClient(TESTNET_CONFIG, starkAccount);

5. Stream Data

import { PerpetualStreamClient, TESTNET_CONFIG } from 'extended-typescript-sdk';

const streamClient = new PerpetualStreamClient({
  apiUrl: TESTNET_CONFIG.streamUrl,
});

// Subscribe to orderbooks
const orderbookStream = streamClient.subscribeToOrderbooks({ marketName: 'BTC-USD' });
await orderbookStream.connect();

for await (const update of orderbookStream) {
  console.log('Orderbook update:', update);
}

// Subscribe to public trades
const tradesStream = streamClient.subscribeToPublicTrades('BTC-USD');
await tradesStream.connect();

for await (const trade of tradesStream) {
  console.log('Trade:', trade);
}

// Subscribe to funding rates
const fundingStream = streamClient.subscribeToFundingRates('BTC-USD');
await fundingStream.connect();

for await (const fundingUpdate of fundingStream) {
  console.log('Funding rate:', fundingUpdate);
}

// Subscribe to candles (OHLCV data)
const candlesStream = streamClient.subscribeToCandles({
  marketName: 'BTC-USD',
  candleType: 'trades', // 'trades', 'mark-prices', or 'index-prices'
  interval: 'PT1M', // ISO 8601 duration (PT1M, PT5M, PT15M, PT1H, etc.)
});
await candlesStream.connect();

for await (const candle of candlesStream) {
  console.log('Candle:', candle);
}

// Subscribe to mark price updates
const markPriceStream = streamClient.subscribeToMarkPrice('BTC-USD');
await markPriceStream.connect();

for await (const priceUpdate of markPriceStream) {
  console.log('Mark price:', priceUpdate);
}

// Subscribe to index price updates
const indexPriceStream = streamClient.subscribeToIndexPrice('BTC-USD');
await indexPriceStream.connect();

for await (const priceUpdate of indexPriceStream) {
  console.log('Index price:', priceUpdate);
}

// Subscribe to account updates (requires API key)
const accountStream = streamClient.subscribeToAccountUpdates(apiKey);
await accountStream.connect();

for await (const update of accountStream) {
  console.log('Account update:', update);
}

Bundler Configuration (Vite, Rollup, Webpack)

If you're using Vite, Rollup, Webpack, or Next.js, you may encounter WASM-related build errors. Here's how to fix them:

Vite Configuration

Add this to your vite.config.js or vite.config.ts:

import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    exclude: ['extended-typescript-sdk']
  },
  assetsInclude: ['**/*.wasm'],
});

Common Build Error

If you see this error:

Could not resolve "./stark_crypto_wasm_bg.js" from "node_modules/extended-typescript-sdk/wasm/..."

Solution: Add the SDK to the exclude list in your bundler configuration:

// vite.config.js
export default {
  optimizeDeps: {
    exclude: ['extended-typescript-sdk']
  }
}

Other Bundlers

Webpack 5

module.exports = {
  experiments: {
    asyncWebAssembly: true,
  },
};

Next.js

// next.config.js
module.exports = {
  webpack: (config) => {
    config.experiments = {
      ...config.experiments,
      asyncWebAssembly: true,
    };
    return config;
  },
};

Rollup

npm install --save-dev @rollup/plugin-wasm
import wasm from '@rollup/plugin-wasm';

export default {
  plugins: [wasm({ targetEnv: 'auto' })],
};

📖 For detailed bundler configurations and troubleshooting, see BUNDLER_CONFIG.md

WASM Signer

The SDK includes a pre-built WASM signer that works in both Node.js and browser environments. No Rust installation is required to use the SDK.

Using the Pre-built Signer

The SDK ships with pre-built WASM files. Simply use the SDK:

import { initWasm, sign } from 'extended-typescript-sdk';

await initWasm(); // Automatically loads the correct WASM for your environment
const [r, s] = sign(privateKey, msgHash);

The signer automatically detects your environment (Node.js or browser) and loads the appropriate WASM module.

Custom Signer Support (Privy, Web3Auth, etc.)

The SDK supports custom signers for integration with remote signing services like Privy, Web3Auth, or hardware wallets:

import { 
  CustomStarkSigner, 
  createStarkPerpetualAccountWithCustomSigner 
} from 'extended-typescript-sdk';

// Implement the CustomStarkSigner interface
class PrivyStarkSigner implements CustomStarkSigner {
  constructor(private privyClient: any, private walletId: string) {}
  
  async sign(msgHash: bigint): Promise<[bigint, bigint]> {
    const msgHashHex = '0x' + msgHash.toString(16);
    const signature = await this.privyClient.signStarknetMessage(
      this.walletId,
      msgHashHex
    );
    return [BigInt(signature.r), BigInt(signature.s)];
  }
}

// Create account with custom signer
const privySigner = new PrivyStarkSigner(privyClient, walletId);
const account = createStarkPerpetualAccountWithCustomSigner(
  vaultId,
  publicKeyHex,
  apiKey,
  privySigner
);

// Use normally - signing will be handled by Privy
const client = new PerpetualTradingClient(TESTNET_CONFIG, account);

See examples/16_privy_integration.ts for a complete example.

Building Your Own WASM Signer

If you want to build your own WASM signer (requires Rust and wasm-pack):

npm run build:signer:custom

Prerequisites:

  1. Install Rust: https://www.rust-lang.org/tools/install
  2. Install wasm-pack: cargo install wasm-pack

This will build both Node.js and browser targets and replace the shipped WASM signer.

Implementation

The WASM signer uses starknet-crypto crate for cryptographic operations. It's production-ready and tested for compatibility with Extended Exchange API.

API Documentation

Trading Client

import { PerpetualTradingClient, TESTNET_CONFIG } from 'extended-typescript-sdk';

const client = new PerpetualTradingClient(config, account);

// Place order
await client.placeOrder({
  marketName: 'BTC-USD',
  amountOfSynthetic: new Decimal('1'),
  price: new Decimal('63000'),
  side: OrderSide.BUY,
});

// Account module
await client.account.getBalance();
await client.account.getPositions();
await client.account.getOpenOrders();
await client.account.updateLeverage('BTC-USD', new Decimal('10'));

// Orders module
await client.orders.cancelOrder(orderId);
await client.orders.cancelOrderByExternalId(externalId);
await client.orders.massCancel({ markets: ['BTC-USD'] });

// Markets module
await client.marketsInfo.getMarkets();
await client.marketsInfo.getMarketStatistics('BTC-USD');
await client.marketsInfo.getOrderbookSnapshot('BTC-USD');

User Client (Onboarding)

import { UserClient } from 'extended-typescript-sdk';

const userClient = new UserClient(config, () => ethPrivateKey);

// Onboard new account
const account = await userClient.onboard();

// Onboard subaccount
const subaccount = await userClient.onboardSubaccount(1, 'My subaccount');

// Get all accounts
const accounts = await userClient.getAccounts();

// Create API key
const apiKey = await userClient.createAccountApiKey(account.account, 'description');

Stream Client

import { PerpetualStreamClient } from 'extended-typescript-sdk';

const streamClient = new PerpetualStreamClient({ apiUrl: config.streamUrl });

// Subscribe to orderbooks
const orderbookStream = streamClient.subscribeToOrderbooks({
  marketName: 'BTC-USD',
  depth: 10,
});

// Subscribe to public trades
const tradesStream = streamClient.subscribeToPublicTrades('BTC-USD');

// Subscribe to funding rates
const fundingStream = streamClient.subscribeToFundingRates('BTC-USD');

// Subscribe to account updates (requires API key)
const accountStream = streamClient.subscribeToAccountUpdates(apiKey);

Environment Configuration

The SDK supports different environments:

import { TESTNET_CONFIG, MAINNET_CONFIG } from 'extended-typescript-sdk';

// Use testnet
const client = new PerpetualTradingClient(TESTNET_CONFIG, account);

// Use mainnet
const client = new PerpetualTradingClient(MAINNET_CONFIG, account);

TypeScript Support

This SDK is written in TypeScript and provides full type definitions. All types are exported:

import {
  OrderSide,
  OrderType,
  OrderStatus,
  TimeInForce,
  StarkPerpetualAccount,
  PerpetualTradingClient,
  UserClient,
  PerpetualStreamClient,
  // ... and more
} from 'extended-typescript-sdk';

Error Handling

The SDK provides specific error types:

import {
  X10Error,
  RateLimitException,
  NotAuthorizedException,
  SubAccountExists,
} from 'extended-typescript-sdk';

try {
  await client.placeOrder({ ... });
} catch (error) {
  if (error instanceof RateLimitException) {
    // Handle rate limit
  } else if (error instanceof NotAuthorizedException) {
    // Handle authentication error
  }
}

Examples

See examples/ directory for complete examples:

  • Basic order placement
  • Onboarding flow
  • Stream subscriptions
  • Market data access
  • Account management

WASM Performance

The WASM signer provides ~90-95% of native Rust performance:

Native Rust:          ~50μs per signature
WASM (Rust):          ~55μs per signature  (10% slower)
Pure JavaScript:      ~500μs per signature (10x slower)

The performance difference is negligible in real-world applications.

Building the SDK

For Users (No Build Required)

The SDK ships with pre-built WASM signer - just install and use:

npm install extended-typescript-sdk

For Developers

If you're developing the SDK or want to build your own WASM signer:

# Install dependencies
npm install

# Build WASM signer (requires Rust and wasm-pack)
npm run build:signer

# Build TypeScript
npm run build:ts

# Build everything
npm run build  # Builds both WASM signer and TypeScript

# Build custom WASM signer (for users who want to replace shipped WASM)
npm run build:signer:custom

Build Commands

  • npm run build - Builds WASM signer and TypeScript (full build)
  • npm run build:signer - Builds WASM signer for both Node.js and browser
  • npm run build:signer:custom - Build your own WASM signer (requires Rust)
  • npm run build:ts - Build TypeScript only
  • npm run clean - Clean all build artifacts

Development Commands

# Run tests
npm test

# Lint
npm run lint

# Format code
npm run format

Contributing

  1. Clone the repository
  2. Install dependencies: npm install
  3. Install Rust and wasm-pack (only if building WASM signer)
  4. Build: npm run build
  5. Run tests: npm test

License

MIT

Support

For issues and questions:

Note: This is an unofficial, community-maintained SDK. For official support, please contact Extended Exchange directly.

Environment Support

  • ✅ Node.js (v18+)
  • ✅ Browsers (Chrome/Firefox/Safari/Edge)
  • ✅ PWAs
  • ✅ React Native (with polyfills or custom signer)
  • ✅ Electron
  • ⚠️ Native iOS/Android (via React Native or WebView)

Details and setup notes: see ENVIRONMENT_SUPPORT.md.

API Coverage

See API_COVERAGE.md for complete API endpoint coverage analysis.

Standalone Signer Functions

The cryptographic signer functions are exported from the main SDK package for standalone use:

import { 
  initWasm, 
  sign, 
  pedersenHash,
  getOrderMsgHash,
  getTransferMsgHash,
  getWithdrawalMsgHash,
  generateKeypairFromEthSignature
} from 'extended-typescript-sdk';

// Initialize WASM module (required first!)
await initWasm();

// Sign a message hash
const privateKey = BigInt('0x...');
const msgHash = BigInt('0x...');
const [r, s] = sign(privateKey, msgHash);

// Compute Pedersen hash
const hash = pedersenHash(BigInt('0x123'), BigInt('0x456'));

// Generate order message hash (for custom order signing)
const orderHash = getOrderMsgHash({
  positionId: 12345,
  baseAssetId: '0x...',
  baseAmount: '1000000',
  // ... other order parameters
});

// Generate keypair from Ethereum signature (for onboarding)
const [privateKey, publicKey] = generateKeypairFromEthSignature(ethSignature);

All signer functions are documented with JSDoc comments. See the signer source code for detailed documentation.