@lifi/perps-sdk 21.1.0 → 23.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -16
- package/dist/cjs/client/PerpsClient.d.ts +9 -9
- package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
- package/dist/cjs/client/PerpsClient.js +12 -17
- package/dist/cjs/client/PerpsClient.js.map +1 -1
- package/dist/cjs/decimal/convert.d.ts +1 -5
- package/dist/cjs/decimal/convert.d.ts.map +1 -1
- package/dist/cjs/decimal/convert.js +10 -28
- package/dist/cjs/decimal/convert.js.map +1 -1
- package/dist/cjs/decimal/format.d.ts +2 -1
- package/dist/cjs/decimal/format.d.ts.map +1 -1
- package/dist/cjs/decimal/format.js.map +1 -1
- package/dist/cjs/decimal/parse.d.ts +2 -4
- package/dist/cjs/decimal/parse.d.ts.map +1 -1
- package/dist/cjs/decimal/parse.js +5 -2
- package/dist/cjs/decimal/parse.js.map +1 -1
- package/dist/cjs/decimal/requireDecimal.d.ts.map +1 -0
- package/dist/cjs/{wire → decimal}/requireDecimal.js +2 -1
- package/dist/cjs/decimal/requireDecimal.js.map +1 -0
- package/dist/cjs/index.d.ts +5 -5
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +6 -20
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/math/fills.d.ts +3 -3
- package/dist/cjs/math/fills.d.ts.map +1 -1
- package/dist/cjs/math/fills.js.map +1 -1
- package/dist/cjs/math/order.d.ts +1 -8
- package/dist/cjs/math/order.d.ts.map +1 -1
- package/dist/cjs/math/order.js +6 -11
- package/dist/cjs/math/order.js.map +1 -1
- package/dist/cjs/math/position.d.ts +3 -8
- package/dist/cjs/math/position.d.ts.map +1 -1
- package/dist/cjs/math/position.js +12 -12
- package/dist/cjs/math/position.js.map +1 -1
- package/dist/cjs/services/resolveSubscribeQuote.d.ts +1 -1
- package/dist/cjs/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/cjs/services/resolveSubscribeQuote.js +24 -13
- package/dist/cjs/services/resolveSubscribeQuote.js.map +1 -1
- package/dist/cjs/types/api.d.ts +4 -4
- package/dist/cjs/types/api.d.ts.map +1 -1
- package/dist/cjs/types/config.d.ts +0 -1
- package/dist/cjs/types/config.d.ts.map +1 -1
- package/dist/cjs/types/provider.d.ts +1 -1
- package/dist/cjs/types/provider.d.ts.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/wire/orderAmounts.d.ts +1 -2
- package/dist/cjs/wire/orderAmounts.d.ts.map +1 -1
- package/dist/cjs/wire/orderAmounts.js +19 -52
- package/dist/cjs/wire/orderAmounts.js.map +1 -1
- package/dist/cjs/wire/refuel.js +1 -1
- package/dist/cjs/wire/refuel.js.map +1 -1
- package/dist/cjs/wire/transferable.js +1 -1
- package/dist/cjs/wire/transferable.js.map +1 -1
- package/dist/cjs/wire/withdraw.d.ts.map +1 -1
- package/dist/cjs/wire/withdraw.js +1 -1
- package/dist/cjs/wire/withdraw.js.map +1 -1
- package/dist/esm/client/PerpsClient.d.ts +9 -9
- package/dist/esm/client/PerpsClient.d.ts.map +1 -1
- package/dist/esm/client/PerpsClient.js +12 -17
- package/dist/esm/client/PerpsClient.js.map +1 -1
- package/dist/esm/decimal/convert.d.ts +8 -24
- package/dist/esm/decimal/convert.d.ts.map +1 -1
- package/dist/esm/decimal/convert.js +16 -42
- package/dist/esm/decimal/convert.js.map +1 -1
- package/dist/esm/decimal/format.d.ts +2 -1
- package/dist/esm/decimal/format.d.ts.map +1 -1
- package/dist/esm/decimal/format.js.map +1 -1
- package/dist/esm/decimal/parse.d.ts +7 -20
- package/dist/esm/decimal/parse.d.ts.map +1 -1
- package/dist/esm/decimal/parse.js +9 -4
- package/dist/esm/decimal/parse.js.map +1 -1
- package/dist/esm/{wire → decimal}/requireDecimal.d.ts +1 -1
- package/dist/esm/decimal/requireDecimal.d.ts.map +1 -0
- package/dist/esm/{wire → decimal}/requireDecimal.js +3 -2
- package/dist/esm/decimal/requireDecimal.js.map +1 -0
- package/dist/esm/index.d.ts +5 -5
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +4 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/math/fills.d.ts +3 -3
- package/dist/esm/math/fills.d.ts.map +1 -1
- package/dist/esm/math/fills.js +1 -1
- package/dist/esm/math/fills.js.map +1 -1
- package/dist/esm/math/order.d.ts +3 -34
- package/dist/esm/math/order.d.ts.map +1 -1
- package/dist/esm/math/order.js +8 -26
- package/dist/esm/math/order.js.map +1 -1
- package/dist/esm/math/position.d.ts +16 -34
- package/dist/esm/math/position.d.ts.map +1 -1
- package/dist/esm/math/position.js +23 -36
- package/dist/esm/math/position.js.map +1 -1
- package/dist/esm/services/resolveSubscribeQuote.d.ts +6 -1
- package/dist/esm/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/esm/services/resolveSubscribeQuote.js +29 -13
- package/dist/esm/services/resolveSubscribeQuote.js.map +1 -1
- package/dist/esm/types/api.d.ts +4 -4
- package/dist/esm/types/api.d.ts.map +1 -1
- package/dist/esm/types/config.d.ts +0 -11
- package/dist/esm/types/config.d.ts.map +1 -1
- package/dist/esm/types/provider.d.ts +1 -1
- package/dist/esm/types/provider.d.ts.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/wire/orderAmounts.d.ts +15 -29
- package/dist/esm/wire/orderAmounts.d.ts.map +1 -1
- package/dist/esm/wire/orderAmounts.js +28 -88
- package/dist/esm/wire/orderAmounts.js.map +1 -1
- package/dist/esm/wire/refuel.js +1 -1
- package/dist/esm/wire/refuel.js.map +1 -1
- package/dist/esm/wire/transferable.js +1 -1
- package/dist/esm/wire/transferable.js.map +1 -1
- package/dist/esm/wire/withdraw.d.ts.map +1 -1
- package/dist/esm/wire/withdraw.js +1 -1
- package/dist/esm/wire/withdraw.js.map +1 -1
- package/dist/types/client/PerpsClient.d.ts +9 -9
- package/dist/types/client/PerpsClient.d.ts.map +1 -1
- package/dist/types/decimal/convert.d.ts +8 -24
- package/dist/types/decimal/convert.d.ts.map +1 -1
- package/dist/types/decimal/format.d.ts +2 -1
- package/dist/types/decimal/format.d.ts.map +1 -1
- package/dist/types/decimal/parse.d.ts +7 -20
- package/dist/types/decimal/parse.d.ts.map +1 -1
- package/dist/types/{wire → decimal}/requireDecimal.d.ts +1 -1
- package/dist/types/decimal/requireDecimal.d.ts.map +1 -0
- package/dist/types/index.d.ts +5 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/math/fills.d.ts +3 -3
- package/dist/types/math/fills.d.ts.map +1 -1
- package/dist/types/math/order.d.ts +3 -34
- package/dist/types/math/order.d.ts.map +1 -1
- package/dist/types/math/position.d.ts +16 -34
- package/dist/types/math/position.d.ts.map +1 -1
- package/dist/types/services/resolveSubscribeQuote.d.ts +6 -1
- package/dist/types/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/types/types/api.d.ts +4 -4
- package/dist/types/types/api.d.ts.map +1 -1
- package/dist/types/types/config.d.ts +0 -11
- package/dist/types/types/config.d.ts.map +1 -1
- package/dist/types/types/provider.d.ts +1 -1
- package/dist/types/types/provider.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/wire/orderAmounts.d.ts +15 -29
- package/dist/types/wire/orderAmounts.d.ts.map +1 -1
- package/dist/types/wire/withdraw.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/client/PerpsClient.ts +41 -26
- package/src/decimal/convert.ts +27 -54
- package/src/decimal/format.ts +3 -1
- package/src/decimal/parse.ts +10 -6
- package/src/{wire → decimal}/requireDecimal.ts +3 -6
- package/src/index.ts +4 -21
- package/src/math/fills.ts +8 -4
- package/src/math/order.ts +8 -31
- package/src/math/position.ts +32 -43
- package/src/services/resolveSubscribeQuote.ts +37 -19
- package/src/types/api.ts +4 -3
- package/src/types/config.ts +0 -11
- package/src/types/provider.ts +1 -1
- package/src/version.ts +1 -1
- package/src/wire/orderAmounts.ts +35 -117
- package/src/wire/refuel.ts +1 -1
- package/src/wire/transferable.ts +1 -1
- package/src/wire/withdraw.ts +1 -1
- package/dist/cjs/wire/requireDecimal.d.ts.map +0 -1
- package/dist/cjs/wire/requireDecimal.js.map +0 -1
- package/dist/esm/wire/requireDecimal.d.ts.map +0 -1
- package/dist/esm/wire/requireDecimal.js.map +0 -1
- package/dist/types/wire/requireDecimal.d.ts.map +0 -1
- /package/dist/cjs/{wire → decimal}/requireDecimal.d.ts +0 -0
package/src/math/position.ts
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Display-tier position formulas
|
|
3
|
-
* exact decimal arithmetic happens
|
|
2
|
+
* Display-tier position formulas and margin-adjustment predicates. Every
|
|
3
|
+
* formula takes and gives `number`; exact decimal arithmetic happens
|
|
4
|
+
* internally with `DivBig`.
|
|
4
5
|
*
|
|
5
6
|
* Sign convention: long = +1, short = -1. Sizes passed to the `estimate*`
|
|
6
7
|
* helpers are always non-negative magnitudes; direction is carried by
|
|
7
8
|
* `isLong`.
|
|
8
9
|
*/
|
|
9
10
|
|
|
11
|
+
import {
|
|
12
|
+
MarginMode,
|
|
13
|
+
type Position,
|
|
14
|
+
PositionMarginAdjustment,
|
|
15
|
+
} from '@lifi/perps-types'
|
|
10
16
|
import { areFinite, DivBig } from '../decimal/big.js'
|
|
11
17
|
|
|
12
|
-
/**
|
|
13
|
-
* Direction sign for a position.
|
|
14
|
-
*
|
|
15
|
-
* @deprecated Inline `isLong ? 1 : -1`. Removed in the next major.
|
|
16
|
-
*/
|
|
17
|
-
export function directionSign(isLong: boolean): 1 | -1 {
|
|
18
|
-
return isLong ? 1 : -1
|
|
19
|
-
}
|
|
20
|
-
|
|
21
18
|
/**
|
|
22
19
|
* Calculate notional value of a position.
|
|
23
20
|
*
|
|
@@ -112,11 +109,6 @@ export function calculateLiquidationDistance(params: {
|
|
|
112
109
|
return Math.abs((liquidationPrice - currentPrice) / currentPrice) * 100
|
|
113
110
|
}
|
|
114
111
|
|
|
115
|
-
/**
|
|
116
|
-
* @deprecated Use `calculateLiquidationDistance`. Removed in the next major.
|
|
117
|
-
*/
|
|
118
|
-
export const liquidationDistancePercent = calculateLiquidationDistance
|
|
119
|
-
|
|
120
112
|
/**
|
|
121
113
|
* Effective leverage of an open position.
|
|
122
114
|
*
|
|
@@ -141,11 +133,6 @@ export function calculateEffectiveLeverage(params: {
|
|
|
141
133
|
return new DivBig(positionValueUsd).div(marginUsd).toNumber()
|
|
142
134
|
}
|
|
143
135
|
|
|
144
|
-
/**
|
|
145
|
-
* @deprecated Use `calculateEffectiveLeverage`. Removed in the next major.
|
|
146
|
-
*/
|
|
147
|
-
export const effectiveLeverage = calculateEffectiveLeverage
|
|
148
|
-
|
|
149
136
|
/**
|
|
150
137
|
* Estimated liquidation price for an isolated-margin position, parameterised
|
|
151
138
|
* by the venue's maintenance margin rate.
|
|
@@ -192,11 +179,6 @@ export function estimateLiquidationPrice(params: {
|
|
|
192
179
|
.toNumber()
|
|
193
180
|
}
|
|
194
181
|
|
|
195
|
-
/**
|
|
196
|
-
* @deprecated Use `estimateLiquidationPrice`. Removed in the next major.
|
|
197
|
-
*/
|
|
198
|
-
export const estimateIsolatedLiquidationPrice = estimateLiquidationPrice
|
|
199
|
-
|
|
200
182
|
/**
|
|
201
183
|
* Whether an isolated position with this liquidation price is already past
|
|
202
184
|
* liquidation at `currentPrice`: a long liquidates when the price falls to its
|
|
@@ -259,11 +241,6 @@ export function estimateAverageEntryPrice(params: {
|
|
|
259
241
|
.toNumber()
|
|
260
242
|
}
|
|
261
243
|
|
|
262
|
-
/**
|
|
263
|
-
* @deprecated Use `estimateAverageEntryPrice`. Removed in the next major.
|
|
264
|
-
*/
|
|
265
|
-
export const predictAverageEntryPrice = estimateAverageEntryPrice
|
|
266
|
-
|
|
267
244
|
/**
|
|
268
245
|
* Estimated effective leverage after adding margin and notional.
|
|
269
246
|
*
|
|
@@ -295,11 +272,6 @@ export function estimateNewLeverage(params: {
|
|
|
295
272
|
.toNumber()
|
|
296
273
|
}
|
|
297
274
|
|
|
298
|
-
/**
|
|
299
|
-
* @deprecated Use `estimateNewLeverage`. Removed in the next major.
|
|
300
|
-
*/
|
|
301
|
-
export const predictNewLeverage = estimateNewLeverage
|
|
302
|
-
|
|
303
275
|
/**
|
|
304
276
|
* Estimated unrealised PnL at the current mark price.
|
|
305
277
|
*
|
|
@@ -325,11 +297,6 @@ export function estimateUnrealizedPnl(params: {
|
|
|
325
297
|
.toNumber()
|
|
326
298
|
}
|
|
327
299
|
|
|
328
|
-
/**
|
|
329
|
-
* @deprecated Use `estimateUnrealizedPnl`. Removed in the next major.
|
|
330
|
-
*/
|
|
331
|
-
export const predictUnrealizedPnl = estimateUnrealizedPnl
|
|
332
|
-
|
|
333
300
|
/**
|
|
334
301
|
* Realised PnL on the portion of a position being closed.
|
|
335
302
|
*
|
|
@@ -356,6 +323,28 @@ export function calculateRealizedPnl(params: {
|
|
|
356
323
|
}
|
|
357
324
|
|
|
358
325
|
/**
|
|
359
|
-
*
|
|
326
|
+
* Whether this position can take a margin adjustment at all: it holds margin of
|
|
327
|
+
* its own and its market exposes individual position margin.
|
|
328
|
+
*
|
|
329
|
+
* @public
|
|
330
|
+
*/
|
|
331
|
+
export function positionSupportsMarginAdjustment(position: Position): boolean {
|
|
332
|
+
return (
|
|
333
|
+
position.marginMode === MarginMode.ISOLATED &&
|
|
334
|
+
position.market.positionMarginAdjustment !== PositionMarginAdjustment.NONE
|
|
335
|
+
)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Whether a removal is among the adjustments this position permits. An
|
|
340
|
+
* `ADD_ONLY` market takes adds and no withdrawal.
|
|
341
|
+
*
|
|
342
|
+
* @public
|
|
360
343
|
*/
|
|
361
|
-
export
|
|
344
|
+
export function positionSupportsMarginRemoval(position: Position): boolean {
|
|
345
|
+
return (
|
|
346
|
+
positionSupportsMarginAdjustment(position) &&
|
|
347
|
+
position.market.positionMarginAdjustment ===
|
|
348
|
+
PositionMarginAdjustment.ADD_AND_REMOVE
|
|
349
|
+
)
|
|
350
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
FeeTier,
|
|
3
|
-
MarketContext,
|
|
4
|
-
OrderbookResponse,
|
|
1
|
+
import {
|
|
2
|
+
type FeeTier,
|
|
3
|
+
type MarketContext,
|
|
4
|
+
type OrderbookResponse,
|
|
5
|
+
PerpsErrorCode,
|
|
5
6
|
} from '@lifi/perps-types'
|
|
7
|
+
import { PerpsError } from '../errors/PerpsError.js'
|
|
6
8
|
import { buildQuote } from '../math/order.js'
|
|
7
9
|
import type {
|
|
8
10
|
PerpsSDKClient,
|
|
@@ -10,6 +12,7 @@ import type {
|
|
|
10
12
|
QuoteListener,
|
|
11
13
|
} from '../types/provider.js'
|
|
12
14
|
import type { WsProvider } from '../websocket/types.js'
|
|
15
|
+
import { wsLog } from '../websocket/wsLog.js'
|
|
13
16
|
import { resolveQuoteMarket, resolveQuotePrice } from './resolveQuote.js'
|
|
14
17
|
|
|
15
18
|
/**
|
|
@@ -37,6 +40,11 @@ export const QUOTE_THROTTLE_MS = 100
|
|
|
37
40
|
* listeners once and cancels any pending trailing emission, so the wire
|
|
38
41
|
* subscriptions' ref counts cannot be double-decremented.
|
|
39
42
|
*
|
|
43
|
+
* A throw while building or delivering a streamed quote (an unparsable mark
|
|
44
|
+
* price, a throwing `onQuote`) is logged via `wsLog.listenerFailure` and the
|
|
45
|
+
* emission is skipped, on both the immediate and the trailing-timer path.
|
|
46
|
+
*
|
|
47
|
+
* @throws {PerpsError} `ValidationError` when `params.size` is not finite.
|
|
40
48
|
* @throws {PerpsError} `MarketNotFound` when no market matches symbol+type.
|
|
41
49
|
* @internal
|
|
42
50
|
*/
|
|
@@ -48,6 +56,12 @@ export async function resolveSubscribeQuote(
|
|
|
48
56
|
feeTier: FeeTier,
|
|
49
57
|
onQuote: QuoteListener
|
|
50
58
|
): Promise<() => void> {
|
|
59
|
+
if (!Number.isFinite(params.size)) {
|
|
60
|
+
throw new PerpsError(
|
|
61
|
+
PerpsErrorCode.ValidationError,
|
|
62
|
+
`Quote size must be a finite number, got ${params.size}`
|
|
63
|
+
)
|
|
64
|
+
}
|
|
51
65
|
const market = await resolveQuoteMarket(client, provider, params)
|
|
52
66
|
// REST snapshot seeds the context; the marketContext subscription below
|
|
53
67
|
// keeps it live so streamed impact/funding track the moving market.
|
|
@@ -66,21 +80,25 @@ export async function resolveSubscribeQuote(
|
|
|
66
80
|
return
|
|
67
81
|
}
|
|
68
82
|
lastEmitAt = Date.now()
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
try {
|
|
84
|
+
onQuote(
|
|
85
|
+
buildQuote({
|
|
86
|
+
provider,
|
|
87
|
+
symbol: params.symbol,
|
|
88
|
+
type: params.type,
|
|
89
|
+
side: params.side,
|
|
90
|
+
sizeUsd: params.size,
|
|
91
|
+
market,
|
|
92
|
+
price: latestContext,
|
|
93
|
+
bids: latestBook.bids,
|
|
94
|
+
asks: latestBook.asks,
|
|
95
|
+
feeTier,
|
|
96
|
+
timestamp: Date.now(),
|
|
97
|
+
})
|
|
98
|
+
)
|
|
99
|
+
} catch (error) {
|
|
100
|
+
wsLog.listenerFailure(provider, 'quote', error)
|
|
101
|
+
}
|
|
84
102
|
}
|
|
85
103
|
|
|
86
104
|
const unsubscribeContext = await ws.subscribe(
|
package/src/types/api.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
ActionParamsMap,
|
|
7
7
|
PlaceTwapOrderParams as ActionPlaceTwapOrderParams,
|
|
8
8
|
ActionStep,
|
|
9
|
+
DecimalString,
|
|
9
10
|
ExecuteActionResponse,
|
|
10
11
|
MarginMode,
|
|
11
12
|
MarketRef,
|
|
@@ -137,9 +138,9 @@ export interface PlaceOrderParams {
|
|
|
137
138
|
side: OrderSide
|
|
138
139
|
type: Exclude<OrderType, OrderType.TWAP>
|
|
139
140
|
/** Base-asset size as a decimal wire string. */
|
|
140
|
-
size:
|
|
141
|
+
size: DecimalString
|
|
141
142
|
/** Limit price as a decimal wire string; required by limit-style orders. */
|
|
142
|
-
price:
|
|
143
|
+
price: DecimalString
|
|
143
144
|
/** Optional leverage multiplier; provider defaults apply when omitted. */
|
|
144
145
|
leverage?: number
|
|
145
146
|
/**
|
|
@@ -223,7 +224,7 @@ export interface SendAssetActionParams {
|
|
|
223
224
|
/** Destination DEX/account identifier understood by the provider. */
|
|
224
225
|
destinationDex: string
|
|
225
226
|
/** Transfer amount as a provider-compatible decimal wire string. */
|
|
226
|
-
amount:
|
|
227
|
+
amount: DecimalString
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
/**
|
package/src/types/config.ts
CHANGED
|
@@ -41,17 +41,6 @@ export type RequestInterceptor = (
|
|
|
41
41
|
export interface SDKRequestOptions {
|
|
42
42
|
/** Abort the request and any pending backoff delay. */
|
|
43
43
|
signal?: AbortSignal
|
|
44
|
-
/**
|
|
45
|
-
* Lighter auth token consumed by provider-direct venue reads (getOrders,
|
|
46
|
-
* getOrder, getActivity, getAccount). Create via
|
|
47
|
-
* `lighterSigner.createAuthToken(deadline, context)`. Sent only to Lighter
|
|
48
|
-
* venue endpoints, never to the LI.FI backend — read-only by design
|
|
49
|
-
* (8h max TTL, cannot authorize writes). Each call routes to a single Lighter
|
|
50
|
-
* instance via `params.provider`, so this token scopes to that instance's
|
|
51
|
-
* venue; token caches are held per `lighterProvider()` instance and do not
|
|
52
|
-
* cross between instances.
|
|
53
|
-
*/
|
|
54
|
-
lighterAuthToken?: string
|
|
55
44
|
}
|
|
56
45
|
|
|
57
46
|
/**
|
package/src/types/provider.ts
CHANGED
|
@@ -597,7 +597,7 @@ export interface PerpsProviderPlugin {
|
|
|
597
597
|
* @throws {PerpsError} `ValidationError` when a `Position` decimal that the
|
|
598
598
|
* venue formula reads is malformed.
|
|
599
599
|
*/
|
|
600
|
-
positionRemovableMargin(position: Position):
|
|
600
|
+
positionRemovableMargin(position: Position): DecimalString | undefined
|
|
601
601
|
|
|
602
602
|
/**
|
|
603
603
|
* Project a typed {@link AccountConfig} against the provider's `setup`
|
package/src/version.ts
CHANGED
package/src/wire/orderAmounts.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type DecimalString,
|
|
3
|
-
isDecimalString,
|
|
4
|
-
type Market,
|
|
5
|
-
PerpsErrorCode,
|
|
6
|
-
} from '@lifi/perps-types'
|
|
1
|
+
import type { DecimalString, Market } from '@lifi/perps-types'
|
|
7
2
|
import Big from 'big.js'
|
|
8
|
-
import { TruncBig } from '../decimal/big.js'
|
|
9
|
-
import {
|
|
3
|
+
import { DivBig, TruncBig } from '../decimal/big.js'
|
|
4
|
+
import { isDecimalString } from '../decimal/parse.js'
|
|
10
5
|
import type { PerpsSDKClient } from '../types/provider.js'
|
|
11
6
|
import { snapOrderSize } from './snap.js'
|
|
12
7
|
|
|
@@ -19,66 +14,22 @@ export interface OrderAmountsInput {
|
|
|
19
14
|
amount: DecimalString
|
|
20
15
|
leverage: number
|
|
21
16
|
price: DecimalString
|
|
22
|
-
/** Decimals for the quote-asset amounts (margin, notional). Default 2. */
|
|
23
|
-
quoteDecimals?: number
|
|
24
17
|
}
|
|
25
18
|
|
|
26
19
|
/** @public */
|
|
27
20
|
export interface OrderAmounts {
|
|
28
21
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
22
|
+
* The held `amount`, byte-identical, when the user holds the margin;
|
|
23
|
+
* otherwise `notional ÷ leverage`, a display and comparison value that
|
|
24
|
+
* never reaches a venue.
|
|
31
25
|
*/
|
|
32
26
|
margin: DecimalString
|
|
33
|
-
/** Snapped onto the venue lot grid. */
|
|
27
|
+
/** Snapped onto the venue lot grid; the one amount an order sends. */
|
|
34
28
|
size: DecimalString
|
|
35
|
-
/**
|
|
29
|
+
/** Exactly `size × price`, from the snapped size. */
|
|
36
30
|
notional: DecimalString
|
|
37
31
|
}
|
|
38
32
|
|
|
39
|
-
const DEFAULT_QUOTE_DECIMALS = 2
|
|
40
|
-
const TEN = new Big(10)
|
|
41
|
-
|
|
42
|
-
/** Round a quote amount down onto its decimal grid, with no trailing zeros. */
|
|
43
|
-
function quoteAmount(value: Big, decimals: number): DecimalString {
|
|
44
|
-
const truncated = value.round(decimals, Big.roundDown)
|
|
45
|
-
return truncated.eq(0) ? '0' : truncated.toFixed()
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* The smallest margin on the `decimals` grid that funds `notional` at
|
|
50
|
-
* `leverage`, so `margin × leverage ≥ notional` holds. The one derived amount
|
|
51
|
-
* that rounds up: a margin rounded down under-funds the size it backs.
|
|
52
|
-
*
|
|
53
|
-
* The ceiling is exact: the remainder decides the carry, so the result never
|
|
54
|
-
* leans on a fixed decimal-place limit the way `div` then `round` would.
|
|
55
|
-
*/
|
|
56
|
-
function coveringMargin(
|
|
57
|
-
notional: Big,
|
|
58
|
-
leverage: Big,
|
|
59
|
-
decimals: number
|
|
60
|
-
): DecimalString {
|
|
61
|
-
const scale = TEN.pow(decimals)
|
|
62
|
-
const scaled = notional.times(scale)
|
|
63
|
-
const remainder = scaled.mod(leverage)
|
|
64
|
-
const whole = scaled.minus(remainder).div(leverage)
|
|
65
|
-
const covering = remainder.eq(0) ? whole : whole.plus(1)
|
|
66
|
-
return covering.eq(0) ? '0' : covering.div(scale).toFixed()
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* An order needs three positive amounts. A grid that snaps any of them to
|
|
71
|
-
* zero — a sub-lot size, a sub-cent quote amount — describes no order a venue
|
|
72
|
-
* can take, so the caller gets `null` instead of a result it has to re-check.
|
|
73
|
-
*/
|
|
74
|
-
function executable(amounts: OrderAmounts): OrderAmounts | null {
|
|
75
|
-
const positive =
|
|
76
|
-
new Big(amounts.size).gt(0) &&
|
|
77
|
-
new Big(amounts.margin).gt(0) &&
|
|
78
|
-
new Big(amounts.notional).gt(0)
|
|
79
|
-
return positive ? amounts : null
|
|
80
|
-
}
|
|
81
|
-
|
|
82
33
|
function positiveDecimal(value: DecimalString): Big | null {
|
|
83
34
|
if (!isDecimalString(value)) {
|
|
84
35
|
return null
|
|
@@ -89,47 +40,22 @@ function positiveDecimal(value: DecimalString): Big | null {
|
|
|
89
40
|
|
|
90
41
|
/**
|
|
91
42
|
* The three order-entry amounts, derived from whichever one the user typed.
|
|
43
|
+
* Only `size` snaps, onto the market's venue lot grid, because an order sends
|
|
44
|
+
* size alone; no quote amount has a grid. A held margin returns byte-identical,
|
|
45
|
+
* `notional` is the snapped size × price, and a derived margin is
|
|
46
|
+
* `notional ÷ leverage` in `DivBig` (40 places, half-up).
|
|
92
47
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* Rounding is directional, so the result always funds itself:
|
|
99
|
-
* `size × price ≤ margin × leverage`. A derived size truncates onto the lot
|
|
100
|
-
* grid and a derived notional truncates onto the quote grid, but a derived
|
|
101
|
-
* margin rounds **up** onto the quote grid, because it is the one amount that
|
|
102
|
-
* has to cover the others rather than cap them.
|
|
103
|
-
*
|
|
104
|
-
* Formulas: `size = margin × leverage ÷ price`,
|
|
105
|
-
* `margin = size × price ÷ leverage`, `notional = size × price`
|
|
106
|
-
* (or `margin × leverage` when the margin is held).
|
|
107
|
-
*
|
|
108
|
-
* @returns `null` when `amount` or `price` is not a positive decimal string,
|
|
109
|
-
* when `leverage` is not a positive finite number, or when the venue and
|
|
110
|
-
* quote grids snap the result to a non-positive amount — a sub-lot size or
|
|
111
|
-
* a sub-cent quote amount describes no order a venue can take.
|
|
112
|
-
* @throws {PerpsError} `ValidationError` when `quoteDecimals` is not a
|
|
113
|
-
* non-negative integer, or `SDKError` when `market.providerId` names no
|
|
114
|
-
* registered provider plugin.
|
|
48
|
+
* @returns `null` when `amount` or `price` is not a positive
|
|
49
|
+
* {@link DecimalString}, when `leverage` is not a positive finite number, or
|
|
50
|
+
* when the snapped size is zero (below one lot).
|
|
51
|
+
* @throws {PerpsError} `SDKError` when `market.providerId` names no registered
|
|
52
|
+
* provider plugin.
|
|
115
53
|
* @public
|
|
116
54
|
*/
|
|
117
55
|
export function calculateOrderAmounts(
|
|
118
56
|
input: OrderAmountsInput
|
|
119
57
|
): OrderAmounts | null {
|
|
120
|
-
const {
|
|
121
|
-
sdk,
|
|
122
|
-
market,
|
|
123
|
-
held,
|
|
124
|
-
leverage,
|
|
125
|
-
quoteDecimals = DEFAULT_QUOTE_DECIMALS,
|
|
126
|
-
} = input
|
|
127
|
-
if (!Number.isInteger(quoteDecimals) || quoteDecimals < 0) {
|
|
128
|
-
throw new PerpsError(
|
|
129
|
-
PerpsErrorCode.ValidationError,
|
|
130
|
-
`Invalid quoteDecimals for order amounts: ${quoteDecimals}`
|
|
131
|
-
)
|
|
132
|
-
}
|
|
58
|
+
const { sdk, market, held, leverage } = input
|
|
133
59
|
const amount = positiveDecimal(input.amount)
|
|
134
60
|
const price = positiveDecimal(input.price)
|
|
135
61
|
if (
|
|
@@ -140,33 +66,25 @@ export function calculateOrderAmounts(
|
|
|
140
66
|
) {
|
|
141
67
|
return null
|
|
142
68
|
}
|
|
143
|
-
const leverageFactor = new TruncBig(leverage)
|
|
144
69
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
70
|
+
const requested =
|
|
71
|
+
held === 'size'
|
|
72
|
+
? input.amount
|
|
73
|
+
: held === 'notional'
|
|
74
|
+
? amount.div(price).toFixed()
|
|
75
|
+
: amount.times(leverage).div(price).toFixed()
|
|
76
|
+
const size = snapOrderSize(sdk, market, requested)
|
|
77
|
+
if (new Big(size).eq(0)) {
|
|
78
|
+
return null
|
|
153
79
|
}
|
|
154
80
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
81
|
+
const notional = new TruncBig(size).times(price)
|
|
82
|
+
return {
|
|
83
|
+
margin:
|
|
84
|
+
held === 'margin'
|
|
85
|
+
? input.amount
|
|
86
|
+
: new DivBig(notional).div(leverage).toFixed(),
|
|
87
|
+
size,
|
|
88
|
+
notional: notional.toFixed(),
|
|
163
89
|
}
|
|
164
|
-
|
|
165
|
-
const margin = quoteAmount(amount, quoteDecimals)
|
|
166
|
-
const notional = new TruncBig(margin).times(leverage)
|
|
167
|
-
return executable({
|
|
168
|
-
margin,
|
|
169
|
-
size: snapOrderSize(sdk, market, notional.div(price).toFixed()),
|
|
170
|
-
notional: quoteAmount(notional, quoteDecimals),
|
|
171
|
-
})
|
|
172
90
|
}
|
package/src/wire/refuel.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type DecimalString, PerpsErrorCode } from '@lifi/perps-types'
|
|
2
2
|
import { DivBig } from '../decimal/big.js'
|
|
3
|
+
import { requireDecimal } from '../decimal/requireDecimal.js'
|
|
3
4
|
import { PerpsError } from '../errors/PerpsError.js'
|
|
4
|
-
import { requireDecimal } from './requireDecimal.js'
|
|
5
5
|
|
|
6
6
|
/** @public */
|
|
7
7
|
export interface RefuelAmountInput {
|
package/src/wire/transferable.ts
CHANGED
package/src/wire/withdraw.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DecimalString } from '@lifi/perps-types'
|
|
2
|
+
import { requireDecimal } from '../decimal/requireDecimal.js'
|
|
2
3
|
import type { WithdrawableBalance } from '../types/withdrawal.js'
|
|
3
|
-
import { requireDecimal } from './requireDecimal.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Largest `amount` a withdrawable row can fund: `available` when the venue
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"requireDecimal.d.ts","sourceRoot":"","sources":["../../../src/wire/requireDecimal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,GAAG,MAAM,QAAQ,CAAA;AAUxB,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,CAQvE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"requireDecimal.js","sourceRoot":"","sources":["../../../src/wire/requireDecimal.ts"],"names":[],"mappings":";;;;;AAeA,wCAQC;AAvBD,mDAI0B;AAC1B,oDAAwB;AACxB,2DAAoD;AASpD,SAAgB,cAAc,CAAC,KAAoB,EAAE,KAAa;IAChE,IAAI,CAAC,IAAA,6BAAe,EAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,0BAAU,CAClB,4BAAc,CAAC,eAAe,EAC9B,aAAa,KAAK,QAAQ,KAAK,4BAA4B,CAC5D,CAAA;IACH,CAAC;IACD,OAAO,IAAI,gBAAG,CAAC,KAAK,CAAC,CAAA;AACvB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"requireDecimal.d.ts","sourceRoot":"","sources":["../../../src/wire/requireDecimal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,GAAG,MAAM,QAAQ,CAAA;AAGxB;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,CAQvE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"requireDecimal.js","sourceRoot":"","sources":["../../../src/wire/requireDecimal.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,cAAc,GACf,MAAM,mBAAmB,CAAA;AAC1B,OAAO,GAAG,MAAM,QAAQ,CAAA;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEpD;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,KAAoB,EAAE,KAAa;IAChE,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,aAAa,KAAK,QAAQ,KAAK,4BAA4B,CAC5D,CAAA;IACH,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;AACvB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"requireDecimal.d.ts","sourceRoot":"","sources":["../../../src/wire/requireDecimal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,GAAG,MAAM,QAAQ,CAAA;AAGxB;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,CAQvE"}
|
|
File without changes
|