@drift-labs/sdk 2.13.0-beta.2 → 2.14.0-beta.0

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 (67) hide show
  1. package/lib/accounts/bulkAccountLoader.d.ts +1 -0
  2. package/lib/accounts/bulkAccountLoader.js +3 -3
  3. package/lib/accounts/fetch.js +2 -2
  4. package/lib/accounts/pollingDriftClientAccountSubscriber.js +7 -7
  5. package/lib/accounts/pollingTokenAccountSubscriber.js +2 -2
  6. package/lib/accounts/pollingUserAccountSubscriber.js +2 -2
  7. package/lib/accounts/pollingUserStatsAccountSubscriber.js +2 -2
  8. package/lib/accounts/types.d.ts +1 -0
  9. package/lib/accounts/webSocketAccountSubscriber.js +1 -1
  10. package/lib/accounts/webSocketDriftClientAccountSubscriber.js +3 -3
  11. package/lib/addresses/marketAddresses.js +1 -1
  12. package/lib/addresses/pda.js +5 -1
  13. package/lib/adminClient.js +61 -57
  14. package/lib/dlob/DLOB.js +67 -67
  15. package/lib/dlob/DLOBNode.js +7 -7
  16. package/lib/dlob/NodeList.js +2 -2
  17. package/lib/driftClient.d.ts +33 -33
  18. package/lib/driftClient.js +120 -116
  19. package/lib/events/eventSubscriber.js +2 -2
  20. package/lib/events/pollingLogProvider.js +1 -1
  21. package/lib/events/types.d.ts +1 -0
  22. package/lib/examples/loadDlob.js +2 -2
  23. package/lib/examples/makeTradeExample.js +9 -9
  24. package/lib/factory/bigNum.js +9 -9
  25. package/lib/factory/oracleClient.js +2 -2
  26. package/lib/idl/drift.json +1 -1
  27. package/lib/index.js +5 -1
  28. package/lib/math/amm.js +23 -23
  29. package/lib/math/auction.js +6 -6
  30. package/lib/math/exchangeStatus.js +2 -2
  31. package/lib/math/funding.d.ts +1 -1
  32. package/lib/math/funding.js +8 -8
  33. package/lib/math/margin.js +5 -5
  34. package/lib/math/market.js +13 -13
  35. package/lib/math/oracles.js +1 -1
  36. package/lib/math/orders.js +23 -23
  37. package/lib/math/position.js +5 -5
  38. package/lib/math/repeg.js +1 -1
  39. package/lib/math/spotBalance.js +9 -9
  40. package/lib/math/spotPosition.js +3 -3
  41. package/lib/math/trade.js +42 -42
  42. package/lib/oracles/oracleClientCache.js +1 -1
  43. package/lib/oracles/pythClient.js +1 -1
  44. package/lib/token/index.js +1 -1
  45. package/lib/tokenFaucet.js +5 -1
  46. package/lib/tx/retryTxSender.js +1 -1
  47. package/lib/user.d.ts +8 -9
  48. package/lib/user.js +153 -158
  49. package/lib/userMap/userMap.js +1 -1
  50. package/lib/userMap/userStatsMap.js +3 -3
  51. package/lib/userStats.js +2 -2
  52. package/package.json +3 -3
  53. package/src/driftClient.ts +209 -68
  54. package/src/events/types.ts +15 -0
  55. package/src/idl/drift.json +1 -1
  56. package/src/math/funding.ts +7 -8
  57. package/src/math/spotBalance.ts +14 -7
  58. package/src/token/index.ts +1 -1
  59. package/src/user.ts +187 -184
  60. package/src/assert/assert.js +0 -9
  61. package/src/token/index.js +0 -38
  62. package/src/tx/types.js +0 -2
  63. package/src/tx/utils.js +0 -17
  64. package/src/util/computeUnits.js +0 -27
  65. package/src/util/getTokenAddress.js +0 -9
  66. package/src/util/promiseTimeout.js +0 -14
  67. package/src/util/tps.js +0 -27
@@ -19,7 +19,8 @@ import { calculateBidAskPrice } from './amm';
19
19
  export async function calculateAllEstimatedFundingRate(
20
20
  market: PerpMarketAccount,
21
21
  oraclePriceData?: OraclePriceData,
22
- periodAdjustment: BN = new BN(1)
22
+ periodAdjustment: BN = new BN(1),
23
+ now?: BN
23
24
  ): Promise<[BN, BN, BN, BN, BN]> {
24
25
  // periodAdjustment
25
26
  // 1: hourly
@@ -36,7 +37,7 @@ export async function calculateAllEstimatedFundingRate(
36
37
  const payFreq = new BN(market.amm.fundingPeriod);
37
38
 
38
39
  // todo: sufficiently differs from blockchain timestamp?
39
- const now = new BN((Date.now() / 1000).toFixed(0));
40
+ now = now || new BN((Date.now() / 1000).toFixed(0));
40
41
  const timeSinceLastUpdate = now.sub(market.amm.lastFundingRateTs);
41
42
 
42
43
  // calculate real-time mark twap
@@ -89,8 +90,8 @@ export async function calculateAllEstimatedFundingRate(
89
90
  .mul(new BN(100))
90
91
  .div(lastOracleTwapWithMantissa);
91
92
 
92
- // verify pyth live input is within 10% of last twap for live update
93
- if (oracleLiveVsTwap.lte(PRICE_PRECISION.mul(new BN(10)))) {
93
+ // verify pyth live input is within 20% of last twap for live update
94
+ if (oracleLiveVsTwap.lte(PRICE_PRECISION.mul(new BN(20)))) {
94
95
  oracleTwapWithMantissa = oracleTwapTimeSinceLastUpdate
95
96
  .mul(lastOracleTwapWithMantissa)
96
97
  .add(timeSinceLastMarkChange.mul(oraclePrice))
@@ -99,13 +100,11 @@ export async function calculateAllEstimatedFundingRate(
99
100
  }
100
101
 
101
102
  const shrunkLastOracleTwapwithMantissa = oracleTwapTimeSinceLastUpdate
102
- .mul(lastOracleTwapWithMantissa)
103
+ .mul(oracleTwapWithMantissa)
103
104
  .add(oracleInvalidDuration.mul(lastMarkTwapWithMantissa))
104
105
  .div(oracleTwapTimeSinceLastUpdate.add(oracleInvalidDuration));
105
106
 
106
- const twapSpread = lastMarkTwapWithMantissa.sub(
107
- shrunkLastOracleTwapwithMantissa
108
- );
107
+ const twapSpread = markTwapWithMantissa.sub(shrunkLastOracleTwapwithMantissa);
109
108
 
110
109
  const twapSpreadPct = twapSpread
111
110
  .mul(PRICE_PRECISION)
@@ -131,7 +131,11 @@ export function calculateAssetWeight(
131
131
  );
132
132
  break;
133
133
  case 'Maintenance':
134
- assetWeight = new BN(spotMarket.maintenanceAssetWeight);
134
+ assetWeight = calculateSizeDiscountAssetWeight(
135
+ sizeInAmmReservePrecision,
136
+ new BN(spotMarket.imfFactor),
137
+ new BN(spotMarket.maintenanceAssetWeight)
138
+ );
135
139
  break;
136
140
  default:
137
141
  assetWeight = new BN(spotMarket.initialAssetWeight);
@@ -322,12 +326,15 @@ export function calculateWithdrawLimit(
322
326
  .add(marketDepositTokenAmount.mul(sinceLast))
323
327
  .div(sinceLast.add(sinceStart));
324
328
 
325
- const maxBorrowTokens = BN.min(
326
- BN.max(
327
- marketDepositTokenAmount.div(new BN(6)),
328
- borrowTokenTwapLive.add(borrowTokenTwapLive.div(new BN(5)))
329
- ),
330
- marketDepositTokenAmount.sub(marketDepositTokenAmount.div(new BN(5)))
329
+ const maxBorrowTokens = BN.max(
330
+ spotMarket.withdrawGuardThreshold,
331
+ BN.min(
332
+ BN.max(
333
+ marketDepositTokenAmount.div(new BN(6)),
334
+ borrowTokenTwapLive.add(borrowTokenTwapLive.div(new BN(5)))
335
+ ),
336
+ marketDepositTokenAmount.sub(marketDepositTokenAmount.div(new BN(5)))
337
+ )
331
338
  ); // between ~15-80% utilization with friction on twap
332
339
 
333
340
  const minDepositTokens = depositTokenTwapLive.sub(
@@ -10,7 +10,7 @@ export function parseTokenAccount(data: Buffer): AccountInfo {
10
10
  if (accountInfo.delegateOption === 0) {
11
11
  accountInfo.delegate = null;
12
12
  // eslint-disable-next-line new-cap
13
- accountInfo.delegatedAmount = new u64(0);
13
+ accountInfo.delegatedAmount = u64.fromBuffer(Buffer.from('0'));
14
14
  } else {
15
15
  accountInfo.delegate = new PublicKey(accountInfo.delegate);
16
16
  accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount);
package/src/user.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  PerpPosition,
11
11
  SpotPosition,
12
12
  isOneOfVariant,
13
+ PerpMarketAccount,
13
14
  } from './types';
14
15
  import { calculateEntryPrice } from './math/position';
15
16
  import {
@@ -20,13 +21,13 @@ import {
20
21
  BN_MAX,
21
22
  QUOTE_PRECISION,
22
23
  AMM_RESERVE_PRECISION,
23
- PRICE_TO_QUOTE_PRECISION,
24
24
  MARGIN_PRECISION,
25
25
  SPOT_MARKET_WEIGHT_PRECISION,
26
26
  QUOTE_SPOT_MARKET_INDEX,
27
27
  TEN,
28
28
  OPEN_ORDER_MARGIN_REQUIREMENT,
29
29
  FIVE_MINUTE,
30
+ BASE_PRECISION,
30
31
  } from './constants/numericConstants';
31
32
  import {
32
33
  UserAccountSubscriber,
@@ -45,6 +46,7 @@ import {
45
46
  SpotMarketAccount,
46
47
  getTokenValue,
47
48
  getStrictTokenValue,
49
+ getSignedTokenAmount,
48
50
  } from '.';
49
51
  import {
50
52
  getTokenAmount,
@@ -1279,238 +1281,244 @@ export class User {
1279
1281
  }
1280
1282
 
1281
1283
  /**
1282
- * Calculate the liquidation price of a perp position, with optional parameter to calculate the liquidation price after a trade
1283
- * @param PerpPosition
1284
- * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
1285
- * @param partial
1284
+ * Calculate the liquidation price of a spot position
1285
+ * @param marketIndex
1286
1286
  * @returns Precision : PRICE_PRECISION
1287
1287
  */
1288
- public spotLiquidationPrice(
1289
- spotPosition: Pick<SpotPosition, 'marketIndex'>
1290
- ): BN {
1291
- const currentSpotPosition = this.getSpotPosition(spotPosition.marketIndex);
1288
+ public spotLiquidationPrice(marketIndex: number): BN {
1289
+ const currentSpotPosition = this.getSpotPosition(marketIndex);
1292
1290
 
1293
1291
  if (!currentSpotPosition) {
1294
1292
  return new BN(-1);
1295
1293
  }
1296
1294
 
1297
- const mtc = this.getTotalCollateral('Maintenance');
1298
- const mmr = this.getMaintenanceMarginRequirement();
1299
-
1300
- const deltaValueToLiq = mtc.sub(mmr); // QUOTE_PRECISION
1301
-
1302
- const currentSpotMarket = this.driftClient.getSpotMarketAccount(
1303
- spotPosition.marketIndex
1295
+ const totalCollateral = this.getTotalCollateral('Maintenance');
1296
+ const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
1297
+ const freeCollateral = BN.max(
1298
+ ZERO,
1299
+ totalCollateral.sub(maintenanceMarginRequirement)
1304
1300
  );
1305
- const tokenAmount = getTokenAmount(
1306
- currentSpotPosition.scaledBalance,
1307
- currentSpotMarket,
1301
+
1302
+ const market = this.driftClient.getSpotMarketAccount(marketIndex);
1303
+ const signedTokenAmount = getSignedTokenAmount(
1304
+ getTokenAmount(
1305
+ currentSpotPosition.scaledBalance,
1306
+ market,
1307
+ currentSpotPosition.balanceType
1308
+ ),
1308
1309
  currentSpotPosition.balanceType
1309
1310
  );
1310
- const tokenAmountQP = tokenAmount
1311
- .mul(QUOTE_PRECISION)
1312
- .div(new BN(10 ** currentSpotMarket.decimals));
1313
1311
 
1314
- if (tokenAmountQP.abs().eq(ZERO)) {
1312
+ if (signedTokenAmount.eq(ZERO)) {
1315
1313
  return new BN(-1);
1316
1314
  }
1317
- let liqPriceDelta: BN;
1318
- if (isVariant(currentSpotPosition.balanceType, 'borrow')) {
1319
- liqPriceDelta = deltaValueToLiq
1320
- .mul(PRICE_PRECISION)
1321
- .mul(SPOT_MARKET_WEIGHT_PRECISION)
1322
- .div(tokenAmountQP)
1323
- .div(new BN(currentSpotMarket.maintenanceLiabilityWeight));
1324
- } else {
1325
- liqPriceDelta = deltaValueToLiq
1326
- .mul(PRICE_PRECISION)
1327
- .mul(SPOT_MARKET_WEIGHT_PRECISION)
1328
- .div(tokenAmountQP)
1329
- .div(new BN(currentSpotMarket.maintenanceAssetWeight))
1330
- .mul(new BN(-1));
1315
+
1316
+ let freeCollateralDelta = this.calculateFreeCollateralDeltaForSpot(
1317
+ market,
1318
+ signedTokenAmount
1319
+ );
1320
+
1321
+ const oracle = market.oracle;
1322
+ const perpMarketWithSameOracle = this.driftClient
1323
+ .getPerpMarketAccounts()
1324
+ .find((market) => market.amm.oracle.equals(oracle));
1325
+ if (perpMarketWithSameOracle) {
1326
+ const perpPosition = this.getPerpPosition(
1327
+ perpMarketWithSameOracle.marketIndex
1328
+ );
1329
+ if (perpPosition) {
1330
+ const freeCollateralDeltaForPerp =
1331
+ this.calculateFreeCollateralDeltaForPerp(
1332
+ perpMarketWithSameOracle,
1333
+ perpPosition,
1334
+ ZERO
1335
+ );
1336
+
1337
+ freeCollateralDelta = freeCollateralDelta.add(
1338
+ freeCollateralDeltaForPerp || ZERO
1339
+ );
1340
+ }
1331
1341
  }
1332
1342
 
1333
- const currentPrice = this.driftClient.getOracleDataForSpotMarket(
1334
- spotPosition.marketIndex
1335
- ).price;
1343
+ if (freeCollateralDelta.eq(ZERO)) {
1344
+ return new BN(-1);
1345
+ }
1346
+
1347
+ const oraclePrice =
1348
+ this.driftClient.getOracleDataForSpotMarket(marketIndex).price;
1349
+ const liqPriceDelta = freeCollateral
1350
+ .mul(QUOTE_PRECISION)
1351
+ .div(freeCollateralDelta);
1336
1352
 
1337
- const liqPrice = currentPrice.add(liqPriceDelta);
1353
+ const liqPrice = oraclePrice.sub(liqPriceDelta);
1354
+
1355
+ if (liqPrice.lt(ZERO)) {
1356
+ return new BN(-1);
1357
+ }
1338
1358
 
1339
1359
  return liqPrice;
1340
1360
  }
1341
1361
 
1342
1362
  /**
1343
1363
  * Calculate the liquidation price of a perp position, with optional parameter to calculate the liquidation price after a trade
1344
- * @param PerpPosition
1364
+ * @param marketIndex
1345
1365
  * @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
1346
- * @param partial
1347
1366
  * @returns Precision : PRICE_PRECISION
1348
1367
  */
1349
1368
  public liquidationPrice(
1350
- perpPosition: Pick<PerpPosition, 'marketIndex'>,
1369
+ marketIndex: number,
1351
1370
  positionBaseSizeChange: BN = ZERO
1352
1371
  ): BN {
1353
- // solves formula for example canBeLiquidated below
1354
-
1355
- /* example: assume BTC price is $40k (examine 10% up/down)
1372
+ const totalCollateral = this.getTotalCollateral('Maintenance');
1373
+ const maintenanceMarginRequirement = this.getMaintenanceMarginRequirement();
1374
+ const freeCollateral = BN.max(
1375
+ ZERO,
1376
+ totalCollateral.sub(maintenanceMarginRequirement)
1377
+ );
1356
1378
 
1357
- if 10k deposit and levered 10x short BTC => BTC up $400 means:
1358
- 1. higher base_asset_value (+$4k)
1359
- 2. lower collateral (-$4k)
1360
- 3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
1379
+ const market = this.driftClient.getPerpMarketAccount(marketIndex);
1380
+ const currentPerpPosition = this.getPerpPosition(marketIndex);
1361
1381
 
1362
- for 10x long, BTC down $400:
1363
- 3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
1382
+ let freeCollateralDelta = this.calculateFreeCollateralDeltaForPerp(
1383
+ market,
1384
+ currentPerpPosition,
1385
+ positionBaseSizeChange
1386
+ );
1364
1387
 
1365
- const totalCollateral = this.getTotalCollateral('Maintenance');
1388
+ if (!freeCollateralDelta) {
1389
+ return new BN(-1);
1390
+ }
1366
1391
 
1367
- // calculate the total position value ignoring any value from the target market of the trade
1368
- const totalPositionValueExcludingTargetMarket =
1369
- this.getTotalPerpPositionValueExcludingMarket(
1370
- perpPosition.marketIndex,
1371
- undefined,
1372
- undefined,
1373
- true
1392
+ const oracle =
1393
+ this.driftClient.getPerpMarketAccount(marketIndex).amm.oracle;
1394
+ const spotMarketWithSameOracle = this.driftClient
1395
+ .getSpotMarketAccounts()
1396
+ .find((market) => market.oracle.equals(oracle));
1397
+ if (spotMarketWithSameOracle) {
1398
+ const spotPosition = this.getSpotPosition(
1399
+ spotMarketWithSameOracle.marketIndex
1374
1400
  );
1401
+ if (spotPosition) {
1402
+ const signedTokenAmount = getSignedTokenAmount(
1403
+ getTokenAmount(
1404
+ spotPosition.scaledBalance,
1405
+ spotMarketWithSameOracle,
1406
+ spotPosition.balanceType
1407
+ ),
1408
+ spotPosition.balanceType
1409
+ );
1375
1410
 
1376
- const currentPerpPosition =
1377
- this.getPerpPosition(perpPosition.marketIndex) ||
1378
- this.getEmptyPosition(perpPosition.marketIndex);
1411
+ const spotFreeCollateralDelta =
1412
+ this.calculateFreeCollateralDeltaForSpot(
1413
+ spotMarketWithSameOracle,
1414
+ signedTokenAmount
1415
+ );
1416
+ freeCollateralDelta = freeCollateralDelta.add(
1417
+ spotFreeCollateralDelta || ZERO
1418
+ );
1419
+ }
1420
+ }
1379
1421
 
1380
- const currentPerpPositionBaseSize = currentPerpPosition.baseAssetAmount;
1422
+ if (freeCollateralDelta.eq(ZERO)) {
1423
+ return new BN(-1);
1424
+ }
1381
1425
 
1382
- const proposedBaseAssetAmount = currentPerpPositionBaseSize.add(
1383
- positionBaseSizeChange
1384
- );
1426
+ const oraclePrice =
1427
+ this.driftClient.getOracleDataForPerpMarket(marketIndex).price;
1428
+ const liqPriceDelta = freeCollateral
1429
+ .mul(QUOTE_PRECISION)
1430
+ .div(freeCollateralDelta);
1385
1431
 
1386
- // calculate position for current market after trade
1387
- const proposedPerpPosition: PerpPosition = {
1388
- marketIndex: perpPosition.marketIndex,
1389
- baseAssetAmount: proposedBaseAssetAmount,
1390
- remainderBaseAssetAmount: 0,
1391
- quoteAssetAmount: currentPerpPosition.quoteAssetAmount,
1392
- lastCumulativeFundingRate: ZERO,
1393
- quoteBreakEvenAmount: new BN(0),
1394
- quoteEntryAmount: new BN(0),
1395
- openOrders: 0,
1396
- openBids: currentPerpPosition.openBids,
1397
- openAsks: currentPerpPosition.openAsks,
1398
- settledPnl: ZERO,
1399
- lpShares: ZERO,
1400
- lastBaseAssetAmountPerLp: ZERO,
1401
- lastQuoteAssetAmountPerLp: ZERO,
1402
- };
1432
+ const liqPrice = oraclePrice.sub(liqPriceDelta);
1403
1433
 
1404
- if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
1434
+ if (liqPrice.lt(ZERO)) {
1435
+ return new BN(-1);
1436
+ }
1405
1437
 
1406
- const market = this.driftClient.getPerpMarketAccount(
1407
- proposedPerpPosition.marketIndex
1408
- );
1438
+ return liqPrice;
1439
+ }
1409
1440
 
1410
- const proposedPerpPositionValue = calculateBaseAssetValueWithOracle(
1411
- market,
1412
- proposedPerpPosition,
1413
- this.getOracleDataForPerpMarket(market.marketIndex),
1414
- true
1441
+ calculateFreeCollateralDeltaForPerp(
1442
+ market: PerpMarketAccount,
1443
+ perpPosition: PerpPosition,
1444
+ positionBaseSizeChange: BN
1445
+ ): BN | undefined {
1446
+ const currentBaseAssetAmount = perpPosition.baseAssetAmount;
1447
+
1448
+ const worstCaseBaseAssetAmount =
1449
+ calculateWorstCaseBaseAssetAmount(perpPosition);
1450
+ const orderBaseAssetAmount = worstCaseBaseAssetAmount.sub(
1451
+ currentBaseAssetAmount
1452
+ );
1453
+ const proposedBaseAssetAmount = currentBaseAssetAmount.add(
1454
+ positionBaseSizeChange
1455
+ );
1456
+ const proposedWorstCaseBaseAssetAmount = worstCaseBaseAssetAmount.add(
1457
+ positionBaseSizeChange
1415
1458
  );
1416
1459
 
1417
- // total position value after trade
1418
- const totalPositionValueAfterTrade =
1419
- totalPositionValueExcludingTargetMarket.add(proposedPerpPositionValue);
1420
-
1421
- const marginRequirementOfAll = this.getMaintenanceMarginRequirement();
1422
- const positionValue = calculateBaseAssetValueWithOracle(
1460
+ const marginRatio = calculateMarketMarginRatio(
1423
1461
  market,
1424
- currentPerpPosition,
1425
- this.getOracleDataForPerpMarket(market.marketIndex),
1426
- true
1462
+ proposedWorstCaseBaseAssetAmount.abs(),
1463
+ 'Maintenance'
1427
1464
  );
1428
- const marginRequirementOfTargetMarket = positionValue
1429
- .mul(
1430
- new BN(
1431
- calculateMarketMarginRatio(
1432
- market,
1433
- calculateWorstCaseBaseAssetAmount(currentPerpPosition).abs(),
1434
- 'Maintenance'
1435
- )
1436
- )
1437
- )
1465
+ const marginRatioQuotePrecision = new BN(marginRatio)
1466
+ .mul(QUOTE_PRECISION)
1438
1467
  .div(MARGIN_PRECISION);
1439
1468
 
1440
- const marginRequirementExcludingTargetMarket = marginRequirementOfAll.sub(
1441
- marginRequirementOfTargetMarket
1442
- );
1469
+ if (proposedWorstCaseBaseAssetAmount.eq(ZERO)) {
1470
+ return undefined;
1471
+ }
1443
1472
 
1444
- const freeCollateralExcludingTargetMarket = totalCollateral.sub(
1445
- marginRequirementExcludingTargetMarket
1446
- );
1473
+ let freeCollateralDelta = ZERO;
1474
+ if (proposedBaseAssetAmount.gt(ZERO)) {
1475
+ freeCollateralDelta = QUOTE_PRECISION.sub(marginRatioQuotePrecision)
1476
+ .mul(proposedBaseAssetAmount)
1477
+ .div(BASE_PRECISION);
1478
+ } else {
1479
+ freeCollateralDelta = QUOTE_PRECISION.neg()
1480
+ .sub(marginRatioQuotePrecision)
1481
+ .mul(proposedBaseAssetAmount.abs())
1482
+ .div(BASE_PRECISION);
1483
+ }
1447
1484
 
1448
- // if the position value after the trade is less than free collateral, there is no liq price
1449
- if (
1450
- totalPositionValueAfterTrade.lte(freeCollateralExcludingTargetMarket) &&
1451
- proposedPerpPosition.baseAssetAmount.gt(ZERO)
1452
- ) {
1453
- return new BN(-1);
1485
+ if (!orderBaseAssetAmount.eq(ZERO)) {
1486
+ freeCollateralDelta = freeCollateralDelta.sub(marginRatioQuotePrecision);
1454
1487
  }
1455
1488
 
1456
- const proposedWorstCastBaseAssetAmount =
1457
- calculateWorstCaseBaseAssetAmount(proposedPerpPosition);
1458
- const marginRequirementTargetMarket = proposedPerpPositionValue
1459
- .mul(
1460
- new BN(
1461
- calculateMarketMarginRatio(
1462
- market,
1463
- proposedWorstCastBaseAssetAmount.abs(),
1464
- 'Maintenance'
1465
- )
1466
- )
1467
- )
1468
- .div(MARGIN_PRECISION);
1489
+ return freeCollateralDelta;
1490
+ }
1469
1491
 
1470
- const marginRequirementAfterTrade =
1471
- marginRequirementExcludingTargetMarket.add(marginRequirementTargetMarket);
1472
- const freeCollateralAfterTrade = totalCollateral.sub(
1473
- marginRequirementAfterTrade
1474
- );
1492
+ calculateFreeCollateralDeltaForSpot(
1493
+ market: SpotMarketAccount,
1494
+ signedTokenAmount: BN
1495
+ ): BN {
1496
+ const tokenPrecision = new BN(Math.pow(10, market.decimals));
1475
1497
 
1476
- const marketMaxMaintLeverage = new BN(
1477
- TEN_THOUSAND.mul(TEN_THOUSAND).toNumber() /
1478
- calculateMarketMarginRatio(
1479
- market,
1480
- proposedWorstCastBaseAssetAmount.abs(),
1481
- 'Maintenance'
1482
- )
1483
- );
1498
+ if (signedTokenAmount.gt(ZERO)) {
1499
+ const assetWeight = calculateAssetWeight(
1500
+ signedTokenAmount,
1501
+ market,
1502
+ 'Maintenance'
1503
+ );
1484
1504
 
1485
- let priceDelta;
1486
- if (proposedBaseAssetAmount.lt(ZERO)) {
1487
- priceDelta = freeCollateralAfterTrade
1488
- .mul(marketMaxMaintLeverage) // precision is TEN_THOUSAND
1489
- .div(marketMaxMaintLeverage.add(TEN_THOUSAND))
1490
- .mul(PRICE_TO_QUOTE_PRECISION)
1491
- .mul(AMM_RESERVE_PRECISION)
1492
- .div(proposedBaseAssetAmount);
1505
+ return QUOTE_PRECISION.mul(assetWeight)
1506
+ .div(SPOT_MARKET_WEIGHT_PRECISION)
1507
+ .mul(signedTokenAmount)
1508
+ .div(tokenPrecision);
1493
1509
  } else {
1494
- priceDelta = freeCollateralAfterTrade
1495
- .mul(marketMaxMaintLeverage) // precision is TEN_THOUSAND
1496
- .div(marketMaxMaintLeverage.sub(TEN_THOUSAND))
1497
- .mul(PRICE_TO_QUOTE_PRECISION)
1498
- .mul(AMM_RESERVE_PRECISION)
1499
- .div(proposedBaseAssetAmount);
1500
- }
1501
-
1502
- const currentPrice = this.getOracleDataForPerpMarket(
1503
- perpPosition.marketIndex
1504
- ).price;
1510
+ const liabilityWeight = calculateLiabilityWeight(
1511
+ signedTokenAmount.abs(),
1512
+ market,
1513
+ 'Maintenance'
1514
+ );
1505
1515
 
1506
- if (
1507
- priceDelta.gt(currentPrice) &&
1508
- proposedPerpPosition.baseAssetAmount.gte(ZERO)
1509
- ) {
1510
- return new BN(-1);
1516
+ return QUOTE_PRECISION.neg()
1517
+ .mul(liabilityWeight)
1518
+ .div(SPOT_MARKET_WEIGHT_PRECISION)
1519
+ .mul(signedTokenAmount.abs())
1520
+ .div(tokenPrecision);
1511
1521
  }
1512
-
1513
- return currentPrice.sub(priceDelta);
1514
1522
  }
1515
1523
 
1516
1524
  /**
@@ -1537,12 +1545,7 @@ export class User {
1537
1545
  )
1538
1546
  .neg();
1539
1547
 
1540
- return this.liquidationPrice(
1541
- {
1542
- marketIndex: positionMarketIndex,
1543
- },
1544
- closeBaseAmount
1545
- );
1548
+ return this.liquidationPrice(positionMarketIndex, closeBaseAmount);
1546
1549
  }
1547
1550
 
1548
1551
  /**
@@ -1845,7 +1848,7 @@ export class User {
1845
1848
  return {
1846
1849
  canBypass: false,
1847
1850
  maxDepositAmount,
1848
- depositAmount: ZERO,
1851
+ depositAmount,
1849
1852
  netDeposits,
1850
1853
  };
1851
1854
  }
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assert = void 0;
4
- function assert(condition, error) {
5
- if (!condition) {
6
- throw new Error(error || 'Unspecified AssertionError');
7
- }
8
- }
9
- exports.assert = assert;
@@ -1,38 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseTokenAccount = void 0;
4
- const spl_token_1 = require("@solana/spl-token");
5
- const web3_js_1 = require("@solana/web3.js");
6
- function parseTokenAccount(data) {
7
- const accountInfo = spl_token_1.AccountLayout.decode(data);
8
- accountInfo.mint = new web3_js_1.PublicKey(accountInfo.mint);
9
- accountInfo.owner = new web3_js_1.PublicKey(accountInfo.owner);
10
- accountInfo.amount = spl_token_1.u64.fromBuffer(accountInfo.amount);
11
- if (accountInfo.delegateOption === 0) {
12
- accountInfo.delegate = null;
13
- // eslint-disable-next-line new-cap
14
- accountInfo.delegatedAmount = new spl_token_1.u64(0);
15
- }
16
- else {
17
- accountInfo.delegate = new web3_js_1.PublicKey(accountInfo.delegate);
18
- accountInfo.delegatedAmount = spl_token_1.u64.fromBuffer(accountInfo.delegatedAmount);
19
- }
20
- accountInfo.isInitialized = accountInfo.state !== 0;
21
- accountInfo.isFrozen = accountInfo.state === 2;
22
- if (accountInfo.isNativeOption === 1) {
23
- accountInfo.rentExemptReserve = spl_token_1.u64.fromBuffer(accountInfo.isNative);
24
- accountInfo.isNative = true;
25
- }
26
- else {
27
- accountInfo.rentExemptReserve = null;
28
- accountInfo.isNative = false;
29
- }
30
- if (accountInfo.closeAuthorityOption === 0) {
31
- accountInfo.closeAuthority = null;
32
- }
33
- else {
34
- accountInfo.closeAuthority = new web3_js_1.PublicKey(accountInfo.closeAuthority);
35
- }
36
- return accountInfo;
37
- }
38
- exports.parseTokenAccount = parseTokenAccount;
package/src/tx/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
package/src/tx/utils.js DELETED
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrapInTx = void 0;
4
- const web3_js_1 = require("@solana/web3.js");
5
- const COMPUTE_UNITS_DEFAULT = 200000;
6
- function wrapInTx(instruction, computeUnits = 600000 // TODO, requires less code change
7
- ) {
8
- const tx = new web3_js_1.Transaction();
9
- if (computeUnits != COMPUTE_UNITS_DEFAULT) {
10
- tx.add(web3_js_1.ComputeBudgetProgram.requestUnits({
11
- units: computeUnits,
12
- additionalFee: 0,
13
- }));
14
- }
15
- return tx.add(instruction);
16
- }
17
- exports.wrapInTx = wrapInTx;
@@ -1,27 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.findComputeUnitConsumption = void 0;
13
- function findComputeUnitConsumption(programId, connection, txSignature, commitment = 'confirmed') {
14
- return __awaiter(this, void 0, void 0, function* () {
15
- const tx = yield connection.getTransaction(txSignature, { commitment });
16
- const computeUnits = [];
17
- const regex = new RegExp(`Program ${programId.toString()} consumed ([0-9]{0,6}) of ([0-9]{0,7}) compute units`);
18
- tx.meta.logMessages.forEach((logMessage) => {
19
- const match = logMessage.match(regex);
20
- if (match && match[1]) {
21
- computeUnits.push(match[1]);
22
- }
23
- });
24
- return computeUnits;
25
- });
26
- }
27
- exports.findComputeUnitConsumption = findComputeUnitConsumption;
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getTokenAddress = void 0;
4
- const spl_token_1 = require("@solana/spl-token");
5
- const web3_js_1 = require("@solana/web3.js");
6
- const getTokenAddress = (mintAddress, userPubKey) => {
7
- return spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
8
- };
9
- exports.getTokenAddress = getTokenAddress;