@rabby-wallet/hyperliquid-sdk 1.0.8 → 1.0.9-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -139
- package/dist/client/exchange-client.d.ts +19 -1
- package/dist/client/exchange-client.js +66 -11
- package/dist/client/symbolConversion.d.ts +2 -0
- package/dist/client/symbolConversion.js +13 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/utils/number.d.ts +1 -0
- package/dist/utils/number.js +8 -0
- package/package.json +37 -37
package/README.md
CHANGED
|
@@ -1,140 +1,140 @@
|
|
|
1
|
-
# Hyperliquid Perpetuals SDK
|
|
2
|
-
|
|
3
|
-
一个简化的 Hyperliquid 永续合约交易 SDK,专为前端应用设计。
|
|
4
|
-
|
|
5
|
-
## 特性
|
|
6
|
-
|
|
7
|
-
- ✅ 仅核心API:最重要的交易与查询能力
|
|
8
|
-
- ✅ 永续合约专用:不包含现货功能
|
|
9
|
-
- ✅ TypeScript:完善的类型定义
|
|
10
|
-
- ✅ WebSocket:实时数据订阅
|
|
11
|
-
- ✅ 前端友好:基于 fetch API 的轻量实现
|
|
12
|
-
|
|
13
|
-
## 安装
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
yarn add @debank/hyperliquid-perp-sdk
|
|
17
|
-
# or
|
|
18
|
-
npm i @debank/hyperliquid-perp-sdk
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## 快速开始
|
|
22
|
-
|
|
23
|
-
### 仅查询(无需私钥)
|
|
24
|
-
```ts
|
|
25
|
-
import { HyperliquidSDK } from '@debank/hyperliquid-perp-sdk';
|
|
26
|
-
|
|
27
|
-
const sdk = new HyperliquidSDK({
|
|
28
|
-
masterAddress: '0xYourEOA',
|
|
29
|
-
isTestnet: true,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
// 获取所有中间价
|
|
33
|
-
const prices = await sdk.info.getAllMids();
|
|
34
|
-
|
|
35
|
-
// 获取市场元数据与资产上下文
|
|
36
|
-
const canUseCache = true; //默认使用缓存,多次请求并发去重 ,需要刷新传false
|
|
37
|
-
const [meta, assetCtxs] = await sdk.info.metaAndAssetCtxs(canUseCache);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// 获取账户综合状态
|
|
41
|
-
const account = await sdk.info.getClearingHouseState();
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### 交易(需要提供代理私钥、公钥、名称)
|
|
45
|
-
```ts
|
|
46
|
-
const sdk = new HyperliquidSDK({
|
|
47
|
-
masterAddress: '0xYourEOA',
|
|
48
|
-
agentPrivateKey: '0xYourAgentPrivKey',
|
|
49
|
-
agentPublicKey: '0xYourAgentPubKey',
|
|
50
|
-
agentName: 'MyAgent',
|
|
51
|
-
isTestnet: true,
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// 限价下单
|
|
55
|
-
await sdk.exchange!.placeOrder({
|
|
56
|
-
coin: 'BTC',
|
|
57
|
-
isBuy: true,
|
|
58
|
-
sz: '0.1',
|
|
59
|
-
limitPx: '45000',
|
|
60
|
-
orderType: { limit: { tif: 'Gtc' } },
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// 批量下单
|
|
64
|
-
await sdk.exchange!.multiOrder({
|
|
65
|
-
orders: [
|
|
66
|
-
{ coin: 'ETH', isBuy: true, sz: '1', limitPx: '3000', orderType: { limit: { tif: 'Ioc' } } },
|
|
67
|
-
{ coin: 'SOL', isBuy: false, sz: '10', limitPx: '150', orderType: { limit: { tif: 'Ioc' } } },
|
|
68
|
-
],
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// 市价开仓(带可选的 TP/SL 触发单)
|
|
72
|
-
await sdk.exchange!.marketOrderOpen({
|
|
73
|
-
coin: 'BTC',
|
|
74
|
-
isBuy: true,
|
|
75
|
-
size: '0.05',
|
|
76
|
-
midPx: '45200',
|
|
77
|
-
tpTriggerPx: '47000',
|
|
78
|
-
slTriggerPx: '44000',
|
|
79
|
-
// slippage 默认 0.08
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// 市价平仓
|
|
83
|
-
await sdk.exchange!.marketOrderClose({
|
|
84
|
-
coin: 'BTC',
|
|
85
|
-
isBuy: false,
|
|
86
|
-
size: '0.05',
|
|
87
|
-
midPx: '45000',
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// 绑定 TP/SL 到已有持仓(按位置绑定)
|
|
91
|
-
await sdk.exchange!.bindTpslByOrderId({
|
|
92
|
-
coin: 'BTC',
|
|
93
|
-
isBuy: true, // 持仓方向
|
|
94
|
-
tpTriggerPx: '47000',
|
|
95
|
-
slTriggerPx: '44000',
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// 更新杠杆
|
|
99
|
-
await sdk.exchange!.updateLeverage({
|
|
100
|
-
coin: 'BTC',
|
|
101
|
-
leverage: 5,
|
|
102
|
-
isCross: true,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// 撤单(可批量)
|
|
106
|
-
await sdk.exchange!.cancelOrder([
|
|
107
|
-
{ coin: 'BTC', oid: 12345 },
|
|
108
|
-
{ coin: 'ETH', oid: 67890 },
|
|
109
|
-
]);
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### 授权持久化代理(主钱包签名)
|
|
113
|
-
```ts
|
|
114
|
-
// 准备主钱包签名的 EIP-712 数据(Approve Agent)
|
|
115
|
-
const approve = sdk.exchange!.prepareApproveAgent();
|
|
116
|
-
// 业务方使用主钱包签名(示例)
|
|
117
|
-
const signature = await mainWallet.signTypedData(approve.domain, approve.types, approve.message);
|
|
118
|
-
// 发送请求
|
|
119
|
-
await sdk.exchange!.sendApproveAgent({ action: approve.message, nonce: approve.nonce, signature });
|
|
120
|
-
|
|
121
|
-
// 准备并签名 Builder 费用
|
|
122
|
-
const builderFee = sdk.exchange!.prepareApproveBuilderFee({ builder: '0xBuilder', maxFee: '0.1%' });
|
|
123
|
-
const sig2 = await mainWallet.signTypedData(builderFee.domain, builderFee.types, builderFee.message);
|
|
124
|
-
await sdk.exchange!.sendApproveBuilderFee({ action: builderFee.message, nonce: builderFee.nonce, signature: sig2 });
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### WebSocket 实时数据
|
|
128
|
-
```ts
|
|
129
|
-
await sdk.connectWebSocket();
|
|
130
|
-
|
|
131
|
-
// 订阅价格
|
|
132
|
-
sdk.ws.subscribeToAllMids((prices) => {
|
|
133
|
-
console.log('价格更新:', prices);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// 订阅用户综合数据
|
|
137
|
-
sdk.ws.subscribeToWebData2('0xYourEOA', (webData2) => {
|
|
138
|
-
console.log('用户数据:', webData2);
|
|
139
|
-
});
|
|
1
|
+
# Hyperliquid Perpetuals SDK
|
|
2
|
+
|
|
3
|
+
一个简化的 Hyperliquid 永续合约交易 SDK,专为前端应用设计。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- ✅ 仅核心API:最重要的交易与查询能力
|
|
8
|
+
- ✅ 永续合约专用:不包含现货功能
|
|
9
|
+
- ✅ TypeScript:完善的类型定义
|
|
10
|
+
- ✅ WebSocket:实时数据订阅
|
|
11
|
+
- ✅ 前端友好:基于 fetch API 的轻量实现
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
yarn add @debank/hyperliquid-perp-sdk
|
|
17
|
+
# or
|
|
18
|
+
npm i @debank/hyperliquid-perp-sdk
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 快速开始
|
|
22
|
+
|
|
23
|
+
### 仅查询(无需私钥)
|
|
24
|
+
```ts
|
|
25
|
+
import { HyperliquidSDK } from '@debank/hyperliquid-perp-sdk';
|
|
26
|
+
|
|
27
|
+
const sdk = new HyperliquidSDK({
|
|
28
|
+
masterAddress: '0xYourEOA',
|
|
29
|
+
isTestnet: true,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// 获取所有中间价
|
|
33
|
+
const prices = await sdk.info.getAllMids();
|
|
34
|
+
|
|
35
|
+
// 获取市场元数据与资产上下文
|
|
36
|
+
const canUseCache = true; //默认使用缓存,多次请求并发去重 ,需要刷新传false
|
|
37
|
+
const [meta, assetCtxs] = await sdk.info.metaAndAssetCtxs(canUseCache);
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
// 获取账户综合状态
|
|
41
|
+
const account = await sdk.info.getClearingHouseState();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 交易(需要提供代理私钥、公钥、名称)
|
|
45
|
+
```ts
|
|
46
|
+
const sdk = new HyperliquidSDK({
|
|
47
|
+
masterAddress: '0xYourEOA',
|
|
48
|
+
agentPrivateKey: '0xYourAgentPrivKey',
|
|
49
|
+
agentPublicKey: '0xYourAgentPubKey',
|
|
50
|
+
agentName: 'MyAgent',
|
|
51
|
+
isTestnet: true,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// 限价下单
|
|
55
|
+
await sdk.exchange!.placeOrder({
|
|
56
|
+
coin: 'BTC',
|
|
57
|
+
isBuy: true,
|
|
58
|
+
sz: '0.1',
|
|
59
|
+
limitPx: '45000',
|
|
60
|
+
orderType: { limit: { tif: 'Gtc' } },
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// 批量下单
|
|
64
|
+
await sdk.exchange!.multiOrder({
|
|
65
|
+
orders: [
|
|
66
|
+
{ coin: 'ETH', isBuy: true, sz: '1', limitPx: '3000', orderType: { limit: { tif: 'Ioc' } } },
|
|
67
|
+
{ coin: 'SOL', isBuy: false, sz: '10', limitPx: '150', orderType: { limit: { tif: 'Ioc' } } },
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// 市价开仓(带可选的 TP/SL 触发单)
|
|
72
|
+
await sdk.exchange!.marketOrderOpen({
|
|
73
|
+
coin: 'BTC',
|
|
74
|
+
isBuy: true,
|
|
75
|
+
size: '0.05',
|
|
76
|
+
midPx: '45200',
|
|
77
|
+
tpTriggerPx: '47000',
|
|
78
|
+
slTriggerPx: '44000',
|
|
79
|
+
// slippage 默认 0.08
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// 市价平仓
|
|
83
|
+
await sdk.exchange!.marketOrderClose({
|
|
84
|
+
coin: 'BTC',
|
|
85
|
+
isBuy: false,
|
|
86
|
+
size: '0.05',
|
|
87
|
+
midPx: '45000',
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// 绑定 TP/SL 到已有持仓(按位置绑定)
|
|
91
|
+
await sdk.exchange!.bindTpslByOrderId({
|
|
92
|
+
coin: 'BTC',
|
|
93
|
+
isBuy: true, // 持仓方向
|
|
94
|
+
tpTriggerPx: '47000',
|
|
95
|
+
slTriggerPx: '44000',
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// 更新杠杆
|
|
99
|
+
await sdk.exchange!.updateLeverage({
|
|
100
|
+
coin: 'BTC',
|
|
101
|
+
leverage: 5,
|
|
102
|
+
isCross: true,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// 撤单(可批量)
|
|
106
|
+
await sdk.exchange!.cancelOrder([
|
|
107
|
+
{ coin: 'BTC', oid: 12345 },
|
|
108
|
+
{ coin: 'ETH', oid: 67890 },
|
|
109
|
+
]);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 授权持久化代理(主钱包签名)
|
|
113
|
+
```ts
|
|
114
|
+
// 准备主钱包签名的 EIP-712 数据(Approve Agent)
|
|
115
|
+
const approve = sdk.exchange!.prepareApproveAgent();
|
|
116
|
+
// 业务方使用主钱包签名(示例)
|
|
117
|
+
const signature = await mainWallet.signTypedData(approve.domain, approve.types, approve.message);
|
|
118
|
+
// 发送请求
|
|
119
|
+
await sdk.exchange!.sendApproveAgent({ action: approve.message, nonce: approve.nonce, signature });
|
|
120
|
+
|
|
121
|
+
// 准备并签名 Builder 费用
|
|
122
|
+
const builderFee = sdk.exchange!.prepareApproveBuilderFee({ builder: '0xBuilder', maxFee: '0.1%' });
|
|
123
|
+
const sig2 = await mainWallet.signTypedData(builderFee.domain, builderFee.types, builderFee.message);
|
|
124
|
+
await sdk.exchange!.sendApproveBuilderFee({ action: builderFee.message, nonce: builderFee.nonce, signature: sig2 });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### WebSocket 实时数据
|
|
128
|
+
```ts
|
|
129
|
+
await sdk.connectWebSocket();
|
|
130
|
+
|
|
131
|
+
// 订阅价格
|
|
132
|
+
sdk.ws.subscribeToAllMids((prices) => {
|
|
133
|
+
console.log('价格更新:', prices);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// 订阅用户综合数据
|
|
137
|
+
sdk.ws.subscribeToWebData2('0xYourEOA', (webData2) => {
|
|
138
|
+
console.log('用户数据:', webData2);
|
|
139
|
+
});
|
|
140
140
|
```
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OrderResponse, CancelResponse, ExchangeClientConfig, PlaceOrderParams, MultiOrderParams, CancelOrderParams, ModifyOrderParams, WithdrawParams, ApproveBuilderFeeParams, PrepareApproveBuilderFeeResult, SendApproveParams, MarketOrderParams, UpdateLeverageParams, BindTpslByOrderIdParams } from '../types';
|
|
1
|
+
import type { OrderResponse, CancelResponse, ExchangeClientConfig, PlaceOrderParams, MultiOrderParams, CancelOrderParams, ModifyOrderParams, WithdrawParams, ApproveBuilderFeeParams, PrepareApproveBuilderFeeResult, SendApproveParams, MarketOrderParams, UpdateLeverageParams, BindTpslByOrderIdParams, UpdateIsolatedMarginParams } from '../types';
|
|
2
2
|
/**
|
|
3
3
|
* Client for executing trades on Hyperliquid (perpetuals only)
|
|
4
4
|
* Only includes essential trading APIs as specified
|
|
@@ -29,7 +29,24 @@ export declare class ExchangeClient {
|
|
|
29
29
|
* Place a single order
|
|
30
30
|
*/
|
|
31
31
|
placeOrder(params: PlaceOrderParams): Promise<OrderResponse>;
|
|
32
|
+
/**
|
|
33
|
+
* Calculate slippage price for market orders following Hyperliquid price rules
|
|
34
|
+
* Based on official Python SDK logic
|
|
35
|
+
*
|
|
36
|
+
* Rules:
|
|
37
|
+
* - Round to 5 significant figures
|
|
38
|
+
* - Round to (6 - szDecimals) decimal places for perps
|
|
39
|
+
*
|
|
40
|
+
* @param midPx - Middle price as string
|
|
41
|
+
* @param slippage - Slippage rate (e.g., 0.08 for 8%)
|
|
42
|
+
* @param isBuy - True for buy orders, false for sell orders
|
|
43
|
+
* @param szDecimals - Size decimals from meta endpoint (default 0)
|
|
44
|
+
*/
|
|
32
45
|
private getSlippagePx;
|
|
46
|
+
/**
|
|
47
|
+
* Round a number to specified decimal places
|
|
48
|
+
*/
|
|
49
|
+
private roundToDecimals;
|
|
33
50
|
/**
|
|
34
51
|
* Place a market order
|
|
35
52
|
* default slippage is 0.08
|
|
@@ -50,6 +67,7 @@ export declare class ExchangeClient {
|
|
|
50
67
|
* Modify an existing order
|
|
51
68
|
*/
|
|
52
69
|
modifyOrder(params: ModifyOrderParams): Promise<any>;
|
|
70
|
+
updateIsolatedMargin(params: UpdateIsolatedMarginParams): Promise<any>;
|
|
53
71
|
/**
|
|
54
72
|
* Set referrer for 10% fee
|
|
55
73
|
*/
|
|
@@ -167,12 +167,39 @@ class ExchangeClient {
|
|
|
167
167
|
});
|
|
168
168
|
});
|
|
169
169
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Calculate slippage price for market orders following Hyperliquid price rules
|
|
172
|
+
* Based on official Python SDK logic
|
|
173
|
+
*
|
|
174
|
+
* Rules:
|
|
175
|
+
* - Round to 5 significant figures
|
|
176
|
+
* - Round to (6 - szDecimals) decimal places for perps
|
|
177
|
+
*
|
|
178
|
+
* @param midPx - Middle price as string
|
|
179
|
+
* @param slippage - Slippage rate (e.g., 0.08 for 8%)
|
|
180
|
+
* @param isBuy - True for buy orders, false for sell orders
|
|
181
|
+
* @param szDecimals - Size decimals from meta endpoint (default 0)
|
|
182
|
+
*/
|
|
183
|
+
getSlippagePx(midPx, slippage, isBuy, szDecimals = 0) {
|
|
184
|
+
let px = parseFloat(midPx);
|
|
185
|
+
if (isNaN(px) || px <= 0) {
|
|
186
|
+
throw new Error('Invalid midPx: must be a positive number');
|
|
187
|
+
}
|
|
188
|
+
// Calculate slippage price
|
|
189
|
+
px *= isBuy ? (1 + slippage) : (1 - slippage);
|
|
190
|
+
// Round to 5 significant figures
|
|
191
|
+
const sigFigRounded = parseFloat(px.toPrecision(5));
|
|
192
|
+
// Round to (6 - szDecimals) decimals for perps
|
|
193
|
+
const maxDecimals = 6 - szDecimals;
|
|
194
|
+
const decimalRounded = this.roundToDecimals(sigFigRounded, maxDecimals);
|
|
195
|
+
return (0, number_1.removeTrailingZeros)(decimalRounded.toFixed(maxDecimals));
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Round a number to specified decimal places
|
|
199
|
+
*/
|
|
200
|
+
roundToDecimals(value, decimals) {
|
|
201
|
+
const multiplier = Math.pow(10, decimals);
|
|
202
|
+
return Math.round(value * multiplier) / multiplier;
|
|
176
203
|
}
|
|
177
204
|
/**
|
|
178
205
|
* Place a market order
|
|
@@ -183,7 +210,8 @@ class ExchangeClient {
|
|
|
183
210
|
return __awaiter(this, void 0, void 0, function* () {
|
|
184
211
|
try {
|
|
185
212
|
const slippage = params.slippage || constants_1.SLIPPAGE;
|
|
186
|
-
const
|
|
213
|
+
const szDecimals = yield this.symbolConversion.getAssetSzDecimals(params.coin);
|
|
214
|
+
const px = this.getSlippagePx((0, number_1.removeTrailingZeros)(params.midPx), slippage, params.isBuy, szDecimals);
|
|
187
215
|
const orders = [{
|
|
188
216
|
coin: params.coin,
|
|
189
217
|
isBuy: params.isBuy,
|
|
@@ -241,7 +269,8 @@ class ExchangeClient {
|
|
|
241
269
|
return __awaiter(this, void 0, void 0, function* () {
|
|
242
270
|
try {
|
|
243
271
|
const slippage = params.slippage || constants_1.SLIPPAGE;
|
|
244
|
-
const
|
|
272
|
+
const szDecimals = yield this.symbolConversion.getAssetSzDecimals(params.coin);
|
|
273
|
+
const px = this.getSlippagePx(params.midPx, slippage, params.isBuy, szDecimals);
|
|
245
274
|
const orders = [{
|
|
246
275
|
coin: params.coin,
|
|
247
276
|
isBuy: params.isBuy,
|
|
@@ -266,6 +295,7 @@ class ExchangeClient {
|
|
|
266
295
|
*/
|
|
267
296
|
multiOrder(params) {
|
|
268
297
|
return __awaiter(this, void 0, void 0, function* () {
|
|
298
|
+
var _a, _b, _c;
|
|
269
299
|
const nonce = Date.now();
|
|
270
300
|
const assetIndexCache = new Map();
|
|
271
301
|
const orderWires = yield Promise.all(params.orders.map((order) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -295,22 +325,29 @@ class ExchangeClient {
|
|
|
295
325
|
};
|
|
296
326
|
}
|
|
297
327
|
const signature = (0, signer_1.signL1AgentAction)(this.getAgentPrivateKey(), action, this.isTestnet, nonce);
|
|
298
|
-
|
|
328
|
+
const res = yield this.httpClient.exchange({
|
|
299
329
|
action,
|
|
300
330
|
nonce,
|
|
301
331
|
signature,
|
|
302
332
|
});
|
|
333
|
+
(_c = (_b = (_a = res === null || res === void 0 ? void 0 : res.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.statuses) === null || _c === void 0 ? void 0 : _c.forEach((status, index) => {
|
|
334
|
+
if (status.error) {
|
|
335
|
+
throw new Error(status.error);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
return res;
|
|
303
339
|
});
|
|
304
340
|
}
|
|
305
341
|
bindTpslByOrderId(params) {
|
|
306
342
|
return __awaiter(this, void 0, void 0, function* () {
|
|
307
343
|
let orders = [];
|
|
344
|
+
const szDecimals = yield this.symbolConversion.getAssetSzDecimals(params.coin);
|
|
308
345
|
if (params.tpTriggerPx) {
|
|
309
346
|
orders.push({
|
|
310
347
|
coin: params.coin,
|
|
311
348
|
isBuy: !params.isBuy,
|
|
312
349
|
sz: '0',
|
|
313
|
-
limitPx: this.getSlippagePx((0, number_1.removeTrailingZeros)(params.tpTriggerPx), constants_1.SLIPPAGE, !params.isBuy),
|
|
350
|
+
limitPx: this.getSlippagePx((0, number_1.removeTrailingZeros)(params.tpTriggerPx), constants_1.SLIPPAGE, !params.isBuy, szDecimals),
|
|
314
351
|
reduceOnly: true,
|
|
315
352
|
orderType: {
|
|
316
353
|
trigger: {
|
|
@@ -326,7 +363,7 @@ class ExchangeClient {
|
|
|
326
363
|
coin: params.coin,
|
|
327
364
|
isBuy: !params.isBuy,
|
|
328
365
|
sz: '0',
|
|
329
|
-
limitPx: this.getSlippagePx((0, number_1.removeTrailingZeros)(params.slTriggerPx), constants_1.SLIPPAGE, !params.isBuy),
|
|
366
|
+
limitPx: this.getSlippagePx((0, number_1.removeTrailingZeros)(params.slTriggerPx), constants_1.SLIPPAGE, !params.isBuy, szDecimals),
|
|
330
367
|
reduceOnly: true,
|
|
331
368
|
orderType: {
|
|
332
369
|
trigger: {
|
|
@@ -401,6 +438,24 @@ class ExchangeClient {
|
|
|
401
438
|
});
|
|
402
439
|
});
|
|
403
440
|
}
|
|
441
|
+
updateIsolatedMargin(params) {
|
|
442
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
443
|
+
const nonce = Date.now();
|
|
444
|
+
const assetIndex = yield this.symbolConversion.getAssetIndex(params.coin);
|
|
445
|
+
const action = {
|
|
446
|
+
type: constants_1.ExchangeType.UPDATE_ISOLATED_MARGIN,
|
|
447
|
+
asset: assetIndex,
|
|
448
|
+
isBuy: true,
|
|
449
|
+
ntli: (0, number_1.floatToInt)(params.value, 6), // 6 decimals
|
|
450
|
+
};
|
|
451
|
+
const signature = (0, signer_1.signL1AgentAction)(this.getAgentPrivateKey(), action, this.isTestnet, nonce);
|
|
452
|
+
return this.httpClient.exchange({
|
|
453
|
+
action,
|
|
454
|
+
nonce,
|
|
455
|
+
signature,
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
}
|
|
404
459
|
/**
|
|
405
460
|
* Set referrer for 10% fee
|
|
406
461
|
*/
|
|
@@ -2,6 +2,7 @@ import { HttpClientConfig } from "./http-client";
|
|
|
2
2
|
import { InfoClient } from "./info-client";
|
|
3
3
|
export declare class SymbolConversion {
|
|
4
4
|
private assetToIndexMap;
|
|
5
|
+
private assetSzDecimalsMap;
|
|
5
6
|
private httpClient;
|
|
6
7
|
private initialized;
|
|
7
8
|
private infoClient?;
|
|
@@ -10,6 +11,7 @@ export declare class SymbolConversion {
|
|
|
10
11
|
private ensureInitialized;
|
|
11
12
|
private refreshAssetMaps;
|
|
12
13
|
getAssetIndex(assetSymbol: string): Promise<number>;
|
|
14
|
+
getAssetSzDecimals(assetSymbol: string): Promise<number>;
|
|
13
15
|
getAllAssets(): Promise<{
|
|
14
16
|
perp: string[];
|
|
15
17
|
}>;
|
|
@@ -15,6 +15,7 @@ const http_client_1 = require("./http-client");
|
|
|
15
15
|
class SymbolConversion {
|
|
16
16
|
constructor(config, infoClient) {
|
|
17
17
|
this.assetToIndexMap = new Map();
|
|
18
|
+
this.assetSzDecimalsMap = new Map();
|
|
18
19
|
this.initialized = false;
|
|
19
20
|
this.infoClient = infoClient;
|
|
20
21
|
this.httpClient = new http_client_1.HttpClient({
|
|
@@ -64,9 +65,11 @@ class SymbolConversion {
|
|
|
64
65
|
throw new Error('Invalid perpetual metadata response');
|
|
65
66
|
}
|
|
66
67
|
this.assetToIndexMap.clear();
|
|
68
|
+
this.assetSzDecimalsMap.clear();
|
|
67
69
|
// Handle perpetual assets
|
|
68
70
|
perpMeta[0].universe.forEach((asset, index) => {
|
|
69
71
|
this.assetToIndexMap.set(asset.name, index);
|
|
72
|
+
this.assetSzDecimalsMap.set(asset.name, asset.szDecimals);
|
|
70
73
|
});
|
|
71
74
|
}
|
|
72
75
|
catch (error) {
|
|
@@ -84,6 +87,16 @@ class SymbolConversion {
|
|
|
84
87
|
return index;
|
|
85
88
|
});
|
|
86
89
|
}
|
|
90
|
+
getAssetSzDecimals(assetSymbol) {
|
|
91
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
92
|
+
yield this.ensureInitialized();
|
|
93
|
+
const szDecimals = this.assetSzDecimalsMap.get(assetSymbol);
|
|
94
|
+
if (szDecimals === undefined) {
|
|
95
|
+
throw new Error(`Unknown asset szDecimals: ${assetSymbol}`);
|
|
96
|
+
}
|
|
97
|
+
return szDecimals;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
87
100
|
getAllAssets() {
|
|
88
101
|
return __awaiter(this, void 0, void 0, function* () {
|
|
89
102
|
yield this.ensureInitialized();
|
package/dist/types/index.d.ts
CHANGED
|
@@ -393,6 +393,10 @@ export interface CancelOrderParams {
|
|
|
393
393
|
coin: string;
|
|
394
394
|
oid: OrderId;
|
|
395
395
|
}
|
|
396
|
+
export interface UpdateIsolatedMarginParams {
|
|
397
|
+
coin: string;
|
|
398
|
+
value: number;
|
|
399
|
+
}
|
|
396
400
|
export interface ModifyOrderParams {
|
|
397
401
|
oid: OrderId;
|
|
398
402
|
coin: string;
|
package/dist/utils/number.d.ts
CHANGED
package/dist/utils/number.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.removeTrailingZeros = removeTrailingZeros;
|
|
4
|
+
exports.floatToInt = floatToInt;
|
|
4
5
|
/**
|
|
5
6
|
* Removes trailing zeros from a string representation of a number.
|
|
6
7
|
* This is useful when working with price and size fields directly.
|
|
@@ -20,3 +21,10 @@ function removeTrailingZeros(value) {
|
|
|
20
21
|
return '0';
|
|
21
22
|
return normalized;
|
|
22
23
|
}
|
|
24
|
+
function floatToInt(x, power) {
|
|
25
|
+
const withDecimals = x * Math.pow(10, power);
|
|
26
|
+
if (Math.abs(Math.round(withDecimals) - withDecimals) >= 1e-3) {
|
|
27
|
+
throw new Error(`floatToInt causes rounding: ${x}`);
|
|
28
|
+
}
|
|
29
|
+
return Math.round(withDecimals);
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@rabby-wallet/hyperliquid-sdk",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Simplified Hyperliquid Perpetuals Trading SDK for Frontend Applications",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"dist"
|
|
9
|
-
],
|
|
10
|
-
"publishConfig": {
|
|
11
|
-
"access": "public"
|
|
12
|
-
},
|
|
13
|
-
"scripts": {
|
|
14
|
-
"build": "rimraf dist && tsc",
|
|
15
|
-
"preversion": "npm run build",
|
|
16
|
-
"prepublishOnly": "npm run build"
|
|
17
|
-
},
|
|
18
|
-
"author": "",
|
|
19
|
-
"license": "UNLICENSED",
|
|
20
|
-
"dependencies": {
|
|
21
|
-
"@ethereumjs/util": "9.0.0",
|
|
22
|
-
"@metamask/eth-sig-util": "5.1.0",
|
|
23
|
-
"@msgpack/msgpack": "3.1.2",
|
|
24
|
-
"@noble/hashes": "1.8.0",
|
|
25
|
-
"ethereum-cryptography": "2.2.1"
|
|
26
|
-
},
|
|
27
|
-
"devDependencies": {
|
|
28
|
-
"@types/node": "24.3.1",
|
|
29
|
-
"prettier": "2.7.1",
|
|
30
|
-
"rimraf": "6.0.0",
|
|
31
|
-
"typescript": "5.9.2"
|
|
32
|
-
},
|
|
33
|
-
"engines": {
|
|
34
|
-
"node": ">=16.0.0"
|
|
35
|
-
},
|
|
36
|
-
"packageManager": "yarn@1.22.22"
|
|
37
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@rabby-wallet/hyperliquid-sdk",
|
|
3
|
+
"version": "1.0.9-beta.2",
|
|
4
|
+
"description": "Simplified Hyperliquid Perpetuals Trading SDK for Frontend Applications",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "rimraf dist && tsc",
|
|
15
|
+
"preversion": "npm run build",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "UNLICENSED",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@ethereumjs/util": "9.0.0",
|
|
22
|
+
"@metamask/eth-sig-util": "5.1.0",
|
|
23
|
+
"@msgpack/msgpack": "3.1.2",
|
|
24
|
+
"@noble/hashes": "1.8.0",
|
|
25
|
+
"ethereum-cryptography": "2.2.1"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "24.3.1",
|
|
29
|
+
"prettier": "2.7.1",
|
|
30
|
+
"rimraf": "6.0.0",
|
|
31
|
+
"typescript": "5.9.2"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=16.0.0"
|
|
35
|
+
},
|
|
36
|
+
"packageManager": "yarn@1.22.22"
|
|
37
|
+
}
|