@lifi/perps-sdk-provider-ondo 17.0.0 → 19.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 +5 -0
- package/dist/cjs/OndoProvider.d.ts.map +1 -1
- package/dist/cjs/OndoProvider.js +27 -11
- package/dist/cjs/OndoProvider.js.map +1 -1
- package/dist/cjs/accountSummary.d.ts +2 -2
- package/dist/cjs/accountSummary.d.ts.map +1 -1
- package/dist/cjs/accountSummary.js +24 -2
- package/dist/cjs/accountSummary.js.map +1 -1
- package/dist/cjs/utils/collateralAsset.d.ts +3 -0
- package/dist/cjs/utils/collateralAsset.d.ts.map +1 -0
- package/dist/cjs/utils/collateralAsset.js +19 -0
- package/dist/cjs/utils/collateralAsset.js.map +1 -0
- package/dist/cjs/utils/decimal.d.ts +3 -0
- package/dist/cjs/utils/decimal.d.ts.map +1 -0
- package/dist/cjs/utils/decimal.js +22 -0
- package/dist/cjs/utils/decimal.js.map +1 -0
- package/dist/cjs/utils/index.d.ts +3 -1
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +6 -2
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/mapOrder.d.ts.map +1 -1
- package/dist/cjs/utils/mapOrder.js +2 -0
- package/dist/cjs/utils/mapOrder.js.map +1 -1
- package/dist/cjs/utils/transferMargin.d.ts +1 -1
- package/dist/cjs/utils/transferMargin.d.ts.map +1 -1
- package/dist/cjs/utils/transferMargin.js +2 -2
- package/dist/cjs/utils/transferMargin.js.map +1 -1
- package/dist/cjs/utils/withdrawableBalances.d.ts +4 -0
- package/dist/cjs/utils/withdrawableBalances.d.ts.map +1 -0
- package/dist/cjs/utils/withdrawableBalances.js +24 -0
- package/dist/cjs/utils/withdrawableBalances.js.map +1 -0
- package/dist/cjs/websocket/OndoWsProvider.d.ts +3 -1
- package/dist/cjs/websocket/OndoWsProvider.d.ts.map +1 -1
- package/dist/cjs/websocket/OndoWsProvider.js +28 -27
- package/dist/cjs/websocket/OndoWsProvider.js.map +1 -1
- package/dist/esm/OndoProvider.d.ts.map +1 -1
- package/dist/esm/OndoProvider.js +29 -13
- package/dist/esm/OndoProvider.js.map +1 -1
- package/dist/esm/accountSummary.d.ts +6 -7
- package/dist/esm/accountSummary.d.ts.map +1 -1
- package/dist/esm/accountSummary.js +29 -8
- package/dist/esm/accountSummary.js.map +1 -1
- package/dist/esm/utils/collateralAsset.d.ts +10 -0
- package/dist/esm/utils/collateralAsset.d.ts.map +1 -0
- package/dist/esm/utils/collateralAsset.js +22 -0
- package/dist/esm/utils/collateralAsset.js.map +1 -0
- package/dist/esm/utils/decimal.d.ts +10 -0
- package/dist/esm/utils/decimal.d.ts.map +1 -0
- package/dist/esm/utils/decimal.js +22 -0
- package/dist/esm/utils/decimal.js.map +1 -0
- package/dist/esm/utils/index.d.ts +3 -1
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +3 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/mapOrder.d.ts.map +1 -1
- package/dist/esm/utils/mapOrder.js +2 -0
- package/dist/esm/utils/mapOrder.js.map +1 -1
- package/dist/esm/utils/transferMargin.d.ts +1 -1
- package/dist/esm/utils/transferMargin.d.ts.map +1 -1
- package/dist/esm/utils/transferMargin.js +1 -1
- package/dist/esm/utils/transferMargin.js.map +1 -1
- package/dist/esm/utils/withdrawableBalances.d.ts +16 -0
- package/dist/esm/utils/withdrawableBalances.d.ts.map +1 -0
- package/dist/esm/utils/withdrawableBalances.js +32 -0
- package/dist/esm/utils/withdrawableBalances.js.map +1 -0
- package/dist/esm/websocket/OndoWsProvider.d.ts +15 -12
- package/dist/esm/websocket/OndoWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/OndoWsProvider.js +41 -39
- package/dist/esm/websocket/OndoWsProvider.js.map +1 -1
- package/dist/types/OndoProvider.d.ts.map +1 -1
- package/dist/types/accountSummary.d.ts +6 -7
- package/dist/types/accountSummary.d.ts.map +1 -1
- package/dist/types/utils/collateralAsset.d.ts +10 -0
- package/dist/types/utils/collateralAsset.d.ts.map +1 -0
- package/dist/types/utils/decimal.d.ts +10 -0
- package/dist/types/utils/decimal.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +3 -1
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/mapOrder.d.ts.map +1 -1
- package/dist/types/utils/transferMargin.d.ts +1 -1
- package/dist/types/utils/transferMargin.d.ts.map +1 -1
- package/dist/types/utils/withdrawableBalances.d.ts +16 -0
- package/dist/types/utils/withdrawableBalances.d.ts.map +1 -0
- package/dist/types/websocket/OndoWsProvider.d.ts +15 -12
- package/dist/types/websocket/OndoWsProvider.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/OndoProvider.ts +45 -21
- package/src/accountSummary.ts +37 -12
- package/src/utils/collateralAsset.ts +30 -0
- package/src/utils/decimal.ts +24 -0
- package/src/utils/index.ts +3 -1
- package/src/utils/mapOrder.ts +2 -0
- package/src/utils/transferMargin.ts +1 -1
- package/src/utils/withdrawableBalances.ts +44 -0
- package/src/websocket/OndoWsProvider.ts +53 -48
|
@@ -47,11 +47,17 @@ export declare class OndoWsProvider extends WsProviderBase<SubState> {
|
|
|
47
47
|
*/
|
|
48
48
|
private readonly authWireRefs;
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
51
|
-
* (`undefined` otherwise).
|
|
52
|
-
*
|
|
50
|
+
* Latest venue balance figures while `accountSummary` is subscribed
|
|
51
|
+
* (`undefined` otherwise). REST-seeded, then re-read on every fills and
|
|
52
|
+
* positions frame, which is what moves them.
|
|
53
53
|
*/
|
|
54
54
|
private accountSummary;
|
|
55
|
+
/**
|
|
56
|
+
* Serializes the balance re-read: a single trade event emits a fills frame
|
|
57
|
+
* and a positions frame together, and two concurrent REST reads can resolve
|
|
58
|
+
* out of order. `'latest'` coalesces the backlog to one trailing refresh.
|
|
59
|
+
*/
|
|
60
|
+
private readonly accountSummaryChain;
|
|
55
61
|
/** Complete (mark-price-bearing) contexts, keyed by venue market symbol. */
|
|
56
62
|
private contexts;
|
|
57
63
|
/** Funding seen before the market's first mark price. */
|
|
@@ -104,19 +110,16 @@ export declare class OndoWsProvider extends WsProviderBase<SubState> {
|
|
|
104
110
|
private ensureLogin;
|
|
105
111
|
private restClient;
|
|
106
112
|
/**
|
|
107
|
-
* Seed the account-summary
|
|
108
|
-
* complete before any positions frame lands. Throws {@link
|
|
113
|
+
* Seed the account-summary figures from the REST balance so the first emit
|
|
114
|
+
* is complete before any positions frame lands. Throws {@link
|
|
109
115
|
* OndoSessionExpiredError} when the SIWE session is missing, matching the
|
|
110
116
|
* other authenticated channels.
|
|
111
117
|
*/
|
|
112
118
|
private seedAccountSummary;
|
|
113
|
-
/** Re-
|
|
114
|
-
private
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
* collateral, the positions carry unrealized PnL, so it counts toward buying
|
|
118
|
-
* power (`availableMargin = walletBalance + unrealizedPnl − marginUsed`).
|
|
119
|
-
*/
|
|
119
|
+
/** Re-read the venue balance moved by the frame and re-emit the summary. */
|
|
120
|
+
private refreshAccountSummary;
|
|
121
|
+
private readBalance;
|
|
122
|
+
/** Emit the current account summary from the venue balance figures. */
|
|
120
123
|
private emitAccountSummary;
|
|
121
124
|
protected handleMessage(raw: string): void;
|
|
122
125
|
private handleBooks;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OndoWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/OndoWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"OndoWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/OndoWsProvider.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifi/perps-sdk-provider-ondo",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "19.0.0",
|
|
4
4
|
"description": "Ondo Perps provider plugin for @lifi/perps-sdk",
|
|
5
5
|
"homepage": "https://github.com/lifinance/perps-sdk",
|
|
6
6
|
"bugs": {
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"big.js": "^7.0.1",
|
|
46
46
|
"viem": "^2.55.18",
|
|
47
|
-
"@lifi/perps-types": "^
|
|
47
|
+
"@lifi/perps-types": "^16.0.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@lifi/perps-sdk": "^
|
|
50
|
+
"@lifi/perps-sdk": "^17.0.0"
|
|
51
51
|
},
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public"
|
package/src/OndoProvider.ts
CHANGED
|
@@ -20,6 +20,8 @@ import {
|
|
|
20
20
|
type ProviderGetPortfolioHistoryParams,
|
|
21
21
|
type ProviderGetPositionsParams,
|
|
22
22
|
type ProviderGetQuoteParams,
|
|
23
|
+
type ProviderGetWithdrawableBalancesParams,
|
|
24
|
+
type ProviderWithdrawableBalance,
|
|
23
25
|
paginateActivity,
|
|
24
26
|
resolveQuote,
|
|
25
27
|
resolveRetryPolicy,
|
|
@@ -111,7 +113,9 @@ import {
|
|
|
111
113
|
mapOpenPositions,
|
|
112
114
|
mapOrder,
|
|
113
115
|
mapWithdrawalActivity,
|
|
114
|
-
|
|
116
|
+
ondoWithdrawableBalances,
|
|
117
|
+
positionRemovableMargin,
|
|
118
|
+
requireOndoCollateralAsset,
|
|
115
119
|
} from './utils/index.js'
|
|
116
120
|
import { mapPortfolioHistory } from './utils/mapPortfolioHistory.js'
|
|
117
121
|
import {
|
|
@@ -323,19 +327,7 @@ export const ondoProvider = (
|
|
|
323
327
|
marketRegistry().sync(),
|
|
324
328
|
])
|
|
325
329
|
|
|
326
|
-
const collateralAsset = providers
|
|
327
|
-
.find((provider) => provider.key === ONDO_PROVIDER_KEY)
|
|
328
|
-
?.categories.find(
|
|
329
|
-
(category) => category.id === ONDO_PROVIDER_KEY
|
|
330
|
-
)?.quoteAsset
|
|
331
|
-
if (collateralAsset === null || collateralAsset === undefined) {
|
|
332
|
-
const error = new PerpsError(
|
|
333
|
-
PerpsErrorCode.SDKError,
|
|
334
|
-
'Ondo provider metadata is missing its collateral asset'
|
|
335
|
-
)
|
|
336
|
-
error.tool = ONDO_PROVIDER_KEY
|
|
337
|
-
throw error
|
|
338
|
-
}
|
|
330
|
+
const collateralAsset = requireOndoCollateralAsset(providers)
|
|
339
331
|
|
|
340
332
|
const positions: Position[] = mapOpenPositions(
|
|
341
333
|
rawPositions ?? [],
|
|
@@ -343,7 +335,7 @@ export const ondoProvider = (
|
|
|
343
335
|
)
|
|
344
336
|
|
|
345
337
|
// The backend owns the collateral identity; the venue supplies its
|
|
346
|
-
//
|
|
338
|
+
// wallet balance (locked margin in, unrealized PnL out).
|
|
347
339
|
return {
|
|
348
340
|
provider: ONDO_PROVIDER_KEY,
|
|
349
341
|
address: params.address,
|
|
@@ -373,12 +365,47 @@ export const ondoProvider = (
|
|
|
373
365
|
apiKeyRegistered,
|
|
374
366
|
referralSet: referral !== null && referral !== undefined,
|
|
375
367
|
depositAddress,
|
|
368
|
+
balance: {
|
|
369
|
+
walletBalance: balance.walletBalance,
|
|
370
|
+
unrealizedPnl: balance.unrealizedPnl,
|
|
371
|
+
marginBalance: balance.marginBalance,
|
|
372
|
+
usedMargin: balance.usedMargin,
|
|
373
|
+
availableMargin: balance.availableMargin,
|
|
374
|
+
withdrawableMargin: balance.withdrawableMargin,
|
|
375
|
+
},
|
|
376
376
|
},
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
379
|
)
|
|
380
380
|
},
|
|
381
381
|
|
|
382
|
+
async getWithdrawableBalances(
|
|
383
|
+
params: ProviderGetWithdrawableBalancesParams,
|
|
384
|
+
opts?: SDKRequestOptions
|
|
385
|
+
): Promise<ProviderWithdrawableBalance[]> {
|
|
386
|
+
return withSession(
|
|
387
|
+
params.address,
|
|
388
|
+
(): ProviderWithdrawableBalance[] => [],
|
|
389
|
+
async (token) => {
|
|
390
|
+
const client = apiClient(opts)
|
|
391
|
+
const [{ providers }, balance, account] = await Promise.all([
|
|
392
|
+
getProviders(requireClient(), opts),
|
|
393
|
+
client.get<OndoBalanceSummary>('/v1/perps/balance', {
|
|
394
|
+
authToken: token.token,
|
|
395
|
+
}),
|
|
396
|
+
client.get<OndoAccountInfo>('/v1/account', {
|
|
397
|
+
authToken: token.token,
|
|
398
|
+
}),
|
|
399
|
+
])
|
|
400
|
+
return ondoWithdrawableBalances(
|
|
401
|
+
requireOndoCollateralAsset(providers).id,
|
|
402
|
+
balance,
|
|
403
|
+
account.withdrawalFeeUSD
|
|
404
|
+
)
|
|
405
|
+
}
|
|
406
|
+
)
|
|
407
|
+
},
|
|
408
|
+
|
|
382
409
|
async accountExists(
|
|
383
410
|
params: ProviderAccountExistsParams,
|
|
384
411
|
opts?: SDKRequestOptions
|
|
@@ -899,11 +926,8 @@ export const ondoProvider = (
|
|
|
899
926
|
)
|
|
900
927
|
},
|
|
901
928
|
|
|
902
|
-
getAccountSummary(
|
|
903
|
-
account
|
|
904
|
-
positions: Position[]
|
|
905
|
-
): AccountSummary {
|
|
906
|
-
return getAccountSummary(account, positions)
|
|
929
|
+
getAccountSummary(account: AccountResponse): AccountSummary {
|
|
930
|
+
return getAccountSummary(account)
|
|
907
931
|
},
|
|
908
932
|
|
|
909
933
|
formatOrderPrice,
|
|
@@ -912,7 +936,7 @@ export const ondoProvider = (
|
|
|
912
936
|
|
|
913
937
|
estimateLiquidationPrice,
|
|
914
938
|
|
|
915
|
-
|
|
939
|
+
positionRemovableMargin,
|
|
916
940
|
|
|
917
941
|
projectConfig(
|
|
918
942
|
config: AccountConfig,
|
package/src/accountSummary.ts
CHANGED
|
@@ -1,22 +1,47 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PerpsError } from '@lifi/perps-sdk'
|
|
2
2
|
import type {
|
|
3
3
|
AccountResponse,
|
|
4
4
|
AccountSummary,
|
|
5
|
-
|
|
5
|
+
OndoAccountBalance,
|
|
6
6
|
} from '@lifi/perps-types'
|
|
7
|
+
import { PerpsErrorCode } from '@lifi/perps-types'
|
|
8
|
+
|
|
9
|
+
const ZERO_SUMMARY: AccountSummary = {
|
|
10
|
+
portfolioValue: '0',
|
|
11
|
+
availableMargin: '0',
|
|
12
|
+
marginUsed: '0',
|
|
13
|
+
unrealizedPnl: '0',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const ondoBalance = (
|
|
17
|
+
account: AccountResponse
|
|
18
|
+
): OndoAccountBalance | undefined => {
|
|
19
|
+
if (account.config.provider !== 'ondo') {
|
|
20
|
+
throw new PerpsError(
|
|
21
|
+
PerpsErrorCode.SDKError,
|
|
22
|
+
`Ondo account summary received a '${account.config.provider}' account config`
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
return account.config.balance
|
|
26
|
+
}
|
|
7
27
|
|
|
8
28
|
/**
|
|
9
|
-
* Roll an Ondo
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* venue counts unrealized PnL toward buying power
|
|
13
|
-
* (`availableMargin = marginBalance − usedMargin`).
|
|
29
|
+
* Roll an Ondo account up into an {@link AccountSummary}, from the venue
|
|
30
|
+
* balance figures the response carries. A logged-out account reads no venue
|
|
31
|
+
* balance and summarizes as zero.
|
|
14
32
|
*
|
|
33
|
+
* @throws {PerpsError} `SDKError` when the account is not an Ondo one.
|
|
15
34
|
* @public
|
|
16
35
|
*/
|
|
17
|
-
export function getAccountSummary(
|
|
18
|
-
account
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
36
|
+
export function getAccountSummary(account: AccountResponse): AccountSummary {
|
|
37
|
+
const balance = ondoBalance(account)
|
|
38
|
+
if (balance === undefined) {
|
|
39
|
+
return ZERO_SUMMARY
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
portfolioValue: balance.marginBalance,
|
|
43
|
+
availableMargin: balance.availableMargin,
|
|
44
|
+
marginUsed: balance.usedMargin,
|
|
45
|
+
unrealizedPnl: balance.unrealizedPnl,
|
|
46
|
+
}
|
|
22
47
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { PerpsError } from '@lifi/perps-sdk'
|
|
2
|
+
import type { Asset, Provider } from '@lifi/perps-types'
|
|
3
|
+
import { PerpsErrorCode } from '@lifi/perps-types'
|
|
4
|
+
import { ONDO_PROVIDER_KEY } from '../constants.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The collateral asset the backend publishes for Ondo's single category. The
|
|
8
|
+
* backend owns the collateral identity, so the venue payload never names it.
|
|
9
|
+
*
|
|
10
|
+
* @throws {PerpsError} `SDKError` when the provider metadata carries none.
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export const requireOndoCollateralAsset = (
|
|
14
|
+
providers: readonly Provider[]
|
|
15
|
+
): Asset => {
|
|
16
|
+
const asset = providers
|
|
17
|
+
.find((provider) => provider.key === ONDO_PROVIDER_KEY)
|
|
18
|
+
?.categories.find(
|
|
19
|
+
(category) => category.id === ONDO_PROVIDER_KEY
|
|
20
|
+
)?.quoteAsset
|
|
21
|
+
if (asset === null || asset === undefined) {
|
|
22
|
+
const error = new PerpsError(
|
|
23
|
+
PerpsErrorCode.SDKError,
|
|
24
|
+
'Ondo provider metadata is missing its collateral asset'
|
|
25
|
+
)
|
|
26
|
+
error.tool = ONDO_PROVIDER_KEY
|
|
27
|
+
throw error
|
|
28
|
+
}
|
|
29
|
+
return asset
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PerpsError } from '@lifi/perps-sdk'
|
|
2
|
+
import { PerpsErrorCode } from '@lifi/perps-types'
|
|
3
|
+
import Big from 'big.js'
|
|
4
|
+
import { ONDO_PROVIDER_KEY } from '../constants.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Exact-decimal parse of an Ondo wire decimal string. `field` names the
|
|
8
|
+
* offending field on failure, so a venue contract breach surfaces as a
|
|
9
|
+
* `PerpsError` instead of an anonymous big.js throw.
|
|
10
|
+
*
|
|
11
|
+
* @throws {PerpsError} `SDKError` when `value` is not a decimal numeric string.
|
|
12
|
+
*/
|
|
13
|
+
export const toWireBig = (value: string, field: string): Big => {
|
|
14
|
+
try {
|
|
15
|
+
return new Big(value)
|
|
16
|
+
} catch {
|
|
17
|
+
const error = new PerpsError(
|
|
18
|
+
PerpsErrorCode.SDKError,
|
|
19
|
+
`Ondo field \`${field}\` is not a valid decimal: '${value}'`
|
|
20
|
+
)
|
|
21
|
+
error.tool = ONDO_PROVIDER_KEY
|
|
22
|
+
throw error
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ export {
|
|
|
16
16
|
type OndoRequestOptions,
|
|
17
17
|
OndoSessionExpiredError,
|
|
18
18
|
} from './apiClient.js'
|
|
19
|
+
export { requireOndoCollateralAsset } from './collateralAsset.js'
|
|
19
20
|
export {
|
|
20
21
|
buildOndoProvisionPayload,
|
|
21
22
|
listOndoDepositAddress,
|
|
@@ -37,4 +38,5 @@ export { mapOpenPositions, mapPosition } from './mapPosition.js'
|
|
|
37
38
|
export { intervalFromBarSpan, mapInterval } from './ohlcvInterval.js'
|
|
38
39
|
export { ondoAsset } from './ondoAsset.js'
|
|
39
40
|
export { formatOrderPrice, formatOrderSize } from './orderFormatting.js'
|
|
40
|
-
export {
|
|
41
|
+
export { positionRemovableMargin } from './transferMargin.js'
|
|
42
|
+
export { ondoWithdrawableBalances } from './withdrawableBalances.js'
|
package/src/utils/mapOrder.ts
CHANGED
|
@@ -7,6 +7,6 @@ import type { Position } from '@lifi/perps-types'
|
|
|
7
7
|
* @see https://docs.ondo.finance/ondo-global-markets/perpetuals/trading/margin
|
|
8
8
|
* @public
|
|
9
9
|
*/
|
|
10
|
-
export function
|
|
10
|
+
export function positionRemovableMargin(_position: Position): undefined {
|
|
11
11
|
return undefined
|
|
12
12
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ProviderWithdrawableBalance } from '@lifi/perps-sdk'
|
|
2
|
+
import type { OndoBalanceSummary } from '../types/wire.js'
|
|
3
|
+
import { toWireBig } from './decimal.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The single route an Ondo withdrawal draws on: `withdrawableMargin`, the
|
|
7
|
+
* venue's own figure for the margin the account can take out. A route with
|
|
8
|
+
* nothing left to draw carries no row, and the caller applies the per-asset
|
|
9
|
+
* venue minimum.
|
|
10
|
+
*
|
|
11
|
+
* @param assetId - `Asset.id` the row is keyed by.
|
|
12
|
+
* @param withdrawalFeeUsd - The account's `withdrawalFeeUSD`. Ondo collateral
|
|
13
|
+
* is USDC, so the USD fee is the row fee 1:1 in collateral units. Absent
|
|
14
|
+
* leaves the row without a fee.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export const ondoWithdrawableBalances = (
|
|
18
|
+
assetId: string,
|
|
19
|
+
balance: OndoBalanceSummary,
|
|
20
|
+
withdrawalFeeUsd?: string
|
|
21
|
+
): ProviderWithdrawableBalance[] => {
|
|
22
|
+
const available = toWireBig(
|
|
23
|
+
balance.withdrawableMargin,
|
|
24
|
+
'balance.withdrawableMargin'
|
|
25
|
+
)
|
|
26
|
+
if (!available.gt(0)) {
|
|
27
|
+
return []
|
|
28
|
+
}
|
|
29
|
+
return [
|
|
30
|
+
{
|
|
31
|
+
assetId,
|
|
32
|
+
route: 'perps',
|
|
33
|
+
available: available.toFixed(),
|
|
34
|
+
...(withdrawalFeeUsd === undefined
|
|
35
|
+
? {}
|
|
36
|
+
: {
|
|
37
|
+
withdrawalFee: toWireBig(
|
|
38
|
+
withdrawalFeeUsd,
|
|
39
|
+
'account.withdrawalFeeUSD'
|
|
40
|
+
).toFixed(),
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
]
|
|
44
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DecodeChain,
|
|
2
3
|
getMarketRegistry,
|
|
3
4
|
localStorageAdapter,
|
|
4
5
|
type MarketRegistry,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
import type {
|
|
19
20
|
MarketContext,
|
|
20
21
|
MarketDisplay,
|
|
22
|
+
OndoAccountBalance,
|
|
21
23
|
PerpsMarketDisplay,
|
|
22
24
|
Subscription,
|
|
23
25
|
} from '@lifi/perps-types'
|
|
@@ -131,13 +133,20 @@ export class OndoWsProvider extends WsProviderBase<SubState> {
|
|
|
131
133
|
private readonly authWireRefs = new Map<string, number>()
|
|
132
134
|
|
|
133
135
|
/**
|
|
134
|
-
*
|
|
135
|
-
* (`undefined` otherwise).
|
|
136
|
-
*
|
|
136
|
+
* Latest venue balance figures while `accountSummary` is subscribed
|
|
137
|
+
* (`undefined` otherwise). REST-seeded, then re-read on every fills and
|
|
138
|
+
* positions frame, which is what moves them.
|
|
137
139
|
*/
|
|
138
|
-
private accountSummary:
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
private accountSummary: OndoAccountBalance | undefined
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Serializes the balance re-read: a single trade event emits a fills frame
|
|
144
|
+
* and a positions frame together, and two concurrent REST reads can resolve
|
|
145
|
+
* out of order. `'latest'` coalesces the backlog to one trailing refresh.
|
|
146
|
+
*/
|
|
147
|
+
private readonly accountSummaryChain = new DecodeChain('latest', (err) =>
|
|
148
|
+
wsLog.handlerFailure(this.providerKey, err)
|
|
149
|
+
)
|
|
141
150
|
|
|
142
151
|
/** Complete (mark-price-bearing) contexts, keyed by venue market symbol. */
|
|
143
152
|
private contexts: Record<string, MarketContext> = {}
|
|
@@ -215,6 +224,8 @@ export class OndoWsProvider extends WsProviderBase<SubState> {
|
|
|
215
224
|
case 'accountSummary':
|
|
216
225
|
case 'spotBalances':
|
|
217
226
|
return `${sub.channel}:${sub.address.toLowerCase()}`
|
|
227
|
+
case 'availableToTrade':
|
|
228
|
+
throw new Error(`Ondo WS does not support channel: ${sub.channel}.`)
|
|
218
229
|
}
|
|
219
230
|
}
|
|
220
231
|
|
|
@@ -269,6 +280,7 @@ export class OndoWsProvider extends WsProviderBase<SubState> {
|
|
|
269
280
|
return () => {
|
|
270
281
|
if (sub.channel === 'accountSummary') {
|
|
271
282
|
this.accountSummary = undefined
|
|
283
|
+
this.accountSummaryChain.reset()
|
|
272
284
|
}
|
|
273
285
|
for (const [key, state] of wireSubs) {
|
|
274
286
|
this.releaseWire(key, state, needsLogin)
|
|
@@ -484,6 +496,7 @@ export class OndoWsProvider extends WsProviderBase<SubState> {
|
|
|
484
496
|
],
|
|
485
497
|
]
|
|
486
498
|
case 'spotBalances':
|
|
499
|
+
case 'availableToTrade':
|
|
487
500
|
return []
|
|
488
501
|
}
|
|
489
502
|
}
|
|
@@ -530,62 +543,60 @@ export class OndoWsProvider extends WsProviderBase<SubState> {
|
|
|
530
543
|
}
|
|
531
544
|
|
|
532
545
|
/**
|
|
533
|
-
* Seed the account-summary
|
|
534
|
-
* complete before any positions frame lands. Throws {@link
|
|
546
|
+
* Seed the account-summary figures from the REST balance so the first emit
|
|
547
|
+
* is complete before any positions frame lands. Throws {@link
|
|
535
548
|
* OndoSessionExpiredError} when the SIWE session is missing, matching the
|
|
536
549
|
* other authenticated channels.
|
|
537
550
|
*/
|
|
538
551
|
private async seedAccountSummary(address: Address): Promise<void> {
|
|
539
552
|
const token = await this.requireSession(address)
|
|
540
|
-
|
|
541
|
-
'/v1/perps/balance',
|
|
542
|
-
{ authToken: token.token }
|
|
543
|
-
)
|
|
544
|
-
this.accountSummary = {
|
|
545
|
-
walletBalance: Number.parseFloat(balance.walletBalance) || 0,
|
|
546
|
-
marginUsed: Number.parseFloat(balance.usedMargin) || 0,
|
|
547
|
-
unrealizedPnl: Number.parseFloat(balance.unrealizedPnl) || 0,
|
|
548
|
-
}
|
|
553
|
+
this.accountSummary = await this.readBalance(token.token)
|
|
549
554
|
this.emitAccountSummary()
|
|
550
555
|
}
|
|
551
556
|
|
|
552
|
-
/** Re-
|
|
553
|
-
private async
|
|
557
|
+
/** Re-read the venue balance moved by the frame and re-emit the summary. */
|
|
558
|
+
private async refreshAccountSummary(address: Address): Promise<void> {
|
|
554
559
|
const token = await this.tokenStore.get(address)
|
|
555
560
|
if (token === null || this.accountSummary === undefined) {
|
|
556
561
|
return
|
|
557
562
|
}
|
|
558
|
-
const balance = await this.
|
|
559
|
-
'/v1/perps/balance',
|
|
560
|
-
{ authToken: token.token }
|
|
561
|
-
)
|
|
563
|
+
const balance = await this.readBalance(token.token)
|
|
562
564
|
if (this.accountSummary === undefined) {
|
|
563
565
|
return
|
|
564
566
|
}
|
|
565
|
-
this.accountSummary
|
|
566
|
-
Number.parseFloat(balance.walletBalance) || 0
|
|
567
|
+
this.accountSummary = balance
|
|
567
568
|
this.emitAccountSummary()
|
|
568
569
|
}
|
|
569
570
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
571
|
+
private async readBalance(authToken: string): Promise<OndoAccountBalance> {
|
|
572
|
+
const balance = await this.restClient().get<OndoBalanceSummary>(
|
|
573
|
+
'/v1/perps/balance',
|
|
574
|
+
{ authToken }
|
|
575
|
+
)
|
|
576
|
+
return {
|
|
577
|
+
walletBalance: balance.walletBalance,
|
|
578
|
+
unrealizedPnl: balance.unrealizedPnl,
|
|
579
|
+
marginBalance: balance.marginBalance,
|
|
580
|
+
usedMargin: balance.usedMargin,
|
|
581
|
+
availableMargin: balance.availableMargin,
|
|
582
|
+
withdrawableMargin: balance.withdrawableMargin,
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/** Emit the current account summary from the venue balance figures. */
|
|
575
587
|
private emitAccountSummary(): void {
|
|
576
|
-
const
|
|
588
|
+
const balance = this.accountSummary
|
|
577
589
|
const address = this.accountAddress
|
|
578
|
-
if (
|
|
590
|
+
if (balance === undefined || address === undefined) {
|
|
579
591
|
return
|
|
580
592
|
}
|
|
581
|
-
const portfolioValue = summary.walletBalance + summary.unrealizedPnl
|
|
582
593
|
this.emit(`accountSummary:${address}`, {
|
|
583
594
|
channel: 'accountSummary',
|
|
584
595
|
data: {
|
|
585
|
-
portfolioValue:
|
|
586
|
-
availableMargin:
|
|
587
|
-
marginUsed:
|
|
588
|
-
unrealizedPnl:
|
|
596
|
+
portfolioValue: balance.marginBalance,
|
|
597
|
+
availableMargin: balance.availableMargin,
|
|
598
|
+
marginUsed: balance.usedMargin,
|
|
599
|
+
unrealizedPnl: balance.unrealizedPnl,
|
|
589
600
|
},
|
|
590
601
|
})
|
|
591
602
|
}
|
|
@@ -792,8 +803,8 @@ export class OndoWsProvider extends WsProviderBase<SubState> {
|
|
|
792
803
|
}
|
|
793
804
|
this.emit(`fills:${address}`, { channel: 'fills', data: mapped })
|
|
794
805
|
if (this.accountSummary !== undefined) {
|
|
795
|
-
this.
|
|
796
|
-
|
|
806
|
+
this.accountSummaryChain.push(() =>
|
|
807
|
+
this.refreshAccountSummary(address as Address)
|
|
797
808
|
)
|
|
798
809
|
}
|
|
799
810
|
}
|
|
@@ -818,15 +829,9 @@ export class OndoWsProvider extends WsProviderBase<SubState> {
|
|
|
818
829
|
data: mapped,
|
|
819
830
|
})
|
|
820
831
|
if (this.accountSummary !== undefined) {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
marginUsed += Number.parseFloat(position.usedMargin) || 0
|
|
825
|
-
unrealizedPnl += Number.parseFloat(position.unrealizedPnl) || 0
|
|
826
|
-
}
|
|
827
|
-
this.accountSummary.marginUsed = marginUsed
|
|
828
|
-
this.accountSummary.unrealizedPnl = unrealizedPnl
|
|
829
|
-
this.emitAccountSummary()
|
|
832
|
+
this.accountSummaryChain.push(() =>
|
|
833
|
+
this.refreshAccountSummary(address as Address)
|
|
834
|
+
)
|
|
830
835
|
}
|
|
831
836
|
}
|
|
832
837
|
}
|