@dhedge/v2-sdk 2.1.5 → 2.1.6

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.
Files changed (34) hide show
  1. package/README.md +180 -45
  2. package/dist/config.d.ts +2 -0
  3. package/dist/entities/pool.d.ts +110 -1
  4. package/dist/services/hyperliquid/constants.d.ts +16 -0
  5. package/dist/services/hyperliquid/index.d.ts +6 -0
  6. package/dist/services/hyperliquid/marketData.d.ts +12 -0
  7. package/dist/services/hyperliquid/positionData.d.ts +1 -0
  8. package/dist/services/toros/limitOrder.d.ts +8 -0
  9. package/dist/test/constants.d.ts +7 -1
  10. package/dist/test/wallet.d.ts +1 -0
  11. package/dist/types.d.ts +12 -2
  12. package/dist/v2-sdk.cjs.development.js +1470 -32
  13. package/dist/v2-sdk.cjs.development.js.map +1 -1
  14. package/dist/v2-sdk.cjs.production.min.js +1 -1
  15. package/dist/v2-sdk.cjs.production.min.js.map +1 -1
  16. package/dist/v2-sdk.esm.js +1449 -12
  17. package/dist/v2-sdk.esm.js.map +1 -1
  18. package/package.json +3 -2
  19. package/src/abi/hyperliquid/ICoreDepositWallet.json +130 -0
  20. package/src/abi/hyperliquid/ICoreWriter.json +1 -0
  21. package/src/abi/toros/IPoolLimitOrderManager.json +78 -0
  22. package/src/config.ts +31 -9
  23. package/src/entities/pool.ts +348 -4
  24. package/src/services/hyperliquid/constants.ts +23 -0
  25. package/src/services/hyperliquid/index.ts +176 -0
  26. package/src/services/hyperliquid/marketData.ts +157 -0
  27. package/src/services/hyperliquid/positionData.ts +33 -0
  28. package/src/services/toros/limitOrder.ts +86 -0
  29. package/src/test/constants.ts +11 -5
  30. package/src/test/hyperliquid.test.ts +107 -0
  31. package/src/test/pool.test.ts +37 -45
  32. package/src/test/torosLimitOrder.test.ts +130 -0
  33. package/src/test/wallet.ts +2 -1
  34. package/src/types.ts +13 -2
@@ -19,7 +19,8 @@ import {
19
19
  nonfungiblePositionManagerAddress,
20
20
  routerAddress,
21
21
  stakingAddress,
22
- SYNTHETIX_TRACKING_CODE
22
+ SYNTHETIX_TRACKING_CODE,
23
+ limitOrderAddress
23
24
  } from "../config";
24
25
  import {
25
26
  Dapp,
@@ -31,7 +32,8 @@ import {
31
32
  LyraOptionType,
32
33
  LyraTradeType,
33
34
  LyraPosition,
34
- SDKOptions
35
+ SDKOptions,
36
+ LimitOrderInfo
35
37
  } from "../types";
36
38
 
37
39
  import { Utils } from "./utils";
@@ -57,8 +59,8 @@ import { getLyraOptionTxData } from "../services/lyra/trade";
57
59
  import { getOptionPositions } from "../services/lyra/positions";
58
60
  import { getDeadline } from "../utils/deadline";
59
61
  import {
60
- getFuturesChangePositionTxData,
61
- getFuturesChangeMarginTxData
62
+ getFuturesChangeMarginTxData,
63
+ getFuturesChangePositionTxData
62
64
  } from "../services/futures";
63
65
  import { getFuturesCancelOrderTxData } from "../services/futures/trade";
64
66
  import { getOneInchSwapTxData } from "../services/oneInch";
@@ -86,7 +88,22 @@ import {
86
88
  import { getOdosSwapTxData } from "../services/odos";
87
89
  import { getPendleMintTxData, getPendleSwapTxData } from "../services/pendle";
88
90
  import { getCompleteWithdrawalTxData } from "../services/toros/completeWithdrawal";
91
+ import {
92
+ getCreateLimitOrderTxData,
93
+ getModifyLimitOrderTxData,
94
+ getDeleteLimitOrderTxData,
95
+ getTorosLimitOrder,
96
+ hasActiveTorosLimitOrder
97
+ } from "../services/toros/limitOrder";
89
98
  import { getKyberSwapTxData } from "../services/kyberSwap";
99
+ import {
100
+ getClosePositionHyperliquidTxData,
101
+ getDepositHyperliquidTxData,
102
+ getLimitOrderHyperliquidTxData,
103
+ getPerpToSpotHyperliquidTxData,
104
+ getWithdrawSpotHyperliquidTxData
105
+ } from "../services/hyperliquid";
106
+ import { CORE_WRITER_ADDRESS } from "../services/hyperliquid/constants";
90
107
 
91
108
  export class Pool {
92
109
  public readonly poolLogic: Contract;
@@ -2147,4 +2164,331 @@ export class Pool {
2147
2164
  );
2148
2165
  return tx;
2149
2166
  }
2167
+
2168
+ /** Deposit USDC from EVM to a HyperCore trading dex via the CoreDepositWallet.
2169
+ * This bridges USDC on-chain to Hyperliquid for perp/spot trading.
2170
+ *
2171
+ * @param {BigNumber | string} amount USDC amount to deposit (6 decimals, e.g. "1000000" = 1 USDC)
2172
+ * @param {number} dexId Destination dex ID where USDC will be available (default 0)
2173
+ * - 0: Core Perp dex (standard perps like BTC, ETH)
2174
+ * - 1: xyz HIP-3 dex (builder perps like TSLA, GOLD)
2175
+ * @param {any} options Transaction options
2176
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2177
+ * @returns {Promise<any>} Transaction
2178
+ */
2179
+ async depositHyperliquid(
2180
+ amount: BigNumber | string,
2181
+ dexId = 0,
2182
+ options: any = null,
2183
+ sdkOptions: SDKOptions = {
2184
+ estimateGas: false
2185
+ }
2186
+ ): Promise<any> {
2187
+ const tx = await getPoolTxOrGasEstimate(
2188
+ this,
2189
+ [
2190
+ routerAddress[this.network][Dapp.HYPERLIQUID],
2191
+ getDepositHyperliquidTxData(dexId, amount),
2192
+ options
2193
+ ],
2194
+ sdkOptions
2195
+ );
2196
+ return tx;
2197
+ }
2198
+
2199
+ /** Move USDC from a HyperCore trading dex to the Spot wallet.
2200
+ * Required before calling withdrawHyperliquid() to bridge USDC back to EVM.
2201
+ *
2202
+ * @param {number} dexId Source dex ID where USDC currently sits
2203
+ * - 0: Core Perp dex (standard perps like BTC, ETH)
2204
+ * - 1: xyz HIP-3 dex (builder perps like TSLA, GOLD)
2205
+ * @param {BigNumber | string} amount USDC amount to transfer (6 decimals, e.g. "1000000" = 1 USDC)
2206
+ * @param {any} options Transaction options
2207
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2208
+ * @returns {Promise<any>} Transaction
2209
+ */
2210
+
2211
+ async perpToSpotHyperliquid(
2212
+ dexId: number,
2213
+ amount: BigNumber | string,
2214
+ options: any = null,
2215
+ sdkOptions: SDKOptions = {
2216
+ estimateGas: false
2217
+ }
2218
+ ): Promise<any> {
2219
+ const tx = await getPoolTxOrGasEstimate(
2220
+ this,
2221
+ [
2222
+ CORE_WRITER_ADDRESS,
2223
+ getPerpToSpotHyperliquidTxData(dexId, this.address, amount),
2224
+ options
2225
+ ],
2226
+ sdkOptions
2227
+ );
2228
+ return tx;
2229
+ }
2230
+
2231
+ /** Withdraw USDC from Hyperliquid Spot wallet back to EVM.
2232
+ * USDC must be in the Spot wallet first — use perpToSpotHyperliquid() to move it from a trading dex.
2233
+ *
2234
+ * @param {BigNumber | string} amount USDC amount to withdraw (6 decimals, e.g. "1000000" = 1 USDC)
2235
+ * @param {any} options Transaction options
2236
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2237
+ * @returns {Promise<any>} Transaction
2238
+ */
2239
+
2240
+ async withdrawHyperliquid(
2241
+ amount: BigNumber | string,
2242
+ options: any = null,
2243
+ sdkOptions: SDKOptions = {
2244
+ estimateGas: false
2245
+ }
2246
+ ): Promise<any> {
2247
+ const tx = await getPoolTxOrGasEstimate(
2248
+ this,
2249
+ [CORE_WRITER_ADDRESS, getWithdrawSpotHyperliquidTxData(amount), options],
2250
+ sdkOptions
2251
+ );
2252
+ return tx;
2253
+ }
2254
+
2255
+ /** Open a market order on Hyperliquid
2256
+ * @param {number} assetId Asset id
2257
+ * @param {boolean} isLong Long or short (Note: Spot assets only support long positions)
2258
+ * @param {number} value Order value in base asset units (positive for opening/increasing,
2259
+ * negative for closing/reducing or selling spot)
2260
+ * @param {number } slippage Slippage tolerance in %
2261
+ * @param {any} options Transaction options
2262
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2263
+ * @returns {Promise<any>} Transaction
2264
+ */
2265
+ async openMarketOrderHyperliquid(
2266
+ assetId: number,
2267
+ isLong: boolean,
2268
+ value: number,
2269
+ slippage = 0.5,
2270
+ options: any = null,
2271
+ sdkOptions: SDKOptions = {
2272
+ estimateGas: false
2273
+ }
2274
+ ): Promise<any> {
2275
+ const tx = await getPoolTxOrGasEstimate(
2276
+ this,
2277
+ [
2278
+ CORE_WRITER_ADDRESS,
2279
+ await getLimitOrderHyperliquidTxData(assetId, isLong, value, slippage),
2280
+ options
2281
+ ],
2282
+ sdkOptions
2283
+ );
2284
+ return tx;
2285
+ }
2286
+
2287
+ /** Close a position on Hyperliquid
2288
+ * @param {number} assetId Asset id
2289
+ * @param {number} percentageToClose Percentage of position to close (0-100)
2290
+ * @param {number } slippage Slippage tolerance in %
2291
+ * @param {any} options Transaction options
2292
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2293
+ * @returns {Promise<any>} Transaction
2294
+ */
2295
+ async closePositionHyperliquid(
2296
+ assetId: number,
2297
+ percentageToClose = 100,
2298
+ slippage = 0.5,
2299
+ options: any = null,
2300
+ sdkOptions: SDKOptions = {
2301
+ estimateGas: false
2302
+ }
2303
+ ): Promise<any> {
2304
+ const tx = await getPoolTxOrGasEstimate(
2305
+ this,
2306
+ [
2307
+ CORE_WRITER_ADDRESS,
2308
+ await getClosePositionHyperliquidTxData(
2309
+ assetId,
2310
+ percentageToClose,
2311
+ slippage,
2312
+ this.address
2313
+ ),
2314
+ options
2315
+ ],
2316
+ sdkOptions
2317
+ );
2318
+ return tx;
2319
+ }
2320
+
2321
+ /**
2322
+ * Approve the Toros vault token for the PoolLimitOrderManager
2323
+ * Must be called before createTorosLimitOrder
2324
+ * @param {string} vaultAddress Address of the Toros vault token to approve
2325
+ * @param {BigNumber | string} amount Amount to approve
2326
+ * @param {any} options Transaction options
2327
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2328
+ * @returns {Promise<any>} Transaction
2329
+ */
2330
+ async approveTorosLimitOrder(
2331
+ vaultAddress: string,
2332
+ amount: BigNumber | string,
2333
+ options: any = null,
2334
+ sdkOptions: SDKOptions = { estimateGas: false }
2335
+ ): Promise<any> {
2336
+ const managerAddress = limitOrderAddress[this.network];
2337
+ const iERC20 = new ethers.utils.Interface(IERC20.abi);
2338
+ const approveTxData = iERC20.encodeFunctionData("approve", [
2339
+ managerAddress,
2340
+ amount
2341
+ ]);
2342
+ return getPoolTxOrGasEstimate(
2343
+ this,
2344
+ [vaultAddress, approveTxData, options],
2345
+ sdkOptions
2346
+ );
2347
+ }
2348
+
2349
+ /**
2350
+ * Create a Toros limit order (stop-loss / take-profit)
2351
+ * @param {string} vaultAddress Address of the Toros vault token
2352
+ * @param {BigNumber | string} amount Vault token amount (18 decimals)
2353
+ * @param {BigNumber | string | null | undefined} stopLossPriceD18 Stop-loss price in D18 (0 or null/undefined = disabled)
2354
+ * @param {BigNumber | string | null | undefined} takeProfitPriceD18 Take-profit price in D18 (MaxUint256 or null/undefined = disabled)
2355
+ * @param {string} pricingAsset Address of the pricing asset (e.g. USDC)
2356
+ * @param {any} options Transaction options
2357
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2358
+ * @returns {Promise<any>} Transaction
2359
+ */
2360
+ async createTorosLimitOrder(
2361
+ vaultAddress: string,
2362
+ amount: BigNumber | string,
2363
+ stopLossPriceD18: BigNumber | string | null | undefined,
2364
+ takeProfitPriceD18: BigNumber | string | null | undefined,
2365
+ pricingAsset: string,
2366
+ options: any = null,
2367
+ sdkOptions: SDKOptions = { estimateGas: false }
2368
+ ): Promise<any> {
2369
+ const managerAddress = limitOrderAddress[this.network];
2370
+ if (!managerAddress) {
2371
+ throw new Error(`Limit orders not supported on ${this.network}`);
2372
+ }
2373
+ const resolvedStopLoss =
2374
+ stopLossPriceD18 == null
2375
+ ? BigNumber.from(0)
2376
+ : BigNumber.from(stopLossPriceD18);
2377
+ const resolvedTakeProfit =
2378
+ takeProfitPriceD18 == null
2379
+ ? ethers.constants.MaxUint256
2380
+ : BigNumber.from(takeProfitPriceD18);
2381
+ const info: LimitOrderInfo = {
2382
+ amount: BigNumber.from(amount),
2383
+ stopLossPriceD18: resolvedStopLoss,
2384
+ takeProfitPriceD18: resolvedTakeProfit,
2385
+ user: this.address,
2386
+ pool: vaultAddress,
2387
+ pricingAsset
2388
+ };
2389
+ const txData = getCreateLimitOrderTxData(info);
2390
+ return getPoolTxOrGasEstimate(
2391
+ this,
2392
+ [managerAddress, txData, options],
2393
+ sdkOptions
2394
+ );
2395
+ }
2396
+
2397
+ /**
2398
+ * Modify an existing Toros limit order
2399
+ * @param {string} vaultAddress Address of the Toros vault token
2400
+ * @param {BigNumber | string} amount New vault token amount (18 decimals)
2401
+ * @param {BigNumber | string | null | undefined} stopLossPriceD18 New stop-loss price in D18 (0 or null/undefined = disabled)
2402
+ * @param {BigNumber | string | null | undefined} takeProfitPriceD18 New take-profit price in D18 (MaxUint256 or null/undefined = disabled)
2403
+ * @param {string} pricingAsset Address of the pricing asset
2404
+ * @param {any} options Transaction options
2405
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2406
+ * @returns {Promise<any>} Transaction
2407
+ */
2408
+ async modifyTorosLimitOrder(
2409
+ vaultAddress: string,
2410
+ amount: BigNumber | string,
2411
+ stopLossPriceD18: BigNumber | string | null | undefined,
2412
+ takeProfitPriceD18: BigNumber | string | null | undefined,
2413
+ pricingAsset: string,
2414
+ options: any = null,
2415
+ sdkOptions: SDKOptions = { estimateGas: false }
2416
+ ): Promise<any> {
2417
+ const managerAddress = limitOrderAddress[this.network];
2418
+ if (!managerAddress) {
2419
+ throw new Error(`Limit orders not supported on ${this.network}`);
2420
+ }
2421
+ const resolvedStopLoss =
2422
+ stopLossPriceD18 == null
2423
+ ? BigNumber.from(0)
2424
+ : BigNumber.from(stopLossPriceD18);
2425
+ const resolvedTakeProfit =
2426
+ takeProfitPriceD18 == null
2427
+ ? ethers.constants.MaxUint256
2428
+ : BigNumber.from(takeProfitPriceD18);
2429
+ const info: LimitOrderInfo = {
2430
+ amount: BigNumber.from(amount),
2431
+ stopLossPriceD18: resolvedStopLoss,
2432
+ takeProfitPriceD18: resolvedTakeProfit,
2433
+ user: this.address,
2434
+ pool: vaultAddress,
2435
+ pricingAsset
2436
+ };
2437
+ const txData = getModifyLimitOrderTxData(info);
2438
+ return getPoolTxOrGasEstimate(
2439
+ this,
2440
+ [managerAddress, txData, options],
2441
+ sdkOptions
2442
+ );
2443
+ }
2444
+
2445
+ /**
2446
+ * Delete an existing Toros limit order
2447
+ * @param {string} vaultAddress Address of the Toros vault token
2448
+ * @param {any} options Transaction options
2449
+ * @param {SDKOptions} sdkOptions SDK options including estimateGas
2450
+ * @returns {Promise<any>} Transaction
2451
+ */
2452
+ async deleteTorosLimitOrder(
2453
+ vaultAddress: string,
2454
+ options: any = null,
2455
+ sdkOptions: SDKOptions = { estimateGas: false }
2456
+ ): Promise<any> {
2457
+ const managerAddress = limitOrderAddress[this.network];
2458
+ if (!managerAddress) {
2459
+ throw new Error(`Limit orders not supported on ${this.network}`);
2460
+ }
2461
+ const txData = getDeleteLimitOrderTxData(vaultAddress);
2462
+ return getPoolTxOrGasEstimate(
2463
+ this,
2464
+ [managerAddress, txData, options],
2465
+ sdkOptions
2466
+ );
2467
+ }
2468
+
2469
+ /**
2470
+ * Fetch a Toros limit order for a given user and vault
2471
+ * @param {string} userAddress Address of the order owner (the dHEDGE pool)
2472
+ * @param {string} vaultAddress Address of the Toros vault token
2473
+ * @returns {Promise<LimitOrderInfo | null>} Order info, or null if none exists
2474
+ */
2475
+ async getTorosLimitOrder(
2476
+ userAddress: string,
2477
+ vaultAddress: string
2478
+ ): Promise<LimitOrderInfo | null> {
2479
+ return getTorosLimitOrder(this, userAddress, vaultAddress);
2480
+ }
2481
+
2482
+ /**
2483
+ * Check whether an active Toros limit order exists for a given user and vault
2484
+ * @param {string} userAddress Address of the order owner (the dHEDGE pool)
2485
+ * @param {string} vaultAddress Address of the Toros vault token
2486
+ * @returns {Promise<boolean>}
2487
+ */
2488
+ async hasActiveTorosLimitOrder(
2489
+ userAddress: string,
2490
+ vaultAddress: string
2491
+ ): Promise<boolean> {
2492
+ return hasActiveTorosLimitOrder(this, userAddress, vaultAddress);
2493
+ }
2150
2494
  }
@@ -0,0 +1,23 @@
1
+ export const USDC_TOKEN_ID = 0;
2
+ export const USDC_CORE_ADDRESS = "0x2000000000000000000000000000000000000000";
3
+ export const CORE_WRITER_ADDRESS = "0x3333333333333333333333333333333333333333";
4
+ export const PERP_DEX_ID = 0;
5
+ export const SPOT_DEX_ID = 4294967295; // max uint32;
6
+ export const HYPERLIQUID_VERSION = 1;
7
+
8
+ //Action IDs
9
+ export const SPOT_SEND_ACTION = 6;
10
+ export const SEND_ASSET_ACTION = 13;
11
+ export const LIMIT_ORDER_ACTION = 1;
12
+
13
+ //Order Time In Force options
14
+ export const LIMIT_ORDER_TIF_ALO = 1;
15
+ export const LIMIT_ORDER_TIF_GTC = 2;
16
+ export const LIMIT_ORDER_TIF_IOC = 3;
17
+
18
+ export const dexIdNameMap: { [key: number]: string } = {
19
+ 0: "",
20
+ 1: "xyz"
21
+ };
22
+
23
+ export const API_URL = "https://api.hyperliquid.xyz/info";
@@ -0,0 +1,176 @@
1
+ import { ethers } from "ethers";
2
+ import ICoreDepositWalletAbi from "../../abi/hyperliquid/ICoreDepositWallet.json";
3
+ import ICoreWriterAbi from "../../abi/hyperliquid/ICoreWriter.json";
4
+ import {
5
+ HYPERLIQUID_VERSION,
6
+ LIMIT_ORDER_ACTION,
7
+ LIMIT_ORDER_TIF_IOC,
8
+ SEND_ASSET_ACTION,
9
+ SPOT_DEX_ID,
10
+ SPOT_SEND_ACTION,
11
+ USDC_CORE_ADDRESS,
12
+ USDC_TOKEN_ID
13
+ } from "./constants";
14
+
15
+ import {
16
+ calculatePrice,
17
+ calculateSize,
18
+ getAssetInfo,
19
+ getMidPrice,
20
+ isSpotAsset,
21
+ scaleSize
22
+ } from "./marketData";
23
+ import { getPositionSize } from "./positionData";
24
+
25
+ const depositWallet = new ethers.utils.Interface(ICoreDepositWalletAbi);
26
+ const coreWriter = new ethers.utils.Interface(ICoreWriterAbi);
27
+
28
+ export const getDepositHyperliquidTxData = (
29
+ dexId: number,
30
+ amount: ethers.BigNumber | string
31
+ ): string => {
32
+ return depositWallet.encodeFunctionData("deposit", [amount, dexId]);
33
+ };
34
+
35
+ export const getWithdrawSpotHyperliquidTxData = (
36
+ amount: ethers.BigNumber | string
37
+ ): string => {
38
+ const coreAmount = ethers.BigNumber.from(amount).mul(100); //USDC on Core has two more decimals
39
+ //Hardcoded to USDC address and id on Hyperliquid Core
40
+ //From Spot to EVM
41
+ const innerEncoded = ethers.utils.defaultAbiCoder.encode(
42
+ //to, token, amount
43
+ ["address", "uint64", "uint64"],
44
+ [USDC_CORE_ADDRESS, USDC_TOKEN_ID, coreAmount]
45
+ );
46
+
47
+ const rawTXData = ethers.utils.solidityPack(
48
+ ["uint8", "uint24", "bytes"],
49
+ [HYPERLIQUID_VERSION, SPOT_SEND_ACTION, innerEncoded]
50
+ );
51
+ return coreWriter.encodeFunctionData("sendRawAction", [rawTXData]);
52
+ };
53
+ export const getPerpToSpotHyperliquidTxData = (
54
+ dexId: number,
55
+ receiver: string,
56
+ amount: ethers.BigNumber | string
57
+ ): string => {
58
+ const coreAmount = ethers.BigNumber.from(amount).mul(100); //USDC on Core has two more decimals
59
+ //From Perp to Spot
60
+ const innerEncoded = ethers.utils.defaultAbiCoder.encode(
61
+ //destination, subAccount, sourceDex, destinationDex, token, amount
62
+ ["address", "address", "uint32", "uint32", "uint64", "uint64"],
63
+ [
64
+ receiver,
65
+ ethers.constants.AddressZero,
66
+ dexId,
67
+ SPOT_DEX_ID,
68
+ USDC_TOKEN_ID,
69
+ coreAmount
70
+ ]
71
+ );
72
+
73
+ const rawTXData = ethers.utils.solidityPack(
74
+ ["uint8", "uint24", "bytes"],
75
+ [HYPERLIQUID_VERSION, SEND_ASSET_ACTION, innerEncoded]
76
+ );
77
+
78
+ return coreWriter.encodeFunctionData("sendRawAction", [rawTXData]);
79
+ };
80
+
81
+ export const getLimitOrderHyperliquidTxData = async (
82
+ assetId: number,
83
+ isLong: boolean,
84
+ changeAmount: number,
85
+ slippage: number
86
+ ): Promise<string> => {
87
+ let isBuy = isLong;
88
+ let reduceOnly = false;
89
+ if (changeAmount < 0) {
90
+ changeAmount = changeAmount * -1;
91
+ isBuy = !isLong;
92
+ reduceOnly = !isSpotAsset(assetId);
93
+ }
94
+
95
+ //Calculate price with slippage
96
+ const { assetName, szDecimals } = await getAssetInfo(assetId);
97
+ const midPrice = await getMidPrice(assetId, assetName);
98
+ const price = calculatePrice(
99
+ isSpotAsset(assetId),
100
+ szDecimals,
101
+ midPrice,
102
+ isBuy,
103
+ slippage
104
+ );
105
+ const size = calculateSize(szDecimals, changeAmount, midPrice);
106
+
107
+ const innerEncoded = ethers.utils.defaultAbiCoder.encode(
108
+ //assetIndex, isBuy, price, size, reduceOnly, tif, clientOrderId
109
+ ["uint32", "bool", "uint64", "uint64", "bool", "uint8", "uint128"],
110
+ [
111
+ assetId,
112
+ isBuy,
113
+ price,
114
+ size,
115
+ reduceOnly,
116
+ LIMIT_ORDER_TIF_IOC, // immediate or cancel
117
+ ethers.BigNumber.from(0) //client order id
118
+ ]
119
+ );
120
+
121
+ const rawTXData = ethers.utils.solidityPack(
122
+ ["uint8", "uint24", "bytes"],
123
+ [HYPERLIQUID_VERSION, LIMIT_ORDER_ACTION, innerEncoded]
124
+ );
125
+
126
+ return coreWriter.encodeFunctionData("sendRawAction", [rawTXData]);
127
+ };
128
+
129
+ export const getClosePositionHyperliquidTxData = async (
130
+ assetId: number,
131
+ percentageToClose: number,
132
+ slippage: number,
133
+ poolAddress: string
134
+ ): Promise<string> => {
135
+ const isSpot = isSpotAsset(assetId);
136
+ const { assetName, szDecimals, baseTokenName } = await getAssetInfo(assetId);
137
+ const positionSize = await getPositionSize(
138
+ assetId,
139
+ isSpot,
140
+ baseTokenName ?? assetName,
141
+ poolAddress
142
+ );
143
+ const isBuy = positionSize < 0; // if position size is negative, we need to buy to close, otherwise sell
144
+ const sizeRaw = scaleSize(szDecimals, positionSize, percentageToClose);
145
+
146
+ //Calculate price with slippage
147
+ const midPrice = await getMidPrice(assetId, assetName);
148
+ const price = calculatePrice(
149
+ isSpotAsset(assetId),
150
+ szDecimals,
151
+ midPrice,
152
+ isBuy,
153
+ slippage
154
+ );
155
+
156
+ const innerEncoded = ethers.utils.defaultAbiCoder.encode(
157
+ //assetIndex, isBuy, price, size, reduceOnly, tif, clientOrderId
158
+ ["uint32", "bool", "uint64", "uint64", "bool", "uint8", "uint128"],
159
+ [
160
+ assetId,
161
+ positionSize < 0, // if position size is negative, we need to buy to close, otherwise sell
162
+ price,
163
+ sizeRaw,
164
+ !isSpot,
165
+ LIMIT_ORDER_TIF_IOC, // immediate or cancel
166
+ ethers.BigNumber.from(0) //client order id
167
+ ]
168
+ );
169
+
170
+ const rawTXData = ethers.utils.solidityPack(
171
+ ["uint8", "uint24", "bytes"],
172
+ [HYPERLIQUID_VERSION, LIMIT_ORDER_ACTION, innerEncoded]
173
+ );
174
+
175
+ return coreWriter.encodeFunctionData("sendRawAction", [rawTXData]);
176
+ };