Community-maintained TypeScript SDK for Extended Exchange - A perpetual DEX built by ex-Revolut team
npm install extended-typescript-sdk
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
`bash
npm install extended-typescript-sdk
`
$3
✅ No configuration needed! Just install and use:
`typescript
import { initWasm, TESTNET_CONFIG } from 'extended-typescript-sdk';
await initWasm(); // Automatically loads Node.js WASM
// Ready to trade!
`
$3
1. Install the SDK:
`bash
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:
`typescript
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)
---
$3
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:
`typescript
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):
`bash
npm install --save-dev vite-plugin-static-copy
`
`typescript
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:
`javascript
module.exports = {
experiments: {
asyncWebAssembly: true,
},
module: {
rules: [
{
test: /\.wasm$/,
type: 'webassembly/async',
},
],
},
};
`
Next.js
Add to next.config.js:
`javascript
/* @type {import('next').NextConfig} /
const nextConfig = {
webpack: (config) => {
config.experiments = {
...config.experiments,
asyncWebAssembly: true,
};
return config;
},
};
module.exports = nextConfig;
`
Rollup Configuration
Install plugin:
`bash
npm install --save-dev @rollup/plugin-wasm
`
Configure rollup.config.js:
`javascript
import wasm from '@rollup/plugin-wasm';
export default {
plugins: [
wasm({
maxFileSize: 10000000, // 10MB
targetEnv: 'auto',
}),
],
};
`
---
$3
Problem: Cannot find module 'extended-typescript-sdk/wasm/...'
Solution: Add to bundler config:
`typescript
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:
`typescript
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:
`bash
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
$3
The SDK ships with pre-built WASM signer - no build step required!
`typescript
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);
`
$3
`typescript
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
`typescript
// 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());
`
$3
`typescript
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);
`
$3
`typescript
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:
$3
Add this to your vite.config.js or vite.config.ts:
`javascript
import { defineConfig } from 'vite';
export default defineConfig({
optimizeDeps: {
exclude: ['extended-typescript-sdk']
},
assetsInclude: ['*/.wasm'],
});
`
$3
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:
`javascript
// vite.config.js
export default {
optimizeDeps: {
exclude: ['extended-typescript-sdk']
}
}
`
$3
#### Webpack 5
`javascript
module.exports = {
experiments: {
asyncWebAssembly: true,
},
};
`
#### Next.js
`javascript
// next.config.js
module.exports = {
webpack: (config) => {
config.experiments = {
...config.experiments,
asyncWebAssembly: true,
};
return config;
},
};
`
#### Rollup
`bash
npm install --save-dev @rollup/plugin-wasm
`
`javascript
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.
$3
The SDK ships with pre-built WASM files. Simply use the SDK:
`typescript
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.
$3
The SDK supports custom signers for integration with remote signing services like Privy, Web3Auth, or hardware wallets:
`typescript
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.
$3
If you want to build your own WASM signer (requires Rust and wasm-pack):
`bash
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.
$3
The WASM signer uses starknet-crypto crate for cryptographic operations. It's production-ready and tested for compatibility with Extended Exchange API.
API Documentation
$3
`typescript
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');
`
$3
`typescript
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');
`
$3
`typescript
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:
`typescript
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:
`typescript
import {
OrderSide,
OrderType,
OrderStatus,
TimeInForce,
StarkPerpetualAccount,
PerpetualTradingClient,
UserClient,
PerpetualStreamClient,
// ... and more
} from 'extended-typescript-sdk';
`
Error Handling
The SDK provides specific error types:
`typescript
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
$3
The SDK ships with pre-built WASM signer - just install and use:
`bash
npm install extended-typescript-sdk
`
$3
If you're developing the SDK or want to build your own WASM signer:
`bash
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
`
$3
- 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
$3
`bash
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:
- GitHub: https://github.com/Bvvvp009/Extended-TS-SDK
- Documentation: https://api.docs.extended.exchange/
- Extended Exchange: https://extended.exchange/
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:
`typescript
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);
``