@drift-labs/sdk 0.2.0-master.3 → 0.2.0-master.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -13
- package/lib/accounts/bulkUserStatsSubscription.d.ts +7 -0
- package/lib/accounts/bulkUserStatsSubscription.js +21 -0
- package/lib/accounts/bulkUserSubscription.js +0 -1
- package/lib/accounts/fetch.d.ts +2 -1
- package/lib/accounts/fetch.js +9 -1
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +16 -16
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +31 -28
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +22 -11
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +17 -17
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +37 -35
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/marketAddresses.d.ts +1 -3
- package/lib/addresses/pda.d.ts +10 -4
- package/lib/addresses/pda.js +51 -14
- package/lib/admin.d.ts +34 -22
- package/lib/admin.js +182 -73
- package/lib/clearingHouse.d.ts +120 -42
- package/lib/clearingHouse.js +1505 -254
- package/lib/clearingHouseConfig.d.ts +4 -4
- package/lib/clearingHouseUser.d.ts +50 -38
- package/lib/clearingHouseUser.js +410 -190
- package/lib/clearingHouseUserStats.d.ts +18 -0
- package/lib/clearingHouseUserStats.js +49 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/lib/clearingHouseUserStatsConfig.js +2 -0
- package/lib/config.d.ts +7 -9
- package/lib/config.js +21 -21
- package/lib/constants/numericConstants.d.ts +18 -12
- package/lib/constants/numericConstants.js +28 -21
- package/lib/constants/perpMarkets.d.ts +18 -0
- package/lib/constants/{markets.js → perpMarkets.js} +7 -7
- package/lib/constants/spotMarkets.d.ts +19 -0
- package/lib/constants/spotMarkets.js +53 -0
- package/lib/dlob/DLOB.d.ts +73 -0
- package/lib/dlob/DLOB.js +553 -0
- package/lib/dlob/DLOBNode.d.ts +52 -0
- package/lib/dlob/DLOBNode.js +82 -0
- package/lib/dlob/NodeList.d.ts +26 -0
- package/lib/dlob/NodeList.js +138 -0
- package/lib/events/eventList.js +3 -0
- package/lib/events/eventSubscriber.d.ts +4 -2
- package/lib/events/eventSubscriber.js +16 -9
- package/lib/events/fetchLogs.d.ts +10 -1
- package/lib/events/fetchLogs.js +27 -7
- package/lib/events/pollingLogProvider.d.ts +2 -1
- package/lib/events/pollingLogProvider.js +6 -2
- package/lib/events/sort.js +8 -11
- package/lib/events/types.d.ts +7 -2
- package/lib/events/types.js +5 -0
- package/lib/examples/makeTradeExample.js +20 -8
- package/lib/factory/bigNum.d.ts +1 -0
- package/lib/factory/bigNum.js +34 -10
- package/lib/idl/clearing_house.json +4313 -1433
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +21 -6
- package/lib/index.js +25 -6
- package/lib/math/amm.d.ts +8 -5
- package/lib/math/amm.js +68 -46
- package/lib/math/auction.js +4 -1
- package/lib/math/conversion.js +1 -1
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +11 -10
- package/lib/math/insurance.d.ts +4 -0
- package/lib/math/insurance.js +27 -0
- package/lib/math/margin.d.ts +11 -0
- package/lib/math/margin.js +77 -0
- package/lib/math/market.d.ts +14 -9
- package/lib/math/market.js +69 -7
- package/lib/math/oracles.d.ts +4 -0
- package/lib/math/oracles.js +36 -8
- package/lib/math/orders.d.ts +6 -2
- package/lib/math/orders.js +78 -3
- package/lib/math/position.d.ts +21 -13
- package/lib/math/position.js +76 -36
- package/lib/math/repeg.js +14 -5
- package/lib/math/spotBalance.d.ts +22 -0
- package/lib/math/spotBalance.js +193 -0
- package/lib/math/spotMarket.d.ts +4 -0
- package/lib/math/spotMarket.js +8 -0
- package/lib/math/spotPosition.d.ts +6 -0
- package/lib/math/spotPosition.js +23 -0
- package/lib/math/trade.d.ts +10 -10
- package/lib/math/trade.js +22 -29
- package/lib/oracles/pythClient.js +1 -1
- package/lib/oracles/quoteAssetOracleClient.js +1 -1
- package/lib/oracles/switchboardClient.js +1 -1
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +12 -92
- package/lib/serum/serumSubscriber.d.ts +23 -0
- package/lib/serum/serumSubscriber.js +41 -0
- package/lib/serum/types.d.ts +11 -0
- package/lib/serum/types.js +2 -0
- package/lib/slot/SlotSubscriber.d.ts +7 -0
- package/lib/slot/SlotSubscriber.js +3 -0
- package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +8 -5
- package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +63 -51
- package/lib/tx/retryTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.js +13 -4
- package/lib/tx/types.d.ts +1 -1
- package/lib/tx/utils.js +1 -1
- package/lib/types.d.ts +474 -123
- package/lib/types.js +99 -5
- package/lib/userMap/userMap.d.ts +25 -0
- package/lib/userMap/userMap.js +73 -0
- package/lib/userMap/userStatsMap.d.ts +19 -0
- package/lib/userMap/userStatsMap.js +68 -0
- package/lib/util/computeUnits.js +1 -1
- package/lib/util/getTokenAddress.d.ts +2 -0
- package/lib/util/getTokenAddress.js +9 -0
- package/package.json +9 -5
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +0 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +46 -42
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +31 -11
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +64 -59
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/marketAddresses.ts +1 -2
- package/src/addresses/pda.ts +88 -14
- package/src/admin.ts +333 -128
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +2464 -458
- package/src/clearingHouseConfig.ts +4 -3
- package/src/clearingHouseUser.ts +747 -291
- package/src/clearingHouseUserStats.ts +75 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +30 -31
- package/src/constants/numericConstants.ts +41 -25
- package/src/constants/{markets.ts → perpMarkets.ts} +10 -10
- package/src/constants/spotMarkets.ts +72 -0
- package/src/dlob/DLOB.ts +868 -0
- package/src/dlob/DLOBNode.ts +162 -0
- package/src/dlob/NodeList.ts +185 -0
- package/src/events/eventList.js +77 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/eventSubscriber.ts +20 -12
- package/src/events/fetchLogs.ts +35 -8
- package/src/events/pollingLogProvider.ts +10 -2
- package/src/events/sort.ts +11 -15
- package/src/events/types.ts +16 -1
- package/src/examples/makeTradeExample.js +157 -0
- package/src/examples/makeTradeExample.ts +32 -14
- package/src/factory/bigNum.ts +42 -13
- package/src/idl/clearing_house.json +4313 -1433
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.ts +21 -6
- package/src/math/amm.ts +136 -66
- package/src/math/auction.ts +5 -1
- package/src/math/conversion.ts +2 -2
- package/src/math/funding.ts +20 -18
- package/src/math/insurance.ts +35 -0
- package/src/math/margin.ts +127 -0
- package/src/math/market.ts +138 -12
- package/src/math/oracles.ts +63 -9
- package/src/math/orders.ts +138 -4
- package/src/math/position.ts +119 -58
- package/src/math/repeg.ts +16 -6
- package/src/math/spotBalance.ts +316 -0
- package/src/math/spotMarket.ts +9 -0
- package/src/math/spotPosition.ts +47 -0
- package/src/math/trade.ts +43 -49
- package/src/oracles/pythClient.ts +2 -2
- package/src/oracles/quoteAssetOracleClient.ts +2 -2
- package/src/oracles/switchboardClient.ts +2 -2
- package/src/orderParams.ts +24 -137
- package/src/serum/serumSubscriber.ts +80 -0
- package/src/serum/types.ts +13 -0
- package/src/slot/SlotSubscriber.ts +11 -1
- package/src/token/index.js +38 -0
- package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
- package/src/tx/retryTxSender.ts +16 -5
- package/src/tx/types.js +2 -0
- package/src/tx/types.ts +2 -1
- package/src/tx/utils.js +17 -0
- package/src/tx/utils.ts +1 -1
- package/src/types.ts +477 -125
- package/src/userMap/userMap.ts +100 -0
- package/src/userMap/userStatsMap.ts +110 -0
- package/src/util/computeUnits.js +21 -11
- package/src/util/computeUnits.ts +1 -1
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/getTokenAddress.ts +18 -0
- package/src/util/promiseTimeout.js +14 -0
- package/src/util/tps.js +27 -0
- package/tests/bn/test.ts +12 -3
- package/tests/dlob/helpers.ts +374 -0
- package/tests/dlob/test.ts +2865 -0
- package/lib/constants/banks.d.ts +0 -16
- package/lib/constants/banks.js +0 -34
- package/lib/constants/markets.d.ts +0 -19
- package/lib/math/bankBalance.d.ts +0 -9
- package/lib/math/bankBalance.js +0 -75
- package/lib/math/state.d.ts +0 -8
- package/lib/math/state.js +0 -15
- package/lib/orders.d.ts +0 -8
- package/lib/orders.js +0 -134
- package/src/constants/banks.ts +0 -43
- package/src/math/bankBalance.ts +0 -112
- package/src/math/state.ts +0 -14
- package/src/math/utils.js +0 -27
- package/src/math/utils.js.map +0 -1
- package/src/orders.ts +0 -244
- package/src/util/computeUnits.js.map +0 -1
package/src/clearingHouse.ts
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
import { AnchorProvider, BN, Idl, Program } from '@project-serum/anchor';
|
|
2
|
-
import
|
|
2
|
+
import bs58 from 'bs58';
|
|
3
|
+
import {
|
|
4
|
+
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
5
|
+
Token,
|
|
6
|
+
TOKEN_PROGRAM_ID,
|
|
7
|
+
} from '@solana/spl-token';
|
|
3
8
|
import {
|
|
4
9
|
StateAccount,
|
|
5
10
|
IWallet,
|
|
6
11
|
PositionDirection,
|
|
7
12
|
UserAccount,
|
|
8
|
-
|
|
13
|
+
PerpMarketAccount,
|
|
9
14
|
OrderParams,
|
|
10
15
|
Order,
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
SpotMarketAccount,
|
|
17
|
+
SpotPosition,
|
|
13
18
|
MakerInfo,
|
|
19
|
+
TakerInfo,
|
|
20
|
+
OptionalOrderParams,
|
|
21
|
+
DefaultOrderParams,
|
|
22
|
+
OrderType,
|
|
23
|
+
ReferrerInfo,
|
|
24
|
+
MarketType,
|
|
25
|
+
SerumV3FulfillmentConfigAccount,
|
|
14
26
|
} from './types';
|
|
15
27
|
import * as anchor from '@project-serum/anchor';
|
|
16
28
|
import clearingHouseIDL from './idl/clearing_house.json';
|
|
@@ -23,16 +35,26 @@ import {
|
|
|
23
35
|
Transaction,
|
|
24
36
|
TransactionInstruction,
|
|
25
37
|
AccountMeta,
|
|
38
|
+
Keypair,
|
|
39
|
+
LAMPORTS_PER_SOL,
|
|
40
|
+
Signer,
|
|
41
|
+
SystemProgram,
|
|
42
|
+
ComputeBudgetProgram,
|
|
26
43
|
} from '@solana/web3.js';
|
|
27
44
|
|
|
28
|
-
import {
|
|
45
|
+
import { TokenFaucet } from './tokenFaucet';
|
|
29
46
|
import { EventEmitter } from 'events';
|
|
30
47
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
31
48
|
import {
|
|
49
|
+
getClearingHouseSignerPublicKey,
|
|
32
50
|
getClearingHouseStateAccountPublicKey,
|
|
51
|
+
getInsuranceFundStakeAccountPublicKey,
|
|
33
52
|
getMarketPublicKey,
|
|
53
|
+
getSerumFulfillmentConfigPublicKey,
|
|
54
|
+
getSerumSignerPublicKey,
|
|
34
55
|
getUserAccountPublicKey,
|
|
35
56
|
getUserAccountPublicKeySync,
|
|
57
|
+
getUserStatsAccountPublicKey,
|
|
36
58
|
} from './addresses/pda';
|
|
37
59
|
import {
|
|
38
60
|
ClearingHouseAccountSubscriber,
|
|
@@ -41,9 +63,13 @@ import {
|
|
|
41
63
|
} from './accounts/types';
|
|
42
64
|
import { TxSender } from './tx/types';
|
|
43
65
|
import { wrapInTx } from './tx/utils';
|
|
44
|
-
import {
|
|
66
|
+
import {
|
|
67
|
+
ONE,
|
|
68
|
+
QUOTE_SPOT_MARKET_INDEX,
|
|
69
|
+
ZERO,
|
|
70
|
+
} from './constants/numericConstants';
|
|
45
71
|
import { findDirectionToClose, positionIsAvailable } from './math/position';
|
|
46
|
-
import { getTokenAmount } from './math/
|
|
72
|
+
import { getTokenAmount } from './math/spotBalance';
|
|
47
73
|
import { DEFAULT_USER_NAME, encodeName } from './userName';
|
|
48
74
|
import { OraclePriceData } from './oracles/types';
|
|
49
75
|
import { ClearingHouseConfig } from './clearingHouseConfig';
|
|
@@ -52,8 +78,10 @@ import { WebSocketClearingHouseAccountSubscriber } from './accounts/webSocketCle
|
|
|
52
78
|
import { RetryTxSender } from './tx/retryTxSender';
|
|
53
79
|
import { ClearingHouseUser } from './clearingHouseUser';
|
|
54
80
|
import { ClearingHouseUserAccountSubscriptionConfig } from './clearingHouseUserConfig';
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
81
|
+
import { getMarketsAndOraclesForSubscription } from './config';
|
|
82
|
+
import { WRAPPED_SOL_MINT } from './constants/spotMarkets';
|
|
83
|
+
import { ClearingHouseUserStats } from './clearingHouseUserStats';
|
|
84
|
+
import { isSpotPositionAvailable } from './math/spotPosition';
|
|
57
85
|
|
|
58
86
|
/**
|
|
59
87
|
* # ClearingHouse
|
|
@@ -66,6 +94,7 @@ export class ClearingHouse {
|
|
|
66
94
|
provider: AnchorProvider;
|
|
67
95
|
opts?: ConfirmOptions;
|
|
68
96
|
users = new Map<number, ClearingHouseUser>();
|
|
97
|
+
userStats?: ClearingHouseUserStats;
|
|
69
98
|
activeUserId: number;
|
|
70
99
|
userAccountSubscriptionConfig: ClearingHouseUserAccountSubscriptionConfig;
|
|
71
100
|
accountSubscriber: ClearingHouseAccountSubscriber;
|
|
@@ -73,6 +102,7 @@ export class ClearingHouse {
|
|
|
73
102
|
_isSubscribed = false;
|
|
74
103
|
txSender: TxSender;
|
|
75
104
|
marketLastSlotCache = new Map<number, number>();
|
|
105
|
+
authority: PublicKey;
|
|
76
106
|
|
|
77
107
|
public get isSubscribed() {
|
|
78
108
|
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
@@ -97,6 +127,7 @@ export class ClearingHouse {
|
|
|
97
127
|
this.provider
|
|
98
128
|
);
|
|
99
129
|
|
|
130
|
+
this.authority = config.authority ?? this.wallet.publicKey;
|
|
100
131
|
const userIds = config.userIds ?? [0];
|
|
101
132
|
this.activeUserId = config.activeUserId ?? userIds[0];
|
|
102
133
|
this.userAccountSubscriptionConfig =
|
|
@@ -109,18 +140,32 @@ export class ClearingHouse {
|
|
|
109
140
|
type: 'websocket',
|
|
110
141
|
};
|
|
111
142
|
this.createUsers(userIds, this.userAccountSubscriptionConfig);
|
|
143
|
+
if (config.userStats) {
|
|
144
|
+
this.userStats = new ClearingHouseUserStats({
|
|
145
|
+
clearingHouse: this,
|
|
146
|
+
userStatsAccountPublicKey: getUserStatsAccountPublicKey(
|
|
147
|
+
this.program.programId,
|
|
148
|
+
this.authority
|
|
149
|
+
),
|
|
150
|
+
accountSubscription: this.userAccountSubscriptionConfig,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
112
153
|
|
|
113
|
-
let
|
|
114
|
-
let
|
|
154
|
+
let perpMarketIndexes = config.perpMarketIndexes;
|
|
155
|
+
let spotMarketIndexes = config.spotMarketIndexes;
|
|
115
156
|
let oracleInfos = config.oracleInfos;
|
|
116
157
|
if (config.env) {
|
|
117
158
|
const {
|
|
118
|
-
|
|
119
|
-
|
|
159
|
+
perpMarketIndexes: envPerpMarketIndexes,
|
|
160
|
+
spotMarketIndexes: envSpotMarketIndexes,
|
|
120
161
|
oracleInfos: envOralceInfos,
|
|
121
|
-
} =
|
|
122
|
-
|
|
123
|
-
|
|
162
|
+
} = getMarketsAndOraclesForSubscription(config.env);
|
|
163
|
+
perpMarketIndexes = perpMarketIndexes
|
|
164
|
+
? perpMarketIndexes
|
|
165
|
+
: envPerpMarketIndexes;
|
|
166
|
+
spotMarketIndexes = spotMarketIndexes
|
|
167
|
+
? spotMarketIndexes
|
|
168
|
+
: envSpotMarketIndexes;
|
|
124
169
|
oracleInfos = oracleInfos ? oracleInfos : envOralceInfos;
|
|
125
170
|
}
|
|
126
171
|
|
|
@@ -128,15 +173,15 @@ export class ClearingHouse {
|
|
|
128
173
|
this.accountSubscriber = new PollingClearingHouseAccountSubscriber(
|
|
129
174
|
this.program,
|
|
130
175
|
config.accountSubscription.accountLoader,
|
|
131
|
-
|
|
132
|
-
|
|
176
|
+
perpMarketIndexes ?? [],
|
|
177
|
+
spotMarketIndexes ?? [],
|
|
133
178
|
oracleInfos ?? []
|
|
134
179
|
);
|
|
135
180
|
} else {
|
|
136
181
|
this.accountSubscriber = new WebSocketClearingHouseAccountSubscriber(
|
|
137
182
|
this.program,
|
|
138
|
-
config.
|
|
139
|
-
config.
|
|
183
|
+
config.perpMarketIndexes ?? [],
|
|
184
|
+
config.spotMarketIndexes ?? [],
|
|
140
185
|
config.oracleInfos ?? []
|
|
141
186
|
);
|
|
142
187
|
}
|
|
@@ -165,7 +210,7 @@ export class ClearingHouse {
|
|
|
165
210
|
): ClearingHouseUser {
|
|
166
211
|
const userAccountPublicKey = getUserAccountPublicKeySync(
|
|
167
212
|
this.program.programId,
|
|
168
|
-
this.
|
|
213
|
+
this.authority,
|
|
169
214
|
userId
|
|
170
215
|
);
|
|
171
216
|
|
|
@@ -180,6 +225,9 @@ export class ClearingHouse {
|
|
|
180
225
|
const subscribePromises = this.subscribeUsers().concat(
|
|
181
226
|
this.accountSubscriber.subscribe()
|
|
182
227
|
);
|
|
228
|
+
if (this.userStats !== undefined) {
|
|
229
|
+
subscribePromises.concat(this.userStats.subscribe());
|
|
230
|
+
}
|
|
183
231
|
this.isSubscribed = (await Promise.all(subscribePromises)).reduce(
|
|
184
232
|
(success, prevSuccess) => success && prevSuccess
|
|
185
233
|
);
|
|
@@ -194,17 +242,22 @@ export class ClearingHouse {
|
|
|
194
242
|
* Forces the accountSubscriber to fetch account updates from rpc
|
|
195
243
|
*/
|
|
196
244
|
public async fetchAccounts(): Promise<void> {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
245
|
+
const promises = [...this.users.values()]
|
|
246
|
+
.map((user) => user.fetchAccounts())
|
|
247
|
+
.concat(this.accountSubscriber.fetch());
|
|
248
|
+
if (this.userStats) {
|
|
249
|
+
promises.concat(this.userStats.fetchAccounts());
|
|
250
|
+
}
|
|
251
|
+
await Promise.all(promises);
|
|
202
252
|
}
|
|
203
253
|
|
|
204
254
|
public async unsubscribe(): Promise<void> {
|
|
205
255
|
const unsubscribePromises = this.unsubscribeUsers().concat(
|
|
206
256
|
this.accountSubscriber.unsubscribe()
|
|
207
257
|
);
|
|
258
|
+
if (this.userStats !== undefined) {
|
|
259
|
+
unsubscribePromises.concat(this.userStats.unsubscribe());
|
|
260
|
+
}
|
|
208
261
|
await Promise.all(unsubscribePromises);
|
|
209
262
|
this.isSubscribed = false;
|
|
210
263
|
}
|
|
@@ -224,29 +277,49 @@ export class ClearingHouse {
|
|
|
224
277
|
return this.statePublicKey;
|
|
225
278
|
}
|
|
226
279
|
|
|
280
|
+
signerPublicKey?: PublicKey;
|
|
281
|
+
public getSignerPublicKey(): PublicKey {
|
|
282
|
+
if (this.signerPublicKey) {
|
|
283
|
+
return this.signerPublicKey;
|
|
284
|
+
}
|
|
285
|
+
this.signerPublicKey = getClearingHouseSignerPublicKey(
|
|
286
|
+
this.program.programId
|
|
287
|
+
);
|
|
288
|
+
return this.signerPublicKey;
|
|
289
|
+
}
|
|
290
|
+
|
|
227
291
|
public getStateAccount(): StateAccount {
|
|
228
292
|
return this.accountSubscriber.getStateAccountAndSlot().data;
|
|
229
293
|
}
|
|
230
294
|
|
|
231
|
-
public
|
|
232
|
-
marketIndex
|
|
295
|
+
public getPerpMarketAccount(
|
|
296
|
+
marketIndex: number
|
|
297
|
+
): PerpMarketAccount | undefined {
|
|
233
298
|
return this.accountSubscriber.getMarketAccountAndSlot(marketIndex)?.data;
|
|
234
299
|
}
|
|
235
300
|
|
|
236
|
-
public
|
|
301
|
+
public getPerpMarketAccounts(): PerpMarketAccount[] {
|
|
237
302
|
return this.accountSubscriber
|
|
238
303
|
.getMarketAccountsAndSlots()
|
|
239
304
|
.map((value) => value.data);
|
|
240
305
|
}
|
|
241
306
|
|
|
242
|
-
public
|
|
243
|
-
|
|
244
|
-
|
|
307
|
+
public getSpotMarketAccount(
|
|
308
|
+
marketIndex: number
|
|
309
|
+
): SpotMarketAccount | undefined {
|
|
310
|
+
return this.accountSubscriber.getSpotMarketAccountAndSlot(marketIndex).data;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
public getSpotMarketAccounts(): SpotMarketAccount[] {
|
|
314
|
+
return this.accountSubscriber
|
|
315
|
+
.getSpotMarketAccountsAndSlots()
|
|
316
|
+
.map((value) => value.data);
|
|
245
317
|
}
|
|
246
318
|
|
|
247
|
-
public
|
|
248
|
-
return this.accountSubscriber.
|
|
249
|
-
|
|
319
|
+
public getQuoteSpotMarketAccount(): SpotMarketAccount {
|
|
320
|
+
return this.accountSubscriber.getSpotMarketAccountAndSlot(
|
|
321
|
+
QUOTE_SPOT_MARKET_INDEX
|
|
322
|
+
).data;
|
|
250
323
|
}
|
|
251
324
|
|
|
252
325
|
public getOraclePriceDataAndSlot(
|
|
@@ -255,6 +328,18 @@ export class ClearingHouse {
|
|
|
255
328
|
return this.accountSubscriber.getOraclePriceDataAndSlot(oraclePublicKey);
|
|
256
329
|
}
|
|
257
330
|
|
|
331
|
+
public async getSerumV3FulfillmentConfig(
|
|
332
|
+
serumMarket: PublicKey
|
|
333
|
+
): Promise<SerumV3FulfillmentConfigAccount> {
|
|
334
|
+
const address = await getSerumFulfillmentConfigPublicKey(
|
|
335
|
+
this.program.programId,
|
|
336
|
+
serumMarket
|
|
337
|
+
);
|
|
338
|
+
return (await this.program.account.serumV3FulfillmentConfig.fetch(
|
|
339
|
+
address
|
|
340
|
+
)) as SerumV3FulfillmentConfigAccount;
|
|
341
|
+
}
|
|
342
|
+
|
|
258
343
|
/**
|
|
259
344
|
* Update the wallet to use for clearing house transactions and linked user account
|
|
260
345
|
* @param newWallet
|
|
@@ -283,6 +368,7 @@ export class ClearingHouse {
|
|
|
283
368
|
this.wallet = newWallet;
|
|
284
369
|
this.provider = newProvider;
|
|
285
370
|
this.program = newProgram;
|
|
371
|
+
this.authority = newWallet.publicKey;
|
|
286
372
|
|
|
287
373
|
if (this.isSubscribed) {
|
|
288
374
|
await Promise.all(this.unsubscribeUsers());
|
|
@@ -294,6 +380,7 @@ export class ClearingHouse {
|
|
|
294
380
|
}
|
|
295
381
|
|
|
296
382
|
this.activeUserId = activeUserId;
|
|
383
|
+
this.userStatsAccountPublicKey = undefined;
|
|
297
384
|
}
|
|
298
385
|
|
|
299
386
|
public async switchActiveUser(userId: number): Promise<void> {
|
|
@@ -312,19 +399,26 @@ export class ClearingHouse {
|
|
|
312
399
|
|
|
313
400
|
public async initializeUserAccount(
|
|
314
401
|
userId = 0,
|
|
315
|
-
name = DEFAULT_USER_NAME
|
|
402
|
+
name = DEFAULT_USER_NAME,
|
|
403
|
+
referrerInfo?: ReferrerInfo
|
|
316
404
|
): Promise<[TransactionSignature, PublicKey]> {
|
|
317
405
|
const [userAccountPublicKey, initializeUserAccountIx] =
|
|
318
|
-
await this.getInitializeUserInstructions(userId, name);
|
|
406
|
+
await this.getInitializeUserInstructions(userId, name, referrerInfo);
|
|
319
407
|
|
|
320
|
-
const tx = new Transaction()
|
|
408
|
+
const tx = new Transaction();
|
|
409
|
+
if (userId === 0) {
|
|
410
|
+
// not the safest assumption, can explicitly check if user stats account exists if it causes problems
|
|
411
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
412
|
+
}
|
|
413
|
+
tx.add(initializeUserAccountIx);
|
|
321
414
|
const { txSig } = await this.txSender.send(tx, [], this.opts);
|
|
322
415
|
return [txSig, userAccountPublicKey];
|
|
323
416
|
}
|
|
324
417
|
|
|
325
418
|
async getInitializeUserInstructions(
|
|
326
419
|
userId = 0,
|
|
327
|
-
name = DEFAULT_USER_NAME
|
|
420
|
+
name = DEFAULT_USER_NAME,
|
|
421
|
+
referrerInfo?: ReferrerInfo
|
|
328
422
|
): Promise<[PublicKey, TransactionInstruction]> {
|
|
329
423
|
const userAccountPublicKey = await getUserAccountPublicKey(
|
|
330
424
|
this.program.programId,
|
|
@@ -332,22 +426,110 @@ export class ClearingHouse {
|
|
|
332
426
|
userId
|
|
333
427
|
);
|
|
334
428
|
|
|
429
|
+
const remainingAccounts = new Array<AccountMeta>();
|
|
430
|
+
if (referrerInfo !== undefined) {
|
|
431
|
+
remainingAccounts.push({
|
|
432
|
+
pubkey: referrerInfo.referrer,
|
|
433
|
+
isWritable: true,
|
|
434
|
+
isSigner: false,
|
|
435
|
+
});
|
|
436
|
+
remainingAccounts.push({
|
|
437
|
+
pubkey: referrerInfo.referrerStats,
|
|
438
|
+
isWritable: true,
|
|
439
|
+
isSigner: false,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
|
335
443
|
const nameBuffer = encodeName(name);
|
|
336
444
|
const initializeUserAccountIx =
|
|
337
445
|
await this.program.instruction.initializeUser(userId, nameBuffer, {
|
|
338
446
|
accounts: {
|
|
339
447
|
user: userAccountPublicKey,
|
|
448
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
340
449
|
authority: this.wallet.publicKey,
|
|
341
450
|
payer: this.wallet.publicKey,
|
|
342
451
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
343
452
|
systemProgram: anchor.web3.SystemProgram.programId,
|
|
344
453
|
state: await this.getStatePublicKey(),
|
|
345
454
|
},
|
|
455
|
+
remainingAccounts,
|
|
346
456
|
});
|
|
347
457
|
|
|
348
458
|
return [userAccountPublicKey, initializeUserAccountIx];
|
|
349
459
|
}
|
|
350
460
|
|
|
461
|
+
async getInitializeUserStatsIx(): Promise<TransactionInstruction> {
|
|
462
|
+
return await this.program.instruction.initializeUserStats({
|
|
463
|
+
accounts: {
|
|
464
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
465
|
+
authority: this.wallet.publicKey,
|
|
466
|
+
payer: this.wallet.publicKey,
|
|
467
|
+
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
468
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
469
|
+
state: await this.getStatePublicKey(),
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
public async updateUserName(
|
|
475
|
+
name: string,
|
|
476
|
+
userId = 0
|
|
477
|
+
): Promise<TransactionSignature> {
|
|
478
|
+
const nameBuffer = encodeName(name);
|
|
479
|
+
return await this.program.rpc.updateUserName(userId, nameBuffer, {
|
|
480
|
+
accounts: {
|
|
481
|
+
user: await this.getUserAccountPublicKey(),
|
|
482
|
+
authority: this.wallet.publicKey,
|
|
483
|
+
},
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
public async updateUserCustomMarginRatio(
|
|
488
|
+
marginRatio: number,
|
|
489
|
+
userId = 0
|
|
490
|
+
): Promise<TransactionSignature> {
|
|
491
|
+
return await this.program.rpc.updateUserCustomMarginRatio(
|
|
492
|
+
userId,
|
|
493
|
+
marginRatio,
|
|
494
|
+
{
|
|
495
|
+
accounts: {
|
|
496
|
+
user: await this.getUserAccountPublicKey(),
|
|
497
|
+
authority: this.wallet.publicKey,
|
|
498
|
+
},
|
|
499
|
+
}
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
public async updateUserDelegate(
|
|
504
|
+
delegate: PublicKey,
|
|
505
|
+
userId = 0
|
|
506
|
+
): Promise<TransactionSignature> {
|
|
507
|
+
return await this.program.rpc.updateUserDelegate(userId, delegate, {
|
|
508
|
+
accounts: {
|
|
509
|
+
user: await this.getUserAccountPublicKey(),
|
|
510
|
+
authority: this.wallet.publicKey,
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
public async getUserAccountsForDelegate(
|
|
516
|
+
delegate: PublicKey
|
|
517
|
+
): Promise<UserAccount[]> {
|
|
518
|
+
const programAccounts = await this.program.account.user.all([
|
|
519
|
+
{
|
|
520
|
+
memcmp: {
|
|
521
|
+
offset: 40,
|
|
522
|
+
/** data to match, as base-58 encoded string and limited to less than 129 bytes */
|
|
523
|
+
bytes: bs58.encode(delegate.toBuffer()),
|
|
524
|
+
},
|
|
525
|
+
},
|
|
526
|
+
]);
|
|
527
|
+
|
|
528
|
+
return programAccounts.map(
|
|
529
|
+
(programAccount) => programAccount.account as UserAccount
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
|
|
351
533
|
public getUser(userId?: number): ClearingHouseUser {
|
|
352
534
|
userId = userId ?? this.activeUserId;
|
|
353
535
|
if (!this.users.has(userId)) {
|
|
@@ -360,6 +542,23 @@ export class ClearingHouse {
|
|
|
360
542
|
return [...this.users.values()];
|
|
361
543
|
}
|
|
362
544
|
|
|
545
|
+
public getUserStats(): ClearingHouseUserStats {
|
|
546
|
+
return this.userStats;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
userStatsAccountPublicKey: PublicKey;
|
|
550
|
+
public getUserStatsAccountPublicKey(): PublicKey {
|
|
551
|
+
if (this.userStatsAccountPublicKey) {
|
|
552
|
+
return this.userStatsAccountPublicKey;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
this.userStatsAccountPublicKey = getUserStatsAccountPublicKey(
|
|
556
|
+
this.program.programId,
|
|
557
|
+
this.authority
|
|
558
|
+
);
|
|
559
|
+
return this.userStatsAccountPublicKey;
|
|
560
|
+
}
|
|
561
|
+
|
|
363
562
|
public async getUserAccountPublicKey(): Promise<PublicKey> {
|
|
364
563
|
return this.getUser().userAccountPublicKey;
|
|
365
564
|
}
|
|
@@ -374,28 +573,27 @@ export class ClearingHouse {
|
|
|
374
573
|
return this.getUser(userId).getUserAccountAndSlot();
|
|
375
574
|
}
|
|
376
575
|
|
|
377
|
-
public
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const bankIndexBN = bankIndex instanceof BN ? bankIndex : new BN(bankIndex);
|
|
381
|
-
return this.getUserAccount().bankBalances.find((bankBalance) =>
|
|
382
|
-
bankBalance.bankIndex.eq(bankIndexBN)
|
|
576
|
+
public getSpotPosition(marketIndex: number): SpotPosition | undefined {
|
|
577
|
+
return this.getUserAccount().spotPositions.find(
|
|
578
|
+
(spotPosition) => spotPosition.marketIndex === marketIndex
|
|
383
579
|
);
|
|
384
580
|
}
|
|
385
581
|
|
|
386
582
|
public getQuoteAssetTokenAmount(): BN {
|
|
387
|
-
const
|
|
388
|
-
const
|
|
583
|
+
const spotMarket = this.getSpotMarketAccount(QUOTE_SPOT_MARKET_INDEX);
|
|
584
|
+
const spotPosition = this.getSpotPosition(QUOTE_SPOT_MARKET_INDEX);
|
|
389
585
|
return getTokenAmount(
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
586
|
+
spotPosition.balance,
|
|
587
|
+
spotMarket,
|
|
588
|
+
spotPosition.balanceType
|
|
393
589
|
);
|
|
394
590
|
}
|
|
395
591
|
|
|
396
592
|
getRemainingAccounts(params: {
|
|
397
|
-
|
|
398
|
-
|
|
593
|
+
writablePerpMarketIndex?: number;
|
|
594
|
+
writableSpotMarketIndex?: number;
|
|
595
|
+
readablePerpMarketIndex?: number;
|
|
596
|
+
readableSpotMarketIndex?: number;
|
|
399
597
|
}): AccountMeta[] {
|
|
400
598
|
const userAccountAndSlot = this.getUserAccountAndSlot();
|
|
401
599
|
if (!userAccountAndSlot) {
|
|
@@ -407,14 +605,14 @@ export class ClearingHouse {
|
|
|
407
605
|
userAccountAndSlot;
|
|
408
606
|
|
|
409
607
|
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
410
|
-
const
|
|
411
|
-
const
|
|
608
|
+
const spotMarketAccountMap = new Map<number, AccountMeta>();
|
|
609
|
+
const perpMarketAccountMap = new Map<number, AccountMeta>();
|
|
412
610
|
for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
|
|
413
611
|
// if cache has more recent slot than user positions account slot, add market to remaining accounts
|
|
414
612
|
// otherwise remove from slot
|
|
415
613
|
if (slot > lastUserPositionsSlot) {
|
|
416
|
-
const marketAccount = this.
|
|
417
|
-
|
|
614
|
+
const marketAccount = this.getPerpMarketAccount(marketIndexNum);
|
|
615
|
+
perpMarketAccountMap.set(marketIndexNum, {
|
|
418
616
|
pubkey: marketAccount.pubkey,
|
|
419
617
|
isSigner: false,
|
|
420
618
|
isWritable: false,
|
|
@@ -429,15 +627,13 @@ export class ClearingHouse {
|
|
|
429
627
|
}
|
|
430
628
|
}
|
|
431
629
|
|
|
432
|
-
for (const position of userAccount.
|
|
630
|
+
for (const position of userAccount.perpPositions) {
|
|
433
631
|
if (!positionIsAvailable(position)) {
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
marketAccountMap.set(marketIndexNum, {
|
|
632
|
+
const marketAccount = this.getPerpMarketAccount(position.marketIndex);
|
|
633
|
+
perpMarketAccountMap.set(position.marketIndex, {
|
|
437
634
|
pubkey: marketAccount.pubkey,
|
|
438
635
|
isSigner: false,
|
|
439
|
-
|
|
440
|
-
isWritable: true,
|
|
636
|
+
isWritable: false,
|
|
441
637
|
});
|
|
442
638
|
oracleAccountMap.set(marketAccount.pubkey.toString(), {
|
|
443
639
|
pubkey: marketAccount.amm.oracle,
|
|
@@ -447,11 +643,27 @@ export class ClearingHouse {
|
|
|
447
643
|
}
|
|
448
644
|
}
|
|
449
645
|
|
|
450
|
-
if (params.
|
|
451
|
-
const marketAccount = this.
|
|
452
|
-
params.
|
|
646
|
+
if (params.readablePerpMarketIndex !== undefined) {
|
|
647
|
+
const marketAccount = this.getPerpMarketAccount(
|
|
648
|
+
params.readablePerpMarketIndex
|
|
649
|
+
);
|
|
650
|
+
perpMarketAccountMap.set(params.readablePerpMarketIndex, {
|
|
651
|
+
pubkey: marketAccount.pubkey,
|
|
652
|
+
isSigner: false,
|
|
653
|
+
isWritable: false,
|
|
654
|
+
});
|
|
655
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
656
|
+
pubkey: marketAccount.amm.oracle,
|
|
657
|
+
isSigner: false,
|
|
658
|
+
isWritable: false,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (params.writablePerpMarketIndex !== undefined) {
|
|
663
|
+
const marketAccount = this.getPerpMarketAccount(
|
|
664
|
+
params.writablePerpMarketIndex
|
|
453
665
|
);
|
|
454
|
-
|
|
666
|
+
perpMarketAccountMap.set(params.writablePerpMarketIndex, {
|
|
455
667
|
pubkey: marketAccount.pubkey,
|
|
456
668
|
isSigner: false,
|
|
457
669
|
isWritable: true,
|
|
@@ -463,17 +675,19 @@ export class ClearingHouse {
|
|
|
463
675
|
});
|
|
464
676
|
}
|
|
465
677
|
|
|
466
|
-
for (const
|
|
467
|
-
if (!
|
|
468
|
-
const
|
|
469
|
-
|
|
470
|
-
|
|
678
|
+
for (const spotPosition of userAccount.spotPositions) {
|
|
679
|
+
if (!isSpotPositionAvailable(spotPosition)) {
|
|
680
|
+
const spotMarketAccount = this.getSpotMarketAccount(
|
|
681
|
+
spotPosition.marketIndex
|
|
682
|
+
);
|
|
683
|
+
spotMarketAccountMap.set(spotPosition.marketIndex, {
|
|
684
|
+
pubkey: spotMarketAccount.pubkey,
|
|
471
685
|
isSigner: false,
|
|
472
686
|
isWritable: false,
|
|
473
687
|
});
|
|
474
|
-
if (
|
|
475
|
-
oracleAccountMap.set(
|
|
476
|
-
pubkey:
|
|
688
|
+
if (spotMarketAccount.marketIndex !== 0) {
|
|
689
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
690
|
+
pubkey: spotMarketAccount.oracle,
|
|
477
691
|
isSigner: false,
|
|
478
692
|
isWritable: false,
|
|
479
693
|
});
|
|
@@ -481,16 +695,36 @@ export class ClearingHouse {
|
|
|
481
695
|
}
|
|
482
696
|
}
|
|
483
697
|
|
|
484
|
-
if (params.
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
698
|
+
if (params.readableSpotMarketIndex !== undefined) {
|
|
699
|
+
const spotMarketAccount = this.getSpotMarketAccount(
|
|
700
|
+
params.readableSpotMarketIndex
|
|
701
|
+
);
|
|
702
|
+
spotMarketAccountMap.set(params.readableSpotMarketIndex, {
|
|
703
|
+
pubkey: spotMarketAccount.pubkey,
|
|
704
|
+
isSigner: false,
|
|
705
|
+
isWritable: false,
|
|
706
|
+
});
|
|
707
|
+
if (spotMarketAccount.marketIndex !== 0) {
|
|
708
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
709
|
+
pubkey: spotMarketAccount.oracle,
|
|
710
|
+
isSigner: false,
|
|
711
|
+
isWritable: false,
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if (params.writableSpotMarketIndex !== undefined) {
|
|
717
|
+
const spotMarketAccount = this.getSpotMarketAccount(
|
|
718
|
+
params.writableSpotMarketIndex
|
|
719
|
+
);
|
|
720
|
+
spotMarketAccountMap.set(params.writableSpotMarketIndex, {
|
|
721
|
+
pubkey: spotMarketAccount.pubkey,
|
|
488
722
|
isSigner: false,
|
|
489
723
|
isWritable: true,
|
|
490
724
|
});
|
|
491
|
-
if (
|
|
492
|
-
oracleAccountMap.set(
|
|
493
|
-
pubkey:
|
|
725
|
+
if (spotMarketAccount.marketIndex !== 0) {
|
|
726
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
727
|
+
pubkey: spotMarketAccount.oracle,
|
|
494
728
|
isSigner: false,
|
|
495
729
|
isWritable: false,
|
|
496
730
|
});
|
|
@@ -499,8 +733,8 @@ export class ClearingHouse {
|
|
|
499
733
|
|
|
500
734
|
return [
|
|
501
735
|
...oracleAccountMap.values(),
|
|
502
|
-
...
|
|
503
|
-
...
|
|
736
|
+
...spotMarketAccountMap.values(),
|
|
737
|
+
...perpMarketAccountMap.values(),
|
|
504
738
|
];
|
|
505
739
|
}
|
|
506
740
|
|
|
@@ -519,29 +753,71 @@ export class ClearingHouse {
|
|
|
519
753
|
|
|
520
754
|
public async deposit(
|
|
521
755
|
amount: BN,
|
|
522
|
-
|
|
756
|
+
marketIndex: number,
|
|
523
757
|
collateralAccountPublicKey: PublicKey,
|
|
524
758
|
userId?: number,
|
|
525
759
|
reduceOnly = false
|
|
526
760
|
): Promise<TransactionSignature> {
|
|
761
|
+
const tx = new Transaction();
|
|
762
|
+
const additionalSigners: Array<Signer> = [];
|
|
763
|
+
|
|
764
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
765
|
+
|
|
766
|
+
const isSolMarket = spotMarketAccount.mint.equals(WRAPPED_SOL_MINT);
|
|
767
|
+
|
|
768
|
+
const authority = this.authority;
|
|
769
|
+
|
|
770
|
+
const createWSOLTokenAccount =
|
|
771
|
+
isSolMarket && collateralAccountPublicKey.equals(authority);
|
|
772
|
+
|
|
773
|
+
if (createWSOLTokenAccount) {
|
|
774
|
+
const { ixs, signers, pubkey } =
|
|
775
|
+
await this.getWrappedSolAccountCreationIxs(amount, true);
|
|
776
|
+
|
|
777
|
+
collateralAccountPublicKey = pubkey;
|
|
778
|
+
|
|
779
|
+
ixs.forEach((ix) => {
|
|
780
|
+
tx.add(ix);
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
signers.forEach((signer) => additionalSigners.push(signer));
|
|
784
|
+
}
|
|
785
|
+
|
|
527
786
|
const depositCollateralIx = await this.getDepositInstruction(
|
|
528
787
|
amount,
|
|
529
|
-
|
|
788
|
+
marketIndex,
|
|
530
789
|
collateralAccountPublicKey,
|
|
531
790
|
userId,
|
|
532
791
|
reduceOnly,
|
|
533
792
|
true
|
|
534
793
|
);
|
|
535
794
|
|
|
536
|
-
|
|
795
|
+
tx.add(depositCollateralIx);
|
|
796
|
+
|
|
797
|
+
// Close the wrapped sol account at the end of the transaction
|
|
798
|
+
if (createWSOLTokenAccount) {
|
|
799
|
+
tx.add(
|
|
800
|
+
Token.createCloseAccountInstruction(
|
|
801
|
+
TOKEN_PROGRAM_ID,
|
|
802
|
+
collateralAccountPublicKey,
|
|
803
|
+
authority,
|
|
804
|
+
authority,
|
|
805
|
+
[]
|
|
806
|
+
)
|
|
807
|
+
);
|
|
808
|
+
}
|
|
537
809
|
|
|
538
|
-
const { txSig } = await this.txSender.send(
|
|
810
|
+
const { txSig } = await this.txSender.send(
|
|
811
|
+
tx,
|
|
812
|
+
additionalSigners,
|
|
813
|
+
this.opts
|
|
814
|
+
);
|
|
539
815
|
return txSig;
|
|
540
816
|
}
|
|
541
817
|
|
|
542
818
|
async getDepositInstruction(
|
|
543
819
|
amount: BN,
|
|
544
|
-
|
|
820
|
+
marketIndex: number,
|
|
545
821
|
userTokenAccount: PublicKey,
|
|
546
822
|
userId?: number,
|
|
547
823
|
reduceOnly = false,
|
|
@@ -550,7 +826,7 @@ export class ClearingHouse {
|
|
|
550
826
|
const userAccountPublicKey = userId
|
|
551
827
|
? await getUserAccountPublicKey(
|
|
552
828
|
this.program.programId,
|
|
553
|
-
this.
|
|
829
|
+
this.authority,
|
|
554
830
|
userId
|
|
555
831
|
)
|
|
556
832
|
: await this.getUserAccountPublicKey();
|
|
@@ -558,30 +834,37 @@ export class ClearingHouse {
|
|
|
558
834
|
let remainingAccounts = [];
|
|
559
835
|
if (userInitialized) {
|
|
560
836
|
remainingAccounts = this.getRemainingAccounts({
|
|
561
|
-
|
|
837
|
+
writableSpotMarketIndex: marketIndex,
|
|
562
838
|
});
|
|
563
839
|
} else {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
840
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
841
|
+
if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
|
|
842
|
+
remainingAccounts.push({
|
|
843
|
+
pubkey: spotMarketAccount.oracle,
|
|
567
844
|
isSigner: false,
|
|
568
|
-
isWritable:
|
|
569
|
-
}
|
|
570
|
-
|
|
845
|
+
isWritable: false,
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
remainingAccounts.push({
|
|
849
|
+
pubkey: spotMarketAccount.pubkey,
|
|
850
|
+
isSigner: false,
|
|
851
|
+
isWritable: true,
|
|
852
|
+
});
|
|
571
853
|
}
|
|
572
854
|
|
|
573
|
-
const
|
|
855
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
574
856
|
|
|
575
857
|
return await this.program.instruction.deposit(
|
|
576
|
-
|
|
858
|
+
marketIndex,
|
|
577
859
|
amount,
|
|
578
860
|
reduceOnly,
|
|
579
861
|
{
|
|
580
862
|
accounts: {
|
|
581
863
|
state: await this.getStatePublicKey(),
|
|
582
|
-
|
|
583
|
-
|
|
864
|
+
spotMarket: spotMarketAccount.pubkey,
|
|
865
|
+
spotMarketVault: spotMarketAccount.vault,
|
|
584
866
|
user: userAccountPublicKey,
|
|
867
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
585
868
|
userTokenAccount: userTokenAccount,
|
|
586
869
|
authority: this.wallet.publicKey,
|
|
587
870
|
tokenProgram: TOKEN_PROGRAM_ID,
|
|
@@ -591,43 +874,172 @@ export class ClearingHouse {
|
|
|
591
874
|
);
|
|
592
875
|
}
|
|
593
876
|
|
|
877
|
+
private async checkIfAccountExists(account: PublicKey): Promise<boolean> {
|
|
878
|
+
try {
|
|
879
|
+
const accountInfo = await this.connection.getAccountInfo(account);
|
|
880
|
+
return accountInfo != null;
|
|
881
|
+
} catch (e) {
|
|
882
|
+
// Doesn't already exist
|
|
883
|
+
return false;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
private async getWrappedSolAccountCreationIxs(
|
|
888
|
+
amount: BN,
|
|
889
|
+
isDeposit?: boolean
|
|
890
|
+
): Promise<{
|
|
891
|
+
ixs: anchor.web3.TransactionInstruction[];
|
|
892
|
+
signers: Signer[];
|
|
893
|
+
pubkey: PublicKey;
|
|
894
|
+
}> {
|
|
895
|
+
const wrappedSolAccount = new Keypair();
|
|
896
|
+
|
|
897
|
+
const result = {
|
|
898
|
+
ixs: [],
|
|
899
|
+
signers: [],
|
|
900
|
+
pubkey: wrappedSolAccount.publicKey,
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
const rentSpaceLamports = new BN(LAMPORTS_PER_SOL / 100);
|
|
904
|
+
|
|
905
|
+
const lamports = isDeposit
|
|
906
|
+
? amount.add(rentSpaceLamports)
|
|
907
|
+
: rentSpaceLamports;
|
|
908
|
+
|
|
909
|
+
const authority = this.wallet.publicKey;
|
|
910
|
+
|
|
911
|
+
result.ixs.push(
|
|
912
|
+
SystemProgram.createAccount({
|
|
913
|
+
fromPubkey: authority,
|
|
914
|
+
newAccountPubkey: wrappedSolAccount.publicKey,
|
|
915
|
+
lamports: lamports.toNumber(),
|
|
916
|
+
space: 165,
|
|
917
|
+
programId: TOKEN_PROGRAM_ID,
|
|
918
|
+
})
|
|
919
|
+
);
|
|
920
|
+
|
|
921
|
+
result.ixs.push(
|
|
922
|
+
Token.createInitAccountInstruction(
|
|
923
|
+
TOKEN_PROGRAM_ID,
|
|
924
|
+
WRAPPED_SOL_MINT,
|
|
925
|
+
wrappedSolAccount.publicKey,
|
|
926
|
+
authority
|
|
927
|
+
)
|
|
928
|
+
);
|
|
929
|
+
|
|
930
|
+
result.signers.push(wrappedSolAccount);
|
|
931
|
+
|
|
932
|
+
return result;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
public getAssociatedTokenAccountCreationIx(
|
|
936
|
+
tokenMintAddress: PublicKey,
|
|
937
|
+
associatedTokenAddress: PublicKey
|
|
938
|
+
): anchor.web3.TransactionInstruction {
|
|
939
|
+
const createAssociatedAccountIx =
|
|
940
|
+
Token.createAssociatedTokenAccountInstruction(
|
|
941
|
+
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
942
|
+
TOKEN_PROGRAM_ID,
|
|
943
|
+
tokenMintAddress,
|
|
944
|
+
associatedTokenAddress,
|
|
945
|
+
this.wallet.publicKey,
|
|
946
|
+
this.wallet.publicKey
|
|
947
|
+
);
|
|
948
|
+
|
|
949
|
+
return createAssociatedAccountIx;
|
|
950
|
+
}
|
|
951
|
+
|
|
594
952
|
/**
|
|
595
953
|
* Creates the Clearing House User account for a user, and deposits some initial collateral
|
|
596
|
-
* @param userId
|
|
597
|
-
* @param name
|
|
598
954
|
* @param amount
|
|
599
955
|
* @param userTokenAccount
|
|
956
|
+
* @param marketIndex
|
|
957
|
+
* @param userId
|
|
958
|
+
* @param name
|
|
600
959
|
* @param fromUserId
|
|
601
960
|
* @returns
|
|
602
961
|
*/
|
|
603
962
|
public async initializeUserAccountAndDepositCollateral(
|
|
604
963
|
amount: BN,
|
|
605
964
|
userTokenAccount: PublicKey,
|
|
606
|
-
|
|
965
|
+
marketIndex = 0,
|
|
607
966
|
userId = 0,
|
|
608
967
|
name = DEFAULT_USER_NAME,
|
|
609
|
-
fromUserId?: number
|
|
968
|
+
fromUserId?: number,
|
|
969
|
+
referrerInfo?: ReferrerInfo
|
|
610
970
|
): Promise<[TransactionSignature, PublicKey]> {
|
|
611
971
|
const [userAccountPublicKey, initializeUserAccountIx] =
|
|
612
|
-
await this.getInitializeUserInstructions(userId, name);
|
|
972
|
+
await this.getInitializeUserInstructions(userId, name, referrerInfo);
|
|
973
|
+
|
|
974
|
+
const additionalSigners: Array<Signer> = [];
|
|
975
|
+
|
|
976
|
+
const spotMarket = this.getSpotMarketAccount(marketIndex);
|
|
977
|
+
|
|
978
|
+
const isSolMarket = spotMarket.mint.equals(WRAPPED_SOL_MINT);
|
|
979
|
+
|
|
980
|
+
const tx = new Transaction();
|
|
981
|
+
|
|
982
|
+
const authority = this.wallet.publicKey;
|
|
983
|
+
|
|
984
|
+
const createWSOLTokenAccount =
|
|
985
|
+
isSolMarket && userTokenAccount.equals(authority);
|
|
986
|
+
|
|
987
|
+
if (createWSOLTokenAccount) {
|
|
988
|
+
const {
|
|
989
|
+
ixs: startIxs,
|
|
990
|
+
signers,
|
|
991
|
+
pubkey,
|
|
992
|
+
} = await this.getWrappedSolAccountCreationIxs(amount, true);
|
|
993
|
+
|
|
994
|
+
userTokenAccount = pubkey;
|
|
995
|
+
|
|
996
|
+
startIxs.forEach((ix) => {
|
|
997
|
+
tx.add(ix);
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
signers.forEach((signer) => additionalSigners.push(signer));
|
|
1001
|
+
}
|
|
613
1002
|
|
|
614
1003
|
const depositCollateralIx =
|
|
615
1004
|
fromUserId != null
|
|
616
|
-
? await this.getTransferDepositIx(
|
|
1005
|
+
? await this.getTransferDepositIx(
|
|
1006
|
+
amount,
|
|
1007
|
+
marketIndex,
|
|
1008
|
+
fromUserId,
|
|
1009
|
+
userId
|
|
1010
|
+
)
|
|
617
1011
|
: await this.getDepositInstruction(
|
|
618
1012
|
amount,
|
|
619
|
-
|
|
1013
|
+
marketIndex,
|
|
620
1014
|
userTokenAccount,
|
|
621
1015
|
userId,
|
|
622
1016
|
false,
|
|
623
1017
|
false
|
|
624
1018
|
);
|
|
625
1019
|
|
|
626
|
-
|
|
627
|
-
.add(
|
|
628
|
-
|
|
1020
|
+
if (userId === 0) {
|
|
1021
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
1022
|
+
}
|
|
1023
|
+
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
1024
|
+
|
|
1025
|
+
// Close the wrapped sol account at the end of the transaction
|
|
1026
|
+
if (createWSOLTokenAccount) {
|
|
1027
|
+
tx.add(
|
|
1028
|
+
Token.createCloseAccountInstruction(
|
|
1029
|
+
TOKEN_PROGRAM_ID,
|
|
1030
|
+
userTokenAccount,
|
|
1031
|
+
authority,
|
|
1032
|
+
authority,
|
|
1033
|
+
[]
|
|
1034
|
+
)
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
629
1037
|
|
|
630
|
-
const { txSig } = await this.txSender.send(
|
|
1038
|
+
const { txSig } = await this.txSender.send(
|
|
1039
|
+
tx,
|
|
1040
|
+
additionalSigners,
|
|
1041
|
+
this.opts
|
|
1042
|
+
);
|
|
631
1043
|
|
|
632
1044
|
return [txSig, userAccountPublicKey];
|
|
633
1045
|
}
|
|
@@ -635,32 +1047,35 @@ export class ClearingHouse {
|
|
|
635
1047
|
public async initializeUserAccountForDevnet(
|
|
636
1048
|
userId = 0,
|
|
637
1049
|
name = DEFAULT_USER_NAME,
|
|
638
|
-
|
|
639
|
-
|
|
1050
|
+
marketIndex: number,
|
|
1051
|
+
tokenFaucet: TokenFaucet,
|
|
1052
|
+
amount: BN,
|
|
1053
|
+
referrerInfo?: ReferrerInfo
|
|
640
1054
|
): Promise<[TransactionSignature, PublicKey]> {
|
|
641
1055
|
const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] =
|
|
642
|
-
await
|
|
1056
|
+
await tokenFaucet.createAssociatedTokenAccountAndMintToInstructions(
|
|
643
1057
|
this.wallet.publicKey,
|
|
644
1058
|
amount
|
|
645
1059
|
);
|
|
646
1060
|
|
|
647
1061
|
const [userAccountPublicKey, initializeUserAccountIx] =
|
|
648
|
-
await this.getInitializeUserInstructions(userId, name);
|
|
1062
|
+
await this.getInitializeUserInstructions(userId, name, referrerInfo);
|
|
649
1063
|
|
|
650
1064
|
const depositCollateralIx = await this.getDepositInstruction(
|
|
651
1065
|
amount,
|
|
652
|
-
|
|
1066
|
+
marketIndex,
|
|
653
1067
|
associateTokenPublicKey,
|
|
654
1068
|
userId,
|
|
655
1069
|
false,
|
|
656
1070
|
false
|
|
657
1071
|
);
|
|
658
1072
|
|
|
659
|
-
const tx = new Transaction()
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
.add(
|
|
663
|
-
|
|
1073
|
+
const tx = new Transaction().add(createAssociatedAccountIx).add(mintToIx);
|
|
1074
|
+
|
|
1075
|
+
if (userId === 0) {
|
|
1076
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
1077
|
+
}
|
|
1078
|
+
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
664
1079
|
|
|
665
1080
|
const txSig = await this.program.provider.sendAndConfirm(tx, []);
|
|
666
1081
|
|
|
@@ -669,20 +1084,72 @@ export class ClearingHouse {
|
|
|
669
1084
|
|
|
670
1085
|
public async withdraw(
|
|
671
1086
|
amount: BN,
|
|
672
|
-
|
|
1087
|
+
marketIndex: number,
|
|
673
1088
|
userTokenAccount: PublicKey,
|
|
674
1089
|
reduceOnly = false
|
|
675
1090
|
): Promise<TransactionSignature> {
|
|
676
|
-
const
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
1091
|
+
const tx = new Transaction();
|
|
1092
|
+
const additionalSigners: Array<Signer> = [];
|
|
1093
|
+
|
|
1094
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
1095
|
+
|
|
1096
|
+
const isSolMarket = spotMarketAccount.mint.equals(WRAPPED_SOL_MINT);
|
|
1097
|
+
|
|
1098
|
+
const authority = this.wallet.publicKey;
|
|
1099
|
+
|
|
1100
|
+
const createWSOLTokenAccount =
|
|
1101
|
+
isSolMarket && userTokenAccount.equals(authority);
|
|
1102
|
+
|
|
1103
|
+
if (createWSOLTokenAccount) {
|
|
1104
|
+
const { ixs, signers, pubkey } =
|
|
1105
|
+
await this.getWrappedSolAccountCreationIxs(amount, false);
|
|
1106
|
+
|
|
1107
|
+
userTokenAccount = pubkey;
|
|
1108
|
+
|
|
1109
|
+
ixs.forEach((ix) => {
|
|
1110
|
+
tx.add(ix);
|
|
1111
|
+
});
|
|
1112
|
+
|
|
1113
|
+
signers.forEach((signer) => additionalSigners.push(signer));
|
|
1114
|
+
} else {
|
|
1115
|
+
const accountExists = await this.checkIfAccountExists(userTokenAccount);
|
|
1116
|
+
|
|
1117
|
+
if (!accountExists) {
|
|
1118
|
+
const createAssociatedTokenAccountIx =
|
|
1119
|
+
this.getAssociatedTokenAccountCreationIx(
|
|
1120
|
+
spotMarketAccount.mint,
|
|
1121
|
+
userTokenAccount
|
|
1122
|
+
);
|
|
1123
|
+
|
|
1124
|
+
tx.add(createAssociatedTokenAccountIx);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
const withdrawCollateral = await this.getWithdrawIx(
|
|
1129
|
+
amount,
|
|
1130
|
+
spotMarketAccount.marketIndex,
|
|
1131
|
+
userTokenAccount,
|
|
1132
|
+
reduceOnly
|
|
1133
|
+
);
|
|
1134
|
+
|
|
1135
|
+
tx.add(withdrawCollateral);
|
|
1136
|
+
|
|
1137
|
+
// Close the wrapped sol account at the end of the transaction
|
|
1138
|
+
if (createWSOLTokenAccount) {
|
|
1139
|
+
tx.add(
|
|
1140
|
+
Token.createCloseAccountInstruction(
|
|
1141
|
+
TOKEN_PROGRAM_ID,
|
|
681
1142
|
userTokenAccount,
|
|
682
|
-
|
|
1143
|
+
authority,
|
|
1144
|
+
authority,
|
|
1145
|
+
[]
|
|
683
1146
|
)
|
|
684
|
-
)
|
|
685
|
-
|
|
1147
|
+
);
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
const { txSig } = await this.txSender.send(
|
|
1151
|
+
tx,
|
|
1152
|
+
additionalSigners,
|
|
686
1153
|
this.opts
|
|
687
1154
|
);
|
|
688
1155
|
return txSig;
|
|
@@ -690,29 +1157,30 @@ export class ClearingHouse {
|
|
|
690
1157
|
|
|
691
1158
|
public async getWithdrawIx(
|
|
692
1159
|
amount: BN,
|
|
693
|
-
|
|
1160
|
+
marketIndex: number,
|
|
694
1161
|
userTokenAccount: PublicKey,
|
|
695
1162
|
reduceOnly = false
|
|
696
1163
|
): Promise<TransactionInstruction> {
|
|
697
1164
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
698
1165
|
|
|
699
1166
|
const remainingAccounts = this.getRemainingAccounts({
|
|
700
|
-
|
|
1167
|
+
writableSpotMarketIndex: marketIndex,
|
|
701
1168
|
});
|
|
702
1169
|
|
|
703
|
-
const
|
|
1170
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
704
1171
|
|
|
705
1172
|
return await this.program.instruction.withdraw(
|
|
706
|
-
|
|
1173
|
+
marketIndex,
|
|
707
1174
|
amount,
|
|
708
1175
|
reduceOnly,
|
|
709
1176
|
{
|
|
710
1177
|
accounts: {
|
|
711
1178
|
state: await this.getStatePublicKey(),
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
1179
|
+
spotMarket: spotMarketAccount.pubkey,
|
|
1180
|
+
spotMarketVault: spotMarketAccount.vault,
|
|
1181
|
+
clearingHouseSigner: this.getSignerPublicKey(),
|
|
715
1182
|
user: userAccountPublicKey,
|
|
1183
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
716
1184
|
userTokenAccount: userTokenAccount,
|
|
717
1185
|
authority: this.wallet.publicKey,
|
|
718
1186
|
tokenProgram: TOKEN_PROGRAM_ID,
|
|
@@ -724,13 +1192,18 @@ export class ClearingHouse {
|
|
|
724
1192
|
|
|
725
1193
|
public async transferDeposit(
|
|
726
1194
|
amount: BN,
|
|
727
|
-
|
|
1195
|
+
marketIndex: number,
|
|
728
1196
|
fromUserId: number,
|
|
729
1197
|
toUserId: number
|
|
730
1198
|
): Promise<TransactionSignature> {
|
|
731
1199
|
const { txSig } = await this.txSender.send(
|
|
732
1200
|
wrapInTx(
|
|
733
|
-
await this.getTransferDepositIx(
|
|
1201
|
+
await this.getTransferDepositIx(
|
|
1202
|
+
amount,
|
|
1203
|
+
marketIndex,
|
|
1204
|
+
fromUserId,
|
|
1205
|
+
toUserId
|
|
1206
|
+
)
|
|
734
1207
|
),
|
|
735
1208
|
[],
|
|
736
1209
|
this.opts
|
|
@@ -740,7 +1213,7 @@ export class ClearingHouse {
|
|
|
740
1213
|
|
|
741
1214
|
public async getTransferDepositIx(
|
|
742
1215
|
amount: BN,
|
|
743
|
-
|
|
1216
|
+
marketIndex: number,
|
|
744
1217
|
fromUserId: number,
|
|
745
1218
|
toUserId: number
|
|
746
1219
|
): Promise<TransactionInstruction> {
|
|
@@ -756,92 +1229,286 @@ export class ClearingHouse {
|
|
|
756
1229
|
);
|
|
757
1230
|
|
|
758
1231
|
const remainingAccounts = this.getRemainingAccounts({
|
|
759
|
-
|
|
1232
|
+
writableSpotMarketIndex: marketIndex,
|
|
760
1233
|
});
|
|
761
1234
|
|
|
762
|
-
return await this.program.instruction.transferDeposit(
|
|
1235
|
+
return await this.program.instruction.transferDeposit(marketIndex, amount, {
|
|
763
1236
|
accounts: {
|
|
764
1237
|
authority: this.wallet.publicKey,
|
|
765
1238
|
fromUser,
|
|
766
1239
|
toUser,
|
|
1240
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
767
1241
|
state: await this.getStatePublicKey(),
|
|
768
1242
|
},
|
|
769
1243
|
remainingAccounts,
|
|
770
1244
|
});
|
|
771
1245
|
}
|
|
772
1246
|
|
|
773
|
-
public async
|
|
774
|
-
|
|
1247
|
+
public async updateSpotMarketCumulativeInterest(
|
|
1248
|
+
marketIndex: number
|
|
775
1249
|
): Promise<TransactionSignature> {
|
|
776
1250
|
const { txSig } = await this.txSender.send(
|
|
777
|
-
wrapInTx(await this.
|
|
1251
|
+
wrapInTx(await this.updateSpotMarketCumulativeInterestIx(marketIndex)),
|
|
778
1252
|
[],
|
|
779
1253
|
this.opts
|
|
780
1254
|
);
|
|
781
1255
|
return txSig;
|
|
782
1256
|
}
|
|
783
1257
|
|
|
784
|
-
public async
|
|
785
|
-
|
|
1258
|
+
public async updateSpotMarketCumulativeInterestIx(
|
|
1259
|
+
marketIndex: number
|
|
786
1260
|
): Promise<TransactionInstruction> {
|
|
787
|
-
const
|
|
788
|
-
return await this.program.instruction.
|
|
1261
|
+
const spotMarket = this.getSpotMarketAccount(marketIndex);
|
|
1262
|
+
return await this.program.instruction.updateSpotMarketCumulativeInterest({
|
|
789
1263
|
accounts: {
|
|
790
|
-
|
|
1264
|
+
spotMarket: spotMarket.pubkey,
|
|
791
1265
|
},
|
|
792
1266
|
});
|
|
793
1267
|
}
|
|
794
1268
|
|
|
795
|
-
public async
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
marketIndex: BN,
|
|
799
|
-
limitPrice?: BN
|
|
800
|
-
): Promise<TransactionSignature> {
|
|
801
|
-
return await this.placeAndTake(
|
|
802
|
-
getMarketOrderParams(
|
|
803
|
-
marketIndex,
|
|
804
|
-
direction,
|
|
805
|
-
ZERO,
|
|
806
|
-
amount,
|
|
807
|
-
false,
|
|
808
|
-
limitPrice
|
|
809
|
-
)
|
|
810
|
-
);
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
public async placeOrder(
|
|
814
|
-
orderParams: OrderParams
|
|
1269
|
+
public async settleLP(
|
|
1270
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
1271
|
+
marketIndex: number
|
|
815
1272
|
): Promise<TransactionSignature> {
|
|
816
|
-
const { txSig
|
|
817
|
-
wrapInTx(await this.
|
|
1273
|
+
const { txSig } = await this.txSender.send(
|
|
1274
|
+
wrapInTx(await this.settleLPIx(settleeUserAccountPublicKey, marketIndex)),
|
|
818
1275
|
[],
|
|
819
1276
|
this.opts
|
|
820
1277
|
);
|
|
821
|
-
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
822
1278
|
return txSig;
|
|
823
1279
|
}
|
|
824
1280
|
|
|
825
|
-
public async
|
|
826
|
-
|
|
1281
|
+
public async settleLPIx(
|
|
1282
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
1283
|
+
marketIndex: number
|
|
827
1284
|
): Promise<TransactionInstruction> {
|
|
828
|
-
const
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
1285
|
+
const settleeUserAccount = (await this.program.account.user.fetch(
|
|
1286
|
+
settleeUserAccountPublicKey
|
|
1287
|
+
)) as UserAccount;
|
|
1288
|
+
const userPositions = settleeUserAccount.perpPositions;
|
|
1289
|
+
const remainingAccounts = [];
|
|
833
1290
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1291
|
+
let foundMarket = false;
|
|
1292
|
+
for (const position of userPositions) {
|
|
1293
|
+
if (!positionIsAvailable(position)) {
|
|
1294
|
+
const marketPublicKey = await getMarketPublicKey(
|
|
1295
|
+
this.program.programId,
|
|
1296
|
+
position.marketIndex
|
|
1297
|
+
);
|
|
1298
|
+
remainingAccounts.push({
|
|
1299
|
+
pubkey: marketPublicKey,
|
|
1300
|
+
isWritable: true,
|
|
1301
|
+
isSigner: false,
|
|
1302
|
+
});
|
|
1303
|
+
|
|
1304
|
+
if (marketIndex === position.marketIndex) {
|
|
1305
|
+
foundMarket = true;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
if (!foundMarket) {
|
|
1311
|
+
console.log(
|
|
1312
|
+
'Warning: lp is not in the market specified -- tx will likely fail'
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
return this.program.instruction.settleLp(marketIndex, {
|
|
1317
|
+
accounts: {
|
|
1318
|
+
state: await this.getStatePublicKey(),
|
|
1319
|
+
user: settleeUserAccountPublicKey,
|
|
1320
|
+
},
|
|
1321
|
+
remainingAccounts: remainingAccounts,
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
public async removeLiquidity(
|
|
1326
|
+
marketIndex: number,
|
|
1327
|
+
sharesToBurn?: BN
|
|
1328
|
+
): Promise<TransactionSignature> {
|
|
1329
|
+
const { txSig } = await this.txSender.send(
|
|
1330
|
+
wrapInTx(await this.getRemoveLiquidityIx(marketIndex, sharesToBurn)),
|
|
1331
|
+
[],
|
|
1332
|
+
this.opts
|
|
1333
|
+
);
|
|
1334
|
+
return txSig;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
public async getRemoveLiquidityIx(
|
|
1338
|
+
marketIndex: number,
|
|
1339
|
+
sharesToBurn?: BN
|
|
1340
|
+
): Promise<TransactionInstruction> {
|
|
1341
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1342
|
+
|
|
1343
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1344
|
+
writablePerpMarketIndex: marketIndex,
|
|
1345
|
+
});
|
|
1346
|
+
|
|
1347
|
+
if (sharesToBurn == undefined) {
|
|
1348
|
+
const userAccount = this.getUserAccount();
|
|
1349
|
+
const perpPosition = userAccount.perpPositions.filter(
|
|
1350
|
+
(position) => position.marketIndex === marketIndex
|
|
1351
|
+
)[0];
|
|
1352
|
+
sharesToBurn = perpPosition.lpShares;
|
|
1353
|
+
console.log('burning lp shares:', sharesToBurn.toString());
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
return this.program.instruction.removeLiquidity(sharesToBurn, marketIndex, {
|
|
1357
|
+
accounts: {
|
|
1358
|
+
state: await this.getStatePublicKey(),
|
|
1359
|
+
user: userAccountPublicKey,
|
|
1360
|
+
authority: this.wallet.publicKey,
|
|
1361
|
+
},
|
|
1362
|
+
remainingAccounts: remainingAccounts,
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
public async addLiquidity(
|
|
1367
|
+
amount: BN,
|
|
1368
|
+
marketIndex: number
|
|
1369
|
+
): Promise<TransactionSignature> {
|
|
1370
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1371
|
+
wrapInTx(await this.getAddLiquidityIx(amount, marketIndex)),
|
|
1372
|
+
[],
|
|
1373
|
+
this.opts
|
|
1374
|
+
);
|
|
1375
|
+
this.marketLastSlotCache.set(marketIndex, slot);
|
|
1376
|
+
return txSig;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
public async getAddLiquidityIx(
|
|
1380
|
+
amount: BN,
|
|
1381
|
+
marketIndex: number
|
|
1382
|
+
): Promise<TransactionInstruction> {
|
|
1383
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1384
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1385
|
+
writablePerpMarketIndex: marketIndex,
|
|
1386
|
+
});
|
|
1387
|
+
|
|
1388
|
+
return this.program.instruction.addLiquidity(amount, marketIndex, {
|
|
1389
|
+
accounts: {
|
|
1390
|
+
state: await this.getStatePublicKey(),
|
|
1391
|
+
user: userAccountPublicKey,
|
|
1392
|
+
authority: this.wallet.publicKey,
|
|
1393
|
+
},
|
|
1394
|
+
remainingAccounts: remainingAccounts,
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
public async openPosition(
|
|
1399
|
+
direction: PositionDirection,
|
|
1400
|
+
amount: BN,
|
|
1401
|
+
marketIndex: number,
|
|
1402
|
+
limitPrice?: BN
|
|
1403
|
+
): Promise<TransactionSignature> {
|
|
1404
|
+
return await this.placeAndTake({
|
|
1405
|
+
orderType: OrderType.MARKET,
|
|
1406
|
+
marketIndex,
|
|
1407
|
+
direction,
|
|
1408
|
+
baseAssetAmount: amount,
|
|
1409
|
+
price: limitPrice,
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
public async sendSignedTx(tx: Transaction): Promise<TransactionSignature> {
|
|
1414
|
+
const { txSig } = await this.txSender.send(tx, undefined, this.opts, true);
|
|
1415
|
+
|
|
1416
|
+
return txSig;
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
/**
|
|
1420
|
+
* Sends a market order and returns a signed tx which can fill the order against the vamm, which the caller can use to fill their own order if required.
|
|
1421
|
+
* @param orderParams
|
|
1422
|
+
* @param userAccountPublicKey
|
|
1423
|
+
* @param userAccount
|
|
1424
|
+
* @returns
|
|
1425
|
+
*/
|
|
1426
|
+
public async sendMarketOrderAndGetSignedFillTx(
|
|
1427
|
+
orderParams: OptionalOrderParams,
|
|
1428
|
+
userAccountPublicKey: PublicKey,
|
|
1429
|
+
userAccount: UserAccount
|
|
1430
|
+
): Promise<{ txSig: TransactionSignature; signedFillTx: Transaction }> {
|
|
1431
|
+
const marketIndex = orderParams.marketIndex;
|
|
1432
|
+
const orderId = userAccount.nextOrderId;
|
|
1433
|
+
|
|
1434
|
+
const marketOrderTx = wrapInTx(await this.getPlaceOrderIx(orderParams));
|
|
1435
|
+
const fillTx = wrapInTx(
|
|
1436
|
+
await this.getFillOrderIx(userAccountPublicKey, userAccount, {
|
|
1437
|
+
orderId,
|
|
1438
|
+
marketIndex,
|
|
1439
|
+
})
|
|
1440
|
+
);
|
|
1441
|
+
|
|
1442
|
+
// Apply the latest blockhash to the txs so that we can sign before sending them
|
|
1443
|
+
const currentBlockHash = (
|
|
1444
|
+
await this.connection.getLatestBlockhash('finalized')
|
|
1445
|
+
).blockhash;
|
|
1446
|
+
marketOrderTx.recentBlockhash = currentBlockHash;
|
|
1447
|
+
fillTx.recentBlockhash = currentBlockHash;
|
|
1448
|
+
|
|
1449
|
+
marketOrderTx.feePayer = userAccount.authority;
|
|
1450
|
+
fillTx.feePayer = userAccount.authority;
|
|
1451
|
+
|
|
1452
|
+
const [signedMarketOrderTx, signedFillTx] =
|
|
1453
|
+
await this.provider.wallet.signAllTransactions([marketOrderTx, fillTx]);
|
|
1454
|
+
|
|
1455
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1456
|
+
signedMarketOrderTx,
|
|
1457
|
+
[],
|
|
1458
|
+
this.opts,
|
|
1459
|
+
true
|
|
1460
|
+
);
|
|
1461
|
+
|
|
1462
|
+
this.marketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
1463
|
+
|
|
1464
|
+
return { txSig, signedFillTx };
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
public async placeOrder(
|
|
1468
|
+
orderParams: OptionalOrderParams
|
|
1469
|
+
): Promise<TransactionSignature> {
|
|
1470
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1471
|
+
wrapInTx(await this.getPlaceOrderIx(orderParams)),
|
|
1472
|
+
[],
|
|
1473
|
+
this.opts
|
|
1474
|
+
);
|
|
1475
|
+
this.marketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
1476
|
+
return txSig;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
getOrderParams(
|
|
1480
|
+
optionalOrderParams: OptionalOrderParams,
|
|
1481
|
+
marketType: MarketType
|
|
1482
|
+
): OrderParams {
|
|
1483
|
+
return Object.assign({}, DefaultOrderParams, optionalOrderParams, {
|
|
1484
|
+
marketType,
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
public async getPlaceOrderIx(
|
|
1489
|
+
orderParams: OptionalOrderParams
|
|
1490
|
+
): Promise<TransactionInstruction> {
|
|
1491
|
+
orderParams = this.getOrderParams(orderParams, MarketType.PERP);
|
|
1492
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1493
|
+
|
|
1494
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1495
|
+
readablePerpMarketIndex: orderParams.marketIndex,
|
|
1496
|
+
});
|
|
1497
|
+
|
|
1498
|
+
return await this.program.instruction.placeOrder(orderParams, {
|
|
1499
|
+
accounts: {
|
|
1500
|
+
state: await this.getStatePublicKey(),
|
|
1501
|
+
user: userAccountPublicKey,
|
|
1502
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
1503
|
+
authority: this.wallet.publicKey,
|
|
1504
|
+
},
|
|
1505
|
+
remainingAccounts,
|
|
841
1506
|
});
|
|
842
1507
|
}
|
|
843
1508
|
|
|
844
|
-
public async updateAMMs(
|
|
1509
|
+
public async updateAMMs(
|
|
1510
|
+
marketIndexes: number[]
|
|
1511
|
+
): Promise<TransactionSignature> {
|
|
845
1512
|
const { txSig } = await this.txSender.send(
|
|
846
1513
|
wrapInTx(await this.getUpdateAMMsIx(marketIndexes)),
|
|
847
1514
|
[],
|
|
@@ -851,16 +1518,16 @@ export class ClearingHouse {
|
|
|
851
1518
|
}
|
|
852
1519
|
|
|
853
1520
|
public async getUpdateAMMsIx(
|
|
854
|
-
marketIndexes:
|
|
1521
|
+
marketIndexes: number[]
|
|
855
1522
|
): Promise<TransactionInstruction> {
|
|
856
1523
|
for (let i = marketIndexes.length; i < 5; i++) {
|
|
857
|
-
marketIndexes.push(
|
|
1524
|
+
marketIndexes.push(100);
|
|
858
1525
|
}
|
|
859
1526
|
const marketAccountInfos = [];
|
|
860
1527
|
const oracleAccountInfos = [];
|
|
861
1528
|
for (const marketIndex of marketIndexes) {
|
|
862
|
-
if (
|
|
863
|
-
const market = this.
|
|
1529
|
+
if (marketIndex !== 100) {
|
|
1530
|
+
const market = this.getPerpMarketAccount(marketIndex);
|
|
864
1531
|
marketAccountInfos.push({
|
|
865
1532
|
pubkey: market.pubkey,
|
|
866
1533
|
isWritable: true,
|
|
@@ -884,6 +1551,54 @@ export class ClearingHouse {
|
|
|
884
1551
|
});
|
|
885
1552
|
}
|
|
886
1553
|
|
|
1554
|
+
public async settleExpiredMarket(
|
|
1555
|
+
marketIndex: number
|
|
1556
|
+
): Promise<TransactionSignature> {
|
|
1557
|
+
const { txSig } = await this.txSender.send(
|
|
1558
|
+
wrapInTx(await this.getSettleExpiredMarketIx(marketIndex)),
|
|
1559
|
+
[],
|
|
1560
|
+
this.opts
|
|
1561
|
+
);
|
|
1562
|
+
return txSig;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
public async getSettleExpiredMarketIx(
|
|
1566
|
+
marketIndex: number
|
|
1567
|
+
): Promise<TransactionInstruction> {
|
|
1568
|
+
const marketAccountInfos = [];
|
|
1569
|
+
const oracleAccountInfos = [];
|
|
1570
|
+
const spotMarketAccountInfos = [];
|
|
1571
|
+
const market = this.getPerpMarketAccount(marketIndex);
|
|
1572
|
+
marketAccountInfos.push({
|
|
1573
|
+
pubkey: market.pubkey,
|
|
1574
|
+
isWritable: true,
|
|
1575
|
+
isSigner: false,
|
|
1576
|
+
});
|
|
1577
|
+
oracleAccountInfos.push({
|
|
1578
|
+
pubkey: market.amm.oracle,
|
|
1579
|
+
isWritable: false,
|
|
1580
|
+
isSigner: false,
|
|
1581
|
+
});
|
|
1582
|
+
|
|
1583
|
+
spotMarketAccountInfos.push({
|
|
1584
|
+
pubkey: this.getSpotMarketAccount(QUOTE_SPOT_MARKET_INDEX).pubkey,
|
|
1585
|
+
isSigner: false,
|
|
1586
|
+
isWritable: true,
|
|
1587
|
+
});
|
|
1588
|
+
|
|
1589
|
+
const remainingAccounts = oracleAccountInfos
|
|
1590
|
+
.concat(spotMarketAccountInfos)
|
|
1591
|
+
.concat(marketAccountInfos);
|
|
1592
|
+
|
|
1593
|
+
return await this.program.instruction.settleExpiredMarket(marketIndex, {
|
|
1594
|
+
accounts: {
|
|
1595
|
+
state: await this.getStatePublicKey(),
|
|
1596
|
+
authority: this.wallet.publicKey,
|
|
1597
|
+
},
|
|
1598
|
+
remainingAccounts,
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
|
|
887
1602
|
public async cancelOrder(orderId?: BN): Promise<TransactionSignature> {
|
|
888
1603
|
const { txSig } = await this.txSender.send(
|
|
889
1604
|
wrapInTx(await this.getCancelOrderIx(orderId)),
|
|
@@ -925,7 +1640,7 @@ export class ClearingHouse {
|
|
|
925
1640
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
926
1641
|
|
|
927
1642
|
const order = this.getOrderByUserId(userOrderId);
|
|
928
|
-
const oracle = this.
|
|
1643
|
+
const oracle = this.getPerpMarketAccount(order.marketIndex).amm.oracle;
|
|
929
1644
|
|
|
930
1645
|
const remainingAccounts = this.getRemainingAccounts({});
|
|
931
1646
|
|
|
@@ -944,11 +1659,18 @@ export class ClearingHouse {
|
|
|
944
1659
|
userAccountPublicKey: PublicKey,
|
|
945
1660
|
user: UserAccount,
|
|
946
1661
|
order?: Order,
|
|
947
|
-
makerInfo?: MakerInfo
|
|
1662
|
+
makerInfo?: MakerInfo,
|
|
1663
|
+
referrerInfo?: ReferrerInfo
|
|
948
1664
|
): Promise<TransactionSignature> {
|
|
949
1665
|
const { txSig } = await this.txSender.send(
|
|
950
1666
|
wrapInTx(
|
|
951
|
-
await this.getFillOrderIx(
|
|
1667
|
+
await this.getFillOrderIx(
|
|
1668
|
+
userAccountPublicKey,
|
|
1669
|
+
user,
|
|
1670
|
+
order,
|
|
1671
|
+
makerInfo,
|
|
1672
|
+
referrerInfo
|
|
1673
|
+
)
|
|
952
1674
|
),
|
|
953
1675
|
[],
|
|
954
1676
|
this.opts
|
|
@@ -959,56 +1681,85 @@ export class ClearingHouse {
|
|
|
959
1681
|
public async getFillOrderIx(
|
|
960
1682
|
userAccountPublicKey: PublicKey,
|
|
961
1683
|
userAccount: UserAccount,
|
|
962
|
-
order: Order,
|
|
963
|
-
makerInfo?: MakerInfo
|
|
1684
|
+
order: Pick<Order, 'marketIndex' | 'orderId'>,
|
|
1685
|
+
makerInfo?: MakerInfo,
|
|
1686
|
+
referrerInfo?: ReferrerInfo
|
|
964
1687
|
): Promise<TransactionInstruction> {
|
|
1688
|
+
const userStatsPublicKey = getUserStatsAccountPublicKey(
|
|
1689
|
+
this.program.programId,
|
|
1690
|
+
userAccount.authority
|
|
1691
|
+
);
|
|
1692
|
+
|
|
965
1693
|
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
1694
|
+
const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
966
1695
|
|
|
967
|
-
const marketIndex = order
|
|
968
|
-
|
|
1696
|
+
const marketIndex = order
|
|
1697
|
+
? order.marketIndex
|
|
1698
|
+
: userAccount.orders.find((order) =>
|
|
1699
|
+
order.orderId.eq(userAccount.nextOrderId.sub(ONE))
|
|
1700
|
+
).marketIndex;
|
|
1701
|
+
const marketAccount = this.getPerpMarketAccount(marketIndex);
|
|
969
1702
|
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1703
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
1704
|
+
const spotMarketAccountMap = new Map<number, AccountMeta>();
|
|
1705
|
+
const perpMarketAccountMap = new Map<number, AccountMeta>();
|
|
1706
|
+
|
|
1707
|
+
for (const spotPosition of userAccount.spotPositions) {
|
|
1708
|
+
if (!isSpotPositionAvailable(spotPosition)) {
|
|
1709
|
+
const spotMarketAccount = this.getSpotMarketAccount(
|
|
1710
|
+
spotPosition.marketIndex
|
|
1711
|
+
);
|
|
1712
|
+
spotMarketAccountMap.set(spotPosition.marketIndex, {
|
|
1713
|
+
pubkey: spotMarketAccount.pubkey,
|
|
1714
|
+
isSigner: false,
|
|
1715
|
+
isWritable: false,
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
|
|
1719
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
1720
|
+
pubkey: spotMarketAccount.oracle,
|
|
1721
|
+
isSigner: false,
|
|
1722
|
+
isWritable: false,
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
for (const position of userAccount.perpPositions) {
|
|
992
1729
|
if (
|
|
993
1730
|
!positionIsAvailable(position) &&
|
|
994
|
-
|
|
1731
|
+
position.marketIndex !== order.marketIndex
|
|
995
1732
|
) {
|
|
996
|
-
const market = this.
|
|
997
|
-
|
|
1733
|
+
const market = this.getPerpMarketAccount(position.marketIndex);
|
|
1734
|
+
perpMarketAccountMap.set(position.marketIndex, {
|
|
998
1735
|
pubkey: market.pubkey,
|
|
999
1736
|
isWritable: false,
|
|
1000
1737
|
isSigner: false,
|
|
1001
1738
|
});
|
|
1002
|
-
|
|
1739
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1003
1740
|
pubkey: market.amm.oracle,
|
|
1004
1741
|
isWritable: false,
|
|
1005
1742
|
isSigner: false,
|
|
1006
1743
|
});
|
|
1007
1744
|
}
|
|
1008
1745
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1746
|
+
|
|
1747
|
+
perpMarketAccountMap.set(marketIndex, {
|
|
1748
|
+
pubkey: marketAccount.pubkey,
|
|
1749
|
+
isWritable: true,
|
|
1750
|
+
isSigner: false,
|
|
1751
|
+
});
|
|
1752
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
1753
|
+
pubkey: marketAccount.amm.oracle,
|
|
1754
|
+
isWritable: false,
|
|
1755
|
+
isSigner: false,
|
|
1756
|
+
});
|
|
1757
|
+
|
|
1758
|
+
const remainingAccounts = [
|
|
1759
|
+
...oracleAccountMap.values(),
|
|
1760
|
+
...spotMarketAccountMap.values(),
|
|
1761
|
+
...perpMarketAccountMap.values(),
|
|
1762
|
+
];
|
|
1012
1763
|
|
|
1013
1764
|
if (makerInfo) {
|
|
1014
1765
|
remainingAccounts.push({
|
|
@@ -1016,204 +1767,1191 @@ export class ClearingHouse {
|
|
|
1016
1767
|
isWritable: true,
|
|
1017
1768
|
isSigner: false,
|
|
1018
1769
|
});
|
|
1770
|
+
remainingAccounts.push({
|
|
1771
|
+
pubkey: makerInfo.makerStats,
|
|
1772
|
+
isWritable: true,
|
|
1773
|
+
isSigner: false,
|
|
1774
|
+
});
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
if (referrerInfo) {
|
|
1778
|
+
remainingAccounts.push({
|
|
1779
|
+
pubkey: referrerInfo.referrer,
|
|
1780
|
+
isWritable: true,
|
|
1781
|
+
isSigner: false,
|
|
1782
|
+
});
|
|
1783
|
+
remainingAccounts.push({
|
|
1784
|
+
pubkey: referrerInfo.referrerStats,
|
|
1785
|
+
isWritable: true,
|
|
1786
|
+
isSigner: false,
|
|
1787
|
+
});
|
|
1019
1788
|
}
|
|
1020
1789
|
|
|
1021
1790
|
const orderId = order.orderId;
|
|
1022
1791
|
const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
|
|
1792
|
+
|
|
1023
1793
|
return await this.program.instruction.fillOrder(orderId, makerOrderId, {
|
|
1024
1794
|
accounts: {
|
|
1025
1795
|
state: await this.getStatePublicKey(),
|
|
1026
1796
|
filler: fillerPublicKey,
|
|
1797
|
+
fillerStats: fillerStatsPublicKey,
|
|
1027
1798
|
user: userAccountPublicKey,
|
|
1799
|
+
userStats: userStatsPublicKey,
|
|
1028
1800
|
authority: this.wallet.publicKey,
|
|
1029
1801
|
},
|
|
1030
1802
|
remainingAccounts,
|
|
1031
1803
|
});
|
|
1032
1804
|
}
|
|
1033
1805
|
|
|
1034
|
-
public async
|
|
1035
|
-
|
|
1036
|
-
user: UserAccount,
|
|
1037
|
-
order: Order
|
|
1806
|
+
public async placeSpotOrder(
|
|
1807
|
+
orderParams: OptionalOrderParams
|
|
1038
1808
|
): Promise<TransactionSignature> {
|
|
1039
1809
|
const { txSig } = await this.txSender.send(
|
|
1040
|
-
wrapInTx(await this.
|
|
1810
|
+
wrapInTx(await this.getPlaceSpotOrderIx(orderParams)),
|
|
1041
1811
|
[],
|
|
1042
1812
|
this.opts
|
|
1043
1813
|
);
|
|
1044
1814
|
return txSig;
|
|
1045
1815
|
}
|
|
1046
1816
|
|
|
1047
|
-
public async
|
|
1048
|
-
|
|
1049
|
-
userAccount: UserAccount,
|
|
1050
|
-
order: Order
|
|
1817
|
+
public async getPlaceSpotOrderIx(
|
|
1818
|
+
orderParams: OptionalOrderParams
|
|
1051
1819
|
): Promise<TransactionInstruction> {
|
|
1052
|
-
|
|
1820
|
+
orderParams = this.getOrderParams(orderParams, MarketType.SPOT);
|
|
1821
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1053
1822
|
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1823
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1824
|
+
readableSpotMarketIndex: orderParams.marketIndex,
|
|
1825
|
+
});
|
|
1056
1826
|
|
|
1057
|
-
|
|
1058
|
-
{
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1827
|
+
return await this.program.instruction.placeSpotOrder(orderParams, {
|
|
1828
|
+
accounts: {
|
|
1829
|
+
state: await this.getStatePublicKey(),
|
|
1830
|
+
user: userAccountPublicKey,
|
|
1831
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
1832
|
+
authority: this.wallet.publicKey,
|
|
1062
1833
|
},
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1834
|
+
remainingAccounts,
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
public async fillSpotOrder(
|
|
1839
|
+
userAccountPublicKey: PublicKey,
|
|
1840
|
+
user: UserAccount,
|
|
1841
|
+
order?: Order,
|
|
1842
|
+
fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
|
|
1843
|
+
makerInfo?: MakerInfo,
|
|
1844
|
+
referrerInfo?: ReferrerInfo
|
|
1845
|
+
): Promise<TransactionSignature> {
|
|
1846
|
+
const { txSig } = await this.txSender.send(
|
|
1847
|
+
wrapInTx(
|
|
1848
|
+
await this.getFillSpotOrderIx(
|
|
1849
|
+
userAccountPublicKey,
|
|
1850
|
+
user,
|
|
1851
|
+
order,
|
|
1852
|
+
fulfillmentConfig,
|
|
1853
|
+
makerInfo,
|
|
1854
|
+
referrerInfo
|
|
1855
|
+
)
|
|
1856
|
+
),
|
|
1857
|
+
[],
|
|
1858
|
+
this.opts
|
|
1859
|
+
);
|
|
1860
|
+
return txSig;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
public async getFillSpotOrderIx(
|
|
1864
|
+
userAccountPublicKey: PublicKey,
|
|
1865
|
+
userAccount: UserAccount,
|
|
1866
|
+
order?: Order,
|
|
1867
|
+
fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
|
|
1868
|
+
makerInfo?: MakerInfo,
|
|
1869
|
+
referrerInfo?: ReferrerInfo
|
|
1870
|
+
): Promise<TransactionInstruction> {
|
|
1871
|
+
const userStatsPublicKey = getUserStatsAccountPublicKey(
|
|
1872
|
+
this.program.programId,
|
|
1873
|
+
userAccount.authority
|
|
1874
|
+
);
|
|
1875
|
+
|
|
1876
|
+
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
1877
|
+
const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
1878
|
+
|
|
1879
|
+
const marketIndex = order
|
|
1880
|
+
? order.marketIndex
|
|
1881
|
+
: userAccount.orders.find((order) =>
|
|
1882
|
+
order.orderId.eq(userAccount.nextOrderId.sub(ONE))
|
|
1883
|
+
).marketIndex;
|
|
1884
|
+
|
|
1885
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
1886
|
+
const spotMarketAccountMap = new Map<number, AccountMeta>();
|
|
1887
|
+
const perpMarketAccountMap = new Map<number, AccountMeta>();
|
|
1888
|
+
|
|
1889
|
+
for (const spotPosition of userAccount.spotPositions) {
|
|
1890
|
+
if (!isSpotPositionAvailable(spotPosition)) {
|
|
1891
|
+
const spotMarket = this.getSpotMarketAccount(spotPosition.marketIndex);
|
|
1892
|
+
spotMarketAccountMap.set(spotPosition.marketIndex, {
|
|
1893
|
+
pubkey: spotMarket.pubkey,
|
|
1894
|
+
isSigner: false,
|
|
1895
|
+
isWritable: false,
|
|
1896
|
+
});
|
|
1897
|
+
|
|
1898
|
+
if (!spotMarket.oracle.equals(PublicKey.default)) {
|
|
1899
|
+
oracleAccountMap.set(spotMarket.oracle.toString(), {
|
|
1900
|
+
pubkey: spotMarket.oracle,
|
|
1901
|
+
isSigner: false,
|
|
1902
|
+
isWritable: false,
|
|
1903
|
+
});
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
for (const position of userAccount.perpPositions) {
|
|
1909
|
+
if (!positionIsAvailable(position)) {
|
|
1910
|
+
const market = this.getPerpMarketAccount(position.marketIndex);
|
|
1911
|
+
perpMarketAccountMap.set(position.marketIndex, {
|
|
1912
|
+
pubkey: market.pubkey,
|
|
1913
|
+
isWritable: false,
|
|
1914
|
+
isSigner: false,
|
|
1915
|
+
});
|
|
1916
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1917
|
+
pubkey: market.amm.oracle,
|
|
1918
|
+
isWritable: false,
|
|
1919
|
+
isSigner: false,
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
1925
|
+
spotMarketAccountMap.set(marketIndex, {
|
|
1926
|
+
pubkey: spotMarketAccount.pubkey,
|
|
1927
|
+
isWritable: true,
|
|
1928
|
+
isSigner: false,
|
|
1929
|
+
});
|
|
1930
|
+
if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
|
|
1931
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
1932
|
+
pubkey: spotMarketAccount.oracle,
|
|
1933
|
+
isWritable: false,
|
|
1068
1934
|
isSigner: false,
|
|
1069
|
-
}
|
|
1935
|
+
});
|
|
1936
|
+
}
|
|
1937
|
+
const quoteMarketAccount = this.getQuoteSpotMarketAccount();
|
|
1938
|
+
spotMarketAccountMap.set(quoteMarketAccount.marketIndex, {
|
|
1939
|
+
pubkey: quoteMarketAccount.pubkey,
|
|
1940
|
+
isWritable: true,
|
|
1941
|
+
isSigner: false,
|
|
1942
|
+
});
|
|
1943
|
+
|
|
1944
|
+
const remainingAccounts = [
|
|
1945
|
+
...oracleAccountMap.values(),
|
|
1946
|
+
...spotMarketAccountMap.values(),
|
|
1947
|
+
...perpMarketAccountMap.values(),
|
|
1070
1948
|
];
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1949
|
+
|
|
1950
|
+
if (makerInfo) {
|
|
1951
|
+
remainingAccounts.push({
|
|
1952
|
+
pubkey: makerInfo.maker,
|
|
1953
|
+
isWritable: true,
|
|
1954
|
+
isSigner: false,
|
|
1955
|
+
});
|
|
1956
|
+
remainingAccounts.push({
|
|
1957
|
+
pubkey: makerInfo.makerStats,
|
|
1958
|
+
isWritable: true,
|
|
1959
|
+
isSigner: false,
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
if (referrerInfo) {
|
|
1964
|
+
remainingAccounts.push({
|
|
1965
|
+
pubkey: referrerInfo.referrer,
|
|
1966
|
+
isWritable: true,
|
|
1967
|
+
isSigner: false,
|
|
1968
|
+
});
|
|
1969
|
+
remainingAccounts.push({
|
|
1970
|
+
pubkey: referrerInfo.referrerStats,
|
|
1971
|
+
isWritable: true,
|
|
1972
|
+
isSigner: false,
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
const orderId = order.orderId;
|
|
1977
|
+
const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
|
|
1978
|
+
|
|
1979
|
+
if (fulfillmentConfig) {
|
|
1980
|
+
remainingAccounts.push({
|
|
1981
|
+
pubkey: fulfillmentConfig.pubkey,
|
|
1074
1982
|
isWritable: false,
|
|
1075
1983
|
isSigner: false,
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1984
|
+
});
|
|
1985
|
+
remainingAccounts.push({
|
|
1986
|
+
pubkey: fulfillmentConfig.serumProgramId,
|
|
1987
|
+
isWritable: false,
|
|
1988
|
+
isSigner: false,
|
|
1989
|
+
});
|
|
1990
|
+
remainingAccounts.push({
|
|
1991
|
+
pubkey: fulfillmentConfig.serumMarket,
|
|
1992
|
+
isWritable: true,
|
|
1993
|
+
isSigner: false,
|
|
1994
|
+
});
|
|
1995
|
+
remainingAccounts.push({
|
|
1996
|
+
pubkey: fulfillmentConfig.serumRequestQueue,
|
|
1997
|
+
isWritable: true,
|
|
1998
|
+
isSigner: false,
|
|
1999
|
+
});
|
|
2000
|
+
remainingAccounts.push({
|
|
2001
|
+
pubkey: fulfillmentConfig.serumEventQueue,
|
|
2002
|
+
isWritable: true,
|
|
2003
|
+
isSigner: false,
|
|
2004
|
+
});
|
|
2005
|
+
remainingAccounts.push({
|
|
2006
|
+
pubkey: fulfillmentConfig.serumBids,
|
|
2007
|
+
isWritable: true,
|
|
2008
|
+
isSigner: false,
|
|
2009
|
+
});
|
|
2010
|
+
remainingAccounts.push({
|
|
2011
|
+
pubkey: fulfillmentConfig.serumAsks,
|
|
2012
|
+
isWritable: true,
|
|
2013
|
+
isSigner: false,
|
|
2014
|
+
});
|
|
2015
|
+
remainingAccounts.push({
|
|
2016
|
+
pubkey: fulfillmentConfig.serumBaseVault,
|
|
2017
|
+
isWritable: true,
|
|
2018
|
+
isSigner: false,
|
|
2019
|
+
});
|
|
2020
|
+
remainingAccounts.push({
|
|
2021
|
+
pubkey: fulfillmentConfig.serumQuoteVault,
|
|
2022
|
+
isWritable: true,
|
|
2023
|
+
isSigner: false,
|
|
2024
|
+
});
|
|
2025
|
+
remainingAccounts.push({
|
|
2026
|
+
pubkey: fulfillmentConfig.serumOpenOrders,
|
|
2027
|
+
isWritable: true,
|
|
2028
|
+
isSigner: false,
|
|
2029
|
+
});
|
|
2030
|
+
remainingAccounts.push({
|
|
2031
|
+
pubkey: getSerumSignerPublicKey(
|
|
2032
|
+
fulfillmentConfig.serumProgramId,
|
|
2033
|
+
fulfillmentConfig.serumMarket,
|
|
2034
|
+
fulfillmentConfig.serumSignerNonce
|
|
2035
|
+
),
|
|
2036
|
+
isWritable: false,
|
|
2037
|
+
isSigner: false,
|
|
2038
|
+
});
|
|
2039
|
+
remainingAccounts.push({
|
|
2040
|
+
pubkey: this.getSignerPublicKey(),
|
|
2041
|
+
isWritable: false,
|
|
2042
|
+
isSigner: false,
|
|
2043
|
+
});
|
|
2044
|
+
remainingAccounts.push({
|
|
2045
|
+
pubkey: TOKEN_PROGRAM_ID,
|
|
2046
|
+
isWritable: false,
|
|
2047
|
+
isSigner: false,
|
|
2048
|
+
});
|
|
2049
|
+
remainingAccounts.push({
|
|
2050
|
+
pubkey: spotMarketAccount.vault,
|
|
2051
|
+
isWritable: true,
|
|
2052
|
+
isSigner: false,
|
|
2053
|
+
});
|
|
2054
|
+
remainingAccounts.push({
|
|
2055
|
+
pubkey: quoteMarketAccount.vault,
|
|
2056
|
+
isWritable: true,
|
|
2057
|
+
isSigner: false,
|
|
2058
|
+
});
|
|
2059
|
+
remainingAccounts.push({
|
|
2060
|
+
pubkey: this.getStateAccount().srmVault,
|
|
2061
|
+
isWritable: false,
|
|
2062
|
+
isSigner: false,
|
|
2063
|
+
});
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
return await this.program.instruction.fillSpotOrder(
|
|
2067
|
+
orderId,
|
|
2068
|
+
fulfillmentConfig ? fulfillmentConfig.fulfillmentType : null,
|
|
2069
|
+
makerOrderId,
|
|
2070
|
+
{
|
|
2071
|
+
accounts: {
|
|
2072
|
+
state: await this.getStatePublicKey(),
|
|
2073
|
+
filler: fillerPublicKey,
|
|
2074
|
+
fillerStats: fillerStatsPublicKey,
|
|
2075
|
+
user: userAccountPublicKey,
|
|
2076
|
+
userStats: userStatsPublicKey,
|
|
2077
|
+
authority: this.wallet.publicKey,
|
|
2078
|
+
},
|
|
2079
|
+
remainingAccounts,
|
|
2080
|
+
}
|
|
2081
|
+
);
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
public async triggerOrder(
|
|
2085
|
+
userAccountPublicKey: PublicKey,
|
|
2086
|
+
user: UserAccount,
|
|
2087
|
+
order: Order
|
|
2088
|
+
): Promise<TransactionSignature> {
|
|
2089
|
+
const { txSig } = await this.txSender.send(
|
|
2090
|
+
wrapInTx(await this.getTriggerOrderIx(userAccountPublicKey, user, order)),
|
|
2091
|
+
[],
|
|
2092
|
+
this.opts
|
|
2093
|
+
);
|
|
2094
|
+
return txSig;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
public async getTriggerOrderIx(
|
|
2098
|
+
userAccountPublicKey: PublicKey,
|
|
2099
|
+
userAccount: UserAccount,
|
|
2100
|
+
order: Order
|
|
2101
|
+
): Promise<TransactionInstruction> {
|
|
2102
|
+
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
2103
|
+
|
|
2104
|
+
const marketIndex = order.marketIndex;
|
|
2105
|
+
const marketAccount = this.getPerpMarketAccount(marketIndex);
|
|
2106
|
+
|
|
2107
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
2108
|
+
const spotMarketAccountMap = new Map<number, AccountMeta>();
|
|
2109
|
+
const perpMarketAccountMap = new Map<number, AccountMeta>();
|
|
2110
|
+
|
|
2111
|
+
for (const spotPosition of userAccount.spotPositions) {
|
|
2112
|
+
if (!isSpotPositionAvailable(spotPosition)) {
|
|
2113
|
+
const spotMarketAccount = this.getSpotMarketAccount(
|
|
2114
|
+
spotPosition.marketIndex
|
|
2115
|
+
);
|
|
2116
|
+
spotMarketAccountMap.set(spotPosition.marketIndex, {
|
|
2117
|
+
pubkey: spotMarketAccount.pubkey,
|
|
2118
|
+
isSigner: false,
|
|
2119
|
+
isWritable: false,
|
|
2120
|
+
});
|
|
2121
|
+
|
|
2122
|
+
if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
|
|
2123
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
2124
|
+
pubkey: spotMarketAccount.oracle,
|
|
2125
|
+
isSigner: false,
|
|
2126
|
+
isWritable: false,
|
|
2127
|
+
});
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
for (const position of userAccount.perpPositions) {
|
|
1079
2133
|
if (
|
|
1080
2134
|
!positionIsAvailable(position) &&
|
|
1081
|
-
|
|
2135
|
+
position.marketIndex !== order.marketIndex
|
|
1082
2136
|
) {
|
|
1083
|
-
const market = this.
|
|
1084
|
-
|
|
2137
|
+
const market = this.getPerpMarketAccount(position.marketIndex);
|
|
2138
|
+
perpMarketAccountMap.set(position.marketIndex, {
|
|
1085
2139
|
pubkey: market.pubkey,
|
|
1086
2140
|
isWritable: false,
|
|
1087
2141
|
isSigner: false,
|
|
1088
|
-
});
|
|
1089
|
-
|
|
1090
|
-
pubkey: market.amm.oracle,
|
|
2142
|
+
});
|
|
2143
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
2144
|
+
pubkey: market.amm.oracle,
|
|
2145
|
+
isWritable: false,
|
|
2146
|
+
isSigner: false,
|
|
2147
|
+
});
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
perpMarketAccountMap.set(marketIndex, {
|
|
2152
|
+
pubkey: marketAccount.pubkey,
|
|
2153
|
+
isWritable: true,
|
|
2154
|
+
isSigner: false,
|
|
2155
|
+
});
|
|
2156
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
2157
|
+
pubkey: marketAccount.amm.oracle,
|
|
2158
|
+
isWritable: false,
|
|
2159
|
+
isSigner: false,
|
|
2160
|
+
});
|
|
2161
|
+
|
|
2162
|
+
const remainingAccounts = [
|
|
2163
|
+
...oracleAccountMap.values(),
|
|
2164
|
+
...spotMarketAccountMap.values(),
|
|
2165
|
+
...perpMarketAccountMap.values(),
|
|
2166
|
+
];
|
|
2167
|
+
|
|
2168
|
+
const orderId = order.orderId;
|
|
2169
|
+
return await this.program.instruction.triggerOrder(orderId, {
|
|
2170
|
+
accounts: {
|
|
2171
|
+
state: await this.getStatePublicKey(),
|
|
2172
|
+
filler: fillerPublicKey,
|
|
2173
|
+
user: userAccountPublicKey,
|
|
2174
|
+
authority: this.wallet.publicKey,
|
|
2175
|
+
},
|
|
2176
|
+
remainingAccounts,
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
public async triggerSpotOrder(
|
|
2181
|
+
userAccountPublicKey: PublicKey,
|
|
2182
|
+
user: UserAccount,
|
|
2183
|
+
order: Order
|
|
2184
|
+
): Promise<TransactionSignature> {
|
|
2185
|
+
const { txSig } = await this.txSender.send(
|
|
2186
|
+
wrapInTx(
|
|
2187
|
+
await this.getTriggerSpotOrderIx(userAccountPublicKey, user, order)
|
|
2188
|
+
),
|
|
2189
|
+
[],
|
|
2190
|
+
this.opts
|
|
2191
|
+
);
|
|
2192
|
+
return txSig;
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
public async getTriggerSpotOrderIx(
|
|
2196
|
+
userAccountPublicKey: PublicKey,
|
|
2197
|
+
userAccount: UserAccount,
|
|
2198
|
+
order: Order
|
|
2199
|
+
): Promise<TransactionInstruction> {
|
|
2200
|
+
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
2201
|
+
|
|
2202
|
+
const marketIndex = order.marketIndex;
|
|
2203
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
2204
|
+
|
|
2205
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
2206
|
+
const spotMarketAccountMap = new Map<number, AccountMeta>();
|
|
2207
|
+
const perpMarketAccountMap = new Map<number, AccountMeta>();
|
|
2208
|
+
|
|
2209
|
+
for (const spotPosition of userAccount.spotPositions) {
|
|
2210
|
+
if (!isSpotPositionAvailable(spotPosition)) {
|
|
2211
|
+
const spotMarketAccount = this.getSpotMarketAccount(
|
|
2212
|
+
spotPosition.marketIndex
|
|
2213
|
+
);
|
|
2214
|
+
spotMarketAccountMap.set(spotPosition.marketIndex, {
|
|
2215
|
+
pubkey: spotMarketAccount.pubkey,
|
|
2216
|
+
isSigner: false,
|
|
2217
|
+
isWritable: false,
|
|
2218
|
+
});
|
|
2219
|
+
|
|
2220
|
+
if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
|
|
2221
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
2222
|
+
pubkey: spotMarketAccount.oracle,
|
|
2223
|
+
isSigner: false,
|
|
2224
|
+
isWritable: false,
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
for (const position of userAccount.perpPositions) {
|
|
2231
|
+
if (
|
|
2232
|
+
!positionIsAvailable(position) &&
|
|
2233
|
+
position.marketIndex !== order.marketIndex
|
|
2234
|
+
) {
|
|
2235
|
+
const market = this.getPerpMarketAccount(position.marketIndex);
|
|
2236
|
+
perpMarketAccountMap.set(position.marketIndex, {
|
|
2237
|
+
pubkey: market.pubkey,
|
|
2238
|
+
isWritable: false,
|
|
2239
|
+
isSigner: false,
|
|
2240
|
+
});
|
|
2241
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
2242
|
+
pubkey: market.amm.oracle,
|
|
2243
|
+
isWritable: false,
|
|
2244
|
+
isSigner: false,
|
|
2245
|
+
});
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
const quoteSpotMarket = this.getQuoteSpotMarketAccount();
|
|
2250
|
+
spotMarketAccountMap.set(quoteSpotMarket.marketIndex, {
|
|
2251
|
+
pubkey: quoteSpotMarket.pubkey,
|
|
2252
|
+
isWritable: true,
|
|
2253
|
+
isSigner: false,
|
|
2254
|
+
});
|
|
2255
|
+
spotMarketAccountMap.set(marketIndex, {
|
|
2256
|
+
pubkey: spotMarketAccount.pubkey,
|
|
2257
|
+
isWritable: false,
|
|
2258
|
+
isSigner: false,
|
|
2259
|
+
});
|
|
2260
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
2261
|
+
pubkey: spotMarketAccount.oracle,
|
|
2262
|
+
isWritable: false,
|
|
2263
|
+
isSigner: false,
|
|
2264
|
+
});
|
|
2265
|
+
|
|
2266
|
+
const remainingAccounts = [
|
|
2267
|
+
...oracleAccountMap.values(),
|
|
2268
|
+
...spotMarketAccountMap.values(),
|
|
2269
|
+
...perpMarketAccountMap.values(),
|
|
2270
|
+
];
|
|
2271
|
+
|
|
2272
|
+
const orderId = order.orderId;
|
|
2273
|
+
return await this.program.instruction.triggerSpotOrder(orderId, {
|
|
2274
|
+
accounts: {
|
|
2275
|
+
state: await this.getStatePublicKey(),
|
|
2276
|
+
filler: fillerPublicKey,
|
|
2277
|
+
user: userAccountPublicKey,
|
|
2278
|
+
authority: this.wallet.publicKey,
|
|
2279
|
+
},
|
|
2280
|
+
remainingAccounts,
|
|
2281
|
+
});
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
public async placeAndTake(
|
|
2285
|
+
orderParams: OptionalOrderParams,
|
|
2286
|
+
makerInfo?: MakerInfo,
|
|
2287
|
+
referrerInfo?: ReferrerInfo
|
|
2288
|
+
): Promise<TransactionSignature> {
|
|
2289
|
+
const { txSig, slot } = await this.txSender.send(
|
|
2290
|
+
wrapInTx(
|
|
2291
|
+
await this.getPlaceAndTakeIx(orderParams, makerInfo, referrerInfo)
|
|
2292
|
+
),
|
|
2293
|
+
[],
|
|
2294
|
+
this.opts
|
|
2295
|
+
);
|
|
2296
|
+
this.marketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
2297
|
+
return txSig;
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
public async getPlaceAndTakeIx(
|
|
2301
|
+
orderParams: OptionalOrderParams,
|
|
2302
|
+
makerInfo?: MakerInfo,
|
|
2303
|
+
referrerInfo?: ReferrerInfo
|
|
2304
|
+
): Promise<TransactionInstruction> {
|
|
2305
|
+
orderParams = this.getOrderParams(orderParams, MarketType.PERP);
|
|
2306
|
+
const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
|
|
2307
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
2308
|
+
|
|
2309
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
2310
|
+
writablePerpMarketIndex: orderParams.marketIndex,
|
|
2311
|
+
writableSpotMarketIndex: QUOTE_SPOT_MARKET_INDEX,
|
|
2312
|
+
});
|
|
2313
|
+
|
|
2314
|
+
let makerOrderId = null;
|
|
2315
|
+
if (makerInfo) {
|
|
2316
|
+
makerOrderId = makerInfo.order.orderId;
|
|
2317
|
+
remainingAccounts.push({
|
|
2318
|
+
pubkey: makerInfo.maker,
|
|
2319
|
+
isSigner: false,
|
|
2320
|
+
isWritable: true,
|
|
2321
|
+
});
|
|
2322
|
+
remainingAccounts.push({
|
|
2323
|
+
pubkey: makerInfo.makerStats,
|
|
2324
|
+
isSigner: false,
|
|
2325
|
+
isWritable: true,
|
|
2326
|
+
});
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2329
|
+
if (referrerInfo) {
|
|
2330
|
+
remainingAccounts.push({
|
|
2331
|
+
pubkey: referrerInfo.referrer,
|
|
2332
|
+
isWritable: true,
|
|
2333
|
+
isSigner: false,
|
|
2334
|
+
});
|
|
2335
|
+
remainingAccounts.push({
|
|
2336
|
+
pubkey: referrerInfo.referrerStats,
|
|
2337
|
+
isWritable: true,
|
|
2338
|
+
isSigner: false,
|
|
2339
|
+
});
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
return await this.program.instruction.placeAndTake(
|
|
2343
|
+
orderParams,
|
|
2344
|
+
makerOrderId,
|
|
2345
|
+
{
|
|
2346
|
+
accounts: {
|
|
2347
|
+
state: await this.getStatePublicKey(),
|
|
2348
|
+
user: userAccountPublicKey,
|
|
2349
|
+
userStats: userStatsPublicKey,
|
|
2350
|
+
authority: this.wallet.publicKey,
|
|
2351
|
+
},
|
|
2352
|
+
remainingAccounts,
|
|
2353
|
+
}
|
|
2354
|
+
);
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
public async placeAndMake(
|
|
2358
|
+
orderParams: OptionalOrderParams,
|
|
2359
|
+
takerInfo: TakerInfo,
|
|
2360
|
+
referrerInfo?: ReferrerInfo
|
|
2361
|
+
): Promise<TransactionSignature> {
|
|
2362
|
+
const { txSig, slot } = await this.txSender.send(
|
|
2363
|
+
wrapInTx(
|
|
2364
|
+
await this.getPlaceAndMakeIx(orderParams, takerInfo, referrerInfo)
|
|
2365
|
+
),
|
|
2366
|
+
[],
|
|
2367
|
+
this.opts
|
|
2368
|
+
);
|
|
2369
|
+
|
|
2370
|
+
this.marketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
2371
|
+
|
|
2372
|
+
return txSig;
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
public async getPlaceAndMakeIx(
|
|
2376
|
+
orderParams: OptionalOrderParams,
|
|
2377
|
+
takerInfo: TakerInfo,
|
|
2378
|
+
referrerInfo?: ReferrerInfo
|
|
2379
|
+
): Promise<TransactionInstruction> {
|
|
2380
|
+
orderParams = this.getOrderParams(orderParams, MarketType.PERP);
|
|
2381
|
+
const userStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
2382
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
2383
|
+
|
|
2384
|
+
// todo merge this with getRemainingAccounts
|
|
2385
|
+
const remainingAccounts = this.getRemainingAccountsWithCounterparty({
|
|
2386
|
+
counterPartyUserAccount: takerInfo.takerUserAccount,
|
|
2387
|
+
writablePerpMarketIndex: orderParams.marketIndex,
|
|
2388
|
+
});
|
|
2389
|
+
|
|
2390
|
+
if (referrerInfo) {
|
|
2391
|
+
remainingAccounts.push({
|
|
2392
|
+
pubkey: referrerInfo.referrer,
|
|
2393
|
+
isWritable: true,
|
|
2394
|
+
isSigner: false,
|
|
2395
|
+
});
|
|
2396
|
+
remainingAccounts.push({
|
|
2397
|
+
pubkey: referrerInfo.referrerStats,
|
|
2398
|
+
isWritable: true,
|
|
2399
|
+
isSigner: false,
|
|
2400
|
+
});
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
const takerOrderId = takerInfo!.order!.orderId;
|
|
2404
|
+
return await this.program.instruction.placeAndMake(
|
|
2405
|
+
orderParams,
|
|
2406
|
+
takerOrderId,
|
|
2407
|
+
{
|
|
2408
|
+
accounts: {
|
|
2409
|
+
state: await this.getStatePublicKey(),
|
|
2410
|
+
user: userAccountPublicKey,
|
|
2411
|
+
userStats: userStatsPublicKey,
|
|
2412
|
+
taker: takerInfo.taker,
|
|
2413
|
+
takerStats: takerInfo.takerStats,
|
|
2414
|
+
authority: this.wallet.publicKey,
|
|
2415
|
+
},
|
|
2416
|
+
remainingAccounts,
|
|
2417
|
+
}
|
|
2418
|
+
);
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
/**
|
|
2422
|
+
* Close an entire position. If you want to reduce a position, use the {@link openPosition} method in the opposite direction of the current position.
|
|
2423
|
+
* @param marketIndex
|
|
2424
|
+
* @returns
|
|
2425
|
+
*/
|
|
2426
|
+
public async closePosition(
|
|
2427
|
+
marketIndex: number,
|
|
2428
|
+
limitPrice?: BN
|
|
2429
|
+
): Promise<TransactionSignature> {
|
|
2430
|
+
const userPosition = this.getUser().getUserPosition(marketIndex);
|
|
2431
|
+
if (!userPosition) {
|
|
2432
|
+
throw Error(`No position in market ${marketIndex.toString()}`);
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
return await this.placeAndTake({
|
|
2436
|
+
orderType: OrderType.MARKET,
|
|
2437
|
+
marketIndex,
|
|
2438
|
+
direction: findDirectionToClose(userPosition),
|
|
2439
|
+
baseAssetAmount: userPosition.baseAssetAmount.abs(),
|
|
2440
|
+
reduceOnly: true,
|
|
2441
|
+
price: limitPrice,
|
|
2442
|
+
});
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
public async settlePNLs(
|
|
2446
|
+
users: {
|
|
2447
|
+
settleeUserAccountPublicKey: PublicKey;
|
|
2448
|
+
settleeUserAccount: UserAccount;
|
|
2449
|
+
}[],
|
|
2450
|
+
marketIndex: number
|
|
2451
|
+
): Promise<TransactionSignature> {
|
|
2452
|
+
const ixs = [];
|
|
2453
|
+
for (const { settleeUserAccountPublicKey, settleeUserAccount } of users) {
|
|
2454
|
+
ixs.push(
|
|
2455
|
+
await this.settlePNLIx(
|
|
2456
|
+
settleeUserAccountPublicKey,
|
|
2457
|
+
settleeUserAccount,
|
|
2458
|
+
marketIndex
|
|
2459
|
+
)
|
|
2460
|
+
);
|
|
2461
|
+
}
|
|
2462
|
+
|
|
2463
|
+
const tx = new Transaction()
|
|
2464
|
+
.add(
|
|
2465
|
+
ComputeBudgetProgram.requestUnits({
|
|
2466
|
+
units: 1_000_000,
|
|
2467
|
+
additionalFee: 0,
|
|
2468
|
+
})
|
|
2469
|
+
)
|
|
2470
|
+
.add(...ixs);
|
|
2471
|
+
|
|
2472
|
+
const { txSig } = await this.txSender.send(tx, [], this.opts);
|
|
2473
|
+
return txSig;
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
public async settlePNL(
|
|
2477
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
2478
|
+
settleeUserAccount: UserAccount,
|
|
2479
|
+
marketIndex: number
|
|
2480
|
+
): Promise<TransactionSignature> {
|
|
2481
|
+
const { txSig } = await this.txSender.send(
|
|
2482
|
+
wrapInTx(
|
|
2483
|
+
await this.settlePNLIx(
|
|
2484
|
+
settleeUserAccountPublicKey,
|
|
2485
|
+
settleeUserAccount,
|
|
2486
|
+
marketIndex
|
|
2487
|
+
)
|
|
2488
|
+
),
|
|
2489
|
+
[],
|
|
2490
|
+
this.opts
|
|
2491
|
+
);
|
|
2492
|
+
return txSig;
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
public async settlePNLIx(
|
|
2496
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
2497
|
+
settleeUserAccount: UserAccount,
|
|
2498
|
+
marketIndex: number
|
|
2499
|
+
): Promise<TransactionInstruction> {
|
|
2500
|
+
const perpMarketAccountMap = new Map<number, AccountMeta>();
|
|
2501
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
2502
|
+
const spotMarketAccountMap = new Map<number, AccountMeta>();
|
|
2503
|
+
|
|
2504
|
+
for (const position of settleeUserAccount.perpPositions) {
|
|
2505
|
+
if (!positionIsAvailable(position)) {
|
|
2506
|
+
const market = this.getPerpMarketAccount(position.marketIndex);
|
|
2507
|
+
perpMarketAccountMap.set(position.marketIndex, {
|
|
2508
|
+
pubkey: market.pubkey,
|
|
2509
|
+
isWritable: false,
|
|
2510
|
+
isSigner: false,
|
|
2511
|
+
});
|
|
2512
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
2513
|
+
pubkey: market.amm.oracle,
|
|
2514
|
+
isWritable: false,
|
|
2515
|
+
isSigner: false,
|
|
2516
|
+
});
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
for (const spotPosition of settleeUserAccount.spotPositions) {
|
|
2521
|
+
if (!isSpotPositionAvailable(spotPosition)) {
|
|
2522
|
+
const spotMarketAccount = this.getSpotMarketAccount(
|
|
2523
|
+
spotPosition.marketIndex
|
|
2524
|
+
);
|
|
2525
|
+
spotMarketAccountMap.set(spotPosition.marketIndex, {
|
|
2526
|
+
pubkey: spotMarketAccount.pubkey,
|
|
2527
|
+
isSigner: false,
|
|
2528
|
+
isWritable: false,
|
|
2529
|
+
});
|
|
2530
|
+
if (spotMarketAccount.marketIndex !== 0) {
|
|
2531
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
2532
|
+
pubkey: spotMarketAccount.oracle,
|
|
2533
|
+
isSigner: false,
|
|
2534
|
+
isWritable: false,
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
const marketAccount = this.getPerpMarketAccount(marketIndex);
|
|
2541
|
+
perpMarketAccountMap.set(marketIndex, {
|
|
2542
|
+
pubkey: marketAccount.pubkey,
|
|
2543
|
+
isSigner: false,
|
|
2544
|
+
isWritable: true,
|
|
2545
|
+
});
|
|
2546
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
2547
|
+
pubkey: marketAccount.amm.oracle,
|
|
2548
|
+
isSigner: false,
|
|
2549
|
+
isWritable: false,
|
|
2550
|
+
});
|
|
2551
|
+
|
|
2552
|
+
spotMarketAccountMap.set(QUOTE_SPOT_MARKET_INDEX, {
|
|
2553
|
+
pubkey: this.getSpotMarketAccount(QUOTE_SPOT_MARKET_INDEX).pubkey,
|
|
2554
|
+
isSigner: false,
|
|
2555
|
+
isWritable: true,
|
|
2556
|
+
});
|
|
2557
|
+
|
|
2558
|
+
const remainingAccounts = [
|
|
2559
|
+
...oracleAccountMap.values(),
|
|
2560
|
+
...spotMarketAccountMap.values(),
|
|
2561
|
+
...perpMarketAccountMap.values(),
|
|
2562
|
+
];
|
|
2563
|
+
|
|
2564
|
+
return await this.program.instruction.settlePnl(marketIndex, {
|
|
2565
|
+
accounts: {
|
|
2566
|
+
state: await this.getStatePublicKey(),
|
|
2567
|
+
authority: this.wallet.publicKey,
|
|
2568
|
+
user: settleeUserAccountPublicKey,
|
|
2569
|
+
},
|
|
2570
|
+
remainingAccounts: remainingAccounts,
|
|
2571
|
+
});
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
public async settleExpiredPosition(
|
|
2575
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
2576
|
+
settleeUserAccount: UserAccount,
|
|
2577
|
+
marketIndex: number
|
|
2578
|
+
): Promise<TransactionSignature> {
|
|
2579
|
+
const { txSig } = await this.txSender.send(
|
|
2580
|
+
wrapInTx(
|
|
2581
|
+
await this.getSettleExpiredPositionIx(
|
|
2582
|
+
settleeUserAccountPublicKey,
|
|
2583
|
+
settleeUserAccount,
|
|
2584
|
+
marketIndex
|
|
2585
|
+
)
|
|
2586
|
+
),
|
|
2587
|
+
[],
|
|
2588
|
+
this.opts
|
|
2589
|
+
);
|
|
2590
|
+
return txSig;
|
|
2591
|
+
}
|
|
2592
|
+
|
|
2593
|
+
public async getSettleExpiredPositionIx(
|
|
2594
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
2595
|
+
settleeUserAccount: UserAccount,
|
|
2596
|
+
marketIndex: number
|
|
2597
|
+
): Promise<TransactionInstruction> {
|
|
2598
|
+
const marketAccountMap = new Map<number, AccountMeta>();
|
|
2599
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
2600
|
+
const spotMarketAccountMap = new Map<number, AccountMeta>();
|
|
2601
|
+
for (const position of settleeUserAccount.perpPositions) {
|
|
2602
|
+
if (!positionIsAvailable(position)) {
|
|
2603
|
+
const market = this.getPerpMarketAccount(position.marketIndex);
|
|
2604
|
+
marketAccountMap.set(position.marketIndex, {
|
|
2605
|
+
pubkey: market.pubkey,
|
|
2606
|
+
isWritable: false,
|
|
2607
|
+
isSigner: false,
|
|
2608
|
+
});
|
|
2609
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
2610
|
+
pubkey: market.amm.oracle,
|
|
2611
|
+
isWritable: false,
|
|
2612
|
+
isSigner: false,
|
|
2613
|
+
});
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
for (const userBankBalance of settleeUserAccount.spotPositions) {
|
|
2618
|
+
if (!userBankBalance.balance.eq(ZERO)) {
|
|
2619
|
+
const bankAccount = this.getSpotMarketAccount(
|
|
2620
|
+
userBankBalance.marketIndex
|
|
2621
|
+
);
|
|
2622
|
+
spotMarketAccountMap.set(userBankBalance.marketIndex, {
|
|
2623
|
+
pubkey: bankAccount.pubkey,
|
|
2624
|
+
isSigner: false,
|
|
1091
2625
|
isWritable: false,
|
|
1092
|
-
isSigner: false,
|
|
1093
2626
|
});
|
|
2627
|
+
if (bankAccount.marketIndex !== 0) {
|
|
2628
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
2629
|
+
pubkey: bankAccount.oracle,
|
|
2630
|
+
isSigner: false,
|
|
2631
|
+
isWritable: false,
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
1094
2634
|
}
|
|
1095
2635
|
}
|
|
1096
|
-
const remainingAccounts = oracleAccountInfos.concat(
|
|
1097
|
-
bankAccountInfos.concat(marketAccountInfos)
|
|
1098
|
-
);
|
|
1099
2636
|
|
|
1100
|
-
const
|
|
1101
|
-
|
|
2637
|
+
const marketAccount = this.getPerpMarketAccount(marketIndex);
|
|
2638
|
+
marketAccountMap.set(marketIndex, {
|
|
2639
|
+
pubkey: marketAccount.pubkey,
|
|
2640
|
+
isSigner: false,
|
|
2641
|
+
isWritable: true,
|
|
2642
|
+
});
|
|
2643
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
2644
|
+
pubkey: marketAccount.amm.oracle,
|
|
2645
|
+
isSigner: false,
|
|
2646
|
+
isWritable: false,
|
|
2647
|
+
});
|
|
2648
|
+
|
|
2649
|
+
spotMarketAccountMap.set(QUOTE_SPOT_MARKET_INDEX, {
|
|
2650
|
+
pubkey: this.getSpotMarketAccount(QUOTE_SPOT_MARKET_INDEX).pubkey,
|
|
2651
|
+
isSigner: false,
|
|
2652
|
+
isWritable: true,
|
|
2653
|
+
});
|
|
2654
|
+
|
|
2655
|
+
const remainingAccounts = [
|
|
2656
|
+
...oracleAccountMap.values(),
|
|
2657
|
+
...spotMarketAccountMap.values(),
|
|
2658
|
+
...marketAccountMap.values(),
|
|
2659
|
+
];
|
|
2660
|
+
|
|
2661
|
+
return await this.program.instruction.settleExpiredPosition(marketIndex, {
|
|
1102
2662
|
accounts: {
|
|
1103
2663
|
state: await this.getStatePublicKey(),
|
|
1104
|
-
filler: fillerPublicKey,
|
|
1105
|
-
user: userAccountPublicKey,
|
|
1106
2664
|
authority: this.wallet.publicKey,
|
|
2665
|
+
user: settleeUserAccountPublicKey,
|
|
1107
2666
|
},
|
|
1108
|
-
remainingAccounts,
|
|
2667
|
+
remainingAccounts: remainingAccounts,
|
|
1109
2668
|
});
|
|
1110
2669
|
}
|
|
1111
2670
|
|
|
1112
|
-
public async
|
|
1113
|
-
|
|
1114
|
-
|
|
2671
|
+
public async liquidatePerp(
|
|
2672
|
+
userAccountPublicKey: PublicKey,
|
|
2673
|
+
userAccount: UserAccount,
|
|
2674
|
+
marketIndex: number,
|
|
2675
|
+
maxBaseAssetAmount: BN
|
|
1115
2676
|
): Promise<TransactionSignature> {
|
|
1116
2677
|
const { txSig, slot } = await this.txSender.send(
|
|
1117
|
-
wrapInTx(
|
|
2678
|
+
wrapInTx(
|
|
2679
|
+
await this.getLiquidatePerpIx(
|
|
2680
|
+
userAccountPublicKey,
|
|
2681
|
+
userAccount,
|
|
2682
|
+
marketIndex,
|
|
2683
|
+
maxBaseAssetAmount
|
|
2684
|
+
)
|
|
2685
|
+
),
|
|
1118
2686
|
[],
|
|
1119
2687
|
this.opts
|
|
1120
2688
|
);
|
|
1121
|
-
this.marketLastSlotCache.set(
|
|
2689
|
+
this.marketLastSlotCache.set(marketIndex, slot);
|
|
1122
2690
|
return txSig;
|
|
1123
2691
|
}
|
|
1124
2692
|
|
|
1125
|
-
public async
|
|
1126
|
-
|
|
1127
|
-
|
|
2693
|
+
public async getLiquidatePerpIx(
|
|
2694
|
+
userAccountPublicKey: PublicKey,
|
|
2695
|
+
userAccount: UserAccount,
|
|
2696
|
+
marketIndex: number,
|
|
2697
|
+
maxBaseAssetAmount: BN
|
|
1128
2698
|
): Promise<TransactionInstruction> {
|
|
1129
|
-
const
|
|
2699
|
+
const userStatsPublicKey = getUserStatsAccountPublicKey(
|
|
2700
|
+
this.program.programId,
|
|
2701
|
+
userAccount.authority
|
|
2702
|
+
);
|
|
1130
2703
|
|
|
1131
|
-
const
|
|
1132
|
-
|
|
1133
|
-
|
|
2704
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2705
|
+
const liquidatorStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
2706
|
+
|
|
2707
|
+
const remainingAccounts = this.getRemainingAccountsWithCounterparty({
|
|
2708
|
+
writablePerpMarketIndex: marketIndex,
|
|
2709
|
+
counterPartyUserAccount: userAccount,
|
|
1134
2710
|
});
|
|
1135
2711
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
2712
|
+
return await this.program.instruction.liquidatePerp(
|
|
2713
|
+
marketIndex,
|
|
2714
|
+
maxBaseAssetAmount,
|
|
2715
|
+
{
|
|
2716
|
+
accounts: {
|
|
2717
|
+
state: await this.getStatePublicKey(),
|
|
2718
|
+
authority: this.wallet.publicKey,
|
|
2719
|
+
user: userAccountPublicKey,
|
|
2720
|
+
userStats: userStatsPublicKey,
|
|
2721
|
+
liquidator: liquidatorPublicKey,
|
|
2722
|
+
liquidatorStats: liquidatorStatsPublicKey,
|
|
2723
|
+
},
|
|
2724
|
+
remainingAccounts: remainingAccounts,
|
|
2725
|
+
}
|
|
2726
|
+
);
|
|
2727
|
+
}
|
|
1145
2728
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
2729
|
+
public async liquidateBorrow(
|
|
2730
|
+
userAccountPublicKey: PublicKey,
|
|
2731
|
+
userAccount: UserAccount,
|
|
2732
|
+
assetMarketIndex: number,
|
|
2733
|
+
liabilityMarketIndex: number,
|
|
2734
|
+
maxLiabilityTransfer: BN
|
|
2735
|
+
): Promise<TransactionSignature> {
|
|
2736
|
+
const { txSig } = await this.txSender.send(
|
|
2737
|
+
wrapInTx(
|
|
2738
|
+
await this.getLiquidateBorrowIx(
|
|
2739
|
+
userAccountPublicKey,
|
|
2740
|
+
userAccount,
|
|
2741
|
+
assetMarketIndex,
|
|
2742
|
+
liabilityMarketIndex,
|
|
2743
|
+
maxLiabilityTransfer
|
|
2744
|
+
)
|
|
2745
|
+
),
|
|
2746
|
+
[],
|
|
2747
|
+
this.opts
|
|
2748
|
+
);
|
|
2749
|
+
return txSig;
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
public async getLiquidateBorrowIx(
|
|
2753
|
+
userAccountPublicKey: PublicKey,
|
|
2754
|
+
userAccount: UserAccount,
|
|
2755
|
+
assetMarketIndex: number,
|
|
2756
|
+
liabilityMarketIndex: number,
|
|
2757
|
+
maxLiabilityTransfer: BN
|
|
2758
|
+
): Promise<TransactionInstruction> {
|
|
2759
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2760
|
+
|
|
2761
|
+
const remainingAccounts = this.getRemainingAccountsWithCounterparty({
|
|
2762
|
+
counterPartyUserAccount: userAccount,
|
|
2763
|
+
writableSpotMarketIndexes: [liabilityMarketIndex, assetMarketIndex],
|
|
2764
|
+
});
|
|
2765
|
+
|
|
2766
|
+
return await this.program.instruction.liquidateBorrow(
|
|
2767
|
+
assetMarketIndex,
|
|
2768
|
+
liabilityMarketIndex,
|
|
2769
|
+
maxLiabilityTransfer,
|
|
1149
2770
|
{
|
|
1150
2771
|
accounts: {
|
|
1151
2772
|
state: await this.getStatePublicKey(),
|
|
2773
|
+
authority: this.wallet.publicKey,
|
|
1152
2774
|
user: userAccountPublicKey,
|
|
2775
|
+
liquidator: liquidatorPublicKey,
|
|
2776
|
+
},
|
|
2777
|
+
remainingAccounts: remainingAccounts,
|
|
2778
|
+
}
|
|
2779
|
+
);
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
public async liquidateBorrowForPerpPnl(
|
|
2783
|
+
userAccountPublicKey: PublicKey,
|
|
2784
|
+
userAccount: UserAccount,
|
|
2785
|
+
perpMarketIndex: number,
|
|
2786
|
+
liabilityMarketIndex: number,
|
|
2787
|
+
maxLiabilityTransfer: BN
|
|
2788
|
+
): Promise<TransactionSignature> {
|
|
2789
|
+
const { txSig, slot } = await this.txSender.send(
|
|
2790
|
+
wrapInTx(
|
|
2791
|
+
await this.getLiquidateBorrowForPerpPnlIx(
|
|
2792
|
+
userAccountPublicKey,
|
|
2793
|
+
userAccount,
|
|
2794
|
+
perpMarketIndex,
|
|
2795
|
+
liabilityMarketIndex,
|
|
2796
|
+
maxLiabilityTransfer
|
|
2797
|
+
)
|
|
2798
|
+
),
|
|
2799
|
+
[],
|
|
2800
|
+
this.opts
|
|
2801
|
+
);
|
|
2802
|
+
this.marketLastSlotCache.set(perpMarketIndex, slot);
|
|
2803
|
+
return txSig;
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
public async getLiquidateBorrowForPerpPnlIx(
|
|
2807
|
+
userAccountPublicKey: PublicKey,
|
|
2808
|
+
userAccount: UserAccount,
|
|
2809
|
+
perpMarketIndex: number,
|
|
2810
|
+
liabilityMarketIndex: number,
|
|
2811
|
+
maxLiabilityTransfer: BN
|
|
2812
|
+
): Promise<TransactionInstruction> {
|
|
2813
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2814
|
+
|
|
2815
|
+
const remainingAccounts = this.getRemainingAccountsWithCounterparty({
|
|
2816
|
+
counterPartyUserAccount: userAccount,
|
|
2817
|
+
writablePerpMarketIndex: perpMarketIndex,
|
|
2818
|
+
writableSpotMarketIndexes: [liabilityMarketIndex],
|
|
2819
|
+
});
|
|
2820
|
+
|
|
2821
|
+
return await this.program.instruction.liquidateBorrowForPerpPnl(
|
|
2822
|
+
perpMarketIndex,
|
|
2823
|
+
liabilityMarketIndex,
|
|
2824
|
+
maxLiabilityTransfer,
|
|
2825
|
+
{
|
|
2826
|
+
accounts: {
|
|
2827
|
+
state: await this.getStatePublicKey(),
|
|
1153
2828
|
authority: this.wallet.publicKey,
|
|
2829
|
+
user: userAccountPublicKey,
|
|
2830
|
+
liquidator: liquidatorPublicKey,
|
|
1154
2831
|
},
|
|
1155
|
-
remainingAccounts,
|
|
2832
|
+
remainingAccounts: remainingAccounts,
|
|
1156
2833
|
}
|
|
1157
2834
|
);
|
|
1158
2835
|
}
|
|
1159
2836
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
2837
|
+
public async liquidatePerpPnlForDeposit(
|
|
2838
|
+
userAccountPublicKey: PublicKey,
|
|
2839
|
+
userAccount: UserAccount,
|
|
2840
|
+
perpMarketIndex: number,
|
|
2841
|
+
assetMarketIndex: number,
|
|
2842
|
+
maxPnlTransfer: BN
|
|
2843
|
+
): Promise<TransactionSignature> {
|
|
2844
|
+
const { txSig, slot } = await this.txSender.send(
|
|
2845
|
+
wrapInTx(
|
|
2846
|
+
await this.getLiquidatePerpPnlForDepositIx(
|
|
2847
|
+
userAccountPublicKey,
|
|
2848
|
+
userAccount,
|
|
2849
|
+
perpMarketIndex,
|
|
2850
|
+
assetMarketIndex,
|
|
2851
|
+
maxPnlTransfer
|
|
2852
|
+
)
|
|
2853
|
+
),
|
|
2854
|
+
[],
|
|
2855
|
+
this.opts
|
|
2856
|
+
);
|
|
2857
|
+
this.marketLastSlotCache.set(perpMarketIndex, slot);
|
|
2858
|
+
return txSig;
|
|
2859
|
+
}
|
|
1170
2860
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
2861
|
+
public async getLiquidatePerpPnlForDepositIx(
|
|
2862
|
+
userAccountPublicKey: PublicKey,
|
|
2863
|
+
userAccount: UserAccount,
|
|
2864
|
+
perpMarketIndex: number,
|
|
2865
|
+
assetMarketIndex: number,
|
|
2866
|
+
maxPnlTransfer: BN
|
|
2867
|
+
): Promise<TransactionInstruction> {
|
|
2868
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2869
|
+
|
|
2870
|
+
const remainingAccounts = this.getRemainingAccountsWithCounterparty({
|
|
2871
|
+
counterPartyUserAccount: userAccount,
|
|
2872
|
+
writablePerpMarketIndex: perpMarketIndex,
|
|
2873
|
+
writableSpotMarketIndexes: [assetMarketIndex],
|
|
2874
|
+
});
|
|
2875
|
+
|
|
2876
|
+
return await this.program.instruction.liquidatePerpPnlForDeposit(
|
|
2877
|
+
perpMarketIndex,
|
|
2878
|
+
assetMarketIndex,
|
|
2879
|
+
maxPnlTransfer,
|
|
2880
|
+
{
|
|
2881
|
+
accounts: {
|
|
2882
|
+
state: await this.getStatePublicKey(),
|
|
2883
|
+
authority: this.wallet.publicKey,
|
|
2884
|
+
user: userAccountPublicKey,
|
|
2885
|
+
liquidator: liquidatorPublicKey,
|
|
2886
|
+
},
|
|
2887
|
+
remainingAccounts: remainingAccounts,
|
|
2888
|
+
}
|
|
1180
2889
|
);
|
|
1181
2890
|
}
|
|
1182
2891
|
|
|
1183
|
-
public async
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
}[],
|
|
1188
|
-
marketIndex: BN
|
|
2892
|
+
public async resolvePerpBankruptcy(
|
|
2893
|
+
userAccountPublicKey: PublicKey,
|
|
2894
|
+
userAccount: UserAccount,
|
|
2895
|
+
marketIndex: number
|
|
1189
2896
|
): Promise<TransactionSignature> {
|
|
1190
|
-
const
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
settleeUserAccount,
|
|
2897
|
+
const { txSig } = await this.txSender.send(
|
|
2898
|
+
wrapInTx(
|
|
2899
|
+
await this.getResolvePerpBankruptcyIx(
|
|
2900
|
+
userAccountPublicKey,
|
|
2901
|
+
userAccount,
|
|
1196
2902
|
marketIndex
|
|
1197
2903
|
)
|
|
1198
|
-
)
|
|
1199
|
-
|
|
2904
|
+
),
|
|
2905
|
+
[],
|
|
2906
|
+
this.opts
|
|
2907
|
+
);
|
|
2908
|
+
return txSig;
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2911
|
+
public async getResolvePerpBankruptcyIx(
|
|
2912
|
+
userAccountPublicKey: PublicKey,
|
|
2913
|
+
userAccount: UserAccount,
|
|
2914
|
+
marketIndex: number
|
|
2915
|
+
): Promise<TransactionInstruction> {
|
|
2916
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1200
2917
|
|
|
1201
|
-
const
|
|
2918
|
+
const remainingAccounts = this.getRemainingAccountsWithCounterparty({
|
|
2919
|
+
writablePerpMarketIndex: marketIndex,
|
|
2920
|
+
writableSpotMarketIndexes: [QUOTE_SPOT_MARKET_INDEX],
|
|
2921
|
+
counterPartyUserAccount: userAccount,
|
|
2922
|
+
});
|
|
1202
2923
|
|
|
1203
|
-
const
|
|
1204
|
-
|
|
2924
|
+
const spotMarket = this.getSpotMarketAccount(marketIndex);
|
|
2925
|
+
|
|
2926
|
+
return await this.program.instruction.resolvePerpBankruptcy(
|
|
2927
|
+
QUOTE_SPOT_MARKET_INDEX,
|
|
2928
|
+
marketIndex,
|
|
2929
|
+
{
|
|
2930
|
+
accounts: {
|
|
2931
|
+
state: await this.getStatePublicKey(),
|
|
2932
|
+
authority: this.wallet.publicKey,
|
|
2933
|
+
user: userAccountPublicKey,
|
|
2934
|
+
liquidator: liquidatorPublicKey,
|
|
2935
|
+
spotMarketVault: spotMarket.vault,
|
|
2936
|
+
insuranceFundVault: spotMarket.insuranceFundVault,
|
|
2937
|
+
clearingHouseSigner: this.getSignerPublicKey(),
|
|
2938
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
2939
|
+
},
|
|
2940
|
+
remainingAccounts: remainingAccounts,
|
|
2941
|
+
}
|
|
2942
|
+
);
|
|
1205
2943
|
}
|
|
1206
2944
|
|
|
1207
|
-
public async
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
marketIndex:
|
|
2945
|
+
public async resolveBorrowBankruptcy(
|
|
2946
|
+
userAccountPublicKey: PublicKey,
|
|
2947
|
+
userAccount: UserAccount,
|
|
2948
|
+
marketIndex: number
|
|
1211
2949
|
): Promise<TransactionSignature> {
|
|
1212
2950
|
const { txSig } = await this.txSender.send(
|
|
1213
2951
|
wrapInTx(
|
|
1214
|
-
await this.
|
|
1215
|
-
|
|
1216
|
-
|
|
2952
|
+
await this.getResolveBorrowBankruptcyIx(
|
|
2953
|
+
userAccountPublicKey,
|
|
2954
|
+
userAccount,
|
|
1217
2955
|
marketIndex
|
|
1218
2956
|
)
|
|
1219
2957
|
),
|
|
@@ -1223,153 +2961,185 @@ export class ClearingHouse {
|
|
|
1223
2961
|
return txSig;
|
|
1224
2962
|
}
|
|
1225
2963
|
|
|
1226
|
-
public async
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
marketIndex:
|
|
2964
|
+
public async getResolveBorrowBankruptcyIx(
|
|
2965
|
+
userAccountPublicKey: PublicKey,
|
|
2966
|
+
userAccount: UserAccount,
|
|
2967
|
+
marketIndex: number
|
|
1230
2968
|
): Promise<TransactionInstruction> {
|
|
1231
|
-
const
|
|
2969
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2970
|
+
|
|
2971
|
+
const remainingAccounts = this.getRemainingAccountsWithCounterparty({
|
|
2972
|
+
writableSpotMarketIndexes: [marketIndex],
|
|
2973
|
+
counterPartyUserAccount: userAccount,
|
|
2974
|
+
});
|
|
2975
|
+
|
|
2976
|
+
const spotMarket = this.getSpotMarketAccount(marketIndex);
|
|
2977
|
+
|
|
2978
|
+
return await this.program.instruction.resolveBorrowBankruptcy(marketIndex, {
|
|
2979
|
+
accounts: {
|
|
2980
|
+
state: await this.getStatePublicKey(),
|
|
2981
|
+
authority: this.wallet.publicKey,
|
|
2982
|
+
user: userAccountPublicKey,
|
|
2983
|
+
liquidator: liquidatorPublicKey,
|
|
2984
|
+
spotMarketVault: spotMarket.vault,
|
|
2985
|
+
insuranceFundVault: spotMarket.insuranceFundVault,
|
|
2986
|
+
clearingHouseSigner: this.getSignerPublicKey(),
|
|
2987
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
2988
|
+
},
|
|
2989
|
+
remainingAccounts: remainingAccounts,
|
|
2990
|
+
});
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
getRemainingAccountsWithCounterparty(params: {
|
|
2994
|
+
counterPartyUserAccount: UserAccount;
|
|
2995
|
+
writablePerpMarketIndex?: number;
|
|
2996
|
+
writableSpotMarketIndexes?: number[];
|
|
2997
|
+
}): AccountMeta[] {
|
|
2998
|
+
const counterPartyUserAccount = params.counterPartyUserAccount;
|
|
2999
|
+
|
|
1232
3000
|
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
1233
|
-
const
|
|
1234
|
-
|
|
3001
|
+
const spotMarketAccountMap = new Map<number, AccountMeta>();
|
|
3002
|
+
const marketAccountMap = new Map<number, AccountMeta>();
|
|
3003
|
+
for (const spotPosition of counterPartyUserAccount.spotPositions) {
|
|
3004
|
+
if (!isSpotPositionAvailable(spotPosition)) {
|
|
3005
|
+
const spotMarket = this.getSpotMarketAccount(spotPosition.marketIndex);
|
|
3006
|
+
spotMarketAccountMap.set(spotPosition.marketIndex, {
|
|
3007
|
+
pubkey: spotMarket.pubkey,
|
|
3008
|
+
isSigner: false,
|
|
3009
|
+
isWritable: false,
|
|
3010
|
+
});
|
|
3011
|
+
|
|
3012
|
+
if (!spotMarket.oracle.equals(PublicKey.default)) {
|
|
3013
|
+
oracleAccountMap.set(spotMarket.oracle.toString(), {
|
|
3014
|
+
pubkey: spotMarket.oracle,
|
|
3015
|
+
isSigner: false,
|
|
3016
|
+
isWritable: false,
|
|
3017
|
+
});
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
for (const position of counterPartyUserAccount.perpPositions) {
|
|
1235
3022
|
if (!positionIsAvailable(position)) {
|
|
1236
|
-
const market = this.
|
|
1237
|
-
marketAccountMap.set(position.marketIndex
|
|
3023
|
+
const market = this.getPerpMarketAccount(position.marketIndex);
|
|
3024
|
+
marketAccountMap.set(position.marketIndex, {
|
|
1238
3025
|
pubkey: market.pubkey,
|
|
1239
|
-
isWritable:
|
|
3026
|
+
isWritable: false,
|
|
3027
|
+
isSigner: false,
|
|
3028
|
+
});
|
|
3029
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
3030
|
+
pubkey: market.amm.oracle,
|
|
3031
|
+
isWritable: false,
|
|
3032
|
+
isSigner: false,
|
|
3033
|
+
});
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
|
|
3037
|
+
const userAccountAndSlot = this.getUserAccountAndSlot();
|
|
3038
|
+
if (!userAccountAndSlot) {
|
|
3039
|
+
throw Error(
|
|
3040
|
+
'No user account found. Most likely user account does not exist or failed to fetch account'
|
|
3041
|
+
);
|
|
3042
|
+
}
|
|
3043
|
+
const { data: userAccount, slot: lastUserPositionsSlot } =
|
|
3044
|
+
userAccountAndSlot;
|
|
3045
|
+
|
|
3046
|
+
for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
|
|
3047
|
+
// if cache has more recent slot than user positions account slot, add market to remaining accounts
|
|
3048
|
+
// otherwise remove from slot
|
|
3049
|
+
if (slot > lastUserPositionsSlot) {
|
|
3050
|
+
const marketAccount = this.getPerpMarketAccount(marketIndexNum);
|
|
3051
|
+
marketAccountMap.set(marketIndexNum, {
|
|
3052
|
+
pubkey: marketAccount.pubkey,
|
|
1240
3053
|
isSigner: false,
|
|
1241
|
-
});
|
|
1242
|
-
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1243
|
-
pubkey: market.amm.oracle,
|
|
1244
3054
|
isWritable: false,
|
|
3055
|
+
});
|
|
3056
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
3057
|
+
pubkey: marketAccount.amm.oracle,
|
|
1245
3058
|
isSigner: false,
|
|
3059
|
+
isWritable: false,
|
|
1246
3060
|
});
|
|
3061
|
+
} else {
|
|
3062
|
+
this.marketLastSlotCache.delete(marketIndexNum);
|
|
1247
3063
|
}
|
|
1248
3064
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
pubkey: bankAccount.pubkey,
|
|
3065
|
+
for (const spotPosition of userAccount.spotPositions) {
|
|
3066
|
+
if (!isSpotPositionAvailable(spotPosition)) {
|
|
3067
|
+
const spotMarket = this.getSpotMarketAccount(spotPosition.marketIndex);
|
|
3068
|
+
spotMarketAccountMap.set(spotPosition.marketIndex, {
|
|
3069
|
+
pubkey: spotMarket.pubkey,
|
|
1255
3070
|
isSigner: false,
|
|
1256
3071
|
isWritable: false,
|
|
1257
3072
|
});
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
3073
|
+
|
|
3074
|
+
if (!spotMarket.oracle.equals(PublicKey.default)) {
|
|
3075
|
+
oracleAccountMap.set(spotMarket.oracle.toString(), {
|
|
3076
|
+
pubkey: spotMarket.oracle,
|
|
1261
3077
|
isSigner: false,
|
|
1262
3078
|
isWritable: false,
|
|
1263
3079
|
});
|
|
1264
3080
|
}
|
|
1265
3081
|
}
|
|
1266
3082
|
}
|
|
1267
|
-
|
|
1268
|
-
const marketAccount = this.getMarketAccount(marketIndex.toNumber());
|
|
1269
|
-
marketAccountMap.set(marketIndex.toNumber(), {
|
|
1270
|
-
pubkey: marketAccount.pubkey,
|
|
1271
|
-
isSigner: false,
|
|
1272
|
-
isWritable: true,
|
|
1273
|
-
});
|
|
1274
|
-
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
1275
|
-
pubkey: marketAccount.amm.oracle,
|
|
1276
|
-
isSigner: false,
|
|
1277
|
-
isWritable: false,
|
|
1278
|
-
});
|
|
1279
|
-
|
|
1280
|
-
bankAccountMap.set(QUOTE_ASSET_BANK_INDEX.toNumber(), {
|
|
1281
|
-
pubkey: this.getBankAccount(QUOTE_ASSET_BANK_INDEX).pubkey,
|
|
1282
|
-
isSigner: false,
|
|
1283
|
-
isWritable: true,
|
|
1284
|
-
});
|
|
1285
|
-
|
|
1286
|
-
const remainingAccounts = [
|
|
1287
|
-
...oracleAccountMap.values(),
|
|
1288
|
-
...bankAccountMap.values(),
|
|
1289
|
-
...marketAccountMap.values(),
|
|
1290
|
-
];
|
|
1291
|
-
|
|
1292
|
-
return await this.program.instruction.settlePnl(marketIndex, {
|
|
1293
|
-
accounts: {
|
|
1294
|
-
state: await this.getStatePublicKey(),
|
|
1295
|
-
authority: this.wallet.publicKey,
|
|
1296
|
-
user: settleeUserAccountPublicKey,
|
|
1297
|
-
},
|
|
1298
|
-
remainingAccounts: remainingAccounts,
|
|
1299
|
-
});
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
public async liquidate(
|
|
1303
|
-
liquidateeUserAccountPublicKey: PublicKey
|
|
1304
|
-
): Promise<TransactionSignature> {
|
|
1305
|
-
const { txSig } = await this.txSender.send(
|
|
1306
|
-
wrapInTx(await this.getLiquidateIx(liquidateeUserAccountPublicKey)),
|
|
1307
|
-
[],
|
|
1308
|
-
this.opts
|
|
1309
|
-
);
|
|
1310
|
-
return txSig;
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
public async getLiquidateIx(
|
|
1314
|
-
liquidateeUserAccountPublicKey: PublicKey
|
|
1315
|
-
): Promise<TransactionInstruction> {
|
|
1316
|
-
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1317
|
-
const liquidateeUserAccount = (await this.program.account.user.fetch(
|
|
1318
|
-
liquidateeUserAccountPublicKey
|
|
1319
|
-
)) as UserAccount;
|
|
1320
|
-
|
|
1321
|
-
const bankAccountInfos = [
|
|
1322
|
-
{
|
|
1323
|
-
pubkey: this.getQuoteAssetBankAccount().pubkey,
|
|
1324
|
-
isSigner: false,
|
|
1325
|
-
isWritable: true,
|
|
1326
|
-
},
|
|
1327
|
-
];
|
|
1328
|
-
const marketAccountInfos = [];
|
|
1329
|
-
const oracleAccountInfos = [];
|
|
1330
|
-
for (const position of liquidateeUserAccount.positions) {
|
|
3083
|
+
for (const position of userAccount.perpPositions) {
|
|
1331
3084
|
if (!positionIsAvailable(position)) {
|
|
1332
|
-
const market = this.
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
);
|
|
1337
|
-
marketAccountInfos.push({
|
|
1338
|
-
pubkey: marketPublicKey,
|
|
1339
|
-
isWritable: true,
|
|
3085
|
+
const market = this.getPerpMarketAccount(position.marketIndex);
|
|
3086
|
+
marketAccountMap.set(position.marketIndex, {
|
|
3087
|
+
pubkey: market.pubkey,
|
|
3088
|
+
isWritable: false,
|
|
1340
3089
|
isSigner: false,
|
|
1341
3090
|
});
|
|
1342
|
-
|
|
3091
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1343
3092
|
pubkey: market.amm.oracle,
|
|
1344
3093
|
isWritable: false,
|
|
1345
3094
|
isSigner: false,
|
|
1346
3095
|
});
|
|
1347
3096
|
}
|
|
1348
3097
|
}
|
|
1349
|
-
const remainingAccounts = oracleAccountInfos.concat(
|
|
1350
|
-
bankAccountInfos.concat(marketAccountInfos)
|
|
1351
|
-
);
|
|
1352
3098
|
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
3099
|
+
if (params.writablePerpMarketIndex !== undefined) {
|
|
3100
|
+
const market = this.getPerpMarketAccount(params.writablePerpMarketIndex);
|
|
3101
|
+
marketAccountMap.set(market.marketIndex, {
|
|
3102
|
+
pubkey: market.pubkey,
|
|
3103
|
+
isSigner: false,
|
|
3104
|
+
isWritable: true,
|
|
3105
|
+
});
|
|
3106
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
3107
|
+
pubkey: market.amm.oracle,
|
|
3108
|
+
isSigner: false,
|
|
3109
|
+
isWritable: false,
|
|
3110
|
+
});
|
|
3111
|
+
}
|
|
3112
|
+
|
|
3113
|
+
if (params.writableSpotMarketIndexes !== undefined) {
|
|
3114
|
+
for (const writableSpotMarketIndex of params.writableSpotMarketIndexes) {
|
|
3115
|
+
const spotMarketAccount = this.getSpotMarketAccount(
|
|
3116
|
+
writableSpotMarketIndex
|
|
3117
|
+
);
|
|
3118
|
+
spotMarketAccountMap.set(spotMarketAccount.marketIndex, {
|
|
3119
|
+
pubkey: spotMarketAccount.pubkey,
|
|
3120
|
+
isSigner: false,
|
|
3121
|
+
isWritable: true,
|
|
3122
|
+
});
|
|
3123
|
+
if (!spotMarketAccount.oracle.equals(PublicKey.default)) {
|
|
3124
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
3125
|
+
pubkey: spotMarketAccount.oracle,
|
|
3126
|
+
isSigner: false,
|
|
3127
|
+
isWritable: false,
|
|
3128
|
+
});
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
return [
|
|
3134
|
+
...oracleAccountMap.values(),
|
|
3135
|
+
...spotMarketAccountMap.values(),
|
|
3136
|
+
...marketAccountMap.values(),
|
|
3137
|
+
];
|
|
1368
3138
|
}
|
|
1369
3139
|
|
|
1370
3140
|
public async updateFundingRate(
|
|
1371
3141
|
oracle: PublicKey,
|
|
1372
|
-
marketIndex:
|
|
3142
|
+
marketIndex: number
|
|
1373
3143
|
): Promise<TransactionSignature> {
|
|
1374
3144
|
const { txSig } = await this.txSender.send(
|
|
1375
3145
|
wrapInTx(await this.getUpdateFundingRateIx(oracle, marketIndex)),
|
|
@@ -1381,7 +3151,7 @@ export class ClearingHouse {
|
|
|
1381
3151
|
|
|
1382
3152
|
public async getUpdateFundingRateIx(
|
|
1383
3153
|
oracle: PublicKey,
|
|
1384
|
-
marketIndex:
|
|
3154
|
+
marketIndex: number
|
|
1385
3155
|
): Promise<TransactionInstruction> {
|
|
1386
3156
|
return await this.program.instruction.updateFundingRate(marketIndex, {
|
|
1387
3157
|
accounts: {
|
|
@@ -1410,7 +3180,7 @@ export class ClearingHouse {
|
|
|
1410
3180
|
userAccount
|
|
1411
3181
|
)) as UserAccount;
|
|
1412
3182
|
|
|
1413
|
-
const userPositions = user.
|
|
3183
|
+
const userPositions = user.perpPositions;
|
|
1414
3184
|
|
|
1415
3185
|
const remainingAccounts = [];
|
|
1416
3186
|
for (const position of userPositions) {
|
|
@@ -1440,10 +3210,246 @@ export class ClearingHouse {
|
|
|
1440
3210
|
this.eventEmitter.emit(eventName, data);
|
|
1441
3211
|
}
|
|
1442
3212
|
|
|
1443
|
-
public getOracleDataForMarket(marketIndex:
|
|
1444
|
-
const oracleKey = this.
|
|
3213
|
+
public getOracleDataForMarket(marketIndex: number): OraclePriceData {
|
|
3214
|
+
const oracleKey = this.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
3215
|
+
const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
|
|
3216
|
+
|
|
3217
|
+
return oracleData;
|
|
3218
|
+
}
|
|
3219
|
+
|
|
3220
|
+
public getOracleDataForSpotMarket(marketIndex: number): OraclePriceData {
|
|
3221
|
+
const oracleKey = this.getSpotMarketAccount(marketIndex).oracle;
|
|
1445
3222
|
const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
|
|
1446
3223
|
|
|
1447
3224
|
return oracleData;
|
|
1448
3225
|
}
|
|
3226
|
+
|
|
3227
|
+
public async initializeInsuranceFundStake(
|
|
3228
|
+
marketIndex: number
|
|
3229
|
+
): Promise<TransactionSignature> {
|
|
3230
|
+
const { txSig } = await this.txSender.send(
|
|
3231
|
+
wrapInTx(await this.getInitializeInsuranceFundStakeIx(marketIndex)),
|
|
3232
|
+
[],
|
|
3233
|
+
this.opts
|
|
3234
|
+
);
|
|
3235
|
+
return txSig;
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3238
|
+
public async getInitializeInsuranceFundStakeIx(
|
|
3239
|
+
marketIndex: number
|
|
3240
|
+
): Promise<TransactionInstruction> {
|
|
3241
|
+
const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
|
|
3242
|
+
this.program.programId,
|
|
3243
|
+
this.wallet.publicKey,
|
|
3244
|
+
marketIndex
|
|
3245
|
+
);
|
|
3246
|
+
|
|
3247
|
+
return await this.program.instruction.initializeInsuranceFundStake(
|
|
3248
|
+
marketIndex,
|
|
3249
|
+
{
|
|
3250
|
+
accounts: {
|
|
3251
|
+
insuranceFundStake: ifStakeAccountPublicKey,
|
|
3252
|
+
spotMarket: this.getSpotMarketAccount(marketIndex).pubkey,
|
|
3253
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
3254
|
+
authority: this.wallet.publicKey,
|
|
3255
|
+
payer: this.wallet.publicKey,
|
|
3256
|
+
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
3257
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
3258
|
+
state: await this.getStatePublicKey(),
|
|
3259
|
+
},
|
|
3260
|
+
}
|
|
3261
|
+
);
|
|
3262
|
+
}
|
|
3263
|
+
|
|
3264
|
+
public async addInsuranceFundStake(
|
|
3265
|
+
marketIndex: number,
|
|
3266
|
+
amount: BN,
|
|
3267
|
+
collateralAccountPublicKey: PublicKey
|
|
3268
|
+
): Promise<TransactionSignature> {
|
|
3269
|
+
const spotMarket = this.getSpotMarketAccount(marketIndex);
|
|
3270
|
+
const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
|
|
3271
|
+
this.program.programId,
|
|
3272
|
+
this.wallet.publicKey,
|
|
3273
|
+
marketIndex
|
|
3274
|
+
);
|
|
3275
|
+
|
|
3276
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
3277
|
+
writableSpotMarketIndex: marketIndex,
|
|
3278
|
+
});
|
|
3279
|
+
|
|
3280
|
+
return await this.program.rpc.addInsuranceFundStake(marketIndex, amount, {
|
|
3281
|
+
accounts: {
|
|
3282
|
+
state: await this.getStatePublicKey(),
|
|
3283
|
+
spotMarket: spotMarket.pubkey,
|
|
3284
|
+
insuranceFundStake: ifStakeAccountPublicKey,
|
|
3285
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
3286
|
+
authority: this.wallet.publicKey,
|
|
3287
|
+
insuranceFundVault: spotMarket.insuranceFundVault,
|
|
3288
|
+
userTokenAccount: collateralAccountPublicKey,
|
|
3289
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
3290
|
+
},
|
|
3291
|
+
remainingAccounts,
|
|
3292
|
+
});
|
|
3293
|
+
}
|
|
3294
|
+
|
|
3295
|
+
public async requestRemoveInsuranceFundStake(
|
|
3296
|
+
marketIndex: number,
|
|
3297
|
+
amount: BN
|
|
3298
|
+
): Promise<TransactionSignature> {
|
|
3299
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
3300
|
+
const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
|
|
3301
|
+
this.program.programId,
|
|
3302
|
+
this.wallet.publicKey,
|
|
3303
|
+
marketIndex
|
|
3304
|
+
);
|
|
3305
|
+
|
|
3306
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
3307
|
+
writableSpotMarketIndex: marketIndex,
|
|
3308
|
+
});
|
|
3309
|
+
|
|
3310
|
+
return await this.program.rpc.requestRemoveInsuranceFundStake(
|
|
3311
|
+
marketIndex,
|
|
3312
|
+
amount,
|
|
3313
|
+
{
|
|
3314
|
+
accounts: {
|
|
3315
|
+
state: await this.getStatePublicKey(),
|
|
3316
|
+
spotMarket: spotMarketAccount.pubkey,
|
|
3317
|
+
insuranceFundStake: ifStakeAccountPublicKey,
|
|
3318
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
3319
|
+
authority: this.wallet.publicKey,
|
|
3320
|
+
insuranceFundVault: spotMarketAccount.insuranceFundVault,
|
|
3321
|
+
// userTokenAccount: collateralAccountPublicKey,
|
|
3322
|
+
// tokenProgram: TOKEN_PROGRAM_ID,
|
|
3323
|
+
},
|
|
3324
|
+
remainingAccounts,
|
|
3325
|
+
}
|
|
3326
|
+
);
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3329
|
+
public async cancelRequestRemoveInsuranceFundStake(
|
|
3330
|
+
marketIndex: number
|
|
3331
|
+
): Promise<TransactionSignature> {
|
|
3332
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
3333
|
+
const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
|
|
3334
|
+
this.program.programId,
|
|
3335
|
+
this.wallet.publicKey,
|
|
3336
|
+
marketIndex
|
|
3337
|
+
);
|
|
3338
|
+
|
|
3339
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
3340
|
+
writableSpotMarketIndex: marketIndex,
|
|
3341
|
+
});
|
|
3342
|
+
|
|
3343
|
+
return await this.program.rpc.cancelRequestRemoveInsuranceFundStake(
|
|
3344
|
+
marketIndex,
|
|
3345
|
+
{
|
|
3346
|
+
accounts: {
|
|
3347
|
+
state: await this.getStatePublicKey(),
|
|
3348
|
+
spotMarket: spotMarketAccount.pubkey,
|
|
3349
|
+
insuranceFundStake: ifStakeAccountPublicKey,
|
|
3350
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
3351
|
+
authority: this.wallet.publicKey,
|
|
3352
|
+
insuranceFundVault: spotMarketAccount.insuranceFundVault,
|
|
3353
|
+
// userTokenAccount: collateralAccountPublicKey,
|
|
3354
|
+
// tokenProgram: TOKEN_PROGRAM_ID,
|
|
3355
|
+
},
|
|
3356
|
+
remainingAccounts,
|
|
3357
|
+
}
|
|
3358
|
+
);
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
public async removeInsuranceFundStake(
|
|
3362
|
+
marketIndex: number,
|
|
3363
|
+
collateralAccountPublicKey: PublicKey
|
|
3364
|
+
): Promise<TransactionSignature> {
|
|
3365
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
3366
|
+
const ifStakeAccountPublicKey = getInsuranceFundStakeAccountPublicKey(
|
|
3367
|
+
this.program.programId,
|
|
3368
|
+
this.wallet.publicKey,
|
|
3369
|
+
marketIndex
|
|
3370
|
+
);
|
|
3371
|
+
|
|
3372
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
3373
|
+
writableSpotMarketIndex: marketIndex,
|
|
3374
|
+
});
|
|
3375
|
+
|
|
3376
|
+
return await this.program.rpc.removeInsuranceFundStake(marketIndex, {
|
|
3377
|
+
accounts: {
|
|
3378
|
+
state: await this.getStatePublicKey(),
|
|
3379
|
+
spotMarket: spotMarketAccount.pubkey,
|
|
3380
|
+
insuranceFundStake: ifStakeAccountPublicKey,
|
|
3381
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
3382
|
+
authority: this.wallet.publicKey,
|
|
3383
|
+
insuranceFundVault: spotMarketAccount.insuranceFundVault,
|
|
3384
|
+
clearingHouseSigner: this.getSignerPublicKey(),
|
|
3385
|
+
userTokenAccount: collateralAccountPublicKey,
|
|
3386
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
3387
|
+
},
|
|
3388
|
+
remainingAccounts,
|
|
3389
|
+
});
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3392
|
+
public async settleRevenueToInsuranceFund(
|
|
3393
|
+
marketIndex: number
|
|
3394
|
+
): Promise<TransactionSignature> {
|
|
3395
|
+
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
3396
|
+
|
|
3397
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
3398
|
+
writableSpotMarketIndex: marketIndex,
|
|
3399
|
+
});
|
|
3400
|
+
|
|
3401
|
+
return await this.program.rpc.settleRevenueToInsuranceFund(marketIndex, {
|
|
3402
|
+
accounts: {
|
|
3403
|
+
state: await this.getStatePublicKey(),
|
|
3404
|
+
spotMarket: spotMarketAccount.pubkey,
|
|
3405
|
+
spotMarketVault: spotMarketAccount.vault,
|
|
3406
|
+
clearingHouseSigner: this.getSignerPublicKey(),
|
|
3407
|
+
insuranceFundVault: spotMarketAccount.insuranceFundVault,
|
|
3408
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
3409
|
+
},
|
|
3410
|
+
remainingAccounts,
|
|
3411
|
+
});
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3414
|
+
public async resolvePerpPnlDeficit(
|
|
3415
|
+
spotMarketIndex: number,
|
|
3416
|
+
perpMarketIndex: number
|
|
3417
|
+
): Promise<TransactionSignature> {
|
|
3418
|
+
const { txSig } = await this.txSender.send(
|
|
3419
|
+
wrapInTx(
|
|
3420
|
+
await this.getResolvePerpPnlDeficitIx(spotMarketIndex, perpMarketIndex)
|
|
3421
|
+
),
|
|
3422
|
+
[],
|
|
3423
|
+
this.opts
|
|
3424
|
+
);
|
|
3425
|
+
return txSig;
|
|
3426
|
+
}
|
|
3427
|
+
|
|
3428
|
+
public async getResolvePerpPnlDeficitIx(
|
|
3429
|
+
spotMarketIndex: number,
|
|
3430
|
+
perpMarketIndex: number
|
|
3431
|
+
): Promise<TransactionInstruction> {
|
|
3432
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
3433
|
+
writablePerpMarketIndex: perpMarketIndex,
|
|
3434
|
+
writableSpotMarketIndex: spotMarketIndex,
|
|
3435
|
+
});
|
|
3436
|
+
|
|
3437
|
+
const spotMarket = this.getSpotMarketAccount(spotMarketIndex);
|
|
3438
|
+
|
|
3439
|
+
return await this.program.instruction.resolvePerpPnlDeficit(
|
|
3440
|
+
spotMarketIndex,
|
|
3441
|
+
perpMarketIndex,
|
|
3442
|
+
{
|
|
3443
|
+
accounts: {
|
|
3444
|
+
state: await this.getStatePublicKey(),
|
|
3445
|
+
authority: this.wallet.publicKey,
|
|
3446
|
+
spotMarketVault: spotMarket.vault,
|
|
3447
|
+
insuranceFundVault: spotMarket.insuranceFundVault,
|
|
3448
|
+
clearingHouseSigner: this.getSignerPublicKey(),
|
|
3449
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
3450
|
+
},
|
|
3451
|
+
remainingAccounts: remainingAccounts,
|
|
3452
|
+
}
|
|
3453
|
+
);
|
|
3454
|
+
}
|
|
1449
3455
|
}
|