@metamask-previews/perps-controller 10.0.0-preview-a42e8d0d2 → 10.0.0-preview-5a03e1b92
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/CHANGELOG.md +77 -0
- package/dist/constants/eventNames.cjs +6 -0
- package/dist/constants/eventNames.cjs.map +1 -1
- package/dist/constants/eventNames.d.cts +4 -0
- package/dist/constants/eventNames.d.cts.map +1 -1
- package/dist/constants/eventNames.d.mts +4 -0
- package/dist/constants/eventNames.d.mts.map +1 -1
- package/dist/constants/eventNames.mjs +6 -0
- package/dist/constants/eventNames.mjs.map +1 -1
- package/dist/index.cjs +86 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -1
- package/dist/perpsErrorCodes.cjs +16 -0
- package/dist/perpsErrorCodes.cjs.map +1 -1
- package/dist/perpsErrorCodes.d.cts +12 -0
- package/dist/perpsErrorCodes.d.cts.map +1 -1
- package/dist/perpsErrorCodes.d.mts +12 -0
- package/dist/perpsErrorCodes.d.mts.map +1 -1
- package/dist/perpsErrorCodes.mjs +16 -0
- package/dist/perpsErrorCodes.mjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.cjs +674 -77
- package/dist/providers/HyperLiquidProvider.cjs.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.cts +13 -0
- package/dist/providers/HyperLiquidProvider.d.cts.map +1 -1
- package/dist/providers/HyperLiquidProvider.d.mts +13 -0
- package/dist/providers/HyperLiquidProvider.d.mts.map +1 -1
- package/dist/providers/HyperLiquidProvider.mjs +676 -79
- package/dist/providers/HyperLiquidProvider.mjs.map +1 -1
- package/dist/selectors.cjs.map +1 -1
- package/dist/selectors.d.cts +17 -17
- package/dist/selectors.d.cts.map +1 -1
- package/dist/selectors.d.mts +17 -17
- package/dist/selectors.d.mts.map +1 -1
- package/dist/selectors.mjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.cjs +121 -11
- package/dist/services/HyperLiquidSubscriptionService.cjs.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.cts +21 -0
- package/dist/services/HyperLiquidSubscriptionService.d.cts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.d.mts +21 -0
- package/dist/services/HyperLiquidSubscriptionService.d.mts.map +1 -1
- package/dist/services/HyperLiquidSubscriptionService.mjs +121 -11
- package/dist/services/HyperLiquidSubscriptionService.mjs.map +1 -1
- package/dist/services/TradingService.cjs +6 -2
- package/dist/services/TradingService.cjs.map +1 -1
- package/dist/services/TradingService.d.cts.map +1 -1
- package/dist/services/TradingService.d.mts.map +1 -1
- package/dist/services/TradingService.mjs +6 -2
- package/dist/services/TradingService.mjs.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +69 -4
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.mts +69 -4
- package/dist/types/index.d.mts.map +1 -1
- package/dist/types/index.mjs.map +1 -1
- package/dist/types/perps-types.cjs.map +1 -1
- package/dist/types/perps-types.d.cts +35 -1
- package/dist/types/perps-types.d.cts.map +1 -1
- package/dist/types/perps-types.d.mts +35 -1
- package/dist/types/perps-types.d.mts.map +1 -1
- package/dist/types/perps-types.mjs.map +1 -1
- package/dist/utils/hyperLiquidAdapter.cjs +168 -10
- package/dist/utils/hyperLiquidAdapter.cjs.map +1 -1
- package/dist/utils/hyperLiquidAdapter.d.cts +35 -1
- package/dist/utils/hyperLiquidAdapter.d.cts.map +1 -1
- package/dist/utils/hyperLiquidAdapter.d.mts +35 -1
- package/dist/utils/hyperLiquidAdapter.d.mts.map +1 -1
- package/dist/utils/hyperLiquidAdapter.mjs +166 -11
- package/dist/utils/hyperLiquidAdapter.mjs.map +1 -1
- package/dist/utils/hyperLiquidValidation.cjs +160 -5
- package/dist/utils/hyperLiquidValidation.cjs.map +1 -1
- package/dist/utils/hyperLiquidValidation.d.cts +23 -4
- package/dist/utils/hyperLiquidValidation.d.cts.map +1 -1
- package/dist/utils/hyperLiquidValidation.d.mts +23 -4
- package/dist/utils/hyperLiquidValidation.d.mts.map +1 -1
- package/dist/utils/hyperLiquidValidation.mjs +160 -5
- package/dist/utils/hyperLiquidValidation.mjs.map +1 -1
- package/dist/utils/index.cjs +5 -1
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.cts +2 -1
- package/dist/utils/index.d.cts.map +1 -1
- package/dist/utils/index.d.mts +2 -1
- package/dist/utils/index.d.mts.map +1 -1
- package/dist/utils/index.mjs +2 -1
- package/dist/utils/index.mjs.map +1 -1
- package/dist/utils/orderCalculations.cjs +363 -37
- package/dist/utils/orderCalculations.cjs.map +1 -1
- package/dist/utils/orderCalculations.d.cts +87 -2
- package/dist/utils/orderCalculations.d.cts.map +1 -1
- package/dist/utils/orderCalculations.d.mts +87 -2
- package/dist/utils/orderCalculations.d.mts.map +1 -1
- package/dist/utils/orderCalculations.mjs +359 -36
- package/dist/utils/orderCalculations.mjs.map +1 -1
- package/dist/utils/orderTypes.cjs +222 -0
- package/dist/utils/orderTypes.cjs.map +1 -0
- package/dist/utils/orderTypes.d.cts +114 -0
- package/dist/utils/orderTypes.d.cts.map +1 -0
- package/dist/utils/orderTypes.d.mts +114 -0
- package/dist/utils/orderTypes.d.mts.map +1 -0
- package/dist/utils/orderTypes.mjs +210 -0
- package/dist/utils/orderTypes.mjs.map +1 -0
- package/package.json +7 -6
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { hasProperty, isHexString } from "@metamask/utils";
|
|
2
|
-
import { HIP3_ASSET_ID_CONFIG } from "../constants/hyperLiquidConfig.mjs";
|
|
3
|
-
import { DECIMAL_PRECISION_CONFIG } from "../constants/perpsConfig.mjs";
|
|
2
|
+
import { BASIS_POINTS_DIVISOR, HIP3_ASSET_ID_CONFIG } from "../constants/hyperLiquidConfig.mjs";
|
|
3
|
+
import { DECIMAL_PRECISION_CONFIG, ORDER_SLIPPAGE_CONFIG } from "../constants/perpsConfig.mjs";
|
|
4
|
+
import { PERPS_ERROR_CODES } from "../perpsErrorCodes.mjs";
|
|
5
|
+
import { buildTriggerOrderType, classifyTriggerDirection, getTriggerDirection, getTriggerExecution, isLimitExecutionOrderType, isTriggerOrderType, toSDKTimeInForce } from "./orderTypes.mjs";
|
|
4
6
|
import { countSignificantFigures, roundToSignificantFigures } from "./significantFigures.mjs";
|
|
5
7
|
const readOptionalString = (value) => typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
6
8
|
const readOptionalOrderId = (value) => {
|
|
@@ -43,21 +45,101 @@ export function adaptOrderToSDK(order, symbolToAssetId) {
|
|
|
43
45
|
return {
|
|
44
46
|
a: assetId,
|
|
45
47
|
b: order.isBuy,
|
|
46
|
-
p: order.price ?? '0',
|
|
48
|
+
p: order.price ?? resolveTriggerCapPrice(order) ?? '0',
|
|
47
49
|
s: order.size,
|
|
48
50
|
r: order.reduceOnly ?? false,
|
|
49
|
-
t: order
|
|
50
|
-
? {
|
|
51
|
-
limit: { tif: 'Gtc' },
|
|
52
|
-
}
|
|
53
|
-
: {
|
|
54
|
-
limit: { tif: 'FrontendMarket' },
|
|
55
|
-
},
|
|
51
|
+
t: adaptOrderTypeToSDK(order),
|
|
56
52
|
c: order.clientOrderId && isHexString(order.clientOrderId)
|
|
57
53
|
? order.clientOrderId
|
|
58
54
|
: undefined,
|
|
59
55
|
};
|
|
60
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Derive the slippage cap a market-on-trigger order submits as its price.
|
|
59
|
+
*
|
|
60
|
+
* A `stop_market` / `take_profit_market` order legitimately carries no limit
|
|
61
|
+
* price, but the SDK still requires a positive `p` — it is the cap the order
|
|
62
|
+
* fills against once the trigger fires, not a resting price. Sending `'0'`
|
|
63
|
+
* fails SDK validation before the request is ever made.
|
|
64
|
+
*
|
|
65
|
+
* The cap follows the order's own tolerance, matching `calculateOrderPriceAndSize`
|
|
66
|
+
* on the `placeOrder` path, so the same order priced through either route gets
|
|
67
|
+
* the same execution bound.
|
|
68
|
+
*
|
|
69
|
+
* @param order - Order params carrying the placement type, trigger price, and
|
|
70
|
+
* slippage tolerance.
|
|
71
|
+
* @returns The formatted cap price, or undefined when the order needs no cap.
|
|
72
|
+
*/
|
|
73
|
+
function resolveTriggerCapPrice(order) {
|
|
74
|
+
if (!isTriggerOrderType(order.orderType) ||
|
|
75
|
+
isLimitExecutionOrderType(order.orderType) ||
|
|
76
|
+
!order.triggerPrice) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const triggerPrice = parseFloat(order.triggerPrice);
|
|
80
|
+
if (!Number.isFinite(triggerPrice)) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
// Accept the deprecated decimal `slippage` too, normalizing it to bps the way
|
|
84
|
+
// `placeOrder` does, so neither spelling silently falls back to the default.
|
|
85
|
+
const effectiveBps = order.maxSlippageBps ??
|
|
86
|
+
(typeof order.slippage === 'number'
|
|
87
|
+
? Math.round(order.slippage * BASIS_POINTS_DIVISOR)
|
|
88
|
+
: undefined) ??
|
|
89
|
+
ORDER_SLIPPAGE_CONFIG.DefaultTpslSlippageBps;
|
|
90
|
+
// Buying pays up to the cap, selling accepts down to it.
|
|
91
|
+
const slippage = effectiveBps / BASIS_POINTS_DIVISOR;
|
|
92
|
+
const capPrice = order.isBuy
|
|
93
|
+
? triggerPrice * (1 + slippage)
|
|
94
|
+
: triggerPrice * (1 - slippage);
|
|
95
|
+
return capPrice.toString();
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Map a placement type onto the SDK's order-type field.
|
|
99
|
+
*
|
|
100
|
+
* @param order - Order params carrying the placement type and trigger price
|
|
101
|
+
* @returns The SDK order-type field
|
|
102
|
+
*/
|
|
103
|
+
function adaptOrderTypeToSDK(order) {
|
|
104
|
+
if (isTriggerOrderType(order.orderType)) {
|
|
105
|
+
if (order.timeInForce !== undefined) {
|
|
106
|
+
throw new Error(PERPS_ERROR_CODES.ORDER_TIME_IN_FORCE_NOT_SUPPORTED);
|
|
107
|
+
}
|
|
108
|
+
if (!order.triggerPrice) {
|
|
109
|
+
throw new Error(PERPS_ERROR_CODES.ORDER_TRIGGER_PRICE_REQUIRED);
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
trigger: {
|
|
113
|
+
isMarket: !isLimitExecutionOrderType(order.orderType),
|
|
114
|
+
triggerPx: order.triggerPrice,
|
|
115
|
+
tpsl: getTriggerDirection(order.orderType) === 'stop' ? 'sl' : 'tp',
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (order.orderType === 'limit') {
|
|
120
|
+
return { limit: { tif: toSDKTimeInForce(order.timeInForce) } };
|
|
121
|
+
}
|
|
122
|
+
if (order.timeInForce !== undefined) {
|
|
123
|
+
throw new Error(PERPS_ERROR_CODES.ORDER_TIME_IN_FORCE_NOT_SUPPORTED);
|
|
124
|
+
}
|
|
125
|
+
return { limit: { tif: 'FrontendMarket' } };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Map the provider-agnostic TP/SL linkage onto HyperLiquid's grouping vocabulary.
|
|
129
|
+
*
|
|
130
|
+
* @param linkage - How the attached TP/SL is linked.
|
|
131
|
+
* @returns The HyperLiquid grouping value.
|
|
132
|
+
*/
|
|
133
|
+
export function adaptTpslLinkageToGrouping(linkage) {
|
|
134
|
+
switch (linkage) {
|
|
135
|
+
case 'position':
|
|
136
|
+
return 'positionTpsl';
|
|
137
|
+
case 'order':
|
|
138
|
+
return 'normalTpsl';
|
|
139
|
+
default:
|
|
140
|
+
return 'na';
|
|
141
|
+
}
|
|
142
|
+
}
|
|
61
143
|
export function adaptPositionFromSDK(assetPosition) {
|
|
62
144
|
const pos = assetPosition.position;
|
|
63
145
|
return {
|
|
@@ -91,8 +173,16 @@ export function adaptOrderFromSDK(rawOrder, position) {
|
|
|
91
173
|
const detailedOrderType = rawOrder.orderType;
|
|
92
174
|
const { isTrigger } = rawOrder;
|
|
93
175
|
const { reduceOnly } = rawOrder;
|
|
176
|
+
const triggerOrderType = adaptTriggerOrderTypeFromSDK(detailedOrderType);
|
|
94
177
|
let orderType = 'market';
|
|
95
|
-
if (
|
|
178
|
+
if (triggerOrderType) {
|
|
179
|
+
// Trigger orders always carry a limitPx (the slippage cap for
|
|
180
|
+
// market-on-trigger execution), so the placement type is the only reliable
|
|
181
|
+
// source for how the order actually executes.
|
|
182
|
+
orderType = getTriggerExecution(triggerOrderType);
|
|
183
|
+
}
|
|
184
|
+
else if (detailedOrderType.toLowerCase().includes('limit') ||
|
|
185
|
+
rawOrder.limitPx) {
|
|
96
186
|
orderType = 'limit';
|
|
97
187
|
}
|
|
98
188
|
const price = rawOrder.limitPx || rawOrder.triggerPx || '0';
|
|
@@ -166,8 +256,73 @@ export function adaptOrderFromSDK(rawOrder, position) {
|
|
|
166
256
|
if (rawOrder.triggerPx) {
|
|
167
257
|
order.triggerPrice = rawOrder.triggerPx;
|
|
168
258
|
}
|
|
259
|
+
if (triggerOrderType) {
|
|
260
|
+
order.triggerOrderType = triggerOrderType;
|
|
261
|
+
}
|
|
169
262
|
return order;
|
|
170
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Map HyperLiquid's human-readable order type string onto the provider-agnostic
|
|
266
|
+
* trigger placement type.
|
|
267
|
+
*
|
|
268
|
+
* @param detailedOrderType - HyperLiquid `orderType` string (e.g. `'Stop Limit'`)
|
|
269
|
+
* @returns The normalized trigger placement type, or undefined for non-trigger orders
|
|
270
|
+
*/
|
|
271
|
+
export function adaptTriggerOrderTypeFromSDK(detailedOrderType) {
|
|
272
|
+
if (!detailedOrderType) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
const isTakeProfit = detailedOrderType.includes('Take Profit');
|
|
276
|
+
const isStop = detailedOrderType.includes('Stop');
|
|
277
|
+
if (!isTakeProfit && !isStop) {
|
|
278
|
+
return undefined;
|
|
279
|
+
}
|
|
280
|
+
return buildTriggerOrderType({
|
|
281
|
+
direction: isTakeProfit ? 'take_profit' : 'stop',
|
|
282
|
+
execution: detailedOrderType.includes('Limit') ? 'limit' : 'market',
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Build the position-state view of a trigger order attached to a position.
|
|
287
|
+
*
|
|
288
|
+
* HyperLiquid encodes "the whole position" as size `0` for position-bound TP/SL,
|
|
289
|
+
* which is resolved here against the position size so consumers always see a
|
|
290
|
+
* concrete quantity and can tell partial triggers apart.
|
|
291
|
+
*
|
|
292
|
+
* @param params - Mapping parameters
|
|
293
|
+
* @param params.rawOrder - Raw HyperLiquid frontend order
|
|
294
|
+
* @param params.positionSize - Signed or unsigned position size
|
|
295
|
+
* @param params.entryPrice - Entry price, used to classify a trigger the exchange left unnamed
|
|
296
|
+
* @returns The normalized trigger order, or undefined when the order is not a trigger
|
|
297
|
+
*/
|
|
298
|
+
export function adaptPositionTriggerOrderFromSDK(params) {
|
|
299
|
+
const { rawOrder, positionSize, entryPrice } = params;
|
|
300
|
+
const orderType = adaptTriggerOrderTypeFromSDK(rawOrder.orderType);
|
|
301
|
+
// HyperLiquid uses '' for "no trigger price", so `||` (not `??`) is required.
|
|
302
|
+
const triggerPrice = rawOrder.triggerPx || rawOrder.limitPx || '0';
|
|
303
|
+
// Same rule as the WebSocket path: an unnamed trigger keeps its recoverable
|
|
304
|
+
// direction and leaves its execution mode unstated, so both transports
|
|
305
|
+
// report the same set of orders.
|
|
306
|
+
const direction = orderType
|
|
307
|
+
? getTriggerDirection(orderType)
|
|
308
|
+
: classifyTriggerDirection({ triggerPrice, entryPrice, positionSize });
|
|
309
|
+
if (!direction) {
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
const absolutePositionSize = Math.abs(parseFloat(positionSize || '0'));
|
|
313
|
+
const rawSize = Math.abs(parseFloat(rawOrder.sz || '0'));
|
|
314
|
+
// Position-bound TP/SL carries size 0, meaning the whole position.
|
|
315
|
+
const size = rawSize > 0 ? rawSize : absolutePositionSize;
|
|
316
|
+
return {
|
|
317
|
+
orderId: rawOrder.oid.toString(),
|
|
318
|
+
direction,
|
|
319
|
+
orderType,
|
|
320
|
+
triggerPrice,
|
|
321
|
+
size: size.toString(),
|
|
322
|
+
isPartial: rawSize > 0 && absolutePositionSize > 0 && rawSize < absolutePositionSize,
|
|
323
|
+
reduceOnly: Boolean(rawOrder.reduceOnly),
|
|
324
|
+
};
|
|
325
|
+
}
|
|
171
326
|
export function adaptMarketFromSDK(sdkMarket) {
|
|
172
327
|
return {
|
|
173
328
|
name: sdkMarket.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hyperLiquidAdapter.mjs","sourceRoot":"","sources":["../../src/utils/hyperLiquidAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { hasProperty, Hex, isHexString } from '@metamask/utils';\n\nimport { HIP3_ASSET_ID_CONFIG } from '../constants/hyperLiquidConfig.js';\nimport { DECIMAL_PRECISION_CONFIG } from '../constants/perpsConfig.js';\nimport type {\n AssetPosition,\n FrontendOrder,\n ClearinghouseStateResponse,\n MetaResponse,\n SDKOrderParams,\n} from '../types/hyperliquid-types.js';\nimport type {\n AccountState,\n MarketInfo,\n Order,\n OrderParams as PerpsOrderParams,\n Position,\n RawLedgerUpdate,\n UserHistoryItem,\n} from '../types/index.js';\nimport {\n countSignificantFigures,\n roundToSignificantFigures,\n} from './significantFigures.js';\n\ntype FrontendOrderWithParentTpsl = FrontendOrder & {\n takeProfitPrice?: unknown;\n stopLossPrice?: unknown;\n takeProfitOrderId?: unknown;\n stopLossOrderId?: unknown;\n};\n\nconst readOptionalString = (value: unknown): string | undefined =>\n typeof value === 'string' && value.length > 0 ? value : undefined;\n\nconst readOptionalOrderId = (value: unknown): string | undefined => {\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value.toString();\n }\n\n return undefined;\n};\n\nconst getParentTpslMetadata = (\n rawOrder: FrontendOrderWithParentTpsl,\n): {\n takeProfitPrice?: string;\n stopLossPrice?: string;\n takeProfitOrderId?: string;\n stopLossOrderId?: string;\n} => ({\n takeProfitPrice: readOptionalString(rawOrder.takeProfitPrice),\n stopLossPrice: readOptionalString(rawOrder.stopLossPrice),\n takeProfitOrderId: readOptionalOrderId(rawOrder.takeProfitOrderId),\n stopLossOrderId: readOptionalOrderId(rawOrder.stopLossOrderId),\n});\n\n/**\n * HyperLiquid SDK Adapter Utilities\n *\n * These functions transform between MetaMask Perps API types and HyperLiquid SDK types.\n * The SDK uses cryptic property names for efficiency, but our API uses descriptive names\n * to provide a consistent interface across different perps protocols.\n */\n\nexport function adaptOrderToSDK(\n order: PerpsOrderParams,\n symbolToAssetId: Map<string, number>,\n): SDKOrderParams {\n const assetId = symbolToAssetId.get(order.symbol);\n if (assetId === undefined) {\n const availableDexs = new Set<string>();\n symbolToAssetId.forEach((_, symbol) => {\n if (symbol.includes(':')) {\n const dex = symbol.split(':')[0];\n availableDexs.add(dex);\n }\n });\n\n const dexHint =\n availableDexs.size > 0\n ? ` Available HIP-3 DEXs: ${Array.from(availableDexs).join(', ')}`\n : ' No HIP-3 DEXs currently available.';\n\n throw new Error(\n `Asset ${order.symbol} not found in asset mapping.${dexHint} Check console logs for \"HyperLiquidProvider: Asset mapping built\" to see available assets.`,\n );\n }\n\n return {\n a: assetId,\n b: order.isBuy,\n p: order.price ?? '0',\n s: order.size,\n r: order.reduceOnly ?? false,\n t:\n order.orderType === 'limit'\n ? {\n limit: { tif: 'Gtc' },\n }\n : {\n limit: { tif: 'FrontendMarket' },\n },\n c:\n order.clientOrderId && isHexString(order.clientOrderId)\n ? (order.clientOrderId as Hex)\n : undefined,\n };\n}\n\nexport function adaptPositionFromSDK(assetPosition: AssetPosition): Position {\n const pos = assetPosition.position;\n return {\n symbol: pos.coin,\n size: pos.szi,\n entryPrice: pos.entryPx,\n positionValue: pos.positionValue,\n unrealizedPnl: pos.unrealizedPnl,\n marginUsed: pos.marginUsed,\n leverage: {\n type: pos.leverage.type,\n value: pos.leverage.value,\n rawUsd:\n pos.leverage.type === 'isolated' ? pos.leverage.rawUsd : undefined,\n },\n liquidationPrice: pos.liquidationPx,\n maxLeverage: pos.maxLeverage,\n returnOnEquity: pos.returnOnEquity,\n cumulativeFunding: pos.cumFunding,\n takeProfitCount: 0,\n stopLossCount: 0,\n };\n}\n\nexport function adaptOrderFromSDK(\n rawOrder: FrontendOrder,\n position?: Position,\n): Order {\n // TODO: Remove this widened boundary type when FrontendOrder includes\n // takeProfitPrice/stopLossPrice and takeProfitOrderId/stopLossOrderId.\n const parentTpslMetadata = getParentTpslMetadata(\n rawOrder as FrontendOrderWithParentTpsl,\n );\n\n // Extract basic fields with appropriate conversions\n const orderId = rawOrder.oid.toString();\n const symbol = rawOrder.coin;\n const side: 'buy' | 'sell' = rawOrder.side === 'B' ? 'buy' : 'sell';\n const detailedOrderType = rawOrder.orderType;\n const { isTrigger } = rawOrder;\n const { reduceOnly } = rawOrder;\n\n let orderType: 'limit' | 'market' = 'market';\n if (detailedOrderType.toLowerCase().includes('limit') || rawOrder.limitPx) {\n orderType = 'limit';\n }\n\n const price = rawOrder.limitPx || rawOrder.triggerPx || '0';\n\n let size = rawOrder.sz;\n let originalSize = rawOrder.origSz || size;\n\n let currentSize = parseFloat(size);\n let origSize = parseFloat(originalSize);\n\n if (rawOrder.isPositionTpsl && origSize === 0 && position) {\n const absPositionSize = Math.abs(parseFloat(position.size));\n currentSize = absPositionSize;\n origSize = absPositionSize;\n size = absPositionSize.toString();\n originalSize = absPositionSize.toString();\n }\n\n const filledSize = origSize - currentSize;\n\n let takeProfitPrice: string | undefined;\n let stopLossPrice: string | undefined;\n let takeProfitOrderId: string | undefined;\n let stopLossOrderId: string | undefined;\n\n // TODO: We assume that there can only be 1 TP and 1 SL as children but there can be several TPSLs as children\n if (rawOrder.children && rawOrder.children.length > 0) {\n rawOrder.children.forEach((child) => {\n if (child.isTrigger && child.orderType) {\n if (child.orderType.includes('Take Profit')) {\n // HyperLiquid represents \"no trigger price\" as an empty string, not\n // null/undefined, so `||` (not `??`) is required to fall back to\n // limitPx when triggerPx is ''.\n takeProfitPrice = child.triggerPx || child.limitPx;\n takeProfitOrderId = child.oid.toString();\n } else if (child.orderType.includes('Stop')) {\n stopLossPrice = child.triggerPx || child.limitPx;\n stopLossOrderId = child.oid.toString();\n }\n }\n });\n }\n\n // Fallback: preserve parent-level TP/SL metadata when children are absent.\n takeProfitPrice ??= parentTpslMetadata.takeProfitPrice;\n stopLossPrice ??= parentTpslMetadata.stopLossPrice;\n takeProfitOrderId ??= parentTpslMetadata.takeProfitOrderId;\n stopLossOrderId ??= parentTpslMetadata.stopLossOrderId;\n\n // Build the order object\n const order: Order = {\n orderId,\n symbol,\n side,\n orderType,\n size,\n originalSize,\n price,\n filledSize: filledSize.toString(),\n remainingSize: size,\n status: 'open' as const,\n timestamp: rawOrder.timestamp,\n detailedOrderType,\n isTrigger,\n reduceOnly,\n };\n\n if (typeof rawOrder.isPositionTpsl === 'boolean') {\n order.isPositionTpsl = rawOrder.isPositionTpsl;\n }\n\n if (takeProfitPrice) {\n order.takeProfitPrice = takeProfitPrice;\n order.takeProfitOrderId = takeProfitOrderId;\n }\n if (stopLossPrice) {\n order.stopLossPrice = stopLossPrice;\n order.stopLossOrderId = stopLossOrderId;\n }\n if (rawOrder.triggerPx) {\n order.triggerPrice = rawOrder.triggerPx;\n }\n\n return order;\n}\n\nexport function adaptMarketFromSDK(\n sdkMarket: MetaResponse['universe'][number],\n): MarketInfo {\n return {\n name: sdkMarket.name,\n szDecimals: sdkMarket.szDecimals,\n maxLeverage: sdkMarket.maxLeverage,\n marginTableId: sdkMarket.marginTableId,\n onlyIsolated: sdkMarket.onlyIsolated,\n isDelisted: sdkMarket.isDelisted,\n };\n}\n\n// Perps-only account adapter. Spot balances are layered on afterwards by\n// addSpotBalanceToAccountState, which enforces the USDC-only policy via\n// SPOT_COLLATERAL_COINS. Keeping spot logic out of here preserves a single\n// source of truth for spot balance math.\nexport function adaptAccountStateFromSDK(\n perpsState: ClearinghouseStateResponse,\n): AccountState {\n const { totalUnrealizedPnl, weightedReturnOnEquity } =\n perpsState.assetPositions.reduce(\n (acc, assetPos: AssetPosition) => {\n const unrealizedPnl = parseFloat(\n assetPos.position.unrealizedPnl || '0',\n );\n const marginUsed = parseFloat(assetPos.position.marginUsed || '0');\n const returnOnEquity = parseFloat(\n assetPos.position.returnOnEquity || '0',\n );\n acc.totalUnrealizedPnl += unrealizedPnl;\n acc.weightedReturnOnEquity += returnOnEquity * marginUsed;\n return acc;\n },\n {\n totalUnrealizedPnl: 0,\n weightedReturnOnEquity: 0,\n },\n );\n const totalMarginUsed = parseFloat(\n perpsState.marginSummary.totalMarginUsed || '0',\n );\n const totalReturnOnEquityPercentage =\n totalMarginUsed > 0\n ? ((weightedReturnOnEquity / totalMarginUsed) * 100).toString()\n : '0';\n\n const perpsBalance = parseFloat(perpsState.marginSummary.accountValue);\n\n const withdrawable = perpsState.withdrawable || '0';\n const accountState: AccountState = {\n spendableBalance: withdrawable,\n withdrawableBalance: withdrawable,\n totalBalance: perpsBalance.toString() || '0',\n marginUsed: perpsState.marginSummary.totalMarginUsed || '0',\n unrealizedPnl: totalUnrealizedPnl.toString() || '0',\n returnOnEquity: totalReturnOnEquityPercentage || '0',\n };\n\n return accountState;\n}\n\nexport function buildAssetMapping(params: {\n metaUniverse: MetaResponse['universe'];\n dex?: string | null;\n perpDexIndex: number;\n}): {\n symbolToAssetId: Map<string, number>;\n assetIdToSymbol: Map<number, string>;\n} {\n const { metaUniverse, perpDexIndex } = params;\n const symbolToAssetId = new Map<string, number>();\n const assetIdToSymbol = new Map<number, string>();\n\n metaUniverse.forEach((asset, index) => {\n const assetId = calculateHip3AssetId(perpDexIndex, index);\n symbolToAssetId.set(asset.name, assetId);\n assetIdToSymbol.set(assetId, asset.name);\n });\n\n return { symbolToAssetId, assetIdToSymbol };\n}\n\nexport function formatHyperLiquidPrice(params: {\n price: string | number;\n szDecimals: number;\n}): string {\n const { price, szDecimals } = params;\n const priceNum = typeof price === 'string' ? parseFloat(price) : price;\n\n if (Number.isInteger(priceNum)) {\n return priceNum.toString();\n }\n\n const maxDecimalPlaces =\n DECIMAL_PRECISION_CONFIG.MaxPriceDecimals - szDecimals;\n\n let formattedPrice = priceNum.toFixed(maxDecimalPlaces);\n formattedPrice = parseFloat(formattedPrice).toString();\n\n const significantDigits = countSignificantFigures(formattedPrice);\n\n if (significantDigits > DECIMAL_PRECISION_CONFIG.MaxSignificantFigures) {\n formattedPrice = roundToSignificantFigures(formattedPrice);\n }\n\n return formattedPrice;\n}\n\nexport function formatHyperLiquidSize(params: {\n size: string | number;\n szDecimals: number;\n}): string {\n const { size, szDecimals } = params;\n const number = typeof size === 'string' ? parseFloat(size) : size;\n\n if (isNaN(number)) {\n return '0';\n }\n\n const formatted = number.toFixed(szDecimals);\n\n if (!formatted.includes('.')) {\n return formatted;\n }\n\n return formatted.replace(/\\.?0+$/u, '');\n}\n\nexport function calculatePositionSize(params: {\n usdValue: number;\n leverage: number;\n assetPrice: number;\n}): number {\n const { usdValue, leverage, assetPrice } = params;\n return (usdValue * leverage) / assetPrice;\n}\n\nexport function calculateHip3AssetId(\n perpDexIndex: number,\n indexInMeta: number,\n): number {\n if (perpDexIndex === 0) {\n return indexInMeta;\n }\n return (\n HIP3_ASSET_ID_CONFIG.BaseAssetId +\n perpDexIndex * HIP3_ASSET_ID_CONFIG.DexMultiplier +\n indexInMeta\n );\n}\n\nexport function parseAssetName(assetName: string): {\n dex: string | null;\n symbol: string;\n} {\n const colonIndex = assetName.indexOf(':');\n if (colonIndex === -1) {\n return { dex: null, symbol: assetName };\n }\n return {\n dex: assetName.substring(0, colonIndex),\n symbol: assetName.substring(colonIndex + 1),\n };\n}\n\nexport function adaptHyperLiquidLedgerUpdateToUserHistoryItem(\n rawLedgerUpdates: RawLedgerUpdate[],\n): UserHistoryItem[] {\n return (rawLedgerUpdates || [])\n .filter((update) => {\n if (update.delta.type === 'deposit') {\n return true;\n }\n if (update.delta.type === 'withdraw') {\n return true;\n }\n if (update.delta.type === 'internalTransfer') {\n const usdc = Number.parseFloat(update.delta.usdc ?? '0');\n if (Number.isNaN(usdc)) {\n return false;\n }\n return usdc > 0;\n }\n return false;\n })\n .map((update) => {\n let amount = '0';\n let asset = 'USDC';\n\n if (hasProperty(update.delta, 'usdc') && update.delta.usdc) {\n amount = Math.abs(parseFloat(update.delta.usdc)).toString();\n }\n if (\n hasProperty(update.delta, 'coin') &&\n typeof update.delta.coin === 'string'\n ) {\n asset = update.delta.coin;\n }\n\n return {\n id: `history-${update.hash}`,\n timestamp: update.time,\n amount,\n asset,\n txHash: update.hash,\n status: 'completed' as const,\n type: update.delta.type === 'withdraw' ? 'withdrawal' : 'deposit',\n details: {\n source: '',\n bridgeContract: undefined,\n recipient: undefined,\n blockNumber: undefined,\n chainId: undefined,\n synthetic: undefined,\n },\n };\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hyperLiquidAdapter.mjs","sourceRoot":"","sources":["../../src/utils/hyperLiquidAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { hasProperty, Hex, isHexString } from '@metamask/utils';\n\nimport {\n BASIS_POINTS_DIVISOR,\n HIP3_ASSET_ID_CONFIG,\n} from '../constants/hyperLiquidConfig.js';\nimport {\n DECIMAL_PRECISION_CONFIG,\n ORDER_SLIPPAGE_CONFIG,\n} from '../constants/perpsConfig.js';\nimport { PERPS_ERROR_CODES } from '../perpsErrorCodes.js';\nimport type {\n AssetPosition,\n FrontendOrder,\n ClearinghouseStateResponse,\n MetaResponse,\n SDKOrderParams,\n} from '../types/hyperliquid-types.js';\nimport type {\n AccountState,\n MarketInfo,\n Order,\n OrderParams as PerpsOrderParams,\n Position,\n PositionTriggerOrder,\n RawLedgerUpdate,\n UserHistoryItem,\n} from '../types/index.js';\nimport type { TpslLinkage, TriggerOrderType } from '../types/perps-types.js';\nimport {\n buildTriggerOrderType,\n classifyTriggerDirection,\n getTriggerDirection,\n getTriggerExecution,\n isLimitExecutionOrderType,\n isTriggerOrderType,\n toSDKTimeInForce,\n} from './orderTypes.js';\nimport {\n countSignificantFigures,\n roundToSignificantFigures,\n} from './significantFigures.js';\n\ntype FrontendOrderWithParentTpsl = FrontendOrder & {\n takeProfitPrice?: unknown;\n stopLossPrice?: unknown;\n takeProfitOrderId?: unknown;\n stopLossOrderId?: unknown;\n};\n\nconst readOptionalString = (value: unknown): string | undefined =>\n typeof value === 'string' && value.length > 0 ? value : undefined;\n\nconst readOptionalOrderId = (value: unknown): string | undefined => {\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value.toString();\n }\n\n return undefined;\n};\n\nconst getParentTpslMetadata = (\n rawOrder: FrontendOrderWithParentTpsl,\n): {\n takeProfitPrice?: string;\n stopLossPrice?: string;\n takeProfitOrderId?: string;\n stopLossOrderId?: string;\n} => ({\n takeProfitPrice: readOptionalString(rawOrder.takeProfitPrice),\n stopLossPrice: readOptionalString(rawOrder.stopLossPrice),\n takeProfitOrderId: readOptionalOrderId(rawOrder.takeProfitOrderId),\n stopLossOrderId: readOptionalOrderId(rawOrder.stopLossOrderId),\n});\n\n/**\n * HyperLiquid SDK Adapter Utilities\n *\n * These functions transform between MetaMask Perps API types and HyperLiquid SDK types.\n * The SDK uses cryptic property names for efficiency, but our API uses descriptive names\n * to provide a consistent interface across different perps protocols.\n */\n\nexport function adaptOrderToSDK(\n order: PerpsOrderParams,\n symbolToAssetId: Map<string, number>,\n): SDKOrderParams {\n const assetId = symbolToAssetId.get(order.symbol);\n if (assetId === undefined) {\n const availableDexs = new Set<string>();\n symbolToAssetId.forEach((_, symbol) => {\n if (symbol.includes(':')) {\n const dex = symbol.split(':')[0];\n availableDexs.add(dex);\n }\n });\n\n const dexHint =\n availableDexs.size > 0\n ? ` Available HIP-3 DEXs: ${Array.from(availableDexs).join(', ')}`\n : ' No HIP-3 DEXs currently available.';\n\n throw new Error(\n `Asset ${order.symbol} not found in asset mapping.${dexHint} Check console logs for \"HyperLiquidProvider: Asset mapping built\" to see available assets.`,\n );\n }\n\n return {\n a: assetId,\n b: order.isBuy,\n p: order.price ?? resolveTriggerCapPrice(order) ?? '0',\n s: order.size,\n r: order.reduceOnly ?? false,\n t: adaptOrderTypeToSDK(order),\n c:\n order.clientOrderId && isHexString(order.clientOrderId)\n ? (order.clientOrderId as Hex)\n : undefined,\n };\n}\n\n/**\n * Derive the slippage cap a market-on-trigger order submits as its price.\n *\n * A `stop_market` / `take_profit_market` order legitimately carries no limit\n * price, but the SDK still requires a positive `p` — it is the cap the order\n * fills against once the trigger fires, not a resting price. Sending `'0'`\n * fails SDK validation before the request is ever made.\n *\n * The cap follows the order's own tolerance, matching `calculateOrderPriceAndSize`\n * on the `placeOrder` path, so the same order priced through either route gets\n * the same execution bound.\n *\n * @param order - Order params carrying the placement type, trigger price, and\n * slippage tolerance.\n * @returns The formatted cap price, or undefined when the order needs no cap.\n */\nfunction resolveTriggerCapPrice(order: PerpsOrderParams): string | undefined {\n if (\n !isTriggerOrderType(order.orderType) ||\n isLimitExecutionOrderType(order.orderType) ||\n !order.triggerPrice\n ) {\n return undefined;\n }\n\n const triggerPrice = parseFloat(order.triggerPrice);\n if (!Number.isFinite(triggerPrice)) {\n return undefined;\n }\n\n // Accept the deprecated decimal `slippage` too, normalizing it to bps the way\n // `placeOrder` does, so neither spelling silently falls back to the default.\n const effectiveBps =\n order.maxSlippageBps ??\n (typeof order.slippage === 'number'\n ? Math.round(order.slippage * BASIS_POINTS_DIVISOR)\n : undefined) ??\n ORDER_SLIPPAGE_CONFIG.DefaultTpslSlippageBps;\n\n // Buying pays up to the cap, selling accepts down to it.\n const slippage = effectiveBps / BASIS_POINTS_DIVISOR;\n const capPrice = order.isBuy\n ? triggerPrice * (1 + slippage)\n : triggerPrice * (1 - slippage);\n\n return capPrice.toString();\n}\n\n/**\n * Map a placement type onto the SDK's order-type field.\n *\n * @param order - Order params carrying the placement type and trigger price\n * @returns The SDK order-type field\n */\nfunction adaptOrderTypeToSDK(order: PerpsOrderParams): SDKOrderParams['t'] {\n if (isTriggerOrderType(order.orderType)) {\n if (order.timeInForce !== undefined) {\n throw new Error(PERPS_ERROR_CODES.ORDER_TIME_IN_FORCE_NOT_SUPPORTED);\n }\n if (!order.triggerPrice) {\n throw new Error(PERPS_ERROR_CODES.ORDER_TRIGGER_PRICE_REQUIRED);\n }\n\n return {\n trigger: {\n isMarket: !isLimitExecutionOrderType(order.orderType),\n triggerPx: order.triggerPrice,\n tpsl: getTriggerDirection(order.orderType) === 'stop' ? 'sl' : 'tp',\n },\n };\n }\n\n if (order.orderType === 'limit') {\n return { limit: { tif: toSDKTimeInForce(order.timeInForce) } };\n }\n if (order.timeInForce !== undefined) {\n throw new Error(PERPS_ERROR_CODES.ORDER_TIME_IN_FORCE_NOT_SUPPORTED);\n }\n return { limit: { tif: 'FrontendMarket' } };\n}\n\n/**\n * Map the provider-agnostic TP/SL linkage onto HyperLiquid's grouping vocabulary.\n *\n * @param linkage - How the attached TP/SL is linked.\n * @returns The HyperLiquid grouping value.\n */\nexport function adaptTpslLinkageToGrouping(\n linkage: TpslLinkage,\n): 'na' | 'normalTpsl' | 'positionTpsl' {\n switch (linkage) {\n case 'position':\n return 'positionTpsl';\n case 'order':\n return 'normalTpsl';\n default:\n return 'na';\n }\n}\n\nexport function adaptPositionFromSDK(assetPosition: AssetPosition): Position {\n const pos = assetPosition.position;\n return {\n symbol: pos.coin,\n size: pos.szi,\n entryPrice: pos.entryPx,\n positionValue: pos.positionValue,\n unrealizedPnl: pos.unrealizedPnl,\n marginUsed: pos.marginUsed,\n leverage: {\n type: pos.leverage.type,\n value: pos.leverage.value,\n rawUsd:\n pos.leverage.type === 'isolated' ? pos.leverage.rawUsd : undefined,\n },\n liquidationPrice: pos.liquidationPx,\n maxLeverage: pos.maxLeverage,\n returnOnEquity: pos.returnOnEquity,\n cumulativeFunding: pos.cumFunding,\n takeProfitCount: 0,\n stopLossCount: 0,\n };\n}\n\nexport function adaptOrderFromSDK(\n rawOrder: FrontendOrder,\n position?: Position,\n): Order {\n // TODO: Remove this widened boundary type when FrontendOrder includes\n // takeProfitPrice/stopLossPrice and takeProfitOrderId/stopLossOrderId.\n const parentTpslMetadata = getParentTpslMetadata(\n rawOrder as FrontendOrderWithParentTpsl,\n );\n\n // Extract basic fields with appropriate conversions\n const orderId = rawOrder.oid.toString();\n const symbol = rawOrder.coin;\n const side: 'buy' | 'sell' = rawOrder.side === 'B' ? 'buy' : 'sell';\n const detailedOrderType = rawOrder.orderType;\n const { isTrigger } = rawOrder;\n const { reduceOnly } = rawOrder;\n\n const triggerOrderType = adaptTriggerOrderTypeFromSDK(detailedOrderType);\n\n let orderType: 'limit' | 'market' = 'market';\n if (triggerOrderType) {\n // Trigger orders always carry a limitPx (the slippage cap for\n // market-on-trigger execution), so the placement type is the only reliable\n // source for how the order actually executes.\n orderType = getTriggerExecution(triggerOrderType);\n } else if (\n detailedOrderType.toLowerCase().includes('limit') ||\n rawOrder.limitPx\n ) {\n orderType = 'limit';\n }\n\n const price = rawOrder.limitPx || rawOrder.triggerPx || '0';\n\n let size = rawOrder.sz;\n let originalSize = rawOrder.origSz || size;\n\n let currentSize = parseFloat(size);\n let origSize = parseFloat(originalSize);\n\n if (rawOrder.isPositionTpsl && origSize === 0 && position) {\n const absPositionSize = Math.abs(parseFloat(position.size));\n currentSize = absPositionSize;\n origSize = absPositionSize;\n size = absPositionSize.toString();\n originalSize = absPositionSize.toString();\n }\n\n const filledSize = origSize - currentSize;\n\n let takeProfitPrice: string | undefined;\n let stopLossPrice: string | undefined;\n let takeProfitOrderId: string | undefined;\n let stopLossOrderId: string | undefined;\n\n // TODO: We assume that there can only be 1 TP and 1 SL as children but there can be several TPSLs as children\n if (rawOrder.children && rawOrder.children.length > 0) {\n rawOrder.children.forEach((child) => {\n if (child.isTrigger && child.orderType) {\n if (child.orderType.includes('Take Profit')) {\n // HyperLiquid represents \"no trigger price\" as an empty string, not\n // null/undefined, so `||` (not `??`) is required to fall back to\n // limitPx when triggerPx is ''.\n takeProfitPrice = child.triggerPx || child.limitPx;\n takeProfitOrderId = child.oid.toString();\n } else if (child.orderType.includes('Stop')) {\n stopLossPrice = child.triggerPx || child.limitPx;\n stopLossOrderId = child.oid.toString();\n }\n }\n });\n }\n\n // Fallback: preserve parent-level TP/SL metadata when children are absent.\n takeProfitPrice ??= parentTpslMetadata.takeProfitPrice;\n stopLossPrice ??= parentTpslMetadata.stopLossPrice;\n takeProfitOrderId ??= parentTpslMetadata.takeProfitOrderId;\n stopLossOrderId ??= parentTpslMetadata.stopLossOrderId;\n\n // Build the order object\n const order: Order = {\n orderId,\n symbol,\n side,\n orderType,\n size,\n originalSize,\n price,\n filledSize: filledSize.toString(),\n remainingSize: size,\n status: 'open' as const,\n timestamp: rawOrder.timestamp,\n detailedOrderType,\n isTrigger,\n reduceOnly,\n };\n\n if (typeof rawOrder.isPositionTpsl === 'boolean') {\n order.isPositionTpsl = rawOrder.isPositionTpsl;\n }\n\n if (takeProfitPrice) {\n order.takeProfitPrice = takeProfitPrice;\n order.takeProfitOrderId = takeProfitOrderId;\n }\n if (stopLossPrice) {\n order.stopLossPrice = stopLossPrice;\n order.stopLossOrderId = stopLossOrderId;\n }\n if (rawOrder.triggerPx) {\n order.triggerPrice = rawOrder.triggerPx;\n }\n\n if (triggerOrderType) {\n order.triggerOrderType = triggerOrderType;\n }\n\n return order;\n}\n\n/**\n * Map HyperLiquid's human-readable order type string onto the provider-agnostic\n * trigger placement type.\n *\n * @param detailedOrderType - HyperLiquid `orderType` string (e.g. `'Stop Limit'`)\n * @returns The normalized trigger placement type, or undefined for non-trigger orders\n */\nexport function adaptTriggerOrderTypeFromSDK(\n detailedOrderType: string | undefined,\n): TriggerOrderType | undefined {\n if (!detailedOrderType) {\n return undefined;\n }\n\n const isTakeProfit = detailedOrderType.includes('Take Profit');\n const isStop = detailedOrderType.includes('Stop');\n\n if (!isTakeProfit && !isStop) {\n return undefined;\n }\n\n return buildTriggerOrderType({\n direction: isTakeProfit ? 'take_profit' : 'stop',\n execution: detailedOrderType.includes('Limit') ? 'limit' : 'market',\n });\n}\n\n/**\n * Build the position-state view of a trigger order attached to a position.\n *\n * HyperLiquid encodes \"the whole position\" as size `0` for position-bound TP/SL,\n * which is resolved here against the position size so consumers always see a\n * concrete quantity and can tell partial triggers apart.\n *\n * @param params - Mapping parameters\n * @param params.rawOrder - Raw HyperLiquid frontend order\n * @param params.positionSize - Signed or unsigned position size\n * @param params.entryPrice - Entry price, used to classify a trigger the exchange left unnamed\n * @returns The normalized trigger order, or undefined when the order is not a trigger\n */\nexport function adaptPositionTriggerOrderFromSDK(params: {\n rawOrder: Pick<\n FrontendOrder,\n 'oid' | 'orderType' | 'triggerPx' | 'limitPx' | 'sz' | 'reduceOnly'\n >;\n positionSize: string;\n entryPrice?: string;\n}): PositionTriggerOrder | undefined {\n const { rawOrder, positionSize, entryPrice } = params;\n\n const orderType = adaptTriggerOrderTypeFromSDK(rawOrder.orderType);\n\n // HyperLiquid uses '' for \"no trigger price\", so `||` (not `??`) is required.\n const triggerPrice = rawOrder.triggerPx || rawOrder.limitPx || '0';\n\n // Same rule as the WebSocket path: an unnamed trigger keeps its recoverable\n // direction and leaves its execution mode unstated, so both transports\n // report the same set of orders.\n const direction = orderType\n ? getTriggerDirection(orderType)\n : classifyTriggerDirection({ triggerPrice, entryPrice, positionSize });\n\n if (!direction) {\n return undefined;\n }\n const absolutePositionSize = Math.abs(parseFloat(positionSize || '0'));\n const rawSize = Math.abs(parseFloat(rawOrder.sz || '0'));\n\n // Position-bound TP/SL carries size 0, meaning the whole position.\n const size = rawSize > 0 ? rawSize : absolutePositionSize;\n\n return {\n orderId: rawOrder.oid.toString(),\n direction,\n orderType,\n triggerPrice,\n size: size.toString(),\n isPartial:\n rawSize > 0 && absolutePositionSize > 0 && rawSize < absolutePositionSize,\n reduceOnly: Boolean(rawOrder.reduceOnly),\n };\n}\n\nexport function adaptMarketFromSDK(\n sdkMarket: MetaResponse['universe'][number],\n): MarketInfo {\n return {\n name: sdkMarket.name,\n szDecimals: sdkMarket.szDecimals,\n maxLeverage: sdkMarket.maxLeverage,\n marginTableId: sdkMarket.marginTableId,\n onlyIsolated: sdkMarket.onlyIsolated,\n isDelisted: sdkMarket.isDelisted,\n };\n}\n\n// Perps-only account adapter. Spot balances are layered on afterwards by\n// addSpotBalanceToAccountState, which enforces the USDC-only policy via\n// SPOT_COLLATERAL_COINS. Keeping spot logic out of here preserves a single\n// source of truth for spot balance math.\nexport function adaptAccountStateFromSDK(\n perpsState: ClearinghouseStateResponse,\n): AccountState {\n const { totalUnrealizedPnl, weightedReturnOnEquity } =\n perpsState.assetPositions.reduce(\n (acc, assetPos: AssetPosition) => {\n const unrealizedPnl = parseFloat(\n assetPos.position.unrealizedPnl || '0',\n );\n const marginUsed = parseFloat(assetPos.position.marginUsed || '0');\n const returnOnEquity = parseFloat(\n assetPos.position.returnOnEquity || '0',\n );\n acc.totalUnrealizedPnl += unrealizedPnl;\n acc.weightedReturnOnEquity += returnOnEquity * marginUsed;\n return acc;\n },\n {\n totalUnrealizedPnl: 0,\n weightedReturnOnEquity: 0,\n },\n );\n const totalMarginUsed = parseFloat(\n perpsState.marginSummary.totalMarginUsed || '0',\n );\n const totalReturnOnEquityPercentage =\n totalMarginUsed > 0\n ? ((weightedReturnOnEquity / totalMarginUsed) * 100).toString()\n : '0';\n\n const perpsBalance = parseFloat(perpsState.marginSummary.accountValue);\n\n const withdrawable = perpsState.withdrawable || '0';\n const accountState: AccountState = {\n spendableBalance: withdrawable,\n withdrawableBalance: withdrawable,\n totalBalance: perpsBalance.toString() || '0',\n marginUsed: perpsState.marginSummary.totalMarginUsed || '0',\n unrealizedPnl: totalUnrealizedPnl.toString() || '0',\n returnOnEquity: totalReturnOnEquityPercentage || '0',\n };\n\n return accountState;\n}\n\nexport function buildAssetMapping(params: {\n metaUniverse: MetaResponse['universe'];\n dex?: string | null;\n perpDexIndex: number;\n}): {\n symbolToAssetId: Map<string, number>;\n assetIdToSymbol: Map<number, string>;\n} {\n const { metaUniverse, perpDexIndex } = params;\n const symbolToAssetId = new Map<string, number>();\n const assetIdToSymbol = new Map<number, string>();\n\n metaUniverse.forEach((asset, index) => {\n const assetId = calculateHip3AssetId(perpDexIndex, index);\n symbolToAssetId.set(asset.name, assetId);\n assetIdToSymbol.set(assetId, asset.name);\n });\n\n return { symbolToAssetId, assetIdToSymbol };\n}\n\nexport function formatHyperLiquidPrice(params: {\n price: string | number;\n szDecimals: number;\n}): string {\n const { price, szDecimals } = params;\n const priceNum = typeof price === 'string' ? parseFloat(price) : price;\n\n if (Number.isInteger(priceNum)) {\n return priceNum.toString();\n }\n\n const maxDecimalPlaces =\n DECIMAL_PRECISION_CONFIG.MaxPriceDecimals - szDecimals;\n\n let formattedPrice = priceNum.toFixed(maxDecimalPlaces);\n formattedPrice = parseFloat(formattedPrice).toString();\n\n const significantDigits = countSignificantFigures(formattedPrice);\n\n if (significantDigits > DECIMAL_PRECISION_CONFIG.MaxSignificantFigures) {\n formattedPrice = roundToSignificantFigures(formattedPrice);\n }\n\n return formattedPrice;\n}\n\nexport function formatHyperLiquidSize(params: {\n size: string | number;\n szDecimals: number;\n}): string {\n const { size, szDecimals } = params;\n const number = typeof size === 'string' ? parseFloat(size) : size;\n\n if (isNaN(number)) {\n return '0';\n }\n\n const formatted = number.toFixed(szDecimals);\n\n if (!formatted.includes('.')) {\n return formatted;\n }\n\n return formatted.replace(/\\.?0+$/u, '');\n}\n\nexport function calculatePositionSize(params: {\n usdValue: number;\n leverage: number;\n assetPrice: number;\n}): number {\n const { usdValue, leverage, assetPrice } = params;\n return (usdValue * leverage) / assetPrice;\n}\n\nexport function calculateHip3AssetId(\n perpDexIndex: number,\n indexInMeta: number,\n): number {\n if (perpDexIndex === 0) {\n return indexInMeta;\n }\n return (\n HIP3_ASSET_ID_CONFIG.BaseAssetId +\n perpDexIndex * HIP3_ASSET_ID_CONFIG.DexMultiplier +\n indexInMeta\n );\n}\n\nexport function parseAssetName(assetName: string): {\n dex: string | null;\n symbol: string;\n} {\n const colonIndex = assetName.indexOf(':');\n if (colonIndex === -1) {\n return { dex: null, symbol: assetName };\n }\n return {\n dex: assetName.substring(0, colonIndex),\n symbol: assetName.substring(colonIndex + 1),\n };\n}\n\nexport function adaptHyperLiquidLedgerUpdateToUserHistoryItem(\n rawLedgerUpdates: RawLedgerUpdate[],\n): UserHistoryItem[] {\n return (rawLedgerUpdates || [])\n .filter((update) => {\n if (update.delta.type === 'deposit') {\n return true;\n }\n if (update.delta.type === 'withdraw') {\n return true;\n }\n if (update.delta.type === 'internalTransfer') {\n const usdc = Number.parseFloat(update.delta.usdc ?? '0');\n if (Number.isNaN(usdc)) {\n return false;\n }\n return usdc > 0;\n }\n return false;\n })\n .map((update) => {\n let amount = '0';\n let asset = 'USDC';\n\n if (hasProperty(update.delta, 'usdc') && update.delta.usdc) {\n amount = Math.abs(parseFloat(update.delta.usdc)).toString();\n }\n if (\n hasProperty(update.delta, 'coin') &&\n typeof update.delta.coin === 'string'\n ) {\n asset = update.delta.coin;\n }\n\n return {\n id: `history-${update.hash}`,\n timestamp: update.time,\n amount,\n asset,\n txHash: update.hash,\n status: 'completed' as const,\n type: update.delta.type === 'withdraw' ? 'withdrawal' : 'deposit',\n details: {\n source: '',\n bridgeContract: undefined,\n recipient: undefined,\n blockNumber: undefined,\n chainId: undefined,\n synthetic: undefined,\n },\n };\n });\n}\n"]}
|
|
@@ -5,6 +5,7 @@ const utils_1 = require("@metamask/utils");
|
|
|
5
5
|
const hyperLiquidConfig_js_1 = require("../constants/hyperLiquidConfig.cjs");
|
|
6
6
|
const perpsConfig_js_1 = require("../constants/perpsConfig.cjs");
|
|
7
7
|
const perpsErrorCodes_js_1 = require("../perpsErrorCodes.cjs");
|
|
8
|
+
const orderTypes_js_1 = require("./orderTypes.cjs");
|
|
8
9
|
/**
|
|
9
10
|
* Validation utilities for HyperLiquid operations
|
|
10
11
|
*/
|
|
@@ -352,7 +353,8 @@ exports.getSupportedPaths = getSupportedPaths;
|
|
|
352
353
|
* Based on HyperLiquid contract specifications.
|
|
353
354
|
*
|
|
354
355
|
* @param maxLeverage - The maximum leverage for the market
|
|
355
|
-
* @param orderType - The order type
|
|
356
|
+
* @param orderType - The order type; trigger types follow the limit/market
|
|
357
|
+
* multiplier of their execution mode (e.g. `stop_limit` is treated as a limit order)
|
|
356
358
|
* @returns Maximum order value in USD
|
|
357
359
|
*/
|
|
358
360
|
function getMaxOrderValue(maxLeverage, orderType) {
|
|
@@ -369,11 +371,20 @@ function getMaxOrderValue(maxLeverage, orderType) {
|
|
|
369
371
|
else {
|
|
370
372
|
marketLimit = perpsConfig_js_1.HYPERLIQUID_ORDER_LIMITS.MarketOrderLimits.LowLeverage;
|
|
371
373
|
}
|
|
372
|
-
return orderType
|
|
374
|
+
return (0, orderTypes_js_1.isLimitExecutionOrderType)(orderType)
|
|
373
375
|
? marketLimit * perpsConfig_js_1.HYPERLIQUID_ORDER_LIMITS.LimitOrderMultiplier
|
|
374
376
|
: marketLimit;
|
|
375
377
|
}
|
|
376
378
|
exports.getMaxOrderValue = getMaxOrderValue;
|
|
379
|
+
/**
|
|
380
|
+
* The `grouping` value each provider-agnostic linkage corresponds to, used to
|
|
381
|
+
* detect a caller supplying both spellings with different meanings.
|
|
382
|
+
*/
|
|
383
|
+
const TPSL_LINKAGE_GROUPING = {
|
|
384
|
+
none: 'na',
|
|
385
|
+
order: 'normalTpsl',
|
|
386
|
+
position: 'positionTpsl',
|
|
387
|
+
};
|
|
377
388
|
/**
|
|
378
389
|
* Validate order parameters.
|
|
379
390
|
* Basic validation - checks required fields are present.
|
|
@@ -383,7 +394,16 @@ exports.getMaxOrderValue = getMaxOrderValue;
|
|
|
383
394
|
* @param params.coin - The trading pair coin symbol
|
|
384
395
|
* @param params.size - The order size as string
|
|
385
396
|
* @param params.price - The order price as string
|
|
386
|
-
* @param params.orderType - The order type
|
|
397
|
+
* @param params.orderType - The order placement type
|
|
398
|
+
* @param params.triggerPrice - Trigger price; required for trigger placement types and
|
|
399
|
+
* rejected for market/limit orders so a stray value can never be silently dropped
|
|
400
|
+
* @param params.takeProfitPrice - Attached take profit price
|
|
401
|
+
* @param params.stopLossPrice - Attached stop loss price
|
|
402
|
+
* @param params.takeProfitSize - Partial take profit size
|
|
403
|
+
* @param params.stopLossSize - Partial stop loss size
|
|
404
|
+
* @param params.tpslLinkage - How an attached TP/SL is linked
|
|
405
|
+
* @param params.grouping - Deprecated protocol-shaped spelling of `tpslLinkage`
|
|
406
|
+
* @param params.timeInForce - Time in force; only a plain limit order can carry one
|
|
387
407
|
* @returns Validation result with isValid flag and optional error message
|
|
388
408
|
*/
|
|
389
409
|
function validateOrderParams(params) {
|
|
@@ -394,8 +414,13 @@ function validateOrderParams(params) {
|
|
|
394
414
|
};
|
|
395
415
|
}
|
|
396
416
|
// Note: Size validation removed - validateOrder handles amount validation using USD as source of truth
|
|
397
|
-
|
|
398
|
-
|
|
417
|
+
const { orderType } = params;
|
|
418
|
+
const isTrigger = orderType !== undefined && (0, orderTypes_js_1.isTriggerOrderType)(orderType);
|
|
419
|
+
// Require price for orders that execute as limit orders (limit, stop_limit,
|
|
420
|
+
// take_profit_limit)
|
|
421
|
+
if (orderType !== undefined &&
|
|
422
|
+
(0, orderTypes_js_1.isLimitExecutionOrderType)(orderType) &&
|
|
423
|
+
!params.price) {
|
|
399
424
|
return {
|
|
400
425
|
isValid: false,
|
|
401
426
|
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_LIMIT_PRICE_REQUIRED,
|
|
@@ -407,9 +432,139 @@ function validateOrderParams(params) {
|
|
|
407
432
|
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_PRICE_POSITIVE,
|
|
408
433
|
};
|
|
409
434
|
}
|
|
435
|
+
if (isTrigger) {
|
|
436
|
+
if (!params.triggerPrice) {
|
|
437
|
+
return {
|
|
438
|
+
isValid: false,
|
|
439
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TRIGGER_PRICE_REQUIRED,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
const triggerPrice = parseFloat(params.triggerPrice);
|
|
443
|
+
if (isNaN(triggerPrice) || triggerPrice <= 0) {
|
|
444
|
+
return {
|
|
445
|
+
isValid: false,
|
|
446
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TRIGGER_PRICE_POSITIVE,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
// A trigger placement combined with attached TP/SL children is rejected
|
|
450
|
+
// rather than silently reshaped: the exchange semantics of a triggered
|
|
451
|
+
// parent owning triggered children are not part of this contract.
|
|
452
|
+
// Each field is checked explicitly: a falsy-but-present price (e.g. '') is
|
|
453
|
+
// still an attached TP/SL request and must be rejected, not skipped.
|
|
454
|
+
if (params.takeProfitPrice !== undefined ||
|
|
455
|
+
params.stopLossPrice !== undefined) {
|
|
456
|
+
return {
|
|
457
|
+
isValid: false,
|
|
458
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TRIGGER_TPSL_UNSUPPORTED,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
// Consistent with the attached-TP/SL check above: a falsy-but-present value
|
|
462
|
+
// (e.g. '') is still a request to place a trigger, not an absent field.
|
|
463
|
+
}
|
|
464
|
+
else if (params.triggerPrice !== undefined) {
|
|
465
|
+
return {
|
|
466
|
+
isValid: false,
|
|
467
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TRIGGER_PRICE_NOT_SUPPORTED,
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
// `tpslLinkage` supersedes `grouping`, but two spellings that disagree are a
|
|
471
|
+
// caller mistake — resolving one silently would hide it.
|
|
472
|
+
if (params.tpslLinkage !== undefined && params.grouping !== undefined) {
|
|
473
|
+
const expectedGrouping = TPSL_LINKAGE_GROUPING[params.tpslLinkage];
|
|
474
|
+
if (expectedGrouping !== params.grouping) {
|
|
475
|
+
return {
|
|
476
|
+
isValid: false,
|
|
477
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TPSL_LINKAGE_CONFLICT,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
const hasAttachedTpsl = params.takeProfitPrice !== undefined || params.stopLossPrice !== undefined;
|
|
482
|
+
// Every order in a `positionTpsl` batch has to be a trigger order, and no
|
|
483
|
+
// shape of order placement produces one. With an attached TP/SL the batch
|
|
484
|
+
// carries the ordinary parent order the TP/SL protects; without one it is
|
|
485
|
+
// that parent order alone. HyperLiquid rejects both, so the linkage is
|
|
486
|
+
// refused outright — it belongs to `updatePositionTPSL`, applied to the
|
|
487
|
+
// position once the parent has filled.
|
|
488
|
+
const requestsPositionLinkage = params.tpslLinkage === 'position' || params.grouping === 'positionTpsl';
|
|
489
|
+
if (requestsPositionLinkage) {
|
|
490
|
+
return {
|
|
491
|
+
isValid: false,
|
|
492
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TPSL_POSITION_LINKAGE_UNSUPPORTED,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
// `na` grouping submits the attached TP/SL as standalone triggers, bound to
|
|
496
|
+
// neither the parent order nor the resulting position. An unfilled parent
|
|
497
|
+
// then leaves them behind as orphan reduce-only triggers that fire against
|
|
498
|
+
// whatever position happens to exist. An attached TP/SL needs a linkage that
|
|
499
|
+
// links it, so the combination is a caller mistake rather than a mode.
|
|
500
|
+
const requestsNoLinkage = params.tpslLinkage === 'none' || params.grouping === 'na';
|
|
501
|
+
if (requestsNoLinkage && hasAttachedTpsl) {
|
|
502
|
+
return {
|
|
503
|
+
isValid: false,
|
|
504
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TPSL_LINKAGE_REQUIRED,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
// Only a plain limit order rests on the book long enough for a time in force to
|
|
508
|
+
// mean anything: a market order fills immediately and a trigger order's
|
|
509
|
+
// execution is decided when it fires. Rejected here, at step 1 of placement, so
|
|
510
|
+
// it cannot fire after leverage changes or a HIP-3 margin transfer.
|
|
511
|
+
if (params.timeInForce !== undefined && orderType !== 'limit') {
|
|
512
|
+
return {
|
|
513
|
+
isValid: false,
|
|
514
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TIME_IN_FORCE_NOT_SUPPORTED,
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
const partialTpslValidation = validatePartialTpslSizes(params);
|
|
518
|
+
if (!partialTpslValidation.isValid) {
|
|
519
|
+
return partialTpslValidation;
|
|
520
|
+
}
|
|
410
521
|
return { isValid: true };
|
|
411
522
|
}
|
|
412
523
|
exports.validateOrderParams = validateOrderParams;
|
|
524
|
+
/**
|
|
525
|
+
* Validate quantity-scoped (partial) TP/SL sizes against the parent order.
|
|
526
|
+
*
|
|
527
|
+
* @param params - Order parameters carrying the TP/SL prices and sizes
|
|
528
|
+
* @param params.size - Parent order size
|
|
529
|
+
* @param params.takeProfitPrice - Attached take profit price
|
|
530
|
+
* @param params.stopLossPrice - Attached stop loss price
|
|
531
|
+
* @param params.takeProfitSize - Partial take profit size
|
|
532
|
+
* @param params.stopLossSize - Partial stop loss size
|
|
533
|
+
* @returns Validation result with isValid flag and optional error message
|
|
534
|
+
*/
|
|
535
|
+
function validatePartialTpslSizes(params) {
|
|
536
|
+
const orderSize = params.size ? Math.abs(parseFloat(params.size)) : undefined;
|
|
537
|
+
const entries = [
|
|
538
|
+
{ size: params.takeProfitSize, price: params.takeProfitPrice },
|
|
539
|
+
{ size: params.stopLossSize, price: params.stopLossPrice },
|
|
540
|
+
];
|
|
541
|
+
for (const entry of entries) {
|
|
542
|
+
if (entry.size === undefined) {
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
// A size without its price would silently place nothing.
|
|
546
|
+
if (!entry.price) {
|
|
547
|
+
return {
|
|
548
|
+
isValid: false,
|
|
549
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TPSL_SIZE_INVALID,
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
const size = parseFloat(entry.size);
|
|
553
|
+
if (isNaN(size) || size <= 0) {
|
|
554
|
+
return {
|
|
555
|
+
isValid: false,
|
|
556
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TPSL_SIZE_INVALID,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
if (orderSize !== undefined && !isNaN(orderSize) && size > orderSize) {
|
|
560
|
+
return {
|
|
561
|
+
isValid: false,
|
|
562
|
+
error: perpsErrorCodes_js_1.PERPS_ERROR_CODES.ORDER_TPSL_SIZE_INVALID,
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return { isValid: true };
|
|
567
|
+
}
|
|
413
568
|
/**
|
|
414
569
|
* Validate coin exists in asset mapping.
|
|
415
570
|
*
|