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