@symmio/trading-core 3.1.0 → 3.3.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/dist/core/chains/registry.js +1 -1
- package/dist/core/chains/registry.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +304 -298
- package/dist/quotes/get-quote-history/solver-fees.d.ts +39 -0
- package/dist/quotes/get-quote-history/solver-fees.d.ts.map +1 -0
- package/dist/quotes/get-quote-history/solver-fees.js +36 -0
- package/dist/quotes/get-quote-history/solver-fees.js.map +1 -0
- package/dist/quotes/get-quote-history/to-history-row.d.ts.map +1 -1
- package/dist/quotes/get-quote-history/to-history-row.js +34 -30
- package/dist/quotes/get-quote-history/to-history-row.js.map +1 -1
- package/dist/quotes/get-quote-history/types.d.ts +20 -0
- package/dist/quotes/get-quote-history/types.d.ts.map +1 -1
- package/dist/quotes/get-quote-history/types.js.map +1 -1
- package/dist/solvers/get-solver-info/get-solver-info.d.ts +36 -0
- package/dist/solvers/get-solver-info/get-solver-info.d.ts.map +1 -0
- package/dist/solvers/get-solver-info/get-solver-info.js +28 -0
- package/dist/solvers/get-solver-info/get-solver-info.js.map +1 -0
- package/dist/solvers/get-solver-info/index.d.ts +3 -0
- package/dist/solvers/get-solver-info/index.d.ts.map +1 -0
- package/dist/solvers/get-solver-info/query.d.ts +29 -0
- package/dist/solvers/get-solver-info/query.d.ts.map +1 -0
- package/dist/solvers/get-solver-info/query.js +24 -0
- package/dist/solvers/get-solver-info/query.js.map +1 -0
- package/dist/solvers/instant-close/get-instant-close-fees/get-instant-close-fees.d.ts +152 -0
- package/dist/solvers/instant-close/get-instant-close-fees/get-instant-close-fees.d.ts.map +1 -0
- package/dist/solvers/instant-close/get-instant-close-fees/get-instant-close-fees.js +82 -0
- package/dist/solvers/instant-close/get-instant-close-fees/get-instant-close-fees.js.map +1 -0
- package/dist/solvers/instant-close/get-instant-close-fees/index.d.ts +3 -0
- package/dist/solvers/instant-close/get-instant-close-fees/index.d.ts.map +1 -0
- package/dist/solvers/instant-close/get-instant-close-fees/query.d.ts +37 -0
- package/dist/solvers/instant-close/get-instant-close-fees/query.d.ts.map +1 -0
- package/dist/solvers/instant-close/get-instant-close-fees/query.js +32 -0
- package/dist/solvers/instant-close/get-instant-close-fees/query.js.map +1 -0
- package/dist/solvers/instant-close/index.d.ts +1 -0
- package/dist/solvers/instant-close/index.d.ts.map +1 -1
- package/dist/solvers/instant-close/instant-close/instant-close.d.ts +4 -3
- package/dist/solvers/instant-close/instant-close/instant-close.d.ts.map +1 -1
- package/dist/solvers/instant-close/instant-close/instant-close.js +26 -22
- package/dist/solvers/instant-close/instant-close/instant-close.js.map +1 -1
- package/dist/solvers/instant-close/instant-close-bulk/instant-close-bulk.d.ts +2 -0
- package/dist/solvers/instant-close/instant-close-bulk/instant-close-bulk.d.ts.map +1 -1
- package/dist/solvers/instant-close/instant-close-bulk/instant-close-bulk.js +26 -22
- package/dist/solvers/instant-close/instant-close-bulk/instant-close-bulk.js.map +1 -1
- package/dist/solvers/instant-close/shared/calldata.d.ts +1 -1
- package/dist/solvers/instant-close/shared/calldata.d.ts.map +1 -1
- package/dist/solvers/instant-close/shared/calldata.js.map +1 -1
- package/dist/solvers/instant-close/shared/resolve-close-order-type.d.ts +13 -0
- package/dist/solvers/instant-close/shared/resolve-close-order-type.d.ts.map +1 -0
- package/dist/solvers/instant-close/shared/resolve-close-order-type.js +9 -0
- package/dist/solvers/instant-close/shared/resolve-close-order-type.js.map +1 -0
- package/dist/solvers/instant-close/shared/types.d.ts +3 -3
- package/dist/solvers/instant-open/get-instant-open-fees/get-instant-open-fees.d.ts +111 -35
- package/dist/solvers/instant-open/get-instant-open-fees/get-instant-open-fees.d.ts.map +1 -1
- package/dist/solvers/instant-open/get-instant-open-fees/get-instant-open-fees.js +168 -91
- package/dist/solvers/instant-open/get-instant-open-fees/get-instant-open-fees.js.map +1 -1
- package/dist/solvers/instant-open/get-instant-open-fees/query.d.ts +3 -2
- package/dist/solvers/instant-open/get-instant-open-fees/query.d.ts.map +1 -1
- package/dist/solvers/instant-open/get-instant-open-fees/query.js +4 -15
- package/dist/solvers/instant-open/get-instant-open-fees/query.js.map +1 -1
- package/dist/solvers/instant-open/prepare-instant-open-params/index.d.ts +1 -0
- package/dist/solvers/instant-open/prepare-instant-open-params/index.d.ts.map +1 -1
- package/dist/solvers/instant-open/prepare-instant-open-params/prepare-instant-open-params.d.ts +108 -12
- package/dist/solvers/instant-open/prepare-instant-open-params/prepare-instant-open-params.d.ts.map +1 -1
- package/dist/solvers/instant-open/prepare-instant-open-params/prepare-instant-open-params.js +169 -149
- package/dist/solvers/instant-open/prepare-instant-open-params/prepare-instant-open-params.js.map +1 -1
- package/dist/solvers/instant-open/prepare-instant-open-params/query.d.ts +49 -0
- package/dist/solvers/instant-open/prepare-instant-open-params/query.d.ts.map +1 -0
- package/dist/solvers/instant-open/prepare-instant-open-params/query.js +24 -0
- package/dist/solvers/instant-open/prepare-instant-open-params/query.js.map +1 -0
- package/dist/solvers/instant-open/prepare-instant-open-params/resolvers/index.d.ts +0 -1
- package/dist/solvers/instant-open/prepare-instant-open-params/resolvers/index.d.ts.map +1 -1
- package/dist/solvers/instant-open/shared/full-balance-sizing.d.ts +164 -0
- package/dist/solvers/instant-open/shared/full-balance-sizing.d.ts.map +1 -0
- package/dist/solvers/instant-open/shared/full-balance-sizing.js +138 -0
- package/dist/solvers/instant-open/shared/full-balance-sizing.js.map +1 -0
- package/dist/solvers/instant-open/shared/index.d.ts +1 -0
- package/dist/solvers/instant-open/shared/index.d.ts.map +1 -1
- package/dist/solvers/instant-open/shared/resolve-instant-open-sizing.d.ts +46 -0
- package/dist/solvers/instant-open/shared/resolve-instant-open-sizing.d.ts.map +1 -0
- package/dist/solvers/instant-open/shared/resolve-instant-open-sizing.js +50 -0
- package/dist/solvers/instant-open/shared/resolve-instant-open-sizing.js.map +1 -0
- package/dist/solvers/instant-open/shared/trade-math.d.ts +73 -26
- package/dist/solvers/instant-open/shared/trade-math.d.ts.map +1 -1
- package/dist/solvers/instant-open/shared/trade-math.js +18 -13
- package/dist/solvers/instant-open/shared/trade-math.js.map +1 -1
- package/dist/solvers/instant-open/shared/types.d.ts +18 -1
- package/dist/solvers/instant-open/shared/types.d.ts.map +1 -1
- package/dist/solvers/instant-open/shared/types.js.map +1 -1
- package/dist/solvers/limit-open/prepare-limit-open-params.d.ts +3 -1
- package/dist/solvers/limit-open/prepare-limit-open-params.d.ts.map +1 -1
- package/dist/solvers/limit-open/prepare-limit-open-params.js.map +1 -1
- package/dist/solvers/shared/resolvers/index.d.ts +2 -0
- package/dist/solvers/shared/resolvers/index.d.ts.map +1 -1
- package/dist/solvers/{instant-open/prepare-instant-open-params → shared}/resolvers/resolve-fee-rates.d.ts +3 -3
- package/dist/solvers/shared/resolvers/resolve-fee-rates.d.ts.map +1 -0
- package/dist/solvers/{instant-open/prepare-instant-open-params → shared}/resolvers/resolve-fee-rates.js +2 -2
- package/dist/solvers/shared/resolvers/resolve-fee-rates.js.map +1 -0
- package/dist/solvers/shared/resolvers/resolve-market.d.ts +21 -0
- package/dist/solvers/shared/resolvers/resolve-market.d.ts.map +1 -1
- package/dist/solvers/shared/resolvers/resolve-market.js +34 -18
- package/dist/solvers/shared/resolvers/resolve-market.js.map +1 -1
- package/dist/solvers/shared/resolvers/resolve-solver-info.d.ts +29 -0
- package/dist/solvers/shared/resolvers/resolve-solver-info.d.ts.map +1 -0
- package/dist/solvers/shared/resolvers/resolve-solver-info.js +21 -0
- package/dist/solvers/shared/resolvers/resolve-solver-info.js.map +1 -0
- package/dist/solvers/shared/resolvers/types.d.ts +12 -0
- package/dist/solvers/shared/resolvers/types.d.ts.map +1 -1
- package/dist/solvers/types/generated/enigma-solver.d.ts +43 -82
- package/dist/solvers/types/generated/enigma-solver.d.ts.map +1 -1
- package/dist/solvers/types/generated/enigma-solver.js +6 -6
- package/dist/solvers/types/generated/enigma-solver.js.map +1 -1
- package/dist/symmio-contracts/abi/v0.8.6/account-layer.d.ts +696 -85
- package/dist/symmio-contracts/abi/v0.8.6/account-layer.d.ts.map +1 -1
- package/dist/symmio-contracts/abi/v0.8.6/account-layer.js +815 -116
- package/dist/symmio-contracts/abi/v0.8.6/account-layer.js.map +1 -1
- package/dist/symmio-contracts/abi/v0.8.6/symmio.d.ts +1044 -467
- package/dist/symmio-contracts/abi/v0.8.6/symmio.d.ts.map +1 -1
- package/dist/symmio-contracts/abi/v0.8.6/symmio.js +1183 -496
- package/dist/symmio-contracts/abi/v0.8.6/symmio.js.map +1 -1
- package/dist/symmio-contracts/symmio/types.d.ts +3 -1
- package/dist/symmio-contracts/symmio/types.d.ts.map +1 -1
- package/dist/symmio-contracts/symmio/types.js +1 -1
- package/dist/symmio-contracts/symmio/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/solvers/instant-open/prepare-instant-open-params/resolvers/resolve-fee-rates.d.ts.map +0 -1
- package/dist/solvers/instant-open/prepare-instant-open-params/resolvers/resolve-fee-rates.js.map +0 -1
|
@@ -2,21 +2,20 @@ import { Address } from 'viem';
|
|
|
2
2
|
import { Config } from '../../../core/config/index.js';
|
|
3
3
|
import { Compute, ReadSolverParameter } from '../../../shared/types/properties.js';
|
|
4
4
|
import { FeeForUser } from '../../../symmio-contracts/symmio/actions/get-fee-for-user.js';
|
|
5
|
+
import { EnigmaSolverInfo } from '../../get-solver-info/index.js';
|
|
6
|
+
import { ApiLockedParamsBySymbolIdResponse } from '../../types/generated/enigma-solver.js';
|
|
7
|
+
import { FullBalanceFunding } from '../prepare-instant-open-params/index.js';
|
|
5
8
|
import { InstantOpenMarketData, PositionType } from '../shared/types.js';
|
|
6
9
|
/**
|
|
7
|
-
*
|
|
8
|
-
* `PrepareInstantOpenParameters` — the trade intent plus optional pre-fetched
|
|
9
|
-
* data; every pre-filled optional field skips its network fetch.
|
|
10
|
+
* Fields shared by every {@link GetInstantOpenFeesParameters} funding mode.
|
|
10
11
|
*/
|
|
11
|
-
|
|
12
|
+
type BaseGetInstantOpenFeesParameters = ReadSolverParameter & {
|
|
12
13
|
/** Sub-account / partyA address the platform fee rates are read for. */
|
|
13
14
|
subAccountAddress: Address;
|
|
14
15
|
/** Market identification + optional pre-fetched precision metadata. */
|
|
15
16
|
market: InstantOpenMarketData;
|
|
16
17
|
/** Trade side. */
|
|
17
18
|
positionType: PositionType;
|
|
18
|
-
/** Collateral (USD) the user enters as initial margin. Decimal string. */
|
|
19
|
-
initialMargin: string;
|
|
20
19
|
/** Position leverage (integer ≥ 1). */
|
|
21
20
|
leverage: number;
|
|
22
21
|
/**
|
|
@@ -27,6 +26,13 @@ export type GetInstantOpenFeesParameters = Compute<ReadSolverParameter & {
|
|
|
27
26
|
* actually charge.
|
|
28
27
|
*/
|
|
29
28
|
slippage?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Whether `totalFee` includes the `expectedSettlementLoss` provision.
|
|
31
|
+
* Defaults to `true` — the provision is part of what the open funds, even
|
|
32
|
+
* though it is a provision rather than a fee the solver keeps. Pass `false`
|
|
33
|
+
* to report fee legs only; the provision stays available as its own field.
|
|
34
|
+
*/
|
|
35
|
+
includeSettlementInTotalFee?: boolean;
|
|
30
36
|
/** Pre-fetched mark price as decimal string. When omitted, fetched via the price service. */
|
|
31
37
|
markPrice?: string;
|
|
32
38
|
/** Pre-fetched on-chain fee rates (matches `getFeeForUser` return). When omitted, fetched. */
|
|
@@ -34,50 +40,105 @@ export type GetInstantOpenFeesParameters = Compute<ReadSolverParameter & {
|
|
|
34
40
|
/**
|
|
35
41
|
* Pre-fetched solver estimated open (fill) price as decimal string —
|
|
36
42
|
* **lowcap/Enigma only**; ignored on any other solver kind. When omitted
|
|
37
|
-
* on a lowcap solver, fetched via `GET /estimated-price`.
|
|
43
|
+
* on a lowcap solver, fetched via `GET /estimated-price`. Pass `null` when
|
|
44
|
+
* an estimate was attempted but unavailable to skip fetching and use the fallback.
|
|
45
|
+
*/
|
|
46
|
+
estimatedOpenPrice?: string | null;
|
|
47
|
+
/**
|
|
48
|
+
* Pre-fetched solver locked params (matches `getLockedParams` return).
|
|
49
|
+
* Consulted for explicit or automatic full-balance sizing, which needs the
|
|
50
|
+
* locked-param percents; when omitted there, fetched via `getLockedParams`.
|
|
38
51
|
*/
|
|
39
|
-
|
|
52
|
+
lockedParamPercent?: ApiLockedParamsBySymbolIdResponse;
|
|
53
|
+
/**
|
|
54
|
+
* Pre-fetched solver static fees (matches `getSolverInfo` return) —
|
|
55
|
+
* **lowcap/Enigma only**; ignored on any other solver kind. When omitted on
|
|
56
|
+
* a lowcap solver, fetched via `getSolverInfo` (fail-soft: an unreachable
|
|
57
|
+
* `/info` prices the static open leg at `"0"`).
|
|
58
|
+
*/
|
|
59
|
+
solverInfo?: EnigmaSolverInfo;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Parameters for {@link getInstantOpenFees}. A subset of
|
|
63
|
+
* `PrepareInstantOpenParameters` — the trade intent plus optional pre-fetched
|
|
64
|
+
* data; every pre-filled optional field skips its network fetch.
|
|
65
|
+
*
|
|
66
|
+
* The funding source mirrors `prepareInstantOpenParams`: pass a typed
|
|
67
|
+
* `initialMargin`, **or** `fund` ({@link FullBalanceFunding}, lowcap only) to
|
|
68
|
+
* preview a full-balance open — the preview then runs the same
|
|
69
|
+
* probe-and-rescale sizing as the open, so its legs and `quantity` equal what
|
|
70
|
+
* the open charges. Provide exactly one; passing both, or neither, throws.
|
|
71
|
+
* With `initialMargin`, `availableBalance` opts into automatic full-balance sizing
|
|
72
|
+
* only when the typed position's required funding exceeds the raw balance.
|
|
73
|
+
* The typed initialMargin itself must not exceed availableBalance.
|
|
74
|
+
*/
|
|
75
|
+
export type GetInstantOpenFeesParameters = Compute<BaseGetInstantOpenFeesParameters & {
|
|
76
|
+
/** Collateral (USD) the user enters as initial margin. Decimal string. Provide this **or** `fund`. */
|
|
77
|
+
initialMargin?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Raw available collateral (USD decimal string). With initialMargin, previews the
|
|
80
|
+
* same automatic full-balance fallback as prepareInstantOpenParams. Lowcap only;
|
|
81
|
+
* must be positive and finite. initialMargin above this balance throws. Cannot accompany fund.
|
|
82
|
+
*/
|
|
83
|
+
availableBalance?: string;
|
|
84
|
+
/**
|
|
85
|
+
* Preview a full-balance open — lowcap (Enigma) only. Provide this **or**
|
|
86
|
+
* `initialMargin`. See {@link FullBalanceFunding}.
|
|
87
|
+
*/
|
|
88
|
+
fund?: FullBalanceFunding;
|
|
40
89
|
}>;
|
|
41
90
|
/**
|
|
42
|
-
* Fee legs every solver kind charges
|
|
91
|
+
* Fee legs every solver kind charges **at open**. Close fees are charged at
|
|
92
|
+
* close from the position — preview them in the close flow with
|
|
93
|
+
* `getInstantCloseFees`, where the notional and holding time are real.
|
|
43
94
|
*/
|
|
44
95
|
export interface BaseInstantOpenFees {
|
|
96
|
+
/** Effective sizing mode, including automatic fallback from a typed initial margin. */
|
|
97
|
+
fundingMode: "initial-margin" | "full-balance";
|
|
45
98
|
/** Platform open fee: `getFeeForUser.openFee × notional / 1e18` (decimal string). */
|
|
46
99
|
platformOpenFee: string;
|
|
47
|
-
/** Platform close fee, provisioned at open: `getFeeForUser.closeFee × notional / 1e18` (decimal string). */
|
|
48
|
-
platformCloseFee: string;
|
|
49
100
|
/** Leveraged notional the fee rates were applied to (decimal string). */
|
|
50
101
|
notional: string;
|
|
51
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Leveraged base-asset quantity the legs were computed on (decimal string) —
|
|
104
|
+
* in full-balance mode this is the rescaled, lot-snapped size the open will
|
|
105
|
+
* actually submit. Feed this to TP/SL and constraint previews instead of
|
|
106
|
+
* re-deriving from the typed margin.
|
|
107
|
+
*/
|
|
108
|
+
quantity: string;
|
|
109
|
+
/**
|
|
110
|
+
* Sum of every leg the open charges now (decimal string). Includes the
|
|
111
|
+
* settlement provision by default; pass `includeSettlementInTotalFee: false`
|
|
112
|
+
* to sum the fee legs only.
|
|
113
|
+
*/
|
|
52
114
|
totalFee: string;
|
|
53
115
|
}
|
|
54
116
|
/**
|
|
55
117
|
* Fee breakdown for a **lowcap (Enigma)** instant open. Extends the platform
|
|
56
|
-
*
|
|
57
|
-
* from the VA balance.
|
|
118
|
+
* leg with the solver open legs and the settlement provision the solver
|
|
119
|
+
* charges from the VA balance.
|
|
58
120
|
*/
|
|
59
121
|
export interface EnigmaInstantOpenFees extends BaseInstantOpenFees {
|
|
60
122
|
/** Discriminant: these fees were priced for an Enigma (lowcap) solver. */
|
|
61
123
|
kind: "enigma";
|
|
62
124
|
/** Solver open fee: `hedgerFeeOpen × notional` (decimal string). */
|
|
63
125
|
openSolverFee: string;
|
|
64
|
-
/**
|
|
65
|
-
* Solver close fee provisioned at open (decimal string). Because the holding
|
|
66
|
-
* time is unknown at open and an early close costs more, this is the
|
|
67
|
-
* worst-case `earlyRate × notional` from the market's close-fee schedule
|
|
68
|
-
* (falling back to the flat `hedgerFeeClose × notional` when no schedule is
|
|
69
|
-
* available).
|
|
70
|
-
*/
|
|
71
|
-
closeSolverFee: string;
|
|
72
126
|
/**
|
|
73
127
|
* Expected settlement loss vs the dry-run estimate: side-aware
|
|
74
128
|
* `max(0, adverse fill deviation × quantity)` (decimal string). `"0"` when
|
|
75
129
|
* no usable estimate exists.
|
|
76
130
|
*/
|
|
77
131
|
expectedSettlementLoss: string;
|
|
132
|
+
/**
|
|
133
|
+
* Static solver fee charged per instant open — a flat USD amount from the
|
|
134
|
+
* solver's `/info` config, independent of the notional (decimal string).
|
|
135
|
+
* `"0"` when the solver publishes none.
|
|
136
|
+
*/
|
|
137
|
+
staticSolverFeeOpen: string;
|
|
78
138
|
}
|
|
79
139
|
/**
|
|
80
|
-
* Fee breakdown for a **majors (Rasa)** instant open — platform
|
|
140
|
+
* Fee breakdown for a **majors (Rasa)** instant open — the platform open leg
|
|
141
|
+
* only.
|
|
81
142
|
*/
|
|
82
143
|
export interface RasaInstantOpenFees extends BaseInstantOpenFees {
|
|
83
144
|
/** Discriminant: these fees were priced for a Rasa (majors) solver. */
|
|
@@ -89,25 +150,39 @@ export interface RasaInstantOpenFees extends BaseInstantOpenFees {
|
|
|
89
150
|
*/
|
|
90
151
|
export type GetInstantOpenFeesReturnType = EnigmaInstantOpenFees | RasaInstantOpenFees;
|
|
91
152
|
/**
|
|
92
|
-
* Preview every fee a new instant-open quote pays
|
|
93
|
-
* total — without signing or submitting anything.
|
|
153
|
+
* Preview every fee a new instant-open quote pays **at open**, separated by leg
|
|
154
|
+
* plus the total — without signing or submitting anything.
|
|
94
155
|
*
|
|
95
156
|
* Mirrors the exact resolution and math `prepareInstantOpenParams` uses, so
|
|
96
157
|
* the preview equals what the open charges for the same inputs:
|
|
97
158
|
*
|
|
98
|
-
* - **Both kinds**: `platformOpenFee`
|
|
99
|
-
*
|
|
100
|
-
* - **Lowcap (Enigma) only**: `openSolverFee` (`hedgerFeeOpen × notional`)
|
|
101
|
-
* `
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
159
|
+
* - **Both kinds**: `platformOpenFee` (on-chain `getFeeForUser.openFee` ×
|
|
160
|
+
* leveraged notional).
|
|
161
|
+
* - **Lowcap (Enigma) only**: `openSolverFee` (`hedgerFeeOpen × notional`),
|
|
162
|
+
* `staticSolverFeeOpen` (flat USD from the solver's `/info` config,
|
|
163
|
+
* size-independent) and `expectedSettlementLoss` (dry-run estimate vs mark)
|
|
164
|
+
* — the legs the solver charges from the VA balance.
|
|
165
|
+
*
|
|
166
|
+
* Close fees (platform close, solver close, static close) are **not** part of
|
|
167
|
+
* this preview: they are charged at close from the position, priced by
|
|
168
|
+
* `getInstantCloseFees` in the close flow from the then-current notional and
|
|
169
|
+
* the position's real holding time.
|
|
170
|
+
*
|
|
171
|
+
* `totalFee` sums every open leg. It includes the settlement provision by
|
|
172
|
+
* default — the amount the user must fund even though the settlement leg is a
|
|
173
|
+
* provision rather than a fee the solver keeps; pass
|
|
174
|
+
* `includeSettlementInTotalFee: false` to sum the fee legs only.
|
|
105
175
|
*
|
|
106
|
-
* `
|
|
107
|
-
*
|
|
108
|
-
*
|
|
176
|
+
* With `fund` ({@link FullBalanceFunding}) instead of `initialMargin`, the
|
|
177
|
+
* preview runs the same probe-and-rescale sizing as the open — lot snap, cost
|
|
178
|
+
* invariant, slippage-bound settlement fallback included — so the reported
|
|
179
|
+
* legs and `quantity` are those of the trade the open will actually submit.
|
|
109
180
|
*
|
|
110
181
|
* @throws {SymmError} `SLIPPAGE_REQUIRED` on majors without `slippage`;
|
|
182
|
+
* `AMBIGUOUS_FUNDING` / `INITIAL_MARGIN_REQUIRED` /
|
|
183
|
+
* `FULL_BALANCE_UNSUPPORTED` for a broken funding one-of;
|
|
184
|
+
* `QUOTE_CONSTRAINT_VIOLATED` when the full-balance sizing violates a
|
|
185
|
+
* published market constraint;
|
|
111
186
|
* `INVALID_SLIPPAGE` / `INVALID_TRADE_PARAMETERS` /
|
|
112
187
|
* `RESOLVE_MARKET_NOT_FOUND` / `RESOLVE_MARK_PRICE_NOT_FOUND` for invalid or
|
|
113
188
|
* unresolvable inputs.
|
|
@@ -126,4 +201,5 @@ export type GetInstantOpenFeesReturnType = EnigmaInstantOpenFees | RasaInstantOp
|
|
|
126
201
|
* ```
|
|
127
202
|
*/
|
|
128
203
|
export declare function getInstantOpenFees(config: Config, parameters: GetInstantOpenFeesParameters): Promise<GetInstantOpenFeesReturnType>;
|
|
204
|
+
export {};
|
|
129
205
|
//# sourceMappingURL=get-instant-open-fees.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-instant-open-fees.d.ts","sourceRoot":"","sources":["../../../../src/solvers/instant-open/get-instant-open-fees/get-instant-open-fees.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2DAA2D,CAAC;
|
|
1
|
+
{"version":3,"file":"get-instant-open-fees.d.ts","sourceRoot":"","sources":["../../../../src/solvers/instant-open/get-instant-open-fees/get-instant-open-fees.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2DAA2D,CAAC;AAC5F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,qCAAqC,CAAC;AAC7F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAgBzE,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE3E;;GAEG;AACH,KAAK,gCAAgC,GAAG,mBAAmB,GAAG;IAC5D,wEAAwE;IACxE,iBAAiB,EAAE,OAAO,CAAC;IAC3B,uEAAuE;IACvE,MAAM,EAAE,qBAAqB,CAAC;IAC9B,kBAAkB;IAClB,YAAY,EAAE,YAAY,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,6FAA6F;IAC7F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,iCAAiC,CAAC;IACvD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,4BAA4B,GAAG,OAAO,CAChD,gCAAgC,GAAG;IACjC,sGAAsG;IACtG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,kBAAkB,CAAC;CAC3B,CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,uFAAuF;IACvF,WAAW,EAAE,gBAAgB,GAAG,cAAc,CAAC;IAC/C,qFAAqF;IACrF,eAAe,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAsB,SAAQ,mBAAmB;IAChE,0EAA0E;IAC1E,IAAI,EAAE,QAAQ,CAAC;IACf,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,sBAAsB,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC9D,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,MAAM,4BAA4B,GAAG,qBAAqB,GAAG,mBAAmB,CAAC;AAEvF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,4BAA4B,GACvC,OAAO,CAAC,4BAA4B,CAAC,CAwPvC"}
|
|
@@ -1,115 +1,192 @@
|
|
|
1
1
|
import { SymmError as e } from "../../../shared/errors/symm-error.js";
|
|
2
2
|
import { calculateExpectedSettlementLoss as t, calculateSolverFees as n, calculateTradeParams as r, computePlatformFeeLegs as i } from "../shared/trade-math.js";
|
|
3
3
|
import { assertValidSlippage as a, deriveAutoSlippage as o, fetchOpenEstimatePrice as s } from "../shared/open-estimate-guard.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { resolveInstantOpenSizing as c, validateInstantOpenBalanceFunding as l } from "../shared/resolve-instant-open-sizing.js";
|
|
5
|
+
import { resolveFeeRates as u } from "../../shared/resolvers/resolve-fee-rates.js";
|
|
6
|
+
import { resolveMarkPrice as d } from "../../shared/resolvers/resolve-mark-price.js";
|
|
7
|
+
import { resolveMarket as f } from "../../shared/resolvers/resolve-market.js";
|
|
8
|
+
import { resolveSolverInfo as p } from "../../shared/resolvers/resolve-solver-info.js";
|
|
9
|
+
import { resolveLockedParams as m } from "../prepare-instant-open-params/resolvers/resolve-locked-params.js";
|
|
10
|
+
import { toDecimal as h } from "@symmio/utils/decimal";
|
|
8
11
|
//#region src/solvers/instant-open/get-instant-open-fees/get-instant-open-fees.ts
|
|
9
|
-
async function
|
|
10
|
-
|
|
11
|
-
let
|
|
12
|
-
chainId:
|
|
13
|
-
solverId:
|
|
12
|
+
async function g(g, _) {
|
|
13
|
+
_.slippage !== void 0 && a(_.slippage);
|
|
14
|
+
let v = g.getSolver({
|
|
15
|
+
chainId: _.chainId,
|
|
16
|
+
solverId: _.solverId
|
|
14
17
|
}).id === "enigma";
|
|
15
|
-
if (
|
|
16
|
-
let
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
18
|
+
if (_.slippage === void 0 && !v) throw new e("validation", "SLIPPAGE_REQUIRED", "getInstantOpenFees: slippage is required on this solver — auto-derived slippage is lowcap-only.");
|
|
19
|
+
let y = _.fund !== void 0;
|
|
20
|
+
l({
|
|
21
|
+
..._,
|
|
22
|
+
isLowcap: v
|
|
23
|
+
});
|
|
24
|
+
let b = y || _.availableBalance !== void 0;
|
|
25
|
+
if (y && _.initialMargin !== void 0) throw new e("validation", "AMBIGUOUS_FUNDING", "getInstantOpenFees: pass exactly one of initialMargin or fund, not both.");
|
|
26
|
+
if (y && !v) throw new e("validation", "FULL_BALANCE_UNSUPPORTED", "getInstantOpenFees: full-balance funding is lowcap (Enigma) only — pass initialMargin on this solver.");
|
|
27
|
+
if (!y && _.initialMargin === void 0) throw new e("validation", "INITIAL_MARGIN_REQUIRED", "getInstantOpenFees: pass initialMargin, or fund: { mode: 'full-balance', balance } on a lowcap solver.");
|
|
28
|
+
let x = y ? _.fund.balance : _.initialMargin, S = _.includeSettlementInTotalFee ?? !0, C = await f(g, {
|
|
29
|
+
chainId: _.chainId,
|
|
30
|
+
solverId: _.solverId,
|
|
31
|
+
marketId: _.market.id,
|
|
32
|
+
marketName: _.market.name,
|
|
33
|
+
pricePrecision: _.market.pricePrecision,
|
|
34
|
+
quantityPrecision: _.market.quantityPrecision,
|
|
35
|
+
hedgerFeeOpen: _.market.hedgerFeeOpen,
|
|
36
|
+
hedgerFeeClose: _.market.hedgerFeeClose,
|
|
37
|
+
hedgerFeeCloseEarlyRate: _.market.hedgerFeeCloseEarlyRate,
|
|
38
|
+
hedgerFeeCloseEarlyThreshold: _.market.hedgerFeeCloseEarlyThreshold,
|
|
39
|
+
hedgerFeeCloseStandardThreshold: _.market.hedgerFeeCloseStandardThreshold,
|
|
40
|
+
includeHedgerFees: v,
|
|
41
|
+
includeQuoteConstraints: b,
|
|
42
|
+
minAcceptablePortionLf: _.market.minAcceptablePortionLf,
|
|
43
|
+
minAcceptableQuoteValue: _.market.minAcceptableQuoteValue,
|
|
44
|
+
maxNotionalValue: _.market.maxNotionalValue,
|
|
45
|
+
minNotionalValue: _.market.minNotionalValue,
|
|
46
|
+
maxQuantity: _.market.maxQuantity,
|
|
47
|
+
lotSize: _.market.lotSize
|
|
48
|
+
}), [w, T, E, D] = await Promise.all([
|
|
49
|
+
d(g, {
|
|
50
|
+
chainId: _.chainId,
|
|
51
|
+
solverId: _.solverId,
|
|
52
|
+
marketName: C.name,
|
|
53
|
+
markPrice: _.markPrice
|
|
54
|
+
}),
|
|
55
|
+
u(g, {
|
|
56
|
+
chainId: _.chainId,
|
|
57
|
+
subAccountAddress: _.subAccountAddress,
|
|
58
|
+
marketId: _.market.id,
|
|
59
|
+
feeRates: _.feeRates
|
|
60
|
+
}),
|
|
61
|
+
b ? m(g, {
|
|
62
|
+
chainId: _.chainId,
|
|
63
|
+
solverId: _.solverId,
|
|
64
|
+
marketName: C.name,
|
|
65
|
+
leverage: _.leverage,
|
|
66
|
+
lockedParamPercent: _.lockedParamPercent
|
|
67
|
+
}) : Promise.resolve(void 0),
|
|
68
|
+
v ? p(g, {
|
|
69
|
+
chainId: _.chainId,
|
|
70
|
+
solverId: _.solverId,
|
|
71
|
+
solverInfo: _.solverInfo
|
|
72
|
+
}) : Promise.resolve({
|
|
73
|
+
staticSolverFeeOpen: "0",
|
|
74
|
+
staticSolverFeeClose: "0"
|
|
75
|
+
})
|
|
76
|
+
]), O = {
|
|
77
|
+
markPrice: w,
|
|
78
|
+
positionType: _.positionType,
|
|
79
|
+
userInput: x,
|
|
43
80
|
inputField: "PRICE",
|
|
44
|
-
leverage:
|
|
45
|
-
pricePrecision:
|
|
46
|
-
quantityPrecision:
|
|
47
|
-
|
|
48
|
-
|
|
81
|
+
leverage: _.leverage,
|
|
82
|
+
pricePrecision: C.pricePrecision,
|
|
83
|
+
quantityPrecision: C.quantityPrecision,
|
|
84
|
+
...E ? {
|
|
85
|
+
cvaPercent: E.cva,
|
|
86
|
+
lfPercent: E.lf,
|
|
87
|
+
partyAmmPercent: E.partyAmm,
|
|
88
|
+
partyBmmPercent: E.partyBmm
|
|
89
|
+
} : {}
|
|
90
|
+
}, k = _.slippage, A = v ? _.estimatedOpenPrice ?? void 0 : void 0, j = v && _.estimatedOpenPrice === void 0;
|
|
91
|
+
if (k === void 0) {
|
|
49
92
|
let t = r({
|
|
50
|
-
...
|
|
93
|
+
...O,
|
|
51
94
|
slippage: 0
|
|
52
95
|
});
|
|
53
96
|
if (!t) throw new e("validation", "INVALID_TRADE_PARAMETERS", "Invalid trade parameters: markPrice or initialMargin is zero/NaN.");
|
|
54
|
-
|
|
55
|
-
chainId:
|
|
56
|
-
solverId:
|
|
57
|
-
symbolId:
|
|
58
|
-
positionType:
|
|
97
|
+
j && (j = !1, A = await s(g, {
|
|
98
|
+
chainId: _.chainId,
|
|
99
|
+
solverId: _.solverId,
|
|
100
|
+
symbolId: _.market.id,
|
|
101
|
+
positionType: _.positionType,
|
|
59
102
|
quantity: t.quantity,
|
|
60
|
-
markPrice:
|
|
61
|
-
})),
|
|
62
|
-
markPrice:
|
|
63
|
-
expectedFillPrice:
|
|
64
|
-
positionType:
|
|
103
|
+
markPrice: w
|
|
104
|
+
})), k = o({
|
|
105
|
+
markPrice: w,
|
|
106
|
+
expectedFillPrice: A,
|
|
107
|
+
positionType: _.positionType
|
|
65
108
|
});
|
|
66
109
|
}
|
|
67
|
-
let
|
|
68
|
-
...
|
|
69
|
-
slippage:
|
|
110
|
+
let M = r({
|
|
111
|
+
...O,
|
|
112
|
+
slippage: k
|
|
70
113
|
});
|
|
71
|
-
if (!
|
|
72
|
-
|
|
73
|
-
chainId:
|
|
74
|
-
solverId:
|
|
75
|
-
symbolId:
|
|
76
|
-
positionType:
|
|
77
|
-
quantity:
|
|
78
|
-
markPrice:
|
|
79
|
-
}))
|
|
80
|
-
|
|
81
|
-
|
|
114
|
+
if (!M) throw new e("validation", "INVALID_TRADE_PARAMETERS", "Invalid trade parameters: markPrice or initialMargin is zero/NaN.");
|
|
115
|
+
if (j && (A = await s(g, {
|
|
116
|
+
chainId: _.chainId,
|
|
117
|
+
solverId: _.solverId,
|
|
118
|
+
symbolId: _.market.id,
|
|
119
|
+
positionType: _.positionType,
|
|
120
|
+
quantity: M.quantity,
|
|
121
|
+
markPrice: w
|
|
122
|
+
})), b) {
|
|
123
|
+
let { trade: e, costs: t, fundingMode: n } = c({
|
|
124
|
+
trade: M,
|
|
125
|
+
isLowcap: v,
|
|
126
|
+
fund: _.fund,
|
|
127
|
+
availableBalance: _.availableBalance,
|
|
128
|
+
calculationInput: {
|
|
129
|
+
...O,
|
|
130
|
+
slippage: k
|
|
131
|
+
},
|
|
132
|
+
expectedFillPrice: A === "0" ? void 0 : A,
|
|
133
|
+
feeRates: T,
|
|
134
|
+
hedgerFeeOpen: C.hedgerFeeOpen,
|
|
135
|
+
staticSolverFeeOpen: D.staticSolverFeeOpen,
|
|
136
|
+
constraints: {
|
|
137
|
+
minAcceptablePortionLf: C.minAcceptablePortionLf,
|
|
138
|
+
minAcceptableQuoteValue: C.minAcceptableQuoteValue,
|
|
139
|
+
maxNotionalValue: C.maxNotionalValue,
|
|
140
|
+
minNotionalValue: C.minNotionalValue,
|
|
141
|
+
maxQuantity: C.maxQuantity,
|
|
142
|
+
lotSize: C.lotSize
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
return {
|
|
146
|
+
fundingMode: n,
|
|
147
|
+
kind: "enigma",
|
|
148
|
+
platformOpenFee: t.platformOpenFee,
|
|
149
|
+
notional: e.notional,
|
|
150
|
+
quantity: e.quantity,
|
|
151
|
+
openSolverFee: t.openSolverFee,
|
|
152
|
+
staticSolverFeeOpen: t.staticSolverFeeOpen,
|
|
153
|
+
expectedSettlementLoss: t.expectedSettlementLoss,
|
|
154
|
+
totalFee: h(t.platformOpenFee).plus(t.openSolverFee).plus(t.staticSolverFeeOpen).plus(S ? t.expectedSettlementLoss : "0").toString()
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
let { platformOpenFee: N } = i(T, M.notional, M.notional);
|
|
158
|
+
if (!v) return {
|
|
159
|
+
fundingMode: "initial-margin",
|
|
82
160
|
kind: "rasa",
|
|
83
|
-
platformOpenFee:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
totalFee:
|
|
161
|
+
platformOpenFee: N,
|
|
162
|
+
notional: M.notional,
|
|
163
|
+
quantity: M.quantity,
|
|
164
|
+
totalFee: N
|
|
87
165
|
};
|
|
88
|
-
let { openSolverFee:
|
|
89
|
-
notional:
|
|
90
|
-
hedgerFeeOpen:
|
|
91
|
-
hedgerFeeClose:
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
expectedFillPrice: b,
|
|
99
|
-
quantity: x.quantity
|
|
166
|
+
let { openSolverFee: P, staticSolverFeeOpen: F } = n({
|
|
167
|
+
notional: M.notional,
|
|
168
|
+
hedgerFeeOpen: C.hedgerFeeOpen,
|
|
169
|
+
hedgerFeeClose: void 0,
|
|
170
|
+
staticSolverFeeOpen: D.staticSolverFeeOpen
|
|
171
|
+
}), I = t({
|
|
172
|
+
positionType: _.positionType,
|
|
173
|
+
markPrice: w,
|
|
174
|
+
expectedFillPrice: A,
|
|
175
|
+
quantity: M.quantity
|
|
100
176
|
});
|
|
101
177
|
return {
|
|
178
|
+
fundingMode: "initial-margin",
|
|
102
179
|
kind: "enigma",
|
|
103
|
-
platformOpenFee:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
openSolverFee:
|
|
107
|
-
|
|
108
|
-
expectedSettlementLoss:
|
|
109
|
-
totalFee:
|
|
180
|
+
platformOpenFee: N,
|
|
181
|
+
notional: M.notional,
|
|
182
|
+
quantity: M.quantity,
|
|
183
|
+
openSolverFee: P,
|
|
184
|
+
staticSolverFeeOpen: F,
|
|
185
|
+
expectedSettlementLoss: I,
|
|
186
|
+
totalFee: h(N).plus(P).plus(F).plus(S ? I : "0").toString()
|
|
110
187
|
};
|
|
111
188
|
}
|
|
112
189
|
//#endregion
|
|
113
|
-
export {
|
|
190
|
+
export { g as getInstantOpenFees };
|
|
114
191
|
|
|
115
192
|
//# sourceMappingURL=get-instant-open-fees.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-instant-open-fees.js","names":[],"sources":["../../../../src/solvers/instant-open/get-instant-open-fees/get-instant-open-fees.ts"],"sourcesContent":["import { toDecimal } from \"@symmio/utils/decimal\";\nimport type { Address } from \"viem\";\nimport type { Config } from \"../../../core/config\";\nimport { SymmError } from \"../../../shared/errors/symm-error\";\nimport type { Compute, ReadSolverParameter } from \"../../../shared/types/properties\";\nimport type { FeeForUser } from \"../../../symmio-contracts/symmio/actions/get-fee-for-user\";\nimport { resolveFeeRates, resolveMarket, resolveMarkPrice } from \"../prepare-instant-open-params/resolvers\";\nimport { assertValidSlippage, deriveAutoSlippage, fetchOpenEstimatePrice } from \"../shared/open-estimate-guard\";\nimport {\n calculateExpectedSettlementLoss,\n calculateSolverFees,\n calculateTradeParams,\n computePlatformFeeLegs,\n} from \"../shared/trade-math\";\nimport type { InstantOpenMarketData, PositionType } from \"../shared/types\";\n\n/**\n * Parameters for {@link getInstantOpenFees}. A subset of\n * `PrepareInstantOpenParameters` — the trade intent plus optional pre-fetched\n * data; every pre-filled optional field skips its network fetch.\n */\nexport type GetInstantOpenFeesParameters = Compute<\n ReadSolverParameter & {\n /** Sub-account / partyA address the platform fee rates are read for. */\n subAccountAddress: Address;\n /** Market identification + optional pre-fetched precision metadata. */\n market: InstantOpenMarketData;\n /** Trade side. */\n positionType: PositionType;\n /** Collateral (USD) the user enters as initial margin. Decimal string. */\n initialMargin: string;\n /** Position leverage (integer ≥ 1). */\n leverage: number;\n /**\n * Slippage tolerance percent (e.g. `5` for 5%). **Required on majors\n * (non-lowcap) solvers.** On a lowcap solver it may be omitted to\n * auto-derive from the dry-run estimate plus 4% headroom — the same rule\n * as `prepareInstantOpenParams`, so the preview prices what the open will\n * actually charge.\n */\n slippage?: number;\n /** Pre-fetched mark price as decimal string. When omitted, fetched via the price service. */\n markPrice?: string;\n /** Pre-fetched on-chain fee rates (matches `getFeeForUser` return). When omitted, fetched. */\n feeRates?: FeeForUser;\n /**\n * Pre-fetched solver estimated open (fill) price as decimal string —\n * **lowcap/Enigma only**; ignored on any other solver kind. When omitted\n * on a lowcap solver, fetched via `GET /estimated-price`.\n */\n estimatedOpenPrice?: string;\n }\n>;\n\n/**\n * Fee legs every solver kind charges on an instant open.\n */\nexport interface BaseInstantOpenFees {\n /** Platform open fee: `getFeeForUser.openFee × notional / 1e18` (decimal string). */\n platformOpenFee: string;\n /** Platform close fee, provisioned at open: `getFeeForUser.closeFee × notional / 1e18` (decimal string). */\n platformCloseFee: string;\n /** Leveraged notional the fee rates were applied to (decimal string). */\n notional: string;\n /** Sum of every fee leg on this quote (decimal string). */\n totalFee: string;\n}\n\n/**\n * Fee breakdown for a **lowcap (Enigma)** instant open. Extends the platform\n * legs with the solver fees and the settlement provision the solver charges\n * from the VA balance.\n */\nexport interface EnigmaInstantOpenFees extends BaseInstantOpenFees {\n /** Discriminant: these fees were priced for an Enigma (lowcap) solver. */\n kind: \"enigma\";\n /** Solver open fee: `hedgerFeeOpen × notional` (decimal string). */\n openSolverFee: string;\n /**\n * Solver close fee provisioned at open (decimal string). Because the holding\n * time is unknown at open and an early close costs more, this is the\n * worst-case `earlyRate × notional` from the market's close-fee schedule\n * (falling back to the flat `hedgerFeeClose × notional` when no schedule is\n * available).\n */\n closeSolverFee: string;\n /**\n * Expected settlement loss vs the dry-run estimate: side-aware\n * `max(0, adverse fill deviation × quantity)` (decimal string). `\"0\"` when\n * no usable estimate exists.\n */\n expectedSettlementLoss: string;\n}\n\n/**\n * Fee breakdown for a **majors (Rasa)** instant open — platform legs only.\n */\nexport interface RasaInstantOpenFees extends BaseInstantOpenFees {\n /** Discriminant: these fees were priced for a Rasa (majors) solver. */\n kind: \"rasa\";\n}\n\n/**\n * Return type of {@link getInstantOpenFees}. Narrow on `kind` to reach the\n * lowcap-only legs.\n */\nexport type GetInstantOpenFeesReturnType = EnigmaInstantOpenFees | RasaInstantOpenFees;\n\n/**\n * Preview every fee a new instant-open quote pays, separated by leg plus the\n * total — without signing or submitting anything.\n *\n * Mirrors the exact resolution and math `prepareInstantOpenParams` uses, so\n * the preview equals what the open charges for the same inputs:\n *\n * - **Both kinds**: `platformOpenFee` + `platformCloseFee`\n * (on-chain `getFeeForUser` rates × leveraged notional).\n * - **Lowcap (Enigma) only**: `openSolverFee` (`hedgerFeeOpen × notional`) +\n * `closeSolverFee` (the worst-case close rate × notional — see\n * {@link EnigmaInstantOpenFees.closeSolverFee}) and\n * `expectedSettlementLoss` (dry-run estimate vs mark) — the legs the solver\n * charges from the VA balance.\n *\n * `totalFee` sums every leg, including the settlement provision — it is the\n * amount the user must fund even though the settlement leg is a provision\n * rather than a fee the solver keeps.\n *\n * @throws {SymmError} `SLIPPAGE_REQUIRED` on majors without `slippage`;\n * `INVALID_SLIPPAGE` / `INVALID_TRADE_PARAMETERS` /\n * `RESOLVE_MARKET_NOT_FOUND` / `RESOLVE_MARK_PRICE_NOT_FOUND` for invalid or\n * unresolvable inputs.\n *\n * @example\n * ```ts\n * const fees = await getInstantOpenFees(config, {\n * subAccountAddress,\n * market: { id: 1 },\n * positionType: PositionType.LONG,\n * initialMargin: \"100\",\n * leverage: 5,\n * });\n * if (fees.kind === \"enigma\") console.log(fees.openSolverFee, fees.expectedSettlementLoss);\n * console.log(fees.totalFee);\n * ```\n */\nexport async function getInstantOpenFees(\n config: Config,\n parameters: GetInstantOpenFeesParameters,\n): Promise<GetInstantOpenFeesReturnType> {\n if (parameters.slippage !== undefined) assertValidSlippage(parameters.slippage);\n\n /** Estimate-driven legs exist only on lowcap (Enigma) solvers — a majors preview is platform legs only. */\n const isLowcap = config.getSolver({ chainId: parameters.chainId, solverId: parameters.solverId }).id === \"enigma\";\n if (parameters.slippage === undefined && !isLowcap) {\n throw new SymmError(\n \"validation\",\n \"SLIPPAGE_REQUIRED\",\n \"getInstantOpenFees: slippage is required on this solver — auto-derived slippage is lowcap-only.\",\n );\n }\n\n const market = await resolveMarket(config, {\n chainId: parameters.chainId,\n solverId: parameters.solverId,\n marketId: parameters.market.id,\n marketName: parameters.market.name,\n pricePrecision: parameters.market.pricePrecision,\n quantityPrecision: parameters.market.quantityPrecision,\n hedgerFeeOpen: parameters.market.hedgerFeeOpen,\n hedgerFeeClose: parameters.market.hedgerFeeClose,\n hedgerFeeCloseEarlyRate: parameters.market.hedgerFeeCloseEarlyRate,\n hedgerFeeCloseEarlyThreshold: parameters.market.hedgerFeeCloseEarlyThreshold,\n hedgerFeeCloseStandardThreshold: parameters.market.hedgerFeeCloseStandardThreshold,\n includeHedgerFees: isLowcap,\n });\n const [markPrice, feeRates] = await Promise.all([\n resolveMarkPrice(config, {\n chainId: parameters.chainId,\n solverId: parameters.solverId,\n marketName: market.name,\n markPrice: parameters.markPrice,\n }),\n resolveFeeRates(config, {\n chainId: parameters.chainId,\n subAccountAddress: parameters.subAccountAddress,\n marketId: parameters.market.id,\n feeRates: parameters.feeRates,\n }),\n ]);\n\n const calculationInput = {\n markPrice,\n positionType: parameters.positionType,\n userInput: parameters.initialMargin,\n inputField: \"PRICE\" as const,\n leverage: parameters.leverage,\n pricePrecision: market.pricePrecision,\n quantityPrecision: market.quantityPrecision,\n };\n\n let slippage = parameters.slippage;\n let expectedFillPrice = isLowcap ? parameters.estimatedOpenPrice : undefined;\n if (slippage === undefined) {\n const sized = calculateTradeParams({ ...calculationInput, slippage: 0 });\n if (!sized) {\n throw new SymmError(\n \"validation\",\n \"INVALID_TRADE_PARAMETERS\",\n \"Invalid trade parameters: markPrice or initialMargin is zero/NaN.\",\n );\n }\n if (isLowcap && expectedFillPrice === undefined) {\n expectedFillPrice = await fetchOpenEstimatePrice(config, {\n chainId: parameters.chainId,\n solverId: parameters.solverId,\n symbolId: parameters.market.id,\n positionType: parameters.positionType,\n quantity: sized.quantity,\n markPrice,\n });\n }\n slippage = deriveAutoSlippage({ markPrice, expectedFillPrice, positionType: parameters.positionType });\n }\n\n const tradeCalc = calculateTradeParams({ ...calculationInput, slippage });\n if (!tradeCalc) {\n throw new SymmError(\n \"validation\",\n \"INVALID_TRADE_PARAMETERS\",\n \"Invalid trade parameters: markPrice or initialMargin is zero/NaN.\",\n );\n }\n\n if (isLowcap && expectedFillPrice === undefined) {\n expectedFillPrice = await fetchOpenEstimatePrice(config, {\n chainId: parameters.chainId,\n solverId: parameters.solverId,\n symbolId: parameters.market.id,\n positionType: parameters.positionType,\n quantity: tradeCalc.quantity,\n markPrice,\n });\n }\n\n const { platformOpenFee, platformCloseFee } = computePlatformFeeLegs(\n feeRates,\n tradeCalc.notional,\n tradeCalc.notional,\n );\n\n if (!isLowcap) {\n return {\n kind: \"rasa\",\n platformOpenFee,\n platformCloseFee,\n notional: tradeCalc.notional,\n totalFee: toDecimal(platformOpenFee).plus(platformCloseFee).toString(),\n };\n }\n\n const { openSolverFee, closeSolverFee } = calculateSolverFees({\n notional: tradeCalc.notional,\n hedgerFeeOpen: market.hedgerFeeOpen,\n hedgerFeeClose: market.hedgerFeeClose,\n hedgerFeeCloseEarlyRate: market.hedgerFeeCloseEarlyRate,\n hedgerFeeCloseEarlyThreshold: market.hedgerFeeCloseEarlyThreshold,\n hedgerFeeCloseStandardThreshold: market.hedgerFeeCloseStandardThreshold,\n });\n const expectedSettlementLoss = calculateExpectedSettlementLoss({\n positionType: parameters.positionType,\n markPrice,\n expectedFillPrice,\n quantity: tradeCalc.quantity,\n });\n\n return {\n kind: \"enigma\",\n platformOpenFee,\n platformCloseFee,\n notional: tradeCalc.notional,\n openSolverFee,\n closeSolverFee,\n expectedSettlementLoss,\n totalFee: toDecimal(platformOpenFee)\n .plus(platformCloseFee)\n .plus(openSolverFee)\n .plus(closeSolverFee)\n .plus(expectedSettlementLoss)\n .toString(),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"get-instant-open-fees.js","names":[],"sources":["../../../../src/solvers/instant-open/get-instant-open-fees/get-instant-open-fees.ts"],"sourcesContent":["import { toDecimal } from \"@symmio/utils/decimal\";\nimport type { Address } from \"viem\";\nimport type { Config } from \"../../../core/config\";\nimport { SymmError } from \"../../../shared/errors/symm-error\";\nimport type { Compute, ReadSolverParameter } from \"../../../shared/types/properties\";\nimport type { FeeForUser } from \"../../../symmio-contracts/symmio/actions/get-fee-for-user\";\nimport type { EnigmaSolverInfo } from \"../../get-solver-info\";\nimport type { ApiLockedParamsBySymbolIdResponse } from \"../../types/generated/enigma-solver\";\nimport type { FullBalanceFunding } from \"../prepare-instant-open-params\";\nimport {\n resolveFeeRates,\n resolveLockedParams,\n resolveMarket,\n resolveMarkPrice,\n resolveSolverInfo,\n} from \"../prepare-instant-open-params/resolvers\";\nimport { assertValidSlippage, deriveAutoSlippage, fetchOpenEstimatePrice } from \"../shared/open-estimate-guard\";\nimport { resolveInstantOpenSizing, validateInstantOpenBalanceFunding } from \"../shared/resolve-instant-open-sizing\";\nimport {\n calculateExpectedSettlementLoss,\n calculateSolverFees,\n calculateTradeParams,\n computePlatformFeeLegs,\n} from \"../shared/trade-math\";\nimport type { InstantOpenMarketData, PositionType } from \"../shared/types\";\n\n/**\n * Fields shared by every {@link GetInstantOpenFeesParameters} funding mode.\n */\ntype BaseGetInstantOpenFeesParameters = ReadSolverParameter & {\n /** Sub-account / partyA address the platform fee rates are read for. */\n subAccountAddress: Address;\n /** Market identification + optional pre-fetched precision metadata. */\n market: InstantOpenMarketData;\n /** Trade side. */\n positionType: PositionType;\n /** Position leverage (integer ≥ 1). */\n leverage: number;\n /**\n * Slippage tolerance percent (e.g. `5` for 5%). **Required on majors\n * (non-lowcap) solvers.** On a lowcap solver it may be omitted to\n * auto-derive from the dry-run estimate plus 4% headroom — the same rule\n * as `prepareInstantOpenParams`, so the preview prices what the open will\n * actually charge.\n */\n slippage?: number;\n /**\n * Whether `totalFee` includes the `expectedSettlementLoss` provision.\n * Defaults to `true` — the provision is part of what the open funds, even\n * though it is a provision rather than a fee the solver keeps. Pass `false`\n * to report fee legs only; the provision stays available as its own field.\n */\n includeSettlementInTotalFee?: boolean;\n /** Pre-fetched mark price as decimal string. When omitted, fetched via the price service. */\n markPrice?: string;\n /** Pre-fetched on-chain fee rates (matches `getFeeForUser` return). When omitted, fetched. */\n feeRates?: FeeForUser;\n /**\n * Pre-fetched solver estimated open (fill) price as decimal string —\n * **lowcap/Enigma only**; ignored on any other solver kind. When omitted\n * on a lowcap solver, fetched via `GET /estimated-price`. Pass `null` when\n * an estimate was attempted but unavailable to skip fetching and use the fallback.\n */\n estimatedOpenPrice?: string | null;\n /**\n * Pre-fetched solver locked params (matches `getLockedParams` return).\n * Consulted for explicit or automatic full-balance sizing, which needs the\n * locked-param percents; when omitted there, fetched via `getLockedParams`.\n */\n lockedParamPercent?: ApiLockedParamsBySymbolIdResponse;\n /**\n * Pre-fetched solver static fees (matches `getSolverInfo` return) —\n * **lowcap/Enigma only**; ignored on any other solver kind. When omitted on\n * a lowcap solver, fetched via `getSolverInfo` (fail-soft: an unreachable\n * `/info` prices the static open leg at `\"0\"`).\n */\n solverInfo?: EnigmaSolverInfo;\n};\n\n/**\n * Parameters for {@link getInstantOpenFees}. A subset of\n * `PrepareInstantOpenParameters` — the trade intent plus optional pre-fetched\n * data; every pre-filled optional field skips its network fetch.\n *\n * The funding source mirrors `prepareInstantOpenParams`: pass a typed\n * `initialMargin`, **or** `fund` ({@link FullBalanceFunding}, lowcap only) to\n * preview a full-balance open — the preview then runs the same\n * probe-and-rescale sizing as the open, so its legs and `quantity` equal what\n * the open charges. Provide exactly one; passing both, or neither, throws.\n * With `initialMargin`, `availableBalance` opts into automatic full-balance sizing\n * only when the typed position's required funding exceeds the raw balance.\n * The typed initialMargin itself must not exceed availableBalance.\n */\nexport type GetInstantOpenFeesParameters = Compute<\n BaseGetInstantOpenFeesParameters & {\n /** Collateral (USD) the user enters as initial margin. Decimal string. Provide this **or** `fund`. */\n initialMargin?: string;\n /**\n * Raw available collateral (USD decimal string). With initialMargin, previews the\n * same automatic full-balance fallback as prepareInstantOpenParams. Lowcap only;\n * must be positive and finite. initialMargin above this balance throws. Cannot accompany fund.\n */\n availableBalance?: string;\n /**\n * Preview a full-balance open — lowcap (Enigma) only. Provide this **or**\n * `initialMargin`. See {@link FullBalanceFunding}.\n */\n fund?: FullBalanceFunding;\n }\n>;\n\n/**\n * Fee legs every solver kind charges **at open**. Close fees are charged at\n * close from the position — preview them in the close flow with\n * `getInstantCloseFees`, where the notional and holding time are real.\n */\nexport interface BaseInstantOpenFees {\n /** Effective sizing mode, including automatic fallback from a typed initial margin. */\n fundingMode: \"initial-margin\" | \"full-balance\";\n /** Platform open fee: `getFeeForUser.openFee × notional / 1e18` (decimal string). */\n platformOpenFee: string;\n /** Leveraged notional the fee rates were applied to (decimal string). */\n notional: string;\n /**\n * Leveraged base-asset quantity the legs were computed on (decimal string) —\n * in full-balance mode this is the rescaled, lot-snapped size the open will\n * actually submit. Feed this to TP/SL and constraint previews instead of\n * re-deriving from the typed margin.\n */\n quantity: string;\n /**\n * Sum of every leg the open charges now (decimal string). Includes the\n * settlement provision by default; pass `includeSettlementInTotalFee: false`\n * to sum the fee legs only.\n */\n totalFee: string;\n}\n\n/**\n * Fee breakdown for a **lowcap (Enigma)** instant open. Extends the platform\n * leg with the solver open legs and the settlement provision the solver\n * charges from the VA balance.\n */\nexport interface EnigmaInstantOpenFees extends BaseInstantOpenFees {\n /** Discriminant: these fees were priced for an Enigma (lowcap) solver. */\n kind: \"enigma\";\n /** Solver open fee: `hedgerFeeOpen × notional` (decimal string). */\n openSolverFee: string;\n /**\n * Expected settlement loss vs the dry-run estimate: side-aware\n * `max(0, adverse fill deviation × quantity)` (decimal string). `\"0\"` when\n * no usable estimate exists.\n */\n expectedSettlementLoss: string;\n /**\n * Static solver fee charged per instant open — a flat USD amount from the\n * solver's `/info` config, independent of the notional (decimal string).\n * `\"0\"` when the solver publishes none.\n */\n staticSolverFeeOpen: string;\n}\n\n/**\n * Fee breakdown for a **majors (Rasa)** instant open — the platform open leg\n * only.\n */\nexport interface RasaInstantOpenFees extends BaseInstantOpenFees {\n /** Discriminant: these fees were priced for a Rasa (majors) solver. */\n kind: \"rasa\";\n}\n\n/**\n * Return type of {@link getInstantOpenFees}. Narrow on `kind` to reach the\n * lowcap-only legs.\n */\nexport type GetInstantOpenFeesReturnType = EnigmaInstantOpenFees | RasaInstantOpenFees;\n\n/**\n * Preview every fee a new instant-open quote pays **at open**, separated by leg\n * plus the total — without signing or submitting anything.\n *\n * Mirrors the exact resolution and math `prepareInstantOpenParams` uses, so\n * the preview equals what the open charges for the same inputs:\n *\n * - **Both kinds**: `platformOpenFee` (on-chain `getFeeForUser.openFee` ×\n * leveraged notional).\n * - **Lowcap (Enigma) only**: `openSolverFee` (`hedgerFeeOpen × notional`),\n * `staticSolverFeeOpen` (flat USD from the solver's `/info` config,\n * size-independent) and `expectedSettlementLoss` (dry-run estimate vs mark)\n * — the legs the solver charges from the VA balance.\n *\n * Close fees (platform close, solver close, static close) are **not** part of\n * this preview: they are charged at close from the position, priced by\n * `getInstantCloseFees` in the close flow from the then-current notional and\n * the position's real holding time.\n *\n * `totalFee` sums every open leg. It includes the settlement provision by\n * default — the amount the user must fund even though the settlement leg is a\n * provision rather than a fee the solver keeps; pass\n * `includeSettlementInTotalFee: false` to sum the fee legs only.\n *\n * With `fund` ({@link FullBalanceFunding}) instead of `initialMargin`, the\n * preview runs the same probe-and-rescale sizing as the open — lot snap, cost\n * invariant, slippage-bound settlement fallback included — so the reported\n * legs and `quantity` are those of the trade the open will actually submit.\n *\n * @throws {SymmError} `SLIPPAGE_REQUIRED` on majors without `slippage`;\n * `AMBIGUOUS_FUNDING` / `INITIAL_MARGIN_REQUIRED` /\n * `FULL_BALANCE_UNSUPPORTED` for a broken funding one-of;\n * `QUOTE_CONSTRAINT_VIOLATED` when the full-balance sizing violates a\n * published market constraint;\n * `INVALID_SLIPPAGE` / `INVALID_TRADE_PARAMETERS` /\n * `RESOLVE_MARKET_NOT_FOUND` / `RESOLVE_MARK_PRICE_NOT_FOUND` for invalid or\n * unresolvable inputs.\n *\n * @example\n * ```ts\n * const fees = await getInstantOpenFees(config, {\n * subAccountAddress,\n * market: { id: 1 },\n * positionType: PositionType.LONG,\n * initialMargin: \"100\",\n * leverage: 5,\n * });\n * if (fees.kind === \"enigma\") console.log(fees.openSolverFee, fees.expectedSettlementLoss);\n * console.log(fees.totalFee);\n * ```\n */\nexport async function getInstantOpenFees(\n config: Config,\n parameters: GetInstantOpenFeesParameters,\n): Promise<GetInstantOpenFeesReturnType> {\n if (parameters.slippage !== undefined) assertValidSlippage(parameters.slippage);\n\n /** Estimate-driven legs exist only on lowcap (Enigma) solvers — a majors preview is the platform leg only. */\n const isLowcap = config.getSolver({ chainId: parameters.chainId, solverId: parameters.solverId }).id === \"enigma\";\n if (parameters.slippage === undefined && !isLowcap) {\n throw new SymmError(\n \"validation\",\n \"SLIPPAGE_REQUIRED\",\n \"getInstantOpenFees: slippage is required on this solver — auto-derived slippage is lowcap-only.\",\n );\n }\n\n // Same one-of funding contract as `prepareInstantOpenParams`, so a preview\n // can always be expressed for the exact open it mirrors.\n const isFullBalance = parameters.fund !== undefined;\n validateInstantOpenBalanceFunding({ ...parameters, isLowcap });\n const canSizeFullBalance = isFullBalance || parameters.availableBalance !== undefined;\n if (isFullBalance && parameters.initialMargin !== undefined) {\n throw new SymmError(\n \"validation\",\n \"AMBIGUOUS_FUNDING\",\n \"getInstantOpenFees: pass exactly one of initialMargin or fund, not both.\",\n );\n }\n if (isFullBalance && !isLowcap) {\n throw new SymmError(\n \"validation\",\n \"FULL_BALANCE_UNSUPPORTED\",\n \"getInstantOpenFees: full-balance funding is lowcap (Enigma) only — pass initialMargin on this solver.\",\n );\n }\n if (!isFullBalance && parameters.initialMargin === undefined) {\n throw new SymmError(\n \"validation\",\n \"INITIAL_MARGIN_REQUIRED\",\n \"getInstantOpenFees: pass initialMargin, or fund: { mode: 'full-balance', balance } on a lowcap solver.\",\n );\n }\n const initialMargin = isFullBalance ? parameters.fund!.balance : parameters.initialMargin!;\n const includeSettlementInTotalFee = parameters.includeSettlementInTotalFee ?? true;\n\n const market = await resolveMarket(config, {\n chainId: parameters.chainId,\n solverId: parameters.solverId,\n marketId: parameters.market.id,\n marketName: parameters.market.name,\n pricePrecision: parameters.market.pricePrecision,\n quantityPrecision: parameters.market.quantityPrecision,\n // The close-side prefills only serve the resolver's short-circuit (skip the\n // markets fetch when the caller pre-fetched the row) — the open cost model\n // uses `hedgerFeeOpen` alone; close fees are priced by `getInstantCloseFees`.\n hedgerFeeOpen: parameters.market.hedgerFeeOpen,\n hedgerFeeClose: parameters.market.hedgerFeeClose,\n hedgerFeeCloseEarlyRate: parameters.market.hedgerFeeCloseEarlyRate,\n hedgerFeeCloseEarlyThreshold: parameters.market.hedgerFeeCloseEarlyThreshold,\n hedgerFeeCloseStandardThreshold: parameters.market.hedgerFeeCloseStandardThreshold,\n includeHedgerFees: isLowcap,\n /** Explicit or automatic full-balance sizing needs the lot grid and published floors. */\n includeQuoteConstraints: canSizeFullBalance,\n minAcceptablePortionLf: parameters.market.minAcceptablePortionLf,\n minAcceptableQuoteValue: parameters.market.minAcceptableQuoteValue,\n maxNotionalValue: parameters.market.maxNotionalValue,\n minNotionalValue: parameters.market.minNotionalValue,\n maxQuantity: parameters.market.maxQuantity,\n lotSize: parameters.market.lotSize,\n });\n const [markPrice, feeRates, lockedParams, staticFees] = await Promise.all([\n resolveMarkPrice(config, {\n chainId: parameters.chainId,\n solverId: parameters.solverId,\n marketName: market.name,\n markPrice: parameters.markPrice,\n }),\n resolveFeeRates(config, {\n chainId: parameters.chainId,\n subAccountAddress: parameters.subAccountAddress,\n marketId: parameters.market.id,\n feeRates: parameters.feeRates,\n }),\n // Full-balance sizing needs the locked-param percents — the locks dominate\n // the margin the balance must cover, including the automatic fallback check.\n canSizeFullBalance\n ? resolveLockedParams(config, {\n chainId: parameters.chainId,\n solverId: parameters.solverId,\n marketName: market.name,\n leverage: parameters.leverage,\n lockedParamPercent: parameters.lockedParamPercent,\n })\n : Promise.resolve(undefined),\n // The static open fee is a lowcap leg — majors previews never fetch it.\n isLowcap\n ? resolveSolverInfo(config, {\n chainId: parameters.chainId,\n solverId: parameters.solverId,\n solverInfo: parameters.solverInfo,\n })\n : Promise.resolve({ staticSolverFeeOpen: \"0\", staticSolverFeeClose: \"0\" }),\n ]);\n\n const calculationInput = {\n markPrice,\n positionType: parameters.positionType,\n userInput: initialMargin,\n inputField: \"PRICE\" as const,\n leverage: parameters.leverage,\n pricePrecision: market.pricePrecision,\n quantityPrecision: market.quantityPrecision,\n ...(lockedParams\n ? {\n cvaPercent: lockedParams.cva,\n lfPercent: lockedParams.lf,\n partyAmmPercent: lockedParams.partyAmm,\n partyBmmPercent: lockedParams.partyBmm,\n }\n : {}),\n };\n\n let slippage = parameters.slippage;\n let expectedFillPrice = isLowcap ? (parameters.estimatedOpenPrice ?? undefined) : undefined;\n let needsEstimate = isLowcap && parameters.estimatedOpenPrice === undefined;\n if (slippage === undefined) {\n const sized = calculateTradeParams({ ...calculationInput, slippage: 0 });\n if (!sized) {\n throw new SymmError(\n \"validation\",\n \"INVALID_TRADE_PARAMETERS\",\n \"Invalid trade parameters: markPrice or initialMargin is zero/NaN.\",\n );\n }\n if (needsEstimate) {\n needsEstimate = false;\n expectedFillPrice = await fetchOpenEstimatePrice(config, {\n chainId: parameters.chainId,\n solverId: parameters.solverId,\n symbolId: parameters.market.id,\n positionType: parameters.positionType,\n quantity: sized.quantity,\n markPrice,\n });\n }\n slippage = deriveAutoSlippage({ markPrice, expectedFillPrice, positionType: parameters.positionType });\n }\n\n const tradeCalc = calculateTradeParams({ ...calculationInput, slippage });\n if (!tradeCalc) {\n throw new SymmError(\n \"validation\",\n \"INVALID_TRADE_PARAMETERS\",\n \"Invalid trade parameters: markPrice or initialMargin is zero/NaN.\",\n );\n }\n\n if (needsEstimate) {\n expectedFillPrice = await fetchOpenEstimatePrice(config, {\n chainId: parameters.chainId,\n solverId: parameters.solverId,\n symbolId: parameters.market.id,\n positionType: parameters.positionType,\n quantity: tradeCalc.quantity,\n markPrice,\n });\n }\n\n // Full-balance preview: run the exact sizing the open runs — probe, linear\n // rescale, lot snap, cost invariant — and report the legs of the trade that\n // will actually be submitted.\n if (canSizeFullBalance) {\n const { trade, costs, fundingMode } = resolveInstantOpenSizing({\n trade: tradeCalc,\n isLowcap,\n fund: parameters.fund,\n availableBalance: parameters.availableBalance,\n calculationInput: { ...calculationInput, slippage },\n // Preserve the legacy zero sentinel for callers; prefer null for unavailable estimates.\n // Full-balance sizing provisions settlement at the price bound when no estimate exists.\n expectedFillPrice: expectedFillPrice === \"0\" ? undefined : expectedFillPrice,\n feeRates,\n hedgerFeeOpen: market.hedgerFeeOpen,\n staticSolverFeeOpen: staticFees.staticSolverFeeOpen,\n constraints: {\n minAcceptablePortionLf: market.minAcceptablePortionLf,\n minAcceptableQuoteValue: market.minAcceptableQuoteValue,\n maxNotionalValue: market.maxNotionalValue,\n minNotionalValue: market.minNotionalValue,\n maxQuantity: market.maxQuantity,\n lotSize: market.lotSize,\n },\n });\n return {\n fundingMode,\n kind: \"enigma\",\n platformOpenFee: costs.platformOpenFee,\n notional: trade.notional,\n quantity: trade.quantity,\n openSolverFee: costs.openSolverFee,\n staticSolverFeeOpen: costs.staticSolverFeeOpen,\n expectedSettlementLoss: costs.expectedSettlementLoss,\n totalFee: toDecimal(costs.platformOpenFee)\n .plus(costs.openSolverFee)\n .plus(costs.staticSolverFeeOpen)\n .plus(includeSettlementInTotalFee ? costs.expectedSettlementLoss : \"0\")\n .toString(),\n };\n }\n\n const { platformOpenFee } = computePlatformFeeLegs(feeRates, tradeCalc.notional, tradeCalc.notional);\n\n if (!isLowcap) {\n return {\n fundingMode: \"initial-margin\",\n kind: \"rasa\",\n platformOpenFee,\n notional: tradeCalc.notional,\n quantity: tradeCalc.quantity,\n totalFee: platformOpenFee,\n };\n }\n\n const { openSolverFee, staticSolverFeeOpen } = calculateSolverFees({\n notional: tradeCalc.notional,\n hedgerFeeOpen: market.hedgerFeeOpen,\n hedgerFeeClose: undefined,\n staticSolverFeeOpen: staticFees.staticSolverFeeOpen,\n });\n const expectedSettlementLoss = calculateExpectedSettlementLoss({\n positionType: parameters.positionType,\n markPrice,\n expectedFillPrice,\n quantity: tradeCalc.quantity,\n });\n\n return {\n fundingMode: \"initial-margin\",\n kind: \"enigma\",\n platformOpenFee,\n notional: tradeCalc.notional,\n quantity: tradeCalc.quantity,\n openSolverFee,\n staticSolverFeeOpen,\n expectedSettlementLoss,\n totalFee: toDecimal(platformOpenFee)\n .plus(openSolverFee)\n .plus(staticSolverFeeOpen)\n .plus(includeSettlementInTotalFee ? expectedSettlementLoss : \"0\")\n .toString(),\n };\n}\n"],"mappings":";;;;;;;;;;;AAoOA,eAAsB,EACpB,GACA,GACuC;CACvC,AAAI,EAAW,aAAa,KAAA,KAAW,EAAoB,EAAW,QAAQ;CAG9E,IAAM,IAAW,EAAO,UAAU;EAAE,SAAS,EAAW;EAAS,UAAU,EAAW;CAAS,CAAC,EAAE,OAAO;CACzG,IAAI,EAAW,aAAa,KAAA,KAAa,CAAC,GACxC,MAAM,IAAI,EACR,cACA,qBACA,iGACF;CAKF,IAAM,IAAgB,EAAW,SAAS,KAAA;CAC1C,EAAkC;EAAE,GAAG;EAAY;CAAS,CAAC;CAC7D,IAAM,IAAqB,KAAiB,EAAW,qBAAqB,KAAA;CAC5E,IAAI,KAAiB,EAAW,kBAAkB,KAAA,GAChD,MAAM,IAAI,EACR,cACA,qBACA,0EACF;CAEF,IAAI,KAAiB,CAAC,GACpB,MAAM,IAAI,EACR,cACA,4BACA,uGACF;CAEF,IAAI,CAAC,KAAiB,EAAW,kBAAkB,KAAA,GACjD,MAAM,IAAI,EACR,cACA,2BACA,wGACF;CAEF,IAAM,IAAgB,IAAgB,EAAW,KAAM,UAAU,EAAW,eACtE,IAA8B,EAAW,+BAA+B,IAExE,IAAS,MAAM,EAAc,GAAQ;EACzC,SAAS,EAAW;EACpB,UAAU,EAAW;EACrB,UAAU,EAAW,OAAO;EAC5B,YAAY,EAAW,OAAO;EAC9B,gBAAgB,EAAW,OAAO;EAClC,mBAAmB,EAAW,OAAO;EAIrC,eAAe,EAAW,OAAO;EACjC,gBAAgB,EAAW,OAAO;EAClC,yBAAyB,EAAW,OAAO;EAC3C,8BAA8B,EAAW,OAAO;EAChD,iCAAiC,EAAW,OAAO;EACnD,mBAAmB;EAEnB,yBAAyB;EACzB,wBAAwB,EAAW,OAAO;EAC1C,yBAAyB,EAAW,OAAO;EAC3C,kBAAkB,EAAW,OAAO;EACpC,kBAAkB,EAAW,OAAO;EACpC,aAAa,EAAW,OAAO;EAC/B,SAAS,EAAW,OAAO;CAC7B,CAAC,GACK,CAAC,GAAW,GAAU,GAAc,KAAc,MAAM,QAAQ,IAAI;EACxE,EAAiB,GAAQ;GACvB,SAAS,EAAW;GACpB,UAAU,EAAW;GACrB,YAAY,EAAO;GACnB,WAAW,EAAW;EACxB,CAAC;EACD,EAAgB,GAAQ;GACtB,SAAS,EAAW;GACpB,mBAAmB,EAAW;GAC9B,UAAU,EAAW,OAAO;GAC5B,UAAU,EAAW;EACvB,CAAC;EAGD,IACI,EAAoB,GAAQ;GAC1B,SAAS,EAAW;GACpB,UAAU,EAAW;GACrB,YAAY,EAAO;GACnB,UAAU,EAAW;GACrB,oBAAoB,EAAW;EACjC,CAAC,IACD,QAAQ,QAAQ,KAAA,CAAS;EAE7B,IACI,EAAkB,GAAQ;GACxB,SAAS,EAAW;GACpB,UAAU,EAAW;GACrB,YAAY,EAAW;EACzB,CAAC,IACD,QAAQ,QAAQ;GAAE,qBAAqB;GAAK,sBAAsB;EAAI,CAAC;CAC7E,CAAC,GAEK,IAAmB;EACvB;EACA,cAAc,EAAW;EACzB,WAAW;EACX,YAAY;EACZ,UAAU,EAAW;EACrB,gBAAgB,EAAO;EACvB,mBAAmB,EAAO;EAC1B,GAAI,IACA;GACE,YAAY,EAAa;GACzB,WAAW,EAAa;GACxB,iBAAiB,EAAa;GAC9B,iBAAiB,EAAa;EAChC,IACA,CAAC;CACP,GAEI,IAAW,EAAW,UACtB,IAAoB,IAAY,EAAW,sBAAsB,KAAA,IAAa,KAAA,GAC9E,IAAgB,KAAY,EAAW,uBAAuB,KAAA;CAClE,IAAI,MAAa,KAAA,GAAW;EAC1B,IAAM,IAAQ,EAAqB;GAAE,GAAG;GAAkB,UAAU;EAAE,CAAC;EACvE,IAAI,CAAC,GACH,MAAM,IAAI,EACR,cACA,4BACA,mEACF;EAaF,AAXI,MACF,IAAgB,IAChB,IAAoB,MAAM,EAAuB,GAAQ;GACvD,SAAS,EAAW;GACpB,UAAU,EAAW;GACrB,UAAU,EAAW,OAAO;GAC5B,cAAc,EAAW;GACzB,UAAU,EAAM;GAChB;EACF,CAAC,IAEH,IAAW,EAAmB;GAAE;GAAW;GAAmB,cAAc,EAAW;EAAa,CAAC;CACvG;CAEA,IAAM,IAAY,EAAqB;EAAE,GAAG;EAAkB;CAAS,CAAC;CACxE,IAAI,CAAC,GACH,MAAM,IAAI,EACR,cACA,4BACA,mEACF;CAiBF,IAdI,MACF,IAAoB,MAAM,EAAuB,GAAQ;EACvD,SAAS,EAAW;EACpB,UAAU,EAAW;EACrB,UAAU,EAAW,OAAO;EAC5B,cAAc,EAAW;EACzB,UAAU,EAAU;EACpB;CACF,CAAC,IAMC,GAAoB;EACtB,IAAM,EAAE,UAAO,UAAO,mBAAgB,EAAyB;GAC7D,OAAO;GACP;GACA,MAAM,EAAW;GACjB,kBAAkB,EAAW;GAC7B,kBAAkB;IAAE,GAAG;IAAkB;GAAS;GAGlD,mBAAmB,MAAsB,MAAM,KAAA,IAAY;GAC3D;GACA,eAAe,EAAO;GACtB,qBAAqB,EAAW;GAChC,aAAa;IACX,wBAAwB,EAAO;IAC/B,yBAAyB,EAAO;IAChC,kBAAkB,EAAO;IACzB,kBAAkB,EAAO;IACzB,aAAa,EAAO;IACpB,SAAS,EAAO;GAClB;EACF,CAAC;EACD,OAAO;GACL;GACA,MAAM;GACN,iBAAiB,EAAM;GACvB,UAAU,EAAM;GAChB,UAAU,EAAM;GAChB,eAAe,EAAM;GACrB,qBAAqB,EAAM;GAC3B,wBAAwB,EAAM;GAC9B,UAAU,EAAU,EAAM,eAAe,EACtC,KAAK,EAAM,aAAa,EACxB,KAAK,EAAM,mBAAmB,EAC9B,KAAK,IAA8B,EAAM,yBAAyB,GAAG,EACrE,SAAS;EACd;CACF;CAEA,IAAM,EAAE,uBAAoB,EAAuB,GAAU,EAAU,UAAU,EAAU,QAAQ;CAEnG,IAAI,CAAC,GACH,OAAO;EACL,aAAa;EACb,MAAM;EACN;EACA,UAAU,EAAU;EACpB,UAAU,EAAU;EACpB,UAAU;CACZ;CAGF,IAAM,EAAE,kBAAe,2BAAwB,EAAoB;EACjE,UAAU,EAAU;EACpB,eAAe,EAAO;EACtB,gBAAgB,KAAA;EAChB,qBAAqB,EAAW;CAClC,CAAC,GACK,IAAyB,EAAgC;EAC7D,cAAc,EAAW;EACzB;EACA;EACA,UAAU,EAAU;CACtB,CAAC;CAED,OAAO;EACL,aAAa;EACb,MAAM;EACN;EACA,UAAU,EAAU;EACpB,UAAU,EAAU;EACpB;EACA;EACA;EACA,UAAU,EAAU,CAAe,EAChC,KAAK,CAAa,EAClB,KAAK,CAAmB,EACxB,KAAK,IAA8B,IAAyB,GAAG,EAC/D,SAAS;CACd;AACF"}
|
|
@@ -14,8 +14,9 @@ export type GetInstantOpenFeesOptions = Compute<GetInstantOpenFeesParameters & Q
|
|
|
14
14
|
export type GetInstantOpenFeesQueryOptions = SymmioQueryOptions<GetInstantOpenFeesData, Error, GetInstantOpenFeesData, GetInstantOpenFeesQueryKey>;
|
|
15
15
|
/**
|
|
16
16
|
* Build TanStack Query options for {@link getInstantOpenFees}. Disabled until
|
|
17
|
-
*
|
|
18
|
-
* amount
|
|
17
|
+
* a funding source exists — a non-empty `initialMargin`, or `fund` with a
|
|
18
|
+
* non-empty balance — so the fee preview does not fire on an empty amount
|
|
19
|
+
* input.
|
|
19
20
|
*
|
|
20
21
|
* @example
|
|
21
22
|
* ```ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../../src/solvers/instant-open/get-instant-open-fees/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtF,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,4BAA4B,EAClC,MAAM,yBAAyB,CAAC;AAEjC,yEAAyE;AACzE,MAAM,MAAM,sBAAsB,GAAG,4BAA4B,CAAC;AAElE,+EAA+E;AAC/E,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,CAAC,4BAA4B,GAAG,kBAAkB,CAAC,4DAE7G;AAED,qEAAqE;AACrE,MAAM,MAAM,0BAA0B,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEvF,kEAAkE;AAClE,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAC7C,4BAA4B,GAC1B,cAAc,CAAC,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,EAAE,0BAA0B,CAAC,CACpG,CAAC;AAEF,iFAAiF;AACjF,MAAM,MAAM,8BAA8B,GAAG,kBAAkB,CAC7D,sBAAsB,EACtB,KAAK,EACL,sBAAsB,EACtB,0BAA0B,CAC3B,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../../src/solvers/instant-open/get-instant-open-fees/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtF,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,4BAA4B,EAClC,MAAM,yBAAyB,CAAC;AAEjC,yEAAyE;AACzE,MAAM,MAAM,sBAAsB,GAAG,4BAA4B,CAAC;AAElE,+EAA+E;AAC/E,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,CAAC,4BAA4B,GAAG,kBAAkB,CAAC,4DAE7G;AAED,qEAAqE;AACrE,MAAM,MAAM,0BAA0B,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEvF,kEAAkE;AAClE,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAC7C,4BAA4B,GAC1B,cAAc,CAAC,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,EAAE,0BAA0B,CAAC,CACpG,CAAC;AAEF,iFAAiF;AACjF,MAAM,MAAM,8BAA8B,GAAG,kBAAkB,CAC7D,sBAAsB,EACtB,KAAK,EACL,sBAAsB,EACtB,0BAA0B,CAC3B,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GACjC,8BAA8B,CAahC"}
|