@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/src/clearingHouse.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnchorProvider, BN, Idl, Program } from '@project-serum/anchor';
|
|
2
|
-
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
2
|
+
import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
3
3
|
import {
|
|
4
4
|
StateAccount,
|
|
5
5
|
IWallet,
|
|
@@ -11,6 +11,11 @@ import {
|
|
|
11
11
|
BankAccount,
|
|
12
12
|
UserBankBalance,
|
|
13
13
|
MakerInfo,
|
|
14
|
+
TakerInfo,
|
|
15
|
+
OptionalOrderParams,
|
|
16
|
+
DefaultOrderParams,
|
|
17
|
+
OrderType,
|
|
18
|
+
ReferrerInfo,
|
|
14
19
|
} from './types';
|
|
15
20
|
import * as anchor from '@project-serum/anchor';
|
|
16
21
|
import clearingHouseIDL from './idl/clearing_house.json';
|
|
@@ -23,9 +28,14 @@ import {
|
|
|
23
28
|
Transaction,
|
|
24
29
|
TransactionInstruction,
|
|
25
30
|
AccountMeta,
|
|
31
|
+
Keypair,
|
|
32
|
+
LAMPORTS_PER_SOL,
|
|
33
|
+
Signer,
|
|
34
|
+
SystemProgram,
|
|
35
|
+
ComputeBudgetProgram,
|
|
26
36
|
} from '@solana/web3.js';
|
|
27
37
|
|
|
28
|
-
import {
|
|
38
|
+
import { TokenFaucet } from './tokenFaucet';
|
|
29
39
|
import { EventEmitter } from 'events';
|
|
30
40
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
31
41
|
import {
|
|
@@ -33,6 +43,7 @@ import {
|
|
|
33
43
|
getMarketPublicKey,
|
|
34
44
|
getUserAccountPublicKey,
|
|
35
45
|
getUserAccountPublicKeySync,
|
|
46
|
+
getUserStatsAccountPublicKey,
|
|
36
47
|
} from './addresses/pda';
|
|
37
48
|
import {
|
|
38
49
|
ClearingHouseAccountSubscriber,
|
|
@@ -41,7 +52,11 @@ import {
|
|
|
41
52
|
} from './accounts/types';
|
|
42
53
|
import { TxSender } from './tx/types';
|
|
43
54
|
import { wrapInTx } from './tx/utils';
|
|
44
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
ONE,
|
|
57
|
+
QUOTE_ASSET_BANK_INDEX,
|
|
58
|
+
ZERO,
|
|
59
|
+
} from './constants/numericConstants';
|
|
45
60
|
import { findDirectionToClose, positionIsAvailable } from './math/position';
|
|
46
61
|
import { getTokenAmount } from './math/bankBalance';
|
|
47
62
|
import { DEFAULT_USER_NAME, encodeName } from './userName';
|
|
@@ -52,8 +67,9 @@ import { WebSocketClearingHouseAccountSubscriber } from './accounts/webSocketCle
|
|
|
52
67
|
import { RetryTxSender } from './tx/retryTxSender';
|
|
53
68
|
import { ClearingHouseUser } from './clearingHouseUser';
|
|
54
69
|
import { ClearingHouseUserAccountSubscriptionConfig } from './clearingHouseUserConfig';
|
|
55
|
-
import { getMarketOrderParams } from './orderParams';
|
|
56
70
|
import { getMarketsBanksAndOraclesForSubscription } from './config';
|
|
71
|
+
import { WRAPPED_SOL_MINT } from './constants/banks';
|
|
72
|
+
import { ClearingHouseUserStats } from './clearingHouseUserStats';
|
|
57
73
|
|
|
58
74
|
/**
|
|
59
75
|
* # ClearingHouse
|
|
@@ -66,6 +82,7 @@ export class ClearingHouse {
|
|
|
66
82
|
provider: AnchorProvider;
|
|
67
83
|
opts?: ConfirmOptions;
|
|
68
84
|
users = new Map<number, ClearingHouseUser>();
|
|
85
|
+
userStats?: ClearingHouseUserStats;
|
|
69
86
|
activeUserId: number;
|
|
70
87
|
userAccountSubscriptionConfig: ClearingHouseUserAccountSubscriptionConfig;
|
|
71
88
|
accountSubscriber: ClearingHouseAccountSubscriber;
|
|
@@ -109,6 +126,16 @@ export class ClearingHouse {
|
|
|
109
126
|
type: 'websocket',
|
|
110
127
|
};
|
|
111
128
|
this.createUsers(userIds, this.userAccountSubscriptionConfig);
|
|
129
|
+
if (config.userStats) {
|
|
130
|
+
this.userStats = new ClearingHouseUserStats({
|
|
131
|
+
clearingHouse: this,
|
|
132
|
+
userStatsAccountPublicKey: getUserStatsAccountPublicKey(
|
|
133
|
+
this.program.programId,
|
|
134
|
+
this.wallet.publicKey
|
|
135
|
+
),
|
|
136
|
+
accountSubscription: this.userAccountSubscriptionConfig,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
112
139
|
|
|
113
140
|
let marketIndexes = config.marketIndexes;
|
|
114
141
|
let bankIndexes = config.bankIndexes;
|
|
@@ -180,6 +207,9 @@ export class ClearingHouse {
|
|
|
180
207
|
const subscribePromises = this.subscribeUsers().concat(
|
|
181
208
|
this.accountSubscriber.subscribe()
|
|
182
209
|
);
|
|
210
|
+
if (this.userStats !== undefined) {
|
|
211
|
+
subscribePromises.concat(this.userStats.subscribe());
|
|
212
|
+
}
|
|
183
213
|
this.isSubscribed = (await Promise.all(subscribePromises)).reduce(
|
|
184
214
|
(success, prevSuccess) => success && prevSuccess
|
|
185
215
|
);
|
|
@@ -205,6 +235,9 @@ export class ClearingHouse {
|
|
|
205
235
|
const unsubscribePromises = this.unsubscribeUsers().concat(
|
|
206
236
|
this.accountSubscriber.unsubscribe()
|
|
207
237
|
);
|
|
238
|
+
if (this.userStats !== undefined) {
|
|
239
|
+
unsubscribePromises.concat(this.userStats.unsubscribe());
|
|
240
|
+
}
|
|
208
241
|
await Promise.all(unsubscribePromises);
|
|
209
242
|
this.isSubscribed = false;
|
|
210
243
|
}
|
|
@@ -294,6 +327,7 @@ export class ClearingHouse {
|
|
|
294
327
|
}
|
|
295
328
|
|
|
296
329
|
this.activeUserId = activeUserId;
|
|
330
|
+
this.userStatsAccountPublicKey = undefined;
|
|
297
331
|
}
|
|
298
332
|
|
|
299
333
|
public async switchActiveUser(userId: number): Promise<void> {
|
|
@@ -312,19 +346,26 @@ export class ClearingHouse {
|
|
|
312
346
|
|
|
313
347
|
public async initializeUserAccount(
|
|
314
348
|
userId = 0,
|
|
315
|
-
name = DEFAULT_USER_NAME
|
|
349
|
+
name = DEFAULT_USER_NAME,
|
|
350
|
+
referrerInfo?: ReferrerInfo
|
|
316
351
|
): Promise<[TransactionSignature, PublicKey]> {
|
|
317
352
|
const [userAccountPublicKey, initializeUserAccountIx] =
|
|
318
|
-
await this.getInitializeUserInstructions(userId, name);
|
|
353
|
+
await this.getInitializeUserInstructions(userId, name, referrerInfo);
|
|
319
354
|
|
|
320
|
-
const tx = new Transaction()
|
|
355
|
+
const tx = new Transaction();
|
|
356
|
+
if (userId === 0) {
|
|
357
|
+
// not the safest assumption, can explicitly check if user stats account exists if it causes problems
|
|
358
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
359
|
+
}
|
|
360
|
+
tx.add(initializeUserAccountIx);
|
|
321
361
|
const { txSig } = await this.txSender.send(tx, [], this.opts);
|
|
322
362
|
return [txSig, userAccountPublicKey];
|
|
323
363
|
}
|
|
324
364
|
|
|
325
365
|
async getInitializeUserInstructions(
|
|
326
366
|
userId = 0,
|
|
327
|
-
name = DEFAULT_USER_NAME
|
|
367
|
+
name = DEFAULT_USER_NAME,
|
|
368
|
+
referrerInfo?: ReferrerInfo
|
|
328
369
|
): Promise<[PublicKey, TransactionInstruction]> {
|
|
329
370
|
const userAccountPublicKey = await getUserAccountPublicKey(
|
|
330
371
|
this.program.programId,
|
|
@@ -332,22 +373,51 @@ export class ClearingHouse {
|
|
|
332
373
|
userId
|
|
333
374
|
);
|
|
334
375
|
|
|
376
|
+
const remainingAccounts = new Array<AccountMeta>();
|
|
377
|
+
if (referrerInfo !== undefined) {
|
|
378
|
+
remainingAccounts.push({
|
|
379
|
+
pubkey: referrerInfo.referrer,
|
|
380
|
+
isWritable: true,
|
|
381
|
+
isSigner: false,
|
|
382
|
+
});
|
|
383
|
+
remainingAccounts.push({
|
|
384
|
+
pubkey: referrerInfo.referrerStats,
|
|
385
|
+
isWritable: true,
|
|
386
|
+
isSigner: false,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
335
390
|
const nameBuffer = encodeName(name);
|
|
336
391
|
const initializeUserAccountIx =
|
|
337
392
|
await this.program.instruction.initializeUser(userId, nameBuffer, {
|
|
338
393
|
accounts: {
|
|
339
394
|
user: userAccountPublicKey,
|
|
395
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
340
396
|
authority: this.wallet.publicKey,
|
|
341
397
|
payer: this.wallet.publicKey,
|
|
342
398
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
343
399
|
systemProgram: anchor.web3.SystemProgram.programId,
|
|
344
400
|
state: await this.getStatePublicKey(),
|
|
345
401
|
},
|
|
402
|
+
remainingAccounts,
|
|
346
403
|
});
|
|
347
404
|
|
|
348
405
|
return [userAccountPublicKey, initializeUserAccountIx];
|
|
349
406
|
}
|
|
350
407
|
|
|
408
|
+
async getInitializeUserStatsIx(): Promise<TransactionInstruction> {
|
|
409
|
+
return await this.program.instruction.initializeUserStats({
|
|
410
|
+
accounts: {
|
|
411
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
412
|
+
authority: this.wallet.publicKey,
|
|
413
|
+
payer: this.wallet.publicKey,
|
|
414
|
+
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
415
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
416
|
+
state: await this.getStatePublicKey(),
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
351
421
|
public getUser(userId?: number): ClearingHouseUser {
|
|
352
422
|
userId = userId ?? this.activeUserId;
|
|
353
423
|
if (!this.users.has(userId)) {
|
|
@@ -360,6 +430,23 @@ export class ClearingHouse {
|
|
|
360
430
|
return [...this.users.values()];
|
|
361
431
|
}
|
|
362
432
|
|
|
433
|
+
public getUserStats(): ClearingHouseUserStats {
|
|
434
|
+
return this.userStats;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
userStatsAccountPublicKey: PublicKey;
|
|
438
|
+
public getUserStatsAccountPublicKey(): PublicKey {
|
|
439
|
+
if (this.userStatsAccountPublicKey) {
|
|
440
|
+
return this.userStatsAccountPublicKey;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
this.userStatsAccountPublicKey = getUserStatsAccountPublicKey(
|
|
444
|
+
this.program.programId,
|
|
445
|
+
this.wallet.publicKey
|
|
446
|
+
);
|
|
447
|
+
return this.userStatsAccountPublicKey;
|
|
448
|
+
}
|
|
449
|
+
|
|
363
450
|
public async getUserAccountPublicKey(): Promise<PublicKey> {
|
|
364
451
|
return this.getUser().userAccountPublicKey;
|
|
365
452
|
}
|
|
@@ -396,6 +483,7 @@ export class ClearingHouse {
|
|
|
396
483
|
getRemainingAccounts(params: {
|
|
397
484
|
writableMarketIndex?: BN;
|
|
398
485
|
writableBankIndex?: BN;
|
|
486
|
+
readableMarketIndex?: BN;
|
|
399
487
|
}): AccountMeta[] {
|
|
400
488
|
const userAccountAndSlot = this.getUserAccountAndSlot();
|
|
401
489
|
if (!userAccountAndSlot) {
|
|
@@ -436,8 +524,7 @@ export class ClearingHouse {
|
|
|
436
524
|
marketAccountMap.set(marketIndexNum, {
|
|
437
525
|
pubkey: marketAccount.pubkey,
|
|
438
526
|
isSigner: false,
|
|
439
|
-
|
|
440
|
-
isWritable: true,
|
|
527
|
+
isWritable: false,
|
|
441
528
|
});
|
|
442
529
|
oracleAccountMap.set(marketAccount.pubkey.toString(), {
|
|
443
530
|
pubkey: marketAccount.amm.oracle,
|
|
@@ -447,6 +534,22 @@ export class ClearingHouse {
|
|
|
447
534
|
}
|
|
448
535
|
}
|
|
449
536
|
|
|
537
|
+
if (params.readableMarketIndex) {
|
|
538
|
+
const marketAccount = this.getMarketAccount(
|
|
539
|
+
params.readableMarketIndex.toNumber()
|
|
540
|
+
);
|
|
541
|
+
marketAccountMap.set(params.readableMarketIndex.toNumber(), {
|
|
542
|
+
pubkey: marketAccount.pubkey,
|
|
543
|
+
isSigner: false,
|
|
544
|
+
isWritable: true,
|
|
545
|
+
});
|
|
546
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
547
|
+
pubkey: marketAccount.amm.oracle,
|
|
548
|
+
isSigner: false,
|
|
549
|
+
isWritable: false,
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
|
|
450
553
|
if (params.writableMarketIndex) {
|
|
451
554
|
const marketAccount = this.getMarketAccount(
|
|
452
555
|
params.writableMarketIndex.toNumber()
|
|
@@ -524,6 +627,31 @@ export class ClearingHouse {
|
|
|
524
627
|
userId?: number,
|
|
525
628
|
reduceOnly = false
|
|
526
629
|
): Promise<TransactionSignature> {
|
|
630
|
+
const tx = new Transaction();
|
|
631
|
+
const additionalSigners: Array<Signer> = [];
|
|
632
|
+
|
|
633
|
+
const bank = this.getBankAccount(bankIndex);
|
|
634
|
+
|
|
635
|
+
const isSolBank = bank.mint.equals(WRAPPED_SOL_MINT);
|
|
636
|
+
|
|
637
|
+
const authority = this.wallet.publicKey;
|
|
638
|
+
|
|
639
|
+
const createWSOLTokenAccount =
|
|
640
|
+
isSolBank && collateralAccountPublicKey.equals(authority);
|
|
641
|
+
|
|
642
|
+
if (createWSOLTokenAccount) {
|
|
643
|
+
const { ixs, signers, pubkey } =
|
|
644
|
+
await this.getWrappedSolAccountCreationIxs(amount);
|
|
645
|
+
|
|
646
|
+
collateralAccountPublicKey = pubkey;
|
|
647
|
+
|
|
648
|
+
ixs.forEach((ix) => {
|
|
649
|
+
tx.add(ix);
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
signers.forEach((signer) => additionalSigners.push(signer));
|
|
653
|
+
}
|
|
654
|
+
|
|
527
655
|
const depositCollateralIx = await this.getDepositInstruction(
|
|
528
656
|
amount,
|
|
529
657
|
bankIndex,
|
|
@@ -533,9 +661,26 @@ export class ClearingHouse {
|
|
|
533
661
|
true
|
|
534
662
|
);
|
|
535
663
|
|
|
536
|
-
|
|
664
|
+
tx.add(depositCollateralIx);
|
|
665
|
+
|
|
666
|
+
// Close the wrapped sol account at the end of the transaction
|
|
667
|
+
if (createWSOLTokenAccount) {
|
|
668
|
+
tx.add(
|
|
669
|
+
Token.createCloseAccountInstruction(
|
|
670
|
+
TOKEN_PROGRAM_ID,
|
|
671
|
+
collateralAccountPublicKey,
|
|
672
|
+
authority,
|
|
673
|
+
authority,
|
|
674
|
+
[]
|
|
675
|
+
)
|
|
676
|
+
);
|
|
677
|
+
}
|
|
537
678
|
|
|
538
|
-
const { txSig } = await this.txSender.send(
|
|
679
|
+
const { txSig } = await this.txSender.send(
|
|
680
|
+
tx,
|
|
681
|
+
additionalSigners,
|
|
682
|
+
this.opts
|
|
683
|
+
);
|
|
539
684
|
return txSig;
|
|
540
685
|
}
|
|
541
686
|
|
|
@@ -561,13 +706,19 @@ export class ClearingHouse {
|
|
|
561
706
|
writableBankIndex: bankIndex,
|
|
562
707
|
});
|
|
563
708
|
} else {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
709
|
+
const bankAccount = this.getBankAccount(bankIndex);
|
|
710
|
+
if (!bankAccount.oracle.equals(PublicKey.default)) {
|
|
711
|
+
remainingAccounts.push({
|
|
712
|
+
pubkey: bankAccount.oracle,
|
|
567
713
|
isSigner: false,
|
|
568
|
-
isWritable:
|
|
569
|
-
}
|
|
570
|
-
|
|
714
|
+
isWritable: false,
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
remainingAccounts.push({
|
|
718
|
+
pubkey: bankAccount.pubkey,
|
|
719
|
+
isSigner: false,
|
|
720
|
+
isWritable: true,
|
|
721
|
+
});
|
|
571
722
|
}
|
|
572
723
|
|
|
573
724
|
const bank = this.getBankAccount(bankIndex);
|
|
@@ -582,6 +733,7 @@ export class ClearingHouse {
|
|
|
582
733
|
bank: bank.pubkey,
|
|
583
734
|
bankVault: bank.vault,
|
|
584
735
|
user: userAccountPublicKey,
|
|
736
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
585
737
|
userTokenAccount: userTokenAccount,
|
|
586
738
|
authority: this.wallet.publicKey,
|
|
587
739
|
tokenProgram: TOKEN_PROGRAM_ID,
|
|
@@ -591,12 +743,119 @@ export class ClearingHouse {
|
|
|
591
743
|
);
|
|
592
744
|
}
|
|
593
745
|
|
|
746
|
+
private async checkIfAccountExists(account: PublicKey) {
|
|
747
|
+
try {
|
|
748
|
+
const accountInfo = await this.connection.getAccountInfo(account);
|
|
749
|
+
return accountInfo && true;
|
|
750
|
+
} catch (e) {
|
|
751
|
+
// Doesn't already exist
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
private async getSolWithdrawalIxs(
|
|
757
|
+
bankIndex: BN,
|
|
758
|
+
amount: BN
|
|
759
|
+
): Promise<{
|
|
760
|
+
ixs: anchor.web3.TransactionInstruction[];
|
|
761
|
+
signers: Signer[];
|
|
762
|
+
pubkey: PublicKey;
|
|
763
|
+
}> {
|
|
764
|
+
const result = {
|
|
765
|
+
ixs: [],
|
|
766
|
+
signers: [],
|
|
767
|
+
pubkey: PublicKey.default,
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
// Create a temporary wrapped SOL account to store the SOL that we're withdrawing
|
|
771
|
+
|
|
772
|
+
const authority = this.wallet.publicKey;
|
|
773
|
+
|
|
774
|
+
const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(
|
|
775
|
+
amount
|
|
776
|
+
);
|
|
777
|
+
result.pubkey = pubkey;
|
|
778
|
+
|
|
779
|
+
ixs.forEach((ix) => {
|
|
780
|
+
result.ixs.push(ix);
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
signers.forEach((ix) => {
|
|
784
|
+
result.signers.push(ix);
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
const withdrawIx = await this.getWithdrawIx(
|
|
788
|
+
amount,
|
|
789
|
+
bankIndex,
|
|
790
|
+
pubkey,
|
|
791
|
+
true
|
|
792
|
+
);
|
|
793
|
+
|
|
794
|
+
result.ixs.push(withdrawIx);
|
|
795
|
+
|
|
796
|
+
result.ixs.push(
|
|
797
|
+
Token.createCloseAccountInstruction(
|
|
798
|
+
TOKEN_PROGRAM_ID,
|
|
799
|
+
pubkey,
|
|
800
|
+
authority,
|
|
801
|
+
authority,
|
|
802
|
+
[]
|
|
803
|
+
)
|
|
804
|
+
);
|
|
805
|
+
|
|
806
|
+
return result;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
private async getWrappedSolAccountCreationIxs(amount: BN): Promise<{
|
|
810
|
+
ixs: anchor.web3.TransactionInstruction[];
|
|
811
|
+
signers: Signer[];
|
|
812
|
+
pubkey: PublicKey;
|
|
813
|
+
}> {
|
|
814
|
+
const wrappedSolAccount = new Keypair();
|
|
815
|
+
|
|
816
|
+
const result = {
|
|
817
|
+
ixs: [],
|
|
818
|
+
signers: [],
|
|
819
|
+
pubkey: wrappedSolAccount.publicKey,
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
const rentSpaceLamports = new BN(LAMPORTS_PER_SOL / 100);
|
|
823
|
+
|
|
824
|
+
const depositAmountLamports = amount.add(rentSpaceLamports);
|
|
825
|
+
|
|
826
|
+
const authority = this.wallet.publicKey;
|
|
827
|
+
|
|
828
|
+
result.ixs.push(
|
|
829
|
+
SystemProgram.createAccount({
|
|
830
|
+
fromPubkey: authority,
|
|
831
|
+
newAccountPubkey: wrappedSolAccount.publicKey,
|
|
832
|
+
lamports: depositAmountLamports.toNumber(),
|
|
833
|
+
space: 165,
|
|
834
|
+
programId: TOKEN_PROGRAM_ID,
|
|
835
|
+
})
|
|
836
|
+
);
|
|
837
|
+
|
|
838
|
+
result.ixs.push(
|
|
839
|
+
Token.createInitAccountInstruction(
|
|
840
|
+
TOKEN_PROGRAM_ID,
|
|
841
|
+
WRAPPED_SOL_MINT,
|
|
842
|
+
wrappedSolAccount.publicKey,
|
|
843
|
+
authority
|
|
844
|
+
)
|
|
845
|
+
);
|
|
846
|
+
|
|
847
|
+
result.signers.push(wrappedSolAccount);
|
|
848
|
+
|
|
849
|
+
return result;
|
|
850
|
+
}
|
|
851
|
+
|
|
594
852
|
/**
|
|
595
853
|
* Creates the Clearing House User account for a user, and deposits some initial collateral
|
|
596
|
-
* @param userId
|
|
597
|
-
* @param name
|
|
598
854
|
* @param amount
|
|
599
855
|
* @param userTokenAccount
|
|
856
|
+
* @param bankIndex
|
|
857
|
+
* @param userId
|
|
858
|
+
* @param name
|
|
600
859
|
* @param fromUserId
|
|
601
860
|
* @returns
|
|
602
861
|
*/
|
|
@@ -606,10 +865,40 @@ export class ClearingHouse {
|
|
|
606
865
|
bankIndex = new BN(0),
|
|
607
866
|
userId = 0,
|
|
608
867
|
name = DEFAULT_USER_NAME,
|
|
609
|
-
fromUserId?: number
|
|
868
|
+
fromUserId?: number,
|
|
869
|
+
referrerInfo?: ReferrerInfo
|
|
610
870
|
): Promise<[TransactionSignature, PublicKey]> {
|
|
611
871
|
const [userAccountPublicKey, initializeUserAccountIx] =
|
|
612
|
-
await this.getInitializeUserInstructions(userId, name);
|
|
872
|
+
await this.getInitializeUserInstructions(userId, name, referrerInfo);
|
|
873
|
+
|
|
874
|
+
const additionalSigners: Array<Signer> = [];
|
|
875
|
+
|
|
876
|
+
const bank = this.getBankAccount(bankIndex);
|
|
877
|
+
|
|
878
|
+
const isSolBank = bank.mint.equals(WRAPPED_SOL_MINT);
|
|
879
|
+
|
|
880
|
+
const tx = new Transaction();
|
|
881
|
+
|
|
882
|
+
const authority = this.wallet.publicKey;
|
|
883
|
+
|
|
884
|
+
const createWSOLTokenAccount =
|
|
885
|
+
isSolBank && userTokenAccount.equals(authority);
|
|
886
|
+
|
|
887
|
+
if (createWSOLTokenAccount) {
|
|
888
|
+
const {
|
|
889
|
+
ixs: startIxs,
|
|
890
|
+
signers,
|
|
891
|
+
pubkey,
|
|
892
|
+
} = await this.getWrappedSolAccountCreationIxs(amount);
|
|
893
|
+
|
|
894
|
+
userTokenAccount = pubkey;
|
|
895
|
+
|
|
896
|
+
startIxs.forEach((ix) => {
|
|
897
|
+
tx.add(ix);
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
signers.forEach((signer) => additionalSigners.push(signer));
|
|
901
|
+
}
|
|
613
902
|
|
|
614
903
|
const depositCollateralIx =
|
|
615
904
|
fromUserId != null
|
|
@@ -623,11 +912,29 @@ export class ClearingHouse {
|
|
|
623
912
|
false
|
|
624
913
|
);
|
|
625
914
|
|
|
626
|
-
|
|
627
|
-
.add(
|
|
628
|
-
|
|
915
|
+
if (userId === 0) {
|
|
916
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
917
|
+
}
|
|
918
|
+
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
919
|
+
|
|
920
|
+
// Close the wrapped sol account at the end of the transaction
|
|
921
|
+
if (createWSOLTokenAccount) {
|
|
922
|
+
tx.add(
|
|
923
|
+
Token.createCloseAccountInstruction(
|
|
924
|
+
TOKEN_PROGRAM_ID,
|
|
925
|
+
userTokenAccount,
|
|
926
|
+
authority,
|
|
927
|
+
authority,
|
|
928
|
+
[]
|
|
929
|
+
)
|
|
930
|
+
);
|
|
931
|
+
}
|
|
629
932
|
|
|
630
|
-
const { txSig } = await this.txSender.send(
|
|
933
|
+
const { txSig } = await this.txSender.send(
|
|
934
|
+
tx,
|
|
935
|
+
additionalSigners,
|
|
936
|
+
this.opts
|
|
937
|
+
);
|
|
631
938
|
|
|
632
939
|
return [txSig, userAccountPublicKey];
|
|
633
940
|
}
|
|
@@ -635,32 +942,35 @@ export class ClearingHouse {
|
|
|
635
942
|
public async initializeUserAccountForDevnet(
|
|
636
943
|
userId = 0,
|
|
637
944
|
name = DEFAULT_USER_NAME,
|
|
638
|
-
|
|
639
|
-
|
|
945
|
+
bankIndex: BN,
|
|
946
|
+
tokenFaucet: TokenFaucet,
|
|
947
|
+
amount: BN,
|
|
948
|
+
referrerInfo?: ReferrerInfo
|
|
640
949
|
): Promise<[TransactionSignature, PublicKey]> {
|
|
641
950
|
const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] =
|
|
642
|
-
await
|
|
951
|
+
await tokenFaucet.createAssociatedTokenAccountAndMintToInstructions(
|
|
643
952
|
this.wallet.publicKey,
|
|
644
953
|
amount
|
|
645
954
|
);
|
|
646
955
|
|
|
647
956
|
const [userAccountPublicKey, initializeUserAccountIx] =
|
|
648
|
-
await this.getInitializeUserInstructions(userId, name);
|
|
957
|
+
await this.getInitializeUserInstructions(userId, name, referrerInfo);
|
|
649
958
|
|
|
650
959
|
const depositCollateralIx = await this.getDepositInstruction(
|
|
651
960
|
amount,
|
|
652
|
-
|
|
961
|
+
bankIndex,
|
|
653
962
|
associateTokenPublicKey,
|
|
654
963
|
userId,
|
|
655
964
|
false,
|
|
656
965
|
false
|
|
657
966
|
);
|
|
658
967
|
|
|
659
|
-
const tx = new Transaction()
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
.add(
|
|
663
|
-
|
|
968
|
+
const tx = new Transaction().add(createAssociatedAccountIx).add(mintToIx);
|
|
969
|
+
|
|
970
|
+
if (userId === 0) {
|
|
971
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
972
|
+
}
|
|
973
|
+
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
664
974
|
|
|
665
975
|
const txSig = await this.program.provider.sendAndConfirm(tx, []);
|
|
666
976
|
|
|
@@ -673,16 +983,56 @@ export class ClearingHouse {
|
|
|
673
983
|
userTokenAccount: PublicKey,
|
|
674
984
|
reduceOnly = false
|
|
675
985
|
): Promise<TransactionSignature> {
|
|
676
|
-
const
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
986
|
+
const tx = new Transaction();
|
|
987
|
+
const additionalSigners: Array<Signer> = [];
|
|
988
|
+
|
|
989
|
+
const bank = this.getBankAccount(bankIndex);
|
|
990
|
+
|
|
991
|
+
const isSolBank = bank.mint.equals(WRAPPED_SOL_MINT);
|
|
992
|
+
|
|
993
|
+
const authority = this.wallet.publicKey;
|
|
994
|
+
|
|
995
|
+
const createWSOLTokenAccount =
|
|
996
|
+
isSolBank && userTokenAccount.equals(authority);
|
|
997
|
+
|
|
998
|
+
if (createWSOLTokenAccount) {
|
|
999
|
+
const { ixs, signers, pubkey } =
|
|
1000
|
+
await this.getWrappedSolAccountCreationIxs(amount);
|
|
1001
|
+
|
|
1002
|
+
userTokenAccount = pubkey;
|
|
1003
|
+
|
|
1004
|
+
ixs.forEach((ix) => {
|
|
1005
|
+
tx.add(ix);
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
signers.forEach((signer) => additionalSigners.push(signer));
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
const withdrawCollateral = await this.getWithdrawIx(
|
|
1012
|
+
amount,
|
|
1013
|
+
bank.bankIndex,
|
|
1014
|
+
userTokenAccount,
|
|
1015
|
+
reduceOnly
|
|
1016
|
+
);
|
|
1017
|
+
|
|
1018
|
+
tx.add(withdrawCollateral);
|
|
1019
|
+
|
|
1020
|
+
// Close the wrapped sol account at the end of the transaction
|
|
1021
|
+
if (createWSOLTokenAccount) {
|
|
1022
|
+
tx.add(
|
|
1023
|
+
Token.createCloseAccountInstruction(
|
|
1024
|
+
TOKEN_PROGRAM_ID,
|
|
681
1025
|
userTokenAccount,
|
|
682
|
-
|
|
1026
|
+
authority,
|
|
1027
|
+
authority,
|
|
1028
|
+
[]
|
|
683
1029
|
)
|
|
684
|
-
)
|
|
685
|
-
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
const { txSig } = await this.txSender.send(
|
|
1034
|
+
tx,
|
|
1035
|
+
additionalSigners,
|
|
686
1036
|
this.opts
|
|
687
1037
|
);
|
|
688
1038
|
return txSig;
|
|
@@ -713,6 +1063,7 @@ export class ClearingHouse {
|
|
|
713
1063
|
bankVault: bank.vault,
|
|
714
1064
|
bankVaultAuthority: bank.vaultAuthority,
|
|
715
1065
|
user: userAccountPublicKey,
|
|
1066
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
716
1067
|
userTokenAccount: userTokenAccount,
|
|
717
1068
|
authority: this.wallet.publicKey,
|
|
718
1069
|
tokenProgram: TOKEN_PROGRAM_ID,
|
|
@@ -764,6 +1115,7 @@ export class ClearingHouse {
|
|
|
764
1115
|
authority: this.wallet.publicKey,
|
|
765
1116
|
fromUser,
|
|
766
1117
|
toUser,
|
|
1118
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
767
1119
|
state: await this.getStatePublicKey(),
|
|
768
1120
|
},
|
|
769
1121
|
remainingAccounts,
|
|
@@ -792,212 +1144,245 @@ export class ClearingHouse {
|
|
|
792
1144
|
});
|
|
793
1145
|
}
|
|
794
1146
|
|
|
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
|
|
1147
|
+
public async settleLP(
|
|
1148
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
1149
|
+
marketIndex: BN
|
|
815
1150
|
): Promise<TransactionSignature> {
|
|
816
|
-
const { txSig
|
|
817
|
-
wrapInTx(await this.
|
|
1151
|
+
const { txSig } = await this.txSender.send(
|
|
1152
|
+
wrapInTx(await this.settleLPIx(settleeUserAccountPublicKey, marketIndex)),
|
|
818
1153
|
[],
|
|
819
1154
|
this.opts
|
|
820
1155
|
);
|
|
821
|
-
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
822
1156
|
return txSig;
|
|
823
1157
|
}
|
|
824
1158
|
|
|
825
|
-
public async
|
|
826
|
-
|
|
1159
|
+
public async settleLPIx(
|
|
1160
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
1161
|
+
marketIndex: BN
|
|
827
1162
|
): Promise<TransactionInstruction> {
|
|
828
|
-
const
|
|
1163
|
+
const settleeUserAccount = (await this.program.account.user.fetch(
|
|
1164
|
+
settleeUserAccountPublicKey
|
|
1165
|
+
)) as UserAccount;
|
|
1166
|
+
const userPositions = settleeUserAccount.positions;
|
|
1167
|
+
const remainingAccounts = [];
|
|
1168
|
+
|
|
1169
|
+
let foundMarket = false;
|
|
1170
|
+
for (const position of userPositions) {
|
|
1171
|
+
if (!positionIsAvailable(position)) {
|
|
1172
|
+
const marketPublicKey = await getMarketPublicKey(
|
|
1173
|
+
this.program.programId,
|
|
1174
|
+
position.marketIndex
|
|
1175
|
+
);
|
|
1176
|
+
remainingAccounts.push({
|
|
1177
|
+
pubkey: marketPublicKey,
|
|
1178
|
+
isWritable: true,
|
|
1179
|
+
isSigner: false,
|
|
1180
|
+
});
|
|
829
1181
|
|
|
830
|
-
|
|
831
|
-
|
|
1182
|
+
if (marketIndex.eq(position.marketIndex)) {
|
|
1183
|
+
foundMarket = true;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
832
1187
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1188
|
+
if (!foundMarket) {
|
|
1189
|
+
console.log(
|
|
1190
|
+
'Warning: lp is not in the market specified -- tx will likely fail'
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
836
1193
|
|
|
837
|
-
return
|
|
1194
|
+
return this.program.instruction.settleLp(marketIndex, {
|
|
838
1195
|
accounts: {
|
|
839
1196
|
state: await this.getStatePublicKey(),
|
|
840
|
-
user:
|
|
841
|
-
authority: this.wallet.publicKey,
|
|
842
|
-
oracle: priceOracle,
|
|
1197
|
+
user: settleeUserAccountPublicKey,
|
|
843
1198
|
},
|
|
844
|
-
remainingAccounts,
|
|
1199
|
+
remainingAccounts: remainingAccounts,
|
|
845
1200
|
});
|
|
846
1201
|
}
|
|
847
1202
|
|
|
848
|
-
public async
|
|
849
|
-
|
|
1203
|
+
public async removeLiquidity(
|
|
1204
|
+
marketIndex: BN,
|
|
1205
|
+
sharesToBurn?: BN
|
|
850
1206
|
): Promise<TransactionSignature> {
|
|
851
1207
|
const { txSig } = await this.txSender.send(
|
|
852
|
-
wrapInTx(await this.
|
|
1208
|
+
wrapInTx(await this.getRemoveLiquidityIx(marketIndex, sharesToBurn)),
|
|
853
1209
|
[],
|
|
854
1210
|
this.opts
|
|
855
1211
|
);
|
|
856
1212
|
return txSig;
|
|
857
1213
|
}
|
|
858
1214
|
|
|
859
|
-
public async
|
|
860
|
-
|
|
1215
|
+
public async getRemoveLiquidityIx(
|
|
1216
|
+
marketIndex: BN,
|
|
1217
|
+
sharesToBurn?: BN
|
|
861
1218
|
): Promise<TransactionInstruction> {
|
|
862
|
-
const
|
|
1219
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1220
|
+
|
|
1221
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1222
|
+
writableMarketIndex: marketIndex,
|
|
1223
|
+
});
|
|
1224
|
+
|
|
1225
|
+
if (sharesToBurn == undefined) {
|
|
1226
|
+
const userAccount = this.getUserAccount();
|
|
1227
|
+
const marketPosition = userAccount.positions.filter((position) =>
|
|
1228
|
+
position.marketIndex.eq(marketIndex)
|
|
1229
|
+
)[0];
|
|
1230
|
+
sharesToBurn = marketPosition.lpShares;
|
|
1231
|
+
console.log('burning lp shares:', sharesToBurn.toString());
|
|
1232
|
+
}
|
|
863
1233
|
|
|
864
|
-
return
|
|
1234
|
+
return this.program.instruction.removeLiquidity(sharesToBurn, marketIndex, {
|
|
865
1235
|
accounts: {
|
|
866
1236
|
state: await this.getStatePublicKey(),
|
|
867
|
-
filler: fillerPublicKey,
|
|
868
1237
|
user: userAccountPublicKey,
|
|
869
1238
|
authority: this.wallet.publicKey,
|
|
870
1239
|
},
|
|
1240
|
+
remainingAccounts: remainingAccounts,
|
|
871
1241
|
});
|
|
872
1242
|
}
|
|
873
1243
|
|
|
874
|
-
public async
|
|
875
|
-
|
|
876
|
-
|
|
1244
|
+
public async addLiquidity(
|
|
1245
|
+
amount: BN,
|
|
1246
|
+
marketIndex: BN
|
|
1247
|
+
): Promise<TransactionSignature> {
|
|
1248
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1249
|
+
wrapInTx(await this.getAddLiquidityIx(amount, marketIndex)),
|
|
877
1250
|
[],
|
|
878
1251
|
this.opts
|
|
879
1252
|
);
|
|
1253
|
+
this.marketLastSlotCache.set(marketIndex.toNumber(), slot);
|
|
880
1254
|
return txSig;
|
|
881
1255
|
}
|
|
882
1256
|
|
|
883
|
-
public async
|
|
884
|
-
|
|
1257
|
+
public async getAddLiquidityIx(
|
|
1258
|
+
amount: BN,
|
|
1259
|
+
marketIndex: BN
|
|
885
1260
|
): Promise<TransactionInstruction> {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
const oracleAccountInfos = [];
|
|
891
|
-
for (const marketIndex of marketIndexes) {
|
|
892
|
-
if (!marketIndex.eq(new BN(100))) {
|
|
893
|
-
const market = this.getMarketAccount(marketIndex);
|
|
894
|
-
marketAccountInfos.push({
|
|
895
|
-
pubkey: market.pubkey,
|
|
896
|
-
isWritable: true,
|
|
897
|
-
isSigner: false,
|
|
898
|
-
});
|
|
899
|
-
oracleAccountInfos.push({
|
|
900
|
-
pubkey: market.amm.oracle,
|
|
901
|
-
isWritable: false,
|
|
902
|
-
isSigner: false,
|
|
903
|
-
});
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
const remainingAccounts = oracleAccountInfos.concat(marketAccountInfos);
|
|
1261
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1262
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1263
|
+
writableMarketIndex: marketIndex,
|
|
1264
|
+
});
|
|
907
1265
|
|
|
908
|
-
return
|
|
1266
|
+
return this.program.instruction.addLiquidity(amount, marketIndex, {
|
|
909
1267
|
accounts: {
|
|
910
1268
|
state: await this.getStatePublicKey(),
|
|
1269
|
+
user: userAccountPublicKey,
|
|
911
1270
|
authority: this.wallet.publicKey,
|
|
912
1271
|
},
|
|
913
|
-
remainingAccounts,
|
|
1272
|
+
remainingAccounts: remainingAccounts,
|
|
914
1273
|
});
|
|
915
1274
|
}
|
|
916
1275
|
|
|
917
|
-
public async
|
|
918
|
-
|
|
919
|
-
|
|
1276
|
+
public async openPosition(
|
|
1277
|
+
direction: PositionDirection,
|
|
1278
|
+
amount: BN,
|
|
1279
|
+
marketIndex: BN,
|
|
1280
|
+
limitPrice?: BN
|
|
1281
|
+
): Promise<TransactionSignature> {
|
|
1282
|
+
return await this.placeAndTake({
|
|
1283
|
+
orderType: OrderType.MARKET,
|
|
1284
|
+
marketIndex,
|
|
1285
|
+
direction,
|
|
1286
|
+
baseAssetAmount: amount,
|
|
1287
|
+
price: limitPrice,
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
public async placeOrder(
|
|
1292
|
+
orderParams: OptionalOrderParams
|
|
1293
|
+
): Promise<TransactionSignature> {
|
|
1294
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1295
|
+
wrapInTx(await this.getPlaceOrderIx(orderParams)),
|
|
920
1296
|
[],
|
|
921
1297
|
this.opts
|
|
922
1298
|
);
|
|
1299
|
+
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
923
1300
|
return txSig;
|
|
924
1301
|
}
|
|
925
1302
|
|
|
926
|
-
|
|
1303
|
+
getOrderParams(optionalOrderParams: OptionalOrderParams): OrderParams {
|
|
1304
|
+
return Object.assign({}, DefaultOrderParams, optionalOrderParams);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
public async getPlaceOrderIx(
|
|
1308
|
+
orderParams: OptionalOrderParams
|
|
1309
|
+
): Promise<TransactionInstruction> {
|
|
1310
|
+
orderParams = this.getOrderParams(orderParams);
|
|
927
1311
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
928
1312
|
|
|
929
|
-
const remainingAccounts = this.getRemainingAccounts({
|
|
1313
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1314
|
+
readableMarketIndex: orderParams.marketIndex,
|
|
1315
|
+
});
|
|
930
1316
|
|
|
931
|
-
return await this.program.instruction.
|
|
1317
|
+
return await this.program.instruction.placeOrder(orderParams, {
|
|
932
1318
|
accounts: {
|
|
933
1319
|
state: await this.getStatePublicKey(),
|
|
934
1320
|
user: userAccountPublicKey,
|
|
1321
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
935
1322
|
authority: this.wallet.publicKey,
|
|
936
1323
|
},
|
|
937
1324
|
remainingAccounts,
|
|
938
1325
|
});
|
|
939
1326
|
}
|
|
940
1327
|
|
|
941
|
-
public async
|
|
942
|
-
userOrderId: number
|
|
943
|
-
): Promise<TransactionSignature> {
|
|
1328
|
+
public async updateAMMs(marketIndexes: BN[]): Promise<TransactionSignature> {
|
|
944
1329
|
const { txSig } = await this.txSender.send(
|
|
945
|
-
wrapInTx(await this.
|
|
1330
|
+
wrapInTx(await this.getUpdateAMMsIx(marketIndexes)),
|
|
946
1331
|
[],
|
|
947
1332
|
this.opts
|
|
948
1333
|
);
|
|
949
1334
|
return txSig;
|
|
950
1335
|
}
|
|
951
1336
|
|
|
952
|
-
public async
|
|
953
|
-
|
|
1337
|
+
public async getUpdateAMMsIx(
|
|
1338
|
+
marketIndexes: BN[]
|
|
954
1339
|
): Promise<TransactionInstruction> {
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
const
|
|
1340
|
+
for (let i = marketIndexes.length; i < 5; i++) {
|
|
1341
|
+
marketIndexes.push(new BN(100));
|
|
1342
|
+
}
|
|
1343
|
+
const marketAccountInfos = [];
|
|
1344
|
+
const oracleAccountInfos = [];
|
|
1345
|
+
for (const marketIndex of marketIndexes) {
|
|
1346
|
+
if (!marketIndex.eq(new BN(100))) {
|
|
1347
|
+
const market = this.getMarketAccount(marketIndex);
|
|
1348
|
+
marketAccountInfos.push({
|
|
1349
|
+
pubkey: market.pubkey,
|
|
1350
|
+
isWritable: true,
|
|
1351
|
+
isSigner: false,
|
|
1352
|
+
});
|
|
1353
|
+
oracleAccountInfos.push({
|
|
1354
|
+
pubkey: market.amm.oracle,
|
|
1355
|
+
isWritable: false,
|
|
1356
|
+
isSigner: false,
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
const remainingAccounts = oracleAccountInfos.concat(marketAccountInfos);
|
|
961
1361
|
|
|
962
|
-
return await this.program.instruction.
|
|
1362
|
+
return await this.program.instruction.updateAmms(marketIndexes, {
|
|
963
1363
|
accounts: {
|
|
964
1364
|
state: await this.getStatePublicKey(),
|
|
965
|
-
user: userAccountPublicKey,
|
|
966
1365
|
authority: this.wallet.publicKey,
|
|
967
|
-
oracle,
|
|
968
1366
|
},
|
|
969
1367
|
remainingAccounts,
|
|
970
1368
|
});
|
|
971
1369
|
}
|
|
972
1370
|
|
|
973
|
-
public async
|
|
974
|
-
bestEffort?: boolean
|
|
975
|
-
): Promise<TransactionSignature> {
|
|
1371
|
+
public async cancelOrder(orderId?: BN): Promise<TransactionSignature> {
|
|
976
1372
|
const { txSig } = await this.txSender.send(
|
|
977
|
-
wrapInTx(await this.
|
|
1373
|
+
wrapInTx(await this.getCancelOrderIx(orderId)),
|
|
978
1374
|
[],
|
|
979
1375
|
this.opts
|
|
980
1376
|
);
|
|
981
1377
|
return txSig;
|
|
982
1378
|
}
|
|
983
1379
|
|
|
984
|
-
public async
|
|
985
|
-
bestEffort?: boolean
|
|
986
|
-
): Promise<TransactionInstruction> {
|
|
1380
|
+
public async getCancelOrderIx(orderId?: BN): Promise<TransactionInstruction> {
|
|
987
1381
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
988
1382
|
|
|
989
1383
|
const remainingAccounts = this.getRemainingAccounts({});
|
|
990
1384
|
|
|
991
|
-
|
|
992
|
-
const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
|
|
993
|
-
remainingAccounts.push({
|
|
994
|
-
pubkey: oracle,
|
|
995
|
-
isWritable: false,
|
|
996
|
-
isSigner: false,
|
|
997
|
-
});
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
return await this.program.instruction.cancelAllOrders(bestEffort, {
|
|
1385
|
+
return await this.program.instruction.cancelOrder(orderId ?? null, {
|
|
1001
1386
|
accounts: {
|
|
1002
1387
|
state: await this.getStatePublicKey(),
|
|
1003
1388
|
user: userAccountPublicKey,
|
|
@@ -1007,67 +1392,54 @@ export class ClearingHouse {
|
|
|
1007
1392
|
});
|
|
1008
1393
|
}
|
|
1009
1394
|
|
|
1010
|
-
public async
|
|
1011
|
-
|
|
1012
|
-
marketIndexOnly?: BN,
|
|
1013
|
-
directionOnly?: PositionDirection
|
|
1395
|
+
public async cancelOrderByUserId(
|
|
1396
|
+
userOrderId: number
|
|
1014
1397
|
): Promise<TransactionSignature> {
|
|
1015
1398
|
const { txSig } = await this.txSender.send(
|
|
1016
|
-
wrapInTx(
|
|
1017
|
-
await this.getCancelOrdersByMarketAndSideIx(
|
|
1018
|
-
bestEffort,
|
|
1019
|
-
marketIndexOnly,
|
|
1020
|
-
directionOnly
|
|
1021
|
-
)
|
|
1022
|
-
),
|
|
1399
|
+
wrapInTx(await this.getCancelOrderByUserIdIx(userOrderId)),
|
|
1023
1400
|
[],
|
|
1024
1401
|
this.opts
|
|
1025
1402
|
);
|
|
1026
1403
|
return txSig;
|
|
1027
1404
|
}
|
|
1028
1405
|
|
|
1029
|
-
public async
|
|
1030
|
-
|
|
1031
|
-
marketIndexOnly?: BN,
|
|
1032
|
-
directionOnly?: PositionDirection
|
|
1406
|
+
public async getCancelOrderByUserIdIx(
|
|
1407
|
+
userOrderId: number
|
|
1033
1408
|
): Promise<TransactionInstruction> {
|
|
1034
1409
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1035
1410
|
|
|
1036
|
-
const
|
|
1411
|
+
const order = this.getOrderByUserId(userOrderId);
|
|
1412
|
+
const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
|
|
1037
1413
|
|
|
1038
|
-
|
|
1039
|
-
const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
|
|
1040
|
-
remainingAccounts.push({
|
|
1041
|
-
pubkey: oracle,
|
|
1042
|
-
isWritable: false,
|
|
1043
|
-
isSigner: false,
|
|
1044
|
-
});
|
|
1045
|
-
}
|
|
1414
|
+
const remainingAccounts = this.getRemainingAccounts({});
|
|
1046
1415
|
|
|
1047
|
-
return await this.program.instruction.
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
},
|
|
1057
|
-
remainingAccounts,
|
|
1058
|
-
}
|
|
1059
|
-
);
|
|
1416
|
+
return await this.program.instruction.cancelOrderByUserId(userOrderId, {
|
|
1417
|
+
accounts: {
|
|
1418
|
+
state: await this.getStatePublicKey(),
|
|
1419
|
+
user: userAccountPublicKey,
|
|
1420
|
+
authority: this.wallet.publicKey,
|
|
1421
|
+
oracle,
|
|
1422
|
+
},
|
|
1423
|
+
remainingAccounts,
|
|
1424
|
+
});
|
|
1060
1425
|
}
|
|
1061
1426
|
|
|
1062
1427
|
public async fillOrder(
|
|
1063
1428
|
userAccountPublicKey: PublicKey,
|
|
1064
1429
|
user: UserAccount,
|
|
1065
1430
|
order?: Order,
|
|
1066
|
-
makerInfo?: MakerInfo
|
|
1431
|
+
makerInfo?: MakerInfo,
|
|
1432
|
+
referrerInfo?: ReferrerInfo
|
|
1067
1433
|
): Promise<TransactionSignature> {
|
|
1068
1434
|
const { txSig } = await this.txSender.send(
|
|
1069
1435
|
wrapInTx(
|
|
1070
|
-
await this.getFillOrderIx(
|
|
1436
|
+
await this.getFillOrderIx(
|
|
1437
|
+
userAccountPublicKey,
|
|
1438
|
+
user,
|
|
1439
|
+
order,
|
|
1440
|
+
makerInfo,
|
|
1441
|
+
referrerInfo
|
|
1442
|
+
)
|
|
1071
1443
|
),
|
|
1072
1444
|
[],
|
|
1073
1445
|
this.opts
|
|
@@ -1079,56 +1451,82 @@ export class ClearingHouse {
|
|
|
1079
1451
|
userAccountPublicKey: PublicKey,
|
|
1080
1452
|
userAccount: UserAccount,
|
|
1081
1453
|
order: Order,
|
|
1082
|
-
makerInfo?: MakerInfo
|
|
1454
|
+
makerInfo?: MakerInfo,
|
|
1455
|
+
referrerInfo?: ReferrerInfo
|
|
1083
1456
|
): Promise<TransactionInstruction> {
|
|
1457
|
+
const userStatsPublicKey = getUserStatsAccountPublicKey(
|
|
1458
|
+
this.program.programId,
|
|
1459
|
+
userAccount.authority
|
|
1460
|
+
);
|
|
1461
|
+
|
|
1084
1462
|
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
1463
|
+
const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
1085
1464
|
|
|
1086
|
-
const marketIndex = order
|
|
1465
|
+
const marketIndex = order
|
|
1466
|
+
? order.marketIndex
|
|
1467
|
+
: userAccount.orders.find((order) =>
|
|
1468
|
+
order.orderId.eq(userAccount.nextOrderId.sub(ONE))
|
|
1469
|
+
).marketIndex;
|
|
1087
1470
|
const marketAccount = this.getMarketAccount(marketIndex);
|
|
1088
|
-
const oracle = marketAccount.amm.oracle;
|
|
1089
1471
|
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1472
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
1473
|
+
const bankAccountMap = new Map<number, AccountMeta>();
|
|
1474
|
+
const marketAccountMap = new Map<number, AccountMeta>();
|
|
1475
|
+
|
|
1476
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
1477
|
+
if (!bankBalance.balance.eq(ZERO)) {
|
|
1478
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
1479
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
1480
|
+
pubkey: bankAccount.pubkey,
|
|
1481
|
+
isSigner: false,
|
|
1482
|
+
isWritable: false,
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
if (!bankAccount.oracle.equals(PublicKey.default)) {
|
|
1486
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
1487
|
+
pubkey: bankAccount.oracle,
|
|
1488
|
+
isSigner: false,
|
|
1489
|
+
isWritable: false,
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1111
1495
|
for (const position of userAccount.positions) {
|
|
1112
1496
|
if (
|
|
1113
1497
|
!positionIsAvailable(position) &&
|
|
1114
1498
|
!position.marketIndex.eq(order.marketIndex)
|
|
1115
1499
|
) {
|
|
1116
1500
|
const market = this.getMarketAccount(position.marketIndex);
|
|
1117
|
-
|
|
1501
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
1118
1502
|
pubkey: market.pubkey,
|
|
1119
1503
|
isWritable: false,
|
|
1120
1504
|
isSigner: false,
|
|
1121
1505
|
});
|
|
1122
|
-
|
|
1506
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1123
1507
|
pubkey: market.amm.oracle,
|
|
1124
1508
|
isWritable: false,
|
|
1125
1509
|
isSigner: false,
|
|
1126
1510
|
});
|
|
1127
1511
|
}
|
|
1128
1512
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1513
|
+
|
|
1514
|
+
marketAccountMap.set(marketIndex.toNumber(), {
|
|
1515
|
+
pubkey: marketAccount.pubkey,
|
|
1516
|
+
isWritable: true,
|
|
1517
|
+
isSigner: false,
|
|
1518
|
+
});
|
|
1519
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
1520
|
+
pubkey: marketAccount.amm.oracle,
|
|
1521
|
+
isWritable: false,
|
|
1522
|
+
isSigner: false,
|
|
1523
|
+
});
|
|
1524
|
+
|
|
1525
|
+
const remainingAccounts = [
|
|
1526
|
+
...oracleAccountMap.values(),
|
|
1527
|
+
...bankAccountMap.values(),
|
|
1528
|
+
...marketAccountMap.values(),
|
|
1529
|
+
];
|
|
1132
1530
|
|
|
1133
1531
|
if (makerInfo) {
|
|
1134
1532
|
remainingAccounts.push({
|
|
@@ -1136,17 +1534,37 @@ export class ClearingHouse {
|
|
|
1136
1534
|
isWritable: true,
|
|
1137
1535
|
isSigner: false,
|
|
1138
1536
|
});
|
|
1537
|
+
remainingAccounts.push({
|
|
1538
|
+
pubkey: makerInfo.makerStats,
|
|
1539
|
+
isWritable: true,
|
|
1540
|
+
isSigner: false,
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
if (referrerInfo) {
|
|
1545
|
+
remainingAccounts.push({
|
|
1546
|
+
pubkey: referrerInfo.referrer,
|
|
1547
|
+
isWritable: true,
|
|
1548
|
+
isSigner: false,
|
|
1549
|
+
});
|
|
1550
|
+
remainingAccounts.push({
|
|
1551
|
+
pubkey: referrerInfo.referrerStats,
|
|
1552
|
+
isWritable: true,
|
|
1553
|
+
isSigner: false,
|
|
1554
|
+
});
|
|
1139
1555
|
}
|
|
1140
1556
|
|
|
1141
1557
|
const orderId = order.orderId;
|
|
1142
1558
|
const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
|
|
1559
|
+
|
|
1143
1560
|
return await this.program.instruction.fillOrder(orderId, makerOrderId, {
|
|
1144
1561
|
accounts: {
|
|
1145
1562
|
state: await this.getStatePublicKey(),
|
|
1146
1563
|
filler: fillerPublicKey,
|
|
1564
|
+
fillerStats: fillerStatsPublicKey,
|
|
1147
1565
|
user: userAccountPublicKey,
|
|
1566
|
+
userStats: userStatsPublicKey,
|
|
1148
1567
|
authority: this.wallet.publicKey,
|
|
1149
|
-
oracle: oracle,
|
|
1150
1568
|
},
|
|
1151
1569
|
remainingAccounts,
|
|
1152
1570
|
});
|
|
@@ -1175,55 +1593,71 @@ export class ClearingHouse {
|
|
|
1175
1593
|
const marketIndex = order.marketIndex;
|
|
1176
1594
|
const marketAccount = this.getMarketAccount(marketIndex);
|
|
1177
1595
|
|
|
1178
|
-
const
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1596
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
1597
|
+
const bankAccountMap = new Map<number, AccountMeta>();
|
|
1598
|
+
const marketAccountMap = new Map<number, AccountMeta>();
|
|
1599
|
+
|
|
1600
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
1601
|
+
if (!bankBalance.balance.eq(ZERO)) {
|
|
1602
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
1603
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
1604
|
+
pubkey: bankAccount.pubkey,
|
|
1605
|
+
isSigner: false,
|
|
1606
|
+
isWritable: false,
|
|
1607
|
+
});
|
|
1608
|
+
|
|
1609
|
+
if (!bankAccount.oracle.equals(PublicKey.default)) {
|
|
1610
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
1611
|
+
pubkey: bankAccount.oracle,
|
|
1612
|
+
isSigner: false,
|
|
1613
|
+
isWritable: false,
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1199
1619
|
for (const position of userAccount.positions) {
|
|
1200
1620
|
if (
|
|
1201
1621
|
!positionIsAvailable(position) &&
|
|
1202
1622
|
!position.marketIndex.eq(order.marketIndex)
|
|
1203
1623
|
) {
|
|
1204
1624
|
const market = this.getMarketAccount(position.marketIndex);
|
|
1205
|
-
|
|
1625
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
1206
1626
|
pubkey: market.pubkey,
|
|
1207
1627
|
isWritable: false,
|
|
1208
1628
|
isSigner: false,
|
|
1209
1629
|
});
|
|
1210
|
-
|
|
1630
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1211
1631
|
pubkey: market.amm.oracle,
|
|
1212
1632
|
isWritable: false,
|
|
1213
1633
|
isSigner: false,
|
|
1214
1634
|
});
|
|
1215
1635
|
}
|
|
1216
1636
|
}
|
|
1217
|
-
const remainingAccounts = oracleAccountInfos.concat(
|
|
1218
|
-
bankAccountInfos.concat(marketAccountInfos)
|
|
1219
|
-
);
|
|
1220
1637
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1638
|
+
marketAccountMap.set(marketIndex.toNumber(), {
|
|
1639
|
+
pubkey: marketAccount.pubkey,
|
|
1640
|
+
isWritable: true,
|
|
1641
|
+
isSigner: false,
|
|
1642
|
+
});
|
|
1643
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
1644
|
+
pubkey: marketAccount.amm.oracle,
|
|
1645
|
+
isWritable: false,
|
|
1646
|
+
isSigner: false,
|
|
1647
|
+
});
|
|
1648
|
+
|
|
1649
|
+
const remainingAccounts = [
|
|
1650
|
+
...oracleAccountMap.values(),
|
|
1651
|
+
...bankAccountMap.values(),
|
|
1652
|
+
...marketAccountMap.values(),
|
|
1653
|
+
];
|
|
1654
|
+
|
|
1655
|
+
const orderId = order.orderId;
|
|
1656
|
+
return await this.program.instruction.triggerOrder(orderId, {
|
|
1657
|
+
accounts: {
|
|
1658
|
+
state: await this.getStatePublicKey(),
|
|
1659
|
+
filler: fillerPublicKey,
|
|
1660
|
+
user: userAccountPublicKey,
|
|
1227
1661
|
authority: this.wallet.publicKey,
|
|
1228
1662
|
},
|
|
1229
1663
|
remainingAccounts,
|
|
@@ -1231,11 +1665,14 @@ export class ClearingHouse {
|
|
|
1231
1665
|
}
|
|
1232
1666
|
|
|
1233
1667
|
public async placeAndTake(
|
|
1234
|
-
orderParams:
|
|
1235
|
-
makerInfo?: MakerInfo
|
|
1668
|
+
orderParams: OptionalOrderParams,
|
|
1669
|
+
makerInfo?: MakerInfo,
|
|
1670
|
+
referrerInfo?: ReferrerInfo
|
|
1236
1671
|
): Promise<TransactionSignature> {
|
|
1237
1672
|
const { txSig, slot } = await this.txSender.send(
|
|
1238
|
-
wrapInTx(
|
|
1673
|
+
wrapInTx(
|
|
1674
|
+
await this.getPlaceAndTakeIx(orderParams, makerInfo, referrerInfo)
|
|
1675
|
+
),
|
|
1239
1676
|
[],
|
|
1240
1677
|
this.opts
|
|
1241
1678
|
);
|
|
@@ -1244,14 +1681,14 @@ export class ClearingHouse {
|
|
|
1244
1681
|
}
|
|
1245
1682
|
|
|
1246
1683
|
public async getPlaceAndTakeIx(
|
|
1247
|
-
orderParams:
|
|
1248
|
-
makerInfo?: MakerInfo
|
|
1684
|
+
orderParams: OptionalOrderParams,
|
|
1685
|
+
makerInfo?: MakerInfo,
|
|
1686
|
+
referrerInfo?: ReferrerInfo
|
|
1249
1687
|
): Promise<TransactionInstruction> {
|
|
1688
|
+
orderParams = this.getOrderParams(orderParams);
|
|
1689
|
+
const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
|
|
1250
1690
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1251
1691
|
|
|
1252
|
-
const priceOracle = this.getMarketAccount(orderParams.marketIndex).amm
|
|
1253
|
-
.oracle;
|
|
1254
|
-
|
|
1255
1692
|
const remainingAccounts = this.getRemainingAccounts({
|
|
1256
1693
|
writableMarketIndex: orderParams.marketIndex,
|
|
1257
1694
|
writableBankIndex: QUOTE_ASSET_BANK_INDEX,
|
|
@@ -1265,6 +1702,24 @@ export class ClearingHouse {
|
|
|
1265
1702
|
isSigner: false,
|
|
1266
1703
|
isWritable: true,
|
|
1267
1704
|
});
|
|
1705
|
+
remainingAccounts.push({
|
|
1706
|
+
pubkey: makerInfo.makerStats,
|
|
1707
|
+
isSigner: false,
|
|
1708
|
+
isWritable: true,
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
if (referrerInfo) {
|
|
1713
|
+
remainingAccounts.push({
|
|
1714
|
+
pubkey: referrerInfo.referrer,
|
|
1715
|
+
isWritable: true,
|
|
1716
|
+
isSigner: false,
|
|
1717
|
+
});
|
|
1718
|
+
remainingAccounts.push({
|
|
1719
|
+
pubkey: referrerInfo.referrerStats,
|
|
1720
|
+
isWritable: true,
|
|
1721
|
+
isSigner: false,
|
|
1722
|
+
});
|
|
1268
1723
|
}
|
|
1269
1724
|
|
|
1270
1725
|
return await this.program.instruction.placeAndTake(
|
|
@@ -1274,8 +1729,70 @@ export class ClearingHouse {
|
|
|
1274
1729
|
accounts: {
|
|
1275
1730
|
state: await this.getStatePublicKey(),
|
|
1276
1731
|
user: userAccountPublicKey,
|
|
1732
|
+
userStats: userStatsPublicKey,
|
|
1733
|
+
authority: this.wallet.publicKey,
|
|
1734
|
+
},
|
|
1735
|
+
remainingAccounts,
|
|
1736
|
+
}
|
|
1737
|
+
);
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
public async placeAndMake(
|
|
1741
|
+
orderParams: OptionalOrderParams,
|
|
1742
|
+
takerInfo: TakerInfo,
|
|
1743
|
+
referrerInfo?: ReferrerInfo
|
|
1744
|
+
): Promise<TransactionSignature> {
|
|
1745
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1746
|
+
wrapInTx(
|
|
1747
|
+
await this.getPlaceAndMakeIx(orderParams, takerInfo, referrerInfo)
|
|
1748
|
+
),
|
|
1749
|
+
[],
|
|
1750
|
+
this.opts
|
|
1751
|
+
);
|
|
1752
|
+
|
|
1753
|
+
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
1754
|
+
|
|
1755
|
+
return txSig;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
public async getPlaceAndMakeIx(
|
|
1759
|
+
orderParams: OptionalOrderParams,
|
|
1760
|
+
takerInfo: TakerInfo,
|
|
1761
|
+
referrerInfo?: ReferrerInfo
|
|
1762
|
+
): Promise<TransactionInstruction> {
|
|
1763
|
+
orderParams = this.getOrderParams(orderParams);
|
|
1764
|
+
const userStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
1765
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1766
|
+
|
|
1767
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1768
|
+
writableMarketIndex: orderParams.marketIndex,
|
|
1769
|
+
});
|
|
1770
|
+
|
|
1771
|
+
if (referrerInfo) {
|
|
1772
|
+
remainingAccounts.push({
|
|
1773
|
+
pubkey: referrerInfo.referrer,
|
|
1774
|
+
isWritable: true,
|
|
1775
|
+
isSigner: false,
|
|
1776
|
+
});
|
|
1777
|
+
remainingAccounts.push({
|
|
1778
|
+
pubkey: referrerInfo.referrerStats,
|
|
1779
|
+
isWritable: true,
|
|
1780
|
+
isSigner: false,
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
const takerOrderId = takerInfo!.order!.orderId;
|
|
1785
|
+
return await this.program.instruction.placeAndMake(
|
|
1786
|
+
orderParams,
|
|
1787
|
+
takerOrderId,
|
|
1788
|
+
{
|
|
1789
|
+
accounts: {
|
|
1790
|
+
state: await this.getStatePublicKey(),
|
|
1791
|
+
user: userAccountPublicKey,
|
|
1792
|
+
userStats: userStatsPublicKey,
|
|
1793
|
+
taker: takerInfo.taker,
|
|
1794
|
+
takerStats: takerInfo.takerStats,
|
|
1277
1795
|
authority: this.wallet.publicKey,
|
|
1278
|
-
oracle: priceOracle,
|
|
1279
1796
|
},
|
|
1280
1797
|
remainingAccounts,
|
|
1281
1798
|
}
|
|
@@ -1287,22 +1804,23 @@ export class ClearingHouse {
|
|
|
1287
1804
|
* @param marketIndex
|
|
1288
1805
|
* @returns
|
|
1289
1806
|
*/
|
|
1290
|
-
public async closePosition(
|
|
1807
|
+
public async closePosition(
|
|
1808
|
+
marketIndex: BN,
|
|
1809
|
+
limitPrice?: BN
|
|
1810
|
+
): Promise<TransactionSignature> {
|
|
1291
1811
|
const userPosition = this.getUser().getUserPosition(marketIndex);
|
|
1292
1812
|
if (!userPosition) {
|
|
1293
1813
|
throw Error(`No position in market ${marketIndex.toString()}`);
|
|
1294
1814
|
}
|
|
1295
1815
|
|
|
1296
|
-
return await this.placeAndTake(
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
)
|
|
1305
|
-
);
|
|
1816
|
+
return await this.placeAndTake({
|
|
1817
|
+
orderType: OrderType.MARKET,
|
|
1818
|
+
marketIndex,
|
|
1819
|
+
direction: findDirectionToClose(userPosition),
|
|
1820
|
+
baseAssetAmount: userPosition.baseAssetAmount.abs(),
|
|
1821
|
+
reduceOnly: true,
|
|
1822
|
+
price: limitPrice,
|
|
1823
|
+
});
|
|
1306
1824
|
}
|
|
1307
1825
|
|
|
1308
1826
|
public async settlePNLs(
|
|
@@ -1323,7 +1841,14 @@ export class ClearingHouse {
|
|
|
1323
1841
|
);
|
|
1324
1842
|
}
|
|
1325
1843
|
|
|
1326
|
-
const tx = new Transaction()
|
|
1844
|
+
const tx = new Transaction()
|
|
1845
|
+
.add(
|
|
1846
|
+
ComputeBudgetProgram.requestUnits({
|
|
1847
|
+
units: 1_000_000,
|
|
1848
|
+
additionalFee: 0,
|
|
1849
|
+
})
|
|
1850
|
+
)
|
|
1851
|
+
.add(...ixs);
|
|
1327
1852
|
|
|
1328
1853
|
const { txSig } = await this.txSender.send(tx, [], this.opts);
|
|
1329
1854
|
return txSig;
|
|
@@ -1356,12 +1881,13 @@ export class ClearingHouse {
|
|
|
1356
1881
|
const marketAccountMap = new Map<number, AccountMeta>();
|
|
1357
1882
|
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
1358
1883
|
const bankAccountMap = new Map<number, AccountMeta>();
|
|
1884
|
+
|
|
1359
1885
|
for (const position of settleeUserAccount.positions) {
|
|
1360
1886
|
if (!positionIsAvailable(position)) {
|
|
1361
1887
|
const market = this.getMarketAccount(position.marketIndex);
|
|
1362
1888
|
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
1363
1889
|
pubkey: market.pubkey,
|
|
1364
|
-
isWritable:
|
|
1890
|
+
isWritable: false,
|
|
1365
1891
|
isSigner: false,
|
|
1366
1892
|
});
|
|
1367
1893
|
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
@@ -1424,72 +1950,451 @@ export class ClearingHouse {
|
|
|
1424
1950
|
});
|
|
1425
1951
|
}
|
|
1426
1952
|
|
|
1427
|
-
public async
|
|
1428
|
-
|
|
1953
|
+
public async liquidatePerp(
|
|
1954
|
+
userAccountPublicKey: PublicKey,
|
|
1955
|
+
userAccount: UserAccount,
|
|
1956
|
+
marketIndex: BN,
|
|
1957
|
+
maxBaseAssetAmount: BN
|
|
1958
|
+
): Promise<TransactionSignature> {
|
|
1959
|
+
const { txSig } = await this.txSender.send(
|
|
1960
|
+
wrapInTx(
|
|
1961
|
+
await this.getLiquidatePerpIx(
|
|
1962
|
+
userAccountPublicKey,
|
|
1963
|
+
userAccount,
|
|
1964
|
+
marketIndex,
|
|
1965
|
+
maxBaseAssetAmount
|
|
1966
|
+
)
|
|
1967
|
+
),
|
|
1968
|
+
[],
|
|
1969
|
+
this.opts
|
|
1970
|
+
);
|
|
1971
|
+
return txSig;
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
public async getLiquidatePerpIx(
|
|
1975
|
+
userAccountPublicKey: PublicKey,
|
|
1976
|
+
userAccount: UserAccount,
|
|
1977
|
+
marketIndex: BN,
|
|
1978
|
+
maxBaseAssetAmount: BN
|
|
1979
|
+
): Promise<TransactionInstruction> {
|
|
1980
|
+
const userStatsPublicKey = getUserStatsAccountPublicKey(
|
|
1981
|
+
this.program.programId,
|
|
1982
|
+
userAccount.authority
|
|
1983
|
+
);
|
|
1984
|
+
|
|
1985
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1986
|
+
const liquidatorStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
1987
|
+
|
|
1988
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1989
|
+
writableMarketIndex: marketIndex,
|
|
1990
|
+
userAccount,
|
|
1991
|
+
});
|
|
1992
|
+
|
|
1993
|
+
return await this.program.instruction.liquidatePerp(
|
|
1994
|
+
marketIndex,
|
|
1995
|
+
maxBaseAssetAmount,
|
|
1996
|
+
{
|
|
1997
|
+
accounts: {
|
|
1998
|
+
state: await this.getStatePublicKey(),
|
|
1999
|
+
authority: this.wallet.publicKey,
|
|
2000
|
+
user: userAccountPublicKey,
|
|
2001
|
+
userStats: userStatsPublicKey,
|
|
2002
|
+
liquidator: liquidatorPublicKey,
|
|
2003
|
+
liquidatorStats: liquidatorStatsPublicKey,
|
|
2004
|
+
},
|
|
2005
|
+
remainingAccounts: remainingAccounts,
|
|
2006
|
+
}
|
|
2007
|
+
);
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
public async liquidateBorrow(
|
|
2011
|
+
userAccountPublicKey: PublicKey,
|
|
2012
|
+
userAccount: UserAccount,
|
|
2013
|
+
assetBankIndex: BN,
|
|
2014
|
+
liabilityBankIndex: BN,
|
|
2015
|
+
maxLiabilityTransfer: BN
|
|
1429
2016
|
): Promise<TransactionSignature> {
|
|
1430
2017
|
const { txSig } = await this.txSender.send(
|
|
1431
|
-
wrapInTx(
|
|
2018
|
+
wrapInTx(
|
|
2019
|
+
await this.getLiquidateBorrowIx(
|
|
2020
|
+
userAccountPublicKey,
|
|
2021
|
+
userAccount,
|
|
2022
|
+
assetBankIndex,
|
|
2023
|
+
liabilityBankIndex,
|
|
2024
|
+
maxLiabilityTransfer
|
|
2025
|
+
)
|
|
2026
|
+
),
|
|
1432
2027
|
[],
|
|
1433
2028
|
this.opts
|
|
1434
2029
|
);
|
|
1435
2030
|
return txSig;
|
|
1436
2031
|
}
|
|
1437
2032
|
|
|
1438
|
-
public async
|
|
1439
|
-
|
|
2033
|
+
public async getLiquidateBorrowIx(
|
|
2034
|
+
userAccountPublicKey: PublicKey,
|
|
2035
|
+
userAccount: UserAccount,
|
|
2036
|
+
assetBankIndex: BN,
|
|
2037
|
+
liabilityBankIndex: BN,
|
|
2038
|
+
maxLiabilityTransfer: BN
|
|
1440
2039
|
): Promise<TransactionInstruction> {
|
|
1441
|
-
const
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
2040
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2041
|
+
|
|
2042
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
2043
|
+
userAccount,
|
|
2044
|
+
writableBankIndexes: [liabilityBankIndex, assetBankIndex],
|
|
2045
|
+
});
|
|
1445
2046
|
|
|
1446
|
-
|
|
2047
|
+
return await this.program.instruction.liquidateBorrow(
|
|
2048
|
+
assetBankIndex,
|
|
2049
|
+
liabilityBankIndex,
|
|
2050
|
+
maxLiabilityTransfer,
|
|
1447
2051
|
{
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
2052
|
+
accounts: {
|
|
2053
|
+
state: await this.getStatePublicKey(),
|
|
2054
|
+
authority: this.wallet.publicKey,
|
|
2055
|
+
user: userAccountPublicKey,
|
|
2056
|
+
liquidator: liquidatorPublicKey,
|
|
2057
|
+
},
|
|
2058
|
+
remainingAccounts: remainingAccounts,
|
|
2059
|
+
}
|
|
2060
|
+
);
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
public async liquidateBorrowForPerpPnl(
|
|
2064
|
+
userAccountPublicKey: PublicKey,
|
|
2065
|
+
userAccount: UserAccount,
|
|
2066
|
+
perpMarketIndex: BN,
|
|
2067
|
+
liabilityBankIndex: BN,
|
|
2068
|
+
maxLiabilityTransfer: BN
|
|
2069
|
+
): Promise<TransactionSignature> {
|
|
2070
|
+
const { txSig } = await this.txSender.send(
|
|
2071
|
+
wrapInTx(
|
|
2072
|
+
await this.getLiquidateBorrowForPerpPnlIx(
|
|
2073
|
+
userAccountPublicKey,
|
|
2074
|
+
userAccount,
|
|
2075
|
+
perpMarketIndex,
|
|
2076
|
+
liabilityBankIndex,
|
|
2077
|
+
maxLiabilityTransfer
|
|
2078
|
+
)
|
|
2079
|
+
),
|
|
2080
|
+
[],
|
|
2081
|
+
this.opts
|
|
2082
|
+
);
|
|
2083
|
+
return txSig;
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
public async getLiquidateBorrowForPerpPnlIx(
|
|
2087
|
+
userAccountPublicKey: PublicKey,
|
|
2088
|
+
userAccount: UserAccount,
|
|
2089
|
+
perpMarketIndex: BN,
|
|
2090
|
+
liabilityBankIndex: BN,
|
|
2091
|
+
maxLiabilityTransfer: BN
|
|
2092
|
+
): Promise<TransactionInstruction> {
|
|
2093
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2094
|
+
|
|
2095
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
2096
|
+
userAccount,
|
|
2097
|
+
writableMarketIndex: perpMarketIndex,
|
|
2098
|
+
writableBankIndexes: [liabilityBankIndex],
|
|
2099
|
+
});
|
|
2100
|
+
|
|
2101
|
+
return await this.program.instruction.liquidateBorrowForPerpPnl(
|
|
2102
|
+
perpMarketIndex,
|
|
2103
|
+
liabilityBankIndex,
|
|
2104
|
+
maxLiabilityTransfer,
|
|
2105
|
+
{
|
|
2106
|
+
accounts: {
|
|
2107
|
+
state: await this.getStatePublicKey(),
|
|
2108
|
+
authority: this.wallet.publicKey,
|
|
2109
|
+
user: userAccountPublicKey,
|
|
2110
|
+
liquidator: liquidatorPublicKey,
|
|
2111
|
+
},
|
|
2112
|
+
remainingAccounts: remainingAccounts,
|
|
2113
|
+
}
|
|
2114
|
+
);
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
public async liquidatePerpPnlForDeposit(
|
|
2118
|
+
userAccountPublicKey: PublicKey,
|
|
2119
|
+
userAccount: UserAccount,
|
|
2120
|
+
perpMarketIndex: BN,
|
|
2121
|
+
assetBankIndex: BN,
|
|
2122
|
+
maxPnlTransfer: BN
|
|
2123
|
+
): Promise<TransactionSignature> {
|
|
2124
|
+
const { txSig } = await this.txSender.send(
|
|
2125
|
+
wrapInTx(
|
|
2126
|
+
await this.getLiquidatePerpPnlForDepositIx(
|
|
2127
|
+
userAccountPublicKey,
|
|
2128
|
+
userAccount,
|
|
2129
|
+
perpMarketIndex,
|
|
2130
|
+
assetBankIndex,
|
|
2131
|
+
maxPnlTransfer
|
|
2132
|
+
)
|
|
2133
|
+
),
|
|
2134
|
+
[],
|
|
2135
|
+
this.opts
|
|
2136
|
+
);
|
|
2137
|
+
return txSig;
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
public async getLiquidatePerpPnlForDepositIx(
|
|
2141
|
+
userAccountPublicKey: PublicKey,
|
|
2142
|
+
userAccount: UserAccount,
|
|
2143
|
+
perpMarketIndex: BN,
|
|
2144
|
+
assetBankIndex: BN,
|
|
2145
|
+
maxPnlTransfer: BN
|
|
2146
|
+
): Promise<TransactionInstruction> {
|
|
2147
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2148
|
+
|
|
2149
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
2150
|
+
userAccount,
|
|
2151
|
+
writableMarketIndex: perpMarketIndex,
|
|
2152
|
+
writableBankIndexes: [assetBankIndex],
|
|
2153
|
+
});
|
|
2154
|
+
|
|
2155
|
+
return await this.program.instruction.liquidatePerpPnlForDeposit(
|
|
2156
|
+
perpMarketIndex,
|
|
2157
|
+
assetBankIndex,
|
|
2158
|
+
maxPnlTransfer,
|
|
2159
|
+
{
|
|
2160
|
+
accounts: {
|
|
2161
|
+
state: await this.getStatePublicKey(),
|
|
2162
|
+
authority: this.wallet.publicKey,
|
|
2163
|
+
user: userAccountPublicKey,
|
|
2164
|
+
liquidator: liquidatorPublicKey,
|
|
2165
|
+
},
|
|
2166
|
+
remainingAccounts: remainingAccounts,
|
|
2167
|
+
}
|
|
2168
|
+
);
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
public async resolvePerpBankruptcy(
|
|
2172
|
+
userAccountPublicKey: PublicKey,
|
|
2173
|
+
userAccount: UserAccount,
|
|
2174
|
+
marketIndex: BN
|
|
2175
|
+
): Promise<TransactionSignature> {
|
|
2176
|
+
const { txSig } = await this.txSender.send(
|
|
2177
|
+
wrapInTx(
|
|
2178
|
+
await this.getResolvePerpBankruptcyIx(
|
|
2179
|
+
userAccountPublicKey,
|
|
2180
|
+
userAccount,
|
|
2181
|
+
marketIndex
|
|
2182
|
+
)
|
|
2183
|
+
),
|
|
2184
|
+
[],
|
|
2185
|
+
this.opts
|
|
2186
|
+
);
|
|
2187
|
+
return txSig;
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
public async getResolvePerpBankruptcyIx(
|
|
2191
|
+
userAccountPublicKey: PublicKey,
|
|
2192
|
+
userAccount: UserAccount,
|
|
2193
|
+
marketIndex: BN
|
|
2194
|
+
): Promise<TransactionInstruction> {
|
|
2195
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2196
|
+
|
|
2197
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
2198
|
+
writableMarketIndex: marketIndex,
|
|
2199
|
+
userAccount,
|
|
2200
|
+
});
|
|
2201
|
+
|
|
2202
|
+
return await this.program.instruction.resolvePerpBankruptcy(marketIndex, {
|
|
2203
|
+
accounts: {
|
|
2204
|
+
state: await this.getStatePublicKey(),
|
|
2205
|
+
authority: this.wallet.publicKey,
|
|
2206
|
+
user: userAccountPublicKey,
|
|
2207
|
+
liquidator: liquidatorPublicKey,
|
|
1451
2208
|
},
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
2209
|
+
remainingAccounts: remainingAccounts,
|
|
2210
|
+
});
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
public async resolveBorrowBankruptcy(
|
|
2214
|
+
userAccountPublicKey: PublicKey,
|
|
2215
|
+
userAccount: UserAccount,
|
|
2216
|
+
bankIndex: BN
|
|
2217
|
+
): Promise<TransactionSignature> {
|
|
2218
|
+
const { txSig } = await this.txSender.send(
|
|
2219
|
+
wrapInTx(
|
|
2220
|
+
await this.getResolveBorrowBankruptcyIx(
|
|
2221
|
+
userAccountPublicKey,
|
|
2222
|
+
userAccount,
|
|
2223
|
+
bankIndex
|
|
2224
|
+
)
|
|
2225
|
+
),
|
|
2226
|
+
[],
|
|
2227
|
+
this.opts
|
|
2228
|
+
);
|
|
2229
|
+
return txSig;
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
public async getResolveBorrowBankruptcyIx(
|
|
2233
|
+
userAccountPublicKey: PublicKey,
|
|
2234
|
+
userAccount: UserAccount,
|
|
2235
|
+
bankIndex: BN
|
|
2236
|
+
): Promise<TransactionInstruction> {
|
|
2237
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2238
|
+
|
|
2239
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
2240
|
+
writableBankIndexes: [bankIndex],
|
|
2241
|
+
userAccount,
|
|
2242
|
+
});
|
|
2243
|
+
|
|
2244
|
+
return await this.program.instruction.resolveBorrowBankruptcy(bankIndex, {
|
|
2245
|
+
accounts: {
|
|
2246
|
+
state: await this.getStatePublicKey(),
|
|
2247
|
+
authority: this.wallet.publicKey,
|
|
2248
|
+
user: userAccountPublicKey,
|
|
2249
|
+
liquidator: liquidatorPublicKey,
|
|
2250
|
+
},
|
|
2251
|
+
remainingAccounts: remainingAccounts,
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
getRemainingAccountsForLiquidation(params: {
|
|
2256
|
+
userAccount: UserAccount;
|
|
2257
|
+
writableMarketIndex?: BN;
|
|
2258
|
+
writableBankIndexes?: BN[];
|
|
2259
|
+
}): AccountMeta[] {
|
|
2260
|
+
const liquidateeUserAccount = params.userAccount;
|
|
2261
|
+
|
|
2262
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
2263
|
+
const bankAccountMap = new Map<number, AccountMeta>();
|
|
2264
|
+
const marketAccountMap = new Map<number, AccountMeta>();
|
|
2265
|
+
for (const bankBalance of liquidateeUserAccount.bankBalances) {
|
|
2266
|
+
if (!bankBalance.balance.eq(ZERO)) {
|
|
2267
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
2268
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
2269
|
+
pubkey: bankAccount.pubkey,
|
|
2270
|
+
isSigner: false,
|
|
2271
|
+
isWritable: false,
|
|
2272
|
+
});
|
|
2273
|
+
|
|
2274
|
+
if (!bankAccount.oracle.equals(PublicKey.default)) {
|
|
2275
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
2276
|
+
pubkey: bankAccount.oracle,
|
|
2277
|
+
isSigner: false,
|
|
2278
|
+
isWritable: false,
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
1455
2283
|
for (const position of liquidateeUserAccount.positions) {
|
|
1456
2284
|
if (!positionIsAvailable(position)) {
|
|
1457
2285
|
const market = this.getMarketAccount(position.marketIndex);
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
);
|
|
1462
|
-
marketAccountInfos.push({
|
|
1463
|
-
pubkey: marketPublicKey,
|
|
1464
|
-
isWritable: true,
|
|
2286
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
2287
|
+
pubkey: market.pubkey,
|
|
2288
|
+
isWritable: false,
|
|
1465
2289
|
isSigner: false,
|
|
1466
2290
|
});
|
|
1467
|
-
|
|
2291
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1468
2292
|
pubkey: market.amm.oracle,
|
|
1469
2293
|
isWritable: false,
|
|
1470
2294
|
isSigner: false,
|
|
1471
2295
|
});
|
|
1472
2296
|
}
|
|
1473
2297
|
}
|
|
1474
|
-
const remainingAccounts = oracleAccountInfos.concat(
|
|
1475
|
-
bankAccountInfos.concat(marketAccountInfos)
|
|
1476
|
-
);
|
|
1477
2298
|
|
|
1478
|
-
const
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
2299
|
+
const userAccountAndSlot = this.getUserAccountAndSlot();
|
|
2300
|
+
if (!userAccountAndSlot) {
|
|
2301
|
+
throw Error(
|
|
2302
|
+
'No user account found. Most likely user account does not exist or failed to fetch account'
|
|
2303
|
+
);
|
|
2304
|
+
}
|
|
2305
|
+
const { data: userAccount, slot: lastUserPositionsSlot } =
|
|
2306
|
+
userAccountAndSlot;
|
|
2307
|
+
|
|
2308
|
+
for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
|
|
2309
|
+
// if cache has more recent slot than user positions account slot, add market to remaining accounts
|
|
2310
|
+
// otherwise remove from slot
|
|
2311
|
+
if (slot > lastUserPositionsSlot) {
|
|
2312
|
+
const marketAccount = this.getMarketAccount(marketIndexNum);
|
|
2313
|
+
marketAccountMap.set(marketIndexNum, {
|
|
2314
|
+
pubkey: marketAccount.pubkey,
|
|
2315
|
+
isSigner: false,
|
|
2316
|
+
isWritable: false,
|
|
2317
|
+
});
|
|
2318
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
2319
|
+
pubkey: marketAccount.amm.oracle,
|
|
2320
|
+
isSigner: false,
|
|
2321
|
+
isWritable: false,
|
|
2322
|
+
});
|
|
2323
|
+
} else {
|
|
2324
|
+
this.marketLastSlotCache.delete(marketIndexNum);
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
2328
|
+
if (!bankBalance.balance.eq(ZERO)) {
|
|
2329
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
2330
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
2331
|
+
pubkey: bankAccount.pubkey,
|
|
2332
|
+
isSigner: false,
|
|
2333
|
+
isWritable: false,
|
|
2334
|
+
});
|
|
2335
|
+
|
|
2336
|
+
if (!bankAccount.oracle.equals(PublicKey.default)) {
|
|
2337
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
2338
|
+
pubkey: bankAccount.oracle,
|
|
2339
|
+
isSigner: false,
|
|
2340
|
+
isWritable: false,
|
|
2341
|
+
});
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
for (const position of userAccount.positions) {
|
|
2346
|
+
if (!positionIsAvailable(position)) {
|
|
2347
|
+
const market = this.getMarketAccount(position.marketIndex);
|
|
2348
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
2349
|
+
pubkey: market.pubkey,
|
|
2350
|
+
isWritable: false,
|
|
2351
|
+
isSigner: false,
|
|
2352
|
+
});
|
|
2353
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
2354
|
+
pubkey: market.amm.oracle,
|
|
2355
|
+
isWritable: false,
|
|
2356
|
+
isSigner: false,
|
|
2357
|
+
});
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
if (params.writableMarketIndex) {
|
|
2362
|
+
const market = this.getMarketAccount(params.writableMarketIndex);
|
|
2363
|
+
marketAccountMap.set(market.marketIndex.toNumber(), {
|
|
2364
|
+
pubkey: market.pubkey,
|
|
2365
|
+
isSigner: false,
|
|
2366
|
+
isWritable: true,
|
|
2367
|
+
});
|
|
2368
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
2369
|
+
pubkey: market.amm.oracle,
|
|
2370
|
+
isSigner: false,
|
|
2371
|
+
isWritable: false,
|
|
2372
|
+
});
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
if (params.writableBankIndexes) {
|
|
2376
|
+
for (const writableBankIndex of params.writableBankIndexes) {
|
|
2377
|
+
const bank = this.getBankAccount(writableBankIndex);
|
|
2378
|
+
bankAccountMap.set(bank.bankIndex.toNumber(), {
|
|
2379
|
+
pubkey: bank.pubkey,
|
|
2380
|
+
isSigner: false,
|
|
2381
|
+
isWritable: true,
|
|
2382
|
+
});
|
|
2383
|
+
if (!bank.oracle.equals(PublicKey.default)) {
|
|
2384
|
+
oracleAccountMap.set(bank.oracle.toString(), {
|
|
2385
|
+
pubkey: bank.oracle,
|
|
2386
|
+
isSigner: false,
|
|
2387
|
+
isWritable: false,
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
return [
|
|
2394
|
+
...oracleAccountMap.values(),
|
|
2395
|
+
...bankAccountMap.values(),
|
|
2396
|
+
...marketAccountMap.values(),
|
|
2397
|
+
];
|
|
1493
2398
|
}
|
|
1494
2399
|
|
|
1495
2400
|
public async updateFundingRate(
|