@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
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { Order, PositionTriggerOrder } from "../types/index.mjs";
|
|
2
|
+
import type { OrderExecution, OrderType, TriggerDirection, TriggerOrderType } from "../types/perps-types.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* All trigger placement types, in a stable order suitable for iteration
|
|
5
|
+
* (validation tables, e2e matrices).
|
|
6
|
+
*/
|
|
7
|
+
export declare const TRIGGER_ORDER_TYPES: readonly ["stop_market", "stop_limit", "take_profit_market", "take_profit_limit"];
|
|
8
|
+
/**
|
|
9
|
+
* Check whether an order type is a trigger placement (stop / take profit).
|
|
10
|
+
*
|
|
11
|
+
* @param orderType - Order type to check.
|
|
12
|
+
* @returns True when the type requires `OrderParams.triggerPrice`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isTriggerOrderType(orderType: OrderType): orderType is TriggerOrderType;
|
|
15
|
+
/**
|
|
16
|
+
* Check whether an order type executes as a limit order.
|
|
17
|
+
*
|
|
18
|
+
* Covers plain limit orders and the `*_limit` trigger types, both of which
|
|
19
|
+
* require `OrderParams.price`.
|
|
20
|
+
*
|
|
21
|
+
* @param orderType - Order type to check.
|
|
22
|
+
* @returns True when the order executes as a limit order.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isLimitExecutionOrderType(orderType: OrderType): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Get how an order executes, ignoring whether it is trigger-gated.
|
|
27
|
+
*
|
|
28
|
+
* This is also the coarse execution type that consumers predating trigger orders
|
|
29
|
+
* understand (fee tiers, max order value, analytics).
|
|
30
|
+
*
|
|
31
|
+
* @param orderType - Order type to inspect.
|
|
32
|
+
* @returns `'limit'` for limit and `*_limit` types, `'market'` otherwise.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getTriggerExecution(orderType: OrderType): OrderExecution;
|
|
35
|
+
/**
|
|
36
|
+
* Get the direction a trigger order fires in.
|
|
37
|
+
*
|
|
38
|
+
* @param orderType - Trigger order type.
|
|
39
|
+
* @returns `'stop'` for `stop_*`, `'take_profit'` for `take_profit_*`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getTriggerDirection(orderType: TriggerOrderType): TriggerDirection;
|
|
42
|
+
/**
|
|
43
|
+
* Recover which way a trigger fires from its price relative to the entry.
|
|
44
|
+
*
|
|
45
|
+
* Used when the exchange reports a trigger without naming its placement type:
|
|
46
|
+
* a long takes profit above its entry and stops out below, a short the other
|
|
47
|
+
* way round. Shared by both transports so they classify identically.
|
|
48
|
+
*
|
|
49
|
+
* @param params - Classification parameters
|
|
50
|
+
* @param params.triggerPrice - Price at which the order activates
|
|
51
|
+
* @param params.entryPrice - Entry price of the position it is attached to
|
|
52
|
+
* @param params.positionSize - Signed position size; its sign gives the side
|
|
53
|
+
* @returns The direction, or undefined when there is nothing to compare against
|
|
54
|
+
*/
|
|
55
|
+
export declare function classifyTriggerDirection(params: {
|
|
56
|
+
triggerPrice?: string;
|
|
57
|
+
entryPrice?: string;
|
|
58
|
+
positionSize: string;
|
|
59
|
+
}): TriggerDirection | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Project a normalized open order onto the position-state view of a trigger order.
|
|
62
|
+
*
|
|
63
|
+
* Returns undefined when the order is not a trigger, or when its direction can
|
|
64
|
+
* be established neither from a named placement type nor from its price.
|
|
65
|
+
*
|
|
66
|
+
* @param params - Mapping parameters
|
|
67
|
+
* @param params.order - Normalized open order
|
|
68
|
+
* @param params.positionSize - Size of the position the trigger is attached to
|
|
69
|
+
* @param params.entryPrice - Entry price, used to classify an unnamed trigger
|
|
70
|
+
* @returns The position trigger order, or undefined
|
|
71
|
+
*/
|
|
72
|
+
export declare function buildPositionTriggerOrderFromOrder(params: {
|
|
73
|
+
order: Order;
|
|
74
|
+
positionSize: string;
|
|
75
|
+
entryPrice?: string;
|
|
76
|
+
}): PositionTriggerOrder | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Build a trigger order type from its two independent dimensions.
|
|
79
|
+
*
|
|
80
|
+
* @param params - Trigger dimensions.
|
|
81
|
+
* @param params.direction - Whether the trigger is a stop or a take profit.
|
|
82
|
+
* @param params.execution - How the order executes once triggered.
|
|
83
|
+
* @returns The matching trigger order type.
|
|
84
|
+
*/
|
|
85
|
+
export declare function buildTriggerOrderType(params: {
|
|
86
|
+
direction: TriggerDirection;
|
|
87
|
+
execution: OrderExecution;
|
|
88
|
+
}): TriggerOrderType;
|
|
89
|
+
/**
|
|
90
|
+
* Map the controller's time in force onto the exchange's spelling.
|
|
91
|
+
*
|
|
92
|
+
* Shared by the two order-building paths so they cannot drift apart.
|
|
93
|
+
*
|
|
94
|
+
* @param timeInForce - Requested time in force; defaults to GTC.
|
|
95
|
+
* @returns The SDK time-in-force value.
|
|
96
|
+
*/
|
|
97
|
+
export declare function toSDKTimeInForce(timeInForce?: 'GTC' | 'IOC' | 'ALO'): 'Gtc' | 'Ioc' | 'Alo';
|
|
98
|
+
/**
|
|
99
|
+
* Hash the identity of a position's trigger orders for change detection.
|
|
100
|
+
*
|
|
101
|
+
* Streamed positions only re-emit when their hash changes, so this has to move
|
|
102
|
+
* when a trigger is added, removed, repriced, resized, or retyped — otherwise
|
|
103
|
+
* subscribers never receive the updated arrays.
|
|
104
|
+
*
|
|
105
|
+
* The placement type is part of the identity because a trigger can be modified
|
|
106
|
+
* in place: switching a stop from market to limit execution keeps its order ID,
|
|
107
|
+
* trigger price, and size, so nothing else here would move even though the
|
|
108
|
+
* execution semantics subscribers rely on have changed.
|
|
109
|
+
*
|
|
110
|
+
* @param orders - Trigger orders attached to a position, if any.
|
|
111
|
+
* @returns A stable string; `'0'` for both empty and absent.
|
|
112
|
+
*/
|
|
113
|
+
export declare function hashTriggerOrders(orders?: PositionTriggerOrder[]): string;
|
|
114
|
+
//# sourceMappingURL=orderTypes.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orderTypes.d.mts","sourceRoot":"","sources":["../../src/utils/orderTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,2BAA0B;AACrE,OAAO,KAAK,EACV,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EACjB,iCAAgC;AAEjC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,mFAKgB,CAAC;AAYjD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,GACnB,SAAS,IAAI,gBAAgB,CAE/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAIvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,cAAc,CAExE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,gBAAgB,GAC1B,gBAAgB,CAIlB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,gBAAgB,GAAG,SAAS,CAuB/B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kCAAkC,CAAC,MAAM,EAAE;IACzD,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,oBAAoB,GAAG,SAAS,CAqDnC;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,SAAS,EAAE,gBAAgB,CAAC;IAC5B,SAAS,EAAE,cAAc,CAAC;CAC3B,GAAG,gBAAgB,CAQnB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAClC,KAAK,GAAG,KAAK,GAAG,KAAK,CASvB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,oBAAoB,EAAE,GAAG,MAAM,CAUzE"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* All trigger placement types, in a stable order suitable for iteration
|
|
3
|
+
* (validation tables, e2e matrices).
|
|
4
|
+
*/
|
|
5
|
+
export const TRIGGER_ORDER_TYPES = [
|
|
6
|
+
'stop_market',
|
|
7
|
+
'stop_limit',
|
|
8
|
+
'take_profit_market',
|
|
9
|
+
'take_profit_limit',
|
|
10
|
+
];
|
|
11
|
+
/**
|
|
12
|
+
* Order types whose price field (`OrderParams.price`) is a real limit price the
|
|
13
|
+
* exchange must honour, as opposed to a slippage cap derived from the market.
|
|
14
|
+
*/
|
|
15
|
+
const LIMIT_EXECUTION_ORDER_TYPES = [
|
|
16
|
+
'limit',
|
|
17
|
+
'stop_limit',
|
|
18
|
+
'take_profit_limit',
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Check whether an order type is a trigger placement (stop / take profit).
|
|
22
|
+
*
|
|
23
|
+
* @param orderType - Order type to check.
|
|
24
|
+
* @returns True when the type requires `OrderParams.triggerPrice`.
|
|
25
|
+
*/
|
|
26
|
+
export function isTriggerOrderType(orderType) {
|
|
27
|
+
return TRIGGER_ORDER_TYPES.includes(orderType);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check whether an order type executes as a limit order.
|
|
31
|
+
*
|
|
32
|
+
* Covers plain limit orders and the `*_limit` trigger types, both of which
|
|
33
|
+
* require `OrderParams.price`.
|
|
34
|
+
*
|
|
35
|
+
* @param orderType - Order type to check.
|
|
36
|
+
* @returns True when the order executes as a limit order.
|
|
37
|
+
*/
|
|
38
|
+
export function isLimitExecutionOrderType(orderType) {
|
|
39
|
+
return LIMIT_EXECUTION_ORDER_TYPES.includes(orderType);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get how an order executes, ignoring whether it is trigger-gated.
|
|
43
|
+
*
|
|
44
|
+
* This is also the coarse execution type that consumers predating trigger orders
|
|
45
|
+
* understand (fee tiers, max order value, analytics).
|
|
46
|
+
*
|
|
47
|
+
* @param orderType - Order type to inspect.
|
|
48
|
+
* @returns `'limit'` for limit and `*_limit` types, `'market'` otherwise.
|
|
49
|
+
*/
|
|
50
|
+
export function getTriggerExecution(orderType) {
|
|
51
|
+
return isLimitExecutionOrderType(orderType) ? 'limit' : 'market';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the direction a trigger order fires in.
|
|
55
|
+
*
|
|
56
|
+
* @param orderType - Trigger order type.
|
|
57
|
+
* @returns `'stop'` for `stop_*`, `'take_profit'` for `take_profit_*`.
|
|
58
|
+
*/
|
|
59
|
+
export function getTriggerDirection(orderType) {
|
|
60
|
+
return orderType === 'stop_market' || orderType === 'stop_limit'
|
|
61
|
+
? 'stop'
|
|
62
|
+
: 'take_profit';
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Recover which way a trigger fires from its price relative to the entry.
|
|
66
|
+
*
|
|
67
|
+
* Used when the exchange reports a trigger without naming its placement type:
|
|
68
|
+
* a long takes profit above its entry and stops out below, a short the other
|
|
69
|
+
* way round. Shared by both transports so they classify identically.
|
|
70
|
+
*
|
|
71
|
+
* @param params - Classification parameters
|
|
72
|
+
* @param params.triggerPrice - Price at which the order activates
|
|
73
|
+
* @param params.entryPrice - Entry price of the position it is attached to
|
|
74
|
+
* @param params.positionSize - Signed position size; its sign gives the side
|
|
75
|
+
* @returns The direction, or undefined when there is nothing to compare against
|
|
76
|
+
*/
|
|
77
|
+
export function classifyTriggerDirection(params) {
|
|
78
|
+
const { triggerPrice, entryPrice, positionSize } = params;
|
|
79
|
+
const trigger = parseFloat(triggerPrice ?? '');
|
|
80
|
+
const entry = parseFloat(entryPrice ?? '');
|
|
81
|
+
const signedSize = parseFloat(positionSize || '0');
|
|
82
|
+
if (!Number.isFinite(trigger) || !Number.isFinite(entry) || entry <= 0) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
// A long takes profit above its entry and stops out below; a short is the
|
|
86
|
+
// mirror image. A trigger sitting exactly at entry is neither, so both sides
|
|
87
|
+
// fall to 'stop' — matching the legacy price fallback the scalar
|
|
88
|
+
// takeProfitPrice/stopLossPrice fields still use. Splitting that tie the
|
|
89
|
+
// other way would file the order under takeProfitOrders while the scalar
|
|
90
|
+
// still reported it as a stop.
|
|
91
|
+
const isLong = signedSize > 0;
|
|
92
|
+
if (isLong) {
|
|
93
|
+
return trigger > entry ? 'take_profit' : 'stop';
|
|
94
|
+
}
|
|
95
|
+
return trigger < entry ? 'take_profit' : 'stop';
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Project a normalized open order onto the position-state view of a trigger order.
|
|
99
|
+
*
|
|
100
|
+
* Returns undefined when the order is not a trigger, or when its direction can
|
|
101
|
+
* be established neither from a named placement type nor from its price.
|
|
102
|
+
*
|
|
103
|
+
* @param params - Mapping parameters
|
|
104
|
+
* @param params.order - Normalized open order
|
|
105
|
+
* @param params.positionSize - Size of the position the trigger is attached to
|
|
106
|
+
* @param params.entryPrice - Entry price, used to classify an unnamed trigger
|
|
107
|
+
* @returns The position trigger order, or undefined
|
|
108
|
+
*/
|
|
109
|
+
export function buildPositionTriggerOrderFromOrder(params) {
|
|
110
|
+
const { order, positionSize, entryPrice } = params;
|
|
111
|
+
if (!order.isTrigger) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
// HyperLiquid sometimes reports a bare 'Trigger', naming neither direction
|
|
115
|
+
// nor execution. The direction is still recoverable from the trigger price
|
|
116
|
+
// against the entry, and it is what decides which array the order belongs
|
|
117
|
+
// to — so an unnamed trigger is kept rather than dropped, with its execution
|
|
118
|
+
// mode left unstated. Without a position to compare against there is nothing
|
|
119
|
+
// to recover, and it is dropped.
|
|
120
|
+
const direction = order.triggerOrderType === undefined
|
|
121
|
+
? classifyTriggerDirection({
|
|
122
|
+
triggerPrice: order.triggerPrice ?? order.price,
|
|
123
|
+
entryPrice,
|
|
124
|
+
positionSize,
|
|
125
|
+
})
|
|
126
|
+
: getTriggerDirection(order.triggerOrderType);
|
|
127
|
+
if (!direction) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
const absolutePositionSize = Math.abs(parseFloat(positionSize || '0'));
|
|
131
|
+
const rawSize = Math.abs(parseFloat(order.size || '0'));
|
|
132
|
+
// A position-bound TP/SL covers whatever the position currently is. The
|
|
133
|
+
// exchange encodes that as size 0, but `adaptOrderFromSDK` has already
|
|
134
|
+
// resolved it against the position as it stood when the order was adapted,
|
|
135
|
+
// so the size carried here goes stale as soon as the position is resized.
|
|
136
|
+
// The flag is the durable statement of what the trigger covers; the number
|
|
137
|
+
// is not. Reading the number instead would report the old size, and would
|
|
138
|
+
// call the order partial whenever the position had since grown.
|
|
139
|
+
const isPositionBound = order.isPositionTpsl === true;
|
|
140
|
+
const size = isPositionBound || rawSize === 0 ? absolutePositionSize : rawSize;
|
|
141
|
+
return {
|
|
142
|
+
orderId: order.orderId,
|
|
143
|
+
direction,
|
|
144
|
+
orderType: order.triggerOrderType,
|
|
145
|
+
triggerPrice: order.triggerPrice ?? order.price,
|
|
146
|
+
size: size.toString(),
|
|
147
|
+
isPartial: !isPositionBound &&
|
|
148
|
+
rawSize > 0 &&
|
|
149
|
+
absolutePositionSize > 0 &&
|
|
150
|
+
rawSize < absolutePositionSize,
|
|
151
|
+
reduceOnly: Boolean(order.reduceOnly),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Build a trigger order type from its two independent dimensions.
|
|
156
|
+
*
|
|
157
|
+
* @param params - Trigger dimensions.
|
|
158
|
+
* @param params.direction - Whether the trigger is a stop or a take profit.
|
|
159
|
+
* @param params.execution - How the order executes once triggered.
|
|
160
|
+
* @returns The matching trigger order type.
|
|
161
|
+
*/
|
|
162
|
+
export function buildTriggerOrderType(params) {
|
|
163
|
+
const { direction, execution } = params;
|
|
164
|
+
if (direction === 'stop') {
|
|
165
|
+
return execution === 'limit' ? 'stop_limit' : 'stop_market';
|
|
166
|
+
}
|
|
167
|
+
return execution === 'limit' ? 'take_profit_limit' : 'take_profit_market';
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Map the controller's time in force onto the exchange's spelling.
|
|
171
|
+
*
|
|
172
|
+
* Shared by the two order-building paths so they cannot drift apart.
|
|
173
|
+
*
|
|
174
|
+
* @param timeInForce - Requested time in force; defaults to GTC.
|
|
175
|
+
* @returns The SDK time-in-force value.
|
|
176
|
+
*/
|
|
177
|
+
export function toSDKTimeInForce(timeInForce) {
|
|
178
|
+
switch (timeInForce) {
|
|
179
|
+
case 'IOC':
|
|
180
|
+
return 'Ioc';
|
|
181
|
+
case 'ALO':
|
|
182
|
+
return 'Alo';
|
|
183
|
+
default:
|
|
184
|
+
return 'Gtc';
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Hash the identity of a position's trigger orders for change detection.
|
|
189
|
+
*
|
|
190
|
+
* Streamed positions only re-emit when their hash changes, so this has to move
|
|
191
|
+
* when a trigger is added, removed, repriced, resized, or retyped — otherwise
|
|
192
|
+
* subscribers never receive the updated arrays.
|
|
193
|
+
*
|
|
194
|
+
* The placement type is part of the identity because a trigger can be modified
|
|
195
|
+
* in place: switching a stop from market to limit execution keeps its order ID,
|
|
196
|
+
* trigger price, and size, so nothing else here would move even though the
|
|
197
|
+
* execution semantics subscribers rely on have changed.
|
|
198
|
+
*
|
|
199
|
+
* @param orders - Trigger orders attached to a position, if any.
|
|
200
|
+
* @returns A stable string; `'0'` for both empty and absent.
|
|
201
|
+
*/
|
|
202
|
+
export function hashTriggerOrders(orders) {
|
|
203
|
+
if (!orders || orders.length === 0) {
|
|
204
|
+
return '0';
|
|
205
|
+
}
|
|
206
|
+
return orders
|
|
207
|
+
.map((order) => `${order.orderId}:${order.direction}:${order.orderType ?? '?'}@${order.triggerPrice}x${order.size}${order.isPartial ? 'p' : ''}`)
|
|
208
|
+
.join(',');
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=orderTypes.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orderTypes.mjs","sourceRoot":"","sources":["../../src/utils/orderTypes.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Order, PositionTriggerOrder } from '../types/index.js';\nimport type {\n OrderExecution,\n OrderType,\n TriggerDirection,\n TriggerOrderType,\n} from '../types/perps-types.js';\n\n/**\n * All trigger placement types, in a stable order suitable for iteration\n * (validation tables, e2e matrices).\n */\nexport const TRIGGER_ORDER_TYPES = [\n 'stop_market',\n 'stop_limit',\n 'take_profit_market',\n 'take_profit_limit',\n] as const satisfies readonly TriggerOrderType[];\n\n/**\n * Order types whose price field (`OrderParams.price`) is a real limit price the\n * exchange must honour, as opposed to a slippage cap derived from the market.\n */\nconst LIMIT_EXECUTION_ORDER_TYPES = [\n 'limit',\n 'stop_limit',\n 'take_profit_limit',\n] as const satisfies readonly OrderType[];\n\n/**\n * Check whether an order type is a trigger placement (stop / take profit).\n *\n * @param orderType - Order type to check.\n * @returns True when the type requires `OrderParams.triggerPrice`.\n */\nexport function isTriggerOrderType(\n orderType: OrderType,\n): orderType is TriggerOrderType {\n return (TRIGGER_ORDER_TYPES as readonly OrderType[]).includes(orderType);\n}\n\n/**\n * Check whether an order type executes as a limit order.\n *\n * Covers plain limit orders and the `*_limit` trigger types, both of which\n * require `OrderParams.price`.\n *\n * @param orderType - Order type to check.\n * @returns True when the order executes as a limit order.\n */\nexport function isLimitExecutionOrderType(orderType: OrderType): boolean {\n return (LIMIT_EXECUTION_ORDER_TYPES as readonly OrderType[]).includes(\n orderType,\n );\n}\n\n/**\n * Get how an order executes, ignoring whether it is trigger-gated.\n *\n * This is also the coarse execution type that consumers predating trigger orders\n * understand (fee tiers, max order value, analytics).\n *\n * @param orderType - Order type to inspect.\n * @returns `'limit'` for limit and `*_limit` types, `'market'` otherwise.\n */\nexport function getTriggerExecution(orderType: OrderType): OrderExecution {\n return isLimitExecutionOrderType(orderType) ? 'limit' : 'market';\n}\n\n/**\n * Get the direction a trigger order fires in.\n *\n * @param orderType - Trigger order type.\n * @returns `'stop'` for `stop_*`, `'take_profit'` for `take_profit_*`.\n */\nexport function getTriggerDirection(\n orderType: TriggerOrderType,\n): TriggerDirection {\n return orderType === 'stop_market' || orderType === 'stop_limit'\n ? 'stop'\n : 'take_profit';\n}\n\n/**\n * Recover which way a trigger fires from its price relative to the entry.\n *\n * Used when the exchange reports a trigger without naming its placement type:\n * a long takes profit above its entry and stops out below, a short the other\n * way round. Shared by both transports so they classify identically.\n *\n * @param params - Classification parameters\n * @param params.triggerPrice - Price at which the order activates\n * @param params.entryPrice - Entry price of the position it is attached to\n * @param params.positionSize - Signed position size; its sign gives the side\n * @returns The direction, or undefined when there is nothing to compare against\n */\nexport function classifyTriggerDirection(params: {\n triggerPrice?: string;\n entryPrice?: string;\n positionSize: string;\n}): TriggerDirection | undefined {\n const { triggerPrice, entryPrice, positionSize } = params;\n\n const trigger = parseFloat(triggerPrice ?? '');\n const entry = parseFloat(entryPrice ?? '');\n const signedSize = parseFloat(positionSize || '0');\n\n if (!Number.isFinite(trigger) || !Number.isFinite(entry) || entry <= 0) {\n return undefined;\n }\n\n // A long takes profit above its entry and stops out below; a short is the\n // mirror image. A trigger sitting exactly at entry is neither, so both sides\n // fall to 'stop' — matching the legacy price fallback the scalar\n // takeProfitPrice/stopLossPrice fields still use. Splitting that tie the\n // other way would file the order under takeProfitOrders while the scalar\n // still reported it as a stop.\n const isLong = signedSize > 0;\n\n if (isLong) {\n return trigger > entry ? 'take_profit' : 'stop';\n }\n return trigger < entry ? 'take_profit' : 'stop';\n}\n\n/**\n * Project a normalized open order onto the position-state view of a trigger order.\n *\n * Returns undefined when the order is not a trigger, or when its direction can\n * be established neither from a named placement type nor from its price.\n *\n * @param params - Mapping parameters\n * @param params.order - Normalized open order\n * @param params.positionSize - Size of the position the trigger is attached to\n * @param params.entryPrice - Entry price, used to classify an unnamed trigger\n * @returns The position trigger order, or undefined\n */\nexport function buildPositionTriggerOrderFromOrder(params: {\n order: Order;\n positionSize: string;\n entryPrice?: string;\n}): PositionTriggerOrder | undefined {\n const { order, positionSize, entryPrice } = params;\n\n if (!order.isTrigger) {\n return undefined;\n }\n\n // HyperLiquid sometimes reports a bare 'Trigger', naming neither direction\n // nor execution. The direction is still recoverable from the trigger price\n // against the entry, and it is what decides which array the order belongs\n // to — so an unnamed trigger is kept rather than dropped, with its execution\n // mode left unstated. Without a position to compare against there is nothing\n // to recover, and it is dropped.\n const direction =\n order.triggerOrderType === undefined\n ? classifyTriggerDirection({\n triggerPrice: order.triggerPrice ?? order.price,\n entryPrice,\n positionSize,\n })\n : getTriggerDirection(order.triggerOrderType);\n\n if (!direction) {\n return undefined;\n }\n\n const absolutePositionSize = Math.abs(parseFloat(positionSize || '0'));\n const rawSize = Math.abs(parseFloat(order.size || '0'));\n\n // A position-bound TP/SL covers whatever the position currently is. The\n // exchange encodes that as size 0, but `adaptOrderFromSDK` has already\n // resolved it against the position as it stood when the order was adapted,\n // so the size carried here goes stale as soon as the position is resized.\n // The flag is the durable statement of what the trigger covers; the number\n // is not. Reading the number instead would report the old size, and would\n // call the order partial whenever the position had since grown.\n const isPositionBound = order.isPositionTpsl === true;\n const size =\n isPositionBound || rawSize === 0 ? absolutePositionSize : rawSize;\n\n return {\n orderId: order.orderId,\n direction,\n orderType: order.triggerOrderType,\n triggerPrice: order.triggerPrice ?? order.price,\n size: size.toString(),\n isPartial:\n !isPositionBound &&\n rawSize > 0 &&\n absolutePositionSize > 0 &&\n rawSize < absolutePositionSize,\n reduceOnly: Boolean(order.reduceOnly),\n };\n}\n\n/**\n * Build a trigger order type from its two independent dimensions.\n *\n * @param params - Trigger dimensions.\n * @param params.direction - Whether the trigger is a stop or a take profit.\n * @param params.execution - How the order executes once triggered.\n * @returns The matching trigger order type.\n */\nexport function buildTriggerOrderType(params: {\n direction: TriggerDirection;\n execution: OrderExecution;\n}): TriggerOrderType {\n const { direction, execution } = params;\n\n if (direction === 'stop') {\n return execution === 'limit' ? 'stop_limit' : 'stop_market';\n }\n\n return execution === 'limit' ? 'take_profit_limit' : 'take_profit_market';\n}\n\n/**\n * Map the controller's time in force onto the exchange's spelling.\n *\n * Shared by the two order-building paths so they cannot drift apart.\n *\n * @param timeInForce - Requested time in force; defaults to GTC.\n * @returns The SDK time-in-force value.\n */\nexport function toSDKTimeInForce(\n timeInForce?: 'GTC' | 'IOC' | 'ALO',\n): 'Gtc' | 'Ioc' | 'Alo' {\n switch (timeInForce) {\n case 'IOC':\n return 'Ioc';\n case 'ALO':\n return 'Alo';\n default:\n return 'Gtc';\n }\n}\n\n/**\n * Hash the identity of a position's trigger orders for change detection.\n *\n * Streamed positions only re-emit when their hash changes, so this has to move\n * when a trigger is added, removed, repriced, resized, or retyped — otherwise\n * subscribers never receive the updated arrays.\n *\n * The placement type is part of the identity because a trigger can be modified\n * in place: switching a stop from market to limit execution keeps its order ID,\n * trigger price, and size, so nothing else here would move even though the\n * execution semantics subscribers rely on have changed.\n *\n * @param orders - Trigger orders attached to a position, if any.\n * @returns A stable string; `'0'` for both empty and absent.\n */\nexport function hashTriggerOrders(orders?: PositionTriggerOrder[]): string {\n if (!orders || orders.length === 0) {\n return '0';\n }\n return orders\n .map(\n (order) =>\n `${order.orderId}:${order.direction}:${order.orderType ?? '?'}@${order.triggerPrice}x${order.size}${order.isPartial ? 'p' : ''}`,\n )\n .join(',');\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/perps-controller",
|
|
3
|
-
"version": "10.0.0-preview-
|
|
3
|
+
"version": "10.0.0-preview-5a03e1b92",
|
|
4
4
|
"description": "Controller for perpetual trading functionality in MetaMask",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|
|
@@ -113,13 +113,13 @@
|
|
|
113
113
|
"@metamask/account-tree-controller": "^7.5.5",
|
|
114
114
|
"@metamask/authenticated-user-storage": "^3.0.1",
|
|
115
115
|
"@metamask/auto-changelog": "^6.1.0",
|
|
116
|
-
"@metamask/geolocation-controller": "^0.
|
|
116
|
+
"@metamask/geolocation-controller": "^1.0.0",
|
|
117
117
|
"@metamask/keyring-controller": "^27.1.0",
|
|
118
118
|
"@metamask/keyring-internal-api": "^11.0.2",
|
|
119
|
-
"@metamask/network-controller": "^
|
|
119
|
+
"@metamask/network-controller": "^35.0.0",
|
|
120
120
|
"@metamask/profile-sync-controller": "^28.3.0",
|
|
121
|
-
"@metamask/remote-feature-flag-controller": "^
|
|
122
|
-
"@metamask/transaction-controller": "^69.
|
|
121
|
+
"@metamask/remote-feature-flag-controller": "^5.0.0",
|
|
122
|
+
"@metamask/transaction-controller": "^69.4.0",
|
|
123
123
|
"@ts-bridge/cli": "^0.6.4",
|
|
124
124
|
"@types/jest": "^30.0.0",
|
|
125
125
|
"@types/uuid": "^8.3.0",
|
|
@@ -129,7 +129,8 @@
|
|
|
129
129
|
"tsx": "^4.20.5",
|
|
130
130
|
"typedoc": "^0.25.13",
|
|
131
131
|
"typedoc-plugin-missing-exports": "^2.0.0",
|
|
132
|
-
"typescript": "~5.3.3"
|
|
132
|
+
"typescript": "~5.3.3",
|
|
133
|
+
"viem": "^2.55.8"
|
|
133
134
|
},
|
|
134
135
|
"optionalDependencies": {
|
|
135
136
|
"@myx-trade/sdk": "^0.1.265"
|