@panoptic-eng/sdk 1.0.40 → 1.0.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cow/index.js +4 -0
- package/dist/cow/index.js.map +1 -1
- package/dist/index.d.ts +50 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +106 -3
- package/dist/index.js.map +1 -1
- package/dist/panoptic/v2/index.d.ts +234 -11
- package/dist/panoptic/v2/index.d.ts.map +1 -1
- package/dist/panoptic/v2/index.js +1795 -1379
- package/dist/panoptic/v2/index.js.map +1 -1
- package/dist/panoptic/v2/react-public.d.ts +234 -11
- package/dist/panoptic/v2/react-public.d.ts.map +1 -1
- package/dist/panoptic/v2/react-public.js +2045 -1629
- package/dist/panoptic/v2/react-public.js.map +1 -1
- package/dist/{transactionFees-C_Qx07mx.js → transactionFees-DUm6ilXB.js} +106 -2
- package/dist/uniswap/index.js +4 -0
- package/dist/uniswap/index.js.map +1 -1
- package/dist/{v2-DG7qG6di.js → v2-Djy0rVdh.js} +430 -45
- package/dist/vault-transaction-fees.d.ts +41 -3
- package/dist/vault-transaction-fees.d.ts.map +1 -1
- package/dist/vault-transaction-fees.js +106 -2
- package/dist/vault-transaction-fees.js.map +1 -1
- package/dist/{writes-Xp9Wa8GQ.js → writes-_gfkBizf.js} +35 -4
- package/package.json +1 -1
|
@@ -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-
|
|
4
|
+
import { addLegToTokenId, buildBatchDispatchArgs, buildUniqueCredit, buildUniqueLoan, 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
|
/**
|
|
@@ -1474,7 +1633,7 @@ async function simulateDispatch(params) {
|
|
|
1474
1633
|
|
|
1475
1634
|
//#endregion
|
|
1476
1635
|
//#region src/panoptic/v2/simulations/tokenShortfallRecovery.ts
|
|
1477
|
-
const BPS_DENOMINATOR$
|
|
1636
|
+
const BPS_DENOMINATOR$2 = 10000n;
|
|
1478
1637
|
const MAX_RECOVERY_QUOTE_ATTEMPTS = 8;
|
|
1479
1638
|
/**
|
|
1480
1639
|
* Wrap a dispatch with a temporary credit leg that sources the shortfall.
|
|
@@ -1524,7 +1683,7 @@ function getNotEnoughTokensError(error) {
|
|
|
1524
1683
|
}
|
|
1525
1684
|
function maximumAmountIn(estimatedAmountIn, slippageBps) {
|
|
1526
1685
|
if (slippageBps < 0n) throw new PanopticError("slippageBps must be non-negative");
|
|
1527
|
-
return (estimatedAmountIn * (BPS_DENOMINATOR$
|
|
1686
|
+
return (estimatedAmountIn * (BPS_DENOMINATOR$2 + slippageBps) + BPS_DENOMINATOR$2 - 1n) / BPS_DENOMINATOR$2;
|
|
1528
1687
|
}
|
|
1529
1688
|
function ceilDiv(numerator, denominator) {
|
|
1530
1689
|
return (numerator + denominator - 1n) / denominator;
|
|
@@ -1552,10 +1711,10 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
1552
1711
|
reason: "invalid-shortfall",
|
|
1553
1712
|
detail: `requested=${shortfallError.assetsRequested} <= balance=${shortfallError.assetBalance}`
|
|
1554
1713
|
};
|
|
1555
|
-
if (params.slippageBps < 0n || params.slippageBps > BPS_DENOMINATOR$
|
|
1714
|
+
if (params.slippageBps < 0n || params.slippageBps > BPS_DENOMINATOR$2) return {
|
|
1556
1715
|
available: false,
|
|
1557
1716
|
reason: "invalid-slippage",
|
|
1558
|
-
detail: `slippageBps=${params.slippageBps} is outside [0, ${BPS_DENOMINATOR$
|
|
1717
|
+
detail: `slippageBps=${params.slippageBps} is outside [0, ${BPS_DENOMINATOR$2}]`
|
|
1559
1718
|
};
|
|
1560
1719
|
const targetBlockNumber = params.blockNumber ?? await params.client.getBlockNumber();
|
|
1561
1720
|
const pool = await getPool({
|
|
@@ -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,
|
|
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
|
|
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:
|
|
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.
|
|
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 [
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
5272
|
+
blockNumber
|
|
5102
5273
|
}));
|
|
5103
|
-
const uniswapDataPromise = includeUniswapFees && legs.length > 0 ? fetchUniswapFeeData(client,
|
|
5104
|
-
const [premiaResults, uniswapData
|
|
5105
|
-
|
|
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
|
|
5124
|
-
|
|
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
|
|
@@ -5612,7 +5796,7 @@ const nfpmAbi = [{
|
|
|
5612
5796
|
}],
|
|
5613
5797
|
stateMutability: "payable"
|
|
5614
5798
|
}];
|
|
5615
|
-
const MAX_UINT128 = 2n ** 128n - 1n;
|
|
5799
|
+
const MAX_UINT128$1 = 2n ** 128n - 1n;
|
|
5616
5800
|
const MAX_UINT256 = 2n ** 256n - 1n;
|
|
5617
5801
|
const Q128 = 2n ** 128n;
|
|
5618
5802
|
/**
|
|
@@ -5654,8 +5838,8 @@ async function getUniswapV3LpPositionState(params) {
|
|
|
5654
5838
|
args: [{
|
|
5655
5839
|
tokenId,
|
|
5656
5840
|
recipient: owner,
|
|
5657
|
-
amount0Max: MAX_UINT128,
|
|
5658
|
-
amount1Max: MAX_UINT128
|
|
5841
|
+
amount0Max: MAX_UINT128$1,
|
|
5842
|
+
amount1Max: MAX_UINT128$1
|
|
5659
5843
|
}],
|
|
5660
5844
|
account: owner,
|
|
5661
5845
|
blockNumber: _meta.blockNumber
|
|
@@ -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
|
-
|
|
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
|
|
6986
|
-
premiaReceived1: tokenFlow.delta1
|
|
7176
|
+
premiaReceived0: tokenFlow.delta0,
|
|
7177
|
+
premiaReceived1: tokenFlow.delta1,
|
|
6987
7178
|
postCollateral0: tokenFlow.balanceAfter0,
|
|
6988
7179
|
postCollateral1: tokenFlow.balanceAfter1,
|
|
6989
7180
|
forfeitAmounts
|
|
@@ -7495,7 +7686,7 @@ async function simulateSwapExactIn(params) {
|
|
|
7495
7686
|
|
|
7496
7687
|
//#endregion
|
|
7497
7688
|
//#region src/panoptic/v2/simulations/oneTokenFlow.ts
|
|
7498
|
-
const BPS_DENOMINATOR = 10000n;
|
|
7689
|
+
const BPS_DENOMINATOR$1 = 10000n;
|
|
7499
7690
|
/**
|
|
7500
7691
|
* Default {@link OneTokenFlowQuoteParams.minSwapRatioBps}: 0.5%.
|
|
7501
7692
|
*
|
|
@@ -7515,7 +7706,7 @@ function abs(value) {
|
|
|
7515
7706
|
return value < 0n ? -value : value;
|
|
7516
7707
|
}
|
|
7517
7708
|
function padForSlippage(amount, slippageBps) {
|
|
7518
|
-
return (amount * (BPS_DENOMINATOR + slippageBps) + BPS_DENOMINATOR - 1n) / BPS_DENOMINATOR;
|
|
7709
|
+
return (amount * (BPS_DENOMINATOR$1 + slippageBps) + BPS_DENOMINATOR$1 - 1n) / BPS_DENOMINATOR$1;
|
|
7519
7710
|
}
|
|
7520
7711
|
/**
|
|
7521
7712
|
* Quote a dispatch wrapped so its net flow lands in `targetTokenIndex` only.
|
|
@@ -7535,10 +7726,10 @@ async function quoteOneTokenFlow(params) {
|
|
|
7535
7726
|
reason: "invalid-target-token",
|
|
7536
7727
|
detail: `targetTokenIndex=${targetTokenIndex} is neither 0 nor 1`
|
|
7537
7728
|
};
|
|
7538
|
-
if (params.slippageBps < 0n || params.slippageBps > BPS_DENOMINATOR) return {
|
|
7729
|
+
if (params.slippageBps < 0n || params.slippageBps > BPS_DENOMINATOR$1) return {
|
|
7539
7730
|
available: false,
|
|
7540
7731
|
reason: "invalid-slippage",
|
|
7541
|
-
detail: `slippageBps=${params.slippageBps} is outside [0, ${BPS_DENOMINATOR}]`
|
|
7732
|
+
detail: `slippageBps=${params.slippageBps} is outside [0, ${BPS_DENOMINATOR$1}]`
|
|
7542
7733
|
};
|
|
7543
7734
|
const tickLimitLow = params.tickLimitLow ?? MIN_TICK;
|
|
7544
7735
|
const tickLimitHigh = params.tickLimitHigh ?? MAX_TICK;
|
|
@@ -7646,7 +7837,7 @@ async function quoteOneTokenFlow(params) {
|
|
|
7646
7837
|
}
|
|
7647
7838
|
if (baseTargetDelta !== null && minSwapRatioBps > 0n) {
|
|
7648
7839
|
const swapInTargetTerms = convertToTokenIndex(swapAmount, otherTokenIndex, targetTokenIndex, pool.sqrtPriceX96);
|
|
7649
|
-
if (swapInTargetTerms * BPS_DENOMINATOR < minSwapRatioBps * abs(baseTargetDelta)) return {
|
|
7840
|
+
if (swapInTargetTerms * BPS_DENOMINATOR$1 < minSwapRatioBps * abs(baseTargetDelta)) return {
|
|
7650
7841
|
available: false,
|
|
7651
7842
|
reason: "below-threshold",
|
|
7652
7843
|
detail: `non-target flow ${swapInTargetTerms} (in target token terms) is below ${minSwapRatioBps}bps of the target flow ${abs(baseTargetDelta)}`
|
|
@@ -7738,6 +7929,200 @@ async function quoteOneTokenFlow(params) {
|
|
|
7738
7929
|
};
|
|
7739
7930
|
}
|
|
7740
7931
|
|
|
7932
|
+
//#endregion
|
|
7933
|
+
//#region src/panoptic/v2/simulations/temporaryLoanRecovery.ts
|
|
7934
|
+
const BPS_DENOMINATOR = 10000n;
|
|
7935
|
+
const MAX_RECOVERY_ATTEMPTS = 8n;
|
|
7936
|
+
const MAX_UINT128 = (1n << 128n) - 1n;
|
|
7937
|
+
const LOAN_GROWTH_DENOMINATOR = 20n;
|
|
7938
|
+
/**
|
|
7939
|
+
* Wrap a dispatch with `loan mint -> user operations -> swapped loan burn`.
|
|
7940
|
+
* The repeated tokenId is intentional: the first occurrence mints it and the
|
|
7941
|
+
* last occurrence burns it after the user's operations have settled.
|
|
7942
|
+
*/
|
|
7943
|
+
function buildTemporaryLoanRecoveryDispatch(params) {
|
|
7944
|
+
const low = params.tickLimitLow <= params.tickLimitHigh ? params.tickLimitLow : params.tickLimitHigh;
|
|
7945
|
+
const high = params.tickLimitLow <= params.tickLimitHigh ? params.tickLimitHigh : params.tickLimitLow;
|
|
7946
|
+
return {
|
|
7947
|
+
positionIdList: [
|
|
7948
|
+
params.loanTokenId,
|
|
7949
|
+
...params.dispatch.positionIdList,
|
|
7950
|
+
params.loanTokenId
|
|
7951
|
+
],
|
|
7952
|
+
finalPositionIdList: [...params.dispatch.finalPositionIdList],
|
|
7953
|
+
positionSizes: [
|
|
7954
|
+
params.loanPositionSize,
|
|
7955
|
+
...params.dispatch.positionSizes,
|
|
7956
|
+
0n
|
|
7957
|
+
],
|
|
7958
|
+
tickAndSpreadLimits: [
|
|
7959
|
+
[
|
|
7960
|
+
low,
|
|
7961
|
+
high,
|
|
7962
|
+
0n
|
|
7963
|
+
],
|
|
7964
|
+
...params.dispatch.tickAndSpreadLimits,
|
|
7965
|
+
[
|
|
7966
|
+
high,
|
|
7967
|
+
low,
|
|
7968
|
+
0n
|
|
7969
|
+
]
|
|
7970
|
+
],
|
|
7971
|
+
usePremiaAsCollateral: params.dispatch.usePremiaAsCollateral,
|
|
7972
|
+
builderCode: params.dispatch.builderCode
|
|
7973
|
+
};
|
|
7974
|
+
}
|
|
7975
|
+
/**
|
|
7976
|
+
* Quotes and simulates an atomic temporary loan around a full-close dispatch.
|
|
7977
|
+
*
|
|
7978
|
+
* @param params - Chain client, account, failed dispatch, shortfall error, and quote limits.
|
|
7979
|
+
* @returns An executable quote when recovery succeeds, otherwise a categorized unavailable result.
|
|
7980
|
+
* @throws {PanopticError} When the dispatch is not a full close or required RPC reads fail.
|
|
7981
|
+
*/
|
|
7982
|
+
async function quoteTemporaryLoanRecovery(params) {
|
|
7983
|
+
const initialShortfall = getNotEnoughTokensError(params.error);
|
|
7984
|
+
if (initialShortfall === null) return {
|
|
7985
|
+
available: false,
|
|
7986
|
+
reason: "not-token-shortfall"
|
|
7987
|
+
};
|
|
7988
|
+
let loanAmount = initialShortfall.assetsRequested - initialShortfall.assetBalance;
|
|
7989
|
+
if (loanAmount <= 0n) return {
|
|
7990
|
+
available: false,
|
|
7991
|
+
reason: "invalid-shortfall",
|
|
7992
|
+
detail: `requested=${initialShortfall.assetsRequested} <= balance=${initialShortfall.assetBalance}`
|
|
7993
|
+
};
|
|
7994
|
+
if (params.slippageBps <= 0n || params.slippageBps > BPS_DENOMINATOR) return {
|
|
7995
|
+
available: false,
|
|
7996
|
+
reason: "invalid-slippage",
|
|
7997
|
+
detail: `slippageBps=${params.slippageBps} is outside (0, ${BPS_DENOMINATOR}]`
|
|
7998
|
+
};
|
|
7999
|
+
if (params.dispatch.finalPositionIdList.length !== 0) throw new PanopticError("Temporary-loan recovery requires a full-close dispatch with an empty finalPositionIdList");
|
|
8000
|
+
let targetBlockNumber;
|
|
8001
|
+
try {
|
|
8002
|
+
targetBlockNumber = params.blockNumber ?? await params.client.getBlockNumber();
|
|
8003
|
+
} catch (error) {
|
|
8004
|
+
if (error instanceof PanopticError) throw error;
|
|
8005
|
+
throw new PanopticError("Failed to resolve the block for temporary-loan recovery", error instanceof Error ? error : new Error(String(error)));
|
|
8006
|
+
}
|
|
8007
|
+
let pool;
|
|
8008
|
+
try {
|
|
8009
|
+
pool = await getPool({
|
|
8010
|
+
client: params.client,
|
|
8011
|
+
poolAddress: params.poolAddress,
|
|
8012
|
+
chainId: params.chainId,
|
|
8013
|
+
blockNumber: targetBlockNumber
|
|
8014
|
+
});
|
|
8015
|
+
} catch (error) {
|
|
8016
|
+
if (error instanceof PanopticError) throw error;
|
|
8017
|
+
throw new PanopticError("Failed to load the pool for temporary-loan recovery", error instanceof Error ? error : new Error(String(error)));
|
|
8018
|
+
}
|
|
8019
|
+
const defaultLimits = tickLimits(pool.currentTick, params.slippageBps);
|
|
8020
|
+
const tickLimitLow = params.tickLimitLow ?? defaultLimits.low;
|
|
8021
|
+
const tickLimitHigh = params.tickLimitHigh ?? defaultLimits.high;
|
|
8022
|
+
if (tickLimitLow >= tickLimitHigh) return {
|
|
8023
|
+
available: false,
|
|
8024
|
+
reason: "invalid-tick-limits",
|
|
8025
|
+
detail: `tickLimitLow=${tickLimitLow} >= tickLimitHigh=${tickLimitHigh}`
|
|
8026
|
+
};
|
|
8027
|
+
const token0 = pool.collateralTracker0.token;
|
|
8028
|
+
const token1 = pool.collateralTracker1.token;
|
|
8029
|
+
const tokenIndexFor = (address) => {
|
|
8030
|
+
const normalized = address.toLowerCase();
|
|
8031
|
+
if (normalized === token0.toLowerCase() || normalized === pool.collateralTracker0.address.toLowerCase()) return 0n;
|
|
8032
|
+
if (normalized === token1.toLowerCase() || normalized === pool.collateralTracker1.address.toLowerCase()) return 1n;
|
|
8033
|
+
return null;
|
|
8034
|
+
};
|
|
8035
|
+
const loanTokenIndex = tokenIndexFor(initialShortfall.tokenAddress);
|
|
8036
|
+
if (loanTokenIndex === null) return {
|
|
8037
|
+
available: false,
|
|
8038
|
+
reason: "unsupported-token",
|
|
8039
|
+
detail: `${initialShortfall.tokenAddress} is neither collateral token of ${params.poolAddress}`
|
|
8040
|
+
};
|
|
8041
|
+
const repaymentTokenIndex = loanTokenIndex === 0n ? 1n : 0n;
|
|
8042
|
+
const loanToken = loanTokenIndex === 0n ? token0 : token1;
|
|
8043
|
+
const repaymentToken = repaymentTokenIndex === 0n ? token0 : token1;
|
|
8044
|
+
const collisionIds = Array.from(new Set([
|
|
8045
|
+
...params.existingPositionIds,
|
|
8046
|
+
...params.dispatch.positionIdList,
|
|
8047
|
+
...params.dispatch.finalPositionIdList
|
|
8048
|
+
]));
|
|
8049
|
+
for (let attempt = 0n; attempt < MAX_RECOVERY_ATTEMPTS; attempt += 1n) {
|
|
8050
|
+
if (loanAmount > MAX_UINT128) return {
|
|
8051
|
+
available: false,
|
|
8052
|
+
reason: "recovery-unavailable",
|
|
8053
|
+
detail: `required loan amount ${loanAmount} exceeds uint128`
|
|
8054
|
+
};
|
|
8055
|
+
const loan = buildUniqueLoan(pool.poolId, loanTokenIndex, loanTokenIndex, pool.currentTick, pool.tickSpacing, collisionIds, loanAmount);
|
|
8056
|
+
const recoveredDispatch = buildTemporaryLoanRecoveryDispatch({
|
|
8057
|
+
dispatch: params.dispatch,
|
|
8058
|
+
loanTokenId: loan.tokenId,
|
|
8059
|
+
loanPositionSize: loan.adjustedSize,
|
|
8060
|
+
tickLimitLow,
|
|
8061
|
+
tickLimitHigh
|
|
8062
|
+
});
|
|
8063
|
+
const simulation = await simulateDispatch({
|
|
8064
|
+
client: params.client,
|
|
8065
|
+
poolAddress: params.poolAddress,
|
|
8066
|
+
account: params.account,
|
|
8067
|
+
existingPositionIdList: params.existingPositionIds,
|
|
8068
|
+
...recoveredDispatch,
|
|
8069
|
+
blockNumber: targetBlockNumber
|
|
8070
|
+
});
|
|
8071
|
+
if (simulation.success && simulation.tokenFlow !== void 0) {
|
|
8072
|
+
const tokenFlow = simulation.tokenFlow;
|
|
8073
|
+
return {
|
|
8074
|
+
available: true,
|
|
8075
|
+
quote: {
|
|
8076
|
+
loanToken,
|
|
8077
|
+
repaymentToken,
|
|
8078
|
+
loanTokenIndex,
|
|
8079
|
+
loanAmount,
|
|
8080
|
+
loanPositionSize: loan.adjustedSize,
|
|
8081
|
+
loanTokenId: loan.tokenId,
|
|
8082
|
+
slippageBps: params.slippageBps,
|
|
8083
|
+
netLoanTokenChange: loanTokenIndex === 0n ? tokenFlow.delta0 : tokenFlow.delta1,
|
|
8084
|
+
netRepaymentTokenChange: repaymentTokenIndex === 0n ? tokenFlow.delta0 : tokenFlow.delta1,
|
|
8085
|
+
dispatch: recoveredDispatch,
|
|
8086
|
+
simulation: {
|
|
8087
|
+
...simulation,
|
|
8088
|
+
tokenFlow
|
|
8089
|
+
},
|
|
8090
|
+
tokenFlow,
|
|
8091
|
+
_meta: simulation._meta
|
|
8092
|
+
}
|
|
8093
|
+
};
|
|
8094
|
+
}
|
|
8095
|
+
if (simulation.success) return {
|
|
8096
|
+
available: false,
|
|
8097
|
+
reason: "recovery-unavailable",
|
|
8098
|
+
detail: "temporary-loan simulation returned no token flow"
|
|
8099
|
+
};
|
|
8100
|
+
const shortfall = getNotEnoughTokensError(simulation.error);
|
|
8101
|
+
if (shortfall === null) return {
|
|
8102
|
+
available: false,
|
|
8103
|
+
reason: "recovery-unavailable",
|
|
8104
|
+
detail: `temporary-loan dispatch reverted: ${simulation.error.message}`,
|
|
8105
|
+
error: simulation.error
|
|
8106
|
+
};
|
|
8107
|
+
const shortfallIndex = tokenIndexFor(shortfall.tokenAddress);
|
|
8108
|
+
if (shortfallIndex !== loanTokenIndex) return {
|
|
8109
|
+
available: false,
|
|
8110
|
+
reason: "repayment-token-shortfall",
|
|
8111
|
+
detail: `repayment token ${shortfall.tokenAddress} requested ${shortfall.assetsRequested}, balance ${shortfall.assetBalance}`,
|
|
8112
|
+
error: simulation.error
|
|
8113
|
+
};
|
|
8114
|
+
const residual = shortfall.assetsRequested - shortfall.assetBalance;
|
|
8115
|
+
const geometricGrowth = (loanAmount + LOAN_GROWTH_DENOMINATOR - 1n) / LOAN_GROWTH_DENOMINATOR;
|
|
8116
|
+
loanAmount += residual > geometricGrowth ? residual : geometricGrowth;
|
|
8117
|
+
}
|
|
8118
|
+
return {
|
|
8119
|
+
available: false,
|
|
8120
|
+
reason: "recovery-unavailable",
|
|
8121
|
+
detail: `temporary-loan recovery remained short after ${MAX_RECOVERY_ATTEMPTS} attempts`,
|
|
8122
|
+
error: new PanopticError("Could not size the temporary loan within the quote attempt limit")
|
|
8123
|
+
};
|
|
8124
|
+
}
|
|
8125
|
+
|
|
7741
8126
|
//#endregion
|
|
7742
8127
|
//#region src/panoptic/v2/abis/poolManager.ts
|
|
7743
8128
|
/**
|
|
@@ -9100,4 +9485,4 @@ function isGasError(error) {
|
|
|
9100
9485
|
}
|
|
9101
9486
|
|
|
9102
9487
|
//#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 };
|
|
9488
|
+
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, buildTemporaryLoanRecoveryDispatch, 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, quoteTemporaryLoanRecovery, quoteTokenShortfallRecovery, removeTrackedChunks, resolveBlockNumbers, resolvePanopticPoolFromPoolId, resolveUniswapV4PoolKey, saveClosedPosition, scanChunks, simulateBatchDispatch, simulateClosePosition, simulateDeployNewPool, simulateDeposit, simulateDispatch, simulateForceExercise, simulateLiquidate, simulateSFPMBurn, simulateSFPMMint, simulateSettle, simulateSwapExactIn, simulateSwapExactOut, simulateWithdraw, slippageBpsToTickDistance, truncateAddress, watchEvents };
|