@drift-labs/sdk 0.1.23-master.2 → 0.1.24
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/accounts/bulkAccountLoader.d.ts +1 -0
- package/lib/accounts/bulkAccountLoader.js +14 -13
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +3 -3
- package/lib/accounts/pollingTokenAccountSubscriber.js +2 -2
- package/lib/accounts/pollingUserAccountSubscriber.js +4 -4
- package/lib/accounts/webSocketAccountSubscriber.js +2 -2
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +1 -1
- package/lib/accounts/webSocketUserAccountSubscriber.js +2 -2
- package/lib/admin.d.ts +2 -2
- package/lib/admin.js +12 -11
- package/lib/clearingHouse.js +19 -19
- package/lib/clearingHouseUser.d.ts +12 -17
- package/lib/clearingHouseUser.js +125 -228
- package/lib/constants/numericConstants.d.ts +1 -2
- package/lib/constants/numericConstants.js +2 -3
- package/lib/examples/makeTradeExample.js +6 -6
- package/lib/idl/clearing_house.json +42 -4
- package/lib/math/amm.js +12 -12
- package/lib/math/conversion.js +1 -1
- package/lib/math/funding.js +1 -1
- package/lib/math/market.js +2 -2
- package/lib/math/orders.d.ts +2 -0
- package/lib/math/orders.js +44 -4
- package/lib/math/position.js +1 -1
- package/lib/math/trade.js +18 -18
- package/lib/orders.d.ts +3 -1
- package/lib/orders.js +47 -19
- package/lib/pythClient.js +1 -1
- package/lib/tx/retryTxSender.js +1 -1
- package/lib/types.d.ts +4 -1
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.ts +18 -13
- package/src/accounts/types.js +10 -0
- package/src/accounts/utils.js +7 -0
- package/src/accounts/webSocketAccountSubscriber.js +76 -0
- package/src/addresses.js +83 -0
- package/src/admin.ts +13 -4
- package/src/clearingHouseUser.ts +161 -330
- package/src/constants/numericConstants.ts +1 -2
- package/src/idl/clearing_house.json +42 -4
- package/src/math/orders.ts +61 -0
- package/src/mockUSDCFaucet.js +171 -0
- package/src/orders.ts +56 -3
- package/src/types.js +60 -0
- package/src/types.ts +5 -1
|
@@ -211,6 +211,18 @@
|
|
|
211
211
|
{
|
|
212
212
|
"name": "ammPegMultiplier",
|
|
213
213
|
"type": "u128"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"name": "marginRatioInitial",
|
|
217
|
+
"type": "u32"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"name": "marginRatioPartial",
|
|
221
|
+
"type": "u32"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"name": "marginRatioMaintenance",
|
|
225
|
+
"type": "u32"
|
|
214
226
|
}
|
|
215
227
|
]
|
|
216
228
|
},
|
|
@@ -1526,22 +1538,31 @@
|
|
|
1526
1538
|
},
|
|
1527
1539
|
{
|
|
1528
1540
|
"name": "state",
|
|
1541
|
+
"isMut": false,
|
|
1542
|
+
"isSigner": false
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
"name": "markets",
|
|
1529
1546
|
"isMut": true,
|
|
1530
1547
|
"isSigner": false
|
|
1531
1548
|
}
|
|
1532
1549
|
],
|
|
1533
1550
|
"args": [
|
|
1551
|
+
{
|
|
1552
|
+
"name": "marketIndex",
|
|
1553
|
+
"type": "u64"
|
|
1554
|
+
},
|
|
1534
1555
|
{
|
|
1535
1556
|
"name": "marginRatioInitial",
|
|
1536
|
-
"type": "
|
|
1557
|
+
"type": "u32"
|
|
1537
1558
|
},
|
|
1538
1559
|
{
|
|
1539
1560
|
"name": "marginRatioPartial",
|
|
1540
|
-
"type": "
|
|
1561
|
+
"type": "u32"
|
|
1541
1562
|
},
|
|
1542
1563
|
{
|
|
1543
1564
|
"name": "marginRatioMaintenance",
|
|
1544
|
-
"type": "
|
|
1565
|
+
"type": "u32"
|
|
1545
1566
|
}
|
|
1546
1567
|
]
|
|
1547
1568
|
},
|
|
@@ -3028,9 +3049,21 @@
|
|
|
3028
3049
|
"defined": "AMM"
|
|
3029
3050
|
}
|
|
3030
3051
|
},
|
|
3052
|
+
{
|
|
3053
|
+
"name": "marginRatioInitial",
|
|
3054
|
+
"type": "u32"
|
|
3055
|
+
},
|
|
3056
|
+
{
|
|
3057
|
+
"name": "marginRatioPartial",
|
|
3058
|
+
"type": "u32"
|
|
3059
|
+
},
|
|
3060
|
+
{
|
|
3061
|
+
"name": "marginRatioMaintenance",
|
|
3062
|
+
"type": "u32"
|
|
3063
|
+
},
|
|
3031
3064
|
{
|
|
3032
3065
|
"name": "padding0",
|
|
3033
|
-
"type": "
|
|
3066
|
+
"type": "u32"
|
|
3034
3067
|
},
|
|
3035
3068
|
{
|
|
3036
3069
|
"name": "padding1",
|
|
@@ -4132,6 +4165,11 @@
|
|
|
4132
4165
|
"code": 6056,
|
|
4133
4166
|
"name": "NoPositionsLiquidatable",
|
|
4134
4167
|
"msg": "No positions liquidatable"
|
|
4168
|
+
},
|
|
4169
|
+
{
|
|
4170
|
+
"code": 6057,
|
|
4171
|
+
"name": "InvalidMarginRatio",
|
|
4172
|
+
"msg": "Invalid Margin Ratio"
|
|
4135
4173
|
}
|
|
4136
4174
|
]
|
|
4137
4175
|
}
|
package/src/math/orders.ts
CHANGED
|
@@ -42,3 +42,64 @@ export function isOrderRiskIncreasing(
|
|
|
42
42
|
|
|
43
43
|
return false;
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
export function isOrderRiskIncreasingInSameDirection(
|
|
47
|
+
user: ClearingHouseUser,
|
|
48
|
+
order: Order
|
|
49
|
+
): boolean {
|
|
50
|
+
if (isVariant(order.status, 'init')) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const position =
|
|
55
|
+
user.getUserPosition(order.marketIndex) ||
|
|
56
|
+
user.getEmptyPosition(order.marketIndex);
|
|
57
|
+
|
|
58
|
+
// if no position exists, it's risk increasing
|
|
59
|
+
if (position.baseAssetAmount.eq(ZERO)) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// if position is long and order is long
|
|
64
|
+
if (position.baseAssetAmount.gt(ZERO) && isVariant(order.direction, 'long')) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// if position is short and order is short
|
|
69
|
+
if (
|
|
70
|
+
position.baseAssetAmount.lt(ZERO) &&
|
|
71
|
+
isVariant(order.direction, 'short')
|
|
72
|
+
) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function isOrderReduceOnly(
|
|
80
|
+
user: ClearingHouseUser,
|
|
81
|
+
order: Order
|
|
82
|
+
): boolean {
|
|
83
|
+
if (isVariant(order.status, 'init')) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const position =
|
|
88
|
+
user.getUserPosition(order.marketIndex) ||
|
|
89
|
+
user.getEmptyPosition(order.marketIndex);
|
|
90
|
+
|
|
91
|
+
// if position is long and order is long
|
|
92
|
+
if (position.baseAssetAmount.gt(ZERO) && isVariant(order.direction, 'long')) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// if position is short and order is short
|
|
97
|
+
if (
|
|
98
|
+
position.baseAssetAmount.lt(ZERO) &&
|
|
99
|
+
isVariant(order.direction, 'short')
|
|
100
|
+
) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return order.baseAssetAmount.abs().lte(position.baseAssetAmount.abs());
|
|
105
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
22
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
23
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
24
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
25
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
26
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
27
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
31
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
32
|
+
};
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.MockUSDCFaucet = void 0;
|
|
35
|
+
const anchor = __importStar(require("@project-serum/anchor"));
|
|
36
|
+
const anchor_1 = require("@project-serum/anchor");
|
|
37
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
38
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
39
|
+
const mock_usdc_faucet_json_1 = __importDefault(require("./idl/mock_usdc_faucet.json"));
|
|
40
|
+
class MockUSDCFaucet {
|
|
41
|
+
constructor(connection, wallet, programId, opts) {
|
|
42
|
+
this.connection = connection;
|
|
43
|
+
this.wallet = wallet;
|
|
44
|
+
this.opts = opts || anchor_1.Provider.defaultOptions();
|
|
45
|
+
const provider = new anchor_1.Provider(connection, wallet, this.opts);
|
|
46
|
+
this.provider = provider;
|
|
47
|
+
this.program = new anchor_1.Program(mock_usdc_faucet_json_1.default, programId, provider);
|
|
48
|
+
}
|
|
49
|
+
getMockUSDCFaucetStatePublicKeyAndNonce() {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
return anchor.web3.PublicKey.findProgramAddress([Buffer.from(anchor.utils.bytes.utf8.encode('mock_usdc_faucet'))], this.program.programId);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
getMockUSDCFaucetStatePublicKey() {
|
|
55
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
if (this.mockUSDCFaucetStatePublicKey) {
|
|
57
|
+
return this.mockUSDCFaucetStatePublicKey;
|
|
58
|
+
}
|
|
59
|
+
this.mockUSDCFaucetStatePublicKey = (yield this.getMockUSDCFaucetStatePublicKeyAndNonce())[0];
|
|
60
|
+
return this.mockUSDCFaucetStatePublicKey;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
initialize() {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
const stateAccountRPCResponse = yield this.connection.getParsedAccountInfo(yield this.getMockUSDCFaucetStatePublicKey());
|
|
66
|
+
if (stateAccountRPCResponse.value !== null) {
|
|
67
|
+
throw new Error('Faucet already initialized');
|
|
68
|
+
}
|
|
69
|
+
const fakeUSDCMint = anchor.web3.Keypair.generate();
|
|
70
|
+
const createUSDCMintAccountIx = web3_js_1.SystemProgram.createAccount({
|
|
71
|
+
fromPubkey: this.wallet.publicKey,
|
|
72
|
+
newAccountPubkey: fakeUSDCMint.publicKey,
|
|
73
|
+
lamports: yield spl_token_1.Token.getMinBalanceRentForExemptMint(this.connection),
|
|
74
|
+
space: spl_token_1.MintLayout.span,
|
|
75
|
+
programId: spl_token_1.TOKEN_PROGRAM_ID,
|
|
76
|
+
});
|
|
77
|
+
const [mintAuthority, _mintAuthorityNonce] = yield web3_js_1.PublicKey.findProgramAddress([fakeUSDCMint.publicKey.toBuffer()], this.program.programId);
|
|
78
|
+
const initUSDCMintIx = spl_token_1.Token.createInitMintInstruction(spl_token_1.TOKEN_PROGRAM_ID, fakeUSDCMint.publicKey, 6, mintAuthority, null);
|
|
79
|
+
const [mockUSDCFaucetStatePublicKey, mockUSDCFaucetStateNonce] = yield this.getMockUSDCFaucetStatePublicKeyAndNonce();
|
|
80
|
+
return yield this.program.rpc.initialize(mockUSDCFaucetStateNonce, {
|
|
81
|
+
accounts: {
|
|
82
|
+
mockUsdcFaucetState: mockUSDCFaucetStatePublicKey,
|
|
83
|
+
admin: this.wallet.publicKey,
|
|
84
|
+
mintAccount: fakeUSDCMint.publicKey,
|
|
85
|
+
rent: web3_js_1.SYSVAR_RENT_PUBKEY,
|
|
86
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
87
|
+
},
|
|
88
|
+
instructions: [createUSDCMintAccountIx, initUSDCMintIx],
|
|
89
|
+
signers: [fakeUSDCMint],
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
fetchState() {
|
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
return yield this.program.account.mockUsdcFaucetState.fetch(yield this.getMockUSDCFaucetStatePublicKey());
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
mintToUser(userTokenAccount, amount) {
|
|
99
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
100
|
+
const state = yield this.fetchState();
|
|
101
|
+
return yield this.program.rpc.mintToUser(amount, {
|
|
102
|
+
accounts: {
|
|
103
|
+
mockUsdcFaucetState: yield this.getMockUSDCFaucetStatePublicKey(),
|
|
104
|
+
mintAccount: state.mint,
|
|
105
|
+
userTokenAccount,
|
|
106
|
+
mintAuthority: state.mintAuthority,
|
|
107
|
+
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
createAssociatedTokenAccountAndMintTo(userPublicKey, amount) {
|
|
113
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
114
|
+
const [associatedTokenPublicKey, createAssociatedAccountIx, mintToTx] = yield this.createAssociatedTokenAccountAndMintToInstructions(userPublicKey, amount);
|
|
115
|
+
const tx = new web3_js_1.Transaction().add(createAssociatedAccountIx).add(mintToTx);
|
|
116
|
+
const txSig = yield this.program.provider.send(tx, [], this.opts);
|
|
117
|
+
return [associatedTokenPublicKey, txSig];
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
createAssociatedTokenAccountAndMintToInstructions(userPublicKey, amount) {
|
|
121
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
122
|
+
const state = yield this.fetchState();
|
|
123
|
+
const associateTokenPublicKey = yield this.getAssosciatedMockUSDMintAddress({ userPubKey: userPublicKey });
|
|
124
|
+
const createAssociatedAccountIx = spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, state.mint, associateTokenPublicKey, userPublicKey, this.wallet.publicKey);
|
|
125
|
+
const mintToIx = yield this.program.instruction.mintToUser(amount, {
|
|
126
|
+
accounts: {
|
|
127
|
+
mockUsdcFaucetState: yield this.getMockUSDCFaucetStatePublicKey(),
|
|
128
|
+
mintAccount: state.mint,
|
|
129
|
+
userTokenAccount: associateTokenPublicKey,
|
|
130
|
+
mintAuthority: state.mintAuthority,
|
|
131
|
+
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
return [associateTokenPublicKey, createAssociatedAccountIx, mintToIx];
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
getAssosciatedMockUSDMintAddress(props) {
|
|
138
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
139
|
+
const state = yield this.fetchState();
|
|
140
|
+
return spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, state.mint, props.userPubKey);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
getTokenAccountInfo(props) {
|
|
144
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
145
|
+
const assosciatedKey = yield this.getAssosciatedMockUSDMintAddress(props);
|
|
146
|
+
const state = yield this.fetchState();
|
|
147
|
+
const token = new spl_token_1.Token(this.connection, state.mint, spl_token_1.TOKEN_PROGRAM_ID,
|
|
148
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
149
|
+
// @ts-ignore
|
|
150
|
+
this.provider.payer);
|
|
151
|
+
return yield token.getAccountInfo(assosciatedKey);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
subscribeToTokenAccount(props) {
|
|
155
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
156
|
+
try {
|
|
157
|
+
const tokenAccountKey = yield this.getAssosciatedMockUSDMintAddress(props);
|
|
158
|
+
props.callback(yield this.getTokenAccountInfo(props));
|
|
159
|
+
// Couldn't find a way to do it using anchor framework subscription, someone on serum discord recommended this way
|
|
160
|
+
this.connection.onAccountChange(tokenAccountKey, (_accountInfo /* accountInfo is a buffer which we don't know how to deserialize */) => __awaiter(this, void 0, void 0, function* () {
|
|
161
|
+
props.callback(yield this.getTokenAccountInfo(props));
|
|
162
|
+
}));
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.MockUSDCFaucet = MockUSDCFaucet;
|
package/src/orders.ts
CHANGED
|
@@ -3,16 +3,25 @@ import {
|
|
|
3
3
|
Market,
|
|
4
4
|
Order,
|
|
5
5
|
PositionDirection,
|
|
6
|
+
SwapDirection,
|
|
6
7
|
UserAccount,
|
|
7
8
|
UserPosition,
|
|
8
9
|
} from './types';
|
|
9
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
BN,
|
|
12
|
+
calculateAmmReservesAfterSwap,
|
|
13
|
+
calculateBaseAssetValue,
|
|
14
|
+
ClearingHouseUser,
|
|
15
|
+
isOrderRiskIncreasingInSameDirection,
|
|
16
|
+
TEN_THOUSAND,
|
|
17
|
+
} from '.';
|
|
10
18
|
import {
|
|
11
19
|
calculateMarkPrice,
|
|
12
20
|
calculateNewMarketAfterTrade,
|
|
13
21
|
} from './math/market';
|
|
14
22
|
import {
|
|
15
23
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
24
|
+
TWO,
|
|
16
25
|
PEG_PRECISION,
|
|
17
26
|
ZERO,
|
|
18
27
|
} from './constants/numericConstants';
|
|
@@ -32,7 +41,10 @@ export function calculateNewStateAfterOrder(
|
|
|
32
41
|
return null;
|
|
33
42
|
}
|
|
34
43
|
|
|
35
|
-
const baseAssetAmountToTrade =
|
|
44
|
+
const baseAssetAmountToTrade = calculateBaseAssetAmountMarketCanExecute(
|
|
45
|
+
market,
|
|
46
|
+
order
|
|
47
|
+
);
|
|
36
48
|
if (baseAssetAmountToTrade.lt(market.amm.minimumBaseAssetTradeSize)) {
|
|
37
49
|
return null;
|
|
38
50
|
}
|
|
@@ -157,7 +169,10 @@ function calculateAmountSwapped(
|
|
|
157
169
|
};
|
|
158
170
|
}
|
|
159
171
|
|
|
160
|
-
function
|
|
172
|
+
export function calculateBaseAssetAmountMarketCanExecute(
|
|
173
|
+
market: Market,
|
|
174
|
+
order: Order
|
|
175
|
+
): BN {
|
|
161
176
|
if (isVariant(order.orderType, 'limit')) {
|
|
162
177
|
return calculateAmountToTradeForLimit(market, order);
|
|
163
178
|
} else if (isVariant(order.orderType, 'triggerLimit')) {
|
|
@@ -234,3 +249,41 @@ function isTriggerConditionSatisfied(market: Market, order: Order): boolean {
|
|
|
234
249
|
return markPrice.lt(order.triggerPrice);
|
|
235
250
|
}
|
|
236
251
|
}
|
|
252
|
+
|
|
253
|
+
export function calculateBaseAssetAmountUserCanExecute(
|
|
254
|
+
market: Market,
|
|
255
|
+
order: Order,
|
|
256
|
+
user: ClearingHouseUser
|
|
257
|
+
): BN {
|
|
258
|
+
const maxLeverage = user.getMaxLeverage(order.marketIndex, 'Initial');
|
|
259
|
+
const freeCollateral = user.getFreeCollateral();
|
|
260
|
+
let quoteAssetAmount: BN;
|
|
261
|
+
if (isOrderRiskIncreasingInSameDirection(user, order)) {
|
|
262
|
+
quoteAssetAmount = freeCollateral.mul(maxLeverage).div(TEN_THOUSAND);
|
|
263
|
+
} else {
|
|
264
|
+
const position =
|
|
265
|
+
user.getUserPosition(order.marketIndex) ||
|
|
266
|
+
user.getEmptyPosition(order.marketIndex);
|
|
267
|
+
const positionValue = calculateBaseAssetValue(market, position);
|
|
268
|
+
quoteAssetAmount = freeCollateral
|
|
269
|
+
.mul(maxLeverage)
|
|
270
|
+
.div(TEN_THOUSAND)
|
|
271
|
+
.add(positionValue.mul(TWO));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (quoteAssetAmount.lte(ZERO)) {
|
|
275
|
+
return ZERO;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const baseAssetReservesBefore = market.amm.baseAssetReserve;
|
|
279
|
+
const [_, baseAssetReservesAfter] = calculateAmmReservesAfterSwap(
|
|
280
|
+
market.amm,
|
|
281
|
+
'quote',
|
|
282
|
+
quoteAssetAmount,
|
|
283
|
+
isVariant(order.direction, 'long')
|
|
284
|
+
? SwapDirection.ADD
|
|
285
|
+
: SwapDirection.REMOVE
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
return baseAssetReservesBefore.sub(baseAssetReservesAfter).abs();
|
|
289
|
+
}
|
package/src/types.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TradeSide = exports.isVariant = exports.OrderTriggerCondition = exports.OrderAction = exports.OrderDiscountTier = exports.OrderStatus = exports.OrderType = exports.OracleSource = exports.PositionDirection = exports.SwapDirection = void 0;
|
|
4
|
+
// # Utility Types / Enums / Constants
|
|
5
|
+
class SwapDirection {
|
|
6
|
+
}
|
|
7
|
+
exports.SwapDirection = SwapDirection;
|
|
8
|
+
SwapDirection.ADD = { add: {} };
|
|
9
|
+
SwapDirection.REMOVE = { remove: {} };
|
|
10
|
+
class PositionDirection {
|
|
11
|
+
}
|
|
12
|
+
exports.PositionDirection = PositionDirection;
|
|
13
|
+
PositionDirection.LONG = { long: {} };
|
|
14
|
+
PositionDirection.SHORT = { short: {} };
|
|
15
|
+
class OracleSource {
|
|
16
|
+
}
|
|
17
|
+
exports.OracleSource = OracleSource;
|
|
18
|
+
OracleSource.PYTH = { pyth: {} };
|
|
19
|
+
OracleSource.SWITCHBOARD = { switchboard: {} };
|
|
20
|
+
class OrderType {
|
|
21
|
+
}
|
|
22
|
+
exports.OrderType = OrderType;
|
|
23
|
+
OrderType.LIMIT = { limit: {} };
|
|
24
|
+
OrderType.TRIGGER_MARKET = { triggerMarket: {} };
|
|
25
|
+
OrderType.TRIGGER_LIMIT = { triggerLimit: {} };
|
|
26
|
+
OrderType.MARKET = { market: {} };
|
|
27
|
+
class OrderStatus {
|
|
28
|
+
}
|
|
29
|
+
exports.OrderStatus = OrderStatus;
|
|
30
|
+
OrderStatus.INIT = { init: {} };
|
|
31
|
+
OrderStatus.OPEN = { open: {} };
|
|
32
|
+
class OrderDiscountTier {
|
|
33
|
+
}
|
|
34
|
+
exports.OrderDiscountTier = OrderDiscountTier;
|
|
35
|
+
OrderDiscountTier.NONE = { none: {} };
|
|
36
|
+
OrderDiscountTier.FIRST = { first: {} };
|
|
37
|
+
OrderDiscountTier.SECOND = { second: {} };
|
|
38
|
+
OrderDiscountTier.THIRD = { third: {} };
|
|
39
|
+
OrderDiscountTier.FOURTH = { fourth: {} };
|
|
40
|
+
class OrderAction {
|
|
41
|
+
}
|
|
42
|
+
exports.OrderAction = OrderAction;
|
|
43
|
+
OrderAction.PLACE = { place: {} };
|
|
44
|
+
OrderAction.CANCEL = { cancel: {} };
|
|
45
|
+
OrderAction.FILL = { fill: {} };
|
|
46
|
+
class OrderTriggerCondition {
|
|
47
|
+
}
|
|
48
|
+
exports.OrderTriggerCondition = OrderTriggerCondition;
|
|
49
|
+
OrderTriggerCondition.ABOVE = { above: {} };
|
|
50
|
+
OrderTriggerCondition.BELOW = { below: {} };
|
|
51
|
+
function isVariant(object, type) {
|
|
52
|
+
return object.hasOwnProperty(type);
|
|
53
|
+
}
|
|
54
|
+
exports.isVariant = isVariant;
|
|
55
|
+
var TradeSide;
|
|
56
|
+
(function (TradeSide) {
|
|
57
|
+
TradeSide[TradeSide["None"] = 0] = "None";
|
|
58
|
+
TradeSide[TradeSide["Buy"] = 1] = "Buy";
|
|
59
|
+
TradeSide[TradeSide["Sell"] = 2] = "Sell";
|
|
60
|
+
})(TradeSide = exports.TradeSide || (exports.TradeSide = {}));
|
package/src/types.ts
CHANGED
|
@@ -267,7 +267,6 @@ export type OrderStateAccount = {
|
|
|
267
267
|
};
|
|
268
268
|
|
|
269
269
|
export type MarketsAccount = {
|
|
270
|
-
accountIndex: BN;
|
|
271
270
|
markets: Market[];
|
|
272
271
|
};
|
|
273
272
|
|
|
@@ -278,6 +277,9 @@ export type Market = {
|
|
|
278
277
|
baseAssetAmountShort: BN;
|
|
279
278
|
initialized: boolean;
|
|
280
279
|
openInterest: BN;
|
|
280
|
+
marginRatioInitial: number;
|
|
281
|
+
marginRatioMaintenance: number;
|
|
282
|
+
marginRatioPartial: number;
|
|
281
283
|
};
|
|
282
284
|
|
|
283
285
|
export type AMM = {
|
|
@@ -443,3 +445,5 @@ export type OrderFillerRewardStructure = {
|
|
|
443
445
|
rewardDenominator: BN;
|
|
444
446
|
timeBasedRewardLowerBound: BN;
|
|
445
447
|
};
|
|
448
|
+
|
|
449
|
+
export type MarginCategory = 'Initial' | 'Partial' | 'Maintenance';
|