@drift-labs/common 1.0.47 → 1.0.48
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/lib/drift/Drift/clients/AuthorityDrift/DriftOperations/index.js +8 -4
- package/lib/drift/Drift/clients/AuthorityDrift/DriftOperations/index.js.map +1 -1
- package/lib/drift/Drift/clients/AuthorityDrift/DriftOperations/types.d.ts +4 -2
- package/lib/drift/Drift/clients/AuthorityDrift/DriftOperations/types.js.map +1 -1
- package/lib/drift/Drift/clients/CentralServerDrift/index.js +0 -1
- package/lib/drift/Drift/clients/CentralServerDrift/index.js.map +1 -1
- package/lib/drift/Drift/clients/CentralServerDrift/types.d.ts +8 -10
- package/lib/drift/Drift/clients/CentralServerDrift/types.js.map +1 -1
- package/lib/drift/base/actions/trade/openPerpOrder/isolatedPositionDeposit.d.ts +56 -1
- package/lib/drift/base/actions/trade/openPerpOrder/isolatedPositionDeposit.js +102 -4
- package/lib/drift/base/actions/trade/openPerpOrder/isolatedPositionDeposit.js.map +1 -1
- package/lib/drift/base/actions/trade/openPerpOrder/openPerpMarketOrder/index.d.ts +13 -12
- package/lib/drift/base/actions/trade/openPerpOrder/openPerpMarketOrder/index.js +51 -17
- package/lib/drift/base/actions/trade/openPerpOrder/openPerpMarketOrder/index.js.map +1 -1
- package/lib/drift/base/actions/trade/openPerpOrder/openPerpNonMarketOrder/index.d.ts +14 -7
- package/lib/drift/base/actions/trade/openPerpOrder/openPerpNonMarketOrder/index.js +56 -23
- package/lib/drift/base/actions/trade/openPerpOrder/openPerpNonMarketOrder/index.js.map +1 -1
- package/lib/drift/base/actions/trade/openPerpOrder/types.d.ts +10 -6
- package/lib/drift/base/actions/trade/openPerpOrder/types.js.map +1 -1
- package/lib/drift/base/details/user/positionMarginMode.d.ts +8 -0
- package/lib/drift/base/details/user/positionMarginMode.js +18 -0
- package/lib/drift/base/details/user/positionMarginMode.js.map +1 -0
- package/lib/drift/utils/orderParams.d.ts +1 -1
- package/lib/drift/utils/orderParams.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,32 +2,30 @@ import { BN, PositionDirection, TxParams } from '@drift-labs/sdk';
|
|
|
2
2
|
import { WithTxnParams } from '../../../base/types';
|
|
3
3
|
import { OpenPerpMarketOrderBaseParams } from '../../../base/actions/trade/openPerpOrder/openPerpMarketOrder';
|
|
4
4
|
import { OpenPerpNonMarketOrderBaseParams } from '../../../base/actions/trade/openPerpOrder/openPerpNonMarketOrder';
|
|
5
|
-
import { PlaceAndTakeParams } from '../../../base/actions/trade/openPerpOrder/types';
|
|
5
|
+
import { IsolatedPositionDepositsOverride, PlaceAndTakeParams } from '../../../base/actions/trade/openPerpOrder/types';
|
|
6
6
|
import { PublicKey } from '@solana/web3.js';
|
|
7
7
|
export type CentralServerSwiftOrderOptions = {
|
|
8
8
|
userSigningSlotBuffer?: number;
|
|
9
9
|
isDelegate?: boolean;
|
|
10
10
|
};
|
|
11
11
|
type CsdBaseMarketOrderParams = Omit<OpenPerpMarketOrderBaseParams, 'driftClient' | 'user' | 'dlobServerHttpUrl'>;
|
|
12
|
-
export type CentralServerGetOpenPerpMarketOrderTxnParams<T extends boolean = boolean> = T extends true ? Omit<CsdBaseMarketOrderParams, 'placeAndTake'
|
|
12
|
+
export type CentralServerGetOpenPerpMarketOrderTxnParams<T extends boolean = boolean> = T extends true ? Omit<CsdBaseMarketOrderParams, 'placeAndTake'> & {
|
|
13
13
|
useSwift: true;
|
|
14
14
|
swiftOptions?: CentralServerSwiftOrderOptions;
|
|
15
|
-
|
|
15
|
+
isolatedPositionDepositsOverride?: Omit<IsolatedPositionDepositsOverride, 'additionalDeposits'>;
|
|
16
16
|
userAccountPublicKey: PublicKey;
|
|
17
17
|
} : WithTxnParams<CsdBaseMarketOrderParams & {
|
|
18
18
|
useSwift: false;
|
|
19
|
-
}> & {
|
|
20
19
|
userAccountPublicKey: PublicKey;
|
|
21
|
-
}
|
|
20
|
+
}>;
|
|
22
21
|
type CsdBaseNonMarketOrderParams = Omit<OpenPerpNonMarketOrderBaseParams, 'driftClient' | 'user'>;
|
|
23
|
-
export type CentralServerGetOpenPerpNonMarketOrderTxnParams<T extends boolean = boolean> = T extends true ?
|
|
22
|
+
export type CentralServerGetOpenPerpNonMarketOrderTxnParams<T extends boolean = boolean> = (T extends true ? CsdBaseNonMarketOrderParams & {
|
|
24
23
|
useSwift: true;
|
|
25
24
|
swiftOptions?: CentralServerSwiftOrderOptions;
|
|
26
|
-
|
|
27
|
-
userAccountPublicKey: PublicKey;
|
|
25
|
+
isolatedPositionDepositsOverride?: Omit<IsolatedPositionDepositsOverride, 'additionalDeposits'>;
|
|
28
26
|
} : WithTxnParams<CsdBaseNonMarketOrderParams & {
|
|
29
27
|
useSwift: false;
|
|
30
|
-
}> & {
|
|
28
|
+
}>) & {
|
|
31
29
|
userAccountPublicKey: PublicKey;
|
|
32
30
|
};
|
|
33
31
|
/** Params for withdrawing collateral from an isolated perp position (transfer to cross). */
|
|
@@ -63,7 +61,7 @@ export interface CentralServerGetCloseAndWithdrawIsolatedPerpPositionTxnParams {
|
|
|
63
61
|
mainSignerOverride?: PublicKey;
|
|
64
62
|
}
|
|
65
63
|
/** Params for deposit from wallet + open isolated perp position (wallet → isolated → place). */
|
|
66
|
-
export interface CentralServerGetDepositAndOpenIsolatedPerpPositionTxnParams extends Omit<CentralServerGetOpenPerpMarketOrderTxnParams<false>, '
|
|
64
|
+
export interface CentralServerGetDepositAndOpenIsolatedPerpPositionTxnParams extends Omit<CentralServerGetOpenPerpMarketOrderTxnParams<false>, 'isolatedPositionDepositsOverride' | 'useSwift' | 'marginMode'> {
|
|
67
65
|
/** Amount to deposit from wallet directly into isolated (QUOTE_PRECISION, e.g. USDC). */
|
|
68
66
|
depositAmount: BN;
|
|
69
67
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/drift/Drift/clients/CentralServerDrift/types.ts"],"names":[],"mappings":"","sourcesContent":["import { BN, PositionDirection, TxParams } from '@drift-labs/sdk';\nimport { WithTxnParams } from '../../../base/types';\nimport { OpenPerpMarketOrderBaseParams } from '../../../base/actions/trade/openPerpOrder/openPerpMarketOrder';\nimport { OpenPerpNonMarketOrderBaseParams } from '../../../base/actions/trade/openPerpOrder/openPerpNonMarketOrder';\nimport {
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/drift/Drift/clients/CentralServerDrift/types.ts"],"names":[],"mappings":"","sourcesContent":["import { BN, PositionDirection, TxParams } from '@drift-labs/sdk';\nimport { WithTxnParams } from '../../../base/types';\nimport { OpenPerpMarketOrderBaseParams } from '../../../base/actions/trade/openPerpOrder/openPerpMarketOrder';\nimport { OpenPerpNonMarketOrderBaseParams } from '../../../base/actions/trade/openPerpOrder/openPerpNonMarketOrder';\nimport {\n\tIsolatedPositionDepositsOverride,\n\tPlaceAndTakeParams,\n} from '../../../base/actions/trade/openPerpOrder/types';\nimport { PublicKey } from '@solana/web3.js';\n\nexport type CentralServerSwiftOrderOptions = {\n\tuserSigningSlotBuffer?: number;\n\tisDelegate?: boolean;\n};\n\ntype CsdBaseMarketOrderParams = Omit<\n\tOpenPerpMarketOrderBaseParams,\n\t'driftClient' | 'user' | 'dlobServerHttpUrl'\n>;\n\nexport type CentralServerGetOpenPerpMarketOrderTxnParams<\n\tT extends boolean = boolean\n> = T extends true\n\t? Omit<CsdBaseMarketOrderParams, 'placeAndTake'> & {\n\t\t\tuseSwift: true;\n\t\t\tswiftOptions?: CentralServerSwiftOrderOptions;\n\t\t\tisolatedPositionDepositsOverride?: Omit<\n\t\t\t\tIsolatedPositionDepositsOverride,\n\t\t\t\t'additionalDeposits'\n\t\t\t>;\n\t\t\tuserAccountPublicKey: PublicKey;\n\t }\n\t: WithTxnParams<\n\t\t\tCsdBaseMarketOrderParams & {\n\t\t\t\tuseSwift: false;\n\t\t\t\tuserAccountPublicKey: PublicKey;\n\t\t\t}\n\t >;\n\ntype CsdBaseNonMarketOrderParams = Omit<\n\tOpenPerpNonMarketOrderBaseParams,\n\t'driftClient' | 'user'\n>;\n\nexport type CentralServerGetOpenPerpNonMarketOrderTxnParams<\n\tT extends boolean = boolean\n> = (T extends true\n\t? CsdBaseNonMarketOrderParams & {\n\t\t\tuseSwift: true;\n\t\t\tswiftOptions?: CentralServerSwiftOrderOptions;\n\t\t\tisolatedPositionDepositsOverride?: Omit<\n\t\t\t\tIsolatedPositionDepositsOverride,\n\t\t\t\t'additionalDeposits'\n\t\t\t>;\n\t }\n\t: WithTxnParams<\n\t\t\tCsdBaseNonMarketOrderParams & {\n\t\t\t\tuseSwift: false;\n\t\t\t}\n\t >) & {\n\tuserAccountPublicKey: PublicKey;\n};\n\n/** Params for withdrawing collateral from an isolated perp position (transfer to cross). */\nexport interface CentralServerGetWithdrawIsolatedPerpPositionCollateralTxnParams {\n\tuserAccountPublicKey: PublicKey;\n\tmarketIndex: number;\n\t/** Positive amount to withdraw in QUOTE_PRECISION. Ignored when isFullWithdrawal is true. */\n\tamount: BN;\n\t/** If true, transfers all available isolated margin (use when position is closed). Prepends settle PnL ix. */\n\tisFullWithdrawal?: boolean;\n\t/** If true, prepends settle PnL ix before transfer (recommended for full withdrawal or when position base is zero). */\n\tsettlePnlFirst?: boolean;\n\ttxParams?: TxParams;\n\t/** Optional signer override for transaction signing; defaults to user authority. */\n\tmainSignerOverride?: PublicKey;\n}\n\n/** Params for single-tx close + withdraw (best-effort; fill-dependent). */\nexport interface CentralServerGetCloseAndWithdrawIsolatedPerpPositionTxnParams {\n\tuserAccountPublicKey: PublicKey;\n\tmarketIndex: number;\n\t/** Base asset amount to close. */\n\tbaseAssetAmount: BN;\n\t/** Direction of the close order (opposite of position). */\n\tdirection: PositionDirection;\n\t/** If true, includes collateral transfer ix after close order (will withdraw available isolated margin; amount is fill-dependent). */\n\twithdrawCollateralAfterClose?: boolean;\n\t/** If true and withdrawCollateralAfterClose, prepends settle PnL ix. */\n\tsettlePnlBeforeClose?: boolean;\n\tassetType?: 'base' | 'quote';\n\tplaceAndTake?: PlaceAndTakeParams;\n\ttxParams?: TxParams;\n\t/** Optional signer override for transaction signing; defaults to user authority. */\n\tmainSignerOverride?: PublicKey;\n}\n\n/** Params for deposit from wallet + open isolated perp position (wallet → isolated → place). */\nexport interface CentralServerGetDepositAndOpenIsolatedPerpPositionTxnParams\n\textends Omit<\n\t\tCentralServerGetOpenPerpMarketOrderTxnParams<false>,\n\t\t'isolatedPositionDepositsOverride' | 'useSwift' | 'marginMode'\n\t> {\n\t/** Amount to deposit from wallet directly into isolated (QUOTE_PRECISION, e.g. USDC). */\n\tdepositAmount: BN;\n}\n\n/** Params for close isolated position + withdraw to wallet (close → withdraw from isolated to wallet). */\nexport interface CentralServerGetCloseAndWithdrawIsolatedPerpPositionToWalletTxnParams {\n\tuserAccountPublicKey: PublicKey;\n\tmarketIndex: number;\n\t/** Base asset amount to close. */\n\tbaseAssetAmount: BN;\n\t/** Direction of the close order (opposite of position). */\n\tdirection: PositionDirection;\n\t/**\n\t * Amount to withdraw (QUOTE_PRECISION). When omitted or larger than available,\n\t * the SDK withdraws all. Pass a specific amount for partial withdrawal.\n\t */\n\testimatedWithdrawAmount?: BN;\n\tassetType?: 'base' | 'quote';\n\tplaceAndTake?: PlaceAndTakeParams;\n\ttxParams?: TxParams;\n\t/** Optional signer override and withdrawal destination; when provided, used for signing and as the wallet that receives the withdrawal; defaults to user authority. */\n\tmainSignerOverride?: PublicKey;\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BN, DriftClient, User, PositionDirection } from '@drift-labs/sdk';
|
|
2
2
|
import { PublicKey, TransactionInstruction } from '@solana/web3.js';
|
|
3
|
+
import { AdditionalIsolatedPositionDeposit, IsolatedPositionDepositsOverride } from './types';
|
|
3
4
|
export declare const ISOLATED_POSITION_DEPOSIT_BUFFER_BPS = 15;
|
|
4
5
|
export interface IsolatedMarginShortfall {
|
|
5
6
|
marketIndex: number;
|
|
@@ -74,10 +75,64 @@ export interface ComputeIsolatedPositionDepositParams {
|
|
|
74
75
|
* will be added to the deposit amount.
|
|
75
76
|
*/
|
|
76
77
|
includeExistingShortfall?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Pre-computed existing shortfall for the current market.
|
|
80
|
+
* When provided alongside includeExistingShortfall, avoids a redundant getMarginCalculation call.
|
|
81
|
+
*/
|
|
82
|
+
existingShortfall?: BN;
|
|
77
83
|
}
|
|
78
84
|
/**
|
|
79
85
|
* Computes the isolated position deposit required for opening an isolated perp position.
|
|
80
86
|
* Returns a BN in QUOTE_PRECISION (USDC).
|
|
81
87
|
*/
|
|
82
|
-
export declare function computeIsolatedPositionDepositForTrade({ driftClient, user, marketIndex, baseAssetAmount, direction, marginRatio, entryPrice, numOfOpenHighLeverageSpots, bufferDenominator, includeExistingShortfall, }: ComputeIsolatedPositionDepositParams): BN | null;
|
|
88
|
+
export declare function computeIsolatedPositionDepositForTrade({ driftClient, user, marketIndex, baseAssetAmount, direction, marginRatio, entryPrice, numOfOpenHighLeverageSpots, bufferDenominator, includeExistingShortfall, existingShortfall: precomputedShortfall, }: ComputeIsolatedPositionDepositParams): BN | null;
|
|
89
|
+
/**
|
|
90
|
+
* Error thrown when underwater isolated positions are detected and
|
|
91
|
+
* replenishUnderwaterPositions is not set to true.
|
|
92
|
+
*/
|
|
93
|
+
export declare class UnderwaterIsolatedPositionsError extends Error {
|
|
94
|
+
readonly shortfalls: IsolatedMarginShortfall[];
|
|
95
|
+
constructor(shortfalls: IsolatedMarginShortfall[]);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Calculates isolated position deposits for a trade.
|
|
99
|
+
* Auto-computes the main deposit from positionMaxLeverage.
|
|
100
|
+
* Also detects underwater positions on other markets and either throws or computes additional deposits.
|
|
101
|
+
*/
|
|
102
|
+
export declare function calculateIsolatedPositionDeposits(params: {
|
|
103
|
+
driftClient: DriftClient;
|
|
104
|
+
user: User;
|
|
105
|
+
marketIndex: number;
|
|
106
|
+
baseAssetAmount: BN;
|
|
107
|
+
direction?: PositionDirection;
|
|
108
|
+
positionMaxLeverage: number;
|
|
109
|
+
replenishUnderwaterPositions?: boolean;
|
|
110
|
+
numOfOpenHighLeverageSpots?: number;
|
|
111
|
+
}): {
|
|
112
|
+
mainDeposit: BN | undefined;
|
|
113
|
+
additionalIsolatedPositionDeposits: AdditionalIsolatedPositionDeposit[] | undefined;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Resolves isolated position deposits based on margin mode.
|
|
117
|
+
* Returns undefined for cross margin mode, otherwise computes deposits.
|
|
118
|
+
*
|
|
119
|
+
* If marginMode is not explicitly provided, derives it from the user's existing position.
|
|
120
|
+
*/
|
|
121
|
+
export declare function resolveIsolatedPositionDeposits(params: {
|
|
122
|
+
driftClient: DriftClient;
|
|
123
|
+
user: User;
|
|
124
|
+
marketIndex: number;
|
|
125
|
+
baseAssetAmount: BN;
|
|
126
|
+
direction?: PositionDirection;
|
|
127
|
+
positionMaxLeverage: number;
|
|
128
|
+
marginMode?: 'isolated' | 'cross';
|
|
129
|
+
replenishUnderwaterPositions?: boolean;
|
|
130
|
+
numOfOpenHighLeverageSpots?: number;
|
|
131
|
+
}): ReturnType<typeof calculateIsolatedPositionDeposits> | undefined;
|
|
132
|
+
/**
|
|
133
|
+
* Resolves isolated position deposits, using pre-computed overrides if provided.
|
|
134
|
+
* When `isolatedPositionDepositsOverride` is provided, skips auto-compute and uses
|
|
135
|
+
* the override values directly. Otherwise, delegates to `resolveIsolatedPositionDeposits()`.
|
|
136
|
+
*/
|
|
137
|
+
export declare function resolveIsolatedPositionDepositsWithOverride(override: IsolatedPositionDepositsOverride | undefined, computeParams: Parameters<typeof resolveIsolatedPositionDeposits>[0]): ReturnType<typeof resolveIsolatedPositionDeposits>;
|
|
83
138
|
export declare function getIsolatedPositionDepositIxIfNeeded(driftClient: DriftClient, user: User, marketIndex: number, isolatedPositionDeposit?: BN, signingAuthority?: PublicKey): Promise<TransactionInstruction | undefined>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getIsolatedPositionDepositIxIfNeeded = exports.computeIsolatedPositionDepositForTrade = exports.getTotalIsolatedMarginShortfall = exports.getOtherIsolatedMarginShortfalls = exports.getIsolatedMarginShortfall = exports.getIsolatedMarginShortfalls = exports.ISOLATED_POSITION_DEPOSIT_BUFFER_BPS = void 0;
|
|
3
|
+
exports.getIsolatedPositionDepositIxIfNeeded = exports.resolveIsolatedPositionDepositsWithOverride = exports.resolveIsolatedPositionDeposits = exports.calculateIsolatedPositionDeposits = exports.UnderwaterIsolatedPositionsError = exports.computeIsolatedPositionDepositForTrade = exports.getTotalIsolatedMarginShortfall = exports.getOtherIsolatedMarginShortfalls = exports.getIsolatedMarginShortfall = exports.getIsolatedMarginShortfalls = exports.ISOLATED_POSITION_DEPOSIT_BUFFER_BPS = void 0;
|
|
4
4
|
const sdk_1 = require("@drift-labs/sdk");
|
|
5
|
+
const trading_1 = require("../../../../../common-ui-utils/trading");
|
|
6
|
+
const positionMarginMode_1 = require("../../../details/user/positionMarginMode");
|
|
5
7
|
exports.ISOLATED_POSITION_DEPOSIT_BUFFER_BPS = 15;
|
|
6
8
|
/**
|
|
7
9
|
* Computes the initial margin shortfall for all isolated perp positions.
|
|
@@ -62,7 +64,7 @@ exports.getTotalIsolatedMarginShortfall = getTotalIsolatedMarginShortfall;
|
|
|
62
64
|
* Computes the isolated position deposit required for opening an isolated perp position.
|
|
63
65
|
* Returns a BN in QUOTE_PRECISION (USDC).
|
|
64
66
|
*/
|
|
65
|
-
function computeIsolatedPositionDepositForTrade({ driftClient, user, marketIndex, baseAssetAmount, direction, marginRatio, entryPrice, numOfOpenHighLeverageSpots, bufferDenominator, includeExistingShortfall, }) {
|
|
67
|
+
function computeIsolatedPositionDepositForTrade({ driftClient, user, marketIndex, baseAssetAmount, direction, marginRatio, entryPrice, numOfOpenHighLeverageSpots, bufferDenominator, includeExistingShortfall, existingShortfall: precomputedShortfall, }) {
|
|
66
68
|
var _a;
|
|
67
69
|
// Only require isolated deposit if the order will increase the position (when direction is provided)
|
|
68
70
|
if (direction !== undefined) {
|
|
@@ -83,10 +85,10 @@ function computeIsolatedPositionDepositForTrade({ driftClient, user, marketIndex
|
|
|
83
85
|
const hasOpenHighLeverageSpots = numOfOpenHighLeverageSpots !== undefined && numOfOpenHighLeverageSpots > 0;
|
|
84
86
|
const enteringHighLeverageMode = userIsInHighLeverageMode || hasOpenHighLeverageSpots;
|
|
85
87
|
const marginRequired = (0, sdk_1.calculateMarginUSDCRequiredForTrade)(driftClient, marketIndex, baseAssetAmount, marginRatio, enteringHighLeverageMode, entryPrice);
|
|
86
|
-
let depositAmount = marginRequired.add(marginRequired.div(new sdk_1.BN(bufferDenominator !== null && bufferDenominator !== void 0 ? bufferDenominator : exports.ISOLATED_POSITION_DEPOSIT_BUFFER_BPS)));
|
|
88
|
+
let depositAmount = marginRequired.add(marginRequired.div(new sdk_1.BN(bufferDenominator !== null && bufferDenominator !== void 0 ? bufferDenominator : exports.ISOLATED_POSITION_DEPOSIT_BUFFER_BPS)));
|
|
87
89
|
// Add existing shortfall for this market if requested
|
|
88
90
|
if (includeExistingShortfall) {
|
|
89
|
-
const existingShortfall = getIsolatedMarginShortfall(user, marketIndex);
|
|
91
|
+
const existingShortfall = precomputedShortfall !== null && precomputedShortfall !== void 0 ? precomputedShortfall : getIsolatedMarginShortfall(user, marketIndex);
|
|
90
92
|
if (existingShortfall.gt(sdk_1.ZERO)) {
|
|
91
93
|
// Add shortfall with a 5% buffer on top (same as new margin)
|
|
92
94
|
const shortfallWithBuffer = existingShortfall.add(existingShortfall.div(new sdk_1.BN(bufferDenominator !== null && bufferDenominator !== void 0 ? bufferDenominator : exports.ISOLATED_POSITION_DEPOSIT_BUFFER_BPS)));
|
|
@@ -96,6 +98,102 @@ function computeIsolatedPositionDepositForTrade({ driftClient, user, marketIndex
|
|
|
96
98
|
return depositAmount;
|
|
97
99
|
}
|
|
98
100
|
exports.computeIsolatedPositionDepositForTrade = computeIsolatedPositionDepositForTrade;
|
|
101
|
+
/**
|
|
102
|
+
* Error thrown when underwater isolated positions are detected and
|
|
103
|
+
* replenishUnderwaterPositions is not set to true.
|
|
104
|
+
*/
|
|
105
|
+
class UnderwaterIsolatedPositionsError extends Error {
|
|
106
|
+
constructor(shortfalls) {
|
|
107
|
+
super(`Underwater isolated positions detected for markets: ${shortfalls
|
|
108
|
+
.map((s) => s.marketIndex)
|
|
109
|
+
.join(', ')}. ` +
|
|
110
|
+
`Set replenishUnderwaterPositions: true to auto-cover, or manually handle shortfalls.`);
|
|
111
|
+
this.shortfalls = shortfalls;
|
|
112
|
+
this.name = 'UnderwaterIsolatedPositionsError';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.UnderwaterIsolatedPositionsError = UnderwaterIsolatedPositionsError;
|
|
116
|
+
/**
|
|
117
|
+
* Calculates isolated position deposits for a trade.
|
|
118
|
+
* Auto-computes the main deposit from positionMaxLeverage.
|
|
119
|
+
* Also detects underwater positions on other markets and either throws or computes additional deposits.
|
|
120
|
+
*/
|
|
121
|
+
function calculateIsolatedPositionDeposits(params) {
|
|
122
|
+
var _a;
|
|
123
|
+
// Compute all shortfalls once (single getMarginCalculation call)
|
|
124
|
+
// to avoid duplicate expensive margin calculations
|
|
125
|
+
const allShortfalls = getIsolatedMarginShortfalls(params.user);
|
|
126
|
+
// Extract current market's shortfall from the pre-computed map
|
|
127
|
+
const currentMarketShortfall = (_a = allShortfalls.get(params.marketIndex)) !== null && _a !== void 0 ? _a : sdk_1.ZERO;
|
|
128
|
+
let mainIsolatedPositionDeposit;
|
|
129
|
+
const marginRatio = trading_1.TRADING_UTILS.convertLeverageToMarginRatio(params.positionMaxLeverage);
|
|
130
|
+
if (marginRatio) {
|
|
131
|
+
mainIsolatedPositionDeposit = computeIsolatedPositionDepositForTrade({
|
|
132
|
+
driftClient: params.driftClient,
|
|
133
|
+
user: params.user,
|
|
134
|
+
marketIndex: params.marketIndex,
|
|
135
|
+
baseAssetAmount: params.baseAssetAmount,
|
|
136
|
+
direction: params.direction,
|
|
137
|
+
marginRatio,
|
|
138
|
+
numOfOpenHighLeverageSpots: params.numOfOpenHighLeverageSpots,
|
|
139
|
+
bufferDenominator: exports.ISOLATED_POSITION_DEPOSIT_BUFFER_BPS,
|
|
140
|
+
includeExistingShortfall: true,
|
|
141
|
+
// Use pre-computed shortfall to avoid a second getMarginCalculation call
|
|
142
|
+
existingShortfall: currentMarketShortfall,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
// Check for underwater positions (excluding current market)
|
|
146
|
+
const otherShortfalls = Array.from(allShortfalls)
|
|
147
|
+
.filter(([marketIndex]) => marketIndex !== params.marketIndex)
|
|
148
|
+
.map(([marketIndex, shortfall]) => ({ marketIndex, shortfall }));
|
|
149
|
+
if (otherShortfalls.length > 0 && !params.replenishUnderwaterPositions) {
|
|
150
|
+
throw new UnderwaterIsolatedPositionsError(otherShortfalls);
|
|
151
|
+
}
|
|
152
|
+
let additionalIsolatedPositionDeposits;
|
|
153
|
+
if (otherShortfalls.length > 0 && params.replenishUnderwaterPositions) {
|
|
154
|
+
additionalIsolatedPositionDeposits = otherShortfalls.map((shortfall) => {
|
|
155
|
+
const shortfallWithBuffer = shortfall.shortfall.add(shortfall.shortfall.div(new sdk_1.BN(exports.ISOLATED_POSITION_DEPOSIT_BUFFER_BPS)));
|
|
156
|
+
return {
|
|
157
|
+
marketIndex: shortfall.marketIndex,
|
|
158
|
+
amount: shortfallWithBuffer,
|
|
159
|
+
};
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
mainDeposit: mainIsolatedPositionDeposit,
|
|
164
|
+
additionalIsolatedPositionDeposits,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
exports.calculateIsolatedPositionDeposits = calculateIsolatedPositionDeposits;
|
|
168
|
+
/**
|
|
169
|
+
* Resolves isolated position deposits based on margin mode.
|
|
170
|
+
* Returns undefined for cross margin mode, otherwise computes deposits.
|
|
171
|
+
*
|
|
172
|
+
* If marginMode is not explicitly provided, derives it from the user's existing position.
|
|
173
|
+
*/
|
|
174
|
+
function resolveIsolatedPositionDeposits(params) {
|
|
175
|
+
var _a;
|
|
176
|
+
const isIsolated = ((_a = params.marginMode) !== null && _a !== void 0 ? _a : (0, positionMarginMode_1.getPositionMarginMode)(params.user, params.marketIndex)) === 'isolated';
|
|
177
|
+
if (!isIsolated)
|
|
178
|
+
return undefined;
|
|
179
|
+
return calculateIsolatedPositionDeposits(params);
|
|
180
|
+
}
|
|
181
|
+
exports.resolveIsolatedPositionDeposits = resolveIsolatedPositionDeposits;
|
|
182
|
+
/**
|
|
183
|
+
* Resolves isolated position deposits, using pre-computed overrides if provided.
|
|
184
|
+
* When `isolatedPositionDepositsOverride` is provided, skips auto-compute and uses
|
|
185
|
+
* the override values directly. Otherwise, delegates to `resolveIsolatedPositionDeposits()`.
|
|
186
|
+
*/
|
|
187
|
+
function resolveIsolatedPositionDepositsWithOverride(override, computeParams) {
|
|
188
|
+
if (override !== undefined) {
|
|
189
|
+
return {
|
|
190
|
+
mainDeposit: override.mainDeposit,
|
|
191
|
+
additionalIsolatedPositionDeposits: override.additionalDeposits,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return resolveIsolatedPositionDeposits(computeParams);
|
|
195
|
+
}
|
|
196
|
+
exports.resolveIsolatedPositionDepositsWithOverride = resolveIsolatedPositionDepositsWithOverride;
|
|
99
197
|
async function getIsolatedPositionDepositIxIfNeeded(driftClient, user, marketIndex, isolatedPositionDeposit, signingAuthority) {
|
|
100
198
|
if (!isolatedPositionDeposit) {
|
|
101
199
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isolatedPositionDeposit.js","sourceRoot":"","sources":["../../../../../../src/drift/base/actions/trade/openPerpOrder/isolatedPositionDeposit.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tBN,\n\tDriftClient,\n\tUser,\n\tcalculateMarginUSDCRequiredForTrade,\n\tOptionalOrderParams,\n\tPositionDirection,\n\tMarketType,\n\tOrderType,\n\tZERO,\n} from '@drift-labs/sdk';\nimport { PublicKey, TransactionInstruction } from '@solana/web3.js';\n\nexport const ISOLATED_POSITION_DEPOSIT_BUFFER_BPS = 15;\n\nexport interface IsolatedMarginShortfall {\n\tmarketIndex: number;\n\tshortfall: BN;\n}\n\n/**\n * Computes the initial margin shortfall for all isolated perp positions.\n * Returns a map of marketIndex -> shortfall (in QUOTE_PRECISION).\n * Only includes positions that are under initial margin (shortfall > 0).\n */\nexport function getIsolatedMarginShortfalls(user: User): Map<number, BN> {\n\tconst shortfalls = new Map<number, BN>();\n\n\tconst marginCalc = user.getMarginCalculation('Initial');\n\n\tfor (const [\n\t\tmarketIndex,\n\t\tisolatedCalc,\n\t] of marginCalc.isolatedMarginCalculations) {\n\t\tconst shortfall = isolatedCalc.marginShortage();\n\t\tif (shortfall.gt(ZERO)) {\n\t\t\tshortfalls.set(marketIndex, shortfall);\n\t\t}\n\t}\n\n\treturn shortfalls;\n}\n\n/**\n * Computes the initial margin shortfall for a single isolated perp position.\n * Returns the shortfall in QUOTE_PRECISION, or ZERO if no shortfall.\n */\nexport function getIsolatedMarginShortfall(\n\tuser: User,\n\tmarketIndex: number\n): BN {\n\tconst marginCalc = user.getMarginCalculation('Initial');\n\tconst isolatedCalc = marginCalc.isolatedMarginCalculations.get(marketIndex);\n\n\tif (!isolatedCalc) {\n\t\treturn ZERO;\n\t}\n\n\treturn isolatedCalc.marginShortage();\n}\n\n/**\n * Returns all isolated margin shortfalls as an array, excluding a specific market index.\n * Useful for getting shortfalls for \"other\" isolated positions.\n */\nexport function getOtherIsolatedMarginShortfalls(\n\tuser: User,\n\texcludeMarketIndex?: number\n): IsolatedMarginShortfall[] {\n\tconst shortfalls = getIsolatedMarginShortfalls(user);\n\tconst result: IsolatedMarginShortfall[] = [];\n\n\tfor (const [marketIndex, shortfall] of shortfalls) {\n\t\tif (\n\t\t\texcludeMarketIndex !== undefined &&\n\t\t\tmarketIndex === excludeMarketIndex\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tresult.push({ marketIndex, shortfall });\n\t}\n\n\treturn result;\n}\n\n/**\n * Computes the total of all isolated margin shortfalls.\n */\nexport function getTotalIsolatedMarginShortfall(\n\tuser: User,\n\texcludeMarketIndex?: number\n): BN {\n\tconst shortfalls = getOtherIsolatedMarginShortfalls(user, excludeMarketIndex);\n\treturn shortfalls.reduce((acc, s) => acc.add(s.shortfall), ZERO);\n}\n\nexport interface ComputeIsolatedPositionDepositParams {\n\tdriftClient: DriftClient;\n\tuser: User;\n\tmarketIndex: number;\n\tbaseAssetAmount: BN;\n\t/**\n\t * Optional direction of the order.\n\t * If provided, we will check if the order will increase the position.\n\t * If the order will not increase the position, we will return 0.\n\t */\n\tdirection?: PositionDirection;\n\t/**\n\t * Margin ratio to use for the position (e.g. 2000 for 5x leverage).\n\t */\n\tmarginRatio: number;\n\t/**\n\t * Optional estimated entry price to use for the margin calculation.\n\t */\n\tentryPrice?: BN;\n\t/**\n\t * Number of open high leverage spots available to the user (if any).\n\t * If greater than 0, we will consider the trade as entering high leverage mode.\n\t */\n\tnumOfOpenHighLeverageSpots?: number;\n\t/**\n\t * Optional buffer denominator for the isolated position deposit.\n\t *\n\t * Smaller numbers mean a bigger buffer.\n\t *\n\t * bufferDenominator -> Buffer %\n\t *\n\t * 15 -> 6.67%\n\t *\n\t * 20 (default) -> 5.00%\n\t *\n\t * 50 -> 2.00%\n\t *\n\t * 100 -> 1.00%\n\t *\n\t * 180 -> 0.56%\n\t *\n\t * 200 -> 0.50%\n\t */\n\tbufferDenominator?: number;\n\t/**\n\t * If true, the current market's initial margin shortfall (if any)\n\t * will be added to the deposit amount.\n\t */\n\tincludeExistingShortfall?: boolean;\n}\n\n/**\n * Computes the isolated position deposit required for opening an isolated perp position.\n * Returns a BN in QUOTE_PRECISION (USDC).\n */\nexport function computeIsolatedPositionDepositForTrade({\n\tdriftClient,\n\tuser,\n\tmarketIndex,\n\tbaseAssetAmount,\n\tdirection,\n\tmarginRatio,\n\tentryPrice,\n\tnumOfOpenHighLeverageSpots,\n\tbufferDenominator,\n\tincludeExistingShortfall,\n}: ComputeIsolatedPositionDepositParams): BN | null {\n\t// Only require isolated deposit if the order will increase the position (when direction is provided)\n\tif (direction !== undefined) {\n\t\tconst maybeOrderParams: OptionalOrderParams = {\n\t\t\tmarketIndex,\n\t\t\tmarketType: MarketType.PERP,\n\t\t\torderType: OrderType.MARKET,\n\t\t\tdirection,\n\t\t\tbaseAssetAmount,\n\t\t};\n\t\tconst subAccountId = user.getUserAccount().subAccountId;\n\t\tconst isIncreasing = driftClient.isOrderIncreasingPosition(\n\t\t\tmaybeOrderParams,\n\t\t\tsubAccountId\n\t\t);\n\t\tif (!isIncreasing) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tconst userIsInHighLeverageMode = user.isHighLeverageMode('Initial') ?? false;\n\tconst hasOpenHighLeverageSpots =\n\t\tnumOfOpenHighLeverageSpots !== undefined && numOfOpenHighLeverageSpots > 0;\n\tconst enteringHighLeverageMode =\n\t\tuserIsInHighLeverageMode || hasOpenHighLeverageSpots;\n\n\tconst marginRequired = calculateMarginUSDCRequiredForTrade(\n\t\tdriftClient,\n\t\tmarketIndex,\n\t\tbaseAssetAmount,\n\t\tmarginRatio,\n\t\tenteringHighLeverageMode,\n\t\tentryPrice\n\t);\n\n\tlet depositAmount = marginRequired.add(\n\t\tmarginRequired.div(\n\t\t\tnew BN(bufferDenominator ?? ISOLATED_POSITION_DEPOSIT_BUFFER_BPS)\n\t\t)\n\t); // buffer in basis points\n\n\t// Add existing shortfall for this market if requested\n\tif (includeExistingShortfall) {\n\t\tconst existingShortfall = getIsolatedMarginShortfall(user, marketIndex);\n\t\tif (existingShortfall.gt(ZERO)) {\n\t\t\t// Add shortfall with a 5% buffer on top (same as new margin)\n\t\t\tconst shortfallWithBuffer = existingShortfall.add(\n\t\t\t\texistingShortfall.div(\n\t\t\t\t\tnew BN(bufferDenominator ?? ISOLATED_POSITION_DEPOSIT_BUFFER_BPS)\n\t\t\t\t)\n\t\t\t);\n\t\t\tdepositAmount = depositAmount.add(shortfallWithBuffer);\n\t\t}\n\t}\n\n\treturn depositAmount;\n}\n\nexport async function getIsolatedPositionDepositIxIfNeeded(\n\tdriftClient: DriftClient,\n\tuser: User,\n\tmarketIndex: number,\n\tisolatedPositionDeposit?: BN,\n\tsigningAuthority?: PublicKey\n): Promise<TransactionInstruction | undefined> {\n\tif (!isolatedPositionDeposit) {\n\t\treturn undefined;\n\t}\n\tif (isolatedPositionDeposit.isZero()) {\n\t\treturn undefined;\n\t}\n\n\treturn driftClient.getTransferIsolatedPerpPositionDepositIx(\n\t\tisolatedPositionDeposit,\n\t\tmarketIndex,\n\t\tuser.getUserAccount().subAccountId,\n\t\tundefined, // noAmountBuffer\n\t\tsigningAuthority\n\t);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"isolatedPositionDeposit.js","sourceRoot":"","sources":["../../../../../../src/drift/base/actions/trade/openPerpOrder/isolatedPositionDeposit.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tBN,\n\tDriftClient,\n\tUser,\n\tcalculateMarginUSDCRequiredForTrade,\n\tOptionalOrderParams,\n\tPositionDirection,\n\tMarketType,\n\tOrderType,\n\tZERO,\n} from '@drift-labs/sdk';\nimport { PublicKey, TransactionInstruction } from '@solana/web3.js';\nimport { TRADING_UTILS } from '../../../../../common-ui-utils/trading';\nimport {\n\tAdditionalIsolatedPositionDeposit,\n\tIsolatedPositionDepositsOverride,\n} from './types';\nimport { getPositionMarginMode } from '../../../details/user/positionMarginMode';\n\nexport const ISOLATED_POSITION_DEPOSIT_BUFFER_BPS = 15;\n\nexport interface IsolatedMarginShortfall {\n\tmarketIndex: number;\n\tshortfall: BN;\n}\n\n/**\n * Computes the initial margin shortfall for all isolated perp positions.\n * Returns a map of marketIndex -> shortfall (in QUOTE_PRECISION).\n * Only includes positions that are under initial margin (shortfall > 0).\n */\nexport function getIsolatedMarginShortfalls(user: User): Map<number, BN> {\n\tconst shortfalls = new Map<number, BN>();\n\n\tconst marginCalc = user.getMarginCalculation('Initial');\n\n\tfor (const [\n\t\tmarketIndex,\n\t\tisolatedCalc,\n\t] of marginCalc.isolatedMarginCalculations) {\n\t\tconst shortfall = isolatedCalc.marginShortage();\n\t\tif (shortfall.gt(ZERO)) {\n\t\t\tshortfalls.set(marketIndex, shortfall);\n\t\t}\n\t}\n\n\treturn shortfalls;\n}\n\n/**\n * Computes the initial margin shortfall for a single isolated perp position.\n * Returns the shortfall in QUOTE_PRECISION, or ZERO if no shortfall.\n */\nexport function getIsolatedMarginShortfall(\n\tuser: User,\n\tmarketIndex: number\n): BN {\n\tconst marginCalc = user.getMarginCalculation('Initial');\n\tconst isolatedCalc = marginCalc.isolatedMarginCalculations.get(marketIndex);\n\n\tif (!isolatedCalc) {\n\t\treturn ZERO;\n\t}\n\n\treturn isolatedCalc.marginShortage();\n}\n\n/**\n * Returns all isolated margin shortfalls as an array, excluding a specific market index.\n * Useful for getting shortfalls for \"other\" isolated positions.\n */\nexport function getOtherIsolatedMarginShortfalls(\n\tuser: User,\n\texcludeMarketIndex?: number\n): IsolatedMarginShortfall[] {\n\tconst shortfalls = getIsolatedMarginShortfalls(user);\n\tconst result: IsolatedMarginShortfall[] = [];\n\n\tfor (const [marketIndex, shortfall] of shortfalls) {\n\t\tif (\n\t\t\texcludeMarketIndex !== undefined &&\n\t\t\tmarketIndex === excludeMarketIndex\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tresult.push({ marketIndex, shortfall });\n\t}\n\n\treturn result;\n}\n\n/**\n * Computes the total of all isolated margin shortfalls.\n */\nexport function getTotalIsolatedMarginShortfall(\n\tuser: User,\n\texcludeMarketIndex?: number\n): BN {\n\tconst shortfalls = getOtherIsolatedMarginShortfalls(user, excludeMarketIndex);\n\treturn shortfalls.reduce((acc, s) => acc.add(s.shortfall), ZERO);\n}\n\nexport interface ComputeIsolatedPositionDepositParams {\n\tdriftClient: DriftClient;\n\tuser: User;\n\tmarketIndex: number;\n\tbaseAssetAmount: BN;\n\t/**\n\t * Optional direction of the order.\n\t * If provided, we will check if the order will increase the position.\n\t * If the order will not increase the position, we will return 0.\n\t */\n\tdirection?: PositionDirection;\n\t/**\n\t * Margin ratio to use for the position (e.g. 2000 for 5x leverage).\n\t */\n\tmarginRatio: number;\n\t/**\n\t * Optional estimated entry price to use for the margin calculation.\n\t */\n\tentryPrice?: BN;\n\t/**\n\t * Number of open high leverage spots available to the user (if any).\n\t * If greater than 0, we will consider the trade as entering high leverage mode.\n\t */\n\tnumOfOpenHighLeverageSpots?: number;\n\t/**\n\t * Optional buffer denominator for the isolated position deposit.\n\t *\n\t * Smaller numbers mean a bigger buffer.\n\t *\n\t * bufferDenominator -> Buffer %\n\t *\n\t * 15 -> 6.67%\n\t *\n\t * 20 (default) -> 5.00%\n\t *\n\t * 50 -> 2.00%\n\t *\n\t * 100 -> 1.00%\n\t *\n\t * 180 -> 0.56%\n\t *\n\t * 200 -> 0.50%\n\t */\n\tbufferDenominator?: number;\n\t/**\n\t * If true, the current market's initial margin shortfall (if any)\n\t * will be added to the deposit amount.\n\t */\n\tincludeExistingShortfall?: boolean;\n\t/**\n\t * Pre-computed existing shortfall for the current market.\n\t * When provided alongside includeExistingShortfall, avoids a redundant getMarginCalculation call.\n\t */\n\texistingShortfall?: BN;\n}\n\n/**\n * Computes the isolated position deposit required for opening an isolated perp position.\n * Returns a BN in QUOTE_PRECISION (USDC).\n */\nexport function computeIsolatedPositionDepositForTrade({\n\tdriftClient,\n\tuser,\n\tmarketIndex,\n\tbaseAssetAmount,\n\tdirection,\n\tmarginRatio,\n\tentryPrice,\n\tnumOfOpenHighLeverageSpots,\n\tbufferDenominator,\n\tincludeExistingShortfall,\n\texistingShortfall: precomputedShortfall,\n}: ComputeIsolatedPositionDepositParams): BN | null {\n\t// Only require isolated deposit if the order will increase the position (when direction is provided)\n\tif (direction !== undefined) {\n\t\tconst maybeOrderParams: OptionalOrderParams = {\n\t\t\tmarketIndex,\n\t\t\tmarketType: MarketType.PERP,\n\t\t\torderType: OrderType.MARKET,\n\t\t\tdirection,\n\t\t\tbaseAssetAmount,\n\t\t};\n\t\tconst subAccountId = user.getUserAccount().subAccountId;\n\t\tconst isIncreasing = driftClient.isOrderIncreasingPosition(\n\t\t\tmaybeOrderParams,\n\t\t\tsubAccountId\n\t\t);\n\t\tif (!isIncreasing) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tconst userIsInHighLeverageMode = user.isHighLeverageMode('Initial') ?? false;\n\tconst hasOpenHighLeverageSpots =\n\t\tnumOfOpenHighLeverageSpots !== undefined && numOfOpenHighLeverageSpots > 0;\n\tconst enteringHighLeverageMode =\n\t\tuserIsInHighLeverageMode || hasOpenHighLeverageSpots;\n\n\tconst marginRequired = calculateMarginUSDCRequiredForTrade(\n\t\tdriftClient,\n\t\tmarketIndex,\n\t\tbaseAssetAmount,\n\t\tmarginRatio,\n\t\tenteringHighLeverageMode,\n\t\tentryPrice\n\t);\n\n\tlet depositAmount = marginRequired.add(\n\t\tmarginRequired.div(\n\t\t\tnew BN(bufferDenominator ?? ISOLATED_POSITION_DEPOSIT_BUFFER_BPS)\n\t\t)\n\t);\n\n\t// Add existing shortfall for this market if requested\n\tif (includeExistingShortfall) {\n\t\tconst existingShortfall =\n\t\t\tprecomputedShortfall ?? getIsolatedMarginShortfall(user, marketIndex);\n\t\tif (existingShortfall.gt(ZERO)) {\n\t\t\t// Add shortfall with a 5% buffer on top (same as new margin)\n\t\t\tconst shortfallWithBuffer = existingShortfall.add(\n\t\t\t\texistingShortfall.div(\n\t\t\t\t\tnew BN(bufferDenominator ?? ISOLATED_POSITION_DEPOSIT_BUFFER_BPS)\n\t\t\t\t)\n\t\t\t);\n\t\t\tdepositAmount = depositAmount.add(shortfallWithBuffer);\n\t\t}\n\t}\n\n\treturn depositAmount;\n}\n\n/**\n * Error thrown when underwater isolated positions are detected and\n * replenishUnderwaterPositions is not set to true.\n */\nexport class UnderwaterIsolatedPositionsError extends Error {\n\tconstructor(public readonly shortfalls: IsolatedMarginShortfall[]) {\n\t\tsuper(\n\t\t\t`Underwater isolated positions detected for markets: ${shortfalls\n\t\t\t\t.map((s) => s.marketIndex)\n\t\t\t\t.join(', ')}. ` +\n\t\t\t\t`Set replenishUnderwaterPositions: true to auto-cover, or manually handle shortfalls.`\n\t\t);\n\t\tthis.name = 'UnderwaterIsolatedPositionsError';\n\t}\n}\n\n/**\n * Calculates isolated position deposits for a trade.\n * Auto-computes the main deposit from positionMaxLeverage.\n * Also detects underwater positions on other markets and either throws or computes additional deposits.\n */\nexport function calculateIsolatedPositionDeposits(params: {\n\tdriftClient: DriftClient;\n\tuser: User;\n\tmarketIndex: number;\n\tbaseAssetAmount: BN;\n\tdirection?: PositionDirection;\n\tpositionMaxLeverage: number;\n\treplenishUnderwaterPositions?: boolean;\n\tnumOfOpenHighLeverageSpots?: number;\n}): {\n\tmainDeposit: BN | undefined;\n\tadditionalIsolatedPositionDeposits:\n\t\t| AdditionalIsolatedPositionDeposit[]\n\t\t| undefined;\n} {\n\t// Compute all shortfalls once (single getMarginCalculation call)\n\t// to avoid duplicate expensive margin calculations\n\tconst allShortfalls = getIsolatedMarginShortfalls(params.user);\n\n\t// Extract current market's shortfall from the pre-computed map\n\tconst currentMarketShortfall = allShortfalls.get(params.marketIndex) ?? ZERO;\n\n\tlet mainIsolatedPositionDeposit: BN | undefined;\n\tconst marginRatio = TRADING_UTILS.convertLeverageToMarginRatio(\n\t\tparams.positionMaxLeverage\n\t);\n\n\tif (marginRatio) {\n\t\tmainIsolatedPositionDeposit = computeIsolatedPositionDepositForTrade({\n\t\t\tdriftClient: params.driftClient,\n\t\t\tuser: params.user,\n\t\t\tmarketIndex: params.marketIndex,\n\t\t\tbaseAssetAmount: params.baseAssetAmount,\n\t\t\tdirection: params.direction,\n\t\t\tmarginRatio,\n\t\t\tnumOfOpenHighLeverageSpots: params.numOfOpenHighLeverageSpots,\n\t\t\tbufferDenominator: ISOLATED_POSITION_DEPOSIT_BUFFER_BPS,\n\t\t\tincludeExistingShortfall: true,\n\t\t\t// Use pre-computed shortfall to avoid a second getMarginCalculation call\n\t\t\texistingShortfall: currentMarketShortfall,\n\t\t});\n\t}\n\n\t// Check for underwater positions (excluding current market)\n\tconst otherShortfalls: IsolatedMarginShortfall[] = Array.from(allShortfalls)\n\t\t.filter(([marketIndex]) => marketIndex !== params.marketIndex)\n\t\t.map(([marketIndex, shortfall]) => ({ marketIndex, shortfall }));\n\n\tif (otherShortfalls.length > 0 && !params.replenishUnderwaterPositions) {\n\t\tthrow new UnderwaterIsolatedPositionsError(otherShortfalls);\n\t}\n\n\tlet additionalIsolatedPositionDeposits:\n\t\t| AdditionalIsolatedPositionDeposit[]\n\t\t| undefined;\n\n\tif (otherShortfalls.length > 0 && params.replenishUnderwaterPositions) {\n\t\tadditionalIsolatedPositionDeposits = otherShortfalls.map((shortfall) => {\n\t\t\tconst shortfallWithBuffer = shortfall.shortfall.add(\n\t\t\t\tshortfall.shortfall.div(new BN(ISOLATED_POSITION_DEPOSIT_BUFFER_BPS))\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tmarketIndex: shortfall.marketIndex,\n\t\t\t\tamount: shortfallWithBuffer,\n\t\t\t};\n\t\t});\n\t}\n\n\treturn {\n\t\tmainDeposit: mainIsolatedPositionDeposit,\n\t\tadditionalIsolatedPositionDeposits,\n\t};\n}\n\n/**\n * Resolves isolated position deposits based on margin mode.\n * Returns undefined for cross margin mode, otherwise computes deposits.\n *\n * If marginMode is not explicitly provided, derives it from the user's existing position.\n */\nexport function resolveIsolatedPositionDeposits(params: {\n\tdriftClient: DriftClient;\n\tuser: User;\n\tmarketIndex: number;\n\tbaseAssetAmount: BN;\n\tdirection?: PositionDirection;\n\tpositionMaxLeverage: number;\n\tmarginMode?: 'isolated' | 'cross';\n\treplenishUnderwaterPositions?: boolean;\n\tnumOfOpenHighLeverageSpots?: number;\n}): ReturnType<typeof calculateIsolatedPositionDeposits> | undefined {\n\tconst isIsolated =\n\t\t(params.marginMode ??\n\t\t\tgetPositionMarginMode(params.user, params.marketIndex)) === 'isolated';\n\n\tif (!isIsolated) return undefined;\n\n\treturn calculateIsolatedPositionDeposits(params);\n}\n\n/**\n * Resolves isolated position deposits, using pre-computed overrides if provided.\n * When `isolatedPositionDepositsOverride` is provided, skips auto-compute and uses\n * the override values directly. Otherwise, delegates to `resolveIsolatedPositionDeposits()`.\n */\nexport function resolveIsolatedPositionDepositsWithOverride(\n\toverride: IsolatedPositionDepositsOverride | undefined,\n\tcomputeParams: Parameters<typeof resolveIsolatedPositionDeposits>[0]\n): ReturnType<typeof resolveIsolatedPositionDeposits> {\n\tif (override !== undefined) {\n\t\treturn {\n\t\t\tmainDeposit: override.mainDeposit,\n\t\t\tadditionalIsolatedPositionDeposits: override.additionalDeposits,\n\t\t};\n\t}\n\treturn resolveIsolatedPositionDeposits(computeParams);\n}\n\nexport async function getIsolatedPositionDepositIxIfNeeded(\n\tdriftClient: DriftClient,\n\tuser: User,\n\tmarketIndex: number,\n\tisolatedPositionDeposit?: BN,\n\tsigningAuthority?: PublicKey\n): Promise<TransactionInstruction | undefined> {\n\tif (!isolatedPositionDeposit) {\n\t\treturn undefined;\n\t}\n\tif (isolatedPositionDeposit.isZero()) {\n\t\treturn undefined;\n\t}\n\n\treturn driftClient.getTransferIsolatedPerpPositionDepositIx(\n\t\tisolatedPositionDeposit,\n\t\tmarketIndex,\n\t\tuser.getUserAccount().subAccountId,\n\t\tundefined, // noAmountBuffer\n\t\tsigningAuthority\n\t);\n}\n"]}
|
|
@@ -4,8 +4,8 @@ import { SwiftOrderOptions, SwiftOrderMessage } from '../openSwiftOrder';
|
|
|
4
4
|
import { OptionalAuctionParamsRequestInputs } from '../dlobServer';
|
|
5
5
|
import { HighLeverageOptions } from '../../../../../../common-ui-utils/order';
|
|
6
6
|
import { WithTxnParams } from '../../../../types';
|
|
7
|
-
import { TxnOrSwiftResult } from '../types';
|
|
8
|
-
import { PlaceAndTakeParams, OptionalTriggerOrderParams
|
|
7
|
+
import { TxnOrSwiftResult, IsolatedPositionDepositsOverride } from '../types';
|
|
8
|
+
import { PlaceAndTakeParams, OptionalTriggerOrderParams } from '../types';
|
|
9
9
|
import { AuctionParamsFetchedCallback } from '../../../../../utils/auctionParamsResponseMapper';
|
|
10
10
|
export interface OpenPerpMarketOrderBaseParams {
|
|
11
11
|
driftClient: DriftClient;
|
|
@@ -31,17 +31,18 @@ export interface OpenPerpMarketOrderBaseParams {
|
|
|
31
31
|
*/
|
|
32
32
|
positionMaxLeverage: number;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
34
|
+
* Position margin mode to use for the order.
|
|
35
|
+
* When 'isolated', auto-computes isolated position deposit from positionMaxLeverage,
|
|
36
|
+
* and any additional isolated position deposits need to replenish under-collateralized positions.
|
|
37
|
+
* If not provided, the position margin mode will be derived from the user's position margin mode,
|
|
38
|
+
* and if that does not exist, it will default to 'cross'.
|
|
37
39
|
*/
|
|
38
|
-
|
|
40
|
+
marginMode?: 'isolated' | 'cross';
|
|
39
41
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* Each deposit will create a separate instruction.
|
|
42
|
+
* Pre-computed isolated position deposits override. When provided,
|
|
43
|
+
* skips auto-compute and uses these values directly.
|
|
43
44
|
*/
|
|
44
|
-
|
|
45
|
+
isolatedPositionDepositsOverride?: IsolatedPositionDepositsOverride;
|
|
45
46
|
/**
|
|
46
47
|
* If provided, will override the main signer for the order. Otherwise, the main signer will be the user's authority.
|
|
47
48
|
* This is only applicable for non-SWIFT orders.
|
|
@@ -111,7 +112,7 @@ export declare function createSwiftMarketOrderMessage(params: CreateSwiftMarketO
|
|
|
111
112
|
* Creates a placeAndTake transaction instruction.
|
|
112
113
|
* Fallbacks to a regular market order if no top makers are found.
|
|
113
114
|
*/
|
|
114
|
-
export declare const createPlaceAndTakePerpMarketOrderIx: ({ assetType, direction, dlobServerHttpUrl, marketIndex, driftClient, user, userOrderId, amount, orderType, price, reduceOnly, referrerInfo, auctionDurationPercentage, optionalAuctionParamsInputs, mainSignerOverride, highLeverageOptions, positionMaxLeverage, callbacks, }: OpenPerpMarketOrderBaseParams & {
|
|
115
|
+
export declare const createPlaceAndTakePerpMarketOrderIx: ({ assetType, direction, dlobServerHttpUrl, marketIndex, driftClient, user, userOrderId, amount, orderType, price, reduceOnly, referrerInfo, auctionDurationPercentage, optionalAuctionParamsInputs, mainSignerOverride, highLeverageOptions, positionMaxLeverage, callbacks, }: Omit<OpenPerpMarketOrderBaseParams, 'marginMode' | 'isolatedPositionDepositsOverride'> & {
|
|
115
116
|
orderType?: OrderType;
|
|
116
117
|
price?: BN;
|
|
117
118
|
direction: PositionDirection;
|
|
@@ -140,7 +141,7 @@ export declare const createPlaceAndTakePerpMarketOrderIx: ({ assetType, directio
|
|
|
140
141
|
* @param userOrderId - the order ID in terms of incremental fills (usually 0). do NOT use the nextOrderId from the user account. values over 255 will cause the order to fail onchain.
|
|
141
142
|
* @returns Promise resolving to an array of transaction instructions for regular orders
|
|
142
143
|
*/
|
|
143
|
-
export declare const createOpenPerpMarketOrderIxs: ({ driftClient, user, assetType, marketIndex, direction, amount, reduceOnly, bracketOrders, dlobServerHttpUrl, placeAndTake, userOrderId, optionalAuctionParamsInputs, positionMaxLeverage, mainSignerOverride, highLeverageOptions,
|
|
144
|
+
export declare const createOpenPerpMarketOrderIxs: ({ driftClient, user, assetType, marketIndex, direction, amount, reduceOnly, bracketOrders, dlobServerHttpUrl, placeAndTake, userOrderId, optionalAuctionParamsInputs, positionMaxLeverage, mainSignerOverride, highLeverageOptions, marginMode, isolatedPositionDepositsOverride, callbacks, }: OpenPerpMarketOrderBaseParams) => Promise<TransactionInstruction[]>;
|
|
144
145
|
/**
|
|
145
146
|
* Creates a complete transaction for opening a perp market order.
|
|
146
147
|
*
|
|
@@ -45,7 +45,18 @@ async function prepSwiftMarketOrderData(params) {
|
|
|
45
45
|
* Creates and submits a Swift (signed message) order. Only available for perp orders.
|
|
46
46
|
*/
|
|
47
47
|
async function createSwiftMarketOrder(params) {
|
|
48
|
-
const { driftClient, user, marketIndex, bracketOrders, swiftOptions, positionMaxLeverage,
|
|
48
|
+
const { driftClient, user, marketIndex, amount, direction, bracketOrders, swiftOptions, positionMaxLeverage, marginMode, highLeverageOptions, builderParams, } = params;
|
|
49
|
+
const resolvedDeposits = (0, isolatedPositionDeposit_1.resolveIsolatedPositionDepositsWithOverride)(params.isolatedPositionDepositsOverride, {
|
|
50
|
+
driftClient,
|
|
51
|
+
user,
|
|
52
|
+
marketIndex,
|
|
53
|
+
baseAssetAmount: amount,
|
|
54
|
+
direction,
|
|
55
|
+
positionMaxLeverage,
|
|
56
|
+
marginMode,
|
|
57
|
+
replenishUnderwaterPositions: false, // Swift doesn't support additional deposits. Will throw error if other isolated position shortfalls exists.
|
|
58
|
+
numOfOpenHighLeverageSpots: highLeverageOptions === null || highLeverageOptions === void 0 ? void 0 : highLeverageOptions.numOfOpenHighLeverageSpots,
|
|
59
|
+
});
|
|
49
60
|
const { userAccount, orderParams } = await prepSwiftMarketOrderData(params);
|
|
50
61
|
await (0, openSwiftOrder_1.prepSignAndSendSwiftOrder)({
|
|
51
62
|
driftClient,
|
|
@@ -59,7 +70,7 @@ async function createSwiftMarketOrder(params) {
|
|
|
59
70
|
takeProfit: bracketOrders === null || bracketOrders === void 0 ? void 0 : bracketOrders.takeProfit,
|
|
60
71
|
stopLoss: bracketOrders === null || bracketOrders === void 0 ? void 0 : bracketOrders.stopLoss,
|
|
61
72
|
positionMaxLeverage,
|
|
62
|
-
isolatedPositionDeposit,
|
|
73
|
+
isolatedPositionDeposit: resolvedDeposits === null || resolvedDeposits === void 0 ? void 0 : resolvedDeposits.mainDeposit,
|
|
63
74
|
},
|
|
64
75
|
builderParams,
|
|
65
76
|
});
|
|
@@ -72,7 +83,18 @@ exports.createSwiftMarketOrder = createSwiftMarketOrder;
|
|
|
72
83
|
* @returns The prepared SwiftOrderMessage ready for client-side signing and sending
|
|
73
84
|
*/
|
|
74
85
|
async function createSwiftMarketOrderMessage(params) {
|
|
75
|
-
const { driftClient, user, marketIndex, bracketOrders, positionMaxLeverage,
|
|
86
|
+
const { driftClient, user, marketIndex, amount, direction, bracketOrders, positionMaxLeverage, marginMode, highLeverageOptions, builderParams, isDelegate = false, userSigningSlotBuffer, } = params;
|
|
87
|
+
const resolvedDeposits = (0, isolatedPositionDeposit_1.resolveIsolatedPositionDepositsWithOverride)(params.isolatedPositionDepositsOverride, {
|
|
88
|
+
driftClient,
|
|
89
|
+
user,
|
|
90
|
+
marketIndex,
|
|
91
|
+
baseAssetAmount: amount,
|
|
92
|
+
direction,
|
|
93
|
+
positionMaxLeverage,
|
|
94
|
+
marginMode,
|
|
95
|
+
replenishUnderwaterPositions: false, // Swift doesn't support additional deposits. Will throw error if other isolated position shortfalls exists.
|
|
96
|
+
numOfOpenHighLeverageSpots: highLeverageOptions === null || highLeverageOptions === void 0 ? void 0 : highLeverageOptions.numOfOpenHighLeverageSpots,
|
|
97
|
+
});
|
|
76
98
|
const { userAccount, orderParams } = await prepSwiftMarketOrderData(params);
|
|
77
99
|
return (0, openSwiftOrder_1.prepSwiftOrderMessage)({
|
|
78
100
|
driftClient,
|
|
@@ -86,7 +108,7 @@ async function createSwiftMarketOrderMessage(params) {
|
|
|
86
108
|
takeProfit: bracketOrders === null || bracketOrders === void 0 ? void 0 : bracketOrders.takeProfit,
|
|
87
109
|
stopLoss: bracketOrders === null || bracketOrders === void 0 ? void 0 : bracketOrders.stopLoss,
|
|
88
110
|
positionMaxLeverage,
|
|
89
|
-
isolatedPositionDeposit,
|
|
111
|
+
isolatedPositionDeposit: resolvedDeposits === null || resolvedDeposits === void 0 ? void 0 : resolvedDeposits.mainDeposit,
|
|
90
112
|
},
|
|
91
113
|
builderParams,
|
|
92
114
|
});
|
|
@@ -163,28 +185,42 @@ exports.createPlaceAndTakePerpMarketOrderIx = createPlaceAndTakePerpMarketOrderI
|
|
|
163
185
|
* @param userOrderId - the order ID in terms of incremental fills (usually 0). do NOT use the nextOrderId from the user account. values over 255 will cause the order to fail onchain.
|
|
164
186
|
* @returns Promise resolving to an array of transaction instructions for regular orders
|
|
165
187
|
*/
|
|
166
|
-
const createOpenPerpMarketOrderIxs = async ({ driftClient, user, assetType, marketIndex, direction, amount, reduceOnly, bracketOrders, dlobServerHttpUrl, placeAndTake, userOrderId, optionalAuctionParamsInputs = {}, positionMaxLeverage, mainSignerOverride, highLeverageOptions,
|
|
188
|
+
const createOpenPerpMarketOrderIxs = async ({ driftClient, user, assetType, marketIndex, direction, amount, reduceOnly, bracketOrders, dlobServerHttpUrl, placeAndTake, userOrderId, optionalAuctionParamsInputs = {}, positionMaxLeverage, mainSignerOverride, highLeverageOptions, marginMode, isolatedPositionDepositsOverride, callbacks, }) => {
|
|
167
189
|
var _a, _b, _c, _d;
|
|
168
190
|
if (!amount || amount.isZero()) {
|
|
169
191
|
throw new Error('Amount must be greater than zero');
|
|
170
192
|
}
|
|
193
|
+
const resolvedDeposits = (0, isolatedPositionDeposit_1.resolveIsolatedPositionDepositsWithOverride)(isolatedPositionDepositsOverride, {
|
|
194
|
+
driftClient,
|
|
195
|
+
user,
|
|
196
|
+
marketIndex,
|
|
197
|
+
baseAssetAmount: amount,
|
|
198
|
+
direction,
|
|
199
|
+
positionMaxLeverage,
|
|
200
|
+
marginMode,
|
|
201
|
+
replenishUnderwaterPositions: true,
|
|
202
|
+
numOfOpenHighLeverageSpots: highLeverageOptions === null || highLeverageOptions === void 0 ? void 0 : highLeverageOptions.numOfOpenHighLeverageSpots,
|
|
203
|
+
});
|
|
204
|
+
const mainIsolatedDeposit = resolvedDeposits === null || resolvedDeposits === void 0 ? void 0 : resolvedDeposits.mainDeposit;
|
|
205
|
+
const resolvedAdditionalDeposits = resolvedDeposits === null || resolvedDeposits === void 0 ? void 0 : resolvedDeposits.additionalIsolatedPositionDeposits;
|
|
171
206
|
const allOrders = [];
|
|
172
207
|
const allIxs = [];
|
|
173
|
-
|
|
208
|
+
// Fetch all deposit/leverage ixs in parallel
|
|
209
|
+
const [leverageIx, additionalDepositIxs, isolatedPositionDepositIx] = await Promise.all([
|
|
210
|
+
(0, positionMaxLeverage_1.getPositionMaxLeverageIxIfNeeded)(driftClient, user, marketIndex, positionMaxLeverage, mainSignerOverride),
|
|
211
|
+
(resolvedAdditionalDeposits === null || resolvedAdditionalDeposits === void 0 ? void 0 : resolvedAdditionalDeposits.length)
|
|
212
|
+
? Promise.all(resolvedAdditionalDeposits.map((deposit) => (0, isolatedPositionDeposit_1.getIsolatedPositionDepositIxIfNeeded)(driftClient, user, deposit.marketIndex, deposit.amount, mainSignerOverride)))
|
|
213
|
+
: Promise.resolve([]),
|
|
214
|
+
(0, isolatedPositionDeposit_1.getIsolatedPositionDepositIxIfNeeded)(driftClient, user, marketIndex, mainIsolatedDeposit, mainSignerOverride),
|
|
215
|
+
]);
|
|
174
216
|
if (leverageIx) {
|
|
175
217
|
allIxs.push(leverageIx);
|
|
176
218
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const additionalDepositIxs = await Promise.all(additionalDepositIxPromises);
|
|
181
|
-
for (const ix of additionalDepositIxs) {
|
|
182
|
-
if (ix) {
|
|
183
|
-
allIxs.push(ix);
|
|
184
|
-
}
|
|
219
|
+
for (const ix of additionalDepositIxs) {
|
|
220
|
+
if (ix) {
|
|
221
|
+
allIxs.push(ix);
|
|
185
222
|
}
|
|
186
223
|
}
|
|
187
|
-
const isolatedPositionDepositIx = await (0, isolatedPositionDeposit_1.getIsolatedPositionDepositIxIfNeeded)(driftClient, user, marketIndex, isolatedPositionDeposit, mainSignerOverride);
|
|
188
224
|
if (isolatedPositionDepositIx) {
|
|
189
225
|
allIxs.push(isolatedPositionDepositIx);
|
|
190
226
|
}
|
|
@@ -255,7 +291,6 @@ const createOpenPerpMarketOrderIxs = async ({ driftClient, user, assetType, mark
|
|
|
255
291
|
limitPrice: bracketOrders.takeProfit.limitPrice,
|
|
256
292
|
},
|
|
257
293
|
reduceOnly: (_b = bracketOrders.takeProfit.reduceOnly) !== null && _b !== void 0 ? _b : true,
|
|
258
|
-
positionMaxLeverage,
|
|
259
294
|
});
|
|
260
295
|
allOrders.push(takeProfitParams);
|
|
261
296
|
}
|
|
@@ -271,7 +306,6 @@ const createOpenPerpMarketOrderIxs = async ({ driftClient, user, assetType, mark
|
|
|
271
306
|
limitPrice: bracketOrders.stopLoss.limitPrice,
|
|
272
307
|
},
|
|
273
308
|
reduceOnly: (_d = bracketOrders.stopLoss.reduceOnly) !== null && _d !== void 0 ? _d : true,
|
|
274
|
-
positionMaxLeverage,
|
|
275
309
|
});
|
|
276
310
|
allOrders.push(stopLossParams);
|
|
277
311
|
}
|