@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
|
@@ -10027,1763 +10027,1922 @@ function hasLoanOrCredit(tokenId) {
|
|
|
10027
10027
|
}
|
|
10028
10028
|
|
|
10029
10029
|
//#endregion
|
|
10030
|
-
//#region src/panoptic/v2/
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
function
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
|
|
10043
|
-
|
|
10044
|
-
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
const
|
|
10061
|
-
|
|
10062
|
-
|
|
10063
|
-
|
|
10064
|
-
|
|
10030
|
+
//#region src/panoptic/v2/formatters/tick.ts
|
|
10031
|
+
const Q192$4 = 1n << 192n;
|
|
10032
|
+
const RAW_PRICE_PRECISION = 40n;
|
|
10033
|
+
function pow10(exponent) {
|
|
10034
|
+
if (exponent < 0n) throw new RangeError("Exponent must be non-negative");
|
|
10035
|
+
return 10n ** exponent;
|
|
10036
|
+
}
|
|
10037
|
+
function absBigint(value) {
|
|
10038
|
+
return value < 0n ? -value : value;
|
|
10039
|
+
}
|
|
10040
|
+
function trimTrailingZeros(value) {
|
|
10041
|
+
const dotIndex = value.indexOf(".");
|
|
10042
|
+
if (dotIndex === -1) return value;
|
|
10043
|
+
let end = value.length;
|
|
10044
|
+
while (end > dotIndex && value[end - 1] === "0") end -= 1;
|
|
10045
|
+
if (end === dotIndex + 1) end = dotIndex;
|
|
10046
|
+
return value.slice(0, end);
|
|
10047
|
+
}
|
|
10048
|
+
function formatRatio$3(numerator, denominator, precision) {
|
|
10049
|
+
if (precision < 0n) throw new RangeError("Precision must be non-negative");
|
|
10050
|
+
const sign = numerator < 0n ? "-" : "";
|
|
10051
|
+
const absNumerator = numerator < 0n ? -numerator : numerator;
|
|
10052
|
+
const scale = pow10(precision);
|
|
10053
|
+
const scaled = (absNumerator * scale + denominator / 2n) / denominator;
|
|
10054
|
+
const integerPart = scaled / scale;
|
|
10055
|
+
const fractionalPart = scaled % scale;
|
|
10056
|
+
if (precision === 0n) return `${sign}${integerPart}`;
|
|
10057
|
+
return `${sign}${integerPart}.${fractionalPart.toString().padStart(Number(precision), "0")}`;
|
|
10058
|
+
}
|
|
10059
|
+
function parseDecimalToFraction(value) {
|
|
10060
|
+
const trimmed = value.trim();
|
|
10061
|
+
if (trimmed.length === 0) throw new Error("Price must be a number");
|
|
10062
|
+
const isNegative = trimmed.startsWith("-");
|
|
10063
|
+
const unsigned = isNegative || trimmed.startsWith("+") ? trimmed.slice(1) : trimmed;
|
|
10064
|
+
const [basePart, exponentPart] = unsigned.toLowerCase().split("e");
|
|
10065
|
+
const [integerStr, fractionalStr = ""] = basePart.split(".");
|
|
10066
|
+
if (integerStr === "" && fractionalStr === "") throw new Error("Price must be a number");
|
|
10067
|
+
const integerDigits = integerStr === "" ? "0" : integerStr;
|
|
10068
|
+
const digits = `${integerDigits}${fractionalStr}`;
|
|
10069
|
+
let numerator = BigInt(digits === "" ? "0" : digits);
|
|
10070
|
+
let denominator = pow10(BigInt(fractionalStr.length));
|
|
10071
|
+
if (exponentPart !== void 0 && exponentPart !== "") {
|
|
10072
|
+
const exponent = BigInt(exponentPart);
|
|
10073
|
+
if (exponent > 0n) numerator *= pow10(exponent);
|
|
10074
|
+
else if (exponent < 0n) denominator *= pow10(-exponent);
|
|
10075
|
+
}
|
|
10076
|
+
if (isNegative) numerator = -numerator;
|
|
10065
10077
|
return {
|
|
10066
|
-
|
|
10067
|
-
|
|
10068
|
-
burnData
|
|
10078
|
+
numerator,
|
|
10079
|
+
denominator
|
|
10069
10080
|
};
|
|
10070
10081
|
}
|
|
10071
|
-
|
|
10072
|
-
|
|
10073
|
-
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
*
|
|
10077
|
-
* `initializeAMMPool` is permissionless and idempotent and **returns the poolId**
|
|
10078
|
-
* whether or not the pool was already registered, so a `simulateContract` call is
|
|
10079
|
-
* enough to learn the id without sending a transaction. Always resolve the id this
|
|
10080
|
-
* way rather than encoding it offline — the SFPM can collision-increment ids.
|
|
10081
|
-
*/
|
|
10082
|
-
async function fetchSfpmV3PoolId(params) {
|
|
10083
|
-
const { client, sfpmAddress, token0, token1, fee } = params;
|
|
10084
|
-
const vegoid$1 = params.vegoid ?? Number(DEFAULT_VEGOID);
|
|
10085
|
-
const { result } = await client.simulateContract({
|
|
10086
|
-
address: sfpmAddress,
|
|
10087
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10088
|
-
functionName: "initializeAMMPool",
|
|
10089
|
-
args: [
|
|
10090
|
-
token0,
|
|
10091
|
-
token1,
|
|
10092
|
-
fee,
|
|
10093
|
-
vegoid$1
|
|
10094
|
-
]
|
|
10095
|
-
});
|
|
10096
|
-
return BigInt(result);
|
|
10082
|
+
function compareRatios(leftNumerator, leftDenominator, rightNumerator, rightDenominator) {
|
|
10083
|
+
const left = leftNumerator * rightDenominator;
|
|
10084
|
+
const right = rightNumerator * leftDenominator;
|
|
10085
|
+
if (left === right) return 0;
|
|
10086
|
+
return left < right ? -1 : 1;
|
|
10097
10087
|
}
|
|
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
|
-
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
chain: wallet.chain ?? null,
|
|
10130
|
-
address: sfpmAddress,
|
|
10131
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10132
|
-
functionName: "initializeAMMPool",
|
|
10133
|
-
args: [
|
|
10134
|
-
token0,
|
|
10135
|
-
token1,
|
|
10136
|
-
fee,
|
|
10137
|
-
vegoid$1
|
|
10138
|
-
]
|
|
10139
|
-
});
|
|
10140
|
-
await client.waitForTransactionReceipt({ hash });
|
|
10141
|
-
initialized = true;
|
|
10142
|
-
resolved = await client.readContract({
|
|
10143
|
-
address: sfpmAddress,
|
|
10144
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10145
|
-
functionName: "getUniswapV3PoolFromId",
|
|
10146
|
-
args: [poolId]
|
|
10147
|
-
});
|
|
10148
|
-
}
|
|
10149
|
-
if (expectedPool !== void 0 && getAddress(resolved) !== getAddress(expectedPool)) throw new WrongUniswapPoolError(new PanopticError(`SFPM poolId ${poolId} resolves to ${resolved}, expected ${expectedPool}`));
|
|
10088
|
+
function tickToSqrtPriceX96(tick) {
|
|
10089
|
+
if (tick < MIN_TICK || tick > MAX_TICK) throw new RangeError("Tick out of bounds");
|
|
10090
|
+
const absTick = tick < 0n ? -tick : tick;
|
|
10091
|
+
let ratio = (absTick & 0x1n) !== 0n ? 0xfffcb933bd6fad37aa2d162d1a594001n : 0x100000000000000000000000000000000n;
|
|
10092
|
+
if ((absTick & 0x2n) !== 0n) ratio = ratio * 0xfff97272373d413259a46990580e213an >> 128n;
|
|
10093
|
+
if ((absTick & 0x4n) !== 0n) ratio = ratio * 0xfff2e50f5f656932ef12357cf3c7fdccn >> 128n;
|
|
10094
|
+
if ((absTick & 0x8n) !== 0n) ratio = ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0n >> 128n;
|
|
10095
|
+
if ((absTick & 0x10n) !== 0n) ratio = ratio * 0xffcb9843d60f6159c9db58835c926644n >> 128n;
|
|
10096
|
+
if ((absTick & 0x20n) !== 0n) ratio = ratio * 0xff973b41fa98c081472e6896dfb254c0n >> 128n;
|
|
10097
|
+
if ((absTick & 0x40n) !== 0n) ratio = ratio * 0xff2ea16466c96a3843ec78b326b52861n >> 128n;
|
|
10098
|
+
if ((absTick & 0x80n) !== 0n) ratio = ratio * 0xfe5dee046a99a2a811c461f1969c3053n >> 128n;
|
|
10099
|
+
if ((absTick & 0x100n) !== 0n) ratio = ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4n >> 128n;
|
|
10100
|
+
if ((absTick & 0x200n) !== 0n) ratio = ratio * 0xf987a7253ac413176f2b074cf7815e54n >> 128n;
|
|
10101
|
+
if ((absTick & 0x400n) !== 0n) ratio = ratio * 0xf3392b0822b70005940c7a398e4b70f3n >> 128n;
|
|
10102
|
+
if ((absTick & 0x800n) !== 0n) ratio = ratio * 0xe7159475a2c29b7443b29c7fa6e889d9n >> 128n;
|
|
10103
|
+
if ((absTick & 0x1000n) !== 0n) ratio = ratio * 0xd097f3bdfd2022b8845ad8f792aa5825n >> 128n;
|
|
10104
|
+
if ((absTick & 0x2000n) !== 0n) ratio = ratio * 0xa9f746462d870fdf8a65dc1f90e061e5n >> 128n;
|
|
10105
|
+
if ((absTick & 0x4000n) !== 0n) ratio = ratio * 0x70d869a156d2a1b890bb3df62baf32f7n >> 128n;
|
|
10106
|
+
if ((absTick & 0x8000n) !== 0n) ratio = ratio * 0x31be135f97d08fd981231505542fcfa6n >> 128n;
|
|
10107
|
+
if ((absTick & 0x10000n) !== 0n) ratio = ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9n >> 128n;
|
|
10108
|
+
if ((absTick & 0x20000n) !== 0n) ratio = ratio * 0x5d6af8dedb81196699c329225ee604n >> 128n;
|
|
10109
|
+
if ((absTick & 0x40000n) !== 0n) ratio = ratio * 0x2216e584f5fa1ea926041bedfe98n >> 128n;
|
|
10110
|
+
if ((absTick & 0x80000n) !== 0n) ratio = ratio * 0x48a170391f7dc42444e8fa2n >> 128n;
|
|
10111
|
+
if (tick > 0n) ratio = ((1n << 256n) - 1n) / ratio;
|
|
10112
|
+
const remainderMask = (1n << 32n) - 1n;
|
|
10113
|
+
const sqrtPriceX96 = (ratio >> 32n) + ((ratio & remainderMask) === 0n ? 0n : 1n);
|
|
10114
|
+
return sqrtPriceX96;
|
|
10115
|
+
}
|
|
10116
|
+
const MIN_SQRT_PRICE_X96 = tickToSqrtPriceX96(MIN_TICK);
|
|
10117
|
+
const MAX_SQRT_PRICE_X96 = tickToSqrtPriceX96(MAX_TICK);
|
|
10118
|
+
function getPriceRatioFromSqrtPriceX96(sqrtPriceX96) {
|
|
10150
10119
|
return {
|
|
10151
|
-
|
|
10152
|
-
|
|
10120
|
+
numerator: sqrtPriceX96 * sqrtPriceX96,
|
|
10121
|
+
denominator: Q192$4
|
|
10153
10122
|
};
|
|
10154
10123
|
}
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
const
|
|
10160
|
-
|
|
10161
|
-
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10167
|
-
|
|
10168
|
-
|
|
10169
|
-
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
let ticks = 0n;
|
|
10173
|
-
while (numerator * 10000n < denominator * (10000n + slippageBps)) {
|
|
10174
|
-
numerator *= 10001n;
|
|
10175
|
-
denominator *= 10000n;
|
|
10176
|
-
ticks += 1n;
|
|
10177
|
-
}
|
|
10178
|
-
return ticks;
|
|
10124
|
+
function getRawPriceRatio(tick) {
|
|
10125
|
+
return getPriceRatioFromSqrtPriceX96(tickToSqrtPriceX96(tick));
|
|
10126
|
+
}
|
|
10127
|
+
function adjustRatioForDecimals(numerator, denominator, decimals0, decimals1) {
|
|
10128
|
+
const diff = decimals0 - decimals1;
|
|
10129
|
+
if (diff === 0n) return {
|
|
10130
|
+
numerator,
|
|
10131
|
+
denominator
|
|
10132
|
+
};
|
|
10133
|
+
if (diff > 0n) return {
|
|
10134
|
+
numerator: numerator * pow10(diff),
|
|
10135
|
+
denominator
|
|
10136
|
+
};
|
|
10137
|
+
return {
|
|
10138
|
+
numerator,
|
|
10139
|
+
denominator: denominator * pow10(-diff)
|
|
10140
|
+
};
|
|
10179
10141
|
}
|
|
10180
10142
|
/**
|
|
10181
|
-
*
|
|
10143
|
+
* Convert a tick to a raw price string (no decimal adjustment).
|
|
10144
|
+
* Uses the formula: price = 1.0001^tick
|
|
10182
10145
|
*
|
|
10183
|
-
*
|
|
10184
|
-
*
|
|
10185
|
-
* exactly `positionSize` of the `tokenType` token when its call carries inverted
|
|
10186
|
-
* tick limits (`low > high`); the paired call uses a wide band and moves nothing.
|
|
10187
|
-
* - `exactIn`: swap on the **mint**; `tokenType` = the **input** token index.
|
|
10188
|
-
* - `exactOut`: swap on the **burn** (isLong flips → exact-output); `tokenType` = the
|
|
10189
|
-
* **output** token index.
|
|
10146
|
+
* This returns the raw price ratio, not adjusted for token decimals.
|
|
10147
|
+
* A fixed internal precision is used and trailing zeros are trimmed.
|
|
10190
10148
|
*
|
|
10191
|
-
*
|
|
10192
|
-
*
|
|
10149
|
+
* @param tick - The tick value
|
|
10150
|
+
* @returns Price string
|
|
10151
|
+
*
|
|
10152
|
+
* @example
|
|
10153
|
+
* ```typescript
|
|
10154
|
+
* tickToPrice(0n) // "1"
|
|
10155
|
+
* tickToPrice(1000n) // "1.105..." (approximately)
|
|
10156
|
+
* tickToPrice(-1000n) // "0.904..." (approximately)
|
|
10157
|
+
* tickToPrice(200000n) // Very large number
|
|
10158
|
+
* ```
|
|
10193
10159
|
*/
|
|
10194
|
-
function
|
|
10195
|
-
const {
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
if (distance < 1n) throw new PanopticError(`slippageBps ${slippageBps} yields a zero-width tick band; use a larger tolerance`);
|
|
10199
|
-
const tokenType = kind === "exactIn" ? zeroForOne ? 0n : 1n : zeroForOne ? 1n : 0n;
|
|
10200
|
-
const tokenId = createTokenIdBuilder(poolId).addLoan({
|
|
10201
|
-
asset: tokenType,
|
|
10202
|
-
tokenType,
|
|
10203
|
-
strike: 0n
|
|
10204
|
-
}).build();
|
|
10205
|
-
const d = Number(distance);
|
|
10206
|
-
const low = Math.min(Number(MAX_TICK), currentTick + d);
|
|
10207
|
-
const high = Math.max(Number(MIN_TICK), currentTick - d);
|
|
10208
|
-
if (low <= high) throw new PanopticError(`slippageBps ${slippageBps} at tick ${currentTick} yields a non-inverted band after clamping`);
|
|
10209
|
-
const invertedLimits = [low, high];
|
|
10210
|
-
const swapOn = kind === "exactIn" ? "mint" : "burn";
|
|
10211
|
-
return {
|
|
10212
|
-
sfpmAddress,
|
|
10213
|
-
poolAddress,
|
|
10214
|
-
poolKey: encodeAbiParameters([{ type: "address" }], [poolAddress]),
|
|
10215
|
-
tokenId,
|
|
10216
|
-
positionSize: amount,
|
|
10217
|
-
mintTickLimits: swapOn === "mint" ? invertedLimits : WIDE_LIMITS,
|
|
10218
|
-
burnTickLimits: swapOn === "burn" ? invertedLimits : WIDE_LIMITS,
|
|
10219
|
-
swapOn,
|
|
10220
|
-
kind
|
|
10221
|
-
};
|
|
10222
|
-
}
|
|
10223
|
-
|
|
10224
|
-
//#endregion
|
|
10225
|
-
//#region src/panoptic/v2/sfpmSwap/quote.ts
|
|
10226
|
-
const UINT128 = 1n << 128n;
|
|
10227
|
-
const INT128_MAX = (1n << 127n) - 1n;
|
|
10228
|
-
/** Extract the two signed 128-bit slots from a packed `LeftRightSigned` int256. */
|
|
10229
|
-
function unpackLeftRightSigned(packed) {
|
|
10230
|
-
const u = packed < 0n ? packed + (1n << 256n) : packed;
|
|
10231
|
-
const toInt128 = (half) => half > INT128_MAX ? half - UINT128 : half;
|
|
10232
|
-
return {
|
|
10233
|
-
right: toInt128(u & UINT128 - 1n),
|
|
10234
|
-
left: toInt128(u >> 128n & UINT128 - 1n)
|
|
10235
|
-
};
|
|
10236
|
-
}
|
|
10237
|
-
/** Wrap an unknown thrown value as a PanopticError, decoding Panoptic reverts when possible. */
|
|
10238
|
-
function toPanopticError(err) {
|
|
10239
|
-
if (err instanceof PanopticError) return err;
|
|
10240
|
-
const parsed = parsePanopticError(err);
|
|
10241
|
-
if (parsed) return parsed.error;
|
|
10242
|
-
return new PanopticError(err instanceof Error ? err.message : "SFPM swap simulation failed", err instanceof Error ? err : void 0);
|
|
10160
|
+
function tickToPrice(tick) {
|
|
10161
|
+
const { numerator, denominator } = getRawPriceRatio(tick);
|
|
10162
|
+
const price = formatRatio$3(numerator, denominator, RAW_PRICE_PRECISION);
|
|
10163
|
+
return trimTrailingZeros(price);
|
|
10243
10164
|
}
|
|
10244
10165
|
/**
|
|
10245
|
-
*
|
|
10246
|
-
*
|
|
10247
|
-
*
|
|
10166
|
+
* Convert a tick to a human-readable price with decimal scaling.
|
|
10167
|
+
* Uses the formula: price = 1.0001^tick * 10^(decimals0-decimals1)
|
|
10168
|
+
*
|
|
10169
|
+
* This adjusts for the different decimals of the two tokens in the pair.
|
|
10170
|
+
*
|
|
10171
|
+
* @param tick - The tick value
|
|
10172
|
+
* @param decimals0 - Decimals of token0
|
|
10173
|
+
* @param decimals1 - Decimals of token1
|
|
10174
|
+
* @param precision - Number of decimal places to display
|
|
10175
|
+
* @returns Formatted price string
|
|
10176
|
+
*
|
|
10177
|
+
* @example
|
|
10178
|
+
* ```typescript
|
|
10179
|
+
* // WETH/USDC pool (18 decimals / 6 decimals)
|
|
10180
|
+
* // At tick ~200000, price is roughly $2000 per ETH
|
|
10181
|
+
* tickToPriceDecimalScaled(200000n, 18n, 6n, 2n) // "2000.00" (approximately)
|
|
10182
|
+
*
|
|
10183
|
+
* // For token1/token0 price, swap the decimals
|
|
10184
|
+
* tickToPriceDecimalScaled(200000n, 6n, 18n, 6n) // "0.000500" (approximately)
|
|
10185
|
+
* ```
|
|
10248
10186
|
*/
|
|
10249
|
-
|
|
10250
|
-
const
|
|
10251
|
-
const {
|
|
10252
|
-
|
|
10253
|
-
client,
|
|
10254
|
-
blockNumber
|
|
10255
|
-
});
|
|
10256
|
-
try {
|
|
10257
|
-
const { result } = await client.simulateContract({
|
|
10258
|
-
account,
|
|
10259
|
-
address: plan.sfpmAddress,
|
|
10260
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10261
|
-
functionName: "multicall",
|
|
10262
|
-
args: [[mintData, burnData]],
|
|
10263
|
-
blockNumber,
|
|
10264
|
-
stateOverride
|
|
10265
|
-
});
|
|
10266
|
-
const swapIndex = plan.swapOn === "mint" ? 0 : 1;
|
|
10267
|
-
const decoded = decodeFunctionResult({
|
|
10268
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10269
|
-
functionName: plan.swapOn === "mint" ? "mintTokenizedPosition" : "burnTokenizedPosition",
|
|
10270
|
-
data: result[swapIndex]
|
|
10271
|
-
});
|
|
10272
|
-
const finalTick = Number(decoded[2]);
|
|
10273
|
-
const { right, left } = unpackLeftRightSigned(decoded[1]);
|
|
10274
|
-
const inSlot = [right, left].find((s) => s > 0n);
|
|
10275
|
-
const outSlot = [right, left].find((s) => s < 0n);
|
|
10276
|
-
if (inSlot === void 0 || outSlot === void 0) return {
|
|
10277
|
-
success: false,
|
|
10278
|
-
error: new PanopticError(`SFPM swap simulation moved no tokens (totalMoved=${decoded[1]})`),
|
|
10279
|
-
_meta
|
|
10280
|
-
};
|
|
10281
|
-
return {
|
|
10282
|
-
success: true,
|
|
10283
|
-
data: {
|
|
10284
|
-
amountIn: inSlot,
|
|
10285
|
-
amountOut: -outSlot,
|
|
10286
|
-
finalTick
|
|
10287
|
-
},
|
|
10288
|
-
gasEstimate: 0n,
|
|
10289
|
-
_meta
|
|
10290
|
-
};
|
|
10291
|
-
} catch (err) {
|
|
10292
|
-
return {
|
|
10293
|
-
success: false,
|
|
10294
|
-
error: toPanopticError(err),
|
|
10295
|
-
_meta
|
|
10296
|
-
};
|
|
10297
|
-
}
|
|
10187
|
+
function tickToPriceDecimalScaled(tick, decimals0, decimals1, precision) {
|
|
10188
|
+
const rawRatio = getRawPriceRatio(tick);
|
|
10189
|
+
const { numerator, denominator } = adjustRatioForDecimals(rawRatio.numerator, rawRatio.denominator, decimals0, decimals1);
|
|
10190
|
+
return formatRatio$3(numerator, denominator, precision);
|
|
10298
10191
|
}
|
|
10299
|
-
|
|
10300
|
-
//#endregion
|
|
10301
|
-
//#region src/uniswap/v4/abis/universalRouter.ts
|
|
10302
10192
|
/**
|
|
10303
|
-
*
|
|
10304
|
-
*
|
|
10193
|
+
* Convert a sqrtPriceX96 to a human-readable price with decimal scaling.
|
|
10194
|
+
*
|
|
10195
|
+
* Uses the formula: price = (sqrtPriceX96^2 / 2^192) * 10^(decimals0-decimals1)
|
|
10196
|
+
*
|
|
10197
|
+
* @param sqrtPriceX96 - The sqrt price in Q64.96 format
|
|
10198
|
+
* @param decimals0 - Decimals of token0
|
|
10199
|
+
* @param decimals1 - Decimals of token1
|
|
10200
|
+
* @param precision - Number of decimal places to display
|
|
10201
|
+
* @returns Formatted price string
|
|
10202
|
+
*
|
|
10203
|
+
* @example
|
|
10204
|
+
* ```typescript
|
|
10205
|
+
* sqrtPriceX96ToPriceDecimalScaled(2n ** 96n, 18n, 18n, 2n) // "1.00"
|
|
10206
|
+
* ```
|
|
10305
10207
|
*/
|
|
10306
|
-
|
|
10307
|
-
|
|
10308
|
-
|
|
10309
|
-
|
|
10310
|
-
|
|
10311
|
-
{
|
|
10312
|
-
name: "commands",
|
|
10313
|
-
type: "bytes"
|
|
10314
|
-
},
|
|
10315
|
-
{
|
|
10316
|
-
name: "inputs",
|
|
10317
|
-
type: "bytes[]"
|
|
10318
|
-
},
|
|
10319
|
-
{
|
|
10320
|
-
name: "deadline",
|
|
10321
|
-
type: "uint256"
|
|
10322
|
-
}
|
|
10323
|
-
],
|
|
10324
|
-
outputs: []
|
|
10325
|
-
}];
|
|
10326
|
-
|
|
10327
|
-
//#endregion
|
|
10328
|
-
//#region src/uniswap/v4/router/errors.ts
|
|
10208
|
+
function sqrtPriceX96ToPriceDecimalScaled(sqrtPriceX96, decimals0, decimals1, precision) {
|
|
10209
|
+
const rawRatio = getPriceRatioFromSqrtPriceX96(sqrtPriceX96);
|
|
10210
|
+
const { numerator, denominator } = adjustRatioForDecimals(rawRatio.numerator, rawRatio.denominator, decimals0, decimals1);
|
|
10211
|
+
return formatRatio$3(numerator, denominator, precision);
|
|
10212
|
+
}
|
|
10329
10213
|
/**
|
|
10330
|
-
*
|
|
10331
|
-
*
|
|
10214
|
+
* Convert a price to a tick value.
|
|
10215
|
+
*
|
|
10216
|
+
* @param price - The price string
|
|
10217
|
+
* @param decimals0 - Decimals of token0
|
|
10218
|
+
* @param decimals1 - Decimals of token1
|
|
10219
|
+
* @returns The tick value (rounded to nearest integer)
|
|
10220
|
+
*
|
|
10221
|
+
* @example
|
|
10222
|
+
* ```typescript
|
|
10223
|
+
* // WETH/USDC: What tick for $2000 per ETH?
|
|
10224
|
+
* priceToTick("2000", 18n, 6n) // ~200000n
|
|
10225
|
+
*
|
|
10226
|
+
* // Inverse: What tick for 0.0005 ETH per USDC?
|
|
10227
|
+
* priceToTick("0.0005", 6n, 18n) // ~200000n
|
|
10228
|
+
* ```
|
|
10332
10229
|
*/
|
|
10333
|
-
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
10230
|
+
function priceToTick(price, decimals0, decimals1) {
|
|
10231
|
+
const parsed = parseDecimalToFraction(price);
|
|
10232
|
+
if (parsed.numerator <= 0n) throw new Error("Price must be positive");
|
|
10233
|
+
let targetNumerator = parsed.numerator;
|
|
10234
|
+
let targetDenominator = parsed.denominator;
|
|
10235
|
+
const diff = decimals0 - decimals1;
|
|
10236
|
+
if (diff > 0n) targetDenominator *= pow10(diff);
|
|
10237
|
+
else if (diff < 0n) targetNumerator *= pow10(-diff);
|
|
10238
|
+
let low = MIN_TICK;
|
|
10239
|
+
let high = MAX_TICK;
|
|
10240
|
+
while (low <= high) {
|
|
10241
|
+
const mid = (low + high) / 2n;
|
|
10242
|
+
const { numerator, denominator } = getRawPriceRatio(mid);
|
|
10243
|
+
const cmp = compareRatios(numerator, denominator, targetNumerator, targetDenominator);
|
|
10244
|
+
if (cmp === 0) return mid;
|
|
10245
|
+
if (cmp < 0) low = mid + 1n;
|
|
10246
|
+
else high = mid - 1n;
|
|
10338
10247
|
}
|
|
10339
|
-
|
|
10248
|
+
const floorTick = high;
|
|
10249
|
+
const ceilTick = low;
|
|
10250
|
+
if (floorTick < MIN_TICK) return MIN_TICK;
|
|
10251
|
+
if (ceilTick > MAX_TICK) return MAX_TICK;
|
|
10252
|
+
const floorRatio = getRawPriceRatio(floorTick);
|
|
10253
|
+
const ceilRatio = getRawPriceRatio(ceilTick);
|
|
10254
|
+
const floorDiffNumerator = absBigint(targetNumerator * floorRatio.denominator - floorRatio.numerator * targetDenominator);
|
|
10255
|
+
const ceilDiffNumerator = absBigint(targetNumerator * ceilRatio.denominator - ceilRatio.numerator * targetDenominator);
|
|
10256
|
+
const floorDiffDenominator = targetDenominator * floorRatio.denominator;
|
|
10257
|
+
const ceilDiffDenominator = targetDenominator * ceilRatio.denominator;
|
|
10258
|
+
return floorDiffNumerator * ceilDiffDenominator <= ceilDiffNumerator * floorDiffDenominator ? floorTick : ceilTick;
|
|
10259
|
+
}
|
|
10340
10260
|
/**
|
|
10341
|
-
*
|
|
10261
|
+
* Convert a sqrtPriceX96 value to the nearest tick.
|
|
10262
|
+
*
|
|
10263
|
+
* @param sqrtPriceX96 - The sqrt price in Q64.96 format
|
|
10264
|
+
* @returns The tick value (rounded to nearest integer)
|
|
10265
|
+
*
|
|
10266
|
+
* @example
|
|
10267
|
+
* ```typescript
|
|
10268
|
+
* const tick = sqrtPriceX96ToTick(2n ** 96n) // 0n
|
|
10269
|
+
* ```
|
|
10342
10270
|
*/
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10349
|
-
|
|
10350
|
-
|
|
10351
|
-
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
*/
|
|
10355
|
-
var AmountExceedsUint128Error = class extends PanopticError {
|
|
10356
|
-
name = "AmountExceedsUint128Error";
|
|
10357
|
-
constructor(amount, cause) {
|
|
10358
|
-
super(`Amount ${amount} exceeds uint128 maximum`, cause);
|
|
10359
|
-
this.amount = amount;
|
|
10360
|
-
}
|
|
10361
|
-
};
|
|
10362
|
-
/**
|
|
10363
|
-
* A native-ETH swap needs a trailing Universal Router SWEEP to deliver the ETH
|
|
10364
|
-
* output (or refund the input overpay), but no `recipient` was supplied.
|
|
10365
|
-
*/
|
|
10366
|
-
var MissingSweepRecipientError = class extends PanopticError {
|
|
10367
|
-
name = "MissingSweepRecipientError";
|
|
10368
|
-
constructor(cause) {
|
|
10369
|
-
super("A recipient is required to sweep native ETH back to the user", cause);
|
|
10370
|
-
}
|
|
10371
|
-
};
|
|
10372
|
-
/**
|
|
10373
|
-
* The V4Quoter is not available for the chain (no fallback in v1).
|
|
10374
|
-
*/
|
|
10375
|
-
var QuoterUnavailableError = class extends PanopticError {
|
|
10376
|
-
name = "QuoterUnavailableError";
|
|
10377
|
-
constructor(chainId, cause) {
|
|
10378
|
-
super(`V4Quoter unavailable for chain ${chainId}`, cause);
|
|
10379
|
-
this.chainId = chainId;
|
|
10271
|
+
function sqrtPriceX96ToTick(sqrtPriceX96) {
|
|
10272
|
+
if (sqrtPriceX96 <= 0n) throw new Error("Sqrt price must be positive");
|
|
10273
|
+
if (sqrtPriceX96 < MIN_SQRT_PRICE_X96 || sqrtPriceX96 > MAX_SQRT_PRICE_X96) throw new RangeError("Sqrt price out of bounds");
|
|
10274
|
+
let low = MIN_TICK;
|
|
10275
|
+
let high = MAX_TICK;
|
|
10276
|
+
while (low <= high) {
|
|
10277
|
+
const mid = (low + high) / 2n;
|
|
10278
|
+
const midSqrt = tickToSqrtPriceX96(mid);
|
|
10279
|
+
if (midSqrt === sqrtPriceX96) return mid;
|
|
10280
|
+
if (midSqrt < sqrtPriceX96) low = mid + 1n;
|
|
10281
|
+
else high = mid - 1n;
|
|
10380
10282
|
}
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10385
|
-
const
|
|
10386
|
-
|
|
10387
|
-
|
|
10388
|
-
|
|
10283
|
+
const floorTick = high;
|
|
10284
|
+
const ceilTick = low;
|
|
10285
|
+
if (floorTick < MIN_TICK) return MIN_TICK;
|
|
10286
|
+
if (ceilTick > MAX_TICK) return MAX_TICK;
|
|
10287
|
+
const floorSqrt = tickToSqrtPriceX96(floorTick);
|
|
10288
|
+
const ceilSqrt = tickToSqrtPriceX96(ceilTick);
|
|
10289
|
+
const floorDiff = absBigint(sqrtPriceX96 - floorSqrt);
|
|
10290
|
+
const ceilDiff = absBigint(ceilSqrt - sqrtPriceX96);
|
|
10291
|
+
return floorDiff <= ceilDiff ? floorTick : ceilTick;
|
|
10292
|
+
}
|
|
10389
10293
|
/**
|
|
10390
|
-
*
|
|
10294
|
+
* Format a tick value for display.
|
|
10391
10295
|
*
|
|
10392
|
-
*
|
|
10393
|
-
*
|
|
10394
|
-
*
|
|
10395
|
-
|
|
10396
|
-
|
|
10397
|
-
|
|
10398
|
-
|
|
10399
|
-
|
|
10400
|
-
inputs: [{
|
|
10401
|
-
name: "params",
|
|
10402
|
-
type: "tuple",
|
|
10403
|
-
components: [
|
|
10404
|
-
{
|
|
10405
|
-
name: "tokenIn",
|
|
10406
|
-
type: "address"
|
|
10407
|
-
},
|
|
10408
|
-
{
|
|
10409
|
-
name: "tokenOut",
|
|
10410
|
-
type: "address"
|
|
10411
|
-
},
|
|
10412
|
-
{
|
|
10413
|
-
name: "amountIn",
|
|
10414
|
-
type: "uint256"
|
|
10415
|
-
},
|
|
10416
|
-
{
|
|
10417
|
-
name: "fee",
|
|
10418
|
-
type: "uint24"
|
|
10419
|
-
},
|
|
10420
|
-
{
|
|
10421
|
-
name: "sqrtPriceLimitX96",
|
|
10422
|
-
type: "uint160"
|
|
10423
|
-
}
|
|
10424
|
-
]
|
|
10425
|
-
}],
|
|
10426
|
-
outputs: [
|
|
10427
|
-
{
|
|
10428
|
-
name: "amountOut",
|
|
10429
|
-
type: "uint256"
|
|
10430
|
-
},
|
|
10431
|
-
{
|
|
10432
|
-
name: "sqrtPriceX96After",
|
|
10433
|
-
type: "uint160"
|
|
10434
|
-
},
|
|
10435
|
-
{
|
|
10436
|
-
name: "initializedTicksCrossed",
|
|
10437
|
-
type: "uint32"
|
|
10438
|
-
},
|
|
10439
|
-
{
|
|
10440
|
-
name: "gasEstimate",
|
|
10441
|
-
type: "uint256"
|
|
10442
|
-
}
|
|
10443
|
-
]
|
|
10444
|
-
}];
|
|
10445
|
-
|
|
10446
|
-
//#endregion
|
|
10447
|
-
//#region src/uniswap/v3/addresses.ts
|
|
10448
|
-
/**
|
|
10449
|
-
* Verified Uniswap v3 QuoterV2 addresses keyed by chainId. Add a chain only
|
|
10450
|
-
* after verifying against the canonical Uniswap v3 deployment listing.
|
|
10296
|
+
* @param tick - The tick value
|
|
10297
|
+
* @returns Formatted tick string
|
|
10298
|
+
*
|
|
10299
|
+
* @example
|
|
10300
|
+
* ```typescript
|
|
10301
|
+
* formatTick(200000n) // "200000"
|
|
10302
|
+
* formatTick(-50000n) // "-50000"
|
|
10303
|
+
* ```
|
|
10451
10304
|
*/
|
|
10452
|
-
|
|
10453
|
-
|
|
10454
|
-
|
|
10455
|
-
} };
|
|
10305
|
+
function formatTick(tick) {
|
|
10306
|
+
return tick.toString();
|
|
10307
|
+
}
|
|
10456
10308
|
/**
|
|
10457
|
-
*
|
|
10309
|
+
* Get the price at a specific tick, returning both token0/token1 and token1/token0 prices.
|
|
10458
10310
|
*
|
|
10459
|
-
* @
|
|
10460
|
-
*
|
|
10311
|
+
* @param tick - The tick value
|
|
10312
|
+
* @param decimals0 - Decimals of token0
|
|
10313
|
+
* @param decimals1 - Decimals of token1
|
|
10314
|
+
* @param precision - Number of decimal places to display
|
|
10315
|
+
* @returns Object with both price directions
|
|
10316
|
+
*
|
|
10317
|
+
* @example
|
|
10318
|
+
* ```typescript
|
|
10319
|
+
* const prices = getPricesAtTick(200000n, 18n, 6n, 2n)
|
|
10320
|
+
* // prices.token0PerToken1 = "0.00" (very small)
|
|
10321
|
+
* // prices.token1PerToken0 = "2000.00" (USDC per ETH)
|
|
10322
|
+
* ```
|
|
10461
10323
|
*/
|
|
10462
|
-
function
|
|
10463
|
-
const
|
|
10464
|
-
const
|
|
10465
|
-
|
|
10466
|
-
|
|
10467
|
-
|
|
10324
|
+
function getPricesAtTick(tick, decimals0, decimals1, precision) {
|
|
10325
|
+
const rawRatio = getRawPriceRatio(tick);
|
|
10326
|
+
const adjustedRatio = adjustRatioForDecimals(rawRatio.numerator, rawRatio.denominator, decimals0, decimals1);
|
|
10327
|
+
return {
|
|
10328
|
+
token0PerToken1: formatRatio$3(adjustedRatio.denominator, adjustedRatio.numerator, precision),
|
|
10329
|
+
token1PerToken0: formatRatio$3(adjustedRatio.numerator, adjustedRatio.denominator, precision)
|
|
10468
10330
|
};
|
|
10469
|
-
if (!merged.quoterV2 || !merged.nonfungiblePositionManager) throw new UnsupportedChainError(BigInt(id));
|
|
10470
|
-
return merged;
|
|
10471
10331
|
}
|
|
10472
|
-
|
|
10473
|
-
//#endregion
|
|
10474
|
-
//#region src/uniswap/v3/router/quote.ts
|
|
10475
|
-
const BPS_DENOMINATOR$5 = 10000n;
|
|
10476
|
-
const UINT128_MAX$3 = (1n << 128n) - 1n;
|
|
10477
10332
|
/**
|
|
10478
|
-
*
|
|
10479
|
-
*
|
|
10480
|
-
*
|
|
10333
|
+
* Format a tick range for display.
|
|
10334
|
+
*
|
|
10335
|
+
* @param tickLower - Lower tick
|
|
10336
|
+
* @param tickUpper - Upper tick
|
|
10337
|
+
* @returns Formatted tick range string
|
|
10338
|
+
*
|
|
10339
|
+
* @example
|
|
10340
|
+
* ```typescript
|
|
10341
|
+
* formatTickRange(-50000n, 200000n) // "-50000 - 200000"
|
|
10342
|
+
* ```
|
|
10481
10343
|
*/
|
|
10482
|
-
|
|
10483
|
-
|
|
10484
|
-
if (amountIn < 0n || amountIn > UINT128_MAX$3) throw new PanopticError(`amountIn ${amountIn} exceeds uint128 maximum`);
|
|
10485
|
-
if (slippageBps < 0n || slippageBps > BPS_DENOMINATOR$5) throw new PanopticError(`invalid slippageBps ${slippageBps}, must be 0..10000`);
|
|
10486
|
-
const { quoterV2 } = getUniswapV3Addresses(chainId, params.addresses);
|
|
10487
|
-
try {
|
|
10488
|
-
const { result } = await client.simulateContract({
|
|
10489
|
-
address: quoterV2,
|
|
10490
|
-
abi: quoterV2Abi,
|
|
10491
|
-
functionName: "quoteExactInputSingle",
|
|
10492
|
-
blockNumber,
|
|
10493
|
-
args: [{
|
|
10494
|
-
tokenIn,
|
|
10495
|
-
tokenOut,
|
|
10496
|
-
amountIn,
|
|
10497
|
-
fee: Number(fee),
|
|
10498
|
-
sqrtPriceLimitX96: 0n
|
|
10499
|
-
}]
|
|
10500
|
-
});
|
|
10501
|
-
const [amountOut, , , gasEstimate] = result;
|
|
10502
|
-
const amountOutMinimum = amountOut * (BPS_DENOMINATOR$5 - slippageBps) / BPS_DENOMINATOR$5;
|
|
10503
|
-
return {
|
|
10504
|
-
amountOut,
|
|
10505
|
-
amountOutMinimum,
|
|
10506
|
-
gasEstimate
|
|
10507
|
-
};
|
|
10508
|
-
} catch (err) {
|
|
10509
|
-
if (isRevert(err)) return null;
|
|
10510
|
-
throw err;
|
|
10511
|
-
}
|
|
10512
|
-
}
|
|
10513
|
-
/** True only for genuine contract reverts (missing pool / no liquidity). */
|
|
10514
|
-
function isRevert(err) {
|
|
10515
|
-
return err instanceof BaseError && err.walk((e) => e instanceof ContractFunctionRevertedError) instanceof ContractFunctionRevertedError;
|
|
10344
|
+
function formatTickRange(tickLower, tickUpper) {
|
|
10345
|
+
return `${tickLower} - ${tickUpper}`;
|
|
10516
10346
|
}
|
|
10517
|
-
|
|
10518
|
-
//#endregion
|
|
10519
|
-
//#region src/panoptic/v2/reads/sfpm.ts
|
|
10520
10347
|
/**
|
|
10521
|
-
*
|
|
10348
|
+
* Format a price range for display.
|
|
10522
10349
|
*
|
|
10523
|
-
*
|
|
10350
|
+
* @param tickLower - Lower tick
|
|
10351
|
+
* @param tickUpper - Upper tick
|
|
10352
|
+
* @param decimals0 - Decimals of token0
|
|
10353
|
+
* @param decimals1 - Decimals of token1
|
|
10354
|
+
* @param precision - Number of decimal places to display
|
|
10355
|
+
* @returns Formatted price range string
|
|
10356
|
+
*
|
|
10357
|
+
* @example
|
|
10358
|
+
* ```typescript
|
|
10359
|
+
* formatPriceRange(0n, 0n, 18n, 18n, 2n) // "1.00 - 1.00"
|
|
10360
|
+
* ```
|
|
10524
10361
|
*/
|
|
10525
|
-
|
|
10526
|
-
const
|
|
10527
|
-
|
|
10528
|
-
|
|
10529
|
-
abi: semiFungiblePositionManagerV3Abi,
|
|
10530
|
-
functionName: "getUniswapV3PoolFromId",
|
|
10531
|
-
args: [poolId]
|
|
10532
|
-
});
|
|
10362
|
+
function formatPriceRange(tickLower, tickUpper, decimals0, decimals1, precision) {
|
|
10363
|
+
const lower = tickToPriceDecimalScaled(tickLower, decimals0, decimals1, precision);
|
|
10364
|
+
const upper = tickToPriceDecimalScaled(tickUpper, decimals0, decimals1, precision);
|
|
10365
|
+
return `${lower} - ${upper}`;
|
|
10533
10366
|
}
|
|
10534
10367
|
/**
|
|
10535
|
-
*
|
|
10368
|
+
* Calculate the tick spacing for a given fee tier.
|
|
10536
10369
|
*
|
|
10537
|
-
*
|
|
10538
|
-
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
|
|
10544
|
-
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
|
|
10548
|
-
|
|
10549
|
-
|
|
10550
|
-
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
10370
|
+
* @param feeBps - Fee in basis points (e.g., 500n for 0.05%)
|
|
10371
|
+
* @returns Tick spacing
|
|
10372
|
+
*
|
|
10373
|
+
* @example
|
|
10374
|
+
* ```typescript
|
|
10375
|
+
* getTickSpacing(100n) // 1n (0.01% fee tier)
|
|
10376
|
+
* getTickSpacing(500n) // 10n (0.05% fee tier)
|
|
10377
|
+
* getTickSpacing(3000n) // 60n (0.30% fee tier)
|
|
10378
|
+
* getTickSpacing(10000n) // 200n (1.00% fee tier)
|
|
10379
|
+
* ```
|
|
10380
|
+
*/
|
|
10381
|
+
function getTickSpacing(feeBps) {
|
|
10382
|
+
switch (feeBps) {
|
|
10383
|
+
case 100n: return 1n;
|
|
10384
|
+
case 500n: return 10n;
|
|
10385
|
+
case 3000n: return 60n;
|
|
10386
|
+
case 10000n: return 200n;
|
|
10387
|
+
default: {
|
|
10388
|
+
const spacing = feeBps / 50n;
|
|
10389
|
+
return spacing > 1n ? spacing : 1n;
|
|
10390
|
+
}
|
|
10391
|
+
}
|
|
10554
10392
|
}
|
|
10555
10393
|
/**
|
|
10556
|
-
*
|
|
10394
|
+
* Round a tick to the nearest valid tick for a given tick spacing.
|
|
10557
10395
|
*
|
|
10558
|
-
* @param
|
|
10559
|
-
* @
|
|
10396
|
+
* @param tick - The tick to round
|
|
10397
|
+
* @param tickSpacing - The tick spacing
|
|
10398
|
+
* @returns Rounded tick
|
|
10399
|
+
*
|
|
10400
|
+
* @example
|
|
10401
|
+
* ```typescript
|
|
10402
|
+
* roundToTickSpacing(12345n, 10n) // 12340n
|
|
10403
|
+
* roundToTickSpacing(12345n, 60n) // 12360n
|
|
10404
|
+
* roundToTickSpacing(-12345n, 10n) // -12350n
|
|
10405
|
+
* ```
|
|
10560
10406
|
*/
|
|
10561
|
-
|
|
10562
|
-
const
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
args: [poolId]
|
|
10568
|
-
});
|
|
10569
|
-
return {
|
|
10570
|
-
minEnforcedTick: minTick,
|
|
10571
|
-
maxEnforcedTick: maxTick
|
|
10572
|
-
};
|
|
10407
|
+
function roundToTickSpacing(tick, tickSpacing) {
|
|
10408
|
+
const remainder = tick % tickSpacing;
|
|
10409
|
+
if (remainder === 0n) return tick;
|
|
10410
|
+
if (tick >= 0n) return remainder >= tickSpacing / 2n ? tick + (tickSpacing - remainder) : tick - remainder;
|
|
10411
|
+
const absRemainder = -remainder;
|
|
10412
|
+
return absRemainder >= tickSpacing / 2n ? tick - (tickSpacing - absRemainder) : tick + absRemainder;
|
|
10573
10413
|
}
|
|
10574
10414
|
/**
|
|
10575
|
-
*
|
|
10415
|
+
* Compute slippage-bounded tick limits around the current tick.
|
|
10576
10416
|
*
|
|
10577
|
-
*
|
|
10578
|
-
*
|
|
10417
|
+
* 1 tick ≈ 1 basis point (0.01 %) of price change, so a `toleranceBps`
|
|
10418
|
+
* of 500 allows roughly 5 % price movement. The result is clamped to
|
|
10419
|
+
* the protocol's `[MIN_TICK, MAX_TICK]` range.
|
|
10420
|
+
*
|
|
10421
|
+
* Useful for setting `tickLimitLow` / `tickLimitHigh` on `openPosition`
|
|
10422
|
+
* and `closePosition` to protect against MEV sandwiches and volatile
|
|
10423
|
+
* tick moves.
|
|
10424
|
+
*
|
|
10425
|
+
* @param currentTick - The current pool tick (must be within [MIN_TICK, MAX_TICK]).
|
|
10426
|
+
* @param toleranceBps - Slippage tolerance in basis points (≈ ticks). Must be non-negative.
|
|
10427
|
+
* @returns Clamped `{ low, high }` tick limits.
|
|
10428
|
+
* @throws {RangeError} If `toleranceBps` is negative or `currentTick` is out of bounds.
|
|
10429
|
+
*
|
|
10430
|
+
* @example
|
|
10431
|
+
* ```typescript
|
|
10432
|
+
* const { low, high } = tickLimits(200_000n, 500n)
|
|
10433
|
+
* // low = 199_500n
|
|
10434
|
+
* // high = 200_500n
|
|
10435
|
+
*
|
|
10436
|
+
* await openPosition({ ..., tickLimitLow: low, tickLimitHigh: high })
|
|
10437
|
+
* ```
|
|
10579
10438
|
*/
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
if (
|
|
10583
|
-
const
|
|
10584
|
-
|
|
10585
|
-
|
|
10586
|
-
|
|
10587
|
-
};
|
|
10588
|
-
const multicallResults = await client.multicall({
|
|
10589
|
-
contracts: chunks.map((chunk) => ({
|
|
10590
|
-
address: sfpmAddress,
|
|
10591
|
-
abi: semiFungiblePositionManagerV4Abi,
|
|
10592
|
-
functionName: "getAccountLiquidity",
|
|
10593
|
-
args: [
|
|
10594
|
-
poolKeyBytes,
|
|
10595
|
-
chunk.owner,
|
|
10596
|
-
chunk.tokenType,
|
|
10597
|
-
Number(chunk.tickLower),
|
|
10598
|
-
Number(chunk.tickUpper)
|
|
10599
|
-
]
|
|
10600
|
-
})),
|
|
10601
|
-
allowFailure: true
|
|
10602
|
-
});
|
|
10603
|
-
const results = multicallResults.map((result) => {
|
|
10604
|
-
if (result.status === "failure") return {
|
|
10605
|
-
netLiquidity: 0n,
|
|
10606
|
-
removedLiquidity: 0n,
|
|
10607
|
-
totalLiquidity: 0n,
|
|
10608
|
-
shortLiquidity: 0n,
|
|
10609
|
-
longLiquidity: 0n
|
|
10610
|
-
};
|
|
10611
|
-
const packed = result.result;
|
|
10612
|
-
const netLiquidity = packed & (1n << 128n) - 1n;
|
|
10613
|
-
const removedLiquidity = packed >> 128n;
|
|
10614
|
-
const totalLiquidity = netLiquidity + removedLiquidity;
|
|
10615
|
-
return {
|
|
10616
|
-
netLiquidity,
|
|
10617
|
-
removedLiquidity,
|
|
10618
|
-
totalLiquidity,
|
|
10619
|
-
shortLiquidity: totalLiquidity,
|
|
10620
|
-
longLiquidity: removedLiquidity
|
|
10621
|
-
};
|
|
10622
|
-
});
|
|
10439
|
+
function tickLimits(currentTick, toleranceBps) {
|
|
10440
|
+
if (toleranceBps < 0n) throw new RangeError(`toleranceBps must be non-negative, got ${toleranceBps}`);
|
|
10441
|
+
if (currentTick < MIN_TICK || currentTick > MAX_TICK) throw new RangeError(`currentTick ${currentTick} is out of bounds [${MIN_TICK}, ${MAX_TICK}]`);
|
|
10442
|
+
const rawLow = currentTick - toleranceBps;
|
|
10443
|
+
const rawHigh = currentTick + toleranceBps;
|
|
10444
|
+
const low = rawLow < MIN_TICK ? MIN_TICK : rawLow;
|
|
10445
|
+
const high = rawHigh > MAX_TICK ? MAX_TICK : rawHigh;
|
|
10446
|
+
if (low > high) throw new RangeError(`Computed tick limits are inverted: low ${low} > high ${high} (currentTick=${currentTick}, toleranceBps=${toleranceBps})`);
|
|
10623
10447
|
return {
|
|
10624
|
-
|
|
10625
|
-
|
|
10448
|
+
low,
|
|
10449
|
+
high
|
|
10626
10450
|
};
|
|
10627
10451
|
}
|
|
10628
10452
|
|
|
10629
10453
|
//#endregion
|
|
10630
|
-
//#region src/panoptic/v2/
|
|
10454
|
+
//#region src/panoptic/v2/tokenId/deriveUniqueTokenId.ts
|
|
10455
|
+
const POOL_ID_MASK$2 = (1n << 64n) - 1n;
|
|
10456
|
+
const MAX_LEGS = TOKEN_ID_BITS.MAX_LEGS;
|
|
10457
|
+
const MAX_OPTION_RATIO = LEG_LIMITS.MAX_RATIO;
|
|
10458
|
+
const Q192$3 = 1n << 192n;
|
|
10631
10459
|
/**
|
|
10632
|
-
*
|
|
10460
|
+
* Floor integer square root for bigints (Newton's method). Mirrors the isqrt
|
|
10461
|
+
* used in reads/collateralEstimate.ts (buildNeutralLeg).
|
|
10633
10462
|
*/
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
10641
|
-
|
|
10463
|
+
function isqrt$1(value) {
|
|
10464
|
+
if (value < 0n) throw new PanopticError("isqrt of negative number");
|
|
10465
|
+
if (value < 2n) return value;
|
|
10466
|
+
let x = value;
|
|
10467
|
+
let y = x + 1n >> 1n;
|
|
10468
|
+
while (y < x) {
|
|
10469
|
+
x = y;
|
|
10470
|
+
y = x + value / x >> 1n;
|
|
10471
|
+
}
|
|
10472
|
+
return x;
|
|
10473
|
+
}
|
|
10474
|
+
const DEFAULT_TICK_SPACING = 200n;
|
|
10475
|
+
/**
|
|
10476
|
+
* Target notional (in wei of the tokenType-side asset) for the appended
|
|
10477
|
+
* tiny credit leg. Chosen at 10 wei — small enough to be economically
|
|
10478
|
+
* meaningless against any real position size, large enough to safely
|
|
10479
|
+
* clear rounding on the SFPM's width-2 internal chunk math without any
|
|
10480
|
+
* risk of underflowing to zero (which would revert ChunkHasZeroLiquidity).
|
|
10481
|
+
*/
|
|
10482
|
+
const TINY_CREDIT_TARGET_NOTIONAL_WEI = 10n;
|
|
10483
|
+
/**
|
|
10484
|
+
* Pick a signedStrike for the appended width=0 credit leg such that:
|
|
10485
|
+
* 1. positionSize · 1.0001^signedStrike ≈ TINY_CREDIT_TARGET_NOTIONAL_WEI
|
|
10486
|
+
* (~10 wei — economically meaningless but comfortably above any
|
|
10487
|
+
* SFPM width-2 chunk rounding);
|
|
10488
|
+
* 2. the leg's tick range (SFPM internally treats width=0 as width=2, so
|
|
10489
|
+
* the range is `strike ± tickSpacing`) stays strictly inside
|
|
10490
|
+
* `[MIN_POOL_TICK, MAX_POOL_TICK]` — otherwise the getSqrtRatioAtTick
|
|
10491
|
+
* call reverts with `InvalidTick`.
|
|
10492
|
+
*
|
|
10493
|
+
* Closed form: `1.0001^signedStrike = target/positionSize`, so
|
|
10494
|
+
* `sqrtKrawX96 = isqrt(target · 2^192 / positionSize)` and
|
|
10495
|
+
* `signedStrike = sqrtPriceX96ToTick(sqrtKrawX96)`. If the notional-optimal
|
|
10496
|
+
* strike falls outside the safe range, we clamp inward. Clamping raises the
|
|
10497
|
+
* notional but keeps it << position size for any reasonable strike.
|
|
10498
|
+
*/
|
|
10499
|
+
function computeTinyCreditSignedStrike(positionSize, tickSpacing) {
|
|
10500
|
+
if (positionSize <= 0n) throw new PanopticError("computeTinyCreditSignedStrike: positionSize must be > 0");
|
|
10501
|
+
const minSafe = MIN_TICK + tickSpacing + 1n;
|
|
10502
|
+
const maxSafe = MAX_TICK - tickSpacing - 1n;
|
|
10503
|
+
let signedStrike;
|
|
10504
|
+
try {
|
|
10505
|
+
const sqrtKrawX96 = isqrt$1(TINY_CREDIT_TARGET_NOTIONAL_WEI * Q192$3 / positionSize);
|
|
10506
|
+
signedStrike = sqrtPriceX96ToTick(sqrtKrawX96);
|
|
10507
|
+
} catch {
|
|
10508
|
+
signedStrike = minSafe;
|
|
10509
|
+
}
|
|
10510
|
+
if (signedStrike < minSafe) return minSafe;
|
|
10511
|
+
if (signedStrike > maxSafe) return maxSafe;
|
|
10512
|
+
return signedStrike;
|
|
10513
|
+
}
|
|
10514
|
+
/**
|
|
10515
|
+
* Assemble the tiny credit leg struct, picking a strike that avoids
|
|
10516
|
+
* colliding with any existing width=0 credit leg on the same (asset,
|
|
10517
|
+
* tokenType) pair.
|
|
10518
|
+
*
|
|
10519
|
+
* The encoded strike stored in the tokenId is
|
|
10520
|
+
* `asset === 0 ? signedStrike : -signedStrike` (mirrors
|
|
10521
|
+
* {@link buildNeutralLeg} in reads/collateralEstimate.ts).
|
|
10522
|
+
*/
|
|
10523
|
+
function pickUniqueTinyCreditLeg(baseTokenId, legIndex, positionSize, tickSpacing) {
|
|
10524
|
+
const asset = 1n;
|
|
10525
|
+
const tokenType = 0n;
|
|
10526
|
+
const existingLegs = decodeAllLegs(baseTokenId);
|
|
10527
|
+
const maxSafe = MAX_TICK - tickSpacing - 1n;
|
|
10528
|
+
let signedStrike = computeTinyCreditSignedStrike(positionSize, tickSpacing);
|
|
10529
|
+
while (signedStrike <= maxSafe) {
|
|
10530
|
+
const candidate = asset === 0n ? signedStrike : -signedStrike;
|
|
10531
|
+
let collides = false;
|
|
10532
|
+
for (const leg of existingLegs) if (leg.width === 0n && leg.isLong && leg.asset === asset && leg.tokenType === tokenType && leg.strike === candidate) {
|
|
10533
|
+
collides = true;
|
|
10534
|
+
break;
|
|
10535
|
+
}
|
|
10536
|
+
if (!collides) break;
|
|
10537
|
+
signedStrike += 1n;
|
|
10538
|
+
}
|
|
10539
|
+
if (signedStrike > maxSafe) throw new PanopticError("deriveUniqueTokenId: exhausted strike space picking a unique tiny credit leg");
|
|
10540
|
+
const encodedStrike = asset === 0n ? signedStrike : -signedStrike;
|
|
10541
|
+
return {
|
|
10542
|
+
index: legIndex,
|
|
10543
|
+
asset,
|
|
10544
|
+
tokenType,
|
|
10545
|
+
optionRatio: 1n,
|
|
10546
|
+
isLong: 1n,
|
|
10547
|
+
riskPartner: legIndex,
|
|
10548
|
+
strike: encodedStrike,
|
|
10549
|
+
width: 0n
|
|
10550
|
+
};
|
|
10551
|
+
}
|
|
10552
|
+
function appendTinyCreditLeg(baseTokenId, baseLegCount, positionSize, tickSpacing) {
|
|
10553
|
+
const newLeg = pickUniqueTinyCreditLeg(baseTokenId, baseLegCount, positionSize, tickSpacing);
|
|
10554
|
+
return addLegToTokenId(baseTokenId, newLeg);
|
|
10555
|
+
}
|
|
10556
|
+
function scaleRatios(baseTokenId, targetPositionSize) {
|
|
10557
|
+
const legs = decodeAllLegs(baseTokenId);
|
|
10558
|
+
const maxRatio = legs.reduce((m, leg) => leg.optionRatio > m ? leg.optionRatio : m, 0n);
|
|
10559
|
+
const N = MAX_OPTION_RATIO / maxRatio;
|
|
10560
|
+
if (N < 2n) throw new PanopticError("deriveUniqueTokenId: cannot derive a unique tokenId — all 4 leg slots used and optionRatios already near the 127 ceiling");
|
|
10561
|
+
const newPositionSize = (targetPositionSize + N - 1n) / N;
|
|
10562
|
+
const poolId = baseTokenId & POOL_ID_MASK$2;
|
|
10563
|
+
let out = poolId;
|
|
10564
|
+
for (const leg of legs) out = addLegToTokenId(out, {
|
|
10565
|
+
index: leg.index,
|
|
10566
|
+
asset: leg.asset,
|
|
10567
|
+
tokenType: leg.tokenType,
|
|
10568
|
+
optionRatio: leg.optionRatio * N,
|
|
10569
|
+
isLong: leg.isLong ? 1n : 0n,
|
|
10570
|
+
riskPartner: leg.riskPartner,
|
|
10571
|
+
strike: leg.strike,
|
|
10572
|
+
width: leg.width
|
|
10642
10573
|
});
|
|
10574
|
+
return {
|
|
10575
|
+
newTokenId: out,
|
|
10576
|
+
newPositionSize,
|
|
10577
|
+
effectivePositionSize: newPositionSize * N,
|
|
10578
|
+
strategy: "ratio-scale"
|
|
10579
|
+
};
|
|
10643
10580
|
}
|
|
10644
10581
|
/**
|
|
10645
|
-
*
|
|
10582
|
+
* Derive a tokenId unique from `baseTokenId` for a partial reduction.
|
|
10583
|
+
*
|
|
10584
|
+
* Prefers a tiny-credit-leg extension (arbitrary new size). Falls back to
|
|
10585
|
+
* optionRatio scaling only when the base tokenId already occupies all 4 leg
|
|
10586
|
+
* slots.
|
|
10646
10587
|
*/
|
|
10647
|
-
|
|
10648
|
-
const {
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10588
|
+
function deriveUniqueTokenId(params) {
|
|
10589
|
+
const { baseTokenId, targetPositionSize, tickSpacing = DEFAULT_TICK_SPACING } = params;
|
|
10590
|
+
if (targetPositionSize <= 0n) throw new PanopticError("deriveUniqueTokenId: targetPositionSize must be > 0");
|
|
10591
|
+
const legCount = countLegs(baseTokenId);
|
|
10592
|
+
if (legCount === 0n) throw new PanopticError("deriveUniqueTokenId: baseTokenId has no legs");
|
|
10593
|
+
if (legCount < MAX_LEGS) {
|
|
10594
|
+
const newTokenId = appendTinyCreditLeg(baseTokenId, legCount, targetPositionSize, tickSpacing);
|
|
10595
|
+
return {
|
|
10596
|
+
newTokenId,
|
|
10597
|
+
newPositionSize: targetPositionSize,
|
|
10598
|
+
effectivePositionSize: targetPositionSize,
|
|
10599
|
+
strategy: "tiny-credit"
|
|
10600
|
+
};
|
|
10601
|
+
}
|
|
10602
|
+
return scaleRatios(baseTokenId, targetPositionSize);
|
|
10656
10603
|
}
|
|
10657
10604
|
/**
|
|
10658
|
-
*
|
|
10605
|
+
* Re-export decoded leg count so callers can gate UI on the strategy that
|
|
10606
|
+
* would be chosen (e.g. show a divisibility hint on ratio-scale positions).
|
|
10659
10607
|
*/
|
|
10660
|
-
|
|
10661
|
-
|
|
10662
|
-
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
|
|
10608
|
+
function planDeriveStrategy(baseTokenId) {
|
|
10609
|
+
return countLegs(baseTokenId) < MAX_LEGS ? "tiny-credit" : "ratio-scale";
|
|
10610
|
+
}
|
|
10611
|
+
|
|
10612
|
+
//#endregion
|
|
10613
|
+
//#region src/panoptic/v2/sfpmSwap/calldata.ts
|
|
10614
|
+
/**
|
|
10615
|
+
* Encode the `multicall([mint, burn])` for a swap plan.
|
|
10616
|
+
*
|
|
10617
|
+
* The order is always `[mint, burn]` — the ERC1155 must be minted before it is
|
|
10618
|
+
* burned. Which call carries the inverted (swap) limits is decided in the plan.
|
|
10619
|
+
*/
|
|
10620
|
+
function buildSfpmSwapCalldata(plan) {
|
|
10621
|
+
const mintData = encodeFunctionData({
|
|
10622
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10623
|
+
functionName: "mintTokenizedPosition",
|
|
10667
10624
|
args: [
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10625
|
+
plan.poolKey,
|
|
10626
|
+
plan.tokenId,
|
|
10627
|
+
plan.positionSize,
|
|
10628
|
+
plan.mintTickLimits[0],
|
|
10629
|
+
plan.mintTickLimits[1]
|
|
10630
|
+
]
|
|
10631
|
+
});
|
|
10632
|
+
const burnData = encodeFunctionData({
|
|
10633
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10634
|
+
functionName: "burnTokenizedPosition",
|
|
10635
|
+
args: [
|
|
10636
|
+
plan.poolKey,
|
|
10637
|
+
plan.tokenId,
|
|
10638
|
+
plan.positionSize,
|
|
10639
|
+
plan.burnTickLimits[0],
|
|
10640
|
+
plan.burnTickLimits[1]
|
|
10672
10641
|
]
|
|
10673
10642
|
});
|
|
10643
|
+
const multicallData = encodeFunctionData({
|
|
10644
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10645
|
+
functionName: "multicall",
|
|
10646
|
+
args: [[mintData, burnData]]
|
|
10647
|
+
});
|
|
10648
|
+
return {
|
|
10649
|
+
multicallData,
|
|
10650
|
+
mintData,
|
|
10651
|
+
burnData
|
|
10652
|
+
};
|
|
10674
10653
|
}
|
|
10654
|
+
|
|
10655
|
+
//#endregion
|
|
10656
|
+
//#region src/panoptic/v2/sfpmSwap/init.ts
|
|
10675
10657
|
/**
|
|
10676
|
-
*
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
abi: panopticFactoryV3Abi,
|
|
10683
|
-
functionName: "getPanopticPool",
|
|
10684
|
-
args: [params.univ3pool, riskEngine]
|
|
10685
|
-
});
|
|
10686
|
-
return client.readContract({
|
|
10687
|
-
address: factoryAddress,
|
|
10688
|
-
abi: panopticFactoryV4Abi,
|
|
10689
|
-
functionName: "getPanopticPool",
|
|
10690
|
-
args: [{
|
|
10691
|
-
currency0: params.poolKey.currency0,
|
|
10692
|
-
currency1: params.poolKey.currency1,
|
|
10693
|
-
fee: Number(params.poolKey.fee),
|
|
10694
|
-
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
10695
|
-
hooks: params.poolKey.hooks
|
|
10696
|
-
}, riskEngine]
|
|
10697
|
-
});
|
|
10698
|
-
}
|
|
10699
|
-
/**
|
|
10700
|
-
* Mine for an optimal pool address salt with high rarity.
|
|
10658
|
+
* Resolve the `uint64` SFPM poolId for a Uniswap v3 pool, initializing it if needed.
|
|
10659
|
+
*
|
|
10660
|
+
* `initializeAMMPool` is permissionless and idempotent and **returns the poolId**
|
|
10661
|
+
* whether or not the pool was already registered, so a `simulateContract` call is
|
|
10662
|
+
* enough to learn the id without sending a transaction. Always resolve the id this
|
|
10663
|
+
* way rather than encoding it offline — the SFPM can collision-increment ids.
|
|
10701
10664
|
*/
|
|
10702
|
-
async function
|
|
10703
|
-
const { client,
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
address:
|
|
10707
|
-
abi:
|
|
10708
|
-
functionName: "
|
|
10709
|
-
args: [
|
|
10710
|
-
deployerAddress,
|
|
10711
|
-
params.v3Pool,
|
|
10712
|
-
riskEngine,
|
|
10713
|
-
salt,
|
|
10714
|
-
loops,
|
|
10715
|
-
minTargetRarity
|
|
10716
|
-
]
|
|
10717
|
-
});
|
|
10718
|
-
else result = await client.readContract({
|
|
10719
|
-
address: factoryAddress,
|
|
10720
|
-
abi: panopticFactoryV4Abi,
|
|
10721
|
-
functionName: "minePoolAddress",
|
|
10665
|
+
async function fetchSfpmV3PoolId(params) {
|
|
10666
|
+
const { client, sfpmAddress, token0, token1, fee } = params;
|
|
10667
|
+
const vegoid$1 = params.vegoid ?? Number(DEFAULT_VEGOID);
|
|
10668
|
+
const { result } = await client.simulateContract({
|
|
10669
|
+
address: sfpmAddress,
|
|
10670
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10671
|
+
functionName: "initializeAMMPool",
|
|
10722
10672
|
args: [
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
fee: Number(params.poolKey.fee),
|
|
10728
|
-
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
10729
|
-
hooks: params.poolKey.hooks
|
|
10730
|
-
},
|
|
10731
|
-
riskEngine,
|
|
10732
|
-
salt,
|
|
10733
|
-
loops,
|
|
10734
|
-
minTargetRarity
|
|
10673
|
+
token0,
|
|
10674
|
+
token1,
|
|
10675
|
+
fee,
|
|
10676
|
+
vegoid$1
|
|
10735
10677
|
]
|
|
10736
10678
|
});
|
|
10737
|
-
return
|
|
10738
|
-
bestSalt: BigInt(result[0]),
|
|
10739
|
-
highestRarity: result[1]
|
|
10740
|
-
};
|
|
10679
|
+
return BigInt(result);
|
|
10741
10680
|
}
|
|
10742
10681
|
/**
|
|
10743
|
-
*
|
|
10682
|
+
* Ensure a Uniswap v3 pool is registered on the SFPM, sending `initializeAMMPool`
|
|
10683
|
+
* only if it is not already registered. Returns the resolved poolId.
|
|
10744
10684
|
*
|
|
10745
|
-
*
|
|
10746
|
-
*
|
|
10685
|
+
* When `expectedPool` is given, the resolved id is checked to map back to it via
|
|
10686
|
+
* `getUniswapV3PoolFromId` — guards against a wrong token/fee triple.
|
|
10747
10687
|
*/
|
|
10748
|
-
async function
|
|
10749
|
-
const { client,
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
10688
|
+
async function ensureSfpmV3PoolInitialized(params) {
|
|
10689
|
+
const { client, wallet, sfpmAddress, token0, token1, fee, expectedPool } = params;
|
|
10690
|
+
const vegoid$1 = params.vegoid ?? Number(DEFAULT_VEGOID);
|
|
10691
|
+
const poolId = await fetchSfpmV3PoolId({
|
|
10692
|
+
client,
|
|
10693
|
+
sfpmAddress,
|
|
10694
|
+
token0,
|
|
10695
|
+
token1,
|
|
10696
|
+
fee,
|
|
10697
|
+
vegoid: vegoid$1
|
|
10698
|
+
});
|
|
10699
|
+
const registered = await client.readContract({
|
|
10700
|
+
address: sfpmAddress,
|
|
10701
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10702
|
+
functionName: "getUniswapV3PoolFromId",
|
|
10703
|
+
args: [poolId]
|
|
10704
|
+
});
|
|
10705
|
+
let initialized = false;
|
|
10706
|
+
let resolved = registered;
|
|
10707
|
+
if (getAddress(registered) === zeroAddress) {
|
|
10708
|
+
const account = wallet.account;
|
|
10709
|
+
if (account === void 0) throw new PanopticError("wallet client has no account");
|
|
10710
|
+
const hash = await wallet.writeContract({
|
|
10711
|
+
account,
|
|
10712
|
+
chain: wallet.chain ?? null,
|
|
10713
|
+
address: sfpmAddress,
|
|
10714
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10715
|
+
functionName: "initializeAMMPool",
|
|
10755
10716
|
args: [
|
|
10756
|
-
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
10762
|
-
|
|
10717
|
+
token0,
|
|
10718
|
+
token1,
|
|
10719
|
+
fee,
|
|
10720
|
+
vegoid$1
|
|
10721
|
+
]
|
|
10722
|
+
});
|
|
10723
|
+
await client.waitForTransactionReceipt({ hash });
|
|
10724
|
+
initialized = true;
|
|
10725
|
+
resolved = await client.readContract({
|
|
10726
|
+
address: sfpmAddress,
|
|
10727
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10728
|
+
functionName: "getUniswapV3PoolFromId",
|
|
10729
|
+
args: [poolId]
|
|
10763
10730
|
});
|
|
10764
|
-
return result$1;
|
|
10765
10731
|
}
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
{
|
|
10772
|
-
currency0: params.poolKey.currency0,
|
|
10773
|
-
currency1: params.poolKey.currency1,
|
|
10774
|
-
fee: Number(params.poolKey.fee),
|
|
10775
|
-
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
10776
|
-
hooks: params.poolKey.hooks
|
|
10777
|
-
},
|
|
10778
|
-
riskEngine,
|
|
10779
|
-
salt
|
|
10780
|
-
],
|
|
10781
|
-
account
|
|
10782
|
-
});
|
|
10783
|
-
return result;
|
|
10732
|
+
if (expectedPool !== void 0 && getAddress(resolved) !== getAddress(expectedPool)) throw new WrongUniswapPoolError(new PanopticError(`SFPM poolId ${poolId} resolves to ${resolved}, expected ${expectedPool}`));
|
|
10733
|
+
return {
|
|
10734
|
+
poolId,
|
|
10735
|
+
initialized
|
|
10736
|
+
};
|
|
10784
10737
|
}
|
|
10738
|
+
|
|
10739
|
+
//#endregion
|
|
10740
|
+
//#region src/panoptic/v2/sfpmSwap/plan.ts
|
|
10741
|
+
/** Wide, non-inverted band for the paired (non-swapping) call — never triggers a swap. */
|
|
10742
|
+
const WIDE_LIMITS = [Number(MIN_TICK) + 1, Number(MAX_TICK) - 1];
|
|
10785
10743
|
/**
|
|
10786
|
-
*
|
|
10744
|
+
* Convert a slippage tolerance in bps to a conservative Uniswap tick distance.
|
|
10787
10745
|
*
|
|
10788
|
-
*
|
|
10789
|
-
*
|
|
10790
|
-
*
|
|
10746
|
+
* Ticks are 1.0001^tick, so each tick ≈ 1 bps. This walks up powers of 1.0001
|
|
10747
|
+
* until the cumulative price move covers `slippageBps`, matching the hedger-bot's
|
|
10748
|
+
* dispatch-path helper so both swap paths agree on band width.
|
|
10791
10749
|
*/
|
|
10792
|
-
|
|
10793
|
-
|
|
10794
|
-
if (
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10801
|
-
|
|
10802
|
-
client,
|
|
10803
|
-
factoryAddress,
|
|
10804
|
-
univ3pool,
|
|
10805
|
-
riskEngine
|
|
10806
|
-
});
|
|
10750
|
+
function slippageBpsToTickDistance(slippageBps) {
|
|
10751
|
+
if (slippageBps < 0n || slippageBps > 1000n) throw new PanopticError(`slippage bps ${slippageBps} out of bounds (0..1000)`);
|
|
10752
|
+
if (slippageBps === 0n) return 0n;
|
|
10753
|
+
let numerator = 1n;
|
|
10754
|
+
let denominator = 1n;
|
|
10755
|
+
let ticks = 0n;
|
|
10756
|
+
while (numerator * 10000n < denominator * (10000n + slippageBps)) {
|
|
10757
|
+
numerator *= 10001n;
|
|
10758
|
+
denominator *= 10000n;
|
|
10759
|
+
ticks += 1n;
|
|
10807
10760
|
}
|
|
10808
|
-
|
|
10809
|
-
client,
|
|
10810
|
-
sfpmAddress,
|
|
10811
|
-
poolId
|
|
10812
|
-
});
|
|
10813
|
-
return getPanopticPoolAddress({
|
|
10814
|
-
version: "v4",
|
|
10815
|
-
client,
|
|
10816
|
-
factoryAddress,
|
|
10817
|
-
poolKey,
|
|
10818
|
-
riskEngine
|
|
10819
|
-
});
|
|
10761
|
+
return ticks;
|
|
10820
10762
|
}
|
|
10821
10763
|
/**
|
|
10822
|
-
*
|
|
10823
|
-
*
|
|
10824
|
-
* Tries both V3 and V4 lookups in parallel. The factory returns `address(0)` for
|
|
10825
|
-
* non-existent pools, so the non-zero result identifies the correct version.
|
|
10764
|
+
* Build the swap plan.
|
|
10826
10765
|
*
|
|
10827
|
-
*
|
|
10766
|
+
* Mechanism (verified in the Phase 0 fork test):
|
|
10767
|
+
* - A single-leg **loan** tokenId (width=0, isLong=false, `asset == tokenType`) moves
|
|
10768
|
+
* exactly `positionSize` of the `tokenType` token when its call carries inverted
|
|
10769
|
+
* tick limits (`low > high`); the paired call uses a wide band and moves nothing.
|
|
10770
|
+
* - `exactIn`: swap on the **mint**; `tokenType` = the **input** token index.
|
|
10771
|
+
* - `exactOut`: swap on the **burn** (isLong flips → exact-output); `tokenType` = the
|
|
10772
|
+
* **output** token index.
|
|
10828
10773
|
*
|
|
10829
|
-
*
|
|
10774
|
+
* The inverted band is centered on `currentTick` at ±`slippageBpsToTickDistance`,
|
|
10775
|
+
* which the SFPM re-sorts and enforces as an open interval on the post-swap tick.
|
|
10830
10776
|
*/
|
|
10831
|
-
|
|
10832
|
-
const {
|
|
10833
|
-
if (
|
|
10834
|
-
const
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
|
|
10839
|
-
|
|
10840
|
-
|
|
10841
|
-
|
|
10842
|
-
|
|
10843
|
-
|
|
10844
|
-
|
|
10845
|
-
|
|
10846
|
-
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
|
|
10851
|
-
|
|
10852
|
-
|
|
10853
|
-
|
|
10854
|
-
|
|
10855
|
-
|
|
10856
|
-
|
|
10857
|
-
|
|
10858
|
-
}).catch((err) => {
|
|
10859
|
-
if (isNotFoundError(err)) return zeroAddress;
|
|
10860
|
-
throw err;
|
|
10861
|
-
}) : Promise.resolve(zeroAddress)]);
|
|
10862
|
-
const [v3Result, v4Result] = results;
|
|
10863
|
-
if (v3Result !== zeroAddress) return {
|
|
10864
|
-
panopticPoolAddress: v3Result,
|
|
10865
|
-
version: "v3"
|
|
10866
|
-
};
|
|
10867
|
-
if (v4Result !== zeroAddress) return {
|
|
10868
|
-
panopticPoolAddress: v4Result,
|
|
10869
|
-
version: "v4"
|
|
10777
|
+
function buildSfpmSwapPlan(params) {
|
|
10778
|
+
const { sfpmAddress, poolAddress, poolId, kind, zeroForOne, amount, currentTick, slippageBps } = params;
|
|
10779
|
+
if (amount <= 0n) throw new PanopticError(`swap amount must be positive (got ${amount})`);
|
|
10780
|
+
const distance = slippageBpsToTickDistance(slippageBps);
|
|
10781
|
+
if (distance < 1n) throw new PanopticError(`slippageBps ${slippageBps} yields a zero-width tick band; use a larger tolerance`);
|
|
10782
|
+
const tokenType = kind === "exactIn" ? zeroForOne ? 0n : 1n : zeroForOne ? 1n : 0n;
|
|
10783
|
+
const tokenId = createTokenIdBuilder(poolId).addLoan({
|
|
10784
|
+
asset: tokenType,
|
|
10785
|
+
tokenType,
|
|
10786
|
+
strike: 0n
|
|
10787
|
+
}).build();
|
|
10788
|
+
const d = Number(distance);
|
|
10789
|
+
const low = Math.min(Number(MAX_TICK), currentTick + d);
|
|
10790
|
+
const high = Math.max(Number(MIN_TICK), currentTick - d);
|
|
10791
|
+
if (low <= high) throw new PanopticError(`slippageBps ${slippageBps} at tick ${currentTick} yields a non-inverted band after clamping`);
|
|
10792
|
+
const invertedLimits = [low, high];
|
|
10793
|
+
const swapOn = kind === "exactIn" ? "mint" : "burn";
|
|
10794
|
+
return {
|
|
10795
|
+
sfpmAddress,
|
|
10796
|
+
poolAddress,
|
|
10797
|
+
poolKey: encodeAbiParameters([{ type: "address" }], [poolAddress]),
|
|
10798
|
+
tokenId,
|
|
10799
|
+
positionSize: amount,
|
|
10800
|
+
mintTickLimits: swapOn === "mint" ? invertedLimits : WIDE_LIMITS,
|
|
10801
|
+
burnTickLimits: swapOn === "burn" ? invertedLimits : WIDE_LIMITS,
|
|
10802
|
+
swapOn,
|
|
10803
|
+
kind
|
|
10870
10804
|
};
|
|
10871
|
-
throw new Error(`No PanopticPool found for poolId ${poolId}`);
|
|
10872
10805
|
}
|
|
10873
10806
|
|
|
10874
10807
|
//#endregion
|
|
10875
|
-
//#region src/panoptic/v2/
|
|
10808
|
+
//#region src/panoptic/v2/sfpmSwap/quote.ts
|
|
10809
|
+
const UINT128 = 1n << 128n;
|
|
10810
|
+
const INT128_MAX = (1n << 127n) - 1n;
|
|
10811
|
+
/** Extract the two signed 128-bit slots from a packed `LeftRightSigned` int256. */
|
|
10812
|
+
function unpackLeftRightSigned(packed) {
|
|
10813
|
+
const u = packed < 0n ? packed + (1n << 256n) : packed;
|
|
10814
|
+
const toInt128 = (half) => half > INT128_MAX ? half - UINT128 : half;
|
|
10815
|
+
return {
|
|
10816
|
+
right: toInt128(u & UINT128 - 1n),
|
|
10817
|
+
left: toInt128(u >> 128n & UINT128 - 1n)
|
|
10818
|
+
};
|
|
10819
|
+
}
|
|
10820
|
+
/** Wrap an unknown thrown value as a PanopticError, decoding Panoptic reverts when possible. */
|
|
10821
|
+
function toPanopticError(err) {
|
|
10822
|
+
if (err instanceof PanopticError) return err;
|
|
10823
|
+
const parsed = parsePanopticError(err);
|
|
10824
|
+
if (parsed) return parsed.error;
|
|
10825
|
+
return new PanopticError(err instanceof Error ? err.message : "SFPM swap simulation failed", err instanceof Error ? err : void 0);
|
|
10826
|
+
}
|
|
10876
10827
|
/**
|
|
10877
|
-
*
|
|
10878
|
-
*
|
|
10828
|
+
* Quote a swap by simulating `SFPM.multicall([mint, burn])` and decoding the swap
|
|
10829
|
+
* call's `totalMoved` return. Authoritative — captures the width-0 loan-leg wei
|
|
10830
|
+
* rounding a raw QuoterV2 quote would miss.
|
|
10879
10831
|
*/
|
|
10880
|
-
|
|
10881
|
-
const
|
|
10882
|
-
const
|
|
10883
|
-
const
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
10832
|
+
async function quoteSfpmSwap(params) {
|
|
10833
|
+
const { client, plan, account, stateOverride, blockNumber } = params;
|
|
10834
|
+
const { mintData, burnData } = buildSfpmSwapCalldata(plan);
|
|
10835
|
+
const _meta = await getBlockMeta({
|
|
10836
|
+
client,
|
|
10837
|
+
blockNumber
|
|
10838
|
+
});
|
|
10839
|
+
try {
|
|
10840
|
+
const { result } = await client.simulateContract({
|
|
10841
|
+
account,
|
|
10842
|
+
address: plan.sfpmAddress,
|
|
10843
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10844
|
+
functionName: "multicall",
|
|
10845
|
+
args: [[mintData, burnData]],
|
|
10846
|
+
blockNumber,
|
|
10847
|
+
stateOverride
|
|
10848
|
+
});
|
|
10849
|
+
const swapIndex = plan.swapOn === "mint" ? 0 : 1;
|
|
10850
|
+
const decoded = decodeFunctionResult({
|
|
10851
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
10852
|
+
functionName: plan.swapOn === "mint" ? "mintTokenizedPosition" : "burnTokenizedPosition",
|
|
10853
|
+
data: result[swapIndex]
|
|
10854
|
+
});
|
|
10855
|
+
const finalTick = Number(decoded[2]);
|
|
10856
|
+
const { right, left } = unpackLeftRightSigned(decoded[1]);
|
|
10857
|
+
const inSlot = [right, left].find((s) => s > 0n);
|
|
10858
|
+
const outSlot = [right, left].find((s) => s < 0n);
|
|
10859
|
+
if (inSlot === void 0 || outSlot === void 0) return {
|
|
10860
|
+
success: false,
|
|
10861
|
+
error: new PanopticError(`SFPM swap simulation moved no tokens (totalMoved=${decoded[1]})`),
|
|
10862
|
+
_meta
|
|
10863
|
+
};
|
|
10864
|
+
return {
|
|
10865
|
+
success: true,
|
|
10866
|
+
data: {
|
|
10867
|
+
amountIn: inSlot,
|
|
10868
|
+
amountOut: -outSlot,
|
|
10869
|
+
finalTick
|
|
10870
|
+
},
|
|
10871
|
+
gasEstimate: 0n,
|
|
10872
|
+
_meta
|
|
10873
|
+
};
|
|
10874
|
+
} catch (err) {
|
|
10875
|
+
return {
|
|
10876
|
+
success: false,
|
|
10877
|
+
error: toPanopticError(err),
|
|
10878
|
+
_meta
|
|
10879
|
+
};
|
|
10891
10880
|
}
|
|
10892
|
-
return bytes;
|
|
10893
|
-
}
|
|
10894
|
-
/** Parse a 0x-prefixed address into 20 bytes. */
|
|
10895
|
-
function addressToBytes(addr) {
|
|
10896
|
-
const hex = addr.slice(2).padStart(40, "0");
|
|
10897
|
-
const bytes = new Uint8Array(20);
|
|
10898
|
-
for (let i = 0; i < 20; i++) bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
10899
|
-
return bytes;
|
|
10900
|
-
}
|
|
10901
|
-
/** Parse a 0x-prefixed 32-byte hex string into bytes. */
|
|
10902
|
-
function hex32ToBytes(hex) {
|
|
10903
|
-
const h = hex.slice(2).padStart(64, "0");
|
|
10904
|
-
const bytes = new Uint8Array(32);
|
|
10905
|
-
for (let i = 0; i < 32; i++) bytes[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16);
|
|
10906
|
-
return bytes;
|
|
10907
10881
|
}
|
|
10882
|
+
|
|
10883
|
+
//#endregion
|
|
10884
|
+
//#region src/uniswap/v4/abis/universalRouter.ts
|
|
10908
10885
|
/**
|
|
10909
|
-
*
|
|
10910
|
-
*
|
|
10911
|
-
* Mirrors `ClonesWithImmutableArgs.addressOfClone3(salt)` (with `address(this)` = factory):
|
|
10912
|
-
* proxy = CREATE2(factory, salt, PROXY_BYTECODE_HASH)
|
|
10913
|
-
* deployed = CREATE1(proxy, nonce=1)
|
|
10914
|
-
*
|
|
10915
|
-
* Returns the deployed address as a uint160 BigInt.
|
|
10886
|
+
* Minimal Universal Router ABI (only the `execute` overload we use).
|
|
10887
|
+
* @module uniswap/v4/abis/universalRouter
|
|
10916
10888
|
*/
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10889
|
+
const universalRouterAbi = [{
|
|
10890
|
+
type: "function",
|
|
10891
|
+
name: "execute",
|
|
10892
|
+
stateMutability: "payable",
|
|
10893
|
+
inputs: [
|
|
10894
|
+
{
|
|
10895
|
+
name: "commands",
|
|
10896
|
+
type: "bytes"
|
|
10897
|
+
},
|
|
10898
|
+
{
|
|
10899
|
+
name: "inputs",
|
|
10900
|
+
type: "bytes[]"
|
|
10901
|
+
},
|
|
10902
|
+
{
|
|
10903
|
+
name: "deadline",
|
|
10904
|
+
type: "uint256"
|
|
10905
|
+
}
|
|
10906
|
+
],
|
|
10907
|
+
outputs: []
|
|
10908
|
+
}];
|
|
10909
|
+
|
|
10910
|
+
//#endregion
|
|
10911
|
+
//#region src/uniswap/v4/router/errors.ts
|
|
10936
10912
|
/**
|
|
10937
|
-
*
|
|
10938
|
-
*
|
|
10939
|
-
* Mirrors `PanopticMath.numberOfLeadingHexZeros(addr)`.
|
|
10940
|
-
* Returns 40 for the zero address.
|
|
10913
|
+
* The chain has no configured Uniswap v4 addresses and none were supplied via
|
|
10914
|
+
* overrides.
|
|
10941
10915
|
*/
|
|
10942
|
-
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
10946
|
-
|
|
10947
|
-
x >>= 128n;
|
|
10948
|
-
r += 32;
|
|
10949
|
-
}
|
|
10950
|
-
if (x >= 0x10000000000000000n) {
|
|
10951
|
-
x >>= 64n;
|
|
10952
|
-
r += 16;
|
|
10953
|
-
}
|
|
10954
|
-
if (x >= 0x100000000n) {
|
|
10955
|
-
x >>= 32n;
|
|
10956
|
-
r += 8;
|
|
10957
|
-
}
|
|
10958
|
-
if (x >= 0x10000n) {
|
|
10959
|
-
x >>= 16n;
|
|
10960
|
-
r += 4;
|
|
10916
|
+
var UnsupportedChainError = class extends PanopticError {
|
|
10917
|
+
name = "UnsupportedChainError";
|
|
10918
|
+
constructor(chainId, cause) {
|
|
10919
|
+
super(`Uniswap v4 router not configured for chain ${chainId}`, cause);
|
|
10920
|
+
this.chainId = chainId;
|
|
10961
10921
|
}
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
10922
|
+
};
|
|
10923
|
+
/**
|
|
10924
|
+
* `tokenIn` is neither `currency0` nor `currency1` of the resolved pool.
|
|
10925
|
+
*/
|
|
10926
|
+
var InvalidSwapTokenError = class extends PanopticError {
|
|
10927
|
+
name = "InvalidSwapTokenError";
|
|
10928
|
+
constructor(token, currency0, currency1, cause) {
|
|
10929
|
+
super(`Token ${token} is not part of the pool (currency0=${currency0}, currency1=${currency1})`, cause);
|
|
10930
|
+
this.token = token;
|
|
10931
|
+
this.currency0 = currency0;
|
|
10932
|
+
this.currency1 = currency1;
|
|
10965
10933
|
}
|
|
10966
|
-
|
|
10967
|
-
return 39 - r;
|
|
10968
|
-
}
|
|
10934
|
+
};
|
|
10969
10935
|
/**
|
|
10970
|
-
*
|
|
10971
|
-
*
|
|
10972
|
-
* Mirrors:
|
|
10973
|
-
* bytes32(abi.encodePacked(
|
|
10974
|
-
* uint80(uint160(deployerAddress) >> 80), // bits [159:80] of deployer → 10 bytes
|
|
10975
|
-
* uint40(uint160(v3Pool) >> 120), // bits [159:120] of v3Pool → 5 bytes
|
|
10976
|
-
* uint40(uint160(riskEngine) >> 120), // bits [159:120] of riskEngine→ 5 bytes
|
|
10977
|
-
* salt // uint96 → 12 bytes
|
|
10978
|
-
* ))
|
|
10936
|
+
* An amount exceeds the uint128 range required by the v4 swap encoding.
|
|
10979
10937
|
*/
|
|
10980
|
-
|
|
10981
|
-
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
}
|
|
10986
|
-
|
|
10987
|
-
* Compute the Uniswap V4 PoolId for a PoolKey.
|
|
10988
|
-
*
|
|
10989
|
-
* Mirrors `PoolId.toId(key)` = keccak256 of the ABI-encoded PoolKey struct
|
|
10990
|
-
* (5 fields × 32 bytes = 160 bytes).
|
|
10991
|
-
*/
|
|
10992
|
-
function computePoolIdV4(poolKey) {
|
|
10993
|
-
const fee = Number(poolKey.fee);
|
|
10994
|
-
if (!Number.isInteger(fee) || fee < 0 || fee >= 2 ** 24) throw new PanopticValidationError(`fee out of uint24 range: ${fee}`);
|
|
10995
|
-
const tickSpacing = Number(poolKey.tickSpacing);
|
|
10996
|
-
if (!Number.isInteger(tickSpacing) || tickSpacing < -(2 ** 23) || tickSpacing > 2 ** 23 - 1) throw new PanopticValidationError(`tickSpacing out of int24 range: ${tickSpacing}`);
|
|
10997
|
-
const encoded = encodeAbiParameters([
|
|
10998
|
-
{ type: "address" },
|
|
10999
|
-
{ type: "address" },
|
|
11000
|
-
{ type: "uint24" },
|
|
11001
|
-
{ type: "int24" },
|
|
11002
|
-
{ type: "address" }
|
|
11003
|
-
], [
|
|
11004
|
-
poolKey.currency0,
|
|
11005
|
-
poolKey.currency1,
|
|
11006
|
-
Number(poolKey.fee),
|
|
11007
|
-
Number(poolKey.tickSpacing),
|
|
11008
|
-
poolKey.hooks
|
|
11009
|
-
]);
|
|
11010
|
-
return BigInt(keccak256(encoded));
|
|
11011
|
-
}
|
|
10938
|
+
var AmountExceedsUint128Error = class extends PanopticError {
|
|
10939
|
+
name = "AmountExceedsUint128Error";
|
|
10940
|
+
constructor(amount, cause) {
|
|
10941
|
+
super(`Amount ${amount} exceeds uint128 maximum`, cause);
|
|
10942
|
+
this.amount = amount;
|
|
10943
|
+
}
|
|
10944
|
+
};
|
|
11012
10945
|
/**
|
|
11013
|
-
*
|
|
11014
|
-
*
|
|
11015
|
-
* Mirrors:
|
|
11016
|
-
* bytes32(abi.encodePacked(
|
|
11017
|
-
* uint80(uint160(deployerAddress) >> 80),
|
|
11018
|
-
* uint40(uint256(PoolId.unwrap(key.toId())) >> 120), // bits [159:120] of poolId
|
|
11019
|
-
* uint40(uint160(riskEngine) >> 120),
|
|
11020
|
-
* salt
|
|
11021
|
-
* ))
|
|
10946
|
+
* A native-ETH swap needs a trailing Universal Router SWEEP to deliver the ETH
|
|
10947
|
+
* output (or refund the input overpay), but no `recipient` was supplied.
|
|
11022
10948
|
*/
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
}
|
|
11029
|
-
/** Number of iterations per chunk before yielding back to the event loop. */
|
|
11030
|
-
const CHUNK_SIZE = 5000n;
|
|
10949
|
+
var MissingSweepRecipientError = class extends PanopticError {
|
|
10950
|
+
name = "MissingSweepRecipientError";
|
|
10951
|
+
constructor(cause) {
|
|
10952
|
+
super("A recipient is required to sweep native ETH back to the user", cause);
|
|
10953
|
+
}
|
|
10954
|
+
};
|
|
11031
10955
|
/**
|
|
11032
|
-
*
|
|
11033
|
-
* between chunks of iterations, preventing the browser UI from freezing.
|
|
11034
|
-
*
|
|
11035
|
-
* @param params - Mining parameters (versioned: 'v3' or 'v4'). No `client` required.
|
|
11036
|
-
* @returns The best salt found and its rarity (number of leading hex zeros).
|
|
10956
|
+
* The V4Quoter is not available for the chain (no fallback in v1).
|
|
11037
10957
|
*/
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
const saltPrefix = params.version === "v3" ? computeSaltPrefixV3(deployerAddress, params.v3Pool, riskEngine) : computeSaltPrefixV4(deployerAddress, params.poolKey, riskEngine);
|
|
11044
|
-
let currentSalt = salt;
|
|
11045
|
-
while (currentSalt < maxSalt) {
|
|
11046
|
-
const chunkEnd = currentSalt + CHUNK_SIZE < maxSalt ? currentSalt + CHUNK_SIZE : maxSalt;
|
|
11047
|
-
let done = false;
|
|
11048
|
-
for (; currentSalt < chunkEnd; currentSalt++) {
|
|
11049
|
-
const newSalt = saltPrefix | currentSalt & MASK_96;
|
|
11050
|
-
const addrInt = addressOfClone3(factoryAddress, newSalt);
|
|
11051
|
-
const rarity = BigInt(numberOfLeadingHexZeros(addrInt));
|
|
11052
|
-
if (rarity > highestRarity) {
|
|
11053
|
-
highestRarity = rarity;
|
|
11054
|
-
bestSalt = currentSalt;
|
|
11055
|
-
}
|
|
11056
|
-
if (rarity >= minTargetRarity) {
|
|
11057
|
-
highestRarity = rarity;
|
|
11058
|
-
bestSalt = currentSalt;
|
|
11059
|
-
done = true;
|
|
11060
|
-
break;
|
|
11061
|
-
}
|
|
11062
|
-
}
|
|
11063
|
-
if (done) break;
|
|
11064
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
10958
|
+
var QuoterUnavailableError = class extends PanopticError {
|
|
10959
|
+
name = "QuoterUnavailableError";
|
|
10960
|
+
constructor(chainId, cause) {
|
|
10961
|
+
super(`V4Quoter unavailable for chain ${chainId}`, cause);
|
|
10962
|
+
this.chainId = chainId;
|
|
11065
10963
|
}
|
|
11066
|
-
|
|
11067
|
-
bestSalt,
|
|
11068
|
-
highestRarity
|
|
11069
|
-
};
|
|
11070
|
-
}
|
|
10964
|
+
};
|
|
11071
10965
|
|
|
11072
10966
|
//#endregion
|
|
11073
|
-
//#region src/
|
|
10967
|
+
//#region src/uniswap/v3/router/encodeSwap.ts
|
|
10968
|
+
const UINT128_MAX$4 = (1n << 128n) - 1n;
|
|
10969
|
+
|
|
10970
|
+
//#endregion
|
|
10971
|
+
//#region src/uniswap/v3/abis/quoterV2.ts
|
|
11074
10972
|
/**
|
|
11075
|
-
* Minimal Uniswap
|
|
11076
|
-
*
|
|
10973
|
+
* Minimal Uniswap v3 QuoterV2 ABI (`quoteExactInputSingle`).
|
|
10974
|
+
*
|
|
10975
|
+
* QuoterV2 is revert/staticcall-based (nonpayable but intended for `eth_call` /
|
|
10976
|
+
* `simulateContract`), so it must be simulated, not read.
|
|
10977
|
+
* @module uniswap/v3/abis/quoterV2
|
|
11077
10978
|
*/
|
|
11078
|
-
const
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
outputs: [
|
|
10979
|
+
const quoterV2Abi = [{
|
|
10980
|
+
type: "function",
|
|
10981
|
+
name: "quoteExactInputSingle",
|
|
10982
|
+
stateMutability: "nonpayable",
|
|
10983
|
+
inputs: [{
|
|
10984
|
+
name: "params",
|
|
10985
|
+
type: "tuple",
|
|
10986
|
+
components: [
|
|
11087
10987
|
{
|
|
11088
|
-
|
|
11089
|
-
|
|
11090
|
-
type: "uint160"
|
|
10988
|
+
name: "tokenIn",
|
|
10989
|
+
type: "address"
|
|
11091
10990
|
},
|
|
11092
10991
|
{
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
type: "int24"
|
|
10992
|
+
name: "tokenOut",
|
|
10993
|
+
type: "address"
|
|
11096
10994
|
},
|
|
11097
10995
|
{
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
type: "uint24"
|
|
10996
|
+
name: "amountIn",
|
|
10997
|
+
type: "uint256"
|
|
11101
10998
|
},
|
|
11102
10999
|
{
|
|
11103
|
-
|
|
11104
|
-
name: "lpFee",
|
|
11000
|
+
name: "fee",
|
|
11105
11001
|
type: "uint24"
|
|
11106
|
-
}
|
|
11107
|
-
],
|
|
11108
|
-
stateMutability: "view",
|
|
11109
|
-
type: "function"
|
|
11110
|
-
},
|
|
11111
|
-
{
|
|
11112
|
-
inputs: [{
|
|
11113
|
-
internalType: "PoolId",
|
|
11114
|
-
name: "poolId",
|
|
11115
|
-
type: "bytes32"
|
|
11116
|
-
}],
|
|
11117
|
-
name: "getFeeGrowthGlobals",
|
|
11118
|
-
outputs: [{
|
|
11119
|
-
internalType: "uint256",
|
|
11120
|
-
name: "feeGrowthGlobal0",
|
|
11121
|
-
type: "uint256"
|
|
11122
|
-
}, {
|
|
11123
|
-
internalType: "uint256",
|
|
11124
|
-
name: "feeGrowthGlobal1",
|
|
11125
|
-
type: "uint256"
|
|
11126
|
-
}],
|
|
11127
|
-
stateMutability: "view",
|
|
11128
|
-
type: "function"
|
|
11129
|
-
},
|
|
11130
|
-
{
|
|
11131
|
-
inputs: [{
|
|
11132
|
-
internalType: "PoolId",
|
|
11133
|
-
name: "poolId",
|
|
11134
|
-
type: "bytes32"
|
|
11135
|
-
}, {
|
|
11136
|
-
internalType: "int24",
|
|
11137
|
-
name: "tick",
|
|
11138
|
-
type: "int24"
|
|
11139
|
-
}],
|
|
11140
|
-
name: "getTickInfo",
|
|
11141
|
-
outputs: [
|
|
11142
|
-
{
|
|
11143
|
-
internalType: "uint128",
|
|
11144
|
-
name: "liquidityGross",
|
|
11145
|
-
type: "uint128"
|
|
11146
|
-
},
|
|
11147
|
-
{
|
|
11148
|
-
internalType: "int128",
|
|
11149
|
-
name: "liquidityNet",
|
|
11150
|
-
type: "int128"
|
|
11151
|
-
},
|
|
11152
|
-
{
|
|
11153
|
-
internalType: "uint256",
|
|
11154
|
-
name: "feeGrowthOutside0X128",
|
|
11155
|
-
type: "uint256"
|
|
11156
11002
|
},
|
|
11157
11003
|
{
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
type: "uint256"
|
|
11004
|
+
name: "sqrtPriceLimitX96",
|
|
11005
|
+
type: "uint160"
|
|
11161
11006
|
}
|
|
11162
|
-
]
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
|
|
11172
|
-
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
]
|
|
11007
|
+
]
|
|
11008
|
+
}],
|
|
11009
|
+
outputs: [
|
|
11010
|
+
{
|
|
11011
|
+
name: "amountOut",
|
|
11012
|
+
type: "uint256"
|
|
11013
|
+
},
|
|
11014
|
+
{
|
|
11015
|
+
name: "sqrtPriceX96After",
|
|
11016
|
+
type: "uint160"
|
|
11017
|
+
},
|
|
11018
|
+
{
|
|
11019
|
+
name: "initializedTicksCrossed",
|
|
11020
|
+
type: "uint32"
|
|
11021
|
+
},
|
|
11022
|
+
{
|
|
11023
|
+
name: "gasEstimate",
|
|
11024
|
+
type: "uint256"
|
|
11025
|
+
}
|
|
11026
|
+
]
|
|
11027
|
+
}];
|
|
11182
11028
|
|
|
11183
11029
|
//#endregion
|
|
11184
|
-
//#region src/
|
|
11030
|
+
//#region src/uniswap/v3/addresses.ts
|
|
11185
11031
|
/**
|
|
11186
|
-
*
|
|
11187
|
-
*
|
|
11032
|
+
* Verified Uniswap v3 QuoterV2 addresses keyed by chainId. Add a chain only
|
|
11033
|
+
* after verifying against the canonical Uniswap v3 deployment listing.
|
|
11188
11034
|
*/
|
|
11189
|
-
const
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
{
|
|
11210
|
-
internalType: "uint16",
|
|
11211
|
-
name: "observationCardinality",
|
|
11212
|
-
type: "uint16"
|
|
11213
|
-
},
|
|
11214
|
-
{
|
|
11215
|
-
internalType: "uint16",
|
|
11216
|
-
name: "observationCardinalityNext",
|
|
11217
|
-
type: "uint16"
|
|
11218
|
-
},
|
|
11219
|
-
{
|
|
11220
|
-
internalType: "uint8",
|
|
11221
|
-
name: "feeProtocol",
|
|
11222
|
-
type: "uint8"
|
|
11223
|
-
},
|
|
11224
|
-
{
|
|
11225
|
-
internalType: "bool",
|
|
11226
|
-
name: "unlocked",
|
|
11227
|
-
type: "bool"
|
|
11228
|
-
}
|
|
11229
|
-
],
|
|
11230
|
-
stateMutability: "view",
|
|
11231
|
-
type: "function"
|
|
11232
|
-
},
|
|
11233
|
-
{
|
|
11234
|
-
inputs: [],
|
|
11235
|
-
name: "feeGrowthGlobal0X128",
|
|
11236
|
-
outputs: [{
|
|
11237
|
-
internalType: "uint256",
|
|
11238
|
-
name: "",
|
|
11239
|
-
type: "uint256"
|
|
11240
|
-
}],
|
|
11241
|
-
stateMutability: "view",
|
|
11242
|
-
type: "function"
|
|
11243
|
-
},
|
|
11244
|
-
{
|
|
11245
|
-
inputs: [],
|
|
11246
|
-
name: "feeGrowthGlobal1X128",
|
|
11247
|
-
outputs: [{
|
|
11248
|
-
internalType: "uint256",
|
|
11249
|
-
name: "",
|
|
11250
|
-
type: "uint256"
|
|
11251
|
-
}],
|
|
11252
|
-
stateMutability: "view",
|
|
11253
|
-
type: "function"
|
|
11254
|
-
},
|
|
11255
|
-
{
|
|
11256
|
-
inputs: [{
|
|
11257
|
-
internalType: "int24",
|
|
11258
|
-
name: "",
|
|
11259
|
-
type: "int24"
|
|
11260
|
-
}],
|
|
11261
|
-
name: "ticks",
|
|
11262
|
-
outputs: [
|
|
11263
|
-
{
|
|
11264
|
-
internalType: "uint128",
|
|
11265
|
-
name: "liquidityGross",
|
|
11266
|
-
type: "uint128"
|
|
11267
|
-
},
|
|
11268
|
-
{
|
|
11269
|
-
internalType: "int128",
|
|
11270
|
-
name: "liquidityNet",
|
|
11271
|
-
type: "int128"
|
|
11272
|
-
},
|
|
11273
|
-
{
|
|
11274
|
-
internalType: "uint256",
|
|
11275
|
-
name: "feeGrowthOutside0X128",
|
|
11276
|
-
type: "uint256"
|
|
11277
|
-
},
|
|
11278
|
-
{
|
|
11279
|
-
internalType: "uint256",
|
|
11280
|
-
name: "feeGrowthOutside1X128",
|
|
11281
|
-
type: "uint256"
|
|
11282
|
-
},
|
|
11283
|
-
{
|
|
11284
|
-
internalType: "int56",
|
|
11285
|
-
name: "tickCumulativeOutside",
|
|
11286
|
-
type: "int56"
|
|
11287
|
-
},
|
|
11288
|
-
{
|
|
11289
|
-
internalType: "uint160",
|
|
11290
|
-
name: "secondsPerLiquidityOutsideX128",
|
|
11291
|
-
type: "uint160"
|
|
11292
|
-
},
|
|
11293
|
-
{
|
|
11294
|
-
internalType: "uint32",
|
|
11295
|
-
name: "secondsOutside",
|
|
11296
|
-
type: "uint32"
|
|
11297
|
-
},
|
|
11298
|
-
{
|
|
11299
|
-
internalType: "bool",
|
|
11300
|
-
name: "initialized",
|
|
11301
|
-
type: "bool"
|
|
11302
|
-
}
|
|
11303
|
-
],
|
|
11304
|
-
stateMutability: "view",
|
|
11305
|
-
type: "function"
|
|
11306
|
-
},
|
|
11307
|
-
{
|
|
11308
|
-
inputs: [],
|
|
11309
|
-
name: "liquidity",
|
|
11310
|
-
outputs: [{
|
|
11311
|
-
internalType: "uint128",
|
|
11312
|
-
name: "",
|
|
11313
|
-
type: "uint128"
|
|
11314
|
-
}],
|
|
11315
|
-
stateMutability: "view",
|
|
11316
|
-
type: "function"
|
|
11317
|
-
},
|
|
11318
|
-
{
|
|
11319
|
-
inputs: [],
|
|
11320
|
-
name: "fee",
|
|
11321
|
-
outputs: [{
|
|
11322
|
-
internalType: "uint24",
|
|
11323
|
-
name: "",
|
|
11324
|
-
type: "uint24"
|
|
11325
|
-
}],
|
|
11326
|
-
stateMutability: "view",
|
|
11327
|
-
type: "function"
|
|
11328
|
-
},
|
|
11329
|
-
{
|
|
11330
|
-
inputs: [],
|
|
11331
|
-
name: "token0",
|
|
11332
|
-
outputs: [{
|
|
11333
|
-
internalType: "address",
|
|
11334
|
-
name: "",
|
|
11335
|
-
type: "address"
|
|
11336
|
-
}],
|
|
11337
|
-
stateMutability: "view",
|
|
11338
|
-
type: "function"
|
|
11339
|
-
},
|
|
11340
|
-
{
|
|
11341
|
-
inputs: [],
|
|
11342
|
-
name: "token1",
|
|
11343
|
-
outputs: [{
|
|
11344
|
-
internalType: "address",
|
|
11345
|
-
name: "",
|
|
11346
|
-
type: "address"
|
|
11347
|
-
}],
|
|
11348
|
-
stateMutability: "view",
|
|
11349
|
-
type: "function"
|
|
11350
|
-
},
|
|
11351
|
-
{
|
|
11352
|
-
inputs: [],
|
|
11353
|
-
name: "tickSpacing",
|
|
11354
|
-
outputs: [{
|
|
11355
|
-
internalType: "int24",
|
|
11356
|
-
name: "",
|
|
11357
|
-
type: "int24"
|
|
11358
|
-
}],
|
|
11359
|
-
stateMutability: "view",
|
|
11360
|
-
type: "function"
|
|
11361
|
-
}
|
|
11362
|
-
];
|
|
11035
|
+
const UNISWAP_V3_ADDRESSES = { 1: {
|
|
11036
|
+
quoterV2: "0x61fFE014bA17989E743c5F6cB21bF9697530B21e",
|
|
11037
|
+
nonfungiblePositionManager: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88"
|
|
11038
|
+
} };
|
|
11039
|
+
/**
|
|
11040
|
+
* Resolve Uniswap v3 addresses for a chain, applying optional overrides.
|
|
11041
|
+
*
|
|
11042
|
+
* @throws {UnsupportedChainError} when the chain is not listed and overrides do
|
|
11043
|
+
* not supply every required address.
|
|
11044
|
+
*/
|
|
11045
|
+
function getUniswapV3Addresses(chainId, overrides) {
|
|
11046
|
+
const id = Number(chainId);
|
|
11047
|
+
const base = UNISWAP_V3_ADDRESSES[id];
|
|
11048
|
+
const merged = {
|
|
11049
|
+
...base,
|
|
11050
|
+
...overrides
|
|
11051
|
+
};
|
|
11052
|
+
if (!merged.quoterV2 || !merged.nonfungiblePositionManager) throw new UnsupportedChainError(BigInt(id));
|
|
11053
|
+
return merged;
|
|
11054
|
+
}
|
|
11363
11055
|
|
|
11364
11056
|
//#endregion
|
|
11365
|
-
//#region src/
|
|
11366
|
-
const
|
|
11367
|
-
const
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
|
|
11371
|
-
|
|
11372
|
-
|
|
11373
|
-
|
|
11057
|
+
//#region src/uniswap/v3/router/quote.ts
|
|
11058
|
+
const BPS_DENOMINATOR$5 = 10000n;
|
|
11059
|
+
const UINT128_MAX$3 = (1n << 128n) - 1n;
|
|
11060
|
+
/**
|
|
11061
|
+
* Quote an exact-in v3 swap. Returns `null` when the quote reverts (e.g. the
|
|
11062
|
+
* pool does not exist / has no liquidity) so callers can skip that pool when
|
|
11063
|
+
* ranking venues, rather than aborting the whole cycle.
|
|
11064
|
+
*/
|
|
11065
|
+
async function quoteV3ExactIn(params) {
|
|
11066
|
+
const { client, chainId, tokenIn, tokenOut, fee, amountIn, slippageBps, blockNumber } = params;
|
|
11067
|
+
if (amountIn < 0n || amountIn > UINT128_MAX$3) throw new PanopticError(`amountIn ${amountIn} exceeds uint128 maximum`);
|
|
11068
|
+
if (slippageBps < 0n || slippageBps > BPS_DENOMINATOR$5) throw new PanopticError(`invalid slippageBps ${slippageBps}, must be 0..10000`);
|
|
11069
|
+
const { quoterV2 } = getUniswapV3Addresses(chainId, params.addresses);
|
|
11070
|
+
try {
|
|
11071
|
+
const { result } = await client.simulateContract({
|
|
11072
|
+
address: quoterV2,
|
|
11073
|
+
abi: quoterV2Abi,
|
|
11074
|
+
functionName: "quoteExactInputSingle",
|
|
11075
|
+
blockNumber,
|
|
11076
|
+
args: [{
|
|
11077
|
+
tokenIn,
|
|
11078
|
+
tokenOut,
|
|
11079
|
+
amountIn,
|
|
11080
|
+
fee: Number(fee),
|
|
11081
|
+
sqrtPriceLimitX96: 0n
|
|
11082
|
+
}]
|
|
11083
|
+
});
|
|
11084
|
+
const [amountOut, , , gasEstimate] = result;
|
|
11085
|
+
const amountOutMinimum = amountOut * (BPS_DENOMINATOR$5 - slippageBps) / BPS_DENOMINATOR$5;
|
|
11086
|
+
return {
|
|
11087
|
+
amountOut,
|
|
11088
|
+
amountOutMinimum,
|
|
11089
|
+
gasEstimate
|
|
11090
|
+
};
|
|
11091
|
+
} catch (err) {
|
|
11092
|
+
if (isRevert(err)) return null;
|
|
11093
|
+
throw err;
|
|
11094
|
+
}
|
|
11374
11095
|
}
|
|
11375
|
-
|
|
11376
|
-
|
|
11377
|
-
|
|
11378
|
-
let end = value.length;
|
|
11379
|
-
while (end > dotIndex && value[end - 1] === "0") end -= 1;
|
|
11380
|
-
if (end === dotIndex + 1) end = dotIndex;
|
|
11381
|
-
return value.slice(0, end);
|
|
11096
|
+
/** True only for genuine contract reverts (missing pool / no liquidity). */
|
|
11097
|
+
function isRevert(err) {
|
|
11098
|
+
return err instanceof BaseError && err.walk((e) => e instanceof ContractFunctionRevertedError) instanceof ContractFunctionRevertedError;
|
|
11382
11099
|
}
|
|
11383
|
-
|
|
11384
|
-
|
|
11385
|
-
|
|
11386
|
-
|
|
11387
|
-
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
11100
|
+
|
|
11101
|
+
//#endregion
|
|
11102
|
+
//#region src/panoptic/v2/reads/sfpm.ts
|
|
11103
|
+
/**
|
|
11104
|
+
* Resolve an SFPM poolId to its corresponding Uniswap V3 pool address.
|
|
11105
|
+
*
|
|
11106
|
+
* Calls `SemiFungiblePositionManagerV3.getUniswapV3PoolFromId(poolId)`.
|
|
11107
|
+
*/
|
|
11108
|
+
async function getUniswapV3PoolFromId(params) {
|
|
11109
|
+
const { client, sfpmAddress, poolId } = params;
|
|
11110
|
+
return client.readContract({
|
|
11111
|
+
address: sfpmAddress,
|
|
11112
|
+
abi: semiFungiblePositionManagerV3Abi,
|
|
11113
|
+
functionName: "getUniswapV3PoolFromId",
|
|
11114
|
+
args: [poolId]
|
|
11115
|
+
});
|
|
11393
11116
|
}
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
const
|
|
11401
|
-
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
const exponent = BigInt(exponentPart);
|
|
11408
|
-
if (exponent > 0n) numerator *= pow10(exponent);
|
|
11409
|
-
else if (exponent < 0n) denominator *= pow10(-exponent);
|
|
11410
|
-
}
|
|
11411
|
-
if (isNegative) numerator = -numerator;
|
|
11117
|
+
/**
|
|
11118
|
+
* Resolve an SFPM poolId to its corresponding Uniswap V4 pool key.
|
|
11119
|
+
*
|
|
11120
|
+
* Calls `SemiFungiblePositionManagerV4.getUniswapV4PoolKeyFromId(poolId)`.
|
|
11121
|
+
*/
|
|
11122
|
+
async function getUniswapV4PoolKeyFromId(params) {
|
|
11123
|
+
const { client, sfpmAddress, poolId } = params;
|
|
11124
|
+
const raw = await client.readContract({
|
|
11125
|
+
address: sfpmAddress,
|
|
11126
|
+
abi: semiFungiblePositionManagerV4Abi,
|
|
11127
|
+
functionName: "getUniswapV4PoolKeyFromId",
|
|
11128
|
+
args: [poolId]
|
|
11129
|
+
});
|
|
11412
11130
|
return {
|
|
11413
|
-
|
|
11414
|
-
|
|
11131
|
+
currency0: raw.currency0,
|
|
11132
|
+
currency1: raw.currency1,
|
|
11133
|
+
fee: BigInt(raw.fee),
|
|
11134
|
+
tickSpacing: BigInt(raw.tickSpacing),
|
|
11135
|
+
hooks: raw.hooks
|
|
11415
11136
|
};
|
|
11416
11137
|
}
|
|
11417
|
-
|
|
11418
|
-
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
11422
|
-
|
|
11423
|
-
function
|
|
11424
|
-
|
|
11425
|
-
const
|
|
11426
|
-
|
|
11427
|
-
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
|
|
11431
|
-
|
|
11432
|
-
|
|
11433
|
-
|
|
11434
|
-
|
|
11435
|
-
if ((absTick & 0x200n) !== 0n) ratio = ratio * 0xf987a7253ac413176f2b074cf7815e54n >> 128n;
|
|
11436
|
-
if ((absTick & 0x400n) !== 0n) ratio = ratio * 0xf3392b0822b70005940c7a398e4b70f3n >> 128n;
|
|
11437
|
-
if ((absTick & 0x800n) !== 0n) ratio = ratio * 0xe7159475a2c29b7443b29c7fa6e889d9n >> 128n;
|
|
11438
|
-
if ((absTick & 0x1000n) !== 0n) ratio = ratio * 0xd097f3bdfd2022b8845ad8f792aa5825n >> 128n;
|
|
11439
|
-
if ((absTick & 0x2000n) !== 0n) ratio = ratio * 0xa9f746462d870fdf8a65dc1f90e061e5n >> 128n;
|
|
11440
|
-
if ((absTick & 0x4000n) !== 0n) ratio = ratio * 0x70d869a156d2a1b890bb3df62baf32f7n >> 128n;
|
|
11441
|
-
if ((absTick & 0x8000n) !== 0n) ratio = ratio * 0x31be135f97d08fd981231505542fcfa6n >> 128n;
|
|
11442
|
-
if ((absTick & 0x10000n) !== 0n) ratio = ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9n >> 128n;
|
|
11443
|
-
if ((absTick & 0x20000n) !== 0n) ratio = ratio * 0x5d6af8dedb81196699c329225ee604n >> 128n;
|
|
11444
|
-
if ((absTick & 0x40000n) !== 0n) ratio = ratio * 0x2216e584f5fa1ea926041bedfe98n >> 128n;
|
|
11445
|
-
if ((absTick & 0x80000n) !== 0n) ratio = ratio * 0x48a170391f7dc42444e8fa2n >> 128n;
|
|
11446
|
-
if (tick > 0n) ratio = ((1n << 256n) - 1n) / ratio;
|
|
11447
|
-
const remainderMask = (1n << 32n) - 1n;
|
|
11448
|
-
const sqrtPriceX96 = (ratio >> 32n) + ((ratio & remainderMask) === 0n ? 0n : 1n);
|
|
11449
|
-
return sqrtPriceX96;
|
|
11138
|
+
/**
|
|
11139
|
+
* Get the enforced tick limits for a pool from the SFPM.
|
|
11140
|
+
*
|
|
11141
|
+
* @param params - The parameters
|
|
11142
|
+
* @returns The min and max enforced ticks
|
|
11143
|
+
*/
|
|
11144
|
+
async function getEnforcedTickLimits(params) {
|
|
11145
|
+
const { client, sfpmAddress, poolId } = params;
|
|
11146
|
+
const [minTick, maxTick] = await client.readContract({
|
|
11147
|
+
address: sfpmAddress,
|
|
11148
|
+
abi: semiFungiblePositionManagerV4Abi,
|
|
11149
|
+
functionName: "getEnforcedTickLimits",
|
|
11150
|
+
args: [poolId]
|
|
11151
|
+
});
|
|
11152
|
+
return {
|
|
11153
|
+
minEnforcedTick: minTick,
|
|
11154
|
+
maxEnforcedTick: maxTick
|
|
11155
|
+
};
|
|
11450
11156
|
}
|
|
11451
|
-
|
|
11452
|
-
|
|
11453
|
-
|
|
11157
|
+
/**
|
|
11158
|
+
* Fetch liquidity breakdown for a batch of chunks via SFPM.getAccountLiquidity().
|
|
11159
|
+
*
|
|
11160
|
+
* Uses multicall for efficiency. Returns one result per input chunk,
|
|
11161
|
+
* along with block metadata for freshness tracking.
|
|
11162
|
+
*/
|
|
11163
|
+
async function getChunkLiquidities(params) {
|
|
11164
|
+
const { client, sfpmAddress, poolKeyBytes, chunks } = params;
|
|
11165
|
+
if (chunks.length > MAX_TRACKED_CHUNKS) throw new ChunkLimitError(BigInt(chunks.length), 0n);
|
|
11166
|
+
const _meta = params._meta ?? await getBlockMeta({ client });
|
|
11167
|
+
if (chunks.length === 0) return {
|
|
11168
|
+
results: [],
|
|
11169
|
+
_meta
|
|
11170
|
+
};
|
|
11171
|
+
const multicallResults = await client.multicall({
|
|
11172
|
+
contracts: chunks.map((chunk) => ({
|
|
11173
|
+
address: sfpmAddress,
|
|
11174
|
+
abi: semiFungiblePositionManagerV4Abi,
|
|
11175
|
+
functionName: "getAccountLiquidity",
|
|
11176
|
+
args: [
|
|
11177
|
+
poolKeyBytes,
|
|
11178
|
+
chunk.owner,
|
|
11179
|
+
chunk.tokenType,
|
|
11180
|
+
Number(chunk.tickLower),
|
|
11181
|
+
Number(chunk.tickUpper)
|
|
11182
|
+
]
|
|
11183
|
+
})),
|
|
11184
|
+
allowFailure: true
|
|
11185
|
+
});
|
|
11186
|
+
const results = multicallResults.map((result) => {
|
|
11187
|
+
if (result.status === "failure") return {
|
|
11188
|
+
netLiquidity: 0n,
|
|
11189
|
+
removedLiquidity: 0n,
|
|
11190
|
+
totalLiquidity: 0n,
|
|
11191
|
+
shortLiquidity: 0n,
|
|
11192
|
+
longLiquidity: 0n
|
|
11193
|
+
};
|
|
11194
|
+
const packed = result.result;
|
|
11195
|
+
const netLiquidity = packed & (1n << 128n) - 1n;
|
|
11196
|
+
const removedLiquidity = packed >> 128n;
|
|
11197
|
+
const totalLiquidity = netLiquidity + removedLiquidity;
|
|
11198
|
+
return {
|
|
11199
|
+
netLiquidity,
|
|
11200
|
+
removedLiquidity,
|
|
11201
|
+
totalLiquidity,
|
|
11202
|
+
shortLiquidity: totalLiquidity,
|
|
11203
|
+
longLiquidity: removedLiquidity
|
|
11204
|
+
};
|
|
11205
|
+
});
|
|
11454
11206
|
return {
|
|
11455
|
-
|
|
11456
|
-
|
|
11207
|
+
results,
|
|
11208
|
+
_meta
|
|
11457
11209
|
};
|
|
11458
11210
|
}
|
|
11459
|
-
|
|
11460
|
-
|
|
11211
|
+
|
|
11212
|
+
//#endregion
|
|
11213
|
+
//#region src/panoptic/v2/reads/factory.ts
|
|
11214
|
+
/**
|
|
11215
|
+
* Get the token URI from a PanopticFactory NFT.
|
|
11216
|
+
*/
|
|
11217
|
+
async function getFactoryTokenURI(params) {
|
|
11218
|
+
const { client, factoryAddress, version, tokenId } = params;
|
|
11219
|
+
const abi = version === "v3" ? panopticFactoryV3Abi : panopticFactoryV4Abi;
|
|
11220
|
+
return client.readContract({
|
|
11221
|
+
address: factoryAddress,
|
|
11222
|
+
abi,
|
|
11223
|
+
functionName: "tokenURI",
|
|
11224
|
+
args: [tokenId]
|
|
11225
|
+
});
|
|
11461
11226
|
}
|
|
11462
|
-
|
|
11463
|
-
|
|
11464
|
-
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11227
|
+
/**
|
|
11228
|
+
* Get the owner of a PanopticFactory NFT.
|
|
11229
|
+
*/
|
|
11230
|
+
async function getFactoryOwnerOf(params) {
|
|
11231
|
+
const { client, factoryAddress, version, tokenId } = params;
|
|
11232
|
+
const abi = version === "v3" ? panopticFactoryV3Abi : panopticFactoryV4Abi;
|
|
11233
|
+
return client.readContract({
|
|
11234
|
+
address: factoryAddress,
|
|
11235
|
+
abi,
|
|
11236
|
+
functionName: "ownerOf",
|
|
11237
|
+
args: [tokenId]
|
|
11238
|
+
});
|
|
11239
|
+
}
|
|
11240
|
+
/**
|
|
11241
|
+
* Construct NFT metadata for a pool via the factory contract.
|
|
11242
|
+
*/
|
|
11243
|
+
async function getFactoryConstructMetadata(params) {
|
|
11244
|
+
const { client, factoryAddress, version, panopticPoolAddress, symbol0, symbol1, fee } = params;
|
|
11245
|
+
const abi = version === "v3" ? panopticFactoryV3Abi : panopticFactoryV4Abi;
|
|
11246
|
+
return client.readContract({
|
|
11247
|
+
address: factoryAddress,
|
|
11248
|
+
abi,
|
|
11249
|
+
functionName: "constructMetadata",
|
|
11250
|
+
args: [
|
|
11251
|
+
panopticPoolAddress,
|
|
11252
|
+
symbol0,
|
|
11253
|
+
symbol1,
|
|
11254
|
+
fee
|
|
11255
|
+
]
|
|
11256
|
+
});
|
|
11257
|
+
}
|
|
11258
|
+
/**
|
|
11259
|
+
* Get the PanopticPool address for a given pool and risk engine.
|
|
11260
|
+
*/
|
|
11261
|
+
async function getPanopticPoolAddress(params) {
|
|
11262
|
+
const { client, factoryAddress, riskEngine } = params;
|
|
11263
|
+
if (params.version === "v3") return client.readContract({
|
|
11264
|
+
address: factoryAddress,
|
|
11265
|
+
abi: panopticFactoryV3Abi,
|
|
11266
|
+
functionName: "getPanopticPool",
|
|
11267
|
+
args: [params.univ3pool, riskEngine]
|
|
11268
|
+
});
|
|
11269
|
+
return client.readContract({
|
|
11270
|
+
address: factoryAddress,
|
|
11271
|
+
abi: panopticFactoryV4Abi,
|
|
11272
|
+
functionName: "getPanopticPool",
|
|
11273
|
+
args: [{
|
|
11274
|
+
currency0: params.poolKey.currency0,
|
|
11275
|
+
currency1: params.poolKey.currency1,
|
|
11276
|
+
fee: Number(params.poolKey.fee),
|
|
11277
|
+
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
11278
|
+
hooks: params.poolKey.hooks
|
|
11279
|
+
}, riskEngine]
|
|
11280
|
+
});
|
|
11281
|
+
}
|
|
11282
|
+
/**
|
|
11283
|
+
* Mine for an optimal pool address salt with high rarity.
|
|
11284
|
+
*/
|
|
11285
|
+
async function minePoolAddress(params) {
|
|
11286
|
+
const { client, factoryAddress, deployerAddress, riskEngine, salt, loops, minTargetRarity } = params;
|
|
11287
|
+
let result;
|
|
11288
|
+
if (params.version === "v3") result = await client.readContract({
|
|
11289
|
+
address: factoryAddress,
|
|
11290
|
+
abi: panopticFactoryV3Abi,
|
|
11291
|
+
functionName: "minePoolAddress",
|
|
11292
|
+
args: [
|
|
11293
|
+
deployerAddress,
|
|
11294
|
+
params.v3Pool,
|
|
11295
|
+
riskEngine,
|
|
11296
|
+
salt,
|
|
11297
|
+
loops,
|
|
11298
|
+
minTargetRarity
|
|
11299
|
+
]
|
|
11300
|
+
});
|
|
11301
|
+
else result = await client.readContract({
|
|
11302
|
+
address: factoryAddress,
|
|
11303
|
+
abi: panopticFactoryV4Abi,
|
|
11304
|
+
functionName: "minePoolAddress",
|
|
11305
|
+
args: [
|
|
11306
|
+
deployerAddress,
|
|
11307
|
+
{
|
|
11308
|
+
currency0: params.poolKey.currency0,
|
|
11309
|
+
currency1: params.poolKey.currency1,
|
|
11310
|
+
fee: Number(params.poolKey.fee),
|
|
11311
|
+
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
11312
|
+
hooks: params.poolKey.hooks
|
|
11313
|
+
},
|
|
11314
|
+
riskEngine,
|
|
11315
|
+
salt,
|
|
11316
|
+
loops,
|
|
11317
|
+
minTargetRarity
|
|
11318
|
+
]
|
|
11319
|
+
});
|
|
11472
11320
|
return {
|
|
11473
|
-
|
|
11474
|
-
|
|
11321
|
+
bestSalt: BigInt(result[0]),
|
|
11322
|
+
highestRarity: result[1]
|
|
11475
11323
|
};
|
|
11476
11324
|
}
|
|
11477
11325
|
/**
|
|
11478
|
-
*
|
|
11479
|
-
* Uses the formula: price = 1.0001^tick
|
|
11480
|
-
*
|
|
11481
|
-
* This returns the raw price ratio, not adjusted for token decimals.
|
|
11482
|
-
* A fixed internal precision is used and trailing zeros are trimmed.
|
|
11483
|
-
*
|
|
11484
|
-
* @param tick - The tick value
|
|
11485
|
-
* @returns Price string
|
|
11326
|
+
* Simulate a pool deployment to get the predicted pool address.
|
|
11486
11327
|
*
|
|
11487
|
-
*
|
|
11488
|
-
*
|
|
11489
|
-
* tickToPrice(0n) // "1"
|
|
11490
|
-
* tickToPrice(1000n) // "1.105..." (approximately)
|
|
11491
|
-
* tickToPrice(-1000n) // "0.904..." (approximately)
|
|
11492
|
-
* tickToPrice(200000n) // Very large number
|
|
11493
|
-
* ```
|
|
11328
|
+
* Uses `simulateContract` on `deployNewPool` — the return value is the new pool address
|
|
11329
|
+
* without actually executing the transaction.
|
|
11494
11330
|
*/
|
|
11495
|
-
function
|
|
11496
|
-
const {
|
|
11497
|
-
|
|
11498
|
-
|
|
11331
|
+
async function simulateDeployNewPool(params) {
|
|
11332
|
+
const { client, factoryAddress, account, riskEngine, salt } = params;
|
|
11333
|
+
if (params.version === "v3") {
|
|
11334
|
+
const { result: result$1 } = await client.simulateContract({
|
|
11335
|
+
address: factoryAddress,
|
|
11336
|
+
abi: panopticFactoryV3Abi,
|
|
11337
|
+
functionName: "deployNewPool",
|
|
11338
|
+
args: [
|
|
11339
|
+
params.token0,
|
|
11340
|
+
params.token1,
|
|
11341
|
+
Number(params.fee),
|
|
11342
|
+
riskEngine,
|
|
11343
|
+
salt
|
|
11344
|
+
],
|
|
11345
|
+
account
|
|
11346
|
+
});
|
|
11347
|
+
return result$1;
|
|
11348
|
+
}
|
|
11349
|
+
const { result } = await client.simulateContract({
|
|
11350
|
+
address: factoryAddress,
|
|
11351
|
+
abi: panopticFactoryV4Abi,
|
|
11352
|
+
functionName: "deployNewPool",
|
|
11353
|
+
args: [
|
|
11354
|
+
{
|
|
11355
|
+
currency0: params.poolKey.currency0,
|
|
11356
|
+
currency1: params.poolKey.currency1,
|
|
11357
|
+
fee: Number(params.poolKey.fee),
|
|
11358
|
+
tickSpacing: Number(params.poolKey.tickSpacing),
|
|
11359
|
+
hooks: params.poolKey.hooks
|
|
11360
|
+
},
|
|
11361
|
+
riskEngine,
|
|
11362
|
+
salt
|
|
11363
|
+
],
|
|
11364
|
+
account
|
|
11365
|
+
});
|
|
11366
|
+
return result;
|
|
11499
11367
|
}
|
|
11500
11368
|
/**
|
|
11501
|
-
*
|
|
11502
|
-
* Uses the formula: price = 1.0001^tick * 10^(decimals0-decimals1)
|
|
11503
|
-
*
|
|
11504
|
-
* This adjusts for the different decimals of the two tokens in the pair.
|
|
11505
|
-
*
|
|
11506
|
-
* @param tick - The tick value
|
|
11507
|
-
* @param decimals0 - Decimals of token0
|
|
11508
|
-
* @param decimals1 - Decimals of token1
|
|
11509
|
-
* @param precision - Number of decimal places to display
|
|
11510
|
-
* @returns Formatted price string
|
|
11511
|
-
*
|
|
11512
|
-
* @example
|
|
11513
|
-
* ```typescript
|
|
11514
|
-
* // WETH/USDC pool (18 decimals / 6 decimals)
|
|
11515
|
-
* // At tick ~200000, price is roughly $2000 per ETH
|
|
11516
|
-
* tickToPriceDecimalScaled(200000n, 18n, 6n, 2n) // "2000.00" (approximately)
|
|
11369
|
+
* Resolve an SFPM poolId to its PanopticPool address.
|
|
11517
11370
|
*
|
|
11518
|
-
*
|
|
11519
|
-
*
|
|
11520
|
-
*
|
|
11371
|
+
* Chains two on-chain lookups:
|
|
11372
|
+
* 1. SFPM: poolId → Uniswap pool address (V3) or pool key (V4)
|
|
11373
|
+
* 2. Factory: Uniswap pool + riskEngine → PanopticPool address
|
|
11521
11374
|
*/
|
|
11522
|
-
function
|
|
11523
|
-
const
|
|
11524
|
-
|
|
11525
|
-
|
|
11375
|
+
async function getPanopticPoolFromPoolId(params) {
|
|
11376
|
+
const { client, sfpmAddress, factoryAddress, riskEngine, poolId, version } = params;
|
|
11377
|
+
if (version === "v3") {
|
|
11378
|
+
const univ3pool = await getUniswapV3PoolFromId({
|
|
11379
|
+
client,
|
|
11380
|
+
sfpmAddress,
|
|
11381
|
+
poolId
|
|
11382
|
+
});
|
|
11383
|
+
return getPanopticPoolAddress({
|
|
11384
|
+
version: "v3",
|
|
11385
|
+
client,
|
|
11386
|
+
factoryAddress,
|
|
11387
|
+
univ3pool,
|
|
11388
|
+
riskEngine
|
|
11389
|
+
});
|
|
11390
|
+
}
|
|
11391
|
+
const poolKey = await getUniswapV4PoolKeyFromId({
|
|
11392
|
+
client,
|
|
11393
|
+
sfpmAddress,
|
|
11394
|
+
poolId
|
|
11395
|
+
});
|
|
11396
|
+
return getPanopticPoolAddress({
|
|
11397
|
+
version: "v4",
|
|
11398
|
+
client,
|
|
11399
|
+
factoryAddress,
|
|
11400
|
+
poolKey,
|
|
11401
|
+
riskEngine
|
|
11402
|
+
});
|
|
11526
11403
|
}
|
|
11527
11404
|
/**
|
|
11528
|
-
*
|
|
11405
|
+
* Resolve an SFPM poolId to its PanopticPool address without knowing the version.
|
|
11529
11406
|
*
|
|
11530
|
-
*
|
|
11407
|
+
* Tries both V3 and V4 lookups in parallel. The factory returns `address(0)` for
|
|
11408
|
+
* non-existent pools, so the non-zero result identifies the correct version.
|
|
11531
11409
|
*
|
|
11532
|
-
*
|
|
11533
|
-
* @param decimals0 - Decimals of token0
|
|
11534
|
-
* @param decimals1 - Decimals of token1
|
|
11535
|
-
* @param precision - Number of decimal places to display
|
|
11536
|
-
* @returns Formatted price string
|
|
11410
|
+
* At least one of `v3` or `v4` must be provided.
|
|
11537
11411
|
*
|
|
11538
|
-
* @
|
|
11539
|
-
* ```typescript
|
|
11540
|
-
* sqrtPriceX96ToPriceDecimalScaled(2n ** 96n, 18n, 18n, 2n) // "1.00"
|
|
11541
|
-
* ```
|
|
11412
|
+
* @throws {PanopticValidationError} If no version config is provided or neither resolves.
|
|
11542
11413
|
*/
|
|
11543
|
-
function
|
|
11544
|
-
const
|
|
11545
|
-
|
|
11546
|
-
|
|
11414
|
+
async function resolvePanopticPoolFromPoolId(params) {
|
|
11415
|
+
const { client, poolId, riskEngine, v3, v4 } = params;
|
|
11416
|
+
if (!v3 && !v4) throw new Error("At least one of v3 or v4 must be provided");
|
|
11417
|
+
const isNotFoundError = (err) => {
|
|
11418
|
+
if (typeof err === "object" && err !== null && "name" in err) {
|
|
11419
|
+
const name = err.name;
|
|
11420
|
+
return name === "ContractFunctionExecutionError" || name === "ContractFunctionRevertedError";
|
|
11421
|
+
}
|
|
11422
|
+
return false;
|
|
11423
|
+
};
|
|
11424
|
+
const results = await Promise.all([v3 ? getPanopticPoolFromPoolId({
|
|
11425
|
+
version: "v3",
|
|
11426
|
+
client,
|
|
11427
|
+
sfpmAddress: v3.sfpmAddress,
|
|
11428
|
+
factoryAddress: v3.factoryAddress,
|
|
11429
|
+
riskEngine,
|
|
11430
|
+
poolId
|
|
11431
|
+
}).catch((err) => {
|
|
11432
|
+
if (isNotFoundError(err)) return zeroAddress;
|
|
11433
|
+
throw err;
|
|
11434
|
+
}) : Promise.resolve(zeroAddress), v4 ? getPanopticPoolFromPoolId({
|
|
11435
|
+
version: "v4",
|
|
11436
|
+
client,
|
|
11437
|
+
sfpmAddress: v4.sfpmAddress,
|
|
11438
|
+
factoryAddress: v4.factoryAddress,
|
|
11439
|
+
riskEngine,
|
|
11440
|
+
poolId
|
|
11441
|
+
}).catch((err) => {
|
|
11442
|
+
if (isNotFoundError(err)) return zeroAddress;
|
|
11443
|
+
throw err;
|
|
11444
|
+
}) : Promise.resolve(zeroAddress)]);
|
|
11445
|
+
const [v3Result, v4Result] = results;
|
|
11446
|
+
if (v3Result !== zeroAddress) return {
|
|
11447
|
+
panopticPoolAddress: v3Result,
|
|
11448
|
+
version: "v3"
|
|
11449
|
+
};
|
|
11450
|
+
if (v4Result !== zeroAddress) return {
|
|
11451
|
+
panopticPoolAddress: v4Result,
|
|
11452
|
+
version: "v4"
|
|
11453
|
+
};
|
|
11454
|
+
throw new Error(`No PanopticPool found for poolId ${poolId}`);
|
|
11547
11455
|
}
|
|
11456
|
+
|
|
11457
|
+
//#endregion
|
|
11458
|
+
//#region src/panoptic/v2/reads/minePoolAddressLocal.ts
|
|
11548
11459
|
/**
|
|
11549
|
-
*
|
|
11550
|
-
*
|
|
11551
|
-
* @param price - The price string
|
|
11552
|
-
* @param decimals0 - Decimals of token0
|
|
11553
|
-
* @param decimals1 - Decimals of token1
|
|
11554
|
-
* @returns The tick value (rounded to nearest integer)
|
|
11555
|
-
*
|
|
11556
|
-
* @example
|
|
11557
|
-
* ```typescript
|
|
11558
|
-
* // WETH/USDC: What tick for $2000 per ETH?
|
|
11559
|
-
* priceToTick("2000", 18n, 6n) // ~200000n
|
|
11560
|
-
*
|
|
11561
|
-
* // Inverse: What tick for 0.0005 ETH per USDC?
|
|
11562
|
-
* priceToTick("0.0005", 6n, 18n) // ~200000n
|
|
11563
|
-
* ```
|
|
11460
|
+
* keccak256 of the CREATE3 proxy initcode used by ClonesWithImmutableArgs.
|
|
11461
|
+
* Source: packages/panoptic-v2-core/lib/clones-with-immutable-args/src/ClonesWithImmutableArgs.sol
|
|
11564
11462
|
*/
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
let
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
const mid = (low + high) / 2n;
|
|
11577
|
-
const { numerator, denominator } = getRawPriceRatio(mid);
|
|
11578
|
-
const cmp = compareRatios(numerator, denominator, targetNumerator, targetDenominator);
|
|
11579
|
-
if (cmp === 0) return mid;
|
|
11580
|
-
if (cmp < 0) low = mid + 1n;
|
|
11581
|
-
else high = mid - 1n;
|
|
11463
|
+
const CREATE3_PROXY_BYTECODE_HASH = "0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f";
|
|
11464
|
+
const MASK_80 = (1n << 80n) - 1n;
|
|
11465
|
+
const MASK_40 = (1n << 40n) - 1n;
|
|
11466
|
+
const MASK_96 = (1n << 96n) - 1n;
|
|
11467
|
+
/** Encode a BigInt as a big-endian fixed-length byte array. */
|
|
11468
|
+
function bigintToBytes(value, byteLength) {
|
|
11469
|
+
const bytes = new Uint8Array(byteLength);
|
|
11470
|
+
let v = value;
|
|
11471
|
+
for (let i = byteLength - 1; i >= 0; i--) {
|
|
11472
|
+
bytes[i] = Number(v & 0xffn);
|
|
11473
|
+
v >>= 8n;
|
|
11582
11474
|
}
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
const
|
|
11588
|
-
const
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11475
|
+
return bytes;
|
|
11476
|
+
}
|
|
11477
|
+
/** Parse a 0x-prefixed address into 20 bytes. */
|
|
11478
|
+
function addressToBytes(addr) {
|
|
11479
|
+
const hex = addr.slice(2).padStart(40, "0");
|
|
11480
|
+
const bytes = new Uint8Array(20);
|
|
11481
|
+
for (let i = 0; i < 20; i++) bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
11482
|
+
return bytes;
|
|
11483
|
+
}
|
|
11484
|
+
/** Parse a 0x-prefixed 32-byte hex string into bytes. */
|
|
11485
|
+
function hex32ToBytes(hex) {
|
|
11486
|
+
const h = hex.slice(2).padStart(64, "0");
|
|
11487
|
+
const bytes = new Uint8Array(32);
|
|
11488
|
+
for (let i = 0; i < 32; i++) bytes[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16);
|
|
11489
|
+
return bytes;
|
|
11594
11490
|
}
|
|
11595
11491
|
/**
|
|
11596
|
-
*
|
|
11492
|
+
* Compute the CREATE3 deployed address for a given factory and packed salt.
|
|
11597
11493
|
*
|
|
11598
|
-
*
|
|
11599
|
-
*
|
|
11494
|
+
* Mirrors `ClonesWithImmutableArgs.addressOfClone3(salt)` (with `address(this)` = factory):
|
|
11495
|
+
* proxy = CREATE2(factory, salt, PROXY_BYTECODE_HASH)
|
|
11496
|
+
* deployed = CREATE1(proxy, nonce=1)
|
|
11600
11497
|
*
|
|
11601
|
-
*
|
|
11602
|
-
* ```typescript
|
|
11603
|
-
* const tick = sqrtPriceX96ToTick(2n ** 96n) // 0n
|
|
11604
|
-
* ```
|
|
11498
|
+
* Returns the deployed address as a uint160 BigInt.
|
|
11605
11499
|
*/
|
|
11606
|
-
function
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
|
|
11612
|
-
|
|
11613
|
-
|
|
11614
|
-
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
const floorDiff = absBigint(sqrtPriceX96 - floorSqrt);
|
|
11625
|
-
const ceilDiff = absBigint(ceilSqrt - sqrtPriceX96);
|
|
11626
|
-
return floorDiff <= ceilDiff ? floorTick : ceilTick;
|
|
11500
|
+
function addressOfClone3(factory, salt) {
|
|
11501
|
+
const saltBytes = bigintToBytes(salt, 32);
|
|
11502
|
+
const create2Input = new Uint8Array(85);
|
|
11503
|
+
create2Input[0] = 255;
|
|
11504
|
+
create2Input.set(addressToBytes(factory), 1);
|
|
11505
|
+
create2Input.set(saltBytes, 21);
|
|
11506
|
+
create2Input.set(hex32ToBytes(CREATE3_PROXY_BYTECODE_HASH), 53);
|
|
11507
|
+
const proxyHash = keccak256(create2Input, "bytes");
|
|
11508
|
+
const proxyAddress = proxyHash.slice(12);
|
|
11509
|
+
const create1Input = new Uint8Array(23);
|
|
11510
|
+
create1Input[0] = 214;
|
|
11511
|
+
create1Input[1] = 148;
|
|
11512
|
+
create1Input.set(proxyAddress, 2);
|
|
11513
|
+
create1Input[22] = 1;
|
|
11514
|
+
const deployedHash = keccak256(create1Input, "bytes");
|
|
11515
|
+
let addr = 0n;
|
|
11516
|
+
for (let i = 12; i < 32; i++) addr = addr << 8n | BigInt(deployedHash[i]);
|
|
11517
|
+
return addr;
|
|
11627
11518
|
}
|
|
11628
11519
|
/**
|
|
11629
|
-
*
|
|
11630
|
-
*
|
|
11631
|
-
* @param tick - The tick value
|
|
11632
|
-
* @returns Formatted tick string
|
|
11520
|
+
* Count leading hex-zero characters in a 160-bit address value.
|
|
11633
11521
|
*
|
|
11634
|
-
*
|
|
11635
|
-
*
|
|
11636
|
-
* formatTick(200000n) // "200000"
|
|
11637
|
-
* formatTick(-50000n) // "-50000"
|
|
11638
|
-
* ```
|
|
11522
|
+
* Mirrors `PanopticMath.numberOfLeadingHexZeros(addr)`.
|
|
11523
|
+
* Returns 40 for the zero address.
|
|
11639
11524
|
*/
|
|
11640
|
-
function
|
|
11641
|
-
|
|
11525
|
+
function numberOfLeadingHexZeros(addrInt) {
|
|
11526
|
+
if (addrInt === 0n) return 40;
|
|
11527
|
+
let x = addrInt;
|
|
11528
|
+
let r = 0;
|
|
11529
|
+
if (x >= 0x100000000000000000000000000000000n) {
|
|
11530
|
+
x >>= 128n;
|
|
11531
|
+
r += 32;
|
|
11532
|
+
}
|
|
11533
|
+
if (x >= 0x10000000000000000n) {
|
|
11534
|
+
x >>= 64n;
|
|
11535
|
+
r += 16;
|
|
11536
|
+
}
|
|
11537
|
+
if (x >= 0x100000000n) {
|
|
11538
|
+
x >>= 32n;
|
|
11539
|
+
r += 8;
|
|
11540
|
+
}
|
|
11541
|
+
if (x >= 0x10000n) {
|
|
11542
|
+
x >>= 16n;
|
|
11543
|
+
r += 4;
|
|
11544
|
+
}
|
|
11545
|
+
if (x >= 0x100n) {
|
|
11546
|
+
x >>= 8n;
|
|
11547
|
+
r += 2;
|
|
11548
|
+
}
|
|
11549
|
+
if (x >= 0x10n) r += 1;
|
|
11550
|
+
return 39 - r;
|
|
11642
11551
|
}
|
|
11643
11552
|
/**
|
|
11644
|
-
*
|
|
11645
|
-
*
|
|
11646
|
-
* @param tick - The tick value
|
|
11647
|
-
* @param decimals0 - Decimals of token0
|
|
11648
|
-
* @param decimals1 - Decimals of token1
|
|
11649
|
-
* @param precision - Number of decimal places to display
|
|
11650
|
-
* @returns Object with both price directions
|
|
11553
|
+
* Construct the bytes32 CREATE3 salt for PanopticFactoryV3.
|
|
11651
11554
|
*
|
|
11652
|
-
*
|
|
11653
|
-
*
|
|
11654
|
-
*
|
|
11655
|
-
* //
|
|
11656
|
-
* //
|
|
11657
|
-
*
|
|
11555
|
+
* Mirrors:
|
|
11556
|
+
* bytes32(abi.encodePacked(
|
|
11557
|
+
* uint80(uint160(deployerAddress) >> 80), // bits [159:80] of deployer → 10 bytes
|
|
11558
|
+
* uint40(uint160(v3Pool) >> 120), // bits [159:120] of v3Pool → 5 bytes
|
|
11559
|
+
* uint40(uint160(riskEngine) >> 120), // bits [159:120] of riskEngine→ 5 bytes
|
|
11560
|
+
* salt // uint96 → 12 bytes
|
|
11561
|
+
* ))
|
|
11658
11562
|
*/
|
|
11659
|
-
function
|
|
11660
|
-
const
|
|
11661
|
-
const
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
token1PerToken0: formatRatio$3(adjustedRatio.numerator, adjustedRatio.denominator, precision)
|
|
11665
|
-
};
|
|
11563
|
+
function computeSaltPrefixV3(deployerAddress, v3Pool, riskEngine) {
|
|
11564
|
+
const deployer80 = BigInt(deployerAddress) >> 80n & MASK_80;
|
|
11565
|
+
const pool40 = BigInt(v3Pool) >> 120n & MASK_40;
|
|
11566
|
+
const risk40 = BigInt(riskEngine) >> 120n & MASK_40;
|
|
11567
|
+
return deployer80 << 176n | pool40 << 136n | risk40 << 96n;
|
|
11666
11568
|
}
|
|
11667
11569
|
/**
|
|
11668
|
-
*
|
|
11669
|
-
*
|
|
11670
|
-
* @param tickLower - Lower tick
|
|
11671
|
-
* @param tickUpper - Upper tick
|
|
11672
|
-
* @returns Formatted tick range string
|
|
11570
|
+
* Compute the Uniswap V4 PoolId for a PoolKey.
|
|
11673
11571
|
*
|
|
11674
|
-
*
|
|
11675
|
-
*
|
|
11676
|
-
* formatTickRange(-50000n, 200000n) // "-50000 - 200000"
|
|
11677
|
-
* ```
|
|
11572
|
+
* Mirrors `PoolId.toId(key)` = keccak256 of the ABI-encoded PoolKey struct
|
|
11573
|
+
* (5 fields × 32 bytes = 160 bytes).
|
|
11678
11574
|
*/
|
|
11679
|
-
function
|
|
11680
|
-
|
|
11575
|
+
function computePoolIdV4(poolKey) {
|
|
11576
|
+
const fee = Number(poolKey.fee);
|
|
11577
|
+
if (!Number.isInteger(fee) || fee < 0 || fee >= 2 ** 24) throw new PanopticValidationError(`fee out of uint24 range: ${fee}`);
|
|
11578
|
+
const tickSpacing = Number(poolKey.tickSpacing);
|
|
11579
|
+
if (!Number.isInteger(tickSpacing) || tickSpacing < -(2 ** 23) || tickSpacing > 2 ** 23 - 1) throw new PanopticValidationError(`tickSpacing out of int24 range: ${tickSpacing}`);
|
|
11580
|
+
const encoded = encodeAbiParameters([
|
|
11581
|
+
{ type: "address" },
|
|
11582
|
+
{ type: "address" },
|
|
11583
|
+
{ type: "uint24" },
|
|
11584
|
+
{ type: "int24" },
|
|
11585
|
+
{ type: "address" }
|
|
11586
|
+
], [
|
|
11587
|
+
poolKey.currency0,
|
|
11588
|
+
poolKey.currency1,
|
|
11589
|
+
Number(poolKey.fee),
|
|
11590
|
+
Number(poolKey.tickSpacing),
|
|
11591
|
+
poolKey.hooks
|
|
11592
|
+
]);
|
|
11593
|
+
return BigInt(keccak256(encoded));
|
|
11681
11594
|
}
|
|
11682
11595
|
/**
|
|
11683
|
-
*
|
|
11684
|
-
*
|
|
11685
|
-
* @param tickLower - Lower tick
|
|
11686
|
-
* @param tickUpper - Upper tick
|
|
11687
|
-
* @param decimals0 - Decimals of token0
|
|
11688
|
-
* @param decimals1 - Decimals of token1
|
|
11689
|
-
* @param precision - Number of decimal places to display
|
|
11690
|
-
* @returns Formatted price range string
|
|
11596
|
+
* Construct the bytes32 CREATE3 salt for PanopticFactoryV4.
|
|
11691
11597
|
*
|
|
11692
|
-
*
|
|
11693
|
-
*
|
|
11694
|
-
*
|
|
11695
|
-
*
|
|
11598
|
+
* Mirrors:
|
|
11599
|
+
* bytes32(abi.encodePacked(
|
|
11600
|
+
* uint80(uint160(deployerAddress) >> 80),
|
|
11601
|
+
* uint40(uint256(PoolId.unwrap(key.toId())) >> 120), // bits [159:120] of poolId
|
|
11602
|
+
* uint40(uint160(riskEngine) >> 120),
|
|
11603
|
+
* salt
|
|
11604
|
+
* ))
|
|
11696
11605
|
*/
|
|
11697
|
-
function
|
|
11698
|
-
const
|
|
11699
|
-
const
|
|
11700
|
-
|
|
11606
|
+
function computeSaltPrefixV4(deployerAddress, poolKey, riskEngine) {
|
|
11607
|
+
const deployer80 = BigInt(deployerAddress) >> 80n & MASK_80;
|
|
11608
|
+
const poolId40 = computePoolIdV4(poolKey) >> 120n & MASK_40;
|
|
11609
|
+
const risk40 = BigInt(riskEngine) >> 120n & MASK_40;
|
|
11610
|
+
return deployer80 << 176n | poolId40 << 136n | risk40 << 96n;
|
|
11701
11611
|
}
|
|
11612
|
+
/** Number of iterations per chunk before yielding back to the event loop. */
|
|
11613
|
+
const CHUNK_SIZE = 5000n;
|
|
11702
11614
|
/**
|
|
11703
|
-
*
|
|
11704
|
-
*
|
|
11705
|
-
* @param feeBps - Fee in basis points (e.g., 500n for 0.05%)
|
|
11706
|
-
* @returns Tick spacing
|
|
11615
|
+
* Async version of {@link minePoolAddressLocal} that yields to the event loop
|
|
11616
|
+
* between chunks of iterations, preventing the browser UI from freezing.
|
|
11707
11617
|
*
|
|
11708
|
-
* @
|
|
11709
|
-
*
|
|
11710
|
-
* getTickSpacing(100n) // 1n (0.01% fee tier)
|
|
11711
|
-
* getTickSpacing(500n) // 10n (0.05% fee tier)
|
|
11712
|
-
* getTickSpacing(3000n) // 60n (0.30% fee tier)
|
|
11713
|
-
* getTickSpacing(10000n) // 200n (1.00% fee tier)
|
|
11714
|
-
* ```
|
|
11618
|
+
* @param params - Mining parameters (versioned: 'v3' or 'v4'). No `client` required.
|
|
11619
|
+
* @returns The best salt found and its rarity (number of leading hex zeros).
|
|
11715
11620
|
*/
|
|
11716
|
-
function
|
|
11717
|
-
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11722
|
-
|
|
11723
|
-
|
|
11724
|
-
|
|
11621
|
+
async function minePoolAddressLocalAsync(params) {
|
|
11622
|
+
const { factoryAddress, deployerAddress, riskEngine, salt, loops, minTargetRarity } = params;
|
|
11623
|
+
let bestSalt = salt;
|
|
11624
|
+
let highestRarity = 0n;
|
|
11625
|
+
const maxSalt = salt + loops;
|
|
11626
|
+
const saltPrefix = params.version === "v3" ? computeSaltPrefixV3(deployerAddress, params.v3Pool, riskEngine) : computeSaltPrefixV4(deployerAddress, params.poolKey, riskEngine);
|
|
11627
|
+
let currentSalt = salt;
|
|
11628
|
+
while (currentSalt < maxSalt) {
|
|
11629
|
+
const chunkEnd = currentSalt + CHUNK_SIZE < maxSalt ? currentSalt + CHUNK_SIZE : maxSalt;
|
|
11630
|
+
let done = false;
|
|
11631
|
+
for (; currentSalt < chunkEnd; currentSalt++) {
|
|
11632
|
+
const newSalt = saltPrefix | currentSalt & MASK_96;
|
|
11633
|
+
const addrInt = addressOfClone3(factoryAddress, newSalt);
|
|
11634
|
+
const rarity = BigInt(numberOfLeadingHexZeros(addrInt));
|
|
11635
|
+
if (rarity > highestRarity) {
|
|
11636
|
+
highestRarity = rarity;
|
|
11637
|
+
bestSalt = currentSalt;
|
|
11638
|
+
}
|
|
11639
|
+
if (rarity >= minTargetRarity) {
|
|
11640
|
+
highestRarity = rarity;
|
|
11641
|
+
bestSalt = currentSalt;
|
|
11642
|
+
done = true;
|
|
11643
|
+
break;
|
|
11644
|
+
}
|
|
11725
11645
|
}
|
|
11646
|
+
if (done) break;
|
|
11647
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
11726
11648
|
}
|
|
11649
|
+
return {
|
|
11650
|
+
bestSalt,
|
|
11651
|
+
highestRarity
|
|
11652
|
+
};
|
|
11727
11653
|
}
|
|
11654
|
+
|
|
11655
|
+
//#endregion
|
|
11656
|
+
//#region src/panoptic/v2/abis/stateView.ts
|
|
11728
11657
|
/**
|
|
11729
|
-
*
|
|
11730
|
-
*
|
|
11731
|
-
* @param tick - The tick to round
|
|
11732
|
-
* @param tickSpacing - The tick spacing
|
|
11733
|
-
* @returns Rounded tick
|
|
11734
|
-
*
|
|
11735
|
-
* @example
|
|
11736
|
-
* ```typescript
|
|
11737
|
-
* roundToTickSpacing(12345n, 10n) // 12340n
|
|
11738
|
-
* roundToTickSpacing(12345n, 60n) // 12360n
|
|
11739
|
-
* roundToTickSpacing(-12345n, 10n) // -12350n
|
|
11740
|
-
* ```
|
|
11658
|
+
* Minimal Uniswap V4 StateView ABI for fee growth reads.
|
|
11659
|
+
* Only includes functions needed by streamia history.
|
|
11741
11660
|
*/
|
|
11742
|
-
|
|
11743
|
-
|
|
11744
|
-
|
|
11745
|
-
|
|
11746
|
-
|
|
11747
|
-
|
|
11748
|
-
}
|
|
11749
|
-
|
|
11750
|
-
|
|
11751
|
-
|
|
11752
|
-
|
|
11753
|
-
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
|
|
11771
|
-
|
|
11772
|
-
|
|
11661
|
+
const stateViewAbi = [
|
|
11662
|
+
{
|
|
11663
|
+
inputs: [{
|
|
11664
|
+
internalType: "PoolId",
|
|
11665
|
+
name: "poolId",
|
|
11666
|
+
type: "bytes32"
|
|
11667
|
+
}],
|
|
11668
|
+
name: "getSlot0",
|
|
11669
|
+
outputs: [
|
|
11670
|
+
{
|
|
11671
|
+
internalType: "uint160",
|
|
11672
|
+
name: "sqrtPriceX96",
|
|
11673
|
+
type: "uint160"
|
|
11674
|
+
},
|
|
11675
|
+
{
|
|
11676
|
+
internalType: "int24",
|
|
11677
|
+
name: "tick",
|
|
11678
|
+
type: "int24"
|
|
11679
|
+
},
|
|
11680
|
+
{
|
|
11681
|
+
internalType: "uint24",
|
|
11682
|
+
name: "protocolFee",
|
|
11683
|
+
type: "uint24"
|
|
11684
|
+
},
|
|
11685
|
+
{
|
|
11686
|
+
internalType: "uint24",
|
|
11687
|
+
name: "lpFee",
|
|
11688
|
+
type: "uint24"
|
|
11689
|
+
}
|
|
11690
|
+
],
|
|
11691
|
+
stateMutability: "view",
|
|
11692
|
+
type: "function"
|
|
11693
|
+
},
|
|
11694
|
+
{
|
|
11695
|
+
inputs: [{
|
|
11696
|
+
internalType: "PoolId",
|
|
11697
|
+
name: "poolId",
|
|
11698
|
+
type: "bytes32"
|
|
11699
|
+
}],
|
|
11700
|
+
name: "getFeeGrowthGlobals",
|
|
11701
|
+
outputs: [{
|
|
11702
|
+
internalType: "uint256",
|
|
11703
|
+
name: "feeGrowthGlobal0",
|
|
11704
|
+
type: "uint256"
|
|
11705
|
+
}, {
|
|
11706
|
+
internalType: "uint256",
|
|
11707
|
+
name: "feeGrowthGlobal1",
|
|
11708
|
+
type: "uint256"
|
|
11709
|
+
}],
|
|
11710
|
+
stateMutability: "view",
|
|
11711
|
+
type: "function"
|
|
11712
|
+
},
|
|
11713
|
+
{
|
|
11714
|
+
inputs: [{
|
|
11715
|
+
internalType: "PoolId",
|
|
11716
|
+
name: "poolId",
|
|
11717
|
+
type: "bytes32"
|
|
11718
|
+
}, {
|
|
11719
|
+
internalType: "int24",
|
|
11720
|
+
name: "tick",
|
|
11721
|
+
type: "int24"
|
|
11722
|
+
}],
|
|
11723
|
+
name: "getTickInfo",
|
|
11724
|
+
outputs: [
|
|
11725
|
+
{
|
|
11726
|
+
internalType: "uint128",
|
|
11727
|
+
name: "liquidityGross",
|
|
11728
|
+
type: "uint128"
|
|
11729
|
+
},
|
|
11730
|
+
{
|
|
11731
|
+
internalType: "int128",
|
|
11732
|
+
name: "liquidityNet",
|
|
11733
|
+
type: "int128"
|
|
11734
|
+
},
|
|
11735
|
+
{
|
|
11736
|
+
internalType: "uint256",
|
|
11737
|
+
name: "feeGrowthOutside0X128",
|
|
11738
|
+
type: "uint256"
|
|
11739
|
+
},
|
|
11740
|
+
{
|
|
11741
|
+
internalType: "uint256",
|
|
11742
|
+
name: "feeGrowthOutside1X128",
|
|
11743
|
+
type: "uint256"
|
|
11744
|
+
}
|
|
11745
|
+
],
|
|
11746
|
+
stateMutability: "view",
|
|
11747
|
+
type: "function"
|
|
11748
|
+
},
|
|
11749
|
+
{
|
|
11750
|
+
inputs: [{
|
|
11751
|
+
internalType: "PoolId",
|
|
11752
|
+
name: "poolId",
|
|
11753
|
+
type: "bytes32"
|
|
11754
|
+
}],
|
|
11755
|
+
name: "getLiquidity",
|
|
11756
|
+
outputs: [{
|
|
11757
|
+
internalType: "uint128",
|
|
11758
|
+
name: "liquidity",
|
|
11759
|
+
type: "uint128"
|
|
11760
|
+
}],
|
|
11761
|
+
stateMutability: "view",
|
|
11762
|
+
type: "function"
|
|
11763
|
+
}
|
|
11764
|
+
];
|
|
11765
|
+
|
|
11766
|
+
//#endregion
|
|
11767
|
+
//#region src/panoptic/v2/abis/uniswapV3Pool.ts
|
|
11768
|
+
/**
|
|
11769
|
+
* Minimal Uniswap V3 Pool ABI for fee growth reads.
|
|
11770
|
+
* Only includes functions needed by streamia history.
|
|
11773
11771
|
*/
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
11785
|
-
|
|
11786
|
-
|
|
11772
|
+
const uniswapV3PoolAbi = [
|
|
11773
|
+
{
|
|
11774
|
+
inputs: [],
|
|
11775
|
+
name: "slot0",
|
|
11776
|
+
outputs: [
|
|
11777
|
+
{
|
|
11778
|
+
internalType: "uint160",
|
|
11779
|
+
name: "sqrtPriceX96",
|
|
11780
|
+
type: "uint160"
|
|
11781
|
+
},
|
|
11782
|
+
{
|
|
11783
|
+
internalType: "int24",
|
|
11784
|
+
name: "tick",
|
|
11785
|
+
type: "int24"
|
|
11786
|
+
},
|
|
11787
|
+
{
|
|
11788
|
+
internalType: "uint16",
|
|
11789
|
+
name: "observationIndex",
|
|
11790
|
+
type: "uint16"
|
|
11791
|
+
},
|
|
11792
|
+
{
|
|
11793
|
+
internalType: "uint16",
|
|
11794
|
+
name: "observationCardinality",
|
|
11795
|
+
type: "uint16"
|
|
11796
|
+
},
|
|
11797
|
+
{
|
|
11798
|
+
internalType: "uint16",
|
|
11799
|
+
name: "observationCardinalityNext",
|
|
11800
|
+
type: "uint16"
|
|
11801
|
+
},
|
|
11802
|
+
{
|
|
11803
|
+
internalType: "uint8",
|
|
11804
|
+
name: "feeProtocol",
|
|
11805
|
+
type: "uint8"
|
|
11806
|
+
},
|
|
11807
|
+
{
|
|
11808
|
+
internalType: "bool",
|
|
11809
|
+
name: "unlocked",
|
|
11810
|
+
type: "bool"
|
|
11811
|
+
}
|
|
11812
|
+
],
|
|
11813
|
+
stateMutability: "view",
|
|
11814
|
+
type: "function"
|
|
11815
|
+
},
|
|
11816
|
+
{
|
|
11817
|
+
inputs: [],
|
|
11818
|
+
name: "feeGrowthGlobal0X128",
|
|
11819
|
+
outputs: [{
|
|
11820
|
+
internalType: "uint256",
|
|
11821
|
+
name: "",
|
|
11822
|
+
type: "uint256"
|
|
11823
|
+
}],
|
|
11824
|
+
stateMutability: "view",
|
|
11825
|
+
type: "function"
|
|
11826
|
+
},
|
|
11827
|
+
{
|
|
11828
|
+
inputs: [],
|
|
11829
|
+
name: "feeGrowthGlobal1X128",
|
|
11830
|
+
outputs: [{
|
|
11831
|
+
internalType: "uint256",
|
|
11832
|
+
name: "",
|
|
11833
|
+
type: "uint256"
|
|
11834
|
+
}],
|
|
11835
|
+
stateMutability: "view",
|
|
11836
|
+
type: "function"
|
|
11837
|
+
},
|
|
11838
|
+
{
|
|
11839
|
+
inputs: [{
|
|
11840
|
+
internalType: "int24",
|
|
11841
|
+
name: "",
|
|
11842
|
+
type: "int24"
|
|
11843
|
+
}],
|
|
11844
|
+
name: "ticks",
|
|
11845
|
+
outputs: [
|
|
11846
|
+
{
|
|
11847
|
+
internalType: "uint128",
|
|
11848
|
+
name: "liquidityGross",
|
|
11849
|
+
type: "uint128"
|
|
11850
|
+
},
|
|
11851
|
+
{
|
|
11852
|
+
internalType: "int128",
|
|
11853
|
+
name: "liquidityNet",
|
|
11854
|
+
type: "int128"
|
|
11855
|
+
},
|
|
11856
|
+
{
|
|
11857
|
+
internalType: "uint256",
|
|
11858
|
+
name: "feeGrowthOutside0X128",
|
|
11859
|
+
type: "uint256"
|
|
11860
|
+
},
|
|
11861
|
+
{
|
|
11862
|
+
internalType: "uint256",
|
|
11863
|
+
name: "feeGrowthOutside1X128",
|
|
11864
|
+
type: "uint256"
|
|
11865
|
+
},
|
|
11866
|
+
{
|
|
11867
|
+
internalType: "int56",
|
|
11868
|
+
name: "tickCumulativeOutside",
|
|
11869
|
+
type: "int56"
|
|
11870
|
+
},
|
|
11871
|
+
{
|
|
11872
|
+
internalType: "uint160",
|
|
11873
|
+
name: "secondsPerLiquidityOutsideX128",
|
|
11874
|
+
type: "uint160"
|
|
11875
|
+
},
|
|
11876
|
+
{
|
|
11877
|
+
internalType: "uint32",
|
|
11878
|
+
name: "secondsOutside",
|
|
11879
|
+
type: "uint32"
|
|
11880
|
+
},
|
|
11881
|
+
{
|
|
11882
|
+
internalType: "bool",
|
|
11883
|
+
name: "initialized",
|
|
11884
|
+
type: "bool"
|
|
11885
|
+
}
|
|
11886
|
+
],
|
|
11887
|
+
stateMutability: "view",
|
|
11888
|
+
type: "function"
|
|
11889
|
+
},
|
|
11890
|
+
{
|
|
11891
|
+
inputs: [],
|
|
11892
|
+
name: "liquidity",
|
|
11893
|
+
outputs: [{
|
|
11894
|
+
internalType: "uint128",
|
|
11895
|
+
name: "",
|
|
11896
|
+
type: "uint128"
|
|
11897
|
+
}],
|
|
11898
|
+
stateMutability: "view",
|
|
11899
|
+
type: "function"
|
|
11900
|
+
},
|
|
11901
|
+
{
|
|
11902
|
+
inputs: [],
|
|
11903
|
+
name: "fee",
|
|
11904
|
+
outputs: [{
|
|
11905
|
+
internalType: "uint24",
|
|
11906
|
+
name: "",
|
|
11907
|
+
type: "uint24"
|
|
11908
|
+
}],
|
|
11909
|
+
stateMutability: "view",
|
|
11910
|
+
type: "function"
|
|
11911
|
+
},
|
|
11912
|
+
{
|
|
11913
|
+
inputs: [],
|
|
11914
|
+
name: "token0",
|
|
11915
|
+
outputs: [{
|
|
11916
|
+
internalType: "address",
|
|
11917
|
+
name: "",
|
|
11918
|
+
type: "address"
|
|
11919
|
+
}],
|
|
11920
|
+
stateMutability: "view",
|
|
11921
|
+
type: "function"
|
|
11922
|
+
},
|
|
11923
|
+
{
|
|
11924
|
+
inputs: [],
|
|
11925
|
+
name: "token1",
|
|
11926
|
+
outputs: [{
|
|
11927
|
+
internalType: "address",
|
|
11928
|
+
name: "",
|
|
11929
|
+
type: "address"
|
|
11930
|
+
}],
|
|
11931
|
+
stateMutability: "view",
|
|
11932
|
+
type: "function"
|
|
11933
|
+
},
|
|
11934
|
+
{
|
|
11935
|
+
inputs: [],
|
|
11936
|
+
name: "tickSpacing",
|
|
11937
|
+
outputs: [{
|
|
11938
|
+
internalType: "int24",
|
|
11939
|
+
name: "",
|
|
11940
|
+
type: "int24"
|
|
11941
|
+
}],
|
|
11942
|
+
stateMutability: "view",
|
|
11943
|
+
type: "function"
|
|
11944
|
+
}
|
|
11945
|
+
];
|
|
11787
11946
|
|
|
11788
11947
|
//#endregion
|
|
11789
11948
|
//#region src/panoptic/v2/reads/mintBuffer.ts
|
|
@@ -14789,7 +14948,7 @@ async function readBlockAndAggregate({ client, calls, blockNumber }) {
|
|
|
14789
14948
|
|
|
14790
14949
|
//#endregion
|
|
14791
14950
|
//#region src/panoptic/v2/reads/checks.ts
|
|
14792
|
-
const FP96$
|
|
14951
|
+
const FP96$2 = 1n << 96n;
|
|
14793
14952
|
const Q128$4 = 1n << 128n;
|
|
14794
14953
|
function convert0to1$3(amount, sqrtPriceX96) {
|
|
14795
14954
|
if (sqrtPriceX96 < Q128$4) return amount * sqrtPriceX96 * sqrtPriceX96 >> 192n;
|
|
@@ -14940,7 +15099,7 @@ async function isLiquidatable(params) {
|
|
|
14940
15099
|
const requiredMargin1 = required1Native + convert0to1$3(required0Native, sqrtPriceX96);
|
|
14941
15100
|
const marginShortfall0 = requiredMargin0 - currentMargin0;
|
|
14942
15101
|
const marginShortfall1 = requiredMargin1 - currentMargin1;
|
|
14943
|
-
const denominatedInToken = sqrtPriceX96 < FP96$
|
|
15102
|
+
const denominatedInToken = sqrtPriceX96 < FP96$2 ? 0n : 1n;
|
|
14944
15103
|
const isLiquidatableResult = denominatedInToken === 0n ? marginShortfall0 > 0n : marginShortfall1 > 0n;
|
|
14945
15104
|
return {
|
|
14946
15105
|
isLiquidatable: isLiquidatableResult,
|
|
@@ -17183,8 +17342,9 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
17183
17342
|
error: new PanopticError("Could not size the prefixed recovery swap")
|
|
17184
17343
|
};
|
|
17185
17344
|
};
|
|
17345
|
+
let creditOutSize = amountOut;
|
|
17186
17346
|
for (let attempt = 0; attempt < MAX_RECOVERY_QUOTE_ATTEMPTS; attempt++) {
|
|
17187
|
-
const credit = buildUniqueCredit(pool.poolId, tokenOutIndex, tokenOutIndex, pool.currentTick, pool.tickSpacing, collisionIds,
|
|
17347
|
+
const credit = buildUniqueCredit(pool.poolId, tokenOutIndex, tokenOutIndex, pool.currentTick, pool.tickSpacing, collisionIds, creditOutSize);
|
|
17188
17348
|
const recoveredDispatch = buildTokenShortfallRecoveryDispatch({
|
|
17189
17349
|
dispatch: params.dispatch,
|
|
17190
17350
|
creditTokenId: credit.tokenId,
|
|
@@ -17228,10 +17388,14 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
17228
17388
|
const maxAmountIn = maximumAmountIn(estimatedAmountIn, params.slippageBps);
|
|
17229
17389
|
const swapOutput = getOutputAmount(swapSimulation.tokenFlow, tokenOutIndex);
|
|
17230
17390
|
const sourceBalance = getBalanceBefore(swapSimulation.tokenFlow, tokenInIndex);
|
|
17231
|
-
if (swapOutput < amountOut
|
|
17391
|
+
if (swapOutput < amountOut) {
|
|
17392
|
+
creditOutSize = swapOutput > 0n ? ceilDiv(creditOutSize * amountOut, swapOutput) + 1n : creditOutSize * 2n;
|
|
17393
|
+
continue;
|
|
17394
|
+
}
|
|
17395
|
+
if (sourceBalance < maxAmountIn) return {
|
|
17232
17396
|
available: false,
|
|
17233
17397
|
reason: "swap-unavailable",
|
|
17234
|
-
detail:
|
|
17398
|
+
detail: `source balance ${sourceBalance} < maximumAmountIn ${maxAmountIn} (estimated ${estimatedAmountIn}, slippageBps ${params.slippageBps})`,
|
|
17235
17399
|
error: new PanopticError("Insufficient source collateral for the recovery swap")
|
|
17236
17400
|
};
|
|
17237
17401
|
const recoverySimulation = await simulateDispatch({
|
|
@@ -17283,6 +17447,7 @@ async function quoteTokenShortfallRecovery(params) {
|
|
|
17283
17447
|
const decodedShortfall = remainingShortfall.assetsRequested - remainingShortfall.assetBalance;
|
|
17284
17448
|
const additionalAmountOut = decodedShortfall > 0n ? decodedShortfall : amountOut;
|
|
17285
17449
|
amountOut += additionalAmountOut;
|
|
17450
|
+
creditOutSize = swapOutput > 0n ? ceilDiv(creditOutSize * amountOut, swapOutput) + 1n : creditOutSize * 2n;
|
|
17286
17451
|
}
|
|
17287
17452
|
return {
|
|
17288
17453
|
available: false,
|
|
@@ -17309,6 +17474,7 @@ const MAX_EFFECTIVE_LIQUIDITY_LIMIT = 8388607;
|
|
|
17309
17474
|
* returned value must be scaled down to the caller's actual `positionSize`.
|
|
17310
17475
|
*/
|
|
17311
17476
|
const MAX_UINT64$1 = 2n ** 64n - 1n;
|
|
17477
|
+
const FP96$1 = 1n << 96n;
|
|
17312
17478
|
/**
|
|
17313
17479
|
* `getRequiredBase` returns `type(uint128).max` as an error sentinel (invalid
|
|
17314
17480
|
* tokenId or reverting `getMargin`). Detect it so we don't scale a garbage value.
|
|
@@ -17321,7 +17487,9 @@ const REQUIRED_BASE_ERROR_SENTINEL = 2n ** 128n - 1n;
|
|
|
17321
17487
|
* computes the requirement at `type(uint64).max` size and 0% utilization. Since
|
|
17322
17488
|
* the requirement is linear in size, the raw result is scaled by
|
|
17323
17489
|
* `positionSize / type(uint64).max` to yield the requirement for the requested
|
|
17324
|
-
* size.
|
|
17490
|
+
* size. `PanopticQuery.getRequiredBase` returns the cross-margin requirement in
|
|
17491
|
+
* the higher-precision raw token at `atTick`; this function places that amount
|
|
17492
|
+
* in the matching `required0` or `required1` field.
|
|
17325
17493
|
*
|
|
17326
17494
|
* @param params - The parameters
|
|
17327
17495
|
* @returns Estimated collateral requirements with block metadata
|
|
@@ -17340,7 +17508,7 @@ async function estimateCollateralRequired(params) {
|
|
|
17340
17508
|
});
|
|
17341
17509
|
effectiveTick = BigInt(currentTickResult);
|
|
17342
17510
|
}
|
|
17343
|
-
const [
|
|
17511
|
+
const [requiredBase, _meta] = await Promise.all([client.readContract({
|
|
17344
17512
|
address: queryAddress,
|
|
17345
17513
|
abi: panopticQueryAbi,
|
|
17346
17514
|
functionName: "getRequiredBase",
|
|
@@ -17354,10 +17522,11 @@ async function estimateCollateralRequired(params) {
|
|
|
17354
17522
|
client,
|
|
17355
17523
|
blockNumber: targetBlockNumber
|
|
17356
17524
|
})]);
|
|
17357
|
-
const
|
|
17525
|
+
const scaledRequirement = requiredBase >= REQUIRED_BASE_ERROR_SENTINEL ? requiredBase : requiredBase * positionSize / MAX_UINT64$1;
|
|
17526
|
+
const denominatedInToken0 = tickToSqrtPriceX96(effectiveTick) < FP96$1;
|
|
17358
17527
|
return {
|
|
17359
|
-
required0:
|
|
17360
|
-
required1: 0n,
|
|
17528
|
+
required0: denominatedInToken0 ? scaledRequirement : 0n,
|
|
17529
|
+
required1: denominatedInToken0 ? 0n : scaledRequirement,
|
|
17361
17530
|
_meta
|
|
17362
17531
|
};
|
|
17363
17532
|
}
|
|
@@ -20994,7 +21163,9 @@ async function getStreamiaHistory(params) {
|
|
|
20994
21163
|
_meta: _meta$1
|
|
20995
21164
|
};
|
|
20996
21165
|
}
|
|
20997
|
-
const
|
|
21166
|
+
const _meta = params._meta ?? await getBlockMeta({ client });
|
|
21167
|
+
const resolvedBlockNumbers = blockNumbers.map((blockNumber) => blockNumber ?? _meta.blockNumber);
|
|
21168
|
+
const premiaRequests = resolvedBlockNumbers.map((blockNumber) => client.readContract({
|
|
20998
21169
|
address: panopticPoolAddress,
|
|
20999
21170
|
abi: panopticPoolV2Abi,
|
|
21000
21171
|
functionName: "getFullPositionsData",
|
|
@@ -21003,18 +21174,36 @@ async function getStreamiaHistory(params) {
|
|
|
21003
21174
|
true,
|
|
21004
21175
|
[tokenId]
|
|
21005
21176
|
],
|
|
21006
|
-
blockNumber
|
|
21177
|
+
blockNumber
|
|
21007
21178
|
}));
|
|
21008
|
-
const uniswapDataPromise = includeUniswapFees && legs.length > 0 ? fetchUniswapFeeData(client,
|
|
21009
|
-
const [premiaResults, uniswapData
|
|
21010
|
-
|
|
21011
|
-
uniswapDataPromise ?? Promise.resolve(void 0),
|
|
21012
|
-
params._meta ? Promise.resolve(params._meta) : getBlockMeta({ client })
|
|
21013
|
-
]);
|
|
21014
|
-
const sortedSettled = settledEvents ? [...settledEvents].sort((a, b) => a.blockNumber < b.blockNumber ? -1 : 1) : [];
|
|
21179
|
+
const uniswapDataPromise = includeUniswapFees && legs.length > 0 ? fetchUniswapFeeData(client, resolvedBlockNumbers, legs, poolConfig) : void 0;
|
|
21180
|
+
const [premiaResults, uniswapData] = await Promise.all([Promise.all(premiaRequests), uniswapDataPromise ?? Promise.resolve(void 0)]);
|
|
21181
|
+
const sortedSettled = settledEvents ? [...settledEvents].sort((a, b) => a.blockNumber === b.blockNumber ? 0 : a.blockNumber < b.blockNumber ? -1 : 1) : [];
|
|
21015
21182
|
let settledIdx = 0;
|
|
21016
21183
|
let accSettled0 = 0n;
|
|
21017
21184
|
let accSettled1 = 0n;
|
|
21185
|
+
const cumulativePremiaByInputIndex = Array.from({ length: blockNumbers.length }, () => ({
|
|
21186
|
+
token0: 0n,
|
|
21187
|
+
token1: 0n
|
|
21188
|
+
}));
|
|
21189
|
+
const chronologicalInputs = resolvedBlockNumbers.map((blockNumber, inputIndex) => ({
|
|
21190
|
+
blockNumber,
|
|
21191
|
+
inputIndex
|
|
21192
|
+
})).sort((a, b) => a.blockNumber === b.blockNumber ? a.inputIndex - b.inputIndex : a.blockNumber < b.blockNumber ? -1 : 1);
|
|
21193
|
+
for (const { blockNumber, inputIndex } of chronologicalInputs) {
|
|
21194
|
+
while (settledIdx < sortedSettled.length && sortedSettled[settledIdx].blockNumber <= blockNumber) {
|
|
21195
|
+
accSettled0 += sortedSettled[settledIdx].settled0;
|
|
21196
|
+
accSettled1 += sortedSettled[settledIdx].settled1;
|
|
21197
|
+
settledIdx++;
|
|
21198
|
+
}
|
|
21199
|
+
const result = premiaResults[inputIndex];
|
|
21200
|
+
const premia0 = (result[0] & MASK_128) - (result[1] & MASK_128);
|
|
21201
|
+
const premia1 = (result[0] >> 128n) - (result[1] >> 128n);
|
|
21202
|
+
cumulativePremiaByInputIndex[inputIndex] = {
|
|
21203
|
+
token0: premia0 + accSettled0,
|
|
21204
|
+
token1: premia1 + accSettled1
|
|
21205
|
+
};
|
|
21206
|
+
}
|
|
21018
21207
|
let initialUniswapFees0 = null;
|
|
21019
21208
|
let initialUniswapFees1 = null;
|
|
21020
21209
|
const snapshots = premiaResults.map((result, i) => {
|
|
@@ -21025,14 +21214,8 @@ async function getStreamiaHistory(params) {
|
|
|
21025
21214
|
const short1 = shortPacked >> 128n;
|
|
21026
21215
|
const long0 = longPacked & MASK_128;
|
|
21027
21216
|
const long1 = longPacked >> 128n;
|
|
21028
|
-
const
|
|
21029
|
-
|
|
21030
|
-
accSettled0 += sortedSettled[settledIdx].settled0;
|
|
21031
|
-
accSettled1 += sortedSettled[settledIdx].settled1;
|
|
21032
|
-
settledIdx++;
|
|
21033
|
-
}
|
|
21034
|
-
const premia0 = short0 - long0 - accSettled0;
|
|
21035
|
-
const premia1 = short1 - long1 - accSettled1;
|
|
21217
|
+
const premia0 = short0 - long0;
|
|
21218
|
+
const premia1 = short1 - long1;
|
|
21036
21219
|
let uniswapFees0 = 0n;
|
|
21037
21220
|
let uniswapFees1 = 0n;
|
|
21038
21221
|
if (uniswapData) {
|
|
@@ -21051,6 +21234,7 @@ async function getStreamiaHistory(params) {
|
|
|
21051
21234
|
token0: premia0,
|
|
21052
21235
|
token1: premia1
|
|
21053
21236
|
},
|
|
21237
|
+
cumulativePanopticPremia: cumulativePremiaByInputIndex[i],
|
|
21054
21238
|
uniswapFees: {
|
|
21055
21239
|
token0: uniswapFees0,
|
|
21056
21240
|
token1: uniswapFees1
|
|
@@ -22032,6 +22216,31 @@ async function fetchSlot0(client, blockNumber, poolConfig) {
|
|
|
22032
22216
|
}
|
|
22033
22217
|
}
|
|
22034
22218
|
|
|
22219
|
+
//#endregion
|
|
22220
|
+
//#region src/panoptic/v2/reads/positionSizes.ts
|
|
22221
|
+
const BIT_MASK_128$1 = (1n << 128n) - 1n;
|
|
22222
|
+
/**
|
|
22223
|
+
* Returns the current stored positionSize for each tokenId, in the same order
|
|
22224
|
+
* as the input `positionIdList`. Reverts (via the contract) if any tokenId is
|
|
22225
|
+
* not held by `account`.
|
|
22226
|
+
*/
|
|
22227
|
+
async function getCurrentPositionSizes(params) {
|
|
22228
|
+
const { client, poolAddress, account, positionIdList, blockNumber } = params;
|
|
22229
|
+
if (positionIdList.length === 0) return [];
|
|
22230
|
+
const [, , positionBalances] = await client.readContract({
|
|
22231
|
+
address: poolAddress,
|
|
22232
|
+
abi: panopticPoolV2Abi,
|
|
22233
|
+
functionName: "getFullPositionsData",
|
|
22234
|
+
args: [
|
|
22235
|
+
account,
|
|
22236
|
+
false,
|
|
22237
|
+
positionIdList
|
|
22238
|
+
],
|
|
22239
|
+
blockNumber
|
|
22240
|
+
});
|
|
22241
|
+
return positionBalances.map((packed) => packed & BIT_MASK_128$1);
|
|
22242
|
+
}
|
|
22243
|
+
|
|
22035
22244
|
//#endregion
|
|
22036
22245
|
//#region src/panoptic/v2/reads/enrichment.ts
|
|
22037
22246
|
/**
|
|
@@ -24065,8 +24274,14 @@ async function forceExerciseAndWait(params) {
|
|
|
24065
24274
|
* ```
|
|
24066
24275
|
*/
|
|
24067
24276
|
async function settleAccumulatedPremia(params) {
|
|
24068
|
-
const { client, walletClient, account, poolAddress, positionIdList, usePremiaAsCollateral = false, builderCode = 0n, txOverrides } = params;
|
|
24069
|
-
|
|
24277
|
+
const { client, walletClient, account, poolAddress, positionIdList, finalPositionIdList, positionSizes: providedSizes, usePremiaAsCollateral = false, builderCode = 0n, txOverrides } = params;
|
|
24278
|
+
if (providedSizes && providedSizes.length !== positionIdList.length) throw new PanopticError("settleAccumulatedPremia: positionSizes length must match positionIdList");
|
|
24279
|
+
const positionSizes = providedSizes ?? await getCurrentPositionSizes({
|
|
24280
|
+
client,
|
|
24281
|
+
poolAddress,
|
|
24282
|
+
account,
|
|
24283
|
+
positionIdList
|
|
24284
|
+
});
|
|
24070
24285
|
const tickAndSpreadLimits = positionIdList.map(() => [
|
|
24071
24286
|
-887272n,
|
|
24072
24287
|
887272n,
|
|
@@ -24081,7 +24296,7 @@ async function settleAccumulatedPremia(params) {
|
|
|
24081
24296
|
functionName: "dispatch",
|
|
24082
24297
|
args: [
|
|
24083
24298
|
positionIdList,
|
|
24084
|
-
positionIdList,
|
|
24299
|
+
finalPositionIdList ?? positionIdList,
|
|
24085
24300
|
positionSizes.map((s) => BigInt(s)),
|
|
24086
24301
|
tickAndSpreadLimits.map((t) => [
|
|
24087
24302
|
Number(t[0]),
|
|
@@ -25662,14 +25877,21 @@ const multicallAbi = [{
|
|
|
25662
25877
|
* @returns Simulation result with settlement data or error
|
|
25663
25878
|
*/
|
|
25664
25879
|
async function simulateSettle(params) {
|
|
25665
|
-
const { client, poolAddress, account, positionIdList, tokenId, blockNumber } = params;
|
|
25880
|
+
const { client, poolAddress, account, positionIdList, finalPositionIdList, positionSizes: providedSizes, tokenId, blockNumber } = params;
|
|
25666
25881
|
const targetBlockNumber = blockNumber ?? await client.getBlockNumber();
|
|
25667
25882
|
const metaPromise = getBlockMeta({
|
|
25668
25883
|
client,
|
|
25669
25884
|
blockNumber: targetBlockNumber
|
|
25670
25885
|
});
|
|
25671
25886
|
try {
|
|
25672
|
-
|
|
25887
|
+
if (providedSizes && providedSizes.length !== positionIdList.length) throw new PanopticError("simulateSettle: positionSizes length must match positionIdList");
|
|
25888
|
+
const positionSizes = providedSizes ?? await getCurrentPositionSizes({
|
|
25889
|
+
client,
|
|
25890
|
+
poolAddress,
|
|
25891
|
+
account,
|
|
25892
|
+
positionIdList,
|
|
25893
|
+
blockNumber: targetBlockNumber
|
|
25894
|
+
});
|
|
25673
25895
|
const tickAndSpreadLimits = positionIdList.map(() => [
|
|
25674
25896
|
-887272n,
|
|
25675
25897
|
887272n,
|
|
@@ -25680,7 +25902,7 @@ async function simulateSettle(params) {
|
|
|
25680
25902
|
functionName: "dispatch",
|
|
25681
25903
|
args: [
|
|
25682
25904
|
positionIdList,
|
|
25683
|
-
positionIdList,
|
|
25905
|
+
finalPositionIdList ?? positionIdList,
|
|
25684
25906
|
positionSizes.map((s) => BigInt(s)),
|
|
25685
25907
|
tickAndSpreadLimits.map((t) => [
|
|
25686
25908
|
Number(t[0]),
|
|
@@ -25712,8 +25934,8 @@ async function simulateSettle(params) {
|
|
|
25712
25934
|
});
|
|
25713
25935
|
const _meta = await metaPromise;
|
|
25714
25936
|
const data = {
|
|
25715
|
-
premiaReceived0: tokenFlow.delta0
|
|
25716
|
-
premiaReceived1: tokenFlow.delta1
|
|
25937
|
+
premiaReceived0: tokenFlow.delta0,
|
|
25938
|
+
premiaReceived1: tokenFlow.delta1,
|
|
25717
25939
|
postCollateral0: tokenFlow.balanceAfter0,
|
|
25718
25940
|
postCollateral1: tokenFlow.balanceAfter1,
|
|
25719
25941
|
forfeitAmounts
|
|
@@ -33299,5 +33521,5 @@ function useTxEventConfirmation({ txHash, poolAddress = zeroAddress, collateralT
|
|
|
33299
33521
|
}
|
|
33300
33522
|
|
|
33301
33523
|
//#endregion
|
|
33302
|
-
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, PanopticProvider, 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, isCowSupportedChain, 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, mutationEffects, openPosition, openPositionAndWait, optimizeTokenIdRiskPartners, oracleEpochAt, packMarketState, panopticPoolV2Abi, parseBps, parseCollateralLog, parsePanopticError, parsePoolLog, parseTokenAmount, parseTokenListId, parseWad, pokeOracle, pokeOracleAndWait, previewBorrow, previewDeposit, previewMint, previewRedeem, previewUnwrap, previewWithdraw, previewWrap, priceToTick, publicBroadcaster, queryKeys, 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, useAccountCollateral, useAccountGreeks, useAccountPremia, useAccountSummaryBasic, useAccountSummaryRisk, useAddPendingPosition, useApprove, useApproveErc20ForCow, useApproveErc20ForPermit2, useApprovePool, useApproveRouterViaPermit2, useBatchDispatch as useBatchDispatchHook, useBorrow as useBorrowHook, useCancelCowOrder, useCheckCowApproval, useCheckRouterApproval, useChunkSpreads, useClearTrackedPositions, useClosePosition as useClosePositionHook, useClosedPositions, useCollateralBreakdown, useCollateralData, useConfirmPendingPosition, useCowOrderStatus, useCurrentRates, useDeployNewPool as useDeployNewPoolHook, useDeposit as useDepositHook, useDispatch as useDispatchHook, useEstimateCollateralRequired, useEventPoller, useEventSubscription, useFactoryConstructMetadata, useFactoryOwnerOf, useFactoryTokenURI, useFailPendingPosition, useFlowNeutralTokenId, useForceExercise as useForceExerciseHook, useGuardianUnlockState, useInterestState, useIsLiquidatable, useLiquidate as useLiquidateHook, useLiquidationPrices, useMarginBuffer, useMaxPositionSize, useMaxRedeem, useMaxWithdrawable, useMinePoolAddress as useMinePoolAddressHook, useMintShares, useNativeTokenPrice, useNetLiquidationValue, useNetLiquidationValues, useOpenPosition as useOpenPositionHook, useOpenPositionPreview, useOptimizeRiskPartners, useOracleState, usePanopticContext, usePanopticPoolAddress, usePokeOracle as usePokeOracleHook, usePool, usePoolLiquidities, usePosition, usePositionGreeks, usePositions, usePositionsWithPremia, usePreviewBorrow, usePreviewDeposit, usePreviewMint, usePreviewRedeem, usePreviewWithdraw, usePriceHistory, useQuoteCowSwap, useQuoteSwapExactInViaRouter, useQuoteSwapExactOutViaRouter, useRealizedPnL, useRedeem as useRedeemHook, useRepay as useRepayHook, useResolveUniswapV4PoolKey, useRiskParameters, useRollPosition as useRollPositionHook, useSafeMode, useSettleAccumulatedPremia as useSettleAccumulatedPremiaHook, useSimulateBatchDispatch, useSimulateClosePosition, useSimulateDeployNewPool, useSimulateDeposit, useSimulateDispatch, useSimulateForceExercise, useSimulateLiquidate, useSimulateOpenPosition, useSimulateSFPMBurn, useSimulateSFPMMint, useSimulateSettle, useSimulateSwapExactIn, useSimulateSwapExactOut, useSimulateWithdraw, useSmartRepay as useSmartRepayHook, useStreamiaHistory, useSubmitCowOrder, useSupply as useSupplyHook, useSwapExactIn, useSwapExactInViaRouter, useSwapExactOut, useSwapExactOutViaRouter, useSyncPositions, useSyncStatus, useTrackedPositionIds, useTradeHistory, useTxEventConfirmation, useUniswapFeeHistory, useUniswapV3PoolInfo, useUniswapV3PoolLiquidities, useUniswapV4PoolBasicState, useUniswapV4PoolInfo, useUniswapV4PoolLiquidities, useUnsupply as useUnsupplyHook, useUnwrapWeth, useUnwrapXstock, useUtilization, useValidateBuilderCode, useWatchEvents, useWithdraw as useWithdrawHook, useWithdrawWithPositions as useWithdrawWithPositionsHook, useWrapEth, useWrapXstock, utilizationBpsToWad, utilizationPctToWad, validateBatch, validateBuilderCode, validatePoolId, verifyBlockContinuity, watchEvents, wethWrapAbi, withdraw, withdrawAndWait, withdrawWithPositions, withdrawWithPositionsAndWait, wrapEth, wrapEthAndWait, wrapXstock, wrapXstockAndWait, xstockWrapperAbi };
|
|
33524
|
+
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, PanopticProvider, 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, isCowSupportedChain, 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, mutationEffects, 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, queryKeys, 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, useAccountCollateral, useAccountGreeks, useAccountPremia, useAccountSummaryBasic, useAccountSummaryRisk, useAddPendingPosition, useApprove, useApproveErc20ForCow, useApproveErc20ForPermit2, useApprovePool, useApproveRouterViaPermit2, useBatchDispatch as useBatchDispatchHook, useBorrow as useBorrowHook, useCancelCowOrder, useCheckCowApproval, useCheckRouterApproval, useChunkSpreads, useClearTrackedPositions, useClosePosition as useClosePositionHook, useClosedPositions, useCollateralBreakdown, useCollateralData, useConfirmPendingPosition, useCowOrderStatus, useCurrentRates, useDeployNewPool as useDeployNewPoolHook, useDeposit as useDepositHook, useDispatch as useDispatchHook, useEstimateCollateralRequired, useEventPoller, useEventSubscription, useFactoryConstructMetadata, useFactoryOwnerOf, useFactoryTokenURI, useFailPendingPosition, useFlowNeutralTokenId, useForceExercise as useForceExerciseHook, useGuardianUnlockState, useInterestState, useIsLiquidatable, useLiquidate as useLiquidateHook, useLiquidationPrices, useMarginBuffer, useMaxPositionSize, useMaxRedeem, useMaxWithdrawable, useMinePoolAddress as useMinePoolAddressHook, useMintShares, useNativeTokenPrice, useNetLiquidationValue, useNetLiquidationValues, useOpenPosition as useOpenPositionHook, useOpenPositionPreview, useOptimizeRiskPartners, useOracleState, usePanopticContext, usePanopticPoolAddress, usePokeOracle as usePokeOracleHook, usePool, usePoolLiquidities, usePosition, usePositionGreeks, usePositions, usePositionsWithPremia, usePreviewBorrow, usePreviewDeposit, usePreviewMint, usePreviewRedeem, usePreviewWithdraw, usePriceHistory, useQuoteCowSwap, useQuoteSwapExactInViaRouter, useQuoteSwapExactOutViaRouter, useRealizedPnL, useRedeem as useRedeemHook, useRepay as useRepayHook, useResolveUniswapV4PoolKey, useRiskParameters, useRollPosition as useRollPositionHook, useSafeMode, useSettleAccumulatedPremia as useSettleAccumulatedPremiaHook, useSimulateBatchDispatch, useSimulateClosePosition, useSimulateDeployNewPool, useSimulateDeposit, useSimulateDispatch, useSimulateForceExercise, useSimulateLiquidate, useSimulateOpenPosition, useSimulateSFPMBurn, useSimulateSFPMMint, useSimulateSettle, useSimulateSwapExactIn, useSimulateSwapExactOut, useSimulateWithdraw, useSmartRepay as useSmartRepayHook, useStreamiaHistory, useSubmitCowOrder, useSupply as useSupplyHook, useSwapExactIn, useSwapExactInViaRouter, useSwapExactOut, useSwapExactOutViaRouter, useSyncPositions, useSyncStatus, useTrackedPositionIds, useTradeHistory, useTxEventConfirmation, useUniswapFeeHistory, useUniswapV3PoolInfo, useUniswapV3PoolLiquidities, useUniswapV4PoolBasicState, useUniswapV4PoolInfo, useUniswapV4PoolLiquidities, useUnsupply as useUnsupplyHook, useUnwrapWeth, useUnwrapXstock, useUtilization, useValidateBuilderCode, useWatchEvents, useWithdraw as useWithdrawHook, useWithdrawWithPositions as useWithdrawWithPositionsHook, useWrapEth, useWrapXstock, utilizationBpsToWad, utilizationPctToWad, validateBatch, validateBuilderCode, validatePoolId, verifyBlockContinuity, watchEvents, wethWrapAbi, withdraw, withdrawAndWait, withdrawWithPositions, withdrawWithPositionsAndWait, wrapEth, wrapEthAndWait, wrapXstock, wrapXstockAndWait, xstockWrapperAbi };
|
|
33303
33525
|
//# sourceMappingURL=react-public.js.map
|