@velocity-exchange/sdk 0.6.1 → 0.8.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 (82) hide show
  1. package/lib/browser/adminClient.d.ts +24 -4
  2. package/lib/browser/adminClient.js +62 -12
  3. package/lib/browser/blockhashSubscriber/BlockhashSubscriber.d.ts +19 -15
  4. package/lib/browser/blockhashSubscriber/BlockhashSubscriber.js +31 -22
  5. package/lib/browser/constants/numericConstants.d.ts +2 -0
  6. package/lib/browser/constants/numericConstants.js +3 -1
  7. package/lib/browser/core/VelocityCore.d.ts +2 -0
  8. package/lib/browser/core/VelocityCore.js +1 -0
  9. package/lib/browser/core/instructions/trigger.d.ts +4 -0
  10. package/lib/browser/core/instructions/trigger.js +4 -0
  11. package/lib/browser/idl/velocity.d.ts +223 -33
  12. package/lib/browser/idl/velocity.json +224 -34
  13. package/lib/browser/math/amm.d.ts +8 -8
  14. package/lib/browser/math/funding.d.ts +2 -2
  15. package/lib/browser/math/liquidation.d.ts +37 -2
  16. package/lib/browser/math/liquidation.js +44 -3
  17. package/lib/browser/math/market.d.ts +5 -4
  18. package/lib/browser/math/market.js +21 -14
  19. package/lib/browser/math/oracles.d.ts +3 -3
  20. package/lib/browser/math/orders.d.ts +1 -1
  21. package/lib/browser/math/spotBalance.d.ts +13 -0
  22. package/lib/browser/math/spotBalance.js +43 -2
  23. package/lib/browser/testClient.js +12 -1
  24. package/lib/browser/tx/txHandler.d.ts +7 -1
  25. package/lib/browser/tx/txHandler.js +7 -3
  26. package/lib/browser/types.d.ts +9 -0
  27. package/lib/browser/user.d.ts +2 -2
  28. package/lib/browser/userMap/userMap.d.ts +1 -0
  29. package/lib/browser/userMap/userMap.js +3 -7
  30. package/lib/browser/velocityClient.d.ts +32 -20
  31. package/lib/browser/velocityClient.js +48 -23
  32. package/lib/node/adminClient.d.ts +24 -4
  33. package/lib/node/adminClient.d.ts.map +1 -1
  34. package/lib/node/adminClient.js +62 -12
  35. package/lib/node/blockhashSubscriber/BlockhashSubscriber.d.ts +19 -15
  36. package/lib/node/blockhashSubscriber/BlockhashSubscriber.d.ts.map +1 -1
  37. package/lib/node/blockhashSubscriber/BlockhashSubscriber.js +31 -22
  38. package/lib/node/constants/numericConstants.d.ts +2 -0
  39. package/lib/node/constants/numericConstants.d.ts.map +1 -1
  40. package/lib/node/constants/numericConstants.js +3 -1
  41. package/lib/node/core/VelocityCore.d.ts +2 -0
  42. package/lib/node/core/VelocityCore.d.ts.map +1 -1
  43. package/lib/node/core/VelocityCore.js +1 -0
  44. package/lib/node/core/instructions/trigger.d.ts +4 -0
  45. package/lib/node/core/instructions/trigger.d.ts.map +1 -1
  46. package/lib/node/core/instructions/trigger.js +4 -0
  47. package/lib/node/idl/velocity.d.ts +223 -33
  48. package/lib/node/idl/velocity.d.ts.map +1 -1
  49. package/lib/node/idl/velocity.json +224 -34
  50. package/lib/node/math/amm.d.ts +8 -8
  51. package/lib/node/math/amm.d.ts.map +1 -1
  52. package/lib/node/math/funding.d.ts +2 -2
  53. package/lib/node/math/funding.d.ts.map +1 -1
  54. package/lib/node/math/liquidation.d.ts +37 -2
  55. package/lib/node/math/liquidation.d.ts.map +1 -1
  56. package/lib/node/math/liquidation.js +44 -3
  57. package/lib/node/math/market.d.ts +5 -4
  58. package/lib/node/math/market.d.ts.map +1 -1
  59. package/lib/node/math/market.js +21 -14
  60. package/lib/node/math/oracles.d.ts +3 -3
  61. package/lib/node/math/oracles.d.ts.map +1 -1
  62. package/lib/node/math/orders.d.ts +1 -1
  63. package/lib/node/math/orders.d.ts.map +1 -1
  64. package/lib/node/math/spotBalance.d.ts +13 -0
  65. package/lib/node/math/spotBalance.d.ts.map +1 -1
  66. package/lib/node/math/spotBalance.js +43 -2
  67. package/lib/node/testClient.d.ts.map +1 -1
  68. package/lib/node/testClient.js +12 -1
  69. package/lib/node/tx/txHandler.d.ts +7 -1
  70. package/lib/node/tx/txHandler.d.ts.map +1 -1
  71. package/lib/node/tx/txHandler.js +7 -3
  72. package/lib/node/types.d.ts +9 -0
  73. package/lib/node/types.d.ts.map +1 -1
  74. package/lib/node/user.d.ts +2 -2
  75. package/lib/node/user.d.ts.map +1 -1
  76. package/lib/node/userMap/userMap.d.ts +1 -0
  77. package/lib/node/userMap/userMap.d.ts.map +1 -1
  78. package/lib/node/userMap/userMap.js +3 -7
  79. package/lib/node/velocityClient.d.ts +32 -20
  80. package/lib/node/velocityClient.d.ts.map +1 -1
  81. package/lib/node/velocityClient.js +48 -23
  82. package/package.json +1 -1
@@ -244,10 +244,11 @@ exports.calculateNetUserPnlImbalance = calculateNetUserPnlImbalance;
244
244
  /**
245
245
  * Calculates the price used to evaluate trigger (stop/take-profit) orders for a perp market,
246
246
  * mirroring the Rust `get_trigger_price`. When `useMedianPrice` is true, the trigger price is the
247
- * median of three candidates — the last fill price (or oracle price if there's been no fill), the
248
- * oracle price adjusted by the implied funding basis, and the oracle price adjusted by the 5min
249
- * mark/oracle TWAP basis then clamped to within a contract-tier-dependent band around the raw
250
- * oracle price (tier A/B: 20bps, tier C: 100bps, others: 250bps) via `clampTriggerPrice`. This
247
+ * median of three candidates — the last fill price (or oracle price if there's been no fill or the
248
+ * last fill is older than `TRIGGER_PRICE_LAST_FILL_MAX_AGE`), the oracle price adjusted by the
249
+ * implied funding basis, and the oracle price adjusted by the 5min mark/oracle TWAP basis — then
250
+ * clamped to within a contract-tier-dependent band around the raw oracle price (tier A/B: 20bps,
251
+ * tier C: 100bps, others: 250bps) via `clampTriggerPrice`. This
251
252
  * resists a single manipulated print (last fill or a momentary oracle/mark divergence) from
252
253
  * triggering orders it shouldn't. When `useMedianPrice` is false, the raw oracle price is used
253
254
  * directly with no smoothing.
@@ -265,17 +266,23 @@ function getTriggerPrice(market, oraclePrice, now, useMedianPrice) {
265
266
  if (!useMedianPrice) {
266
267
  return oraclePrice.abs();
267
268
  }
269
+ // Leg A: last trade price, only while fresh. `lastTradeTs` is stamped by
270
+ // the same fill path that writes `lastFillPrice`.
268
271
  const lastFillPrice = market.lastFillPrice;
269
- // Calculate 5-minute basis
272
+ const lastFillIsFresh = now
273
+ .sub(market.marketStats.lastTradeTs)
274
+ .lte(numericConstants_1.TRIGGER_PRICE_LAST_FILL_MAX_AGE);
275
+ // Leg C: oracle + (mark_twap_5min - oracle_twap_5min)
270
276
  const markPrice5minTwap = market.marketStats.lastMarkPriceTwap5Min;
271
277
  const lastOraclePriceTwap5min = market.marketStats.historicalOracleData.lastOraclePriceTwap5Min;
272
278
  const basis5min = markPrice5minTwap.sub(lastOraclePriceTwap5min);
273
279
  const oraclePlusBasis5min = oraclePrice.add(basis5min);
274
- // Calculate funding basis
280
+ // Leg B: oracle + decayed funding basis
275
281
  const lastFundingBasis = getLastFundingBasis(market, oraclePrice, now);
276
282
  const oraclePlusFundingBasis = oraclePrice.add(lastFundingBasis);
283
+ // No fill yet or last fill is stale: oracle price stands in for Leg A
277
284
  const prices = [
278
- lastFillPrice.gt(numericConstants_1.ZERO) ? lastFillPrice : oraclePrice,
285
+ lastFillPrice.gt(numericConstants_1.ZERO) && lastFillIsFresh ? lastFillPrice : oraclePrice,
279
286
  oraclePlusFundingBasis,
280
287
  oraclePlusBasis5min,
281
288
  ].sort((a, b) => a.cmp(b));
@@ -294,11 +301,11 @@ function getLastFundingBasis(market, oraclePrice, now) {
294
301
  .div(market.marketStats.lastFundingOracleTwap)
295
302
  .muln(24);
296
303
  const lastFundingRatePreAdj = lastFundingRate.sub(numericConstants_1.FUNDING_RATE_OFFSET_PERCENTAGE);
297
- const timeLeftUntilFundingUpdate = anchor_1.BN.min(anchor_1.BN.max(now.sub(market.lastFundingRateTs), numericConstants_1.ZERO), market.marketStats.fundingPeriod);
304
+ const timeSinceFundingUpdate = anchor_1.BN.min(anchor_1.BN.max(now.sub(market.lastFundingRateTs), numericConstants_1.ZERO), market.marketStats.fundingPeriod);
298
305
  const lastFundingBasis = oraclePrice
299
306
  .mul(lastFundingRatePreAdj)
300
307
  .div(numericConstants_1.PERCENTAGE_PRECISION)
301
- .mul(market.marketStats.fundingPeriod.sub(timeLeftUntilFundingUpdate))
308
+ .mul(market.marketStats.fundingPeriod.sub(timeSinceFundingUpdate))
302
309
  .div(market.marketStats.fundingPeriod)
303
310
  .div(new anchor_1.BN(1000)); // FUNDING_RATE_BUFFER
304
311
  return lastFundingBasis;
@@ -312,17 +319,17 @@ function getLastFundingBasis(market, oraclePrice, now) {
312
319
  * Implements the same logic as the Rust clamp_trigger_price function
313
320
  */
314
321
  function clampTriggerPrice(market, oraclePrice, medianPrice) {
315
- let maxBpsDiff;
322
+ let clampDivisor;
316
323
  const tier = market.contractTier;
317
324
  if ((0, types_1.isVariant)(tier, 'a') || (0, types_1.isVariant)(tier, 'b')) {
318
- maxBpsDiff = new anchor_1.BN(500); // 20 BPS
325
+ clampDivisor = new anchor_1.BN(500); // oracle / 500 = 20 bps
319
326
  }
320
327
  else if ((0, types_1.isVariant)(tier, 'c')) {
321
- maxBpsDiff = new anchor_1.BN(100); // 100 BPS
328
+ clampDivisor = new anchor_1.BN(100); // oracle / 100 = 100 bps
322
329
  }
323
330
  else {
324
- maxBpsDiff = new anchor_1.BN(40); // 250 BPS
331
+ clampDivisor = new anchor_1.BN(40); // oracle / 40 = 250 bps
325
332
  }
326
- const maxOracleDiff = oraclePrice.div(maxBpsDiff);
333
+ const maxOracleDiff = oraclePrice.div(clampDivisor);
327
334
  return anchor_1.BN.min(anchor_1.BN.max(medianPrice, oraclePrice.sub(maxOracleDiff)), oraclePrice.add(maxOracleDiff));
328
335
  }
@@ -88,7 +88,7 @@ export declare function isMarkOracleTooDivergent(priceSpreadPct: BN, oracleGuard
88
88
  * @param period TWAP window length in seconds — pass `FIVE_MINUTE` for the 5-minute TWAP, otherwise the funding period is assumed.
89
89
  * @returns Live-projected oracle TWAP, PRICE_PRECISION (1e6).
90
90
  */
91
- export declare function calculateLiveOracleTwap(histOracleData: HistoricalOracleData, oraclePriceData: OraclePriceData, now: BN, period: BN): BN;
91
+ export declare function calculateLiveOracleTwap(histOracleData: HistoricalOracleData, oraclePriceData: Pick<OraclePriceData, 'price'>, now: BN, period: BN): BN;
92
92
  /**
93
93
  * Live-projected oracle price standard deviation, combining the live oracle price's
94
94
  * deviation from the freshly-projected 1hr and 5min TWAPs with the decayed stored
@@ -98,7 +98,7 @@ export declare function calculateLiveOracleTwap(histOracleData: HistoricalOracle
98
98
  * @param now Current unix timestamp (seconds).
99
99
  * @returns Live oracle price standard deviation, PRICE_PRECISION (1e6).
100
100
  */
101
- export declare function calculateLiveOracleStd(marketStats: MarketStats, oraclePriceData: OraclePriceData, now: BN): BN;
101
+ export declare function calculateLiveOracleStd(marketStats: MarketStats, oraclePriceData: Pick<OraclePriceData, 'price'>, now: BN): BN;
102
102
  /**
103
103
  * Live-projected oracle confidence interval as a fraction of `reservePrice`, floored by a
104
104
  * decaying lower bound derived from the market's last stored confidence (so confidence
@@ -111,7 +111,7 @@ export declare function calculateLiveOracleStd(marketStats: MarketStats, oracleP
111
111
  * @param now Current unix timestamp (seconds).
112
112
  * @returns Oracle confidence as a fraction of price, BID_ASK_SPREAD_PRECISION (1e6).
113
113
  */
114
- export declare function getNewOracleConfPct(marketStats: MarketStats, oraclePriceData: OraclePriceData, reservePrice: BN, now: BN): BN;
114
+ export declare function getNewOracleConfPct(marketStats: MarketStats, oraclePriceData: Pick<OraclePriceData, 'confidence'>, reservePrice: BN, now: BN): BN;
115
115
  /**
116
116
  * Returns the scale factor to convert a price quoted under `firstOracleSource` into the
117
117
  * equivalent price under `secondOracleSource`, for the Pyth Lazer "scaled" variants
@@ -89,7 +89,7 @@ export declare function calculateBaseAssetAmountForAmmToFulfill(order: Order, ma
89
89
  * @param mmOraclePriceData Current MM oracle price data.
90
90
  * @returns Fillable base asset amount up to the limit price, BASE_PRECISION (1e9).
91
91
  */
92
- export declare function calculateBaseAssetAmountToFillUpToLimitPrice(order: Order, amm: AMM, marketStats: MarketStats, orderStepSize: BN, orderTickSize: BN, limitPrice: BN, mmOraclePriceData: MMOraclePriceData): BN;
92
+ export declare function calculateBaseAssetAmountToFillUpToLimitPrice(order: Order, amm: AMM, marketStats: MarketStats, orderStepSize: BN, orderTickSize: BN, limitPrice: BN, mmOraclePriceData: Pick<MMOraclePriceData, 'price' | 'confidence'>): BN;
93
93
  /**
94
94
  * True if `order.maxTs` has passed as of `ts`. Never true for trigger orders, non-`open`
95
95
  * orders, or orders with no expiry (`maxTs == 0`).
@@ -241,6 +241,19 @@ export declare function calculateWithdrawLimit(spotMarket: SpotMarketAccount, no
241
241
  currentDepositAmount: BN;
242
242
  currentBorrowAmount: BN;
243
243
  };
244
+ /**
245
+ * Mirror of the program's `calculate_max_deposit_token_amount`. Returns the max
246
+ * resulting deposit token amount permitted by the daily deposit cap: growth up
247
+ * to `maxDepositBpsPerDay` above the 24h deposit TWAP, but never below the
248
+ * deposit guard threshold. Returns null when the cap is disabled (pct == 0).
249
+ */
250
+ export declare function calculateMaxDepositTokenAmount(depositTokenTwap: BN, depositGuardThreshold: BN, maxDepositBpsPerDay: number): BN | null;
251
+ /**
252
+ * Mirror of the program's `check_deposit_limits`. Returns true if the market's
253
+ * current deposit level is within the daily deposit cap (always true when the
254
+ * cap is disabled).
255
+ */
256
+ export declare function checkDepositLimits(spotMarket: SpotMarketAccount): boolean;
244
257
  /**
245
258
  * Calculates the margin-weighted value of a spot deposit, mirroring the asset-side of the
246
259
  * program's collateral valuation (`get_strict_token_value` + `get_asset_weight`). Uses the
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSpotLiabilityValue = exports.getSpotAssetValue = exports.calculateWithdrawLimit = exports.calculateTokenUtilizationLimits = exports.calculateInterestAccumulated = exports.calculateBorrowRate = exports.calculateDepositRate = exports.calculateInterestRate = exports.calculateSpotMarketBorrowCapacity = exports.calculateUtilization = exports.calculateLiabilityWeight = exports.calculateScaledInitialAssetWeight = exports.calculateAssetWeight = exports.getTokenValue = exports.getStrictTokenValue = exports.getSignedTokenAmount = exports.getTokenAmount = exports.getBalance = void 0;
3
+ exports.getSpotLiabilityValue = exports.getSpotAssetValue = exports.checkDepositLimits = exports.calculateMaxDepositTokenAmount = exports.calculateWithdrawLimit = exports.calculateTokenUtilizationLimits = exports.calculateInterestAccumulated = exports.calculateBorrowRate = exports.calculateDepositRate = exports.calculateInterestRate = exports.calculateSpotMarketBorrowCapacity = exports.calculateUtilization = exports.calculateLiabilityWeight = exports.calculateScaledInitialAssetWeight = exports.calculateAssetWeight = exports.getTokenValue = exports.getStrictTokenValue = exports.getSignedTokenAmount = exports.getTokenAmount = exports.getBalance = void 0;
4
4
  const types_1 = require("../types");
5
5
  const anchor_1 = require("../isomorphic/anchor");
6
6
  const numericConstants_1 = require("../constants/numericConstants");
@@ -571,7 +571,14 @@ function calculateWithdrawLimit(spotMarket, now) {
571
571
  else {
572
572
  maxBorrowTokensTwap = anchor_1.BN.max(spotMarket.withdrawGuardThreshold, anchor_1.BN.min(anchor_1.BN.max(lesserDepositAmount.div(new anchor_1.BN(2)), borrowTokenTwapLive.add(lesserDepositAmount.div(new anchor_1.BN(3)))), lesserDepositAmount.sub(lesserDepositAmount.div(new anchor_1.BN(20))))); // isolated pools between 50-95% utilization with friction on twap in 33% increments
573
573
  }
574
- const minDepositTokensTwap = depositTokenTwapLive.sub(anchor_1.BN.max(depositTokenTwapLive.div(new anchor_1.BN(4)), anchor_1.BN.min(spotMarket.withdrawGuardThreshold, depositTokenTwapLive)));
574
+ // 0 is treated as the default 25% (2500 bps) so markets created before the
575
+ // field existed keep prior behavior (mirrors calculate_min_deposit_token_amount).
576
+ // withdrawCircuitBreakerBps is in basis points (BPS_PRECISION = 10_000 = 100%).
577
+ const breakerPct = spotMarket.withdrawCircuitBreakerBps === 0
578
+ ? numericConstants_2.BPS_PRECISION.divn(4)
579
+ : new anchor_1.BN(spotMarket.withdrawCircuitBreakerBps);
580
+ const maxDrop = depositTokenTwapLive.mul(breakerPct).div(numericConstants_2.BPS_PRECISION);
581
+ const minDepositTokensTwap = depositTokenTwapLive.sub(anchor_1.BN.max(maxDrop, anchor_1.BN.min(spotMarket.withdrawGuardThreshold, depositTokenTwapLive)));
575
582
  const { minDepositTokensForUtilization, maxBorrowTokensForUtilization } = calculateTokenUtilizationLimits(marketDepositTokenAmount, marketBorrowTokenAmount, spotMarket);
576
583
  const minDepositTokens = anchor_1.BN.max(minDepositTokensForUtilization, minDepositTokensTwap);
577
584
  let maxBorrowTokens = anchor_1.BN.min(maxBorrowTokensForUtilization, maxBorrowTokensTwap);
@@ -599,6 +606,40 @@ function calculateWithdrawLimit(spotMarket, now) {
599
606
  };
600
607
  }
601
608
  exports.calculateWithdrawLimit = calculateWithdrawLimit;
609
+ /**
610
+ * Mirror of the program's `calculate_max_deposit_token_amount`. Returns the max
611
+ * resulting deposit token amount permitted by the daily deposit cap: growth up
612
+ * to `maxDepositBpsPerDay` above the 24h deposit TWAP, but never below the
613
+ * deposit guard threshold. Returns null when the cap is disabled (pct == 0).
614
+ */
615
+ function calculateMaxDepositTokenAmount(depositTokenTwap, depositGuardThreshold, maxDepositBpsPerDay) {
616
+ if (maxDepositBpsPerDay === 0) {
617
+ return null; // disabled
618
+ }
619
+ // maxDepositBpsPerDay is in basis points (BPS_PRECISION = 10_000 = 100%).
620
+ const maxIncrease = depositTokenTwap
621
+ .mul(new anchor_1.BN(maxDepositBpsPerDay))
622
+ .div(numericConstants_2.BPS_PRECISION);
623
+ return anchor_1.BN.max(depositTokenTwap.add(maxIncrease), depositGuardThreshold);
624
+ }
625
+ exports.calculateMaxDepositTokenAmount = calculateMaxDepositTokenAmount;
626
+ /**
627
+ * Mirror of the program's `check_deposit_limits`. Returns true if the market's
628
+ * current deposit level is within the daily deposit cap (always true when the
629
+ * cap is disabled).
630
+ */
631
+ function checkDepositLimits(spotMarket) {
632
+ if (spotMarket.maxDepositBpsPerDay === 0) {
633
+ return true;
634
+ }
635
+ const depositTokenAmount = getTokenAmount(spotMarket.depositBalance, spotMarket, types_1.SpotBalanceType.DEPOSIT);
636
+ const maxDepositToken = calculateMaxDepositTokenAmount(spotMarket.depositTokenTwap, spotMarket.depositGuardThreshold, spotMarket.maxDepositBpsPerDay);
637
+ if (maxDepositToken === null) {
638
+ return true;
639
+ }
640
+ return depositTokenAmount.lte(maxDepositToken);
641
+ }
642
+ exports.checkDepositLimits = checkDepositLimits;
602
643
  /**
603
644
  * Calculates the margin-weighted value of a spot deposit, mirroring the asset-side of the
604
645
  * program's collateral valuation (`get_strict_token_value` + `get_asset_weight`). Uses the
@@ -4,11 +4,22 @@ exports.TestClient = void 0;
4
4
  const adminClient_1 = require("./adminClient");
5
5
  class TestClient extends adminClient_1.AdminClient {
6
6
  constructor(config) {
7
- var _a;
7
+ var _a, _b, _c;
8
8
  config.txVersion = 'legacy';
9
9
  if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) !== 'polling') {
10
10
  throw new Error('Test client must be polling');
11
11
  }
12
+ // Blockhash caching keys its TTL off the wall clock, which is incompatible
13
+ // with bankrun's simulated clock: within a single 2s wall-clock window the
14
+ // bankrun validator advances many slots (and its blockhash), so a cached
15
+ // blockhash goes stale and sequential builds collide into identical
16
+ // transactions ("already processed") or reference an expired blockhash
17
+ // ("Blockhash not found"). There is also no real RPC to save in bankrun.
18
+ // Force fresh fetches unless a test explicitly opts back in.
19
+ config.txHandlerConfig = {
20
+ ...config.txHandlerConfig,
21
+ blockhashCachingEnabled: (_c = (_b = config.txHandlerConfig) === null || _b === void 0 ? void 0 : _b.blockhashCachingEnabled) !== null && _c !== void 0 ? _c : false,
22
+ };
12
23
  super(config);
13
24
  }
14
25
  async sendTransaction(tx, additionalSigners, opts, preSigned) {
@@ -37,7 +37,13 @@ export type TxBuildingProps = {
37
37
  };
38
38
  /** Configuration for `TxHandler`'s blockhash-fetching strategy. */
39
39
  export type TxHandlerConfig = {
40
- /** If `true`, use a `CachedBlockhashFetcher` (reduces RPC calls during bursts of tx construction); otherwise fetch fresh every time via `BaseBlockhashFetcher`. */
40
+ /**
41
+ * Blockhash-fetching strategy. Defaults to `true`: a `CachedBlockhashFetcher`
42
+ * reuses a recent blockhash for `RECENT_BLOCKHASH_STALE_TIME_MS` (2s) to avoid a
43
+ * `getLatestBlockhash` RPC call on every transaction build — this is safe because a
44
+ * blockhash stays valid on-chain far longer than the cache TTL. Set to `false` to
45
+ * force a fresh RPC fetch on every build via `BaseBlockhashFetcher`.
46
+ */
41
47
  blockhashCachingEnabled?: boolean;
42
48
  /** Tuning for `CachedBlockhashFetcher` when `blockhashCachingEnabled` is `true`; each field defaults if omitted (see `BLOCKHASH_FETCH_RETRY_COUNT`/`BLOCKHASH_FETCH_RETRY_SLEEP`/`RECENT_BLOCKHASH_STALE_TIME_MS`). */
43
49
  blockhashCachingConfig?: {
@@ -64,9 +64,13 @@ class TxHandler {
64
64
  this.confirmationOptions = props.confirmationOptions;
65
65
  this.blockhashCommitment =
66
66
  (_f = (_e = (_c = (_b = props.confirmationOptions) === null || _b === void 0 ? void 0 : _b.preflightCommitment) !== null && _c !== void 0 ? _c : (_d = props === null || props === void 0 ? void 0 : props.connection) === null || _d === void 0 ? void 0 : _d.commitment) !== null && _e !== void 0 ? _e : this.blockhashCommitment) !== null && _f !== void 0 ? _f : 'confirmed';
67
- this.blockHashFetcher = ((_g = props === null || props === void 0 ? void 0 : props.config) === null || _g === void 0 ? void 0 : _g.blockhashCachingEnabled)
68
- ? new cachedBlockhashFetcher_1.CachedBlockhashFetcher(this.connection, this.blockhashCommitment, (_k = (_j = (_h = props === null || props === void 0 ? void 0 : props.config) === null || _h === void 0 ? void 0 : _h.blockhashCachingConfig) === null || _j === void 0 ? void 0 : _j.retryCount) !== null && _k !== void 0 ? _k : BLOCKHASH_FETCH_RETRY_COUNT, (_o = (_m = (_l = props === null || props === void 0 ? void 0 : props.config) === null || _l === void 0 ? void 0 : _l.blockhashCachingConfig) === null || _m === void 0 ? void 0 : _m.retrySleepTimeMs) !== null && _o !== void 0 ? _o : BLOCKHASH_FETCH_RETRY_SLEEP, (_r = (_q = (_p = props === null || props === void 0 ? void 0 : props.config) === null || _p === void 0 ? void 0 : _p.blockhashCachingConfig) === null || _q === void 0 ? void 0 : _q.staleCacheTimeMs) !== null && _r !== void 0 ? _r : RECENT_BLOCKHASH_STALE_TIME_MS)
69
- : new baseBlockhashFetcher_1.BaseBlockhashFetcher(this.connection, this.blockhashCommitment);
67
+ // Cache by default: only opt out when a consumer explicitly disables it. This
68
+ // collapses per-build `getLatestBlockhash` RPC calls (crankers dominate these)
69
+ // into at most one fetch per staleCacheTimeMs window.
70
+ this.blockHashFetcher =
71
+ ((_g = props === null || props === void 0 ? void 0 : props.config) === null || _g === void 0 ? void 0 : _g.blockhashCachingEnabled) === false
72
+ ? new baseBlockhashFetcher_1.BaseBlockhashFetcher(this.connection, this.blockhashCommitment)
73
+ : new cachedBlockhashFetcher_1.CachedBlockhashFetcher(this.connection, this.blockhashCommitment, (_k = (_j = (_h = props === null || props === void 0 ? void 0 : props.config) === null || _h === void 0 ? void 0 : _h.blockhashCachingConfig) === null || _j === void 0 ? void 0 : _j.retryCount) !== null && _k !== void 0 ? _k : BLOCKHASH_FETCH_RETRY_COUNT, (_o = (_m = (_l = props === null || props === void 0 ? void 0 : props.config) === null || _l === void 0 ? void 0 : _l.blockhashCachingConfig) === null || _m === void 0 ? void 0 : _m.retrySleepTimeMs) !== null && _o !== void 0 ? _o : BLOCKHASH_FETCH_RETRY_SLEEP, (_r = (_q = (_p = props === null || props === void 0 ? void 0 : props.config) === null || _p === void 0 ? void 0 : _p.blockhashCachingConfig) === null || _q === void 0 ? void 0 : _q.staleCacheTimeMs) !== null && _r !== void 0 ? _r : RECENT_BLOCKHASH_STALE_TIME_MS);
70
74
  // #Optionals
71
75
  this.returnBlockHeightsWithSignedTxCallbackData =
72
76
  (_t = (_s = props.opts) === null || _s === void 0 ? void 0 : _s.returnBlockHeightsWithSignedTxCallbackData) !== null && _t !== void 0 ? _t : false;
@@ -1207,6 +1207,8 @@ export type PerpMarketAccount = {
1207
1207
  feePoolBufferTarget: BN;
1208
1208
  /** PERCENTAGE_PRECISION (1e6 = 100%); fraction of OI notional (at the oracle TWAP) the sweep leaves behind in `feeLedger.pendingIfFee` as a standing bankruptcy first-loss tranche; 0 disables */
1209
1209
  bankruptcyIfFloorPct: number;
1210
+ /** QUOTE_PRECISION (1e6); aggregate builder/referrer revenue share accrued but not yet paid out of this market's pnl pool. The fee sweep reserves it (like `max(net_user_pnl, 0)` and the floored IF tranche) so a protocol-fee drain can't leave accrued revenue-share claims temporarily unpayable */
1211
+ pendingRevenueShare: BN;
1210
1212
  /** MARGIN_PRECISION (1e4); scales margin ratio up for large positions */
1211
1213
  imfFactor: number;
1212
1214
  /** MARGIN_PRECISION (1e4); discounts positive-unrealized-pnl asset weight for large positions */
@@ -1357,6 +1359,10 @@ export type SpotMarketAccount = {
1357
1359
  protocolLiquidationFee: number;
1358
1360
  /** IF_FACTOR_PRECISION (1e6); protocol's carveout of lending deposit-interest gains */
1359
1361
  protocolFeeFactor: number;
1362
+ /** token mint precision; IF vault balance recorded at the last revenue settle, used as a
1363
+ * donation-proof base for the per-period revenue-settle APR cap (see `settle_revenue_to_insurance_fund`);
1364
+ * `0` = uninitialized (pre-upgrade accounts, seeded on first settle) */
1365
+ ifLastSettleVaultAmount: BN;
1360
1366
  /** token mint decimals; token-mint precision throughout this account is 10^decimals */
1361
1367
  decimals: number;
1362
1368
  /** SPOT_UTILIZATION_PRECISION (1e6) */
@@ -1439,6 +1445,9 @@ export type SpotMarketAccount = {
1439
1445
  poolId: number;
1440
1446
  /** -100 to 100; percentage adjustment applied to the base fee rate */
1441
1447
  feeAdjustment: number;
1448
+ depositGuardThreshold: BN;
1449
+ withdrawCircuitBreakerBps: number;
1450
+ maxDepositBpsPerDay: number;
1442
1451
  };
1443
1452
  /** A scaled token balance inside a market's internal pools (pnl pool, protocol fee pool, revenue pool, spot fee pool, AMM fee pool). Multiply `scaledBalance` (SPOT_BALANCE_PRECISION, 1e9) by the referenced spot market's `cumulativeDepositInterest`/`cumulativeBorrowInterest` to get the token amount. */
1444
1453
  export type PoolBalance = {
@@ -957,8 +957,8 @@ export declare class User {
957
957
  getPerpPositionHealth({ marginCategory, perpPosition, oraclePriceData, quoteOraclePriceData, includeOpenOrders, }: {
958
958
  marginCategory: MarginCategory;
959
959
  perpPosition: PerpPosition;
960
- oraclePriceData?: OraclePriceData;
961
- quoteOraclePriceData?: OraclePriceData;
960
+ oraclePriceData?: Pick<OraclePriceData, 'price'>;
961
+ quoteOraclePriceData?: Pick<OraclePriceData, 'price'>;
962
962
  includeOpenOrders?: boolean;
963
963
  }): HealthComponent;
964
964
  /**
@@ -10,6 +10,7 @@ import { PublicKey } from '@solana/web3.js';
10
10
  import { UserAccountFilterCriteria as UserFilterCriteria, UserMapConfig } from './userMapConfig';
11
11
  import StrictEventEmitter from 'strict-event-emitter-types';
12
12
  import { EventEmitter } from 'events';
13
+ export declare const USER_ACCOUNT_SIZE_BYTES = 4496;
13
14
  /** Public surface implemented by `UserMap`. */
14
15
  export interface UserMapInterface {
15
16
  eventEmitter: StrictEventEmitter<EventEmitter, UserEvents>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UserMap = void 0;
3
+ exports.UserMap = exports.USER_ACCOUNT_SIZE_BYTES = void 0;
4
4
  const user_1 = require("../user");
5
5
  const DLOB_1 = require("../dlob/DLOB");
6
6
  const oneShotUserAccountSubscriber_1 = require("../accounts/oneShotUserAccountSubscriber");
@@ -13,11 +13,7 @@ const PollingSubscription_1 = require("./PollingSubscription");
13
13
  const user_2 = require("../decode/user");
14
14
  const grpcSubscription_1 = require("./grpcSubscription");
15
15
  const events_1 = require("events");
16
- // Velocity's User account is 4496 bytes (8-byte discriminator + 4488 struct);
17
- // drift's was 4376. This caps the zstd-decompressed buffer in defaultSync — if it's
18
- // smaller than the real account, the buffer is truncated and decodeUser reads past
19
- // the end (RangeError: ERR_BUFFER_OUT_OF_BOUNDS). Must be >= the on-chain User size.
20
- const MAX_USER_ACCOUNT_SIZE_BYTES = 4496;
16
+ exports.USER_ACCOUNT_SIZE_BYTES = 4496;
21
17
  /**
22
18
  * In-memory cache of every `User` account on the program, keyed by the
23
19
  * `User` account's own public key.
@@ -393,7 +389,7 @@ class UserMap {
393
389
  const compressedUserData = buffer_1.Buffer.from(programAccount.account.data[0], 'base64');
394
390
  const decoder = new zstddec_1.ZSTDDecoder();
395
391
  await decoder.init();
396
- const userBuffer = decoder.decode(compressedUserData, MAX_USER_ACCOUNT_SIZE_BYTES);
392
+ const userBuffer = decoder.decode(compressedUserData, exports.USER_ACCOUNT_SIZE_BYTES);
397
393
  programAccountBufferMap.set(programAccount.pubkey.toString(), buffer_1.Buffer.from(userBuffer));
398
394
  });
399
395
  await Promise.all(decodingPromises);
@@ -433,25 +433,24 @@ export declare class VelocityClient {
433
433
  externalWallet?: PublicKey;
434
434
  }): Promise<[PublicKey, TransactionInstruction]>;
435
435
  /**
436
- * Grows an existing `SignedMsgUserOrders` account to hold more order-message slots. The program
437
- * only allows growing, never shrinking.
436
+ * Resizes an existing `SignedMsgUserOrders` account. Growing (adding order-message slots) is
437
+ * permitted for any payer; shrinking is only permitted when the payer is the account's
438
+ * `authority`, because the account is authority-scoped and shared across all of the authority's
439
+ * subaccounts — a shrink evicts replay-protection UUIDs for every subaccount.
438
440
  * @param authority - Authority whose account is resized.
439
- * @param numOrders - New (larger) number of order-message slots.
440
- * @param userSubaccountId - Sub-account id used to derive the `user` account passed to the
441
- * instruction; defaults to `0`.
441
+ * @param numOrders - New number of order-message slots.
442
442
  * @param txParams - Optional compute-unit/priority-fee overrides for the transaction.
443
443
  * @returns The transaction signature.
444
444
  */
445
- resizeSignedMsgUserOrders(authority: PublicKey, numOrders: number, userSubaccountId?: number, txParams?: TxParams): Promise<TransactionSignature>;
445
+ resizeSignedMsgUserOrders(authority: PublicKey, numOrders: number, txParams?: TxParams): Promise<TransactionSignature>;
446
446
  /**
447
447
  * Builds the `resizeSignedMsgUserOrders` instruction. See `resizeSignedMsgUserOrders` for
448
448
  * semantics.
449
449
  * @param authority - Authority whose account is resized.
450
- * @param numOrders - New (larger) number of order-message slots.
451
- * @param userSubaccountId - Sub-account id used to derive the `user` account; defaults to `0`.
450
+ * @param numOrders - New number of order-message slots.
452
451
  * @returns The resize instruction.
453
452
  */
454
- getResizeSignedMsgUserOrdersInstruction(authority: PublicKey, numOrders: number, userSubaccountId?: number): Promise<TransactionInstruction>;
453
+ getResizeSignedMsgUserOrdersInstruction(authority: PublicKey, numOrders: number): Promise<TransactionInstruction>;
455
454
  /**
456
455
  * Initializes `authority`'s `SignedMsgWsDelegates` account, which lists wallets authorized to
457
456
  * co-sign/relay that authority's signed-message ("swift") orders over a websocket connection
@@ -1574,9 +1573,11 @@ export declare class VelocityClient {
1574
1573
  * @param fromSubAccountId - Sub-account id to debit.
1575
1574
  * @param toSubAccountId - Sub-account id to credit.
1576
1575
  * @param equityFloorDelta - Equity floor (QUOTE_PRECISION) to move from the debited to the credited
1577
- * sub-account along with the funds, keeping the sum of floors constant. The debited side must stay
1578
- * at/above its reduced floor and the credited side's collateral (after the transfer lands) must back
1579
- * its increased floor, else the transfer reverts with `InvalidEquityFloorTransfer`. Pass `'auto'`
1576
+ * sub-account along with the funds, keeping the sum of floors constant. The debited side must not
1577
+ * already be below the floor being reduced (a below-floor sub-account cannot shed floor to defuse a
1578
+ * pending equity-breaker trip), must stay at/above its reduced floor, and the credited side's
1579
+ * collateral (after the transfer lands) must back its increased floor, else the transfer reverts with
1580
+ * `InvalidEquityFloorTransfer`. Pass `'auto'`
1580
1581
  * (quote market only) to move the minimal floor needed for the debited side to stay at/above its
1581
1582
  * floor: `max(0, amount - (collateral - floor))`, capped at the debited side's floor. The auto delta
1582
1583
  * never exceeds `amount`, so the credited side stays backed whenever it was before. Client-side
@@ -3220,7 +3221,8 @@ export declare class VelocityClient {
3220
3221
  * position to the calling liquidator's sub-account at the oracle price (subject to `limitPrice`
3221
3222
  * and the on-chain liquidation fee). Reverts if `userAccountPublicKey` equals the liquidator's
3222
3223
  * own user account. Permissionless — any signer can act as liquidator, taking on the position
3223
- * and its PnL themselves.
3224
+ * and its PnL themselves. Reverts with `EquityBelowFloor` if the liquidator's authority-wide
3225
+ * equity breaker is tripped (a tripped authority is barred from position-acquiring liquidations).
3224
3226
  * @param userAccountPublicKey - Public key of the user account being liquidated.
3225
3227
  * @param userAccount - Decoded user account being liquidated.
3226
3228
  * @param marketIndex - Perp market index of the position to liquidate.
@@ -3272,7 +3274,9 @@ export declare class VelocityClient {
3272
3274
  * debt from the user to the liquidator's own sub-account in exchange for `assetMarketIndex`
3273
3275
  * collateral, when the user is below maintenance margin (or already flagged `beingLiquidated`).
3274
3276
  * Reverts if `userAccountPublicKey` equals the liquidator's own user account. Permissionless —
3275
- * any signer can act as liquidator.
3277
+ * any signer can act as liquidator. Reverts with `EquityBelowFloor` if the liquidator's
3278
+ * authority-wide equity breaker is tripped (a tripped authority is barred from position-acquiring
3279
+ * liquidations).
3276
3280
  * @param userAccountPublicKey - Public key of the user account being liquidated.
3277
3281
  * @param userAccount - Decoded user account being liquidated.
3278
3282
  * @param assetMarketIndex - Spot market index of the collateral the liquidator receives.
@@ -3381,7 +3385,9 @@ export declare class VelocityClient {
3381
3385
  * PnL in `perpMarketIndex`. Only usable once the user's position size in `perpMarketIndex` is
3382
3386
  * zero (the PnL must already be fully unrealized/settled-out, not backed by an open position).
3383
3387
  * Reverts if `userAccountPublicKey` equals the liquidator's own user account. Permissionless —
3384
- * any signer can act as liquidator.
3388
+ * any signer can act as liquidator. Reverts with `EquityBelowFloor` if the liquidator's
3389
+ * authority-wide equity breaker is tripped (a tripped authority is barred from
3390
+ * balance-acquiring liquidations).
3385
3391
  * @param userAccountPublicKey - Public key of the user account being liquidated.
3386
3392
  * @param userAccount - Decoded user account being liquidated.
3387
3393
  * @param perpMarketIndex - Perp market index whose unsettled PnL backs the transfer, QUOTE_PRECISION (1e6).
@@ -3412,7 +3418,9 @@ export declare class VelocityClient {
3412
3418
  * `perpMarketIndex` from the user to the liquidator in exchange for `assetMarketIndex` spot
3413
3419
  * collateral (the inverse of `liquidateBorrowForPerpPnl`). Only usable once the user's position
3414
3420
  * size in `perpMarketIndex` is zero. Reverts if `userAccountPublicKey` equals the liquidator's
3415
- * own user account. Permissionless — any signer can act as liquidator.
3421
+ * own user account. Permissionless — any signer can act as liquidator. Reverts with
3422
+ * `EquityBelowFloor` if the liquidator's authority-wide equity breaker is tripped (a tripped
3423
+ * authority is barred from balance-acquiring liquidations).
3416
3424
  * @param userAccountPublicKey - Public key of the user account being liquidated.
3417
3425
  * @param userAccount - Decoded user account being liquidated.
3418
3426
  * @param perpMarketIndex - Perp market index of the negative unsettled PnL being absorbed.
@@ -3693,8 +3701,10 @@ export declare class VelocityClient {
3693
3701
  }): Promise<TransactionInstruction[]>;
3694
3702
  /**
3695
3703
  * Starts the unstaking cooldown for this wallet's insurance fund stake in `marketIndex`, locking
3696
- * in the number of IF shares corresponding to `amount` at the current share price. The actual
3697
- * withdrawal must be completed with `removeInsuranceFundStake` after
3704
+ * in the number of IF shares corresponding to `amount` at the current share price. Any revenue
3705
+ * already due to the insurance fund is settled first (mirroring `addInsuranceFundStake`), so the
3706
+ * frozen exit value includes the staker's share of it rather than forfeiting it to the remaining
3707
+ * stakers. The actual withdrawal must be completed with `removeInsuranceFundStake` after
3698
3708
  * `spotMarket.insuranceFund.unstakingPeriod` seconds have elapsed; only one request may be
3699
3709
  * in-flight per stake account (`cancelRequestRemoveInsuranceFundStake` to reset). A caller may
3700
3710
  * only act on their own stake account.
@@ -3770,8 +3780,10 @@ export declare class VelocityClient {
3770
3780
  * `pendingAmmProvision` into the AMM's fee pool (both leave `feePoolBufferTarget` behind). Every
3771
3781
  * drain reserves `max(netUserPnl, 0)` so user claims stay backed. This runs inline on every
3772
3782
  * `settlePNL` already — this instruction lets a keeper run it on demand without settling anyone's
3773
- * PnL. Gates the oracle price used to value `netUserPnl` the same way `settlePNL` does (price-band
3774
- * + validity/divergence checks when the market has curve updates enabled).
3783
+ * PnL. Values `netUserPnl` at the market's fixed `expiryPrice` when the market is in `settlement`
3784
+ * status (expired positions settle at that price, not the live oracle, so no live-oracle gate is
3785
+ * applied); otherwise it uses the live oracle price and gates it the same way `settlePNL` does
3786
+ * (price-band + validity/divergence checks when the market has curve updates enabled).
3775
3787
  * @param perpMarketIndex - Perp market index to sweep fees for.
3776
3788
  * @param txParams - Optional compute-unit/priority-fee overrides.
3777
3789
  * @returns The transaction signature.