@drift-labs/sdk 0.1.2 → 0.1.8

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  <p>
7
7
  <a href="https://www.npmjs.com/package/@drift-labs/sdk"><img alt="SDK npm package" src="https://img.shields.io/npm/v/@drift-labs/sdk" /></a>
8
- <a href="https://docs.drift.trade/drift-sdk-documentation"><img alt="Docs" src="https://img.shields.io/badge/docs-tutorials-blueviolet" /></a>
8
+ <a href="https://drift-labs.github.io/protocol-v1/sdk/"><img alt="Docs" src="https://img.shields.io/badge/docs-tutorials-blueviolet" /></a>
9
9
  <a href="https://discord.com/channels/849494028176588802/878700556904980500"><img alt="Discord Chat" src="https://img.shields.io/discord/889577356681945098?color=blueviolet" /></a>
10
10
  <a href="https://opensource.org/licenses/Apache-2.0"><img alt="License" src="https://img.shields.io/github/license/project-serum/anchor?color=blueviolet" /></a>
11
11
  </p>
@@ -17,7 +17,7 @@ This repository provides open source access to Drift's Typescript SDK, Solana Pr
17
17
 
18
18
  # SDK Guide
19
19
 
20
- More of the SDK docs can be found on Drift's dedicated Docs hosted [here](https://docs.drift.trade/drift-sdk-documentation), and technical documentation of the SDK's code can be found [here](https://drift-labs.github.io/sdk/).
20
+ The technical documentation for the SDK can be found [here](https://drift-labs.github.io/protocol-v1/sdk/), and you can visit Drift's general purpose documentation [here](https://docs.drift.trade/drift-sdk-documentation).
21
21
 
22
22
  ## Installation
23
23
 
@@ -38,7 +38,7 @@ solana address
38
38
 
39
39
  # Put the private key into your .env to be used by your bot
40
40
  cd {projectLocation}
41
- echo BOT_PRIVATE_KEY=`cat /Users/lukesteyn/.config/solana/id.json` >> .env
41
+ echo BOT_PRIVATE_KEY=`cat ~/.config/solana/id.json` >> .env
42
42
  ```
43
43
 
44
44
  ## Concepts
@@ -64,16 +64,19 @@ The Drift SDK uses some common precisions, which are available as constants to i
64
64
 
65
65
  **Important Note for BigNum division**
66
66
 
67
- Because BN only supports integers, you need to be conscious of the numbers you are using when dividing. BN will always take the floor of the division, if you want to get the exact divison, you need to add the modulus of the two numbers as well. There is a helper function `convertToNumber` in the SDK which will do this for you.
67
+ Because BN only supports integers, you need to be conscious of the numbers you are using when dividing. BN will return the floor when using the regular division function; if you want to get the exact divison, you need to add the modulus of the two numbers as well. There is a helper function `convertToNumber` in the SDK which will do this for you.
68
68
 
69
- ```
70
- Example:
69
+ ```typescript
70
+ import {convertToNumber} from @drift-labs/sdk
71
71
 
72
72
  // Gets the floor value
73
73
  new BN(10500).div(new BN(1000)).toNumber(); // = 10
74
74
 
75
75
  // Gets the exact value
76
76
  new BN(10500).div(new BN(1000)).toNumber() + BN(10500).mod(new BN(1000)).toNumber(); // = 10.5
77
+
78
+ // Also gets the exact value
79
+ convertToNumber(new BN(10500), new BN(1000)); // = 10.5
77
80
  ```
78
81
 
79
82
  ## Examples
package/lib/admin.d.ts CHANGED
@@ -6,7 +6,7 @@ import { ClearingHouse } from './clearingHouse';
6
6
  export declare class Admin extends ClearingHouse {
7
7
  static from(connection: Connection, wallet: IWallet, clearingHouseProgramId: PublicKey, opts?: ConfirmOptions): Admin;
8
8
  initialize(usdcMint: PublicKey, adminControlsPrices: boolean): Promise<[TransactionSignature, TransactionSignature]>;
9
- initializeMarket(marketIndex: BN, priceOracle: PublicKey, baseAmount: BN, quoteAmount: BN, periodicity: BN, pegMultiplier?: BN): Promise<TransactionSignature>;
9
+ initializeMarket(marketIndex: BN, priceOracle: PublicKey, baseAssetReserve: BN, quoteAssetReserve: BN, periodicity: BN, pegMultiplier?: BN): Promise<TransactionSignature>;
10
10
  moveAmmPrice(baseAssetReserve: BN, quoteAssetReserve: BN, marketIndex: BN): Promise<TransactionSignature>;
11
11
  updateK(sqrtK: BN, marketIndex: BN): Promise<TransactionSignature>;
12
12
  moveAmmToPrice(marketIndex: BN, targetPrice: BN): Promise<TransactionSignature>;
package/lib/admin.js CHANGED
@@ -122,12 +122,12 @@ class Admin extends clearingHouse_1.ClearingHouse {
122
122
  return [initializeTxSig, initializeHistoryTxSig];
123
123
  });
124
124
  }
125
- initializeMarket(marketIndex, priceOracle, baseAmount, quoteAmount, periodicity, pegMultiplier = numericConstants_1.PEG_PRECISION) {
125
+ initializeMarket(marketIndex, priceOracle, baseAssetReserve, quoteAssetReserve, periodicity, pegMultiplier = numericConstants_1.PEG_PRECISION) {
126
126
  return __awaiter(this, void 0, void 0, function* () {
127
127
  if (this.getMarketsAccount().markets[marketIndex.toNumber()].initialized) {
128
128
  throw Error(`MarketIndex ${marketIndex.toNumber()} already initialized`);
129
129
  }
130
- const initializeMarketTx = yield this.program.transaction.initializeMarket(marketIndex, baseAmount, quoteAmount, periodicity, pegMultiplier, {
130
+ const initializeMarketTx = yield this.program.transaction.initializeMarket(marketIndex, baseAssetReserve, quoteAssetReserve, periodicity, pegMultiplier, {
131
131
  accounts: {
132
132
  state: yield this.getStatePublicKey(),
133
133
  admin: this.wallet.publicKey,
@@ -72,7 +72,7 @@ export declare class ClearingHouseUser {
72
72
  * calculates average exit price for closing 100% of position
73
73
  * @returns : Precision MARK_PRICE_PRECISION
74
74
  */
75
- getPositionEstimatedExitPrice(position: UserPosition): BN;
75
+ getPositionEstimatedExitPrice(position: UserPosition, amountToClose?: BN): BN;
76
76
  /**
77
77
  * calculates current user leverage across all positions
78
78
  * @returns : Precision TEN_THOUSAND
@@ -60,7 +60,13 @@ class ClearingHouseUser {
60
60
  * @returns userPosition
61
61
  */
62
62
  getUserPosition(marketIndex) {
63
- return this.getUserPositionsAccount().positions.find((position) => position.marketIndex.eq(marketIndex));
63
+ var _a;
64
+ return ((_a = this.getUserPositionsAccount().positions.find((position) => position.marketIndex.eq(marketIndex))) !== null && _a !== void 0 ? _a : {
65
+ baseAssetAmount: numericConstants_1.ZERO,
66
+ lastCumulativeFundingRate: numericConstants_1.ZERO,
67
+ marketIndex,
68
+ quoteAssetAmount: numericConstants_1.ZERO,
69
+ });
64
70
  }
65
71
  getUserAccountPublicKey() {
66
72
  return __awaiter(this, void 0, void 0, function* () {
@@ -158,8 +164,19 @@ class ClearingHouseUser {
158
164
  * calculates average exit price for closing 100% of position
159
165
  * @returns : Precision MARK_PRICE_PRECISION
160
166
  */
161
- getPositionEstimatedExitPrice(position) {
167
+ getPositionEstimatedExitPrice(position, amountToClose) {
162
168
  const market = this.clearingHouse.getMarket(position.marketIndex);
169
+ if (amountToClose) {
170
+ if (amountToClose.eq(numericConstants_1.ZERO)) {
171
+ return _1.calculateMarkPrice(market);
172
+ }
173
+ position = {
174
+ baseAssetAmount: amountToClose,
175
+ lastCumulativeFundingRate: position.lastCumulativeFundingRate,
176
+ marketIndex: position.marketIndex,
177
+ quoteAssetAmount: position.quoteAssetAmount,
178
+ };
179
+ }
163
180
  const baseAssetValue = _1.calculateBaseAssetValue(market, position);
164
181
  if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
165
182
  return numericConstants_1.ZERO;
package/lib/config.js CHANGED
@@ -5,7 +5,7 @@ exports.configs = {
5
5
  devnet: {
6
6
  ENV: 'devnet',
7
7
  PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
8
- CLEARING_HOUSE_PROGRAM_ID: 'tCyWBVHtN4iGtZWs2dkefWk38SyN4RGtED14KzUopK9',
8
+ CLEARING_HOUSE_PROGRAM_ID: 'AsW7LnXB9UA1uec9wi9MctYTgTz7YH9snhxd16GsFaGX',
9
9
  USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
10
10
  },
11
11
  'mainnet-beta': {
@@ -13,20 +13,20 @@ exports.Markets = [
13
13
  devnetPythOracle: 'J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix',
14
14
  mainnetPythOracle: 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG',
15
15
  },
16
- // {
17
- // symbol: 'BTC-PERP',
18
- // baseAssetSymbol: 'BTC',
19
- // marketIndex: new BN(1),
20
- // devnetPythOracle: 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J',
21
- // mainnetPythOracle: 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU',
22
- // },
23
- // {
24
- // symbol: 'ETH-PERP',
25
- // baseAssetSymbol: 'ETH',
26
- // marketIndex: new BN(2),
27
- // devnetPythOracle: 'EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw',
28
- // mainnetPythOracle: 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB',
29
- // },
16
+ {
17
+ symbol: 'BTC-PERP',
18
+ baseAssetSymbol: 'BTC',
19
+ marketIndex: new bn_js_1.default(1),
20
+ devnetPythOracle: 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J',
21
+ mainnetPythOracle: 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU',
22
+ },
23
+ {
24
+ symbol: 'ETH-PERP',
25
+ baseAssetSymbol: 'ETH',
26
+ marketIndex: new bn_js_1.default(2),
27
+ devnetPythOracle: 'EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw',
28
+ mainnetPythOracle: 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB',
29
+ },
30
30
  // {
31
31
  // symbol: 'COPE-PERP',
32
32
  // baseAssetSymbol: 'COPE',
@@ -1724,6 +1724,34 @@
1724
1724
  }
1725
1725
  ],
1726
1726
  "types": [
1727
+ {
1728
+ "name": "InitializeUserOptionalAccounts",
1729
+ "type": {
1730
+ "kind": "struct",
1731
+ "fields": [
1732
+ {
1733
+ "name": "whitelistToken",
1734
+ "type": "bool"
1735
+ }
1736
+ ]
1737
+ }
1738
+ },
1739
+ {
1740
+ "name": "ManagePositionOptionalAccounts",
1741
+ "type": {
1742
+ "kind": "struct",
1743
+ "fields": [
1744
+ {
1745
+ "name": "discountToken",
1746
+ "type": "bool"
1747
+ },
1748
+ {
1749
+ "name": "referrer",
1750
+ "type": "bool"
1751
+ }
1752
+ ]
1753
+ }
1754
+ },
1727
1755
  {
1728
1756
  "name": "CurveRecord",
1729
1757
  "type": {
@@ -1938,34 +1966,6 @@
1938
1966
  ]
1939
1967
  }
1940
1968
  },
1941
- {
1942
- "name": "InitializeUserOptionalAccounts",
1943
- "type": {
1944
- "kind": "struct",
1945
- "fields": [
1946
- {
1947
- "name": "whitelistToken",
1948
- "type": "bool"
1949
- }
1950
- ]
1951
- }
1952
- },
1953
- {
1954
- "name": "ManagePositionOptionalAccounts",
1955
- "type": {
1956
- "kind": "struct",
1957
- "fields": [
1958
- {
1959
- "name": "discountToken",
1960
- "type": "bool"
1961
- },
1962
- {
1963
- "name": "referrer",
1964
- "type": "bool"
1965
- }
1966
- ]
1967
- }
1968
- },
1969
1969
  {
1970
1970
  "name": "LiquidationRecord",
1971
1971
  "type": {
@@ -2757,6 +2757,11 @@
2757
2757
  "code": 337,
2758
2758
  "name": "InvalidFundingProfitability",
2759
2759
  "msg": "AMM funding out of bounds pnl"
2760
+ },
2761
+ {
2762
+ "code": 338,
2763
+ "name": "CastingFailure",
2764
+ "msg": "Casting Failure"
2760
2765
  }
2761
2766
  ]
2762
2767
  }
@@ -2,6 +2,14 @@
2
2
  import { BN } from '@project-serum/anchor';
3
3
  import { PythClient } from '../pythClient';
4
4
  import { Market } from '../types';
5
+ /**
6
+ *
7
+ * @param market
8
+ * @param pythClient
9
+ * @param periodAdjustment
10
+ * @returns Estimated funding rate. : Precision //TODO-PRECISION
11
+ */
12
+ export declare function calculateAllEstimatedFundingRate(market: Market, pythClient: PythClient, periodAdjustment?: BN): Promise<[BN, BN, BN]>;
5
13
  /**
6
14
  *
7
15
  * @param market
@@ -10,4 +18,19 @@ import { Market } from '../types';
10
18
  * @param estimationMethod
11
19
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
12
20
  */
13
- export declare function calculateEstimatedFundingRate(market: Market, pythClient: PythClient, periodAdjustment: BN, estimationMethod: 'interpolated' | 'lowerbound'): Promise<BN>;
21
+ export declare function calculateEstimatedFundingRate(market: Market, pythClient: PythClient, periodAdjustment: BN, estimationMethod: 'interpolated' | 'lowerbound' | 'capped'): Promise<BN>;
22
+ /**
23
+ *
24
+ * @param market
25
+ * @param pythClient
26
+ * @param periodAdjustment
27
+ * @param estimationMethod
28
+ * @returns Estimated funding rate. : Precision //TODO-PRECISION
29
+ */
30
+ export declare function calculateLongShortFundingRate(market: Market, pythClient: PythClient, periodAdjustment?: BN): Promise<[BN, BN]>;
31
+ /**
32
+ *
33
+ * @param market
34
+ * @returns Estimated fee pool size
35
+ */
36
+ export declare function calculateFundingPool(market: Market): BN;
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.calculateEstimatedFundingRate = void 0;
12
+ exports.calculateFundingPool = exports.calculateLongShortFundingRate = exports.calculateEstimatedFundingRate = exports.calculateAllEstimatedFundingRate = void 0;
13
13
  const anchor_1 = require("@project-serum/anchor");
14
14
  const numericConstants_1 = require("../constants/numericConstants");
15
15
  const market_1 = require("./market");
@@ -18,10 +18,9 @@ const market_1 = require("./market");
18
18
  * @param market
19
19
  * @param pythClient
20
20
  * @param periodAdjustment
21
- * @param estimationMethod
22
21
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
23
22
  */
24
- function calculateEstimatedFundingRate(market, pythClient, periodAdjustment = new anchor_1.BN(1), estimationMethod) {
23
+ function calculateAllEstimatedFundingRate(market, pythClient, periodAdjustment = new anchor_1.BN(1)) {
25
24
  return __awaiter(this, void 0, void 0, function* () {
26
25
  // periodAdjustment
27
26
  // 1: hourly
@@ -30,7 +29,7 @@ function calculateEstimatedFundingRate(market, pythClient, periodAdjustment = ne
30
29
  const secondsInHour = new anchor_1.BN(3600);
31
30
  const hoursInDay = new anchor_1.BN(24);
32
31
  if (!market.initialized) {
33
- return new anchor_1.BN(0);
32
+ return [new anchor_1.BN(0), new anchor_1.BN(0), new anchor_1.BN(0)];
34
33
  }
35
34
  const payFreq = new anchor_1.BN(market.amm.fundingPeriod);
36
35
  const oraclePriceData = yield pythClient.getPriceData(market.amm.oracle);
@@ -51,19 +50,116 @@ function calculateEstimatedFundingRate(market, pythClient, periodAdjustment = ne
51
50
  .mul(numericConstants_1.MARK_PRICE_PRECISION)
52
51
  .mul(new anchor_1.BN(100))
53
52
  .div(oracleTwapWithMantissa);
53
+ const lowerboundEst = twapSpreadPct
54
+ .mul(payFreq)
55
+ .mul(anchor_1.BN.min(secondsInHour, timeSinceLastUpdate))
56
+ .mul(periodAdjustment)
57
+ .div(secondsInHour)
58
+ .div(secondsInHour)
59
+ .div(hoursInDay);
60
+ const interpEst = twapSpreadPct.mul(periodAdjustment).div(hoursInDay);
61
+ const interpRateQuote = twapSpreadPct.mul(periodAdjustment).div(hoursInDay)
62
+ .div(numericConstants_1.MARK_PRICE_PRECISION.div(numericConstants_1.QUOTE_PRECISION));
63
+ let feePoolSize = calculateFundingPool(market);
64
+ if (interpRateQuote.lt(new anchor_1.BN(0))) {
65
+ feePoolSize = feePoolSize.mul(new anchor_1.BN(-1));
66
+ }
67
+ let cappedAltEst;
68
+ let largerSide;
69
+ let smallerSide;
70
+ if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort)) {
71
+ largerSide = market.baseAssetAmountLong.abs();
72
+ smallerSide = market.baseAssetAmountShort.abs();
73
+ if (twapSpread.gt(new anchor_1.BN(0))) {
74
+ return [lowerboundEst, interpEst, interpEst];
75
+ }
76
+ }
77
+ else if (market.baseAssetAmountLong.lt(market.baseAssetAmountShort)) {
78
+ largerSide = market.baseAssetAmountShort.abs();
79
+ smallerSide = market.baseAssetAmountLong.abs();
80
+ if (twapSpread.lt(new anchor_1.BN(0))) {
81
+ return [lowerboundEst, interpEst, interpEst];
82
+ }
83
+ }
84
+ else {
85
+ return [lowerboundEst, interpEst, interpEst];
86
+ }
87
+ if (largerSide.gt(numericConstants_1.ZERO)) {
88
+ cappedAltEst = smallerSide.mul(twapSpread).div(largerSide);
89
+ const feePoolTopOff = feePoolSize.mul(numericConstants_1.MARK_PRICE_PRECISION.div(numericConstants_1.QUOTE_PRECISION))
90
+ .mul(numericConstants_1.AMM_RESERVE_PRECISION).div(largerSide);
91
+ cappedAltEst = cappedAltEst.add(feePoolTopOff);
92
+ cappedAltEst = cappedAltEst.mul(numericConstants_1.MARK_PRICE_PRECISION)
93
+ .mul(new anchor_1.BN(100))
94
+ .div(oracleTwapWithMantissa)
95
+ .mul(periodAdjustment).div(hoursInDay);
96
+ if (cappedAltEst.abs().gt(interpEst.abs())) {
97
+ cappedAltEst = interpEst;
98
+ }
99
+ }
100
+ else {
101
+ cappedAltEst = interpEst;
102
+ }
103
+ return [lowerboundEst, cappedAltEst, interpEst];
104
+ });
105
+ }
106
+ exports.calculateAllEstimatedFundingRate = calculateAllEstimatedFundingRate;
107
+ /**
108
+ *
109
+ * @param market
110
+ * @param pythClient
111
+ * @param periodAdjustment
112
+ * @param estimationMethod
113
+ * @returns Estimated funding rate. : Precision //TODO-PRECISION
114
+ */
115
+ function calculateEstimatedFundingRate(market, pythClient, periodAdjustment = new anchor_1.BN(1), estimationMethod) {
116
+ return __awaiter(this, void 0, void 0, function* () {
117
+ const [lowerboundEst, cappedAltEst, interpEst] = yield calculateAllEstimatedFundingRate(market, pythClient, periodAdjustment);
54
118
  if (estimationMethod == 'lowerbound') {
55
119
  //assuming remaining funding period has no gap
56
- return twapSpreadPct
57
- .mul(payFreq)
58
- .mul(anchor_1.BN.min(secondsInHour, timeSinceLastUpdate))
59
- .mul(periodAdjustment)
60
- .div(secondsInHour)
61
- .div(secondsInHour)
62
- .div(hoursInDay);
120
+ return lowerboundEst;
121
+ }
122
+ else if (estimationMethod == 'capped') {
123
+ return cappedAltEst;
63
124
  }
64
125
  else {
65
- return twapSpreadPct.mul(periodAdjustment).div(hoursInDay);
126
+ return interpEst;
66
127
  }
67
128
  });
68
129
  }
69
130
  exports.calculateEstimatedFundingRate = calculateEstimatedFundingRate;
131
+ /**
132
+ *
133
+ * @param market
134
+ * @param pythClient
135
+ * @param periodAdjustment
136
+ * @param estimationMethod
137
+ * @returns Estimated funding rate. : Precision //TODO-PRECISION
138
+ */
139
+ function calculateLongShortFundingRate(market, pythClient, periodAdjustment = new anchor_1.BN(1)) {
140
+ return __awaiter(this, void 0, void 0, function* () {
141
+ const [_, cappedAltEst, interpEst] = yield calculateAllEstimatedFundingRate(market, pythClient, periodAdjustment);
142
+ if (market.baseAssetAmountLong.gt(market.baseAssetAmountShort)) {
143
+ return [cappedAltEst, interpEst];
144
+ }
145
+ else if (market.baseAssetAmountLong.lt(market.baseAssetAmountShort)) {
146
+ return [interpEst, cappedAltEst];
147
+ }
148
+ else {
149
+ return [interpEst, interpEst];
150
+ }
151
+ });
152
+ }
153
+ exports.calculateLongShortFundingRate = calculateLongShortFundingRate;
154
+ /**
155
+ *
156
+ * @param market
157
+ * @returns Estimated fee pool size
158
+ */
159
+ function calculateFundingPool(market) {
160
+ const totalFeeLB = market.amm.totalFee.div(new anchor_1.BN(2));
161
+ const feePool = market.amm.totalFeeMinusDistributions.sub(totalFeeLB);
162
+ // return new BN(QUOTE_PRECISION.mul(new BN(2400)));
163
+ return feePool;
164
+ }
165
+ exports.calculateFundingPool = calculateFundingPool;
@@ -1,6 +1,7 @@
1
1
  /// <reference types="bn.js" />
2
2
  import { Market, PositionDirection } from '../types';
3
3
  import { BN } from '@project-serum/anchor';
4
+ import { AssetType } from './amm';
4
5
  export declare type PriceImpactUnit = 'entryPrice' | 'maxPrice' | 'priceDelta' | 'priceDeltaAsNumber' | 'pctAvg' | 'pctMax' | 'quoteAssetAmount' | 'quoteAssetAmountPeg' | 'acquiredBaseAssetAmount' | 'acquiredQuoteAssetAmount';
5
6
  /**
6
7
  * Calculates avg/max slippage (price impact) for candidate trade
@@ -17,7 +18,7 @@ export declare type PriceImpactUnit = 'entryPrice' | 'maxPrice' | 'priceDelta' |
17
18
  *
18
19
  * 'newPrice' => the price of the asset after the trade : Precision MARK_PRICE_PRECISION
19
20
  */
20
- export declare function calculateTradeSlippage(direction: PositionDirection, amount: BN, market: Market): [BN, BN, BN, BN];
21
+ export declare function calculateTradeSlippage(direction: PositionDirection, amount: BN, market: Market, inputAssetType?: AssetType): [BN, BN, BN, BN];
21
22
  /**
22
23
  * Calculates acquired amounts for trade executed
23
24
  * @param direction
@@ -27,7 +28,7 @@ export declare function calculateTradeSlippage(direction: PositionDirection, amo
27
28
  * | 'acquiredBase' => positive/negative change in user's base : BN TODO-PRECISION
28
29
  * | 'acquiredQuote' => positive/negative change in user's quote : BN TODO-PRECISION
29
30
  */
30
- export declare function calculateTradeAcquiredAmounts(direction: PositionDirection, amount: BN, market: Market): [BN, BN];
31
+ export declare function calculateTradeAcquiredAmounts(direction: PositionDirection, amount: BN, market: Market, inputAssetType?: AssetType): [BN, BN];
31
32
  /**
32
33
  * calculateTargetPriceTrade
33
34
  * simple function for finding arbitraging trades
package/lib/math/trade.js CHANGED
@@ -24,12 +24,12 @@ const MAXPCT = new anchor_1.BN(1000); //percentage units are [0,1000] => [0,1]
24
24
  *
25
25
  * 'newPrice' => the price of the asset after the trade : Precision MARK_PRICE_PRECISION
26
26
  */
27
- function calculateTradeSlippage(direction, amount, market) {
27
+ function calculateTradeSlippage(direction, amount, market, inputAssetType = 'quote') {
28
28
  const oldPrice = market_1.calculateMarkPrice(market);
29
29
  if (amount.eq(numericConstants_1.ZERO)) {
30
30
  return [numericConstants_1.ZERO, numericConstants_1.ZERO, oldPrice, oldPrice];
31
31
  }
32
- const [acquiredBase, acquiredQuote] = calculateTradeAcquiredAmounts(direction, amount, market);
32
+ const [acquiredBase, acquiredQuote] = calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType);
33
33
  const entryPrice = amm_1.calculatePrice(acquiredBase, acquiredQuote, market.amm.pegMultiplier).mul(new anchor_1.BN(-1));
34
34
  const newPrice = amm_1.calculatePrice(market.amm.baseAssetReserve.sub(acquiredBase), market.amm.quoteAssetReserve.sub(acquiredQuote), market.amm.pegMultiplier);
35
35
  if (direction == types_1.PositionDirection.SHORT) {
@@ -60,11 +60,11 @@ exports.calculateTradeSlippage = calculateTradeSlippage;
60
60
  * | 'acquiredBase' => positive/negative change in user's base : BN TODO-PRECISION
61
61
  * | 'acquiredQuote' => positive/negative change in user's quote : BN TODO-PRECISION
62
62
  */
63
- function calculateTradeAcquiredAmounts(direction, amount, market) {
63
+ function calculateTradeAcquiredAmounts(direction, amount, market, inputAssetType = 'quote') {
64
64
  if (amount.eq(numericConstants_1.ZERO)) {
65
65
  return [numericConstants_1.ZERO, numericConstants_1.ZERO];
66
66
  }
67
- const [newQuoteAssetReserve, newBaseAssetReserve] = amm_1.calculateAmmReservesAfterSwap(market.amm, 'quote', amount, amm_1.getSwapDirection('quote', direction));
67
+ const [newQuoteAssetReserve, newBaseAssetReserve] = amm_1.calculateAmmReservesAfterSwap(market.amm, inputAssetType, amount, amm_1.getSwapDirection(inputAssetType, direction));
68
68
  const acquiredBase = market.amm.baseAssetReserve.sub(newBaseAssetReserve);
69
69
  const acquiredQuote = market.amm.quoteAssetReserve.sub(newQuoteAssetReserve);
70
70
  return [acquiredBase, acquiredQuote];
@@ -158,6 +158,7 @@ function calculateTargetPriceTrade(market, targetPrice, pct = MAXPCT) {
158
158
  }
159
159
  const entryPrice = tradeSize
160
160
  .mul(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
161
+ .mul(numericConstants_1.MARK_PRICE_PRECISION)
161
162
  .div(baseSize.abs());
162
163
  assert_1.assert(tp1.sub(tp2).lte(originalDiff), 'Target Price Calculation incorrect');
163
164
  assert_1.assert(tp2.lte(tp1) || tp2.sub(tp1).abs() < 100000, 'Target Price Calculation incorrect' +
package/lib/types.d.ts CHANGED
@@ -241,6 +241,7 @@ export interface Trade {
241
241
  side: TradeSide;
242
242
  size: number;
243
243
  ts: number;
244
+ fee: number;
244
245
  marketIndex: number;
245
246
  chainTs: number;
246
247
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.8",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -11,10 +11,13 @@
11
11
  },
12
12
  "scripts": {
13
13
  "build": "yarn clean && tsc",
14
- "clean": "rm -rf lib"
14
+ "clean": "rm -rf lib",
15
+ "patch-and-pub": "npm version patch --force && npm publish"
15
16
  },
16
17
  "keywords": [
17
- "drift-labs", "drift", "perps"
18
+ "drift-labs",
19
+ "drift",
20
+ "perps"
18
21
  ],
19
22
  "license": "Apache-2.0",
20
23
  "directories": {
package/src/admin.ts CHANGED
@@ -178,8 +178,8 @@ export class Admin extends ClearingHouse {
178
178
  public async initializeMarket(
179
179
  marketIndex: BN,
180
180
  priceOracle: PublicKey,
181
- baseAmount: BN,
182
- quoteAmount: BN,
181
+ baseAssetReserve: BN,
182
+ quoteAssetReserve: BN,
183
183
  periodicity: BN,
184
184
  pegMultiplier: BN = PEG_PRECISION
185
185
  ): Promise<TransactionSignature> {
@@ -189,8 +189,8 @@ export class Admin extends ClearingHouse {
189
189
 
190
190
  const initializeMarketTx = await this.program.transaction.initializeMarket(
191
191
  marketIndex,
192
- baseAmount,
193
- quoteAmount,
192
+ baseAssetReserve,
193
+ quoteAssetReserve,
194
194
  periodicity,
195
195
  pegMultiplier,
196
196
  {
@@ -52,10 +52,10 @@ import { wrapInTx } from './tx/utils';
52
52
 
53
53
  /**
54
54
  * # ClearingHouse
55
- * This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
56
- *
55
+ * This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
56
+ *
57
57
  * The default way to construct a ClearingHouse instance is using the {@link from} method. This will create an instance using the static {@link DefaultClearingHouseAccountSubscriber}, which will use a websocket for each state account subscription.
58
- * Alternatively, if you want to implement your own method of subscribing to the state accounts on the blockchain, you can implement a {@link ClearingHouseAccountSubscriber} and use it in the {@link ClearingHouse.constructor}
58
+ * Alternatively, if you want to implement your own method of subscribing to the state accounts on the blockchain, you can implement a {@link ClearingHouseAccountSubscriber} and use it in the {@link ClearingHouse.constructor}
59
59
  */
60
60
  export class ClearingHouse {
61
61
  connection: Connection;
@@ -200,7 +200,7 @@ export class ClearingHouse {
200
200
 
201
201
  /**
202
202
  * Update the wallet to use for clearing house transactions and linked user account
203
- * @param newWallet
203
+ * @param newWallet
204
204
  */
205
205
  public updateWallet(newWallet: IWallet): void {
206
206
  const newProvider = new Provider(this.connection, newWallet, this.opts);
@@ -290,7 +290,7 @@ export class ClearingHouse {
290
290
  userAccountPublicKey?: PublicKey;
291
291
  /**
292
292
  * Get the address for the Clearing House User's account. NOT the user's wallet address.
293
- * @returns
293
+ * @returns
294
294
  */
295
295
  public async getUserAccountPublicKey(): Promise<PublicKey> {
296
296
  if (this.userAccountPublicKey) {
@@ -361,9 +361,9 @@ export class ClearingHouse {
361
361
 
362
362
  /**
363
363
  * Creates the Clearing House User account for a user, and deposits some initial collateral
364
- * @param amount
365
- * @param collateralAccountPublicKey
366
- * @returns
364
+ * @param amount
365
+ * @param collateralAccountPublicKey
366
+ * @returns
367
367
  */
368
368
  public async initializeUserAccountAndDepositCollateral(
369
369
  amount: BN,
@@ -568,10 +568,10 @@ export class ClearingHouse {
568
568
 
569
569
  /**
570
570
  * Close an entire position. If you want to reduce a position, use the {@link openPosition} method in the opposite direction of the current position.
571
- * @param marketIndex
572
- * @param discountToken
573
- * @param referrer
574
- * @returns
571
+ * @param marketIndex
572
+ * @param discountToken
573
+ * @param referrer
574
+ * @returns
575
575
  */
576
576
  public async closePosition(
577
577
  marketIndex: BN,
@@ -86,8 +86,15 @@ export class ClearingHouseUser {
86
86
  * @returns userPosition
87
87
  */
88
88
  public getUserPosition(marketIndex: BN): UserPosition {
89
- return this.getUserPositionsAccount().positions.find((position) =>
90
- position.marketIndex.eq(marketIndex)
89
+ return (
90
+ this.getUserPositionsAccount().positions.find((position) =>
91
+ position.marketIndex.eq(marketIndex)
92
+ ) ?? {
93
+ baseAssetAmount: ZERO,
94
+ lastCumulativeFundingRate: ZERO,
95
+ marketIndex,
96
+ quoteAssetAmount: ZERO,
97
+ }
91
98
  );
92
99
  }
93
100
 
@@ -217,8 +224,21 @@ export class ClearingHouseUser {
217
224
  * calculates average exit price for closing 100% of position
218
225
  * @returns : Precision MARK_PRICE_PRECISION
219
226
  */
220
- public getPositionEstimatedExitPrice(position: UserPosition): BN {
227
+ public getPositionEstimatedExitPrice(position: UserPosition, amountToClose?: BN): BN {
221
228
  const market = this.clearingHouse.getMarket(position.marketIndex);
229
+
230
+ if(amountToClose){
231
+ if(amountToClose.eq(ZERO)){
232
+ return calculateMarkPrice(market);
233
+ }
234
+ position = {
235
+ baseAssetAmount: amountToClose,
236
+ lastCumulativeFundingRate: position.lastCumulativeFundingRate,
237
+ marketIndex: position.marketIndex,
238
+ quoteAssetAmount: position.quoteAssetAmount,
239
+ } as UserPosition;
240
+ }
241
+
222
242
  const baseAssetValue = calculateBaseAssetValue(market, position);
223
243
  if (position.baseAssetAmount.eq(ZERO)) {
224
244
  return ZERO;
package/src/config.ts CHANGED
@@ -11,7 +11,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
11
11
  devnet: {
12
12
  ENV: 'devnet',
13
13
  PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
14
- CLEARING_HOUSE_PROGRAM_ID: 'tCyWBVHtN4iGtZWs2dkefWk38SyN4RGtED14KzUopK9',
14
+ CLEARING_HOUSE_PROGRAM_ID: 'AsW7LnXB9UA1uec9wi9MctYTgTz7YH9snhxd16GsFaGX',
15
15
  USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
16
16
  },
17
17
  'mainnet-beta': {
@@ -37,7 +37,6 @@ export const initialize = (props: {
37
37
  env: DriftEnv;
38
38
  overrideEnv?: Partial<DriftConfig>;
39
39
  }): DriftConfig => {
40
-
41
40
  //@ts-ignore
42
41
  if (props.env === 'master')
43
42
  return { ...configs['devnet'], ...(props.overrideEnv ?? {}) };
@@ -16,20 +16,20 @@ export const Markets: Market[] = [
16
16
  devnetPythOracle: 'J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix',
17
17
  mainnetPythOracle: 'H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG',
18
18
  },
19
- // {
20
- // symbol: 'BTC-PERP',
21
- // baseAssetSymbol: 'BTC',
22
- // marketIndex: new BN(1),
23
- // devnetPythOracle: 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J',
24
- // mainnetPythOracle: 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU',
25
- // },
26
- // {
27
- // symbol: 'ETH-PERP',
28
- // baseAssetSymbol: 'ETH',
29
- // marketIndex: new BN(2),
30
- // devnetPythOracle: 'EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw',
31
- // mainnetPythOracle: 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB',
32
- // },
19
+ {
20
+ symbol: 'BTC-PERP',
21
+ baseAssetSymbol: 'BTC',
22
+ marketIndex: new BN(1),
23
+ devnetPythOracle: 'HovQMDrbAgAYPCmHVSrezcSmkMtXSSUsLDFANExrZh2J',
24
+ mainnetPythOracle: 'GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU',
25
+ },
26
+ {
27
+ symbol: 'ETH-PERP',
28
+ baseAssetSymbol: 'ETH',
29
+ marketIndex: new BN(2),
30
+ devnetPythOracle: 'EdVCmQ9FSPcVe5YySXDPCRmc8aDQLKJ9xvYBMZPie1Vw',
31
+ mainnetPythOracle: 'JBu1AL4obBcCMqKBBxhpWCNUt136ijcuMZLFvTP7iWdB',
32
+ },
33
33
  // {
34
34
  // symbol: 'COPE-PERP',
35
35
  // baseAssetSymbol: 'COPE',
@@ -1724,6 +1724,34 @@
1724
1724
  }
1725
1725
  ],
1726
1726
  "types": [
1727
+ {
1728
+ "name": "InitializeUserOptionalAccounts",
1729
+ "type": {
1730
+ "kind": "struct",
1731
+ "fields": [
1732
+ {
1733
+ "name": "whitelistToken",
1734
+ "type": "bool"
1735
+ }
1736
+ ]
1737
+ }
1738
+ },
1739
+ {
1740
+ "name": "ManagePositionOptionalAccounts",
1741
+ "type": {
1742
+ "kind": "struct",
1743
+ "fields": [
1744
+ {
1745
+ "name": "discountToken",
1746
+ "type": "bool"
1747
+ },
1748
+ {
1749
+ "name": "referrer",
1750
+ "type": "bool"
1751
+ }
1752
+ ]
1753
+ }
1754
+ },
1727
1755
  {
1728
1756
  "name": "CurveRecord",
1729
1757
  "type": {
@@ -1938,34 +1966,6 @@
1938
1966
  ]
1939
1967
  }
1940
1968
  },
1941
- {
1942
- "name": "InitializeUserOptionalAccounts",
1943
- "type": {
1944
- "kind": "struct",
1945
- "fields": [
1946
- {
1947
- "name": "whitelistToken",
1948
- "type": "bool"
1949
- }
1950
- ]
1951
- }
1952
- },
1953
- {
1954
- "name": "ManagePositionOptionalAccounts",
1955
- "type": {
1956
- "kind": "struct",
1957
- "fields": [
1958
- {
1959
- "name": "discountToken",
1960
- "type": "bool"
1961
- },
1962
- {
1963
- "name": "referrer",
1964
- "type": "bool"
1965
- }
1966
- ]
1967
- }
1968
- },
1969
1969
  {
1970
1970
  "name": "LiquidationRecord",
1971
1971
  "type": {
@@ -2757,6 +2757,11 @@
2757
2757
  "code": 337,
2758
2758
  "name": "InvalidFundingProfitability",
2759
2759
  "msg": "AMM funding out of bounds pnl"
2760
+ },
2761
+ {
2762
+ "code": 338,
2763
+ "name": "CastingFailure",
2764
+ "msg": "Casting Failure"
2760
2765
  }
2761
2766
  ]
2762
2767
  }
@@ -1,6 +1,8 @@
1
1
  import { BN } from '@project-serum/anchor';
2
+ import {
3
+ AMM_RESERVE_PRECISION, MARK_PRICE_PRECISION, QUOTE_PRECISION, ZERO
4
+ } from '../constants/numericConstants';
2
5
  import { PythClient } from '../pythClient';
3
- import { MARK_PRICE_PRECISION } from '../constants/numericConstants';
4
6
  import { Market } from '../types';
5
7
  import { calculateMarkPrice } from './market';
6
8
 
@@ -9,15 +11,13 @@ import { calculateMarkPrice } from './market';
9
11
  * @param market
10
12
  * @param pythClient
11
13
  * @param periodAdjustment
12
- * @param estimationMethod
13
14
  * @returns Estimated funding rate. : Precision //TODO-PRECISION
14
15
  */
15
- export async function calculateEstimatedFundingRate(
16
+ export async function calculateAllEstimatedFundingRate(
16
17
  market: Market,
17
18
  pythClient: PythClient,
18
19
  periodAdjustment: BN = new BN(1),
19
- estimationMethod: 'interpolated' | 'lowerbound'
20
- ): Promise<BN> {
20
+ ): Promise<[BN, BN, BN]> {
21
21
  // periodAdjustment
22
22
  // 1: hourly
23
23
  // 24: daily
@@ -26,7 +26,7 @@ export async function calculateEstimatedFundingRate(
26
26
  const hoursInDay = new BN(24);
27
27
 
28
28
  if (!market.initialized) {
29
- return new BN(0);
29
+ return [new BN(0), new BN(0), new BN(0)];
30
30
  }
31
31
 
32
32
  const payFreq = new BN(market.amm.fundingPeriod);
@@ -61,16 +61,129 @@ export async function calculateEstimatedFundingRate(
61
61
  .mul(new BN(100))
62
62
  .div(oracleTwapWithMantissa);
63
63
 
64
+
65
+ const lowerboundEst = twapSpreadPct
66
+ .mul(payFreq)
67
+ .mul(BN.min(secondsInHour, timeSinceLastUpdate))
68
+ .mul(periodAdjustment)
69
+ .div(secondsInHour)
70
+ .div(secondsInHour)
71
+ .div(hoursInDay);
72
+
73
+ const interpEst = twapSpreadPct.mul(periodAdjustment).div(hoursInDay);
74
+
75
+
76
+ const interpRateQuote = twapSpreadPct.mul(periodAdjustment).div(hoursInDay)
77
+ .div(MARK_PRICE_PRECISION.div(QUOTE_PRECISION));
78
+ let feePoolSize = calculateFundingPool(market);
79
+ if(interpRateQuote.lt(new BN(0))){
80
+ feePoolSize = feePoolSize.mul(new BN(-1));
81
+ }
82
+
83
+ let cappedAltEst: BN;
84
+ let largerSide: BN;
85
+ let smallerSide: BN;
86
+
87
+ if(market.baseAssetAmountLong.gt(market.baseAssetAmountShort)){
88
+ largerSide = market.baseAssetAmountLong.abs();
89
+ smallerSide = market.baseAssetAmountShort.abs();
90
+ if(twapSpread.gt(new BN(0))){
91
+ return [lowerboundEst, interpEst, interpEst];
92
+ }
93
+ } else if(market.baseAssetAmountLong.lt(market.baseAssetAmountShort)){
94
+ largerSide = market.baseAssetAmountShort.abs();
95
+ smallerSide = market.baseAssetAmountLong.abs();
96
+ if(twapSpread.lt(new BN(0))){
97
+ return [lowerboundEst, interpEst, interpEst];
98
+ }
99
+ } else{
100
+ return [lowerboundEst, interpEst, interpEst];
101
+ }
102
+
103
+ if(largerSide.gt(ZERO)){
104
+ cappedAltEst = smallerSide.mul(twapSpread).div(largerSide);
105
+ const feePoolTopOff = feePoolSize.mul(MARK_PRICE_PRECISION.div(QUOTE_PRECISION))
106
+ .mul(AMM_RESERVE_PRECISION).div(largerSide);
107
+ cappedAltEst = cappedAltEst.add(feePoolTopOff);
108
+
109
+ cappedAltEst = cappedAltEst.mul(MARK_PRICE_PRECISION)
110
+ .mul(new BN(100))
111
+ .div(oracleTwapWithMantissa)
112
+ .mul(periodAdjustment).div(hoursInDay);
113
+
114
+ if(cappedAltEst.abs().gt(interpEst.abs())){
115
+ cappedAltEst = interpEst;
116
+ }
117
+ } else{
118
+ cappedAltEst = interpEst;
119
+ }
120
+
121
+
122
+ return [lowerboundEst, cappedAltEst, interpEst];
123
+ }
124
+
125
+ /**
126
+ *
127
+ * @param market
128
+ * @param pythClient
129
+ * @param periodAdjustment
130
+ * @param estimationMethod
131
+ * @returns Estimated funding rate. : Precision //TODO-PRECISION
132
+ */
133
+ export async function calculateEstimatedFundingRate(
134
+ market: Market,
135
+ pythClient: PythClient,
136
+ periodAdjustment: BN = new BN(1),
137
+ estimationMethod: 'interpolated' | 'lowerbound' | 'capped'
138
+ ): Promise<BN> {
139
+ const [lowerboundEst, cappedAltEst, interpEst] =
140
+ await calculateAllEstimatedFundingRate(market, pythClient, periodAdjustment);
141
+
64
142
  if (estimationMethod == 'lowerbound') {
65
143
  //assuming remaining funding period has no gap
66
- return twapSpreadPct
67
- .mul(payFreq)
68
- .mul(BN.min(secondsInHour, timeSinceLastUpdate))
69
- .mul(periodAdjustment)
70
- .div(secondsInHour)
71
- .div(secondsInHour)
72
- .div(hoursInDay);
144
+ return lowerboundEst;
145
+ } else if (estimationMethod == 'capped') {
146
+ return cappedAltEst;
73
147
  } else {
74
- return twapSpreadPct.mul(periodAdjustment).div(hoursInDay);
148
+ return interpEst;
75
149
  }
76
150
  }
151
+
152
+
153
+ /**
154
+ *
155
+ * @param market
156
+ * @param pythClient
157
+ * @param periodAdjustment
158
+ * @param estimationMethod
159
+ * @returns Estimated funding rate. : Precision //TODO-PRECISION
160
+ */
161
+ export async function calculateLongShortFundingRate(
162
+ market: Market,
163
+ pythClient: PythClient,
164
+ periodAdjustment: BN = new BN(1),
165
+ ): Promise<[BN, BN]> {
166
+ const [_, cappedAltEst, interpEst] =
167
+ await calculateAllEstimatedFundingRate(market, pythClient, periodAdjustment);
168
+
169
+ if(market.baseAssetAmountLong.gt(market.baseAssetAmountShort)){
170
+ return [cappedAltEst, interpEst];
171
+ } else if(market.baseAssetAmountLong.lt(market.baseAssetAmountShort)){
172
+ return [interpEst, cappedAltEst];
173
+ } else{
174
+ return [interpEst, interpEst];
175
+ }
176
+
177
+ }
178
+
179
+ /**
180
+ *
181
+ * @param market
182
+ * @returns Estimated fee pool size
183
+ */
184
+ export function calculateFundingPool(market: Market): BN {
185
+ const totalFeeLB = market.amm.totalFee.div(new BN(2));
186
+ const feePool = market.amm.totalFeeMinusDistributions.sub(totalFeeLB);
187
+ // return new BN(QUOTE_PRECISION.mul(new BN(2400)));
188
+ return feePool;
189
+ }
@@ -102,9 +102,9 @@ export function calculatePositionPNL(
102
102
  }
103
103
 
104
104
  /**
105
- *
106
- * @param market
107
- * @param marketPosition
105
+ *
106
+ * @param market
107
+ * @param marketPosition
108
108
  * @returns // TODO-PRECISION
109
109
  */
110
110
  export function calculatePositionFundingPNL(
package/src/math/trade.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  calculateAmmReservesAfterSwap,
13
13
  calculatePrice,
14
14
  getSwapDirection,
15
+ AssetType,
15
16
  } from './amm';
16
17
  import { squareRootBN } from './utils';
17
18
 
@@ -47,7 +48,8 @@ export type PriceImpactUnit =
47
48
  export function calculateTradeSlippage(
48
49
  direction: PositionDirection,
49
50
  amount: BN,
50
- market: Market
51
+ market: Market,
52
+ inputAssetType: AssetType = 'quote',
51
53
  ): [BN, BN, BN, BN] {
52
54
  const oldPrice = calculateMarkPrice(market);
53
55
  if (amount.eq(ZERO)) {
@@ -56,7 +58,8 @@ export function calculateTradeSlippage(
56
58
  const [acquiredBase, acquiredQuote] = calculateTradeAcquiredAmounts(
57
59
  direction,
58
60
  amount,
59
- market
61
+ market,
62
+ inputAssetType
60
63
  );
61
64
 
62
65
  const entryPrice = calculatePrice(
@@ -103,7 +106,8 @@ export function calculateTradeSlippage(
103
106
  export function calculateTradeAcquiredAmounts(
104
107
  direction: PositionDirection,
105
108
  amount: BN,
106
- market: Market
109
+ market: Market,
110
+ inputAssetType: AssetType = 'quote',
107
111
  ): [BN, BN] {
108
112
  if (amount.eq(ZERO)) {
109
113
  return [ZERO, ZERO];
@@ -112,9 +116,9 @@ export function calculateTradeAcquiredAmounts(
112
116
  const [newQuoteAssetReserve, newBaseAssetReserve] =
113
117
  calculateAmmReservesAfterSwap(
114
118
  market.amm,
115
- 'quote',
119
+ inputAssetType,
116
120
  amount,
117
- getSwapDirection('quote', direction)
121
+ getSwapDirection(inputAssetType, direction)
118
122
  );
119
123
 
120
124
  const acquiredBase = market.amm.baseAssetReserve.sub(newBaseAssetReserve);
@@ -129,8 +133,8 @@ export function calculateTradeAcquiredAmounts(
129
133
  * @param market
130
134
  * @param targetPrice
131
135
  * @param pct optional default is 100% gap filling, can set smaller.
132
- * @returns trade direction/size in order to push price to a targetPrice,
133
- *
136
+ * @returns trade direction/size in order to push price to a targetPrice,
137
+ *
134
138
  * [
135
139
  * direction => direction of trade required, TODO-PRECISION
136
140
  * tradeSize => size of trade required, TODO-PRECISION
@@ -236,6 +240,7 @@ export function calculateTargetPriceTrade(
236
240
 
237
241
  const entryPrice = tradeSize
238
242
  .mul(AMM_TO_QUOTE_PRECISION_RATIO)
243
+ .mul(MARK_PRICE_PRECISION)
239
244
  .div(baseSize.abs());
240
245
 
241
246
  assert(tp1.sub(tp2).lte(originalDiff), 'Target Price Calculation incorrect');
package/src/types.ts CHANGED
@@ -265,6 +265,7 @@ export interface Trade {
265
265
  side: TradeSide;
266
266
  size: number;
267
267
  ts: number;
268
+ fee: number;
268
269
  marketIndex: number;
269
270
  chainTs: number;
270
271
  }