@drift-labs/sdk 0.1.23-master.0 → 0.1.23-master.4
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.js +4 -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.js +7 -7
- package/lib/clearingHouse.js +21 -22
- package/lib/clearingHouseUser.js +21 -21
- package/lib/examples/makeTradeExample.js +6 -6
- package/lib/idl/clearing_house.json +68 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- 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 +1 -0
- package/lib/math/orders.js +26 -4
- package/lib/math/position.js +4 -3
- package/lib/math/trade.js +21 -17
- package/lib/orders.d.ts +3 -1
- package/lib/orders.js +47 -19
- package/lib/pythClient.js +1 -1
- package/lib/tx/retryTxSender.d.ts +19 -0
- package/lib/tx/retryTxSender.js +153 -0
- package/lib/tx/types.d.ts +2 -0
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.ts +5 -13
- package/src/clearingHouse.ts +3 -3
- package/src/idl/clearing_house.json +68 -0
- package/src/index.ts +2 -0
- package/src/math/orders.ts +33 -0
- package/src/math/position.ts +3 -2
- package/src/math/trade.ts +8 -3
- package/src/orders.ts +56 -3
- package/src/tx/retryTxSender.ts +196 -0
- package/src/tx/types.ts +3 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.RetryTxSender = void 0;
|
|
16
|
+
const assert_1 = __importDefault(require("assert"));
|
|
17
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
18
|
+
const DEFAULT_TIMEOUT = 35000;
|
|
19
|
+
const DEFAULT_RETRY = 8000;
|
|
20
|
+
class RetryTxSender {
|
|
21
|
+
constructor(provider, timeout, retrySleep) {
|
|
22
|
+
this.provider = provider;
|
|
23
|
+
this.timeout = timeout !== null && timeout !== void 0 ? timeout : DEFAULT_TIMEOUT;
|
|
24
|
+
this.retrySleep = retrySleep !== null && retrySleep !== void 0 ? retrySleep : DEFAULT_RETRY;
|
|
25
|
+
}
|
|
26
|
+
send(tx, additionalSigners, opts) {
|
|
27
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
if (additionalSigners === undefined) {
|
|
29
|
+
additionalSigners = [];
|
|
30
|
+
}
|
|
31
|
+
if (opts === undefined) {
|
|
32
|
+
opts = this.provider.opts;
|
|
33
|
+
}
|
|
34
|
+
yield this.prepareTx(tx, additionalSigners, opts);
|
|
35
|
+
const rawTransaction = tx.serialize();
|
|
36
|
+
const startTime = this.getTimestamp();
|
|
37
|
+
const txid = yield this.provider.connection.sendRawTransaction(rawTransaction, opts);
|
|
38
|
+
let done = false;
|
|
39
|
+
const resolveReference = {
|
|
40
|
+
resolve: undefined,
|
|
41
|
+
};
|
|
42
|
+
const stopWaiting = () => {
|
|
43
|
+
done = true;
|
|
44
|
+
if (resolveReference.resolve) {
|
|
45
|
+
resolveReference.resolve();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
(() => __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
while (!done && this.getTimestamp() - startTime < this.timeout) {
|
|
50
|
+
yield this.sleep(resolveReference);
|
|
51
|
+
if (!done) {
|
|
52
|
+
this.provider.connection
|
|
53
|
+
.sendRawTransaction(rawTransaction, opts)
|
|
54
|
+
.catch((e) => {
|
|
55
|
+
console.error(e);
|
|
56
|
+
stopWaiting();
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}))();
|
|
61
|
+
try {
|
|
62
|
+
yield this.confirmTransaction(txid, opts.commitment);
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
console.error(e);
|
|
66
|
+
throw e;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
stopWaiting();
|
|
70
|
+
}
|
|
71
|
+
return txid;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
prepareTx(tx, additionalSigners, opts) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
tx.feePayer = this.provider.wallet.publicKey;
|
|
77
|
+
tx.recentBlockhash = (yield this.provider.connection.getRecentBlockhash(opts.preflightCommitment)).blockhash;
|
|
78
|
+
yield this.provider.wallet.signTransaction(tx);
|
|
79
|
+
additionalSigners
|
|
80
|
+
.filter((s) => s !== undefined)
|
|
81
|
+
.forEach((kp) => {
|
|
82
|
+
tx.partialSign(kp);
|
|
83
|
+
});
|
|
84
|
+
return tx;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
confirmTransaction(signature, commitment) {
|
|
88
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
let decodedSignature;
|
|
90
|
+
try {
|
|
91
|
+
decodedSignature = bs58_1.default.decode(signature);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
throw new Error('signature must be base58 encoded: ' + signature);
|
|
95
|
+
}
|
|
96
|
+
(0, assert_1.default)(decodedSignature.length === 64, 'signature has invalid length');
|
|
97
|
+
const start = Date.now();
|
|
98
|
+
const subscriptionCommitment = commitment || this.provider.opts.commitment;
|
|
99
|
+
let subscriptionId;
|
|
100
|
+
let response = null;
|
|
101
|
+
const confirmPromise = new Promise((resolve, reject) => {
|
|
102
|
+
try {
|
|
103
|
+
subscriptionId = this.provider.connection.onSignature(signature, (result, context) => {
|
|
104
|
+
subscriptionId = undefined;
|
|
105
|
+
response = {
|
|
106
|
+
context,
|
|
107
|
+
value: result,
|
|
108
|
+
};
|
|
109
|
+
resolve(null);
|
|
110
|
+
}, subscriptionCommitment);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
reject(err);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
try {
|
|
117
|
+
yield this.promiseTimeout(confirmPromise, this.timeout);
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
if (subscriptionId) {
|
|
121
|
+
this.provider.connection.removeSignatureListener(subscriptionId);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (response === null) {
|
|
125
|
+
const duration = (Date.now() - start) / 1000;
|
|
126
|
+
throw new Error(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`);
|
|
127
|
+
}
|
|
128
|
+
return response;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
getTimestamp() {
|
|
132
|
+
return new Date().getTime();
|
|
133
|
+
}
|
|
134
|
+
sleep(reference) {
|
|
135
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
136
|
+
return new Promise((resolve) => {
|
|
137
|
+
reference.resolve = resolve;
|
|
138
|
+
setTimeout(resolve, this.retrySleep);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
promiseTimeout(promise, timeoutMs) {
|
|
143
|
+
let timeoutId;
|
|
144
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
145
|
+
timeoutId = setTimeout(() => resolve(null), timeoutMs);
|
|
146
|
+
});
|
|
147
|
+
return Promise.race([promise, timeoutPromise]).then((result) => {
|
|
148
|
+
clearTimeout(timeoutId);
|
|
149
|
+
return result;
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.RetryTxSender = RetryTxSender;
|
package/lib/tx/types.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { Provider } from '@project-serum/anchor';
|
|
1
2
|
import { ConfirmOptions, Signer, Transaction, TransactionSignature } from '@solana/web3.js';
|
|
2
3
|
export interface TxSender {
|
|
4
|
+
provider: Provider;
|
|
3
5
|
send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<TransactionSignature>;
|
|
4
6
|
}
|
package/package.json
CHANGED
|
@@ -135,19 +135,11 @@ export class BulkAccountLoader {
|
|
|
135
135
|
{ commitment: this.commitment },
|
|
136
136
|
];
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
args
|
|
144
|
-
);
|
|
145
|
-
} catch (e) {
|
|
146
|
-
for (const [_, callback] of this.errorCallbacks) {
|
|
147
|
-
callback(e);
|
|
148
|
-
}
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
138
|
+
// @ts-ignore
|
|
139
|
+
const rpcResponse = await this.connection._rpcRequest(
|
|
140
|
+
'getMultipleAccounts',
|
|
141
|
+
args
|
|
142
|
+
);
|
|
151
143
|
|
|
152
144
|
const newSlot = rpcResponse.result.context.slot;
|
|
153
145
|
|
package/src/clearingHouse.ts
CHANGED
|
@@ -52,7 +52,6 @@ import {
|
|
|
52
52
|
ClearingHouseAccountTypes,
|
|
53
53
|
} from './accounts/types';
|
|
54
54
|
import { TxSender } from './tx/types';
|
|
55
|
-
import { DefaultTxSender } from './tx/defaultTxSender';
|
|
56
55
|
import { wrapInTx } from './tx/utils';
|
|
57
56
|
import {
|
|
58
57
|
getClearingHouse,
|
|
@@ -250,12 +249,13 @@ export class ClearingHouse {
|
|
|
250
249
|
this.program.programId,
|
|
251
250
|
newProvider
|
|
252
251
|
);
|
|
253
|
-
|
|
252
|
+
|
|
253
|
+
// Update provider for txSender with new wallet details
|
|
254
|
+
this.txSender.provider = newProvider;
|
|
254
255
|
|
|
255
256
|
this.wallet = newWallet;
|
|
256
257
|
this.provider = newProvider;
|
|
257
258
|
this.program = newProgram;
|
|
258
|
-
this.txSender = newTxSender;
|
|
259
259
|
this.userAccountPublicKey = undefined;
|
|
260
260
|
this.userAccount = undefined;
|
|
261
261
|
}
|
|
@@ -1321,6 +1321,52 @@
|
|
|
1321
1321
|
}
|
|
1322
1322
|
]
|
|
1323
1323
|
},
|
|
1324
|
+
{
|
|
1325
|
+
"name": "initializeUserOrdersWithExplicitPayer",
|
|
1326
|
+
"accounts": [
|
|
1327
|
+
{
|
|
1328
|
+
"name": "user",
|
|
1329
|
+
"isMut": false,
|
|
1330
|
+
"isSigner": false
|
|
1331
|
+
},
|
|
1332
|
+
{
|
|
1333
|
+
"name": "userOrders",
|
|
1334
|
+
"isMut": true,
|
|
1335
|
+
"isSigner": false
|
|
1336
|
+
},
|
|
1337
|
+
{
|
|
1338
|
+
"name": "state",
|
|
1339
|
+
"isMut": false,
|
|
1340
|
+
"isSigner": false
|
|
1341
|
+
},
|
|
1342
|
+
{
|
|
1343
|
+
"name": "authority",
|
|
1344
|
+
"isMut": false,
|
|
1345
|
+
"isSigner": true
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
"name": "payer",
|
|
1349
|
+
"isMut": true,
|
|
1350
|
+
"isSigner": true
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
"name": "rent",
|
|
1354
|
+
"isMut": false,
|
|
1355
|
+
"isSigner": false
|
|
1356
|
+
},
|
|
1357
|
+
{
|
|
1358
|
+
"name": "systemProgram",
|
|
1359
|
+
"isMut": false,
|
|
1360
|
+
"isSigner": false
|
|
1361
|
+
}
|
|
1362
|
+
],
|
|
1363
|
+
"args": [
|
|
1364
|
+
{
|
|
1365
|
+
"name": "userOrdersNonce",
|
|
1366
|
+
"type": "u8"
|
|
1367
|
+
}
|
|
1368
|
+
]
|
|
1369
|
+
},
|
|
1324
1370
|
{
|
|
1325
1371
|
"name": "deleteUser",
|
|
1326
1372
|
"accounts": [
|
|
@@ -3667,6 +3713,23 @@
|
|
|
3667
3713
|
]
|
|
3668
3714
|
}
|
|
3669
3715
|
},
|
|
3716
|
+
{
|
|
3717
|
+
"name": "LiquidationType",
|
|
3718
|
+
"type": {
|
|
3719
|
+
"kind": "enum",
|
|
3720
|
+
"variants": [
|
|
3721
|
+
{
|
|
3722
|
+
"name": "NONE"
|
|
3723
|
+
},
|
|
3724
|
+
{
|
|
3725
|
+
"name": "PARTIAL"
|
|
3726
|
+
},
|
|
3727
|
+
{
|
|
3728
|
+
"name": "FULL"
|
|
3729
|
+
}
|
|
3730
|
+
]
|
|
3731
|
+
}
|
|
3732
|
+
},
|
|
3670
3733
|
{
|
|
3671
3734
|
"name": "OracleSource",
|
|
3672
3735
|
"type": {
|
|
@@ -4064,6 +4127,11 @@
|
|
|
4064
4127
|
"code": 6055,
|
|
4065
4128
|
"name": "UserOrderIdAlreadyInUse",
|
|
4066
4129
|
"msg": "User Order Id Already In Use"
|
|
4130
|
+
},
|
|
4131
|
+
{
|
|
4132
|
+
"code": 6056,
|
|
4133
|
+
"name": "NoPositionsLiquidatable",
|
|
4134
|
+
"msg": "No positions liquidatable"
|
|
4067
4135
|
}
|
|
4068
4136
|
]
|
|
4069
4137
|
}
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './types';
|
|
|
7
7
|
export * from './constants/markets';
|
|
8
8
|
export * from './accounts/webSocketClearingHouseAccountSubscriber';
|
|
9
9
|
export * from './accounts/bulkAccountLoader';
|
|
10
|
+
export * from './accounts/bulkUserSubscription';
|
|
10
11
|
export * from './accounts/pollingClearingHouseAccountSubscriber';
|
|
11
12
|
export * from './accounts/pollingTokenAccountSubscriber';
|
|
12
13
|
export * from './accounts/types';
|
|
@@ -31,6 +32,7 @@ export * from './types';
|
|
|
31
32
|
export * from './math/utils';
|
|
32
33
|
export * from './config';
|
|
33
34
|
export * from './constants/numericConstants';
|
|
35
|
+
export * from './tx/retryTxSender';
|
|
34
36
|
export * from './util/computeUnits';
|
|
35
37
|
export * from './util/tps';
|
|
36
38
|
|
package/src/math/orders.ts
CHANGED
|
@@ -42,3 +42,36 @@ 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
|
+
}
|
package/src/math/position.ts
CHANGED
|
@@ -47,7 +47,8 @@ export function calculateBaseAssetValue(
|
|
|
47
47
|
return newQuoteAssetReserve
|
|
48
48
|
.sub(market.amm.quoteAssetReserve)
|
|
49
49
|
.mul(market.amm.pegMultiplier)
|
|
50
|
-
.div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO)
|
|
50
|
+
.div(AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO)
|
|
51
|
+
.add(ONE);
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -74,7 +75,7 @@ export function calculatePositionPNL(
|
|
|
74
75
|
if (marketPosition.baseAssetAmount.gt(ZERO)) {
|
|
75
76
|
pnl = baseAssetValue.sub(marketPosition.quoteAssetAmount);
|
|
76
77
|
} else {
|
|
77
|
-
pnl = marketPosition.quoteAssetAmount.sub(baseAssetValue)
|
|
78
|
+
pnl = marketPosition.quoteAssetAmount.sub(baseAssetValue);
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
if (withFunding) {
|
package/src/math/trade.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Market, PositionDirection } from '../types';
|
|
1
|
+
import { isVariant, Market, PositionDirection } from '../types';
|
|
2
2
|
import { BN } from '@project-serum/anchor';
|
|
3
3
|
import { assert } from '../assert/assert';
|
|
4
4
|
import {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
PEG_PRECISION,
|
|
7
7
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
8
8
|
ZERO,
|
|
9
|
+
ONE,
|
|
9
10
|
} from '../constants/numericConstants';
|
|
10
11
|
import { calculateMarkPrice } from './market';
|
|
11
12
|
import {
|
|
@@ -114,16 +115,20 @@ export function calculateTradeAcquiredAmounts(
|
|
|
114
115
|
return [ZERO, ZERO];
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
const swapDirection = getSwapDirection(inputAssetType, direction);
|
|
117
119
|
const [newQuoteAssetReserve, newBaseAssetReserve] =
|
|
118
120
|
calculateAmmReservesAfterSwap(
|
|
119
121
|
market.amm,
|
|
120
122
|
inputAssetType,
|
|
121
123
|
amount,
|
|
122
|
-
|
|
124
|
+
swapDirection
|
|
123
125
|
);
|
|
124
126
|
|
|
125
127
|
const acquiredBase = market.amm.baseAssetReserve.sub(newBaseAssetReserve);
|
|
126
|
-
|
|
128
|
+
let acquiredQuote = market.amm.quoteAssetReserve.sub(newQuoteAssetReserve);
|
|
129
|
+
if (inputAssetType === 'base' && isVariant(swapDirection, 'remove')) {
|
|
130
|
+
acquiredQuote = acquiredQuote.sub(ONE);
|
|
131
|
+
}
|
|
127
132
|
|
|
128
133
|
return [acquiredBase, acquiredQuote];
|
|
129
134
|
}
|
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('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
|
+
}
|