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