@drift-labs/sdk 0.2.0-master.27 → 0.2.0-master.29

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.
@@ -1809,6 +1809,31 @@
1809
1809
  }
1810
1810
  ]
1811
1811
  },
1812
+ {
1813
+ "name": "updateUserDelegate",
1814
+ "accounts": [
1815
+ {
1816
+ "name": "user",
1817
+ "isMut": true,
1818
+ "isSigner": false
1819
+ },
1820
+ {
1821
+ "name": "authority",
1822
+ "isMut": false,
1823
+ "isSigner": true
1824
+ }
1825
+ ],
1826
+ "args": [
1827
+ {
1828
+ "name": "userId",
1829
+ "type": "u8"
1830
+ },
1831
+ {
1832
+ "name": "delegate",
1833
+ "type": "publicKey"
1834
+ }
1835
+ ]
1836
+ },
1812
1837
  {
1813
1838
  "name": "settleFundingPayment",
1814
1839
  "accounts": [
@@ -2253,7 +2278,7 @@
2253
2278
  ]
2254
2279
  },
2255
2280
  {
2256
- "name": "updateFee",
2281
+ "name": "updatePerpFeeStructure",
2257
2282
  "accounts": [
2258
2283
  {
2259
2284
  "name": "admin",
@@ -2268,7 +2293,7 @@
2268
2293
  ],
2269
2294
  "args": [
2270
2295
  {
2271
- "name": "fees",
2296
+ "name": "feeStructure",
2272
2297
  "type": {
2273
2298
  "defined": "FeeStructure"
2274
2299
  }
@@ -2276,7 +2301,7 @@
2276
2301
  ]
2277
2302
  },
2278
2303
  {
2279
- "name": "updateOrderFillerRewardStructure",
2304
+ "name": "updateSpotFeeStructure",
2280
2305
  "accounts": [
2281
2306
  {
2282
2307
  "name": "admin",
@@ -2291,9 +2316,9 @@
2291
2316
  ],
2292
2317
  "args": [
2293
2318
  {
2294
- "name": "orderFillerRewardStructure",
2319
+ "name": "feeStructure",
2295
2320
  "type": {
2296
- "defined": "OrderFillerRewardStructure"
2321
+ "defined": "FeeStructure"
2297
2322
  }
2298
2323
  }
2299
2324
  ]
@@ -2971,6 +2996,42 @@
2971
2996
  "type": "u64"
2972
2997
  }
2973
2998
  ]
2999
+ },
3000
+ {
3001
+ "name": "updateUserQuoteAssetInsuranceStake",
3002
+ "accounts": [
3003
+ {
3004
+ "name": "state",
3005
+ "isMut": false,
3006
+ "isSigner": false
3007
+ },
3008
+ {
3009
+ "name": "spotMarket",
3010
+ "isMut": false,
3011
+ "isSigner": false
3012
+ },
3013
+ {
3014
+ "name": "insuranceFundStake",
3015
+ "isMut": true,
3016
+ "isSigner": false
3017
+ },
3018
+ {
3019
+ "name": "userStats",
3020
+ "isMut": true,
3021
+ "isSigner": false
3022
+ },
3023
+ {
3024
+ "name": "authority",
3025
+ "isMut": false,
3026
+ "isSigner": true
3027
+ },
3028
+ {
3029
+ "name": "insuranceFundVault",
3030
+ "isMut": true,
3031
+ "isSigner": false
3032
+ }
3033
+ ],
3034
+ "args": []
2974
3035
  }
2975
3036
  ],
2976
3037
  "accounts": [
@@ -3447,18 +3508,6 @@
3447
3508
  "name": "insuranceVault",
3448
3509
  "type": "publicKey"
3449
3510
  },
3450
- {
3451
- "name": "perpFeeStructure",
3452
- "type": {
3453
- "defined": "FeeStructure"
3454
- }
3455
- },
3456
- {
3457
- "name": "spotFeeStructure",
3458
- "type": {
3459
- "defined": "FeeStructure"
3460
- }
3461
- },
3462
3511
  {
3463
3512
  "name": "whitelistMint",
3464
3513
  "type": "publicKey"
@@ -3512,6 +3561,18 @@
3512
3561
  {
3513
3562
  "name": "signerNonce",
3514
3563
  "type": "u8"
3564
+ },
3565
+ {
3566
+ "name": "perpFeeStructure",
3567
+ "type": {
3568
+ "defined": "FeeStructure"
3569
+ }
3570
+ },
3571
+ {
3572
+ "name": "spotFeeStructure",
3573
+ "type": {
3574
+ "defined": "FeeStructure"
3575
+ }
3515
3576
  }
3516
3577
  ]
3517
3578
  }
@@ -3525,6 +3586,10 @@
3525
3586
  "name": "authority",
3526
3587
  "type": "publicKey"
3527
3588
  },
3589
+ {
3590
+ "name": "delegate",
3591
+ "type": "publicKey"
3592
+ },
3528
3593
  {
3529
3594
  "name": "userId",
3530
3595
  "type": "u8"
@@ -3619,6 +3684,14 @@
3619
3684
  "name": "totalReferrerReward",
3620
3685
  "type": "u64"
3621
3686
  },
3687
+ {
3688
+ "name": "currentEpochReferrerReward",
3689
+ "type": "u64"
3690
+ },
3691
+ {
3692
+ "name": "nextEpochTs",
3693
+ "type": "i64"
3694
+ },
3622
3695
  {
3623
3696
  "name": "fees",
3624
3697
  "type": {
@@ -3650,8 +3723,8 @@
3650
3723
  "type": "i64"
3651
3724
  },
3652
3725
  {
3653
- "name": "quoteAssetInsuranceFundStake",
3654
- "type": "u128"
3726
+ "name": "stakedQuoteAssetAmount",
3727
+ "type": "u64"
3655
3728
  }
3656
3729
  ]
3657
3730
  }
@@ -4342,39 +4415,26 @@
4342
4415
  "kind": "struct",
4343
4416
  "fields": [
4344
4417
  {
4345
- "name": "feeNumerator",
4346
- "type": "u128"
4347
- },
4348
- {
4349
- "name": "feeDenominator",
4350
- "type": "u128"
4351
- },
4352
- {
4353
- "name": "discountTokenTiers",
4418
+ "name": "feeTiers",
4354
4419
  "type": {
4355
- "defined": "DiscountTokenTiers"
4356
- }
4357
- },
4358
- {
4359
- "name": "referralDiscount",
4360
- "type": {
4361
- "defined": "ReferralDiscount"
4420
+ "array": [
4421
+ {
4422
+ "defined": "FeeTier"
4423
+ },
4424
+ 10
4425
+ ]
4362
4426
  }
4363
4427
  },
4364
- {
4365
- "name": "makerRebateNumerator",
4366
- "type": "u128"
4367
- },
4368
- {
4369
- "name": "makerRebateDenominator",
4370
- "type": "u128"
4371
- },
4372
4428
  {
4373
4429
  "name": "fillerRewardStructure",
4374
4430
  "type": {
4375
4431
  "defined": "OrderFillerRewardStructure"
4376
4432
  }
4377
4433
  },
4434
+ {
4435
+ "name": "referrerRewardEpochUpperBound",
4436
+ "type": "u64"
4437
+ },
4378
4438
  {
4379
4439
  "name": "flatFillerFee",
4380
4440
  "type": "u128"
@@ -4383,77 +4443,41 @@
4383
4443
  }
4384
4444
  },
4385
4445
  {
4386
- "name": "DiscountTokenTiers",
4446
+ "name": "FeeTier",
4387
4447
  "type": {
4388
4448
  "kind": "struct",
4389
4449
  "fields": [
4390
4450
  {
4391
- "name": "firstTier",
4392
- "type": {
4393
- "defined": "DiscountTokenTier"
4394
- }
4395
- },
4396
- {
4397
- "name": "secondTier",
4398
- "type": {
4399
- "defined": "DiscountTokenTier"
4400
- }
4451
+ "name": "feeNumerator",
4452
+ "type": "u32"
4401
4453
  },
4402
4454
  {
4403
- "name": "thirdTier",
4404
- "type": {
4405
- "defined": "DiscountTokenTier"
4406
- }
4455
+ "name": "feeDenominator",
4456
+ "type": "u32"
4407
4457
  },
4408
4458
  {
4409
- "name": "fourthTier",
4410
- "type": {
4411
- "defined": "DiscountTokenTier"
4412
- }
4413
- }
4414
- ]
4415
- }
4416
- },
4417
- {
4418
- "name": "DiscountTokenTier",
4419
- "type": {
4420
- "kind": "struct",
4421
- "fields": [
4422
- {
4423
- "name": "minimumBalance",
4424
- "type": "u64"
4459
+ "name": "makerRebateNumerator",
4460
+ "type": "u32"
4425
4461
  },
4426
4462
  {
4427
- "name": "discountNumerator",
4428
- "type": "u128"
4463
+ "name": "makerRebateDenominator",
4464
+ "type": "u32"
4429
4465
  },
4430
- {
4431
- "name": "discountDenominator",
4432
- "type": "u128"
4433
- }
4434
- ]
4435
- }
4436
- },
4437
- {
4438
- "name": "ReferralDiscount",
4439
- "type": {
4440
- "kind": "struct",
4441
- "fields": [
4442
4466
  {
4443
4467
  "name": "referrerRewardNumerator",
4444
- "type": "u128"
4468
+ "type": "u32"
4445
4469
  },
4446
4470
  {
4447
4471
  "name": "referrerRewardDenominator",
4448
- "type": "u128"
4472
+ "type": "u32"
4449
4473
  },
4450
4474
  {
4451
- "name": "refereeDiscountNumerator",
4452
- "type": "u128"
4475
+ "name": "refereeFeeNumerator",
4476
+ "type": "u32"
4453
4477
  },
4454
4478
  {
4455
- "name": "refereeDiscountDenominator",
4456
- "type": "u128"
4479
+ "name": "refereeFeeDenominator",
4480
+ "type": "u32"
4457
4481
  }
4458
4482
  ]
4459
4483
  }
@@ -4536,6 +4560,10 @@
4536
4560
  {
4537
4561
  "name": "openAsks",
4538
4562
  "type": "i128"
4563
+ },
4564
+ {
4565
+ "name": "cumulativeDeposits",
4566
+ "type": "i64"
4539
4567
  }
4540
4568
  ]
4541
4569
  }
@@ -4586,7 +4614,7 @@
4586
4614
  "type": "i128"
4587
4615
  },
4588
4616
  {
4589
- "name": "realizedPnl",
4617
+ "name": "settledPnl",
4590
4618
  "type": "i64"
4591
4619
  },
4592
4620
  {
@@ -1,4 +1,4 @@
1
- import { ONE, ZERO } from '../constants/numericConstants';
1
+ import { ZERO } from '../constants/numericConstants';
2
2
  import { BN } from '../index';
3
3
 
4
4
  export function stakeAmountToShares(
@@ -25,7 +25,7 @@ export function unstakeSharesToAmount(
25
25
  if (totalIfShares.gt(ZERO)) {
26
26
  amount = BN.max(
27
27
  ZERO,
28
- nShares.mul(insuranceFundVaultBalance).div(totalIfShares).sub(ONE)
28
+ nShares.mul(insuranceFundVaultBalance).div(totalIfShares)
29
29
  );
30
30
  } else {
31
31
  amount = ZERO;
@@ -157,7 +157,7 @@ export function calculateUnrealizedAssetWeight(
157
157
  assetWeight = new BN(market.unrealizedInitialAssetWeight);
158
158
 
159
159
  if (market.unrealizedMaxImbalance.gt(ZERO)) {
160
- const netUnsettledPnl = calculateNetUserImbalance(
160
+ const netUnsettledPnl = calculateNetUserPnlImbalance(
161
161
  market,
162
162
  quoteSpotMarket,
163
163
  oraclePriceData
@@ -194,29 +194,38 @@ export function calculateMarketAvailablePNL(
194
194
  );
195
195
  }
196
196
 
197
- export function calculateNetUserImbalance(
198
- market: PerpMarketAccount,
199
- bank: SpotMarketAccount,
197
+ export function calculateNetUserPnl(
198
+ perpMarket: PerpMarketAccount,
200
199
  oraclePriceData: OraclePriceData
201
200
  ): BN {
202
- const netUserPositionValue = market.amm.netBaseAssetAmount
201
+ const netUserPositionValue = perpMarket.amm.netBaseAssetAmount
203
202
  .mul(oraclePriceData.price)
204
203
  .div(BASE_PRECISION)
205
204
  .div(PRICE_TO_QUOTE_PRECISION);
206
205
 
207
- const netUserCostBasis = market.amm.quoteAssetAmountLong
208
- .add(market.amm.quoteAssetAmountShort)
209
- .sub(market.amm.cumulativeSocialLoss);
206
+ const netUserCostBasis = perpMarket.amm.quoteAssetAmountLong
207
+ .add(perpMarket.amm.quoteAssetAmountShort)
208
+ .sub(perpMarket.amm.cumulativeSocialLoss);
209
+
210
+ const netUserPnl = netUserPositionValue.add(netUserCostBasis);
211
+
212
+ return netUserPnl;
213
+ }
210
214
 
211
- const userEntitledPnl = netUserPositionValue.add(netUserCostBasis);
215
+ export function calculateNetUserPnlImbalance(
216
+ perpMarket: PerpMarketAccount,
217
+ spotMarket: SpotMarketAccount,
218
+ oraclePriceData: OraclePriceData
219
+ ): BN {
220
+ const netUserPnl = calculateNetUserPnl(perpMarket, oraclePriceData);
212
221
 
213
222
  const pnlPool = getTokenAmount(
214
- market.pnlPool.balance,
215
- bank,
223
+ perpMarket.pnlPool.balance,
224
+ spotMarket,
216
225
  SpotBalanceType.DEPOSIT
217
226
  );
218
227
 
219
- const imbalance = userEntitledPnl.sub(pnlPool);
228
+ const imbalance = netUserPnl.sub(pnlPool);
220
229
 
221
230
  return imbalance;
222
231
  }
@@ -1,4 +1,4 @@
1
- import { BN } from '../';
1
+ import { BN, SpotMarketAccount } from '../';
2
2
  import {
3
3
  AMM_RESERVE_PRECISION,
4
4
  AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO,
@@ -17,8 +17,8 @@ import {
17
17
  calculateAmmReservesAfterSwap,
18
18
  getSwapDirection,
19
19
  } from './amm';
20
-
21
20
  import { calculateBaseAssetValueWithOracle } from './margin';
21
+ import { calculateNetUserPnlImbalance } from './market';
22
22
 
23
23
  /**
24
24
  * calculateBaseAssetValue
@@ -31,7 +31,9 @@ import { calculateBaseAssetValueWithOracle } from './margin';
31
31
  export function calculateBaseAssetValue(
32
32
  market: PerpMarketAccount,
33
33
  userPosition: PerpPosition,
34
- oraclePriceData: OraclePriceData
34
+ oraclePriceData: OraclePriceData,
35
+ useSpread = true,
36
+ skipUpdate = false
35
37
  ): BN {
36
38
  if (userPosition.baseAssetAmount.eq(ZERO)) {
37
39
  return ZERO;
@@ -40,21 +42,25 @@ export function calculateBaseAssetValue(
40
42
  const directionToClose = findDirectionToClose(userPosition);
41
43
  let prepegAmm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
42
44
 
43
- if (market.amm.baseSpread > 0) {
44
- const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
45
- calculateUpdatedAMMSpreadReserves(
46
- market.amm,
47
- directionToClose,
48
- oraclePriceData
49
- );
50
- prepegAmm = {
51
- baseAssetReserve,
52
- quoteAssetReserve,
53
- sqrtK: sqrtK,
54
- pegMultiplier: newPeg,
55
- };
45
+ if (!skipUpdate) {
46
+ if (market.amm.baseSpread > 0 && useSpread) {
47
+ const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } =
48
+ calculateUpdatedAMMSpreadReserves(
49
+ market.amm,
50
+ directionToClose,
51
+ oraclePriceData
52
+ );
53
+ prepegAmm = {
54
+ baseAssetReserve,
55
+ quoteAssetReserve,
56
+ sqrtK: sqrtK,
57
+ pegMultiplier: newPeg,
58
+ };
59
+ } else {
60
+ prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
61
+ }
56
62
  } else {
57
- prepegAmm = calculateUpdatedAMM(market.amm, oraclePriceData);
63
+ prepegAmm = market.amm;
58
64
  }
59
65
 
60
66
  const [newQuoteAssetReserve, _] = calculateAmmReservesAfterSwap(
@@ -124,8 +130,9 @@ export function calculatePositionPNL(
124
130
  return pnl;
125
131
  }
126
132
 
127
- export function calculateUnsettledPnl(
133
+ export function calculateClaimablePnl(
128
134
  market: PerpMarketAccount,
135
+ spotMarket: SpotMarketAccount,
129
136
  perpPosition: PerpPosition,
130
137
  oraclePriceData: OraclePriceData
131
138
  ): BN {
@@ -136,16 +143,23 @@ export function calculateUnsettledPnl(
136
143
  oraclePriceData
137
144
  );
138
145
 
139
- let unsettledPnl = unrealizedPnl;
146
+ const fundingPnL = calculatePositionFundingPNL(market, perpPosition).div(
147
+ PRICE_TO_QUOTE_PRECISION
148
+ );
149
+
150
+ let unsettledPnl = unrealizedPnl.add(fundingPnL);
140
151
  if (unrealizedPnl.gt(ZERO)) {
141
- const fundingPnL = calculatePositionFundingPNL(market, perpPosition).div(
142
- PRICE_TO_QUOTE_PRECISION
152
+ const excessPnlPool = BN.max(
153
+ ZERO,
154
+ calculateNetUserPnlImbalance(market, spotMarket, oraclePriceData).mul(
155
+ new BN(-1)
156
+ )
143
157
  );
144
158
 
145
159
  const maxPositivePnl = BN.max(
146
160
  perpPosition.quoteAssetAmount
147
161
  .sub(perpPosition.quoteEntryAmount)
148
- .add(fundingPnL),
162
+ .add(excessPnlPool),
149
163
  ZERO
150
164
  );
151
165
 
package/src/math/repeg.ts CHANGED
@@ -98,6 +98,15 @@ export function calculateBudgetedKBN(
98
98
  .div(QUOTE_PRECISION);
99
99
  const denom2 = pegged_y_d_d;
100
100
 
101
+ // protocol is spending to increase k
102
+ if (C.lt(ZERO)) {
103
+ // thus denom1 is negative and solution is unstable
104
+ if (denom1.lt(pegged_y_d_d.abs())) {
105
+ console.log('budget cost exceeds stable K solution');
106
+ return [new BN(10000), new BN(1)];
107
+ }
108
+ }
109
+
101
110
  const numerator = numer1.sub(numer2).div(AMM_TO_QUOTE_PRECISION_RATIO);
102
111
  const denominator = denom1.add(denom2).div(AMM_TO_QUOTE_PRECISION_RATIO);
103
112
 
package/src/types.ts CHANGED
@@ -385,8 +385,6 @@ export type StateAccount = {
385
385
  exchangePaused: boolean;
386
386
  adminControlsPrices: boolean;
387
387
  insuranceVault: PublicKey;
388
- perpFeeStructure: FeeStructure;
389
- spotFeeStructure: FeeStructure;
390
388
  totalFee: BN;
391
389
  totalFeeWithdrawn: BN;
392
390
  whitelistMint: PublicKey;
@@ -402,6 +400,8 @@ export type StateAccount = {
402
400
  minPerpAuctionDuration: number;
403
401
  defaultSpotAuctionDuration: number;
404
402
  liquidationMarginBufferRatio: number;
403
+ perpFeeStructure: FeeStructure;
404
+ spotFeeStructure: FeeStructure;
405
405
  };
406
406
 
407
407
  export type PerpMarketAccount = {
@@ -559,7 +559,7 @@ export type PerpPosition = {
559
559
  openOrders: BN;
560
560
  openBids: BN;
561
561
  openAsks: BN;
562
- realizedPnl: BN;
562
+ settledPnl: BN;
563
563
  lpShares: BN;
564
564
  lastFeePerLp: BN;
565
565
  lastNetBaseAssetAmountPerLp: BN;
@@ -584,11 +584,12 @@ export type UserStatsAccount = {
584
584
  isReferrer: boolean;
585
585
  totalReferrerReward: BN;
586
586
  authority: PublicKey;
587
- quoteAssetInsuranceFundStake: BN;
587
+ stakedQuoteAssetAmount: BN;
588
588
  };
589
589
 
590
590
  export type UserAccount = {
591
591
  authority: PublicKey;
592
+ delegate: PublicKey;
592
593
  name: number[];
593
594
  userId: number;
594
595
  spotPositions: SpotPosition[];
@@ -717,40 +718,29 @@ export interface IWallet {
717
718
  }
718
719
 
719
720
  export type FeeStructure = {
720
- feeNumerator: BN;
721
- feeDenominator: BN;
722
- discountTokenTiers: {
723
- firstTier: {
724
- minimumBalance: BN;
725
- discountNumerator: BN;
726
- discountDenominator: BN;
727
- };
728
- secondTier: {
729
- minimumBalance: BN;
730
- discountNumerator: BN;
731
- discountDenominator: BN;
732
- };
733
- thirdTier: {
734
- minimumBalance: BN;
735
- discountNumerator: BN;
736
- discountDenominator: BN;
737
- };
738
- fourthTier: {
739
- minimumBalance: BN;
740
- discountNumerator: BN;
741
- discountDenominator: BN;
742
- };
743
- };
744
- referralDiscount: {
745
- referrerRewardNumerator: BN;
746
- referrerRewardDenominator: BN;
747
- refereeDiscountNumerator: BN;
748
- refereeDiscountDenominator: BN;
749
- };
721
+ feeTiers: FeeTier[];
750
722
  makerRebateNumerator: BN;
751
723
  makerRebateDenominator: BN;
752
724
  fillerRewardStructure: OrderFillerRewardStructure;
753
725
  flatFillerFee: BN;
726
+ referrerRewardEpochUpperBound: BN;
727
+ };
728
+
729
+ export type FeeTier = {
730
+ feeNumerator: number;
731
+ feeDenominator: number;
732
+ makerRebateNumerator: number;
733
+ makerRebateDenominator: number;
734
+ referrerRewardNumerator: number;
735
+ referrerRewardDenominator: number;
736
+ refereeFeeNumerator: number;
737
+ refereeFeeDenominator: number;
738
+ };
739
+
740
+ export type OrderFillerRewardStructure = {
741
+ rewardNumerator: BN;
742
+ rewardDenominator: BN;
743
+ timeBasedRewardLowerBound: BN;
754
744
  };
755
745
 
756
746
  export type OracleGuardRails = {
@@ -766,12 +756,6 @@ export type OracleGuardRails = {
766
756
  useForLiquidations: boolean;
767
757
  };
768
758
 
769
- export type OrderFillerRewardStructure = {
770
- rewardNumerator: BN;
771
- rewardDenominator: BN;
772
- timeBasedRewardLowerBound: BN;
773
- };
774
-
775
759
  export type MarginCategory = 'Initial' | 'Maintenance';
776
760
 
777
761
  export type InsuranceFundStake = {
@@ -20,7 +20,7 @@ export const mockPerpPosition = {
20
20
  openOrders: new BN(0),
21
21
  openBids: new BN(0),
22
22
  openAsks: new BN(0),
23
- realizedPnl: new BN(0),
23
+ settledPnl: new BN(0),
24
24
  lpShares: new BN(0),
25
25
  lastFeePerLp: new BN(0),
26
26
  lastNetBaseAssetAmountPerLp: new BN(0),
@@ -1,8 +0,0 @@
1
- import { StateAccount } from '../types';
2
- /**
3
- * Get the clearing house percent fee charged on notional of taking trades
4
- *
5
- * @param state
6
- * @returns Precision : basis points (bps)
7
- */
8
- export declare function getExchangeFee(state: StateAccount): number;
package/lib/math/state.js DELETED
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getExchangeFee = void 0;
4
- /**
5
- * Get the clearing house percent fee charged on notional of taking trades
6
- *
7
- * @param state
8
- * @returns Precision : basis points (bps)
9
- */
10
- function getExchangeFee(state) {
11
- const exchangeFee = state.perpFeeStructure.feeNumerator.toNumber() /
12
- state.perpFeeStructure.feeDenominator.toNumber();
13
- return exchangeFee;
14
- }
15
- exports.getExchangeFee = getExchangeFee;