@drift-labs/sdk 0.2.0-master.13 → 0.2.0-master.14
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/fetch.d.ts +2 -1
- package/lib/accounts/fetch.js +9 -1
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +14 -1
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/pda.d.ts +1 -0
- package/lib/addresses/pda.js +8 -1
- package/lib/admin.d.ts +2 -0
- package/lib/admin.js +18 -0
- package/lib/clearingHouse.d.ts +17 -1
- package/lib/clearingHouse.js +195 -14
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.d.ts +5 -0
- package/lib/clearingHouseUser.js +97 -3
- package/lib/clearingHouseUserStats.d.ts +17 -0
- package/lib/clearingHouseUserStats.js +36 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/{src/clearingHouseConfig.js → lib/clearingHouseUserStatsConfig.js} +0 -0
- package/lib/config.js +1 -1
- package/lib/idl/clearing_house.json +614 -64
- package/lib/math/bankBalance.d.ts +4 -0
- package/lib/math/bankBalance.js +23 -1
- package/lib/math/oracles.d.ts +3 -0
- package/lib/math/oracles.js +25 -5
- package/lib/math/position.js +2 -1
- package/lib/math/trade.js +2 -2
- package/lib/types.d.ts +55 -8
- package/lib/types.js +6 -0
- package/package.json +1 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +18 -0
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/pda.ts +13 -0
- package/src/admin.ts +29 -1
- package/src/clearingHouse.ts +318 -15
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +113 -10
- package/src/clearingHouseUserStats.ts +53 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +1 -1
- package/src/idl/clearing_house.json +614 -64
- package/src/math/bankBalance.ts +49 -0
- package/src/math/oracles.ts +42 -5
- package/src/math/position.ts +2 -1
- package/src/math/trade.ts +2 -2
- package/src/types.ts +59 -8
- package/src/accounts/bulkAccountLoader.js +0 -197
- package/src/accounts/bulkUserSubscription.js +0 -33
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -311
- package/src/accounts/pollingOracleSubscriber.js +0 -93
- package/src/accounts/pollingTokenAccountSubscriber.js +0 -90
- package/src/accounts/pollingUserAccountSubscriber.js +0 -132
- package/src/accounts/types.js +0 -10
- package/src/accounts/utils.js +0 -7
- package/src/accounts/webSocketAccountSubscriber.js +0 -93
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -233
- package/src/accounts/webSocketUserAccountSubscriber.js +0 -62
- package/src/clearingHouseUserConfig.js +0 -2
- package/src/index.js +0 -69
- package/src/mockUSDCFaucet.js +0 -280
package/src/clearingHouse.ts
CHANGED
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
getMarketPublicKey,
|
|
42
42
|
getUserAccountPublicKey,
|
|
43
43
|
getUserAccountPublicKeySync,
|
|
44
|
+
getUserStatsAccountPublicKey,
|
|
44
45
|
} from './addresses/pda';
|
|
45
46
|
import {
|
|
46
47
|
ClearingHouseAccountSubscriber,
|
|
@@ -62,6 +63,7 @@ import { ClearingHouseUser } from './clearingHouseUser';
|
|
|
62
63
|
import { ClearingHouseUserAccountSubscriptionConfig } from './clearingHouseUserConfig';
|
|
63
64
|
import { getMarketsBanksAndOraclesForSubscription } from './config';
|
|
64
65
|
import { WRAPPED_SOL_MINT } from './constants/banks';
|
|
66
|
+
import { ClearingHouseUserStats } from './clearingHouseUserStats';
|
|
65
67
|
|
|
66
68
|
/**
|
|
67
69
|
* # ClearingHouse
|
|
@@ -74,6 +76,7 @@ export class ClearingHouse {
|
|
|
74
76
|
provider: AnchorProvider;
|
|
75
77
|
opts?: ConfirmOptions;
|
|
76
78
|
users = new Map<number, ClearingHouseUser>();
|
|
79
|
+
userStats?: ClearingHouseUserStats;
|
|
77
80
|
activeUserId: number;
|
|
78
81
|
userAccountSubscriptionConfig: ClearingHouseUserAccountSubscriptionConfig;
|
|
79
82
|
accountSubscriber: ClearingHouseAccountSubscriber;
|
|
@@ -117,6 +120,16 @@ export class ClearingHouse {
|
|
|
117
120
|
type: 'websocket',
|
|
118
121
|
};
|
|
119
122
|
this.createUsers(userIds, this.userAccountSubscriptionConfig);
|
|
123
|
+
if (config.userStats) {
|
|
124
|
+
this.userStats = new ClearingHouseUserStats({
|
|
125
|
+
clearingHouse: this,
|
|
126
|
+
userStatsAccountPublicKey: getUserStatsAccountPublicKey(
|
|
127
|
+
this.program.programId,
|
|
128
|
+
this.wallet.publicKey
|
|
129
|
+
),
|
|
130
|
+
accountSubscription: this.userAccountSubscriptionConfig,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
120
133
|
|
|
121
134
|
let marketIndexes = config.marketIndexes;
|
|
122
135
|
let bankIndexes = config.bankIndexes;
|
|
@@ -188,6 +201,9 @@ export class ClearingHouse {
|
|
|
188
201
|
const subscribePromises = this.subscribeUsers().concat(
|
|
189
202
|
this.accountSubscriber.subscribe()
|
|
190
203
|
);
|
|
204
|
+
if (this.userStats !== undefined) {
|
|
205
|
+
subscribePromises.concat(this.userStats.subscribe());
|
|
206
|
+
}
|
|
191
207
|
this.isSubscribed = (await Promise.all(subscribePromises)).reduce(
|
|
192
208
|
(success, prevSuccess) => success && prevSuccess
|
|
193
209
|
);
|
|
@@ -213,6 +229,9 @@ export class ClearingHouse {
|
|
|
213
229
|
const unsubscribePromises = this.unsubscribeUsers().concat(
|
|
214
230
|
this.accountSubscriber.unsubscribe()
|
|
215
231
|
);
|
|
232
|
+
if (this.userStats !== undefined) {
|
|
233
|
+
unsubscribePromises.concat(this.userStats.unsubscribe());
|
|
234
|
+
}
|
|
216
235
|
await Promise.all(unsubscribePromises);
|
|
217
236
|
this.isSubscribed = false;
|
|
218
237
|
}
|
|
@@ -302,6 +321,7 @@ export class ClearingHouse {
|
|
|
302
321
|
}
|
|
303
322
|
|
|
304
323
|
this.activeUserId = activeUserId;
|
|
324
|
+
this.userStatsAccountPublicKey = undefined;
|
|
305
325
|
}
|
|
306
326
|
|
|
307
327
|
public async switchActiveUser(userId: number): Promise<void> {
|
|
@@ -325,7 +345,12 @@ export class ClearingHouse {
|
|
|
325
345
|
const [userAccountPublicKey, initializeUserAccountIx] =
|
|
326
346
|
await this.getInitializeUserInstructions(userId, name);
|
|
327
347
|
|
|
328
|
-
const tx = new Transaction()
|
|
348
|
+
const tx = new Transaction();
|
|
349
|
+
if (userId === 0) {
|
|
350
|
+
// not the safest assumption, can explicitly check if user stats account exists if it causes problems
|
|
351
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
352
|
+
}
|
|
353
|
+
tx.add(initializeUserAccountIx);
|
|
329
354
|
const { txSig } = await this.txSender.send(tx, [], this.opts);
|
|
330
355
|
return [txSig, userAccountPublicKey];
|
|
331
356
|
}
|
|
@@ -345,6 +370,7 @@ export class ClearingHouse {
|
|
|
345
370
|
await this.program.instruction.initializeUser(userId, nameBuffer, {
|
|
346
371
|
accounts: {
|
|
347
372
|
user: userAccountPublicKey,
|
|
373
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
348
374
|
authority: this.wallet.publicKey,
|
|
349
375
|
payer: this.wallet.publicKey,
|
|
350
376
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
@@ -356,6 +382,19 @@ export class ClearingHouse {
|
|
|
356
382
|
return [userAccountPublicKey, initializeUserAccountIx];
|
|
357
383
|
}
|
|
358
384
|
|
|
385
|
+
async getInitializeUserStatsIx(): Promise<TransactionInstruction> {
|
|
386
|
+
return await this.program.instruction.initializeUserStats({
|
|
387
|
+
accounts: {
|
|
388
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
389
|
+
authority: this.wallet.publicKey,
|
|
390
|
+
payer: this.wallet.publicKey,
|
|
391
|
+
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
392
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
393
|
+
state: await this.getStatePublicKey(),
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
|
|
359
398
|
public getUser(userId?: number): ClearingHouseUser {
|
|
360
399
|
userId = userId ?? this.activeUserId;
|
|
361
400
|
if (!this.users.has(userId)) {
|
|
@@ -368,6 +407,23 @@ export class ClearingHouse {
|
|
|
368
407
|
return [...this.users.values()];
|
|
369
408
|
}
|
|
370
409
|
|
|
410
|
+
public getUserStats(): ClearingHouseUserStats {
|
|
411
|
+
return this.userStats;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
userStatsAccountPublicKey: PublicKey;
|
|
415
|
+
public getUserStatsAccountPublicKey(): PublicKey {
|
|
416
|
+
if (this.userStatsAccountPublicKey) {
|
|
417
|
+
return this.userStatsAccountPublicKey;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
this.userStatsAccountPublicKey = getUserStatsAccountPublicKey(
|
|
421
|
+
this.program.programId,
|
|
422
|
+
this.wallet.publicKey
|
|
423
|
+
);
|
|
424
|
+
return this.userStatsAccountPublicKey;
|
|
425
|
+
}
|
|
426
|
+
|
|
371
427
|
public async getUserAccountPublicKey(): Promise<PublicKey> {
|
|
372
428
|
return this.getUser().userAccountPublicKey;
|
|
373
429
|
}
|
|
@@ -831,6 +887,9 @@ export class ClearingHouse {
|
|
|
831
887
|
false
|
|
832
888
|
);
|
|
833
889
|
|
|
890
|
+
if (userId === 0) {
|
|
891
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
892
|
+
}
|
|
834
893
|
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
835
894
|
|
|
836
895
|
// Close the wrapped sol account at the end of the transaction
|
|
@@ -880,11 +939,12 @@ export class ClearingHouse {
|
|
|
880
939
|
false
|
|
881
940
|
);
|
|
882
941
|
|
|
883
|
-
const tx = new Transaction()
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
.add(
|
|
887
|
-
|
|
942
|
+
const tx = new Transaction().add(createAssociatedAccountIx).add(mintToIx);
|
|
943
|
+
|
|
944
|
+
if (userId === 0) {
|
|
945
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
946
|
+
}
|
|
947
|
+
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
888
948
|
|
|
889
949
|
const txSig = await this.program.provider.sendAndConfirm(tx, []);
|
|
890
950
|
|
|
@@ -1056,6 +1116,135 @@ export class ClearingHouse {
|
|
|
1056
1116
|
});
|
|
1057
1117
|
}
|
|
1058
1118
|
|
|
1119
|
+
public async settleLP(
|
|
1120
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
1121
|
+
marketIndex: BN
|
|
1122
|
+
): Promise<TransactionSignature> {
|
|
1123
|
+
const { txSig } = await this.txSender.send(
|
|
1124
|
+
wrapInTx(await this.settleLPIx(settleeUserAccountPublicKey, marketIndex)),
|
|
1125
|
+
[],
|
|
1126
|
+
this.opts
|
|
1127
|
+
);
|
|
1128
|
+
return txSig;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
public async settleLPIx(
|
|
1132
|
+
settleeUserAccountPublicKey: PublicKey,
|
|
1133
|
+
marketIndex: BN
|
|
1134
|
+
): Promise<TransactionInstruction> {
|
|
1135
|
+
const settleeUserAccount = (await this.program.account.user.fetch(
|
|
1136
|
+
settleeUserAccountPublicKey
|
|
1137
|
+
)) as UserAccount;
|
|
1138
|
+
const userPositions = settleeUserAccount.positions;
|
|
1139
|
+
const remainingAccounts = [];
|
|
1140
|
+
|
|
1141
|
+
let foundMarket = false;
|
|
1142
|
+
for (const position of userPositions) {
|
|
1143
|
+
if (!positionIsAvailable(position)) {
|
|
1144
|
+
const marketPublicKey = await getMarketPublicKey(
|
|
1145
|
+
this.program.programId,
|
|
1146
|
+
position.marketIndex
|
|
1147
|
+
);
|
|
1148
|
+
remainingAccounts.push({
|
|
1149
|
+
pubkey: marketPublicKey,
|
|
1150
|
+
isWritable: true,
|
|
1151
|
+
isSigner: false,
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1154
|
+
if (marketIndex.eq(position.marketIndex)) {
|
|
1155
|
+
foundMarket = true;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
if (!foundMarket) {
|
|
1161
|
+
console.log(
|
|
1162
|
+
'Warning: lp is not in the market specified -- tx will likely fail'
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
return this.program.instruction.settleLp(marketIndex, {
|
|
1167
|
+
accounts: {
|
|
1168
|
+
state: await this.getStatePublicKey(),
|
|
1169
|
+
user: settleeUserAccountPublicKey,
|
|
1170
|
+
},
|
|
1171
|
+
remainingAccounts: remainingAccounts,
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
public async removeLiquidity(
|
|
1176
|
+
marketIndex: BN,
|
|
1177
|
+
sharesToBurn?: BN
|
|
1178
|
+
): Promise<TransactionSignature> {
|
|
1179
|
+
const { txSig } = await this.txSender.send(
|
|
1180
|
+
wrapInTx(await this.getRemoveLiquidityIx(marketIndex, sharesToBurn)),
|
|
1181
|
+
[],
|
|
1182
|
+
this.opts
|
|
1183
|
+
);
|
|
1184
|
+
return txSig;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
public async getRemoveLiquidityIx(
|
|
1188
|
+
marketIndex: BN,
|
|
1189
|
+
sharesToBurn?: BN
|
|
1190
|
+
): Promise<TransactionInstruction> {
|
|
1191
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1192
|
+
|
|
1193
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1194
|
+
writableMarketIndex: marketIndex,
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
if (sharesToBurn == undefined) {
|
|
1198
|
+
const userAccount = this.getUserAccount();
|
|
1199
|
+
const marketPosition = userAccount.positions.filter((position) =>
|
|
1200
|
+
position.marketIndex.eq(marketIndex)
|
|
1201
|
+
)[0];
|
|
1202
|
+
sharesToBurn = marketPosition.lpShares;
|
|
1203
|
+
console.log('burning lp shares:', sharesToBurn.toString());
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
return this.program.instruction.removeLiquidity(sharesToBurn, marketIndex, {
|
|
1207
|
+
accounts: {
|
|
1208
|
+
state: await this.getStatePublicKey(),
|
|
1209
|
+
user: userAccountPublicKey,
|
|
1210
|
+
authority: this.wallet.publicKey,
|
|
1211
|
+
},
|
|
1212
|
+
remainingAccounts: remainingAccounts,
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
public async addLiquidity(
|
|
1217
|
+
amount: BN,
|
|
1218
|
+
marketIndex: BN
|
|
1219
|
+
): Promise<TransactionSignature> {
|
|
1220
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1221
|
+
wrapInTx(await this.getAddLiquidityIx(amount, marketIndex)),
|
|
1222
|
+
[],
|
|
1223
|
+
this.opts
|
|
1224
|
+
);
|
|
1225
|
+
this.marketLastSlotCache.set(marketIndex.toNumber(), slot);
|
|
1226
|
+
return txSig;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
public async getAddLiquidityIx(
|
|
1230
|
+
amount: BN,
|
|
1231
|
+
marketIndex: BN
|
|
1232
|
+
): Promise<TransactionInstruction> {
|
|
1233
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1234
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
1235
|
+
writableMarketIndex: marketIndex,
|
|
1236
|
+
});
|
|
1237
|
+
|
|
1238
|
+
return this.program.instruction.addLiquidity(amount, marketIndex, {
|
|
1239
|
+
accounts: {
|
|
1240
|
+
state: await this.getStatePublicKey(),
|
|
1241
|
+
user: userAccountPublicKey,
|
|
1242
|
+
authority: this.wallet.publicKey,
|
|
1243
|
+
},
|
|
1244
|
+
remainingAccounts: remainingAccounts,
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1059
1248
|
public async openPosition(
|
|
1060
1249
|
direction: PositionDirection,
|
|
1061
1250
|
amount: BN,
|
|
@@ -1101,6 +1290,7 @@ export class ClearingHouse {
|
|
|
1101
1290
|
accounts: {
|
|
1102
1291
|
state: await this.getStatePublicKey(),
|
|
1103
1292
|
user: userAccountPublicKey,
|
|
1293
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
1104
1294
|
authority: this.wallet.publicKey,
|
|
1105
1295
|
},
|
|
1106
1296
|
remainingAccounts,
|
|
@@ -1228,7 +1418,13 @@ export class ClearingHouse {
|
|
|
1228
1418
|
order: Order,
|
|
1229
1419
|
makerInfo?: MakerInfo
|
|
1230
1420
|
): Promise<TransactionInstruction> {
|
|
1421
|
+
const userStatsPublicKey = getUserStatsAccountPublicKey(
|
|
1422
|
+
this.program.programId,
|
|
1423
|
+
userAccount.authority
|
|
1424
|
+
);
|
|
1425
|
+
|
|
1231
1426
|
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
1427
|
+
const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
1232
1428
|
|
|
1233
1429
|
const marketIndex = order.marketIndex;
|
|
1234
1430
|
const marketAccount = this.getMarketAccount(marketIndex);
|
|
@@ -1298,6 +1494,11 @@ export class ClearingHouse {
|
|
|
1298
1494
|
isWritable: true,
|
|
1299
1495
|
isSigner: false,
|
|
1300
1496
|
});
|
|
1497
|
+
remainingAccounts.push({
|
|
1498
|
+
pubkey: makerInfo.makerStats,
|
|
1499
|
+
isWritable: true,
|
|
1500
|
+
isSigner: false,
|
|
1501
|
+
});
|
|
1301
1502
|
}
|
|
1302
1503
|
|
|
1303
1504
|
const orderId = order.orderId;
|
|
@@ -1307,7 +1508,9 @@ export class ClearingHouse {
|
|
|
1307
1508
|
accounts: {
|
|
1308
1509
|
state: await this.getStatePublicKey(),
|
|
1309
1510
|
filler: fillerPublicKey,
|
|
1511
|
+
fillerStats: fillerStatsPublicKey,
|
|
1310
1512
|
user: userAccountPublicKey,
|
|
1513
|
+
userStats: userStatsPublicKey,
|
|
1311
1514
|
authority: this.wallet.publicKey,
|
|
1312
1515
|
},
|
|
1313
1516
|
remainingAccounts,
|
|
@@ -1426,6 +1629,7 @@ export class ClearingHouse {
|
|
|
1426
1629
|
makerInfo?: MakerInfo
|
|
1427
1630
|
): Promise<TransactionInstruction> {
|
|
1428
1631
|
orderParams = this.getOrderParams(orderParams);
|
|
1632
|
+
const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
|
|
1429
1633
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1430
1634
|
|
|
1431
1635
|
const remainingAccounts = this.getRemainingAccounts({
|
|
@@ -1441,6 +1645,11 @@ export class ClearingHouse {
|
|
|
1441
1645
|
isSigner: false,
|
|
1442
1646
|
isWritable: true,
|
|
1443
1647
|
});
|
|
1648
|
+
remainingAccounts.push({
|
|
1649
|
+
pubkey: makerInfo.makerStats,
|
|
1650
|
+
isSigner: false,
|
|
1651
|
+
isWritable: true,
|
|
1652
|
+
});
|
|
1444
1653
|
}
|
|
1445
1654
|
|
|
1446
1655
|
return await this.program.instruction.placeAndTake(
|
|
@@ -1450,6 +1659,7 @@ export class ClearingHouse {
|
|
|
1450
1659
|
accounts: {
|
|
1451
1660
|
state: await this.getStatePublicKey(),
|
|
1452
1661
|
user: userAccountPublicKey,
|
|
1662
|
+
userStats: userStatsPublicKey,
|
|
1453
1663
|
authority: this.wallet.publicKey,
|
|
1454
1664
|
},
|
|
1455
1665
|
remainingAccounts,
|
|
@@ -1477,20 +1687,14 @@ export class ClearingHouse {
|
|
|
1477
1687
|
takerInfo: TakerInfo
|
|
1478
1688
|
): Promise<TransactionInstruction> {
|
|
1479
1689
|
orderParams = this.getOrderParams(orderParams);
|
|
1690
|
+
const userStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
1480
1691
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
1481
1692
|
|
|
1482
1693
|
const remainingAccounts = this.getRemainingAccounts({
|
|
1483
1694
|
writableMarketIndex: orderParams.marketIndex,
|
|
1484
|
-
writableBankIndex: QUOTE_ASSET_BANK_INDEX,
|
|
1485
1695
|
});
|
|
1486
1696
|
|
|
1487
1697
|
const takerOrderId = takerInfo!.order!.orderId;
|
|
1488
|
-
remainingAccounts.push({
|
|
1489
|
-
pubkey: takerInfo.taker,
|
|
1490
|
-
isSigner: false,
|
|
1491
|
-
isWritable: true,
|
|
1492
|
-
});
|
|
1493
|
-
|
|
1494
1698
|
return await this.program.instruction.placeAndMake(
|
|
1495
1699
|
orderParams,
|
|
1496
1700
|
takerOrderId,
|
|
@@ -1498,7 +1702,9 @@ export class ClearingHouse {
|
|
|
1498
1702
|
accounts: {
|
|
1499
1703
|
state: await this.getStatePublicKey(),
|
|
1500
1704
|
user: userAccountPublicKey,
|
|
1705
|
+
userStats: userStatsPublicKey,
|
|
1501
1706
|
taker: takerInfo.taker,
|
|
1707
|
+
takerStats: takerInfo.takerStats,
|
|
1502
1708
|
authority: this.wallet.publicKey,
|
|
1503
1709
|
},
|
|
1504
1710
|
remainingAccounts,
|
|
@@ -1511,7 +1717,10 @@ export class ClearingHouse {
|
|
|
1511
1717
|
* @param marketIndex
|
|
1512
1718
|
* @returns
|
|
1513
1719
|
*/
|
|
1514
|
-
public async closePosition(
|
|
1720
|
+
public async closePosition(
|
|
1721
|
+
marketIndex: BN,
|
|
1722
|
+
limitPrice?: BN
|
|
1723
|
+
): Promise<TransactionSignature> {
|
|
1515
1724
|
const userPosition = this.getUser().getUserPosition(marketIndex);
|
|
1516
1725
|
if (!userPosition) {
|
|
1517
1726
|
throw Error(`No position in market ${marketIndex.toString()}`);
|
|
@@ -1521,8 +1730,9 @@ export class ClearingHouse {
|
|
|
1521
1730
|
orderType: OrderType.MARKET,
|
|
1522
1731
|
marketIndex,
|
|
1523
1732
|
direction: findDirectionToClose(userPosition),
|
|
1524
|
-
baseAssetAmount: userPosition.baseAssetAmount,
|
|
1733
|
+
baseAssetAmount: userPosition.baseAssetAmount.abs(),
|
|
1525
1734
|
reduceOnly: true,
|
|
1735
|
+
price: limitPrice,
|
|
1526
1736
|
});
|
|
1527
1737
|
}
|
|
1528
1738
|
|
|
@@ -1577,6 +1787,7 @@ export class ClearingHouse {
|
|
|
1577
1787
|
const marketAccountMap = new Map<number, AccountMeta>();
|
|
1578
1788
|
const oracleAccountMap = new Map<string, AccountMeta>();
|
|
1579
1789
|
const bankAccountMap = new Map<number, AccountMeta>();
|
|
1790
|
+
|
|
1580
1791
|
for (const position of settleeUserAccount.positions) {
|
|
1581
1792
|
if (!positionIsAvailable(position)) {
|
|
1582
1793
|
const market = this.getMarketAccount(position.marketIndex);
|
|
@@ -1672,7 +1883,13 @@ export class ClearingHouse {
|
|
|
1672
1883
|
marketIndex: BN,
|
|
1673
1884
|
maxBaseAssetAmount: BN
|
|
1674
1885
|
): Promise<TransactionInstruction> {
|
|
1886
|
+
const userStatsPublicKey = getUserStatsAccountPublicKey(
|
|
1887
|
+
this.program.programId,
|
|
1888
|
+
userAccount.authority
|
|
1889
|
+
);
|
|
1890
|
+
|
|
1675
1891
|
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1892
|
+
const liquidatorStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
1676
1893
|
|
|
1677
1894
|
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1678
1895
|
writableMarketIndex: marketIndex,
|
|
@@ -1687,7 +1904,9 @@ export class ClearingHouse {
|
|
|
1687
1904
|
state: await this.getStatePublicKey(),
|
|
1688
1905
|
authority: this.wallet.publicKey,
|
|
1689
1906
|
user: userAccountPublicKey,
|
|
1907
|
+
userStats: userStatsPublicKey,
|
|
1690
1908
|
liquidator: liquidatorPublicKey,
|
|
1909
|
+
liquidatorStats: liquidatorStatsPublicKey,
|
|
1691
1910
|
},
|
|
1692
1911
|
remainingAccounts: remainingAccounts,
|
|
1693
1912
|
}
|
|
@@ -1855,6 +2074,90 @@ export class ClearingHouse {
|
|
|
1855
2074
|
);
|
|
1856
2075
|
}
|
|
1857
2076
|
|
|
2077
|
+
public async resolvePerpBankruptcy(
|
|
2078
|
+
userAccountPublicKey: PublicKey,
|
|
2079
|
+
userAccount: UserAccount,
|
|
2080
|
+
marketIndex: BN
|
|
2081
|
+
): Promise<TransactionSignature> {
|
|
2082
|
+
const { txSig } = await this.txSender.send(
|
|
2083
|
+
wrapInTx(
|
|
2084
|
+
await this.getResolvePerpBankruptcyIx(
|
|
2085
|
+
userAccountPublicKey,
|
|
2086
|
+
userAccount,
|
|
2087
|
+
marketIndex
|
|
2088
|
+
)
|
|
2089
|
+
),
|
|
2090
|
+
[],
|
|
2091
|
+
this.opts
|
|
2092
|
+
);
|
|
2093
|
+
return txSig;
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
public async getResolvePerpBankruptcyIx(
|
|
2097
|
+
userAccountPublicKey: PublicKey,
|
|
2098
|
+
userAccount: UserAccount,
|
|
2099
|
+
marketIndex: BN
|
|
2100
|
+
): Promise<TransactionInstruction> {
|
|
2101
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2102
|
+
|
|
2103
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
2104
|
+
writableMarketIndex: marketIndex,
|
|
2105
|
+
userAccount,
|
|
2106
|
+
});
|
|
2107
|
+
|
|
2108
|
+
return await this.program.instruction.resolvePerpBankruptcy(marketIndex, {
|
|
2109
|
+
accounts: {
|
|
2110
|
+
state: await this.getStatePublicKey(),
|
|
2111
|
+
authority: this.wallet.publicKey,
|
|
2112
|
+
user: userAccountPublicKey,
|
|
2113
|
+
liquidator: liquidatorPublicKey,
|
|
2114
|
+
},
|
|
2115
|
+
remainingAccounts: remainingAccounts,
|
|
2116
|
+
});
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
public async resolveBorrowBankruptcy(
|
|
2120
|
+
userAccountPublicKey: PublicKey,
|
|
2121
|
+
userAccount: UserAccount,
|
|
2122
|
+
bankIndex: BN
|
|
2123
|
+
): Promise<TransactionSignature> {
|
|
2124
|
+
const { txSig } = await this.txSender.send(
|
|
2125
|
+
wrapInTx(
|
|
2126
|
+
await this.getResolveBorrowBankruptcyIx(
|
|
2127
|
+
userAccountPublicKey,
|
|
2128
|
+
userAccount,
|
|
2129
|
+
bankIndex
|
|
2130
|
+
)
|
|
2131
|
+
),
|
|
2132
|
+
[],
|
|
2133
|
+
this.opts
|
|
2134
|
+
);
|
|
2135
|
+
return txSig;
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
public async getResolveBorrowBankruptcyIx(
|
|
2139
|
+
userAccountPublicKey: PublicKey,
|
|
2140
|
+
userAccount: UserAccount,
|
|
2141
|
+
bankIndex: BN
|
|
2142
|
+
): Promise<TransactionInstruction> {
|
|
2143
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
2144
|
+
|
|
2145
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
2146
|
+
writableBankIndexes: [bankIndex],
|
|
2147
|
+
userAccount,
|
|
2148
|
+
});
|
|
2149
|
+
|
|
2150
|
+
return await this.program.instruction.resolveBorrowBankruptcy(bankIndex, {
|
|
2151
|
+
accounts: {
|
|
2152
|
+
state: await this.getStatePublicKey(),
|
|
2153
|
+
authority: this.wallet.publicKey,
|
|
2154
|
+
user: userAccountPublicKey,
|
|
2155
|
+
liquidator: liquidatorPublicKey,
|
|
2156
|
+
},
|
|
2157
|
+
remainingAccounts: remainingAccounts,
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
|
|
1858
2161
|
getRemainingAccountsForLiquidation(params: {
|
|
1859
2162
|
userAccount: UserAccount;
|
|
1860
2163
|
writableMarketIndex?: BN;
|
package/src/clearingHouseUser.ts
CHANGED
|
@@ -53,7 +53,6 @@ import { OraclePriceData } from './oracles/types';
|
|
|
53
53
|
import { ClearingHouseUserConfig } from './clearingHouseUserConfig';
|
|
54
54
|
import { PollingUserAccountSubscriber } from './accounts/pollingUserAccountSubscriber';
|
|
55
55
|
import { WebSocketUserAccountSubscriber } from './accounts/webSocketUserAccountSubscriber';
|
|
56
|
-
|
|
57
56
|
export class ClearingHouseUser {
|
|
58
57
|
clearingHouse: ClearingHouse;
|
|
59
58
|
userAccountPublicKey: PublicKey;
|
|
@@ -137,6 +136,11 @@ export class ClearingHouseUser {
|
|
|
137
136
|
openOrders: ZERO,
|
|
138
137
|
openBids: ZERO,
|
|
139
138
|
openAsks: ZERO,
|
|
139
|
+
realizedPnl: ZERO,
|
|
140
|
+
lpShares: ZERO,
|
|
141
|
+
lastFeePerLp: ZERO,
|
|
142
|
+
lastNetBaseAssetAmountPerLp: ZERO,
|
|
143
|
+
lastNetQuoteAssetAmountPerLp: ZERO,
|
|
140
144
|
};
|
|
141
145
|
}
|
|
142
146
|
|
|
@@ -172,6 +176,98 @@ export class ClearingHouseUser {
|
|
|
172
176
|
return userAccountRPCResponse.value !== null;
|
|
173
177
|
}
|
|
174
178
|
|
|
179
|
+
/**
|
|
180
|
+
* calculates the market position if the lp position was settled
|
|
181
|
+
* @returns : userPosition
|
|
182
|
+
*/
|
|
183
|
+
public getSettledLPPosition(marketIndex: BN): [UserPosition, BN] {
|
|
184
|
+
const position = this.getUserPosition(marketIndex);
|
|
185
|
+
const market = this.clearingHouse.getMarketAccount(position.marketIndex);
|
|
186
|
+
const nShares = position.lpShares;
|
|
187
|
+
|
|
188
|
+
const deltaBaa = market.amm.marketPositionPerLp.baseAssetAmount
|
|
189
|
+
.sub(position.lastNetBaseAssetAmountPerLp)
|
|
190
|
+
.mul(nShares)
|
|
191
|
+
.div(AMM_RESERVE_PRECISION);
|
|
192
|
+
const deltaQaa = market.amm.marketPositionPerLp.quoteAssetAmount
|
|
193
|
+
.sub(position.lastNetQuoteAssetAmountPerLp)
|
|
194
|
+
.mul(nShares)
|
|
195
|
+
.div(AMM_RESERVE_PRECISION);
|
|
196
|
+
|
|
197
|
+
function sign(v: BN) {
|
|
198
|
+
const sign = { true: new BN(1), false: new BN(-1) }[
|
|
199
|
+
v.gte(ZERO).toString()
|
|
200
|
+
];
|
|
201
|
+
return sign;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const remainder = deltaBaa
|
|
205
|
+
.abs()
|
|
206
|
+
.mod(market.amm.baseAssetAmountStepSize)
|
|
207
|
+
.mul(sign(deltaBaa));
|
|
208
|
+
const _standardizedBaa = deltaBaa.sub(remainder);
|
|
209
|
+
|
|
210
|
+
let remainderBaa;
|
|
211
|
+
if (_standardizedBaa.abs().gte(market.amm.baseAssetAmountStepSize)) {
|
|
212
|
+
remainderBaa = remainder;
|
|
213
|
+
} else {
|
|
214
|
+
remainderBaa = deltaBaa;
|
|
215
|
+
}
|
|
216
|
+
const standardizedBaa = deltaBaa.sub(remainderBaa);
|
|
217
|
+
|
|
218
|
+
const reaminderPerLP = remainderBaa.mul(AMM_RESERVE_PRECISION).div(nShares);
|
|
219
|
+
|
|
220
|
+
position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
|
|
221
|
+
position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
|
|
222
|
+
|
|
223
|
+
position.lastNetBaseAssetAmountPerLp =
|
|
224
|
+
market.amm.marketPositionPerLp.baseAssetAmount.sub(reaminderPerLP);
|
|
225
|
+
|
|
226
|
+
let updateType;
|
|
227
|
+
if (position.baseAssetAmount.eq(ZERO)) {
|
|
228
|
+
updateType = 'open';
|
|
229
|
+
} else if (sign(position.baseAssetAmount).eq(sign(deltaBaa))) {
|
|
230
|
+
updateType = 'increase';
|
|
231
|
+
} else if (position.baseAssetAmount.abs().gt(deltaBaa.abs())) {
|
|
232
|
+
updateType = 'reduce';
|
|
233
|
+
} else if (position.baseAssetAmount.abs().eq(deltaBaa.abs())) {
|
|
234
|
+
updateType = 'close';
|
|
235
|
+
} else {
|
|
236
|
+
updateType = 'flip';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
let newQuoteEntry;
|
|
240
|
+
let pnl;
|
|
241
|
+
if (updateType == 'open' || updateType == 'increase') {
|
|
242
|
+
newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
|
|
243
|
+
pnl = 0;
|
|
244
|
+
} else if (updateType == 'reduce' || updateType == 'close') {
|
|
245
|
+
newQuoteEntry = position.quoteEntryAmount.sub(
|
|
246
|
+
position.quoteEntryAmount
|
|
247
|
+
.mul(deltaBaa.abs())
|
|
248
|
+
.div(position.baseAssetAmount.abs())
|
|
249
|
+
);
|
|
250
|
+
pnl = position.quoteEntryAmount.sub(newQuoteEntry);
|
|
251
|
+
} else {
|
|
252
|
+
newQuoteEntry = deltaQaa.sub(
|
|
253
|
+
deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs())
|
|
254
|
+
);
|
|
255
|
+
pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
|
|
256
|
+
}
|
|
257
|
+
position.quoteEntryAmount = newQuoteEntry;
|
|
258
|
+
|
|
259
|
+
if (position.baseAssetAmount.gt(ZERO)) {
|
|
260
|
+
position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
|
|
261
|
+
} else if (position.baseAssetAmount.lt(ZERO)) {
|
|
262
|
+
position.lastCumulativeFundingRate =
|
|
263
|
+
market.amm.cumulativeFundingRateShort;
|
|
264
|
+
} else {
|
|
265
|
+
position.lastCumulativeFundingRate = ZERO;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return [position, pnl];
|
|
269
|
+
}
|
|
270
|
+
|
|
175
271
|
/**
|
|
176
272
|
* calculates Buying Power = FC * MAX_LEVERAGE
|
|
177
273
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -716,13 +812,17 @@ export class ClearingHouseUser {
|
|
|
716
812
|
const proposedMarketPosition: UserPosition = {
|
|
717
813
|
marketIndex: marketPosition.marketIndex,
|
|
718
814
|
baseAssetAmount: proposedBaseAssetAmount,
|
|
719
|
-
lastCumulativeFundingRate:
|
|
720
|
-
currentMarketPosition.lastCumulativeFundingRate,
|
|
721
815
|
quoteAssetAmount: new BN(0),
|
|
816
|
+
lastCumulativeFundingRate: ZERO,
|
|
722
817
|
quoteEntryAmount: new BN(0),
|
|
723
818
|
openOrders: new BN(0),
|
|
724
819
|
openBids: new BN(0),
|
|
725
820
|
openAsks: new BN(0),
|
|
821
|
+
realizedPnl: ZERO,
|
|
822
|
+
lpShares: ZERO,
|
|
823
|
+
lastFeePerLp: ZERO,
|
|
824
|
+
lastNetBaseAssetAmountPerLp: ZERO,
|
|
825
|
+
lastNetQuoteAssetAmountPerLp: ZERO,
|
|
726
826
|
};
|
|
727
827
|
|
|
728
828
|
if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
|
|
@@ -753,14 +853,17 @@ export class ClearingHouseUser {
|
|
|
753
853
|
position,
|
|
754
854
|
this.getOracleDataForMarket(market.marketIndex)
|
|
755
855
|
);
|
|
756
|
-
const marketMarginRequirement = positionValue
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
856
|
+
const marketMarginRequirement = positionValue
|
|
857
|
+
.mul(
|
|
858
|
+
new BN(
|
|
859
|
+
calculateMarketMarginRatio(
|
|
860
|
+
market,
|
|
861
|
+
position.baseAssetAmount.abs(),
|
|
862
|
+
'Maintenance'
|
|
863
|
+
)
|
|
864
|
+
)
|
|
762
865
|
)
|
|
763
|
-
|
|
866
|
+
.div(MARGIN_PRECISION);
|
|
764
867
|
totalMarginRequirement = totalMarginRequirement.add(
|
|
765
868
|
marketMarginRequirement
|
|
766
869
|
);
|