@panoptic-eng/sdk 1.0.69 → 1.0.71
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.d.ts.map +1 -1
- package/dist/{cow-BBPknr5W.js → cow-QYYo31eR.js} +1 -1
- package/dist/index.d.ts +42 -36
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +59 -22
- package/dist/index.js.map +1 -1
- package/dist/{irm-DurYJ0ht.js → irm-HM0KEH12.js} +926 -2
- package/dist/panoptic/v2/index.d.ts +156 -2
- package/dist/panoptic/v2/index.d.ts.map +1 -1
- package/dist/panoptic/v2/index.js +1538 -74
- package/dist/panoptic/v2/index.js.map +1 -1
- package/dist/panoptic/v2/react-public.d.ts +177 -2
- package/dist/panoptic/v2/react-public.d.ts.map +1 -1
- package/dist/panoptic/v2/react-public.js +1584 -74
- package/dist/panoptic/v2/react-public.js.map +1 -1
- package/dist/{providers-DubVMHWU.js → providers-CbcNt27n.js} +2 -1
- package/dist/{rates-B-eRYOTS.js → rates-DlqTkuXt.js} +1 -1
- package/dist/{router-ChMhfTqT.js → router-DDJ3OnDA.js} +29 -3
- package/dist/rpc/index.d.ts +9 -1
- package/dist/rpc/index.d.ts.map +1 -1
- package/dist/rpc/index.js +34 -2
- package/dist/rpc/index.js.map +1 -1
- package/dist/uniswap/index.d.ts +10 -1
- package/dist/uniswap/index.d.ts.map +1 -1
- package/dist/uniswap/index.js +27 -1
- package/dist/uniswap/index.js.map +1 -1
- package/dist/{v2-Bo1vZXvR.js → v2-BJtBYpJa.js} +537 -28
- package/dist/{writes-D53wWDT-.js → writes-DBu2ltcP.js} +33 -2
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { getAccountCollateral, getNetLiquidationValue, panopticQueryAbi$1 as panopticQueryAbi, readBlockAndAggregate, requireReturnData } from "./irm-
|
|
2
|
-
import { AccountInsolventError, ChunkLimitError, DEFAULT_VEGOID, InvalidHistoryRangeError, MulticallResultMissingError, NotEnoughTokensError, PanopticError, PanopticValidationError, SafeModeError, StaleDataError, StorageDataNotFoundError, UnhealthyPoolError, WrongUniswapPoolError, applyMintBufferPerToken, availableToBorrow, collateralTrackerV2Abi, decodeLeftRightSigned, decodeLeftRightUnsigned, decodePositionBalance, getBlockMeta, getClosedPositionsKey, getPendingPositionsKey, getPool, getPoolMetaKey, getPoolMetadata, getPositionMetaKey, getPositionsKey, getTrackedChunksKey, getTrackedPositionIds, isPanopticErrorType, jsonSerializer, mintableAfterBuffer, panopticFactoryV3Abi, panopticFactoryV4Abi, panopticGuardianAbi, panopticLiquidatorAbi, panopticPoolV2Abi, panopticQueryAbi as panopticQueryAbi$1, parsePanopticError, riskEngineAbi, riskEngineMulticall, semiFungiblePositionManagerV3Abi, semiFungiblePositionManagerV4Abi, stateViewAbi, uniswapV3PoolAbi } from "./rates-
|
|
3
|
-
import { MAX_TICK, MAX_TRACKED_CHUNKS, MIN_TICK, NO_LOWER_LIQUIDATION_TICK, NO_UPPER_LIQUIDATION_TICK, WAD, calculatePositionDelta, calculatePositionDeltaDebtOnly, calculatePositionGamma, calculatePositionValue, priceToTick, sqrtPriceX96ToTick, tickLimits, tickToPriceDecimalScaled, tickToSqrtPriceX96, toVaultFrameAtTick } from "./greeks-DNPP24KL.js";
|
|
4
|
-
import { addLegToTokenId, buildBatchDispatchArgs, buildProtectedSettlePlan, buildSettleSequenceCalls, buildUniqueCredit, buildUniqueLoan, countLegs, createTokenIdBuilder, decodeAllLegs, decodeTokenId, getCurrentPositionSizes, getPoolTokensForSimulation, loadCheckpoint, resolveTokenIndex, simulateDispatch, simulateOpenPosition, simulateWithTokenFlow } from "./writes-
|
|
5
|
-
import { feesFromFeeGrowthDelta, getLpPositionFunding, getMaxLpPositionSize, getPriceHistory, preparePositionGamma, quoteSwapExactOutViaRouter, quoteSwapExactOutViaV3Router } from "./router-
|
|
1
|
+
import { UniswapV3PoolAbi, getAccountCollateral, getNetLiquidationValue, panopticQueryAbi$1 as panopticQueryAbi, readBlockAndAggregate, requireReturnData } from "./irm-HM0KEH12.js";
|
|
2
|
+
import { AccountInsolventError, ChunkLimitError, DEFAULT_VEGOID, InvalidHistoryRangeError, MulticallResultMissingError, NotEnoughTokensError, PanopticError, PanopticValidationError, SafeModeError, StaleDataError, StorageDataNotFoundError, UnhealthyPoolError, WrongUniswapPoolError, applyMintBufferPerToken, availableToBorrow, collateralTrackerV2Abi, decodeLeftRightSigned, decodeLeftRightUnsigned, decodePositionBalance, getBlockMeta, getClosedPositionsKey, getPendingPositionsKey, getPool, getPoolMetaKey, getPoolMetadata, getPositionMetaKey, getPositionsKey, getTrackedChunksKey, getTrackedPositionIds, isPanopticErrorType, jsonSerializer, mintableAfterBuffer, panopticFactoryV3Abi, panopticFactoryV4Abi, panopticGuardianAbi, panopticLiquidatorAbi, panopticPoolV2Abi, panopticQueryAbi as panopticQueryAbi$1, parsePanopticError, riskEngineAbi, riskEngineMulticall, semiFungiblePositionManagerV3Abi, semiFungiblePositionManagerV4Abi, stateViewAbi, uniswapV3PoolAbi } from "./rates-DlqTkuXt.js";
|
|
3
|
+
import { MAX_TICK, MAX_TRACKED_CHUNKS, MIN_TICK, NO_LOWER_LIQUIDATION_TICK, NO_UPPER_LIQUIDATION_TICK, WAD, calculatePositionDelta, calculatePositionDeltaDebtOnly, calculatePositionGamma, calculatePositionValue, getLegLiquidityRange, priceToTick, sqrtPriceX96ToTick, tickLimits, tickToPriceDecimalScaled, tickToSqrtPriceX96, toVaultFrameAtTick } from "./greeks-DNPP24KL.js";
|
|
4
|
+
import { addLegToTokenId, buildBatchDispatchArgs, buildProtectedSettlePlan, buildSettleSequenceCalls, buildUniqueCredit, buildUniqueLoan, countLegs, createTokenIdBuilder, decodeAllLegs, decodeTokenId, getCurrentPositionSizes, getPoolTokensForSimulation, loadCheckpoint, resolveTokenIndex, simulateDispatch, simulateOpenPosition, simulateWithTokenFlow } from "./writes-DBu2ltcP.js";
|
|
5
|
+
import { feesFromFeeGrowthDelta, getLpPositionFunding, getMaxLpPositionSize, getPriceHistory, preparePositionGamma, quoteSwapExactOutViaRouter, quoteSwapExactOutViaV3Router } from "./router-DDJ3OnDA.js";
|
|
6
6
|
import { ContractFunctionExecutionError, decodeFunctionResult, encodeAbiParameters, encodeFunctionData, getAddress, hexToString, isAddress, isAddressEqual, isHex, keccak256, parseAbi, parseEventLogs, trim, zeroAddress } from "viem";
|
|
7
7
|
import { multicall } from "viem/actions";
|
|
8
8
|
import Decimal from "decimal.js";
|
|
@@ -672,7 +672,7 @@ function maximumAmountIn(estimatedAmountIn, slippageBps) {
|
|
|
672
672
|
if (slippageBps < 0n) throw new PanopticError("slippageBps must be non-negative");
|
|
673
673
|
return (estimatedAmountIn * (BPS_DENOMINATOR$2 + slippageBps) + BPS_DENOMINATOR$2 - 1n) / BPS_DENOMINATOR$2;
|
|
674
674
|
}
|
|
675
|
-
function ceilDiv$
|
|
675
|
+
function ceilDiv$3(numerator, denominator) {
|
|
676
676
|
return (numerator + denominator - 1n) / denominator;
|
|
677
677
|
}
|
|
678
678
|
function getInputAmount(tokenFlow, tokenInIndex) {
|
|
@@ -777,7 +777,7 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
777
777
|
const estimatedAmountIn = getInputAmount(swapSimulation.tokenFlow, tokenInIndex);
|
|
778
778
|
const estimatedAmountOut = getOutputAmount(swapSimulation.tokenFlow, tokenOutIndex);
|
|
779
779
|
if (estimatedAmountOut < requiredOutput) {
|
|
780
|
-
creditInput = estimatedAmountOut > 0n ? ceilDiv$
|
|
780
|
+
creditInput = estimatedAmountOut > 0n ? ceilDiv$3(creditInput * requiredOutput, estimatedAmountOut) + 1n : creditInput * 2n;
|
|
781
781
|
continue;
|
|
782
782
|
}
|
|
783
783
|
const recoveredDispatch = buildPrefixedExactInputRecoveryDispatch({
|
|
@@ -832,7 +832,7 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
832
832
|
};
|
|
833
833
|
const residual = remainingShortfall.assetsRequested - remainingShortfall.assetBalance;
|
|
834
834
|
requiredOutput += residual > 0n ? residual : requiredOutput;
|
|
835
|
-
creditInput = ceilDiv$
|
|
835
|
+
creditInput = ceilDiv$3(creditInput * requiredOutput, estimatedAmountOut) + 1n;
|
|
836
836
|
}
|
|
837
837
|
return {
|
|
838
838
|
available: false,
|
|
@@ -887,7 +887,7 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
887
887
|
const maxAmountIn = maximumAmountIn(estimatedAmountIn, params.slippageBps);
|
|
888
888
|
const swapOutput = getOutputAmount(swapSimulation.tokenFlow, tokenOutIndex);
|
|
889
889
|
if (swapOutput < amountOut) {
|
|
890
|
-
creditOutSize = swapOutput > 0n ? ceilDiv$
|
|
890
|
+
creditOutSize = swapOutput > 0n ? ceilDiv$3(creditOutSize * amountOut, swapOutput) + 1n : creditOutSize * 2n;
|
|
891
891
|
continue;
|
|
892
892
|
}
|
|
893
893
|
const recoverySimulation = await simulateDispatch({
|
|
@@ -942,7 +942,7 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
942
942
|
if (decodedShortfall >= shortfallError.assetsRequested - shortfallError.assetBalance) return quotePrefixedExactInput(amountOut);
|
|
943
943
|
const additionalAmountOut = decodedShortfall > 0n ? decodedShortfall : amountOut;
|
|
944
944
|
amountOut += additionalAmountOut;
|
|
945
|
-
creditOutSize = swapOutput > 0n ? ceilDiv$
|
|
945
|
+
creditOutSize = swapOutput > 0n ? ceilDiv$3(creditOutSize * amountOut, swapOutput) + 1n : creditOutSize * 2n;
|
|
946
946
|
}
|
|
947
947
|
return quotePrefixedExactInput(shortfallError.assetsRequested - shortfallError.assetBalance);
|
|
948
948
|
}
|
|
@@ -2250,7 +2250,7 @@ async function getItmAmounts(params) {
|
|
|
2250
2250
|
* high-decimal amount can't masquerade as real flow.
|
|
2251
2251
|
*/
|
|
2252
2252
|
const FLOW_NEUTRAL_DUST_THRESHOLD = 1000n;
|
|
2253
|
-
const Q192$
|
|
2253
|
+
const Q192$3 = 1n << 192n;
|
|
2254
2254
|
const POOL_ID_MASK$1 = (1n << 64n) - 1n;
|
|
2255
2255
|
/**
|
|
2256
2256
|
* Floor integer square root for bigints (Newton's method). Exact for all
|
|
@@ -2286,7 +2286,7 @@ function buildNeutralLeg(tokenIndex, signedAmount, positionSize) {
|
|
|
2286
2286
|
const absAmount = signedAmount < 0n ? -signedAmount : signedAmount;
|
|
2287
2287
|
const legAsset = tokenIndex === 0n ? 1n : 0n;
|
|
2288
2288
|
const legIsLong = signedAmount < 0n;
|
|
2289
|
-
const sqrtKrawX96 = isqrt(absAmount * Q192$
|
|
2289
|
+
const sqrtKrawX96 = isqrt(absAmount * Q192$3 / positionSize);
|
|
2290
2290
|
let signedTick;
|
|
2291
2291
|
try {
|
|
2292
2292
|
signedTick = sqrtPriceX96ToTick(sqrtKrawX96);
|
|
@@ -2544,7 +2544,7 @@ async function createFlowNeutralTokenId(params) {
|
|
|
2544
2544
|
const sqrtPX96 = tickToSqrtPriceX96(tickBefore);
|
|
2545
2545
|
const valueAbs = (index, amount) => {
|
|
2546
2546
|
const abs$1 = amount < 0n ? -amount : amount;
|
|
2547
|
-
return index === 0n ? abs$1 * sqrtPX96 * sqrtPX96 / Q192$
|
|
2547
|
+
return index === 0n ? abs$1 * sqrtPX96 * sqrtPX96 / Q192$3 : abs$1;
|
|
2548
2548
|
};
|
|
2549
2549
|
const flowFor = (index) => index === 0n ? credit.creditAmount0 : credit.creditAmount1;
|
|
2550
2550
|
if (queryAddress !== void 0) {
|
|
@@ -3517,7 +3517,7 @@ async function getPoolLiquidities(params) {
|
|
|
3517
3517
|
|
|
3518
3518
|
//#endregion
|
|
3519
3519
|
//#region src/panoptic/v2/reads/accountGreeks.ts
|
|
3520
|
-
const Q192$
|
|
3520
|
+
const Q192$2 = 1n << 192n;
|
|
3521
3521
|
/**
|
|
3522
3522
|
* Calculate account-level greeks using stored position data.
|
|
3523
3523
|
*
|
|
@@ -3638,8 +3638,8 @@ async function getAccountGreeks(params) {
|
|
|
3638
3638
|
const assetBal = isAssetToken0 ? collateral.token0.assets : collateral.token1.assets;
|
|
3639
3639
|
const otherBal = isAssetToken0 ? collateral.token1.assets : collateral.token0.assets;
|
|
3640
3640
|
const sqrtPriceX96 = tickToSqrtPriceX96(BigInt(currentTick));
|
|
3641
|
-
if (isAssetToken0) collateralValue = assetBal * sqrtPriceX96 * sqrtPriceX96 / Q192$
|
|
3642
|
-
else collateralValue = assetBal * Q192$
|
|
3641
|
+
if (isAssetToken0) collateralValue = assetBal * sqrtPriceX96 * sqrtPriceX96 / Q192$2 + otherBal;
|
|
3642
|
+
else collateralValue = assetBal * Q192$2 / (sqrtPriceX96 * sqrtPriceX96) + otherBal;
|
|
3643
3643
|
collateralDelta = assetBal;
|
|
3644
3644
|
}
|
|
3645
3645
|
return {
|
|
@@ -3679,7 +3679,7 @@ function calculateAccountGreeksPure(params) {
|
|
|
3679
3679
|
const totalDelta$1 = [];
|
|
3680
3680
|
for (let i = 0; i < n; i++) {
|
|
3681
3681
|
const sqrtPriceX96 = tickToSqrtPriceX96(atTicks[i]);
|
|
3682
|
-
const assetValueInNumeraire = isAssetToken0 ? assetBal * sqrtPriceX96 * sqrtPriceX96 / Q192$
|
|
3682
|
+
const assetValueInNumeraire = isAssetToken0 ? assetBal * sqrtPriceX96 * sqrtPriceX96 / Q192$2 : assetBal * Q192$2 / (sqrtPriceX96 * sqrtPriceX96);
|
|
3683
3683
|
totalValue$1.push(assetValueInNumeraire + otherBal);
|
|
3684
3684
|
totalDelta$1.push(assetBal);
|
|
3685
3685
|
}
|
|
@@ -3729,7 +3729,7 @@ function calculateAccountGreeksPure(params) {
|
|
|
3729
3729
|
}
|
|
3730
3730
|
for (let i = 0; i < n; i++) {
|
|
3731
3731
|
const sqrtPriceX96 = tickToSqrtPriceX96(atTicks[i]);
|
|
3732
|
-
const assetValueInNumeraire = isAssetToken0 ? assetBal * sqrtPriceX96 * sqrtPriceX96 / Q192$
|
|
3732
|
+
const assetValueInNumeraire = isAssetToken0 ? assetBal * sqrtPriceX96 * sqrtPriceX96 / Q192$2 : assetBal * Q192$2 / (sqrtPriceX96 * sqrtPriceX96);
|
|
3733
3733
|
totalValue[i] += assetValueInNumeraire + otherBal;
|
|
3734
3734
|
totalDelta[i] += assetBal;
|
|
3735
3735
|
}
|
|
@@ -5323,10 +5323,10 @@ async function processClosedPositions(client, queryAddress, positions) {
|
|
|
5323
5323
|
//#endregion
|
|
5324
5324
|
//#region src/panoptic/v2/reads/hedgeCapacity.ts
|
|
5325
5325
|
const SCALE$1 = 10000000n;
|
|
5326
|
-
const FEE_SCALE = 10000n;
|
|
5327
|
-
const Q192 = 1n << 192n;
|
|
5326
|
+
const FEE_SCALE$1 = 10000n;
|
|
5327
|
+
const Q192$1 = 1n << 192n;
|
|
5328
5328
|
const MASK128$1 = (1n << 128n) - 1n;
|
|
5329
|
-
const ceilDiv$
|
|
5329
|
+
const ceilDiv$2 = (value, divisor) => (value + divisor - 1n) / divisor;
|
|
5330
5330
|
function accountHedgeDelta({ positionIds, balances, collateralDelta, tick, tickSpacing, assetIndex }) {
|
|
5331
5331
|
return positionIds.reduce((sum$1, id, index) => {
|
|
5332
5332
|
const balance = balances[index];
|
|
@@ -5346,8 +5346,8 @@ function accountHedgeDelta({ positionIds, balances, collateralDelta, tick, tickS
|
|
|
5346
5346
|
function buildCapacityHedge({ delta, assetIndex, tick, tickSpacing, poolId, notionalFee, swapFee }) {
|
|
5347
5347
|
const borrowToken = delta >= 0n ? assetIndex : assetIndex === 0n ? 1n : 0n;
|
|
5348
5348
|
const receiveToken = borrowToken === 0n ? 1n : 0n;
|
|
5349
|
-
const amount = delta >= 0n ? delta : ceilDiv$
|
|
5350
|
-
const commission = ceilDiv$
|
|
5349
|
+
const amount = delta >= 0n ? delta : ceilDiv$2((toVaultFrameAtTick(-delta, assetIndex, borrowToken, tick) + 1n) * 1000000n * FEE_SCALE$1, (1000000n - swapFee) * (FEE_SCALE$1 - notionalFee));
|
|
5350
|
+
const commission = ceilDiv$2(amount * notionalFee, FEE_SCALE$1);
|
|
5351
5351
|
const proceeds = toVaultFrameAtTick((amount - commission) * (1000000n - swapFee) / 1000000n, borrowToken, receiveToken, tick);
|
|
5352
5352
|
const tokenId = addLegToTokenId(poolId, {
|
|
5353
5353
|
index: 0n,
|
|
@@ -5379,7 +5379,7 @@ function hedgeMargin({ tokenData, balanceChanges, crossRatios, tick, buffer }) {
|
|
|
5379
5379
|
const surplus1 = balances[1] > required1 ? (balances[1] - required1) * crossRatios[1] / SCALE$1 : 0n;
|
|
5380
5380
|
const sqrt = tickToSqrtPriceX96(tick);
|
|
5381
5381
|
const price = sqrt * sqrt;
|
|
5382
|
-
const pairs = sqrt < 1n << 96n ? [[balances[0] + surplus1 * Q192 / price, required0], [balances[1] * Q192 / price + surplus0, ceilDiv$
|
|
5382
|
+
const pairs = sqrt < 1n << 96n ? [[balances[0] + surplus1 * Q192$1 / price, required0], [balances[1] * Q192$1 / price + surplus0, ceilDiv$2(required1 * Q192$1, price)]] : [[balances[0] * price / Q192$1 + surplus1, ceilDiv$2(required0 * price, Q192$1)], [balances[1] + surplus0 * price / Q192$1, required1]];
|
|
5383
5383
|
const headroom = pairs.map(([balance, required]) => balance - required);
|
|
5384
5384
|
return {
|
|
5385
5385
|
solvent: balances.every((balance) => balance >= 0n) && headroom.every((value) => value >= 0n),
|
|
@@ -5592,7 +5592,7 @@ async function getHedgeLimits({ client, poolAddress, account, positionIds, asset
|
|
|
5592
5592
|
if (hedge.amount > 0n && BigInt(legCount) >= maxLegs) return unavailable("leg-limit");
|
|
5593
5593
|
const totalAssets = hedge.borrowToken === 0n ? total0 : total1;
|
|
5594
5594
|
if (hedge.amount > 0n && (hedge.amount > MAX_SIZE || hedge.amount > borrowCapacity[Number(hedge.borrowToken)] || totalAssets === 0n)) return unavailable("capacity");
|
|
5595
|
-
const projectedUtilization = currentUtilizations.map((util, i) => hedge.amount > 0n && BigInt(i) === hedge.borrowToken ? ceilDiv$
|
|
5595
|
+
const projectedUtilization = currentUtilizations.map((util, i) => hedge.amount > 0n && BigInt(i) === hedge.borrowToken ? ceilDiv$2(util * totalAssets + hedge.amount * 10000n, totalAssets) : util);
|
|
5596
5596
|
if (hedge.amount > 0n && projectedUtilization.some((util) => util > 10000n)) return unavailable("capacity");
|
|
5597
5597
|
const global = projectedUtilization.map((util, i) => util > globalUtilizations[i] ? util : globalUtilizations[i]);
|
|
5598
5598
|
const syntheticBalance = hedge.amount | projectedUtilization[0] << 128n | projectedUtilization[1] << 144n;
|
|
@@ -5684,6 +5684,90 @@ async function getHedgeLimits({ client, poolAddress, account, positionIds, asset
|
|
|
5684
5684
|
};
|
|
5685
5685
|
}
|
|
5686
5686
|
|
|
5687
|
+
//#endregion
|
|
5688
|
+
//#region src/panoptic/v2/reads/positionMintFunding.ts
|
|
5689
|
+
const Q96 = 1n << 96n;
|
|
5690
|
+
const Q192 = 1n << 192n;
|
|
5691
|
+
const BPS = 10000n;
|
|
5692
|
+
const FEE_SCALE = 1000000n;
|
|
5693
|
+
const max = (a, b) => a > b ? a : b;
|
|
5694
|
+
const ceilDiv$1 = (n, d) => n > 0n ? (n + d - 1n) / d : n / d;
|
|
5695
|
+
/**
|
|
5696
|
+
* Estimate deposit-independent mint funding, including settlement and commission.
|
|
5697
|
+
* Swaps use spot conversion with fees and slippage allowance; execution still needs a live quote.
|
|
5698
|
+
* Received tokens cover post-mint margin but cannot fund the other tracker's upfront payment.
|
|
5699
|
+
* Each requiredValue is the starting balance when funding entirely in that token.
|
|
5700
|
+
*/
|
|
5701
|
+
function getPositionMintFunding(params) {
|
|
5702
|
+
const { tokenId, positionSize, sqrtPriceX96, valuationSqrtPriceX96, swapAtMint, commissionRate, swapFee, slippageBps, required0, required1 } = params;
|
|
5703
|
+
if (positionSize < 0n || sqrtPriceX96 <= 0n || valuationSqrtPriceX96 <= 0n || commissionRate < 0n || swapFee < 0n || swapFee >= FEE_SCALE || slippageBps < 0n || slippageBps >= BPS || required0 < 0n || required1 < 0n) throw new RangeError("Invalid mint funding inputs");
|
|
5704
|
+
const { legs, tickSpacing } = decodeTokenId(tokenId);
|
|
5705
|
+
const firstLeg = legs[0];
|
|
5706
|
+
if (!firstLeg || tickSpacing <= 0n) throw new RangeError("Invalid position");
|
|
5707
|
+
let paid0 = 0n;
|
|
5708
|
+
let paid1 = 0n;
|
|
5709
|
+
let itm0 = 0n;
|
|
5710
|
+
let itm1 = 0n;
|
|
5711
|
+
let notional0 = 0n;
|
|
5712
|
+
let notional1 = 0n;
|
|
5713
|
+
for (const leg of legs) {
|
|
5714
|
+
const { sqrtLower, sqrtUpper, liquidity } = getLegLiquidityRange(leg.width === 0n ? {
|
|
5715
|
+
...leg,
|
|
5716
|
+
width: 2n
|
|
5717
|
+
} : leg, positionSize, tickSpacing);
|
|
5718
|
+
const round = !leg.isLong || leg.width === 0n ? ceilDiv$1 : (n, d) => n / d;
|
|
5719
|
+
const moved0 = round((liquidity << 96n) * (sqrtUpper - sqrtLower), sqrtUpper * sqrtLower);
|
|
5720
|
+
const moved1 = round(liquidity * (sqrtUpper - sqrtLower), Q96);
|
|
5721
|
+
const sign = leg.isLong ? -1n : 1n;
|
|
5722
|
+
let amm0 = 0n;
|
|
5723
|
+
let amm1 = 0n;
|
|
5724
|
+
if (leg.width > 0n) {
|
|
5725
|
+
const price = max(sqrtLower, sqrtPriceX96 < sqrtUpper ? sqrtPriceX96 : sqrtUpper);
|
|
5726
|
+
amm0 = sign * round((liquidity << 96n) * (sqrtUpper - price), sqrtUpper * price);
|
|
5727
|
+
amm1 = sign * round(liquidity * (price - sqrtLower), Q96);
|
|
5728
|
+
itm0 += leg.tokenType === 1n ? amm0 : 0n;
|
|
5729
|
+
itm1 += leg.tokenType === 0n ? amm1 : 0n;
|
|
5730
|
+
} else {
|
|
5731
|
+
itm0 -= leg.tokenType === 0n ? sign * moved0 : 0n;
|
|
5732
|
+
itm1 -= leg.tokenType === 1n ? sign * moved1 : 0n;
|
|
5733
|
+
}
|
|
5734
|
+
paid0 += amm0 - (leg.tokenType === 0n ? sign * moved0 : 0n);
|
|
5735
|
+
paid1 += amm1 - (leg.tokenType === 1n ? sign * moved1 : 0n);
|
|
5736
|
+
notional0 += leg.tokenType === 0n ? moved0 : 0n;
|
|
5737
|
+
notional1 += leg.tokenType === 1n ? moved1 : 0n;
|
|
5738
|
+
}
|
|
5739
|
+
if (swapAtMint && (itm0 !== 0n || itm1 !== 0n)) {
|
|
5740
|
+
const swapToken0 = itm0 !== 0n && (itm1 === 0n || firstLeg.asset === 0n);
|
|
5741
|
+
const priceSquared$1 = sqrtPriceX96 * sqrtPriceX96;
|
|
5742
|
+
const itm = swapToken0 ? itm0 : itm1;
|
|
5743
|
+
const numerator = swapToken0 ? priceSquared$1 : Q192;
|
|
5744
|
+
const denominator = swapToken0 ? Q192 : priceSquared$1;
|
|
5745
|
+
const retained$1 = (FEE_SCALE - swapFee) * (BPS - slippageBps);
|
|
5746
|
+
const scale$1 = FEE_SCALE * BPS;
|
|
5747
|
+
const payment = itm > 0n ? ceilDiv$1(itm * numerator * scale$1, denominator * retained$1) : itm * numerator * retained$1 / (denominator * scale$1);
|
|
5748
|
+
paid0 += swapToken0 ? -itm : payment;
|
|
5749
|
+
paid1 += swapToken0 ? payment : -itm;
|
|
5750
|
+
}
|
|
5751
|
+
paid0 += ceilDiv$1(notional0 * commissionRate, BPS);
|
|
5752
|
+
paid1 += ceilDiv$1(notional1 * commissionRate, BPS);
|
|
5753
|
+
const priceSquared = valuationSqrtPriceX96 * valuationSqrtPriceX96;
|
|
5754
|
+
const inToken0 = (amount0, amount1) => amount0 + ceilDiv$1(amount1 * Q192, priceSquared);
|
|
5755
|
+
const inToken1 = (amount0, amount1) => amount1 + ceilDiv$1(amount0 * priceSquared, Q192);
|
|
5756
|
+
const retained = (FEE_SCALE - swapFee) * (BPS - slippageBps);
|
|
5757
|
+
const scale = FEE_SCALE * BPS;
|
|
5758
|
+
const spotSquared = sqrtPriceX96 * sqrtPriceX96;
|
|
5759
|
+
const upfront0 = max(paid0, 0n) + ceilDiv$1(max(paid1, 0n) * Q192 * scale, spotSquared * retained);
|
|
5760
|
+
const upfront1 = max(paid1, 0n) + ceilDiv$1(max(paid0, 0n) * spotSquared * scale, Q192 * retained);
|
|
5761
|
+
const requiredValue0 = upfront0 + max(0n, inToken0(required0 - max(-paid0, 0n), required1 - max(-paid1, 0n)));
|
|
5762
|
+
const requiredValue1 = upfront1 + max(0n, inToken1(required0 - max(-paid0, 0n), required1 - max(-paid1, 0n)));
|
|
5763
|
+
return {
|
|
5764
|
+
paid0,
|
|
5765
|
+
paid1,
|
|
5766
|
+
requiredValue0,
|
|
5767
|
+
requiredValue1
|
|
5768
|
+
};
|
|
5769
|
+
}
|
|
5770
|
+
|
|
5687
5771
|
//#endregion
|
|
5688
5772
|
//#region src/panoptic/v2/sync/getSyncStatus.ts
|
|
5689
5773
|
/**
|
|
@@ -8645,7 +8729,7 @@ const DEFAULT_INTERVAL_MS = 12000n;
|
|
|
8645
8729
|
/**
|
|
8646
8730
|
* Default maximum block range per poll.
|
|
8647
8731
|
*/
|
|
8648
|
-
const DEFAULT_MAX_BLOCK_RANGE = 1000n;
|
|
8732
|
+
const DEFAULT_MAX_BLOCK_RANGE$1 = 1000n;
|
|
8649
8733
|
/**
|
|
8650
8734
|
* Create an HTTP polling-based event fetcher.
|
|
8651
8735
|
*
|
|
@@ -8682,7 +8766,7 @@ const DEFAULT_MAX_BLOCK_RANGE = 1000n;
|
|
|
8682
8766
|
* ```
|
|
8683
8767
|
*/
|
|
8684
8768
|
function createEventPoller(params) {
|
|
8685
|
-
const { client, poolAddress, collateralTracker0, collateralTracker1, riskEngineAddress, sfpmAddress, poolManagerAddress, eventTypes, onLogs, onError, intervalMs = DEFAULT_INTERVAL_MS, maxBlockRange = DEFAULT_MAX_BLOCK_RANGE, fromBlock } = params;
|
|
8769
|
+
const { client, poolAddress, collateralTracker0, collateralTracker1, riskEngineAddress, sfpmAddress, poolManagerAddress, eventTypes, onLogs, onError, intervalMs = DEFAULT_INTERVAL_MS, maxBlockRange = DEFAULT_MAX_BLOCK_RANGE$1, fromBlock } = params;
|
|
8686
8770
|
let isRunning = false;
|
|
8687
8771
|
let lastPolledBlock = fromBlock ?? 0n;
|
|
8688
8772
|
let pollTimeout = null;
|
|
@@ -8870,6 +8954,431 @@ function createEventPoller(params) {
|
|
|
8870
8954
|
};
|
|
8871
8955
|
}
|
|
8872
8956
|
|
|
8957
|
+
//#endregion
|
|
8958
|
+
//#region src/panoptic/v2/events/poolSwapStream.ts
|
|
8959
|
+
const DEFAULT_POLL_INTERVAL_MS$1 = 3e3;
|
|
8960
|
+
const FAILURE_WINDOW_MS = 3e4;
|
|
8961
|
+
const FAILURES_BEFORE_POLL = 3;
|
|
8962
|
+
const STREAM_RETRY_MIN_MS = 15e3;
|
|
8963
|
+
const STREAM_RETRY_MAX_MS = 3e5;
|
|
8964
|
+
const RESYNC_JITTER_MS = 2e3;
|
|
8965
|
+
const EVENT_SOURCE_CLOSED = 2;
|
|
8966
|
+
function parseRecord(data) {
|
|
8967
|
+
const value = JSON.parse(data);
|
|
8968
|
+
if (typeof value !== "object" || value === null) throw new Error("Malformed stream frame");
|
|
8969
|
+
return value;
|
|
8970
|
+
}
|
|
8971
|
+
function bigintField(record, field) {
|
|
8972
|
+
const value = record[field];
|
|
8973
|
+
if (typeof value !== "string") throw new Error(`Stream frame is missing ${field}`);
|
|
8974
|
+
return BigInt(value);
|
|
8975
|
+
}
|
|
8976
|
+
function numberField(record, field) {
|
|
8977
|
+
const value = record[field];
|
|
8978
|
+
if (typeof value !== "number") throw new Error(`Stream frame is missing ${field}`);
|
|
8979
|
+
return value;
|
|
8980
|
+
}
|
|
8981
|
+
function parseStreamedKey(data) {
|
|
8982
|
+
const record = parseRecord(data);
|
|
8983
|
+
return {
|
|
8984
|
+
blockNumber: bigintField(record, "blockNumber"),
|
|
8985
|
+
logIndex: numberField(record, "logIndex")
|
|
8986
|
+
};
|
|
8987
|
+
}
|
|
8988
|
+
function parseStreamedSwap(data) {
|
|
8989
|
+
const record = parseRecord(data);
|
|
8990
|
+
const transactionHash = record.transactionHash;
|
|
8991
|
+
if (typeof transactionHash !== "string") throw new Error("Stream frame is missing transactionHash");
|
|
8992
|
+
return {
|
|
8993
|
+
...parseStreamedKey(data),
|
|
8994
|
+
timestamp: bigintField(record, "timestamp"),
|
|
8995
|
+
transactionHash,
|
|
8996
|
+
tick: numberField(record, "tick"),
|
|
8997
|
+
amount0: bigintField(record, "amount0"),
|
|
8998
|
+
amount1: bigintField(record, "amount1"),
|
|
8999
|
+
sqrtPriceX96: bigintField(record, "sqrtPriceX96"),
|
|
9000
|
+
liquidity: bigintField(record, "liquidity")
|
|
9001
|
+
};
|
|
9002
|
+
}
|
|
9003
|
+
function parseHead(data) {
|
|
9004
|
+
return bigintField(parseRecord(data ?? ""), "head");
|
|
9005
|
+
}
|
|
9006
|
+
function defaultEventSource() {
|
|
9007
|
+
const EventSourceCtor = globalThis.EventSource;
|
|
9008
|
+
return EventSourceCtor && ((url) => new EventSourceCtor(url));
|
|
9009
|
+
}
|
|
9010
|
+
function toError$1(error) {
|
|
9011
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
9012
|
+
}
|
|
9013
|
+
/**
|
|
9014
|
+
* Stream a pool's swaps from the relay at `streamUrl`.
|
|
9015
|
+
*
|
|
9016
|
+
* Every `ready`/`resync` frame carries the relay's head; swaps from the cursor up
|
|
9017
|
+
* to that head are fetched over HTTP so nothing is lost across reconnects. A
|
|
9018
|
+
* stream that closes, or errors three times in 30 s, is replaced by HTTP polling
|
|
9019
|
+
* and retried with backoff; one that closes before ever opening is not retried.
|
|
9020
|
+
*/
|
|
9021
|
+
function streamPoolSwaps(params) {
|
|
9022
|
+
const { client, pool, fromBlock, pollIntervalMs = DEFAULT_POLL_INTERVAL_MS$1, maxBlockRange = DEFAULT_MAX_BLOCK_RANGE, streamUrl, onSwaps, onError, onRemoved, onTransport, eventSource = defaultEventSource() } = params;
|
|
9023
|
+
let running = true;
|
|
9024
|
+
let cursor = fromBlock === void 0 ? void 0 : fromBlock - 1n;
|
|
9025
|
+
let transport = "off";
|
|
9026
|
+
let failures = [];
|
|
9027
|
+
let source;
|
|
9028
|
+
let poller;
|
|
9029
|
+
let retryTimer;
|
|
9030
|
+
let retryDelayMs = STREAM_RETRY_MIN_MS;
|
|
9031
|
+
let catchUpTimer;
|
|
9032
|
+
let catchUpTarget;
|
|
9033
|
+
let catchingUp = false;
|
|
9034
|
+
let everOpened = false;
|
|
9035
|
+
const setTransport = (next) => {
|
|
9036
|
+
if (next === transport) return;
|
|
9037
|
+
transport = next;
|
|
9038
|
+
onTransport?.(next);
|
|
9039
|
+
};
|
|
9040
|
+
const advance = (block) => {
|
|
9041
|
+
if (block !== void 0 && (cursor === void 0 || block > cursor)) cursor = block;
|
|
9042
|
+
};
|
|
9043
|
+
const report = (error) => {
|
|
9044
|
+
if (running) onError?.(toError$1(error));
|
|
9045
|
+
};
|
|
9046
|
+
const catchUpPending = () => catchingUp || catchUpTarget !== void 0;
|
|
9047
|
+
const runCatchUp = async () => {
|
|
9048
|
+
catchingUp = true;
|
|
9049
|
+
while (running && catchUpTarget !== void 0) {
|
|
9050
|
+
const head = catchUpTarget;
|
|
9051
|
+
catchUpTarget = void 0;
|
|
9052
|
+
if (cursor === void 0) {
|
|
9053
|
+
cursor = head;
|
|
9054
|
+
continue;
|
|
9055
|
+
}
|
|
9056
|
+
try {
|
|
9057
|
+
const { swaps } = await fetchPoolSwaps(client, pool, cursor + 1n, head, maxBlockRange);
|
|
9058
|
+
if (!running) break;
|
|
9059
|
+
const first = swaps[0];
|
|
9060
|
+
const last = swaps[swaps.length - 1];
|
|
9061
|
+
if (first && last) onSwaps(swaps, {
|
|
9062
|
+
fromBlock: first.blockNumber,
|
|
9063
|
+
toBlock: last.blockNumber
|
|
9064
|
+
});
|
|
9065
|
+
advance(head);
|
|
9066
|
+
} catch (error) {
|
|
9067
|
+
report(error);
|
|
9068
|
+
if (catchUpTarget === void 0 || catchUpTarget < head) catchUpTarget = head;
|
|
9069
|
+
catchingUp = false;
|
|
9070
|
+
catchUpTimer = setTimeout(() => void runCatchUp(), pollIntervalMs);
|
|
9071
|
+
return;
|
|
9072
|
+
}
|
|
9073
|
+
}
|
|
9074
|
+
catchingUp = false;
|
|
9075
|
+
};
|
|
9076
|
+
const catchUp = (head, delayMs = 0) => {
|
|
9077
|
+
if (catchUpTarget === void 0 || head > catchUpTarget) catchUpTarget = head;
|
|
9078
|
+
if (catchingUp) return;
|
|
9079
|
+
if (catchUpTimer !== void 0) clearTimeout(catchUpTimer);
|
|
9080
|
+
catchUpTimer = setTimeout(() => {
|
|
9081
|
+
catchUpTimer = void 0;
|
|
9082
|
+
runCatchUp();
|
|
9083
|
+
}, delayMs);
|
|
9084
|
+
};
|
|
9085
|
+
const startPolling = () => {
|
|
9086
|
+
if (poller) return;
|
|
9087
|
+
poller = watchPoolSwaps({
|
|
9088
|
+
client,
|
|
9089
|
+
pool,
|
|
9090
|
+
fromBlock: cursor === void 0 ? void 0 : cursor + 1n,
|
|
9091
|
+
pollIntervalMs,
|
|
9092
|
+
maxBlockRange,
|
|
9093
|
+
onSwaps,
|
|
9094
|
+
onError
|
|
9095
|
+
});
|
|
9096
|
+
setTransport("poll");
|
|
9097
|
+
};
|
|
9098
|
+
const stopPolling = () => {
|
|
9099
|
+
if (!poller) return;
|
|
9100
|
+
advance(poller.lastScannedBlock());
|
|
9101
|
+
poller.stop();
|
|
9102
|
+
poller = void 0;
|
|
9103
|
+
};
|
|
9104
|
+
const closeStream = () => {
|
|
9105
|
+
source?.close();
|
|
9106
|
+
source = void 0;
|
|
9107
|
+
};
|
|
9108
|
+
const scheduleStreamRetry = () => {
|
|
9109
|
+
retryTimer = setTimeout(() => {
|
|
9110
|
+
retryTimer = void 0;
|
|
9111
|
+
if (running) openStream();
|
|
9112
|
+
}, retryDelayMs);
|
|
9113
|
+
retryDelayMs = Math.min(retryDelayMs * 2, STREAM_RETRY_MAX_MS);
|
|
9114
|
+
};
|
|
9115
|
+
const openStream = () => {
|
|
9116
|
+
if (!eventSource) {
|
|
9117
|
+
startPolling();
|
|
9118
|
+
return;
|
|
9119
|
+
}
|
|
9120
|
+
const es = eventSource(streamUrl);
|
|
9121
|
+
source = es;
|
|
9122
|
+
failures = [];
|
|
9123
|
+
let opened = false;
|
|
9124
|
+
const listen = (type, handle) => es.addEventListener(type, (event) => {
|
|
9125
|
+
if (!running || source !== es) return;
|
|
9126
|
+
try {
|
|
9127
|
+
handle(event.data);
|
|
9128
|
+
} catch (error) {
|
|
9129
|
+
report(error);
|
|
9130
|
+
}
|
|
9131
|
+
});
|
|
9132
|
+
listen("open", () => {
|
|
9133
|
+
opened = true;
|
|
9134
|
+
everOpened = true;
|
|
9135
|
+
failures = [];
|
|
9136
|
+
retryDelayMs = STREAM_RETRY_MIN_MS;
|
|
9137
|
+
});
|
|
9138
|
+
listen("ready", (data) => {
|
|
9139
|
+
const head = parseHead(data);
|
|
9140
|
+
stopPolling();
|
|
9141
|
+
setTransport("stream");
|
|
9142
|
+
catchUp(head);
|
|
9143
|
+
});
|
|
9144
|
+
listen("resync", (data) => {
|
|
9145
|
+
catchUp(parseHead(data), Math.random() * RESYNC_JITTER_MS);
|
|
9146
|
+
});
|
|
9147
|
+
listen("swap", (data) => {
|
|
9148
|
+
const swap = parseStreamedSwap(data ?? "");
|
|
9149
|
+
onSwaps([swap], {
|
|
9150
|
+
fromBlock: swap.blockNumber,
|
|
9151
|
+
toBlock: swap.blockNumber
|
|
9152
|
+
});
|
|
9153
|
+
if (!catchUpPending()) advance(swap.blockNumber);
|
|
9154
|
+
});
|
|
9155
|
+
listen("removed", (data) => {
|
|
9156
|
+
onRemoved?.(parseStreamedKey(data ?? ""));
|
|
9157
|
+
});
|
|
9158
|
+
listen("error", () => {
|
|
9159
|
+
const now = Date.now();
|
|
9160
|
+
failures = failures.filter((at) => now - at < FAILURE_WINDOW_MS);
|
|
9161
|
+
failures.push(now);
|
|
9162
|
+
const closed = es.readyState === EVENT_SOURCE_CLOSED;
|
|
9163
|
+
if (!closed && failures.length < FAILURES_BEFORE_POLL) return;
|
|
9164
|
+
closeStream();
|
|
9165
|
+
startPolling();
|
|
9166
|
+
if (closed && !opened && !everOpened) return;
|
|
9167
|
+
scheduleStreamRetry();
|
|
9168
|
+
});
|
|
9169
|
+
};
|
|
9170
|
+
openStream();
|
|
9171
|
+
return {
|
|
9172
|
+
stop() {
|
|
9173
|
+
running = false;
|
|
9174
|
+
closeStream();
|
|
9175
|
+
stopPolling();
|
|
9176
|
+
if (retryTimer !== void 0) clearTimeout(retryTimer);
|
|
9177
|
+
if (catchUpTimer !== void 0) clearTimeout(catchUpTimer);
|
|
9178
|
+
setTransport("off");
|
|
9179
|
+
},
|
|
9180
|
+
lastScannedBlock: () => cursor,
|
|
9181
|
+
transport: () => transport
|
|
9182
|
+
};
|
|
9183
|
+
}
|
|
9184
|
+
|
|
9185
|
+
//#endregion
|
|
9186
|
+
//#region src/panoptic/v2/events/poolSwaps.ts
|
|
9187
|
+
const DEFAULT_POLL_INTERVAL_MS = 3e3;
|
|
9188
|
+
const DEFAULT_MAX_BLOCK_RANGE = 2000n;
|
|
9189
|
+
const SHARED_BUFFER_LIMIT = 4096;
|
|
9190
|
+
/**
|
|
9191
|
+
* Parse a decoded v3 `UniswapV3Pool.Swap` or v4 `PoolManager.Swap` log.
|
|
9192
|
+
*/
|
|
9193
|
+
function parseSwapLog(log, timestamp) {
|
|
9194
|
+
if (log.blockNumber === null || log.logIndex === null || log.transactionHash === null) throw new Error("Cannot parse a pending Swap log");
|
|
9195
|
+
const args = log.args;
|
|
9196
|
+
return {
|
|
9197
|
+
blockNumber: log.blockNumber,
|
|
9198
|
+
logIndex: log.logIndex,
|
|
9199
|
+
timestamp,
|
|
9200
|
+
transactionHash: log.transactionHash,
|
|
9201
|
+
tick: Number(args.tick),
|
|
9202
|
+
amount0: args.amount0,
|
|
9203
|
+
amount1: args.amount1,
|
|
9204
|
+
sqrtPriceX96: args.sqrtPriceX96,
|
|
9205
|
+
liquidity: args.liquidity
|
|
9206
|
+
};
|
|
9207
|
+
}
|
|
9208
|
+
function toError(error) {
|
|
9209
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
9210
|
+
}
|
|
9211
|
+
async function fetchSwapLogs(client, pool, fromBlock, toBlock) {
|
|
9212
|
+
if (pool.version === "v3") return client.getContractEvents({
|
|
9213
|
+
address: pool.poolAddress,
|
|
9214
|
+
abi: UniswapV3PoolAbi,
|
|
9215
|
+
eventName: "Swap",
|
|
9216
|
+
fromBlock,
|
|
9217
|
+
toBlock
|
|
9218
|
+
});
|
|
9219
|
+
return client.getContractEvents({
|
|
9220
|
+
address: pool.poolManager,
|
|
9221
|
+
abi: poolManagerAbi,
|
|
9222
|
+
eventName: "Swap",
|
|
9223
|
+
args: { id: pool.poolId },
|
|
9224
|
+
fromBlock,
|
|
9225
|
+
toBlock
|
|
9226
|
+
});
|
|
9227
|
+
}
|
|
9228
|
+
async function fetchSwaps(client, pool, fromBlock, toBlock) {
|
|
9229
|
+
const logs = await fetchSwapLogs(client, pool, fromBlock, toBlock);
|
|
9230
|
+
if (logs.length === 0) return [];
|
|
9231
|
+
const blockNumbers = [...new Set(logs.flatMap((log) => log.blockNumber === null ? [] : [log.blockNumber]))];
|
|
9232
|
+
const blocks = await Promise.all(blockNumbers.map((blockNumber) => client.getBlock({ blockNumber })));
|
|
9233
|
+
const timestamps = new Map(blocks.map((block, i) => [blockNumbers[i], block.timestamp]));
|
|
9234
|
+
return logs.map((log) => parseSwapLog(log, timestamps.get(log.blockNumber ?? -1n) ?? 0n)).sort((a, b) => a.blockNumber === b.blockNumber ? a.logIndex - b.logIndex : a.blockNumber < b.blockNumber ? -1 : 1);
|
|
9235
|
+
}
|
|
9236
|
+
/**
|
|
9237
|
+
* Fetch a pool's swaps in `[fromBlock, toBlock]` (default: the current head), in
|
|
9238
|
+
* chain order. Returns no swaps when `fromBlock > toBlock`.
|
|
9239
|
+
*/
|
|
9240
|
+
async function fetchPoolSwaps(client, pool, fromBlock, toBlock, maxBlockRange = DEFAULT_MAX_BLOCK_RANGE) {
|
|
9241
|
+
const end = toBlock ?? await client.getBlockNumber();
|
|
9242
|
+
const swaps = [];
|
|
9243
|
+
for (let from = fromBlock; from <= end; from += maxBlockRange) {
|
|
9244
|
+
const to = from + maxBlockRange - 1n < end ? from + maxBlockRange - 1n : end;
|
|
9245
|
+
swaps.push(...await fetchSwaps(client, pool, from, to));
|
|
9246
|
+
}
|
|
9247
|
+
return {
|
|
9248
|
+
swaps,
|
|
9249
|
+
toBlock: end
|
|
9250
|
+
};
|
|
9251
|
+
}
|
|
9252
|
+
/**
|
|
9253
|
+
* Poll a single pool's `Swap` logs with `eth_getLogs`, timestamped by block.
|
|
9254
|
+
*
|
|
9255
|
+
* Works over plain HTTP (no filters or websockets). A chunk that fails is retried on
|
|
9256
|
+
* the next tick; errors never stop the loop.
|
|
9257
|
+
*/
|
|
9258
|
+
function watchPoolSwaps(params) {
|
|
9259
|
+
const { client, pool, fromBlock, pollIntervalMs = DEFAULT_POLL_INTERVAL_MS, maxBlockRange = DEFAULT_MAX_BLOCK_RANGE, onSwaps, onError } = params;
|
|
9260
|
+
let running = true;
|
|
9261
|
+
let lastScanned;
|
|
9262
|
+
let timer;
|
|
9263
|
+
const poll = async () => {
|
|
9264
|
+
try {
|
|
9265
|
+
const head = await client.getBlockNumber();
|
|
9266
|
+
let from = lastScanned !== void 0 ? lastScanned + 1n : fromBlock ?? head;
|
|
9267
|
+
while (running && from <= head) {
|
|
9268
|
+
const to = from + maxBlockRange - 1n < head ? from + maxBlockRange - 1n : head;
|
|
9269
|
+
const swaps = await fetchSwaps(client, pool, from, to);
|
|
9270
|
+
if (!running) return;
|
|
9271
|
+
if (swaps.length > 0) onSwaps(swaps, {
|
|
9272
|
+
fromBlock: from,
|
|
9273
|
+
toBlock: to
|
|
9274
|
+
});
|
|
9275
|
+
lastScanned = to;
|
|
9276
|
+
from = to + 1n;
|
|
9277
|
+
}
|
|
9278
|
+
} catch (error) {
|
|
9279
|
+
if (running) onError?.(toError(error));
|
|
9280
|
+
}
|
|
9281
|
+
if (running) timer = setTimeout(() => void poll(), pollIntervalMs);
|
|
9282
|
+
};
|
|
9283
|
+
poll();
|
|
9284
|
+
return {
|
|
9285
|
+
stop() {
|
|
9286
|
+
running = false;
|
|
9287
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
9288
|
+
},
|
|
9289
|
+
lastScannedBlock: () => lastScanned
|
|
9290
|
+
};
|
|
9291
|
+
}
|
|
9292
|
+
const sharedWatchers = new Map();
|
|
9293
|
+
function swapKey(key) {
|
|
9294
|
+
return `${key.blockNumber}:${key.logIndex}`;
|
|
9295
|
+
}
|
|
9296
|
+
/**
|
|
9297
|
+
* Ref-counted pool swap feed: subscribers with the same `key` share one watcher
|
|
9298
|
+
* (relay stream when `streamUrl` is set, else HTTP polling), duplicates are
|
|
9299
|
+
* dropped, late subscribers first receive the swaps already seen, and the watcher
|
|
9300
|
+
* stops when the last subscriber unsubscribes.
|
|
9301
|
+
*/
|
|
9302
|
+
function subscribePoolSwaps(params) {
|
|
9303
|
+
const { key, streamUrl, onSwaps, onError, onRemoved, onTransport,...watchParams } = params;
|
|
9304
|
+
const listener = {
|
|
9305
|
+
onSwaps,
|
|
9306
|
+
onError,
|
|
9307
|
+
onRemoved,
|
|
9308
|
+
onTransport
|
|
9309
|
+
};
|
|
9310
|
+
const existing = sharedWatchers.get(key);
|
|
9311
|
+
if (existing) {
|
|
9312
|
+
existing.listeners.add(listener);
|
|
9313
|
+
const buffered = [...existing.buffer.values()];
|
|
9314
|
+
const first = buffered[0];
|
|
9315
|
+
const last = buffered[buffered.length - 1];
|
|
9316
|
+
if (first && last) onSwaps(buffered, {
|
|
9317
|
+
fromBlock: first.blockNumber,
|
|
9318
|
+
toBlock: last.blockNumber
|
|
9319
|
+
});
|
|
9320
|
+
onTransport?.(existing.transport);
|
|
9321
|
+
} else {
|
|
9322
|
+
const listeners = new Set([listener]);
|
|
9323
|
+
const buffer = new Map();
|
|
9324
|
+
const entry = {
|
|
9325
|
+
watcher: {
|
|
9326
|
+
stop: () => void 0,
|
|
9327
|
+
lastScannedBlock: () => void 0
|
|
9328
|
+
},
|
|
9329
|
+
listeners,
|
|
9330
|
+
buffer,
|
|
9331
|
+
transport: "off"
|
|
9332
|
+
};
|
|
9333
|
+
const setTransport = (transport) => {
|
|
9334
|
+
entry.transport = transport;
|
|
9335
|
+
for (const l of listeners) l.onTransport?.(transport);
|
|
9336
|
+
};
|
|
9337
|
+
const callbacks = {
|
|
9338
|
+
onSwaps: (swaps, range) => {
|
|
9339
|
+
const fresh = swaps.filter((swap) => !buffer.has(swapKey(swap)));
|
|
9340
|
+
if (fresh.length === 0) return;
|
|
9341
|
+
for (const swap of fresh) buffer.set(swapKey(swap), swap);
|
|
9342
|
+
for (const k of buffer.keys()) {
|
|
9343
|
+
if (buffer.size <= SHARED_BUFFER_LIMIT) break;
|
|
9344
|
+
buffer.delete(k);
|
|
9345
|
+
}
|
|
9346
|
+
for (const l of listeners) l.onSwaps(fresh, range);
|
|
9347
|
+
},
|
|
9348
|
+
onError: (error) => {
|
|
9349
|
+
for (const l of listeners) l.onError?.(error);
|
|
9350
|
+
}
|
|
9351
|
+
};
|
|
9352
|
+
sharedWatchers.set(key, entry);
|
|
9353
|
+
if (streamUrl !== void 0) entry.watcher = streamPoolSwaps({
|
|
9354
|
+
...watchParams,
|
|
9355
|
+
...callbacks,
|
|
9356
|
+
streamUrl,
|
|
9357
|
+
onRemoved: (removed) => {
|
|
9358
|
+
buffer.delete(swapKey(removed));
|
|
9359
|
+
for (const l of listeners) l.onRemoved?.(removed);
|
|
9360
|
+
},
|
|
9361
|
+
onTransport: setTransport
|
|
9362
|
+
});
|
|
9363
|
+
else {
|
|
9364
|
+
entry.watcher = watchPoolSwaps({
|
|
9365
|
+
...watchParams,
|
|
9366
|
+
...callbacks
|
|
9367
|
+
});
|
|
9368
|
+
setTransport("poll");
|
|
9369
|
+
}
|
|
9370
|
+
}
|
|
9371
|
+
return () => {
|
|
9372
|
+
const entry = sharedWatchers.get(key);
|
|
9373
|
+
if (!entry) return;
|
|
9374
|
+
entry.listeners.delete(listener);
|
|
9375
|
+
if (entry.listeners.size === 0) {
|
|
9376
|
+
entry.watcher.stop();
|
|
9377
|
+
sharedWatchers.delete(key);
|
|
9378
|
+
}
|
|
9379
|
+
};
|
|
9380
|
+
}
|
|
9381
|
+
|
|
8873
9382
|
//#endregion
|
|
8874
9383
|
//#region src/panoptic/v2/strike/ladder.ts
|
|
8875
9384
|
/** Target number of rungs across a leg's full range (lower tick → upper tick). */
|
|
@@ -10233,4 +10742,4 @@ async function getPositionVolatilityHistory({ client, poolAddress, account, toke
|
|
|
10233
10742
|
}
|
|
10234
10743
|
|
|
10235
10744
|
//#endregion
|
|
10236
|
-
export { DEFAULT_MIN_SWAP_RATIO_BPS, DEFAULT_RECONNECT_CONFIG, MARKET_INDICATOR_PERIODS, REQUIRED_BASE_ERROR_SENTINEL, STRIKE_LADDER_TARGET_STRIKES, VARIANCE_RATIO_LAG, addPendingPosition, addTrackedChunks, apportion, assertCanBurn, assertCanForceExercise, assertCanLiquidate, assertCanMint, assertFresh, assertHealthy, assertLpPositionFunded, assertTradeable, buildCreditWrappedDispatch, buildSfpmSwapCalldata, buildSfpmSwapPlan, buildTemporaryLoanRecoveryDispatch, buildTokenShortfallRecoveryDispatch, calculateAccountGreeksPure, calculateMarketIndicator, calculateSpreadWad, calculateVarianceProfile, checkCollateralAcrossTicks, classifyStrategyGroups, classifyStrike, cleanupStalePendingPositions, clearPendingPositions, clearTrackedChunks, clearTradeHistory, collateralCurveTicks, collateralRuleKindFor, computeV4PoolId, confirmPendingPosition, convertToAssets, convertToShares, createEventPoller, createEventSubscription, createFlowNeutralTokenId, decodePanopticTokenURI, emptyLiquidateParams, encodePoolKeyBytes, encodeV3PoolKeyBytes, ensureSfpmV3PoolInitialized, estimateBlockNumbers, estimateCloseZapSwap, estimateCollateralBreakdown, estimateCollateralRequired, failPendingPosition, feeGrowthInsideX128, fetchSfpmV3PoolId, fetchUniswapFeeData, getAccountBuyingPower, getAccountGreeks, getAccountHistory, getChunkLiquidities, getChunkSpreads, getClosePositionTransferEstimate, getClosedPositions, getCollateralCurve, getCollateralCurveInputs, getCollateralRequiredBase, getCollateralSharePrices, getCollateralTotalAssetsBatch, getDeltaHedgeParams, getEnforcedTickLimits, getExecutableLpMaxSize, getFactoryConstructMetadata, getFactoryOwnerOf, getFactoryTokenURI, getGuardianUnlockState, getHedgeLimits, getItmAmounts, getMarginBuffer, getMaxPositionSize, getMaxRedeem, getMaxWithdrawable, getNativeTokenPrice, getNotEnoughTokensError, getOpenPositionPreview, getPanopticPoolAddress, getPanopticPoolFromPoolId, getPendingPositions, getPoolCollateralAddresses, getPoolLiquidities, getPortfolioValue, getPositionChunkData, getPositionEnrichmentData, getPositionValueCurve, getPositionVolatilityHistory, getRealizedPnL, getRequiredCreditForITM, getSafeMode, getStreamiaHistory, getSyncStatus, getTrackedChunks, getTradeHistory, getUniswapFeeHistory, getUniswapV3PoolFromId, getUniswapV3PoolInfo, getUniswapV3PoolLiquidities, getUniswapV4PoolBasicState, getUniswapV4PoolInfo, getUniswapV4PoolKeyFromId, getUniswapV4PoolLiquidities, interpolateBlocks, isGasError, isNonceError, isRetryableRpcError, isolateGroupTokenId, ladderStrikeSequence, logReturns, marketPnlInQuote, marketRiskFromValues, marketScenario, minePoolAddress, minePoolAddressLocalAsync, multicallRead, netLiquidationValueInQuote, optimizeTokenIdRiskPartners, parseCollateralLog, parsePoolLog, positionValueKey, positionValueTicks, prepareIndicatorCandles, preparePositionValueCurve, previewDeposit, previewMint, previewRedeem, previewWithdraw, quoteLiquidation, quoteOneTokenFlow, quoteSfpmSwap, quoteTemporaryLoanRecovery, quoteTokenShortfallRecovery, quoteTokenShortfallSwap, realizedBeta, removeTrackedChunks, resolveBlockNumbers, resolveLadderStrike, resolvePanopticPoolFromPoolId, resolveUniswapV4PoolKey, saveClosedPosition, scaleCollateralRequired, scanChunks, screenAccountExact, simulateBatchDispatch, simulateClosePosition, simulateClosePremiumProtection, simulateDeployNewPool, simulateDeposit, simulateForceExercise, simulateLiquidate, simulateSFPMBurn, simulateSFPMMint, simulateSwapExactIn, simulateSwapExactOut, simulateWithdraw, slippageBpsToTickDistance, watchEvents };
|
|
10745
|
+
export { DEFAULT_MIN_SWAP_RATIO_BPS, DEFAULT_RECONNECT_CONFIG, MARKET_INDICATOR_PERIODS, REQUIRED_BASE_ERROR_SENTINEL, STRIKE_LADDER_TARGET_STRIKES, VARIANCE_RATIO_LAG, addPendingPosition, addTrackedChunks, apportion, assertCanBurn, assertCanForceExercise, assertCanLiquidate, assertCanMint, assertFresh, assertHealthy, assertLpPositionFunded, assertTradeable, buildCreditWrappedDispatch, buildSfpmSwapCalldata, buildSfpmSwapPlan, buildTemporaryLoanRecoveryDispatch, buildTokenShortfallRecoveryDispatch, calculateAccountGreeksPure, calculateMarketIndicator, calculateSpreadWad, calculateVarianceProfile, checkCollateralAcrossTicks, classifyStrategyGroups, classifyStrike, cleanupStalePendingPositions, clearPendingPositions, clearTrackedChunks, clearTradeHistory, collateralCurveTicks, collateralRuleKindFor, computeV4PoolId, confirmPendingPosition, convertToAssets, convertToShares, createEventPoller, createEventSubscription, createFlowNeutralTokenId, decodePanopticTokenURI, emptyLiquidateParams, encodePoolKeyBytes, encodeV3PoolKeyBytes, ensureSfpmV3PoolInitialized, estimateBlockNumbers, estimateCloseZapSwap, estimateCollateralBreakdown, estimateCollateralRequired, failPendingPosition, feeGrowthInsideX128, fetchPoolSwaps, fetchSfpmV3PoolId, fetchUniswapFeeData, getAccountBuyingPower, getAccountGreeks, getAccountHistory, getChunkLiquidities, getChunkSpreads, getClosePositionTransferEstimate, getClosedPositions, getCollateralCurve, getCollateralCurveInputs, getCollateralRequiredBase, getCollateralSharePrices, getCollateralTotalAssetsBatch, getDeltaHedgeParams, getEnforcedTickLimits, getExecutableLpMaxSize, getFactoryConstructMetadata, getFactoryOwnerOf, getFactoryTokenURI, getGuardianUnlockState, getHedgeLimits, getItmAmounts, getMarginBuffer, getMaxPositionSize, getMaxRedeem, getMaxWithdrawable, getNativeTokenPrice, getNotEnoughTokensError, getOpenPositionPreview, getPanopticPoolAddress, getPanopticPoolFromPoolId, getPendingPositions, getPoolCollateralAddresses, getPoolLiquidities, getPortfolioValue, getPositionChunkData, getPositionEnrichmentData, getPositionMintFunding, getPositionValueCurve, getPositionVolatilityHistory, getRealizedPnL, getRequiredCreditForITM, getSafeMode, getStreamiaHistory, getSyncStatus, getTrackedChunks, getTradeHistory, getUniswapFeeHistory, getUniswapV3PoolFromId, getUniswapV3PoolInfo, getUniswapV3PoolLiquidities, getUniswapV4PoolBasicState, getUniswapV4PoolInfo, getUniswapV4PoolKeyFromId, getUniswapV4PoolLiquidities, interpolateBlocks, isGasError, isNonceError, isRetryableRpcError, isolateGroupTokenId, ladderStrikeSequence, logReturns, marketPnlInQuote, marketRiskFromValues, marketScenario, minePoolAddress, minePoolAddressLocalAsync, multicallRead, netLiquidationValueInQuote, optimizeTokenIdRiskPartners, parseCollateralLog, parsePoolLog, parseStreamedKey, parseStreamedSwap, parseSwapLog, positionValueKey, positionValueTicks, prepareIndicatorCandles, preparePositionValueCurve, previewDeposit, previewMint, previewRedeem, previewWithdraw, quoteLiquidation, quoteOneTokenFlow, quoteSfpmSwap, quoteTemporaryLoanRecovery, quoteTokenShortfallRecovery, quoteTokenShortfallSwap, realizedBeta, removeTrackedChunks, resolveBlockNumbers, resolveLadderStrike, resolvePanopticPoolFromPoolId, resolveUniswapV4PoolKey, saveClosedPosition, scaleCollateralRequired, scanChunks, screenAccountExact, simulateBatchDispatch, simulateClosePosition, simulateClosePremiumProtection, simulateDeployNewPool, simulateDeposit, simulateForceExercise, simulateLiquidate, simulateSFPMBurn, simulateSFPMMint, simulateSwapExactIn, simulateSwapExactOut, simulateWithdraw, slippageBpsToTickDistance, streamPoolSwaps, subscribePoolSwaps, watchEvents, watchPoolSwaps };
|