@drift-labs/sdk 0.1.36-master.3 → 0.1.36-master.6

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 (39) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +1 -0
  2. package/lib/accounts/bulkAccountLoader.js +4 -0
  3. package/lib/admin.js +1 -1
  4. package/lib/clearingHouse.d.ts +6 -4
  5. package/lib/clearingHouse.js +46 -8
  6. package/lib/examples/makeTradeExample.js +1 -1
  7. package/lib/factory/clearingHouse.js +4 -4
  8. package/lib/idl/clearing_house.json +72 -1
  9. package/lib/index.d.ts +1 -0
  10. package/lib/index.js +1 -0
  11. package/lib/math/oracles.d.ts +3 -0
  12. package/lib/math/oracles.js +26 -0
  13. package/lib/math/trade.d.ts +10 -6
  14. package/lib/math/trade.js +68 -13
  15. package/lib/mockUSDCFaucet.d.ts +2 -2
  16. package/lib/mockUSDCFaucet.js +3 -3
  17. package/lib/oracles/pythClient.js +1 -0
  18. package/lib/oracles/switchboardClient.js +4 -1
  19. package/lib/oracles/types.d.ts +1 -0
  20. package/lib/tx/defaultTxSender.d.ts +3 -3
  21. package/lib/tx/defaultTxSender.js +1 -1
  22. package/lib/tx/retryTxSender.d.ts +3 -3
  23. package/package.json +2 -2
  24. package/src/accounts/bulkAccountLoader.ts +5 -0
  25. package/src/accounts/webSocketAccountSubscriber.ts +3 -3
  26. package/src/admin.ts +2 -2
  27. package/src/clearingHouse.ts +81 -10
  28. package/src/examples/makeTradeExample.ts +6 -2
  29. package/src/factory/clearingHouse.ts +13 -5
  30. package/src/idl/clearing_house.json +72 -1
  31. package/src/index.ts +1 -0
  32. package/src/math/oracles.ts +36 -0
  33. package/src/math/trade.ts +84 -16
  34. package/src/mockUSDCFaucet.ts +5 -5
  35. package/src/oracles/pythClient.ts +1 -0
  36. package/src/oracles/switchboardClient.ts +7 -2
  37. package/src/oracles/types.ts +1 -0
  38. package/src/tx/defaultTxSender.ts +4 -4
  39. package/src/tx/retryTxSender.ts +3 -3
@@ -16,6 +16,7 @@ export declare class BulkAccountLoader {
16
16
  loadPromise?: Promise<void>;
17
17
  loadPromiseResolver: () => void;
18
18
  lastTimeLoadingPromiseCleared: number;
19
+ mostRecentSlot: number;
19
20
  constructor(connection: Connection, commitment: Commitment, pollingFrequency: number);
20
21
  addAccount(publicKey: PublicKey, callback: (buffer: Buffer) => void): string;
21
22
  removeAccount(publicKey: PublicKey, callbackId: string): void;
@@ -20,6 +20,7 @@ class BulkAccountLoader {
20
20
  this.accountData = new Map();
21
21
  this.errorCallbacks = new Map();
22
22
  this.lastTimeLoadingPromiseCleared = Date.now();
23
+ this.mostRecentSlot = 0;
23
24
  this.connection = connection;
24
25
  this.commitment = commitment;
25
26
  this.pollingFrequency = pollingFrequency;
@@ -127,6 +128,9 @@ class BulkAccountLoader {
127
128
  return;
128
129
  }
129
130
  const newSlot = rpcResponse.result.context.slot;
131
+ if (newSlot > this.mostRecentSlot) {
132
+ this.mostRecentSlot = newSlot;
133
+ }
130
134
  for (const i in accountsToLoad) {
131
135
  const accountToLoad = accountsToLoad[i];
132
136
  const key = accountToLoad.publicKey.toString();
package/lib/admin.js CHANGED
@@ -45,7 +45,7 @@ const trade_1 = require("./math/trade");
45
45
  const amm_1 = require("./math/amm");
46
46
  const clearingHouse_2 = require("./factory/clearingHouse");
47
47
  class Admin extends clearingHouse_1.ClearingHouse {
48
- static from(connection, wallet, clearingHouseProgramId, opts = anchor_1.Provider.defaultOptions()) {
48
+ static from(connection, wallet, clearingHouseProgramId, opts = anchor_1.AnchorProvider.defaultOptions()) {
49
49
  const config = (0, clearingHouse_2.getWebSocketClearingHouseConfig)(connection, wallet, clearingHouseProgramId, opts);
50
50
  return (0, clearingHouse_2.getAdmin)(config);
51
51
  }
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="bn.js" />
3
- import { BN, Program, Provider } from '@project-serum/anchor';
3
+ import { AnchorProvider, BN, Program } from '@project-serum/anchor';
4
4
  import { MarketsAccount, StateAccount, DepositHistoryAccount, FundingPaymentHistoryAccount, FundingRateHistoryAccount, IWallet, LiquidationHistoryAccount, PositionDirection, TradeHistoryAccount, UserAccount, Market, OrderHistoryAccount, OrderStateAccount, OrderParams, Order, ExtendedCurveHistoryAccount, UserPositionsAccount } from './types';
5
5
  import { Connection, PublicKey, TransactionSignature, Keypair, ConfirmOptions, TransactionInstruction } from '@solana/web3.js';
6
6
  import { MockUSDCFaucet } from './mockUSDCFaucet';
@@ -19,7 +19,7 @@ export declare class ClearingHouse {
19
19
  connection: Connection;
20
20
  wallet: IWallet;
21
21
  program: Program;
22
- provider: Provider;
22
+ provider: AnchorProvider;
23
23
  opts?: ConfirmOptions;
24
24
  accountSubscriber: ClearingHouseAccountSubscriber;
25
25
  eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
@@ -126,8 +126,10 @@ export declare class ClearingHouse {
126
126
  getCancelOrderIx(orderId: BN, oracle?: PublicKey): Promise<TransactionInstruction>;
127
127
  cancelOrderByUserId(userOrderId: number, oracle?: PublicKey): Promise<TransactionSignature>;
128
128
  getCancelOrderByUserIdIx(userOrderId: number, oracle?: PublicKey): Promise<TransactionInstruction>;
129
- cancelAllOrders(oracles?: PublicKey[]): Promise<TransactionSignature>;
130
- getCancelAllOrdersIx(oracles: PublicKey[]): Promise<TransactionInstruction>;
129
+ cancelAllOrders(oracles?: PublicKey[], bestEffort?: boolean): Promise<TransactionSignature>;
130
+ getCancelAllOrdersIx(oracles: PublicKey[], bestEffort?: boolean): Promise<TransactionInstruction>;
131
+ cancelOrdersByMarketAndSide(oracles?: PublicKey[], bestEffort?: boolean, marketIndexOnly?: BN, directionOnly?: PositionDirection): Promise<TransactionSignature>;
132
+ getCancelOrdersByMarketAndSideIx(oracles: PublicKey[], bestEffort?: boolean, marketIndexOnly?: BN, directionOnly?: PositionDirection): Promise<TransactionInstruction>;
131
133
  fillOrder(userAccountPublicKey: PublicKey, userOrdersAccountPublicKey: PublicKey, order: Order): Promise<TransactionSignature>;
132
134
  getFillOrderIx(userAccountPublicKey: PublicKey, userOrdersAccountPublicKey: PublicKey, order: Order): Promise<TransactionInstruction>;
133
135
  initializeUserOrdersThenPlaceAndFillOrder(orderParams: OrderParams, discountToken?: PublicKey, referrer?: PublicKey): Promise<TransactionSignature>;
@@ -77,7 +77,7 @@ class ClearingHouse {
77
77
  * @param opts
78
78
  * @returns
79
79
  */
80
- static from(connection, wallet, clearingHouseProgramId, opts = anchor_1.Provider.defaultOptions()) {
80
+ static from(connection, wallet, clearingHouseProgramId, opts = anchor_1.AnchorProvider.defaultOptions()) {
81
81
  const config = (0, clearingHouse_1.getWebSocketClearingHouseConfig)(connection, wallet, clearingHouseProgramId, opts);
82
82
  return (0, clearingHouse_1.getClearingHouse)(config);
83
83
  }
@@ -185,7 +185,7 @@ class ClearingHouse {
185
185
  * @param newWallet
186
186
  */
187
187
  updateWallet(newWallet) {
188
- const newProvider = new anchor_1.Provider(this.connection, newWallet, this.opts);
188
+ const newProvider = new anchor_1.AnchorProvider(this.connection, newWallet, this.opts);
189
189
  const newProgram = new anchor_1.Program(clearing_house_json_1.default, this.program.programId, newProvider);
190
190
  // Update provider for txSender with new wallet details
191
191
  this.txSender.provider = newProvider;
@@ -352,7 +352,7 @@ class ClearingHouse {
352
352
  .add(initializeUserAccountIx)
353
353
  .add(initializeUserOrdersAccountIx)
354
354
  .add(depositCollateralIx);
355
- const txSig = yield this.program.provider.send(tx, [userPositionsAccount]);
355
+ const txSig = yield this.txSender.send(tx, [userPositionsAccount]);
356
356
  return [txSig, userAccountPublicKey];
357
357
  });
358
358
  }
@@ -367,7 +367,9 @@ class ClearingHouse {
367
367
  .add(initializeUserAccountIx)
368
368
  .add(initializeUserOrdersAccountIx)
369
369
  .add(depositCollateralIx);
370
- const txSig = yield this.program.provider.send(tx, [userPositionsAccount]);
370
+ const txSig = yield this.program.provider.sendAndConfirm(tx, [
371
+ userPositionsAccount,
372
+ ]);
371
373
  return [txSig, userAccountPublicKey];
372
374
  });
373
375
  }
@@ -620,12 +622,48 @@ class ClearingHouse {
620
622
  });
621
623
  });
622
624
  }
623
- cancelAllOrders(oracles) {
625
+ cancelAllOrders(oracles, bestEffort) {
626
+ return __awaiter(this, void 0, void 0, function* () {
627
+ return yield this.txSender.send((0, utils_1.wrapInTx)(yield this.getCancelAllOrdersIx(oracles, bestEffort)), [], this.opts);
628
+ });
629
+ }
630
+ getCancelAllOrdersIx(oracles, bestEffort) {
631
+ return __awaiter(this, void 0, void 0, function* () {
632
+ const userAccountPublicKey = yield this.getUserAccountPublicKey();
633
+ const userAccount = yield this.getUserAccount();
634
+ const state = this.getStateAccount();
635
+ const orderState = this.getOrderStateAccount();
636
+ const remainingAccounts = [];
637
+ for (const oracle of oracles) {
638
+ remainingAccounts.push({
639
+ pubkey: oracle,
640
+ isWritable: false,
641
+ isSigner: false,
642
+ });
643
+ }
644
+ return yield this.program.instruction.cancelAllOrders(bestEffort, {
645
+ accounts: {
646
+ state: yield this.getStatePublicKey(),
647
+ user: userAccountPublicKey,
648
+ authority: this.wallet.publicKey,
649
+ markets: state.markets,
650
+ userOrders: yield this.getUserOrdersAccountPublicKey(),
651
+ userPositions: userAccount.positions,
652
+ fundingPaymentHistory: state.fundingPaymentHistory,
653
+ fundingRateHistory: state.fundingRateHistory,
654
+ orderState: yield this.getOrderStatePublicKey(),
655
+ orderHistory: orderState.orderHistory,
656
+ },
657
+ remainingAccounts,
658
+ });
659
+ });
660
+ }
661
+ cancelOrdersByMarketAndSide(oracles, bestEffort, marketIndexOnly, directionOnly) {
624
662
  return __awaiter(this, void 0, void 0, function* () {
625
- return yield this.txSender.send((0, utils_1.wrapInTx)(yield this.getCancelAllOrdersIx(oracles)), [], this.opts);
663
+ return yield this.txSender.send((0, utils_1.wrapInTx)(yield this.getCancelOrdersByMarketAndSideIx(oracles, bestEffort, marketIndexOnly, directionOnly)), [], this.opts);
626
664
  });
627
665
  }
628
- getCancelAllOrdersIx(oracles) {
666
+ getCancelOrdersByMarketAndSideIx(oracles, bestEffort, marketIndexOnly, directionOnly) {
629
667
  return __awaiter(this, void 0, void 0, function* () {
630
668
  const userAccountPublicKey = yield this.getUserAccountPublicKey();
631
669
  const userAccount = yield this.getUserAccount();
@@ -639,7 +677,7 @@ class ClearingHouse {
639
677
  isSigner: false,
640
678
  });
641
679
  }
642
- return yield this.program.instruction.cancelAllOrders({
680
+ return yield this.program.instruction.cancelOrdersByMarketAndSide(bestEffort, marketIndexOnly, directionOnly, {
643
681
  accounts: {
644
682
  state: yield this.getStatePublicKey(),
645
683
  user: userAccountPublicKey,
@@ -30,7 +30,7 @@ const main = () => __awaiter(void 0, void 0, void 0, function* () {
30
30
  const rpcAddress = process.env.RPC_ADDRESS; // can use: https://api.devnet.solana.com for devnet; https://api.mainnet-beta.solana.com for mainnet;
31
31
  const connection = new web3_js_1.Connection(rpcAddress);
32
32
  // Set up the Provider
33
- const provider = new anchor_1.Provider(connection, wallet, anchor_1.Provider.defaultOptions());
33
+ const provider = new anchor_1.AnchorProvider(connection, wallet, anchor_1.AnchorProvider.defaultOptions());
34
34
  // Check SOL Balance
35
35
  const lamportsBalance = yield connection.getBalance(wallet.publicKey);
36
36
  console.log('SOL balance:', lamportsBalance / Math.pow(10, 9));
@@ -12,7 +12,7 @@ const defaultTxSender_1 = require("../tx/defaultTxSender");
12
12
  const pollingClearingHouseAccountSubscriber_1 = require("../accounts/pollingClearingHouseAccountSubscriber");
13
13
  const admin_1 = require("../admin");
14
14
  const retryTxSender_1 = require("../tx/retryTxSender");
15
- function getWebSocketClearingHouseConfig(connection, wallet, programID, opts = anchor_1.Provider.defaultOptions(), txSenderConfig) {
15
+ function getWebSocketClearingHouseConfig(connection, wallet, programID, opts = anchor_1.AnchorProvider.defaultOptions(), txSenderConfig) {
16
16
  return {
17
17
  type: 'websocket',
18
18
  connection,
@@ -23,7 +23,7 @@ function getWebSocketClearingHouseConfig(connection, wallet, programID, opts = a
23
23
  };
24
24
  }
25
25
  exports.getWebSocketClearingHouseConfig = getWebSocketClearingHouseConfig;
26
- function getPollingClearingHouseConfig(connection, wallet, programID, accountLoader, opts = anchor_1.Provider.defaultOptions(), txSenderConfig) {
26
+ function getPollingClearingHouseConfig(connection, wallet, programID, accountLoader, opts = anchor_1.AnchorProvider.defaultOptions(), txSenderConfig) {
27
27
  return {
28
28
  type: 'polling',
29
29
  connection,
@@ -37,7 +37,7 @@ function getPollingClearingHouseConfig(connection, wallet, programID, accountLoa
37
37
  exports.getPollingClearingHouseConfig = getPollingClearingHouseConfig;
38
38
  function getClearingHouse(config) {
39
39
  var _a;
40
- const provider = new anchor_1.Provider(config.connection, config.wallet, config.opts);
40
+ const provider = new anchor_1.AnchorProvider(config.connection, config.wallet, config.opts);
41
41
  const program = new anchor_1.Program(clearing_house_json_1.default, config.programID, provider);
42
42
  let accountSubscriber;
43
43
  if (config.type === 'websocket') {
@@ -59,7 +59,7 @@ function getClearingHouse(config) {
59
59
  exports.getClearingHouse = getClearingHouse;
60
60
  function getAdmin(config) {
61
61
  var _a;
62
- const provider = new anchor_1.Provider(config.connection, config.wallet, config.opts);
62
+ const provider = new anchor_1.AnchorProvider(config.connection, config.wallet, config.opts);
63
63
  const program = new anchor_1.Program(clearing_house_json_1.default, config.programID, provider);
64
64
  let accountSubscriber;
65
65
  if (config.type === 'websocket') {
@@ -726,7 +726,78 @@
726
726
  "isSigner": false
727
727
  }
728
728
  ],
729
- "args": []
729
+ "args": [
730
+ {
731
+ "name": "bestEffort",
732
+ "type": "bool"
733
+ }
734
+ ]
735
+ },
736
+ {
737
+ "name": "cancelOrdersByMarketAndSide",
738
+ "accounts": [
739
+ {
740
+ "name": "state",
741
+ "isMut": false,
742
+ "isSigner": false
743
+ },
744
+ {
745
+ "name": "orderState",
746
+ "isMut": false,
747
+ "isSigner": false
748
+ },
749
+ {
750
+ "name": "user",
751
+ "isMut": false,
752
+ "isSigner": false
753
+ },
754
+ {
755
+ "name": "authority",
756
+ "isMut": false,
757
+ "isSigner": true
758
+ },
759
+ {
760
+ "name": "markets",
761
+ "isMut": false,
762
+ "isSigner": false
763
+ },
764
+ {
765
+ "name": "userPositions",
766
+ "isMut": true,
767
+ "isSigner": false
768
+ },
769
+ {
770
+ "name": "userOrders",
771
+ "isMut": true,
772
+ "isSigner": false
773
+ },
774
+ {
775
+ "name": "fundingPaymentHistory",
776
+ "isMut": true,
777
+ "isSigner": false
778
+ },
779
+ {
780
+ "name": "orderHistory",
781
+ "isMut": true,
782
+ "isSigner": false
783
+ }
784
+ ],
785
+ "args": [
786
+ {
787
+ "name": "bestEffort",
788
+ "type": "bool"
789
+ },
790
+ {
791
+ "name": "marketIndexOnly",
792
+ "type": "u64"
793
+ },
794
+ {
795
+ "name": "directionOnly",
796
+ "type": {
797
+ "defined": "PositionDirection"
798
+ }
799
+ }
800
+ ]
730
801
  },
731
802
  {
732
803
  "name": "expireOrders",
package/lib/index.d.ts CHANGED
@@ -25,6 +25,7 @@ export * from './math/funding';
25
25
  export * from './math/insuranceFund';
26
26
  export * from './math/market';
27
27
  export * from './math/position';
28
+ export * from './math/oracles';
28
29
  export * from './math/amm';
29
30
  export * from './math/trade';
30
31
  export * from './math/orders';
package/lib/index.js CHANGED
@@ -44,6 +44,7 @@ __exportStar(require("./math/funding"), exports);
44
44
  __exportStar(require("./math/insuranceFund"), exports);
45
45
  __exportStar(require("./math/market"), exports);
46
46
  __exportStar(require("./math/position"), exports);
47
+ __exportStar(require("./math/oracles"), exports);
47
48
  __exportStar(require("./math/amm"), exports);
48
49
  __exportStar(require("./math/trade"), exports);
49
50
  __exportStar(require("./math/orders"), exports);
@@ -0,0 +1,3 @@
1
+ import { AMM, OracleGuardRails } from '../types';
2
+ import { OraclePriceData } from '../oracles/types';
3
+ export declare function isOracleValid(amm: AMM, oraclePriceData: OraclePriceData, oracleGuardRails: OracleGuardRails, slot: number): boolean;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isOracleValid = void 0;
4
+ const numericConstants_1 = require("../constants/numericConstants");
5
+ const index_1 = require("../index");
6
+ function isOracleValid(amm, oraclePriceData, oracleGuardRails, slot) {
7
+ const isOraclePriceNonPositive = oraclePriceData.price.lt(numericConstants_1.ZERO);
8
+ const isOraclePriceTooVolatile = oraclePriceData.price
9
+ .div(index_1.BN.max(numericConstants_1.ONE, amm.lastOraclePriceTwap))
10
+ .gt(oracleGuardRails.validity.tooVolatileRatio) ||
11
+ amm.lastOraclePriceTwap
12
+ .div(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.price))
13
+ .gt(oracleGuardRails.validity.tooVolatileRatio);
14
+ const isConfidenceTooLarge = oraclePriceData.price
15
+ .div(index_1.BN.max(numericConstants_1.ONE, oraclePriceData.confidence))
16
+ .lt(oracleGuardRails.validity.confidenceIntervalMaxSize);
17
+ const oracleIsStale = oraclePriceData.slot
18
+ .sub(new index_1.BN(slot))
19
+ .gt(oracleGuardRails.validity.slotsBeforeStale);
20
+ return !(!oraclePriceData.hasSufficientNumberOfDataPoints ||
21
+ oracleIsStale ||
22
+ isOraclePriceNonPositive ||
23
+ isOraclePriceTooVolatile ||
24
+ isConfidenceTooLarge);
25
+ }
26
+ exports.isOracleValid = isOracleValid;
@@ -8,6 +8,8 @@ export declare type PriceImpactUnit = 'entryPrice' | 'maxPrice' | 'priceDelta' |
8
8
  * @param direction
9
9
  * @param amount
10
10
  * @param market
11
+ * @param inputAssetType which asset is being traded
12
+ * @param useSpread whether to consider spread with calculating slippage
11
13
  * @return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]
12
14
  *
13
15
  * 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision MARK_PRICE_PRECISION
@@ -18,7 +20,7 @@ export declare type PriceImpactUnit = 'entryPrice' | 'maxPrice' | 'priceDelta' |
18
20
  *
19
21
  * 'newPrice' => the price of the asset after the trade : Precision MARK_PRICE_PRECISION
20
22
  */
21
- export declare function calculateTradeSlippage(direction: PositionDirection, amount: BN, market: Market, inputAssetType?: AssetType): [BN, BN, BN, BN];
23
+ export declare function calculateTradeSlippage(direction: PositionDirection, amount: BN, market: Market, inputAssetType?: AssetType, useSpread?: boolean): [BN, BN, BN, BN];
22
24
  /**
23
25
  * Calculates acquired amounts for trade executed
24
26
  * @param direction
@@ -27,7 +29,7 @@ export declare function calculateTradeSlippage(direction: PositionDirection, amo
27
29
  * @param inputAssetType
28
30
  * @param useSpread
29
31
  * @return
30
- * | 'acquiredBase' => positive/negative change in user's base : BN TODO-PRECISION
32
+ * | 'acquiredBase' => positive/negative change in user's base : BN AMM_RESERVE_PRECISION
31
33
  * | 'acquiredQuote' => positive/negative change in user's quote : BN TODO-PRECISION
32
34
  */
33
35
  export declare function calculateTradeAcquiredAmounts(direction: PositionDirection, amount: BN, market: Market, inputAssetType?: AssetType, useSpread?: boolean): [BN, BN];
@@ -37,13 +39,15 @@ export declare function calculateTradeAcquiredAmounts(direction: PositionDirecti
37
39
  * @param market
38
40
  * @param targetPrice
39
41
  * @param pct optional default is 100% gap filling, can set smaller.
42
+ * @param outputAssetType which asset to trade.
43
+ * @param useSpread whether or not to consider the spread when calculating the trade size
40
44
  * @returns trade direction/size in order to push price to a targetPrice,
41
45
  *
42
46
  * [
43
- * direction => direction of trade required, TODO-PRECISION
47
+ * direction => direction of trade required, PositionDirection
44
48
  * tradeSize => size of trade required, TODO-PRECISION
45
- * entryPrice => the entry price for the trade, TODO-PRECISION
46
- * targetPrice => the target price TODO-PRECISION
49
+ * entryPrice => the entry price for the trade, MARK_PRICE_PRECISION
50
+ * targetPrice => the target price MARK_PRICE_PRECISION
47
51
  * ]
48
52
  */
49
- export declare function calculateTargetPriceTrade(market: Market, targetPrice: BN, pct?: BN, outputAssetType?: AssetType): [PositionDirection, BN, BN, BN];
53
+ export declare function calculateTargetPriceTrade(market: Market, targetPrice: BN, pct?: BN, outputAssetType?: AssetType, useSpread?: boolean): [PositionDirection, BN, BN, BN];
package/lib/math/trade.js CHANGED
@@ -8,12 +8,15 @@ const numericConstants_1 = require("../constants/numericConstants");
8
8
  const market_1 = require("./market");
9
9
  const amm_1 = require("./amm");
10
10
  const utils_1 = require("./utils");
11
+ const types_2 = require("../types");
11
12
  const MAXPCT = new anchor_1.BN(1000); //percentage units are [0,1000] => [0,1]
12
13
  /**
13
14
  * Calculates avg/max slippage (price impact) for candidate trade
14
15
  * @param direction
15
16
  * @param amount
16
17
  * @param market
18
+ * @param inputAssetType which asset is being traded
19
+ * @param useSpread whether to consider spread with calculating slippage
17
20
  * @return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]
18
21
  *
19
22
  * 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision MARK_PRICE_PRECISION
@@ -24,14 +27,38 @@ const MAXPCT = new anchor_1.BN(1000); //percentage units are [0,1000] => [0,1]
24
27
  *
25
28
  * 'newPrice' => the price of the asset after the trade : Precision MARK_PRICE_PRECISION
26
29
  */
27
- function calculateTradeSlippage(direction, amount, market, inputAssetType = 'quote') {
28
- const oldPrice = (0, market_1.calculateMarkPrice)(market);
30
+ function calculateTradeSlippage(direction, amount, market, inputAssetType = 'quote', useSpread = true) {
31
+ let oldPrice;
32
+ if (useSpread && market.amm.baseSpread > 0) {
33
+ if ((0, types_2.isVariant)(direction, 'long')) {
34
+ oldPrice = (0, market_1.calculateAskPrice)(market);
35
+ }
36
+ else {
37
+ oldPrice = (0, market_1.calculateBidPrice)(market);
38
+ }
39
+ }
40
+ else {
41
+ oldPrice = (0, market_1.calculateMarkPrice)(market);
42
+ }
29
43
  if (amount.eq(numericConstants_1.ZERO)) {
30
44
  return [numericConstants_1.ZERO, numericConstants_1.ZERO, oldPrice, oldPrice];
31
45
  }
32
- const [acquiredBase, acquiredQuote] = calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType);
46
+ const [acquiredBase, acquiredQuote] = calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType, useSpread);
33
47
  const entryPrice = (0, amm_1.calculatePrice)(acquiredBase, acquiredQuote, market.amm.pegMultiplier).mul(new anchor_1.BN(-1));
34
- const newPrice = (0, amm_1.calculatePrice)(market.amm.baseAssetReserve.sub(acquiredBase), market.amm.quoteAssetReserve.sub(acquiredQuote), market.amm.pegMultiplier);
48
+ let amm;
49
+ if (useSpread && market.amm.baseSpread > 0) {
50
+ const { baseAssetReserve, quoteAssetReserve } = (0, amm_1.calculateSpreadReserves)(market.amm, direction);
51
+ amm = {
52
+ baseAssetReserve,
53
+ quoteAssetReserve,
54
+ sqrtK: market.amm.sqrtK,
55
+ pegMultiplier: market.amm.pegMultiplier,
56
+ };
57
+ }
58
+ else {
59
+ amm = market.amm;
60
+ }
61
+ const newPrice = (0, amm_1.calculatePrice)(amm.baseAssetReserve.sub(acquiredBase), amm.quoteAssetReserve.sub(acquiredQuote), amm.pegMultiplier);
35
62
  if (direction == types_1.PositionDirection.SHORT) {
36
63
  (0, assert_1.assert)(newPrice.lt(oldPrice));
37
64
  }
@@ -59,7 +86,7 @@ exports.calculateTradeSlippage = calculateTradeSlippage;
59
86
  * @param inputAssetType
60
87
  * @param useSpread
61
88
  * @return
62
- * | 'acquiredBase' => positive/negative change in user's base : BN TODO-PRECISION
89
+ * | 'acquiredBase' => positive/negative change in user's base : BN AMM_RESERVE_PRECISION
63
90
  * | 'acquiredQuote' => positive/negative change in user's quote : BN TODO-PRECISION
64
91
  */
65
92
  function calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType = 'quote', useSpread = true) {
@@ -92,35 +119,50 @@ exports.calculateTradeAcquiredAmounts = calculateTradeAcquiredAmounts;
92
119
  * @param market
93
120
  * @param targetPrice
94
121
  * @param pct optional default is 100% gap filling, can set smaller.
122
+ * @param outputAssetType which asset to trade.
123
+ * @param useSpread whether or not to consider the spread when calculating the trade size
95
124
  * @returns trade direction/size in order to push price to a targetPrice,
96
125
  *
97
126
  * [
98
- * direction => direction of trade required, TODO-PRECISION
127
+ * direction => direction of trade required, PositionDirection
99
128
  * tradeSize => size of trade required, TODO-PRECISION
100
- * entryPrice => the entry price for the trade, TODO-PRECISION
101
- * targetPrice => the target price TODO-PRECISION
129
+ * entryPrice => the entry price for the trade, MARK_PRICE_PRECISION
130
+ * targetPrice => the target price MARK_PRICE_PRECISION
102
131
  * ]
103
132
  */
104
- function calculateTargetPriceTrade(market, targetPrice, pct = MAXPCT, outputAssetType = 'quote') {
133
+ function calculateTargetPriceTrade(market, targetPrice, pct = MAXPCT, outputAssetType = 'quote', useSpread = true) {
105
134
  (0, assert_1.assert)(market.amm.baseAssetReserve.gt(numericConstants_1.ZERO));
106
135
  (0, assert_1.assert)(targetPrice.gt(numericConstants_1.ZERO));
107
136
  (0, assert_1.assert)(pct.lte(MAXPCT) && pct.gt(numericConstants_1.ZERO));
108
137
  const markPriceBefore = (0, market_1.calculateMarkPrice)(market);
138
+ const bidPriceBefore = (0, market_1.calculateBidPrice)(market);
139
+ const askPriceBefore = (0, market_1.calculateAskPrice)(market);
140
+ let direction;
109
141
  if (targetPrice.gt(markPriceBefore)) {
110
142
  const priceGap = targetPrice.sub(markPriceBefore);
111
143
  const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
112
144
  targetPrice = markPriceBefore.add(priceGapScaled);
145
+ direction = types_1.PositionDirection.LONG;
113
146
  }
114
147
  else {
115
148
  const priceGap = markPriceBefore.sub(targetPrice);
116
149
  const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
117
150
  targetPrice = markPriceBefore.sub(priceGapScaled);
151
+ direction = types_1.PositionDirection.SHORT;
118
152
  }
119
- let direction;
120
153
  let tradeSize;
121
154
  let baseSize;
122
- const baseAssetReserveBefore = market.amm.baseAssetReserve;
123
- const quoteAssetReserveBefore = market.amm.quoteAssetReserve;
155
+ let baseAssetReserveBefore;
156
+ let quoteAssetReserveBefore;
157
+ if (useSpread && market.amm.baseSpread > 0) {
158
+ const { baseAssetReserve, quoteAssetReserve } = (0, amm_1.calculateSpreadReserves)(market.amm, direction);
159
+ baseAssetReserveBefore = baseAssetReserve;
160
+ quoteAssetReserveBefore = quoteAssetReserve;
161
+ }
162
+ else {
163
+ baseAssetReserveBefore = market.amm.baseAssetReserve;
164
+ quoteAssetReserveBefore = market.amm.quoteAssetReserve;
165
+ }
124
166
  const peg = market.amm.pegMultiplier;
125
167
  const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
126
168
  const k = invariant.mul(numericConstants_1.MARK_PRICE_PRECISION);
@@ -128,7 +170,20 @@ function calculateTargetPriceTrade(market, targetPrice, pct = MAXPCT, outputAsse
128
170
  let quoteAssetReserveAfter;
129
171
  const biasModifier = new anchor_1.BN(1);
130
172
  let markPriceAfter;
131
- if (markPriceBefore.gt(targetPrice)) {
173
+ if (useSpread &&
174
+ targetPrice.lt(askPriceBefore) &&
175
+ targetPrice.gt(bidPriceBefore)) {
176
+ // no trade, market is at target
177
+ if (markPriceBefore.gt(targetPrice)) {
178
+ direction = types_1.PositionDirection.SHORT;
179
+ }
180
+ else {
181
+ direction = types_1.PositionDirection.LONG;
182
+ }
183
+ tradeSize = numericConstants_1.ZERO;
184
+ return [direction, tradeSize, targetPrice, targetPrice];
185
+ }
186
+ else if (markPriceBefore.gt(targetPrice)) {
132
187
  // overestimate y2
133
188
  baseAssetReserveAfter = (0, utils_1.squareRootBN)(k.div(targetPrice).mul(peg).div(numericConstants_1.PEG_PRECISION).sub(biasModifier)).sub(new anchor_1.BN(1));
134
189
  quoteAssetReserveAfter = k
@@ -1,6 +1,6 @@
1
1
  /// <reference types="bn.js" />
2
2
  import * as anchor from '@project-serum/anchor';
3
- import { Program, Provider } from '@project-serum/anchor';
3
+ import { AnchorProvider, Program } from '@project-serum/anchor';
4
4
  import { AccountInfo } from '@solana/spl-token';
5
5
  import { ConfirmOptions, Connection, PublicKey, TransactionInstruction, TransactionSignature } from '@solana/web3.js';
6
6
  import { BN } from '.';
@@ -9,7 +9,7 @@ export declare class MockUSDCFaucet {
9
9
  connection: Connection;
10
10
  wallet: IWallet;
11
11
  program: Program;
12
- provider: Provider;
12
+ provider: AnchorProvider;
13
13
  opts?: ConfirmOptions;
14
14
  constructor(connection: Connection, wallet: IWallet, programId: PublicKey, opts?: ConfirmOptions);
15
15
  getMockUSDCFaucetStatePublicKeyAndNonce(): Promise<[
@@ -45,8 +45,8 @@ class MockUSDCFaucet {
45
45
  constructor(connection, wallet, programId, opts) {
46
46
  this.connection = connection;
47
47
  this.wallet = wallet;
48
- this.opts = opts || anchor_1.Provider.defaultOptions();
49
- const provider = new anchor_1.Provider(connection, wallet, this.opts);
48
+ this.opts = opts || anchor_1.AnchorProvider.defaultOptions();
49
+ const provider = new anchor_1.AnchorProvider(connection, wallet, this.opts);
50
50
  this.provider = provider;
51
51
  this.program = new anchor_1.Program(mock_usdc_faucet_json_1.default, programId, provider);
52
52
  }
@@ -117,7 +117,7 @@ class MockUSDCFaucet {
117
117
  return __awaiter(this, void 0, void 0, function* () {
118
118
  const [associatedTokenPublicKey, createAssociatedAccountIx, mintToTx] = yield this.createAssociatedTokenAccountAndMintToInstructions(userPublicKey, amount);
119
119
  const tx = new web3_js_1.Transaction().add(createAssociatedAccountIx).add(mintToTx);
120
- const txSig = yield this.program.provider.send(tx, [], this.opts);
120
+ const txSig = yield this.program.provider.sendAndConfirm(tx, [], this.opts);
121
121
  return [associatedTokenPublicKey, txSig];
122
122
  });
123
123
  }
@@ -38,6 +38,7 @@ class PythClient {
38
38
  confidence: convertPythPrice(priceData.confidence, priceData.exponent),
39
39
  twap: convertPythPrice(priceData.twap.value, priceData.exponent),
40
40
  twapConfidence: convertPythPrice(priceData.twac.value, priceData.exponent),
41
+ hasSufficientNumberOfDataPoints: true,
41
42
  };
42
43
  });
43
44
  }
@@ -39,11 +39,14 @@ class SwitchboardClient {
39
39
  const price = convertSwitchboardDecimal(aggregatorAccountData.latestConfirmedRound.result);
40
40
  const confidence = convertSwitchboardDecimal(aggregatorAccountData.latestConfirmedRound
41
41
  .stdDeviation);
42
+ const hasSufficientNumberOfDataPoints = aggregatorAccountData.latestConfirmedRound.numSuccess >=
43
+ aggregatorAccountData.minOracleResults;
42
44
  const slot = aggregatorAccountData.latestConfirmedRound.roundOpenSlot;
43
45
  return {
44
46
  price,
45
47
  slot,
46
48
  confidence,
49
+ hasSufficientNumberOfDataPoints,
47
50
  };
48
51
  });
49
52
  }
@@ -64,7 +67,7 @@ function getSwitchboardProgram(env, connection) {
64
67
  const DEFAULT_KEYPAIR = web3_js_1.Keypair.fromSeed(new Uint8Array(32).fill(1));
65
68
  const programId = (0, switchboard_v2_1.getSwitchboardPid)(env);
66
69
  const wallet = new wallet_1.Wallet(DEFAULT_KEYPAIR);
67
- const provider = new anchor_1.Provider(connection, wallet, {});
70
+ const provider = new anchor_1.AnchorProvider(connection, wallet, {});
68
71
  return new anchor_1.Program(switchboard_v2_json_1.default, programId, provider);
69
72
  });
70
73
  }
@@ -6,6 +6,7 @@ export declare type OraclePriceData = {
6
6
  price: BN;
7
7
  slot: BN;
8
8
  confidence: BN;
9
+ hasSufficientNumberOfDataPoints: boolean;
9
10
  twap?: BN;
10
11
  twapConfidence?: BN;
11
12
  };
@@ -1,8 +1,8 @@
1
1
  import { TxSender } from './types';
2
2
  import { ConfirmOptions, Signer, Transaction, TransactionSignature } from '@solana/web3.js';
3
- import { Provider } from '@project-serum/anchor';
3
+ import { AnchorProvider } from '@project-serum/anchor';
4
4
  export declare class DefaultTxSender implements TxSender {
5
- provider: Provider;
6
- constructor(provider: Provider);
5
+ provider: AnchorProvider;
6
+ constructor(provider: AnchorProvider);
7
7
  send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<TransactionSignature>;
8
8
  }
@@ -6,7 +6,7 @@ class DefaultTxSender {
6
6
  this.provider = provider;
7
7
  }
8
8
  send(tx, additionalSigners, opts) {
9
- return this.provider.send(tx, additionalSigners, opts);
9
+ return this.provider.sendAndConfirm(tx, additionalSigners, opts);
10
10
  }
11
11
  }
12
12
  exports.DefaultTxSender = DefaultTxSender;