@drift-labs/sdk 0.1.36-master.7 → 0.2.0-master.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/accounts/bulkAccountLoader.d.ts +6 -6
- package/lib/accounts/bulkAccountLoader.js +81 -95
- package/lib/accounts/bulkUserSubscription.js +13 -57
- package/lib/accounts/fetch.d.ts +4 -0
- package/lib/accounts/fetch.js +18 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +34 -38
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +224 -224
- package/lib/accounts/pollingOracleSubscriber.d.ts +3 -3
- package/lib/accounts/pollingOracleSubscriber.js +37 -49
- package/lib/accounts/pollingTokenAccountSubscriber.d.ts +3 -3
- package/lib/accounts/pollingTokenAccountSubscriber.js +35 -50
- package/lib/accounts/pollingUserAccountSubscriber.d.ts +7 -13
- package/lib/accounts/pollingUserAccountSubscriber.js +71 -134
- package/lib/accounts/types.d.ts +34 -41
- package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -4
- package/lib/accounts/webSocketAccountSubscriber.js +39 -35
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +33 -28
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +153 -185
- package/lib/accounts/webSocketUserAccountSubscriber.d.ts +5 -11
- package/lib/accounts/webSocketUserAccountSubscriber.js +22 -67
- package/lib/addresses/marketAddresses.d.ts +4 -0
- package/lib/addresses/marketAddresses.js +15 -0
- package/lib/addresses/pda.d.ts +12 -0
- package/lib/addresses/pda.js +83 -0
- package/lib/admin.d.ts +12 -18
- package/lib/admin.js +398 -558
- package/lib/clearingHouse.d.ts +83 -109
- package/lib/clearingHouse.js +832 -893
- package/lib/clearingHouseConfig.d.ts +34 -0
- package/lib/clearingHouseConfig.js +2 -0
- package/lib/clearingHouseUser.d.ts +19 -22
- package/lib/clearingHouseUser.js +155 -141
- package/lib/clearingHouseUserConfig.d.ts +14 -0
- package/lib/clearingHouseUserConfig.js +2 -0
- package/lib/config.d.ts +12 -0
- package/lib/config.js +35 -4
- package/lib/constants/banks.d.ts +16 -0
- package/lib/constants/banks.js +41 -0
- package/lib/constants/markets.d.ts +8 -3
- package/lib/constants/markets.js +13 -206
- package/lib/constants/numericConstants.d.ts +17 -0
- package/lib/constants/numericConstants.js +23 -6
- package/lib/events/eventList.d.ts +22 -0
- package/lib/events/eventList.js +77 -0
- package/lib/events/eventSubscriber.d.ts +34 -0
- package/lib/events/eventSubscriber.js +126 -0
- package/lib/events/fetchLogs.d.ts +13 -0
- package/lib/events/fetchLogs.js +39 -0
- package/lib/events/pollingLogProvider.d.ts +15 -0
- package/lib/events/pollingLogProvider.js +53 -0
- package/lib/events/sort.d.ts +2 -0
- package/lib/events/sort.js +44 -0
- package/lib/events/txEventCache.d.ts +24 -0
- package/lib/events/txEventCache.js +71 -0
- package/lib/events/types.d.ts +49 -0
- package/lib/events/types.js +20 -0
- package/lib/events/webSocketLogProvider.d.ts +12 -0
- package/lib/events/webSocketLogProvider.js +30 -0
- package/lib/examples/makeTradeExample.js +26 -27
- package/lib/factory/bigNum.d.ts +118 -0
- package/lib/factory/bigNum.js +364 -0
- package/lib/factory/oracleClient.d.ts +1 -2
- package/lib/factory/oracleClient.js +6 -2
- package/lib/idl/clearing_house.json +2258 -2774
- package/lib/index.d.ts +14 -5
- package/lib/index.js +18 -5
- package/lib/math/amm.d.ts +24 -29
- package/lib/math/amm.js +209 -176
- package/lib/math/auction.d.ts +5 -0
- package/lib/math/auction.js +42 -0
- package/lib/math/bankBalance.d.ts +9 -0
- package/lib/math/bankBalance.js +75 -0
- package/lib/math/conversion.d.ts +0 -1
- package/lib/math/conversion.js +1 -5
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +158 -175
- package/lib/math/market.d.ts +6 -6
- package/lib/math/market.js +10 -9
- package/lib/math/orders.d.ts +6 -1
- package/lib/math/orders.js +38 -1
- package/lib/math/position.d.ts +7 -5
- package/lib/math/position.js +29 -27
- package/lib/math/repeg.d.ts +22 -0
- package/lib/math/repeg.js +128 -0
- package/lib/math/trade.d.ts +5 -4
- package/lib/math/trade.js +29 -24
- package/lib/mockUSDCFaucet.js +87 -116
- package/lib/oracles/oracleClientCache.d.ts +8 -0
- package/lib/oracles/oracleClientCache.js +19 -0
- package/lib/oracles/pythClient.d.ts +3 -5
- package/lib/oracles/pythClient.js +12 -31
- package/lib/oracles/quoteAssetOracleClient.d.ts +9 -0
- package/lib/oracles/quoteAssetOracleClient.js +21 -0
- package/lib/oracles/switchboardClient.d.ts +3 -5
- package/lib/oracles/switchboardClient.js +29 -50
- package/lib/oracles/types.d.ts +6 -1
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +8 -96
- package/lib/orders.d.ts +6 -7
- package/lib/orders.js +11 -89
- package/lib/slot/SlotSubscriber.d.ts +19 -0
- package/lib/slot/SlotSubscriber.js +26 -0
- package/lib/tx/retryTxSender.d.ts +2 -2
- package/lib/tx/retryTxSender.js +108 -123
- package/lib/tx/types.d.ts +5 -1
- package/lib/tx/utils.d.ts +1 -1
- package/lib/tx/utils.js +11 -2
- package/lib/types.d.ts +180 -110
- package/lib/types.js +54 -1
- package/lib/userName.d.ts +4 -0
- package/lib/userName.js +20 -0
- package/lib/util/computeUnits.js +10 -21
- package/lib/util/tps.js +11 -22
- package/lib/wallet.js +7 -20
- package/package.json +11 -4
- package/src/accounts/bulkAccountLoader.js +197 -0
- package/src/accounts/bulkAccountLoader.ts +21 -15
- package/src/accounts/bulkUserSubscription.js +33 -0
- package/src/accounts/bulkUserSubscription.ts +1 -45
- package/src/accounts/fetch.js +29 -0
- package/src/accounts/fetch.ts +33 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +311 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +249 -214
- package/src/accounts/pollingOracleSubscriber.js +93 -0
- package/src/accounts/pollingOracleSubscriber.ts +16 -8
- package/src/accounts/pollingTokenAccountSubscriber.js +90 -0
- package/src/accounts/pollingTokenAccountSubscriber.ts +11 -8
- package/src/accounts/pollingUserAccountSubscriber.js +132 -0
- package/src/accounts/pollingUserAccountSubscriber.ts +21 -86
- package/src/accounts/types.js +10 -0
- package/src/accounts/types.ts +41 -70
- package/src/accounts/utils.js +7 -0
- package/src/accounts/webSocketAccountSubscriber.js +93 -0
- package/src/accounts/webSocketAccountSubscriber.ts +33 -16
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +233 -0
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +190 -240
- package/src/accounts/webSocketUserAccountSubscriber.js +62 -0
- package/src/accounts/webSocketUserAccountSubscriber.ts +11 -71
- package/src/addresses/marketAddresses.js +26 -0
- package/src/addresses/marketAddresses.ts +18 -0
- package/{lib/addresses.js → src/addresses/pda.js} +45 -34
- package/src/addresses/pda.ts +118 -0
- package/src/admin.ts +247 -336
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +1023 -1026
- package/src/clearingHouseConfig.ts +37 -0
- package/src/clearingHouseUser.ts +275 -185
- package/src/clearingHouseUserConfig.ts +18 -0
- package/src/config.ts +54 -1
- package/src/constants/banks.ts +50 -0
- package/src/constants/markets.ts +16 -207
- package/src/constants/numericConstants.ts +34 -5
- package/src/events/eventList.js +77 -0
- package/src/events/eventList.ts +94 -0
- package/src/events/eventSubscriber.js +139 -0
- package/src/events/eventSubscriber.ts +194 -0
- package/src/events/fetchLogs.js +50 -0
- package/src/events/fetchLogs.ts +80 -0
- package/src/events/pollingLogProvider.js +64 -0
- package/src/events/pollingLogProvider.ts +79 -0
- package/src/events/sort.js +44 -0
- package/src/events/sort.ts +65 -0
- package/src/events/txEventCache.js +71 -0
- package/src/events/txEventCache.ts +74 -0
- package/src/events/types.js +20 -0
- package/src/events/types.ts +98 -0
- package/src/events/webSocketLogProvider.js +41 -0
- package/src/events/webSocketLogProvider.ts +38 -0
- package/src/examples/makeTradeExample.js +80 -0
- package/src/examples/makeTradeExample.ts +20 -11
- package/src/factory/bigNum.js +364 -0
- package/src/factory/bigNum.ts +524 -0
- package/src/factory/oracleClient.js +20 -0
- package/src/factory/oracleClient.ts +7 -4
- package/src/idl/clearing_house.json +2258 -2774
- package/src/index.js +69 -0
- package/src/index.ts +14 -5
- package/src/math/amm.js +369 -0
- package/src/math/amm.ts +382 -243
- package/src/math/auction.js +42 -0
- package/src/math/auction.ts +43 -0
- package/src/math/bankBalance.js +75 -0
- package/src/math/bankBalance.ts +112 -0
- package/src/math/conversion.js +11 -0
- package/src/math/conversion.ts +1 -11
- package/src/math/funding.js +248 -0
- package/src/math/funding.ts +12 -9
- package/src/math/market.js +57 -0
- package/src/math/market.ts +37 -30
- package/src/math/oracles.js +26 -0
- package/src/math/orders.js +110 -0
- package/src/math/orders.ts +43 -1
- package/src/math/position.js +140 -0
- package/src/math/position.ts +52 -35
- package/src/math/repeg.js +128 -0
- package/src/math/repeg.ts +176 -0
- package/src/math/state.js +15 -0
- package/src/math/trade.js +253 -0
- package/src/math/trade.ts +55 -47
- package/src/math/utils.js +26 -0
- package/src/math/utils.js.map +1 -0
- package/src/mockUSDCFaucet.js +171 -0
- package/src/oracles/oracleClientCache.js +19 -0
- package/src/oracles/oracleClientCache.ts +20 -0
- package/src/oracles/pythClient.js +46 -0
- package/src/oracles/pythClient.ts +4 -11
- package/src/oracles/quoteAssetOracleClient.js +32 -0
- package/src/oracles/quoteAssetOracleClient.ts +25 -0
- package/src/oracles/switchboardClient.js +69 -0
- package/src/oracles/switchboardClient.ts +11 -24
- package/src/oracles/types.js +2 -0
- package/src/oracles/types.ts +7 -1
- package/src/orderParams.js +20 -0
- package/src/orderParams.ts +20 -141
- package/src/orders.js +134 -0
- package/src/orders.ts +25 -134
- package/src/slot/SlotSubscriber.js +39 -0
- package/src/slot/SlotSubscriber.ts +42 -0
- package/src/token/index.js +38 -0
- package/src/tx/retryTxSender.js +188 -0
- package/src/tx/retryTxSender.ts +6 -4
- package/src/tx/types.js +2 -0
- package/src/tx/types.ts +6 -1
- package/src/tx/utils.js +17 -0
- package/src/tx/utils.ts +22 -3
- package/src/types.js +114 -0
- package/src/types.ts +176 -124
- package/src/userName.js +20 -0
- package/src/userName.ts +20 -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 +255 -0
- package/tsconfig.json +12 -12
- package/lib/addresses.d.ts +0 -10
- package/lib/constants/accounts.d.ts +0 -15
- package/lib/constants/accounts.js +0 -18
- package/lib/factory/clearingHouse.d.ts +0 -35
- package/lib/factory/clearingHouse.js +0 -81
- package/lib/factory/clearingHouseUser.d.ts +0 -19
- package/lib/factory/clearingHouseUser.js +0 -34
- package/lib/math/insuranceFund.d.ts +0 -15
- package/lib/math/insuranceFund.js +0 -33
- package/lib/settlement.d.ts +0 -4
- package/lib/settlement.js +0 -10
- package/lib/tx/defaultTxSender.d.ts +0 -8
- package/lib/tx/defaultTxSender.js +0 -12
- package/src/addresses.ts +0 -82
- package/src/constants/accounts.ts +0 -26
- package/src/factory/clearingHouse.ts +0 -173
- package/src/factory/clearingHouseUser.ts +0 -73
- package/src/math/insuranceFund.ts +0 -29
- package/src/settlement.ts +0 -9
- package/src/tx/defaultTxSender.ts +0 -24
package/src/clearingHouse.ts
CHANGED
|
@@ -1,28 +1,20 @@
|
|
|
1
1
|
import { AnchorProvider, BN, Idl, Program } from '@project-serum/anchor';
|
|
2
|
+
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
2
3
|
import {
|
|
3
|
-
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
4
|
-
Token,
|
|
5
|
-
TOKEN_PROGRAM_ID,
|
|
6
|
-
} from '@solana/spl-token';
|
|
7
|
-
import {
|
|
8
|
-
MarketsAccount,
|
|
9
4
|
StateAccount,
|
|
10
|
-
DepositHistoryAccount,
|
|
11
|
-
FundingPaymentHistoryAccount,
|
|
12
|
-
FundingRateHistoryAccount,
|
|
13
5
|
IWallet,
|
|
14
|
-
LiquidationHistoryAccount,
|
|
15
6
|
PositionDirection,
|
|
16
|
-
TradeHistoryAccount,
|
|
17
7
|
UserAccount,
|
|
18
|
-
|
|
19
|
-
OrderHistoryAccount,
|
|
20
|
-
OrderStateAccount,
|
|
8
|
+
MarketAccount,
|
|
21
9
|
OrderParams,
|
|
22
10
|
Order,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
11
|
+
BankAccount,
|
|
12
|
+
UserBankBalance,
|
|
13
|
+
MakerInfo,
|
|
14
|
+
TakerInfo,
|
|
15
|
+
OptionalOrderParams,
|
|
16
|
+
DefaultOrderParams,
|
|
17
|
+
OrderType,
|
|
26
18
|
} from './types';
|
|
27
19
|
import * as anchor from '@project-serum/anchor';
|
|
28
20
|
import clearingHouseIDL from './idl/clearing_house.json';
|
|
@@ -31,10 +23,10 @@ import {
|
|
|
31
23
|
Connection,
|
|
32
24
|
PublicKey,
|
|
33
25
|
TransactionSignature,
|
|
34
|
-
Keypair,
|
|
35
26
|
ConfirmOptions,
|
|
36
27
|
Transaction,
|
|
37
28
|
TransactionInstruction,
|
|
29
|
+
AccountMeta,
|
|
38
30
|
} from '@solana/web3.js';
|
|
39
31
|
|
|
40
32
|
import { MockUSDCFaucet } from './mockUSDCFaucet';
|
|
@@ -42,40 +34,33 @@ import { EventEmitter } from 'events';
|
|
|
42
34
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
43
35
|
import {
|
|
44
36
|
getClearingHouseStateAccountPublicKey,
|
|
45
|
-
|
|
46
|
-
getSettlementStatePublicKey,
|
|
37
|
+
getMarketPublicKey,
|
|
47
38
|
getUserAccountPublicKey,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
getUserOrdersAccountPublicKeyAndNonce,
|
|
51
|
-
} from './addresses';
|
|
39
|
+
getUserAccountPublicKeySync,
|
|
40
|
+
} from './addresses/pda';
|
|
52
41
|
import {
|
|
53
42
|
ClearingHouseAccountSubscriber,
|
|
54
43
|
ClearingHouseAccountEvents,
|
|
55
|
-
|
|
44
|
+
DataAndSlot,
|
|
56
45
|
} from './accounts/types';
|
|
57
46
|
import { TxSender } from './tx/types';
|
|
58
47
|
import { wrapInTx } from './tx/utils';
|
|
59
|
-
import {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
} from './
|
|
64
|
-
import {
|
|
65
|
-
import {
|
|
48
|
+
import { QUOTE_ASSET_BANK_INDEX, ZERO } from './constants/numericConstants';
|
|
49
|
+
import { findDirectionToClose, positionIsAvailable } from './math/position';
|
|
50
|
+
import { getTokenAmount } from './math/bankBalance';
|
|
51
|
+
import { DEFAULT_USER_NAME, encodeName } from './userName';
|
|
52
|
+
import { OraclePriceData } from './oracles/types';
|
|
53
|
+
import { ClearingHouseConfig } from './clearingHouseConfig';
|
|
54
|
+
import { PollingClearingHouseAccountSubscriber } from './accounts/pollingClearingHouseAccountSubscriber';
|
|
55
|
+
import { WebSocketClearingHouseAccountSubscriber } from './accounts/webSocketClearingHouseAccountSubscriber';
|
|
56
|
+
import { RetryTxSender } from './tx/retryTxSender';
|
|
66
57
|
import { ClearingHouseUser } from './clearingHouseUser';
|
|
67
|
-
import {
|
|
68
|
-
|
|
69
|
-
getPollingClearingHouseUserConfig,
|
|
70
|
-
} from './factory/clearingHouseUser';
|
|
71
|
-
import { bulkPollingUserSubscribe } from './accounts/bulkUserSubscription';
|
|
58
|
+
import { ClearingHouseUserAccountSubscriptionConfig } from './clearingHouseUserConfig';
|
|
59
|
+
import { getMarketsBanksAndOraclesForSubscription } from './config';
|
|
72
60
|
|
|
73
61
|
/**
|
|
74
62
|
* # ClearingHouse
|
|
75
63
|
* This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
|
|
76
|
-
*
|
|
77
|
-
* The default way to construct a ClearingHouse instance is using the {@link from} method. This will create an instance using the static {@link WebSocketClearingHouseAccountSubscriber}, which will use a websocket for each state account subscription.
|
|
78
|
-
* Alternatively, if you want to implement your own method of subscribing to the state accounts on the blockchain, you can implement a {@link ClearingHouseAccountSubscriber} and use it in the {@link ClearingHouse.constructor}
|
|
79
64
|
*/
|
|
80
65
|
export class ClearingHouse {
|
|
81
66
|
connection: Connection;
|
|
@@ -83,10 +68,14 @@ export class ClearingHouse {
|
|
|
83
68
|
public program: Program;
|
|
84
69
|
provider: AnchorProvider;
|
|
85
70
|
opts?: ConfirmOptions;
|
|
71
|
+
users = new Map<number, ClearingHouseUser>();
|
|
72
|
+
activeUserId: number;
|
|
73
|
+
userAccountSubscriptionConfig: ClearingHouseUserAccountSubscriptionConfig;
|
|
86
74
|
accountSubscriber: ClearingHouseAccountSubscriber;
|
|
87
75
|
eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
|
|
88
76
|
_isSubscribed = false;
|
|
89
77
|
txSender: TxSender;
|
|
78
|
+
marketLastSlotCache = new Map<number, number>();
|
|
90
79
|
|
|
91
80
|
public get isSubscribed() {
|
|
92
81
|
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
@@ -96,91 +85,137 @@ export class ClearingHouse {
|
|
|
96
85
|
this._isSubscribed = val;
|
|
97
86
|
}
|
|
98
87
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
): ClearingHouse {
|
|
113
|
-
const config = getWebSocketClearingHouseConfig(
|
|
114
|
-
connection,
|
|
115
|
-
wallet,
|
|
116
|
-
clearingHouseProgramId,
|
|
117
|
-
opts
|
|
88
|
+
public constructor(config: ClearingHouseConfig) {
|
|
89
|
+
this.connection = config.connection;
|
|
90
|
+
this.wallet = config.wallet;
|
|
91
|
+
this.opts = config.opts || AnchorProvider.defaultOptions();
|
|
92
|
+
this.provider = new AnchorProvider(
|
|
93
|
+
config.connection,
|
|
94
|
+
config.wallet,
|
|
95
|
+
this.opts
|
|
96
|
+
);
|
|
97
|
+
this.program = new Program(
|
|
98
|
+
clearingHouseIDL as Idl,
|
|
99
|
+
config.programID,
|
|
100
|
+
this.provider
|
|
118
101
|
);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
this.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
102
|
+
|
|
103
|
+
const userIds = config.userIds ?? [0];
|
|
104
|
+
this.activeUserId = config.activeUserId ?? userIds[0];
|
|
105
|
+
this.userAccountSubscriptionConfig =
|
|
106
|
+
config.accountSubscription?.type === 'polling'
|
|
107
|
+
? {
|
|
108
|
+
type: 'polling',
|
|
109
|
+
accountLoader: config.accountSubscription.accountLoader,
|
|
110
|
+
}
|
|
111
|
+
: {
|
|
112
|
+
type: 'websocket',
|
|
113
|
+
};
|
|
114
|
+
this.createUsers(userIds, this.userAccountSubscriptionConfig);
|
|
115
|
+
|
|
116
|
+
let marketIndexes = config.marketIndexes;
|
|
117
|
+
let bankIndexes = config.bankIndexes;
|
|
118
|
+
let oracleInfos = config.oracleInfos;
|
|
119
|
+
if (config.env) {
|
|
120
|
+
const {
|
|
121
|
+
marketIndexes: envMarketIndexes,
|
|
122
|
+
bankIndexes: envBankIndexes,
|
|
123
|
+
oracleInfos: envOralceInfos,
|
|
124
|
+
} = getMarketsBanksAndOraclesForSubscription(config.env);
|
|
125
|
+
marketIndexes = marketIndexes ? marketIndexes : envMarketIndexes;
|
|
126
|
+
bankIndexes = bankIndexes ? bankIndexes : envBankIndexes;
|
|
127
|
+
oracleInfos = oracleInfos ? oracleInfos : envOralceInfos;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (config.accountSubscription?.type === 'polling') {
|
|
131
|
+
this.accountSubscriber = new PollingClearingHouseAccountSubscriber(
|
|
132
|
+
this.program,
|
|
133
|
+
config.accountSubscription.accountLoader,
|
|
134
|
+
marketIndexes ?? [],
|
|
135
|
+
bankIndexes ?? [],
|
|
136
|
+
oracleInfos ?? []
|
|
137
|
+
);
|
|
138
|
+
} else {
|
|
139
|
+
this.accountSubscriber = new WebSocketClearingHouseAccountSubscriber(
|
|
140
|
+
this.program,
|
|
141
|
+
config.marketIndexes ?? [],
|
|
142
|
+
config.bankIndexes ?? [],
|
|
143
|
+
config.oracleInfos ?? []
|
|
144
|
+
);
|
|
145
|
+
}
|
|
135
146
|
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
136
|
-
this.txSender =
|
|
147
|
+
this.txSender = new RetryTxSender(
|
|
148
|
+
this.provider,
|
|
149
|
+
config.txSenderConfig?.timeout,
|
|
150
|
+
config.txSenderConfig?.retrySleep,
|
|
151
|
+
config.txSenderConfig?.additionalConnections
|
|
152
|
+
);
|
|
137
153
|
}
|
|
138
154
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
createUsers(
|
|
156
|
+
userIds: number[],
|
|
157
|
+
accountSubscriptionConfig: ClearingHouseUserAccountSubscriptionConfig
|
|
158
|
+
): void {
|
|
159
|
+
for (const userId of userIds) {
|
|
160
|
+
const user = this.createUser(userId, accountSubscriptionConfig);
|
|
161
|
+
this.users.set(userId, user);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
createUser(
|
|
166
|
+
userId: number,
|
|
167
|
+
accountSubscriptionConfig: ClearingHouseUserAccountSubscriptionConfig
|
|
168
|
+
): ClearingHouseUser {
|
|
169
|
+
const userAccountPublicKey = getUserAccountPublicKeySync(
|
|
170
|
+
this.program.programId,
|
|
171
|
+
this.wallet.publicKey,
|
|
172
|
+
userId
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
return new ClearingHouseUser({
|
|
176
|
+
clearingHouse: this,
|
|
177
|
+
userAccountPublicKey,
|
|
178
|
+
accountSubscription: accountSubscriptionConfig,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public async subscribe(): Promise<boolean> {
|
|
183
|
+
const subscribePromises = this.subscribeUsers().concat(
|
|
184
|
+
this.accountSubscriber.subscribe()
|
|
185
|
+
);
|
|
186
|
+
this.isSubscribed = (await Promise.all(subscribePromises)).reduce(
|
|
187
|
+
(success, prevSuccess) => success && prevSuccess
|
|
149
188
|
);
|
|
150
189
|
return this.isSubscribed;
|
|
151
190
|
}
|
|
152
191
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
* @returns Promise<boolean> : SubscriptionSuccess
|
|
156
|
-
*/
|
|
157
|
-
public async subscribeToAll(): Promise<boolean> {
|
|
158
|
-
return this.subscribe([
|
|
159
|
-
'curveHistoryAccount',
|
|
160
|
-
'depositHistoryAccount',
|
|
161
|
-
'fundingPaymentHistoryAccount',
|
|
162
|
-
'fundingRateHistoryAccount',
|
|
163
|
-
'liquidationHistoryAccount',
|
|
164
|
-
'tradeHistoryAccount',
|
|
165
|
-
'orderHistoryAccount',
|
|
166
|
-
]);
|
|
192
|
+
subscribeUsers(): Promise<boolean>[] {
|
|
193
|
+
return [...this.users.values()].map((user) => user.subscribe());
|
|
167
194
|
}
|
|
168
195
|
|
|
169
196
|
/**
|
|
170
197
|
* Forces the accountSubscriber to fetch account updates from rpc
|
|
171
198
|
*/
|
|
172
199
|
public async fetchAccounts(): Promise<void> {
|
|
173
|
-
await
|
|
200
|
+
await Promise.all(
|
|
201
|
+
[...this.users.values()]
|
|
202
|
+
.map((user) => user.fetchAccounts())
|
|
203
|
+
.concat(this.accountSubscriber.fetch())
|
|
204
|
+
);
|
|
174
205
|
}
|
|
175
206
|
|
|
176
|
-
/**
|
|
177
|
-
* Unsubscribe from all currently subscribed state accounts
|
|
178
|
-
*/
|
|
179
207
|
public async unsubscribe(): Promise<void> {
|
|
180
|
-
|
|
208
|
+
const unsubscribePromises = this.unsubscribeUsers().concat(
|
|
209
|
+
this.accountSubscriber.unsubscribe()
|
|
210
|
+
);
|
|
211
|
+
await Promise.all(unsubscribePromises);
|
|
181
212
|
this.isSubscribed = false;
|
|
182
213
|
}
|
|
183
214
|
|
|
215
|
+
unsubscribeUsers(): Promise<void>[] {
|
|
216
|
+
return [...this.users.values()].map((user) => user.unsubscribe());
|
|
217
|
+
}
|
|
218
|
+
|
|
184
219
|
statePublicKey?: PublicKey;
|
|
185
220
|
public async getStatePublicKey(): Promise<PublicKey> {
|
|
186
221
|
if (this.statePublicKey) {
|
|
@@ -193,75 +228,47 @@ export class ClearingHouse {
|
|
|
193
228
|
}
|
|
194
229
|
|
|
195
230
|
public getStateAccount(): StateAccount {
|
|
196
|
-
return this.accountSubscriber.
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
public async getSettlementAccount(): Promise<SettlementStateAccount> {
|
|
200
|
-
// @ts-ignore
|
|
201
|
-
return await this.program.account.settlementState.fetch(
|
|
202
|
-
await getSettlementStatePublicKey(this.program.programId)
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
public getMarketsAccount(): MarketsAccount {
|
|
207
|
-
return this.accountSubscriber.getMarketsAccount();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
public getMarket(marketIndex: BN | number): Market {
|
|
211
|
-
if (marketIndex instanceof BN) {
|
|
212
|
-
marketIndex = marketIndex.toNumber();
|
|
213
|
-
}
|
|
214
|
-
return this.getMarketsAccount().markets[marketIndex];
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
public getFundingPaymentHistoryAccount(): FundingPaymentHistoryAccount {
|
|
218
|
-
return this.accountSubscriber.getFundingPaymentHistoryAccount();
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
public getFundingRateHistoryAccount(): FundingRateHistoryAccount {
|
|
222
|
-
return this.accountSubscriber.getFundingRateHistoryAccount();
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
public getTradeHistoryAccount(): TradeHistoryAccount {
|
|
226
|
-
return this.accountSubscriber.getTradeHistoryAccount();
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
public getLiquidationHistoryAccount(): LiquidationHistoryAccount {
|
|
230
|
-
return this.accountSubscriber.getLiquidationHistoryAccount();
|
|
231
|
+
return this.accountSubscriber.getStateAccountAndSlot().data;
|
|
231
232
|
}
|
|
232
233
|
|
|
233
|
-
public
|
|
234
|
-
|
|
234
|
+
public getMarketAccount(marketIndex: BN | number): MarketAccount | undefined {
|
|
235
|
+
marketIndex = marketIndex instanceof BN ? marketIndex : new BN(marketIndex);
|
|
236
|
+
return this.accountSubscriber.getMarketAccountAndSlot(marketIndex)?.data;
|
|
235
237
|
}
|
|
236
238
|
|
|
237
|
-
public
|
|
238
|
-
return this.accountSubscriber
|
|
239
|
+
public getMarketAccounts(): MarketAccount[] {
|
|
240
|
+
return this.accountSubscriber
|
|
241
|
+
.getMarketAccountsAndSlots()
|
|
242
|
+
.map((value) => value.data);
|
|
239
243
|
}
|
|
240
244
|
|
|
241
|
-
public
|
|
242
|
-
|
|
245
|
+
public getBankAccount(bankIndex: BN | number): BankAccount | undefined {
|
|
246
|
+
bankIndex = bankIndex instanceof BN ? bankIndex : new BN(bankIndex);
|
|
247
|
+
return this.accountSubscriber.getBankAccountAndSlot(bankIndex).data;
|
|
243
248
|
}
|
|
244
249
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
return this.orderStatePublicKey;
|
|
249
|
-
}
|
|
250
|
-
this.orderStatePublicKey = await getOrderStateAccountPublicKey(
|
|
251
|
-
this.program.programId
|
|
252
|
-
);
|
|
253
|
-
return this.orderStatePublicKey;
|
|
250
|
+
public getQuoteAssetBankAccount(): BankAccount {
|
|
251
|
+
return this.accountSubscriber.getBankAccountAndSlot(QUOTE_ASSET_BANK_INDEX)
|
|
252
|
+
.data;
|
|
254
253
|
}
|
|
255
254
|
|
|
256
|
-
public
|
|
257
|
-
|
|
255
|
+
public getOraclePriceDataAndSlot(
|
|
256
|
+
oraclePublicKey: PublicKey
|
|
257
|
+
): DataAndSlot<OraclePriceData> | undefined {
|
|
258
|
+
return this.accountSubscriber.getOraclePriceDataAndSlot(oraclePublicKey);
|
|
258
259
|
}
|
|
259
260
|
|
|
260
261
|
/**
|
|
261
262
|
* Update the wallet to use for clearing house transactions and linked user account
|
|
262
263
|
* @param newWallet
|
|
264
|
+
* @param userIds
|
|
265
|
+
* @param activeUserId
|
|
263
266
|
*/
|
|
264
|
-
public updateWallet(
|
|
267
|
+
public async updateWallet(
|
|
268
|
+
newWallet: IWallet,
|
|
269
|
+
userIds = [0],
|
|
270
|
+
activeUserId = 0
|
|
271
|
+
): Promise<void> {
|
|
265
272
|
const newProvider = new AnchorProvider(
|
|
266
273
|
this.connection,
|
|
267
274
|
newWallet,
|
|
@@ -279,257 +286,364 @@ export class ClearingHouse {
|
|
|
279
286
|
this.wallet = newWallet;
|
|
280
287
|
this.provider = newProvider;
|
|
281
288
|
this.program = newProgram;
|
|
282
|
-
this.userAccountPublicKey = undefined;
|
|
283
|
-
this.userAccount = undefined;
|
|
284
|
-
this.userOrdersAccountPublicKey = undefined;
|
|
285
|
-
this.userOrdersExist = undefined;
|
|
286
|
-
}
|
|
287
289
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
] = await this.getInitializeUserInstructions();
|
|
290
|
+
if (this.isSubscribed) {
|
|
291
|
+
await Promise.all(this.unsubscribeUsers());
|
|
292
|
+
}
|
|
293
|
+
this.users.clear();
|
|
294
|
+
this.createUsers(userIds, this.userAccountSubscriptionConfig);
|
|
295
|
+
if (this.isSubscribed) {
|
|
296
|
+
await Promise.all(this.subscribeUsers());
|
|
297
|
+
}
|
|
297
298
|
|
|
298
|
-
|
|
299
|
-
.add(initializeUserAccountIx)
|
|
300
|
-
.add(initializeUserOrdersAccountIx);
|
|
301
|
-
const txSig = await this.txSender.send(
|
|
302
|
-
tx,
|
|
303
|
-
[userPositionsAccount],
|
|
304
|
-
this.opts
|
|
305
|
-
);
|
|
306
|
-
return [txSig, userAccountPublicKey];
|
|
299
|
+
this.activeUserId = activeUserId;
|
|
307
300
|
}
|
|
308
301
|
|
|
309
|
-
async
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const [userAccountPublicKey, userAccountNonce] =
|
|
313
|
-
await getUserAccountPublicKeyAndNonce(
|
|
314
|
-
this.program.programId,
|
|
315
|
-
this.wallet.publicKey
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
const remainingAccounts = [];
|
|
319
|
-
const optionalAccounts = {
|
|
320
|
-
whitelistToken: false,
|
|
321
|
-
};
|
|
302
|
+
public async switchActiveUser(userId: number): Promise<void> {
|
|
303
|
+
this.activeUserId = userId;
|
|
304
|
+
}
|
|
322
305
|
|
|
323
|
-
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
const associatedTokenPublicKey = await Token.getAssociatedTokenAddress(
|
|
327
|
-
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
328
|
-
TOKEN_PROGRAM_ID,
|
|
329
|
-
state.whitelistMint,
|
|
330
|
-
this.wallet.publicKey
|
|
331
|
-
);
|
|
332
|
-
remainingAccounts.push({
|
|
333
|
-
pubkey: associatedTokenPublicKey,
|
|
334
|
-
isWritable: false,
|
|
335
|
-
isSigner: false,
|
|
336
|
-
});
|
|
306
|
+
public async addUser(userId: number): Promise<void> {
|
|
307
|
+
if (this.users.has(userId)) {
|
|
308
|
+
return;
|
|
337
309
|
}
|
|
338
310
|
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
optionalAccounts,
|
|
344
|
-
{
|
|
345
|
-
accounts: {
|
|
346
|
-
user: userAccountPublicKey,
|
|
347
|
-
authority: this.wallet.publicKey,
|
|
348
|
-
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
349
|
-
systemProgram: anchor.web3.SystemProgram.programId,
|
|
350
|
-
userPositions: userPositions.publicKey,
|
|
351
|
-
state: await this.getStatePublicKey(),
|
|
352
|
-
},
|
|
353
|
-
remainingAccounts: remainingAccounts,
|
|
354
|
-
}
|
|
355
|
-
);
|
|
311
|
+
const user = this.createUser(userId, this.userAccountSubscriptionConfig);
|
|
312
|
+
await user.subscribe();
|
|
313
|
+
this.users.set(userId, user);
|
|
314
|
+
}
|
|
356
315
|
|
|
357
|
-
|
|
358
|
-
|
|
316
|
+
public async initializeUserAccount(
|
|
317
|
+
userId = 0,
|
|
318
|
+
name = DEFAULT_USER_NAME
|
|
319
|
+
): Promise<[TransactionSignature, PublicKey]> {
|
|
320
|
+
const [userAccountPublicKey, initializeUserAccountIx] =
|
|
321
|
+
await this.getInitializeUserInstructions(userId, name);
|
|
359
322
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
initializeUserAccountIx,
|
|
364
|
-
initializeUserOrdersAccountIx,
|
|
365
|
-
];
|
|
323
|
+
const tx = new Transaction().add(initializeUserAccountIx);
|
|
324
|
+
const { txSig } = await this.txSender.send(tx, [], this.opts);
|
|
325
|
+
return [txSig, userAccountPublicKey];
|
|
366
326
|
}
|
|
367
327
|
|
|
368
|
-
async
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
this.program.programId,
|
|
378
|
-
userAccountPublicKey
|
|
379
|
-
);
|
|
328
|
+
async getInitializeUserInstructions(
|
|
329
|
+
userId = 0,
|
|
330
|
+
name = DEFAULT_USER_NAME
|
|
331
|
+
): Promise<[PublicKey, TransactionInstruction]> {
|
|
332
|
+
const userAccountPublicKey = await getUserAccountPublicKey(
|
|
333
|
+
this.program.programId,
|
|
334
|
+
this.wallet.publicKey,
|
|
335
|
+
userId
|
|
336
|
+
);
|
|
380
337
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
{
|
|
338
|
+
const nameBuffer = encodeName(name);
|
|
339
|
+
const initializeUserAccountIx =
|
|
340
|
+
await this.program.instruction.initializeUser(userId, nameBuffer, {
|
|
384
341
|
accounts: {
|
|
385
342
|
user: userAccountPublicKey,
|
|
386
343
|
authority: this.wallet.publicKey,
|
|
344
|
+
payer: this.wallet.publicKey,
|
|
387
345
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
388
346
|
systemProgram: anchor.web3.SystemProgram.programId,
|
|
389
|
-
userOrders: userOrdersAccountPublicKey,
|
|
390
347
|
state: await this.getStatePublicKey(),
|
|
391
348
|
},
|
|
392
|
-
}
|
|
393
|
-
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
return [userAccountPublicKey, initializeUserAccountIx];
|
|
394
352
|
}
|
|
395
353
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
*/
|
|
401
|
-
public async getUserAccountPublicKey(): Promise<PublicKey> {
|
|
402
|
-
if (this.userAccountPublicKey) {
|
|
403
|
-
return this.userAccountPublicKey;
|
|
354
|
+
public getUser(userId?: number): ClearingHouseUser {
|
|
355
|
+
userId = userId ?? this.activeUserId;
|
|
356
|
+
if (!this.users.has(userId)) {
|
|
357
|
+
throw new Error(`Clearing House has no user for user id ${userId}`);
|
|
404
358
|
}
|
|
359
|
+
return this.users.get(userId);
|
|
360
|
+
}
|
|
405
361
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
this.wallet.publicKey
|
|
409
|
-
);
|
|
410
|
-
return this.userAccountPublicKey;
|
|
362
|
+
public getUsers(): ClearingHouseUser[] {
|
|
363
|
+
return [...this.users.values()];
|
|
411
364
|
}
|
|
412
365
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
return this.userAccount;
|
|
417
|
-
}
|
|
366
|
+
public async getUserAccountPublicKey(): Promise<PublicKey> {
|
|
367
|
+
return this.getUser().userAccountPublicKey;
|
|
368
|
+
}
|
|
418
369
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
)) as UserAccount;
|
|
422
|
-
return this.userAccount;
|
|
370
|
+
public getUserAccount(userId?: number): UserAccount | undefined {
|
|
371
|
+
return this.getUser(userId).getUserAccount();
|
|
423
372
|
}
|
|
424
373
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
public async getUserOrdersAccountPublicKey(): Promise<PublicKey> {
|
|
431
|
-
if (this.userOrdersAccountPublicKey) {
|
|
432
|
-
return this.userOrdersAccountPublicKey;
|
|
433
|
-
}
|
|
374
|
+
public getUserAccountAndSlot(
|
|
375
|
+
userId?: number
|
|
376
|
+
): DataAndSlot<UserAccount> | undefined {
|
|
377
|
+
return this.getUser(userId).getUserAccountAndSlot();
|
|
378
|
+
}
|
|
434
379
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
380
|
+
public getUserBankBalance(
|
|
381
|
+
bankIndex: number | BN
|
|
382
|
+
): UserBankBalance | undefined {
|
|
383
|
+
const bankIndexBN = bankIndex instanceof BN ? bankIndex : new BN(bankIndex);
|
|
384
|
+
return this.getUserAccount().bankBalances.find((bankBalance) =>
|
|
385
|
+
bankBalance.bankIndex.eq(bankIndexBN)
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
public getQuoteAssetTokenAmount(): BN {
|
|
390
|
+
const bank = this.getBankAccount(QUOTE_ASSET_BANK_INDEX);
|
|
391
|
+
const userBankBalance = this.getUserBankBalance(QUOTE_ASSET_BANK_INDEX);
|
|
392
|
+
return getTokenAmount(
|
|
393
|
+
userBankBalance.balance,
|
|
394
|
+
bank,
|
|
395
|
+
userBankBalance.balanceType
|
|
438
396
|
);
|
|
439
|
-
return this.userOrdersAccountPublicKey;
|
|
440
397
|
}
|
|
441
398
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
399
|
+
getRemainingAccounts(params: {
|
|
400
|
+
writableMarketIndex?: BN;
|
|
401
|
+
writableBankIndex?: BN;
|
|
402
|
+
}): AccountMeta[] {
|
|
403
|
+
const userAccountAndSlot = this.getUserAccountAndSlot();
|
|
404
|
+
if (!userAccountAndSlot) {
|
|
405
|
+
throw Error(
|
|
406
|
+
'No user account found. Most likely user account does not exist or failed to fetch account'
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
const { data: userAccount, slot: lastUserPositionsSlot } =
|
|
410
|
+
userAccountAndSlot;
|
|
411
|
+
|
|
412
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
413
|
+
const bankAccountMap = new Map<number, AccountMeta>();
|
|
414
|
+
const marketAccountMap = new Map<number, AccountMeta>();
|
|
415
|
+
for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
|
|
416
|
+
// if cache has more recent slot than user positions account slot, add market to remaining accounts
|
|
417
|
+
// otherwise remove from slot
|
|
418
|
+
if (slot > lastUserPositionsSlot) {
|
|
419
|
+
const marketAccount = this.getMarketAccount(marketIndexNum);
|
|
420
|
+
marketAccountMap.set(marketIndexNum, {
|
|
421
|
+
pubkey: marketAccount.pubkey,
|
|
422
|
+
isSigner: false,
|
|
423
|
+
isWritable: false,
|
|
424
|
+
});
|
|
425
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
426
|
+
pubkey: marketAccount.amm.oracle,
|
|
427
|
+
isSigner: false,
|
|
428
|
+
isWritable: false,
|
|
429
|
+
});
|
|
430
|
+
} else {
|
|
431
|
+
this.marketLastSlotCache.delete(marketIndexNum);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
for (const position of userAccount.positions) {
|
|
436
|
+
if (!positionIsAvailable(position)) {
|
|
437
|
+
const marketIndexNum = position.marketIndex.toNumber();
|
|
438
|
+
const marketAccount = this.getMarketAccount(marketIndexNum);
|
|
439
|
+
marketAccountMap.set(marketIndexNum, {
|
|
440
|
+
pubkey: marketAccount.pubkey,
|
|
441
|
+
isSigner: false,
|
|
442
|
+
// isWritable: false, // TODO
|
|
443
|
+
isWritable: true,
|
|
444
|
+
});
|
|
445
|
+
oracleAccountMap.set(marketAccount.pubkey.toString(), {
|
|
446
|
+
pubkey: marketAccount.amm.oracle,
|
|
447
|
+
isSigner: false,
|
|
448
|
+
isWritable: false,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
446
451
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
452
|
+
|
|
453
|
+
if (params.writableMarketIndex) {
|
|
454
|
+
const marketAccount = this.getMarketAccount(
|
|
455
|
+
params.writableMarketIndex.toNumber()
|
|
450
456
|
);
|
|
457
|
+
marketAccountMap.set(params.writableMarketIndex.toNumber(), {
|
|
458
|
+
pubkey: marketAccount.pubkey,
|
|
459
|
+
isSigner: false,
|
|
460
|
+
isWritable: true,
|
|
461
|
+
});
|
|
462
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
463
|
+
pubkey: marketAccount.amm.oracle,
|
|
464
|
+
isSigner: false,
|
|
465
|
+
isWritable: false,
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
for (const userBankBalance of userAccount.bankBalances) {
|
|
470
|
+
if (!userBankBalance.balance.eq(ZERO)) {
|
|
471
|
+
const bankAccount = this.getBankAccount(userBankBalance.bankIndex);
|
|
472
|
+
bankAccountMap.set(userBankBalance.bankIndex.toNumber(), {
|
|
473
|
+
pubkey: bankAccount.pubkey,
|
|
474
|
+
isSigner: false,
|
|
475
|
+
isWritable: false,
|
|
476
|
+
});
|
|
477
|
+
if (!bankAccount.bankIndex.eq(ZERO)) {
|
|
478
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
479
|
+
pubkey: bankAccount.oracle,
|
|
480
|
+
isSigner: false,
|
|
481
|
+
isWritable: false,
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (params.writableBankIndex) {
|
|
488
|
+
const bankAccount = this.getBankAccount(params.writableBankIndex);
|
|
489
|
+
bankAccountMap.set(params.writableBankIndex.toNumber(), {
|
|
490
|
+
pubkey: bankAccount.pubkey,
|
|
491
|
+
isSigner: false,
|
|
492
|
+
isWritable: true,
|
|
493
|
+
});
|
|
494
|
+
if (!bankAccount.bankIndex.eq(ZERO)) {
|
|
495
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
496
|
+
pubkey: bankAccount.oracle,
|
|
497
|
+
isSigner: false,
|
|
498
|
+
isWritable: false,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return [
|
|
504
|
+
...oracleAccountMap.values(),
|
|
505
|
+
...bankAccountMap.values(),
|
|
506
|
+
...marketAccountMap.values(),
|
|
507
|
+
];
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
public getOrder(orderId: BN | number): Order | undefined {
|
|
511
|
+
const orderIdBN = orderId instanceof BN ? orderId : new BN(orderId);
|
|
512
|
+
return this.getUserAccount()?.orders.find((order) =>
|
|
513
|
+
order.orderId.eq(orderIdBN)
|
|
514
|
+
);
|
|
515
|
+
}
|
|
451
516
|
|
|
452
|
-
|
|
453
|
-
return this.
|
|
517
|
+
public getOrderByUserId(userOrderId: number): Order | undefined {
|
|
518
|
+
return this.getUserAccount()?.orders.find(
|
|
519
|
+
(order) => order.userOrderId === userOrderId
|
|
520
|
+
);
|
|
454
521
|
}
|
|
455
522
|
|
|
456
|
-
public async
|
|
523
|
+
public async deposit(
|
|
457
524
|
amount: BN,
|
|
525
|
+
bankIndex: BN,
|
|
458
526
|
collateralAccountPublicKey: PublicKey,
|
|
459
|
-
|
|
527
|
+
userId?: number,
|
|
528
|
+
reduceOnly = false
|
|
460
529
|
): Promise<TransactionSignature> {
|
|
461
|
-
const depositCollateralIx = await this.
|
|
530
|
+
const depositCollateralIx = await this.getDepositInstruction(
|
|
462
531
|
amount,
|
|
532
|
+
bankIndex,
|
|
463
533
|
collateralAccountPublicKey,
|
|
464
|
-
|
|
534
|
+
userId,
|
|
535
|
+
reduceOnly,
|
|
536
|
+
true
|
|
465
537
|
);
|
|
466
538
|
|
|
467
539
|
const tx = new Transaction().add(depositCollateralIx);
|
|
468
540
|
|
|
469
|
-
|
|
541
|
+
const { txSig } = await this.txSender.send(tx);
|
|
542
|
+
return txSig;
|
|
470
543
|
}
|
|
471
544
|
|
|
472
|
-
async
|
|
545
|
+
async getDepositInstruction(
|
|
473
546
|
amount: BN,
|
|
474
|
-
|
|
475
|
-
|
|
547
|
+
bankIndex: BN,
|
|
548
|
+
userTokenAccount: PublicKey,
|
|
549
|
+
userId?: number,
|
|
550
|
+
reduceOnly = false,
|
|
551
|
+
userInitialized = true
|
|
476
552
|
): Promise<TransactionInstruction> {
|
|
477
|
-
const userAccountPublicKey =
|
|
478
|
-
|
|
479
|
-
|
|
553
|
+
const userAccountPublicKey = userId
|
|
554
|
+
? await getUserAccountPublicKey(
|
|
555
|
+
this.program.programId,
|
|
556
|
+
this.wallet.publicKey,
|
|
557
|
+
userId
|
|
558
|
+
)
|
|
559
|
+
: await this.getUserAccountPublicKey();
|
|
560
|
+
|
|
561
|
+
let remainingAccounts = [];
|
|
562
|
+
if (userInitialized) {
|
|
563
|
+
remainingAccounts = this.getRemainingAccounts({
|
|
564
|
+
writableBankIndex: bankIndex,
|
|
565
|
+
});
|
|
566
|
+
} else {
|
|
567
|
+
const bankAccount = this.getBankAccount(bankIndex);
|
|
568
|
+
if (!bankAccount.oracle.equals(PublicKey.default)) {
|
|
569
|
+
remainingAccounts.push({
|
|
570
|
+
pubkey: bankAccount.oracle,
|
|
571
|
+
isSigner: false,
|
|
572
|
+
isWritable: false,
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
remainingAccounts.push({
|
|
576
|
+
pubkey: bankAccount.pubkey,
|
|
577
|
+
isSigner: false,
|
|
578
|
+
isWritable: true,
|
|
579
|
+
});
|
|
480
580
|
}
|
|
481
581
|
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
582
|
+
const bank = this.getBankAccount(bankIndex);
|
|
583
|
+
|
|
584
|
+
return await this.program.instruction.deposit(
|
|
585
|
+
bankIndex,
|
|
586
|
+
amount,
|
|
587
|
+
reduceOnly,
|
|
588
|
+
{
|
|
589
|
+
accounts: {
|
|
590
|
+
state: await this.getStatePublicKey(),
|
|
591
|
+
bank: bank.pubkey,
|
|
592
|
+
bankVault: bank.vault,
|
|
593
|
+
user: userAccountPublicKey,
|
|
594
|
+
userTokenAccount: userTokenAccount,
|
|
595
|
+
authority: this.wallet.publicKey,
|
|
596
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
597
|
+
},
|
|
598
|
+
remainingAccounts,
|
|
599
|
+
}
|
|
600
|
+
);
|
|
497
601
|
}
|
|
498
602
|
|
|
499
603
|
/**
|
|
500
604
|
* Creates the Clearing House User account for a user, and deposits some initial collateral
|
|
605
|
+
* @param userId
|
|
606
|
+
* @param name
|
|
501
607
|
* @param amount
|
|
502
|
-
* @param
|
|
608
|
+
* @param userTokenAccount
|
|
609
|
+
* @param fromUserId
|
|
503
610
|
* @returns
|
|
504
611
|
*/
|
|
505
612
|
public async initializeUserAccountAndDepositCollateral(
|
|
506
613
|
amount: BN,
|
|
507
|
-
|
|
614
|
+
userTokenAccount: PublicKey,
|
|
615
|
+
bankIndex = new BN(0),
|
|
616
|
+
userId = 0,
|
|
617
|
+
name = DEFAULT_USER_NAME,
|
|
618
|
+
fromUserId?: number
|
|
508
619
|
): Promise<[TransactionSignature, PublicKey]> {
|
|
509
|
-
const [
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
620
|
+
const [userAccountPublicKey, initializeUserAccountIx] =
|
|
621
|
+
await this.getInitializeUserInstructions(userId, name);
|
|
622
|
+
|
|
623
|
+
const depositCollateralIx =
|
|
624
|
+
fromUserId != null
|
|
625
|
+
? await this.getTransferDepositIx(amount, bankIndex, fromUserId, userId)
|
|
626
|
+
: await this.getDepositInstruction(
|
|
627
|
+
amount,
|
|
628
|
+
bankIndex,
|
|
629
|
+
userTokenAccount,
|
|
630
|
+
userId,
|
|
631
|
+
false,
|
|
632
|
+
false
|
|
633
|
+
);
|
|
521
634
|
|
|
522
635
|
const tx = new Transaction()
|
|
523
636
|
.add(initializeUserAccountIx)
|
|
524
|
-
.add(initializeUserOrdersAccountIx)
|
|
525
637
|
.add(depositCollateralIx);
|
|
526
638
|
|
|
527
|
-
const txSig = await this.txSender.send(tx, [
|
|
639
|
+
const { txSig } = await this.txSender.send(tx, []);
|
|
528
640
|
|
|
529
641
|
return [txSig, userAccountPublicKey];
|
|
530
642
|
}
|
|
531
643
|
|
|
532
644
|
public async initializeUserAccountForDevnet(
|
|
645
|
+
userId = 0,
|
|
646
|
+
name = DEFAULT_USER_NAME,
|
|
533
647
|
mockUSDCFaucet: MockUSDCFaucet,
|
|
534
648
|
amount: BN
|
|
535
649
|
): Promise<[TransactionSignature, PublicKey]> {
|
|
@@ -539,826 +653,806 @@ export class ClearingHouse {
|
|
|
539
653
|
amount
|
|
540
654
|
);
|
|
541
655
|
|
|
542
|
-
const [
|
|
543
|
-
|
|
544
|
-
userAccountPublicKey,
|
|
545
|
-
initializeUserAccountIx,
|
|
546
|
-
initializeUserOrdersAccountIx,
|
|
547
|
-
] = await this.getInitializeUserInstructions();
|
|
656
|
+
const [userAccountPublicKey, initializeUserAccountIx] =
|
|
657
|
+
await this.getInitializeUserInstructions(userId, name);
|
|
548
658
|
|
|
549
|
-
const depositCollateralIx = await this.
|
|
659
|
+
const depositCollateralIx = await this.getDepositInstruction(
|
|
550
660
|
amount,
|
|
661
|
+
new BN(0),
|
|
551
662
|
associateTokenPublicKey,
|
|
552
|
-
|
|
663
|
+
userId,
|
|
664
|
+
false,
|
|
665
|
+
false
|
|
553
666
|
);
|
|
554
667
|
|
|
555
668
|
const tx = new Transaction()
|
|
556
669
|
.add(createAssociatedAccountIx)
|
|
557
670
|
.add(mintToIx)
|
|
558
671
|
.add(initializeUserAccountIx)
|
|
559
|
-
.add(initializeUserOrdersAccountIx)
|
|
560
672
|
.add(depositCollateralIx);
|
|
561
673
|
|
|
562
|
-
const txSig = await this.program.provider.sendAndConfirm(tx, [
|
|
563
|
-
userPositionsAccount,
|
|
564
|
-
]);
|
|
674
|
+
const txSig = await this.program.provider.sendAndConfirm(tx, []);
|
|
565
675
|
|
|
566
676
|
return [txSig, userAccountPublicKey];
|
|
567
677
|
}
|
|
568
678
|
|
|
569
|
-
public async
|
|
570
|
-
amount: BN,
|
|
571
|
-
collateralAccountPublicKey: PublicKey
|
|
572
|
-
): Promise<TransactionSignature> {
|
|
573
|
-
return this.txSender.send(
|
|
574
|
-
wrapInTx(
|
|
575
|
-
await this.getWithdrawCollateralIx(amount, collateralAccountPublicKey)
|
|
576
|
-
),
|
|
577
|
-
[],
|
|
578
|
-
this.opts
|
|
579
|
-
);
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
public async getWithdrawCollateralIx(
|
|
583
|
-
amount: BN,
|
|
584
|
-
collateralAccountPublicKey: PublicKey
|
|
585
|
-
): Promise<TransactionInstruction> {
|
|
586
|
-
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
587
|
-
const user: any = await this.program.account.user.fetch(
|
|
588
|
-
userAccountPublicKey
|
|
589
|
-
);
|
|
590
|
-
|
|
591
|
-
const state = this.getStateAccount();
|
|
592
|
-
return await this.program.instruction.withdrawCollateral(amount, {
|
|
593
|
-
accounts: {
|
|
594
|
-
state: await this.getStatePublicKey(),
|
|
595
|
-
user: userAccountPublicKey,
|
|
596
|
-
collateralVault: state.collateralVault,
|
|
597
|
-
collateralVaultAuthority: state.collateralVaultAuthority,
|
|
598
|
-
insuranceVault: state.insuranceVault,
|
|
599
|
-
insuranceVaultAuthority: state.insuranceVaultAuthority,
|
|
600
|
-
userCollateralAccount: collateralAccountPublicKey,
|
|
601
|
-
authority: this.wallet.publicKey,
|
|
602
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
603
|
-
markets: state.markets,
|
|
604
|
-
userPositions: user.positions,
|
|
605
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
606
|
-
depositHistory: state.depositHistory,
|
|
607
|
-
},
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
public async openPosition(
|
|
612
|
-
direction: PositionDirection,
|
|
679
|
+
public async withdraw(
|
|
613
680
|
amount: BN,
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
referrer?: PublicKey
|
|
681
|
+
bankIndex: BN,
|
|
682
|
+
userTokenAccount: PublicKey,
|
|
683
|
+
reduceOnly = false
|
|
618
684
|
): Promise<TransactionSignature> {
|
|
619
|
-
|
|
685
|
+
const { txSig } = await this.txSender.send(
|
|
620
686
|
wrapInTx(
|
|
621
|
-
await this.
|
|
622
|
-
direction,
|
|
687
|
+
await this.getWithdrawIx(
|
|
623
688
|
amount,
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
referrer
|
|
689
|
+
bankIndex,
|
|
690
|
+
userTokenAccount,
|
|
691
|
+
reduceOnly
|
|
628
692
|
)
|
|
629
693
|
),
|
|
630
694
|
[],
|
|
631
695
|
this.opts
|
|
632
696
|
);
|
|
697
|
+
return txSig;
|
|
633
698
|
}
|
|
634
699
|
|
|
635
|
-
public async
|
|
636
|
-
direction: PositionDirection,
|
|
700
|
+
public async getWithdrawIx(
|
|
637
701
|
amount: BN,
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
referrer?: PublicKey
|
|
702
|
+
bankIndex: BN,
|
|
703
|
+
userTokenAccount: PublicKey,
|
|
704
|
+
reduceOnly = false
|
|
642
705
|
): Promise<TransactionInstruction> {
|
|
643
706
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
644
|
-
const userAccount = await this.getUserAccount();
|
|
645
707
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
const optionalAccounts = {
|
|
651
|
-
discountToken: false,
|
|
652
|
-
referrer: false,
|
|
653
|
-
};
|
|
654
|
-
const remainingAccounts = [];
|
|
655
|
-
if (discountToken) {
|
|
656
|
-
optionalAccounts.discountToken = true;
|
|
657
|
-
remainingAccounts.push({
|
|
658
|
-
pubkey: discountToken,
|
|
659
|
-
isWritable: false,
|
|
660
|
-
isSigner: false,
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
if (referrer) {
|
|
664
|
-
optionalAccounts.referrer = true;
|
|
665
|
-
remainingAccounts.push({
|
|
666
|
-
pubkey: referrer,
|
|
667
|
-
isWritable: true,
|
|
668
|
-
isSigner: false,
|
|
669
|
-
});
|
|
670
|
-
}
|
|
708
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
709
|
+
writableBankIndex: bankIndex,
|
|
710
|
+
});
|
|
671
711
|
|
|
672
|
-
const
|
|
673
|
-
this.getMarketsAccount().markets[marketIndex.toNumber()].amm.oracle;
|
|
712
|
+
const bank = this.getBankAccount(bankIndex);
|
|
674
713
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
direction,
|
|
714
|
+
return await this.program.instruction.withdraw(
|
|
715
|
+
bankIndex,
|
|
678
716
|
amount,
|
|
679
|
-
|
|
680
|
-
limitPrice,
|
|
681
|
-
optionalAccounts,
|
|
717
|
+
reduceOnly,
|
|
682
718
|
{
|
|
683
719
|
accounts: {
|
|
684
720
|
state: await this.getStatePublicKey(),
|
|
721
|
+
bank: bank.pubkey,
|
|
722
|
+
bankVault: bank.vault,
|
|
723
|
+
bankVaultAuthority: bank.vaultAuthority,
|
|
685
724
|
user: userAccountPublicKey,
|
|
725
|
+
userTokenAccount: userTokenAccount,
|
|
686
726
|
authority: this.wallet.publicKey,
|
|
687
|
-
|
|
688
|
-
userPositions: userAccount.positions,
|
|
689
|
-
tradeHistory: state.tradeHistory,
|
|
690
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
691
|
-
fundingRateHistory: state.fundingRateHistory,
|
|
692
|
-
oracle: priceOracle,
|
|
727
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
693
728
|
},
|
|
694
|
-
remainingAccounts
|
|
729
|
+
remainingAccounts,
|
|
695
730
|
}
|
|
696
731
|
);
|
|
697
732
|
}
|
|
698
733
|
|
|
699
|
-
public async
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
734
|
+
public async transferDeposit(
|
|
735
|
+
amount: BN,
|
|
736
|
+
bankIndex: BN,
|
|
737
|
+
fromUserId: number,
|
|
738
|
+
toUserId: number
|
|
703
739
|
): Promise<TransactionSignature> {
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
await this.getPlaceOrderIx(orderParams, discountToken, referrer)
|
|
740
|
+
const { txSig } = await this.txSender.send(
|
|
741
|
+
wrapInTx(
|
|
742
|
+
await this.getTransferDepositIx(amount, bankIndex, fromUserId, toUserId)
|
|
743
|
+
),
|
|
744
|
+
[],
|
|
745
|
+
this.opts
|
|
711
746
|
);
|
|
712
|
-
|
|
713
|
-
for (const instruction of instructions) {
|
|
714
|
-
tx.add(instruction);
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
return await this.txSender.send(tx, [], this.opts);
|
|
747
|
+
return txSig;
|
|
718
748
|
}
|
|
719
749
|
|
|
720
|
-
public async
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
return await this.txSender.send(
|
|
726
|
-
wrapInTx(
|
|
727
|
-
await this.getPlaceOrderIx(orderParams, discountToken, referrer)
|
|
728
|
-
),
|
|
729
|
-
[],
|
|
730
|
-
this.opts
|
|
731
|
-
);
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
public async getPlaceOrderIx(
|
|
735
|
-
orderParams: OrderParams,
|
|
736
|
-
discountToken?: PublicKey,
|
|
737
|
-
referrer?: PublicKey
|
|
750
|
+
public async getTransferDepositIx(
|
|
751
|
+
amount: BN,
|
|
752
|
+
bankIndex: BN,
|
|
753
|
+
fromUserId: number,
|
|
754
|
+
toUserId: number
|
|
738
755
|
): Promise<TransactionInstruction> {
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
throw Error(
|
|
750
|
-
'Optional accounts specified discount token but no discount token present'
|
|
751
|
-
);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
remainingAccounts.push({
|
|
755
|
-
pubkey: discountToken,
|
|
756
|
-
isWritable: false,
|
|
757
|
-
isSigner: false,
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
if (orderParams.optionalAccounts.referrer) {
|
|
762
|
-
if (!referrer) {
|
|
763
|
-
throw Error(
|
|
764
|
-
'Optional accounts specified referrer but no referrer present'
|
|
765
|
-
);
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
remainingAccounts.push({
|
|
769
|
-
pubkey: referrer,
|
|
770
|
-
isWritable: false,
|
|
771
|
-
isSigner: false,
|
|
772
|
-
});
|
|
773
|
-
}
|
|
756
|
+
const fromUser = await getUserAccountPublicKey(
|
|
757
|
+
this.program.programId,
|
|
758
|
+
this.wallet.publicKey,
|
|
759
|
+
fromUserId
|
|
760
|
+
);
|
|
761
|
+
const toUser = await getUserAccountPublicKey(
|
|
762
|
+
this.program.programId,
|
|
763
|
+
this.wallet.publicKey,
|
|
764
|
+
toUserId
|
|
765
|
+
);
|
|
774
766
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
isWritable: false,
|
|
779
|
-
isSigner: false,
|
|
780
|
-
});
|
|
781
|
-
}
|
|
767
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
768
|
+
writableBankIndex: bankIndex,
|
|
769
|
+
});
|
|
782
770
|
|
|
783
|
-
|
|
784
|
-
const orderState = this.getOrderStateAccount();
|
|
785
|
-
return await this.program.instruction.placeOrder(orderParams, {
|
|
771
|
+
return await this.program.instruction.transferDeposit(bankIndex, amount, {
|
|
786
772
|
accounts: {
|
|
787
|
-
state: await this.getStatePublicKey(),
|
|
788
|
-
user: userAccountPublicKey,
|
|
789
773
|
authority: this.wallet.publicKey,
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
794
|
-
fundingRateHistory: state.fundingRateHistory,
|
|
795
|
-
orderState: await this.getOrderStatePublicKey(),
|
|
796
|
-
orderHistory: orderState.orderHistory,
|
|
774
|
+
fromUser,
|
|
775
|
+
toUser,
|
|
776
|
+
state: await this.getStatePublicKey(),
|
|
797
777
|
},
|
|
798
778
|
remainingAccounts,
|
|
799
779
|
});
|
|
800
780
|
}
|
|
801
781
|
|
|
802
|
-
public async
|
|
803
|
-
|
|
804
|
-
userOrdersAccountPublicKey: PublicKey
|
|
782
|
+
public async updateBankCumulativeInterest(
|
|
783
|
+
bankIndex: BN
|
|
805
784
|
): Promise<TransactionSignature> {
|
|
806
|
-
|
|
807
|
-
wrapInTx(
|
|
808
|
-
await this.getExpireOrdersIx(
|
|
809
|
-
userAccountPublicKey,
|
|
810
|
-
userOrdersAccountPublicKey
|
|
811
|
-
)
|
|
812
|
-
),
|
|
785
|
+
const { txSig } = await this.txSender.send(
|
|
786
|
+
wrapInTx(await this.updateBankCumulativeInterestIx(bankIndex)),
|
|
813
787
|
[],
|
|
814
788
|
this.opts
|
|
815
789
|
);
|
|
790
|
+
return txSig;
|
|
816
791
|
}
|
|
817
792
|
|
|
818
|
-
public async
|
|
819
|
-
|
|
820
|
-
userOrdersAccountPublicKey: PublicKey
|
|
793
|
+
public async updateBankCumulativeInterestIx(
|
|
794
|
+
bankIndex: BN
|
|
821
795
|
): Promise<TransactionInstruction> {
|
|
822
|
-
const
|
|
823
|
-
|
|
824
|
-
userAccountPublicKey
|
|
825
|
-
);
|
|
826
|
-
|
|
827
|
-
const orderState = this.getOrderStateAccount();
|
|
828
|
-
return await this.program.instruction.expireOrders({
|
|
796
|
+
const bank = this.getBankAccount(bankIndex);
|
|
797
|
+
return await this.program.instruction.updateBankCumulativeInterest({
|
|
829
798
|
accounts: {
|
|
830
|
-
|
|
831
|
-
filler: fillerPublicKey,
|
|
832
|
-
user: userAccountPublicKey,
|
|
833
|
-
authority: this.wallet.publicKey,
|
|
834
|
-
userPositions: userAccount.positions,
|
|
835
|
-
userOrders: userOrdersAccountPublicKey,
|
|
836
|
-
orderState: await this.getOrderStatePublicKey(),
|
|
837
|
-
orderHistory: orderState.orderHistory,
|
|
799
|
+
bank: bank.pubkey,
|
|
838
800
|
},
|
|
839
801
|
});
|
|
840
802
|
}
|
|
841
803
|
|
|
842
|
-
public async
|
|
843
|
-
|
|
844
|
-
|
|
804
|
+
public async openPosition(
|
|
805
|
+
direction: PositionDirection,
|
|
806
|
+
amount: BN,
|
|
807
|
+
marketIndex: BN,
|
|
808
|
+
limitPrice?: BN
|
|
809
|
+
): Promise<TransactionSignature> {
|
|
810
|
+
return await this.placeAndTake({
|
|
811
|
+
orderType: OrderType.MARKET,
|
|
812
|
+
marketIndex,
|
|
813
|
+
direction,
|
|
814
|
+
baseAssetAmount: amount,
|
|
815
|
+
price: limitPrice,
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
public async placeOrder(
|
|
820
|
+
orderParams: OptionalOrderParams
|
|
845
821
|
): Promise<TransactionSignature> {
|
|
846
|
-
|
|
847
|
-
wrapInTx(await this.
|
|
822
|
+
const { txSig, slot } = await this.txSender.send(
|
|
823
|
+
wrapInTx(await this.getPlaceOrderIx(orderParams)),
|
|
848
824
|
[],
|
|
849
825
|
this.opts
|
|
850
826
|
);
|
|
827
|
+
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
828
|
+
return txSig;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
getOrderParams(optionalOrderParams: OptionalOrderParams): OrderParams {
|
|
832
|
+
return Object.assign({}, DefaultOrderParams, optionalOrderParams);
|
|
851
833
|
}
|
|
852
834
|
|
|
853
|
-
public async
|
|
854
|
-
|
|
855
|
-
oracle?: PublicKey
|
|
835
|
+
public async getPlaceOrderIx(
|
|
836
|
+
orderParams: OptionalOrderParams
|
|
856
837
|
): Promise<TransactionInstruction> {
|
|
838
|
+
orderParams = this.getOrderParams(orderParams);
|
|
857
839
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
858
|
-
const userAccount = await this.getUserAccount();
|
|
859
|
-
|
|
860
|
-
const state = this.getStateAccount();
|
|
861
|
-
const orderState = this.getOrderStateAccount();
|
|
862
840
|
|
|
863
|
-
const remainingAccounts =
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
pubkey: oracle,
|
|
867
|
-
isWritable: false,
|
|
868
|
-
isSigner: false,
|
|
869
|
-
});
|
|
870
|
-
}
|
|
841
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
842
|
+
writableMarketIndex: orderParams.marketIndex,
|
|
843
|
+
});
|
|
871
844
|
|
|
872
|
-
return await this.program.instruction.
|
|
845
|
+
return await this.program.instruction.placeOrder(orderParams, {
|
|
873
846
|
accounts: {
|
|
874
847
|
state: await this.getStatePublicKey(),
|
|
875
848
|
user: userAccountPublicKey,
|
|
876
849
|
authority: this.wallet.publicKey,
|
|
877
|
-
markets: state.markets,
|
|
878
|
-
userOrders: await this.getUserOrdersAccountPublicKey(),
|
|
879
|
-
userPositions: userAccount.positions,
|
|
880
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
881
|
-
fundingRateHistory: state.fundingRateHistory,
|
|
882
|
-
orderState: await this.getOrderStatePublicKey(),
|
|
883
|
-
orderHistory: orderState.orderHistory,
|
|
884
850
|
},
|
|
885
851
|
remainingAccounts,
|
|
886
852
|
});
|
|
887
853
|
}
|
|
888
854
|
|
|
889
|
-
public async
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
): Promise<TransactionSignature> {
|
|
893
|
-
return await this.txSender.send(
|
|
894
|
-
wrapInTx(await this.getCancelOrderByUserIdIx(userOrderId, oracle)),
|
|
855
|
+
public async updateAMMs(marketIndexes: BN[]): Promise<TransactionSignature> {
|
|
856
|
+
const { txSig } = await this.txSender.send(
|
|
857
|
+
wrapInTx(await this.getUpdateAMMsIx(marketIndexes)),
|
|
895
858
|
[],
|
|
896
859
|
this.opts
|
|
897
860
|
);
|
|
861
|
+
return txSig;
|
|
898
862
|
}
|
|
899
863
|
|
|
900
|
-
public async
|
|
901
|
-
|
|
902
|
-
oracle?: PublicKey
|
|
864
|
+
public async getUpdateAMMsIx(
|
|
865
|
+
marketIndexes: BN[]
|
|
903
866
|
): Promise<TransactionInstruction> {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
const
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
867
|
+
for (let i = marketIndexes.length; i < 5; i++) {
|
|
868
|
+
marketIndexes.push(new BN(100));
|
|
869
|
+
}
|
|
870
|
+
const marketAccountInfos = [];
|
|
871
|
+
const oracleAccountInfos = [];
|
|
872
|
+
for (const marketIndex of marketIndexes) {
|
|
873
|
+
if (!marketIndex.eq(new BN(100))) {
|
|
874
|
+
const market = this.getMarketAccount(marketIndex);
|
|
875
|
+
marketAccountInfos.push({
|
|
876
|
+
pubkey: market.pubkey,
|
|
877
|
+
isWritable: true,
|
|
878
|
+
isSigner: false,
|
|
879
|
+
});
|
|
880
|
+
oracleAccountInfos.push({
|
|
881
|
+
pubkey: market.amm.oracle,
|
|
882
|
+
isWritable: false,
|
|
883
|
+
isSigner: false,
|
|
884
|
+
});
|
|
885
|
+
}
|
|
917
886
|
}
|
|
887
|
+
const remainingAccounts = oracleAccountInfos.concat(marketAccountInfos);
|
|
918
888
|
|
|
919
|
-
return await this.program.instruction.
|
|
889
|
+
return await this.program.instruction.updateAmms(marketIndexes, {
|
|
920
890
|
accounts: {
|
|
921
891
|
state: await this.getStatePublicKey(),
|
|
922
|
-
user: userAccountPublicKey,
|
|
923
892
|
authority: this.wallet.publicKey,
|
|
924
|
-
markets: state.markets,
|
|
925
|
-
userOrders: await this.getUserOrdersAccountPublicKey(),
|
|
926
|
-
userPositions: userAccount.positions,
|
|
927
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
928
|
-
fundingRateHistory: state.fundingRateHistory,
|
|
929
|
-
orderState: await this.getOrderStatePublicKey(),
|
|
930
|
-
orderHistory: orderState.orderHistory,
|
|
931
893
|
},
|
|
932
894
|
remainingAccounts,
|
|
933
895
|
});
|
|
934
896
|
}
|
|
935
897
|
|
|
936
|
-
public async
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
): Promise<TransactionSignature> {
|
|
940
|
-
return await this.txSender.send(
|
|
941
|
-
wrapInTx(await this.getCancelAllOrdersIx(oracles, bestEffort)),
|
|
898
|
+
public async cancelOrder(orderId?: BN): Promise<TransactionSignature> {
|
|
899
|
+
const { txSig } = await this.txSender.send(
|
|
900
|
+
wrapInTx(await this.getCancelOrderIx(orderId)),
|
|
942
901
|
[],
|
|
943
902
|
this.opts
|
|
944
903
|
);
|
|
904
|
+
return txSig;
|
|
945
905
|
}
|
|
946
906
|
|
|
947
|
-
public async
|
|
948
|
-
oracles: PublicKey[],
|
|
949
|
-
bestEffort?: boolean
|
|
950
|
-
): Promise<TransactionInstruction> {
|
|
907
|
+
public async getCancelOrderIx(orderId?: BN): Promise<TransactionInstruction> {
|
|
951
908
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
952
|
-
const userAccount = await this.getUserAccount();
|
|
953
909
|
|
|
954
|
-
const
|
|
955
|
-
const orderState = this.getOrderStateAccount();
|
|
956
|
-
|
|
957
|
-
const remainingAccounts = [];
|
|
958
|
-
for (const oracle of oracles) {
|
|
959
|
-
remainingAccounts.push({
|
|
960
|
-
pubkey: oracle,
|
|
961
|
-
isWritable: false,
|
|
962
|
-
isSigner: false,
|
|
963
|
-
});
|
|
964
|
-
}
|
|
910
|
+
const remainingAccounts = this.getRemainingAccounts({});
|
|
965
911
|
|
|
966
|
-
return await this.program.instruction.
|
|
912
|
+
return await this.program.instruction.cancelOrder(orderId ?? null, {
|
|
967
913
|
accounts: {
|
|
968
914
|
state: await this.getStatePublicKey(),
|
|
969
915
|
user: userAccountPublicKey,
|
|
970
916
|
authority: this.wallet.publicKey,
|
|
971
|
-
markets: state.markets,
|
|
972
|
-
userOrders: await this.getUserOrdersAccountPublicKey(),
|
|
973
|
-
userPositions: userAccount.positions,
|
|
974
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
975
|
-
fundingRateHistory: state.fundingRateHistory,
|
|
976
|
-
orderState: await this.getOrderStatePublicKey(),
|
|
977
|
-
orderHistory: orderState.orderHistory,
|
|
978
917
|
},
|
|
979
918
|
remainingAccounts,
|
|
980
919
|
});
|
|
981
920
|
}
|
|
982
921
|
|
|
983
|
-
public async
|
|
984
|
-
|
|
985
|
-
bestEffort?: boolean,
|
|
986
|
-
marketIndexOnly?: BN,
|
|
987
|
-
directionOnly?: PositionDirection
|
|
922
|
+
public async cancelOrderByUserId(
|
|
923
|
+
userOrderId: number
|
|
988
924
|
): Promise<TransactionSignature> {
|
|
989
|
-
|
|
990
|
-
wrapInTx(
|
|
991
|
-
await this.getCancelOrdersByMarketAndSideIx(
|
|
992
|
-
oracles,
|
|
993
|
-
bestEffort,
|
|
994
|
-
marketIndexOnly,
|
|
995
|
-
directionOnly
|
|
996
|
-
)
|
|
997
|
-
),
|
|
925
|
+
const { txSig } = await this.txSender.send(
|
|
926
|
+
wrapInTx(await this.getCancelOrderByUserIdIx(userOrderId)),
|
|
998
927
|
[],
|
|
999
928
|
this.opts
|
|
1000
929
|
);
|
|
930
|
+
return txSig;
|
|
1001
931
|
}
|
|
1002
932
|
|
|
1003
|
-
public async
|
|
1004
|
-
|
|
1005
|
-
bestEffort?: boolean,
|
|
1006
|
-
marketIndexOnly?: BN,
|
|
1007
|
-
directionOnly?: PositionDirection
|
|
933
|
+
public async getCancelOrderByUserIdIx(
|
|
934
|
+
userOrderId: number
|
|
1008
935
|
): Promise<TransactionInstruction> {
|
|
1009
936
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1010
|
-
const userAccount = await this.getUserAccount();
|
|
1011
937
|
|
|
1012
|
-
const
|
|
1013
|
-
const
|
|
938
|
+
const order = this.getOrderByUserId(userOrderId);
|
|
939
|
+
const oracle = this.getMarketAccount(order.marketIndex).amm.oracle;
|
|
1014
940
|
|
|
1015
|
-
const remainingAccounts =
|
|
1016
|
-
for (const oracle of oracles) {
|
|
1017
|
-
remainingAccounts.push({
|
|
1018
|
-
pubkey: oracle,
|
|
1019
|
-
isWritable: false,
|
|
1020
|
-
isSigner: false,
|
|
1021
|
-
});
|
|
1022
|
-
}
|
|
941
|
+
const remainingAccounts = this.getRemainingAccounts({});
|
|
1023
942
|
|
|
1024
|
-
return await this.program.instruction.
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
markets: state.markets,
|
|
1034
|
-
userOrders: await this.getUserOrdersAccountPublicKey(),
|
|
1035
|
-
userPositions: userAccount.positions,
|
|
1036
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
1037
|
-
fundingRateHistory: state.fundingRateHistory,
|
|
1038
|
-
orderState: await this.getOrderStatePublicKey(),
|
|
1039
|
-
orderHistory: orderState.orderHistory,
|
|
1040
|
-
},
|
|
1041
|
-
remainingAccounts,
|
|
1042
|
-
}
|
|
1043
|
-
);
|
|
943
|
+
return await this.program.instruction.cancelOrderByUserId(userOrderId, {
|
|
944
|
+
accounts: {
|
|
945
|
+
state: await this.getStatePublicKey(),
|
|
946
|
+
user: userAccountPublicKey,
|
|
947
|
+
authority: this.wallet.publicKey,
|
|
948
|
+
oracle,
|
|
949
|
+
},
|
|
950
|
+
remainingAccounts,
|
|
951
|
+
});
|
|
1044
952
|
}
|
|
1045
953
|
|
|
1046
954
|
public async fillOrder(
|
|
1047
955
|
userAccountPublicKey: PublicKey,
|
|
1048
|
-
|
|
1049
|
-
order
|
|
956
|
+
user: UserAccount,
|
|
957
|
+
order?: Order,
|
|
958
|
+
makerInfo?: MakerInfo
|
|
1050
959
|
): Promise<TransactionSignature> {
|
|
1051
|
-
|
|
960
|
+
const { txSig } = await this.txSender.send(
|
|
1052
961
|
wrapInTx(
|
|
1053
|
-
await this.getFillOrderIx(
|
|
1054
|
-
userAccountPublicKey,
|
|
1055
|
-
userOrdersAccountPublicKey,
|
|
1056
|
-
order
|
|
1057
|
-
)
|
|
962
|
+
await this.getFillOrderIx(userAccountPublicKey, user, order, makerInfo)
|
|
1058
963
|
),
|
|
1059
964
|
[],
|
|
1060
965
|
this.opts
|
|
1061
966
|
);
|
|
967
|
+
return txSig;
|
|
1062
968
|
}
|
|
1063
969
|
|
|
1064
970
|
public async getFillOrderIx(
|
|
1065
971
|
userAccountPublicKey: PublicKey,
|
|
1066
|
-
|
|
1067
|
-
order: Order
|
|
972
|
+
userAccount: UserAccount,
|
|
973
|
+
order: Order,
|
|
974
|
+
makerInfo?: MakerInfo
|
|
1068
975
|
): Promise<TransactionInstruction> {
|
|
1069
976
|
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
1070
|
-
const userAccount: any = await this.program.account.user.fetch(
|
|
1071
|
-
userAccountPublicKey
|
|
1072
|
-
);
|
|
1073
977
|
|
|
1074
978
|
const marketIndex = order.marketIndex;
|
|
1075
|
-
const
|
|
979
|
+
const marketAccount = this.getMarketAccount(marketIndex);
|
|
1076
980
|
|
|
1077
|
-
const
|
|
1078
|
-
const
|
|
981
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
982
|
+
const bankAccountMap = new Map<number, AccountMeta>();
|
|
983
|
+
const marketAccountMap = new Map<number, AccountMeta>();
|
|
1079
984
|
|
|
1080
|
-
|
|
1081
|
-
|
|
985
|
+
marketAccountMap.set(marketIndex.toNumber(), {
|
|
986
|
+
pubkey: marketAccount.pubkey,
|
|
987
|
+
isWritable: true,
|
|
988
|
+
isSigner: false,
|
|
989
|
+
});
|
|
990
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
991
|
+
pubkey: marketAccount.amm.oracle,
|
|
992
|
+
isWritable: false,
|
|
993
|
+
isSigner: false,
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
997
|
+
if (!bankBalance.balance.eq(ZERO)) {
|
|
998
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
999
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
1000
|
+
pubkey: bankAccount.pubkey,
|
|
1001
|
+
isSigner: false,
|
|
1002
|
+
isWritable: true,
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
if (!bankAccount.oracle.equals(PublicKey.default)) {
|
|
1006
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
1007
|
+
pubkey: bankAccount.oracle,
|
|
1008
|
+
isSigner: false,
|
|
1009
|
+
isWritable: false,
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
for (const position of userAccount.positions) {
|
|
1016
|
+
if (
|
|
1017
|
+
!positionIsAvailable(position) &&
|
|
1018
|
+
!position.marketIndex.eq(order.marketIndex)
|
|
1019
|
+
) {
|
|
1020
|
+
const market = this.getMarketAccount(position.marketIndex);
|
|
1021
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
1022
|
+
pubkey: market.pubkey,
|
|
1023
|
+
isWritable: true,
|
|
1024
|
+
isSigner: false,
|
|
1025
|
+
});
|
|
1026
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1027
|
+
pubkey: market.amm.oracle,
|
|
1028
|
+
isWritable: false,
|
|
1029
|
+
isSigner: false,
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
const remainingAccounts = [
|
|
1035
|
+
...oracleAccountMap.values(),
|
|
1036
|
+
...bankAccountMap.values(),
|
|
1037
|
+
...marketAccountMap.values(),
|
|
1038
|
+
];
|
|
1039
|
+
|
|
1040
|
+
if (makerInfo) {
|
|
1082
1041
|
remainingAccounts.push({
|
|
1083
|
-
pubkey:
|
|
1042
|
+
pubkey: makerInfo.maker,
|
|
1084
1043
|
isWritable: true,
|
|
1085
1044
|
isSigner: false,
|
|
1086
1045
|
});
|
|
1087
1046
|
}
|
|
1088
1047
|
|
|
1089
1048
|
const orderId = order.orderId;
|
|
1090
|
-
|
|
1049
|
+
const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
|
|
1050
|
+
|
|
1051
|
+
return await this.program.instruction.fillOrder(orderId, makerOrderId, {
|
|
1091
1052
|
accounts: {
|
|
1092
1053
|
state: await this.getStatePublicKey(),
|
|
1093
1054
|
filler: fillerPublicKey,
|
|
1094
1055
|
user: userAccountPublicKey,
|
|
1095
1056
|
authority: this.wallet.publicKey,
|
|
1096
|
-
markets: state.markets,
|
|
1097
|
-
userPositions: userAccount.positions,
|
|
1098
|
-
userOrders: userOrdersAccountPublicKey,
|
|
1099
|
-
tradeHistory: state.tradeHistory,
|
|
1100
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
1101
|
-
fundingRateHistory: state.fundingRateHistory,
|
|
1102
|
-
orderState: await this.getOrderStatePublicKey(),
|
|
1103
|
-
orderHistory: orderState.orderHistory,
|
|
1104
|
-
extendedCurveHistory: state.extendedCurveHistory,
|
|
1105
|
-
oracle: oracle,
|
|
1106
1057
|
},
|
|
1107
1058
|
remainingAccounts,
|
|
1108
1059
|
});
|
|
1109
1060
|
}
|
|
1110
1061
|
|
|
1111
|
-
public async
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
): Promise<TransactionSignature> {
|
|
1116
|
-
const instructions: anchor.web3.TransactionInstruction[] = [];
|
|
1117
|
-
const userOrdersAccountExists = await this.userOrdersAccountExists();
|
|
1118
|
-
if (!userOrdersAccountExists) {
|
|
1119
|
-
instructions.push(await this.getInitializeUserOrdersInstruction());
|
|
1120
|
-
}
|
|
1121
|
-
instructions.push(
|
|
1122
|
-
await this.getPlaceAndFillOrderIx(orderParams, discountToken, referrer)
|
|
1123
|
-
);
|
|
1124
|
-
const tx = new Transaction();
|
|
1125
|
-
for (const instruction of instructions) {
|
|
1126
|
-
tx.add(instruction);
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
return await this.txSender.send(tx, [], this.opts);
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
public async placeAndFillOrder(
|
|
1133
|
-
orderParams: OrderParams,
|
|
1134
|
-
discountToken?: PublicKey,
|
|
1135
|
-
referrer?: PublicKey
|
|
1062
|
+
public async triggerOrder(
|
|
1063
|
+
userAccountPublicKey: PublicKey,
|
|
1064
|
+
user: UserAccount,
|
|
1065
|
+
order: Order
|
|
1136
1066
|
): Promise<TransactionSignature> {
|
|
1137
|
-
|
|
1138
|
-
wrapInTx(
|
|
1139
|
-
await this.getPlaceAndFillOrderIx(orderParams, discountToken, referrer)
|
|
1140
|
-
),
|
|
1067
|
+
const { txSig } = await this.txSender.send(
|
|
1068
|
+
wrapInTx(await this.getTriggerOrderIx(userAccountPublicKey, user, order)),
|
|
1141
1069
|
[],
|
|
1142
1070
|
this.opts
|
|
1143
1071
|
);
|
|
1072
|
+
return txSig;
|
|
1144
1073
|
}
|
|
1145
1074
|
|
|
1146
|
-
public async
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1075
|
+
public async getTriggerOrderIx(
|
|
1076
|
+
userAccountPublicKey: PublicKey,
|
|
1077
|
+
userAccount: UserAccount,
|
|
1078
|
+
order: Order
|
|
1150
1079
|
): Promise<TransactionInstruction> {
|
|
1151
|
-
const
|
|
1152
|
-
const userAccount = await this.getUserAccount();
|
|
1080
|
+
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
1153
1081
|
|
|
1154
|
-
const
|
|
1155
|
-
|
|
1156
|
-
.oracle;
|
|
1082
|
+
const marketIndex = order.marketIndex;
|
|
1083
|
+
const marketAccount = this.getMarketAccount(marketIndex);
|
|
1157
1084
|
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
throw Error(
|
|
1162
|
-
'Optional accounts specified discount token but no discount token present'
|
|
1163
|
-
);
|
|
1164
|
-
}
|
|
1085
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
1086
|
+
const bankAccountMap = new Map<number, AccountMeta>();
|
|
1087
|
+
const marketAccountMap = new Map<number, AccountMeta>();
|
|
1165
1088
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1089
|
+
marketAccountMap.set(marketIndex.toNumber(), {
|
|
1090
|
+
pubkey: marketAccount.pubkey,
|
|
1091
|
+
isWritable: true,
|
|
1092
|
+
isSigner: false,
|
|
1093
|
+
});
|
|
1094
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
1095
|
+
pubkey: marketAccount.amm.oracle,
|
|
1096
|
+
isWritable: false,
|
|
1097
|
+
isSigner: false,
|
|
1098
|
+
});
|
|
1172
1099
|
|
|
1173
|
-
|
|
1174
|
-
if (!
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1100
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
1101
|
+
if (!bankBalance.balance.eq(ZERO)) {
|
|
1102
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
1103
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
1104
|
+
pubkey: bankAccount.pubkey,
|
|
1105
|
+
isSigner: false,
|
|
1106
|
+
isWritable: true,
|
|
1107
|
+
});
|
|
1108
|
+
|
|
1109
|
+
if (!bankAccount.oracle.equals(PublicKey.default)) {
|
|
1110
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
1111
|
+
pubkey: bankAccount.oracle,
|
|
1112
|
+
isSigner: false,
|
|
1113
|
+
isWritable: false,
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1178
1116
|
}
|
|
1117
|
+
}
|
|
1179
1118
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1119
|
+
for (const position of userAccount.positions) {
|
|
1120
|
+
if (
|
|
1121
|
+
!positionIsAvailable(position) &&
|
|
1122
|
+
!position.marketIndex.eq(order.marketIndex)
|
|
1123
|
+
) {
|
|
1124
|
+
const market = this.getMarketAccount(position.marketIndex);
|
|
1125
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
1126
|
+
pubkey: market.pubkey,
|
|
1127
|
+
isWritable: true,
|
|
1128
|
+
isSigner: false,
|
|
1129
|
+
});
|
|
1130
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1131
|
+
pubkey: market.amm.oracle,
|
|
1132
|
+
isWritable: false,
|
|
1133
|
+
isSigner: false,
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1185
1136
|
}
|
|
1186
1137
|
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1138
|
+
const remainingAccounts = [
|
|
1139
|
+
...oracleAccountMap.values(),
|
|
1140
|
+
...bankAccountMap.values(),
|
|
1141
|
+
...marketAccountMap.values(),
|
|
1142
|
+
];
|
|
1143
|
+
|
|
1144
|
+
const orderId = order.orderId;
|
|
1145
|
+
return await this.program.instruction.triggerOrder(orderId, {
|
|
1190
1146
|
accounts: {
|
|
1191
1147
|
state: await this.getStatePublicKey(),
|
|
1148
|
+
filler: fillerPublicKey,
|
|
1192
1149
|
user: userAccountPublicKey,
|
|
1193
1150
|
authority: this.wallet.publicKey,
|
|
1194
|
-
markets: state.markets,
|
|
1195
|
-
userOrders: await this.getUserOrdersAccountPublicKey(),
|
|
1196
|
-
userPositions: userAccount.positions,
|
|
1197
|
-
tradeHistory: state.tradeHistory,
|
|
1198
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
1199
|
-
fundingRateHistory: state.fundingRateHistory,
|
|
1200
|
-
orderState: await this.getOrderStatePublicKey(),
|
|
1201
|
-
orderHistory: orderState.orderHistory,
|
|
1202
|
-
extendedCurveHistory: state.extendedCurveHistory,
|
|
1203
|
-
oracle: priceOracle,
|
|
1204
1151
|
},
|
|
1205
1152
|
remainingAccounts,
|
|
1206
1153
|
});
|
|
1207
1154
|
}
|
|
1208
1155
|
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
* @param discountToken
|
|
1213
|
-
* @param referrer
|
|
1214
|
-
* @returns
|
|
1215
|
-
*/
|
|
1216
|
-
public async closePosition(
|
|
1217
|
-
marketIndex: BN,
|
|
1218
|
-
discountToken?: PublicKey,
|
|
1219
|
-
referrer?: PublicKey
|
|
1156
|
+
public async placeAndTake(
|
|
1157
|
+
orderParams: OptionalOrderParams,
|
|
1158
|
+
makerInfo?: MakerInfo
|
|
1220
1159
|
): Promise<TransactionSignature> {
|
|
1221
|
-
|
|
1222
|
-
wrapInTx(
|
|
1223
|
-
await this.getClosePositionIx(marketIndex, discountToken, referrer)
|
|
1224
|
-
),
|
|
1160
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1161
|
+
wrapInTx(await this.getPlaceAndTakeIx(orderParams, makerInfo)),
|
|
1225
1162
|
[],
|
|
1226
1163
|
this.opts
|
|
1227
1164
|
);
|
|
1165
|
+
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
1166
|
+
return txSig;
|
|
1228
1167
|
}
|
|
1229
1168
|
|
|
1230
|
-
public async
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
referrer?: PublicKey
|
|
1169
|
+
public async getPlaceAndTakeIx(
|
|
1170
|
+
orderParams: OptionalOrderParams,
|
|
1171
|
+
makerInfo?: MakerInfo
|
|
1234
1172
|
): Promise<TransactionInstruction> {
|
|
1173
|
+
orderParams = this.getOrderParams(orderParams);
|
|
1235
1174
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1236
|
-
const userAccount = await this.getUserAccount();
|
|
1237
1175
|
|
|
1238
|
-
const
|
|
1239
|
-
|
|
1176
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1177
|
+
writableMarketIndex: orderParams.marketIndex,
|
|
1178
|
+
writableBankIndex: QUOTE_ASSET_BANK_INDEX,
|
|
1179
|
+
});
|
|
1240
1180
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
};
|
|
1245
|
-
const remainingAccounts = [];
|
|
1246
|
-
if (discountToken) {
|
|
1247
|
-
optionalAccounts.discountToken = true;
|
|
1181
|
+
let makerOrderId = null;
|
|
1182
|
+
if (makerInfo) {
|
|
1183
|
+
makerOrderId = makerInfo.order.orderId;
|
|
1248
1184
|
remainingAccounts.push({
|
|
1249
|
-
pubkey:
|
|
1250
|
-
isWritable: false,
|
|
1185
|
+
pubkey: makerInfo.maker,
|
|
1251
1186
|
isSigner: false,
|
|
1252
|
-
});
|
|
1253
|
-
}
|
|
1254
|
-
if (referrer) {
|
|
1255
|
-
optionalAccounts.referrer = true;
|
|
1256
|
-
remainingAccounts.push({
|
|
1257
|
-
pubkey: referrer,
|
|
1258
1187
|
isWritable: true,
|
|
1259
|
-
isSigner: false,
|
|
1260
1188
|
});
|
|
1261
1189
|
}
|
|
1262
1190
|
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
optionalAccounts,
|
|
1191
|
+
return await this.program.instruction.placeAndTake(
|
|
1192
|
+
orderParams,
|
|
1193
|
+
makerOrderId,
|
|
1267
1194
|
{
|
|
1268
1195
|
accounts: {
|
|
1269
1196
|
state: await this.getStatePublicKey(),
|
|
1270
1197
|
user: userAccountPublicKey,
|
|
1271
1198
|
authority: this.wallet.publicKey,
|
|
1272
|
-
markets: state.markets,
|
|
1273
|
-
userPositions: userAccount.positions,
|
|
1274
|
-
tradeHistory: state.tradeHistory,
|
|
1275
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
1276
|
-
fundingRateHistory: state.fundingRateHistory,
|
|
1277
|
-
oracle: priceOracle,
|
|
1278
1199
|
},
|
|
1279
|
-
remainingAccounts
|
|
1200
|
+
remainingAccounts,
|
|
1280
1201
|
}
|
|
1281
1202
|
);
|
|
1282
1203
|
}
|
|
1283
1204
|
|
|
1284
|
-
public async
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
referrer?: PublicKey
|
|
1205
|
+
public async placeAndMake(
|
|
1206
|
+
orderParams: OptionalOrderParams,
|
|
1207
|
+
takerInfo: TakerInfo
|
|
1288
1208
|
): Promise<TransactionSignature> {
|
|
1289
|
-
const
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1209
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1210
|
+
wrapInTx(await this.getPlaceAndMakeIx(orderParams, takerInfo)),
|
|
1211
|
+
[],
|
|
1212
|
+
this.opts
|
|
1213
|
+
);
|
|
1214
|
+
|
|
1215
|
+
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
1216
|
+
|
|
1217
|
+
return txSig;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
public async getPlaceAndMakeIx(
|
|
1221
|
+
orderParams: OptionalOrderParams,
|
|
1222
|
+
takerInfo: TakerInfo
|
|
1223
|
+
): Promise<TransactionInstruction> {
|
|
1224
|
+
orderParams = this.getOrderParams(orderParams);
|
|
1225
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1226
|
+
|
|
1227
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1228
|
+
writableMarketIndex: orderParams.marketIndex,
|
|
1229
|
+
writableBankIndex: QUOTE_ASSET_BANK_INDEX,
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
const takerOrderId = takerInfo!.order!.orderId;
|
|
1233
|
+
remainingAccounts.push({
|
|
1234
|
+
pubkey: takerInfo.taker,
|
|
1235
|
+
isSigner: false,
|
|
1236
|
+
isWritable: true,
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
return await this.program.instruction.placeAndMake(
|
|
1240
|
+
orderParams,
|
|
1241
|
+
takerOrderId,
|
|
1242
|
+
{
|
|
1243
|
+
accounts: {
|
|
1244
|
+
state: await this.getStatePublicKey(),
|
|
1245
|
+
user: userAccountPublicKey,
|
|
1246
|
+
taker: takerInfo.taker,
|
|
1247
|
+
authority: this.wallet.publicKey,
|
|
1248
|
+
},
|
|
1249
|
+
remainingAccounts,
|
|
1293
1250
|
}
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* Close an entire position. If you want to reduce a position, use the {@link openPosition} method in the opposite direction of the current position.
|
|
1256
|
+
* @param marketIndex
|
|
1257
|
+
* @returns
|
|
1258
|
+
*/
|
|
1259
|
+
public async closePosition(marketIndex: BN): Promise<TransactionSignature> {
|
|
1260
|
+
const userPosition = this.getUser().getUserPosition(marketIndex);
|
|
1261
|
+
if (!userPosition) {
|
|
1262
|
+
throw Error(`No position in market ${marketIndex.toString()}`);
|
|
1263
|
+
}
|
|
1294
1264
|
|
|
1265
|
+
return await this.placeAndTake({
|
|
1266
|
+
orderType: OrderType.MARKET,
|
|
1267
|
+
marketIndex,
|
|
1268
|
+
direction: findDirectionToClose(userPosition),
|
|
1269
|
+
baseAssetAmount: userPosition.baseAssetAmount,
|
|
1270
|
+
reduceOnly: true,
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
public async settlePNLs(
|
|
1275
|
+
users: {
|
|
1276
|
+
settleeUserAccountPublicKey: PublicKey;
|
|
1277
|
+
settleeUserAccount: UserAccount;
|
|
1278
|
+
}[],
|
|
1279
|
+
marketIndex: BN
|
|
1280
|
+
): Promise<TransactionSignature> {
|
|
1281
|
+
const ixs = [];
|
|
1282
|
+
for (const { settleeUserAccountPublicKey, settleeUserAccount } of users) {
|
|
1295
1283
|
ixs.push(
|
|
1296
|
-
await this.
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1284
|
+
await this.settlePNLIx(
|
|
1285
|
+
settleeUserAccountPublicKey,
|
|
1286
|
+
settleeUserAccount,
|
|
1287
|
+
marketIndex
|
|
1300
1288
|
)
|
|
1301
1289
|
);
|
|
1302
1290
|
}
|
|
1303
1291
|
|
|
1304
1292
|
const tx = new Transaction().add(...ixs);
|
|
1305
1293
|
|
|
1306
|
-
|
|
1294
|
+
const { txSig } = await this.txSender.send(tx, [], this.opts);
|
|
1295
|
+
return txSig;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
public async settlePNL(
|
|
1299
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
1300
|
+
settleeUserAccount: UserAccount,
|
|
1301
|
+
marketIndex: BN
|
|
1302
|
+
): Promise<TransactionSignature> {
|
|
1303
|
+
const { txSig } = await this.txSender.send(
|
|
1304
|
+
wrapInTx(
|
|
1305
|
+
await this.settlePNLIx(
|
|
1306
|
+
settleeUserAccountPublicKey,
|
|
1307
|
+
settleeUserAccount,
|
|
1308
|
+
marketIndex
|
|
1309
|
+
)
|
|
1310
|
+
),
|
|
1311
|
+
[],
|
|
1312
|
+
this.opts
|
|
1313
|
+
);
|
|
1314
|
+
return txSig;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
public async settlePNLIx(
|
|
1318
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
1319
|
+
settleeUserAccount: UserAccount,
|
|
1320
|
+
marketIndex: BN
|
|
1321
|
+
): Promise<TransactionInstruction> {
|
|
1322
|
+
const marketAccountMap = new Map<number, AccountMeta>();
|
|
1323
|
+
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
1324
|
+
const bankAccountMap = new Map<number, AccountMeta>();
|
|
1325
|
+
for (const position of settleeUserAccount.positions) {
|
|
1326
|
+
if (!positionIsAvailable(position)) {
|
|
1327
|
+
const market = this.getMarketAccount(position.marketIndex);
|
|
1328
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
1329
|
+
pubkey: market.pubkey,
|
|
1330
|
+
isWritable: true, // TODO
|
|
1331
|
+
isSigner: false,
|
|
1332
|
+
});
|
|
1333
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1334
|
+
pubkey: market.amm.oracle,
|
|
1335
|
+
isWritable: false,
|
|
1336
|
+
isSigner: false,
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
for (const userBankBalance of settleeUserAccount.bankBalances) {
|
|
1342
|
+
if (!userBankBalance.balance.eq(QUOTE_ASSET_BANK_INDEX)) {
|
|
1343
|
+
const bankAccount = this.getBankAccount(userBankBalance.bankIndex);
|
|
1344
|
+
bankAccountMap.set(userBankBalance.bankIndex.toNumber(), {
|
|
1345
|
+
pubkey: bankAccount.pubkey,
|
|
1346
|
+
isSigner: false,
|
|
1347
|
+
isWritable: false,
|
|
1348
|
+
});
|
|
1349
|
+
if (!bankAccount.bankIndex.eq(ZERO)) {
|
|
1350
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
1351
|
+
pubkey: bankAccount.oracle,
|
|
1352
|
+
isSigner: false,
|
|
1353
|
+
isWritable: false,
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
const marketAccount = this.getMarketAccount(marketIndex.toNumber());
|
|
1360
|
+
marketAccountMap.set(marketIndex.toNumber(), {
|
|
1361
|
+
pubkey: marketAccount.pubkey,
|
|
1362
|
+
isSigner: false,
|
|
1363
|
+
isWritable: true,
|
|
1364
|
+
});
|
|
1365
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
1366
|
+
pubkey: marketAccount.amm.oracle,
|
|
1367
|
+
isSigner: false,
|
|
1368
|
+
isWritable: false,
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
bankAccountMap.set(QUOTE_ASSET_BANK_INDEX.toNumber(), {
|
|
1372
|
+
pubkey: this.getBankAccount(QUOTE_ASSET_BANK_INDEX).pubkey,
|
|
1373
|
+
isSigner: false,
|
|
1374
|
+
isWritable: true,
|
|
1375
|
+
});
|
|
1376
|
+
|
|
1377
|
+
const remainingAccounts = [
|
|
1378
|
+
...oracleAccountMap.values(),
|
|
1379
|
+
...bankAccountMap.values(),
|
|
1380
|
+
...marketAccountMap.values(),
|
|
1381
|
+
];
|
|
1382
|
+
|
|
1383
|
+
return await this.program.instruction.settlePnl(marketIndex, {
|
|
1384
|
+
accounts: {
|
|
1385
|
+
state: await this.getStatePublicKey(),
|
|
1386
|
+
authority: this.wallet.publicKey,
|
|
1387
|
+
user: settleeUserAccountPublicKey,
|
|
1388
|
+
},
|
|
1389
|
+
remainingAccounts: remainingAccounts,
|
|
1390
|
+
});
|
|
1307
1391
|
}
|
|
1308
1392
|
|
|
1309
1393
|
public async liquidate(
|
|
1310
1394
|
liquidateeUserAccountPublicKey: PublicKey
|
|
1311
1395
|
): Promise<TransactionSignature> {
|
|
1312
|
-
|
|
1396
|
+
const { txSig } = await this.txSender.send(
|
|
1313
1397
|
wrapInTx(await this.getLiquidateIx(liquidateeUserAccountPublicKey)),
|
|
1314
1398
|
[],
|
|
1315
1399
|
this.opts
|
|
1316
1400
|
);
|
|
1401
|
+
return txSig;
|
|
1317
1402
|
}
|
|
1318
1403
|
|
|
1319
1404
|
public async getLiquidateIx(
|
|
1320
1405
|
liquidateeUserAccountPublicKey: PublicKey
|
|
1321
1406
|
): Promise<TransactionInstruction> {
|
|
1322
1407
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1323
|
-
|
|
1324
|
-
const liquidateeUserAccount: any = await this.program.account.user.fetch(
|
|
1408
|
+
const liquidateeUserAccount = (await this.program.account.user.fetch(
|
|
1325
1409
|
liquidateeUserAccountPublicKey
|
|
1326
|
-
);
|
|
1327
|
-
const liquidateePositions: any =
|
|
1328
|
-
await this.program.account.userPositions.fetch(
|
|
1329
|
-
liquidateeUserAccount.positions
|
|
1330
|
-
);
|
|
1331
|
-
const markets = this.getMarketsAccount();
|
|
1410
|
+
)) as UserAccount;
|
|
1332
1411
|
|
|
1333
|
-
const
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1412
|
+
const bankAccountInfos = [
|
|
1413
|
+
{
|
|
1414
|
+
pubkey: this.getQuoteAssetBankAccount().pubkey,
|
|
1415
|
+
isSigner: false,
|
|
1416
|
+
isWritable: true,
|
|
1417
|
+
},
|
|
1418
|
+
];
|
|
1419
|
+
const marketAccountInfos = [];
|
|
1420
|
+
const oracleAccountInfos = [];
|
|
1421
|
+
for (const position of liquidateeUserAccount.positions) {
|
|
1422
|
+
if (!positionIsAvailable(position)) {
|
|
1423
|
+
const market = this.getMarketAccount(position.marketIndex);
|
|
1424
|
+
const marketPublicKey = await getMarketPublicKey(
|
|
1425
|
+
this.program.programId,
|
|
1426
|
+
position.marketIndex
|
|
1427
|
+
);
|
|
1428
|
+
marketAccountInfos.push({
|
|
1429
|
+
pubkey: marketPublicKey,
|
|
1430
|
+
isWritable: true,
|
|
1431
|
+
isSigner: false,
|
|
1432
|
+
});
|
|
1433
|
+
oracleAccountInfos.push({
|
|
1338
1434
|
pubkey: market.amm.oracle,
|
|
1339
1435
|
isWritable: false,
|
|
1340
1436
|
isSigner: false,
|
|
1341
1437
|
});
|
|
1342
1438
|
}
|
|
1343
1439
|
}
|
|
1440
|
+
const remainingAccounts = oracleAccountInfos.concat(
|
|
1441
|
+
bankAccountInfos.concat(marketAccountInfos)
|
|
1442
|
+
);
|
|
1344
1443
|
|
|
1345
1444
|
const state = this.getStateAccount();
|
|
1445
|
+
const quoteAssetBankAccount = this.getQuoteAssetBankAccount();
|
|
1346
1446
|
return await this.program.instruction.liquidate({
|
|
1347
1447
|
accounts: {
|
|
1348
1448
|
state: await this.getStatePublicKey(),
|
|
1349
1449
|
authority: this.wallet.publicKey,
|
|
1350
1450
|
user: liquidateeUserAccountPublicKey,
|
|
1351
1451
|
liquidator: userAccountPublicKey,
|
|
1352
|
-
|
|
1353
|
-
|
|
1452
|
+
bankVault: quoteAssetBankAccount.vault,
|
|
1453
|
+
bankVaultAuthority: quoteAssetBankAccount.vaultAuthority,
|
|
1354
1454
|
insuranceVault: state.insuranceVault,
|
|
1355
|
-
insuranceVaultAuthority: state.insuranceVaultAuthority,
|
|
1356
1455
|
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1357
|
-
markets: state.markets,
|
|
1358
|
-
userPositions: liquidateeUserAccount.positions,
|
|
1359
|
-
tradeHistory: state.tradeHistory,
|
|
1360
|
-
liquidationHistory: state.liquidationHistory,
|
|
1361
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
1362
1456
|
},
|
|
1363
1457
|
remainingAccounts: remainingAccounts,
|
|
1364
1458
|
});
|
|
@@ -1368,54 +1462,68 @@ export class ClearingHouse {
|
|
|
1368
1462
|
oracle: PublicKey,
|
|
1369
1463
|
marketIndex: BN
|
|
1370
1464
|
): Promise<TransactionSignature> {
|
|
1371
|
-
|
|
1465
|
+
const { txSig } = await this.txSender.send(
|
|
1372
1466
|
wrapInTx(await this.getUpdateFundingRateIx(oracle, marketIndex)),
|
|
1373
1467
|
[],
|
|
1374
1468
|
this.opts
|
|
1375
1469
|
);
|
|
1470
|
+
return txSig;
|
|
1376
1471
|
}
|
|
1377
1472
|
|
|
1378
1473
|
public async getUpdateFundingRateIx(
|
|
1379
1474
|
oracle: PublicKey,
|
|
1380
1475
|
marketIndex: BN
|
|
1381
1476
|
): Promise<TransactionInstruction> {
|
|
1382
|
-
const state = this.getStateAccount();
|
|
1383
1477
|
return await this.program.instruction.updateFundingRate(marketIndex, {
|
|
1384
1478
|
accounts: {
|
|
1385
1479
|
state: await this.getStatePublicKey(),
|
|
1386
|
-
|
|
1480
|
+
market: await getMarketPublicKey(this.program.programId, marketIndex),
|
|
1387
1481
|
oracle: oracle,
|
|
1388
|
-
fundingRateHistory: state.fundingRateHistory,
|
|
1389
1482
|
},
|
|
1390
1483
|
});
|
|
1391
1484
|
}
|
|
1392
1485
|
|
|
1393
1486
|
public async settleFundingPayment(
|
|
1394
|
-
userAccount: PublicKey
|
|
1395
|
-
userPositionsAccount: PublicKey
|
|
1487
|
+
userAccount: PublicKey
|
|
1396
1488
|
): Promise<TransactionSignature> {
|
|
1397
|
-
|
|
1398
|
-
wrapInTx(
|
|
1399
|
-
await this.getSettleFundingPaymentIx(userAccount, userPositionsAccount)
|
|
1400
|
-
),
|
|
1489
|
+
const { txSig } = await this.txSender.send(
|
|
1490
|
+
wrapInTx(await this.getSettleFundingPaymentIx(userAccount)),
|
|
1401
1491
|
[],
|
|
1402
1492
|
this.opts
|
|
1403
1493
|
);
|
|
1494
|
+
return txSig;
|
|
1404
1495
|
}
|
|
1405
1496
|
|
|
1406
1497
|
public async getSettleFundingPaymentIx(
|
|
1407
|
-
userAccount: PublicKey
|
|
1408
|
-
userPositionsAccount: PublicKey
|
|
1498
|
+
userAccount: PublicKey
|
|
1409
1499
|
): Promise<TransactionInstruction> {
|
|
1410
|
-
const
|
|
1500
|
+
const user = (await this.program.account.user.fetch(
|
|
1501
|
+
userAccount
|
|
1502
|
+
)) as UserAccount;
|
|
1503
|
+
|
|
1504
|
+
const userPositions = user.positions;
|
|
1505
|
+
|
|
1506
|
+
const remainingAccounts = [];
|
|
1507
|
+
for (const position of userPositions) {
|
|
1508
|
+
if (!positionIsAvailable(position)) {
|
|
1509
|
+
const marketPublicKey = await getMarketPublicKey(
|
|
1510
|
+
this.program.programId,
|
|
1511
|
+
position.marketIndex
|
|
1512
|
+
);
|
|
1513
|
+
remainingAccounts.push({
|
|
1514
|
+
pubkey: marketPublicKey,
|
|
1515
|
+
isWritable: false,
|
|
1516
|
+
isSigner: false,
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1411
1521
|
return await this.program.instruction.settleFundingPayment({
|
|
1412
1522
|
accounts: {
|
|
1413
1523
|
state: await this.getStatePublicKey(),
|
|
1414
|
-
markets: state.markets,
|
|
1415
1524
|
user: userAccount,
|
|
1416
|
-
userPositions: userPositionsAccount,
|
|
1417
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
1418
1525
|
},
|
|
1526
|
+
remainingAccounts,
|
|
1419
1527
|
});
|
|
1420
1528
|
}
|
|
1421
1529
|
|
|
@@ -1423,121 +1531,10 @@ export class ClearingHouse {
|
|
|
1423
1531
|
this.eventEmitter.emit(eventName, data);
|
|
1424
1532
|
}
|
|
1425
1533
|
|
|
1426
|
-
public
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
const settlePositionIx = await this.getSettlePositionIx();
|
|
1430
|
-
const claimCollateralIx = await this.getClaimCollateralIx(
|
|
1431
|
-
collateralAccountPublicKey
|
|
1432
|
-
);
|
|
1433
|
-
const tx = new Transaction().add(settlePositionIx).add(claimCollateralIx);
|
|
1434
|
-
|
|
1435
|
-
return this.txSender.send(tx, [], this.opts);
|
|
1436
|
-
}
|
|
1534
|
+
public getOracleDataForMarket(marketIndex: BN): OraclePriceData {
|
|
1535
|
+
const oracleKey = this.getMarketAccount(marketIndex).amm.oracle;
|
|
1536
|
+
const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
|
|
1437
1537
|
|
|
1438
|
-
|
|
1439
|
-
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1440
|
-
const user: any = await this.program.account.user.fetch(
|
|
1441
|
-
userAccountPublicKey
|
|
1442
|
-
);
|
|
1443
|
-
const state = this.getStateAccount();
|
|
1444
|
-
|
|
1445
|
-
const settlementState = await getSettlementStatePublicKey(
|
|
1446
|
-
this.program.programId
|
|
1447
|
-
);
|
|
1448
|
-
|
|
1449
|
-
return await this.program.instruction.settlePosition({
|
|
1450
|
-
accounts: {
|
|
1451
|
-
state: await this.getStatePublicKey(),
|
|
1452
|
-
user: userAccountPublicKey,
|
|
1453
|
-
markets: state.markets,
|
|
1454
|
-
authority: this.wallet.publicKey,
|
|
1455
|
-
userPositions: user.positions,
|
|
1456
|
-
settlementState,
|
|
1457
|
-
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
1458
|
-
},
|
|
1459
|
-
});
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
public async getClaimCollateralIx(
|
|
1463
|
-
collateralAccountPublicKey: PublicKey
|
|
1464
|
-
): Promise<TransactionInstruction> {
|
|
1465
|
-
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1466
|
-
const state = this.getStateAccount();
|
|
1467
|
-
|
|
1468
|
-
const settlementState = await getSettlementStatePublicKey(
|
|
1469
|
-
this.program.programId
|
|
1470
|
-
);
|
|
1471
|
-
|
|
1472
|
-
return await this.program.instruction.claimCollateral({
|
|
1473
|
-
accounts: {
|
|
1474
|
-
state: await this.getStatePublicKey(),
|
|
1475
|
-
user: userAccountPublicKey,
|
|
1476
|
-
collateralVault: state.collateralVault,
|
|
1477
|
-
collateralVaultAuthority: state.collateralVaultAuthority,
|
|
1478
|
-
userCollateralAccount: collateralAccountPublicKey,
|
|
1479
|
-
authority: this.wallet.publicKey,
|
|
1480
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
1481
|
-
settlementState,
|
|
1482
|
-
},
|
|
1483
|
-
});
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
public async getTotalSettlementSize(): Promise<BN> {
|
|
1487
|
-
const accountLoader = new BulkAccountLoader(
|
|
1488
|
-
this.connection,
|
|
1489
|
-
'processed',
|
|
1490
|
-
50000
|
|
1491
|
-
);
|
|
1492
|
-
const clearingHouse = getClearingHouse(
|
|
1493
|
-
getPollingClearingHouseConfig(
|
|
1494
|
-
this.connection,
|
|
1495
|
-
this.wallet,
|
|
1496
|
-
this.program.programId,
|
|
1497
|
-
accountLoader
|
|
1498
|
-
)
|
|
1499
|
-
);
|
|
1500
|
-
|
|
1501
|
-
console.log('loading all users');
|
|
1502
|
-
const programUserAccounts =
|
|
1503
|
-
(await this.program.account.user.all()) as any[];
|
|
1504
|
-
const userArray: ClearingHouseUser[] = [];
|
|
1505
|
-
for (const programUserAccount of programUserAccounts) {
|
|
1506
|
-
const user = getClearingHouseUser(
|
|
1507
|
-
getPollingClearingHouseUserConfig(
|
|
1508
|
-
clearingHouse,
|
|
1509
|
-
programUserAccount.account.authority,
|
|
1510
|
-
accountLoader
|
|
1511
|
-
)
|
|
1512
|
-
);
|
|
1513
|
-
userArray.push(user);
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
console.log('subscribing all users');
|
|
1517
|
-
await bulkPollingUserSubscribe(userArray, accountLoader);
|
|
1518
|
-
|
|
1519
|
-
console.log('calculating settlement size');
|
|
1520
|
-
const settlementSize = userArray.reduce((collateralToBeSettled, user) => {
|
|
1521
|
-
return collateralToBeSettled.add(
|
|
1522
|
-
user.getUserAccount().forgoPositionSettlement === 0
|
|
1523
|
-
? user.getSettledPositionValue()
|
|
1524
|
-
: ZERO
|
|
1525
|
-
);
|
|
1526
|
-
}, ZERO);
|
|
1527
|
-
|
|
1528
|
-
for (const user of userArray) {
|
|
1529
|
-
await user.unsubscribe();
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
return settlementSize;
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
public async updateUserForgoSettlement(): Promise<TransactionSignature> {
|
|
1536
|
-
return await this.program.rpc.updateUserForgoSettlement({
|
|
1537
|
-
accounts: {
|
|
1538
|
-
authority: this.wallet.publicKey,
|
|
1539
|
-
user: await this.getUserAccountPublicKey(),
|
|
1540
|
-
},
|
|
1541
|
-
});
|
|
1538
|
+
return oracleData;
|
|
1542
1539
|
}
|
|
1543
1540
|
}
|