@drift-labs/sdk 0.2.0-master.2 → 0.2.0-master.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/accounts/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/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +14 -1
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/pda.d.ts +1 -0
- package/lib/addresses/pda.js +8 -1
- package/lib/admin.d.ts +9 -5
- package/lib/admin.js +52 -11
- package/lib/clearingHouse.d.ts +52 -23
- package/lib/clearingHouse.js +727 -197
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.d.ts +17 -17
- package/lib/clearingHouseUser.js +186 -101
- 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.js +1 -1
- package/lib/constants/banks.d.ts +2 -2
- package/lib/constants/banks.js +12 -4
- package/lib/constants/numericConstants.d.ts +5 -0
- package/lib/constants/numericConstants.js +8 -3
- package/lib/events/eventList.js +3 -0
- package/lib/events/types.d.ts +3 -1
- package/lib/events/types.js +2 -0
- package/lib/factory/bigNum.d.ts +1 -0
- package/lib/factory/bigNum.js +34 -10
- package/lib/idl/clearing_house.json +1609 -388
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +9 -3
- package/lib/index.js +13 -3
- package/lib/math/amm.d.ts +1 -0
- package/lib/math/amm.js +22 -38
- package/lib/math/auction.js +4 -1
- package/lib/math/bankBalance.d.ts +7 -1
- package/lib/math/bankBalance.js +77 -2
- package/lib/math/margin.d.ts +11 -0
- package/lib/math/margin.js +72 -0
- package/lib/math/market.d.ts +4 -1
- package/lib/math/market.js +35 -1
- package/lib/math/oracles.d.ts +3 -0
- package/lib/math/oracles.js +25 -5
- package/lib/math/orders.d.ts +5 -2
- package/lib/math/orders.js +53 -12
- package/lib/math/position.d.ts +8 -0
- package/lib/math/position.js +45 -12
- package/lib/math/trade.d.ts +1 -1
- package/lib/math/trade.js +7 -10
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +8 -96
- 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.js +9 -2
- package/lib/tx/utils.js +1 -1
- package/lib/types.d.ts +233 -26
- package/lib/types.js +64 -1
- 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 +3 -3
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +0 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +18 -0
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/marketAddresses.js +26 -0
- package/src/addresses/pda.ts +13 -0
- package/src/admin.ts +82 -15
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +1224 -319
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +311 -148
- package/src/clearingHouseUserStats.ts +75 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +1 -1
- package/src/constants/banks.js +42 -0
- package/src/constants/banks.ts +14 -4
- package/src/constants/markets.js +42 -0
- package/src/constants/numericConstants.js +41 -0
- package/src/constants/numericConstants.ts +14 -2
- package/src/events/eventList.js +77 -0
- package/src/events/eventList.ts +3 -0
- package/src/events/eventSubscriber.js +139 -0
- package/src/events/fetchLogs.js +50 -0
- package/src/events/pollingLogProvider.js +64 -0
- package/src/events/sort.js +44 -0
- package/src/events/txEventCache.js +71 -0
- package/src/events/types.ts +6 -0
- package/src/events/webSocketLogProvider.js +41 -0
- package/src/examples/makeTradeExample.js +80 -0
- package/src/factory/bigNum.js +390 -0
- package/src/factory/bigNum.ts +42 -13
- package/src/factory/oracleClient.js +20 -0
- package/src/idl/clearing_house.json +1609 -388
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.ts +9 -3
- package/src/math/amm.ts +54 -55
- package/src/math/auction.js +42 -0
- package/src/math/auction.ts +5 -1
- package/src/math/bankBalance.ts +148 -2
- package/src/math/conversion.js +11 -0
- package/src/math/funding.js +248 -0
- package/src/math/margin.ts +124 -0
- package/src/math/market.ts +66 -1
- package/src/math/oracles.js +26 -0
- package/src/math/oracles.ts +42 -5
- package/src/math/orders.ts +112 -13
- package/src/math/position.ts +64 -9
- package/src/math/repeg.js +128 -0
- package/src/math/state.js +15 -0
- package/src/math/trade.js +253 -0
- package/src/math/trade.ts +23 -25
- package/src/math/utils.js +0 -1
- package/src/oracles/oracleClientCache.js +19 -0
- package/src/oracles/pythClient.js +46 -0
- package/src/oracles/quoteAssetOracleClient.js +32 -0
- package/src/oracles/switchboardClient.js +69 -0
- package/src/oracles/types.js +2 -0
- package/src/orderParams.js +20 -0
- package/src/orderParams.ts +20 -141
- package/src/slot/SlotSubscriber.js +39 -0
- package/src/slot/SlotSubscriber.ts +11 -1
- package/src/token/index.js +38 -0
- package/src/tokenFaucet.js +189 -0
- package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +82 -70
- package/src/tx/retryTxSender.ts +11 -3
- package/src/tx/types.js +2 -0
- package/src/tx/utils.js +17 -0
- package/src/tx/utils.ts +1 -1
- package/src/types.ts +236 -27
- package/src/userName.js +20 -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/src/wallet.js +35 -0
- package/tests/bn/test.ts +10 -0
- package/lib/orders.d.ts +0 -8
- package/lib/orders.js +0 -142
- package/src/orders.ts +0 -251
- package/src/util/computeUnits.js.map +0 -1
package/lib/clearingHouse.js
CHANGED
|
@@ -29,6 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
29
29
|
exports.ClearingHouse = void 0;
|
|
30
30
|
const anchor_1 = require("@project-serum/anchor");
|
|
31
31
|
const spl_token_1 = require("@solana/spl-token");
|
|
32
|
+
const types_1 = require("./types");
|
|
32
33
|
const anchor = __importStar(require("@project-serum/anchor"));
|
|
33
34
|
const clearing_house_json_1 = __importDefault(require("./idl/clearing_house.json"));
|
|
34
35
|
const web3_js_1 = require("@solana/web3.js");
|
|
@@ -42,8 +43,9 @@ const pollingClearingHouseAccountSubscriber_1 = require("./accounts/pollingClear
|
|
|
42
43
|
const webSocketClearingHouseAccountSubscriber_1 = require("./accounts/webSocketClearingHouseAccountSubscriber");
|
|
43
44
|
const retryTxSender_1 = require("./tx/retryTxSender");
|
|
44
45
|
const clearingHouseUser_1 = require("./clearingHouseUser");
|
|
45
|
-
const orderParams_1 = require("./orderParams");
|
|
46
46
|
const config_1 = require("./config");
|
|
47
|
+
const banks_1 = require("./constants/banks");
|
|
48
|
+
const clearingHouseUserStats_1 = require("./clearingHouseUserStats");
|
|
47
49
|
/**
|
|
48
50
|
* # ClearingHouse
|
|
49
51
|
* This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
|
|
@@ -71,6 +73,13 @@ class ClearingHouse {
|
|
|
71
73
|
type: 'websocket',
|
|
72
74
|
};
|
|
73
75
|
this.createUsers(userIds, this.userAccountSubscriptionConfig);
|
|
76
|
+
if (config.userStats) {
|
|
77
|
+
this.userStats = new clearingHouseUserStats_1.ClearingHouseUserStats({
|
|
78
|
+
clearingHouse: this,
|
|
79
|
+
userStatsAccountPublicKey: (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.wallet.publicKey),
|
|
80
|
+
accountSubscription: this.userAccountSubscriptionConfig,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
74
83
|
let marketIndexes = config.marketIndexes;
|
|
75
84
|
let bankIndexes = config.bankIndexes;
|
|
76
85
|
let oracleInfos = config.oracleInfos;
|
|
@@ -111,6 +120,9 @@ class ClearingHouse {
|
|
|
111
120
|
}
|
|
112
121
|
async subscribe() {
|
|
113
122
|
const subscribePromises = this.subscribeUsers().concat(this.accountSubscriber.subscribe());
|
|
123
|
+
if (this.userStats !== undefined) {
|
|
124
|
+
subscribePromises.concat(this.userStats.subscribe());
|
|
125
|
+
}
|
|
114
126
|
this.isSubscribed = (await Promise.all(subscribePromises)).reduce((success, prevSuccess) => success && prevSuccess);
|
|
115
127
|
return this.isSubscribed;
|
|
116
128
|
}
|
|
@@ -127,6 +139,9 @@ class ClearingHouse {
|
|
|
127
139
|
}
|
|
128
140
|
async unsubscribe() {
|
|
129
141
|
const unsubscribePromises = this.unsubscribeUsers().concat(this.accountSubscriber.unsubscribe());
|
|
142
|
+
if (this.userStats !== undefined) {
|
|
143
|
+
unsubscribePromises.concat(this.userStats.unsubscribe());
|
|
144
|
+
}
|
|
130
145
|
await Promise.all(unsubscribePromises);
|
|
131
146
|
this.isSubscribed = false;
|
|
132
147
|
}
|
|
@@ -187,6 +202,7 @@ class ClearingHouse {
|
|
|
187
202
|
await Promise.all(this.subscribeUsers());
|
|
188
203
|
}
|
|
189
204
|
this.activeUserId = activeUserId;
|
|
205
|
+
this.userStatsAccountPublicKey = undefined;
|
|
190
206
|
}
|
|
191
207
|
async switchActiveUser(userId) {
|
|
192
208
|
this.activeUserId = userId;
|
|
@@ -199,27 +215,59 @@ class ClearingHouse {
|
|
|
199
215
|
await user.subscribe();
|
|
200
216
|
this.users.set(userId, user);
|
|
201
217
|
}
|
|
202
|
-
async initializeUserAccount(userId = 0, name = userName_1.DEFAULT_USER_NAME) {
|
|
203
|
-
const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
|
|
204
|
-
const tx = new web3_js_1.Transaction()
|
|
218
|
+
async initializeUserAccount(userId = 0, name = userName_1.DEFAULT_USER_NAME, referrerInfo) {
|
|
219
|
+
const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name, referrerInfo);
|
|
220
|
+
const tx = new web3_js_1.Transaction();
|
|
221
|
+
if (userId === 0) {
|
|
222
|
+
// not the safest assumption, can explicitly check if user stats account exists if it causes problems
|
|
223
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
224
|
+
}
|
|
225
|
+
tx.add(initializeUserAccountIx);
|
|
205
226
|
const { txSig } = await this.txSender.send(tx, [], this.opts);
|
|
206
227
|
return [txSig, userAccountPublicKey];
|
|
207
228
|
}
|
|
208
|
-
async getInitializeUserInstructions(userId = 0, name = userName_1.DEFAULT_USER_NAME) {
|
|
229
|
+
async getInitializeUserInstructions(userId = 0, name = userName_1.DEFAULT_USER_NAME, referrerInfo) {
|
|
209
230
|
const userAccountPublicKey = await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.wallet.publicKey, userId);
|
|
231
|
+
const remainingAccounts = new Array();
|
|
232
|
+
if (referrerInfo !== undefined) {
|
|
233
|
+
remainingAccounts.push({
|
|
234
|
+
pubkey: referrerInfo.referrer,
|
|
235
|
+
isWritable: true,
|
|
236
|
+
isSigner: false,
|
|
237
|
+
});
|
|
238
|
+
remainingAccounts.push({
|
|
239
|
+
pubkey: referrerInfo.referrerStats,
|
|
240
|
+
isWritable: true,
|
|
241
|
+
isSigner: false,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
210
244
|
const nameBuffer = (0, userName_1.encodeName)(name);
|
|
211
245
|
const initializeUserAccountIx = await this.program.instruction.initializeUser(userId, nameBuffer, {
|
|
212
246
|
accounts: {
|
|
213
247
|
user: userAccountPublicKey,
|
|
248
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
214
249
|
authority: this.wallet.publicKey,
|
|
215
250
|
payer: this.wallet.publicKey,
|
|
216
251
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
217
252
|
systemProgram: anchor.web3.SystemProgram.programId,
|
|
218
253
|
state: await this.getStatePublicKey(),
|
|
219
254
|
},
|
|
255
|
+
remainingAccounts,
|
|
220
256
|
});
|
|
221
257
|
return [userAccountPublicKey, initializeUserAccountIx];
|
|
222
258
|
}
|
|
259
|
+
async getInitializeUserStatsIx() {
|
|
260
|
+
return await this.program.instruction.initializeUserStats({
|
|
261
|
+
accounts: {
|
|
262
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
263
|
+
authority: this.wallet.publicKey,
|
|
264
|
+
payer: this.wallet.publicKey,
|
|
265
|
+
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
266
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
267
|
+
state: await this.getStatePublicKey(),
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
}
|
|
223
271
|
getUser(userId) {
|
|
224
272
|
userId = userId !== null && userId !== void 0 ? userId : this.activeUserId;
|
|
225
273
|
if (!this.users.has(userId)) {
|
|
@@ -230,6 +278,16 @@ class ClearingHouse {
|
|
|
230
278
|
getUsers() {
|
|
231
279
|
return [...this.users.values()];
|
|
232
280
|
}
|
|
281
|
+
getUserStats() {
|
|
282
|
+
return this.userStats;
|
|
283
|
+
}
|
|
284
|
+
getUserStatsAccountPublicKey() {
|
|
285
|
+
if (this.userStatsAccountPublicKey) {
|
|
286
|
+
return this.userStatsAccountPublicKey;
|
|
287
|
+
}
|
|
288
|
+
this.userStatsAccountPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.wallet.publicKey);
|
|
289
|
+
return this.userStatsAccountPublicKey;
|
|
290
|
+
}
|
|
233
291
|
async getUserAccountPublicKey() {
|
|
234
292
|
return this.getUser().userAccountPublicKey;
|
|
235
293
|
}
|
|
@@ -284,8 +342,7 @@ class ClearingHouse {
|
|
|
284
342
|
marketAccountMap.set(marketIndexNum, {
|
|
285
343
|
pubkey: marketAccount.pubkey,
|
|
286
344
|
isSigner: false,
|
|
287
|
-
|
|
288
|
-
isWritable: true,
|
|
345
|
+
isWritable: false,
|
|
289
346
|
});
|
|
290
347
|
oracleAccountMap.set(marketAccount.pubkey.toString(), {
|
|
291
348
|
pubkey: marketAccount.amm.oracle,
|
|
@@ -294,6 +351,19 @@ class ClearingHouse {
|
|
|
294
351
|
});
|
|
295
352
|
}
|
|
296
353
|
}
|
|
354
|
+
if (params.readableMarketIndex) {
|
|
355
|
+
const marketAccount = this.getMarketAccount(params.readableMarketIndex.toNumber());
|
|
356
|
+
marketAccountMap.set(params.readableMarketIndex.toNumber(), {
|
|
357
|
+
pubkey: marketAccount.pubkey,
|
|
358
|
+
isSigner: false,
|
|
359
|
+
isWritable: true,
|
|
360
|
+
});
|
|
361
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
362
|
+
pubkey: marketAccount.amm.oracle,
|
|
363
|
+
isSigner: false,
|
|
364
|
+
isWritable: false,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
297
367
|
if (params.writableMarketIndex) {
|
|
298
368
|
const marketAccount = this.getMarketAccount(params.writableMarketIndex.toNumber());
|
|
299
369
|
marketAccountMap.set(params.writableMarketIndex.toNumber(), {
|
|
@@ -355,9 +425,27 @@ class ClearingHouse {
|
|
|
355
425
|
return (_a = this.getUserAccount()) === null || _a === void 0 ? void 0 : _a.orders.find((order) => order.userOrderId === userOrderId);
|
|
356
426
|
}
|
|
357
427
|
async deposit(amount, bankIndex, collateralAccountPublicKey, userId, reduceOnly = false) {
|
|
428
|
+
const tx = new web3_js_1.Transaction();
|
|
429
|
+
const additionalSigners = [];
|
|
430
|
+
const bank = this.getBankAccount(bankIndex);
|
|
431
|
+
const isSolBank = bank.mint.equals(banks_1.WRAPPED_SOL_MINT);
|
|
432
|
+
const authority = this.wallet.publicKey;
|
|
433
|
+
const createWSOLTokenAccount = isSolBank && collateralAccountPublicKey.equals(authority);
|
|
434
|
+
if (createWSOLTokenAccount) {
|
|
435
|
+
const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount);
|
|
436
|
+
collateralAccountPublicKey = pubkey;
|
|
437
|
+
ixs.forEach((ix) => {
|
|
438
|
+
tx.add(ix);
|
|
439
|
+
});
|
|
440
|
+
signers.forEach((signer) => additionalSigners.push(signer));
|
|
441
|
+
}
|
|
358
442
|
const depositCollateralIx = await this.getDepositInstruction(amount, bankIndex, collateralAccountPublicKey, userId, reduceOnly, true);
|
|
359
|
-
|
|
360
|
-
|
|
443
|
+
tx.add(depositCollateralIx);
|
|
444
|
+
// Close the wrapped sol account at the end of the transaction
|
|
445
|
+
if (createWSOLTokenAccount) {
|
|
446
|
+
tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, collateralAccountPublicKey, authority, authority, []));
|
|
447
|
+
}
|
|
448
|
+
const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
|
|
361
449
|
return txSig;
|
|
362
450
|
}
|
|
363
451
|
async getDepositInstruction(amount, bankIndex, userTokenAccount, userId, reduceOnly = false, userInitialized = true) {
|
|
@@ -371,13 +459,19 @@ class ClearingHouse {
|
|
|
371
459
|
});
|
|
372
460
|
}
|
|
373
461
|
else {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
462
|
+
const bankAccount = this.getBankAccount(bankIndex);
|
|
463
|
+
if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
464
|
+
remainingAccounts.push({
|
|
465
|
+
pubkey: bankAccount.oracle,
|
|
377
466
|
isSigner: false,
|
|
378
|
-
isWritable:
|
|
379
|
-
}
|
|
380
|
-
|
|
467
|
+
isWritable: false,
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
remainingAccounts.push({
|
|
471
|
+
pubkey: bankAccount.pubkey,
|
|
472
|
+
isSigner: false,
|
|
473
|
+
isWritable: true,
|
|
474
|
+
});
|
|
381
475
|
}
|
|
382
476
|
const bank = this.getBankAccount(bankIndex);
|
|
383
477
|
return await this.program.instruction.deposit(bankIndex, amount, reduceOnly, {
|
|
@@ -386,6 +480,7 @@ class ClearingHouse {
|
|
|
386
480
|
bank: bank.pubkey,
|
|
387
481
|
bankVault: bank.vault,
|
|
388
482
|
user: userAccountPublicKey,
|
|
483
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
389
484
|
userTokenAccount: userTokenAccount,
|
|
390
485
|
authority: this.wallet.publicKey,
|
|
391
486
|
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
@@ -393,40 +488,132 @@ class ClearingHouse {
|
|
|
393
488
|
remainingAccounts,
|
|
394
489
|
});
|
|
395
490
|
}
|
|
491
|
+
async checkIfAccountExists(account) {
|
|
492
|
+
try {
|
|
493
|
+
const accountInfo = await this.connection.getAccountInfo(account);
|
|
494
|
+
return accountInfo && true;
|
|
495
|
+
}
|
|
496
|
+
catch (e) {
|
|
497
|
+
// Doesn't already exist
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
async getSolWithdrawalIxs(bankIndex, amount) {
|
|
502
|
+
const result = {
|
|
503
|
+
ixs: [],
|
|
504
|
+
signers: [],
|
|
505
|
+
pubkey: web3_js_1.PublicKey.default,
|
|
506
|
+
};
|
|
507
|
+
// Create a temporary wrapped SOL account to store the SOL that we're withdrawing
|
|
508
|
+
const authority = this.wallet.publicKey;
|
|
509
|
+
const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount);
|
|
510
|
+
result.pubkey = pubkey;
|
|
511
|
+
ixs.forEach((ix) => {
|
|
512
|
+
result.ixs.push(ix);
|
|
513
|
+
});
|
|
514
|
+
signers.forEach((ix) => {
|
|
515
|
+
result.signers.push(ix);
|
|
516
|
+
});
|
|
517
|
+
const withdrawIx = await this.getWithdrawIx(amount, bankIndex, pubkey, true);
|
|
518
|
+
result.ixs.push(withdrawIx);
|
|
519
|
+
result.ixs.push(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, pubkey, authority, authority, []));
|
|
520
|
+
return result;
|
|
521
|
+
}
|
|
522
|
+
async getWrappedSolAccountCreationIxs(amount) {
|
|
523
|
+
const wrappedSolAccount = new web3_js_1.Keypair();
|
|
524
|
+
const result = {
|
|
525
|
+
ixs: [],
|
|
526
|
+
signers: [],
|
|
527
|
+
pubkey: wrappedSolAccount.publicKey,
|
|
528
|
+
};
|
|
529
|
+
const rentSpaceLamports = new anchor_1.BN(web3_js_1.LAMPORTS_PER_SOL / 100);
|
|
530
|
+
const depositAmountLamports = amount.add(rentSpaceLamports);
|
|
531
|
+
const authority = this.wallet.publicKey;
|
|
532
|
+
result.ixs.push(web3_js_1.SystemProgram.createAccount({
|
|
533
|
+
fromPubkey: authority,
|
|
534
|
+
newAccountPubkey: wrappedSolAccount.publicKey,
|
|
535
|
+
lamports: depositAmountLamports.toNumber(),
|
|
536
|
+
space: 165,
|
|
537
|
+
programId: spl_token_1.TOKEN_PROGRAM_ID,
|
|
538
|
+
}));
|
|
539
|
+
result.ixs.push(spl_token_1.Token.createInitAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, banks_1.WRAPPED_SOL_MINT, wrappedSolAccount.publicKey, authority));
|
|
540
|
+
result.signers.push(wrappedSolAccount);
|
|
541
|
+
return result;
|
|
542
|
+
}
|
|
396
543
|
/**
|
|
397
544
|
* Creates the Clearing House User account for a user, and deposits some initial collateral
|
|
398
|
-
* @param userId
|
|
399
|
-
* @param name
|
|
400
545
|
* @param amount
|
|
401
546
|
* @param userTokenAccount
|
|
547
|
+
* @param bankIndex
|
|
548
|
+
* @param userId
|
|
549
|
+
* @param name
|
|
402
550
|
* @param fromUserId
|
|
403
551
|
* @returns
|
|
404
552
|
*/
|
|
405
|
-
async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, bankIndex = new anchor_1.BN(0), userId = 0, name = userName_1.DEFAULT_USER_NAME, fromUserId) {
|
|
406
|
-
const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
|
|
553
|
+
async initializeUserAccountAndDepositCollateral(amount, userTokenAccount, bankIndex = new anchor_1.BN(0), userId = 0, name = userName_1.DEFAULT_USER_NAME, fromUserId, referrerInfo) {
|
|
554
|
+
const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name, referrerInfo);
|
|
555
|
+
const additionalSigners = [];
|
|
556
|
+
const bank = this.getBankAccount(bankIndex);
|
|
557
|
+
const isSolBank = bank.mint.equals(banks_1.WRAPPED_SOL_MINT);
|
|
558
|
+
const tx = new web3_js_1.Transaction();
|
|
559
|
+
const authority = this.wallet.publicKey;
|
|
560
|
+
const createWSOLTokenAccount = isSolBank && userTokenAccount.equals(authority);
|
|
561
|
+
if (createWSOLTokenAccount) {
|
|
562
|
+
const { ixs: startIxs, signers, pubkey, } = await this.getWrappedSolAccountCreationIxs(amount);
|
|
563
|
+
userTokenAccount = pubkey;
|
|
564
|
+
startIxs.forEach((ix) => {
|
|
565
|
+
tx.add(ix);
|
|
566
|
+
});
|
|
567
|
+
signers.forEach((signer) => additionalSigners.push(signer));
|
|
568
|
+
}
|
|
407
569
|
const depositCollateralIx = fromUserId != null
|
|
408
570
|
? await this.getTransferDepositIx(amount, bankIndex, fromUserId, userId)
|
|
409
571
|
: await this.getDepositInstruction(amount, bankIndex, userTokenAccount, userId, false, false);
|
|
410
|
-
|
|
411
|
-
.add(
|
|
412
|
-
|
|
413
|
-
|
|
572
|
+
if (userId === 0) {
|
|
573
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
574
|
+
}
|
|
575
|
+
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
576
|
+
// Close the wrapped sol account at the end of the transaction
|
|
577
|
+
if (createWSOLTokenAccount) {
|
|
578
|
+
tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, userTokenAccount, authority, authority, []));
|
|
579
|
+
}
|
|
580
|
+
const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
|
|
414
581
|
return [txSig, userAccountPublicKey];
|
|
415
582
|
}
|
|
416
|
-
async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME,
|
|
417
|
-
const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await
|
|
418
|
-
const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
|
|
419
|
-
const depositCollateralIx = await this.getDepositInstruction(amount,
|
|
420
|
-
const tx = new web3_js_1.Transaction()
|
|
421
|
-
|
|
422
|
-
.add(
|
|
423
|
-
|
|
424
|
-
|
|
583
|
+
async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME, bankIndex, tokenFaucet, amount, referrerInfo) {
|
|
584
|
+
const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await tokenFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
|
|
585
|
+
const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name, referrerInfo);
|
|
586
|
+
const depositCollateralIx = await this.getDepositInstruction(amount, bankIndex, associateTokenPublicKey, userId, false, false);
|
|
587
|
+
const tx = new web3_js_1.Transaction().add(createAssociatedAccountIx).add(mintToIx);
|
|
588
|
+
if (userId === 0) {
|
|
589
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
590
|
+
}
|
|
591
|
+
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
425
592
|
const txSig = await this.program.provider.sendAndConfirm(tx, []);
|
|
426
593
|
return [txSig, userAccountPublicKey];
|
|
427
594
|
}
|
|
428
595
|
async withdraw(amount, bankIndex, userTokenAccount, reduceOnly = false) {
|
|
429
|
-
const
|
|
596
|
+
const tx = new web3_js_1.Transaction();
|
|
597
|
+
const additionalSigners = [];
|
|
598
|
+
const bank = this.getBankAccount(bankIndex);
|
|
599
|
+
const isSolBank = bank.mint.equals(banks_1.WRAPPED_SOL_MINT);
|
|
600
|
+
const authority = this.wallet.publicKey;
|
|
601
|
+
const createWSOLTokenAccount = isSolBank && userTokenAccount.equals(authority);
|
|
602
|
+
if (createWSOLTokenAccount) {
|
|
603
|
+
const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount);
|
|
604
|
+
userTokenAccount = pubkey;
|
|
605
|
+
ixs.forEach((ix) => {
|
|
606
|
+
tx.add(ix);
|
|
607
|
+
});
|
|
608
|
+
signers.forEach((signer) => additionalSigners.push(signer));
|
|
609
|
+
}
|
|
610
|
+
const withdrawCollateral = await this.getWithdrawIx(amount, bank.bankIndex, userTokenAccount, reduceOnly);
|
|
611
|
+
tx.add(withdrawCollateral);
|
|
612
|
+
// Close the wrapped sol account at the end of the transaction
|
|
613
|
+
if (createWSOLTokenAccount) {
|
|
614
|
+
tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, userTokenAccount, authority, authority, []));
|
|
615
|
+
}
|
|
616
|
+
const { txSig } = await this.txSender.send(tx, additionalSigners, this.opts);
|
|
430
617
|
return txSig;
|
|
431
618
|
}
|
|
432
619
|
async getWithdrawIx(amount, bankIndex, userTokenAccount, reduceOnly = false) {
|
|
@@ -442,6 +629,7 @@ class ClearingHouse {
|
|
|
442
629
|
bankVault: bank.vault,
|
|
443
630
|
bankVaultAuthority: bank.vaultAuthority,
|
|
444
631
|
user: userAccountPublicKey,
|
|
632
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
445
633
|
userTokenAccount: userTokenAccount,
|
|
446
634
|
authority: this.wallet.publicKey,
|
|
447
635
|
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
|
|
@@ -464,6 +652,7 @@ class ClearingHouse {
|
|
|
464
652
|
authority: this.wallet.publicKey,
|
|
465
653
|
fromUser,
|
|
466
654
|
toUser,
|
|
655
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
467
656
|
state: await this.getStatePublicKey(),
|
|
468
657
|
},
|
|
469
658
|
remainingAccounts,
|
|
@@ -481,44 +670,113 @@ class ClearingHouse {
|
|
|
481
670
|
},
|
|
482
671
|
});
|
|
483
672
|
}
|
|
484
|
-
async
|
|
485
|
-
|
|
673
|
+
async settleLP(settleeUserAccountPublicKey, marketIndex) {
|
|
674
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.settleLPIx(settleeUserAccountPublicKey, marketIndex)), [], this.opts);
|
|
675
|
+
return txSig;
|
|
486
676
|
}
|
|
487
|
-
async
|
|
488
|
-
const
|
|
489
|
-
|
|
677
|
+
async settleLPIx(settleeUserAccountPublicKey, marketIndex) {
|
|
678
|
+
const settleeUserAccount = (await this.program.account.user.fetch(settleeUserAccountPublicKey));
|
|
679
|
+
const userPositions = settleeUserAccount.positions;
|
|
680
|
+
const remainingAccounts = [];
|
|
681
|
+
let foundMarket = false;
|
|
682
|
+
for (const position of userPositions) {
|
|
683
|
+
if (!(0, position_1.positionIsAvailable)(position)) {
|
|
684
|
+
const marketPublicKey = await (0, pda_1.getMarketPublicKey)(this.program.programId, position.marketIndex);
|
|
685
|
+
remainingAccounts.push({
|
|
686
|
+
pubkey: marketPublicKey,
|
|
687
|
+
isWritable: true,
|
|
688
|
+
isSigner: false,
|
|
689
|
+
});
|
|
690
|
+
if (marketIndex.eq(position.marketIndex)) {
|
|
691
|
+
foundMarket = true;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
if (!foundMarket) {
|
|
696
|
+
console.log('Warning: lp is not in the market specified -- tx will likely fail');
|
|
697
|
+
}
|
|
698
|
+
return this.program.instruction.settleLp(marketIndex, {
|
|
699
|
+
accounts: {
|
|
700
|
+
state: await this.getStatePublicKey(),
|
|
701
|
+
user: settleeUserAccountPublicKey,
|
|
702
|
+
},
|
|
703
|
+
remainingAccounts: remainingAccounts,
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
async removeLiquidity(marketIndex, sharesToBurn) {
|
|
707
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getRemoveLiquidityIx(marketIndex, sharesToBurn)), [], this.opts);
|
|
490
708
|
return txSig;
|
|
491
709
|
}
|
|
492
|
-
async
|
|
710
|
+
async getRemoveLiquidityIx(marketIndex, sharesToBurn) {
|
|
493
711
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
494
|
-
const priceOracle = this.getMarketAccount(orderParams.marketIndex).amm
|
|
495
|
-
.oracle;
|
|
496
712
|
const remainingAccounts = this.getRemainingAccounts({
|
|
497
|
-
writableMarketIndex:
|
|
713
|
+
writableMarketIndex: marketIndex,
|
|
498
714
|
});
|
|
499
|
-
|
|
715
|
+
if (sharesToBurn == undefined) {
|
|
716
|
+
const userAccount = this.getUserAccount();
|
|
717
|
+
const marketPosition = userAccount.positions.filter((position) => position.marketIndex.eq(marketIndex))[0];
|
|
718
|
+
sharesToBurn = marketPosition.lpShares;
|
|
719
|
+
console.log('burning lp shares:', sharesToBurn.toString());
|
|
720
|
+
}
|
|
721
|
+
return this.program.instruction.removeLiquidity(sharesToBurn, marketIndex, {
|
|
500
722
|
accounts: {
|
|
501
723
|
state: await this.getStatePublicKey(),
|
|
502
724
|
user: userAccountPublicKey,
|
|
503
725
|
authority: this.wallet.publicKey,
|
|
504
|
-
oracle: priceOracle,
|
|
505
726
|
},
|
|
506
|
-
remainingAccounts,
|
|
727
|
+
remainingAccounts: remainingAccounts,
|
|
507
728
|
});
|
|
508
729
|
}
|
|
509
|
-
async
|
|
510
|
-
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.
|
|
730
|
+
async addLiquidity(amount, marketIndex) {
|
|
731
|
+
const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getAddLiquidityIx(amount, marketIndex)), [], this.opts);
|
|
732
|
+
this.marketLastSlotCache.set(marketIndex.toNumber(), slot);
|
|
511
733
|
return txSig;
|
|
512
734
|
}
|
|
513
|
-
async
|
|
514
|
-
const
|
|
515
|
-
|
|
735
|
+
async getAddLiquidityIx(amount, marketIndex) {
|
|
736
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
737
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
738
|
+
writableMarketIndex: marketIndex,
|
|
739
|
+
});
|
|
740
|
+
return this.program.instruction.addLiquidity(amount, marketIndex, {
|
|
741
|
+
accounts: {
|
|
742
|
+
state: await this.getStatePublicKey(),
|
|
743
|
+
user: userAccountPublicKey,
|
|
744
|
+
authority: this.wallet.publicKey,
|
|
745
|
+
},
|
|
746
|
+
remainingAccounts: remainingAccounts,
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
async openPosition(direction, amount, marketIndex, limitPrice) {
|
|
750
|
+
return await this.placeAndTake({
|
|
751
|
+
orderType: types_1.OrderType.MARKET,
|
|
752
|
+
marketIndex,
|
|
753
|
+
direction,
|
|
754
|
+
baseAssetAmount: amount,
|
|
755
|
+
price: limitPrice,
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
async placeOrder(orderParams) {
|
|
759
|
+
const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceOrderIx(orderParams)), [], this.opts);
|
|
760
|
+
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
761
|
+
return txSig;
|
|
762
|
+
}
|
|
763
|
+
getOrderParams(optionalOrderParams) {
|
|
764
|
+
return Object.assign({}, types_1.DefaultOrderParams, optionalOrderParams);
|
|
765
|
+
}
|
|
766
|
+
async getPlaceOrderIx(orderParams) {
|
|
767
|
+
orderParams = this.getOrderParams(orderParams);
|
|
768
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
769
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
770
|
+
readableMarketIndex: orderParams.marketIndex,
|
|
771
|
+
});
|
|
772
|
+
return await this.program.instruction.placeOrder(orderParams, {
|
|
516
773
|
accounts: {
|
|
517
774
|
state: await this.getStatePublicKey(),
|
|
518
|
-
filler: fillerPublicKey,
|
|
519
775
|
user: userAccountPublicKey,
|
|
776
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
520
777
|
authority: this.wallet.publicKey,
|
|
521
778
|
},
|
|
779
|
+
remainingAccounts,
|
|
522
780
|
});
|
|
523
781
|
}
|
|
524
782
|
async updateAMMs(marketIndexes) {
|
|
@@ -590,107 +848,92 @@ class ClearingHouse {
|
|
|
590
848
|
remainingAccounts,
|
|
591
849
|
});
|
|
592
850
|
}
|
|
593
|
-
async
|
|
594
|
-
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.
|
|
595
|
-
return txSig;
|
|
596
|
-
}
|
|
597
|
-
async getCancelAllOrdersIx(bestEffort) {
|
|
598
|
-
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
599
|
-
const remainingAccounts = this.getRemainingAccounts({});
|
|
600
|
-
for (const order of this.getUserAccount().orders) {
|
|
601
|
-
const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
|
|
602
|
-
remainingAccounts.push({
|
|
603
|
-
pubkey: oracle,
|
|
604
|
-
isWritable: false,
|
|
605
|
-
isSigner: false,
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
return await this.program.instruction.cancelAllOrders(bestEffort, {
|
|
609
|
-
accounts: {
|
|
610
|
-
state: await this.getStatePublicKey(),
|
|
611
|
-
user: userAccountPublicKey,
|
|
612
|
-
authority: this.wallet.publicKey,
|
|
613
|
-
},
|
|
614
|
-
remainingAccounts,
|
|
615
|
-
});
|
|
616
|
-
}
|
|
617
|
-
async cancelOrdersByMarketAndSide(bestEffort, marketIndexOnly, directionOnly) {
|
|
618
|
-
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getCancelOrdersByMarketAndSideIx(bestEffort, marketIndexOnly, directionOnly)), [], this.opts);
|
|
619
|
-
return txSig;
|
|
620
|
-
}
|
|
621
|
-
async getCancelOrdersByMarketAndSideIx(bestEffort, marketIndexOnly, directionOnly) {
|
|
622
|
-
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
623
|
-
const remainingAccounts = this.getRemainingAccounts({});
|
|
624
|
-
for (const order of this.getUserAccount().orders) {
|
|
625
|
-
const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
|
|
626
|
-
remainingAccounts.push({
|
|
627
|
-
pubkey: oracle,
|
|
628
|
-
isWritable: false,
|
|
629
|
-
isSigner: false,
|
|
630
|
-
});
|
|
631
|
-
}
|
|
632
|
-
return await this.program.instruction.cancelOrdersByMarketAndSide(bestEffort, marketIndexOnly, directionOnly, {
|
|
633
|
-
accounts: {
|
|
634
|
-
state: await this.getStatePublicKey(),
|
|
635
|
-
user: userAccountPublicKey,
|
|
636
|
-
authority: this.wallet.publicKey,
|
|
637
|
-
},
|
|
638
|
-
remainingAccounts,
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
|
-
async fillOrder(userAccountPublicKey, user, order, makerInfo) {
|
|
642
|
-
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getFillOrderIx(userAccountPublicKey, user, order, makerInfo)), [], this.opts);
|
|
851
|
+
async fillOrder(userAccountPublicKey, user, order, makerInfo, referrerInfo) {
|
|
852
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getFillOrderIx(userAccountPublicKey, user, order, makerInfo, referrerInfo)), [], this.opts);
|
|
643
853
|
return txSig;
|
|
644
854
|
}
|
|
645
|
-
async getFillOrderIx(userAccountPublicKey, userAccount, order, makerInfo) {
|
|
855
|
+
async getFillOrderIx(userAccountPublicKey, userAccount, order, makerInfo, referrerInfo) {
|
|
856
|
+
const userStatsPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, userAccount.authority);
|
|
646
857
|
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
647
|
-
const
|
|
858
|
+
const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
859
|
+
const marketIndex = order
|
|
860
|
+
? order.marketIndex
|
|
861
|
+
: userAccount.orders.find((order) => order.orderId.eq(userAccount.nextOrderId.sub(numericConstants_1.ONE))).marketIndex;
|
|
648
862
|
const marketAccount = this.getMarketAccount(marketIndex);
|
|
649
|
-
const
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
},
|
|
670
|
-
];
|
|
863
|
+
const oracleAccountMap = new Map();
|
|
864
|
+
const bankAccountMap = new Map();
|
|
865
|
+
const marketAccountMap = new Map();
|
|
866
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
867
|
+
if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
|
|
868
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
869
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
870
|
+
pubkey: bankAccount.pubkey,
|
|
871
|
+
isSigner: false,
|
|
872
|
+
isWritable: false,
|
|
873
|
+
});
|
|
874
|
+
if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
875
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
876
|
+
pubkey: bankAccount.oracle,
|
|
877
|
+
isSigner: false,
|
|
878
|
+
isWritable: false,
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
671
883
|
for (const position of userAccount.positions) {
|
|
672
884
|
if (!(0, position_1.positionIsAvailable)(position) &&
|
|
673
885
|
!position.marketIndex.eq(order.marketIndex)) {
|
|
674
886
|
const market = this.getMarketAccount(position.marketIndex);
|
|
675
|
-
|
|
887
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
676
888
|
pubkey: market.pubkey,
|
|
677
889
|
isWritable: false,
|
|
678
890
|
isSigner: false,
|
|
679
891
|
});
|
|
680
|
-
|
|
892
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
681
893
|
pubkey: market.amm.oracle,
|
|
682
894
|
isWritable: false,
|
|
683
895
|
isSigner: false,
|
|
684
896
|
});
|
|
685
897
|
}
|
|
686
898
|
}
|
|
687
|
-
|
|
899
|
+
marketAccountMap.set(marketIndex.toNumber(), {
|
|
900
|
+
pubkey: marketAccount.pubkey,
|
|
901
|
+
isWritable: true,
|
|
902
|
+
isSigner: false,
|
|
903
|
+
});
|
|
904
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
905
|
+
pubkey: marketAccount.amm.oracle,
|
|
906
|
+
isWritable: false,
|
|
907
|
+
isSigner: false,
|
|
908
|
+
});
|
|
909
|
+
const remainingAccounts = [
|
|
910
|
+
...oracleAccountMap.values(),
|
|
911
|
+
...bankAccountMap.values(),
|
|
912
|
+
...marketAccountMap.values(),
|
|
913
|
+
];
|
|
688
914
|
if (makerInfo) {
|
|
689
915
|
remainingAccounts.push({
|
|
690
916
|
pubkey: makerInfo.maker,
|
|
691
917
|
isWritable: true,
|
|
692
918
|
isSigner: false,
|
|
693
919
|
});
|
|
920
|
+
remainingAccounts.push({
|
|
921
|
+
pubkey: makerInfo.makerStats,
|
|
922
|
+
isWritable: true,
|
|
923
|
+
isSigner: false,
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
if (referrerInfo) {
|
|
927
|
+
remainingAccounts.push({
|
|
928
|
+
pubkey: referrerInfo.referrer,
|
|
929
|
+
isWritable: true,
|
|
930
|
+
isSigner: false,
|
|
931
|
+
});
|
|
932
|
+
remainingAccounts.push({
|
|
933
|
+
pubkey: referrerInfo.referrerStats,
|
|
934
|
+
isWritable: true,
|
|
935
|
+
isSigner: false,
|
|
936
|
+
});
|
|
694
937
|
}
|
|
695
938
|
const orderId = order.orderId;
|
|
696
939
|
const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
|
|
@@ -698,9 +941,10 @@ class ClearingHouse {
|
|
|
698
941
|
accounts: {
|
|
699
942
|
state: await this.getStatePublicKey(),
|
|
700
943
|
filler: fillerPublicKey,
|
|
944
|
+
fillerStats: fillerStatsPublicKey,
|
|
701
945
|
user: userAccountPublicKey,
|
|
946
|
+
userStats: userStatsPublicKey,
|
|
702
947
|
authority: this.wallet.publicKey,
|
|
703
|
-
oracle: oracle,
|
|
704
948
|
},
|
|
705
949
|
remainingAccounts,
|
|
706
950
|
});
|
|
@@ -713,44 +957,57 @@ class ClearingHouse {
|
|
|
713
957
|
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
714
958
|
const marketIndex = order.marketIndex;
|
|
715
959
|
const marketAccount = this.getMarketAccount(marketIndex);
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
];
|
|
960
|
+
const oracleAccountMap = new Map();
|
|
961
|
+
const bankAccountMap = new Map();
|
|
962
|
+
const marketAccountMap = new Map();
|
|
963
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
964
|
+
if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
|
|
965
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
966
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
967
|
+
pubkey: bankAccount.pubkey,
|
|
968
|
+
isSigner: false,
|
|
969
|
+
isWritable: false,
|
|
970
|
+
});
|
|
971
|
+
if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
972
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
973
|
+
pubkey: bankAccount.oracle,
|
|
974
|
+
isSigner: false,
|
|
975
|
+
isWritable: false,
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
737
980
|
for (const position of userAccount.positions) {
|
|
738
981
|
if (!(0, position_1.positionIsAvailable)(position) &&
|
|
739
982
|
!position.marketIndex.eq(order.marketIndex)) {
|
|
740
983
|
const market = this.getMarketAccount(position.marketIndex);
|
|
741
|
-
|
|
984
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
742
985
|
pubkey: market.pubkey,
|
|
743
986
|
isWritable: false,
|
|
744
987
|
isSigner: false,
|
|
745
988
|
});
|
|
746
|
-
|
|
989
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
747
990
|
pubkey: market.amm.oracle,
|
|
748
991
|
isWritable: false,
|
|
749
992
|
isSigner: false,
|
|
750
993
|
});
|
|
751
994
|
}
|
|
752
995
|
}
|
|
753
|
-
|
|
996
|
+
marketAccountMap.set(marketIndex.toNumber(), {
|
|
997
|
+
pubkey: marketAccount.pubkey,
|
|
998
|
+
isWritable: true,
|
|
999
|
+
isSigner: false,
|
|
1000
|
+
});
|
|
1001
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
1002
|
+
pubkey: marketAccount.amm.oracle,
|
|
1003
|
+
isWritable: false,
|
|
1004
|
+
isSigner: false,
|
|
1005
|
+
});
|
|
1006
|
+
const remainingAccounts = [
|
|
1007
|
+
...oracleAccountMap.values(),
|
|
1008
|
+
...bankAccountMap.values(),
|
|
1009
|
+
...marketAccountMap.values(),
|
|
1010
|
+
];
|
|
754
1011
|
const orderId = order.orderId;
|
|
755
1012
|
return await this.program.instruction.triggerOrder(orderId, {
|
|
756
1013
|
accounts: {
|
|
@@ -762,15 +1019,15 @@ class ClearingHouse {
|
|
|
762
1019
|
remainingAccounts,
|
|
763
1020
|
});
|
|
764
1021
|
}
|
|
765
|
-
async placeAndTake(orderParams, makerInfo) {
|
|
766
|
-
const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceAndTakeIx(orderParams, makerInfo)), [], this.opts);
|
|
1022
|
+
async placeAndTake(orderParams, makerInfo, referrerInfo) {
|
|
1023
|
+
const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceAndTakeIx(orderParams, makerInfo, referrerInfo)), [], this.opts);
|
|
767
1024
|
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
768
1025
|
return txSig;
|
|
769
1026
|
}
|
|
770
|
-
async getPlaceAndTakeIx(orderParams, makerInfo) {
|
|
1027
|
+
async getPlaceAndTakeIx(orderParams, makerInfo, referrerInfo) {
|
|
1028
|
+
orderParams = this.getOrderParams(orderParams);
|
|
1029
|
+
const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
|
|
771
1030
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
772
|
-
const priceOracle = this.getMarketAccount(orderParams.marketIndex).amm
|
|
773
|
-
.oracle;
|
|
774
1031
|
const remainingAccounts = this.getRemainingAccounts({
|
|
775
1032
|
writableMarketIndex: orderParams.marketIndex,
|
|
776
1033
|
writableBankIndex: numericConstants_1.QUOTE_ASSET_BANK_INDEX,
|
|
@@ -783,13 +1040,67 @@ class ClearingHouse {
|
|
|
783
1040
|
isSigner: false,
|
|
784
1041
|
isWritable: true,
|
|
785
1042
|
});
|
|
1043
|
+
remainingAccounts.push({
|
|
1044
|
+
pubkey: makerInfo.makerStats,
|
|
1045
|
+
isSigner: false,
|
|
1046
|
+
isWritable: true,
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
if (referrerInfo) {
|
|
1050
|
+
remainingAccounts.push({
|
|
1051
|
+
pubkey: referrerInfo.referrer,
|
|
1052
|
+
isWritable: true,
|
|
1053
|
+
isSigner: false,
|
|
1054
|
+
});
|
|
1055
|
+
remainingAccounts.push({
|
|
1056
|
+
pubkey: referrerInfo.referrerStats,
|
|
1057
|
+
isWritable: true,
|
|
1058
|
+
isSigner: false,
|
|
1059
|
+
});
|
|
786
1060
|
}
|
|
787
1061
|
return await this.program.instruction.placeAndTake(orderParams, makerOrderId, {
|
|
788
1062
|
accounts: {
|
|
789
1063
|
state: await this.getStatePublicKey(),
|
|
790
1064
|
user: userAccountPublicKey,
|
|
1065
|
+
userStats: userStatsPublicKey,
|
|
1066
|
+
authority: this.wallet.publicKey,
|
|
1067
|
+
},
|
|
1068
|
+
remainingAccounts,
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
async placeAndMake(orderParams, takerInfo, referrerInfo) {
|
|
1072
|
+
const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceAndMakeIx(orderParams, takerInfo, referrerInfo)), [], this.opts);
|
|
1073
|
+
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
1074
|
+
return txSig;
|
|
1075
|
+
}
|
|
1076
|
+
async getPlaceAndMakeIx(orderParams, takerInfo, referrerInfo) {
|
|
1077
|
+
orderParams = this.getOrderParams(orderParams);
|
|
1078
|
+
const userStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
1079
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1080
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1081
|
+
writableMarketIndex: orderParams.marketIndex,
|
|
1082
|
+
});
|
|
1083
|
+
if (referrerInfo) {
|
|
1084
|
+
remainingAccounts.push({
|
|
1085
|
+
pubkey: referrerInfo.referrer,
|
|
1086
|
+
isWritable: true,
|
|
1087
|
+
isSigner: false,
|
|
1088
|
+
});
|
|
1089
|
+
remainingAccounts.push({
|
|
1090
|
+
pubkey: referrerInfo.referrerStats,
|
|
1091
|
+
isWritable: true,
|
|
1092
|
+
isSigner: false,
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
const takerOrderId = takerInfo.order.orderId;
|
|
1096
|
+
return await this.program.instruction.placeAndMake(orderParams, takerOrderId, {
|
|
1097
|
+
accounts: {
|
|
1098
|
+
state: await this.getStatePublicKey(),
|
|
1099
|
+
user: userAccountPublicKey,
|
|
1100
|
+
userStats: userStatsPublicKey,
|
|
1101
|
+
taker: takerInfo.taker,
|
|
1102
|
+
takerStats: takerInfo.takerStats,
|
|
791
1103
|
authority: this.wallet.publicKey,
|
|
792
|
-
oracle: priceOracle,
|
|
793
1104
|
},
|
|
794
1105
|
remainingAccounts,
|
|
795
1106
|
});
|
|
@@ -799,19 +1110,31 @@ class ClearingHouse {
|
|
|
799
1110
|
* @param marketIndex
|
|
800
1111
|
* @returns
|
|
801
1112
|
*/
|
|
802
|
-
async closePosition(marketIndex) {
|
|
1113
|
+
async closePosition(marketIndex, limitPrice) {
|
|
803
1114
|
const userPosition = this.getUser().getUserPosition(marketIndex);
|
|
804
1115
|
if (!userPosition) {
|
|
805
1116
|
throw Error(`No position in market ${marketIndex.toString()}`);
|
|
806
1117
|
}
|
|
807
|
-
return await this.placeAndTake(
|
|
1118
|
+
return await this.placeAndTake({
|
|
1119
|
+
orderType: types_1.OrderType.MARKET,
|
|
1120
|
+
marketIndex,
|
|
1121
|
+
direction: (0, position_1.findDirectionToClose)(userPosition),
|
|
1122
|
+
baseAssetAmount: userPosition.baseAssetAmount.abs(),
|
|
1123
|
+
reduceOnly: true,
|
|
1124
|
+
price: limitPrice,
|
|
1125
|
+
});
|
|
808
1126
|
}
|
|
809
1127
|
async settlePNLs(users, marketIndex) {
|
|
810
1128
|
const ixs = [];
|
|
811
1129
|
for (const { settleeUserAccountPublicKey, settleeUserAccount } of users) {
|
|
812
1130
|
ixs.push(await this.settlePNLIx(settleeUserAccountPublicKey, settleeUserAccount, marketIndex));
|
|
813
1131
|
}
|
|
814
|
-
const tx = new web3_js_1.Transaction()
|
|
1132
|
+
const tx = new web3_js_1.Transaction()
|
|
1133
|
+
.add(web3_js_1.ComputeBudgetProgram.requestUnits({
|
|
1134
|
+
units: 1000000,
|
|
1135
|
+
additionalFee: 0,
|
|
1136
|
+
}))
|
|
1137
|
+
.add(...ixs);
|
|
815
1138
|
const { txSig } = await this.txSender.send(tx, [], this.opts);
|
|
816
1139
|
return txSig;
|
|
817
1140
|
}
|
|
@@ -828,7 +1151,7 @@ class ClearingHouse {
|
|
|
828
1151
|
const market = this.getMarketAccount(position.marketIndex);
|
|
829
1152
|
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
830
1153
|
pubkey: market.pubkey,
|
|
831
|
-
isWritable:
|
|
1154
|
+
isWritable: false,
|
|
832
1155
|
isSigner: false,
|
|
833
1156
|
});
|
|
834
1157
|
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
@@ -885,54 +1208,261 @@ class ClearingHouse {
|
|
|
885
1208
|
remainingAccounts: remainingAccounts,
|
|
886
1209
|
});
|
|
887
1210
|
}
|
|
888
|
-
async
|
|
889
|
-
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.
|
|
1211
|
+
async liquidatePerp(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
|
|
1212
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount)), [], this.opts);
|
|
890
1213
|
return txSig;
|
|
891
1214
|
}
|
|
892
|
-
async
|
|
893
|
-
const
|
|
894
|
-
const
|
|
895
|
-
const
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
1215
|
+
async getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
|
|
1216
|
+
const userStatsPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, userAccount.authority);
|
|
1217
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1218
|
+
const liquidatorStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
1219
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1220
|
+
writableMarketIndex: marketIndex,
|
|
1221
|
+
userAccount,
|
|
1222
|
+
});
|
|
1223
|
+
return await this.program.instruction.liquidatePerp(marketIndex, maxBaseAssetAmount, {
|
|
1224
|
+
accounts: {
|
|
1225
|
+
state: await this.getStatePublicKey(),
|
|
1226
|
+
authority: this.wallet.publicKey,
|
|
1227
|
+
user: userAccountPublicKey,
|
|
1228
|
+
userStats: userStatsPublicKey,
|
|
1229
|
+
liquidator: liquidatorPublicKey,
|
|
1230
|
+
liquidatorStats: liquidatorStatsPublicKey,
|
|
900
1231
|
},
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1232
|
+
remainingAccounts: remainingAccounts,
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
async liquidateBorrow(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer) {
|
|
1236
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateBorrowIx(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer)), [], this.opts);
|
|
1237
|
+
return txSig;
|
|
1238
|
+
}
|
|
1239
|
+
async getLiquidateBorrowIx(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer) {
|
|
1240
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1241
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1242
|
+
userAccount,
|
|
1243
|
+
writableBankIndexes: [liabilityBankIndex, assetBankIndex],
|
|
1244
|
+
});
|
|
1245
|
+
return await this.program.instruction.liquidateBorrow(assetBankIndex, liabilityBankIndex, maxLiabilityTransfer, {
|
|
1246
|
+
accounts: {
|
|
1247
|
+
state: await this.getStatePublicKey(),
|
|
1248
|
+
authority: this.wallet.publicKey,
|
|
1249
|
+
user: userAccountPublicKey,
|
|
1250
|
+
liquidator: liquidatorPublicKey,
|
|
1251
|
+
},
|
|
1252
|
+
remainingAccounts: remainingAccounts,
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
async liquidateBorrowForPerpPnl(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer) {
|
|
1256
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateBorrowForPerpPnlIx(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer)), [], this.opts);
|
|
1257
|
+
return txSig;
|
|
1258
|
+
}
|
|
1259
|
+
async getLiquidateBorrowForPerpPnlIx(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer) {
|
|
1260
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1261
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1262
|
+
userAccount,
|
|
1263
|
+
writableMarketIndex: perpMarketIndex,
|
|
1264
|
+
writableBankIndexes: [liabilityBankIndex],
|
|
1265
|
+
});
|
|
1266
|
+
return await this.program.instruction.liquidateBorrowForPerpPnl(perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer, {
|
|
1267
|
+
accounts: {
|
|
1268
|
+
state: await this.getStatePublicKey(),
|
|
1269
|
+
authority: this.wallet.publicKey,
|
|
1270
|
+
user: userAccountPublicKey,
|
|
1271
|
+
liquidator: liquidatorPublicKey,
|
|
1272
|
+
},
|
|
1273
|
+
remainingAccounts: remainingAccounts,
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
async liquidatePerpPnlForDeposit(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer) {
|
|
1277
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidatePerpPnlForDepositIx(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer)), [], this.opts);
|
|
1278
|
+
return txSig;
|
|
1279
|
+
}
|
|
1280
|
+
async getLiquidatePerpPnlForDepositIx(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer) {
|
|
1281
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1282
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1283
|
+
userAccount,
|
|
1284
|
+
writableMarketIndex: perpMarketIndex,
|
|
1285
|
+
writableBankIndexes: [assetBankIndex],
|
|
1286
|
+
});
|
|
1287
|
+
return await this.program.instruction.liquidatePerpPnlForDeposit(perpMarketIndex, assetBankIndex, maxPnlTransfer, {
|
|
1288
|
+
accounts: {
|
|
1289
|
+
state: await this.getStatePublicKey(),
|
|
1290
|
+
authority: this.wallet.publicKey,
|
|
1291
|
+
user: userAccountPublicKey,
|
|
1292
|
+
liquidator: liquidatorPublicKey,
|
|
1293
|
+
},
|
|
1294
|
+
remainingAccounts: remainingAccounts,
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
async resolvePerpBankruptcy(userAccountPublicKey, userAccount, marketIndex) {
|
|
1298
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getResolvePerpBankruptcyIx(userAccountPublicKey, userAccount, marketIndex)), [], this.opts);
|
|
1299
|
+
return txSig;
|
|
1300
|
+
}
|
|
1301
|
+
async getResolvePerpBankruptcyIx(userAccountPublicKey, userAccount, marketIndex) {
|
|
1302
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1303
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1304
|
+
writableMarketIndex: marketIndex,
|
|
1305
|
+
userAccount,
|
|
1306
|
+
});
|
|
1307
|
+
return await this.program.instruction.resolvePerpBankruptcy(marketIndex, {
|
|
1308
|
+
accounts: {
|
|
1309
|
+
state: await this.getStatePublicKey(),
|
|
1310
|
+
authority: this.wallet.publicKey,
|
|
1311
|
+
user: userAccountPublicKey,
|
|
1312
|
+
liquidator: liquidatorPublicKey,
|
|
1313
|
+
},
|
|
1314
|
+
remainingAccounts: remainingAccounts,
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
async resolveBorrowBankruptcy(userAccountPublicKey, userAccount, bankIndex) {
|
|
1318
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getResolveBorrowBankruptcyIx(userAccountPublicKey, userAccount, bankIndex)), [], this.opts);
|
|
1319
|
+
return txSig;
|
|
1320
|
+
}
|
|
1321
|
+
async getResolveBorrowBankruptcyIx(userAccountPublicKey, userAccount, bankIndex) {
|
|
1322
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1323
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1324
|
+
writableBankIndexes: [bankIndex],
|
|
1325
|
+
userAccount,
|
|
1326
|
+
});
|
|
1327
|
+
return await this.program.instruction.resolveBorrowBankruptcy(bankIndex, {
|
|
1328
|
+
accounts: {
|
|
1329
|
+
state: await this.getStatePublicKey(),
|
|
1330
|
+
authority: this.wallet.publicKey,
|
|
1331
|
+
user: userAccountPublicKey,
|
|
1332
|
+
liquidator: liquidatorPublicKey,
|
|
1333
|
+
},
|
|
1334
|
+
remainingAccounts: remainingAccounts,
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
getRemainingAccountsForLiquidation(params) {
|
|
1338
|
+
const liquidateeUserAccount = params.userAccount;
|
|
1339
|
+
const oracleAccountMap = new Map();
|
|
1340
|
+
const bankAccountMap = new Map();
|
|
1341
|
+
const marketAccountMap = new Map();
|
|
1342
|
+
for (const bankBalance of liquidateeUserAccount.bankBalances) {
|
|
1343
|
+
if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
|
|
1344
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
1345
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
1346
|
+
pubkey: bankAccount.pubkey,
|
|
1347
|
+
isSigner: false,
|
|
1348
|
+
isWritable: false,
|
|
1349
|
+
});
|
|
1350
|
+
if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
1351
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
1352
|
+
pubkey: bankAccount.oracle,
|
|
1353
|
+
isSigner: false,
|
|
1354
|
+
isWritable: false,
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
904
1359
|
for (const position of liquidateeUserAccount.positions) {
|
|
905
1360
|
if (!(0, position_1.positionIsAvailable)(position)) {
|
|
906
1361
|
const market = this.getMarketAccount(position.marketIndex);
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
isWritable: true,
|
|
1362
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
1363
|
+
pubkey: market.pubkey,
|
|
1364
|
+
isWritable: false,
|
|
911
1365
|
isSigner: false,
|
|
912
1366
|
});
|
|
913
|
-
|
|
1367
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
914
1368
|
pubkey: market.amm.oracle,
|
|
915
1369
|
isWritable: false,
|
|
916
1370
|
isSigner: false,
|
|
917
1371
|
});
|
|
918
1372
|
}
|
|
919
1373
|
}
|
|
920
|
-
const
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1374
|
+
const userAccountAndSlot = this.getUserAccountAndSlot();
|
|
1375
|
+
if (!userAccountAndSlot) {
|
|
1376
|
+
throw Error('No user account found. Most likely user account does not exist or failed to fetch account');
|
|
1377
|
+
}
|
|
1378
|
+
const { data: userAccount, slot: lastUserPositionsSlot } = userAccountAndSlot;
|
|
1379
|
+
for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
|
|
1380
|
+
// if cache has more recent slot than user positions account slot, add market to remaining accounts
|
|
1381
|
+
// otherwise remove from slot
|
|
1382
|
+
if (slot > lastUserPositionsSlot) {
|
|
1383
|
+
const marketAccount = this.getMarketAccount(marketIndexNum);
|
|
1384
|
+
marketAccountMap.set(marketIndexNum, {
|
|
1385
|
+
pubkey: marketAccount.pubkey,
|
|
1386
|
+
isSigner: false,
|
|
1387
|
+
isWritable: false,
|
|
1388
|
+
});
|
|
1389
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
1390
|
+
pubkey: marketAccount.amm.oracle,
|
|
1391
|
+
isSigner: false,
|
|
1392
|
+
isWritable: false,
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
else {
|
|
1396
|
+
this.marketLastSlotCache.delete(marketIndexNum);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
1400
|
+
if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
|
|
1401
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
1402
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
1403
|
+
pubkey: bankAccount.pubkey,
|
|
1404
|
+
isSigner: false,
|
|
1405
|
+
isWritable: false,
|
|
1406
|
+
});
|
|
1407
|
+
if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
1408
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
1409
|
+
pubkey: bankAccount.oracle,
|
|
1410
|
+
isSigner: false,
|
|
1411
|
+
isWritable: false,
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
for (const position of userAccount.positions) {
|
|
1417
|
+
if (!(0, position_1.positionIsAvailable)(position)) {
|
|
1418
|
+
const market = this.getMarketAccount(position.marketIndex);
|
|
1419
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
1420
|
+
pubkey: market.pubkey,
|
|
1421
|
+
isWritable: false,
|
|
1422
|
+
isSigner: false,
|
|
1423
|
+
});
|
|
1424
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1425
|
+
pubkey: market.amm.oracle,
|
|
1426
|
+
isWritable: false,
|
|
1427
|
+
isSigner: false,
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
if (params.writableMarketIndex) {
|
|
1432
|
+
const market = this.getMarketAccount(params.writableMarketIndex);
|
|
1433
|
+
marketAccountMap.set(market.marketIndex.toNumber(), {
|
|
1434
|
+
pubkey: market.pubkey,
|
|
1435
|
+
isSigner: false,
|
|
1436
|
+
isWritable: true,
|
|
1437
|
+
});
|
|
1438
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1439
|
+
pubkey: market.amm.oracle,
|
|
1440
|
+
isSigner: false,
|
|
1441
|
+
isWritable: false,
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
if (params.writableBankIndexes) {
|
|
1445
|
+
for (const writableBankIndex of params.writableBankIndexes) {
|
|
1446
|
+
const bank = this.getBankAccount(writableBankIndex);
|
|
1447
|
+
bankAccountMap.set(bank.bankIndex.toNumber(), {
|
|
1448
|
+
pubkey: bank.pubkey,
|
|
1449
|
+
isSigner: false,
|
|
1450
|
+
isWritable: true,
|
|
1451
|
+
});
|
|
1452
|
+
if (!bank.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
1453
|
+
oracleAccountMap.set(bank.oracle.toString(), {
|
|
1454
|
+
pubkey: bank.oracle,
|
|
1455
|
+
isSigner: false,
|
|
1456
|
+
isWritable: false,
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return [
|
|
1462
|
+
...oracleAccountMap.values(),
|
|
1463
|
+
...bankAccountMap.values(),
|
|
1464
|
+
...marketAccountMap.values(),
|
|
1465
|
+
];
|
|
936
1466
|
}
|
|
937
1467
|
async updateFundingRate(oracle, marketIndex) {
|
|
938
1468
|
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getUpdateFundingRateIx(oracle, marketIndex)), [], this.opts);
|