@panoptic-eng/sdk 1.0.40 → 1.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cow/index.d.ts.map +1 -1
- package/dist/cow/index.js +4 -0
- package/dist/cow/index.js.map +1 -1
- package/dist/index.d.ts +40 -2
- 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 +117 -11
- package/dist/panoptic/v2/index.d.ts.map +1 -1
- package/dist/panoptic/v2/index.js +1589 -1367
- package/dist/panoptic/v2/index.js.map +1 -1
- package/dist/panoptic/v2/react-public.d.ts +117 -11
- package/dist/panoptic/v2/react-public.d.ts.map +1 -1
- package/dist/panoptic/v2/react-public.js +1822 -1600
- 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-ChGyiigb.js} +224 -33
- 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
|
@@ -10024,1502 +10024,1661 @@ function hasLoanOrCredit(tokenId) {
|
|
|
10024
10024
|
}
|
|
10025
10025
|
|
|
10026
10026
|
//#endregion
|
|
10027
|
-
//#region src/panoptic/v2/
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
function
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
|
|
10043
|
-
|
|
10044
|
-
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
const
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
|
|
10027
|
+
//#region src/panoptic/v2/formatters/tick.ts
|
|
10028
|
+
const Q192$4 = 1n << 192n;
|
|
10029
|
+
const RAW_PRICE_PRECISION = 40n;
|
|
10030
|
+
function pow10(exponent) {
|
|
10031
|
+
if (exponent < 0n) throw new RangeError("Exponent must be non-negative");
|
|
10032
|
+
return 10n ** exponent;
|
|
10033
|
+
}
|
|
10034
|
+
function absBigint(value) {
|
|
10035
|
+
return value < 0n ? -value : value;
|
|
10036
|
+
}
|
|
10037
|
+
function trimTrailingZeros(value) {
|
|
10038
|
+
const dotIndex = value.indexOf(".");
|
|
10039
|
+
if (dotIndex === -1) return value;
|
|
10040
|
+
let end = value.length;
|
|
10041
|
+
while (end > dotIndex && value[end - 1] === "0") end -= 1;
|
|
10042
|
+
if (end === dotIndex + 1) end = dotIndex;
|
|
10043
|
+
return value.slice(0, end);
|
|
10044
|
+
}
|
|
10045
|
+
function formatRatio$3(numerator, denominator, precision) {
|
|
10046
|
+
if (precision < 0n) throw new RangeError("Precision must be non-negative");
|
|
10047
|
+
const sign = numerator < 0n ? "-" : "";
|
|
10048
|
+
const absNumerator = numerator < 0n ? -numerator : numerator;
|
|
10049
|
+
const scale = pow10(precision);
|
|
10050
|
+
const scaled = (absNumerator * scale + denominator / 2n) / denominator;
|
|
10051
|
+
const integerPart = scaled / scale;
|
|
10052
|
+
const fractionalPart = scaled % scale;
|
|
10053
|
+
if (precision === 0n) return `${sign}${integerPart}`;
|
|
10054
|
+
return `${sign}${integerPart}.${fractionalPart.toString().padStart(Number(precision), "0")}`;
|
|
10055
|
+
}
|
|
10056
|
+
function parseDecimalToFraction(value) {
|
|
10057
|
+
const trimmed = value.trim();
|
|
10058
|
+
if (trimmed.length === 0) throw new Error("Price must be a number");
|
|
10059
|
+
const isNegative = trimmed.startsWith("-");
|
|
10060
|
+
const unsigned = isNegative || trimmed.startsWith("+") ? trimmed.slice(1) : trimmed;
|
|
10061
|
+
const [basePart, exponentPart] = unsigned.toLowerCase().split("e");
|
|
10062
|
+
const [integerStr, fractionalStr = ""] = basePart.split(".");
|
|
10063
|
+
if (integerStr === "" && fractionalStr === "") throw new Error("Price must be a number");
|
|
10064
|
+
const integerDigits = integerStr === "" ? "0" : integerStr;
|
|
10065
|
+
const digits = `${integerDigits}${fractionalStr}`;
|
|
10066
|
+
let numerator = BigInt(digits === "" ? "0" : digits);
|
|
10067
|
+
let denominator = pow10(BigInt(fractionalStr.length));
|
|
10068
|
+
if (exponentPart !== void 0 && exponentPart !== "") {
|
|
10069
|
+
const exponent = BigInt(exponentPart);
|
|
10070
|
+
if (exponent > 0n) numerator *= pow10(exponent);
|
|
10071
|
+
else if (exponent < 0n) denominator *= pow10(-exponent);
|
|
10072
|
+
}
|
|
10073
|
+
if (isNegative) numerator = -numerator;
|
|
10062
10074
|
return {
|
|
10063
|
-
|
|
10064
|
-
|
|
10065
|
-
burnData
|
|
10075
|
+
numerator,
|
|
10076
|
+
denominator
|
|
10066
10077
|
};
|
|
10067
10078
|
}
|
|
10068
|
-
|
|
10069
|
-
|
|
10070
|
-
|
|
10071
|
-
|
|
10072
|
-
|
|
10073
|
-
*
|
|
10074
|
-
* `initializeAMMPool` is permissionless and idempotent and **returns the poolId**
|
|
10075
|
-
* whether or not the pool was already registered, so a `simulateContract` call is
|
|
10076
|
-
* enough to learn the id without sending a transaction. Always resolve the id this
|
|
10077
|
-
* way rather than encoding it offline — the SFPM can collision-increment ids.
|
|
10078
|
-
*/
|
|
10079
|
-
async function fetchSfpmV3PoolId(params) {
|
|
10080
|
-
const { client, sfpmAddress, token0, token1, fee } = params;
|
|
10081
|
-
const vegoid$1 = params.vegoid ?? Number(DEFAULT_VEGOID);
|
|
10082
|
-
const { result } = await client.simulateContract({
|
|
10083
|
-
address: sfpmAddress,
|
|
10084
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10085
|
-
functionName: "initializeAMMPool",
|
|
10086
|
-
args: [
|
|
10087
|
-
token0,
|
|
10088
|
-
token1,
|
|
10089
|
-
fee,
|
|
10090
|
-
vegoid$1
|
|
10091
|
-
]
|
|
10092
|
-
});
|
|
10093
|
-
return BigInt(result);
|
|
10079
|
+
function compareRatios(leftNumerator, leftDenominator, rightNumerator, rightDenominator) {
|
|
10080
|
+
const left = leftNumerator * rightDenominator;
|
|
10081
|
+
const right = rightNumerator * leftDenominator;
|
|
10082
|
+
if (left === right) return 0;
|
|
10083
|
+
return left < right ? -1 : 1;
|
|
10094
10084
|
}
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
|
|
10119
|
-
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
chain: wallet.chain ?? null,
|
|
10127
|
-
address: sfpmAddress,
|
|
10128
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10129
|
-
functionName: "initializeAMMPool",
|
|
10130
|
-
args: [
|
|
10131
|
-
token0,
|
|
10132
|
-
token1,
|
|
10133
|
-
fee,
|
|
10134
|
-
vegoid$1
|
|
10135
|
-
]
|
|
10136
|
-
});
|
|
10137
|
-
await client.waitForTransactionReceipt({ hash });
|
|
10138
|
-
initialized = true;
|
|
10139
|
-
resolved = await client.readContract({
|
|
10140
|
-
address: sfpmAddress,
|
|
10141
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10142
|
-
functionName: "getUniswapV3PoolFromId",
|
|
10143
|
-
args: [poolId]
|
|
10144
|
-
});
|
|
10145
|
-
}
|
|
10146
|
-
if (expectedPool !== void 0 && getAddress(resolved) !== getAddress(expectedPool)) throw new WrongUniswapPoolError(new PanopticError(`SFPM poolId ${poolId} resolves to ${resolved}, expected ${expectedPool}`));
|
|
10085
|
+
function tickToSqrtPriceX96(tick) {
|
|
10086
|
+
if (tick < MIN_TICK || tick > MAX_TICK) throw new RangeError("Tick out of bounds");
|
|
10087
|
+
const absTick = tick < 0n ? -tick : tick;
|
|
10088
|
+
let ratio = (absTick & 0x1n) !== 0n ? 0xfffcb933bd6fad37aa2d162d1a594001n : 0x100000000000000000000000000000000n;
|
|
10089
|
+
if ((absTick & 0x2n) !== 0n) ratio = ratio * 0xfff97272373d413259a46990580e213an >> 128n;
|
|
10090
|
+
if ((absTick & 0x4n) !== 0n) ratio = ratio * 0xfff2e50f5f656932ef12357cf3c7fdccn >> 128n;
|
|
10091
|
+
if ((absTick & 0x8n) !== 0n) ratio = ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0n >> 128n;
|
|
10092
|
+
if ((absTick & 0x10n) !== 0n) ratio = ratio * 0xffcb9843d60f6159c9db58835c926644n >> 128n;
|
|
10093
|
+
if ((absTick & 0x20n) !== 0n) ratio = ratio * 0xff973b41fa98c081472e6896dfb254c0n >> 128n;
|
|
10094
|
+
if ((absTick & 0x40n) !== 0n) ratio = ratio * 0xff2ea16466c96a3843ec78b326b52861n >> 128n;
|
|
10095
|
+
if ((absTick & 0x80n) !== 0n) ratio = ratio * 0xfe5dee046a99a2a811c461f1969c3053n >> 128n;
|
|
10096
|
+
if ((absTick & 0x100n) !== 0n) ratio = ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4n >> 128n;
|
|
10097
|
+
if ((absTick & 0x200n) !== 0n) ratio = ratio * 0xf987a7253ac413176f2b074cf7815e54n >> 128n;
|
|
10098
|
+
if ((absTick & 0x400n) !== 0n) ratio = ratio * 0xf3392b0822b70005940c7a398e4b70f3n >> 128n;
|
|
10099
|
+
if ((absTick & 0x800n) !== 0n) ratio = ratio * 0xe7159475a2c29b7443b29c7fa6e889d9n >> 128n;
|
|
10100
|
+
if ((absTick & 0x1000n) !== 0n) ratio = ratio * 0xd097f3bdfd2022b8845ad8f792aa5825n >> 128n;
|
|
10101
|
+
if ((absTick & 0x2000n) !== 0n) ratio = ratio * 0xa9f746462d870fdf8a65dc1f90e061e5n >> 128n;
|
|
10102
|
+
if ((absTick & 0x4000n) !== 0n) ratio = ratio * 0x70d869a156d2a1b890bb3df62baf32f7n >> 128n;
|
|
10103
|
+
if ((absTick & 0x8000n) !== 0n) ratio = ratio * 0x31be135f97d08fd981231505542fcfa6n >> 128n;
|
|
10104
|
+
if ((absTick & 0x10000n) !== 0n) ratio = ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9n >> 128n;
|
|
10105
|
+
if ((absTick & 0x20000n) !== 0n) ratio = ratio * 0x5d6af8dedb81196699c329225ee604n >> 128n;
|
|
10106
|
+
if ((absTick & 0x40000n) !== 0n) ratio = ratio * 0x2216e584f5fa1ea926041bedfe98n >> 128n;
|
|
10107
|
+
if ((absTick & 0x80000n) !== 0n) ratio = ratio * 0x48a170391f7dc42444e8fa2n >> 128n;
|
|
10108
|
+
if (tick > 0n) ratio = ((1n << 256n) - 1n) / ratio;
|
|
10109
|
+
const remainderMask = (1n << 32n) - 1n;
|
|
10110
|
+
const sqrtPriceX96 = (ratio >> 32n) + ((ratio & remainderMask) === 0n ? 0n : 1n);
|
|
10111
|
+
return sqrtPriceX96;
|
|
10112
|
+
}
|
|
10113
|
+
const MIN_SQRT_PRICE_X96 = tickToSqrtPriceX96(MIN_TICK);
|
|
10114
|
+
const MAX_SQRT_PRICE_X96 = tickToSqrtPriceX96(MAX_TICK);
|
|
10115
|
+
function getPriceRatioFromSqrtPriceX96(sqrtPriceX96) {
|
|
10147
10116
|
return {
|
|
10148
|
-
|
|
10149
|
-
|
|
10117
|
+
numerator: sqrtPriceX96 * sqrtPriceX96,
|
|
10118
|
+
denominator: Q192$4
|
|
10150
10119
|
};
|
|
10151
10120
|
}
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
const
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10167
|
-
|
|
10168
|
-
|
|
10169
|
-
let ticks = 0n;
|
|
10170
|
-
while (numerator * 10000n < denominator * (10000n + slippageBps)) {
|
|
10171
|
-
numerator *= 10001n;
|
|
10172
|
-
denominator *= 10000n;
|
|
10173
|
-
ticks += 1n;
|
|
10174
|
-
}
|
|
10175
|
-
return ticks;
|
|
10121
|
+
function getRawPriceRatio(tick) {
|
|
10122
|
+
return getPriceRatioFromSqrtPriceX96(tickToSqrtPriceX96(tick));
|
|
10123
|
+
}
|
|
10124
|
+
function adjustRatioForDecimals(numerator, denominator, decimals0, decimals1) {
|
|
10125
|
+
const diff = decimals0 - decimals1;
|
|
10126
|
+
if (diff === 0n) return {
|
|
10127
|
+
numerator,
|
|
10128
|
+
denominator
|
|
10129
|
+
};
|
|
10130
|
+
if (diff > 0n) return {
|
|
10131
|
+
numerator: numerator * pow10(diff),
|
|
10132
|
+
denominator
|
|
10133
|
+
};
|
|
10134
|
+
return {
|
|
10135
|
+
numerator,
|
|
10136
|
+
denominator: denominator * pow10(-diff)
|
|
10137
|
+
};
|
|
10176
10138
|
}
|
|
10177
10139
|
/**
|
|
10178
|
-
*
|
|
10140
|
+
* Convert a tick to a raw price string (no decimal adjustment).
|
|
10141
|
+
* Uses the formula: price = 1.0001^tick
|
|
10179
10142
|
*
|
|
10180
|
-
*
|
|
10181
|
-
*
|
|
10182
|
-
* exactly `positionSize` of the `tokenType` token when its call carries inverted
|
|
10183
|
-
* tick limits (`low > high`); the paired call uses a wide band and moves nothing.
|
|
10184
|
-
* - `exactIn`: swap on the **mint**; `tokenType` = the **input** token index.
|
|
10185
|
-
* - `exactOut`: swap on the **burn** (isLong flips → exact-output); `tokenType` = the
|
|
10186
|
-
* **output** token index.
|
|
10143
|
+
* This returns the raw price ratio, not adjusted for token decimals.
|
|
10144
|
+
* A fixed internal precision is used and trailing zeros are trimmed.
|
|
10187
10145
|
*
|
|
10188
|
-
*
|
|
10189
|
-
*
|
|
10146
|
+
* @param tick - The tick value
|
|
10147
|
+
* @returns Price string
|
|
10148
|
+
*
|
|
10149
|
+
* @example
|
|
10150
|
+
* ```typescript
|
|
10151
|
+
* tickToPrice(0n) // "1"
|
|
10152
|
+
* tickToPrice(1000n) // "1.105..." (approximately)
|
|
10153
|
+
* tickToPrice(-1000n) // "0.904..." (approximately)
|
|
10154
|
+
* tickToPrice(200000n) // Very large number
|
|
10155
|
+
* ```
|
|
10190
10156
|
*/
|
|
10191
|
-
function
|
|
10192
|
-
const {
|
|
10193
|
-
|
|
10194
|
-
|
|
10195
|
-
if (distance < 1n) throw new PanopticError(`slippageBps ${slippageBps} yields a zero-width tick band; use a larger tolerance`);
|
|
10196
|
-
const tokenType = kind === "exactIn" ? zeroForOne ? 0n : 1n : zeroForOne ? 1n : 0n;
|
|
10197
|
-
const tokenId = createTokenIdBuilder(poolId).addLoan({
|
|
10198
|
-
asset: tokenType,
|
|
10199
|
-
tokenType,
|
|
10200
|
-
strike: 0n
|
|
10201
|
-
}).build();
|
|
10202
|
-
const d = Number(distance);
|
|
10203
|
-
const low = Math.min(Number(MAX_TICK), currentTick + d);
|
|
10204
|
-
const high = Math.max(Number(MIN_TICK), currentTick - d);
|
|
10205
|
-
if (low <= high) throw new PanopticError(`slippageBps ${slippageBps} at tick ${currentTick} yields a non-inverted band after clamping`);
|
|
10206
|
-
const invertedLimits = [low, high];
|
|
10207
|
-
const swapOn = kind === "exactIn" ? "mint" : "burn";
|
|
10208
|
-
return {
|
|
10209
|
-
sfpmAddress,
|
|
10210
|
-
poolAddress,
|
|
10211
|
-
poolKey: encodeAbiParameters([{ type: "address" }], [poolAddress]),
|
|
10212
|
-
tokenId,
|
|
10213
|
-
positionSize: amount,
|
|
10214
|
-
mintTickLimits: swapOn === "mint" ? invertedLimits : WIDE_LIMITS,
|
|
10215
|
-
burnTickLimits: swapOn === "burn" ? invertedLimits : WIDE_LIMITS,
|
|
10216
|
-
swapOn,
|
|
10217
|
-
kind
|
|
10218
|
-
};
|
|
10157
|
+
function tickToPrice(tick) {
|
|
10158
|
+
const { numerator, denominator } = getRawPriceRatio(tick);
|
|
10159
|
+
const price = formatRatio$3(numerator, denominator, RAW_PRICE_PRECISION);
|
|
10160
|
+
return trimTrailingZeros(price);
|
|
10219
10161
|
}
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
|
|
10162
|
+
/**
|
|
10163
|
+
* Convert a tick to a human-readable price with decimal scaling.
|
|
10164
|
+
* Uses the formula: price = 1.0001^tick * 10^(decimals0-decimals1)
|
|
10165
|
+
*
|
|
10166
|
+
* This adjusts for the different decimals of the two tokens in the pair.
|
|
10167
|
+
*
|
|
10168
|
+
* @param tick - The tick value
|
|
10169
|
+
* @param decimals0 - Decimals of token0
|
|
10170
|
+
* @param decimals1 - Decimals of token1
|
|
10171
|
+
* @param precision - Number of decimal places to display
|
|
10172
|
+
* @returns Formatted price string
|
|
10173
|
+
*
|
|
10174
|
+
* @example
|
|
10175
|
+
* ```typescript
|
|
10176
|
+
* // WETH/USDC pool (18 decimals / 6 decimals)
|
|
10177
|
+
* // At tick ~200000, price is roughly $2000 per ETH
|
|
10178
|
+
* tickToPriceDecimalScaled(200000n, 18n, 6n, 2n) // "2000.00" (approximately)
|
|
10179
|
+
*
|
|
10180
|
+
* // For token1/token0 price, swap the decimals
|
|
10181
|
+
* tickToPriceDecimalScaled(200000n, 6n, 18n, 6n) // "0.000500" (approximately)
|
|
10182
|
+
* ```
|
|
10183
|
+
*/
|
|
10184
|
+
function tickToPriceDecimalScaled(tick, decimals0, decimals1, precision) {
|
|
10185
|
+
const rawRatio = getRawPriceRatio(tick);
|
|
10186
|
+
const { numerator, denominator } = adjustRatioForDecimals(rawRatio.numerator, rawRatio.denominator, decimals0, decimals1);
|
|
10187
|
+
return formatRatio$3(numerator, denominator, precision);
|
|
10233
10188
|
}
|
|
10234
|
-
/**
|
|
10235
|
-
|
|
10236
|
-
|
|
10237
|
-
|
|
10238
|
-
|
|
10239
|
-
|
|
10189
|
+
/**
|
|
10190
|
+
* Convert a sqrtPriceX96 to a human-readable price with decimal scaling.
|
|
10191
|
+
*
|
|
10192
|
+
* Uses the formula: price = (sqrtPriceX96^2 / 2^192) * 10^(decimals0-decimals1)
|
|
10193
|
+
*
|
|
10194
|
+
* @param sqrtPriceX96 - The sqrt price in Q64.96 format
|
|
10195
|
+
* @param decimals0 - Decimals of token0
|
|
10196
|
+
* @param decimals1 - Decimals of token1
|
|
10197
|
+
* @param precision - Number of decimal places to display
|
|
10198
|
+
* @returns Formatted price string
|
|
10199
|
+
*
|
|
10200
|
+
* @example
|
|
10201
|
+
* ```typescript
|
|
10202
|
+
* sqrtPriceX96ToPriceDecimalScaled(2n ** 96n, 18n, 18n, 2n) // "1.00"
|
|
10203
|
+
* ```
|
|
10204
|
+
*/
|
|
10205
|
+
function sqrtPriceX96ToPriceDecimalScaled(sqrtPriceX96, decimals0, decimals1, precision) {
|
|
10206
|
+
const rawRatio = getPriceRatioFromSqrtPriceX96(sqrtPriceX96);
|
|
10207
|
+
const { numerator, denominator } = adjustRatioForDecimals(rawRatio.numerator, rawRatio.denominator, decimals0, decimals1);
|
|
10208
|
+
return formatRatio$3(numerator, denominator, precision);
|
|
10240
10209
|
}
|
|
10241
10210
|
/**
|
|
10242
|
-
*
|
|
10243
|
-
*
|
|
10244
|
-
*
|
|
10211
|
+
* Convert a price to a tick value.
|
|
10212
|
+
*
|
|
10213
|
+
* @param price - The price string
|
|
10214
|
+
* @param decimals0 - Decimals of token0
|
|
10215
|
+
* @param decimals1 - Decimals of token1
|
|
10216
|
+
* @returns The tick value (rounded to nearest integer)
|
|
10217
|
+
*
|
|
10218
|
+
* @example
|
|
10219
|
+
* ```typescript
|
|
10220
|
+
* // WETH/USDC: What tick for $2000 per ETH?
|
|
10221
|
+
* priceToTick("2000", 18n, 6n) // ~200000n
|
|
10222
|
+
*
|
|
10223
|
+
* // Inverse: What tick for 0.0005 ETH per USDC?
|
|
10224
|
+
* priceToTick("0.0005", 6n, 18n) // ~200000n
|
|
10225
|
+
* ```
|
|
10245
10226
|
*/
|
|
10246
|
-
|
|
10247
|
-
const
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
const swapIndex = plan.swapOn === "mint" ? 0 : 1;
|
|
10264
|
-
const decoded = decodeFunctionResult({
|
|
10265
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10266
|
-
functionName: plan.swapOn === "mint" ? "mintTokenizedPosition" : "burnTokenizedPosition",
|
|
10267
|
-
data: result[swapIndex]
|
|
10268
|
-
});
|
|
10269
|
-
const finalTick = Number(decoded[2]);
|
|
10270
|
-
const { right, left } = unpackLeftRightSigned(decoded[1]);
|
|
10271
|
-
const inSlot = [right, left].find((s) => s > 0n);
|
|
10272
|
-
const outSlot = [right, left].find((s) => s < 0n);
|
|
10273
|
-
if (inSlot === void 0 || outSlot === void 0) return {
|
|
10274
|
-
success: false,
|
|
10275
|
-
error: new PanopticError(`SFPM swap simulation moved no tokens (totalMoved=${decoded[1]})`),
|
|
10276
|
-
_meta
|
|
10277
|
-
};
|
|
10278
|
-
return {
|
|
10279
|
-
success: true,
|
|
10280
|
-
data: {
|
|
10281
|
-
amountIn: inSlot,
|
|
10282
|
-
amountOut: -outSlot,
|
|
10283
|
-
finalTick
|
|
10284
|
-
},
|
|
10285
|
-
gasEstimate: 0n,
|
|
10286
|
-
_meta
|
|
10287
|
-
};
|
|
10288
|
-
} catch (err) {
|
|
10289
|
-
return {
|
|
10290
|
-
success: false,
|
|
10291
|
-
error: toPanopticError(err),
|
|
10292
|
-
_meta
|
|
10293
|
-
};
|
|
10227
|
+
function priceToTick(price, decimals0, decimals1) {
|
|
10228
|
+
const parsed = parseDecimalToFraction(price);
|
|
10229
|
+
if (parsed.numerator <= 0n) throw new Error("Price must be positive");
|
|
10230
|
+
let targetNumerator = parsed.numerator;
|
|
10231
|
+
let targetDenominator = parsed.denominator;
|
|
10232
|
+
const diff = decimals0 - decimals1;
|
|
10233
|
+
if (diff > 0n) targetDenominator *= pow10(diff);
|
|
10234
|
+
else if (diff < 0n) targetNumerator *= pow10(-diff);
|
|
10235
|
+
let low = MIN_TICK;
|
|
10236
|
+
let high = MAX_TICK;
|
|
10237
|
+
while (low <= high) {
|
|
10238
|
+
const mid = (low + high) / 2n;
|
|
10239
|
+
const { numerator, denominator } = getRawPriceRatio(mid);
|
|
10240
|
+
const cmp = compareRatios(numerator, denominator, targetNumerator, targetDenominator);
|
|
10241
|
+
if (cmp === 0) return mid;
|
|
10242
|
+
if (cmp < 0) low = mid + 1n;
|
|
10243
|
+
else high = mid - 1n;
|
|
10294
10244
|
}
|
|
10245
|
+
const floorTick = high;
|
|
10246
|
+
const ceilTick = low;
|
|
10247
|
+
if (floorTick < MIN_TICK) return MIN_TICK;
|
|
10248
|
+
if (ceilTick > MAX_TICK) return MAX_TICK;
|
|
10249
|
+
const floorRatio = getRawPriceRatio(floorTick);
|
|
10250
|
+
const ceilRatio = getRawPriceRatio(ceilTick);
|
|
10251
|
+
const floorDiffNumerator = absBigint(targetNumerator * floorRatio.denominator - floorRatio.numerator * targetDenominator);
|
|
10252
|
+
const ceilDiffNumerator = absBigint(targetNumerator * ceilRatio.denominator - ceilRatio.numerator * targetDenominator);
|
|
10253
|
+
const floorDiffDenominator = targetDenominator * floorRatio.denominator;
|
|
10254
|
+
const ceilDiffDenominator = targetDenominator * ceilRatio.denominator;
|
|
10255
|
+
return floorDiffNumerator * ceilDiffDenominator <= ceilDiffNumerator * floorDiffDenominator ? floorTick : ceilTick;
|
|
10295
10256
|
}
|
|
10296
|
-
|
|
10297
|
-
//#endregion
|
|
10298
|
-
//#region src/uniswap/v4/router/errors.ts
|
|
10299
10257
|
/**
|
|
10300
|
-
*
|
|
10301
|
-
*
|
|
10258
|
+
* Convert a sqrtPriceX96 value to the nearest tick.
|
|
10259
|
+
*
|
|
10260
|
+
* @param sqrtPriceX96 - The sqrt price in Q64.96 format
|
|
10261
|
+
* @returns The tick value (rounded to nearest integer)
|
|
10262
|
+
*
|
|
10263
|
+
* @example
|
|
10264
|
+
* ```typescript
|
|
10265
|
+
* const tick = sqrtPriceX96ToTick(2n ** 96n) // 0n
|
|
10266
|
+
* ```
|
|
10302
10267
|
*/
|
|
10303
|
-
|
|
10304
|
-
|
|
10305
|
-
|
|
10306
|
-
|
|
10307
|
-
|
|
10268
|
+
function sqrtPriceX96ToTick(sqrtPriceX96) {
|
|
10269
|
+
if (sqrtPriceX96 <= 0n) throw new Error("Sqrt price must be positive");
|
|
10270
|
+
if (sqrtPriceX96 < MIN_SQRT_PRICE_X96 || sqrtPriceX96 > MAX_SQRT_PRICE_X96) throw new RangeError("Sqrt price out of bounds");
|
|
10271
|
+
let low = MIN_TICK;
|
|
10272
|
+
let high = MAX_TICK;
|
|
10273
|
+
while (low <= high) {
|
|
10274
|
+
const mid = (low + high) / 2n;
|
|
10275
|
+
const midSqrt = tickToSqrtPriceX96(mid);
|
|
10276
|
+
if (midSqrt === sqrtPriceX96) return mid;
|
|
10277
|
+
if (midSqrt < sqrtPriceX96) low = mid + 1n;
|
|
10278
|
+
else high = mid - 1n;
|
|
10308
10279
|
}
|
|
10309
|
-
|
|
10310
|
-
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
const
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10280
|
+
const floorTick = high;
|
|
10281
|
+
const ceilTick = low;
|
|
10282
|
+
if (floorTick < MIN_TICK) return MIN_TICK;
|
|
10283
|
+
if (ceilTick > MAX_TICK) return MAX_TICK;
|
|
10284
|
+
const floorSqrt = tickToSqrtPriceX96(floorTick);
|
|
10285
|
+
const ceilSqrt = tickToSqrtPriceX96(ceilTick);
|
|
10286
|
+
const floorDiff = absBigint(sqrtPriceX96 - floorSqrt);
|
|
10287
|
+
const ceilDiff = absBigint(ceilSqrt - sqrtPriceX96);
|
|
10288
|
+
return floorDiff <= ceilDiff ? floorTick : ceilTick;
|
|
10289
|
+
}
|
|
10317
10290
|
/**
|
|
10318
|
-
*
|
|
10291
|
+
* Format a tick value for display.
|
|
10319
10292
|
*
|
|
10320
|
-
*
|
|
10321
|
-
*
|
|
10322
|
-
*
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
inputs: [{
|
|
10329
|
-
name: "params",
|
|
10330
|
-
type: "tuple",
|
|
10331
|
-
components: [
|
|
10332
|
-
{
|
|
10333
|
-
name: "tokenIn",
|
|
10334
|
-
type: "address"
|
|
10335
|
-
},
|
|
10336
|
-
{
|
|
10337
|
-
name: "tokenOut",
|
|
10338
|
-
type: "address"
|
|
10339
|
-
},
|
|
10340
|
-
{
|
|
10341
|
-
name: "amountIn",
|
|
10342
|
-
type: "uint256"
|
|
10343
|
-
},
|
|
10344
|
-
{
|
|
10345
|
-
name: "fee",
|
|
10346
|
-
type: "uint24"
|
|
10347
|
-
},
|
|
10348
|
-
{
|
|
10349
|
-
name: "sqrtPriceLimitX96",
|
|
10350
|
-
type: "uint160"
|
|
10351
|
-
}
|
|
10352
|
-
]
|
|
10353
|
-
}],
|
|
10354
|
-
outputs: [
|
|
10355
|
-
{
|
|
10356
|
-
name: "amountOut",
|
|
10357
|
-
type: "uint256"
|
|
10358
|
-
},
|
|
10359
|
-
{
|
|
10360
|
-
name: "sqrtPriceX96After",
|
|
10361
|
-
type: "uint160"
|
|
10362
|
-
},
|
|
10363
|
-
{
|
|
10364
|
-
name: "initializedTicksCrossed",
|
|
10365
|
-
type: "uint32"
|
|
10366
|
-
},
|
|
10367
|
-
{
|
|
10368
|
-
name: "gasEstimate",
|
|
10369
|
-
type: "uint256"
|
|
10370
|
-
}
|
|
10371
|
-
]
|
|
10372
|
-
}];
|
|
10373
|
-
|
|
10374
|
-
//#endregion
|
|
10375
|
-
//#region src/uniswap/v3/addresses.ts
|
|
10376
|
-
/**
|
|
10377
|
-
* Verified Uniswap v3 QuoterV2 addresses keyed by chainId. Add a chain only
|
|
10378
|
-
* after verifying against the canonical Uniswap v3 deployment listing.
|
|
10293
|
+
* @param tick - The tick value
|
|
10294
|
+
* @returns Formatted tick string
|
|
10295
|
+
*
|
|
10296
|
+
* @example
|
|
10297
|
+
* ```typescript
|
|
10298
|
+
* formatTick(200000n) // "200000"
|
|
10299
|
+
* formatTick(-50000n) // "-50000"
|
|
10300
|
+
* ```
|
|
10379
10301
|
*/
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
} };
|
|
10302
|
+
function formatTick(tick) {
|
|
10303
|
+
return tick.toString();
|
|
10304
|
+
}
|
|
10384
10305
|
/**
|
|
10385
|
-
*
|
|
10306
|
+
* Get the price at a specific tick, returning both token0/token1 and token1/token0 prices.
|
|
10386
10307
|
*
|
|
10387
|
-
* @
|
|
10388
|
-
*
|
|
10308
|
+
* @param tick - The tick value
|
|
10309
|
+
* @param decimals0 - Decimals of token0
|
|
10310
|
+
* @param decimals1 - Decimals of token1
|
|
10311
|
+
* @param precision - Number of decimal places to display
|
|
10312
|
+
* @returns Object with both price directions
|
|
10313
|
+
*
|
|
10314
|
+
* @example
|
|
10315
|
+
* ```typescript
|
|
10316
|
+
* const prices = getPricesAtTick(200000n, 18n, 6n, 2n)
|
|
10317
|
+
* // prices.token0PerToken1 = "0.00" (very small)
|
|
10318
|
+
* // prices.token1PerToken0 = "2000.00" (USDC per ETH)
|
|
10319
|
+
* ```
|
|
10389
10320
|
*/
|
|
10390
|
-
function
|
|
10391
|
-
const
|
|
10392
|
-
const
|
|
10393
|
-
|
|
10394
|
-
|
|
10395
|
-
|
|
10321
|
+
function getPricesAtTick(tick, decimals0, decimals1, precision) {
|
|
10322
|
+
const rawRatio = getRawPriceRatio(tick);
|
|
10323
|
+
const adjustedRatio = adjustRatioForDecimals(rawRatio.numerator, rawRatio.denominator, decimals0, decimals1);
|
|
10324
|
+
return {
|
|
10325
|
+
token0PerToken1: formatRatio$3(adjustedRatio.denominator, adjustedRatio.numerator, precision),
|
|
10326
|
+
token1PerToken0: formatRatio$3(adjustedRatio.numerator, adjustedRatio.denominator, precision)
|
|
10396
10327
|
};
|
|
10397
|
-
if (!merged.quoterV2 || !merged.nonfungiblePositionManager) throw new UnsupportedChainError(BigInt(id));
|
|
10398
|
-
return merged;
|
|
10399
10328
|
}
|
|
10400
|
-
|
|
10401
|
-
//#endregion
|
|
10402
|
-
//#region src/uniswap/v3/router/quote.ts
|
|
10403
|
-
const BPS_DENOMINATOR$3 = 10000n;
|
|
10404
|
-
const UINT128_MAX = (1n << 128n) - 1n;
|
|
10405
10329
|
/**
|
|
10406
|
-
*
|
|
10407
|
-
*
|
|
10408
|
-
*
|
|
10330
|
+
* Format a tick range for display.
|
|
10331
|
+
*
|
|
10332
|
+
* @param tickLower - Lower tick
|
|
10333
|
+
* @param tickUpper - Upper tick
|
|
10334
|
+
* @returns Formatted tick range string
|
|
10335
|
+
*
|
|
10336
|
+
* @example
|
|
10337
|
+
* ```typescript
|
|
10338
|
+
* formatTickRange(-50000n, 200000n) // "-50000 - 200000"
|
|
10339
|
+
* ```
|
|
10409
10340
|
*/
|
|
10410
|
-
|
|
10411
|
-
|
|
10412
|
-
if (amountIn < 0n || amountIn > UINT128_MAX) throw new PanopticError(`amountIn ${amountIn} exceeds uint128 maximum`);
|
|
10413
|
-
if (slippageBps < 0n || slippageBps > BPS_DENOMINATOR$3) throw new PanopticError(`invalid slippageBps ${slippageBps}, must be 0..10000`);
|
|
10414
|
-
const { quoterV2 } = getUniswapV3Addresses(chainId, params.addresses);
|
|
10415
|
-
try {
|
|
10416
|
-
const { result } = await client.simulateContract({
|
|
10417
|
-
address: quoterV2,
|
|
10418
|
-
abi: quoterV2Abi,
|
|
10419
|
-
functionName: "quoteExactInputSingle",
|
|
10420
|
-
blockNumber,
|
|
10421
|
-
args: [{
|
|
10422
|
-
tokenIn,
|
|
10423
|
-
tokenOut,
|
|
10424
|
-
amountIn,
|
|
10425
|
-
fee: Number(fee),
|
|
10426
|
-
sqrtPriceLimitX96: 0n
|
|
10427
|
-
}]
|
|
10428
|
-
});
|
|
10429
|
-
const [amountOut, , , gasEstimate] = result;
|
|
10430
|
-
const amountOutMinimum = amountOut * (BPS_DENOMINATOR$3 - slippageBps) / BPS_DENOMINATOR$3;
|
|
10431
|
-
return {
|
|
10432
|
-
amountOut,
|
|
10433
|
-
amountOutMinimum,
|
|
10434
|
-
gasEstimate
|
|
10435
|
-
};
|
|
10436
|
-
} catch (err) {
|
|
10437
|
-
if (isRevert(err)) return null;
|
|
10438
|
-
throw err;
|
|
10439
|
-
}
|
|
10440
|
-
}
|
|
10441
|
-
/** True only for genuine contract reverts (missing pool / no liquidity). */
|
|
10442
|
-
function isRevert(err) {
|
|
10443
|
-
return err instanceof BaseError && err.walk((e) => e instanceof ContractFunctionRevertedError) instanceof ContractFunctionRevertedError;
|
|
10341
|
+
function formatTickRange(tickLower, tickUpper) {
|
|
10342
|
+
return `${tickLower} - ${tickUpper}`;
|
|
10444
10343
|
}
|
|
10445
|
-
|
|
10446
|
-
//#endregion
|
|
10447
|
-
//#region src/panoptic/v2/reads/sfpm.ts
|
|
10448
10344
|
/**
|
|
10449
|
-
*
|
|
10345
|
+
* Format a price range for display.
|
|
10450
10346
|
*
|
|
10451
|
-
*
|
|
10347
|
+
* @param tickLower - Lower tick
|
|
10348
|
+
* @param tickUpper - Upper tick
|
|
10349
|
+
* @param decimals0 - Decimals of token0
|
|
10350
|
+
* @param decimals1 - Decimals of token1
|
|
10351
|
+
* @param precision - Number of decimal places to display
|
|
10352
|
+
* @returns Formatted price range string
|
|
10353
|
+
*
|
|
10354
|
+
* @example
|
|
10355
|
+
* ```typescript
|
|
10356
|
+
* formatPriceRange(0n, 0n, 18n, 18n, 2n) // "1.00 - 1.00"
|
|
10357
|
+
* ```
|
|
10452
10358
|
*/
|
|
10453
|
-
|
|
10454
|
-
const
|
|
10455
|
-
|
|
10456
|
-
|
|
10457
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10458
|
-
functionName: "getUniswapV3PoolFromId",
|
|
10459
|
-
args: [poolId]
|
|
10460
|
-
});
|
|
10359
|
+
function formatPriceRange(tickLower, tickUpper, decimals0, decimals1, precision) {
|
|
10360
|
+
const lower = tickToPriceDecimalScaled(tickLower, decimals0, decimals1, precision);
|
|
10361
|
+
const upper = tickToPriceDecimalScaled(tickUpper, decimals0, decimals1, precision);
|
|
10362
|
+
return `${lower} - ${upper}`;
|
|
10461
10363
|
}
|
|
10462
10364
|
/**
|
|
10463
|
-
*
|
|
10365
|
+
* Calculate the tick spacing for a given fee tier.
|
|
10464
10366
|
*
|
|
10465
|
-
*
|
|
10367
|
+
* @param feeBps - Fee in basis points (e.g., 500n for 0.05%)
|
|
10368
|
+
* @returns Tick spacing
|
|
10369
|
+
*
|
|
10370
|
+
* @example
|
|
10371
|
+
* ```typescript
|
|
10372
|
+
* getTickSpacing(100n) // 1n (0.01% fee tier)
|
|
10373
|
+
* getTickSpacing(500n) // 10n (0.05% fee tier)
|
|
10374
|
+
* getTickSpacing(3000n) // 60n (0.30% fee tier)
|
|
10375
|
+
* getTickSpacing(10000n) // 200n (1.00% fee tier)
|
|
10376
|
+
* ```
|
|
10466
10377
|
*/
|
|
10467
|
-
|
|
10468
|
-
|
|
10469
|
-
|
|
10470
|
-
|
|
10471
|
-
|
|
10472
|
-
|
|
10473
|
-
|
|
10474
|
-
|
|
10475
|
-
|
|
10476
|
-
|
|
10477
|
-
|
|
10478
|
-
fee: BigInt(raw.fee),
|
|
10479
|
-
tickSpacing: BigInt(raw.tickSpacing),
|
|
10480
|
-
hooks: raw.hooks
|
|
10481
|
-
};
|
|
10378
|
+
function getTickSpacing(feeBps) {
|
|
10379
|
+
switch (feeBps) {
|
|
10380
|
+
case 100n: return 1n;
|
|
10381
|
+
case 500n: return 10n;
|
|
10382
|
+
case 3000n: return 60n;
|
|
10383
|
+
case 10000n: return 200n;
|
|
10384
|
+
default: {
|
|
10385
|
+
const spacing = feeBps / 50n;
|
|
10386
|
+
return spacing > 1n ? spacing : 1n;
|
|
10387
|
+
}
|
|
10388
|
+
}
|
|
10482
10389
|
}
|
|
10483
10390
|
/**
|
|
10484
|
-
*
|
|
10391
|
+
* Round a tick to the nearest valid tick for a given tick spacing.
|
|
10485
10392
|
*
|
|
10486
|
-
* @param
|
|
10487
|
-
* @
|
|
10393
|
+
* @param tick - The tick to round
|
|
10394
|
+
* @param tickSpacing - The tick spacing
|
|
10395
|
+
* @returns Rounded tick
|
|
10396
|
+
*
|
|
10397
|
+
* @example
|
|
10398
|
+
* ```typescript
|
|
10399
|
+
* roundToTickSpacing(12345n, 10n) // 12340n
|
|
10400
|
+
* roundToTickSpacing(12345n, 60n) // 12360n
|
|
10401
|
+
* roundToTickSpacing(-12345n, 10n) // -12350n
|
|
10402
|
+
* ```
|
|
10488
10403
|
*/
|
|
10489
|
-
|
|
10490
|
-
const
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
|
|
10494
|
-
|
|
10495
|
-
args: [poolId]
|
|
10496
|
-
});
|
|
10497
|
-
return {
|
|
10498
|
-
minEnforcedTick: minTick,
|
|
10499
|
-
maxEnforcedTick: maxTick
|
|
10500
|
-
};
|
|
10404
|
+
function roundToTickSpacing(tick, tickSpacing) {
|
|
10405
|
+
const remainder = tick % tickSpacing;
|
|
10406
|
+
if (remainder === 0n) return tick;
|
|
10407
|
+
if (tick >= 0n) return remainder >= tickSpacing / 2n ? tick + (tickSpacing - remainder) : tick - remainder;
|
|
10408
|
+
const absRemainder = -remainder;
|
|
10409
|
+
return absRemainder >= tickSpacing / 2n ? tick - (tickSpacing - absRemainder) : tick + absRemainder;
|
|
10501
10410
|
}
|
|
10502
10411
|
/**
|
|
10503
|
-
*
|
|
10412
|
+
* Compute slippage-bounded tick limits around the current tick.
|
|
10504
10413
|
*
|
|
10505
|
-
*
|
|
10506
|
-
*
|
|
10414
|
+
* 1 tick ≈ 1 basis point (0.01 %) of price change, so a `toleranceBps`
|
|
10415
|
+
* of 500 allows roughly 5 % price movement. The result is clamped to
|
|
10416
|
+
* the protocol's `[MIN_TICK, MAX_TICK]` range.
|
|
10417
|
+
*
|
|
10418
|
+
* Useful for setting `tickLimitLow` / `tickLimitHigh` on `openPosition`
|
|
10419
|
+
* and `closePosition` to protect against MEV sandwiches and volatile
|
|
10420
|
+
* tick moves.
|
|
10421
|
+
*
|
|
10422
|
+
* @param currentTick - The current pool tick (must be within [MIN_TICK, MAX_TICK]).
|
|
10423
|
+
* @param toleranceBps - Slippage tolerance in basis points (≈ ticks). Must be non-negative.
|
|
10424
|
+
* @returns Clamped `{ low, high }` tick limits.
|
|
10425
|
+
* @throws {RangeError} If `toleranceBps` is negative or `currentTick` is out of bounds.
|
|
10426
|
+
*
|
|
10427
|
+
* @example
|
|
10428
|
+
* ```typescript
|
|
10429
|
+
* const { low, high } = tickLimits(200_000n, 500n)
|
|
10430
|
+
* // low = 199_500n
|
|
10431
|
+
* // high = 200_500n
|
|
10432
|
+
*
|
|
10433
|
+
* await openPosition({ ..., tickLimitLow: low, tickLimitHigh: high })
|
|
10434
|
+
* ```
|
|
10507
10435
|
*/
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
if (
|
|
10511
|
-
const
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
};
|
|
10516
|
-
const multicallResults = await client.multicall({
|
|
10517
|
-
contracts: chunks.map((chunk) => ({
|
|
10518
|
-
address: sfpmAddress,
|
|
10519
|
-
abi: semiFungiblePositionManagerV4Abi,
|
|
10520
|
-
functionName: "getAccountLiquidity",
|
|
10521
|
-
args: [
|
|
10522
|
-
poolKeyBytes,
|
|
10523
|
-
chunk.owner,
|
|
10524
|
-
chunk.tokenType,
|
|
10525
|
-
Number(chunk.tickLower),
|
|
10526
|
-
Number(chunk.tickUpper)
|
|
10527
|
-
]
|
|
10528
|
-
})),
|
|
10529
|
-
allowFailure: true
|
|
10530
|
-
});
|
|
10531
|
-
const results = multicallResults.map((result) => {
|
|
10532
|
-
if (result.status === "failure") return {
|
|
10533
|
-
netLiquidity: 0n,
|
|
10534
|
-
removedLiquidity: 0n,
|
|
10535
|
-
totalLiquidity: 0n,
|
|
10536
|
-
shortLiquidity: 0n,
|
|
10537
|
-
longLiquidity: 0n
|
|
10538
|
-
};
|
|
10539
|
-
const packed = result.result;
|
|
10540
|
-
const netLiquidity = packed & (1n << 128n) - 1n;
|
|
10541
|
-
const removedLiquidity = packed >> 128n;
|
|
10542
|
-
const totalLiquidity = netLiquidity + removedLiquidity;
|
|
10543
|
-
return {
|
|
10544
|
-
netLiquidity,
|
|
10545
|
-
removedLiquidity,
|
|
10546
|
-
totalLiquidity,
|
|
10547
|
-
shortLiquidity: totalLiquidity,
|
|
10548
|
-
longLiquidity: removedLiquidity
|
|
10549
|
-
};
|
|
10550
|
-
});
|
|
10436
|
+
function tickLimits(currentTick, toleranceBps) {
|
|
10437
|
+
if (toleranceBps < 0n) throw new RangeError(`toleranceBps must be non-negative, got ${toleranceBps}`);
|
|
10438
|
+
if (currentTick < MIN_TICK || currentTick > MAX_TICK) throw new RangeError(`currentTick ${currentTick} is out of bounds [${MIN_TICK}, ${MAX_TICK}]`);
|
|
10439
|
+
const rawLow = currentTick - toleranceBps;
|
|
10440
|
+
const rawHigh = currentTick + toleranceBps;
|
|
10441
|
+
const low = rawLow < MIN_TICK ? MIN_TICK : rawLow;
|
|
10442
|
+
const high = rawHigh > MAX_TICK ? MAX_TICK : rawHigh;
|
|
10443
|
+
if (low > high) throw new RangeError(`Computed tick limits are inverted: low ${low} > high ${high} (currentTick=${currentTick}, toleranceBps=${toleranceBps})`);
|
|
10551
10444
|
return {
|
|
10552
|
-
|
|
10553
|
-
|
|
10445
|
+
low,
|
|
10446
|
+
high
|
|
10554
10447
|
};
|
|
10555
10448
|
}
|
|
10556
10449
|
|
|
10557
10450
|
//#endregion
|
|
10558
|
-
//#region src/panoptic/v2/
|
|
10451
|
+
//#region src/panoptic/v2/tokenId/deriveUniqueTokenId.ts
|
|
10452
|
+
const POOL_ID_MASK$2 = (1n << 64n) - 1n;
|
|
10453
|
+
const MAX_LEGS = TOKEN_ID_BITS.MAX_LEGS;
|
|
10454
|
+
const MAX_OPTION_RATIO = LEG_LIMITS.MAX_RATIO;
|
|
10455
|
+
const Q192$3 = 1n << 192n;
|
|
10559
10456
|
/**
|
|
10560
|
-
*
|
|
10457
|
+
* Floor integer square root for bigints (Newton's method). Mirrors the isqrt
|
|
10458
|
+
* used in reads/collateralEstimate.ts (buildNeutralLeg).
|
|
10561
10459
|
*/
|
|
10562
|
-
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
|
|
10569
|
-
|
|
10570
|
-
}
|
|
10460
|
+
function isqrt$1(value) {
|
|
10461
|
+
if (value < 0n) throw new PanopticError("isqrt of negative number");
|
|
10462
|
+
if (value < 2n) return value;
|
|
10463
|
+
let x = value;
|
|
10464
|
+
let y = x + 1n >> 1n;
|
|
10465
|
+
while (y < x) {
|
|
10466
|
+
x = y;
|
|
10467
|
+
y = x + value / x >> 1n;
|
|
10468
|
+
}
|
|
10469
|
+
return x;
|
|
10571
10470
|
}
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
|
|
10471
|
+
const DEFAULT_TICK_SPACING = 200n;
|
|
10472
|
+
/**
|
|
10473
|
+
* Target notional (in wei of the tokenType-side asset) for the appended
|
|
10474
|
+
* tiny credit leg. Chosen at 10 wei — small enough to be economically
|
|
10475
|
+
* meaningless against any real position size, large enough to safely
|
|
10476
|
+
* clear rounding on the SFPM's width-2 internal chunk math without any
|
|
10477
|
+
* risk of underflowing to zero (which would revert ChunkHasZeroLiquidity).
|
|
10478
|
+
*/
|
|
10479
|
+
const TINY_CREDIT_TARGET_NOTIONAL_WEI = 10n;
|
|
10480
|
+
/**
|
|
10481
|
+
* Pick a signedStrike for the appended width=0 credit leg such that:
|
|
10482
|
+
* 1. positionSize · 1.0001^signedStrike ≈ TINY_CREDIT_TARGET_NOTIONAL_WEI
|
|
10483
|
+
* (~10 wei — economically meaningless but comfortably above any
|
|
10484
|
+
* SFPM width-2 chunk rounding);
|
|
10485
|
+
* 2. the leg's tick range (SFPM internally treats width=0 as width=2, so
|
|
10486
|
+
* the range is `strike ± tickSpacing`) stays strictly inside
|
|
10487
|
+
* `[MIN_POOL_TICK, MAX_POOL_TICK]` — otherwise the getSqrtRatioAtTick
|
|
10488
|
+
* call reverts with `InvalidTick`.
|
|
10489
|
+
*
|
|
10490
|
+
* Closed form: `1.0001^signedStrike = target/positionSize`, so
|
|
10491
|
+
* `sqrtKrawX96 = isqrt(target · 2^192 / positionSize)` and
|
|
10492
|
+
* `signedStrike = sqrtPriceX96ToTick(sqrtKrawX96)`. If the notional-optimal
|
|
10493
|
+
* strike falls outside the safe range, we clamp inward. Clamping raises the
|
|
10494
|
+
* notional but keeps it << position size for any reasonable strike.
|
|
10495
|
+
*/
|
|
10496
|
+
function computeTinyCreditSignedStrike(positionSize, tickSpacing) {
|
|
10497
|
+
if (positionSize <= 0n) throw new PanopticError("computeTinyCreditSignedStrike: positionSize must be > 0");
|
|
10498
|
+
const minSafe = MIN_TICK + tickSpacing + 1n;
|
|
10499
|
+
const maxSafe = MAX_TICK - tickSpacing - 1n;
|
|
10500
|
+
let signedStrike;
|
|
10501
|
+
try {
|
|
10502
|
+
const sqrtKrawX96 = isqrt$1(TINY_CREDIT_TARGET_NOTIONAL_WEI * Q192$3 / positionSize);
|
|
10503
|
+
signedStrike = sqrtPriceX96ToTick(sqrtKrawX96);
|
|
10504
|
+
} catch {
|
|
10505
|
+
signedStrike = minSafe;
|
|
10506
|
+
}
|
|
10507
|
+
if (signedStrike < minSafe) return minSafe;
|
|
10508
|
+
if (signedStrike > maxSafe) return maxSafe;
|
|
10509
|
+
return signedStrike;
|
|
10510
|
+
}
|
|
10511
|
+
/**
|
|
10512
|
+
* Assemble the tiny credit leg struct, picking a strike that avoids
|
|
10513
|
+
* colliding with any existing width=0 credit leg on the same (asset,
|
|
10514
|
+
* tokenType) pair.
|
|
10515
|
+
*
|
|
10516
|
+
* The encoded strike stored in the tokenId is
|
|
10517
|
+
* `asset === 0 ? signedStrike : -signedStrike` (mirrors
|
|
10518
|
+
* {@link buildNeutralLeg} in reads/collateralEstimate.ts).
|
|
10519
|
+
*/
|
|
10520
|
+
function pickUniqueTinyCreditLeg(baseTokenId, legIndex, positionSize, tickSpacing) {
|
|
10521
|
+
const asset = 1n;
|
|
10522
|
+
const tokenType = 0n;
|
|
10523
|
+
const existingLegs = decodeAllLegs(baseTokenId);
|
|
10524
|
+
const maxSafe = MAX_TICK - tickSpacing - 1n;
|
|
10525
|
+
let signedStrike = computeTinyCreditSignedStrike(positionSize, tickSpacing);
|
|
10526
|
+
while (signedStrike <= maxSafe) {
|
|
10527
|
+
const candidate = asset === 0n ? signedStrike : -signedStrike;
|
|
10528
|
+
let collides = false;
|
|
10529
|
+
for (const leg of existingLegs) if (leg.width === 0n && leg.isLong && leg.asset === asset && leg.tokenType === tokenType && leg.strike === candidate) {
|
|
10530
|
+
collides = true;
|
|
10531
|
+
break;
|
|
10532
|
+
}
|
|
10533
|
+
if (!collides) break;
|
|
10534
|
+
signedStrike += 1n;
|
|
10535
|
+
}
|
|
10536
|
+
if (signedStrike > maxSafe) throw new PanopticError("deriveUniqueTokenId: exhausted strike space picking a unique tiny credit leg");
|
|
10537
|
+
const encodedStrike = asset === 0n ? signedStrike : -signedStrike;
|
|
10538
|
+
return {
|
|
10539
|
+
index: legIndex,
|
|
10540
|
+
asset,
|
|
10541
|
+
tokenType,
|
|
10542
|
+
optionRatio: 1n,
|
|
10543
|
+
isLong: 1n,
|
|
10544
|
+
riskPartner: legIndex,
|
|
10545
|
+
strike: encodedStrike,
|
|
10546
|
+
width: 0n
|
|
10547
|
+
};
|
|
10548
|
+
}
|
|
10549
|
+
function appendTinyCreditLeg(baseTokenId, baseLegCount, positionSize, tickSpacing) {
|
|
10550
|
+
const newLeg = pickUniqueTinyCreditLeg(baseTokenId, baseLegCount, positionSize, tickSpacing);
|
|
10551
|
+
return addLegToTokenId(baseTokenId, newLeg);
|
|
10552
|
+
}
|
|
10553
|
+
function scaleRatios(baseTokenId, targetPositionSize) {
|
|
10554
|
+
const legs = decodeAllLegs(baseTokenId);
|
|
10555
|
+
const maxRatio = legs.reduce((m, leg) => leg.optionRatio > m ? leg.optionRatio : m, 0n);
|
|
10556
|
+
const N = MAX_OPTION_RATIO / maxRatio;
|
|
10557
|
+
if (N < 2n) throw new PanopticError("deriveUniqueTokenId: cannot derive a unique tokenId — all 4 leg slots used and optionRatios already near the 127 ceiling");
|
|
10558
|
+
const newPositionSize = (targetPositionSize + N - 1n) / N;
|
|
10559
|
+
const poolId = baseTokenId & POOL_ID_MASK$2;
|
|
10560
|
+
let out = poolId;
|
|
10561
|
+
for (const leg of legs) out = addLegToTokenId(out, {
|
|
10562
|
+
index: leg.index,
|
|
10563
|
+
asset: leg.asset,
|
|
10564
|
+
tokenType: leg.tokenType,
|
|
10565
|
+
optionRatio: leg.optionRatio * N,
|
|
10566
|
+
isLong: leg.isLong ? 1n : 0n,
|
|
10567
|
+
riskPartner: leg.riskPartner,
|
|
10568
|
+
strike: leg.strike,
|
|
10569
|
+
width: leg.width
|
|
10583
10570
|
});
|
|
10571
|
+
return {
|
|
10572
|
+
newTokenId: out,
|
|
10573
|
+
newPositionSize,
|
|
10574
|
+
effectivePositionSize: newPositionSize * N,
|
|
10575
|
+
strategy: "ratio-scale"
|
|
10576
|
+
};
|
|
10584
10577
|
}
|
|
10585
10578
|
/**
|
|
10586
|
-
*
|
|
10579
|
+
* Derive a tokenId unique from `baseTokenId` for a partial reduction.
|
|
10580
|
+
*
|
|
10581
|
+
* Prefers a tiny-credit-leg extension (arbitrary new size). Falls back to
|
|
10582
|
+
* optionRatio scaling only when the base tokenId already occupies all 4 leg
|
|
10583
|
+
* slots.
|
|
10587
10584
|
*/
|
|
10588
|
-
|
|
10589
|
-
const {
|
|
10590
|
-
|
|
10591
|
-
|
|
10592
|
-
|
|
10593
|
-
|
|
10594
|
-
|
|
10595
|
-
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
|
|
10600
|
-
|
|
10601
|
-
}
|
|
10585
|
+
function deriveUniqueTokenId(params) {
|
|
10586
|
+
const { baseTokenId, targetPositionSize, tickSpacing = DEFAULT_TICK_SPACING } = params;
|
|
10587
|
+
if (targetPositionSize <= 0n) throw new PanopticError("deriveUniqueTokenId: targetPositionSize must be > 0");
|
|
10588
|
+
const legCount = countLegs(baseTokenId);
|
|
10589
|
+
if (legCount === 0n) throw new PanopticError("deriveUniqueTokenId: baseTokenId has no legs");
|
|
10590
|
+
if (legCount < MAX_LEGS) {
|
|
10591
|
+
const newTokenId = appendTinyCreditLeg(baseTokenId, legCount, targetPositionSize, tickSpacing);
|
|
10592
|
+
return {
|
|
10593
|
+
newTokenId,
|
|
10594
|
+
newPositionSize: targetPositionSize,
|
|
10595
|
+
effectivePositionSize: targetPositionSize,
|
|
10596
|
+
strategy: "tiny-credit"
|
|
10597
|
+
};
|
|
10598
|
+
}
|
|
10599
|
+
return scaleRatios(baseTokenId, targetPositionSize);
|
|
10602
10600
|
}
|
|
10603
10601
|
/**
|
|
10604
|
-
*
|
|
10602
|
+
* Re-export decoded leg count so callers can gate UI on the strategy that
|
|
10603
|
+
* would be chosen (e.g. show a divisibility hint on ratio-scale positions).
|
|
10605
10604
|
*/
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
if (params.version === "v3") return client.readContract({
|
|
10609
|
-
address: factoryAddress,
|
|
10610
|
-
abi: panopticFactoryV3Abi,
|
|
10611
|
-
functionName: "getPanopticPool",
|
|
10612
|
-
args: [params.univ3pool, riskEngine]
|
|
10613
|
-
});
|
|
10614
|
-
return client.readContract({
|
|
10615
|
-
address: factoryAddress,
|
|
10616
|
-
abi: panopticFactoryV4Abi,
|
|
10617
|
-
functionName: "getPanopticPool",
|
|
10618
|
-
args: [{
|
|
10619
|
-
currency0: params.poolKey.currency0,
|
|
10620
|
-
currency1: params.poolKey.currency1,
|
|
10621
|
-
fee: Number(params.poolKey.fee),
|
|
10622
|
-
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
10623
|
-
hooks: params.poolKey.hooks
|
|
10624
|
-
}, riskEngine]
|
|
10625
|
-
});
|
|
10605
|
+
function planDeriveStrategy(baseTokenId) {
|
|
10606
|
+
return countLegs(baseTokenId) < MAX_LEGS ? "tiny-credit" : "ratio-scale";
|
|
10626
10607
|
}
|
|
10608
|
+
|
|
10609
|
+
//#endregion
|
|
10610
|
+
//#region src/panoptic/v2/sfpmSwap/calldata.ts
|
|
10627
10611
|
/**
|
|
10628
|
-
*
|
|
10612
|
+
* Encode the `multicall([mint, burn])` for a swap plan.
|
|
10613
|
+
*
|
|
10614
|
+
* The order is always `[mint, burn]` — the ERC1155 must be minted before it is
|
|
10615
|
+
* burned. Which call carries the inverted (swap) limits is decided in the plan.
|
|
10629
10616
|
*/
|
|
10630
|
-
|
|
10631
|
-
const
|
|
10632
|
-
|
|
10633
|
-
|
|
10634
|
-
address: factoryAddress,
|
|
10635
|
-
abi: panopticFactoryV3Abi,
|
|
10636
|
-
functionName: "minePoolAddress",
|
|
10617
|
+
function buildSfpmSwapCalldata(plan) {
|
|
10618
|
+
const mintData = encodeFunctionData({
|
|
10619
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10620
|
+
functionName: "mintTokenizedPosition",
|
|
10637
10621
|
args: [
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
10641
|
-
|
|
10642
|
-
|
|
10643
|
-
minTargetRarity
|
|
10622
|
+
plan.poolKey,
|
|
10623
|
+
plan.tokenId,
|
|
10624
|
+
plan.positionSize,
|
|
10625
|
+
plan.mintTickLimits[0],
|
|
10626
|
+
plan.mintTickLimits[1]
|
|
10644
10627
|
]
|
|
10645
10628
|
});
|
|
10646
|
-
|
|
10647
|
-
|
|
10648
|
-
|
|
10649
|
-
functionName: "minePoolAddress",
|
|
10629
|
+
const burnData = encodeFunctionData({
|
|
10630
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10631
|
+
functionName: "burnTokenizedPosition",
|
|
10650
10632
|
args: [
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10656
|
-
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
10657
|
-
hooks: params.poolKey.hooks
|
|
10658
|
-
},
|
|
10659
|
-
riskEngine,
|
|
10660
|
-
salt,
|
|
10661
|
-
loops,
|
|
10662
|
-
minTargetRarity
|
|
10633
|
+
plan.poolKey,
|
|
10634
|
+
plan.tokenId,
|
|
10635
|
+
plan.positionSize,
|
|
10636
|
+
plan.burnTickLimits[0],
|
|
10637
|
+
plan.burnTickLimits[1]
|
|
10663
10638
|
]
|
|
10664
10639
|
});
|
|
10640
|
+
const multicallData = encodeFunctionData({
|
|
10641
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10642
|
+
functionName: "multicall",
|
|
10643
|
+
args: [[mintData, burnData]]
|
|
10644
|
+
});
|
|
10665
10645
|
return {
|
|
10666
|
-
|
|
10667
|
-
|
|
10646
|
+
multicallData,
|
|
10647
|
+
mintData,
|
|
10648
|
+
burnData
|
|
10668
10649
|
};
|
|
10669
10650
|
}
|
|
10651
|
+
|
|
10652
|
+
//#endregion
|
|
10653
|
+
//#region src/panoptic/v2/sfpmSwap/init.ts
|
|
10670
10654
|
/**
|
|
10671
|
-
*
|
|
10655
|
+
* Resolve the `uint64` SFPM poolId for a Uniswap v3 pool, initializing it if needed.
|
|
10672
10656
|
*
|
|
10673
|
-
*
|
|
10674
|
-
*
|
|
10657
|
+
* `initializeAMMPool` is permissionless and idempotent and **returns the poolId**
|
|
10658
|
+
* whether or not the pool was already registered, so a `simulateContract` call is
|
|
10659
|
+
* enough to learn the id without sending a transaction. Always resolve the id this
|
|
10660
|
+
* way rather than encoding it offline — the SFPM can collision-increment ids.
|
|
10675
10661
|
*/
|
|
10676
|
-
async function
|
|
10677
|
-
const { client,
|
|
10678
|
-
|
|
10679
|
-
const { result: result$1 } = await client.simulateContract({
|
|
10680
|
-
address: factoryAddress,
|
|
10681
|
-
abi: panopticFactoryV3Abi,
|
|
10682
|
-
functionName: "deployNewPool",
|
|
10683
|
-
args: [
|
|
10684
|
-
params.token0,
|
|
10685
|
-
params.token1,
|
|
10686
|
-
Number(params.fee),
|
|
10687
|
-
riskEngine,
|
|
10688
|
-
salt
|
|
10689
|
-
],
|
|
10690
|
-
account
|
|
10691
|
-
});
|
|
10692
|
-
return result$1;
|
|
10693
|
-
}
|
|
10662
|
+
async function fetchSfpmV3PoolId(params) {
|
|
10663
|
+
const { client, sfpmAddress, token0, token1, fee } = params;
|
|
10664
|
+
const vegoid$1 = params.vegoid ?? Number(DEFAULT_VEGOID);
|
|
10694
10665
|
const { result } = await client.simulateContract({
|
|
10695
|
-
address:
|
|
10696
|
-
abi:
|
|
10697
|
-
functionName: "
|
|
10666
|
+
address: sfpmAddress,
|
|
10667
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10668
|
+
functionName: "initializeAMMPool",
|
|
10698
10669
|
args: [
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
hooks: params.poolKey.hooks
|
|
10705
|
-
},
|
|
10706
|
-
riskEngine,
|
|
10707
|
-
salt
|
|
10708
|
-
],
|
|
10709
|
-
account
|
|
10670
|
+
token0,
|
|
10671
|
+
token1,
|
|
10672
|
+
fee,
|
|
10673
|
+
vegoid$1
|
|
10674
|
+
]
|
|
10710
10675
|
});
|
|
10711
|
-
return result;
|
|
10676
|
+
return BigInt(result);
|
|
10712
10677
|
}
|
|
10713
10678
|
/**
|
|
10714
|
-
*
|
|
10679
|
+
* Ensure a Uniswap v3 pool is registered on the SFPM, sending `initializeAMMPool`
|
|
10680
|
+
* only if it is not already registered. Returns the resolved poolId.
|
|
10715
10681
|
*
|
|
10716
|
-
*
|
|
10717
|
-
*
|
|
10718
|
-
* 2. Factory: Uniswap pool + riskEngine → PanopticPool address
|
|
10682
|
+
* When `expectedPool` is given, the resolved id is checked to map back to it via
|
|
10683
|
+
* `getUniswapV3PoolFromId` — guards against a wrong token/fee triple.
|
|
10719
10684
|
*/
|
|
10720
|
-
async function
|
|
10721
|
-
const { client, sfpmAddress,
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
client,
|
|
10725
|
-
sfpmAddress,
|
|
10726
|
-
poolId
|
|
10727
|
-
});
|
|
10728
|
-
return getPanopticPoolAddress({
|
|
10729
|
-
version: "v3",
|
|
10730
|
-
client,
|
|
10731
|
-
factoryAddress,
|
|
10732
|
-
univ3pool,
|
|
10733
|
-
riskEngine
|
|
10734
|
-
});
|
|
10735
|
-
}
|
|
10736
|
-
const poolKey = await getUniswapV4PoolKeyFromId({
|
|
10685
|
+
async function ensureSfpmV3PoolInitialized(params) {
|
|
10686
|
+
const { client, wallet, sfpmAddress, token0, token1, fee, expectedPool } = params;
|
|
10687
|
+
const vegoid$1 = params.vegoid ?? Number(DEFAULT_VEGOID);
|
|
10688
|
+
const poolId = await fetchSfpmV3PoolId({
|
|
10737
10689
|
client,
|
|
10738
10690
|
sfpmAddress,
|
|
10739
|
-
|
|
10691
|
+
token0,
|
|
10692
|
+
token1,
|
|
10693
|
+
fee,
|
|
10694
|
+
vegoid: vegoid$1
|
|
10740
10695
|
});
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
riskEngine
|
|
10696
|
+
const registered = await client.readContract({
|
|
10697
|
+
address: sfpmAddress,
|
|
10698
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10699
|
+
functionName: "getUniswapV3PoolFromId",
|
|
10700
|
+
args: [poolId]
|
|
10747
10701
|
});
|
|
10702
|
+
let initialized = false;
|
|
10703
|
+
let resolved = registered;
|
|
10704
|
+
if (getAddress(registered) === zeroAddress) {
|
|
10705
|
+
const account = wallet.account;
|
|
10706
|
+
if (account === void 0) throw new PanopticError("wallet client has no account");
|
|
10707
|
+
const hash = await wallet.writeContract({
|
|
10708
|
+
account,
|
|
10709
|
+
chain: wallet.chain ?? null,
|
|
10710
|
+
address: sfpmAddress,
|
|
10711
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10712
|
+
functionName: "initializeAMMPool",
|
|
10713
|
+
args: [
|
|
10714
|
+
token0,
|
|
10715
|
+
token1,
|
|
10716
|
+
fee,
|
|
10717
|
+
vegoid$1
|
|
10718
|
+
]
|
|
10719
|
+
});
|
|
10720
|
+
await client.waitForTransactionReceipt({ hash });
|
|
10721
|
+
initialized = true;
|
|
10722
|
+
resolved = await client.readContract({
|
|
10723
|
+
address: sfpmAddress,
|
|
10724
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10725
|
+
functionName: "getUniswapV3PoolFromId",
|
|
10726
|
+
args: [poolId]
|
|
10727
|
+
});
|
|
10728
|
+
}
|
|
10729
|
+
if (expectedPool !== void 0 && getAddress(resolved) !== getAddress(expectedPool)) throw new WrongUniswapPoolError(new PanopticError(`SFPM poolId ${poolId} resolves to ${resolved}, expected ${expectedPool}`));
|
|
10730
|
+
return {
|
|
10731
|
+
poolId,
|
|
10732
|
+
initialized
|
|
10733
|
+
};
|
|
10748
10734
|
}
|
|
10735
|
+
|
|
10736
|
+
//#endregion
|
|
10737
|
+
//#region src/panoptic/v2/sfpmSwap/plan.ts
|
|
10738
|
+
/** Wide, non-inverted band for the paired (non-swapping) call — never triggers a swap. */
|
|
10739
|
+
const WIDE_LIMITS = [Number(MIN_TICK) + 1, Number(MAX_TICK) - 1];
|
|
10749
10740
|
/**
|
|
10750
|
-
*
|
|
10741
|
+
* Convert a slippage tolerance in bps to a conservative Uniswap tick distance.
|
|
10751
10742
|
*
|
|
10752
|
-
*
|
|
10753
|
-
*
|
|
10743
|
+
* Ticks are 1.0001^tick, so each tick ≈ 1 bps. This walks up powers of 1.0001
|
|
10744
|
+
* until the cumulative price move covers `slippageBps`, matching the hedger-bot's
|
|
10745
|
+
* dispatch-path helper so both swap paths agree on band width.
|
|
10746
|
+
*/
|
|
10747
|
+
function slippageBpsToTickDistance(slippageBps) {
|
|
10748
|
+
if (slippageBps < 0n || slippageBps > 1000n) throw new PanopticError(`slippage bps ${slippageBps} out of bounds (0..1000)`);
|
|
10749
|
+
if (slippageBps === 0n) return 0n;
|
|
10750
|
+
let numerator = 1n;
|
|
10751
|
+
let denominator = 1n;
|
|
10752
|
+
let ticks = 0n;
|
|
10753
|
+
while (numerator * 10000n < denominator * (10000n + slippageBps)) {
|
|
10754
|
+
numerator *= 10001n;
|
|
10755
|
+
denominator *= 10000n;
|
|
10756
|
+
ticks += 1n;
|
|
10757
|
+
}
|
|
10758
|
+
return ticks;
|
|
10759
|
+
}
|
|
10760
|
+
/**
|
|
10761
|
+
* Build the swap plan.
|
|
10754
10762
|
*
|
|
10755
|
-
*
|
|
10763
|
+
* Mechanism (verified in the Phase 0 fork test):
|
|
10764
|
+
* - A single-leg **loan** tokenId (width=0, isLong=false, `asset == tokenType`) moves
|
|
10765
|
+
* exactly `positionSize` of the `tokenType` token when its call carries inverted
|
|
10766
|
+
* tick limits (`low > high`); the paired call uses a wide band and moves nothing.
|
|
10767
|
+
* - `exactIn`: swap on the **mint**; `tokenType` = the **input** token index.
|
|
10768
|
+
* - `exactOut`: swap on the **burn** (isLong flips → exact-output); `tokenType` = the
|
|
10769
|
+
* **output** token index.
|
|
10756
10770
|
*
|
|
10757
|
-
*
|
|
10771
|
+
* The inverted band is centered on `currentTick` at ±`slippageBpsToTickDistance`,
|
|
10772
|
+
* which the SFPM re-sorts and enforces as an open interval on the post-swap tick.
|
|
10758
10773
|
*/
|
|
10759
|
-
|
|
10760
|
-
const {
|
|
10761
|
-
if (
|
|
10762
|
-
const
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
}).catch((err) => {
|
|
10787
|
-
if (isNotFoundError(err)) return zeroAddress;
|
|
10788
|
-
throw err;
|
|
10789
|
-
}) : Promise.resolve(zeroAddress)]);
|
|
10790
|
-
const [v3Result, v4Result] = results;
|
|
10791
|
-
if (v3Result !== zeroAddress) return {
|
|
10792
|
-
panopticPoolAddress: v3Result,
|
|
10793
|
-
version: "v3"
|
|
10794
|
-
};
|
|
10795
|
-
if (v4Result !== zeroAddress) return {
|
|
10796
|
-
panopticPoolAddress: v4Result,
|
|
10797
|
-
version: "v4"
|
|
10774
|
+
function buildSfpmSwapPlan(params) {
|
|
10775
|
+
const { sfpmAddress, poolAddress, poolId, kind, zeroForOne, amount, currentTick, slippageBps } = params;
|
|
10776
|
+
if (amount <= 0n) throw new PanopticError(`swap amount must be positive (got ${amount})`);
|
|
10777
|
+
const distance = slippageBpsToTickDistance(slippageBps);
|
|
10778
|
+
if (distance < 1n) throw new PanopticError(`slippageBps ${slippageBps} yields a zero-width tick band; use a larger tolerance`);
|
|
10779
|
+
const tokenType = kind === "exactIn" ? zeroForOne ? 0n : 1n : zeroForOne ? 1n : 0n;
|
|
10780
|
+
const tokenId = createTokenIdBuilder(poolId).addLoan({
|
|
10781
|
+
asset: tokenType,
|
|
10782
|
+
tokenType,
|
|
10783
|
+
strike: 0n
|
|
10784
|
+
}).build();
|
|
10785
|
+
const d = Number(distance);
|
|
10786
|
+
const low = Math.min(Number(MAX_TICK), currentTick + d);
|
|
10787
|
+
const high = Math.max(Number(MIN_TICK), currentTick - d);
|
|
10788
|
+
if (low <= high) throw new PanopticError(`slippageBps ${slippageBps} at tick ${currentTick} yields a non-inverted band after clamping`);
|
|
10789
|
+
const invertedLimits = [low, high];
|
|
10790
|
+
const swapOn = kind === "exactIn" ? "mint" : "burn";
|
|
10791
|
+
return {
|
|
10792
|
+
sfpmAddress,
|
|
10793
|
+
poolAddress,
|
|
10794
|
+
poolKey: encodeAbiParameters([{ type: "address" }], [poolAddress]),
|
|
10795
|
+
tokenId,
|
|
10796
|
+
positionSize: amount,
|
|
10797
|
+
mintTickLimits: swapOn === "mint" ? invertedLimits : WIDE_LIMITS,
|
|
10798
|
+
burnTickLimits: swapOn === "burn" ? invertedLimits : WIDE_LIMITS,
|
|
10799
|
+
swapOn,
|
|
10800
|
+
kind
|
|
10798
10801
|
};
|
|
10799
|
-
throw new Error(`No PanopticPool found for poolId ${poolId}`);
|
|
10800
10802
|
}
|
|
10801
10803
|
|
|
10802
10804
|
//#endregion
|
|
10803
|
-
//#region src/panoptic/v2/
|
|
10804
|
-
const
|
|
10805
|
-
const
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
outputs: [
|
|
10823
|
-
{
|
|
10824
|
-
internalType: "uint160",
|
|
10825
|
-
name: "sqrtPriceX96",
|
|
10826
|
-
type: "uint160"
|
|
10827
|
-
},
|
|
10828
|
-
{
|
|
10829
|
-
internalType: "int24",
|
|
10830
|
-
name: "tick",
|
|
10831
|
-
type: "int24"
|
|
10832
|
-
},
|
|
10833
|
-
{
|
|
10834
|
-
internalType: "uint24",
|
|
10835
|
-
name: "protocolFee",
|
|
10836
|
-
type: "uint24"
|
|
10837
|
-
},
|
|
10838
|
-
{
|
|
10839
|
-
internalType: "uint24",
|
|
10840
|
-
name: "lpFee",
|
|
10841
|
-
type: "uint24"
|
|
10842
|
-
}
|
|
10843
|
-
],
|
|
10844
|
-
stateMutability: "view",
|
|
10845
|
-
type: "function"
|
|
10846
|
-
},
|
|
10847
|
-
{
|
|
10848
|
-
inputs: [{
|
|
10849
|
-
internalType: "PoolId",
|
|
10850
|
-
name: "poolId",
|
|
10851
|
-
type: "bytes32"
|
|
10852
|
-
}],
|
|
10853
|
-
name: "getFeeGrowthGlobals",
|
|
10854
|
-
outputs: [{
|
|
10855
|
-
internalType: "uint256",
|
|
10856
|
-
name: "feeGrowthGlobal0",
|
|
10857
|
-
type: "uint256"
|
|
10858
|
-
}, {
|
|
10859
|
-
internalType: "uint256",
|
|
10860
|
-
name: "feeGrowthGlobal1",
|
|
10861
|
-
type: "uint256"
|
|
10862
|
-
}],
|
|
10863
|
-
stateMutability: "view",
|
|
10864
|
-
type: "function"
|
|
10865
|
-
},
|
|
10866
|
-
{
|
|
10867
|
-
inputs: [{
|
|
10868
|
-
internalType: "PoolId",
|
|
10869
|
-
name: "poolId",
|
|
10870
|
-
type: "bytes32"
|
|
10871
|
-
}, {
|
|
10872
|
-
internalType: "int24",
|
|
10873
|
-
name: "tick",
|
|
10874
|
-
type: "int24"
|
|
10875
|
-
}],
|
|
10876
|
-
name: "getTickInfo",
|
|
10877
|
-
outputs: [
|
|
10878
|
-
{
|
|
10879
|
-
internalType: "uint128",
|
|
10880
|
-
name: "liquidityGross",
|
|
10881
|
-
type: "uint128"
|
|
10882
|
-
},
|
|
10883
|
-
{
|
|
10884
|
-
internalType: "int128",
|
|
10885
|
-
name: "liquidityNet",
|
|
10886
|
-
type: "int128"
|
|
10887
|
-
},
|
|
10888
|
-
{
|
|
10889
|
-
internalType: "uint256",
|
|
10890
|
-
name: "feeGrowthOutside0X128",
|
|
10891
|
-
type: "uint256"
|
|
10892
|
-
},
|
|
10893
|
-
{
|
|
10894
|
-
internalType: "uint256",
|
|
10895
|
-
name: "feeGrowthOutside1X128",
|
|
10896
|
-
type: "uint256"
|
|
10897
|
-
}
|
|
10898
|
-
],
|
|
10899
|
-
stateMutability: "view",
|
|
10900
|
-
type: "function"
|
|
10901
|
-
},
|
|
10902
|
-
{
|
|
10903
|
-
inputs: [{
|
|
10904
|
-
internalType: "PoolId",
|
|
10905
|
-
name: "poolId",
|
|
10906
|
-
type: "bytes32"
|
|
10907
|
-
}],
|
|
10908
|
-
name: "getLiquidity",
|
|
10909
|
-
outputs: [{
|
|
10910
|
-
internalType: "uint128",
|
|
10911
|
-
name: "liquidity",
|
|
10912
|
-
type: "uint128"
|
|
10913
|
-
}],
|
|
10914
|
-
stateMutability: "view",
|
|
10915
|
-
type: "function"
|
|
10916
|
-
}
|
|
10917
|
-
];
|
|
10918
|
-
|
|
10919
|
-
//#endregion
|
|
10920
|
-
//#region src/panoptic/v2/abis/uniswapV3Pool.ts
|
|
10805
|
+
//#region src/panoptic/v2/sfpmSwap/quote.ts
|
|
10806
|
+
const UINT128 = 1n << 128n;
|
|
10807
|
+
const INT128_MAX = (1n << 127n) - 1n;
|
|
10808
|
+
/** Extract the two signed 128-bit slots from a packed `LeftRightSigned` int256. */
|
|
10809
|
+
function unpackLeftRightSigned(packed) {
|
|
10810
|
+
const u = packed < 0n ? packed + (1n << 256n) : packed;
|
|
10811
|
+
const toInt128 = (half) => half > INT128_MAX ? half - UINT128 : half;
|
|
10812
|
+
return {
|
|
10813
|
+
right: toInt128(u & UINT128 - 1n),
|
|
10814
|
+
left: toInt128(u >> 128n & UINT128 - 1n)
|
|
10815
|
+
};
|
|
10816
|
+
}
|
|
10817
|
+
/** Wrap an unknown thrown value as a PanopticError, decoding Panoptic reverts when possible. */
|
|
10818
|
+
function toPanopticError(err) {
|
|
10819
|
+
if (err instanceof PanopticError) return err;
|
|
10820
|
+
const parsed = parsePanopticError(err);
|
|
10821
|
+
if (parsed) return parsed.error;
|
|
10822
|
+
return new PanopticError(err instanceof Error ? err.message : "SFPM swap simulation failed", err instanceof Error ? err : void 0);
|
|
10823
|
+
}
|
|
10921
10824
|
/**
|
|
10922
|
-
*
|
|
10923
|
-
*
|
|
10825
|
+
* Quote a swap by simulating `SFPM.multicall([mint, burn])` and decoding the swap
|
|
10826
|
+
* call's `totalMoved` return. Authoritative — captures the width-0 loan-leg wei
|
|
10827
|
+
* rounding a raw QuoterV2 quote would miss.
|
|
10924
10828
|
*/
|
|
10925
|
-
|
|
10926
|
-
{
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10936
|
-
|
|
10937
|
-
|
|
10938
|
-
|
|
10939
|
-
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
10946
|
-
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
10950
|
-
|
|
10951
|
-
|
|
10952
|
-
|
|
10953
|
-
|
|
10954
|
-
},
|
|
10955
|
-
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
type: "bool"
|
|
10964
|
-
}
|
|
10965
|
-
],
|
|
10966
|
-
stateMutability: "view",
|
|
10967
|
-
type: "function"
|
|
10968
|
-
},
|
|
10969
|
-
{
|
|
10970
|
-
inputs: [],
|
|
10971
|
-
name: "feeGrowthGlobal0X128",
|
|
10972
|
-
outputs: [{
|
|
10973
|
-
internalType: "uint256",
|
|
10974
|
-
name: "",
|
|
10975
|
-
type: "uint256"
|
|
10976
|
-
}],
|
|
10977
|
-
stateMutability: "view",
|
|
10978
|
-
type: "function"
|
|
10979
|
-
},
|
|
10980
|
-
{
|
|
10981
|
-
inputs: [],
|
|
10982
|
-
name: "feeGrowthGlobal1X128",
|
|
10983
|
-
outputs: [{
|
|
10984
|
-
internalType: "uint256",
|
|
10985
|
-
name: "",
|
|
10986
|
-
type: "uint256"
|
|
10987
|
-
}],
|
|
10988
|
-
stateMutability: "view",
|
|
10989
|
-
type: "function"
|
|
10990
|
-
},
|
|
10991
|
-
{
|
|
10992
|
-
inputs: [{
|
|
10993
|
-
internalType: "int24",
|
|
10994
|
-
name: "",
|
|
10995
|
-
type: "int24"
|
|
10996
|
-
}],
|
|
10997
|
-
name: "ticks",
|
|
10998
|
-
outputs: [
|
|
10999
|
-
{
|
|
11000
|
-
internalType: "uint128",
|
|
11001
|
-
name: "liquidityGross",
|
|
11002
|
-
type: "uint128"
|
|
10829
|
+
async function quoteSfpmSwap(params) {
|
|
10830
|
+
const { client, plan, account, stateOverride, blockNumber } = params;
|
|
10831
|
+
const { mintData, burnData } = buildSfpmSwapCalldata(plan);
|
|
10832
|
+
const _meta = await getBlockMeta({
|
|
10833
|
+
client,
|
|
10834
|
+
blockNumber
|
|
10835
|
+
});
|
|
10836
|
+
try {
|
|
10837
|
+
const { result } = await client.simulateContract({
|
|
10838
|
+
account,
|
|
10839
|
+
address: plan.sfpmAddress,
|
|
10840
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10841
|
+
functionName: "multicall",
|
|
10842
|
+
args: [[mintData, burnData]],
|
|
10843
|
+
blockNumber,
|
|
10844
|
+
stateOverride
|
|
10845
|
+
});
|
|
10846
|
+
const swapIndex = plan.swapOn === "mint" ? 0 : 1;
|
|
10847
|
+
const decoded = decodeFunctionResult({
|
|
10848
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10849
|
+
functionName: plan.swapOn === "mint" ? "mintTokenizedPosition" : "burnTokenizedPosition",
|
|
10850
|
+
data: result[swapIndex]
|
|
10851
|
+
});
|
|
10852
|
+
const finalTick = Number(decoded[2]);
|
|
10853
|
+
const { right, left } = unpackLeftRightSigned(decoded[1]);
|
|
10854
|
+
const inSlot = [right, left].find((s) => s > 0n);
|
|
10855
|
+
const outSlot = [right, left].find((s) => s < 0n);
|
|
10856
|
+
if (inSlot === void 0 || outSlot === void 0) return {
|
|
10857
|
+
success: false,
|
|
10858
|
+
error: new PanopticError(`SFPM swap simulation moved no tokens (totalMoved=${decoded[1]})`),
|
|
10859
|
+
_meta
|
|
10860
|
+
};
|
|
10861
|
+
return {
|
|
10862
|
+
success: true,
|
|
10863
|
+
data: {
|
|
10864
|
+
amountIn: inSlot,
|
|
10865
|
+
amountOut: -outSlot,
|
|
10866
|
+
finalTick
|
|
11003
10867
|
},
|
|
10868
|
+
gasEstimate: 0n,
|
|
10869
|
+
_meta
|
|
10870
|
+
};
|
|
10871
|
+
} catch (err) {
|
|
10872
|
+
return {
|
|
10873
|
+
success: false,
|
|
10874
|
+
error: toPanopticError(err),
|
|
10875
|
+
_meta
|
|
10876
|
+
};
|
|
10877
|
+
}
|
|
10878
|
+
}
|
|
10879
|
+
|
|
10880
|
+
//#endregion
|
|
10881
|
+
//#region src/uniswap/v4/router/errors.ts
|
|
10882
|
+
/**
|
|
10883
|
+
* The chain has no configured Uniswap v4 addresses and none were supplied via
|
|
10884
|
+
* overrides.
|
|
10885
|
+
*/
|
|
10886
|
+
var UnsupportedChainError = class extends PanopticError {
|
|
10887
|
+
name = "UnsupportedChainError";
|
|
10888
|
+
constructor(chainId, cause) {
|
|
10889
|
+
super(`Uniswap v4 router not configured for chain ${chainId}`, cause);
|
|
10890
|
+
this.chainId = chainId;
|
|
10891
|
+
}
|
|
10892
|
+
};
|
|
10893
|
+
|
|
10894
|
+
//#endregion
|
|
10895
|
+
//#region src/uniswap/v3/router/encodeSwap.ts
|
|
10896
|
+
const UINT128_MAX$1 = (1n << 128n) - 1n;
|
|
10897
|
+
|
|
10898
|
+
//#endregion
|
|
10899
|
+
//#region src/uniswap/v3/abis/quoterV2.ts
|
|
10900
|
+
/**
|
|
10901
|
+
* Minimal Uniswap v3 QuoterV2 ABI (`quoteExactInputSingle`).
|
|
10902
|
+
*
|
|
10903
|
+
* QuoterV2 is revert/staticcall-based (nonpayable but intended for `eth_call` /
|
|
10904
|
+
* `simulateContract`), so it must be simulated, not read.
|
|
10905
|
+
* @module uniswap/v3/abis/quoterV2
|
|
10906
|
+
*/
|
|
10907
|
+
const quoterV2Abi = [{
|
|
10908
|
+
type: "function",
|
|
10909
|
+
name: "quoteExactInputSingle",
|
|
10910
|
+
stateMutability: "nonpayable",
|
|
10911
|
+
inputs: [{
|
|
10912
|
+
name: "params",
|
|
10913
|
+
type: "tuple",
|
|
10914
|
+
components: [
|
|
11004
10915
|
{
|
|
11005
|
-
|
|
11006
|
-
|
|
11007
|
-
type: "int128"
|
|
10916
|
+
name: "tokenIn",
|
|
10917
|
+
type: "address"
|
|
11008
10918
|
},
|
|
11009
10919
|
{
|
|
11010
|
-
|
|
11011
|
-
|
|
11012
|
-
type: "uint256"
|
|
10920
|
+
name: "tokenOut",
|
|
10921
|
+
type: "address"
|
|
11013
10922
|
},
|
|
11014
10923
|
{
|
|
11015
|
-
|
|
11016
|
-
name: "feeGrowthOutside1X128",
|
|
10924
|
+
name: "amountIn",
|
|
11017
10925
|
type: "uint256"
|
|
11018
10926
|
},
|
|
11019
10927
|
{
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
type: "int56"
|
|
10928
|
+
name: "fee",
|
|
10929
|
+
type: "uint24"
|
|
11023
10930
|
},
|
|
11024
10931
|
{
|
|
11025
|
-
|
|
11026
|
-
name: "secondsPerLiquidityOutsideX128",
|
|
10932
|
+
name: "sqrtPriceLimitX96",
|
|
11027
10933
|
type: "uint160"
|
|
11028
|
-
},
|
|
11029
|
-
{
|
|
11030
|
-
internalType: "uint32",
|
|
11031
|
-
name: "secondsOutside",
|
|
11032
|
-
type: "uint32"
|
|
11033
|
-
},
|
|
11034
|
-
{
|
|
11035
|
-
internalType: "bool",
|
|
11036
|
-
name: "initialized",
|
|
11037
|
-
type: "bool"
|
|
11038
10934
|
}
|
|
11039
|
-
]
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
type: "uint24"
|
|
11061
|
-
}],
|
|
11062
|
-
stateMutability: "view",
|
|
11063
|
-
type: "function"
|
|
11064
|
-
},
|
|
11065
|
-
{
|
|
11066
|
-
inputs: [],
|
|
11067
|
-
name: "token0",
|
|
11068
|
-
outputs: [{
|
|
11069
|
-
internalType: "address",
|
|
11070
|
-
name: "",
|
|
11071
|
-
type: "address"
|
|
11072
|
-
}],
|
|
11073
|
-
stateMutability: "view",
|
|
11074
|
-
type: "function"
|
|
11075
|
-
},
|
|
11076
|
-
{
|
|
11077
|
-
inputs: [],
|
|
11078
|
-
name: "token1",
|
|
11079
|
-
outputs: [{
|
|
11080
|
-
internalType: "address",
|
|
11081
|
-
name: "",
|
|
11082
|
-
type: "address"
|
|
11083
|
-
}],
|
|
11084
|
-
stateMutability: "view",
|
|
11085
|
-
type: "function"
|
|
11086
|
-
},
|
|
11087
|
-
{
|
|
11088
|
-
inputs: [],
|
|
11089
|
-
name: "tickSpacing",
|
|
11090
|
-
outputs: [{
|
|
11091
|
-
internalType: "int24",
|
|
11092
|
-
name: "",
|
|
11093
|
-
type: "int24"
|
|
11094
|
-
}],
|
|
11095
|
-
stateMutability: "view",
|
|
11096
|
-
type: "function"
|
|
11097
|
-
}
|
|
11098
|
-
];
|
|
10935
|
+
]
|
|
10936
|
+
}],
|
|
10937
|
+
outputs: [
|
|
10938
|
+
{
|
|
10939
|
+
name: "amountOut",
|
|
10940
|
+
type: "uint256"
|
|
10941
|
+
},
|
|
10942
|
+
{
|
|
10943
|
+
name: "sqrtPriceX96After",
|
|
10944
|
+
type: "uint160"
|
|
10945
|
+
},
|
|
10946
|
+
{
|
|
10947
|
+
name: "initializedTicksCrossed",
|
|
10948
|
+
type: "uint32"
|
|
10949
|
+
},
|
|
10950
|
+
{
|
|
10951
|
+
name: "gasEstimate",
|
|
10952
|
+
type: "uint256"
|
|
10953
|
+
}
|
|
10954
|
+
]
|
|
10955
|
+
}];
|
|
11099
10956
|
|
|
11100
10957
|
//#endregion
|
|
11101
|
-
//#region src/
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
const absNumerator = numerator < 0n ? -numerator : numerator;
|
|
11123
|
-
const scale = pow10(precision);
|
|
11124
|
-
const scaled = (absNumerator * scale + denominator / 2n) / denominator;
|
|
11125
|
-
const integerPart = scaled / scale;
|
|
11126
|
-
const fractionalPart = scaled % scale;
|
|
11127
|
-
if (precision === 0n) return `${sign}${integerPart}`;
|
|
11128
|
-
return `${sign}${integerPart}.${fractionalPart.toString().padStart(Number(precision), "0")}`;
|
|
11129
|
-
}
|
|
11130
|
-
function parseDecimalToFraction(value) {
|
|
11131
|
-
const trimmed = value.trim();
|
|
11132
|
-
if (trimmed.length === 0) throw new Error("Price must be a number");
|
|
11133
|
-
const isNegative = trimmed.startsWith("-");
|
|
11134
|
-
const unsigned = isNegative || trimmed.startsWith("+") ? trimmed.slice(1) : trimmed;
|
|
11135
|
-
const [basePart, exponentPart] = unsigned.toLowerCase().split("e");
|
|
11136
|
-
const [integerStr, fractionalStr = ""] = basePart.split(".");
|
|
11137
|
-
if (integerStr === "" && fractionalStr === "") throw new Error("Price must be a number");
|
|
11138
|
-
const integerDigits = integerStr === "" ? "0" : integerStr;
|
|
11139
|
-
const digits = `${integerDigits}${fractionalStr}`;
|
|
11140
|
-
let numerator = BigInt(digits === "" ? "0" : digits);
|
|
11141
|
-
let denominator = pow10(BigInt(fractionalStr.length));
|
|
11142
|
-
if (exponentPart !== void 0 && exponentPart !== "") {
|
|
11143
|
-
const exponent = BigInt(exponentPart);
|
|
11144
|
-
if (exponent > 0n) numerator *= pow10(exponent);
|
|
11145
|
-
else if (exponent < 0n) denominator *= pow10(-exponent);
|
|
11146
|
-
}
|
|
11147
|
-
if (isNegative) numerator = -numerator;
|
|
11148
|
-
return {
|
|
11149
|
-
numerator,
|
|
11150
|
-
denominator
|
|
10958
|
+
//#region src/uniswap/v3/addresses.ts
|
|
10959
|
+
/**
|
|
10960
|
+
* Verified Uniswap v3 QuoterV2 addresses keyed by chainId. Add a chain only
|
|
10961
|
+
* after verifying against the canonical Uniswap v3 deployment listing.
|
|
10962
|
+
*/
|
|
10963
|
+
const UNISWAP_V3_ADDRESSES = { 1: {
|
|
10964
|
+
quoterV2: "0x61fFE014bA17989E743c5F6cB21bF9697530B21e",
|
|
10965
|
+
nonfungiblePositionManager: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88"
|
|
10966
|
+
} };
|
|
10967
|
+
/**
|
|
10968
|
+
* Resolve Uniswap v3 addresses for a chain, applying optional overrides.
|
|
10969
|
+
*
|
|
10970
|
+
* @throws {UnsupportedChainError} when the chain is not listed and overrides do
|
|
10971
|
+
* not supply every required address.
|
|
10972
|
+
*/
|
|
10973
|
+
function getUniswapV3Addresses(chainId, overrides) {
|
|
10974
|
+
const id = Number(chainId);
|
|
10975
|
+
const base = UNISWAP_V3_ADDRESSES[id];
|
|
10976
|
+
const merged = {
|
|
10977
|
+
...base,
|
|
10978
|
+
...overrides
|
|
11151
10979
|
};
|
|
10980
|
+
if (!merged.quoterV2 || !merged.nonfungiblePositionManager) throw new UnsupportedChainError(BigInt(id));
|
|
10981
|
+
return merged;
|
|
11152
10982
|
}
|
|
11153
|
-
|
|
11154
|
-
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
if (
|
|
11166
|
-
if (
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
|
|
11172
|
-
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
10983
|
+
|
|
10984
|
+
//#endregion
|
|
10985
|
+
//#region src/uniswap/v3/router/quote.ts
|
|
10986
|
+
const BPS_DENOMINATOR$3 = 10000n;
|
|
10987
|
+
const UINT128_MAX = (1n << 128n) - 1n;
|
|
10988
|
+
/**
|
|
10989
|
+
* Quote an exact-in v3 swap. Returns `null` when the quote reverts (e.g. the
|
|
10990
|
+
* pool does not exist / has no liquidity) so callers can skip that pool when
|
|
10991
|
+
* ranking venues, rather than aborting the whole cycle.
|
|
10992
|
+
*/
|
|
10993
|
+
async function quoteV3ExactIn(params) {
|
|
10994
|
+
const { client, chainId, tokenIn, tokenOut, fee, amountIn, slippageBps, blockNumber } = params;
|
|
10995
|
+
if (amountIn < 0n || amountIn > UINT128_MAX) throw new PanopticError(`amountIn ${amountIn} exceeds uint128 maximum`);
|
|
10996
|
+
if (slippageBps < 0n || slippageBps > BPS_DENOMINATOR$3) throw new PanopticError(`invalid slippageBps ${slippageBps}, must be 0..10000`);
|
|
10997
|
+
const { quoterV2 } = getUniswapV3Addresses(chainId, params.addresses);
|
|
10998
|
+
try {
|
|
10999
|
+
const { result } = await client.simulateContract({
|
|
11000
|
+
address: quoterV2,
|
|
11001
|
+
abi: quoterV2Abi,
|
|
11002
|
+
functionName: "quoteExactInputSingle",
|
|
11003
|
+
blockNumber,
|
|
11004
|
+
args: [{
|
|
11005
|
+
tokenIn,
|
|
11006
|
+
tokenOut,
|
|
11007
|
+
amountIn,
|
|
11008
|
+
fee: Number(fee),
|
|
11009
|
+
sqrtPriceLimitX96: 0n
|
|
11010
|
+
}]
|
|
11011
|
+
});
|
|
11012
|
+
const [amountOut, , , gasEstimate] = result;
|
|
11013
|
+
const amountOutMinimum = amountOut * (BPS_DENOMINATOR$3 - slippageBps) / BPS_DENOMINATOR$3;
|
|
11014
|
+
return {
|
|
11015
|
+
amountOut,
|
|
11016
|
+
amountOutMinimum,
|
|
11017
|
+
gasEstimate
|
|
11018
|
+
};
|
|
11019
|
+
} catch (err) {
|
|
11020
|
+
if (isRevert(err)) return null;
|
|
11021
|
+
throw err;
|
|
11022
|
+
}
|
|
11186
11023
|
}
|
|
11187
|
-
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
return {
|
|
11191
|
-
numerator: sqrtPriceX96 * sqrtPriceX96,
|
|
11192
|
-
denominator: Q192$3
|
|
11193
|
-
};
|
|
11024
|
+
/** True only for genuine contract reverts (missing pool / no liquidity). */
|
|
11025
|
+
function isRevert(err) {
|
|
11026
|
+
return err instanceof BaseError && err.walk((e) => e instanceof ContractFunctionRevertedError) instanceof ContractFunctionRevertedError;
|
|
11194
11027
|
}
|
|
11195
|
-
|
|
11196
|
-
|
|
11028
|
+
|
|
11029
|
+
//#endregion
|
|
11030
|
+
//#region src/panoptic/v2/reads/sfpm.ts
|
|
11031
|
+
/**
|
|
11032
|
+
* Resolve an SFPM poolId to its corresponding Uniswap V3 pool address.
|
|
11033
|
+
*
|
|
11034
|
+
* Calls `SemiFungiblePositionManagerV3.getUniswapV3PoolFromId(poolId)`.
|
|
11035
|
+
*/
|
|
11036
|
+
async function getUniswapV3PoolFromId(params) {
|
|
11037
|
+
const { client, sfpmAddress, poolId } = params;
|
|
11038
|
+
return client.readContract({
|
|
11039
|
+
address: sfpmAddress,
|
|
11040
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
11041
|
+
functionName: "getUniswapV3PoolFromId",
|
|
11042
|
+
args: [poolId]
|
|
11043
|
+
});
|
|
11197
11044
|
}
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11045
|
+
/**
|
|
11046
|
+
* Resolve an SFPM poolId to its corresponding Uniswap V4 pool key.
|
|
11047
|
+
*
|
|
11048
|
+
* Calls `SemiFungiblePositionManagerV4.getUniswapV4PoolKeyFromId(poolId)`.
|
|
11049
|
+
*/
|
|
11050
|
+
async function getUniswapV4PoolKeyFromId(params) {
|
|
11051
|
+
const { client, sfpmAddress, poolId } = params;
|
|
11052
|
+
const raw = await client.readContract({
|
|
11053
|
+
address: sfpmAddress,
|
|
11054
|
+
abi: semiFungiblePositionManagerV4Abi,
|
|
11055
|
+
functionName: "getUniswapV4PoolKeyFromId",
|
|
11056
|
+
args: [poolId]
|
|
11057
|
+
});
|
|
11208
11058
|
return {
|
|
11209
|
-
|
|
11210
|
-
|
|
11059
|
+
currency0: raw.currency0,
|
|
11060
|
+
currency1: raw.currency1,
|
|
11061
|
+
fee: BigInt(raw.fee),
|
|
11062
|
+
tickSpacing: BigInt(raw.tickSpacing),
|
|
11063
|
+
hooks: raw.hooks
|
|
11211
11064
|
};
|
|
11212
11065
|
}
|
|
11213
11066
|
/**
|
|
11214
|
-
*
|
|
11215
|
-
* Uses the formula: price = 1.0001^tick
|
|
11216
|
-
*
|
|
11217
|
-
* This returns the raw price ratio, not adjusted for token decimals.
|
|
11218
|
-
* A fixed internal precision is used and trailing zeros are trimmed.
|
|
11219
|
-
*
|
|
11220
|
-
* @param tick - The tick value
|
|
11221
|
-
* @returns Price string
|
|
11067
|
+
* Get the enforced tick limits for a pool from the SFPM.
|
|
11222
11068
|
*
|
|
11223
|
-
* @
|
|
11224
|
-
*
|
|
11225
|
-
* tickToPrice(0n) // "1"
|
|
11226
|
-
* tickToPrice(1000n) // "1.105..." (approximately)
|
|
11227
|
-
* tickToPrice(-1000n) // "0.904..." (approximately)
|
|
11228
|
-
* tickToPrice(200000n) // Very large number
|
|
11229
|
-
* ```
|
|
11069
|
+
* @param params - The parameters
|
|
11070
|
+
* @returns The min and max enforced ticks
|
|
11230
11071
|
*/
|
|
11231
|
-
function
|
|
11232
|
-
const {
|
|
11233
|
-
const
|
|
11234
|
-
|
|
11072
|
+
async function getEnforcedTickLimits(params) {
|
|
11073
|
+
const { client, sfpmAddress, poolId } = params;
|
|
11074
|
+
const [minTick, maxTick] = await client.readContract({
|
|
11075
|
+
address: sfpmAddress,
|
|
11076
|
+
abi: semiFungiblePositionManagerV4Abi,
|
|
11077
|
+
functionName: "getEnforcedTickLimits",
|
|
11078
|
+
args: [poolId]
|
|
11079
|
+
});
|
|
11080
|
+
return {
|
|
11081
|
+
minEnforcedTick: minTick,
|
|
11082
|
+
maxEnforcedTick: maxTick
|
|
11083
|
+
};
|
|
11235
11084
|
}
|
|
11236
11085
|
/**
|
|
11237
|
-
*
|
|
11238
|
-
* Uses the formula: price = 1.0001^tick * 10^(decimals0-decimals1)
|
|
11239
|
-
*
|
|
11240
|
-
* This adjusts for the different decimals of the two tokens in the pair.
|
|
11241
|
-
*
|
|
11242
|
-
* @param tick - The tick value
|
|
11243
|
-
* @param decimals0 - Decimals of token0
|
|
11244
|
-
* @param decimals1 - Decimals of token1
|
|
11245
|
-
* @param precision - Number of decimal places to display
|
|
11246
|
-
* @returns Formatted price string
|
|
11247
|
-
*
|
|
11248
|
-
* @example
|
|
11249
|
-
* ```typescript
|
|
11250
|
-
* // WETH/USDC pool (18 decimals / 6 decimals)
|
|
11251
|
-
* // At tick ~200000, price is roughly $2000 per ETH
|
|
11252
|
-
* tickToPriceDecimalScaled(200000n, 18n, 6n, 2n) // "2000.00" (approximately)
|
|
11086
|
+
* Fetch liquidity breakdown for a batch of chunks via SFPM.getAccountLiquidity().
|
|
11253
11087
|
*
|
|
11254
|
-
*
|
|
11255
|
-
*
|
|
11256
|
-
* ```
|
|
11088
|
+
* Uses multicall for efficiency. Returns one result per input chunk,
|
|
11089
|
+
* along with block metadata for freshness tracking.
|
|
11257
11090
|
*/
|
|
11258
|
-
function
|
|
11259
|
-
const
|
|
11260
|
-
|
|
11261
|
-
|
|
11091
|
+
async function getChunkLiquidities(params) {
|
|
11092
|
+
const { client, sfpmAddress, poolKeyBytes, chunks } = params;
|
|
11093
|
+
if (chunks.length > MAX_TRACKED_CHUNKS) throw new ChunkLimitError(BigInt(chunks.length), 0n);
|
|
11094
|
+
const _meta = params._meta ?? await getBlockMeta({ client });
|
|
11095
|
+
if (chunks.length === 0) return {
|
|
11096
|
+
results: [],
|
|
11097
|
+
_meta
|
|
11098
|
+
};
|
|
11099
|
+
const multicallResults = await client.multicall({
|
|
11100
|
+
contracts: chunks.map((chunk) => ({
|
|
11101
|
+
address: sfpmAddress,
|
|
11102
|
+
abi: semiFungiblePositionManagerV4Abi,
|
|
11103
|
+
functionName: "getAccountLiquidity",
|
|
11104
|
+
args: [
|
|
11105
|
+
poolKeyBytes,
|
|
11106
|
+
chunk.owner,
|
|
11107
|
+
chunk.tokenType,
|
|
11108
|
+
Number(chunk.tickLower),
|
|
11109
|
+
Number(chunk.tickUpper)
|
|
11110
|
+
]
|
|
11111
|
+
})),
|
|
11112
|
+
allowFailure: true
|
|
11113
|
+
});
|
|
11114
|
+
const results = multicallResults.map((result) => {
|
|
11115
|
+
if (result.status === "failure") return {
|
|
11116
|
+
netLiquidity: 0n,
|
|
11117
|
+
removedLiquidity: 0n,
|
|
11118
|
+
totalLiquidity: 0n,
|
|
11119
|
+
shortLiquidity: 0n,
|
|
11120
|
+
longLiquidity: 0n
|
|
11121
|
+
};
|
|
11122
|
+
const packed = result.result;
|
|
11123
|
+
const netLiquidity = packed & (1n << 128n) - 1n;
|
|
11124
|
+
const removedLiquidity = packed >> 128n;
|
|
11125
|
+
const totalLiquidity = netLiquidity + removedLiquidity;
|
|
11126
|
+
return {
|
|
11127
|
+
netLiquidity,
|
|
11128
|
+
removedLiquidity,
|
|
11129
|
+
totalLiquidity,
|
|
11130
|
+
shortLiquidity: totalLiquidity,
|
|
11131
|
+
longLiquidity: removedLiquidity
|
|
11132
|
+
};
|
|
11133
|
+
});
|
|
11134
|
+
return {
|
|
11135
|
+
results,
|
|
11136
|
+
_meta
|
|
11137
|
+
};
|
|
11262
11138
|
}
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
*
|
|
11268
|
-
* @param sqrtPriceX96 - The sqrt price in Q64.96 format
|
|
11269
|
-
* @param decimals0 - Decimals of token0
|
|
11270
|
-
* @param decimals1 - Decimals of token1
|
|
11271
|
-
* @param precision - Number of decimal places to display
|
|
11272
|
-
* @returns Formatted price string
|
|
11273
|
-
*
|
|
11274
|
-
* @example
|
|
11275
|
-
* ```typescript
|
|
11276
|
-
* sqrtPriceX96ToPriceDecimalScaled(2n ** 96n, 18n, 18n, 2n) // "1.00"
|
|
11277
|
-
* ```
|
|
11139
|
+
|
|
11140
|
+
//#endregion
|
|
11141
|
+
//#region src/panoptic/v2/reads/factory.ts
|
|
11142
|
+
/**
|
|
11143
|
+
* Get the token URI from a PanopticFactory NFT.
|
|
11278
11144
|
*/
|
|
11279
|
-
function
|
|
11280
|
-
const
|
|
11281
|
-
const
|
|
11282
|
-
return
|
|
11145
|
+
async function getFactoryTokenURI(params) {
|
|
11146
|
+
const { client, factoryAddress, version, tokenId } = params;
|
|
11147
|
+
const abi = version === "v3" ? panopticFactoryV3Abi : panopticFactoryV4Abi;
|
|
11148
|
+
return client.readContract({
|
|
11149
|
+
address: factoryAddress,
|
|
11150
|
+
abi,
|
|
11151
|
+
functionName: "tokenURI",
|
|
11152
|
+
args: [tokenId]
|
|
11153
|
+
});
|
|
11283
11154
|
}
|
|
11284
11155
|
/**
|
|
11285
|
-
*
|
|
11286
|
-
*
|
|
11287
|
-
* @param price - The price string
|
|
11288
|
-
* @param decimals0 - Decimals of token0
|
|
11289
|
-
* @param decimals1 - Decimals of token1
|
|
11290
|
-
* @returns The tick value (rounded to nearest integer)
|
|
11291
|
-
*
|
|
11292
|
-
* @example
|
|
11293
|
-
* ```typescript
|
|
11294
|
-
* // WETH/USDC: What tick for $2000 per ETH?
|
|
11295
|
-
* priceToTick("2000", 18n, 6n) // ~200000n
|
|
11296
|
-
*
|
|
11297
|
-
* // Inverse: What tick for 0.0005 ETH per USDC?
|
|
11298
|
-
* priceToTick("0.0005", 6n, 18n) // ~200000n
|
|
11299
|
-
* ```
|
|
11156
|
+
* Get the owner of a PanopticFactory NFT.
|
|
11300
11157
|
*/
|
|
11301
|
-
function
|
|
11302
|
-
const
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
|
|
11306
|
-
|
|
11307
|
-
|
|
11308
|
-
|
|
11309
|
-
|
|
11310
|
-
let high = MAX_TICK;
|
|
11311
|
-
while (low <= high) {
|
|
11312
|
-
const mid = (low + high) / 2n;
|
|
11313
|
-
const { numerator, denominator } = getRawPriceRatio(mid);
|
|
11314
|
-
const cmp = compareRatios(numerator, denominator, targetNumerator, targetDenominator);
|
|
11315
|
-
if (cmp === 0) return mid;
|
|
11316
|
-
if (cmp < 0) low = mid + 1n;
|
|
11317
|
-
else high = mid - 1n;
|
|
11318
|
-
}
|
|
11319
|
-
const floorTick = high;
|
|
11320
|
-
const ceilTick = low;
|
|
11321
|
-
if (floorTick < MIN_TICK) return MIN_TICK;
|
|
11322
|
-
if (ceilTick > MAX_TICK) return MAX_TICK;
|
|
11323
|
-
const floorRatio = getRawPriceRatio(floorTick);
|
|
11324
|
-
const ceilRatio = getRawPriceRatio(ceilTick);
|
|
11325
|
-
const floorDiffNumerator = absBigint(targetNumerator * floorRatio.denominator - floorRatio.numerator * targetDenominator);
|
|
11326
|
-
const ceilDiffNumerator = absBigint(targetNumerator * ceilRatio.denominator - ceilRatio.numerator * targetDenominator);
|
|
11327
|
-
const floorDiffDenominator = targetDenominator * floorRatio.denominator;
|
|
11328
|
-
const ceilDiffDenominator = targetDenominator * ceilRatio.denominator;
|
|
11329
|
-
return floorDiffNumerator * ceilDiffDenominator <= ceilDiffNumerator * floorDiffDenominator ? floorTick : ceilTick;
|
|
11158
|
+
async function getFactoryOwnerOf(params) {
|
|
11159
|
+
const { client, factoryAddress, version, tokenId } = params;
|
|
11160
|
+
const abi = version === "v3" ? panopticFactoryV3Abi : panopticFactoryV4Abi;
|
|
11161
|
+
return client.readContract({
|
|
11162
|
+
address: factoryAddress,
|
|
11163
|
+
abi,
|
|
11164
|
+
functionName: "ownerOf",
|
|
11165
|
+
args: [tokenId]
|
|
11166
|
+
});
|
|
11330
11167
|
}
|
|
11331
11168
|
/**
|
|
11332
|
-
*
|
|
11333
|
-
*
|
|
11334
|
-
* @param sqrtPriceX96 - The sqrt price in Q64.96 format
|
|
11335
|
-
* @returns The tick value (rounded to nearest integer)
|
|
11336
|
-
*
|
|
11337
|
-
* @example
|
|
11338
|
-
* ```typescript
|
|
11339
|
-
* const tick = sqrtPriceX96ToTick(2n ** 96n) // 0n
|
|
11340
|
-
* ```
|
|
11169
|
+
* Construct NFT metadata for a pool via the factory contract.
|
|
11341
11170
|
*/
|
|
11342
|
-
function
|
|
11343
|
-
|
|
11344
|
-
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
11354
|
-
|
|
11355
|
-
|
|
11356
|
-
if (floorTick < MIN_TICK) return MIN_TICK;
|
|
11357
|
-
if (ceilTick > MAX_TICK) return MAX_TICK;
|
|
11358
|
-
const floorSqrt = tickToSqrtPriceX96(floorTick);
|
|
11359
|
-
const ceilSqrt = tickToSqrtPriceX96(ceilTick);
|
|
11360
|
-
const floorDiff = absBigint(sqrtPriceX96 - floorSqrt);
|
|
11361
|
-
const ceilDiff = absBigint(ceilSqrt - sqrtPriceX96);
|
|
11362
|
-
return floorDiff <= ceilDiff ? floorTick : ceilTick;
|
|
11171
|
+
async function getFactoryConstructMetadata(params) {
|
|
11172
|
+
const { client, factoryAddress, version, panopticPoolAddress, symbol0, symbol1, fee } = params;
|
|
11173
|
+
const abi = version === "v3" ? panopticFactoryV3Abi : panopticFactoryV4Abi;
|
|
11174
|
+
return client.readContract({
|
|
11175
|
+
address: factoryAddress,
|
|
11176
|
+
abi,
|
|
11177
|
+
functionName: "constructMetadata",
|
|
11178
|
+
args: [
|
|
11179
|
+
panopticPoolAddress,
|
|
11180
|
+
symbol0,
|
|
11181
|
+
symbol1,
|
|
11182
|
+
fee
|
|
11183
|
+
]
|
|
11184
|
+
});
|
|
11363
11185
|
}
|
|
11364
11186
|
/**
|
|
11365
|
-
*
|
|
11366
|
-
*
|
|
11367
|
-
* @param tick - The tick value
|
|
11368
|
-
* @returns Formatted tick string
|
|
11369
|
-
*
|
|
11370
|
-
* @example
|
|
11371
|
-
* ```typescript
|
|
11372
|
-
* formatTick(200000n) // "200000"
|
|
11373
|
-
* formatTick(-50000n) // "-50000"
|
|
11374
|
-
* ```
|
|
11187
|
+
* Get the PanopticPool address for a given pool and risk engine.
|
|
11375
11188
|
*/
|
|
11376
|
-
function
|
|
11377
|
-
|
|
11189
|
+
async function getPanopticPoolAddress(params) {
|
|
11190
|
+
const { client, factoryAddress, riskEngine } = params;
|
|
11191
|
+
if (params.version === "v3") return client.readContract({
|
|
11192
|
+
address: factoryAddress,
|
|
11193
|
+
abi: panopticFactoryV3Abi,
|
|
11194
|
+
functionName: "getPanopticPool",
|
|
11195
|
+
args: [params.univ3pool, riskEngine]
|
|
11196
|
+
});
|
|
11197
|
+
return client.readContract({
|
|
11198
|
+
address: factoryAddress,
|
|
11199
|
+
abi: panopticFactoryV4Abi,
|
|
11200
|
+
functionName: "getPanopticPool",
|
|
11201
|
+
args: [{
|
|
11202
|
+
currency0: params.poolKey.currency0,
|
|
11203
|
+
currency1: params.poolKey.currency1,
|
|
11204
|
+
fee: Number(params.poolKey.fee),
|
|
11205
|
+
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
11206
|
+
hooks: params.poolKey.hooks
|
|
11207
|
+
}, riskEngine]
|
|
11208
|
+
});
|
|
11378
11209
|
}
|
|
11379
11210
|
/**
|
|
11380
|
-
*
|
|
11381
|
-
*
|
|
11382
|
-
* @param tick - The tick value
|
|
11383
|
-
* @param decimals0 - Decimals of token0
|
|
11384
|
-
* @param decimals1 - Decimals of token1
|
|
11385
|
-
* @param precision - Number of decimal places to display
|
|
11386
|
-
* @returns Object with both price directions
|
|
11387
|
-
*
|
|
11388
|
-
* @example
|
|
11389
|
-
* ```typescript
|
|
11390
|
-
* const prices = getPricesAtTick(200000n, 18n, 6n, 2n)
|
|
11391
|
-
* // prices.token0PerToken1 = "0.00" (very small)
|
|
11392
|
-
* // prices.token1PerToken0 = "2000.00" (USDC per ETH)
|
|
11393
|
-
* ```
|
|
11211
|
+
* Mine for an optimal pool address salt with high rarity.
|
|
11394
11212
|
*/
|
|
11395
|
-
function
|
|
11396
|
-
const
|
|
11397
|
-
|
|
11213
|
+
async function minePoolAddress(params) {
|
|
11214
|
+
const { client, factoryAddress, deployerAddress, riskEngine, salt, loops, minTargetRarity } = params;
|
|
11215
|
+
let result;
|
|
11216
|
+
if (params.version === "v3") result = await client.readContract({
|
|
11217
|
+
address: factoryAddress,
|
|
11218
|
+
abi: panopticFactoryV3Abi,
|
|
11219
|
+
functionName: "minePoolAddress",
|
|
11220
|
+
args: [
|
|
11221
|
+
deployerAddress,
|
|
11222
|
+
params.v3Pool,
|
|
11223
|
+
riskEngine,
|
|
11224
|
+
salt,
|
|
11225
|
+
loops,
|
|
11226
|
+
minTargetRarity
|
|
11227
|
+
]
|
|
11228
|
+
});
|
|
11229
|
+
else result = await client.readContract({
|
|
11230
|
+
address: factoryAddress,
|
|
11231
|
+
abi: panopticFactoryV4Abi,
|
|
11232
|
+
functionName: "minePoolAddress",
|
|
11233
|
+
args: [
|
|
11234
|
+
deployerAddress,
|
|
11235
|
+
{
|
|
11236
|
+
currency0: params.poolKey.currency0,
|
|
11237
|
+
currency1: params.poolKey.currency1,
|
|
11238
|
+
fee: Number(params.poolKey.fee),
|
|
11239
|
+
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
11240
|
+
hooks: params.poolKey.hooks
|
|
11241
|
+
},
|
|
11242
|
+
riskEngine,
|
|
11243
|
+
salt,
|
|
11244
|
+
loops,
|
|
11245
|
+
minTargetRarity
|
|
11246
|
+
]
|
|
11247
|
+
});
|
|
11398
11248
|
return {
|
|
11399
|
-
|
|
11400
|
-
|
|
11249
|
+
bestSalt: BigInt(result[0]),
|
|
11250
|
+
highestRarity: result[1]
|
|
11401
11251
|
};
|
|
11402
11252
|
}
|
|
11403
11253
|
/**
|
|
11404
|
-
*
|
|
11405
|
-
*
|
|
11406
|
-
* @param tickLower - Lower tick
|
|
11407
|
-
* @param tickUpper - Upper tick
|
|
11408
|
-
* @returns Formatted tick range string
|
|
11254
|
+
* Simulate a pool deployment to get the predicted pool address.
|
|
11409
11255
|
*
|
|
11410
|
-
*
|
|
11411
|
-
*
|
|
11412
|
-
* formatTickRange(-50000n, 200000n) // "-50000 - 200000"
|
|
11413
|
-
* ```
|
|
11256
|
+
* Uses `simulateContract` on `deployNewPool` — the return value is the new pool address
|
|
11257
|
+
* without actually executing the transaction.
|
|
11414
11258
|
*/
|
|
11415
|
-
function
|
|
11416
|
-
|
|
11259
|
+
async function simulateDeployNewPool(params) {
|
|
11260
|
+
const { client, factoryAddress, account, riskEngine, salt } = params;
|
|
11261
|
+
if (params.version === "v3") {
|
|
11262
|
+
const { result: result$1 } = await client.simulateContract({
|
|
11263
|
+
address: factoryAddress,
|
|
11264
|
+
abi: panopticFactoryV3Abi,
|
|
11265
|
+
functionName: "deployNewPool",
|
|
11266
|
+
args: [
|
|
11267
|
+
params.token0,
|
|
11268
|
+
params.token1,
|
|
11269
|
+
Number(params.fee),
|
|
11270
|
+
riskEngine,
|
|
11271
|
+
salt
|
|
11272
|
+
],
|
|
11273
|
+
account
|
|
11274
|
+
});
|
|
11275
|
+
return result$1;
|
|
11276
|
+
}
|
|
11277
|
+
const { result } = await client.simulateContract({
|
|
11278
|
+
address: factoryAddress,
|
|
11279
|
+
abi: panopticFactoryV4Abi,
|
|
11280
|
+
functionName: "deployNewPool",
|
|
11281
|
+
args: [
|
|
11282
|
+
{
|
|
11283
|
+
currency0: params.poolKey.currency0,
|
|
11284
|
+
currency1: params.poolKey.currency1,
|
|
11285
|
+
fee: Number(params.poolKey.fee),
|
|
11286
|
+
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
11287
|
+
hooks: params.poolKey.hooks
|
|
11288
|
+
},
|
|
11289
|
+
riskEngine,
|
|
11290
|
+
salt
|
|
11291
|
+
],
|
|
11292
|
+
account
|
|
11293
|
+
});
|
|
11294
|
+
return result;
|
|
11417
11295
|
}
|
|
11418
11296
|
/**
|
|
11419
|
-
*
|
|
11420
|
-
*
|
|
11421
|
-
* @param tickLower - Lower tick
|
|
11422
|
-
* @param tickUpper - Upper tick
|
|
11423
|
-
* @param decimals0 - Decimals of token0
|
|
11424
|
-
* @param decimals1 - Decimals of token1
|
|
11425
|
-
* @param precision - Number of decimal places to display
|
|
11426
|
-
* @returns Formatted price range string
|
|
11297
|
+
* Resolve an SFPM poolId to its PanopticPool address.
|
|
11427
11298
|
*
|
|
11428
|
-
*
|
|
11429
|
-
*
|
|
11430
|
-
*
|
|
11431
|
-
* ```
|
|
11299
|
+
* Chains two on-chain lookups:
|
|
11300
|
+
* 1. SFPM: poolId → Uniswap pool address (V3) or pool key (V4)
|
|
11301
|
+
* 2. Factory: Uniswap pool + riskEngine → PanopticPool address
|
|
11432
11302
|
*/
|
|
11433
|
-
function
|
|
11434
|
-
const
|
|
11435
|
-
|
|
11436
|
-
|
|
11303
|
+
async function getPanopticPoolFromPoolId(params) {
|
|
11304
|
+
const { client, sfpmAddress, factoryAddress, riskEngine, poolId, version } = params;
|
|
11305
|
+
if (version === "v3") {
|
|
11306
|
+
const univ3pool = await getUniswapV3PoolFromId({
|
|
11307
|
+
client,
|
|
11308
|
+
sfpmAddress,
|
|
11309
|
+
poolId
|
|
11310
|
+
});
|
|
11311
|
+
return getPanopticPoolAddress({
|
|
11312
|
+
version: "v3",
|
|
11313
|
+
client,
|
|
11314
|
+
factoryAddress,
|
|
11315
|
+
univ3pool,
|
|
11316
|
+
riskEngine
|
|
11317
|
+
});
|
|
11318
|
+
}
|
|
11319
|
+
const poolKey = await getUniswapV4PoolKeyFromId({
|
|
11320
|
+
client,
|
|
11321
|
+
sfpmAddress,
|
|
11322
|
+
poolId
|
|
11323
|
+
});
|
|
11324
|
+
return getPanopticPoolAddress({
|
|
11325
|
+
version: "v4",
|
|
11326
|
+
client,
|
|
11327
|
+
factoryAddress,
|
|
11328
|
+
poolKey,
|
|
11329
|
+
riskEngine
|
|
11330
|
+
});
|
|
11437
11331
|
}
|
|
11438
11332
|
/**
|
|
11439
|
-
*
|
|
11333
|
+
* Resolve an SFPM poolId to its PanopticPool address without knowing the version.
|
|
11440
11334
|
*
|
|
11441
|
-
*
|
|
11442
|
-
*
|
|
11335
|
+
* Tries both V3 and V4 lookups in parallel. The factory returns `address(0)` for
|
|
11336
|
+
* non-existent pools, so the non-zero result identifies the correct version.
|
|
11443
11337
|
*
|
|
11444
|
-
*
|
|
11445
|
-
*
|
|
11446
|
-
*
|
|
11447
|
-
* getTickSpacing(500n) // 10n (0.05% fee tier)
|
|
11448
|
-
* getTickSpacing(3000n) // 60n (0.30% fee tier)
|
|
11449
|
-
* getTickSpacing(10000n) // 200n (1.00% fee tier)
|
|
11450
|
-
* ```
|
|
11338
|
+
* At least one of `v3` or `v4` must be provided.
|
|
11339
|
+
*
|
|
11340
|
+
* @throws {PanopticValidationError} If no version config is provided or neither resolves.
|
|
11451
11341
|
*/
|
|
11452
|
-
function
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
11458
|
-
|
|
11459
|
-
const spacing = feeBps / 50n;
|
|
11460
|
-
return spacing > 1n ? spacing : 1n;
|
|
11342
|
+
async function resolvePanopticPoolFromPoolId(params) {
|
|
11343
|
+
const { client, poolId, riskEngine, v3, v4 } = params;
|
|
11344
|
+
if (!v3 && !v4) throw new Error("At least one of v3 or v4 must be provided");
|
|
11345
|
+
const isNotFoundError = (err) => {
|
|
11346
|
+
if (typeof err === "object" && err !== null && "name" in err) {
|
|
11347
|
+
const name = err.name;
|
|
11348
|
+
return name === "ContractFunctionExecutionError" || name === "ContractFunctionRevertedError";
|
|
11461
11349
|
}
|
|
11462
|
-
|
|
11350
|
+
return false;
|
|
11351
|
+
};
|
|
11352
|
+
const results = await Promise.all([v3 ? getPanopticPoolFromPoolId({
|
|
11353
|
+
version: "v3",
|
|
11354
|
+
client,
|
|
11355
|
+
sfpmAddress: v3.sfpmAddress,
|
|
11356
|
+
factoryAddress: v3.factoryAddress,
|
|
11357
|
+
riskEngine,
|
|
11358
|
+
poolId
|
|
11359
|
+
}).catch((err) => {
|
|
11360
|
+
if (isNotFoundError(err)) return zeroAddress;
|
|
11361
|
+
throw err;
|
|
11362
|
+
}) : Promise.resolve(zeroAddress), v4 ? getPanopticPoolFromPoolId({
|
|
11363
|
+
version: "v4",
|
|
11364
|
+
client,
|
|
11365
|
+
sfpmAddress: v4.sfpmAddress,
|
|
11366
|
+
factoryAddress: v4.factoryAddress,
|
|
11367
|
+
riskEngine,
|
|
11368
|
+
poolId
|
|
11369
|
+
}).catch((err) => {
|
|
11370
|
+
if (isNotFoundError(err)) return zeroAddress;
|
|
11371
|
+
throw err;
|
|
11372
|
+
}) : Promise.resolve(zeroAddress)]);
|
|
11373
|
+
const [v3Result, v4Result] = results;
|
|
11374
|
+
if (v3Result !== zeroAddress) return {
|
|
11375
|
+
panopticPoolAddress: v3Result,
|
|
11376
|
+
version: "v3"
|
|
11377
|
+
};
|
|
11378
|
+
if (v4Result !== zeroAddress) return {
|
|
11379
|
+
panopticPoolAddress: v4Result,
|
|
11380
|
+
version: "v4"
|
|
11381
|
+
};
|
|
11382
|
+
throw new Error(`No PanopticPool found for poolId ${poolId}`);
|
|
11463
11383
|
}
|
|
11384
|
+
|
|
11385
|
+
//#endregion
|
|
11386
|
+
//#region src/panoptic/v2/reads/minePoolAddressLocal.ts
|
|
11387
|
+
const MASK_80 = (1n << 80n) - 1n;
|
|
11388
|
+
const MASK_40 = (1n << 40n) - 1n;
|
|
11389
|
+
const MASK_96 = (1n << 96n) - 1n;
|
|
11390
|
+
|
|
11391
|
+
//#endregion
|
|
11392
|
+
//#region src/panoptic/v2/abis/stateView.ts
|
|
11464
11393
|
/**
|
|
11465
|
-
*
|
|
11466
|
-
*
|
|
11467
|
-
* @param tick - The tick to round
|
|
11468
|
-
* @param tickSpacing - The tick spacing
|
|
11469
|
-
* @returns Rounded tick
|
|
11470
|
-
*
|
|
11471
|
-
* @example
|
|
11472
|
-
* ```typescript
|
|
11473
|
-
* roundToTickSpacing(12345n, 10n) // 12340n
|
|
11474
|
-
* roundToTickSpacing(12345n, 60n) // 12360n
|
|
11475
|
-
* roundToTickSpacing(-12345n, 10n) // -12350n
|
|
11476
|
-
* ```
|
|
11394
|
+
* Minimal Uniswap V4 StateView ABI for fee growth reads.
|
|
11395
|
+
* Only includes functions needed by streamia history.
|
|
11477
11396
|
*/
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
}
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11492
|
-
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
|
|
11508
|
-
|
|
11397
|
+
const stateViewAbi = [
|
|
11398
|
+
{
|
|
11399
|
+
inputs: [{
|
|
11400
|
+
internalType: "PoolId",
|
|
11401
|
+
name: "poolId",
|
|
11402
|
+
type: "bytes32"
|
|
11403
|
+
}],
|
|
11404
|
+
name: "getSlot0",
|
|
11405
|
+
outputs: [
|
|
11406
|
+
{
|
|
11407
|
+
internalType: "uint160",
|
|
11408
|
+
name: "sqrtPriceX96",
|
|
11409
|
+
type: "uint160"
|
|
11410
|
+
},
|
|
11411
|
+
{
|
|
11412
|
+
internalType: "int24",
|
|
11413
|
+
name: "tick",
|
|
11414
|
+
type: "int24"
|
|
11415
|
+
},
|
|
11416
|
+
{
|
|
11417
|
+
internalType: "uint24",
|
|
11418
|
+
name: "protocolFee",
|
|
11419
|
+
type: "uint24"
|
|
11420
|
+
},
|
|
11421
|
+
{
|
|
11422
|
+
internalType: "uint24",
|
|
11423
|
+
name: "lpFee",
|
|
11424
|
+
type: "uint24"
|
|
11425
|
+
}
|
|
11426
|
+
],
|
|
11427
|
+
stateMutability: "view",
|
|
11428
|
+
type: "function"
|
|
11429
|
+
},
|
|
11430
|
+
{
|
|
11431
|
+
inputs: [{
|
|
11432
|
+
internalType: "PoolId",
|
|
11433
|
+
name: "poolId",
|
|
11434
|
+
type: "bytes32"
|
|
11435
|
+
}],
|
|
11436
|
+
name: "getFeeGrowthGlobals",
|
|
11437
|
+
outputs: [{
|
|
11438
|
+
internalType: "uint256",
|
|
11439
|
+
name: "feeGrowthGlobal0",
|
|
11440
|
+
type: "uint256"
|
|
11441
|
+
}, {
|
|
11442
|
+
internalType: "uint256",
|
|
11443
|
+
name: "feeGrowthGlobal1",
|
|
11444
|
+
type: "uint256"
|
|
11445
|
+
}],
|
|
11446
|
+
stateMutability: "view",
|
|
11447
|
+
type: "function"
|
|
11448
|
+
},
|
|
11449
|
+
{
|
|
11450
|
+
inputs: [{
|
|
11451
|
+
internalType: "PoolId",
|
|
11452
|
+
name: "poolId",
|
|
11453
|
+
type: "bytes32"
|
|
11454
|
+
}, {
|
|
11455
|
+
internalType: "int24",
|
|
11456
|
+
name: "tick",
|
|
11457
|
+
type: "int24"
|
|
11458
|
+
}],
|
|
11459
|
+
name: "getTickInfo",
|
|
11460
|
+
outputs: [
|
|
11461
|
+
{
|
|
11462
|
+
internalType: "uint128",
|
|
11463
|
+
name: "liquidityGross",
|
|
11464
|
+
type: "uint128"
|
|
11465
|
+
},
|
|
11466
|
+
{
|
|
11467
|
+
internalType: "int128",
|
|
11468
|
+
name: "liquidityNet",
|
|
11469
|
+
type: "int128"
|
|
11470
|
+
},
|
|
11471
|
+
{
|
|
11472
|
+
internalType: "uint256",
|
|
11473
|
+
name: "feeGrowthOutside0X128",
|
|
11474
|
+
type: "uint256"
|
|
11475
|
+
},
|
|
11476
|
+
{
|
|
11477
|
+
internalType: "uint256",
|
|
11478
|
+
name: "feeGrowthOutside1X128",
|
|
11479
|
+
type: "uint256"
|
|
11480
|
+
}
|
|
11481
|
+
],
|
|
11482
|
+
stateMutability: "view",
|
|
11483
|
+
type: "function"
|
|
11484
|
+
},
|
|
11485
|
+
{
|
|
11486
|
+
inputs: [{
|
|
11487
|
+
internalType: "PoolId",
|
|
11488
|
+
name: "poolId",
|
|
11489
|
+
type: "bytes32"
|
|
11490
|
+
}],
|
|
11491
|
+
name: "getLiquidity",
|
|
11492
|
+
outputs: [{
|
|
11493
|
+
internalType: "uint128",
|
|
11494
|
+
name: "liquidity",
|
|
11495
|
+
type: "uint128"
|
|
11496
|
+
}],
|
|
11497
|
+
stateMutability: "view",
|
|
11498
|
+
type: "function"
|
|
11499
|
+
}
|
|
11500
|
+
];
|
|
11501
|
+
|
|
11502
|
+
//#endregion
|
|
11503
|
+
//#region src/panoptic/v2/abis/uniswapV3Pool.ts
|
|
11504
|
+
/**
|
|
11505
|
+
* Minimal Uniswap V3 Pool ABI for fee growth reads.
|
|
11506
|
+
* Only includes functions needed by streamia history.
|
|
11509
11507
|
*/
|
|
11510
|
-
|
|
11511
|
-
|
|
11512
|
-
|
|
11513
|
-
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11508
|
+
const uniswapV3PoolAbi = [
|
|
11509
|
+
{
|
|
11510
|
+
inputs: [],
|
|
11511
|
+
name: "slot0",
|
|
11512
|
+
outputs: [
|
|
11513
|
+
{
|
|
11514
|
+
internalType: "uint160",
|
|
11515
|
+
name: "sqrtPriceX96",
|
|
11516
|
+
type: "uint160"
|
|
11517
|
+
},
|
|
11518
|
+
{
|
|
11519
|
+
internalType: "int24",
|
|
11520
|
+
name: "tick",
|
|
11521
|
+
type: "int24"
|
|
11522
|
+
},
|
|
11523
|
+
{
|
|
11524
|
+
internalType: "uint16",
|
|
11525
|
+
name: "observationIndex",
|
|
11526
|
+
type: "uint16"
|
|
11527
|
+
},
|
|
11528
|
+
{
|
|
11529
|
+
internalType: "uint16",
|
|
11530
|
+
name: "observationCardinality",
|
|
11531
|
+
type: "uint16"
|
|
11532
|
+
},
|
|
11533
|
+
{
|
|
11534
|
+
internalType: "uint16",
|
|
11535
|
+
name: "observationCardinalityNext",
|
|
11536
|
+
type: "uint16"
|
|
11537
|
+
},
|
|
11538
|
+
{
|
|
11539
|
+
internalType: "uint8",
|
|
11540
|
+
name: "feeProtocol",
|
|
11541
|
+
type: "uint8"
|
|
11542
|
+
},
|
|
11543
|
+
{
|
|
11544
|
+
internalType: "bool",
|
|
11545
|
+
name: "unlocked",
|
|
11546
|
+
type: "bool"
|
|
11547
|
+
}
|
|
11548
|
+
],
|
|
11549
|
+
stateMutability: "view",
|
|
11550
|
+
type: "function"
|
|
11551
|
+
},
|
|
11552
|
+
{
|
|
11553
|
+
inputs: [],
|
|
11554
|
+
name: "feeGrowthGlobal0X128",
|
|
11555
|
+
outputs: [{
|
|
11556
|
+
internalType: "uint256",
|
|
11557
|
+
name: "",
|
|
11558
|
+
type: "uint256"
|
|
11559
|
+
}],
|
|
11560
|
+
stateMutability: "view",
|
|
11561
|
+
type: "function"
|
|
11562
|
+
},
|
|
11563
|
+
{
|
|
11564
|
+
inputs: [],
|
|
11565
|
+
name: "feeGrowthGlobal1X128",
|
|
11566
|
+
outputs: [{
|
|
11567
|
+
internalType: "uint256",
|
|
11568
|
+
name: "",
|
|
11569
|
+
type: "uint256"
|
|
11570
|
+
}],
|
|
11571
|
+
stateMutability: "view",
|
|
11572
|
+
type: "function"
|
|
11573
|
+
},
|
|
11574
|
+
{
|
|
11575
|
+
inputs: [{
|
|
11576
|
+
internalType: "int24",
|
|
11577
|
+
name: "",
|
|
11578
|
+
type: "int24"
|
|
11579
|
+
}],
|
|
11580
|
+
name: "ticks",
|
|
11581
|
+
outputs: [
|
|
11582
|
+
{
|
|
11583
|
+
internalType: "uint128",
|
|
11584
|
+
name: "liquidityGross",
|
|
11585
|
+
type: "uint128"
|
|
11586
|
+
},
|
|
11587
|
+
{
|
|
11588
|
+
internalType: "int128",
|
|
11589
|
+
name: "liquidityNet",
|
|
11590
|
+
type: "int128"
|
|
11591
|
+
},
|
|
11592
|
+
{
|
|
11593
|
+
internalType: "uint256",
|
|
11594
|
+
name: "feeGrowthOutside0X128",
|
|
11595
|
+
type: "uint256"
|
|
11596
|
+
},
|
|
11597
|
+
{
|
|
11598
|
+
internalType: "uint256",
|
|
11599
|
+
name: "feeGrowthOutside1X128",
|
|
11600
|
+
type: "uint256"
|
|
11601
|
+
},
|
|
11602
|
+
{
|
|
11603
|
+
internalType: "int56",
|
|
11604
|
+
name: "tickCumulativeOutside",
|
|
11605
|
+
type: "int56"
|
|
11606
|
+
},
|
|
11607
|
+
{
|
|
11608
|
+
internalType: "uint160",
|
|
11609
|
+
name: "secondsPerLiquidityOutsideX128",
|
|
11610
|
+
type: "uint160"
|
|
11611
|
+
},
|
|
11612
|
+
{
|
|
11613
|
+
internalType: "uint32",
|
|
11614
|
+
name: "secondsOutside",
|
|
11615
|
+
type: "uint32"
|
|
11616
|
+
},
|
|
11617
|
+
{
|
|
11618
|
+
internalType: "bool",
|
|
11619
|
+
name: "initialized",
|
|
11620
|
+
type: "bool"
|
|
11621
|
+
}
|
|
11622
|
+
],
|
|
11623
|
+
stateMutability: "view",
|
|
11624
|
+
type: "function"
|
|
11625
|
+
},
|
|
11626
|
+
{
|
|
11627
|
+
inputs: [],
|
|
11628
|
+
name: "liquidity",
|
|
11629
|
+
outputs: [{
|
|
11630
|
+
internalType: "uint128",
|
|
11631
|
+
name: "",
|
|
11632
|
+
type: "uint128"
|
|
11633
|
+
}],
|
|
11634
|
+
stateMutability: "view",
|
|
11635
|
+
type: "function"
|
|
11636
|
+
},
|
|
11637
|
+
{
|
|
11638
|
+
inputs: [],
|
|
11639
|
+
name: "fee",
|
|
11640
|
+
outputs: [{
|
|
11641
|
+
internalType: "uint24",
|
|
11642
|
+
name: "",
|
|
11643
|
+
type: "uint24"
|
|
11644
|
+
}],
|
|
11645
|
+
stateMutability: "view",
|
|
11646
|
+
type: "function"
|
|
11647
|
+
},
|
|
11648
|
+
{
|
|
11649
|
+
inputs: [],
|
|
11650
|
+
name: "token0",
|
|
11651
|
+
outputs: [{
|
|
11652
|
+
internalType: "address",
|
|
11653
|
+
name: "",
|
|
11654
|
+
type: "address"
|
|
11655
|
+
}],
|
|
11656
|
+
stateMutability: "view",
|
|
11657
|
+
type: "function"
|
|
11658
|
+
},
|
|
11659
|
+
{
|
|
11660
|
+
inputs: [],
|
|
11661
|
+
name: "token1",
|
|
11662
|
+
outputs: [{
|
|
11663
|
+
internalType: "address",
|
|
11664
|
+
name: "",
|
|
11665
|
+
type: "address"
|
|
11666
|
+
}],
|
|
11667
|
+
stateMutability: "view",
|
|
11668
|
+
type: "function"
|
|
11669
|
+
},
|
|
11670
|
+
{
|
|
11671
|
+
inputs: [],
|
|
11672
|
+
name: "tickSpacing",
|
|
11673
|
+
outputs: [{
|
|
11674
|
+
internalType: "int24",
|
|
11675
|
+
name: "",
|
|
11676
|
+
type: "int24"
|
|
11677
|
+
}],
|
|
11678
|
+
stateMutability: "view",
|
|
11679
|
+
type: "function"
|
|
11680
|
+
}
|
|
11681
|
+
];
|
|
11523
11682
|
|
|
11524
11683
|
//#endregion
|
|
11525
11684
|
//#region src/panoptic/v2/reads/mintBuffer.ts
|
|
@@ -14525,7 +14684,7 @@ async function readBlockAndAggregate({ client, calls, blockNumber }) {
|
|
|
14525
14684
|
|
|
14526
14685
|
//#endregion
|
|
14527
14686
|
//#region src/panoptic/v2/reads/checks.ts
|
|
14528
|
-
const FP96$
|
|
14687
|
+
const FP96$2 = 1n << 96n;
|
|
14529
14688
|
const Q128$4 = 1n << 128n;
|
|
14530
14689
|
function convert0to1$3(amount, sqrtPriceX96) {
|
|
14531
14690
|
if (sqrtPriceX96 < Q128$4) return amount * sqrtPriceX96 * sqrtPriceX96 >> 192n;
|
|
@@ -14676,7 +14835,7 @@ async function isLiquidatable(params) {
|
|
|
14676
14835
|
const requiredMargin1 = required1Native + convert0to1$3(required0Native, sqrtPriceX96);
|
|
14677
14836
|
const marginShortfall0 = requiredMargin0 - currentMargin0;
|
|
14678
14837
|
const marginShortfall1 = requiredMargin1 - currentMargin1;
|
|
14679
|
-
const denominatedInToken = sqrtPriceX96 < FP96$
|
|
14838
|
+
const denominatedInToken = sqrtPriceX96 < FP96$2 ? 0n : 1n;
|
|
14680
14839
|
const isLiquidatableResult = denominatedInToken === 0n ? marginShortfall0 > 0n : marginShortfall1 > 0n;
|
|
14681
14840
|
return {
|
|
14682
14841
|
isLiquidatable: isLiquidatableResult,
|
|
@@ -16919,8 +17078,9 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
16919
17078
|
error: new PanopticError("Could not size the prefixed recovery swap")
|
|
16920
17079
|
};
|
|
16921
17080
|
};
|
|
17081
|
+
let creditOutSize = amountOut;
|
|
16922
17082
|
for (let attempt = 0; attempt < MAX_RECOVERY_QUOTE_ATTEMPTS; attempt++) {
|
|
16923
|
-
const credit = buildUniqueCredit(pool.poolId, tokenOutIndex, tokenOutIndex, pool.currentTick, pool.tickSpacing, collisionIds,
|
|
17083
|
+
const credit = buildUniqueCredit(pool.poolId, tokenOutIndex, tokenOutIndex, pool.currentTick, pool.tickSpacing, collisionIds, creditOutSize);
|
|
16924
17084
|
const recoveredDispatch = buildTokenShortfallRecoveryDispatch({
|
|
16925
17085
|
dispatch: params.dispatch,
|
|
16926
17086
|
creditTokenId: credit.tokenId,
|
|
@@ -16964,10 +17124,14 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
16964
17124
|
const maxAmountIn = maximumAmountIn(estimatedAmountIn, params.slippageBps);
|
|
16965
17125
|
const swapOutput = getOutputAmount(swapSimulation.tokenFlow, tokenOutIndex);
|
|
16966
17126
|
const sourceBalance = getBalanceBefore(swapSimulation.tokenFlow, tokenInIndex);
|
|
16967
|
-
if (swapOutput < amountOut
|
|
17127
|
+
if (swapOutput < amountOut) {
|
|
17128
|
+
creditOutSize = swapOutput > 0n ? ceilDiv(creditOutSize * amountOut, swapOutput) + 1n : creditOutSize * 2n;
|
|
17129
|
+
continue;
|
|
17130
|
+
}
|
|
17131
|
+
if (sourceBalance < maxAmountIn) return {
|
|
16968
17132
|
available: false,
|
|
16969
17133
|
reason: "swap-unavailable",
|
|
16970
|
-
detail:
|
|
17134
|
+
detail: `source balance ${sourceBalance} < maximumAmountIn ${maxAmountIn} (estimated ${estimatedAmountIn}, slippageBps ${params.slippageBps})`,
|
|
16971
17135
|
error: new PanopticError("Insufficient source collateral for the recovery swap")
|
|
16972
17136
|
};
|
|
16973
17137
|
const recoverySimulation = await simulateDispatch({
|
|
@@ -17019,6 +17183,7 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
17019
17183
|
const decodedShortfall = remainingShortfall.assetsRequested - remainingShortfall.assetBalance;
|
|
17020
17184
|
const additionalAmountOut = decodedShortfall > 0n ? decodedShortfall : amountOut;
|
|
17021
17185
|
amountOut += additionalAmountOut;
|
|
17186
|
+
creditOutSize = swapOutput > 0n ? ceilDiv(creditOutSize * amountOut, swapOutput) + 1n : creditOutSize * 2n;
|
|
17022
17187
|
}
|
|
17023
17188
|
return {
|
|
17024
17189
|
available: false,
|
|
@@ -17045,6 +17210,7 @@ const MAX_EFFECTIVE_LIQUIDITY_LIMIT = 8388607;
|
|
|
17045
17210
|
* returned value must be scaled down to the caller's actual `positionSize`.
|
|
17046
17211
|
*/
|
|
17047
17212
|
const MAX_UINT64$1 = 2n ** 64n - 1n;
|
|
17213
|
+
const FP96$1 = 1n << 96n;
|
|
17048
17214
|
/**
|
|
17049
17215
|
* `getRequiredBase` returns `type(uint128).max` as an error sentinel (invalid
|
|
17050
17216
|
* tokenId or reverting `getMargin`). Detect it so we don't scale a garbage value.
|
|
@@ -17057,7 +17223,9 @@ const REQUIRED_BASE_ERROR_SENTINEL = 2n ** 128n - 1n;
|
|
|
17057
17223
|
* computes the requirement at `type(uint64).max` size and 0% utilization. Since
|
|
17058
17224
|
* the requirement is linear in size, the raw result is scaled by
|
|
17059
17225
|
* `positionSize / type(uint64).max` to yield the requirement for the requested
|
|
17060
|
-
* size.
|
|
17226
|
+
* size. `PanopticQuery.getRequiredBase` returns the cross-margin requirement in
|
|
17227
|
+
* the higher-precision raw token at `atTick`; this function places that amount
|
|
17228
|
+
* in the matching `required0` or `required1` field.
|
|
17061
17229
|
*
|
|
17062
17230
|
* @param params - The parameters
|
|
17063
17231
|
* @returns Estimated collateral requirements with block metadata
|
|
@@ -17076,7 +17244,7 @@ async function estimateCollateralRequired(params) {
|
|
|
17076
17244
|
});
|
|
17077
17245
|
effectiveTick = BigInt(currentTickResult);
|
|
17078
17246
|
}
|
|
17079
|
-
const [
|
|
17247
|
+
const [requiredBase, _meta] = await Promise.all([client.readContract({
|
|
17080
17248
|
address: queryAddress,
|
|
17081
17249
|
abi: panopticQueryAbi,
|
|
17082
17250
|
functionName: "getRequiredBase",
|
|
@@ -17090,10 +17258,11 @@ async function estimateCollateralRequired(params) {
|
|
|
17090
17258
|
client,
|
|
17091
17259
|
blockNumber: targetBlockNumber
|
|
17092
17260
|
})]);
|
|
17093
|
-
const
|
|
17261
|
+
const scaledRequirement = requiredBase >= REQUIRED_BASE_ERROR_SENTINEL ? requiredBase : requiredBase * positionSize / MAX_UINT64$1;
|
|
17262
|
+
const denominatedInToken0 = tickToSqrtPriceX96(effectiveTick) < FP96$1;
|
|
17094
17263
|
return {
|
|
17095
|
-
required0:
|
|
17096
|
-
required1: 0n,
|
|
17264
|
+
required0: denominatedInToken0 ? scaledRequirement : 0n,
|
|
17265
|
+
required1: denominatedInToken0 ? 0n : scaledRequirement,
|
|
17097
17266
|
_meta
|
|
17098
17267
|
};
|
|
17099
17268
|
}
|
|
@@ -20730,7 +20899,9 @@ async function getStreamiaHistory(params) {
|
|
|
20730
20899
|
_meta: _meta$1
|
|
20731
20900
|
};
|
|
20732
20901
|
}
|
|
20733
|
-
const
|
|
20902
|
+
const _meta = params._meta ?? await getBlockMeta({ client });
|
|
20903
|
+
const resolvedBlockNumbers = blockNumbers.map((blockNumber) => blockNumber ?? _meta.blockNumber);
|
|
20904
|
+
const premiaRequests = resolvedBlockNumbers.map((blockNumber) => client.readContract({
|
|
20734
20905
|
address: panopticPoolAddress,
|
|
20735
20906
|
abi: panopticPoolV2Abi,
|
|
20736
20907
|
functionName: "getFullPositionsData",
|
|
@@ -20739,18 +20910,36 @@ async function getStreamiaHistory(params) {
|
|
|
20739
20910
|
true,
|
|
20740
20911
|
[tokenId]
|
|
20741
20912
|
],
|
|
20742
|
-
blockNumber
|
|
20913
|
+
blockNumber
|
|
20743
20914
|
}));
|
|
20744
|
-
const uniswapDataPromise = includeUniswapFees && legs.length > 0 ? fetchUniswapFeeData(client,
|
|
20745
|
-
const [premiaResults, uniswapData
|
|
20746
|
-
|
|
20747
|
-
uniswapDataPromise ?? Promise.resolve(void 0),
|
|
20748
|
-
params._meta ? Promise.resolve(params._meta) : getBlockMeta({ client })
|
|
20749
|
-
]);
|
|
20750
|
-
const sortedSettled = settledEvents ? [...settledEvents].sort((a, b) => a.blockNumber < b.blockNumber ? -1 : 1) : [];
|
|
20915
|
+
const uniswapDataPromise = includeUniswapFees && legs.length > 0 ? fetchUniswapFeeData(client, resolvedBlockNumbers, legs, poolConfig) : void 0;
|
|
20916
|
+
const [premiaResults, uniswapData] = await Promise.all([Promise.all(premiaRequests), uniswapDataPromise ?? Promise.resolve(void 0)]);
|
|
20917
|
+
const sortedSettled = settledEvents ? [...settledEvents].sort((a, b) => a.blockNumber === b.blockNumber ? 0 : a.blockNumber < b.blockNumber ? -1 : 1) : [];
|
|
20751
20918
|
let settledIdx = 0;
|
|
20752
20919
|
let accSettled0 = 0n;
|
|
20753
20920
|
let accSettled1 = 0n;
|
|
20921
|
+
const cumulativePremiaByInputIndex = Array.from({ length: blockNumbers.length }, () => ({
|
|
20922
|
+
token0: 0n,
|
|
20923
|
+
token1: 0n
|
|
20924
|
+
}));
|
|
20925
|
+
const chronologicalInputs = resolvedBlockNumbers.map((blockNumber, inputIndex) => ({
|
|
20926
|
+
blockNumber,
|
|
20927
|
+
inputIndex
|
|
20928
|
+
})).sort((a, b) => a.blockNumber === b.blockNumber ? a.inputIndex - b.inputIndex : a.blockNumber < b.blockNumber ? -1 : 1);
|
|
20929
|
+
for (const { blockNumber, inputIndex } of chronologicalInputs) {
|
|
20930
|
+
while (settledIdx < sortedSettled.length && sortedSettled[settledIdx].blockNumber <= blockNumber) {
|
|
20931
|
+
accSettled0 += sortedSettled[settledIdx].settled0;
|
|
20932
|
+
accSettled1 += sortedSettled[settledIdx].settled1;
|
|
20933
|
+
settledIdx++;
|
|
20934
|
+
}
|
|
20935
|
+
const result = premiaResults[inputIndex];
|
|
20936
|
+
const premia0 = (result[0] & MASK_128) - (result[1] & MASK_128);
|
|
20937
|
+
const premia1 = (result[0] >> 128n) - (result[1] >> 128n);
|
|
20938
|
+
cumulativePremiaByInputIndex[inputIndex] = {
|
|
20939
|
+
token0: premia0 + accSettled0,
|
|
20940
|
+
token1: premia1 + accSettled1
|
|
20941
|
+
};
|
|
20942
|
+
}
|
|
20754
20943
|
let initialUniswapFees0 = null;
|
|
20755
20944
|
let initialUniswapFees1 = null;
|
|
20756
20945
|
const snapshots = premiaResults.map((result, i) => {
|
|
@@ -20761,14 +20950,8 @@ async function getStreamiaHistory(params) {
|
|
|
20761
20950
|
const short1 = shortPacked >> 128n;
|
|
20762
20951
|
const long0 = longPacked & MASK_128;
|
|
20763
20952
|
const long1 = longPacked >> 128n;
|
|
20764
|
-
const
|
|
20765
|
-
|
|
20766
|
-
accSettled0 += sortedSettled[settledIdx].settled0;
|
|
20767
|
-
accSettled1 += sortedSettled[settledIdx].settled1;
|
|
20768
|
-
settledIdx++;
|
|
20769
|
-
}
|
|
20770
|
-
const premia0 = short0 - long0 - accSettled0;
|
|
20771
|
-
const premia1 = short1 - long1 - accSettled1;
|
|
20953
|
+
const premia0 = short0 - long0;
|
|
20954
|
+
const premia1 = short1 - long1;
|
|
20772
20955
|
let uniswapFees0 = 0n;
|
|
20773
20956
|
let uniswapFees1 = 0n;
|
|
20774
20957
|
if (uniswapData) {
|
|
@@ -20787,6 +20970,7 @@ async function getStreamiaHistory(params) {
|
|
|
20787
20970
|
token0: premia0,
|
|
20788
20971
|
token1: premia1
|
|
20789
20972
|
},
|
|
20973
|
+
cumulativePanopticPremia: cumulativePremiaByInputIndex[i],
|
|
20790
20974
|
uniswapFees: {
|
|
20791
20975
|
token0: uniswapFees0,
|
|
20792
20976
|
token1: uniswapFees1
|
|
@@ -21768,6 +21952,31 @@ async function fetchSlot0(client, blockNumber, poolConfig) {
|
|
|
21768
21952
|
}
|
|
21769
21953
|
}
|
|
21770
21954
|
|
|
21955
|
+
//#endregion
|
|
21956
|
+
//#region src/panoptic/v2/reads/positionSizes.ts
|
|
21957
|
+
const BIT_MASK_128$1 = (1n << 128n) - 1n;
|
|
21958
|
+
/**
|
|
21959
|
+
* Returns the current stored positionSize for each tokenId, in the same order
|
|
21960
|
+
* as the input `positionIdList`. Reverts (via the contract) if any tokenId is
|
|
21961
|
+
* not held by `account`.
|
|
21962
|
+
*/
|
|
21963
|
+
async function getCurrentPositionSizes(params) {
|
|
21964
|
+
const { client, poolAddress, account, positionIdList, blockNumber } = params;
|
|
21965
|
+
if (positionIdList.length === 0) return [];
|
|
21966
|
+
const [, , positionBalances] = await client.readContract({
|
|
21967
|
+
address: poolAddress,
|
|
21968
|
+
abi: panopticPoolV2Abi,
|
|
21969
|
+
functionName: "getFullPositionsData",
|
|
21970
|
+
args: [
|
|
21971
|
+
account,
|
|
21972
|
+
false,
|
|
21973
|
+
positionIdList
|
|
21974
|
+
],
|
|
21975
|
+
blockNumber
|
|
21976
|
+
});
|
|
21977
|
+
return positionBalances.map((packed) => packed & BIT_MASK_128$1);
|
|
21978
|
+
}
|
|
21979
|
+
|
|
21771
21980
|
//#endregion
|
|
21772
21981
|
//#region src/panoptic/v2/reads/enrichment.ts
|
|
21773
21982
|
/**
|
|
@@ -23801,8 +24010,14 @@ async function forceExerciseAndWait(params) {
|
|
|
23801
24010
|
* ```
|
|
23802
24011
|
*/
|
|
23803
24012
|
async function settleAccumulatedPremia(params) {
|
|
23804
|
-
const { client, walletClient, account, poolAddress, positionIdList, usePremiaAsCollateral = false, builderCode = 0n, txOverrides } = params;
|
|
23805
|
-
|
|
24013
|
+
const { client, walletClient, account, poolAddress, positionIdList, finalPositionIdList, positionSizes: providedSizes, usePremiaAsCollateral = false, builderCode = 0n, txOverrides } = params;
|
|
24014
|
+
if (providedSizes && providedSizes.length !== positionIdList.length) throw new PanopticError("settleAccumulatedPremia: positionSizes length must match positionIdList");
|
|
24015
|
+
const positionSizes = providedSizes ?? await getCurrentPositionSizes({
|
|
24016
|
+
client,
|
|
24017
|
+
poolAddress,
|
|
24018
|
+
account,
|
|
24019
|
+
positionIdList
|
|
24020
|
+
});
|
|
23806
24021
|
const tickAndSpreadLimits = positionIdList.map(() => [
|
|
23807
24022
|
-887272n,
|
|
23808
24023
|
887272n,
|
|
@@ -23817,7 +24032,7 @@ async function settleAccumulatedPremia(params) {
|
|
|
23817
24032
|
functionName: "dispatch",
|
|
23818
24033
|
args: [
|
|
23819
24034
|
positionIdList,
|
|
23820
|
-
positionIdList,
|
|
24035
|
+
finalPositionIdList ?? positionIdList,
|
|
23821
24036
|
positionSizes.map((s) => BigInt(s)),
|
|
23822
24037
|
tickAndSpreadLimits.map((t) => [
|
|
23823
24038
|
Number(t[0]),
|
|
@@ -25398,14 +25613,21 @@ const multicallAbi = [{
|
|
|
25398
25613
|
* @returns Simulation result with settlement data or error
|
|
25399
25614
|
*/
|
|
25400
25615
|
async function simulateSettle(params) {
|
|
25401
|
-
const { client, poolAddress, account, positionIdList, tokenId, blockNumber } = params;
|
|
25616
|
+
const { client, poolAddress, account, positionIdList, finalPositionIdList, positionSizes: providedSizes, tokenId, blockNumber } = params;
|
|
25402
25617
|
const targetBlockNumber = blockNumber ?? await client.getBlockNumber();
|
|
25403
25618
|
const metaPromise = getBlockMeta({
|
|
25404
25619
|
client,
|
|
25405
25620
|
blockNumber: targetBlockNumber
|
|
25406
25621
|
});
|
|
25407
25622
|
try {
|
|
25408
|
-
|
|
25623
|
+
if (providedSizes && providedSizes.length !== positionIdList.length) throw new PanopticError("simulateSettle: positionSizes length must match positionIdList");
|
|
25624
|
+
const positionSizes = providedSizes ?? await getCurrentPositionSizes({
|
|
25625
|
+
client,
|
|
25626
|
+
poolAddress,
|
|
25627
|
+
account,
|
|
25628
|
+
positionIdList,
|
|
25629
|
+
blockNumber: targetBlockNumber
|
|
25630
|
+
});
|
|
25409
25631
|
const tickAndSpreadLimits = positionIdList.map(() => [
|
|
25410
25632
|
-887272n,
|
|
25411
25633
|
887272n,
|
|
@@ -25416,7 +25638,7 @@ async function simulateSettle(params) {
|
|
|
25416
25638
|
functionName: "dispatch",
|
|
25417
25639
|
args: [
|
|
25418
25640
|
positionIdList,
|
|
25419
|
-
positionIdList,
|
|
25641
|
+
finalPositionIdList ?? positionIdList,
|
|
25420
25642
|
positionSizes.map((s) => BigInt(s)),
|
|
25421
25643
|
tickAndSpreadLimits.map((t) => [
|
|
25422
25644
|
Number(t[0]),
|
|
@@ -25448,8 +25670,8 @@ async function simulateSettle(params) {
|
|
|
25448
25670
|
});
|
|
25449
25671
|
const _meta = await metaPromise;
|
|
25450
25672
|
const data = {
|
|
25451
|
-
premiaReceived0: tokenFlow.delta0
|
|
25452
|
-
premiaReceived1: tokenFlow.delta1
|
|
25673
|
+
premiaReceived0: tokenFlow.delta0,
|
|
25674
|
+
premiaReceived1: tokenFlow.delta1,
|
|
25453
25675
|
postCollateral0: tokenFlow.balanceAfter0,
|
|
25454
25676
|
postCollateral1: tokenFlow.balanceAfter1,
|
|
25455
25677
|
forfeitAmounts
|
|
@@ -27871,5 +28093,5 @@ const VAULT_DISPLAY_NAME_RESOLVERS_PER_CHAIN = {
|
|
|
27871
28093
|
};
|
|
27872
28094
|
|
|
27873
28095
|
//#endregion
|
|
27874
|
-
export { AccountInsolventError, AlreadyInitializedError, BORROW_INDEX_BITS, BPS_DENOMINATOR, BPS_SCALE, BatchValidationError, BelowMinimumRedemptionError, CastingError, ChunkHasZeroLiquidityError, ChunkLimitError, CrossPoolError, DEFAULT_MAX_SPREAD, DEFAULT_MINT_BUFFER, DEFAULT_MIN_SWAP_RATIO_BPS, DEFAULT_RECONNECT_CONFIG, DEFAULT_VEGOID, DepositTooLargeError, DuplicateTokenIdError, EffectiveLiquidityAboveThresholdError, ExceedsMaximumRedemptionError, InputListFailError, InsufficientCreditLiquidityError, InvalidBuilderCodeError, InvalidHistoryRangeError, InvalidTickBoundError, InvalidTickError, InvalidTokenIdParameterError, InvalidUniswapCallbackError, LEG_BITS, LEG_LIMITS, LEG_MASKS, LengthMismatchError, LiquidityTooHighError, LoanSlotExhaustedError, MARKET_EPOCH_BITS, MARKET_EPOCH_SHIFT, MAX_TICK, MAX_TRACKED_CHUNKS, MINT_BUFFER, MINT_BUFFER_DENOMINATOR, MIN_TICK, MaxRetriesExceededError, MissingPositionIdsError, NetLiquidityZeroError, NetworkMismatchError, NoLegsExercisableError, NotALongLegError, NotBuilderError, NotEnoughLiquidityInChunkError, NotEnoughTokensError, NotGuardianError, NotMarginCalledError, NotPanopticPoolError, ORACLE_EPOCH_SECONDS, OracleRateLimitedError, PanopticError, PanopticHelperNotDeployedError, PanopticValidationError, PoolNotInitializedError, PositionCountNotZeroError, PositionNotOwnedError, PositionSnapshotNotFoundError, PositionTooLargeError, PriceBoundFailError, PriceImpactTooLargeError, ProviderLagError, RATE_AT_TARGET_BITS, REORG_DEPTH, REQUIRED_BASE_ERROR_SENTINEL, ReentrancyError, RpcError, RpcResponseError, SCHEMA_VERSION, SECONDS_PER_YEAR, STANDARD_TICK_WIDTHS, STORAGE_PREFIX, SafeModeError, StaleDataError, StaleOracleError, SwapTokenMismatchError, SyncTimeoutError, TOKEN_ID_BITS, TokenIdHasZeroLegsError, TooManyLegsOpenError, TransferFailedError, UNREALIZED_INTEREST_BITS, UTILIZATION_DENOMINATOR, UnauthorizedUniswapCallbackError, UnderOverFlowError, UnhealthyPoolError, WAD, WrongPoolIdError, WrongUniswapPoolError, ZERO_COLLATERAL, ZERO_VALUATION, ZeroAddressError, ZeroCollateralRequirementError, addLegToTokenId, addPendingPosition, addTrackedChunks, annualizePerSecondRateWad, applyMintBuffer, applyMintBufferPerToken, apportion, approve, approveAndWait, approvePool, assertCanBurn, assertCanForceExercise, assertCanLiquidate, assertCanMint, assertFresh, assertHealthy, assertTradeable, borrow, borrowAndWait, buildBatchDispatchArgs, buildCreditSwapCall, buildCreditWrappedDispatch, buildOpenPositionCalldata, buildSfpmSwapCalldata, buildSfpmSwapPlan, buildTokenShortfallRecoveryDispatch, buildUniqueCredit, buildUniqueLoan, buildUniqueWidthZeroLeg, calculateAccountGreeksPure, calculatePortfolioDelta, calculatePortfolioGamma, calculatePortfolioGreeks, calculatePortfolioValue, calculatePositionDelta, calculatePositionDeltaDebtOnly, calculatePositionDeltaWithSwap, calculatePositionGamma, calculatePositionGreeks, calculatePositionValue, calculateResyncBlock, calculateSpreadWad, cancelTransaction, checkApproval, checkCollateralAcrossTicks, classifyStrategyGroups, cleanupStalePendingPositions, clearCheckpoint, clearPendingPositions, clearTrackedChunks, clearTrackedPositions, clearTradeHistory, closePosition, closePositionAndWait, collateralRuleKindFor, collateralTrackerV2Abi, computeV4PoolId, confirmPendingPosition, convertToAssets, convertToShares, countLegs, createEventPoller, createEventSubscription, createFileStorage, createFlowNeutralTokenId, createMemoryStorage, createNonceManager, createPoolFormatters, createTokenIdBuilder, decodeAllDispatchCalldata, decodeAllLegs, decodeDispatchCalldata, decodeLeftRightSigned, decodeLeftRightUnsigned, decodeLeg, decodeOraclePack, decodeOracleRiskParameters, decodeOracleTiming, decodePanopticTokenURI, decodePoolId, decodeTickSpacing, decodeTokenId, decodeVegoid, deployNewPool, deployNewPoolAndWait, deposit, depositAndWait, deriveSupplyRatePerSecWad, detectReorg, diagnoseOracleSafeMode, dispatch, dispatchAndWait, encodeLeg, encodePoolId, encodePoolKeyBytes, encodeV3PoolKeyBytes, encodeV4PoolId, ensureSfpmV3PoolInitialized, estimateBlockNumbers, estimateCollateralBreakdown, estimateCollateralRequired, executeBatchDispatch, executeBatchDispatchAndWait, failPendingPosition, feesFromFeeGrowthDelta, fetchPoolId, fetchSfpmV3PoolId, forceExercise, forceExerciseAndWait, formatBlockNumber, formatBps, formatCompact, formatDatetime, formatDuration, formatDurationSeconds, formatFeeTier, formatGas, formatGwei, formatPerSecondRateWadAsAprPct, formatPerSecondRateWadAsApyPct, formatPoolIdHex, formatPriceRange, formatRateWad, formatRatioPercent, formatTick, formatTickRange, formatTimestamp, formatTimestampLocale, formatTokenAmount, formatTokenAmountSigned, formatTokenDelta, formatTokenFlow, formatTokenIdHex, formatTokenIdShort, formatTxHash, formatUtilization, formatWad, formatWadPercent, formatWadSigned, formatWei, getAccountBuyingPower, getAccountCollateral, getAccountGreeks, getAccountHistory, getAccountPremia, getAccountSummaryBasic, getAccountSummaryRisk, getAssetIndex, getBlockMeta, getChainDeployment, getChunkLiquidities, getChunkSpreads, getClosedPositions, getClosedPositionsKey, getCollateralAddresses, getCollateralData, getCollateralSharePrices, getCollateralTotalAssetsBatch, getCurrentRates, getDeltaHedgeParams, getEnforcedTickLimits, getFactoryConstructMetadata, getFactoryOwnerOf, getFactoryTokenURI, getGuardianUnlockState, getInterestState, getIrmCurrent, getIrmCurve, getItmAmounts, getLegDelta, getLegDeltaInVaultFrame, getLegGamma, getLegNetValueWidth0, getLegValue, getLiquidationPrices, getMarginBuffer, getMaxPositionSize, getMaxRedeem, getMaxWithdrawable, getNativeTokenPrice, getNetLiquidationValue, getNetLiquidationValues, getNotEnoughTokensError, getOpenPositionIds, getOpenPositionPreview, getOracleRiskParameters, getOracleState, getPanopticPoolAddress, getPanopticPoolFromPoolId, getPendingPositions, getPendingPositionsKey, getPool, getPoolDeploymentBlock, getPoolDisplayId, getPoolLiquidities, getPoolMetaKey, getPoolMetadata, getPoolPrefix, getPortfolioValue, getPosition, getPositionChunkData, getPositionEnrichmentData, getPositionGreeks, getPositionMetaKey, getPositions, getPositionsKey, getPositionsWithPremia, getPriceHistory, getPricesAtTick, getRealizedPnL, getRequiredCreditForITM, getRiskParameters, getSafeMode, getSchemaVersionKey, getStreamiaHistory, getSyncCheckpointKey, getSyncStatus, getTickSpacing, getTokenListId, getTrackedChunks, getTrackedChunksKey, getTrackedPositionIds, getTradeHistory, getUniswapFeeHistory, getUniswapV3LpPositionState, getUniswapV3PoolFromId, getUniswapV3PoolInfo, getUniswapV3PoolLiquidities, getUniswapV4LpPositionState, getUniswapV4PoolBasicState, getUniswapV4PoolInfo, getUniswapV4PoolKeyFromId, getUniswapV4PoolLiquidities, getUtilization, hasLoanOrCredit, hasLongLeg, interpolateBlocks, isCall, isCredit, isCreditLeg, isDefinedRisk, isGasError, isInputListFailError, isLiquidatable, isLoan, isLoanLeg, isNonceError, isPanopticErrorType, isPositionTracked, isRetryableRpcError, isShortOnly, isSpread, isSupportedChain, isolateGroupTokenId, jsonSerializer, liquidate, liquidateAndWait, loadCheckpoint, minePoolAddress, mint, mintAndWait, mintableAfterBuffer, multicallRead, openPosition, openPositionAndWait, optimizeTokenIdRiskPartners, oracleEpochAt, packMarketState, panopticPoolV2Abi, parseBps, parseCollateralLog, parsePanopticError, parsePoolLog, parseTokenAmount, parseTokenListId, parseWad, pokeOracle, pokeOracleAndWait, previewBorrow, previewDeposit, previewMint, previewRedeem, previewUnwrap, previewWithdraw, previewWrap, priceToTick, publicBroadcaster, quoteOneTokenFlow, quoteSfpmSwap, quoteTokenShortfallRecovery, quoteV3ExactIn, ratePerSecWadToAprPct, reconstructFromEvents, recoverSnapshot, recoverSnapshotFromTx, redeem, redeemAndWait, removeTrackedChunks, repay, repayAndWait, requireChainDeployment, resolveBlockNumbers, resolvePanopticPoolFromPoolId, resolveTokenIndex, resolveUniswapV4PoolKey, riskEngineAbi, rollPosition, rollPositionAndWait, roundToTickSpacing, saveCheckpoint, saveClosedPosition, scanChunks, selectDispatchForAccount, settleAccumulatedPremia, settleAccumulatedPremiaAndWait, simulateBatchDispatch, simulateClosePosition, simulateDeployNewPool, simulateDeposit, simulateDispatch, simulateForceExercise, simulateLiquidate, simulateOpenPosition, simulateSFPMBurn, simulateSFPMMint, simulateSettle, simulateSwapExactIn, simulateSwapExactOut, simulateWithTokenFlow, simulateWithdraw, slippageBpsToTickDistance, smartRepay, smartRepayAndWait, speedUpTransaction, sqrtPriceX96ToPriceDecimalScaled, sqrtPriceX96ToTick, supply, supplyAndWait, swapExactIn, swapExactInAndWait, swapExactOut, swapExactOutAndWait, syncPositions, tickLimits, tickToPrice, tickToPriceDecimalScaled, tickToSqrtPriceX96, toVaultFrameAtTick, truncateAddress, unsupply, unsupplyAndWait, unwrapWeth, unwrapWethAndWait, unwrapXstock, unwrapXstockAndWait, utilizationBpsToWad, utilizationPctToWad, validateBatch, validateBuilderCode, validatePoolId, verifyBlockContinuity, watchEvents, wethWrapAbi, withdraw, withdrawAndWait, withdrawWithPositions, withdrawWithPositionsAndWait, wrapEth, wrapEthAndWait, wrapXstock, wrapXstockAndWait, xstockWrapperAbi };
|
|
28096
|
+
export { AccountInsolventError, AlreadyInitializedError, BORROW_INDEX_BITS, BPS_DENOMINATOR, BPS_SCALE, BatchValidationError, BelowMinimumRedemptionError, CastingError, ChunkHasZeroLiquidityError, ChunkLimitError, CrossPoolError, DEFAULT_MAX_SPREAD, DEFAULT_MINT_BUFFER, DEFAULT_MIN_SWAP_RATIO_BPS, DEFAULT_RECONNECT_CONFIG, DEFAULT_VEGOID, DepositTooLargeError, DuplicateTokenIdError, EffectiveLiquidityAboveThresholdError, ExceedsMaximumRedemptionError, InputListFailError, InsufficientCreditLiquidityError, InvalidBuilderCodeError, InvalidHistoryRangeError, InvalidTickBoundError, InvalidTickError, InvalidTokenIdParameterError, InvalidUniswapCallbackError, LEG_BITS, LEG_LIMITS, LEG_MASKS, LengthMismatchError, LiquidityTooHighError, LoanSlotExhaustedError, MARKET_EPOCH_BITS, MARKET_EPOCH_SHIFT, MAX_TICK, MAX_TRACKED_CHUNKS, MINT_BUFFER, MINT_BUFFER_DENOMINATOR, MIN_TICK, MaxRetriesExceededError, MissingPositionIdsError, NetLiquidityZeroError, NetworkMismatchError, NoLegsExercisableError, NotALongLegError, NotBuilderError, NotEnoughLiquidityInChunkError, NotEnoughTokensError, NotGuardianError, NotMarginCalledError, NotPanopticPoolError, ORACLE_EPOCH_SECONDS, OracleRateLimitedError, PanopticError, PanopticHelperNotDeployedError, PanopticValidationError, PoolNotInitializedError, PositionCountNotZeroError, PositionNotOwnedError, PositionSnapshotNotFoundError, PositionTooLargeError, PriceBoundFailError, PriceImpactTooLargeError, ProviderLagError, RATE_AT_TARGET_BITS, REORG_DEPTH, REQUIRED_BASE_ERROR_SENTINEL, ReentrancyError, RpcError, RpcResponseError, SCHEMA_VERSION, SECONDS_PER_YEAR, STANDARD_TICK_WIDTHS, STORAGE_PREFIX, SafeModeError, StaleDataError, StaleOracleError, SwapTokenMismatchError, SyncTimeoutError, TOKEN_ID_BITS, TokenIdHasZeroLegsError, TooManyLegsOpenError, TransferFailedError, UNREALIZED_INTEREST_BITS, UTILIZATION_DENOMINATOR, UnauthorizedUniswapCallbackError, UnderOverFlowError, UnhealthyPoolError, WAD, WrongPoolIdError, WrongUniswapPoolError, ZERO_COLLATERAL, ZERO_VALUATION, ZeroAddressError, ZeroCollateralRequirementError, addLegToTokenId, addPendingPosition, addTrackedChunks, annualizePerSecondRateWad, applyMintBuffer, applyMintBufferPerToken, apportion, approve, approveAndWait, approvePool, assertCanBurn, assertCanForceExercise, assertCanLiquidate, assertCanMint, assertFresh, assertHealthy, assertTradeable, borrow, borrowAndWait, buildBatchDispatchArgs, buildCreditSwapCall, buildCreditWrappedDispatch, buildOpenPositionCalldata, buildSfpmSwapCalldata, buildSfpmSwapPlan, buildTokenShortfallRecoveryDispatch, buildUniqueCredit, buildUniqueLoan, buildUniqueWidthZeroLeg, calculateAccountGreeksPure, calculatePortfolioDelta, calculatePortfolioGamma, calculatePortfolioGreeks, calculatePortfolioValue, calculatePositionDelta, calculatePositionDeltaDebtOnly, calculatePositionDeltaWithSwap, calculatePositionGamma, calculatePositionGreeks, calculatePositionValue, calculateResyncBlock, calculateSpreadWad, cancelTransaction, checkApproval, checkCollateralAcrossTicks, classifyStrategyGroups, cleanupStalePendingPositions, clearCheckpoint, clearPendingPositions, clearTrackedChunks, clearTrackedPositions, clearTradeHistory, closePosition, closePositionAndWait, collateralRuleKindFor, collateralTrackerV2Abi, computeV4PoolId, confirmPendingPosition, convertToAssets, convertToShares, countLegs, createEventPoller, createEventSubscription, createFileStorage, createFlowNeutralTokenId, createMemoryStorage, createNonceManager, createPoolFormatters, createTokenIdBuilder, decodeAllDispatchCalldata, decodeAllLegs, decodeDispatchCalldata, decodeLeftRightSigned, decodeLeftRightUnsigned, decodeLeg, decodeOraclePack, decodeOracleRiskParameters, decodeOracleTiming, decodePanopticTokenURI, decodePoolId, decodeTickSpacing, decodeTokenId, decodeVegoid, deployNewPool, deployNewPoolAndWait, deposit, depositAndWait, deriveSupplyRatePerSecWad, deriveUniqueTokenId, detectReorg, diagnoseOracleSafeMode, dispatch, dispatchAndWait, encodeLeg, encodePoolId, encodePoolKeyBytes, encodeV3PoolKeyBytes, encodeV4PoolId, ensureSfpmV3PoolInitialized, estimateBlockNumbers, estimateCollateralBreakdown, estimateCollateralRequired, executeBatchDispatch, executeBatchDispatchAndWait, failPendingPosition, feesFromFeeGrowthDelta, fetchPoolId, fetchSfpmV3PoolId, forceExercise, forceExerciseAndWait, formatBlockNumber, formatBps, formatCompact, formatDatetime, formatDuration, formatDurationSeconds, formatFeeTier, formatGas, formatGwei, formatPerSecondRateWadAsAprPct, formatPerSecondRateWadAsApyPct, formatPoolIdHex, formatPriceRange, formatRateWad, formatRatioPercent, formatTick, formatTickRange, formatTimestamp, formatTimestampLocale, formatTokenAmount, formatTokenAmountSigned, formatTokenDelta, formatTokenFlow, formatTokenIdHex, formatTokenIdShort, formatTxHash, formatUtilization, formatWad, formatWadPercent, formatWadSigned, formatWei, getAccountBuyingPower, getAccountCollateral, getAccountGreeks, getAccountHistory, getAccountPremia, getAccountSummaryBasic, getAccountSummaryRisk, getAssetIndex, getBlockMeta, getChainDeployment, getChunkLiquidities, getChunkSpreads, getClosedPositions, getClosedPositionsKey, getCollateralAddresses, getCollateralData, getCollateralSharePrices, getCollateralTotalAssetsBatch, getCurrentRates, getDeltaHedgeParams, getEnforcedTickLimits, getFactoryConstructMetadata, getFactoryOwnerOf, getFactoryTokenURI, getGuardianUnlockState, getInterestState, getIrmCurrent, getIrmCurve, getItmAmounts, getLegDelta, getLegDeltaInVaultFrame, getLegGamma, getLegNetValueWidth0, getLegValue, getLiquidationPrices, getMarginBuffer, getMaxPositionSize, getMaxRedeem, getMaxWithdrawable, getNativeTokenPrice, getNetLiquidationValue, getNetLiquidationValues, getNotEnoughTokensError, getOpenPositionIds, getOpenPositionPreview, getOracleRiskParameters, getOracleState, getPanopticPoolAddress, getPanopticPoolFromPoolId, getPendingPositions, getPendingPositionsKey, getPool, getPoolDeploymentBlock, getPoolDisplayId, getPoolLiquidities, getPoolMetaKey, getPoolMetadata, getPoolPrefix, getPortfolioValue, getPosition, getPositionChunkData, getPositionEnrichmentData, getPositionGreeks, getPositionMetaKey, getPositions, getPositionsKey, getPositionsWithPremia, getPriceHistory, getPricesAtTick, getRealizedPnL, getRequiredCreditForITM, getRiskParameters, getSafeMode, getSchemaVersionKey, getStreamiaHistory, getSyncCheckpointKey, getSyncStatus, getTickSpacing, getTokenListId, getTrackedChunks, getTrackedChunksKey, getTrackedPositionIds, getTradeHistory, getUniswapFeeHistory, getUniswapV3LpPositionState, getUniswapV3PoolFromId, getUniswapV3PoolInfo, getUniswapV3PoolLiquidities, getUniswapV4LpPositionState, getUniswapV4PoolBasicState, getUniswapV4PoolInfo, getUniswapV4PoolKeyFromId, getUniswapV4PoolLiquidities, getUtilization, hasLoanOrCredit, hasLongLeg, interpolateBlocks, isCall, isCredit, isCreditLeg, isDefinedRisk, isGasError, isInputListFailError, isLiquidatable, isLoan, isLoanLeg, isNonceError, isPanopticErrorType, isPositionTracked, isRetryableRpcError, isShortOnly, isSpread, isSupportedChain, isolateGroupTokenId, jsonSerializer, liquidate, liquidateAndWait, loadCheckpoint, minePoolAddress, mint, mintAndWait, mintableAfterBuffer, multicallRead, openPosition, openPositionAndWait, optimizeTokenIdRiskPartners, oracleEpochAt, packMarketState, panopticPoolV2Abi, parseBps, parseCollateralLog, parsePanopticError, parsePoolLog, parseTokenAmount, parseTokenListId, parseWad, planDeriveStrategy, pokeOracle, pokeOracleAndWait, previewBorrow, previewDeposit, previewMint, previewRedeem, previewUnwrap, previewWithdraw, previewWrap, priceToTick, publicBroadcaster, quoteOneTokenFlow, quoteSfpmSwap, quoteTokenShortfallRecovery, quoteV3ExactIn, ratePerSecWadToAprPct, reconstructFromEvents, recoverSnapshot, recoverSnapshotFromTx, redeem, redeemAndWait, removeTrackedChunks, repay, repayAndWait, requireChainDeployment, resolveBlockNumbers, resolvePanopticPoolFromPoolId, resolveTokenIndex, resolveUniswapV4PoolKey, riskEngineAbi, rollPosition, rollPositionAndWait, roundToTickSpacing, saveCheckpoint, saveClosedPosition, scanChunks, selectDispatchForAccount, settleAccumulatedPremia, settleAccumulatedPremiaAndWait, simulateBatchDispatch, simulateClosePosition, simulateDeployNewPool, simulateDeposit, simulateDispatch, simulateForceExercise, simulateLiquidate, simulateOpenPosition, simulateSFPMBurn, simulateSFPMMint, simulateSettle, simulateSwapExactIn, simulateSwapExactOut, simulateWithTokenFlow, simulateWithdraw, slippageBpsToTickDistance, smartRepay, smartRepayAndWait, speedUpTransaction, sqrtPriceX96ToPriceDecimalScaled, sqrtPriceX96ToTick, supply, supplyAndWait, swapExactIn, swapExactInAndWait, swapExactOut, swapExactOutAndWait, syncPositions, tickLimits, tickToPrice, tickToPriceDecimalScaled, tickToSqrtPriceX96, toVaultFrameAtTick, truncateAddress, unsupply, unsupplyAndWait, unwrapWeth, unwrapWethAndWait, unwrapXstock, unwrapXstockAndWait, utilizationBpsToWad, utilizationPctToWad, validateBatch, validateBuilderCode, validatePoolId, verifyBlockContinuity, watchEvents, wethWrapAbi, withdraw, withdrawAndWait, withdrawWithPositions, withdrawWithPositionsAndWait, wrapEth, wrapEthAndWait, wrapXstock, wrapXstockAndWait, xstockWrapperAbi };
|
|
27875
28097
|
//# sourceMappingURL=index.js.map
|