A TypeScript SDK for interacting with the Limits trading platform API. This SDK provides type-safe methods for trading operations, account management, and device verification.
- 🔒 Type Safety: Full TypeScript support with comprehensive type definitions
- 🚀 Easy to Use: Simple, intuitive API for core trading operations
- Error Handling: Comprehensive error handling with detailed error types
- 🌐 HTTP Client: Built-in HTTP client with request/response interceptors
- 📚 Well Documented: Extensive documentation and examples
npm i @limits-trade/limits-sdkimport { LimitsSDK } from '@limits-trade/limits-sdk';
import { ethers } from 'ethers';
// Initialize the SDK with default configuration
const sdk = new LimitsSDK();
// Setup your device wallet
const devicePk = ethers.Wallet.createRandom().privateKey;
// Make sure you store the device private key as its used for all actions
const device = new ethers.Wallet(devicePrivateKey);
const deviceAddress = device.address;
async function quickStart() {
const userAddress = '0x1234567890123456789012345678901234567890';
// Step 1 (Optional): Assign CLOID for volume tracking
let cloid: string;
const cloidResult = await sdk.assignCloid({ address: userAddress });
cloid = cloidResult.data.cloid;
// Step 2: Connect user
const connectionResult = await sdk.connectUser({
userAddress,
deviceAddress: deviceAddress,
});
// Step 2.5
// Approve BuilderFee and Agent
// Please refer to examples/basic-usage.ts
// Step 3: Verify user keys (required before trading)
const verifyResult = await sdk.verifyUser({
userAddress,
agentAddress: connectionResult.hypeApiAddress,
nonce: Date.now(),
r: '0xabc123...', // From approveAgent signature
s: '0xdef456...', // From approveAgent signature
v: 27,
chainId: 1,
});
// Step 4: Create an order
const orderNonce = Date.now();
// Generate EIP-712 signature data using the SDK helper
const signatureData = sdk.generateSignatureData({
userAddress,
coin: 'BTC',
nonce: orderNonce,
chainId: 1,
signatureType: 'createOrder',
isBuy: true,
reduceOnly: false,
});
// Sign the typed data with your device private key to get r, s, v values
const signature = await device.signTypedData(
signatureData.domain,
signatureData.types,
signatureData.message
);
const { r, s, v } = ethers.Signature.from(signature);
// Create the order
const result = await sdk.createOrder({
userAddress,
coin: 'BTC',
isBuy: true,
sz: 1.0,
reduceOnly: false,
nonce: orderNonce,
r,
s,
v,
chainId: 1,
cloid, // Include CLOID if assigned for volume tracking
});
}Before creating orders, ensure you've connected and verified your device using connectUser() and verifyUser(). The device private key from that flow must be used to sign order requests.
// First, sign the order data with your device private key using EIP-712
// Use the domain, types, and message structure shown in Quick Start
const signature = await wallet.signTypedData(domain, types, message);
const { r, s, v } = ethers.utils.splitSignature(signature);
const orderResult = await sdk.createOrder({
userAddress: '0x...',
coin: 'BTC',
isBuy: true,
sz: 1.0,
reduceOnly: false,
nonce: 123456,
r: r, // From EIP-712 signature above
s: s, // From EIP-712 signature above
v: v, // From EIP-712 signature above
chainId: 1,
orderId: 'optional-order-id', // Optional
cloid: 'custom-client-order-id', // Optional
threshold: 0.01, // Optional
});Create multiple orders in a single request with validation and leverage parameters:
// First, generate signature data for batch orders
const nonce = Date.now();
const signatureData = sdk.generateSignatureData({
signatureType: 'createOrders',
userAddress: '0x...',
nonce,
chainId: 1,
orders: [
{
coin: 'BTC',
isBuy: true,
reduceOnly: false,
},
{
coin: 'ETH',
isBuy: false,
reduceOnly: false,
},
],
});
// Sign with your device private key
const signature = await device.signTypedData(
signatureData.domain,
signatureData.types,
signatureData.message
);
const sig = ethers.Signature.from(signature);
const { r, s, v } = sig;
// Create the batch order request
const batchOrderResult = await sdk.createOrders({
userAddress: '0x...',
validateOrder: true,
validationParams: {
leverage: 10,
managementInterval: 3000,
builderFee: 15,
builderAddress: '0x746337a98821e1e38AA2bAd0e77900d98B80609e',
takerFallbackInterval: 60000,
},
nonce,
r,
s,
v,
chainId: 1,
orders: [
{
coin: 'BTC',
cloid: '0x4c494d495470a25c11944846c4cf3bb1',
isBuy: true,
sz: '0.00022',
reduceOnly: false,
},
{
coin: 'ETH',
cloid: '0x4c494d495470a25c11944846c4cf3bb2',
isBuy: false,
sz: '0.01',
reduceOnly: false,
},
],
});const leverageResult = await sdk.updateLeverage({
userAddress: '0x...',
coin: 'BTC',
leverage: 10,
isCross: true,
nonce
r: '',
s: '',
v: 27
chainId: 1
});const connectResult = await sdk.connectUser({
userAddress: '0x...',
deviceAddress: 'your-device-address',
});Important: The r, s, v signature parameters required for verifyUser are generated during the approveAgent process. Use the same signature that you send to the Hyperliquid API approveAgent endpoint.
const verifyResult = await sdk.verifyUser({
userAddress: '0x...',
agentAddress: '0x...',
nonce: number,
r: '0xabc', // From approveAgent signature
s: '0xdef', // From approveAgent signature
v: 27, // From approveAgent signature
chainId: 1,
});This endpoint exists to make sure that the user device key matches the device key stored on our side.
const deviceVerifyResult = await sdk.verifyDevice({
signature: 'signature-string',
nonce: number,
agentAddress: '0x...',
userAddress: '0x...',
chainId: 1,
});The SDK provides a helper method to generate EIP-712 signature data for different request types:
// For create order requests
const orderData = {
nonce: 123456,
coin: 'BTC',
isBuy: true,
reduceOnly: false,
userAddress: '0x...',
chainId: 1,
};
const signatureData = sdk.generateSignatureData('createOrder', orderData);
// Returns: { domain, types, message } for EIP-712 signing
// For update leverage requests
const leverageData = {
userAddress: '0x...',
coin: 'BTC',
leverage: 10,
isCross: true,
chainId: 1,
};
const leverageSignatureData = sdk.generateSignatureData(
'updateLeverage',
leverageData
);
// Use with ethers.js or similar library
const signature = await wallet.signTypedData(
signatureData.domain,
signatureData.types,
signatureData.message
);
const { r, s, v } = ethers.utils.splitSignature(signature);The SDK exports all types used in the API:
import {
LimitsOrderRequest,
LeverageRequest,
ConnectUserRequest,
VerifyDeviceRequest,
VerifyKeysRequest,
OrderResponse,
LeverageResponse,
ConnectUserResponse,
VerifyDeviceResponse,
VerifyKeysResponse,
LimitsSDKConfig,
SDKError,
SignatureType,
SignatureData,
EIP712Domain,
EIP712Types,
} from 'limits-sdk';The SDK provides detailed error information:
import { SDKError } from 'limits-sdk';
try {
const result = await sdk.createOrder(orderRequest);
} catch (error) {
if (error instanceof Error) {
const sdkError = error as SDKError;
console.error('Error:', sdkError.message);
console.error('Code:', sdkError.code);
console.error('Status:', sdkError.status);
console.error('Response:', sdkError.response);
}
}interface LimitsSDKConfig {
baseURL?: string; // Optional, defaults to 'http://localhost:3001/dmp'
timeout?: number; // Optional, defaults to 30000ms
headers?: Record<string, string>; // Optional custom headers
}
// Default configuration
const sdk = new LimitsSDK();Check out the examples directory for more detailed usage examples:
- Basic Usage - Simple trading operations
Client Order IDs (CLOIDs) are used to track integrations and associate trading volume with specific partners on the Hyperliquid core. When orders are submitted with a CLOID, they can be tracked for volume attribution and rewards distribution.
- A CLOID is a 128-bit hexadecimal identifier used to track integration volume
- It associates trading activity with specific integrators for rewards distribution
- CLOIDs can be auto-generated by the system or provided by the integrator
- Once assigned to an address, all orders from that address will use the assigned CLOID
- The CLOID must be passed in the
placeOrderrequest for correct volume tracking on Hyperliquid
Assign a CLOID to an address for volume tracking and rewards distribution:
// Option 1: Let the system generate a CLOID
const assignResult = await sdk.assignCloid({
address: '0x1234567890123456789012345678901234567890',
});
// Option 2: Provide your own 128-bit hex CLOID
const customCloid = '0x' + 'a'.repeat(32); // 128-bit hex string
const assignResult = await sdk.assignCloid({
address: '0x1234567890123456789012345678901234567890',
cloid: customCloid,
});
// Response structure
interface AssignCloidResponse {
success: boolean;
message: string;
data: {
address: string;
cloid?: string;
};
}Retrieve the assigned CLOID for an Ethereum address:
const cloidResult = await sdk.getCloid(
'0x1234567890123456789012345678901234567890'
);
// Response structure
interface GetCloidResponse {
success: boolean;
message: string;
data: {
address: string;
cloid?: string; // undefined if no CLOID is assigned
};
}- Assign CLOID: Use
assignCloid()to associate a CLOID with user addresses - Track Volume: All orders from addresses with assigned CLOIDs will be tracked
- Rewards Distribution: Volume attribution enables proper rewards distribution to integrators
// Complete integration workflow
async function setupIntegration() {
const userAddress = '0x1234567890123456789012345678901234567890';
// Step 1: Assign CLOID for tracking
const assignResult = await sdk.assignCloid({
address: userAddress,
// cloid: customCloid // Optional: provide your own CLOID
});
if (assignResult.success) {
console.log(`CLOID assigned: ${assignResult.data.cloid}`);
// Step 2: Verify assignment
const cloidResult = await sdk.getCloid(userAddress);
console.log(`Retrieved CLOID: ${cloidResult.data.cloid}`);
// Step 3: All subsequent orders from this address will be tracked
// ... proceed with normal order creation workflow
}
}try {
const result = await sdk.assignCloid({
address: '0x1234567890123456789012345678901234567890',
});
if (!result.success) {
console.error('Assignment failed:', result.message);
// Handle business logic errors (e.g., CLOID already assigned)
}
} catch (error) {
console.error('Request failed:', error.message);
// Handle network/validation errors
}- Format: 128-bit hexadecimal string (32 hex characters after '0x')
- Uniqueness: Each CLOID should be unique across the system
- Persistence: Once assigned, CLOIDs remain associated with the address
- Usage: All orders from addresses with CLOIDs will include the CLOID for tracking
The SDK covers the core API endpoints:
POST /order- Create single orderPOST /leverage- Update leveragePOST /connect- Connect userPUT /connect- Verify user keysPOST /verifyDevice- Verify devicePOST /assignCloid- Assign CLOID to addressGET /getCloid/:address- Get CLOID for address
npm run buildnpm test
npm run test:watchnpm run lint
npm run lint:fixnpm run typecheckThis project is licensed under the MIT License - see the LICENSE file for details.
For support, please contact the development team or create an issue in the repository.