@nktkas/hyperliquid
Version:
Unofficial Hyperliquid API SDK for all major JS runtimes, written in TypeScript.
1,255 lines • 63.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExchangeClient = exports.ApiRequestError = void 0;
const base_js_1 = require("../base.js");
const mod_js_1 = require("../signing/mod.js");
/** Custom error class for API request errors. */
class ApiRequestError extends base_js_1.HyperliquidError {
response;
constructor(response) {
let message;
if (response.status === "err") {
// ErrorResponse
message = response.response;
}
else {
if ("statuses" in response.response.data) {
// OrderResponse | CancelResponse
const errors = response.response.data.statuses.reduce((acc, status, index) => {
if (typeof status === "object" && "error" in status) {
acc.push(`Order ${index}: ${status.error}`);
}
return acc;
}, []);
if (errors.length > 0) {
message = errors.join(", ");
}
}
else {
// TwapOrderResponse | TwapCancelResponse
if (typeof response.response.data.status === "object" && "error" in response.response.data.status) {
message = response.response.data.status.error;
}
}
}
super(message || "An unknown error occurred while processing an API request. See `response` for more details.");
this.response = response;
this.name = "ApiRequestError";
}
}
exports.ApiRequestError = ApiRequestError;
/** Nonce manager for generating unique nonces for signing transactions. */
class NonceManager {
/** The last nonce used for signing transactions. */
lastNonce = 0;
/**
* Gets the next nonce for signing transactions.
* @returns The next nonce.
*/
getNonce() {
let nonce = Date.now();
if (nonce <= this.lastNonce) {
nonce = ++this.lastNonce;
}
else {
this.lastNonce = nonce;
}
return nonce;
}
}
/**
* Exchange client for interacting with the Hyperliquid API.
* @typeParam T The transport used to connect to the Hyperliquid API.
* @typeParam W The wallet used for signing transactions.
*/
class ExchangeClient {
transport;
wallet;
isTestnet;
defaultVaultAddress;
defaultExpiresAfter;
signatureChainId;
nonceManager;
/**
* Initialises a new instance.
* @param args - The parameters for the client.
*
* @example Private key directly
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x...";
*
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
* ```
*
* @example [Viem](https://viem.sh/docs/clients/wallet#local-accounts-private-key-mnemonic-etc)
* ```ts
* import * as hl from "@nktkas/hyperliquid";
* import { privateKeyToAccount } from "viem/accounts";
*
* const account = privateKeyToAccount("0x...");
*
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: account, transport });
* ```
*
* @example [ethers.js](https://docs.ethers.org/v6/api/wallet/#Wallet) or [ethers.js v5](https://docs.ethers.org/v5/api/signer/#Wallet)
* ```ts
* import * as hl from "@nktkas/hyperliquid";
* import { ethers } from "ethers";
*
* const wallet = new ethers.Wallet("0x...");
*
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet, transport });
* ```
*
* @example External wallet (e.g. MetaMask) via [viem](https://viem.sh/docs/clients/wallet)
* ```ts
* import * as hl from "@nktkas/hyperliquid";
* import { createWalletClient, custom } from "viem";
*
* const ethereum = (window as any).ethereum;
* const [account] = await ethereum.request({ method: "eth_requestAccounts" });
* const wallet = createWalletClient({ account, transport: custom(ethereum) });
*
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet, transport });
* ```
*/
constructor(args) {
this.transport = args.transport;
this.wallet = args.wallet;
this.isTestnet = args.isTestnet ?? false;
this.defaultVaultAddress = args.defaultVaultAddress;
this.defaultExpiresAfter = args.defaultExpiresAfter;
this.signatureChainId = args.signatureChainId ?? (() => (0, mod_js_1.getWalletChainId)(this.wallet));
this.nonceManager = args.nonceManager ?? new NonceManager().getNonce;
}
/**
* Approve an agent to sign on behalf of the master account.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#approve-an-api-wallet
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.approveAgent({ agentAddress: "0x...", agentName: "..." });
* ```
*/
async approveAgent(params, opts) {
const action = mod_js_1.actionSorter.approveAgent({
type: "approveAgent",
hyperliquidChain: this._getHyperliquidChain(),
signatureChainId: await this._getSignatureChainId(),
nonce: await this.nonceManager(),
...params,
});
return await this._executeUserSignedAction({ action }, opts?.signal);
}
/**
* Approve a maximum fee rate for a builder.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#approve-a-builder-fee
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.approveBuilderFee({ maxFeeRate: "0.01%", builder: "0x..." });
* ```
*/
async approveBuilderFee(params, opts) {
const action = mod_js_1.actionSorter.approveBuilderFee({
type: "approveBuilderFee",
hyperliquidChain: this._getHyperliquidChain(),
signatureChainId: await this._getSignatureChainId(),
nonce: await this.nonceManager(),
...params,
});
return await this._executeUserSignedAction({ action }, opts?.signal);
}
/**
* Modify multiple orders.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful variant of {@link OrderResponse} without error statuses.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-multiple-orders
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* const data = await exchClient.batchModify({
* modifies: [
* {
* oid: 123,
* order: {
* a: 0,
* b: true,
* p: "31000",
* s: "0.2",
* r: false,
* t: { limit: { tif: "Gtc" } },
* },
* },
* ],
* });
* ```
*/
async batchModify(params, opts) {
const action = mod_js_1.actionSorter.batchModify({
type: "batchModify",
...params,
});
const vaultAddress = opts?.vaultAddress ?? this.defaultVaultAddress;
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, vaultAddress, expiresAfter }, opts?.signal);
}
/**
* Cancel order(s).
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful variant of {@link CancelResponse} without error statuses.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* const data = await exchClient.cancel({
* cancels: [
* { a: 0, o: 123 },
* ],
* });
* ```
*/
async cancel(params, opts) {
const action = mod_js_1.actionSorter.cancel({
type: "cancel",
...params,
});
const vaultAddress = opts?.vaultAddress ?? this.defaultVaultAddress;
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, vaultAddress, expiresAfter }, opts?.signal);
}
/**
* Cancel order(s) by cloid.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful variant of {@link CancelResponse} without error statuses.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* const data = await exchClient.cancelByCloid({
* cancels: [
* { asset: 0, cloid: "0x..." },
* ],
* });
* ```
*/
async cancelByCloid(params, opts) {
const action = mod_js_1.actionSorter.cancelByCloid({
type: "cancelByCloid",
...params,
});
const vaultAddress = opts?.vaultAddress ?? this.defaultVaultAddress;
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, vaultAddress, expiresAfter }, opts?.signal);
}
/**
* Transfer native token from the user's spot account into staking for delegating to validators.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#deposit-into-staking
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.cDeposit({ wei: 1 * 1e8 });
* ```
*/
async cDeposit(params, opts) {
const action = mod_js_1.actionSorter.cDeposit({
type: "cDeposit",
hyperliquidChain: this._getHyperliquidChain(),
signatureChainId: await this._getSignatureChainId(),
nonce: await this.nonceManager(),
...params,
});
return await this._executeUserSignedAction({ action }, opts?.signal);
}
/**
* Claim rewards from referral program.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.claimRewards();
* ```
*/
async claimRewards(opts) {
const action = mod_js_1.actionSorter.claimRewards({
type: "claimRewards",
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Convert a single-signature account to a multi-signature account or vice versa.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore/multi-sig
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* // Convert to multi-sig user
* await exchClient.convertToMultiSigUser({
* signers: {
* authorizedUsers: ["0x...", "0x...", "0x..."],
* threshold: 2,
* },
* });
*
* // Convert to single-sig user
* await exchClient.convertToMultiSigUser({ signers: null });
* ```
*/
async convertToMultiSigUser(params, opts) {
const action = mod_js_1.actionSorter.convertToMultiSigUser({
type: "convertToMultiSigUser",
hyperliquidChain: this._getHyperliquidChain(),
signatureChainId: await this._getSignatureChainId(),
nonce: await this.nonceManager(),
...params,
});
return await this._executeUserSignedAction({ action }, opts?.signal);
}
/**
* Create a sub-account.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Response for creating a sub-account.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* const data = await exchClient.createSubAccount({ name: "..." });
* ```
*/
async createSubAccount(params, opts) {
const action = mod_js_1.actionSorter.createSubAccount({
type: "createSubAccount",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Create a vault.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Response for creating a vault.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* const data = await exchClient.createVault({
* name: "...",
* description: "...",
* initialUsd: 100 * 1e6,
* nonce: Date.now(),
* });
* ```
*/
async createVault(params, opts) {
const action = mod_js_1.actionSorter.createVault({
type: "createVault",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Jail or unjail self as a validator signer.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* // Jail self
* await exchClient.cSignerAction({ jailSelf: null });
*
* // Unjail self
* await exchClient.cSignerAction({ unjailSelf: null });
* ```
*/
async cSignerAction(params, opts) {
const action = mod_js_1.actionSorter.CSignerAction({
type: "CSignerAction",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Action related to validator management.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* // Change validator profile
* await exchClient.cValidatorAction({
* changeProfile: {
* node_ip: { Ip: "1.2.3.4" },
* name: "...",
* description: "...",
* unjailed: true,
* disable_delegations: false,
* commission_bps: null,
* signer: null,
* },
* });
*
* // Register a new validator
* await exchClient.cValidatorAction({
* register: {
* profile: {
* node_ip: { Ip: "1.2.3.4" },
* name: "...",
* description: "...",
* delegations_disabled: true,
* commission_bps: 1,
* signer: "0x...",
* },
* unjailed: false,
* initial_wei: 1,
* },
* });
*
* // Unregister a validator
* await exchClient.cValidatorAction({ unregister: null });
* ```
*/
async cValidatorAction(params, opts) {
const action = mod_js_1.actionSorter.CValidatorAction({
type: "CValidatorAction",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Transfer native token from staking into the user's spot account.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#withdraw-from-staking
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.cWithdraw({ wei: 1 * 1e8 });
* ```
*/
async cWithdraw(params, opts) {
const action = mod_js_1.actionSorter.cWithdraw({
type: "cWithdraw",
hyperliquidChain: this._getHyperliquidChain(),
signatureChainId: await this._getSignatureChainId(),
nonce: await this.nonceManager(),
...params,
});
return await this._executeUserSignedAction({ action }, opts?.signal);
}
/**
* Configure block type for EVM transactions.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Response for creating a sub-account.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/dual-block-architecture
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* const data = await exchClient.evmUserModify({ usingBigBlocks: true });
* ```
*/
async evmUserModify(params, opts) {
const action = mod_js_1.actionSorter.evmUserModify({
type: "evmUserModify",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Modify an order.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-an-order
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.modify({
* oid: 123,
* order: {
* a: 0,
* b: true,
* p: "31000",
* s: "0.2",
* r: false,
* t: { limit: { tif: "Gtc" } },
* c: "0x...",
* },
* });
* ```
*/
async modify(params, opts) {
const action = mod_js_1.actionSorter.modify({
type: "modify",
...params,
});
const vaultAddress = opts?.vaultAddress ?? this.defaultVaultAddress;
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, vaultAddress, expiresAfter }, opts?.signal);
}
/**
* A multi-signature request.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Any successful response.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore/multi-sig
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
* import { actionSorter, signL1Action } from "@nktkas/hyperliquid/signing";
* import { privateKeyToAccount } from "viem/accounts";
*
* const wallet = privateKeyToAccount("0x..."); // or any other wallet libraries
* const multiSigUser = "0x...";
*
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet, transport });
*
* const nonce = Date.now();
* const action = actionSorter.scheduleCancel({
* type: "scheduleCancel",
* time: Date.now() + 10000,
* });
*
* // Create the required number of signatures
* const signatures = await Promise.all(["0x...", "0x..."].map(async (signerPrivKey) => {
* return await signL1Action({
* wallet: signerPrivKey as `0x${string}`,
* action: [multiSigUser.toLowerCase(), wallet.address.toLowerCase(), action],
* nonce,
* });
* }));
*
* // or user-signed action
* // const signatures = await Promise.all(["0x...", "0x..."].map(async (signerPrivKey) => {
* // return await signUserSignedAction({
* // wallet: signerPrivKey as `0x${string}`,
* // action: {
* // ...action,
* // payloadMultiSigUser: multiSigUser,
* // outerSigner: wallet.address,
* // },
* // types: userSignedActionEip712Types[action.type],
* // });
* // }));
*
* // Then use signatures in the `multiSig` action
* const data = await exchClient.multiSig({
* signatures,
* payload: {
* multiSigUser,
* outerSigner: wallet.address,
* action,
* },
* nonce,
* });
* ```
*/
async multiSig(params_and_nonce, opts) {
const { nonce, ...params } = params_and_nonce;
const action = mod_js_1.actionSorter.multiSig({
type: "multiSig",
signatureChainId: await this._getSignatureChainId(),
...params,
});
const vaultAddress = opts?.vaultAddress ?? this.defaultVaultAddress;
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeMultiSigAction({ action, vaultAddress, expiresAfter, nonce }, opts?.signal);
}
/**
* Place an order(s).
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful variant of {@link OrderResponse} without error statuses.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* const data = await exchClient.order({
* orders: [
* {
* a: 0,
* b: true,
* p: "30000",
* s: "0.1",
* r: false,
* t: { limit: { tif: "Gtc" } },
* c: "0x...",
* },
* ],
* grouping: "na",
* });
* ```
*/
async order(params, opts) {
const action = mod_js_1.actionSorter.order({
type: "order",
...params,
});
const vaultAddress = opts?.vaultAddress ?? this.defaultVaultAddress;
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, vaultAddress, expiresAfter }, opts?.signal);
}
/**
* Deploying HIP-3 assets.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/deploying-hip-3-assets
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.perpDeploy({
* registerAsset: {
* maxGas: 1000000,
* assetRequest: {
* coin: "USDC",
* szDecimals: 8,
* oraclePx: "1",
* marginTableId: 1,
* onlyIsolated: false,
* },
* dex: "test",
* schema: null,
* },
* });
* ```
*/
async perpDeploy(params, opts) {
const action = mod_js_1.actionSorter.perpDeploy({
type: "perpDeploy",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Create a referral code.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.registerReferrer({ code: "..." });
* ```
*/
async registerReferrer(params, opts) {
const action = mod_js_1.actionSorter.registerReferrer({
type: "registerReferrer",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Reserve additional rate-limited actions for a fee.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#reserve-additional-actions
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.reserveRequestWeight({ weight: 10 });
* ```
*/
async reserveRequestWeight(params, opts) {
const action = mod_js_1.actionSorter.reserveRequestWeight({
type: "reserveRequestWeight",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
async scheduleCancel(params_or_opts, maybeOpts) {
const isFirstArgParams = params_or_opts && "time" in params_or_opts;
const params = isFirstArgParams ? params_or_opts : {};
const opts = isFirstArgParams ? maybeOpts : params_or_opts;
const action = mod_js_1.actionSorter.scheduleCancel({
type: "scheduleCancel",
...params,
});
const vaultAddress = opts?.vaultAddress ?? this.defaultVaultAddress;
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, vaultAddress, expiresAfter }, opts?.signal);
}
/**
* Set the display name in the leaderboard.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.setDisplayName({ displayName: "..." });
* ```
*/
async setDisplayName(params, opts) {
const action = mod_js_1.actionSorter.setDisplayName({
type: "setDisplayName",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Set a referral code.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.setReferrer({ code: "..." });
* ```
*/
async setReferrer(params, opts) {
const action = mod_js_1.actionSorter.setReferrer({
type: "setReferrer",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Deploying HIP-1 and HIP-2 assets.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/deploying-hip-1-and-hip-2-assets
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.spotDeploy({
* registerToken2: {
* spec: {
* name: "USDC",
* szDecimals: 8,
* weiDecimals: 8,
* },
* maxGas: 1000000,
* fullName: "USD Coin",
* },
* });
* ```
*/
async spotDeploy(params, opts) {
const action = mod_js_1.actionSorter.spotDeploy({
type: "spotDeploy",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Send spot assets to another address.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#core-spot-transfer
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.spotSend({
* destination: "0x...",
* token: "USDC:0xeb62eee3685fc4c43992febcd9e75443",
* amount: "1",
* });
* ```
*/
async spotSend(params, opts) {
const action = mod_js_1.actionSorter.spotSend({
type: "spotSend",
hyperliquidChain: this._getHyperliquidChain(),
signatureChainId: await this._getSignatureChainId(),
time: await this.nonceManager(),
...params,
});
return await this._executeUserSignedAction({ action }, opts?.signal);
}
/**
* Opt Out of Spot Dusting.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.spotUser({ toggleSpotDusting: { optOut: false } });
* ```
*/
async spotUser(params, opts) {
const action = mod_js_1.actionSorter.spotUser({
type: "spotUser",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Modify a sub-account's.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.subAccountModify({ subAccountUser: "0x...", name: "..." });
* ```
*/
async subAccountModify(params, opts) {
const action = mod_js_1.actionSorter.subAccountModify({
type: "subAccountModify",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Transfer between sub-accounts (spot).
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.subAccountSpotTransfer({
* subAccountUser: "0x...",
* isDeposit: true,
* token: "USDC:0xeb62eee3685fc4c43992febcd9e75443",
* amount: "1",
* });
* ```
*/
async subAccountSpotTransfer(params, opts) {
const action = mod_js_1.actionSorter.subAccountSpotTransfer({
type: "subAccountSpotTransfer",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Transfer between sub-accounts (perpetual).
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see null
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.subAccountTransfer({ subAccountUser: "0x...", isDeposit: true, usd: 1 * 1e6 });
* ```
*/
async subAccountTransfer(params, opts) {
const action = mod_js_1.actionSorter.subAccountTransfer({
type: "subAccountTransfer",
...params,
});
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, expiresAfter }, opts?.signal);
}
/**
* Delegate or undelegate native tokens to or from a validator.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#delegate-or-undelegate-stake-from-validator
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* await exchClient.tokenDelegate({ validator: "0x...", isUndelegate: true, wei: 1 * 1e8 });
* ```
*/
async tokenDelegate(params, opts) {
const action = mod_js_1.actionSorter.tokenDelegate({
type: "tokenDelegate",
hyperliquidChain: this._getHyperliquidChain(),
signatureChainId: await this._getSignatureChainId(),
nonce: await this.nonceManager(),
...params,
});
return await this._executeUserSignedAction({ action }, opts?.signal);
}
/**
* Cancel a TWAP order.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful variant of {@link TwapCancelResponse} without error status.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-a-twap-order
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* const data = await exchClient.twapCancel({ a: 0, t: 1 });
* ```
*/
async twapCancel(params, opts) {
const action = mod_js_1.actionSorter.twapCancel({
type: "twapCancel",
...params,
});
const vaultAddress = opts?.vaultAddress ?? this.defaultVaultAddress;
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, vaultAddress, expiresAfter }, opts?.signal);
}
/**
* Place a TWAP order.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful variant of {@link TwapOrderResponse} without error status.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-a-twap-order
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const transport = new hl.HttpTransport(); // or `WebSocketTransport`
* const exchClient = new hl.ExchangeClient({ wallet: privateKey, transport });
*
* const data = await exchClient.twapOrder({
* twap: {
* a: 0,
* b: true,
* s: "1",
* r: false,
* m: 10,
* t: true,
* },
* });
* ```
*/
async twapOrder(params, opts) {
const action = mod_js_1.actionSorter.twapOrder({
type: "twapOrder",
...params,
});
const vaultAddress = opts?.vaultAddress ?? this.defaultVaultAddress;
const expiresAfter = opts?.expiresAfter ?? await this._getDefaultExpiresAfter();
return await this._executeL1Action({ action, vaultAddress, expiresAfter }, opts?.signal);
}
/**
* Add or remove margin from isolated position.
* @param params - Action-specific parameters.
* @param opts - Request execution options.
* @returns Successful response without specific data.
*
* @throws {ApiRequestError} When the API returns an unsuccessful response.
* @throws {TransportError} When the transport layer throws an error.
*
* @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
* @example
* ```ts
* import * as hl from "@nktkas/hyperliquid";
*
* const privateKey = "0x..."; // `viem`, `ethers`, or private key directly`
* const