@panoptic-eng/sdk 1.0.40 → 1.0.41

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.
@@ -1,7 +1,7 @@
1
1
  import { StateViewAbi, formatTokenAmount, getAccountCollateral, panopticQueryAbi$1 as panopticQueryAbi, parseTokenAmount, readBlockAndAggregate, requireReturnData } from "./irm-SPC2KxLA.js";
2
- import { AccountInsolventError, ChunkLimitError, DEFAULT_VEGOID, InvalidHistoryRangeError, NotEnoughTokensError, PanopticError, PanopticValidationError, SafeModeError, StaleDataError, StorageDataNotFoundError, UnhealthyPoolError, WrongUniswapPoolError, collateralTrackerV2Abi, decodeLeftRightSigned, decodeLeftRightUnsigned, decodePosition, decodePositionBalance, decodeTickSpacing, getBlockMeta, getClosedPositionsKey, getPendingPositionsKey, getPool, getPoolMetaKey, getPositionMetaKey, getPositionsKey, getTrackedChunksKey, getTrackedPositionIds, jsonSerializer, mintableAfterBuffer, panopticFactoryV3Abi, panopticFactoryV4Abi, panopticGuardianAbi, panopticPoolV2Abi, panopticQueryAbi as panopticQueryAbi$1, parsePanopticError, riskEngineAbi, semiFungiblePositionManagerV3Abi, semiFungiblePositionManagerV4Abi, stateViewAbi, uniswapV3PoolAbi } from "./getTrackedPositionIds-ms3W9dYB.js";
2
+ import { AccountInsolventError, ChunkLimitError, DEFAULT_VEGOID, InvalidHistoryRangeError, LEG_LIMITS, NotEnoughTokensError, PanopticError, PanopticValidationError, SafeModeError, StaleDataError, StorageDataNotFoundError, TOKEN_ID_BITS, UnhealthyPoolError, WrongUniswapPoolError, collateralTrackerV2Abi, decodeLeftRightSigned, decodeLeftRightUnsigned, decodePosition, decodePositionBalance, decodeTickSpacing, getBlockMeta, getClosedPositionsKey, getPendingPositionsKey, getPool, getPoolMetaKey, getPositionMetaKey, getPositionsKey, getTrackedChunksKey, getTrackedPositionIds, jsonSerializer, mintableAfterBuffer, panopticFactoryV3Abi, panopticFactoryV4Abi, panopticGuardianAbi, panopticPoolV2Abi, panopticQueryAbi as panopticQueryAbi$1, parsePanopticError, riskEngineAbi, semiFungiblePositionManagerV3Abi, semiFungiblePositionManagerV4Abi, stateViewAbi, uniswapV3PoolAbi } from "./getTrackedPositionIds-ms3W9dYB.js";
3
3
  import { MAX_TICK, MAX_TRACKED_CHUNKS, MIN_TICK, WAD, calculatePositionDelta, calculatePositionGamma, calculatePositionValue, priceToTick, sqrtPriceX96ToTick, tickLimits, tickToPrice, tickToPriceDecimalScaled, tickToSqrtPriceX96 } from "./greeks-GysWXct-.js";
4
- import { addLegToTokenId, buildBatchDispatchArgs, buildUniqueCredit, countLegs, createTokenIdBuilder, decodeAllLegs, decodeTokenId, getPoolTokensForSimulation, loadCheckpoint, resolveTokenIndex, simulateOpenPosition, simulateWithTokenFlow } from "./writes-Xp9Wa8GQ.js";
4
+ import { addLegToTokenId, buildBatchDispatchArgs, buildUniqueCredit, countLegs, createTokenIdBuilder, decodeAllLegs, decodeTokenId, getCurrentPositionSizes, getPoolTokensForSimulation, loadCheckpoint, resolveTokenIndex, simulateOpenPosition, simulateWithTokenFlow } from "./writes-_gfkBizf.js";
5
5
  import { BaseError, ContractFunctionExecutionError, ContractFunctionRevertedError, ExecutionRevertedError, decodeFunctionResult, encodeAbiParameters, encodeFunctionData, getAddress, keccak256, toHex, zeroAddress } from "viem";
6
6
  import { multicall } from "viem/actions";
7
7
 
@@ -203,6 +203,165 @@ function interpolateBlocks(startBlock, endBlock, points) {
203
203
  return Array.from({ length: points }, (_, i) => startBlock + range * BigInt(i) / BigInt(points - 1));
204
204
  }
205
205
 
206
+ //#endregion
207
+ //#region src/panoptic/v2/tokenId/deriveUniqueTokenId.ts
208
+ const POOL_ID_MASK$2 = (1n << 64n) - 1n;
209
+ const MAX_LEGS = TOKEN_ID_BITS.MAX_LEGS;
210
+ const MAX_OPTION_RATIO = LEG_LIMITS.MAX_RATIO;
211
+ const Q192$2 = 1n << 192n;
212
+ /**
213
+ * Floor integer square root for bigints (Newton's method). Mirrors the isqrt
214
+ * used in reads/collateralEstimate.ts (buildNeutralLeg).
215
+ */
216
+ function isqrt$1(value) {
217
+ if (value < 0n) throw new PanopticError("isqrt of negative number");
218
+ if (value < 2n) return value;
219
+ let x = value;
220
+ let y = x + 1n >> 1n;
221
+ while (y < x) {
222
+ x = y;
223
+ y = x + value / x >> 1n;
224
+ }
225
+ return x;
226
+ }
227
+ const DEFAULT_TICK_SPACING = 200n;
228
+ /**
229
+ * Target notional (in wei of the tokenType-side asset) for the appended
230
+ * tiny credit leg. Chosen at 10 wei — small enough to be economically
231
+ * meaningless against any real position size, large enough to safely
232
+ * clear rounding on the SFPM's width-2 internal chunk math without any
233
+ * risk of underflowing to zero (which would revert ChunkHasZeroLiquidity).
234
+ */
235
+ const TINY_CREDIT_TARGET_NOTIONAL_WEI = 10n;
236
+ /**
237
+ * Pick a signedStrike for the appended width=0 credit leg such that:
238
+ * 1. positionSize · 1.0001^signedStrike ≈ TINY_CREDIT_TARGET_NOTIONAL_WEI
239
+ * (~10 wei — economically meaningless but comfortably above any
240
+ * SFPM width-2 chunk rounding);
241
+ * 2. the leg's tick range (SFPM internally treats width=0 as width=2, so
242
+ * the range is `strike ± tickSpacing`) stays strictly inside
243
+ * `[MIN_POOL_TICK, MAX_POOL_TICK]` — otherwise the getSqrtRatioAtTick
244
+ * call reverts with `InvalidTick`.
245
+ *
246
+ * Closed form: `1.0001^signedStrike = target/positionSize`, so
247
+ * `sqrtKrawX96 = isqrt(target · 2^192 / positionSize)` and
248
+ * `signedStrike = sqrtPriceX96ToTick(sqrtKrawX96)`. If the notional-optimal
249
+ * strike falls outside the safe range, we clamp inward. Clamping raises the
250
+ * notional but keeps it << position size for any reasonable strike.
251
+ */
252
+ function computeTinyCreditSignedStrike(positionSize, tickSpacing) {
253
+ if (positionSize <= 0n) throw new PanopticError("computeTinyCreditSignedStrike: positionSize must be > 0");
254
+ const minSafe = MIN_TICK + tickSpacing + 1n;
255
+ const maxSafe = MAX_TICK - tickSpacing - 1n;
256
+ let signedStrike;
257
+ try {
258
+ const sqrtKrawX96 = isqrt$1(TINY_CREDIT_TARGET_NOTIONAL_WEI * Q192$2 / positionSize);
259
+ signedStrike = sqrtPriceX96ToTick(sqrtKrawX96);
260
+ } catch {
261
+ signedStrike = minSafe;
262
+ }
263
+ if (signedStrike < minSafe) return minSafe;
264
+ if (signedStrike > maxSafe) return maxSafe;
265
+ return signedStrike;
266
+ }
267
+ /**
268
+ * Assemble the tiny credit leg struct, picking a strike that avoids
269
+ * colliding with any existing width=0 credit leg on the same (asset,
270
+ * tokenType) pair.
271
+ *
272
+ * The encoded strike stored in the tokenId is
273
+ * `asset === 0 ? signedStrike : -signedStrike` (mirrors
274
+ * {@link buildNeutralLeg} in reads/collateralEstimate.ts).
275
+ */
276
+ function pickUniqueTinyCreditLeg(baseTokenId, legIndex, positionSize, tickSpacing) {
277
+ const asset = 1n;
278
+ const tokenType = 0n;
279
+ const existingLegs = decodeAllLegs(baseTokenId);
280
+ const maxSafe = MAX_TICK - tickSpacing - 1n;
281
+ let signedStrike = computeTinyCreditSignedStrike(positionSize, tickSpacing);
282
+ while (signedStrike <= maxSafe) {
283
+ const candidate = asset === 0n ? signedStrike : -signedStrike;
284
+ let collides = false;
285
+ for (const leg of existingLegs) if (leg.width === 0n && leg.isLong && leg.asset === asset && leg.tokenType === tokenType && leg.strike === candidate) {
286
+ collides = true;
287
+ break;
288
+ }
289
+ if (!collides) break;
290
+ signedStrike += 1n;
291
+ }
292
+ if (signedStrike > maxSafe) throw new PanopticError("deriveUniqueTokenId: exhausted strike space picking a unique tiny credit leg");
293
+ const encodedStrike = asset === 0n ? signedStrike : -signedStrike;
294
+ return {
295
+ index: legIndex,
296
+ asset,
297
+ tokenType,
298
+ optionRatio: 1n,
299
+ isLong: 1n,
300
+ riskPartner: legIndex,
301
+ strike: encodedStrike,
302
+ width: 0n
303
+ };
304
+ }
305
+ function appendTinyCreditLeg(baseTokenId, baseLegCount, positionSize, tickSpacing) {
306
+ const newLeg = pickUniqueTinyCreditLeg(baseTokenId, baseLegCount, positionSize, tickSpacing);
307
+ return addLegToTokenId(baseTokenId, newLeg);
308
+ }
309
+ function scaleRatios(baseTokenId, targetPositionSize) {
310
+ const legs = decodeAllLegs(baseTokenId);
311
+ const maxRatio = legs.reduce((m, leg) => leg.optionRatio > m ? leg.optionRatio : m, 0n);
312
+ const N = MAX_OPTION_RATIO / maxRatio;
313
+ if (N < 2n) throw new PanopticError("deriveUniqueTokenId: cannot derive a unique tokenId — all 4 leg slots used and optionRatios already near the 127 ceiling");
314
+ const newPositionSize = (targetPositionSize + N - 1n) / N;
315
+ const poolId = baseTokenId & POOL_ID_MASK$2;
316
+ let out = poolId;
317
+ for (const leg of legs) out = addLegToTokenId(out, {
318
+ index: leg.index,
319
+ asset: leg.asset,
320
+ tokenType: leg.tokenType,
321
+ optionRatio: leg.optionRatio * N,
322
+ isLong: leg.isLong ? 1n : 0n,
323
+ riskPartner: leg.riskPartner,
324
+ strike: leg.strike,
325
+ width: leg.width
326
+ });
327
+ return {
328
+ newTokenId: out,
329
+ newPositionSize,
330
+ effectivePositionSize: newPositionSize * N,
331
+ strategy: "ratio-scale"
332
+ };
333
+ }
334
+ /**
335
+ * Derive a tokenId unique from `baseTokenId` for a partial reduction.
336
+ *
337
+ * Prefers a tiny-credit-leg extension (arbitrary new size). Falls back to
338
+ * optionRatio scaling only when the base tokenId already occupies all 4 leg
339
+ * slots.
340
+ */
341
+ function deriveUniqueTokenId(params) {
342
+ const { baseTokenId, targetPositionSize, tickSpacing = DEFAULT_TICK_SPACING } = params;
343
+ if (targetPositionSize <= 0n) throw new PanopticError("deriveUniqueTokenId: targetPositionSize must be > 0");
344
+ const legCount = countLegs(baseTokenId);
345
+ if (legCount === 0n) throw new PanopticError("deriveUniqueTokenId: baseTokenId has no legs");
346
+ if (legCount < MAX_LEGS) {
347
+ const newTokenId = appendTinyCreditLeg(baseTokenId, legCount, targetPositionSize, tickSpacing);
348
+ return {
349
+ newTokenId,
350
+ newPositionSize: targetPositionSize,
351
+ effectivePositionSize: targetPositionSize,
352
+ strategy: "tiny-credit"
353
+ };
354
+ }
355
+ return scaleRatios(baseTokenId, targetPositionSize);
356
+ }
357
+ /**
358
+ * Re-export decoded leg count so callers can gate UI on the strategy that
359
+ * would be chosen (e.g. show a divisibility hint on ratio-scale positions).
360
+ */
361
+ function planDeriveStrategy(baseTokenId) {
362
+ return countLegs(baseTokenId) < MAX_LEGS ? "tiny-credit" : "ratio-scale";
363
+ }
364
+
206
365
  //#endregion
207
366
  //#region src/panoptic/v2/sfpmSwap/calldata.ts
208
367
  /**
@@ -1703,8 +1862,9 @@ async function quoteTokenShortfallRecovery(params) {
1703
1862
  error: new PanopticError("Could not size the prefixed recovery swap")
1704
1863
  };
1705
1864
  };
1865
+ let creditOutSize = amountOut;
1706
1866
  for (let attempt = 0; attempt < MAX_RECOVERY_QUOTE_ATTEMPTS; attempt++) {
1707
- const credit = buildUniqueCredit(pool.poolId, tokenOutIndex, tokenOutIndex, pool.currentTick, pool.tickSpacing, collisionIds, amountOut);
1867
+ const credit = buildUniqueCredit(pool.poolId, tokenOutIndex, tokenOutIndex, pool.currentTick, pool.tickSpacing, collisionIds, creditOutSize);
1708
1868
  const recoveredDispatch = buildTokenShortfallRecoveryDispatch({
1709
1869
  dispatch: params.dispatch,
1710
1870
  creditTokenId: credit.tokenId,
@@ -1748,10 +1908,14 @@ async function quoteTokenShortfallRecovery(params) {
1748
1908
  const maxAmountIn = maximumAmountIn(estimatedAmountIn, params.slippageBps);
1749
1909
  const swapOutput = getOutputAmount(swapSimulation.tokenFlow, tokenOutIndex);
1750
1910
  const sourceBalance = getBalanceBefore(swapSimulation.tokenFlow, tokenInIndex);
1751
- if (swapOutput < amountOut || sourceBalance < maxAmountIn) return {
1911
+ if (swapOutput < amountOut) {
1912
+ creditOutSize = swapOutput > 0n ? ceilDiv(creditOutSize * amountOut, swapOutput) + 1n : creditOutSize * 2n;
1913
+ continue;
1914
+ }
1915
+ if (sourceBalance < maxAmountIn) return {
1752
1916
  available: false,
1753
1917
  reason: "swap-unavailable",
1754
- detail: swapOutput < amountOut ? `swap output ${swapOutput} < required ${amountOut}` : `source balance ${sourceBalance} < maximumAmountIn ${maxAmountIn} (estimated ${estimatedAmountIn}, slippageBps ${params.slippageBps})`,
1918
+ detail: `source balance ${sourceBalance} < maximumAmountIn ${maxAmountIn} (estimated ${estimatedAmountIn}, slippageBps ${params.slippageBps})`,
1755
1919
  error: new PanopticError("Insufficient source collateral for the recovery swap")
1756
1920
  };
1757
1921
  const recoverySimulation = await simulateDispatch({
@@ -1803,6 +1967,7 @@ async function quoteTokenShortfallRecovery(params) {
1803
1967
  const decodedShortfall = remainingShortfall.assetsRequested - remainingShortfall.assetBalance;
1804
1968
  const additionalAmountOut = decodedShortfall > 0n ? decodedShortfall : amountOut;
1805
1969
  amountOut += additionalAmountOut;
1970
+ creditOutSize = swapOutput > 0n ? ceilDiv(creditOutSize * amountOut, swapOutput) + 1n : creditOutSize * 2n;
1806
1971
  }
1807
1972
  return {
1808
1973
  available: false,
@@ -1829,6 +1994,7 @@ const MAX_EFFECTIVE_LIQUIDITY_LIMIT = 8388607;
1829
1994
  * returned value must be scaled down to the caller's actual `positionSize`.
1830
1995
  */
1831
1996
  const MAX_UINT64$1 = 2n ** 64n - 1n;
1997
+ const FP96$1 = 1n << 96n;
1832
1998
  /**
1833
1999
  * `getRequiredBase` returns `type(uint128).max` as an error sentinel (invalid
1834
2000
  * tokenId or reverting `getMargin`). Detect it so we don't scale a garbage value.
@@ -1841,7 +2007,9 @@ const REQUIRED_BASE_ERROR_SENTINEL = 2n ** 128n - 1n;
1841
2007
  * computes the requirement at `type(uint64).max` size and 0% utilization. Since
1842
2008
  * the requirement is linear in size, the raw result is scaled by
1843
2009
  * `positionSize / type(uint64).max` to yield the requirement for the requested
1844
- * size. Returns collateral requirement in terms of token0.
2010
+ * size. `PanopticQuery.getRequiredBase` returns the cross-margin requirement in
2011
+ * the higher-precision raw token at `atTick`; this function places that amount
2012
+ * in the matching `required0` or `required1` field.
1845
2013
  *
1846
2014
  * @param params - The parameters
1847
2015
  * @returns Estimated collateral requirements with block metadata
@@ -1860,7 +2028,7 @@ async function estimateCollateralRequired(params) {
1860
2028
  });
1861
2029
  effectiveTick = BigInt(currentTickResult);
1862
2030
  }
1863
- const [required0, _meta] = await Promise.all([client.readContract({
2031
+ const [requiredBase, _meta] = await Promise.all([client.readContract({
1864
2032
  address: queryAddress,
1865
2033
  abi: panopticQueryAbi,
1866
2034
  functionName: "getRequiredBase",
@@ -1874,10 +2042,11 @@ async function estimateCollateralRequired(params) {
1874
2042
  client,
1875
2043
  blockNumber: targetBlockNumber
1876
2044
  })]);
1877
- const scaled0 = required0 >= REQUIRED_BASE_ERROR_SENTINEL ? required0 : required0 * positionSize / MAX_UINT64$1;
2045
+ const scaledRequirement = requiredBase >= REQUIRED_BASE_ERROR_SENTINEL ? requiredBase : requiredBase * positionSize / MAX_UINT64$1;
2046
+ const denominatedInToken0 = tickToSqrtPriceX96(effectiveTick) < FP96$1;
1878
2047
  return {
1879
- required0: scaled0,
1880
- required1: 0n,
2048
+ required0: denominatedInToken0 ? scaledRequirement : 0n,
2049
+ required1: denominatedInToken0 ? 0n : scaledRequirement,
1881
2050
  _meta
1882
2051
  };
1883
2052
  }
@@ -5089,7 +5258,9 @@ async function getStreamiaHistory(params) {
5089
5258
  _meta: _meta$1
5090
5259
  };
5091
5260
  }
5092
- const premiaRequests = blockNumbers.map((bn) => client.readContract({
5261
+ const _meta = params._meta ?? await getBlockMeta({ client });
5262
+ const resolvedBlockNumbers = blockNumbers.map((blockNumber) => blockNumber ?? _meta.blockNumber);
5263
+ const premiaRequests = resolvedBlockNumbers.map((blockNumber) => client.readContract({
5093
5264
  address: panopticPoolAddress,
5094
5265
  abi: panopticPoolV2Abi,
5095
5266
  functionName: "getFullPositionsData",
@@ -5098,18 +5269,36 @@ async function getStreamiaHistory(params) {
5098
5269
  true,
5099
5270
  [tokenId]
5100
5271
  ],
5101
- blockNumber: bn
5272
+ blockNumber
5102
5273
  }));
5103
- const uniswapDataPromise = includeUniswapFees && legs.length > 0 ? fetchUniswapFeeData(client, blockNumbers, legs, poolConfig) : void 0;
5104
- const [premiaResults, uniswapData, _meta] = await Promise.all([
5105
- Promise.all(premiaRequests),
5106
- uniswapDataPromise ?? Promise.resolve(void 0),
5107
- params._meta ? Promise.resolve(params._meta) : getBlockMeta({ client })
5108
- ]);
5109
- const sortedSettled = settledEvents ? [...settledEvents].sort((a, b) => a.blockNumber < b.blockNumber ? -1 : 1) : [];
5274
+ const uniswapDataPromise = includeUniswapFees && legs.length > 0 ? fetchUniswapFeeData(client, resolvedBlockNumbers, legs, poolConfig) : void 0;
5275
+ const [premiaResults, uniswapData] = await Promise.all([Promise.all(premiaRequests), uniswapDataPromise ?? Promise.resolve(void 0)]);
5276
+ const sortedSettled = settledEvents ? [...settledEvents].sort((a, b) => a.blockNumber === b.blockNumber ? 0 : a.blockNumber < b.blockNumber ? -1 : 1) : [];
5110
5277
  let settledIdx = 0;
5111
5278
  let accSettled0 = 0n;
5112
5279
  let accSettled1 = 0n;
5280
+ const cumulativePremiaByInputIndex = Array.from({ length: blockNumbers.length }, () => ({
5281
+ token0: 0n,
5282
+ token1: 0n
5283
+ }));
5284
+ const chronologicalInputs = resolvedBlockNumbers.map((blockNumber, inputIndex) => ({
5285
+ blockNumber,
5286
+ inputIndex
5287
+ })).sort((a, b) => a.blockNumber === b.blockNumber ? a.inputIndex - b.inputIndex : a.blockNumber < b.blockNumber ? -1 : 1);
5288
+ for (const { blockNumber, inputIndex } of chronologicalInputs) {
5289
+ while (settledIdx < sortedSettled.length && sortedSettled[settledIdx].blockNumber <= blockNumber) {
5290
+ accSettled0 += sortedSettled[settledIdx].settled0;
5291
+ accSettled1 += sortedSettled[settledIdx].settled1;
5292
+ settledIdx++;
5293
+ }
5294
+ const result = premiaResults[inputIndex];
5295
+ const premia0 = (result[0] & MASK_128) - (result[1] & MASK_128);
5296
+ const premia1 = (result[0] >> 128n) - (result[1] >> 128n);
5297
+ cumulativePremiaByInputIndex[inputIndex] = {
5298
+ token0: premia0 + accSettled0,
5299
+ token1: premia1 + accSettled1
5300
+ };
5301
+ }
5113
5302
  let initialUniswapFees0 = null;
5114
5303
  let initialUniswapFees1 = null;
5115
5304
  const snapshots = premiaResults.map((result, i) => {
@@ -5120,14 +5309,8 @@ async function getStreamiaHistory(params) {
5120
5309
  const short1 = shortPacked >> 128n;
5121
5310
  const long0 = longPacked & MASK_128;
5122
5311
  const long1 = longPacked >> 128n;
5123
- const effectiveBn = bn ?? BigInt(Number.MAX_SAFE_INTEGER);
5124
- while (settledIdx < sortedSettled.length && sortedSettled[settledIdx].blockNumber <= effectiveBn) {
5125
- accSettled0 += sortedSettled[settledIdx].settled0;
5126
- accSettled1 += sortedSettled[settledIdx].settled1;
5127
- settledIdx++;
5128
- }
5129
- const premia0 = short0 - long0 - accSettled0;
5130
- const premia1 = short1 - long1 - accSettled1;
5312
+ const premia0 = short0 - long0;
5313
+ const premia1 = short1 - long1;
5131
5314
  let uniswapFees0 = 0n;
5132
5315
  let uniswapFees1 = 0n;
5133
5316
  if (uniswapData) {
@@ -5146,6 +5329,7 @@ async function getStreamiaHistory(params) {
5146
5329
  token0: premia0,
5147
5330
  token1: premia1
5148
5331
  },
5332
+ cumulativePanopticPremia: cumulativePremiaByInputIndex[i],
5149
5333
  uniswapFees: {
5150
5334
  token0: uniswapFees0,
5151
5335
  token1: uniswapFees1
@@ -6932,14 +7116,21 @@ const multicallAbi = [{
6932
7116
  * @returns Simulation result with settlement data or error
6933
7117
  */
6934
7118
  async function simulateSettle(params) {
6935
- const { client, poolAddress, account, positionIdList, tokenId, blockNumber } = params;
7119
+ const { client, poolAddress, account, positionIdList, finalPositionIdList, positionSizes: providedSizes, tokenId, blockNumber } = params;
6936
7120
  const targetBlockNumber = blockNumber ?? await client.getBlockNumber();
6937
7121
  const metaPromise = getBlockMeta({
6938
7122
  client,
6939
7123
  blockNumber: targetBlockNumber
6940
7124
  });
6941
7125
  try {
6942
- const positionSizes = positionIdList.map(() => 0n);
7126
+ if (providedSizes && providedSizes.length !== positionIdList.length) throw new PanopticError("simulateSettle: positionSizes length must match positionIdList");
7127
+ const positionSizes = providedSizes ?? await getCurrentPositionSizes({
7128
+ client,
7129
+ poolAddress,
7130
+ account,
7131
+ positionIdList,
7132
+ blockNumber: targetBlockNumber
7133
+ });
6943
7134
  const tickAndSpreadLimits = positionIdList.map(() => [
6944
7135
  -887272n,
6945
7136
  887272n,
@@ -6950,7 +7141,7 @@ async function simulateSettle(params) {
6950
7141
  functionName: "dispatch",
6951
7142
  args: [
6952
7143
  positionIdList,
6953
- positionIdList,
7144
+ finalPositionIdList ?? positionIdList,
6954
7145
  positionSizes.map((s) => BigInt(s)),
6955
7146
  tickAndSpreadLimits.map((t) => [
6956
7147
  Number(t[0]),
@@ -6982,8 +7173,8 @@ async function simulateSettle(params) {
6982
7173
  });
6983
7174
  const _meta = await metaPromise;
6984
7175
  const data = {
6985
- premiaReceived0: tokenFlow.delta0 > 0n ? tokenFlow.delta0 : 0n,
6986
- premiaReceived1: tokenFlow.delta1 > 0n ? tokenFlow.delta1 : 0n,
7176
+ premiaReceived0: tokenFlow.delta0,
7177
+ premiaReceived1: tokenFlow.delta1,
6987
7178
  postCollateral0: tokenFlow.balanceAfter0,
6988
7179
  postCollateral1: tokenFlow.balanceAfter1,
6989
7180
  forfeitAmounts
@@ -9100,4 +9291,4 @@ function isGasError(error) {
9100
9291
  }
9101
9292
 
9102
9293
  //#endregion
9103
- export { DEFAULT_MIN_SWAP_RATIO_BPS, DEFAULT_RECONNECT_CONFIG, REQUIRED_BASE_ERROR_SENTINEL, addPendingPosition, addTrackedChunks, apportion, assertCanBurn, assertCanForceExercise, assertCanLiquidate, assertCanMint, assertFresh, assertHealthy, assertTradeable, buildCreditWrappedDispatch, buildSfpmSwapCalldata, buildSfpmSwapPlan, buildTokenShortfallRecoveryDispatch, calculateAccountGreeksPure, calculateSpreadWad, checkCollateralAcrossTicks, classifyStrategyGroups, cleanupStalePendingPositions, clearPendingPositions, clearTrackedChunks, clearTradeHistory, collateralRuleKindFor, computeV4PoolId, confirmPendingPosition, convertToAssets, convertToShares, createEventPoller, createEventSubscription, createFlowNeutralTokenId, createPoolFormatters, decodePanopticTokenURI, encodePoolKeyBytes, encodeV3PoolKeyBytes, ensureSfpmV3PoolInitialized, estimateBlockNumbers, estimateCollateralBreakdown, estimateCollateralRequired, failPendingPosition, feesFromFeeGrowthDelta, fetchSfpmV3PoolId, formatBlockNumber, formatBps, formatCompact, formatDatetime, formatDuration, formatDurationSeconds, formatFeeTier, formatGas, formatGwei, formatPoolIdHex, formatRatioPercent, formatTimestamp, formatTimestampLocale, formatTokenIdHex, formatTokenIdShort, formatTxHash, formatUtilization, formatWei, getAccountBuyingPower, getAccountGreeks, getAccountHistory, getAccountPremia, getChunkLiquidities, getChunkSpreads, getClosedPositions, getCollateralSharePrices, getCollateralTotalAssetsBatch, getDeltaHedgeParams, getEnforcedTickLimits, getFactoryConstructMetadata, getFactoryOwnerOf, getFactoryTokenURI, getGuardianUnlockState, getItmAmounts, getMarginBuffer, getMaxPositionSize, getMaxRedeem, getMaxWithdrawable, getNativeTokenPrice, getNotEnoughTokensError, getOpenPositionPreview, getPanopticPoolAddress, getPanopticPoolFromPoolId, getPendingPositions, getPoolDisplayId, getPoolLiquidities, getPortfolioValue, getPositionChunkData, getPositionEnrichmentData, getPositionsWithPremia, getPriceHistory, getRealizedPnL, getRequiredCreditForITM, getSafeMode, getStreamiaHistory, getSyncStatus, getTokenListId, getTrackedChunks, getTradeHistory, getUniswapFeeHistory, getUniswapV3LpPositionState, getUniswapV3PoolFromId, getUniswapV3PoolInfo, getUniswapV3PoolLiquidities, getUniswapV4LpPositionState, getUniswapV4PoolBasicState, getUniswapV4PoolInfo, getUniswapV4PoolKeyFromId, getUniswapV4PoolLiquidities, interpolateBlocks, isGasError, isNonceError, isRetryableRpcError, isolateGroupTokenId, minePoolAddress, minePoolAddressLocalAsync, multicallRead, optimizeTokenIdRiskPartners, parseBps, parseCollateralLog, parsePoolLog, parseTokenListId, previewDeposit, previewMint, previewRedeem, previewWithdraw, quoteOneTokenFlow, quoteSfpmSwap, quoteTokenShortfallRecovery, removeTrackedChunks, resolveBlockNumbers, resolvePanopticPoolFromPoolId, resolveUniswapV4PoolKey, saveClosedPosition, scanChunks, simulateBatchDispatch, simulateClosePosition, simulateDeployNewPool, simulateDeposit, simulateDispatch, simulateForceExercise, simulateLiquidate, simulateSFPMBurn, simulateSFPMMint, simulateSettle, simulateSwapExactIn, simulateSwapExactOut, simulateWithdraw, slippageBpsToTickDistance, truncateAddress, watchEvents };
9294
+ export { DEFAULT_MIN_SWAP_RATIO_BPS, DEFAULT_RECONNECT_CONFIG, REQUIRED_BASE_ERROR_SENTINEL, addPendingPosition, addTrackedChunks, apportion, assertCanBurn, assertCanForceExercise, assertCanLiquidate, assertCanMint, assertFresh, assertHealthy, assertTradeable, buildCreditWrappedDispatch, buildSfpmSwapCalldata, buildSfpmSwapPlan, buildTokenShortfallRecoveryDispatch, calculateAccountGreeksPure, calculateSpreadWad, checkCollateralAcrossTicks, classifyStrategyGroups, cleanupStalePendingPositions, clearPendingPositions, clearTrackedChunks, clearTradeHistory, collateralRuleKindFor, computeV4PoolId, confirmPendingPosition, convertToAssets, convertToShares, createEventPoller, createEventSubscription, createFlowNeutralTokenId, createPoolFormatters, decodePanopticTokenURI, deriveUniqueTokenId, encodePoolKeyBytes, encodeV3PoolKeyBytes, ensureSfpmV3PoolInitialized, estimateBlockNumbers, estimateCollateralBreakdown, estimateCollateralRequired, failPendingPosition, feesFromFeeGrowthDelta, fetchSfpmV3PoolId, formatBlockNumber, formatBps, formatCompact, formatDatetime, formatDuration, formatDurationSeconds, formatFeeTier, formatGas, formatGwei, formatPoolIdHex, formatRatioPercent, formatTimestamp, formatTimestampLocale, formatTokenIdHex, formatTokenIdShort, formatTxHash, formatUtilization, formatWei, getAccountBuyingPower, getAccountGreeks, getAccountHistory, getAccountPremia, getChunkLiquidities, getChunkSpreads, getClosedPositions, getCollateralSharePrices, getCollateralTotalAssetsBatch, getDeltaHedgeParams, getEnforcedTickLimits, getFactoryConstructMetadata, getFactoryOwnerOf, getFactoryTokenURI, getGuardianUnlockState, getItmAmounts, getMarginBuffer, getMaxPositionSize, getMaxRedeem, getMaxWithdrawable, getNativeTokenPrice, getNotEnoughTokensError, getOpenPositionPreview, getPanopticPoolAddress, getPanopticPoolFromPoolId, getPendingPositions, getPoolDisplayId, getPoolLiquidities, getPortfolioValue, getPositionChunkData, getPositionEnrichmentData, getPositionsWithPremia, getPriceHistory, getRealizedPnL, getRequiredCreditForITM, getSafeMode, getStreamiaHistory, getSyncStatus, getTokenListId, getTrackedChunks, getTradeHistory, getUniswapFeeHistory, getUniswapV3LpPositionState, getUniswapV3PoolFromId, getUniswapV3PoolInfo, getUniswapV3PoolLiquidities, getUniswapV4LpPositionState, getUniswapV4PoolBasicState, getUniswapV4PoolInfo, getUniswapV4PoolKeyFromId, getUniswapV4PoolLiquidities, interpolateBlocks, isGasError, isNonceError, isRetryableRpcError, isolateGroupTokenId, minePoolAddress, minePoolAddressLocalAsync, multicallRead, optimizeTokenIdRiskPartners, parseBps, parseCollateralLog, parsePoolLog, parseTokenListId, planDeriveStrategy, previewDeposit, previewMint, previewRedeem, previewWithdraw, quoteOneTokenFlow, quoteSfpmSwap, quoteTokenShortfallRecovery, removeTrackedChunks, resolveBlockNumbers, resolvePanopticPoolFromPoolId, resolveUniswapV4PoolKey, saveClosedPosition, scanChunks, simulateBatchDispatch, simulateClosePosition, simulateDeployNewPool, simulateDeposit, simulateDispatch, simulateForceExercise, simulateLiquidate, simulateSFPMBurn, simulateSFPMMint, simulateSettle, simulateSwapExactIn, simulateSwapExactOut, simulateWithdraw, slippageBpsToTickDistance, truncateAddress, watchEvents };
@@ -8,7 +8,10 @@ type VaultTransactionFeeQuote = {
8
8
  maxFeePerGas: bigint;
9
9
  maxPriorityFeePerGas: bigint;
10
10
  minimumMaxFeePerGas: bigint;
11
- source: 'fee_history' | 'viem_fallback';
11
+ source: 'fee_history' | 'viem_fallback' | 'rpc_priority_fee' | 'fee_history_p25';
12
+ };
13
+ type VaultDeltaHedgeFeeQuote = VaultTransactionFeeQuote & {
14
+ rawPriorityFeePerGas: bigint;
12
15
  };
13
16
  type VaultSignedTransactionFeeCaps = {
14
17
  gasLimit?: bigint | null;
@@ -47,6 +50,34 @@ declare class VaultTransactionGasCostLimitError extends Error {
47
50
  minimumRequiredFeePerGas: bigint;
48
51
  });
49
52
  }
53
+ declare class VaultTransactionReplacementLimitError extends Error {
54
+ readonly code: 'GasCostCapExceeded';
55
+ readonly requiredMaxFeePerGas: bigint;
56
+ readonly requiredMaxPriorityFeePerGas: bigint;
57
+ readonly maximumAffordableFeePerGas: bigint;
58
+ constructor({
59
+ code,
60
+ gasLimit,
61
+ requiredMaxFeePerGas,
62
+ requiredMaxPriorityFeePerGas,
63
+ maximumAffordableFeePerGas
64
+ }: {
65
+ code: 'GasCostCapExceeded';
66
+ gasLimit: bigint;
67
+ requiredMaxFeePerGas: bigint;
68
+ requiredMaxPriorityFeePerGas: bigint;
69
+ maximumAffordableFeePerGas: bigint;
70
+ });
71
+ }
72
+ declare function getVaultTransactionReplacementFeeQuote({
73
+ originalQuote,
74
+ historicalQuote,
75
+ gasLimit
76
+ }: {
77
+ originalQuote: Pick<VaultTransactionFeeQuote, 'maxFeePerGas' | 'maxPriorityFeePerGas'>;
78
+ historicalQuote: VaultDeltaHedgeFeeQuote;
79
+ gasLimit: bigint;
80
+ }): VaultDeltaHedgeFeeQuote;
50
81
  declare function applyVaultTransactionGasCostLimit(quote: VaultTransactionFeeQuote, gasLimit: bigint): VaultTransactionFeeQuote;
51
82
  declare function bufferVaultTransactionGasEstimate(gasEstimate: bigint): bigint;
52
83
  declare function validateVaultSignedTransactionFeeCaps(feeCaps: VaultSignedTransactionFeeCaps, quote?: VaultTransactionFeeQuote): VaultSignedTransactionFeeValidationResult;
@@ -58,6 +89,13 @@ declare function validateVaultSignedTransactionFeeCaps(feeCaps: VaultSignedTrans
58
89
  * Viem's estimate is used while preserving those bounds and its original
59
90
  * base-fee allowance.
60
91
  */
61
- declare function getVaultTransactionFeeQuote<chain extends Chain | undefined>(client: Client<Transport, chain>): Promise<VaultTransactionFeeQuote>; //#endregion
62
- export { MAX_VAULT_PRIORITY_FEE_PER_GAS, MAX_VAULT_TRANSACTION_GAS_COST, MIN_VAULT_PRIORITY_FEE_PER_GAS, VaultSignedTransactionFeeCaps, VaultSignedTransactionFeeValidationResult, VaultTransactionFeeEstimationError, VaultTransactionFeeQuote, VaultTransactionGasCostLimitError, applyVaultTransactionGasCostLimit, bufferVaultTransactionGasEstimate, getVaultTransactionFeeQuote, validateVaultSignedTransactionFeeCaps };
92
+ declare function getVaultTransactionFeeQuote<chain extends Chain | undefined>(client: Client<Transport, chain>): Promise<VaultTransactionFeeQuote>;
93
+ declare function getVaultDeltaHedgeHistoricalFeeQuote<chain extends Chain | undefined>(client: Client<Transport, chain>): Promise<VaultDeltaHedgeFeeQuote>;
94
+ /**
95
+ * Resolve the first fee quote for a delta hedge from the connected RPC's
96
+ * eth_maxPriorityFeePerGas recommendation. A failed RPC recommendation falls
97
+ * back immediately to the rolling historical p25 quote.
98
+ */
99
+ declare function getVaultDeltaHedgeInitialFeeQuote<chain extends Chain | undefined>(client: Client<Transport, chain>): Promise<VaultDeltaHedgeFeeQuote>; //#endregion
100
+ export { MAX_VAULT_PRIORITY_FEE_PER_GAS, MAX_VAULT_TRANSACTION_GAS_COST, MIN_VAULT_PRIORITY_FEE_PER_GAS, VaultDeltaHedgeFeeQuote, VaultSignedTransactionFeeCaps, VaultSignedTransactionFeeValidationResult, VaultTransactionFeeEstimationError, VaultTransactionFeeQuote, VaultTransactionGasCostLimitError, VaultTransactionReplacementLimitError, applyVaultTransactionGasCostLimit, bufferVaultTransactionGasEstimate, getVaultDeltaHedgeHistoricalFeeQuote, getVaultDeltaHedgeInitialFeeQuote, getVaultTransactionFeeQuote, getVaultTransactionReplacementFeeQuote, validateVaultSignedTransactionFeeCaps };
63
101
  //# sourceMappingURL=vault-transaction-fees.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vault-transaction-fees.d.ts","names":["Chain","Client","Transport","MIN_VAULT_PRIORITY_FEE_PER_GAS","MAX_VAULT_PRIORITY_FEE_PER_GAS","MAX_VAULT_TRANSACTION_GAS_COST","VaultTransactionFeeQuote","VaultSignedTransactionFeeCaps","VaultSignedTransactionFeeValidationResult","VaultTransactionFeeEstimationError","feeHistoryError","fallbackError","Error","VaultTransactionGasCostLimitError","gasLimit","maximumAffordableFeePerGas","minimumRequiredFeePerGas","FeeHistorySnapshot","FallbackFeeEstimate","resolveFeeHistoryQuote","baseFeePerGas","reward","resolveFallbackQuote","estimatedMaxFeePerGas","estimatedPriorityFeePerGas","applyVaultTransactionGasCostLimit","bufferVaultTransactionGasEstimate","validateVaultSignedTransactionFeeCaps","resolveVaultTransactionFeeQuote","readFeeHistory","readFallbackEstimate","Promise","getVaultTransactionFeeQuote","chain","__transactionFeeTestUtils"],"sources":["../src/hypoVault/transactionFees.d.ts"],"sourcesContent":null,"mappings":";;;cACqBG,8BAAAA;cACAC,8BAAAA;AADAD,cAEAE,8BAAAA,GAF8B,kBAAA;AAC9BD,KAETE,wBAAAA,GAFuC;EAC9BD,YAAAA,EAAAA,MAAAA;EACTC,oBAAAA,EAAAA,MAAwB;EAMxBC,mBAAAA,EAAAA,MAAAA;EAKAC,MAAAA,EAAAA,aAAAA,GAAAA,eAAAA;AAOZ,CAAA;AAAuD,KAZ3CD,6BAAAA,GAY2C;EAAA,QAGrCG,CAAAA,EAAAA,MAAAA,GAAAA,IAAAA;EAAe,YAAEC,EAAAA,MAAAA,GAAAA,IAAAA;EAAa,oBAHgBC,EAAAA,MAAAA,GAAAA,IAAAA;AAAK,CAAA;AAQhDC,KAfTL,yCAAAA,GAe0C;EAAA,KAAA,EAAA,IAAA;CAAA,GAAA;EAI5B,KAAEO,EAAAA,KAAAA;EAA0B,IAAEC,EAAAA,oBAAAA,GAAAA,gBAAAA,GAAAA,mBAAAA,GAAAA,oBAAAA,GAAAA,cAAAA,GAAAA,gBAAAA;EAAwB,MAJjBJ,EAAAA,MAAAA;AAAK,CAAA;AA0B5Ca,cAlCHhB,kCAAAA,SAA2CG,KAAAA,CAkCP;EAAA,SAAA,eAAA,EAAA,OAAA;EAAA,SAAQN,aAAAA,EAAAA,OAAAA;EAAwB,WAAqBA,CAAAA;IAAAA,eAAAA;IAAAA;EAEtFqB,CAFsFrB,EAAAA;IAAwB,eAAA,EAAA,OAAA;IAC9GoB,aAAAA,EAAAA,OAAAA;EACAC,CAAAA;;AAA+CpB,cA5BlDM,iCAAAA,SAA0CD,KAAAA,CA4BQL;EAA6B,SAAUD,QAAAA,EAAAA,MAAAA;EAAwB,SAAGE,0BAAAA,EAAAA,MAAAA;EAAyC,SAAA,wBAAA,EAAA,MAAA;;;;;;;;;;;iBAF1JiB,iCAAAA,QAAyCnB,6CAA6CA;iBACtFoB,iCAAAA;iBACAC,qCAAAA,UAA+CpB,uCAAuCD,2BAA2BE;;;;;;;;;iBAajHwB,0CAA0ChC,2BAA2BC,OAAOC,WAAW+B,SAASF,QAAQzB"}
1
+ {"version":3,"file":"vault-transaction-fees.d.ts","names":["Chain","Client","Transport","MIN_VAULT_PRIORITY_FEE_PER_GAS","MAX_VAULT_PRIORITY_FEE_PER_GAS","MAX_VAULT_TRANSACTION_GAS_COST","VaultTransactionFeeQuote","VaultDeltaHedgeFeeQuote","VaultSignedTransactionFeeCaps","VaultSignedTransactionFeeValidationResult","VaultTransactionFeeEstimationError","feeHistoryError","fallbackError","Error","VaultTransactionGasCostLimitError","gasLimit","maximumAffordableFeePerGas","minimumRequiredFeePerGas","VaultTransactionReplacementLimitError","code","requiredMaxFeePerGas","requiredMaxPriorityFeePerGas","FeeHistorySnapshot","FallbackFeeEstimate","clampPriorityFee","resolveFeeHistoryQuote","baseFeePerGas","reward","resolveDeltaHedgeFeeHistoryQuote","resolveRpcPriorityFeeQuote","rawPriorityFeePerGas","getVaultTransactionReplacementFeeQuote","originalQuote","historicalQuote","Pick","resolveFallbackQuote","estimatedMaxFeePerGas","estimatedPriorityFeePerGas","applyVaultTransactionGasCostLimit","bufferVaultTransactionGasEstimate","validateVaultSignedTransactionFeeCaps","resolveVaultTransactionFeeQuote","readFeeHistory","readFallbackEstimate","Promise","getVaultTransactionFeeQuote","chain","getVaultDeltaHedgeHistoricalFeeQuote","resolveVaultDeltaHedgeInitialFeeQuote","readRpcQuote","readHistoricalQuote","getVaultDeltaHedgeInitialFeeQuote","__transactionFeeTestUtils"],"sources":["../src/hypoVault/transactionFees.d.ts"],"sourcesContent":null,"mappings":"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"}
@@ -1,4 +1,5 @@
1
- import { estimateFeesPerGas, getFeeHistory } from "viem/actions";
1
+ import { hexToBigInt } from "viem";
2
+ import { estimateFeesPerGas, getBlock, getFeeHistory } from "viem/actions";
2
3
 
3
4
  //#region src/hypoVault/transactionFees.ts
4
5
  const MIN_VAULT_PRIORITY_FEE_PER_GAS = 100000000n;
@@ -6,8 +7,11 @@ const MAX_VAULT_PRIORITY_FEE_PER_GAS = 3000000000n;
6
7
  const MAX_VAULT_TRANSACTION_GAS_COST = 15000000000000000n;
7
8
  const FEE_HISTORY_BLOCK_COUNT = 20;
8
9
  const FEE_HISTORY_REWARD_PERCENTILES = [90];
10
+ const DELTA_HEDGE_FEE_HISTORY_REWARD_PERCENTILES = [25];
9
11
  const BASE_FEE_BUFFER_NUMERATOR = 1125n;
10
12
  const BASE_FEE_BUFFER_DENOMINATOR = 1000n;
13
+ const REPLACEMENT_FEE_BUMP_NUMERATOR = 1125n;
14
+ const REPLACEMENT_FEE_BUMP_DENOMINATOR = 1000n;
11
15
  const GAS_ESTIMATE_BUFFER_NUMERATOR = 3n;
12
16
  const GAS_ESTIMATE_BUFFER_DENOMINATOR = 2n;
13
17
  var VaultTransactionFeeEstimationError = class extends Error {
@@ -32,6 +36,20 @@ var VaultTransactionGasCostLimitError = class extends Error {
32
36
  this.minimumRequiredFeePerGas = minimumRequiredFeePerGas;
33
37
  }
34
38
  };
39
+ var VaultTransactionReplacementLimitError = class extends Error {
40
+ code;
41
+ requiredMaxFeePerGas;
42
+ requiredMaxPriorityFeePerGas;
43
+ maximumAffordableFeePerGas;
44
+ constructor({ code, gasLimit, requiredMaxFeePerGas, requiredMaxPriorityFeePerGas, maximumAffordableFeePerGas }) {
45
+ super(`Vault transaction replacement blocked by ${code}: gasLimit=${gasLimit.toString()}, requiredMaxFeePerGas=${requiredMaxFeePerGas.toString()}, requiredMaxPriorityFeePerGas=${requiredMaxPriorityFeePerGas.toString()}, maximumAffordableFeePerGas=${maximumAffordableFeePerGas.toString()}`);
46
+ this.name = "VaultTransactionReplacementLimitError";
47
+ this.code = code;
48
+ this.requiredMaxFeePerGas = requiredMaxFeePerGas;
49
+ this.requiredMaxPriorityFeePerGas = requiredMaxPriorityFeePerGas;
50
+ this.maximumAffordableFeePerGas = maximumAffordableFeePerGas;
51
+ }
52
+ };
35
53
  function ceilMultiplyFraction(value, numerator, denominator) {
36
54
  return (value * numerator + denominator - 1n) / denominator;
37
55
  }
@@ -68,6 +86,57 @@ function resolveFeeHistoryQuote({ baseFeePerGas, reward }) {
68
86
  source: "fee_history"
69
87
  };
70
88
  }
89
+ function resolveDeltaHedgeFeeHistoryQuote({ baseFeePerGas, reward }) {
90
+ const latestBaseFeeIndex = baseFeePerGas.length - 2;
91
+ if (latestBaseFeeIndex < 0 || reward === void 0 || reward.length === 0) return null;
92
+ const p25Rewards = reward.flatMap((blockRewards) => {
93
+ const p25 = blockRewards[0];
94
+ return p25 === void 0 ? [] : [p25];
95
+ });
96
+ const rawPriorityFeePerGas = medianBigInt(p25Rewards);
97
+ if (rawPriorityFeePerGas === void 0) return null;
98
+ const maxPriorityFeePerGas = clampPriorityFee(rawPriorityFeePerGas);
99
+ const bufferedBaseFee = ceilMultiplyFraction(baseFeePerGas[latestBaseFeeIndex], BASE_FEE_BUFFER_NUMERATOR, BASE_FEE_BUFFER_DENOMINATOR);
100
+ return {
101
+ maxFeePerGas: bufferedBaseFee + maxPriorityFeePerGas,
102
+ maxPriorityFeePerGas,
103
+ minimumMaxFeePerGas: bufferedBaseFee + MIN_VAULT_PRIORITY_FEE_PER_GAS,
104
+ rawPriorityFeePerGas,
105
+ source: "fee_history_p25"
106
+ };
107
+ }
108
+ function resolveRpcPriorityFeeQuote({ baseFeePerGas, rawPriorityFeePerGas }) {
109
+ const bufferedBaseFee = ceilMultiplyFraction(baseFeePerGas, BASE_FEE_BUFFER_NUMERATOR, BASE_FEE_BUFFER_DENOMINATOR);
110
+ return {
111
+ maxFeePerGas: bufferedBaseFee + rawPriorityFeePerGas,
112
+ maxPriorityFeePerGas: rawPriorityFeePerGas,
113
+ minimumMaxFeePerGas: bufferedBaseFee + rawPriorityFeePerGas,
114
+ rawPriorityFeePerGas,
115
+ source: "rpc_priority_fee"
116
+ };
117
+ }
118
+ function getVaultTransactionReplacementFeeQuote({ originalQuote, historicalQuote, gasLimit }) {
119
+ if (gasLimit <= 0n) throw new Error(`Vault transaction gas limit must be positive, received ${gasLimit.toString()}`);
120
+ const bumpedPriorityFee = ceilMultiplyFraction(originalQuote.maxPriorityFeePerGas, REPLACEMENT_FEE_BUMP_NUMERATOR, REPLACEMENT_FEE_BUMP_DENOMINATOR);
121
+ const bumpedMaxFee = ceilMultiplyFraction(originalQuote.maxFeePerGas, REPLACEMENT_FEE_BUMP_NUMERATOR, REPLACEMENT_FEE_BUMP_DENOMINATOR);
122
+ const requiredMaxPriorityFeePerGas = historicalQuote.maxPriorityFeePerGas > bumpedPriorityFee ? historicalQuote.maxPriorityFeePerGas : bumpedPriorityFee;
123
+ const bufferedBaseFee = historicalQuote.minimumMaxFeePerGas - MIN_VAULT_PRIORITY_FEE_PER_GAS;
124
+ const currentMarketMaxFee = bufferedBaseFee + requiredMaxPriorityFeePerGas;
125
+ const requiredMaxFeePerGas = currentMarketMaxFee > bumpedMaxFee ? currentMarketMaxFee : bumpedMaxFee;
126
+ const maximumAffordableFeePerGas = MAX_VAULT_TRANSACTION_GAS_COST / gasLimit;
127
+ if (requiredMaxFeePerGas > maximumAffordableFeePerGas) throw new VaultTransactionReplacementLimitError({
128
+ code: "GasCostCapExceeded",
129
+ gasLimit,
130
+ requiredMaxFeePerGas,
131
+ requiredMaxPriorityFeePerGas,
132
+ maximumAffordableFeePerGas
133
+ });
134
+ return {
135
+ ...historicalQuote,
136
+ maxFeePerGas: requiredMaxFeePerGas,
137
+ maxPriorityFeePerGas: requiredMaxPriorityFeePerGas
138
+ };
139
+ }
71
140
  function resolveFallbackQuote({ maxFeePerGas: estimatedMaxFeePerGas, maxPriorityFeePerGas: estimatedPriorityFeePerGas }) {
72
141
  const maxPriorityFeePerGas = clampPriorityFee(estimatedPriorityFeePerGas);
73
142
  const estimatedBaseFeeAllowance = estimatedMaxFeePerGas > estimatedPriorityFeePerGas ? estimatedMaxFeePerGas - estimatedPriorityFeePerGas : 0n;
@@ -169,7 +238,42 @@ async function getVaultTransactionFeeQuote(client) {
169
238
  readFallbackEstimate: () => estimateFeesPerGas(client)
170
239
  });
171
240
  }
241
+ async function getVaultDeltaHedgeHistoricalFeeQuote(client) {
242
+ const feeHistory = await getFeeHistory(client, {
243
+ blockCount: FEE_HISTORY_BLOCK_COUNT,
244
+ blockTag: "latest",
245
+ rewardPercentiles: DELTA_HEDGE_FEE_HISTORY_REWARD_PERCENTILES
246
+ });
247
+ const quote = resolveDeltaHedgeFeeHistoryQuote(feeHistory);
248
+ if (quote === null) throw new Error("eth_feeHistory returned incomplete p25 base fee or reward data");
249
+ return quote;
250
+ }
251
+ async function resolveVaultDeltaHedgeInitialFeeQuote({ readRpcQuote, readHistoricalQuote }) {
252
+ try {
253
+ return resolveRpcPriorityFeeQuote(await readRpcQuote());
254
+ } catch {
255
+ return readHistoricalQuote();
256
+ }
257
+ }
258
+ /**
259
+ * Resolve the first fee quote for a delta hedge from the connected RPC's
260
+ * eth_maxPriorityFeePerGas recommendation. A failed RPC recommendation falls
261
+ * back immediately to the rolling historical p25 quote.
262
+ */
263
+ async function getVaultDeltaHedgeInitialFeeQuote(client) {
264
+ return resolveVaultDeltaHedgeInitialFeeQuote({
265
+ readRpcQuote: async () => {
266
+ const [rawPriorityFee, latestBlock] = await Promise.all([client.request({ method: "eth_maxPriorityFeePerGas" }), getBlock(client, { blockTag: "latest" })]);
267
+ if (latestBlock.baseFeePerGas === null) throw new Error("Latest block does not include an EIP-1559 base fee");
268
+ return {
269
+ baseFeePerGas: latestBlock.baseFeePerGas,
270
+ rawPriorityFeePerGas: hexToBigInt(rawPriorityFee)
271
+ };
272
+ },
273
+ readHistoricalQuote: () => getVaultDeltaHedgeHistoricalFeeQuote(client)
274
+ });
275
+ }
172
276
 
173
277
  //#endregion
174
- export { MAX_VAULT_PRIORITY_FEE_PER_GAS, MAX_VAULT_TRANSACTION_GAS_COST, MIN_VAULT_PRIORITY_FEE_PER_GAS, VaultTransactionFeeEstimationError, VaultTransactionGasCostLimitError, applyVaultTransactionGasCostLimit, bufferVaultTransactionGasEstimate, getVaultTransactionFeeQuote, validateVaultSignedTransactionFeeCaps };
278
+ export { MAX_VAULT_PRIORITY_FEE_PER_GAS, MAX_VAULT_TRANSACTION_GAS_COST, MIN_VAULT_PRIORITY_FEE_PER_GAS, VaultTransactionFeeEstimationError, VaultTransactionGasCostLimitError, VaultTransactionReplacementLimitError, applyVaultTransactionGasCostLimit, bufferVaultTransactionGasEstimate, getVaultDeltaHedgeHistoricalFeeQuote, getVaultDeltaHedgeInitialFeeQuote, getVaultTransactionFeeQuote, getVaultTransactionReplacementFeeQuote, validateVaultSignedTransactionFeeCaps };
175
279
  //# sourceMappingURL=vault-transaction-fees.js.map