@drift-labs/sdk 0.1.23-master.4 → 0.1.26

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.
Files changed (61) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +2 -0
  2. package/lib/accounts/bulkAccountLoader.js +24 -0
  3. package/lib/addresses.js +5 -1
  4. package/lib/admin.d.ts +2 -2
  5. package/lib/admin.js +11 -5
  6. package/lib/clearingHouse.js +7 -1
  7. package/lib/clearingHouseUser.d.ts +12 -17
  8. package/lib/clearingHouseUser.js +114 -217
  9. package/lib/constants/markets.d.ts +6 -4
  10. package/lib/constants/markets.js +48 -0
  11. package/lib/constants/numericConstants.d.ts +2 -2
  12. package/lib/constants/numericConstants.js +3 -3
  13. package/lib/factory/oracleClient.d.ts +5 -0
  14. package/lib/factory/oracleClient.js +16 -0
  15. package/lib/idl/clearing_house.json +58 -5
  16. package/lib/idl/switchboard_v2.json +4663 -0
  17. package/lib/index.d.ts +4 -1
  18. package/lib/index.js +9 -2
  19. package/lib/math/funding.d.ts +6 -6
  20. package/lib/math/funding.js +4 -16
  21. package/lib/math/orders.d.ts +1 -0
  22. package/lib/math/orders.js +19 -1
  23. package/lib/mockUSDCFaucet.js +5 -1
  24. package/lib/oracles/pythClient.d.ts +14 -0
  25. package/lib/oracles/pythClient.js +53 -0
  26. package/lib/oracles/switchboardClient.d.ts +13 -0
  27. package/lib/oracles/switchboardClient.js +76 -0
  28. package/lib/oracles/types.d.ts +15 -0
  29. package/lib/oracles/types.js +2 -0
  30. package/lib/orderParams.d.ts +1 -1
  31. package/lib/orderParams.js +2 -2
  32. package/lib/orders.js +1 -1
  33. package/lib/types.d.ts +5 -1
  34. package/package.json +2 -1
  35. package/src/accounts/bulkAccountLoader.ts +32 -0
  36. package/src/accounts/types.js +10 -0
  37. package/src/accounts/utils.js +7 -0
  38. package/src/accounts/webSocketAccountSubscriber.js +76 -0
  39. package/src/addresses.js +83 -0
  40. package/src/admin.ts +15 -4
  41. package/src/clearingHouse.ts +2 -0
  42. package/src/clearingHouseUser.ts +161 -330
  43. package/src/constants/markets.ts +54 -3
  44. package/src/constants/numericConstants.ts +2 -2
  45. package/src/factory/oracleClient.ts +22 -0
  46. package/src/idl/clearing_house.json +58 -5
  47. package/src/idl/switchboard_v2.json +4663 -0
  48. package/src/index.ts +4 -1
  49. package/src/math/funding.ts +9 -25
  50. package/src/math/orders.ts +28 -0
  51. package/src/mockUSDCFaucet.js +171 -0
  52. package/src/oracles/pythClient.ts +49 -0
  53. package/src/oracles/switchboardClient.ts +87 -0
  54. package/src/oracles/types.ts +15 -0
  55. package/src/orderParams.ts +3 -2
  56. package/src/orders.ts +1 -1
  57. package/src/types.js +60 -0
  58. package/src/types.ts +6 -1
  59. package/lib/pythClient.d.ts +0 -7
  60. package/lib/pythClient.js +0 -25
  61. package/src/pythClient.ts +0 -15
package/src/index.ts CHANGED
@@ -2,7 +2,9 @@ import { BN } from '@project-serum/anchor';
2
2
  import { PublicKey } from '@solana/web3.js';
3
3
 
4
4
  export * from './mockUSDCFaucet';
5
- export * from './pythClient';
5
+ export * from './oracles/types';
6
+ export * from './oracles/pythClient';
7
+ export * from './oracles/switchboardClient';
6
8
  export * from './types';
7
9
  export * from './constants/markets';
8
10
  export * from './accounts/webSocketClearingHouseAccountSubscriber';
@@ -17,6 +19,7 @@ export * from './clearingHouseUser';
17
19
  export * from './clearingHouse';
18
20
  export * from './factory/clearingHouse';
19
21
  export * from './factory/clearingHouseUser';
22
+ export * from './factory/oracleClient';
20
23
  export * from './math/conversion';
21
24
  export * from './math/funding';
22
25
  export * from './math/insuranceFund';
@@ -1,5 +1,4 @@
1
1
  import { BN } from '@project-serum/anchor';
2
- import { PriceData } from '@pythnetwork/client';
3
2
  import {
4
3
  AMM_RESERVE_PRECISION,
5
4
  MARK_PRICE_PRECISION,
@@ -8,17 +7,18 @@ import {
8
7
  } from '../constants/numericConstants';
9
8
  import { Market } from '../types';
10
9
  import { calculateMarkPrice } from './market';
10
+ import { OraclePriceData } from '../oracles/types';
11
11
 
12
12
  /**
13
13
  *
14
14
  * @param market
15
- * @param pythClient
15
+ * @param oraclePriceData
16
16
  * @param periodAdjustment
17
17
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
18
18
  */
19
19
  export async function calculateAllEstimatedFundingRate(
20
20
  market: Market,
21
- oraclePriceData: PriceData,
21
+ oraclePriceData: OraclePriceData,
22
22
  periodAdjustment: BN = new BN(1)
23
23
  ): Promise<[BN, BN, BN, BN, BN]> {
24
24
  // periodAdjustment
@@ -65,26 +65,10 @@ export async function calculateAllEstimatedFundingRate(
65
65
  secondsInHour.sub(timeSinceLastOracleTwapUpdate)
66
66
  );
67
67
 
68
- // verify pyth input is positive for live update
69
- let oracleStablePriceNum = 0;
70
- let oracleInputCount = 0;
71
- if (oraclePriceData.price >= 0) {
72
- oracleStablePriceNum += oraclePriceData.price;
73
- oracleInputCount += 1;
74
- }
75
- if (oraclePriceData.previousPrice >= 0) {
76
- oracleStablePriceNum += oraclePriceData.previousPrice;
77
- oracleInputCount += 1;
78
- }
79
-
80
- oracleStablePriceNum = oracleStablePriceNum / oracleInputCount;
81
- const oraclePriceStableWithMantissa = new BN(
82
- oracleStablePriceNum * MARK_PRICE_PRECISION.toNumber()
83
- );
84
-
68
+ const oraclePrice = oraclePriceData.price;
85
69
  let oracleTwapWithMantissa = lastOracleTwapWithMantissa;
86
70
 
87
- const oracleLiveVsTwap = oraclePriceStableWithMantissa
71
+ const oracleLiveVsTwap = oraclePrice
88
72
  .sub(lastOracleTwapWithMantissa)
89
73
  .abs()
90
74
  .mul(MARK_PRICE_PRECISION)
@@ -95,7 +79,7 @@ export async function calculateAllEstimatedFundingRate(
95
79
  if (oracleLiveVsTwap.lte(MARK_PRICE_PRECISION.mul(new BN(10)))) {
96
80
  oracleTwapWithMantissa = oracleTwapTimeSinceLastUpdate
97
81
  .mul(lastOracleTwapWithMantissa)
98
- .add(timeSinceLastMarkChange.mul(oraclePriceStableWithMantissa))
82
+ .add(timeSinceLastMarkChange.mul(oraclePrice))
99
83
  .div(timeSinceLastOracleTwapUpdate.add(oracleTwapTimeSinceLastUpdate));
100
84
  }
101
85
 
@@ -203,7 +187,7 @@ export async function calculateAllEstimatedFundingRate(
203
187
  */
204
188
  export async function calculateEstimatedFundingRate(
205
189
  market: Market,
206
- oraclePriceData: PriceData,
190
+ oraclePriceData: OraclePriceData,
207
191
  periodAdjustment: BN = new BN(1),
208
192
  estimationMethod: 'interpolated' | 'lowerbound' | 'capped'
209
193
  ): Promise<BN> {
@@ -233,7 +217,7 @@ export async function calculateEstimatedFundingRate(
233
217
  */
234
218
  export async function calculateLongShortFundingRate(
235
219
  market: Market,
236
- oraclePriceData: PriceData,
220
+ oraclePriceData: OraclePriceData,
237
221
  periodAdjustment: BN = new BN(1)
238
222
  ): Promise<[BN, BN]> {
239
223
  const [_1, _2, _, cappedAltEst, interpEst] =
@@ -261,7 +245,7 @@ export async function calculateLongShortFundingRate(
261
245
  */
262
246
  export async function calculateLongShortFundingRateAndLiveTwaps(
263
247
  market: Market,
264
- oraclePriceData: PriceData,
248
+ oraclePriceData: OraclePriceData,
265
249
  periodAdjustment: BN = new BN(1)
266
250
  ): Promise<[BN, BN, BN, BN]> {
267
251
  const [markTwapLive, oracleTwapLive, _2, cappedAltEst, interpEst] =
@@ -75,3 +75,31 @@ export function isOrderRiskIncreasingInSameDirection(
75
75
 
76
76
  return false;
77
77
  }
78
+
79
+ export function isOrderReduceOnly(
80
+ user: ClearingHouseUser,
81
+ order: Order
82
+ ): boolean {
83
+ if (isVariant(order.status, 'init')) {
84
+ return false;
85
+ }
86
+
87
+ const position =
88
+ user.getUserPosition(order.marketIndex) ||
89
+ user.getEmptyPosition(order.marketIndex);
90
+
91
+ // if position is long and order is long
92
+ if (position.baseAssetAmount.gt(ZERO) && isVariant(order.direction, 'long')) {
93
+ return false;
94
+ }
95
+
96
+ // if position is short and order is short
97
+ if (
98
+ position.baseAssetAmount.lt(ZERO) &&
99
+ isVariant(order.direction, 'short')
100
+ ) {
101
+ return false;
102
+ }
103
+
104
+ return order.baseAssetAmount.abs().lte(position.baseAssetAmount.abs());
105
+ }
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
+ return new (P || (P = Promise))(function (resolve, reject) {
24
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
25
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
26
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
27
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
28
+ });
29
+ };
30
+ var __importDefault = (this && this.__importDefault) || function (mod) {
31
+ return (mod && mod.__esModule) ? mod : { "default": mod };
32
+ };
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.MockUSDCFaucet = void 0;
35
+ const anchor = __importStar(require("@project-serum/anchor"));
36
+ const anchor_1 = require("@project-serum/anchor");
37
+ const spl_token_1 = require("@solana/spl-token");
38
+ const web3_js_1 = require("@solana/web3.js");
39
+ const mock_usdc_faucet_json_1 = __importDefault(require("./idl/mock_usdc_faucet.json"));
40
+ class MockUSDCFaucet {
41
+ constructor(connection, wallet, programId, opts) {
42
+ this.connection = connection;
43
+ this.wallet = wallet;
44
+ this.opts = opts || anchor_1.Provider.defaultOptions();
45
+ const provider = new anchor_1.Provider(connection, wallet, this.opts);
46
+ this.provider = provider;
47
+ this.program = new anchor_1.Program(mock_usdc_faucet_json_1.default, programId, provider);
48
+ }
49
+ getMockUSDCFaucetStatePublicKeyAndNonce() {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ return anchor.web3.PublicKey.findProgramAddress([Buffer.from(anchor.utils.bytes.utf8.encode('mock_usdc_faucet'))], this.program.programId);
52
+ });
53
+ }
54
+ getMockUSDCFaucetStatePublicKey() {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ if (this.mockUSDCFaucetStatePublicKey) {
57
+ return this.mockUSDCFaucetStatePublicKey;
58
+ }
59
+ this.mockUSDCFaucetStatePublicKey = (yield this.getMockUSDCFaucetStatePublicKeyAndNonce())[0];
60
+ return this.mockUSDCFaucetStatePublicKey;
61
+ });
62
+ }
63
+ initialize() {
64
+ return __awaiter(this, void 0, void 0, function* () {
65
+ const stateAccountRPCResponse = yield this.connection.getParsedAccountInfo(yield this.getMockUSDCFaucetStatePublicKey());
66
+ if (stateAccountRPCResponse.value !== null) {
67
+ throw new Error('Faucet already initialized');
68
+ }
69
+ const fakeUSDCMint = anchor.web3.Keypair.generate();
70
+ const createUSDCMintAccountIx = web3_js_1.SystemProgram.createAccount({
71
+ fromPubkey: this.wallet.publicKey,
72
+ newAccountPubkey: fakeUSDCMint.publicKey,
73
+ lamports: yield spl_token_1.Token.getMinBalanceRentForExemptMint(this.connection),
74
+ space: spl_token_1.MintLayout.span,
75
+ programId: spl_token_1.TOKEN_PROGRAM_ID,
76
+ });
77
+ const [mintAuthority, _mintAuthorityNonce] = yield web3_js_1.PublicKey.findProgramAddress([fakeUSDCMint.publicKey.toBuffer()], this.program.programId);
78
+ const initUSDCMintIx = spl_token_1.Token.createInitMintInstruction(spl_token_1.TOKEN_PROGRAM_ID, fakeUSDCMint.publicKey, 6, mintAuthority, null);
79
+ const [mockUSDCFaucetStatePublicKey, mockUSDCFaucetStateNonce] = yield this.getMockUSDCFaucetStatePublicKeyAndNonce();
80
+ return yield this.program.rpc.initialize(mockUSDCFaucetStateNonce, {
81
+ accounts: {
82
+ mockUsdcFaucetState: mockUSDCFaucetStatePublicKey,
83
+ admin: this.wallet.publicKey,
84
+ mintAccount: fakeUSDCMint.publicKey,
85
+ rent: web3_js_1.SYSVAR_RENT_PUBKEY,
86
+ systemProgram: anchor.web3.SystemProgram.programId,
87
+ },
88
+ instructions: [createUSDCMintAccountIx, initUSDCMintIx],
89
+ signers: [fakeUSDCMint],
90
+ });
91
+ });
92
+ }
93
+ fetchState() {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ return yield this.program.account.mockUsdcFaucetState.fetch(yield this.getMockUSDCFaucetStatePublicKey());
96
+ });
97
+ }
98
+ mintToUser(userTokenAccount, amount) {
99
+ return __awaiter(this, void 0, void 0, function* () {
100
+ const state = yield this.fetchState();
101
+ return yield this.program.rpc.mintToUser(amount, {
102
+ accounts: {
103
+ mockUsdcFaucetState: yield this.getMockUSDCFaucetStatePublicKey(),
104
+ mintAccount: state.mint,
105
+ userTokenAccount,
106
+ mintAuthority: state.mintAuthority,
107
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
108
+ },
109
+ });
110
+ });
111
+ }
112
+ createAssociatedTokenAccountAndMintTo(userPublicKey, amount) {
113
+ return __awaiter(this, void 0, void 0, function* () {
114
+ const [associatedTokenPublicKey, createAssociatedAccountIx, mintToTx] = yield this.createAssociatedTokenAccountAndMintToInstructions(userPublicKey, amount);
115
+ const tx = new web3_js_1.Transaction().add(createAssociatedAccountIx).add(mintToTx);
116
+ const txSig = yield this.program.provider.send(tx, [], this.opts);
117
+ return [associatedTokenPublicKey, txSig];
118
+ });
119
+ }
120
+ createAssociatedTokenAccountAndMintToInstructions(userPublicKey, amount) {
121
+ return __awaiter(this, void 0, void 0, function* () {
122
+ const state = yield this.fetchState();
123
+ const associateTokenPublicKey = yield this.getAssosciatedMockUSDMintAddress({ userPubKey: userPublicKey });
124
+ const createAssociatedAccountIx = spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, state.mint, associateTokenPublicKey, userPublicKey, this.wallet.publicKey);
125
+ const mintToIx = yield this.program.instruction.mintToUser(amount, {
126
+ accounts: {
127
+ mockUsdcFaucetState: yield this.getMockUSDCFaucetStatePublicKey(),
128
+ mintAccount: state.mint,
129
+ userTokenAccount: associateTokenPublicKey,
130
+ mintAuthority: state.mintAuthority,
131
+ tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
132
+ },
133
+ });
134
+ return [associateTokenPublicKey, createAssociatedAccountIx, mintToIx];
135
+ });
136
+ }
137
+ getAssosciatedMockUSDMintAddress(props) {
138
+ return __awaiter(this, void 0, void 0, function* () {
139
+ const state = yield this.fetchState();
140
+ return spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, state.mint, props.userPubKey);
141
+ });
142
+ }
143
+ getTokenAccountInfo(props) {
144
+ return __awaiter(this, void 0, void 0, function* () {
145
+ const assosciatedKey = yield this.getAssosciatedMockUSDMintAddress(props);
146
+ const state = yield this.fetchState();
147
+ const token = new spl_token_1.Token(this.connection, state.mint, spl_token_1.TOKEN_PROGRAM_ID,
148
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
149
+ // @ts-ignore
150
+ this.provider.payer);
151
+ return yield token.getAccountInfo(assosciatedKey);
152
+ });
153
+ }
154
+ subscribeToTokenAccount(props) {
155
+ return __awaiter(this, void 0, void 0, function* () {
156
+ try {
157
+ const tokenAccountKey = yield this.getAssosciatedMockUSDMintAddress(props);
158
+ props.callback(yield this.getTokenAccountInfo(props));
159
+ // Couldn't find a way to do it using anchor framework subscription, someone on serum discord recommended this way
160
+ this.connection.onAccountChange(tokenAccountKey, (_accountInfo /* accountInfo is a buffer which we don't know how to deserialize */) => __awaiter(this, void 0, void 0, function* () {
161
+ props.callback(yield this.getTokenAccountInfo(props));
162
+ }));
163
+ return true;
164
+ }
165
+ catch (e) {
166
+ return false;
167
+ }
168
+ });
169
+ }
170
+ }
171
+ exports.MockUSDCFaucet = MockUSDCFaucet;
@@ -0,0 +1,49 @@
1
+ import { parsePriceData, PriceData } from '@pythnetwork/client';
2
+ import { Connection, PublicKey } from '@solana/web3.js';
3
+ import { OraclePriceData } from './types';
4
+ import { BN } from '@project-serum/anchor';
5
+ import { MARK_PRICE_PRECISION, TEN } from '../constants/numericConstants';
6
+
7
+ export class PythClient {
8
+ private connection: Connection;
9
+
10
+ public constructor(connection: Connection) {
11
+ this.connection = connection;
12
+ }
13
+
14
+ public async getPriceData(pricePublicKey: PublicKey): Promise<PriceData> {
15
+ const account = await this.connection.getAccountInfo(pricePublicKey);
16
+ return parsePriceData(account.data);
17
+ }
18
+
19
+ public async getOraclePriceData(
20
+ pricePublicKey: PublicKey
21
+ ): Promise<OraclePriceData> {
22
+ const accountInfo = await this.connection.getAccountInfo(pricePublicKey);
23
+ return this.getOraclePriceDataFromBuffer(accountInfo.data);
24
+ }
25
+
26
+ public async getOraclePriceDataFromBuffer(
27
+ buffer: Buffer
28
+ ): Promise<OraclePriceData> {
29
+ const priceData = parsePriceData(buffer);
30
+ return {
31
+ price: convertPythPrice(priceData.price, priceData.exponent),
32
+ slot: new BN(priceData.lastSlot.toString()),
33
+ confidence: convertPythPrice(priceData.confidence, priceData.exponent),
34
+ twap: convertPythPrice(priceData.twap.value, priceData.exponent),
35
+ twapConfidence: convertPythPrice(
36
+ priceData.twac.value,
37
+ priceData.exponent
38
+ ),
39
+ };
40
+ }
41
+ }
42
+
43
+ export function convertPythPrice(price: number, exponent: number): BN {
44
+ exponent = Math.abs(exponent);
45
+ const pythPrecision = TEN.pow(new BN(exponent).abs());
46
+ return new BN(price * Math.pow(10, exponent))
47
+ .mul(MARK_PRICE_PRECISION)
48
+ .div(pythPrecision);
49
+ }
@@ -0,0 +1,87 @@
1
+ import {
2
+ getSwitchboardPid,
3
+ SwitchboardDecimal,
4
+ } from '@switchboard-xyz/switchboard-v2';
5
+ import { Connection, Keypair, PublicKey } from '@solana/web3.js';
6
+ import { DriftEnv } from '../config';
7
+ import { BN, Provider, Program, Idl } from '@project-serum/anchor';
8
+ import { MARK_PRICE_PRECISION, TEN } from '../constants/numericConstants';
9
+ import { OracleClient, OraclePriceData } from './types';
10
+ import { Wallet } from '../wallet';
11
+ import switchboardV2Idl from '../idl/switchboard_v2.json';
12
+
13
+ // cache switchboard program for every client object since itll always be the same
14
+ const programMap = new Map<string, Program>();
15
+
16
+ export class SwitchboardClient implements OracleClient {
17
+ connection: Connection;
18
+ env: DriftEnv;
19
+
20
+ public constructor(connection: Connection, env: DriftEnv) {
21
+ this.connection = connection;
22
+ this.env = env;
23
+ }
24
+
25
+ public async getOraclePriceData(
26
+ pricePublicKey: PublicKey
27
+ ): Promise<OraclePriceData> {
28
+ const accountInfo = await this.connection.getAccountInfo(pricePublicKey);
29
+ return this.getOraclePriceDataFromBuffer(accountInfo.data);
30
+ }
31
+
32
+ public async getOraclePriceDataFromBuffer(
33
+ buffer: Buffer
34
+ ): Promise<OraclePriceData> {
35
+ const program = await this.getProgram();
36
+
37
+ const aggregatorAccountData =
38
+ program.account.aggregatorAccountData.coder.accounts.decode(
39
+ 'AggregatorAccountData',
40
+ buffer
41
+ );
42
+ const price = convertSwitchboardDecimal(
43
+ aggregatorAccountData.latestConfirmedRound.result as SwitchboardDecimal
44
+ );
45
+
46
+ const confidence = convertSwitchboardDecimal(
47
+ aggregatorAccountData.latestConfirmedRound
48
+ .stdDeviation as SwitchboardDecimal
49
+ );
50
+
51
+ const slot: BN = aggregatorAccountData.latestConfirmedRound.roundOpenSlot;
52
+ return {
53
+ price,
54
+ slot,
55
+ confidence,
56
+ };
57
+ }
58
+
59
+ public async getProgram(): Promise<Program> {
60
+ if (programMap.has(this.env)) {
61
+ return programMap.get(this.env);
62
+ }
63
+
64
+ const program = await getSwitchboardProgram(this.env, this.connection);
65
+ programMap.set(this.env, program);
66
+ return program;
67
+ }
68
+ }
69
+
70
+ async function getSwitchboardProgram(
71
+ env: DriftEnv,
72
+ connection: Connection
73
+ ): Promise<Program> {
74
+ const DEFAULT_KEYPAIR = Keypair.fromSeed(new Uint8Array(32).fill(1));
75
+ const programId = getSwitchboardPid(env);
76
+ const wallet = new Wallet(DEFAULT_KEYPAIR);
77
+ const provider = new Provider(connection, wallet, {});
78
+
79
+ return new Program(switchboardV2Idl as Idl, programId, provider);
80
+ }
81
+
82
+ function convertSwitchboardDecimal(switchboardDecimal: SwitchboardDecimal): BN {
83
+ const switchboardPrecision = TEN.pow(new BN(switchboardDecimal.scale));
84
+ return switchboardDecimal.mantissa
85
+ .mul(MARK_PRICE_PRECISION)
86
+ .div(switchboardPrecision);
87
+ }
@@ -0,0 +1,15 @@
1
+ import { BN } from '@project-serum/anchor';
2
+ import { PublicKey } from '@solana/web3.js';
3
+
4
+ export type OraclePriceData = {
5
+ price: BN;
6
+ slot: BN;
7
+ confidence: BN;
8
+ twap?: BN;
9
+ twapConfidence?: BN;
10
+ };
11
+
12
+ export interface OracleClient {
13
+ getOraclePriceDataFromBuffer(buffer: Buffer): Promise<OraclePriceData>;
14
+ getOraclePriceData(publicKey: PublicKey): Promise<OraclePriceData>;
15
+ }
@@ -15,7 +15,8 @@ export function getLimitOrderParams(
15
15
  reduceOnly: boolean,
16
16
  discountToken = false,
17
17
  referrer = false,
18
- userOrderId = 0
18
+ userOrderId = 0,
19
+ postOnly = false
19
20
  ): OrderParams {
20
21
  return {
21
22
  orderType: OrderType.LIMIT,
@@ -26,7 +27,7 @@ export function getLimitOrderParams(
26
27
  baseAssetAmount,
27
28
  price,
28
29
  reduceOnly,
29
- postOnly: false,
30
+ postOnly,
30
31
  immediateOrCancel: false,
31
32
  positionLimit: ZERO,
32
33
  padding0: true,
package/src/orders.ts CHANGED
@@ -255,7 +255,7 @@ export function calculateBaseAssetAmountUserCanExecute(
255
255
  order: Order,
256
256
  user: ClearingHouseUser
257
257
  ): BN {
258
- const maxLeverage = user.getMaxLeverage('Initial');
258
+ const maxLeverage = user.getMaxLeverage(order.marketIndex, 'Initial');
259
259
  const freeCollateral = user.getFreeCollateral();
260
260
  let quoteAssetAmount: BN;
261
261
  if (isOrderRiskIncreasingInSameDirection(user, order)) {
package/src/types.js ADDED
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TradeSide = exports.isVariant = exports.OrderTriggerCondition = exports.OrderAction = exports.OrderDiscountTier = exports.OrderStatus = exports.OrderType = exports.OracleSource = exports.PositionDirection = exports.SwapDirection = void 0;
4
+ // # Utility Types / Enums / Constants
5
+ class SwapDirection {
6
+ }
7
+ exports.SwapDirection = SwapDirection;
8
+ SwapDirection.ADD = { add: {} };
9
+ SwapDirection.REMOVE = { remove: {} };
10
+ class PositionDirection {
11
+ }
12
+ exports.PositionDirection = PositionDirection;
13
+ PositionDirection.LONG = { long: {} };
14
+ PositionDirection.SHORT = { short: {} };
15
+ class OracleSource {
16
+ }
17
+ exports.OracleSource = OracleSource;
18
+ OracleSource.PYTH = { pyth: {} };
19
+ OracleSource.SWITCHBOARD = { switchboard: {} };
20
+ class OrderType {
21
+ }
22
+ exports.OrderType = OrderType;
23
+ OrderType.LIMIT = { limit: {} };
24
+ OrderType.TRIGGER_MARKET = { triggerMarket: {} };
25
+ OrderType.TRIGGER_LIMIT = { triggerLimit: {} };
26
+ OrderType.MARKET = { market: {} };
27
+ class OrderStatus {
28
+ }
29
+ exports.OrderStatus = OrderStatus;
30
+ OrderStatus.INIT = { init: {} };
31
+ OrderStatus.OPEN = { open: {} };
32
+ class OrderDiscountTier {
33
+ }
34
+ exports.OrderDiscountTier = OrderDiscountTier;
35
+ OrderDiscountTier.NONE = { none: {} };
36
+ OrderDiscountTier.FIRST = { first: {} };
37
+ OrderDiscountTier.SECOND = { second: {} };
38
+ OrderDiscountTier.THIRD = { third: {} };
39
+ OrderDiscountTier.FOURTH = { fourth: {} };
40
+ class OrderAction {
41
+ }
42
+ exports.OrderAction = OrderAction;
43
+ OrderAction.PLACE = { place: {} };
44
+ OrderAction.CANCEL = { cancel: {} };
45
+ OrderAction.FILL = { fill: {} };
46
+ class OrderTriggerCondition {
47
+ }
48
+ exports.OrderTriggerCondition = OrderTriggerCondition;
49
+ OrderTriggerCondition.ABOVE = { above: {} };
50
+ OrderTriggerCondition.BELOW = { below: {} };
51
+ function isVariant(object, type) {
52
+ return object.hasOwnProperty(type);
53
+ }
54
+ exports.isVariant = isVariant;
55
+ var TradeSide;
56
+ (function (TradeSide) {
57
+ TradeSide[TradeSide["None"] = 0] = "None";
58
+ TradeSide[TradeSide["Buy"] = 1] = "Buy";
59
+ TradeSide[TradeSide["Sell"] = 2] = "Sell";
60
+ })(TradeSide = exports.TradeSide || (exports.TradeSide = {}));
package/src/types.ts CHANGED
@@ -217,6 +217,7 @@ export type OrderRecord = {
217
217
  fee: BN;
218
218
  fillerReward: BN;
219
219
  tradeRecordId: BN;
220
+ quoteAssetAmountSurplus: BN;
220
221
  };
221
222
 
222
223
  export type StateAccount = {
@@ -267,7 +268,6 @@ export type OrderStateAccount = {
267
268
  };
268
269
 
269
270
  export type MarketsAccount = {
270
- accountIndex: BN;
271
271
  markets: Market[];
272
272
  };
273
273
 
@@ -278,6 +278,9 @@ export type Market = {
278
278
  baseAssetAmountShort: BN;
279
279
  initialized: boolean;
280
280
  openInterest: BN;
281
+ marginRatioInitial: number;
282
+ marginRatioMaintenance: number;
283
+ marginRatioPartial: number;
281
284
  };
282
285
 
283
286
  export type AMM = {
@@ -443,3 +446,5 @@ export type OrderFillerRewardStructure = {
443
446
  rewardDenominator: BN;
444
447
  timeBasedRewardLowerBound: BN;
445
448
  };
449
+
450
+ export type MarginCategory = 'Initial' | 'Partial' | 'Maintenance';
@@ -1,7 +0,0 @@
1
- import { PriceData } from '@pythnetwork/client';
2
- import { Connection, PublicKey } from '@solana/web3.js';
3
- export declare class PythClient {
4
- private connection;
5
- constructor(connection: Connection);
6
- getPriceData(pricePublicKey: PublicKey): Promise<PriceData>;
7
- }
package/lib/pythClient.js DELETED
@@ -1,25 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.PythClient = void 0;
13
- const client_1 = require("@pythnetwork/client");
14
- class PythClient {
15
- constructor(connection) {
16
- this.connection = connection;
17
- }
18
- getPriceData(pricePublicKey) {
19
- return __awaiter(this, void 0, void 0, function* () {
20
- const account = yield this.connection.getAccountInfo(pricePublicKey);
21
- return (0, client_1.parsePriceData)(account.data);
22
- });
23
- }
24
- }
25
- exports.PythClient = PythClient;
package/src/pythClient.ts DELETED
@@ -1,15 +0,0 @@
1
- import { parsePriceData, PriceData } from '@pythnetwork/client';
2
- import { Connection, PublicKey } from '@solana/web3.js';
3
-
4
- export class PythClient {
5
- private connection: Connection;
6
-
7
- public constructor(connection: Connection) {
8
- this.connection = connection;
9
- }
10
-
11
- public async getPriceData(pricePublicKey: PublicKey): Promise<PriceData> {
12
- const account = await this.connection.getAccountInfo(pricePublicKey);
13
- return parsePriceData(account.data);
14
- }
15
- }