@desk-exchange/typescript-sdk
Version:
Typescript SDK for DESK Exchange API
1,196 lines (1,180 loc) • 33.5 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
DeskExchange: () => DeskExchange,
OrderUpdateClientStatus: () => OrderUpdateClientStatus,
OrderUpdateStatus: () => OrderUpdateStatus
});
module.exports = __toCommonJS(index_exports);
// src/api/auth.ts
var import_crypto = require("crypto");
var import_ethers = require("ethers");
var import_axios = __toESM(require("axios"), 1);
// src/types/constants.ts
var BASE_URLS = {
mainnet: "https://api.happytrading.global",
testnet: "https://stg-trade-api.happytrading.global"
};
var CRM_URLS = {
mainnet: "https://api.desk.exchange",
testnet: "https://dev-api.desk.exchange"
};
var WSS_URLS = {
mainnet: "wss://ws-api.happytrading.global/ws",
testnet: "wss://stg-trade-ws-api.happytrading.global/ws"
};
var CHAIN_ID = {
mainnet: 8453,
testnet: 421614,
base: 8453,
arbitrumSepolia: 421614
};
var VAULT_ADDRESS = {
mainnet: "0x764ab030159466edf9663e3fe3198c5d5c26c122",
testnet: "0x6e664f5025ee54704040a970d2bfa1ecbbc20fd4",
[CHAIN_ID.base]: "0x764ab030159466edf9663e3fe3198c5d5c26c122",
[CHAIN_ID.arbitrumSepolia]: "0x6e664f5025ee54704040a970d2bfa1ecbbc20fd4"
};
var BROKER_ID = "DESK-SDK";
// src/api/auth.ts
var Auth = class {
wallet;
subAccountId;
authenticated;
client;
crmClient;
network;
provider;
constructor(network, privateKey = process.env.PRIVATE_KEY, subAccountId) {
this.provider = new import_ethers.ethers.JsonRpcProvider(
"https://arbitrum-sepolia-rpc.publicnode.com"
);
this.wallet = privateKey ? new import_ethers.ethers.Wallet(privateKey, this.provider) : void 0;
this.subAccountId = subAccountId;
this.network = network;
this.client = import_axios.default.create({
baseURL: BASE_URLS[network],
headers: {
"Content-Type": "application/json"
}
});
this.crmClient = import_axios.default.create({
baseURL: CRM_URLS[network],
headers: {
"Content-Type": "application/json"
}
});
this.authenticated = false;
}
generateNonce() {
const expiredAt = BigInt(Date.now() + 1e3 * 60) * BigInt(1 << 20);
const random = parseInt((0, import_crypto.randomBytes)(3).toString("hex"), 16) % (1 << 20);
return (expiredAt + BigInt(random)).toString();
}
async generateJwt() {
if (!this.wallet) return;
const nonce = this.generateNonce();
const message = `Welcome to DESK!
Please sign this message to verify ownership of your wallet and proceed. By signing, you confirm the following: you have read, understood, and agreed to the Terms & Conditions, Privacy Policy, and any other relevant terms and conditions announced by DESK.
This request will not trigger a blockchain transaction or cost any gas fees.
Wallet address: ${this.wallet.address?.toLowerCase()}
Sub-account id: ${this.subAccountId.toString()}
Nonce: ${nonce}`;
const signature = await this.wallet.signMessage(message);
const orderbookJwtResponse = await this.client.post(`/v2/auth/evm`, {
account: this.wallet.address,
subaccount_id: this.subAccountId.toString(),
nonce,
signature
});
const crmJwtResponse = await this.crmClient.post(`/v1/users/auth`, {
nonce,
signature,
subaccount_id: this.subAccountId.toString(),
wallet_address: this.wallet.address
});
if (orderbookJwtResponse.status === 200 && crmJwtResponse.status === 200) {
this.client.defaults.headers.common["Authorization"] = `Bearer ${orderbookJwtResponse.data.data.jwt}`;
this.crmClient.defaults.headers.common["Authorization"] = `Bearer ${crmJwtResponse.data.data.jwt}`;
this.authenticated = true;
} else {
throw new Error("Could not generate JWT");
}
}
getSubaccount = () => {
const subaccountIdHex = BigInt(this.subAccountId).toString(16).padStart(24, "0");
return this.wallet.address.concat(subaccountIdHex);
};
isAuthenticated() {
return this.authenticated;
}
};
// src/api/exchange.ts
var import_ethers2 = require("ethers");
// src/api/vault_abi.json
var vault_abi_default = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
{ type: "receive", stateMutability: "payable" },
{
type: "function",
name: "WETH",
inputs: [],
outputs: [{ name: "", type: "address", internalType: "address" }],
stateMutability: "view"
},
{
type: "function",
name: "collateralIds",
inputs: [
{ name: "token", type: "address", internalType: "address" }
],
outputs: [
{ name: "collateralId", type: "address", internalType: "address" }
],
stateMutability: "view"
},
{
type: "function",
name: "deposit",
inputs: [
{
name: "_tokenAddress",
type: "address",
internalType: "address"
},
{ name: "_subaccount", type: "bytes32", internalType: "bytes32" },
{ name: "_amount", type: "uint256", internalType: "uint256" }
],
outputs: [
{ name: "_requestId", type: "uint256", internalType: "uint256" }
],
stateMutability: "payable"
},
{
type: "function",
name: "depositRequests",
inputs: [
{ name: "requestId", type: "uint256", internalType: "uint256" }
],
outputs: [
{ name: "subaccount", type: "bytes32", internalType: "bytes32" },
{ name: "amount", type: "uint256", internalType: "uint256" },
{ name: "tokenAddress", type: "address", internalType: "address" }
],
stateMutability: "view"
},
{
type: "function",
name: "executeWithdrawal",
inputs: [
{ name: "_requestId", type: "uint256", internalType: "uint256" },
{
name: "_transferAmount",
type: "uint256",
internalType: "uint256"
}
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "initialize",
inputs: [
{
name: "_withdrawHandler",
type: "address",
internalType: "address"
}
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "minDeposits",
inputs: [
{ name: "token", type: "address", internalType: "address" }
],
outputs: [
{
name: "minDepositAmount",
type: "uint256",
internalType: "uint256"
}
],
stateMutability: "view"
},
{
type: "function",
name: "owner",
inputs: [],
outputs: [{ name: "", type: "address", internalType: "address" }],
stateMutability: "view"
},
{
type: "function",
name: "renounceOwnership",
inputs: [],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "setCollateralId",
inputs: [
{
name: "_tokenAddress",
type: "address",
internalType: "address"
},
{
name: "_collateralId",
type: "address",
internalType: "address"
}
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "setMinDeposit",
inputs: [
{
name: "_tokenAddress",
type: "address",
internalType: "address"
},
{ name: "_amount", type: "uint256", internalType: "uint256" }
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "setWETH",
inputs: [
{ name: "_weth", type: "address", internalType: "address" }
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "setWhitelist",
inputs: [
{ name: "_user", type: "address", internalType: "address" },
{ name: "_isWhitelisted", type: "bool", internalType: "bool" }
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "setWithdrawableToken",
inputs: [
{
name: "_tokenAddress",
type: "address",
internalType: "address"
},
{ name: "_isWithdrawable", type: "bool", internalType: "bool" }
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "totalDepositRequests",
inputs: [],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view"
},
{
type: "function",
name: "totalWithdrawalRequests",
inputs: [],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view"
},
{
type: "function",
name: "transferOwnership",
inputs: [
{ name: "newOwner", type: "address", internalType: "address" }
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "whitelists",
inputs: [
{ name: "actor", type: "address", internalType: "address" }
],
outputs: [
{ name: "isWhitelisted", type: "bool", internalType: "bool" }
],
stateMutability: "view"
},
{
type: "function",
name: "withdraw",
inputs: [
{
name: "_tokenAddress",
type: "address",
internalType: "address"
},
{ name: "_subaccount", type: "bytes32", internalType: "bytes32" },
{ name: "_amount", type: "uint256", internalType: "uint256" }
],
outputs: [
{ name: "_requestId", type: "uint256", internalType: "uint256" }
],
stateMutability: "nonpayable"
},
{
type: "function",
name: "withdrawHandler",
inputs: [],
outputs: [{ name: "", type: "address", internalType: "address" }],
stateMutability: "view"
},
{
type: "function",
name: "withdrawableTokens",
inputs: [
{ name: "token", type: "address", internalType: "address" }
],
outputs: [{ name: "isAllow", type: "bool", internalType: "bool" }],
stateMutability: "view"
},
{
type: "function",
name: "withdrawalRequests",
inputs: [
{ name: "requestId", type: "uint256", internalType: "uint256" }
],
outputs: [
{ name: "subaccount", type: "bytes32", internalType: "bytes32" },
{ name: "amount", type: "uint256", internalType: "uint256" },
{
name: "tokenAddress",
type: "address",
internalType: "address"
},
{ name: "timestamp", type: "uint48", internalType: "uint48" },
{ name: "isExecuted", type: "bool", internalType: "bool" }
],
stateMutability: "view"
},
{
type: "event",
name: "Initialized",
inputs: [
{
name: "version",
type: "uint8",
indexed: false,
internalType: "uint8"
}
],
anonymous: false
},
{
type: "event",
name: "LogDeposit",
inputs: [
{
name: "requestId",
type: "uint256",
indexed: true,
internalType: "uint256"
},
{
name: "subaccount",
type: "bytes32",
indexed: false,
internalType: "bytes32"
},
{
name: "tokenAddress",
type: "address",
indexed: false,
internalType: "address"
},
{
name: "amount",
type: "uint256",
indexed: false,
internalType: "uint256"
}
],
anonymous: false
},
{
type: "event",
name: "LogSetAcceptedToken",
inputs: [
{
name: "tokenAddress",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "isAccepted",
type: "bool",
indexed: false,
internalType: "bool"
}
],
anonymous: false
},
{
type: "event",
name: "LogSetAssetService",
inputs: [
{
name: "oldAssetService",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "newAssetService",
type: "address",
indexed: false,
internalType: "address"
}
],
anonymous: false
},
{
type: "event",
name: "LogSetCollateralId",
inputs: [
{
name: "tokenAddress",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "collateralId",
type: "address",
indexed: true,
internalType: "address"
}
],
anonymous: false
},
{
type: "event",
name: "LogSetMinDeposit",
inputs: [
{
name: "tokenAddress",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "amount",
type: "uint256",
indexed: false,
internalType: "uint256"
}
],
anonymous: false
},
{
type: "event",
name: "LogSetWETH",
inputs: [
{
name: "weth",
type: "address",
indexed: true,
internalType: "address"
}
],
anonymous: false
},
{
type: "event",
name: "LogSetWhitelist",
inputs: [
{
name: "user",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "isWhitelisted",
type: "bool",
indexed: false,
internalType: "bool"
}
],
anonymous: false
},
{
type: "event",
name: "LogSetWithdrawableToken",
inputs: [
{
name: "tokenAddress",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "isWithdrawable",
type: "bool",
indexed: false,
internalType: "bool"
}
],
anonymous: false
},
{
type: "event",
name: "LogWithdrawal",
inputs: [
{
name: "requestId",
type: "uint256",
indexed: true,
internalType: "uint256"
},
{
name: "subaccount",
type: "bytes32",
indexed: false,
internalType: "bytes32"
},
{
name: "tokenAddress",
type: "address",
indexed: false,
internalType: "address"
},
{
name: "amount",
type: "uint256",
indexed: false,
internalType: "uint256"
},
{
name: "timestamp",
type: "uint48",
indexed: false,
internalType: "uint48"
}
],
anonymous: false
},
{
type: "event",
name: "LogWithdrawalProcessed",
inputs: [
{
name: "receiver",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "tokenAddress",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "amount",
type: "uint256",
indexed: false,
internalType: "uint256"
},
{
name: "transferAmount",
type: "uint256",
indexed: false,
internalType: "uint256"
}
],
anonymous: false
},
{
type: "event",
name: "OwnershipTransferred",
inputs: [
{
name: "previousOwner",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "newOwner",
type: "address",
indexed: true,
internalType: "address"
}
],
anonymous: false
},
{ type: "error", name: "Vault_AlreadyExecutedRequest", inputs: [] },
{ type: "error", name: "Vault_ExceedWithdrawableAmount", inputs: [] },
{ type: "error", name: "Vault_InvalidAddress", inputs: [] },
{ type: "error", name: "Vault_InvalidAmount", inputs: [] },
{ type: "error", name: "Vault_InvalidAuthentication", inputs: [] },
{ type: "error", name: "Vault_InvalidRequest", inputs: [] },
{ type: "error", name: "Vault_InvalidSubaccount", inputs: [] },
{ type: "error", name: "Vault_InvalidWithdrawalToken", inputs: [] },
{ type: "error", name: "Vault_LessThanMinimumDeposit", inputs: [] }
];
// src/api/exchange.ts
var erc20ABI = [
"function approve(address spender, uint256 amount) returns (bool)",
"function allowance(address owner, address spender) view returns (uint256)",
"function decimals() view returns (uint8)",
"function symbol() view returns (string)"
];
var Exchange = class {
auth;
parent;
constructor(auth, parent) {
this.auth = auth;
this.parent = parent;
}
async depositCollateral(tokenAddress, amount) {
if (!this.auth.wallet)
throw new Error("PRIVATE_KEY is required in .env file");
const erc20 = new import_ethers2.ethers.Contract(tokenAddress, erc20ABI, this.auth.wallet);
const vaultAddress = VAULT_ADDRESS[this.auth.network];
const vaultContract = new import_ethers2.ethers.Contract(
vaultAddress,
vault_abi_default,
this.auth.wallet
);
const minDepositAmount = await vaultContract.minDeposits(tokenAddress);
const decimals = await erc20.decimals();
const amountToDeposit = import_ethers2.ethers.parseUnits(amount.toString(), decimals);
const tokenSymbol = await erc20.symbol();
if (amountToDeposit < minDepositAmount) {
throw new Error(
`Minimum deposit ${import_ethers2.ethers.formatUnits(
minDepositAmount,
decimals
)} ${tokenSymbol}`
);
}
const allowance = await erc20.allowance(
this.auth.wallet.address,
vaultAddress
);
console.log(
`Depositing ${amount} ${tokenSymbol} to DESK Exchange for ${this.auth.getSubaccount()}`
);
if (allowance < amountToDeposit) {
const tx2 = await erc20.approve(vaultAddress, amountToDeposit);
console.log(`Approving ${amount} ${tokenSymbol}...`);
await tx2.wait();
console.log(`Approval success!`);
}
const tx = await vaultContract.deposit(
tokenAddress,
this.auth.getSubaccount(),
amountToDeposit
);
const receipt = await tx.wait();
console.log("Deposit successful!");
return receipt;
}
async withdrawCollateral(tokenAddress, amount) {
if (!this.auth.wallet)
throw new Error("PRIVATE_KEY is required in .env file");
const erc20 = new import_ethers2.ethers.Contract(tokenAddress, erc20ABI, this.auth.wallet);
const vaultAddress = VAULT_ADDRESS[this.auth.network];
const vaultContract = new import_ethers2.ethers.Contract(
vaultAddress,
vault_abi_default,
this.auth.wallet
);
const decimals = await erc20.decimals();
const amountToWithdraw = import_ethers2.ethers.parseUnits(amount.toString(), decimals);
const tokenSymbol = await erc20.symbol();
console.log(
`Withdrawing ${amount} ${tokenSymbol} from DESK Exchange from ${this.auth.getSubaccount()}`
);
const tx = await vaultContract.withdraw(
tokenAddress,
this.auth.getSubaccount(),
amountToWithdraw
);
const receipt = await tx.wait();
console.log("Withdrawal successful!");
return receipt;
}
async getSubAccountSummary() {
await this.parent.ensureInitialized();
const response = await this.auth.client.get(
`/v2/subaccount-summary/${this.auth.getSubaccount()}`
);
return response.data.data;
}
async placeOrder(request) {
await this.parent.ensureInitialized();
const response = await this.auth.client.post(`v2/place-order`, {
symbol: request.symbol,
subaccount: this.auth.getSubaccount(),
amount: request.amount,
price: request.price,
side: request.side,
nonce: this.auth.generateNonce(),
broker_id: BROKER_ID,
order_type: request.orderType,
reduce_only: request.reduceOnly,
time_in_force: request.timeInForce,
wait_for_reply: request.waitForReply
});
return response.data.data;
}
async batchPlaceOrder(requests) {
await this.parent.ensureInitialized();
const response = await this.auth.client.post(
`v2/batch-place-order`,
requests.map(
(request) => ({
symbol: request.symbol,
subaccount: this.auth.getSubaccount(),
amount: request.amount,
price: request.price,
side: request.side,
nonce: this.auth.generateNonce(),
broker_id: BROKER_ID,
order_type: request.orderType,
reduce_only: request.reduceOnly,
time_in_force: request.timeInForce,
wait_for_reply: request.waitForReply
})
)
);
return response.data.data;
}
async cancelOrder(request) {
await this.parent.ensureInitialized();
const response = await this.auth.client.post(`/v2/cancel-order`, {
symbol: request.symbol,
subaccount: this.auth.getSubaccount(),
nonce: this.auth.generateNonce(),
order_digest: request.orderDigest,
is_conditional_order: false,
wait_for_reply: request.waitForReply ?? false
});
return response.data.data;
}
async batchCancelOrder(requests) {
await this.parent.ensureInitialized();
const cancelRequests = requests.map((request) => this.cancelOrder(request));
return Promise.all(cancelRequests);
}
};
// src/websocket/connection.ts
var import_ws = __toESM(require("ws"), 1);
var import_events = require("events");
var WebSocketClient = class extends import_events.EventEmitter {
ws = null;
url;
pingInterval = null;
reconnectAttempts = 0;
maxReconnectAttempts = 5;
initialReconnectDelay = 1e3;
maxReconnectDelay = 3e4;
constructor(auth) {
super();
this.url = WSS_URLS[auth.network];
}
connect() {
return new Promise((resolve, reject) => {
this.ws = new import_ws.default(this.url);
this.ws.on("open", () => {
console.log("WebSocket connected");
this.reconnectAttempts = 0;
this.startPingInterval();
resolve();
});
this.ws.on("message", (data) => {
const message = JSON.parse(data.toString());
this.emit("message", message);
});
this.ws.on("error", (error) => {
console.error("WebSocket error:", error);
reject(error);
});
this.ws.on("close", () => {
console.log("WebSocket disconnected");
this.stopPingInterval();
this.reconnect();
});
});
}
reconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
const delay = Math.min(
this.initialReconnectDelay * Math.pow(2, this.reconnectAttempts - 1),
this.maxReconnectDelay
);
console.log(
`Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts}) in ${delay}ms...`
);
setTimeout(() => this.connect(), delay);
} else {
console.error(
"Max reconnection attempts reached. Please reconnect manually."
);
this.emit("maxReconnectAttemptsReached");
}
}
startPingInterval() {
this.pingInterval = setInterval(() => {
this.sendMessage({ method: "ping" });
}, 15e3);
}
stopPingInterval() {
if (this.pingInterval) {
clearInterval(this.pingInterval);
this.pingInterval = null;
}
}
sendMessage(message) {
if (!this.ws || this.ws.readyState !== import_ws.default.OPEN) {
throw new Error("WebSocket is not connected");
}
this.ws.send(JSON.stringify(message));
}
close() {
if (this.ws) {
this.ws.close();
}
this.stopPingInterval();
}
removeListener(event, listener) {
super.removeListener(event, listener);
return this;
}
removeAllListeners(event) {
super.removeAllListeners(event);
return this;
}
};
// src/websocket/subscriptions.ts
var WebSocketSubscriptions = class {
ws;
parent;
subscriptions = /* @__PURE__ */ new Map();
constructor(ws, parent) {
this.ws = ws;
this.parent = parent;
}
getSubscriptionKey(subscription) {
return JSON.stringify(subscription);
}
addSubscription(subscription, callback, messageHandler) {
const key = this.getSubscriptionKey(subscription);
if (!this.subscriptions.has(key)) {
this.subscriptions.set(key, /* @__PURE__ */ new Set());
}
this.subscriptions.get(key)?.add({ callback, messageHandler });
}
async subscribe(subscription) {
await this.parent.ensureInitialized();
await this.ws.sendMessage({
method: "subscribe",
subscription
});
}
async unsubscribe(subscription) {
await this.parent.ensureInitialized();
await this.ws.sendMessage({
method: "unsubscribe",
subscription
});
}
removeSubscription(subscription) {
const key = this.getSubscriptionKey(subscription);
const callbacks = this.subscriptions.get(key);
if (callbacks) {
for (const { messageHandler } of callbacks) {
this.ws.removeListener("message", messageHandler);
}
this.subscriptions.delete(key);
}
}
async subscribeToMarkPrices(callback) {
if (typeof callback !== "function") {
throw new Error("Callback must be a function");
}
const subscription = { type: "markPricesV2" /* MarkPrices */ };
const messageHandler = (message) => {
if (message.type === "markPricesV2" && message.data) {
const markPrices = message.data.map((item) => ({
symbol: item.symbol,
markPrice: item.mark_price,
indexPrice: item.index_price
}));
callback(markPrices);
}
};
this.addSubscription(subscription, callback, messageHandler);
this.ws.on("message", messageHandler);
await this.subscribe(subscription);
}
async unsubscribeFromMarkPrices() {
const subscription = { type: "markPricesV2" /* MarkPrices */ };
this.removeSubscription(subscription);
await this.unsubscribe(subscription);
}
async subscribeToOrderbook(symbol, callback) {
if (typeof callback !== "function") {
throw new Error("Callback must be a function");
}
const subscription = { type: "l2BookV2" /* Orderbook */, symbol };
const messageHandler = (message) => {
if (message.type === "l2BookV2" /* Orderbook */ && message.data) {
callback(message.data);
}
};
this.addSubscription(subscription, callback, messageHandler);
this.ws.on("message", messageHandler);
await this.subscribe(subscription);
}
async unsubscribeFromOrderbook(symbol) {
const subscription = { type: "l2BookV2" /* Orderbook */, symbol };
this.removeSubscription(subscription);
await this.unsubscribe(subscription);
}
async subscribeToTrades(symbol, callback) {
if (typeof callback !== "function") {
throw new Error("Callback must be a function");
}
const subscription = {
type: "tradesV2" /* Trades */,
symbol
};
const messageHandler = (message) => {
if (message.type === "tradesV2" /* Trades */ && message.data) {
callback(message.data);
}
};
this.addSubscription(subscription, callback, messageHandler);
this.ws.on("message", messageHandler);
await this.subscribe(subscription);
}
async unsubscribeFromTrades(symbol) {
const subscription = { type: "tradesV2" /* Trades */, symbol };
this.removeSubscription(subscription);
await this.unsubscribe(subscription);
}
async subscribeToCollateralPrices(callback) {
if (typeof callback !== "function") {
throw new Error("Callback must be a function");
}
const subscription = {
type: "collateralPricesV2" /* CollateralPrices */
};
const messageHandler = (message) => {
if (message.type === "collateralPricesV2" /* CollateralPrices */ && message.data) {
callback(message.data);
}
};
this.addSubscription(subscription, callback, messageHandler);
this.ws.on("message", messageHandler);
await this.subscribe(subscription);
}
async unsubscribeFromCollateralPrices(symbol) {
const subscription = {
type: "collateralPricesV2" /* CollateralPrices */,
symbol
};
this.removeSubscription(subscription);
await this.unsubscribe(subscription);
}
async subscribeToOrderUpdates(subaccount, callback) {
if (typeof callback !== "function") {
throw new Error("Callback must be a function");
}
const subscription = {
type: "orderUpdatesV2" /* OrderUpdatesV2 */,
subaccount: subaccount || this.parent.auth.getSubaccount()
};
const messageHandler = (message) => {
if (message.type === "orderUpdatesV2" /* OrderUpdatesV2 */ && message.data) {
callback(message.data);
}
};
this.addSubscription(subscription, callback, messageHandler);
this.ws.on("message", messageHandler);
await this.subscribe(subscription);
}
async unsubscribeFromOrderUpdates(symbol) {
const subscription = {
type: "orderUpdatesV2" /* OrderUpdatesV2 */,
symbol
};
this.removeSubscription(subscription);
await this.unsubscribe(subscription);
}
async subscribeToPositionUpdates(subaccount, callback) {
if (typeof callback !== "function") {
throw new Error("Callback must be a function");
}
const subscription = {
type: "positionUpdatesV2" /* PositionUpdatesV2 */,
subaccount: subaccount || this.parent.auth.getSubaccount()
};
const messageHandler = (message) => {
if (message.type === "positionUpdatesV2" /* PositionUpdatesV2 */ && message.data) {
callback(message.data);
}
};
this.addSubscription(subscription, callback, messageHandler);
this.ws.on("message", messageHandler);
await this.subscribe(subscription);
}
async unsubscribeFromPositionUpdates(symbol) {
const subscription = {
type: "positionUpdatesV2" /* PositionUpdatesV2 */,
symbol
};
this.removeSubscription(subscription);
await this.unsubscribe(subscription);
}
};
// src/api/info.ts
var Info = class {
auth;
parent;
constructor(auth, parent) {
this.auth = auth;
this.parent = parent;
}
async getMarketInfos() {
const response = await this.auth.client.get(
`/v2/market-info/brokers/${BROKER_ID}`
);
return response.data.data;
}
async getCollateralInfos() {
const response = await this.auth.client.get(`/v2/collaterals`);
return response.data.data;
}
async getHistoricalFundingRates(symbol, from, to) {
const response = await this.auth.client.get(
`/v2/funding-rate-history/${symbol}`,
{
params: { from, to }
}
);
return response.data.data;
}
// Get current 1h funding rate
async getCurrentFundingRate(symbol) {
const response = await this.auth.client.get("/v2/premium-index", {
params: { symbol }
});
return response.data.data.last_funding_rate;
}
};
// src/types/index.ts
var OrderUpdateStatus = /* @__PURE__ */ ((OrderUpdateStatus2) => {
OrderUpdateStatus2["Open"] = "Open";
OrderUpdateStatus2["Filled"] = "Filled";
OrderUpdateStatus2["Canceled"] = "Canceled";
OrderUpdateStatus2["Expired"] = "Expired";
OrderUpdateStatus2["NotFound"] = "NotFound";
return OrderUpdateStatus2;
})(OrderUpdateStatus || {});
var OrderUpdateClientStatus = /* @__PURE__ */ ((OrderUpdateClientStatus2) => {
OrderUpdateClientStatus2["PartialFilled"] = "PartialFilled";
return OrderUpdateClientStatus2;
})(OrderUpdateClientStatus || {});
// src/index.ts
var DeskExchange = class {
auth;
exchange;
info;
wsClient;
subscriptions;
enableWs;
initialized;
constructor(params) {
this.auth = new Auth(
params.network,
params.privateKey,
params.subAccountId
);
this.exchange = new Exchange(this.auth, this);
this.info = new Info(this.auth, this);
this.wsClient = new WebSocketClient(this.auth);
this.subscriptions = new WebSocketSubscriptions(this.wsClient, this);
this.enableWs = params.enableWs;
this.initialized = false;
}
async initialize() {
await this.auth.generateJwt();
if (this.enableWs) await this.wsClient.connect();
this.initialized = true;
}
async ensureInitialized() {
if (!this.initialized) {
await this.initialize();
}
}
async authenticate() {
await this.auth.generateJwt();
}
isInitialized() {
return this.initialized;
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
DeskExchange,
OrderUpdateClientStatus,
OrderUpdateStatus
});