@steerprotocol/sdk 3.3.0 → 3.4.0
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/README.md +11 -3
- package/dist/index.browser.mjs +4002 -82
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.cjs +4089 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +1679 -20
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4002 -82
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decodeFunctionResult, encodeAbiParameters, encodeFunctionData, formatUnits, getAddress, getContract, isAddress, isAddressEqual, keccak256, parseAbi } from "viem";
|
|
1
|
+
import { decodeEventLog, decodeFunctionResult, encodeAbiParameters, encodeFunctionData, formatUnits, getAddress, getContract, isAddress, isAddressEqual, keccak256, parseAbi } from "viem";
|
|
2
2
|
import { createClient } from "@steerprotocol/api-sdk";
|
|
3
3
|
import { Rounding, Token } from "@uniswap/sdk-core";
|
|
4
4
|
import { Pool } from "@uniswap/v3-sdk";
|
|
@@ -8910,7 +8910,7 @@ const networks = {
|
|
|
8910
8910
|
...bittensorAddresses
|
|
8911
8911
|
},
|
|
8912
8912
|
[Chain.Robinhood]: {
|
|
8913
|
-
address: "
|
|
8913
|
+
address: "0x0bd7d308f8e1639fab988df18a8011f41eacad73",
|
|
8914
8914
|
name: Chain.Robinhood,
|
|
8915
8915
|
wrappedNativeToken: "WETH",
|
|
8916
8916
|
isWrappingEnabled: false,
|
|
@@ -14457,7 +14457,10 @@ const pancakeSwapConfig = (theGraphApiKey) => ({
|
|
|
14457
14457
|
[Chain.Arbitrum]: "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865"
|
|
14458
14458
|
},
|
|
14459
14459
|
swapRouterAddress: { [Chain.BSC]: "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4" },
|
|
14460
|
-
NFTManagerAddress: {
|
|
14460
|
+
NFTManagerAddress: {
|
|
14461
|
+
[Chain.BSC]: "0x46A15B0b27311cedF172AB29E4f4766fbE7F4364",
|
|
14462
|
+
[Chain.Arbitrum]: "0x46A15B0b27311cedF172AB29E4f4766fbE7F4364"
|
|
14463
|
+
},
|
|
14461
14464
|
TickLensAddress: {
|
|
14462
14465
|
[Chain.BSC]: "0x9a489505a00cE272eAa5e07Dba6491314CaE3796",
|
|
14463
14466
|
[Chain.Arbitrum]: "0x9a489505a00cE272eAa5e07Dba6491314CaE3796"
|
|
@@ -14654,7 +14657,24 @@ const sushiConfig = (theGraphApiKey) => ({
|
|
|
14654
14657
|
[Chain.Robinhood]: "0xe51960f1b45f1c9fb6d166e6a884f866fc70433b",
|
|
14655
14658
|
[Chain.Mainnet]: "0xbaceb8ec6b9355dfc0269c18bac9d6e2bdc29c4f"
|
|
14656
14659
|
},
|
|
14657
|
-
NFTManagerAddress: {
|
|
14660
|
+
NFTManagerAddress: {
|
|
14661
|
+
[Chain.Polygon]: "0xb7402ee99f0a008e461098ac3a27f4957df89a40",
|
|
14662
|
+
[Chain.Arbitrum]: "0xf0cbce1942a68beb3d1b73f0dd86c8dcc363ef49",
|
|
14663
|
+
[Chain.Optimism]: "0x1af415a1eba07a4986a52b6f2e7de7003d82231e",
|
|
14664
|
+
[Chain.BSC]: "0xf70c086618dcf2b1a461311275e00d6b722ef914",
|
|
14665
|
+
[Chain.Avalanche]: "0x18350b048ab366ed601ffdbc669110ecb36016f3",
|
|
14666
|
+
[Chain.Thundercore]: "0xf4d73326c13a4fc5fd7a064217e12780e9bd62c3",
|
|
14667
|
+
[Chain.PolygonzkEVM]: "0xf4d73326c13a4fc5fd7a064217e12780e9bd62c3",
|
|
14668
|
+
[Chain.Base]: "0x80c7dd17b01855a6d2347444a0fcc36136a314de",
|
|
14669
|
+
[Chain.Linea]: "0x80c7dd17b01855a6d2347444a0fcc36136a314de",
|
|
14670
|
+
[Chain.Blast]: "0x51edb3e5bce8618b77b60215f84ad3db14709051",
|
|
14671
|
+
[Chain.Rootstock]: "0x0389879e0156033202c44bf784ac18fc02edee4f",
|
|
14672
|
+
[Chain.Filecoin]: "0xf4d73326c13a4fc5fd7a064217e12780e9bd62c3",
|
|
14673
|
+
[Chain.Hemi]: "0xe43ca1dee3f0fc1e2df73a0745674545f11a59f5",
|
|
14674
|
+
[Chain.Katana]: "0x2659c6085d26144117d904c46b48b6d180393d27",
|
|
14675
|
+
[Chain.Robinhood]: "0x51d0e5188afe12d502e29d982d20c190e7816107",
|
|
14676
|
+
[Chain.Mainnet]: "0x2214a42d8e2a1d20635c2cb0664422c528b6a432"
|
|
14677
|
+
},
|
|
14658
14678
|
TickLensAddress: {
|
|
14659
14679
|
[Chain.Polygon]: "0x9fdeA1412e50D78B25aCE4f96d35801647Fdf7dA",
|
|
14660
14680
|
[Chain.Arbitrum]: "0x8516944E89f296eb6473d79aED1Ba12088016c9e",
|
|
@@ -14679,8 +14699,22 @@ const sushiConfig = (theGraphApiKey) => ({
|
|
|
14679
14699
|
[Chain.Linea]: "0xc14Ee6B248787847527e11b8d7Cf257b212f7a9F"
|
|
14680
14700
|
},
|
|
14681
14701
|
initCodeHash: {
|
|
14702
|
+
[Chain.Polygon]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14703
|
+
[Chain.Arbitrum]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14704
|
+
[Chain.Optimism]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14705
|
+
[Chain.BSC]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14706
|
+
[Chain.Avalanche]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14707
|
+
[Chain.Thundercore]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14708
|
+
[Chain.PolygonzkEVM]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14709
|
+
[Chain.Base]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14710
|
+
[Chain.Linea]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14682
14711
|
[Chain.Blast]: "0x8e13daee7f5a62e37e71bf852bcd44e7d16b90617ed2b17c24c2ee62411c5bae",
|
|
14683
|
-
[Chain.
|
|
14712
|
+
[Chain.Rootstock]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14713
|
+
[Chain.Filecoin]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14714
|
+
[Chain.Hemi]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14715
|
+
[Chain.Katana]: "0xe040f12c7cee3904b78f24f8fc395629c2e69525c2815da7a659f7483e378ecb",
|
|
14716
|
+
[Chain.Robinhood]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54",
|
|
14717
|
+
[Chain.Mainnet]: "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54"
|
|
14684
14718
|
},
|
|
14685
14719
|
QuoterV2Address: {
|
|
14686
14720
|
[Chain.Polygon]: "0xb1E835Dc2785b52265711e17fCCb0fd018226a6e",
|
|
@@ -14772,7 +14806,8 @@ const uniswapConfig = (theGraphApiKey) => ({
|
|
|
14772
14806
|
[Chain.Arbitrum]: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
|
14773
14807
|
[Chain.BSC]: "0x7b8A01B39D58278b5DE7e48c8449c9f4F5170613",
|
|
14774
14808
|
[Chain.Celo]: "0x3d79EdAaBC0EaB6F08ED885C05Fc0B014290D95A",
|
|
14775
|
-
[Chain.
|
|
14809
|
+
[Chain.Rootstock]: "0x9d9386c042F194B460Ec424a1e57ACDE25f5C4b1",
|
|
14810
|
+
[Chain.Base]: "0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1",
|
|
14776
14811
|
[Chain.Filecoin]: "0x4cd986dD509fbB6A695aE971d5C56c8795f640ee",
|
|
14777
14812
|
[Chain.Sonic]: "0x743E03cceB4af2efA3CC76838f6E8B50B63F184c",
|
|
14778
14813
|
[Chain.Unichain]: "0x943e6e07a7e8e791dafc44083e54041d743c46e9",
|
|
@@ -15118,6 +15153,7 @@ const uniswapV4Config = (theGraphApiKey) => ({
|
|
|
15118
15153
|
[Chain.Robinhood]: "0x9639443158e8c5efa35bd45287bf2effd3d8dc06"
|
|
15119
15154
|
},
|
|
15120
15155
|
PositionManager: {
|
|
15156
|
+
[Chain.Unichain]: "0x4529A01c7A0410167c5740C487A8DE60232617bf",
|
|
15121
15157
|
[Chain.BSC]: "0x7a4a5c919ae2541aed11041a1aeee68f1287f95b",
|
|
15122
15158
|
[Chain.Base]: "0x7c5f5a4bbd8fd63184577525326123b519429bdc",
|
|
15123
15159
|
[Chain.Arbitrum]: "0xd88f38f930b7952f2db2432cb002e7abbf3dd869",
|
|
@@ -19646,6 +19682,320 @@ var VaultWithdrawClient = class {
|
|
|
19646
19682
|
}
|
|
19647
19683
|
};
|
|
19648
19684
|
//#endregion
|
|
19685
|
+
//#region src/pool-lifecycle/abis/v4.ts
|
|
19686
|
+
/** Minimal authoritative IPoolManager surface used by the V4 lifecycle adapter. */
|
|
19687
|
+
const v4PoolManagerAbi = parseAbi(["function initialize((address currency0,address currency1,uint24 fee,int24 tickSpacing,address hooks) key, uint160 sqrtPriceX96) returns (int24 tick)", "event Initialize(bytes32 indexed id, address indexed currency0, address indexed currency1, uint24 fee, int24 tickSpacing, address hooks, uint160 sqrtPriceX96, int24 tick)"]);
|
|
19688
|
+
/** Minimal StateView/ImmutableState surface used for deployment and state checks. */
|
|
19689
|
+
const v4StateViewAbi = parseAbi(["function poolManager() view returns (address)", "function getSlot0(bytes32 poolId) view returns (uint160 sqrtPriceX96, int24 tick, uint24 protocolFee, uint24 lpFee)"]);
|
|
19690
|
+
//#endregion
|
|
19691
|
+
//#region src/pool-lifecycle/errors.ts
|
|
19692
|
+
/** Error thrown when a pool lifecycle primitive cannot safely continue. */
|
|
19693
|
+
var PoolLifecycleError = class extends Error {
|
|
19694
|
+
constructor(code, message, causeValue) {
|
|
19695
|
+
super(message);
|
|
19696
|
+
this.name = "PoolLifecycleError";
|
|
19697
|
+
this.code = code;
|
|
19698
|
+
this.causeValue = causeValue;
|
|
19699
|
+
}
|
|
19700
|
+
};
|
|
19701
|
+
//#endregion
|
|
19702
|
+
//#region src/pool-lifecycle/math.ts
|
|
19703
|
+
/** The smallest sqrt price accepted by Uniswap TickMath, inclusive. */
|
|
19704
|
+
const MIN_SQRT_RATIO = 4295128739n;
|
|
19705
|
+
/** The largest TickMath sqrt-price boundary, which is not itself valid. */
|
|
19706
|
+
const MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342n;
|
|
19707
|
+
const ZERO_ADDRESS$3 = "0x0000000000000000000000000000000000000000";
|
|
19708
|
+
const MAX_ERC20_DECIMALS = 255;
|
|
19709
|
+
function greatestCommonDivisor(a, b) {
|
|
19710
|
+
let left = a;
|
|
19711
|
+
let right = b;
|
|
19712
|
+
while (right !== 0n) {
|
|
19713
|
+
const remainder = left % right;
|
|
19714
|
+
left = right;
|
|
19715
|
+
right = remainder;
|
|
19716
|
+
}
|
|
19717
|
+
return left;
|
|
19718
|
+
}
|
|
19719
|
+
function checksumAddress(value, label, allowZero) {
|
|
19720
|
+
if (typeof value !== "string" || !isAddress(value, { strict: true })) throw new TypeError(`${label} must be a valid EVM address`);
|
|
19721
|
+
const address = getAddress(value);
|
|
19722
|
+
if (!allowZero && address === ZERO_ADDRESS$3) throw new RangeError(`${label} must not be the zero address`);
|
|
19723
|
+
return address;
|
|
19724
|
+
}
|
|
19725
|
+
function assertErc20Decimals(value, label) {
|
|
19726
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > MAX_ERC20_DECIMALS) throw new RangeError(`${label} must be an integer from 0 through 255`);
|
|
19727
|
+
}
|
|
19728
|
+
function assertPositiveFraction(value) {
|
|
19729
|
+
if (typeof value?.numerator !== "bigint" || typeof value?.denominator !== "bigint") throw new TypeError("quotePerBase must contain bigint numerator and denominator values");
|
|
19730
|
+
if (value.numerator <= 0n) throw new RangeError("quotePerBase numerator must be greater than zero");
|
|
19731
|
+
if (value.denominator <= 0n) throw new RangeError("quotePerBase denominator must be greater than zero");
|
|
19732
|
+
}
|
|
19733
|
+
/**
|
|
19734
|
+
* Parses an unsigned, fixed-point decimal string without converting through a
|
|
19735
|
+
* JavaScript number. Signs, exponent notation, whitespace, and omitted whole
|
|
19736
|
+
* or fractional digits are rejected. The returned fraction is reduced.
|
|
19737
|
+
*/
|
|
19738
|
+
function parseExactDecimal(value) {
|
|
19739
|
+
if (typeof value !== "string") throw new TypeError("Decimal value must be provided as a string");
|
|
19740
|
+
const match = /^([0-9]+)(?:\.([0-9]+))?$/.exec(value);
|
|
19741
|
+
if (match === null || match[0] !== value) throw new TypeError("Decimal value must use unsigned fixed-point notation, for example \"123.45\"");
|
|
19742
|
+
const wholeDigits = match[1];
|
|
19743
|
+
const fractionalDigits = match[2] ?? "";
|
|
19744
|
+
const numerator = BigInt(`${wholeDigits}${fractionalDigits}`);
|
|
19745
|
+
if (numerator === 0n) return {
|
|
19746
|
+
numerator: 0n,
|
|
19747
|
+
denominator: 1n
|
|
19748
|
+
};
|
|
19749
|
+
const denominator = 10n ** BigInt(fractionalDigits.length);
|
|
19750
|
+
const divisor = greatestCommonDivisor(numerator, denominator);
|
|
19751
|
+
return {
|
|
19752
|
+
numerator: numerator / divisor,
|
|
19753
|
+
denominator: denominator / divisor
|
|
19754
|
+
};
|
|
19755
|
+
}
|
|
19756
|
+
/**
|
|
19757
|
+
* Validates, checksums, and sorts two distinct non-zero ERC20 addresses.
|
|
19758
|
+
*/
|
|
19759
|
+
function sortErc20Pair(tokenA, tokenB) {
|
|
19760
|
+
const normalizedTokenA = checksumAddress(tokenA, "tokenA", false);
|
|
19761
|
+
const normalizedTokenB = checksumAddress(tokenB, "tokenB", false);
|
|
19762
|
+
if (normalizedTokenA === normalizedTokenB) throw new RangeError("ERC20 pair tokens must be different");
|
|
19763
|
+
return BigInt(normalizedTokenA) < BigInt(normalizedTokenB) ? {
|
|
19764
|
+
token0: normalizedTokenA,
|
|
19765
|
+
token1: normalizedTokenB
|
|
19766
|
+
} : {
|
|
19767
|
+
token0: normalizedTokenB,
|
|
19768
|
+
token1: normalizedTokenA
|
|
19769
|
+
};
|
|
19770
|
+
}
|
|
19771
|
+
/**
|
|
19772
|
+
* Validates, checksums, and sorts two distinct EVM currencies. The zero
|
|
19773
|
+
* address is allowed and, when present, necessarily sorts as currency0.
|
|
19774
|
+
*/
|
|
19775
|
+
function sortEvmCurrencyPair(currencyA, currencyB) {
|
|
19776
|
+
const normalizedCurrencyA = checksumAddress(currencyA, "currencyA", true);
|
|
19777
|
+
const normalizedCurrencyB = checksumAddress(currencyB, "currencyB", true);
|
|
19778
|
+
if (normalizedCurrencyA === normalizedCurrencyB) throw new RangeError("EVM pair currencies must be different");
|
|
19779
|
+
return BigInt(normalizedCurrencyA) < BigInt(normalizedCurrencyB) ? {
|
|
19780
|
+
currency0: normalizedCurrencyA,
|
|
19781
|
+
currency1: normalizedCurrencyB
|
|
19782
|
+
} : {
|
|
19783
|
+
currency0: normalizedCurrencyB,
|
|
19784
|
+
currency1: normalizedCurrencyA
|
|
19785
|
+
};
|
|
19786
|
+
}
|
|
19787
|
+
/**
|
|
19788
|
+
* Returns floor(sqrt(value)) using bigint arithmetic only.
|
|
19789
|
+
*/
|
|
19790
|
+
function integerSqrt(value) {
|
|
19791
|
+
if (typeof value !== "bigint") throw new TypeError("Square-root input must be a bigint");
|
|
19792
|
+
if (value < 0n) throw new RangeError("Square-root input must not be negative");
|
|
19793
|
+
if (value < 2n) return value;
|
|
19794
|
+
let estimate = value;
|
|
19795
|
+
let nextEstimate = estimate + 1n >> 1n;
|
|
19796
|
+
while (nextEstimate < estimate) {
|
|
19797
|
+
estimate = nextEstimate;
|
|
19798
|
+
nextEstimate = estimate + value / estimate >> 1n;
|
|
19799
|
+
}
|
|
19800
|
+
return estimate;
|
|
19801
|
+
}
|
|
19802
|
+
/**
|
|
19803
|
+
* Enforces the Uniswap TickMath interval: MIN is inclusive and MAX exclusive.
|
|
19804
|
+
* Returns the input so it can be composed with transaction builders.
|
|
19805
|
+
*/
|
|
19806
|
+
function validateSqrtPriceX96(sqrtPriceX96) {
|
|
19807
|
+
if (typeof sqrtPriceX96 !== "bigint") throw new TypeError("sqrtPriceX96 must be a bigint");
|
|
19808
|
+
if (sqrtPriceX96 < 4295128739n || sqrtPriceX96 >= 1461446703485210103287273052203988822378723970342n) throw new RangeError(`sqrtPriceX96 must be in [${MIN_SQRT_RATIO}, ${MAX_SQRT_RATIO})`);
|
|
19809
|
+
return sqrtPriceX96;
|
|
19810
|
+
}
|
|
19811
|
+
/**
|
|
19812
|
+
* Encode an exact raw token1/token0 amount ratio without token metadata.
|
|
19813
|
+
* The result matches the canonical V3 floor-rounding operation.
|
|
19814
|
+
*/
|
|
19815
|
+
function encodeSqrtRatioX96(amount1Raw, amount0Raw) {
|
|
19816
|
+
if (typeof amount0Raw !== "bigint" || typeof amount1Raw !== "bigint") throw new TypeError("Raw ratio amounts must be bigint values");
|
|
19817
|
+
if (amount0Raw <= 0n || amount1Raw <= 0n) throw new RangeError("Raw ratio amounts must be greater than zero");
|
|
19818
|
+
return validateSqrtPriceX96(integerSqrt((amount1Raw << 192n) / amount0Raw));
|
|
19819
|
+
}
|
|
19820
|
+
/**
|
|
19821
|
+
* Converts an exact quote-per-base human price into the canonical raw-token
|
|
19822
|
+
* ratio and sqrtPriceX96 expected by concentrated-liquidity initializers.
|
|
19823
|
+
*
|
|
19824
|
+
* Address sorting and reciprocal orientation happen before the only lossy
|
|
19825
|
+
* operation. The final encoding is exactly:
|
|
19826
|
+
*
|
|
19827
|
+
* floor(sqrt((amount1Raw << 192) / amount0Raw))
|
|
19828
|
+
*/
|
|
19829
|
+
function encodeInitialSqrtPriceX96(price) {
|
|
19830
|
+
const pair = sortErc20Pair(price.baseToken, price.quoteToken);
|
|
19831
|
+
const baseToken = checksumAddress(price.baseToken, "baseToken", false);
|
|
19832
|
+
assertErc20Decimals(price.baseTokenDecimals, "baseTokenDecimals");
|
|
19833
|
+
assertErc20Decimals(price.quoteTokenDecimals, "quoteTokenDecimals");
|
|
19834
|
+
assertPositiveFraction(price.quotePerBase);
|
|
19835
|
+
const baseScale = 10n ** BigInt(price.baseTokenDecimals);
|
|
19836
|
+
const quoteScale = 10n ** BigInt(price.quoteTokenDecimals);
|
|
19837
|
+
const baseTokenIsToken0 = baseToken === pair.token0;
|
|
19838
|
+
const amount0Raw = baseTokenIsToken0 ? price.quotePerBase.denominator * baseScale : price.quotePerBase.numerator * quoteScale;
|
|
19839
|
+
const amount1Raw = baseTokenIsToken0 ? price.quotePerBase.numerator * quoteScale : price.quotePerBase.denominator * baseScale;
|
|
19840
|
+
const sqrtPriceX96 = encodeSqrtRatioX96(amount1Raw, amount0Raw);
|
|
19841
|
+
return {
|
|
19842
|
+
...pair,
|
|
19843
|
+
amount0Raw,
|
|
19844
|
+
amount1Raw,
|
|
19845
|
+
sqrtPriceX96,
|
|
19846
|
+
baseTokenIsToken0
|
|
19847
|
+
};
|
|
19848
|
+
}
|
|
19849
|
+
/**
|
|
19850
|
+
* Currency-aware counterpart to {@link encodeInitialSqrtPriceX96}. It keeps
|
|
19851
|
+
* the same exact orientation and floor-rounding rules while permitting the
|
|
19852
|
+
* native zero-address currency required by Uniswap V4.
|
|
19853
|
+
*/
|
|
19854
|
+
function encodeCurrencyInitialSqrtPriceX96(price) {
|
|
19855
|
+
const pair = sortEvmCurrencyPair(price.baseCurrency, price.quoteCurrency);
|
|
19856
|
+
const baseCurrency = checksumAddress(price.baseCurrency, "baseCurrency", true);
|
|
19857
|
+
assertErc20Decimals(price.baseCurrencyDecimals, "baseCurrencyDecimals");
|
|
19858
|
+
assertErc20Decimals(price.quoteCurrencyDecimals, "quoteCurrencyDecimals");
|
|
19859
|
+
assertPositiveFraction(price.quotePerBase);
|
|
19860
|
+
const baseScale = 10n ** BigInt(price.baseCurrencyDecimals);
|
|
19861
|
+
const quoteScale = 10n ** BigInt(price.quoteCurrencyDecimals);
|
|
19862
|
+
const baseCurrencyIsCurrency0 = baseCurrency === pair.currency0;
|
|
19863
|
+
const amount0Raw = baseCurrencyIsCurrency0 ? price.quotePerBase.denominator * baseScale : price.quotePerBase.numerator * quoteScale;
|
|
19864
|
+
const amount1Raw = baseCurrencyIsCurrency0 ? price.quotePerBase.numerator * quoteScale : price.quotePerBase.denominator * baseScale;
|
|
19865
|
+
return {
|
|
19866
|
+
...pair,
|
|
19867
|
+
amount0Raw,
|
|
19868
|
+
amount1Raw,
|
|
19869
|
+
sqrtPriceX96: encodeSqrtRatioX96(amount1Raw, amount0Raw),
|
|
19870
|
+
baseCurrencyIsCurrency0
|
|
19871
|
+
};
|
|
19872
|
+
}
|
|
19873
|
+
//#endregion
|
|
19874
|
+
//#region src/pool-lifecycle/v4/key.ts
|
|
19875
|
+
const V4_DYNAMIC_FEE_FLAG = 8388608;
|
|
19876
|
+
const V4_MAX_STATIC_FEE = 1e6;
|
|
19877
|
+
const V4_MAX_TICK_SPACING = 32767;
|
|
19878
|
+
const V4_ALL_HOOK_MASK = (1n << 14n) - 1n;
|
|
19879
|
+
const V4_ZERO_ADDRESS = getAddress("0x0000000000000000000000000000000000000000");
|
|
19880
|
+
const BEFORE_SWAP_FLAG = 1n << 7n;
|
|
19881
|
+
const AFTER_SWAP_FLAG = 1n << 6n;
|
|
19882
|
+
const AFTER_ADD_LIQUIDITY_FLAG = 1n << 10n;
|
|
19883
|
+
const AFTER_REMOVE_LIQUIDITY_FLAG = 1n << 8n;
|
|
19884
|
+
const BEFORE_SWAP_RETURNS_DELTA_FLAG = 1n << 3n;
|
|
19885
|
+
const AFTER_SWAP_RETURNS_DELTA_FLAG = 1n << 2n;
|
|
19886
|
+
const AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG = 1n << 1n;
|
|
19887
|
+
const AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG = 1n;
|
|
19888
|
+
const POOL_KEY_ABI_PARAMETER = {
|
|
19889
|
+
type: "tuple",
|
|
19890
|
+
components: [
|
|
19891
|
+
{
|
|
19892
|
+
name: "currency0",
|
|
19893
|
+
type: "address"
|
|
19894
|
+
},
|
|
19895
|
+
{
|
|
19896
|
+
name: "currency1",
|
|
19897
|
+
type: "address"
|
|
19898
|
+
},
|
|
19899
|
+
{
|
|
19900
|
+
name: "fee",
|
|
19901
|
+
type: "uint24"
|
|
19902
|
+
},
|
|
19903
|
+
{
|
|
19904
|
+
name: "tickSpacing",
|
|
19905
|
+
type: "int24"
|
|
19906
|
+
},
|
|
19907
|
+
{
|
|
19908
|
+
name: "hooks",
|
|
19909
|
+
type: "address"
|
|
19910
|
+
}
|
|
19911
|
+
]
|
|
19912
|
+
};
|
|
19913
|
+
function invalidInput(message, cause) {
|
|
19914
|
+
throw new PoolLifecycleError("INVALID_INPUT", message, cause);
|
|
19915
|
+
}
|
|
19916
|
+
function normalizeAddress(value, label) {
|
|
19917
|
+
if (typeof value !== "string" || !isAddress(value, { strict: true })) return invalidInput(`${label} must be a valid EVM address.`);
|
|
19918
|
+
return getAddress(value);
|
|
19919
|
+
}
|
|
19920
|
+
function validateFee(fee) {
|
|
19921
|
+
if (!Number.isSafeInteger(fee) || Number(fee) < 0 || Number(fee) > 1e6 && Number(fee) !== 8388608) return invalidInput("V4 fee must be an integer from 0 through 1000000 or the dynamic fee flag 0x800000.");
|
|
19922
|
+
return Number(fee);
|
|
19923
|
+
}
|
|
19924
|
+
function validateTickSpacing(tickSpacing) {
|
|
19925
|
+
if (!Number.isSafeInteger(tickSpacing) || Number(tickSpacing) < 1 || Number(tickSpacing) > 32767) return invalidInput("V4 tickSpacing must be an integer from 1 through 32767.");
|
|
19926
|
+
return Number(tickSpacing);
|
|
19927
|
+
}
|
|
19928
|
+
function validateHookAddress(hooksAddress, fee) {
|
|
19929
|
+
const hooks = BigInt(hooksAddress);
|
|
19930
|
+
const hasFlag = (flag) => (hooks & flag) !== 0n;
|
|
19931
|
+
if (!hasFlag(BEFORE_SWAP_FLAG) && hasFlag(BEFORE_SWAP_RETURNS_DELTA_FLAG) || !hasFlag(AFTER_SWAP_FLAG) && hasFlag(AFTER_SWAP_RETURNS_DELTA_FLAG) || !hasFlag(AFTER_ADD_LIQUIDITY_FLAG) && hasFlag(AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG) || !hasFlag(AFTER_REMOVE_LIQUIDITY_FLAG) && hasFlag(AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG)) invalidInput("V4 hook return-delta flags require their corresponding action flags.");
|
|
19932
|
+
const dynamicFee = fee === V4_DYNAMIC_FEE_FLAG;
|
|
19933
|
+
if (!(hooks === 0n ? !dynamicFee : (hooks & V4_ALL_HOOK_MASK) !== 0n || dynamicFee)) invalidInput("V4 hooks address is incompatible with its fee and permission flags.");
|
|
19934
|
+
}
|
|
19935
|
+
/** Validate a complete PoolKey whose currencies are already canonically ordered. */
|
|
19936
|
+
function validateV4PoolKey(value) {
|
|
19937
|
+
const currency0 = normalizeAddress(value?.currency0, "currency0");
|
|
19938
|
+
const currency1 = normalizeAddress(value?.currency1, "currency1");
|
|
19939
|
+
const fee = validateFee(value?.fee);
|
|
19940
|
+
const tickSpacing = validateTickSpacing(value?.tickSpacing);
|
|
19941
|
+
const hooks = normalizeAddress(value?.hooks, "hooks");
|
|
19942
|
+
if (BigInt(currency0) >= BigInt(currency1)) invalidInput("V4 currencies must be distinct and canonically ordered.");
|
|
19943
|
+
validateHookAddress(hooks, fee);
|
|
19944
|
+
return {
|
|
19945
|
+
currency0,
|
|
19946
|
+
currency1,
|
|
19947
|
+
fee,
|
|
19948
|
+
tickSpacing,
|
|
19949
|
+
hooks
|
|
19950
|
+
};
|
|
19951
|
+
}
|
|
19952
|
+
/**
|
|
19953
|
+
* Validate and sort two currencies. Address zero is deliberately accepted and
|
|
19954
|
+
* sorts first because V4 represents the native currency as address(0).
|
|
19955
|
+
*/
|
|
19956
|
+
function canonicalizeV4PoolKey(value) {
|
|
19957
|
+
const currencyA = normalizeAddress(value?.currencyA, "currencyA");
|
|
19958
|
+
const currencyB = normalizeAddress(value?.currencyB, "currencyB");
|
|
19959
|
+
if (currencyA === currencyB) return invalidInput("V4 pool currencies must be different.");
|
|
19960
|
+
const [currency0, currency1] = BigInt(currencyA) < BigInt(currencyB) ? [currencyA, currencyB] : [currencyB, currencyA];
|
|
19961
|
+
return validateV4PoolKey({
|
|
19962
|
+
currency0,
|
|
19963
|
+
currency1,
|
|
19964
|
+
fee: value?.fee,
|
|
19965
|
+
tickSpacing: value?.tickSpacing,
|
|
19966
|
+
hooks: value?.hooks
|
|
19967
|
+
});
|
|
19968
|
+
}
|
|
19969
|
+
/** Return the exact PoolId used by PoolIdLibrary.toId. */
|
|
19970
|
+
function getV4PoolId(key) {
|
|
19971
|
+
const validated = validateV4PoolKey(key);
|
|
19972
|
+
return keccak256(encodeAbiParameters([POOL_KEY_ABI_PARAMETER], [validated]));
|
|
19973
|
+
}
|
|
19974
|
+
function v4PoolKeysEqual(left, right) {
|
|
19975
|
+
try {
|
|
19976
|
+
const a = validateV4PoolKey(left);
|
|
19977
|
+
const b = validateV4PoolKey(right);
|
|
19978
|
+
return a.currency0 === b.currency0 && a.currency1 === b.currency1 && a.fee === b.fee && a.tickSpacing === b.tickSpacing && a.hooks === b.hooks;
|
|
19979
|
+
} catch {
|
|
19980
|
+
return false;
|
|
19981
|
+
}
|
|
19982
|
+
}
|
|
19983
|
+
/** Validate price bounds and bind the price to the canonical PoolKey order. */
|
|
19984
|
+
function assertV4InitialPrice(key, value) {
|
|
19985
|
+
const currency0 = normalizeAddress(value?.currency0, "initialPrice.currency0");
|
|
19986
|
+
const currency1 = normalizeAddress(value?.currency1, "initialPrice.currency1");
|
|
19987
|
+
if (currency0 !== key.currency0 || currency1 !== key.currency1) return invalidInput("V4 initial price currencies must match the canonical PoolKey order.");
|
|
19988
|
+
try {
|
|
19989
|
+
return {
|
|
19990
|
+
currency0,
|
|
19991
|
+
currency1,
|
|
19992
|
+
sqrtPriceX96: validateSqrtPriceX96(value?.sqrtPriceX96)
|
|
19993
|
+
};
|
|
19994
|
+
} catch (error) {
|
|
19995
|
+
return invalidInput(error instanceof Error ? error.message : "V4 sqrtPriceX96 is invalid.", error);
|
|
19996
|
+
}
|
|
19997
|
+
}
|
|
19998
|
+
//#endregion
|
|
19649
19999
|
//#region src/base/vault/execution-context.ts
|
|
19650
20000
|
const VAULT_REGISTRY_ABI = parseAbi(["function getVaultDetails(address vault) view returns ((uint8 state,uint256 tokenId,uint256 vaultID,string payloadIpfs,address vaultAddress,string beaconName) details)", "function beaconAddresses(string beaconName) view returns (address)"]);
|
|
19651
20001
|
const VAULT_EXECUTION_ABI = parseAbi([
|
|
@@ -19683,19 +20033,6 @@ const ALGEBRA_DIRECTIONAL_POOL_ABI = parseAbi([
|
|
|
19683
20033
|
"function globalState() view returns (uint160 price,int24 tick,uint16 feeZto,uint16 feeOtz,uint16 timepointIndex,uint8 communityFeeToken0,uint8 communityFeeToken1,bool unlocked)",
|
|
19684
20034
|
"function tickSpacing() view returns (int24)"
|
|
19685
20035
|
]);
|
|
19686
|
-
const STATE_VIEW_ABI = parseAbi(["function getSlot0(bytes32 poolId) view returns (uint160 sqrtPriceX96,int24 tick,uint24 protocolFee,uint24 lpFee)"]);
|
|
19687
|
-
const V4_DYNAMIC_FEE_FLAG = 8388608;
|
|
19688
|
-
const V4_MAX_STATIC_FEE = 1e6;
|
|
19689
|
-
const V4_MAX_TICK_SPACING = 32767;
|
|
19690
|
-
const V4_ALL_HOOK_MASK = (1n << 14n) - 1n;
|
|
19691
|
-
const V4_BEFORE_SWAP_FLAG = 1n << 7n;
|
|
19692
|
-
const V4_AFTER_SWAP_FLAG = 1n << 6n;
|
|
19693
|
-
const V4_AFTER_ADD_LIQUIDITY_FLAG = 1n << 10n;
|
|
19694
|
-
const V4_AFTER_REMOVE_LIQUIDITY_FLAG = 1n << 8n;
|
|
19695
|
-
const V4_BEFORE_SWAP_RETURNS_DELTA_FLAG = 1n << 3n;
|
|
19696
|
-
const V4_AFTER_SWAP_RETURNS_DELTA_FLAG = 1n << 2n;
|
|
19697
|
-
const V4_AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG = 1n << 1n;
|
|
19698
|
-
const V4_AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG = 1n;
|
|
19699
20036
|
var ExecutionContextError = class extends Error {
|
|
19700
20037
|
constructor(status, message) {
|
|
19701
20038
|
super(message);
|
|
@@ -19712,23 +20049,11 @@ function resolvePoolFamily(protocol) {
|
|
|
19712
20049
|
return "uniswap-v3-compatible";
|
|
19713
20050
|
}
|
|
19714
20051
|
function assertPoolKey(poolKey, invalidStatus = 400) {
|
|
19715
|
-
|
|
19716
|
-
|
|
19717
|
-
|
|
19718
|
-
|
|
19719
|
-
|
|
19720
|
-
currency1: getAddress(poolKey.currency1),
|
|
19721
|
-
fee: poolKey.fee,
|
|
19722
|
-
tickSpacing: poolKey.tickSpacing,
|
|
19723
|
-
hooks: getAddress(poolKey.hooks)
|
|
19724
|
-
};
|
|
19725
|
-
if (BigInt(normalized.currency0) >= BigInt(normalized.currency1)) throw new ExecutionContextError(invalidStatus, "Uniswap v4 poolKey currencies are not canonically ordered.");
|
|
19726
|
-
const hooks = BigInt(normalized.hooks);
|
|
19727
|
-
const isDynamicFee = normalized.fee === V4_DYNAMIC_FEE_FLAG;
|
|
19728
|
-
const hasFlag = (flag) => (hooks & flag) !== 0n;
|
|
19729
|
-
if (!hasFlag(V4_BEFORE_SWAP_FLAG) && hasFlag(V4_BEFORE_SWAP_RETURNS_DELTA_FLAG) || !hasFlag(V4_AFTER_SWAP_FLAG) && hasFlag(V4_AFTER_SWAP_RETURNS_DELTA_FLAG) || !hasFlag(V4_AFTER_ADD_LIQUIDITY_FLAG) && hasFlag(V4_AFTER_ADD_LIQUIDITY_RETURNS_DELTA_FLAG) || !hasFlag(V4_AFTER_REMOVE_LIQUIDITY_FLAG) && hasFlag(V4_AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA_FLAG)) throw new ExecutionContextError(invalidStatus, "Uniswap v4 poolKey hook return-delta flags require their corresponding action flags.");
|
|
19730
|
-
if (!(hooks === 0n ? !isDynamicFee : (hooks & V4_ALL_HOOK_MASK) !== 0n || isDynamicFee)) throw new ExecutionContextError(invalidStatus, "Uniswap v4 poolKey hook address is incompatible with its fee and permission flags.");
|
|
19731
|
-
return normalized;
|
|
20052
|
+
try {
|
|
20053
|
+
return validateV4PoolKey(poolKey);
|
|
20054
|
+
} catch (error) {
|
|
20055
|
+
throw new ExecutionContextError(invalidStatus, error instanceof Error ? error.message : "Uniswap v4 poolKey is invalid.");
|
|
20056
|
+
}
|
|
19732
20057
|
}
|
|
19733
20058
|
function normalizeRawPoolKey(raw) {
|
|
19734
20059
|
return assertPoolKey({
|
|
@@ -19740,34 +20065,10 @@ function normalizeRawPoolKey(raw) {
|
|
|
19740
20065
|
}, 422);
|
|
19741
20066
|
}
|
|
19742
20067
|
function poolKeysEqual(a, b) {
|
|
19743
|
-
return
|
|
20068
|
+
return v4PoolKeysEqual(a, b);
|
|
19744
20069
|
}
|
|
19745
20070
|
function getPoolId(poolKey) {
|
|
19746
|
-
return
|
|
19747
|
-
type: "tuple",
|
|
19748
|
-
components: [
|
|
19749
|
-
{
|
|
19750
|
-
name: "currency0",
|
|
19751
|
-
type: "address"
|
|
19752
|
-
},
|
|
19753
|
-
{
|
|
19754
|
-
name: "currency1",
|
|
19755
|
-
type: "address"
|
|
19756
|
-
},
|
|
19757
|
-
{
|
|
19758
|
-
name: "fee",
|
|
19759
|
-
type: "uint24"
|
|
19760
|
-
},
|
|
19761
|
-
{
|
|
19762
|
-
name: "tickSpacing",
|
|
19763
|
-
type: "int24"
|
|
19764
|
-
},
|
|
19765
|
-
{
|
|
19766
|
-
name: "hooks",
|
|
19767
|
-
type: "address"
|
|
19768
|
-
}
|
|
19769
|
-
]
|
|
19770
|
-
}], [poolKey]));
|
|
20071
|
+
return getV4PoolId(poolKey);
|
|
19771
20072
|
}
|
|
19772
20073
|
function normalizePositions(raw) {
|
|
19773
20074
|
const [lowerTicks, upperTicks, relativeWeights] = raw;
|
|
@@ -19845,8 +20146,7 @@ async function getVaultExecutionContext(params) {
|
|
|
19845
20146
|
if (blockNumber < 0n) throw new ExecutionContextError(400, "blockNumber must be non-negative.");
|
|
19846
20147
|
if (epochTimestamp < 0n) throw new ExecutionContextError(400, "epochTimestamp must be a non-negative Unix timestamp.");
|
|
19847
20148
|
if (!isAddress(params.vaultAddress)) throw new ExecutionContextError(400, "vaultAddress must be a valid EVM address.");
|
|
19848
|
-
const chainId = publicClient.
|
|
19849
|
-
if (!chainId) throw new ExecutionContextError(400, "publicClient must have an active chain.");
|
|
20149
|
+
const chainId = await publicClient.getChainId();
|
|
19850
20150
|
const chain = chainIdToName(chainId);
|
|
19851
20151
|
const network = getNetworkByChainId(chainId);
|
|
19852
20152
|
const vaultRegistry = getContractAddressByChainIdAndContractName(chainId, "VaultRegistry");
|
|
@@ -19911,13 +20211,19 @@ async function getVaultExecutionContext(params) {
|
|
|
19911
20211
|
const stateView = v4Config?.StateView?.[chain];
|
|
19912
20212
|
if (!poolManager || !stateView || !isAddress(poolManager) || !isAddress(stateView)) throw new ExecutionContextError(422, "Uniswap v4 PoolManager or StateView is missing from SDK config.");
|
|
19913
20213
|
poolManagerAddress = getAddress(poolManager);
|
|
19914
|
-
const slot0 = await publicClient.readContract({
|
|
20214
|
+
const [stateViewPoolManager, slot0] = await Promise.all([publicClient.readContract({
|
|
20215
|
+
address: getAddress(stateView),
|
|
20216
|
+
abi: v4StateViewAbi,
|
|
20217
|
+
functionName: "poolManager",
|
|
20218
|
+
blockNumber
|
|
20219
|
+
}), publicClient.readContract({
|
|
19915
20220
|
address: getAddress(stateView),
|
|
19916
|
-
abi:
|
|
20221
|
+
abi: v4StateViewAbi,
|
|
19917
20222
|
functionName: "getSlot0",
|
|
19918
20223
|
args: [poolId],
|
|
19919
20224
|
blockNumber
|
|
19920
|
-
});
|
|
20225
|
+
})]);
|
|
20226
|
+
if (getAddress(stateViewPoolManager) !== poolManagerAddress) throw new ExecutionContextError(422, "Configured Uniswap v4 StateView is bound to a different PoolManager.");
|
|
19921
20227
|
if (slot0[0] === 0n) throw new ExecutionContextError(422, `Uniswap v4 pool ${poolId} is not initialized in the configured PoolManager.`);
|
|
19922
20228
|
currentTick = Number(slot0[1]);
|
|
19923
20229
|
tickSpacing = poolKey.tickSpacing;
|
|
@@ -22366,19 +22672,19 @@ const getPoolDetailsQuery = (isAlgebraPool, protocol) => {
|
|
|
22366
22672
|
*
|
|
22367
22673
|
* @example
|
|
22368
22674
|
* ```typescript
|
|
22369
|
-
* import { createPublicClient,
|
|
22675
|
+
* import { createPublicClient, http } from 'viem';
|
|
22370
22676
|
* import { mainnet } from 'viem/chains';
|
|
22371
22677
|
* import { PoolClient } from '@steerprotocol/sdk';
|
|
22372
22678
|
*
|
|
22373
22679
|
* const client = createPublicClient({
|
|
22374
22680
|
* chain: mainnet,
|
|
22375
22681
|
* transport: http()
|
|
22376
|
-
* })
|
|
22682
|
+
* });
|
|
22377
22683
|
*
|
|
22378
22684
|
* const poolClient = new PoolClient(client, 'your-subgraph-studio-key');
|
|
22379
22685
|
*
|
|
22380
22686
|
* // Fetch top pools
|
|
22381
|
-
* const topPools = await poolClient.getTopPools(100, Protocol.
|
|
22687
|
+
* const topPools = await poolClient.getTopPools(100, Protocol.Uniswap, 1);
|
|
22382
22688
|
* ```
|
|
22383
22689
|
*
|
|
22384
22690
|
* @extends SubgraphClient
|
|
@@ -22388,7 +22694,7 @@ var PoolClient = class extends SubgraphClient {
|
|
|
22388
22694
|
/**
|
|
22389
22695
|
* Creates a new PoolClient instance
|
|
22390
22696
|
*
|
|
22391
|
-
* @param client -
|
|
22697
|
+
* @param client - Public client for read-only blockchain interactions
|
|
22392
22698
|
* @param subgraphStudioKey - Optional Subgraph Studio API key for higher rate limits
|
|
22393
22699
|
*
|
|
22394
22700
|
* @example
|
|
@@ -22544,7 +22850,7 @@ var PoolClient = class extends SubgraphClient {
|
|
|
22544
22850
|
* @example
|
|
22545
22851
|
* ```typescript
|
|
22546
22852
|
* // Get top 100 Uniswap V3 pools on Ethereum
|
|
22547
|
-
* const topPools = await poolClient.getTopPools(100, Protocol.
|
|
22853
|
+
* const topPools = await poolClient.getTopPools(100, Protocol.Uniswap, 1);
|
|
22548
22854
|
* if (topPools.success) {
|
|
22549
22855
|
* console.log(`Found ${topPools.data.length} pools`);
|
|
22550
22856
|
* }
|
|
@@ -22593,7 +22899,7 @@ var PoolClient = class extends SubgraphClient {
|
|
|
22593
22899
|
* // Get specific pool details
|
|
22594
22900
|
* const poolDetails = await poolClient.getPoolById(
|
|
22595
22901
|
* '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
|
|
22596
|
-
* Protocol.
|
|
22902
|
+
* Protocol.Uniswap,
|
|
22597
22903
|
* 1
|
|
22598
22904
|
* );
|
|
22599
22905
|
* if (poolDetails.success && poolDetails.data) {
|
|
@@ -22641,7 +22947,7 @@ var PoolClient = class extends SubgraphClient {
|
|
|
22641
22947
|
* ];
|
|
22642
22948
|
* const pools = await poolClient.fetchPoolsForTokensBatch(
|
|
22643
22949
|
* tokenAddresses,
|
|
22644
|
-
* Protocol.
|
|
22950
|
+
* Protocol.Uniswap,
|
|
22645
22951
|
* 1,
|
|
22646
22952
|
* 5
|
|
22647
22953
|
* );
|
|
@@ -22723,7 +23029,7 @@ var PoolClient = class extends SubgraphClient {
|
|
|
22723
23029
|
* // Get all USDC pools on Uniswap V3
|
|
22724
23030
|
* const usdcPools = await poolClient.fetchPoolsForToken(
|
|
22725
23031
|
* '0xa0b86a33e6f8b07b71c3a39ef77a6b6e8f1b7b7e',
|
|
22726
|
-
* Protocol.
|
|
23032
|
+
* Protocol.Uniswap,
|
|
22727
23033
|
* 1
|
|
22728
23034
|
* );
|
|
22729
23035
|
* if (usdcPools.success) {
|
|
@@ -23453,8 +23759,8 @@ var StakingClient = class extends SubgraphClient {
|
|
|
23453
23759
|
* const summary = await steerClient.rewards.getRewardSummary(userAddress, chainId);
|
|
23454
23760
|
*
|
|
23455
23761
|
* // Use pool data functionality
|
|
23456
|
-
* const topPools = await steerClient.pools.getTopPools(100, Protocol.
|
|
23457
|
-
* const poolDetails = await steerClient.pools.getPoolById(poolId, Protocol.
|
|
23762
|
+
* const topPools = await steerClient.pools.getTopPools(100, Protocol.Uniswap, 1);
|
|
23763
|
+
* const poolDetails = await steerClient.pools.getPoolById(poolId, Protocol.Uniswap, 1);
|
|
23458
23764
|
*
|
|
23459
23765
|
* // Use staking functionality
|
|
23460
23766
|
* const stakingPools = await steerClient.staking.getStakingPools(1);
|
|
@@ -23493,10 +23799,7 @@ var SteerClient = class extends SubgraphClient {
|
|
|
23493
23799
|
...publicClient,
|
|
23494
23800
|
...walletClient
|
|
23495
23801
|
} : publicClient);
|
|
23496
|
-
this.pools = new PoolClient(
|
|
23497
|
-
...publicClient,
|
|
23498
|
-
...walletClient
|
|
23499
|
-
} : publicClient, subgraphStudioKey);
|
|
23802
|
+
this.pools = new PoolClient(publicClient, subgraphStudioKey);
|
|
23500
23803
|
if (walletClient) this.rewards = new SmartRewardsClient(publicClient, walletClient, this.environment === "production" ? "production" : "development");
|
|
23501
23804
|
else this.rewards = new SmartRewardsClient(publicClient, publicClient, this.environment === "production" ? "production" : "development");
|
|
23502
23805
|
}
|
|
@@ -24048,6 +24351,3623 @@ var FeeManagerClient = class extends SubgraphClient {
|
|
|
24048
24351
|
}
|
|
24049
24352
|
};
|
|
24050
24353
|
//#endregion
|
|
24354
|
+
//#region src/pool-lifecycle/types.ts
|
|
24355
|
+
const PREPARED_POOL_ACTION_SERIALIZATION_VERSION = 1;
|
|
24356
|
+
const BIGINT_TAG = "__steer_pool_lifecycle_bigint__";
|
|
24357
|
+
function isRecord(value) {
|
|
24358
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24359
|
+
}
|
|
24360
|
+
/**
|
|
24361
|
+
* Serialize a prepared action in a versioned JSON envelope. Bigints use an
|
|
24362
|
+
* explicit tag so ordinary decimal strings remain distinguishable on decode.
|
|
24363
|
+
*/
|
|
24364
|
+
function serializePreparedPoolAction(action, space = 2) {
|
|
24365
|
+
if (!isRecord(action) || action.schemaVersion !== 1 || typeof action.kind !== "string") throw new TypeError("Prepared pool action must be a schema-version-1 object");
|
|
24366
|
+
return JSON.stringify({
|
|
24367
|
+
serializationVersion: 1,
|
|
24368
|
+
action
|
|
24369
|
+
}, (_key, value) => {
|
|
24370
|
+
if (typeof value === "bigint") return { [BIGINT_TAG]: value.toString() };
|
|
24371
|
+
if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") throw new TypeError("Prepared pool action contains a non-JSON value");
|
|
24372
|
+
if (typeof value === "number" && !Number.isFinite(value)) throw new TypeError("Prepared pool action contains a non-finite number");
|
|
24373
|
+
return value;
|
|
24374
|
+
}, space);
|
|
24375
|
+
}
|
|
24376
|
+
/** Parse a versioned serialized action; protocol adapters must validate its shape. */
|
|
24377
|
+
function deserializePreparedPoolAction(serialized) {
|
|
24378
|
+
if (typeof serialized !== "string") throw new TypeError("Serialized prepared pool action must be a string");
|
|
24379
|
+
const envelope = JSON.parse(serialized, (_key, value) => {
|
|
24380
|
+
if (isRecord(value) && Object.keys(value).length === 1 && BIGINT_TAG in value) {
|
|
24381
|
+
const encoded = value[BIGINT_TAG];
|
|
24382
|
+
if (typeof encoded !== "string" || !/^-?(0|[1-9][0-9]*)$/.test(encoded)) throw new TypeError("Serialized prepared pool action contains an invalid bigint");
|
|
24383
|
+
return BigInt(encoded);
|
|
24384
|
+
}
|
|
24385
|
+
return value;
|
|
24386
|
+
});
|
|
24387
|
+
if (!isRecord(envelope) || envelope.serializationVersion !== 1 || !isRecord(envelope.action)) throw new TypeError("Serialized prepared pool action envelope is invalid or unsupported");
|
|
24388
|
+
return envelope.action;
|
|
24389
|
+
}
|
|
24390
|
+
//#endregion
|
|
24391
|
+
//#region src/pool-lifecycle/capabilities/registry.ts
|
|
24392
|
+
/** Build a frozen string-keyed index and fail closed on every duplicate key. */
|
|
24393
|
+
function buildCheckedRegistry(values, keyOf, duplicateLabel) {
|
|
24394
|
+
const registry = Object.create(null);
|
|
24395
|
+
for (const value of values) {
|
|
24396
|
+
const key = keyOf(value);
|
|
24397
|
+
if (Object.prototype.hasOwnProperty.call(registry, key)) throw new Error(`Duplicate ${duplicateLabel}: ${key}`);
|
|
24398
|
+
registry[key] = value;
|
|
24399
|
+
}
|
|
24400
|
+
return Object.freeze(registry);
|
|
24401
|
+
}
|
|
24402
|
+
//#endregion
|
|
24403
|
+
//#region src/pool-lifecycle/capabilities/algebra.ts
|
|
24404
|
+
const SDK_CONFIG_URL = "https://github.com/SteerProtocol/sdk/tree/2dfaa0ee00bb80be684206f73e67b8d35f8ce9ff/src/const/amm/configs/protocols";
|
|
24405
|
+
function provenance$1(...urls) {
|
|
24406
|
+
return Object.freeze({
|
|
24407
|
+
source: "sdk-config",
|
|
24408
|
+
urls: Object.freeze(urls)
|
|
24409
|
+
});
|
|
24410
|
+
}
|
|
24411
|
+
const PROVENANCE_BY_VARIANT = Object.freeze({
|
|
24412
|
+
legacy: provenance$1(SDK_CONFIG_URL, "https://github.com/cryptoalgebra/Algebra/blob/11fff534a351d92b816f81953d0ad70de4ef35e9/src/core/contracts/interfaces/IAlgebraFactory.sol"),
|
|
24413
|
+
directional: provenance$1(SDK_CONFIG_URL, "https://github.com/cryptoalgebra/Algebra/blob/ab8ea842204839802524f762b751ef835eb79ec3/src/core/contracts/interfaces/IAlgebraFactory.sol", "https://github.com/cryptoalgebra/Algebra/blob/ab8ea842204839802524f762b751ef835eb79ec3/src/core/contracts/interfaces/pool/IAlgebraPoolState.sol"),
|
|
24414
|
+
"integral-v1": provenance$1(SDK_CONFIG_URL, "https://github.com/cryptoalgebra/Algebra/blob/3eae63f432a889fca5b000e9bd61078c6f923995/src/core/contracts/interfaces/IAlgebraFactory.sol"),
|
|
24415
|
+
"integral-v2": provenance$1(SDK_CONFIG_URL, "https://github.com/cryptoalgebra/Algebra/blob/62f01348af24b96d7d16f6b56fbaa61e512ba1c5/src/core/contracts/interfaces/IAlgebraFactory.sol", "https://github.com/cryptoalgebra/Algebra/blob/62f01348af24b96d7d16f6b56fbaa61e512ba1c5/src/periphery/contracts/interfaces/IAlgebraCustomPoolEntryPoint.sol")
|
|
24416
|
+
});
|
|
24417
|
+
function deployment$1(input) {
|
|
24418
|
+
const shape = input.variant === "directional" ? {
|
|
24419
|
+
adapter: "algebra-directional-pair-v1",
|
|
24420
|
+
version: 1,
|
|
24421
|
+
createPool: "pair",
|
|
24422
|
+
state: "directional-global-state"
|
|
24423
|
+
} : input.variant === "integral-v1" ? {
|
|
24424
|
+
adapter: "algebra-integral-pair-v1",
|
|
24425
|
+
version: 1,
|
|
24426
|
+
createPool: "pair",
|
|
24427
|
+
state: "integral-global-state"
|
|
24428
|
+
} : input.variant === "integral-v2" ? {
|
|
24429
|
+
adapter: "algebra-integral-plugin-data-v2",
|
|
24430
|
+
version: 2,
|
|
24431
|
+
createPool: "pair-with-plugin-data",
|
|
24432
|
+
state: "integral-global-state"
|
|
24433
|
+
} : {
|
|
24434
|
+
adapter: "algebra-legacy-pair-v1",
|
|
24435
|
+
version: 1,
|
|
24436
|
+
createPool: "pair",
|
|
24437
|
+
state: "legacy-global-state"
|
|
24438
|
+
};
|
|
24439
|
+
return Object.freeze({
|
|
24440
|
+
supported: true,
|
|
24441
|
+
schemaVersion: 1,
|
|
24442
|
+
family: "algebra",
|
|
24443
|
+
chainId: input.chainId,
|
|
24444
|
+
protocol: input.protocol,
|
|
24445
|
+
variant: input.variant,
|
|
24446
|
+
...shape,
|
|
24447
|
+
factory: getAddress(input.factory),
|
|
24448
|
+
...input.customPoolEntryPoint ? { customPoolEntryPoint: getAddress(input.customPoolEntryPoint) } : {},
|
|
24449
|
+
customPoolCreation: input.customPoolEntryPoint ? "adapter-specific-deployer-required" : "not-configured",
|
|
24450
|
+
provenance: PROVENANCE_BY_VARIANT[input.variant]
|
|
24451
|
+
});
|
|
24452
|
+
}
|
|
24453
|
+
/**
|
|
24454
|
+
* Explicit lifecycle capabilities for every Algebra-family protocol/chain pair
|
|
24455
|
+
* currently present in the SDK AMM registry. Subgraph presence is never used as
|
|
24456
|
+
* a runtime fallback.
|
|
24457
|
+
*/
|
|
24458
|
+
const ALGEBRA_LIFECYCLE_DEPLOYMENTS = Object.freeze([
|
|
24459
|
+
deployment$1({
|
|
24460
|
+
chainId: ChainId.Polygon,
|
|
24461
|
+
protocol: Protocol.QuickSwap,
|
|
24462
|
+
variant: "legacy",
|
|
24463
|
+
factory: "0x411b0fAcC3489691f28ad58c47006AF5E3Ab3A28"
|
|
24464
|
+
}),
|
|
24465
|
+
deployment$1({
|
|
24466
|
+
chainId: ChainId.PolygonzkEVM,
|
|
24467
|
+
protocol: Protocol.QuickSwap,
|
|
24468
|
+
variant: "legacy",
|
|
24469
|
+
factory: "0x4B9f4d2435Ef65559567e5DbFC1BbB37abC43B57"
|
|
24470
|
+
}),
|
|
24471
|
+
deployment$1({
|
|
24472
|
+
chainId: ChainId.Zircuit,
|
|
24473
|
+
protocol: Protocol.Ocelex,
|
|
24474
|
+
variant: "legacy",
|
|
24475
|
+
factory: "0x03057ae6294292b299a1863420edD65e0197AFEf"
|
|
24476
|
+
}),
|
|
24477
|
+
deployment$1({
|
|
24478
|
+
chainId: ChainId.Arbitrum,
|
|
24479
|
+
protocol: Protocol.Camelot,
|
|
24480
|
+
variant: "directional",
|
|
24481
|
+
factory: "0x1a3c9B1d2F0529D97f2afC5136Cc23e58f1FD35B"
|
|
24482
|
+
}),
|
|
24483
|
+
deployment$1({
|
|
24484
|
+
chainId: ChainId.Apechain,
|
|
24485
|
+
protocol: Protocol.Camelot,
|
|
24486
|
+
variant: "directional",
|
|
24487
|
+
factory: "0x1a3c9B1d2F0529D97f2afC5136Cc23e58f1FD35B"
|
|
24488
|
+
}),
|
|
24489
|
+
deployment$1({
|
|
24490
|
+
chainId: ChainId.Linea,
|
|
24491
|
+
protocol: Protocol.Lynex,
|
|
24492
|
+
variant: "legacy",
|
|
24493
|
+
factory: "0x622b2c98123D303ae067DB4925CD6282B3A08D0F"
|
|
24494
|
+
}),
|
|
24495
|
+
deployment$1({
|
|
24496
|
+
chainId: ChainId.BSC,
|
|
24497
|
+
protocol: Protocol.Thena,
|
|
24498
|
+
variant: "legacy",
|
|
24499
|
+
factory: "0x306F06C147f064A010530292A1EB6737c3e378e4"
|
|
24500
|
+
}),
|
|
24501
|
+
deployment$1({
|
|
24502
|
+
chainId: ChainId.Metis,
|
|
24503
|
+
protocol: Protocol.Hercules,
|
|
24504
|
+
variant: "directional",
|
|
24505
|
+
factory: "0xC5BfA92f27dF36d268422EE314a1387bB5ffB06A"
|
|
24506
|
+
}),
|
|
24507
|
+
deployment$1({
|
|
24508
|
+
chainId: ChainId.XLayer,
|
|
24509
|
+
protocol: Protocol.QuickSwapAlgebra,
|
|
24510
|
+
variant: "legacy",
|
|
24511
|
+
factory: "0xd2480162Aa7F02Ead7BF4C127465446150D58452"
|
|
24512
|
+
}),
|
|
24513
|
+
deployment$1({
|
|
24514
|
+
chainId: ChainId.Moonbeam,
|
|
24515
|
+
protocol: Protocol.StellaSwap,
|
|
24516
|
+
variant: "legacy",
|
|
24517
|
+
factory: "0xabE1655110112D0E45EF91e94f8d757e4ddBA59C"
|
|
24518
|
+
}),
|
|
24519
|
+
deployment$1({
|
|
24520
|
+
chainId: ChainId.Mode,
|
|
24521
|
+
protocol: Protocol.Kim,
|
|
24522
|
+
variant: "integral-v1",
|
|
24523
|
+
factory: "0xB5F00c2C5f8821155D8ed27E31932CFD9DB3C5D5"
|
|
24524
|
+
}),
|
|
24525
|
+
deployment$1({
|
|
24526
|
+
chainId: ChainId.Base,
|
|
24527
|
+
protocol: Protocol.Kim,
|
|
24528
|
+
variant: "integral-v1",
|
|
24529
|
+
factory: "0x2F0d41f94d5D1550b79A83D2fe85C82d68c5a3ca"
|
|
24530
|
+
}),
|
|
24531
|
+
deployment$1({
|
|
24532
|
+
chainId: ChainId.Telos,
|
|
24533
|
+
protocol: Protocol.Swapsicle,
|
|
24534
|
+
variant: "integral-v1",
|
|
24535
|
+
factory: "0xA09BAbf9A48003ae9b9333966a8Bda94d820D0d9"
|
|
24536
|
+
}),
|
|
24537
|
+
deployment$1({
|
|
24538
|
+
chainId: ChainId.Blast,
|
|
24539
|
+
protocol: Protocol.Fenix,
|
|
24540
|
+
variant: "integral-v1",
|
|
24541
|
+
factory: "0x7a44CD060afC1B6F4c80A2B9b37f4473E74E25Df"
|
|
24542
|
+
}),
|
|
24543
|
+
deployment$1({
|
|
24544
|
+
chainId: ChainId.Taiko,
|
|
24545
|
+
protocol: Protocol.Henjin,
|
|
24546
|
+
variant: "integral-v1",
|
|
24547
|
+
factory: "0x42B08e7a9211482d3643a126a7dF1895448d3509",
|
|
24548
|
+
customPoolEntryPoint: "0x441013A52DDedc8D02eB9B90F7A555F6848188b5"
|
|
24549
|
+
}),
|
|
24550
|
+
deployment$1({
|
|
24551
|
+
chainId: ChainId.Sonic,
|
|
24552
|
+
protocol: Protocol.SilverSwap,
|
|
24553
|
+
variant: "integral-v1",
|
|
24554
|
+
factory: "0xb860200BD68dc39cEAfd6ebb82883f189f4CdA76"
|
|
24555
|
+
}),
|
|
24556
|
+
deployment$1({
|
|
24557
|
+
chainId: ChainId.Nibiru,
|
|
24558
|
+
protocol: Protocol.SilverSwap,
|
|
24559
|
+
variant: "integral-v1",
|
|
24560
|
+
factory: "0xb860200BD68dc39cEAfd6ebb82883f189f4CdA76"
|
|
24561
|
+
}),
|
|
24562
|
+
deployment$1({
|
|
24563
|
+
chainId: ChainId.Zeta,
|
|
24564
|
+
protocol: Protocol.Beam,
|
|
24565
|
+
variant: "integral-v1",
|
|
24566
|
+
factory: "0x28b5244B6CA7Cb07f2f7F40edE944c07C2395603"
|
|
24567
|
+
}),
|
|
24568
|
+
deployment$1({
|
|
24569
|
+
chainId: ChainId.Core,
|
|
24570
|
+
protocol: Protocol.Glyph,
|
|
24571
|
+
variant: "integral-v1",
|
|
24572
|
+
factory: "0x74EfE55beA4988e7D92D03EFd8ddB8BF8b7bD597"
|
|
24573
|
+
}),
|
|
24574
|
+
deployment$1({
|
|
24575
|
+
chainId: ChainId.Hyperevm,
|
|
24576
|
+
protocol: Protocol.Nest,
|
|
24577
|
+
variant: "integral-v1",
|
|
24578
|
+
factory: "0xF77Bd082c627aA54591cF2f2EaA811fd1AB3b1F3"
|
|
24579
|
+
}),
|
|
24580
|
+
deployment$1({
|
|
24581
|
+
chainId: ChainId.Soneium,
|
|
24582
|
+
protocol: Protocol.QuickSwapIntegral,
|
|
24583
|
+
variant: "integral-v2",
|
|
24584
|
+
factory: "0x8Ff309F68F6Caf77a78E9C20d2Af7Ed4bE2D7093"
|
|
24585
|
+
}),
|
|
24586
|
+
deployment$1({
|
|
24587
|
+
chainId: ChainId.Base,
|
|
24588
|
+
protocol: Protocol.QuickSwapIntegral,
|
|
24589
|
+
variant: "integral-v2",
|
|
24590
|
+
factory: "0xC5396866754799B9720125B104AE01d935Ab9C7b",
|
|
24591
|
+
customPoolEntryPoint: "0xb9ce7698cE3dCf21cc88bf7dCc1fE20C85E4226E"
|
|
24592
|
+
}),
|
|
24593
|
+
deployment$1({
|
|
24594
|
+
chainId: ChainId.Polygon,
|
|
24595
|
+
protocol: Protocol.QuickSwapIntegral,
|
|
24596
|
+
variant: "integral-v2",
|
|
24597
|
+
factory: "0x134c1dBE4860A9cAaf89002574fFe814772D9904",
|
|
24598
|
+
customPoolEntryPoint: "0xfcfE065bc131Fa8Bb31A227b2fF4F0EC47D3F1a2"
|
|
24599
|
+
}),
|
|
24600
|
+
deployment$1({
|
|
24601
|
+
chainId: ChainId.Bera,
|
|
24602
|
+
protocol: Protocol.Wasabee,
|
|
24603
|
+
variant: "integral-v2",
|
|
24604
|
+
factory: "0x7d53327D78EFD0b463bd8d7dc938C52402323b95"
|
|
24605
|
+
}),
|
|
24606
|
+
deployment$1({
|
|
24607
|
+
chainId: ChainId.Ronin,
|
|
24608
|
+
protocol: Protocol.KatanaIntegral,
|
|
24609
|
+
variant: "integral-v2",
|
|
24610
|
+
factory: "0x7ecaf729C6FFb04448aA89A722cA370724BF70De"
|
|
24611
|
+
}),
|
|
24612
|
+
deployment$1({
|
|
24613
|
+
chainId: ChainId.Avalanche,
|
|
24614
|
+
protocol: Protocol.Blackhole,
|
|
24615
|
+
variant: "integral-v2",
|
|
24616
|
+
factory: "0x512eb749541B7cf294be882D636218c84a5e9E5F"
|
|
24617
|
+
}),
|
|
24618
|
+
deployment$1({
|
|
24619
|
+
chainId: ChainId.Mainnet,
|
|
24620
|
+
protocol: Protocol.Cypher,
|
|
24621
|
+
variant: "integral-v2",
|
|
24622
|
+
factory: "0xfb8Ed3485EfA29a0e4bed93351dD51B59fC4b0f0",
|
|
24623
|
+
customPoolEntryPoint: "0x79616564DB0294ecBa5912f1cE985FD1c11eeF51"
|
|
24624
|
+
}),
|
|
24625
|
+
deployment$1({
|
|
24626
|
+
chainId: ChainId.Flare,
|
|
24627
|
+
protocol: Protocol.SparkIntegral,
|
|
24628
|
+
variant: "integral-v2",
|
|
24629
|
+
factory: "0x805488DaA81c1b9e7C5cE3f1DCeA28F21448EC6A"
|
|
24630
|
+
}),
|
|
24631
|
+
deployment$1({
|
|
24632
|
+
chainId: ChainId.Base,
|
|
24633
|
+
protocol: Protocol.Hydrex,
|
|
24634
|
+
variant: "integral-v2",
|
|
24635
|
+
factory: "0x36077D39cdC65E1e3FB65810430E5b2c4D5fA29E"
|
|
24636
|
+
})
|
|
24637
|
+
]);
|
|
24638
|
+
function key$1(chainId, protocol) {
|
|
24639
|
+
return `${chainId}:${protocol}`;
|
|
24640
|
+
}
|
|
24641
|
+
const BY_KEY = buildCheckedRegistry(ALGEBRA_LIFECYCLE_DEPLOYMENTS, (item) => key$1(item.chainId, item.protocol), "Algebra lifecycle deployment");
|
|
24642
|
+
function resolveAlgebraLifecycleDeployment(params) {
|
|
24643
|
+
return BY_KEY[key$1(params.chainId, params.protocol)];
|
|
24644
|
+
}
|
|
24645
|
+
/** Validate external capability metadata and return its canonical frozen entry. */
|
|
24646
|
+
function validateAlgebraLifecycleDeployment(value) {
|
|
24647
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", "Algebra lifecycle deployment must be an object.");
|
|
24648
|
+
const candidate = value;
|
|
24649
|
+
if (!Number.isSafeInteger(candidate.chainId) || typeof candidate.protocol !== "string") throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", "Algebra lifecycle deployment chainId and protocol are invalid.");
|
|
24650
|
+
const configured = resolveAlgebraLifecycleDeployment({
|
|
24651
|
+
chainId: Number(candidate.chainId),
|
|
24652
|
+
protocol: candidate.protocol
|
|
24653
|
+
});
|
|
24654
|
+
let matches = false;
|
|
24655
|
+
try {
|
|
24656
|
+
const candidateEntryPoint = candidate.customPoolEntryPoint ? getAddress(candidate.customPoolEntryPoint) : void 0;
|
|
24657
|
+
const configuredEntryPoint = configured?.customPoolEntryPoint;
|
|
24658
|
+
matches = configured !== void 0 && candidate.supported === true && candidate.schemaVersion === configured.schemaVersion && candidate.family === configured.family && candidate.variant === configured.variant && candidate.adapter === configured.adapter && candidate.version === configured.version && getAddress(candidate.factory) === configured.factory && candidate.createPool === configured.createPool && candidate.state === configured.state && candidateEntryPoint === configuredEntryPoint && candidate.customPoolCreation === configured.customPoolCreation;
|
|
24659
|
+
} catch {}
|
|
24660
|
+
if (!matches || !configured) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", `Algebra lifecycle deployment is not configured for chain ${String(candidate.chainId)} and protocol ${String(candidate.protocol)}.`);
|
|
24661
|
+
return configured;
|
|
24662
|
+
}
|
|
24663
|
+
//#endregion
|
|
24664
|
+
//#region src/pool-lifecycle/capabilities/v3.ts
|
|
24665
|
+
const STANDARD_V3_POOL_INIT_CODE_HASH = "0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54";
|
|
24666
|
+
const SDK_CONFIG_ROOT = "https://github.com/SteerProtocol/sdk/blob/2dfaa0ee00bb80be684206f73e67b8d35f8ce9ff/src/const/amm/configs/protocols";
|
|
24667
|
+
const UNISWAP_DEPLOYMENTS = "https://developers.uniswap.org/docs/protocols/v3/deployments";
|
|
24668
|
+
const UNISWAP_GOVERNANCE_DEPLOYMENTS = "https://gov.uniswap.org/t/official-uniswap-v3-deployments-list/24323";
|
|
24669
|
+
const SUSHI_DEPLOYMENTS = "https://unpkg.com/sushi@6.5.1/_esm/evm/config/features/sushiswap-v3.js";
|
|
24670
|
+
const PANCAKE_DEPLOYMENTS = "https://developer.pancakeswap.finance/contracts/v3/addresses";
|
|
24671
|
+
function deploymentKey$2(chainId, protocol) {
|
|
24672
|
+
return `${chainId}:${protocol}`;
|
|
24673
|
+
}
|
|
24674
|
+
function provenance(source, ...urls) {
|
|
24675
|
+
return Object.freeze({
|
|
24676
|
+
source,
|
|
24677
|
+
urls: Object.freeze(urls)
|
|
24678
|
+
});
|
|
24679
|
+
}
|
|
24680
|
+
function sdkConfigUrl(file) {
|
|
24681
|
+
return `${SDK_CONFIG_ROOT}/${file}.ts`;
|
|
24682
|
+
}
|
|
24683
|
+
function atomic(params) {
|
|
24684
|
+
return Object.freeze({
|
|
24685
|
+
supported: true,
|
|
24686
|
+
schemaVersion: 1,
|
|
24687
|
+
family: "uniswap-v3-compatible",
|
|
24688
|
+
adapter: "pool-initializer-v1",
|
|
24689
|
+
version: 1,
|
|
24690
|
+
atomicCreateAndInitialize: true,
|
|
24691
|
+
...params,
|
|
24692
|
+
factory: getAddress(params.factory.toLowerCase()),
|
|
24693
|
+
initializer: getAddress(params.initializer.toLowerCase())
|
|
24694
|
+
});
|
|
24695
|
+
}
|
|
24696
|
+
function factoryOnly(params) {
|
|
24697
|
+
return Object.freeze({
|
|
24698
|
+
supported: true,
|
|
24699
|
+
schemaVersion: 1,
|
|
24700
|
+
family: "uniswap-v3-compatible",
|
|
24701
|
+
adapter: "v3-factory-v1",
|
|
24702
|
+
version: 1,
|
|
24703
|
+
atomicCreateAndInitialize: false,
|
|
24704
|
+
initializer: null,
|
|
24705
|
+
...params,
|
|
24706
|
+
factory: getAddress(params.factory.toLowerCase())
|
|
24707
|
+
});
|
|
24708
|
+
}
|
|
24709
|
+
const uniswapProvenance = provenance("official-deployment", UNISWAP_DEPLOYMENTS, UNISWAP_GOVERNANCE_DEPLOYMENTS);
|
|
24710
|
+
const sushiProvenance = provenance("official-deployment", SUSHI_DEPLOYMENTS);
|
|
24711
|
+
const pancakeProvenance = provenance("official-deployment", PANCAKE_DEPLOYMENTS);
|
|
24712
|
+
/** Explicit, fail-closed V3 create/initialize deployment allowlist. */
|
|
24713
|
+
const V3_LIFECYCLE_DEPLOYMENTS = buildCheckedRegistry([
|
|
24714
|
+
atomic({
|
|
24715
|
+
chainId: ChainId.Mainnet,
|
|
24716
|
+
protocol: Protocol.Uniswap,
|
|
24717
|
+
factory: "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
|
24718
|
+
initializer: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
|
24719
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24720
|
+
provenance: uniswapProvenance
|
|
24721
|
+
}),
|
|
24722
|
+
atomic({
|
|
24723
|
+
chainId: ChainId.Polygon,
|
|
24724
|
+
protocol: Protocol.Uniswap,
|
|
24725
|
+
factory: "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
|
24726
|
+
initializer: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
|
24727
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24728
|
+
provenance: uniswapProvenance
|
|
24729
|
+
}),
|
|
24730
|
+
atomic({
|
|
24731
|
+
chainId: ChainId.Optimism,
|
|
24732
|
+
protocol: Protocol.Uniswap,
|
|
24733
|
+
factory: "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
|
24734
|
+
initializer: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
|
24735
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24736
|
+
provenance: uniswapProvenance
|
|
24737
|
+
}),
|
|
24738
|
+
atomic({
|
|
24739
|
+
chainId: ChainId.Arbitrum,
|
|
24740
|
+
protocol: Protocol.Uniswap,
|
|
24741
|
+
factory: "0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
|
24742
|
+
initializer: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88",
|
|
24743
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24744
|
+
provenance: uniswapProvenance
|
|
24745
|
+
}),
|
|
24746
|
+
atomic({
|
|
24747
|
+
chainId: ChainId.BSC,
|
|
24748
|
+
protocol: Protocol.Uniswap,
|
|
24749
|
+
factory: "0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7",
|
|
24750
|
+
initializer: "0x7b8A01B39D58278b5DE7e48c8449c9f4F5170613",
|
|
24751
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24752
|
+
provenance: uniswapProvenance
|
|
24753
|
+
}),
|
|
24754
|
+
atomic({
|
|
24755
|
+
chainId: ChainId.Celo,
|
|
24756
|
+
protocol: Protocol.Uniswap,
|
|
24757
|
+
factory: "0xAfE208a311B21f13EF87E33A90049fC17A7acDEc",
|
|
24758
|
+
initializer: "0x3d79EdAaBC0EaB6F08ED885C05Fc0B014290D95A",
|
|
24759
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24760
|
+
provenance: uniswapProvenance
|
|
24761
|
+
}),
|
|
24762
|
+
atomic({
|
|
24763
|
+
chainId: ChainId.Rootstock,
|
|
24764
|
+
protocol: Protocol.Uniswap,
|
|
24765
|
+
factory: "0xaF37EC98A00FD63689CF3060BF3B6784E00caD82",
|
|
24766
|
+
initializer: "0x9d9386c042F194B460Ec424a1e57ACDE25f5C4b1",
|
|
24767
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24768
|
+
provenance: uniswapProvenance
|
|
24769
|
+
}),
|
|
24770
|
+
atomic({
|
|
24771
|
+
chainId: ChainId.Base,
|
|
24772
|
+
protocol: Protocol.Uniswap,
|
|
24773
|
+
factory: "0x33128a8fC17869897dcE68Ed026d694621f6FDfD",
|
|
24774
|
+
initializer: "0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1",
|
|
24775
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24776
|
+
provenance: uniswapProvenance
|
|
24777
|
+
}),
|
|
24778
|
+
atomic({
|
|
24779
|
+
chainId: ChainId.Filecoin,
|
|
24780
|
+
protocol: Protocol.Uniswap,
|
|
24781
|
+
factory: "0xB4C47eD546Fc31E26470a186eC2C5F19eF09BA41",
|
|
24782
|
+
initializer: "0x4cd986dD509fbB6A695aE971d5C56c8795f640ee",
|
|
24783
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24784
|
+
provenance: uniswapProvenance
|
|
24785
|
+
}),
|
|
24786
|
+
atomic({
|
|
24787
|
+
chainId: ChainId.Sonic,
|
|
24788
|
+
protocol: Protocol.Uniswap,
|
|
24789
|
+
factory: "0xcb2436774C3e191c85056d248EF4260ce5f27A9D",
|
|
24790
|
+
initializer: "0x743E03cceB4af2efA3CC76838f6E8B50B63F184c",
|
|
24791
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24792
|
+
provenance: uniswapProvenance
|
|
24793
|
+
}),
|
|
24794
|
+
atomic({
|
|
24795
|
+
chainId: ChainId.Unichain,
|
|
24796
|
+
protocol: Protocol.Uniswap,
|
|
24797
|
+
factory: "0x1f98400000000000000000000000000000000003",
|
|
24798
|
+
initializer: "0x943e6e07a7e8e791dafc44083e54041d743c46e9",
|
|
24799
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24800
|
+
provenance: uniswapProvenance
|
|
24801
|
+
}),
|
|
24802
|
+
atomic({
|
|
24803
|
+
chainId: ChainId.Telos,
|
|
24804
|
+
protocol: Protocol.Uniswap,
|
|
24805
|
+
factory: "0xcb2436774C3e191c85056d248EF4260ce5f27A9D",
|
|
24806
|
+
initializer: "0x743E03cceB4af2efA3CC76838f6E8B50B63F184c",
|
|
24807
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24808
|
+
provenance: uniswapProvenance
|
|
24809
|
+
}),
|
|
24810
|
+
atomic({
|
|
24811
|
+
chainId: ChainId.Saga,
|
|
24812
|
+
protocol: Protocol.Uniswap,
|
|
24813
|
+
factory: "0x454050C4c9190390981Ac4b8d5AFcd7aC65eEffa",
|
|
24814
|
+
initializer: "0xdD489C75be1039ec7d843A6aC2Fd658350B067Cf",
|
|
24815
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24816
|
+
provenance: uniswapProvenance
|
|
24817
|
+
}),
|
|
24818
|
+
atomic({
|
|
24819
|
+
chainId: ChainId.Nibiru,
|
|
24820
|
+
protocol: Protocol.Uniswap,
|
|
24821
|
+
factory: "0x346239972d1fa486FC4a521031BC81bFB7D6e8a4",
|
|
24822
|
+
initializer: "0xEFdE184f4b5d79f7c3b7Efc0388d829ff9af0050",
|
|
24823
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24824
|
+
provenance: uniswapProvenance
|
|
24825
|
+
}),
|
|
24826
|
+
atomic({
|
|
24827
|
+
chainId: ChainId.Robinhood,
|
|
24828
|
+
protocol: Protocol.Uniswap,
|
|
24829
|
+
factory: "0x1f7d7550b1b028f7571e69a784071f0205fd2efa",
|
|
24830
|
+
initializer: "0x73991a25c818bf1f1128deaab1492d45638de0d3",
|
|
24831
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24832
|
+
provenance: uniswapProvenance
|
|
24833
|
+
}),
|
|
24834
|
+
atomic({
|
|
24835
|
+
chainId: ChainId.Polygon,
|
|
24836
|
+
protocol: Protocol.Sushi,
|
|
24837
|
+
factory: "0x917933899c6a5F8E37F31E19f92CdBFF7e8FF0e2",
|
|
24838
|
+
initializer: "0xb7402ee99f0a008e461098ac3a27f4957df89a40",
|
|
24839
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24840
|
+
provenance: sushiProvenance
|
|
24841
|
+
}),
|
|
24842
|
+
atomic({
|
|
24843
|
+
chainId: ChainId.Arbitrum,
|
|
24844
|
+
protocol: Protocol.Sushi,
|
|
24845
|
+
factory: "0x1af415a1EbA07a4986a52B6f2e7dE7003D82231e",
|
|
24846
|
+
initializer: "0xf0cbce1942a68beb3d1b73f0dd86c8dcc363ef49",
|
|
24847
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24848
|
+
provenance: sushiProvenance
|
|
24849
|
+
}),
|
|
24850
|
+
atomic({
|
|
24851
|
+
chainId: ChainId.Optimism,
|
|
24852
|
+
protocol: Protocol.Sushi,
|
|
24853
|
+
factory: "0x9c6522117e2ed1fE5bdb72bb0eD5E3f2bdE7DBe0",
|
|
24854
|
+
initializer: "0x1af415a1eba07a4986a52b6f2e7de7003d82231e",
|
|
24855
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24856
|
+
provenance: sushiProvenance
|
|
24857
|
+
}),
|
|
24858
|
+
atomic({
|
|
24859
|
+
chainId: ChainId.BSC,
|
|
24860
|
+
protocol: Protocol.Sushi,
|
|
24861
|
+
factory: "0x126555dd55a39328F69400d6aE4F782Bd4C34ABb",
|
|
24862
|
+
initializer: "0xf70c086618dcf2b1a461311275e00d6b722ef914",
|
|
24863
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24864
|
+
provenance: sushiProvenance
|
|
24865
|
+
}),
|
|
24866
|
+
atomic({
|
|
24867
|
+
chainId: ChainId.Avalanche,
|
|
24868
|
+
protocol: Protocol.Sushi,
|
|
24869
|
+
factory: "0x3e603C14aF37EBdaD31709C4f848Fc6aD5BEc715",
|
|
24870
|
+
initializer: "0x18350b048ab366ed601ffdbc669110ecb36016f3",
|
|
24871
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24872
|
+
provenance: sushiProvenance
|
|
24873
|
+
}),
|
|
24874
|
+
atomic({
|
|
24875
|
+
chainId: ChainId.Thundercore,
|
|
24876
|
+
protocol: Protocol.Sushi,
|
|
24877
|
+
factory: "0xc35DADB65012eC5796536bD9864eD8773aBc74C4",
|
|
24878
|
+
initializer: "0xf4d73326c13a4fc5fd7a064217e12780e9bd62c3",
|
|
24879
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24880
|
+
provenance: sushiProvenance
|
|
24881
|
+
}),
|
|
24882
|
+
atomic({
|
|
24883
|
+
chainId: ChainId.PolygonzkEVM,
|
|
24884
|
+
protocol: Protocol.Sushi,
|
|
24885
|
+
factory: "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506",
|
|
24886
|
+
initializer: "0xf4d73326c13a4fc5fd7a064217e12780e9bd62c3",
|
|
24887
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24888
|
+
provenance: sushiProvenance
|
|
24889
|
+
}),
|
|
24890
|
+
atomic({
|
|
24891
|
+
chainId: ChainId.Base,
|
|
24892
|
+
protocol: Protocol.Sushi,
|
|
24893
|
+
factory: "0xc35DADB65012eC5796536bD9864eD8773aBc74C4",
|
|
24894
|
+
initializer: "0x80c7dd17b01855a6d2347444a0fcc36136a314de",
|
|
24895
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24896
|
+
provenance: sushiProvenance
|
|
24897
|
+
}),
|
|
24898
|
+
atomic({
|
|
24899
|
+
chainId: ChainId.Linea,
|
|
24900
|
+
protocol: Protocol.Sushi,
|
|
24901
|
+
factory: "0xc35DADB65012eC5796536bD9864eD8773aBc74C4",
|
|
24902
|
+
initializer: "0x80c7dd17b01855a6d2347444a0fcc36136a314de",
|
|
24903
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24904
|
+
provenance: sushiProvenance
|
|
24905
|
+
}),
|
|
24906
|
+
atomic({
|
|
24907
|
+
chainId: ChainId.Blast,
|
|
24908
|
+
protocol: Protocol.Sushi,
|
|
24909
|
+
factory: "0x7680D4B43f3d1d54d6cfEeB2169463bFa7a6cf0d",
|
|
24910
|
+
initializer: "0x51edb3e5bce8618b77b60215f84ad3db14709051",
|
|
24911
|
+
poolInitCodeHash: "0x8e13daee7f5a62e37e71bf852bcd44e7d16b90617ed2b17c24c2ee62411c5bae",
|
|
24912
|
+
provenance: sushiProvenance
|
|
24913
|
+
}),
|
|
24914
|
+
atomic({
|
|
24915
|
+
chainId: ChainId.Rootstock,
|
|
24916
|
+
protocol: Protocol.Sushi,
|
|
24917
|
+
factory: "0x46B3fDF7b5CDe91Ac049936bF0bDb12c5d22202e",
|
|
24918
|
+
initializer: "0x0389879e0156033202c44bf784ac18fc02edee4f",
|
|
24919
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24920
|
+
provenance: sushiProvenance
|
|
24921
|
+
}),
|
|
24922
|
+
atomic({
|
|
24923
|
+
chainId: ChainId.Filecoin,
|
|
24924
|
+
protocol: Protocol.Sushi,
|
|
24925
|
+
factory: "0xc35DADB65012eC5796536bD9864eD8773aBc74C4",
|
|
24926
|
+
initializer: "0xf4d73326c13a4fc5fd7a064217e12780e9bd62c3",
|
|
24927
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24928
|
+
provenance: sushiProvenance
|
|
24929
|
+
}),
|
|
24930
|
+
atomic({
|
|
24931
|
+
chainId: ChainId.Hemi,
|
|
24932
|
+
protocol: Protocol.Sushi,
|
|
24933
|
+
factory: "0xCdBCd51a5E8728E0AF4895ce5771b7d17fF71959",
|
|
24934
|
+
initializer: "0xe43ca1dee3f0fc1e2df73a0745674545f11a59f5",
|
|
24935
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24936
|
+
provenance: sushiProvenance
|
|
24937
|
+
}),
|
|
24938
|
+
atomic({
|
|
24939
|
+
chainId: ChainId.Katana,
|
|
24940
|
+
protocol: Protocol.Sushi,
|
|
24941
|
+
factory: "0x203e8740894c8955cB8950759876d7E7E45E04c1",
|
|
24942
|
+
initializer: "0x2659c6085d26144117d904c46b48b6d180393d27",
|
|
24943
|
+
poolInitCodeHash: "0xe040f12c7cee3904b78f24f8fc395629c2e69525c2815da7a659f7483e378ecb",
|
|
24944
|
+
provenance: sushiProvenance
|
|
24945
|
+
}),
|
|
24946
|
+
atomic({
|
|
24947
|
+
chainId: ChainId.Robinhood,
|
|
24948
|
+
protocol: Protocol.Sushi,
|
|
24949
|
+
factory: "0xe51960f1b45f1c9fb6d166e6a884f866fc70433b",
|
|
24950
|
+
initializer: "0x51d0e5188afe12d502e29d982d20c190e7816107",
|
|
24951
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24952
|
+
provenance: provenance("verified-explorer", "https://robinhoodchain.blockscout.com/address/0xe51960f1b45f1c9fb6d166e6a884f866fc70433b", "https://robinhoodchain.blockscout.com/address/0x51d0e5188afe12d502e29d982d20c190e7816107"),
|
|
24953
|
+
startBlock: 6292626n
|
|
24954
|
+
}),
|
|
24955
|
+
atomic({
|
|
24956
|
+
chainId: ChainId.Mainnet,
|
|
24957
|
+
protocol: Protocol.Sushi,
|
|
24958
|
+
factory: "0xbaceb8ec6b9355dfc0269c18bac9d6e2bdc29c4f",
|
|
24959
|
+
initializer: "0x2214a42d8e2a1d20635c2cb0664422c528b6a432",
|
|
24960
|
+
poolInitCodeHash: STANDARD_V3_POOL_INIT_CODE_HASH,
|
|
24961
|
+
provenance: sushiProvenance
|
|
24962
|
+
}),
|
|
24963
|
+
atomic({
|
|
24964
|
+
chainId: ChainId.BSC,
|
|
24965
|
+
protocol: Protocol.PancakeSwap,
|
|
24966
|
+
factory: "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865",
|
|
24967
|
+
initializer: "0x46A15B0b27311cedF172AB29E4f4766fbE7F4364",
|
|
24968
|
+
provenance: pancakeProvenance
|
|
24969
|
+
}),
|
|
24970
|
+
atomic({
|
|
24971
|
+
chainId: ChainId.Arbitrum,
|
|
24972
|
+
protocol: Protocol.PancakeSwap,
|
|
24973
|
+
factory: "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865",
|
|
24974
|
+
initializer: "0x46A15B0b27311cedF172AB29E4f4766fbE7F4364",
|
|
24975
|
+
provenance: pancakeProvenance
|
|
24976
|
+
}),
|
|
24977
|
+
atomic({
|
|
24978
|
+
chainId: ChainId.Evmos,
|
|
24979
|
+
protocol: Protocol.Forge,
|
|
24980
|
+
factory: "0xf544365e7065966f190155F629cE0182fC68Eaa2",
|
|
24981
|
+
initializer: "0x5fE5dAAa011673289847dA4f76d63246DDB2965d",
|
|
24982
|
+
provenance: provenance("sdk-config", sdkConfigUrl("forge"))
|
|
24983
|
+
}),
|
|
24984
|
+
atomic({
|
|
24985
|
+
chainId: ChainId.Arbitrum,
|
|
24986
|
+
protocol: Protocol.Horiza,
|
|
24987
|
+
factory: "0x5b1C257B88537d1Ce2AF55a1760336288CcD28B6",
|
|
24988
|
+
initializer: "0x39f16045432dc7cb6160269724821459b35938f9",
|
|
24989
|
+
provenance: provenance("sdk-config", sdkConfigUrl("horiza"))
|
|
24990
|
+
}),
|
|
24991
|
+
atomic({
|
|
24992
|
+
chainId: ChainId.Metis,
|
|
24993
|
+
protocol: Protocol.Maia,
|
|
24994
|
+
factory: "0xf5fd18Cd5325904cC7141cB9Daca1F2F964B9927",
|
|
24995
|
+
initializer: "0x1fc37a909cB3997f96cE395B3Ee9ac268C9bCcdb",
|
|
24996
|
+
provenance: provenance("sdk-config", sdkConfigUrl("maia"))
|
|
24997
|
+
}),
|
|
24998
|
+
atomic({
|
|
24999
|
+
chainId: ChainId.Linea,
|
|
25000
|
+
protocol: Protocol.MetaVault,
|
|
25001
|
+
factory: "0x9367c561915f9D062aFE3b57B18e30dEC62b8488",
|
|
25002
|
+
initializer: "0x5979C5315625276ff99a56f95eE5cC44293e7b36",
|
|
25003
|
+
provenance: provenance("sdk-config", sdkConfigUrl("metavault"))
|
|
25004
|
+
}),
|
|
25005
|
+
atomic({
|
|
25006
|
+
chainId: ChainId.Scroll,
|
|
25007
|
+
protocol: Protocol.MetaVault,
|
|
25008
|
+
factory: "0x9367c561915f9D062aFE3b57B18e30dEC62b8488",
|
|
25009
|
+
initializer: "0x5979C5315625276ff99a56f95eE5cC44293e7b36",
|
|
25010
|
+
provenance: provenance("sdk-config", sdkConfigUrl("metavault"))
|
|
25011
|
+
}),
|
|
25012
|
+
atomic({
|
|
25013
|
+
chainId: ChainId.Manta,
|
|
25014
|
+
protocol: Protocol.QuickSwapUniv3,
|
|
25015
|
+
factory: "0x56c2162254b0E4417288786eE402c2B41d4e181e",
|
|
25016
|
+
initializer: "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff",
|
|
25017
|
+
provenance: provenance("sdk-config", sdkConfigUrl("quickswap-univ3"))
|
|
25018
|
+
}),
|
|
25019
|
+
atomic({
|
|
25020
|
+
chainId: ChainId.AstarZkevm,
|
|
25021
|
+
protocol: Protocol.QuickSwapUniv3,
|
|
25022
|
+
factory: "0x56c2162254b0E4417288786eE402c2B41d4e181e",
|
|
25023
|
+
initializer: "0xF6Ad3CcF71Abb3E12beCf6b3D2a74C963859ADCd",
|
|
25024
|
+
provenance: provenance("sdk-config", sdkConfigUrl("quickswap-univ3"))
|
|
25025
|
+
}),
|
|
25026
|
+
atomic({
|
|
25027
|
+
chainId: ChainId.Bittensor,
|
|
25028
|
+
protocol: Protocol.BittensorUniV3,
|
|
25029
|
+
factory: "0xfB30AE7542a5E8A5BC134128c0c9dEb4646a2508",
|
|
25030
|
+
initializer: "0x32aF22F550bB1E9dd1382BEaBb0E3e6bb12fA549",
|
|
25031
|
+
provenance: provenance("sdk-config", sdkConfigUrl("bittensor-univ3"))
|
|
25032
|
+
}),
|
|
25033
|
+
factoryOnly({
|
|
25034
|
+
chainId: ChainId.Astar,
|
|
25035
|
+
protocol: Protocol.ArthSwap,
|
|
25036
|
+
factory: "0x69E92b56e4BF4C0FFa2cFB087c7EA47E846a7244",
|
|
25037
|
+
provenance: provenance("sdk-config", sdkConfigUrl("arthswap"))
|
|
25038
|
+
}),
|
|
25039
|
+
factoryOnly({
|
|
25040
|
+
chainId: ChainId.AstarZkevm,
|
|
25041
|
+
protocol: Protocol.ArthSwap,
|
|
25042
|
+
factory: "0xAeaaf0e2c81Af264101B9129C00F4440cCF0F720",
|
|
25043
|
+
provenance: provenance("sdk-config", sdkConfigUrl("arthswap"))
|
|
25044
|
+
}),
|
|
25045
|
+
factoryOnly({
|
|
25046
|
+
chainId: ChainId.Base,
|
|
25047
|
+
protocol: Protocol.BaseSwap,
|
|
25048
|
+
factory: "0x38015D05f4fEC8AFe15D7cc0386a126574e8077B",
|
|
25049
|
+
provenance: provenance("sdk-config", sdkConfigUrl("baseswap"))
|
|
25050
|
+
}),
|
|
25051
|
+
factoryOnly({
|
|
25052
|
+
chainId: ChainId.Base,
|
|
25053
|
+
protocol: Protocol.BaseX,
|
|
25054
|
+
factory: "0xdC323d16C451819890805737997F4Ede96b95e3e",
|
|
25055
|
+
provenance: provenance("sdk-config", sdkConfigUrl("basex"))
|
|
25056
|
+
}),
|
|
25057
|
+
factoryOnly({
|
|
25058
|
+
chainId: ChainId.Moonbeam,
|
|
25059
|
+
protocol: Protocol.BeamSwap,
|
|
25060
|
+
factory: "0xD118fa707147c54387B738F54838Ea5dD4196E71",
|
|
25061
|
+
provenance: provenance("sdk-config", sdkConfigUrl("beamswap"))
|
|
25062
|
+
}),
|
|
25063
|
+
factoryOnly({
|
|
25064
|
+
chainId: ChainId.Mantle,
|
|
25065
|
+
protocol: Protocol.Crust,
|
|
25066
|
+
factory: "0xe67a97d7e55256F33fA0B1465d31E6CED36065d0",
|
|
25067
|
+
provenance: provenance("sdk-config", sdkConfigUrl("crust"))
|
|
25068
|
+
}),
|
|
25069
|
+
factoryOnly({
|
|
25070
|
+
chainId: ChainId.Taiko,
|
|
25071
|
+
protocol: Protocol.Dodo,
|
|
25072
|
+
factory: "0x78172691DD3B8ADa7aEbd9bFfB487FB11D735DB2",
|
|
25073
|
+
provenance: provenance("sdk-config", sdkConfigUrl("dodo"))
|
|
25074
|
+
}),
|
|
25075
|
+
factoryOnly({
|
|
25076
|
+
chainId: ChainId.Sei,
|
|
25077
|
+
protocol: Protocol.DragonSwap,
|
|
25078
|
+
factory: "0x179D9a5592Bc77050796F7be28058c51cA575df4",
|
|
25079
|
+
provenance: provenance("sdk-config", sdkConfigUrl("dragonswap"))
|
|
25080
|
+
}),
|
|
25081
|
+
factoryOnly({
|
|
25082
|
+
chainId: ChainId.Zeta,
|
|
25083
|
+
protocol: Protocol.Eddy,
|
|
25084
|
+
factory: "0x67AA6B2b715937Edc1Eb4D3b7B5d5dCD1fd93E8C",
|
|
25085
|
+
provenance: provenance("sdk-config", sdkConfigUrl("eddy"))
|
|
25086
|
+
}),
|
|
25087
|
+
factoryOnly({
|
|
25088
|
+
chainId: ChainId.Scroll,
|
|
25089
|
+
protocol: Protocol.Equilibre,
|
|
25090
|
+
factory: "0x952aC46B2586737df679e836d9B980E43E12B2d8",
|
|
25091
|
+
provenance: provenance("sdk-config", sdkConfigUrl("equilibre"))
|
|
25092
|
+
}),
|
|
25093
|
+
factoryOnly({
|
|
25094
|
+
chainId: ChainId.Mantle,
|
|
25095
|
+
protocol: Protocol.FusionX,
|
|
25096
|
+
factory: "0x530d2766D1988CC1c000C8b7d00334c14B69AD71",
|
|
25097
|
+
poolInitCodeHash: "0x1bce652aaa6528355d7a339037433a20cd28410e3967635ba8d2ddb037440dbf",
|
|
25098
|
+
provenance: provenance("sdk-config", sdkConfigUrl("fusionx"))
|
|
25099
|
+
}),
|
|
25100
|
+
factoryOnly({
|
|
25101
|
+
chainId: ChainId.TataraTestnet,
|
|
25102
|
+
protocol: Protocol.Katana,
|
|
25103
|
+
factory: "0x9B3336186a38E1b6c21955d112dbb0343Ee061eE",
|
|
25104
|
+
provenance: provenance("sdk-config", sdkConfigUrl("katana"))
|
|
25105
|
+
}),
|
|
25106
|
+
factoryOnly({
|
|
25107
|
+
chainId: ChainId.Kava,
|
|
25108
|
+
protocol: Protocol.Kinetix,
|
|
25109
|
+
factory: "0x2dBB6254231C5569B6A4313c6C1F5Fe1340b35C2",
|
|
25110
|
+
provenance: provenance("sdk-config", sdkConfigUrl("kinetix"))
|
|
25111
|
+
}),
|
|
25112
|
+
factoryOnly({
|
|
25113
|
+
chainId: ChainId.Base,
|
|
25114
|
+
protocol: Protocol.Kinetix,
|
|
25115
|
+
factory: "0xdDF5a3259a88Ab79D5530eB3eB14c1C92CD97FCf",
|
|
25116
|
+
provenance: provenance("sdk-config", sdkConfigUrl("kinetix"))
|
|
25117
|
+
}),
|
|
25118
|
+
factoryOnly({
|
|
25119
|
+
chainId: ChainId.BeraChainBartio,
|
|
25120
|
+
protocol: Protocol.Kodiak,
|
|
25121
|
+
factory: "0x217Cd80795EfCa5025d47023da5c03a24fA95356",
|
|
25122
|
+
provenance: provenance("sdk-config", sdkConfigUrl("kodiak"))
|
|
25123
|
+
}),
|
|
25124
|
+
factoryOnly({
|
|
25125
|
+
chainId: ChainId.Bera,
|
|
25126
|
+
protocol: Protocol.Kodiak,
|
|
25127
|
+
factory: "0xD84CBf0B02636E7f53dB9E5e45A616E05d710990",
|
|
25128
|
+
provenance: provenance("sdk-config", sdkConfigUrl("kodiak"))
|
|
25129
|
+
}),
|
|
25130
|
+
factoryOnly({
|
|
25131
|
+
chainId: ChainId.Soneium,
|
|
25132
|
+
protocol: Protocol.Kyo,
|
|
25133
|
+
factory: "0x137841043180BBA8EF52828F9030D1b7fE065F95",
|
|
25134
|
+
provenance: provenance("sdk-config", sdkConfigUrl("kyo"))
|
|
25135
|
+
}),
|
|
25136
|
+
factoryOnly({
|
|
25137
|
+
chainId: ChainId.Linea,
|
|
25138
|
+
protocol: Protocol.LineHub,
|
|
25139
|
+
factory: "0x6c379d538F2F7cb642851e154A8E572D63238DF4",
|
|
25140
|
+
provenance: provenance("sdk-config", sdkConfigUrl("linehub"))
|
|
25141
|
+
}),
|
|
25142
|
+
factoryOnly({
|
|
25143
|
+
chainId: ChainId.ZklinkNova,
|
|
25144
|
+
protocol: Protocol.NovaSwap,
|
|
25145
|
+
factory: "0x9f94c91b178F5bc9fCcA3e5428b09A3d01CE5AC6",
|
|
25146
|
+
provenance: provenance("sdk-config", sdkConfigUrl("novaswap"))
|
|
25147
|
+
}),
|
|
25148
|
+
factoryOnly({
|
|
25149
|
+
chainId: ChainId.OkxTestnet,
|
|
25150
|
+
protocol: Protocol.QuickSwapUniv3,
|
|
25151
|
+
factory: "0x56c2162254b0E4417288786eE402c2B41d4e181e",
|
|
25152
|
+
provenance: provenance("sdk-config", sdkConfigUrl("quickswap-univ3"))
|
|
25153
|
+
}),
|
|
25154
|
+
factoryOnly({
|
|
25155
|
+
chainId: ChainId.Sei,
|
|
25156
|
+
protocol: Protocol.Sailor,
|
|
25157
|
+
factory: "0x137841043180BBA8EF52828F9030D1b7fE065F95",
|
|
25158
|
+
provenance: provenance("sdk-config", sdkConfigUrl("sailor"))
|
|
25159
|
+
}),
|
|
25160
|
+
factoryOnly({
|
|
25161
|
+
chainId: ChainId.Flare,
|
|
25162
|
+
protocol: Protocol.Spark,
|
|
25163
|
+
factory: "0xb3fB4f96175f6f9D716c17744e5A6d4BA9da8176",
|
|
25164
|
+
provenance: provenance("sdk-config", sdkConfigUrl("spark"))
|
|
25165
|
+
}),
|
|
25166
|
+
factoryOnly({
|
|
25167
|
+
chainId: ChainId.Flare,
|
|
25168
|
+
protocol: Protocol.Spark32,
|
|
25169
|
+
factory: "0x8A2578d23d4C532cC9A98FaD91C0523f5efDE652",
|
|
25170
|
+
provenance: provenance("sdk-config", sdkConfigUrl("spark32"))
|
|
25171
|
+
}),
|
|
25172
|
+
factoryOnly({
|
|
25173
|
+
chainId: ChainId.Sonic,
|
|
25174
|
+
protocol: Protocol.SpookySwap,
|
|
25175
|
+
factory: "0x3D91B700252e0E3eE7805d12e048a988Ab69C8ad",
|
|
25176
|
+
provenance: provenance("sdk-config", sdkConfigUrl("spookyswap"))
|
|
25177
|
+
}),
|
|
25178
|
+
factoryOnly({
|
|
25179
|
+
chainId: ChainId.Mode,
|
|
25180
|
+
protocol: Protocol.SupSwap,
|
|
25181
|
+
factory: "0xa0b018Fe0d00ed075fb9b0eEe26d25cf72e1F693",
|
|
25182
|
+
provenance: provenance("sdk-config", sdkConfigUrl("supswap"))
|
|
25183
|
+
}),
|
|
25184
|
+
factoryOnly({
|
|
25185
|
+
chainId: ChainId.Mode,
|
|
25186
|
+
protocol: Protocol.SwapMode,
|
|
25187
|
+
factory: "0x6E36FC34eA123044F278d3a9F3819027B21c9c32",
|
|
25188
|
+
provenance: provenance("sdk-config", sdkConfigUrl("swapmode"))
|
|
25189
|
+
}),
|
|
25190
|
+
factoryOnly({
|
|
25191
|
+
chainId: ChainId.Fantom,
|
|
25192
|
+
protocol: Protocol.Thick,
|
|
25193
|
+
factory: "0xE6dA85feb3B4E0d6AEd95c41a125fba859bB9d24",
|
|
25194
|
+
provenance: provenance("sdk-config", sdkConfigUrl("thick"))
|
|
25195
|
+
}),
|
|
25196
|
+
factoryOnly({
|
|
25197
|
+
chainId: ChainId.Blast,
|
|
25198
|
+
protocol: Protocol.Thruster,
|
|
25199
|
+
factory: "0x71b08f13B3c3aF35aAdEb3949AFEb1ded1016127",
|
|
25200
|
+
poolInitCodeHash: "0xd0c3a51b16dbc778f000c620eaabeecd33b33a80bd145e1f7cbc0d4de335193d",
|
|
25201
|
+
provenance: provenance("sdk-config", sdkConfigUrl("thruster"))
|
|
25202
|
+
})
|
|
25203
|
+
], (entry) => deploymentKey$2(entry.chainId, entry.protocol), "V3 lifecycle deployment");
|
|
25204
|
+
/**
|
|
25205
|
+
* Protocols whose current SDK configuration is intentionally inventoried by
|
|
25206
|
+
* the V3 lifecycle registry. Adding a factory for one of these protocols must
|
|
25207
|
+
* also add an explicit lifecycle capability entry.
|
|
25208
|
+
*/
|
|
25209
|
+
const V3_CONFIG_PROTOCOLS = Object.freeze([
|
|
25210
|
+
Protocol.ArthSwap,
|
|
25211
|
+
Protocol.BaseSwap,
|
|
25212
|
+
Protocol.BaseX,
|
|
25213
|
+
Protocol.BeamSwap,
|
|
25214
|
+
Protocol.BittensorUniV3,
|
|
25215
|
+
Protocol.Crust,
|
|
25216
|
+
Protocol.Dodo,
|
|
25217
|
+
Protocol.DragonSwap,
|
|
25218
|
+
Protocol.Eddy,
|
|
25219
|
+
Protocol.Equilibre,
|
|
25220
|
+
Protocol.Forge,
|
|
25221
|
+
Protocol.FusionX,
|
|
25222
|
+
Protocol.Horiza,
|
|
25223
|
+
Protocol.Katana,
|
|
25224
|
+
Protocol.Kinetix,
|
|
25225
|
+
Protocol.Kodiak,
|
|
25226
|
+
Protocol.Kyo,
|
|
25227
|
+
Protocol.LineHub,
|
|
25228
|
+
Protocol.Maia,
|
|
25229
|
+
Protocol.MetaVault,
|
|
25230
|
+
Protocol.NovaSwap,
|
|
25231
|
+
Protocol.PancakeSwap,
|
|
25232
|
+
Protocol.QuickSwapUniv3,
|
|
25233
|
+
Protocol.Sailor,
|
|
25234
|
+
Protocol.Spark,
|
|
25235
|
+
Protocol.Spark32,
|
|
25236
|
+
Protocol.SpookySwap,
|
|
25237
|
+
Protocol.SupSwap,
|
|
25238
|
+
Protocol.Sushi,
|
|
25239
|
+
Protocol.SwapMode,
|
|
25240
|
+
Protocol.Thick,
|
|
25241
|
+
Protocol.Thruster,
|
|
25242
|
+
Protocol.Uniswap
|
|
25243
|
+
]);
|
|
25244
|
+
function resolveV3LifecycleDeployment(params) {
|
|
25245
|
+
return V3_LIFECYCLE_DEPLOYMENTS[deploymentKey$2(params.chainId, params.protocol)];
|
|
25246
|
+
}
|
|
25247
|
+
//#endregion
|
|
25248
|
+
//#region src/pool-lifecycle/capabilities/v4.ts
|
|
25249
|
+
const OFFICIAL_DEPLOYMENTS_URL = "https://developers.uniswap.org/deployments.json";
|
|
25250
|
+
function getV4LifecycleDeploymentId(params) {
|
|
25251
|
+
const poolManager = getAddress(params.poolManager).toLowerCase();
|
|
25252
|
+
const stateView = getAddress(params.stateView).toLowerCase();
|
|
25253
|
+
return `uniswap-v4:${params.chainId}:${params.protocol}:${poolManager}:${stateView}:${params.adapter}:v${params.version}`;
|
|
25254
|
+
}
|
|
25255
|
+
function deployment(chainId, poolManager, stateView, startBlock) {
|
|
25256
|
+
const poolManagerAddress = getAddress(poolManager);
|
|
25257
|
+
const stateViewAddress = getAddress(stateView);
|
|
25258
|
+
const identity = {
|
|
25259
|
+
chainId,
|
|
25260
|
+
protocol: Protocol.UniswapV4,
|
|
25261
|
+
poolManager: poolManagerAddress,
|
|
25262
|
+
stateView: stateViewAddress,
|
|
25263
|
+
adapter: "pool-manager-initialize-v1",
|
|
25264
|
+
version: 1
|
|
25265
|
+
};
|
|
25266
|
+
return Object.freeze({
|
|
25267
|
+
supported: true,
|
|
25268
|
+
schemaVersion: 1,
|
|
25269
|
+
deploymentId: getV4LifecycleDeploymentId(identity),
|
|
25270
|
+
chainId,
|
|
25271
|
+
protocol: Protocol.UniswapV4,
|
|
25272
|
+
family: "uniswap-v4",
|
|
25273
|
+
adapter: identity.adapter,
|
|
25274
|
+
version: identity.version,
|
|
25275
|
+
poolManager: poolManagerAddress,
|
|
25276
|
+
stateView: stateViewAddress,
|
|
25277
|
+
startBlock,
|
|
25278
|
+
provenance: Object.freeze({
|
|
25279
|
+
source: "official-deployment",
|
|
25280
|
+
urls: Object.freeze([OFFICIAL_DEPLOYMENTS_URL])
|
|
25281
|
+
})
|
|
25282
|
+
});
|
|
25283
|
+
}
|
|
25284
|
+
/**
|
|
25285
|
+
* Explicit lifecycle-write registry. Entries are not inferred from discovery
|
|
25286
|
+
* configuration so a newly discovered deployment remains unsupported until it
|
|
25287
|
+
* is deliberately reviewed and versioned here.
|
|
25288
|
+
*/
|
|
25289
|
+
const CURRENT_V4_LIFECYCLE_DEPLOYMENTS = Object.freeze([
|
|
25290
|
+
deployment(ChainId.Mainnet, "0x000000000004444c5dc75cB358380D2e3dE08A90", "0x7ffe42c4a5deea5b0fec41c94c136cf115597227", 21688329n),
|
|
25291
|
+
deployment(ChainId.BSC, "0x28e2ea090877bf75740558f6bfb36a5ffee9e9df", "0xd13dd3d6e93f276fafc9db9e6bb47c1180aee0c4", 45970610n),
|
|
25292
|
+
deployment(ChainId.Unichain, "0x1f98400000000000000000000000000000000004", "0x86e8631a016f9068c3f085faf484ee3f5fdee8f2", 25500n),
|
|
25293
|
+
deployment(ChainId.Robinhood, "0x8366a39cc670b4001a1121b8f6a443a643e40951", "0xf3334192d15450cdd385c8b70e03f9a6bd9e673b", 9070n),
|
|
25294
|
+
deployment(ChainId.Base, "0x498581ff718922c3f8e6a244956af099b2652b2b", "0xa3c0c9b65bad0b08107aa264b0f3db444b867a71", 25350988n),
|
|
25295
|
+
deployment(ChainId.Arbitrum, "0x360e68faccca8ca495c1b759fd9eee466db9fb32", "0x76fd297e2d437cd7f76d50f01afe6160f86e9990", 297842872n)
|
|
25296
|
+
]);
|
|
25297
|
+
/**
|
|
25298
|
+
* Every approved V4 deployment, including historical managers. When a current
|
|
25299
|
+
* deployment changes, retain the former entry here so existing plans remain
|
|
25300
|
+
* independently resolvable by deploymentId.
|
|
25301
|
+
*/
|
|
25302
|
+
const V4_LIFECYCLE_DEPLOYMENTS = Object.freeze([...CURRENT_V4_LIFECYCLE_DEPLOYMENTS]);
|
|
25303
|
+
function deploymentKey$1(chainId, protocol) {
|
|
25304
|
+
return `${chainId}:${protocol}`;
|
|
25305
|
+
}
|
|
25306
|
+
const V4_LIFECYCLE_DEPLOYMENTS_BY_ID = buildCheckedRegistry(V4_LIFECYCLE_DEPLOYMENTS, (entry) => entry.deploymentId, "V4 lifecycle deployment id");
|
|
25307
|
+
const CURRENT_DEPLOYMENTS_BY_KEY = buildCheckedRegistry(CURRENT_V4_LIFECYCLE_DEPLOYMENTS, (entry) => deploymentKey$1(entry.chainId, entry.protocol), "current V4 lifecycle deployment");
|
|
25308
|
+
/** Resolve the explicitly selected current-default deployment for a chain/protocol pair. */
|
|
25309
|
+
function resolveCurrentV4LifecycleDeployment(params) {
|
|
25310
|
+
return CURRENT_DEPLOYMENTS_BY_KEY[deploymentKey$1(params.chainId, params.protocol)];
|
|
25311
|
+
}
|
|
25312
|
+
/** Backwards-compatible alias; prefer the name that makes current-default semantics explicit. */
|
|
25313
|
+
const resolveV4LifecycleDeployment = resolveCurrentV4LifecycleDeployment;
|
|
25314
|
+
/** Resolve an exact current or historical deployment without consulting defaults. */
|
|
25315
|
+
function resolveV4LifecycleDeploymentById(deploymentId) {
|
|
25316
|
+
return V4_LIFECYCLE_DEPLOYMENTS_BY_ID[deploymentId];
|
|
25317
|
+
}
|
|
25318
|
+
/**
|
|
25319
|
+
* Validate capability metadata supplied across a UI/CLI boundary and return
|
|
25320
|
+
* the canonical frozen registry entry.
|
|
25321
|
+
*/
|
|
25322
|
+
function validateV4LifecycleDeployment(value) {
|
|
25323
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", "V4 deployment must be an object.");
|
|
25324
|
+
const candidate = value;
|
|
25325
|
+
if (typeof candidate.deploymentId !== "string" || !Number.isSafeInteger(candidate.chainId) || typeof candidate.protocol !== "string") throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", "V4 deployment id, chainId, and protocol are invalid.");
|
|
25326
|
+
const configured = resolveV4LifecycleDeploymentById(candidate.deploymentId);
|
|
25327
|
+
let matches = false;
|
|
25328
|
+
try {
|
|
25329
|
+
matches = configured !== void 0 && candidate.supported === true && candidate.deploymentId === configured.deploymentId && candidate.schemaVersion === configured.schemaVersion && candidate.chainId === configured.chainId && candidate.protocol === configured.protocol && candidate.family === configured.family && candidate.adapter === configured.adapter && candidate.version === configured.version && getAddress(candidate.poolManager) === configured.poolManager && getAddress(candidate.stateView) === configured.stateView && candidate.startBlock === configured.startBlock;
|
|
25330
|
+
} catch {}
|
|
25331
|
+
if (!matches || !configured) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", `V4 lifecycle deployment ${String(candidate.deploymentId)} is not configured.`);
|
|
25332
|
+
return configured;
|
|
25333
|
+
}
|
|
25334
|
+
//#endregion
|
|
25335
|
+
//#region src/pool-lifecycle/capabilities.ts
|
|
25336
|
+
function deploymentKey(deployment) {
|
|
25337
|
+
return `${deployment.chainId}:${deployment.protocol}`;
|
|
25338
|
+
}
|
|
25339
|
+
function buildLifecycleRegistry() {
|
|
25340
|
+
return buildCheckedRegistry([
|
|
25341
|
+
...Object.values(V3_LIFECYCLE_DEPLOYMENTS).filter((deployment) => deployment !== void 0),
|
|
25342
|
+
...CURRENT_V4_LIFECYCLE_DEPLOYMENTS,
|
|
25343
|
+
...ALGEBRA_LIFECYCLE_DEPLOYMENTS
|
|
25344
|
+
], deploymentKey, "pool lifecycle deployment");
|
|
25345
|
+
}
|
|
25346
|
+
/**
|
|
25347
|
+
* Collision-checked current-default deployments, independent of discovery.
|
|
25348
|
+
* Historical V4 entries remain available through V4_LIFECYCLE_DEPLOYMENTS and
|
|
25349
|
+
* its deployment-id resolver instead of competing for this chain/protocol key.
|
|
25350
|
+
*/
|
|
25351
|
+
const POOL_LIFECYCLE_DEPLOYMENTS = buildLifecycleRegistry();
|
|
25352
|
+
/**
|
|
25353
|
+
* Resolve only explicitly versioned lifecycle capabilities. Discovery and
|
|
25354
|
+
* subgraph metadata are never an implicit fallback for transaction building.
|
|
25355
|
+
*/
|
|
25356
|
+
function resolvePoolLifecycleDeployment(params) {
|
|
25357
|
+
const deployment = POOL_LIFECYCLE_DEPLOYMENTS[deploymentKey(params)];
|
|
25358
|
+
if (deployment) return deployment;
|
|
25359
|
+
return Object.freeze({
|
|
25360
|
+
supported: false,
|
|
25361
|
+
schemaVersion: 1,
|
|
25362
|
+
family: "unsupported",
|
|
25363
|
+
chainId: params.chainId,
|
|
25364
|
+
protocol: params.protocol,
|
|
25365
|
+
reason: "deployment-not-configured"
|
|
25366
|
+
});
|
|
25367
|
+
}
|
|
25368
|
+
//#endregion
|
|
25369
|
+
//#region src/pool-lifecycle/abis/algebra.ts
|
|
25370
|
+
const algebraPairFactoryAbi = parseAbi([
|
|
25371
|
+
"event Pool(address indexed token0,address indexed token1,address pool)",
|
|
25372
|
+
"function poolDeployer() view returns (address)",
|
|
25373
|
+
"function poolByPair(address tokenA,address tokenB) view returns (address pool)",
|
|
25374
|
+
"function createPool(address tokenA,address tokenB) returns (address pool)"
|
|
25375
|
+
]);
|
|
25376
|
+
const algebraIntegralPluginDataFactoryAbi = parseAbi([
|
|
25377
|
+
"event Pool(address indexed token0,address indexed token1,address pool)",
|
|
25378
|
+
"event CustomPool(address indexed deployer,address indexed token0,address indexed token1,address pool)",
|
|
25379
|
+
"function poolDeployer() view returns (address)",
|
|
25380
|
+
"function poolByPair(address tokenA,address tokenB) view returns (address pool)",
|
|
25381
|
+
"function createPool(address tokenA,address tokenB,bytes data) returns (address pool)",
|
|
25382
|
+
"function defaultConfigurationForPool() view returns (uint16 communityFee,int24 tickSpacing,uint16 fee)",
|
|
25383
|
+
"function defaultPluginFactory() view returns (address)"
|
|
25384
|
+
]);
|
|
25385
|
+
const algebraIntegralPairFactoryAbi = parseAbi([
|
|
25386
|
+
"event Pool(address indexed token0,address indexed token1,address pool)",
|
|
25387
|
+
"event CustomPool(address indexed deployer,address indexed token0,address indexed token1,address pool)",
|
|
25388
|
+
"function poolDeployer() view returns (address)",
|
|
25389
|
+
"function poolByPair(address tokenA,address tokenB) view returns (address pool)",
|
|
25390
|
+
"function createPool(address tokenA,address tokenB) returns (address pool)",
|
|
25391
|
+
"function defaultTickspacing() view returns (int24)",
|
|
25392
|
+
"function defaultFee() view returns (uint16)",
|
|
25393
|
+
"function defaultPluginFactory() view returns (address)"
|
|
25394
|
+
]);
|
|
25395
|
+
const algebraPoolBaseAbi = parseAbi([
|
|
25396
|
+
"event Initialize(uint160 price,int24 tick)",
|
|
25397
|
+
"function factory() view returns (address)",
|
|
25398
|
+
"function token0() view returns (address)",
|
|
25399
|
+
"function token1() view returns (address)",
|
|
25400
|
+
"function tickSpacing() view returns (int24)",
|
|
25401
|
+
"function initialize(uint160 initialPrice)"
|
|
25402
|
+
]);
|
|
25403
|
+
const algebraLegacyPoolStateAbi = parseAbi(["function globalState() view returns (uint160 price,int24 tick,int24 prevInitializedTick,uint16 fee,uint16 timepointIndex,uint8 communityFee,bool unlocked)"]);
|
|
25404
|
+
const algebraDirectionalPoolStateAbi = parseAbi(["function globalState() view returns (uint160 price,int24 tick,uint16 feeZto,uint16 feeOtz,uint16 timepointIndex,uint8 communityFeeToken0,uint8 communityFeeToken1,bool unlocked)"]);
|
|
25405
|
+
const algebraIntegralPoolStateAbi = parseAbi(["function globalState() view returns (uint160 price,int24 tick,uint16 lastFee,uint8 pluginConfig,uint16 communityFee,bool unlocked)", "function plugin() view returns (address)"]);
|
|
25406
|
+
/**
|
|
25407
|
+
* Kept separate from standard pool creation. Calling this directly from an EOA
|
|
25408
|
+
* is invalid because the entry point requires msg.sender == deployer.
|
|
25409
|
+
*/
|
|
25410
|
+
const algebraCustomPoolEntryPointAbi = parseAbi(["function factory() view returns (address)", "function createCustomPool(address deployer,address creator,address tokenA,address tokenB,bytes data) returns (address customPool)"]);
|
|
25411
|
+
//#endregion
|
|
25412
|
+
//#region src/pool-lifecycle/abis/v3.ts
|
|
25413
|
+
/** Minimal canonical Uniswap V3-compatible factory ABI used by pool lifecycle flows. */
|
|
25414
|
+
const v3FactoryAbi = [
|
|
25415
|
+
{
|
|
25416
|
+
type: "function",
|
|
25417
|
+
name: "createPool",
|
|
25418
|
+
stateMutability: "nonpayable",
|
|
25419
|
+
inputs: [
|
|
25420
|
+
{
|
|
25421
|
+
name: "tokenA",
|
|
25422
|
+
type: "address"
|
|
25423
|
+
},
|
|
25424
|
+
{
|
|
25425
|
+
name: "tokenB",
|
|
25426
|
+
type: "address"
|
|
25427
|
+
},
|
|
25428
|
+
{
|
|
25429
|
+
name: "fee",
|
|
25430
|
+
type: "uint24"
|
|
25431
|
+
}
|
|
25432
|
+
],
|
|
25433
|
+
outputs: [{
|
|
25434
|
+
name: "pool",
|
|
25435
|
+
type: "address"
|
|
25436
|
+
}]
|
|
25437
|
+
},
|
|
25438
|
+
{
|
|
25439
|
+
type: "function",
|
|
25440
|
+
name: "getPool",
|
|
25441
|
+
stateMutability: "view",
|
|
25442
|
+
inputs: [
|
|
25443
|
+
{
|
|
25444
|
+
name: "tokenA",
|
|
25445
|
+
type: "address"
|
|
25446
|
+
},
|
|
25447
|
+
{
|
|
25448
|
+
name: "tokenB",
|
|
25449
|
+
type: "address"
|
|
25450
|
+
},
|
|
25451
|
+
{
|
|
25452
|
+
name: "fee",
|
|
25453
|
+
type: "uint24"
|
|
25454
|
+
}
|
|
25455
|
+
],
|
|
25456
|
+
outputs: [{
|
|
25457
|
+
name: "pool",
|
|
25458
|
+
type: "address"
|
|
25459
|
+
}]
|
|
25460
|
+
},
|
|
25461
|
+
{
|
|
25462
|
+
type: "function",
|
|
25463
|
+
name: "feeAmountTickSpacing",
|
|
25464
|
+
stateMutability: "view",
|
|
25465
|
+
inputs: [{
|
|
25466
|
+
name: "fee",
|
|
25467
|
+
type: "uint24"
|
|
25468
|
+
}],
|
|
25469
|
+
outputs: [{
|
|
25470
|
+
name: "tickSpacing",
|
|
25471
|
+
type: "int24"
|
|
25472
|
+
}]
|
|
25473
|
+
},
|
|
25474
|
+
{
|
|
25475
|
+
type: "event",
|
|
25476
|
+
name: "PoolCreated",
|
|
25477
|
+
inputs: [
|
|
25478
|
+
{
|
|
25479
|
+
name: "token0",
|
|
25480
|
+
type: "address",
|
|
25481
|
+
indexed: true
|
|
25482
|
+
},
|
|
25483
|
+
{
|
|
25484
|
+
name: "token1",
|
|
25485
|
+
type: "address",
|
|
25486
|
+
indexed: true
|
|
25487
|
+
},
|
|
25488
|
+
{
|
|
25489
|
+
name: "fee",
|
|
25490
|
+
type: "uint24",
|
|
25491
|
+
indexed: true
|
|
25492
|
+
},
|
|
25493
|
+
{
|
|
25494
|
+
name: "tickSpacing",
|
|
25495
|
+
type: "int24",
|
|
25496
|
+
indexed: false
|
|
25497
|
+
},
|
|
25498
|
+
{
|
|
25499
|
+
name: "pool",
|
|
25500
|
+
type: "address",
|
|
25501
|
+
indexed: false
|
|
25502
|
+
}
|
|
25503
|
+
]
|
|
25504
|
+
}
|
|
25505
|
+
];
|
|
25506
|
+
/** Minimal PoolInitializer/NonfungiblePositionManager ABI used for atomic V3 setup. */
|
|
25507
|
+
const v3PoolInitializerAbi = [{
|
|
25508
|
+
type: "function",
|
|
25509
|
+
name: "createAndInitializePoolIfNecessary",
|
|
25510
|
+
stateMutability: "payable",
|
|
25511
|
+
inputs: [
|
|
25512
|
+
{
|
|
25513
|
+
name: "token0",
|
|
25514
|
+
type: "address"
|
|
25515
|
+
},
|
|
25516
|
+
{
|
|
25517
|
+
name: "token1",
|
|
25518
|
+
type: "address"
|
|
25519
|
+
},
|
|
25520
|
+
{
|
|
25521
|
+
name: "fee",
|
|
25522
|
+
type: "uint24"
|
|
25523
|
+
},
|
|
25524
|
+
{
|
|
25525
|
+
name: "sqrtPriceX96",
|
|
25526
|
+
type: "uint160"
|
|
25527
|
+
}
|
|
25528
|
+
],
|
|
25529
|
+
outputs: [{
|
|
25530
|
+
name: "pool",
|
|
25531
|
+
type: "address"
|
|
25532
|
+
}]
|
|
25533
|
+
}, {
|
|
25534
|
+
type: "function",
|
|
25535
|
+
name: "factory",
|
|
25536
|
+
stateMutability: "view",
|
|
25537
|
+
inputs: [],
|
|
25538
|
+
outputs: [{
|
|
25539
|
+
name: "",
|
|
25540
|
+
type: "address"
|
|
25541
|
+
}]
|
|
25542
|
+
}];
|
|
25543
|
+
/** Minimal canonical V3 pool ABI needed to initialize and verify a deployment. */
|
|
25544
|
+
const v3PoolAbi = [
|
|
25545
|
+
{
|
|
25546
|
+
type: "function",
|
|
25547
|
+
name: "initialize",
|
|
25548
|
+
stateMutability: "nonpayable",
|
|
25549
|
+
inputs: [{
|
|
25550
|
+
name: "sqrtPriceX96",
|
|
25551
|
+
type: "uint160"
|
|
25552
|
+
}],
|
|
25553
|
+
outputs: []
|
|
25554
|
+
},
|
|
25555
|
+
{
|
|
25556
|
+
type: "function",
|
|
25557
|
+
name: "factory",
|
|
25558
|
+
stateMutability: "view",
|
|
25559
|
+
inputs: [],
|
|
25560
|
+
outputs: [{
|
|
25561
|
+
name: "",
|
|
25562
|
+
type: "address"
|
|
25563
|
+
}]
|
|
25564
|
+
},
|
|
25565
|
+
{
|
|
25566
|
+
type: "function",
|
|
25567
|
+
name: "token0",
|
|
25568
|
+
stateMutability: "view",
|
|
25569
|
+
inputs: [],
|
|
25570
|
+
outputs: [{
|
|
25571
|
+
name: "",
|
|
25572
|
+
type: "address"
|
|
25573
|
+
}]
|
|
25574
|
+
},
|
|
25575
|
+
{
|
|
25576
|
+
type: "function",
|
|
25577
|
+
name: "token1",
|
|
25578
|
+
stateMutability: "view",
|
|
25579
|
+
inputs: [],
|
|
25580
|
+
outputs: [{
|
|
25581
|
+
name: "",
|
|
25582
|
+
type: "address"
|
|
25583
|
+
}]
|
|
25584
|
+
},
|
|
25585
|
+
{
|
|
25586
|
+
type: "function",
|
|
25587
|
+
name: "fee",
|
|
25588
|
+
stateMutability: "view",
|
|
25589
|
+
inputs: [],
|
|
25590
|
+
outputs: [{
|
|
25591
|
+
name: "",
|
|
25592
|
+
type: "uint24"
|
|
25593
|
+
}]
|
|
25594
|
+
},
|
|
25595
|
+
{
|
|
25596
|
+
type: "function",
|
|
25597
|
+
name: "tickSpacing",
|
|
25598
|
+
stateMutability: "view",
|
|
25599
|
+
inputs: [],
|
|
25600
|
+
outputs: [{
|
|
25601
|
+
name: "",
|
|
25602
|
+
type: "int24"
|
|
25603
|
+
}]
|
|
25604
|
+
},
|
|
25605
|
+
{
|
|
25606
|
+
type: "function",
|
|
25607
|
+
name: "slot0",
|
|
25608
|
+
stateMutability: "view",
|
|
25609
|
+
inputs: [],
|
|
25610
|
+
outputs: [
|
|
25611
|
+
{
|
|
25612
|
+
name: "sqrtPriceX96",
|
|
25613
|
+
type: "uint160"
|
|
25614
|
+
},
|
|
25615
|
+
{
|
|
25616
|
+
name: "tick",
|
|
25617
|
+
type: "int24"
|
|
25618
|
+
},
|
|
25619
|
+
{
|
|
25620
|
+
name: "observationIndex",
|
|
25621
|
+
type: "uint16"
|
|
25622
|
+
},
|
|
25623
|
+
{
|
|
25624
|
+
name: "observationCardinality",
|
|
25625
|
+
type: "uint16"
|
|
25626
|
+
},
|
|
25627
|
+
{
|
|
25628
|
+
name: "observationCardinalityNext",
|
|
25629
|
+
type: "uint16"
|
|
25630
|
+
},
|
|
25631
|
+
{
|
|
25632
|
+
name: "feeProtocol",
|
|
25633
|
+
type: "uint8"
|
|
25634
|
+
},
|
|
25635
|
+
{
|
|
25636
|
+
name: "unlocked",
|
|
25637
|
+
type: "bool"
|
|
25638
|
+
}
|
|
25639
|
+
]
|
|
25640
|
+
},
|
|
25641
|
+
{
|
|
25642
|
+
type: "event",
|
|
25643
|
+
name: "Initialize",
|
|
25644
|
+
inputs: [{
|
|
25645
|
+
name: "sqrtPriceX96",
|
|
25646
|
+
type: "uint160",
|
|
25647
|
+
indexed: false
|
|
25648
|
+
}, {
|
|
25649
|
+
name: "tick",
|
|
25650
|
+
type: "int24",
|
|
25651
|
+
indexed: false
|
|
25652
|
+
}]
|
|
25653
|
+
}
|
|
25654
|
+
];
|
|
25655
|
+
//#endregion
|
|
25656
|
+
//#region src/pool-lifecycle/algebra/key.ts
|
|
25657
|
+
function canonicalizeAlgebraPoolKey(input) {
|
|
25658
|
+
if (!isAddress(input.tokenA, { strict: true }) || !isAddress(input.tokenB, { strict: true })) throw new PoolLifecycleError("INVALID_INPUT", "Algebra tokens must be valid EVM addresses.");
|
|
25659
|
+
const tokenA = getAddress(input.tokenA);
|
|
25660
|
+
const tokenB = getAddress(input.tokenB);
|
|
25661
|
+
if (tokenA === "0x0000000000000000000000000000000000000000" || tokenB === "0x0000000000000000000000000000000000000000" || tokenA === tokenB) throw new PoolLifecycleError("INVALID_INPUT", "Algebra tokens must be distinct and non-zero.");
|
|
25662
|
+
return BigInt(tokenA) < BigInt(tokenB) ? {
|
|
25663
|
+
token0: tokenA,
|
|
25664
|
+
token1: tokenB
|
|
25665
|
+
} : {
|
|
25666
|
+
token0: tokenB,
|
|
25667
|
+
token1: tokenA
|
|
25668
|
+
};
|
|
25669
|
+
}
|
|
25670
|
+
function assertAlgebraInitialPrice(key, price) {
|
|
25671
|
+
const priceKey = canonicalizeAlgebraPoolKey({
|
|
25672
|
+
tokenA: price.token0,
|
|
25673
|
+
tokenB: price.token1
|
|
25674
|
+
});
|
|
25675
|
+
if (priceKey.token0 !== key.token0 || priceKey.token1 !== key.token1) throw new PoolLifecycleError("INVALID_INPUT", "Algebra price tokens do not match the pool key.");
|
|
25676
|
+
validateSqrtPriceX96(price.sqrtPriceX96);
|
|
25677
|
+
return {
|
|
25678
|
+
token0: key.token0,
|
|
25679
|
+
token1: key.token1,
|
|
25680
|
+
sqrtPriceX96: price.sqrtPriceX96
|
|
25681
|
+
};
|
|
25682
|
+
}
|
|
25683
|
+
//#endregion
|
|
25684
|
+
//#region src/pool-lifecycle/algebra/inspect.ts
|
|
25685
|
+
const ZERO = getAddress("0x0000000000000000000000000000000000000000");
|
|
25686
|
+
async function requireCode(client, address, label, blockNumber) {
|
|
25687
|
+
const code = await client.getCode({
|
|
25688
|
+
address,
|
|
25689
|
+
blockNumber
|
|
25690
|
+
});
|
|
25691
|
+
if (!code || code === "0x") throw new PoolLifecycleError("CONTRACT_NOT_DEPLOYED", `${label} ${address} has no bytecode at block ${blockNumber}.`);
|
|
25692
|
+
}
|
|
25693
|
+
/** Verify configured custom-pool routing without claiming a generic deployer ABI. */
|
|
25694
|
+
async function inspectAlgebraCustomPoolEntryPoint(params) {
|
|
25695
|
+
const deployment = validateAlgebraLifecycleDeployment(params.deployment);
|
|
25696
|
+
if (!deployment.customPoolEntryPoint) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", `No custom Algebra entry point is configured for chain ${deployment.chainId} and protocol ${deployment.protocol}.`);
|
|
25697
|
+
const chainId = await params.publicClient.getChainId();
|
|
25698
|
+
if (chainId !== deployment.chainId) throw new PoolLifecycleError("CHAIN_MISMATCH", `Public client chain ${chainId} does not match Algebra deployment chain ${deployment.chainId}.`);
|
|
25699
|
+
const blockNumber = params.blockNumber ?? await params.publicClient.getBlockNumber();
|
|
25700
|
+
const entryPoint = deployment.customPoolEntryPoint;
|
|
25701
|
+
const factory = deployment.factory;
|
|
25702
|
+
await requireCode(params.publicClient, entryPoint, "Algebra custom pool entry point", blockNumber);
|
|
25703
|
+
const entryFactory = getAddress(await params.publicClient.readContract({
|
|
25704
|
+
address: entryPoint,
|
|
25705
|
+
abi: algebraCustomPoolEntryPointAbi,
|
|
25706
|
+
functionName: "factory",
|
|
25707
|
+
blockNumber
|
|
25708
|
+
}));
|
|
25709
|
+
if (entryFactory !== factory) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", `Algebra entry point factory ${entryFactory} does not match ${factory}.`);
|
|
25710
|
+
return {
|
|
25711
|
+
blockNumber,
|
|
25712
|
+
entryPoint,
|
|
25713
|
+
factory
|
|
25714
|
+
};
|
|
25715
|
+
}
|
|
25716
|
+
async function inspectAlgebraPool(params) {
|
|
25717
|
+
const { publicClient } = params;
|
|
25718
|
+
const deployment = validateAlgebraLifecycleDeployment(params.deployment);
|
|
25719
|
+
const key = canonicalizeAlgebraPoolKey(params.key);
|
|
25720
|
+
const chainId = await publicClient.getChainId();
|
|
25721
|
+
if (chainId !== deployment.chainId) throw new PoolLifecycleError("CHAIN_MISMATCH", `Public client chain ${chainId} does not match Algebra deployment chain ${deployment.chainId}.`);
|
|
25722
|
+
const blockNumber = params.blockNumber ?? await publicClient.getBlockNumber();
|
|
25723
|
+
const factory = getAddress(deployment.factory);
|
|
25724
|
+
await Promise.all([
|
|
25725
|
+
requireCode(publicClient, factory, "Algebra factory", blockNumber),
|
|
25726
|
+
requireCode(publicClient, key.token0, "token0", blockNumber),
|
|
25727
|
+
requireCode(publicClient, key.token1, "token1", blockNumber)
|
|
25728
|
+
]);
|
|
25729
|
+
const factoryAbi = deployment.createPool === "pair-with-plugin-data" ? algebraIntegralPluginDataFactoryAbi : deployment.variant === "integral-v1" ? algebraIntegralPairFactoryAbi : algebraPairFactoryAbi;
|
|
25730
|
+
const [poolRaw, poolDeployerRaw] = await Promise.all([publicClient.readContract({
|
|
25731
|
+
address: factory,
|
|
25732
|
+
abi: factoryAbi,
|
|
25733
|
+
functionName: "poolByPair",
|
|
25734
|
+
args: [key.token0, key.token1],
|
|
25735
|
+
blockNumber
|
|
25736
|
+
}), publicClient.readContract({
|
|
25737
|
+
address: factory,
|
|
25738
|
+
abi: factoryAbi,
|
|
25739
|
+
functionName: "poolDeployer",
|
|
25740
|
+
blockNumber
|
|
25741
|
+
})]);
|
|
25742
|
+
const poolDeployer = getAddress(poolDeployerRaw);
|
|
25743
|
+
if (poolDeployer === ZERO) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", `Algebra factory ${factory} reports a zero pool deployer.`);
|
|
25744
|
+
await requireCode(publicClient, poolDeployer, "Algebra pool deployer", blockNumber);
|
|
25745
|
+
let defaultTickSpacing = null;
|
|
25746
|
+
let defaultFee = null;
|
|
25747
|
+
if (deployment.variant === "integral-v1") {
|
|
25748
|
+
const [tickSpacing, fee] = await Promise.all([publicClient.readContract({
|
|
25749
|
+
address: factory,
|
|
25750
|
+
abi: algebraIntegralPairFactoryAbi,
|
|
25751
|
+
functionName: "defaultTickspacing",
|
|
25752
|
+
blockNumber
|
|
25753
|
+
}), publicClient.readContract({
|
|
25754
|
+
address: factory,
|
|
25755
|
+
abi: algebraIntegralPairFactoryAbi,
|
|
25756
|
+
functionName: "defaultFee",
|
|
25757
|
+
blockNumber
|
|
25758
|
+
})]);
|
|
25759
|
+
defaultTickSpacing = Number(tickSpacing);
|
|
25760
|
+
defaultFee = Number(fee);
|
|
25761
|
+
} else if (deployment.variant === "integral-v2") {
|
|
25762
|
+
const configuration = await publicClient.readContract({
|
|
25763
|
+
address: factory,
|
|
25764
|
+
abi: algebraIntegralPluginDataFactoryAbi,
|
|
25765
|
+
functionName: "defaultConfigurationForPool",
|
|
25766
|
+
blockNumber
|
|
25767
|
+
});
|
|
25768
|
+
defaultTickSpacing = Number(configuration[1]);
|
|
25769
|
+
defaultFee = Number(configuration[2]);
|
|
25770
|
+
}
|
|
25771
|
+
if (defaultTickSpacing !== null && (!Number.isInteger(defaultTickSpacing) || defaultTickSpacing <= 0)) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", `Algebra factory ${factory} reports invalid default tick spacing.`);
|
|
25772
|
+
const poolAddress = getAddress(poolRaw);
|
|
25773
|
+
if (poolAddress === ZERO) return {
|
|
25774
|
+
schemaVersion: 1,
|
|
25775
|
+
blockNumber,
|
|
25776
|
+
deployment,
|
|
25777
|
+
key,
|
|
25778
|
+
status: "absent",
|
|
25779
|
+
poolAddress: null,
|
|
25780
|
+
sqrtPriceX96: 0n,
|
|
25781
|
+
tick: null,
|
|
25782
|
+
tickSpacing: defaultTickSpacing,
|
|
25783
|
+
fee: defaultFee,
|
|
25784
|
+
directionalFee: null,
|
|
25785
|
+
plugin: null,
|
|
25786
|
+
pluginConfig: null,
|
|
25787
|
+
unlocked: null
|
|
25788
|
+
};
|
|
25789
|
+
await requireCode(publicClient, poolAddress, "Algebra pool", blockNumber);
|
|
25790
|
+
const [actualFactoryRaw, token0Raw, token1Raw, tickSpacingRaw] = await Promise.all([
|
|
25791
|
+
publicClient.readContract({
|
|
25792
|
+
address: poolAddress,
|
|
25793
|
+
abi: algebraPoolBaseAbi,
|
|
25794
|
+
functionName: "factory",
|
|
25795
|
+
blockNumber
|
|
25796
|
+
}),
|
|
25797
|
+
publicClient.readContract({
|
|
25798
|
+
address: poolAddress,
|
|
25799
|
+
abi: algebraPoolBaseAbi,
|
|
25800
|
+
functionName: "token0",
|
|
25801
|
+
blockNumber
|
|
25802
|
+
}),
|
|
25803
|
+
publicClient.readContract({
|
|
25804
|
+
address: poolAddress,
|
|
25805
|
+
abi: algebraPoolBaseAbi,
|
|
25806
|
+
functionName: "token1",
|
|
25807
|
+
blockNumber
|
|
25808
|
+
}),
|
|
25809
|
+
publicClient.readContract({
|
|
25810
|
+
address: poolAddress,
|
|
25811
|
+
abi: algebraPoolBaseAbi,
|
|
25812
|
+
functionName: "tickSpacing",
|
|
25813
|
+
blockNumber
|
|
25814
|
+
})
|
|
25815
|
+
]);
|
|
25816
|
+
if (getAddress(actualFactoryRaw) !== factory || getAddress(token0Raw) !== key.token0 || getAddress(token1Raw) !== key.token1) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", `Pool ${poolAddress} does not match the configured Algebra deployment and token pair.`);
|
|
25817
|
+
const tickSpacing = Number(tickSpacingRaw);
|
|
25818
|
+
let sqrtPriceX96;
|
|
25819
|
+
let tick;
|
|
25820
|
+
let fee = null;
|
|
25821
|
+
let directionalFee = null;
|
|
25822
|
+
let plugin = null;
|
|
25823
|
+
let pluginConfig = null;
|
|
25824
|
+
let unlocked;
|
|
25825
|
+
if (deployment.state === "directional-global-state") {
|
|
25826
|
+
const state = await publicClient.readContract({
|
|
25827
|
+
address: poolAddress,
|
|
25828
|
+
abi: algebraDirectionalPoolStateAbi,
|
|
25829
|
+
functionName: "globalState",
|
|
25830
|
+
blockNumber
|
|
25831
|
+
});
|
|
25832
|
+
sqrtPriceX96 = state[0];
|
|
25833
|
+
tick = Number(state[1]);
|
|
25834
|
+
directionalFee = {
|
|
25835
|
+
zeroToOne: Number(state[2]),
|
|
25836
|
+
oneToZero: Number(state[3])
|
|
25837
|
+
};
|
|
25838
|
+
unlocked = state[7];
|
|
25839
|
+
} else if (deployment.state === "integral-global-state") {
|
|
25840
|
+
const [state, pluginRaw] = await Promise.all([publicClient.readContract({
|
|
25841
|
+
address: poolAddress,
|
|
25842
|
+
abi: algebraIntegralPoolStateAbi,
|
|
25843
|
+
functionName: "globalState",
|
|
25844
|
+
blockNumber
|
|
25845
|
+
}), publicClient.readContract({
|
|
25846
|
+
address: poolAddress,
|
|
25847
|
+
abi: algebraIntegralPoolStateAbi,
|
|
25848
|
+
functionName: "plugin",
|
|
25849
|
+
blockNumber
|
|
25850
|
+
})]);
|
|
25851
|
+
sqrtPriceX96 = state[0];
|
|
25852
|
+
tick = Number(state[1]);
|
|
25853
|
+
fee = Number(state[2]);
|
|
25854
|
+
pluginConfig = Number(state[3]);
|
|
25855
|
+
unlocked = state[5];
|
|
25856
|
+
const pluginAddress = getAddress(pluginRaw);
|
|
25857
|
+
plugin = pluginAddress === ZERO ? null : pluginAddress;
|
|
25858
|
+
} else {
|
|
25859
|
+
const state = await publicClient.readContract({
|
|
25860
|
+
address: poolAddress,
|
|
25861
|
+
abi: algebraLegacyPoolStateAbi,
|
|
25862
|
+
functionName: "globalState",
|
|
25863
|
+
blockNumber
|
|
25864
|
+
});
|
|
25865
|
+
sqrtPriceX96 = state[0];
|
|
25866
|
+
tick = Number(state[1]);
|
|
25867
|
+
fee = Number(state[3]);
|
|
25868
|
+
unlocked = state[6];
|
|
25869
|
+
}
|
|
25870
|
+
const uninitializedIntegralPool = deployment.variant.startsWith("integral") && sqrtPriceX96 === 0n && tickSpacing === 0;
|
|
25871
|
+
if (!Number.isInteger(tickSpacing) || tickSpacing <= 0 && !uninitializedIntegralPool) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", `Pool ${poolAddress} reports invalid tick spacing.`);
|
|
25872
|
+
return {
|
|
25873
|
+
schemaVersion: 1,
|
|
25874
|
+
blockNumber,
|
|
25875
|
+
deployment,
|
|
25876
|
+
key,
|
|
25877
|
+
status: sqrtPriceX96 === 0n ? "uninitialized" : "initialized",
|
|
25878
|
+
poolAddress,
|
|
25879
|
+
sqrtPriceX96,
|
|
25880
|
+
tick,
|
|
25881
|
+
tickSpacing,
|
|
25882
|
+
fee,
|
|
25883
|
+
directionalFee,
|
|
25884
|
+
plugin,
|
|
25885
|
+
pluginConfig,
|
|
25886
|
+
unlocked
|
|
25887
|
+
};
|
|
25888
|
+
}
|
|
25889
|
+
//#endregion
|
|
25890
|
+
//#region src/pool-lifecycle/algebra/actions.ts
|
|
25891
|
+
const ZERO_ADDRESS$2 = getAddress("0x0000000000000000000000000000000000000000");
|
|
25892
|
+
function assertPreflight(deployment, key, snapshot) {
|
|
25893
|
+
let matches = false;
|
|
25894
|
+
try {
|
|
25895
|
+
const snapshotDeployment = validateAlgebraLifecycleDeployment(snapshot.deployment);
|
|
25896
|
+
matches = snapshot.schemaVersion === 1 && typeof snapshot.blockNumber === "bigint" && snapshot.blockNumber >= 0n && snapshotDeployment === deployment && snapshot.key.token0 === key.token0 && snapshot.key.token1 === key.token1 && (snapshot.status === "absent" || snapshot.status === "uninitialized" || snapshot.status === "initialized");
|
|
25897
|
+
} catch {}
|
|
25898
|
+
if (!matches) throw new PoolLifecycleError("INVALID_INPUT", "Algebra preflight does not match the requested deployment and token pair.");
|
|
25899
|
+
if (snapshot.status === "absent") {
|
|
25900
|
+
if (snapshot.poolAddress !== null || snapshot.sqrtPriceX96 !== 0n || snapshot.tick !== null) throw new PoolLifecycleError("INVALID_INPUT", "Absent Algebra preflight is inconsistent.");
|
|
25901
|
+
return;
|
|
25902
|
+
}
|
|
25903
|
+
if (!snapshot.poolAddress || getAddress(snapshot.poolAddress) === ZERO_ADDRESS$2) throw new PoolLifecycleError("INVALID_INPUT", "Algebra preflight pool address is invalid.");
|
|
25904
|
+
if (snapshot.status === "uninitialized" && snapshot.sqrtPriceX96 !== 0n) throw new PoolLifecycleError("INVALID_INPUT", "Uninitialized Algebra preflight must have zero sqrtPriceX96.");
|
|
25905
|
+
}
|
|
25906
|
+
function summary(snapshot) {
|
|
25907
|
+
return {
|
|
25908
|
+
blockNumber: snapshot.blockNumber,
|
|
25909
|
+
status: snapshot.status,
|
|
25910
|
+
poolAddress: snapshot.poolAddress,
|
|
25911
|
+
sqrtPriceX96: snapshot.sqrtPriceX96
|
|
25912
|
+
};
|
|
25913
|
+
}
|
|
25914
|
+
function identity$1(deployment, key, poolAddress) {
|
|
25915
|
+
return {
|
|
25916
|
+
family: "algebra",
|
|
25917
|
+
adapter: deployment.adapter,
|
|
25918
|
+
version: deployment.version,
|
|
25919
|
+
variant: deployment.variant,
|
|
25920
|
+
chainId: deployment.chainId,
|
|
25921
|
+
factory: getAddress(deployment.factory),
|
|
25922
|
+
key,
|
|
25923
|
+
poolAddress
|
|
25924
|
+
};
|
|
25925
|
+
}
|
|
25926
|
+
/** Build the version-specific standard-pool factory call without signing it. */
|
|
25927
|
+
function buildAlgebraCreatePoolTransaction(params) {
|
|
25928
|
+
const deployment = validateAlgebraLifecycleDeployment(params.deployment);
|
|
25929
|
+
const key = canonicalizeAlgebraPoolKey(params.key);
|
|
25930
|
+
assertPreflight(deployment, key, params.preflight);
|
|
25931
|
+
if (params.preflight.status !== "absent") throw new PoolLifecycleError("POOL_STATE_MISMATCH", `Algebra pool already exists at ${params.preflight.poolAddress}.`);
|
|
25932
|
+
const pluginData = params.pluginData ?? "0x";
|
|
25933
|
+
if (deployment.createPool === "pair" && pluginData !== "0x") throw new PoolLifecycleError("INVALID_INPUT", `${deployment.variant} pool creation does not accept plugin data.`);
|
|
25934
|
+
const data = deployment.createPool === "pair-with-plugin-data" ? encodeFunctionData({
|
|
25935
|
+
abi: algebraIntegralPluginDataFactoryAbi,
|
|
25936
|
+
functionName: "createPool",
|
|
25937
|
+
args: [
|
|
25938
|
+
key.token0,
|
|
25939
|
+
key.token1,
|
|
25940
|
+
pluginData
|
|
25941
|
+
]
|
|
25942
|
+
}) : encodeFunctionData({
|
|
25943
|
+
abi: deployment.variant === "integral-v1" ? algebraIntegralPairFactoryAbi : algebraPairFactoryAbi,
|
|
25944
|
+
functionName: "createPool",
|
|
25945
|
+
args: [key.token0, key.token1]
|
|
25946
|
+
});
|
|
25947
|
+
return {
|
|
25948
|
+
schemaVersion: 1,
|
|
25949
|
+
kind: "algebra-create",
|
|
25950
|
+
protocol: deployment.protocol,
|
|
25951
|
+
transaction: {
|
|
25952
|
+
chainId: deployment.chainId,
|
|
25953
|
+
to: deployment.factory,
|
|
25954
|
+
data,
|
|
25955
|
+
value: 0n
|
|
25956
|
+
},
|
|
25957
|
+
identity: identity$1(deployment, key, null),
|
|
25958
|
+
expected: {
|
|
25959
|
+
sqrtPriceX96: null,
|
|
25960
|
+
pluginData
|
|
25961
|
+
},
|
|
25962
|
+
preflight: summary(params.preflight)
|
|
25963
|
+
};
|
|
25964
|
+
}
|
|
25965
|
+
/** Build a direct initialization call bound to an inspected, uninitialized pool. */
|
|
25966
|
+
function buildAlgebraInitializePoolTransaction(params) {
|
|
25967
|
+
const deployment = validateAlgebraLifecycleDeployment(params.deployment);
|
|
25968
|
+
const key = canonicalizeAlgebraPoolKey(params.key);
|
|
25969
|
+
const price = assertAlgebraInitialPrice(key, params.initialPrice);
|
|
25970
|
+
assertPreflight(deployment, key, params.preflight);
|
|
25971
|
+
if (params.preflight.status !== "uninitialized" || !params.preflight.poolAddress) throw new PoolLifecycleError("POOL_STATE_MISMATCH", "Algebra initialization requires an inspected, uninitialized factory pool.");
|
|
25972
|
+
const poolAddress = getAddress(params.preflight.poolAddress);
|
|
25973
|
+
return {
|
|
25974
|
+
schemaVersion: 1,
|
|
25975
|
+
kind: "algebra-initialize",
|
|
25976
|
+
protocol: deployment.protocol,
|
|
25977
|
+
transaction: {
|
|
25978
|
+
chainId: deployment.chainId,
|
|
25979
|
+
to: poolAddress,
|
|
25980
|
+
data: encodeFunctionData({
|
|
25981
|
+
abi: algebraPoolBaseAbi,
|
|
25982
|
+
functionName: "initialize",
|
|
25983
|
+
args: [price.sqrtPriceX96]
|
|
25984
|
+
}),
|
|
25985
|
+
value: 0n
|
|
25986
|
+
},
|
|
25987
|
+
identity: identity$1(deployment, key, poolAddress),
|
|
25988
|
+
expected: {
|
|
25989
|
+
sqrtPriceX96: price.sqrtPriceX96,
|
|
25990
|
+
pluginData: null
|
|
25991
|
+
},
|
|
25992
|
+
preflight: summary(params.preflight)
|
|
25993
|
+
};
|
|
25994
|
+
}
|
|
25995
|
+
/**
|
|
25996
|
+
* Prepare the next honest lifecycle step. Creation and initialization remain
|
|
25997
|
+
* separate when the SDK has no proven atomic initializer deployment.
|
|
25998
|
+
*/
|
|
25999
|
+
async function prepareAlgebraPool(params) {
|
|
26000
|
+
const snapshot = await inspectAlgebraPool(params);
|
|
26001
|
+
if (snapshot.status === "absent") return {
|
|
26002
|
+
status: "ready-create",
|
|
26003
|
+
snapshot,
|
|
26004
|
+
action: buildAlgebraCreatePoolTransaction({
|
|
26005
|
+
deployment: snapshot.deployment,
|
|
26006
|
+
key: params.key,
|
|
26007
|
+
preflight: snapshot,
|
|
26008
|
+
pluginData: params.pluginData
|
|
26009
|
+
})
|
|
26010
|
+
};
|
|
26011
|
+
if (snapshot.status === "uninitialized") return {
|
|
26012
|
+
status: "ready-initialize",
|
|
26013
|
+
snapshot,
|
|
26014
|
+
action: buildAlgebraInitializePoolTransaction({
|
|
26015
|
+
deployment: snapshot.deployment,
|
|
26016
|
+
key: params.key,
|
|
26017
|
+
preflight: snapshot,
|
|
26018
|
+
initialPrice: params.initialPrice
|
|
26019
|
+
})
|
|
26020
|
+
};
|
|
26021
|
+
const expected = assertAlgebraInitialPrice(snapshot.key, params.initialPrice);
|
|
26022
|
+
if (snapshot.sqrtPriceX96 !== expected.sqrtPriceX96) throw new PoolLifecycleError("POOL_STATE_MISMATCH", `Algebra pool ${snapshot.poolAddress} is already initialized at a different price.`);
|
|
26023
|
+
return {
|
|
26024
|
+
status: "already-initialized-matching",
|
|
26025
|
+
snapshot,
|
|
26026
|
+
action: null
|
|
26027
|
+
};
|
|
26028
|
+
}
|
|
26029
|
+
//#endregion
|
|
26030
|
+
//#region src/pool-lifecycle/algebra/types.ts
|
|
26031
|
+
function invalid$1(message) {
|
|
26032
|
+
throw new PoolLifecycleError("INVALID_INPUT", message);
|
|
26033
|
+
}
|
|
26034
|
+
function record$1(value, label) {
|
|
26035
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return invalid$1(`${label} must be an object.`);
|
|
26036
|
+
return value;
|
|
26037
|
+
}
|
|
26038
|
+
function address$1(value, label, nullable = false) {
|
|
26039
|
+
if (nullable && value === null) return null;
|
|
26040
|
+
if (typeof value !== "string" || !isAddress(value, { strict: true })) return invalid$1(`${label} must be a valid address.`);
|
|
26041
|
+
const result = getAddress(value);
|
|
26042
|
+
if (result === "0x0000000000000000000000000000000000000000") return invalid$1(`${label} must not be zero.`);
|
|
26043
|
+
return result;
|
|
26044
|
+
}
|
|
26045
|
+
function hex(value, label) {
|
|
26046
|
+
if (typeof value !== "string" || !/^0x(?:[0-9a-fA-F]{2})*$/.test(value)) return invalid$1(`${label} must be hex bytes.`);
|
|
26047
|
+
return value;
|
|
26048
|
+
}
|
|
26049
|
+
function key(value) {
|
|
26050
|
+
const item = record$1(value, "Algebra key");
|
|
26051
|
+
const token0 = address$1(item.token0, "Algebra token0");
|
|
26052
|
+
const token1 = address$1(item.token1, "Algebra token1");
|
|
26053
|
+
if (BigInt(token0) >= BigInt(token1)) return invalid$1("Algebra tokens must be canonically ordered and distinct.");
|
|
26054
|
+
return {
|
|
26055
|
+
token0,
|
|
26056
|
+
token1
|
|
26057
|
+
};
|
|
26058
|
+
}
|
|
26059
|
+
/** Re-derive target and calldata after a plan crosses a UI/CLI/JSON boundary. */
|
|
26060
|
+
function validatePreparedAlgebraPoolAction(value) {
|
|
26061
|
+
const action = record$1(value, "Prepared Algebra action");
|
|
26062
|
+
if (action.schemaVersion !== 1 || action.kind !== "algebra-create" && action.kind !== "algebra-initialize") return invalid$1("Prepared Algebra action kind or schema version is unsupported.");
|
|
26063
|
+
if (typeof action.protocol !== "string") return invalid$1("Algebra action protocol must be a string.");
|
|
26064
|
+
const tx = record$1(action.transaction, "Algebra transaction");
|
|
26065
|
+
if (!Number.isSafeInteger(tx.chainId) || Number(tx.chainId) <= 0) return invalid$1("Algebra chainId must be a positive safe integer.");
|
|
26066
|
+
if (tx.value !== 0n) return invalid$1("Algebra lifecycle transactions must have zero value.");
|
|
26067
|
+
const to = address$1(tx.to, "Algebra transaction target");
|
|
26068
|
+
const data = hex(tx.data, "Algebra calldata");
|
|
26069
|
+
const deployment = resolveAlgebraLifecycleDeployment({
|
|
26070
|
+
chainId: Number(tx.chainId),
|
|
26071
|
+
protocol: action.protocol
|
|
26072
|
+
});
|
|
26073
|
+
if (!deployment) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", `No Algebra lifecycle deployment is configured for chain ${tx.chainId} and protocol ${action.protocol}.`);
|
|
26074
|
+
const identity = record$1(action.identity, "Algebra identity");
|
|
26075
|
+
const poolKey = key(identity.key);
|
|
26076
|
+
if (identity.family !== "algebra" || identity.adapter !== deployment.adapter || identity.version !== deployment.version || identity.variant !== deployment.variant || identity.chainId !== deployment.chainId || address$1(identity.factory, "Algebra identity factory") !== getAddress(deployment.factory)) return invalid$1("Algebra identity does not match the configured deployment.");
|
|
26077
|
+
const expected = record$1(action.expected, "Algebra expectation");
|
|
26078
|
+
const preflight = record$1(action.preflight, "Algebra preflight");
|
|
26079
|
+
if (typeof preflight.blockNumber !== "bigint" || preflight.blockNumber < 0n) return invalid$1("Algebra preflight blockNumber must be a non-negative bigint.");
|
|
26080
|
+
let expectedTo;
|
|
26081
|
+
let expectedData;
|
|
26082
|
+
if (action.kind === "algebra-create") {
|
|
26083
|
+
if (identity.poolAddress !== null || expected.sqrtPriceX96 !== null || preflight.status !== "absent" || preflight.poolAddress !== null || preflight.sqrtPriceX96 !== 0n) return invalid$1("Algebra create cannot bind an existing pool or price.");
|
|
26084
|
+
const pluginData = hex(expected.pluginData, "Algebra plugin data");
|
|
26085
|
+
expectedTo = getAddress(deployment.factory);
|
|
26086
|
+
expectedData = deployment.createPool === "pair-with-plugin-data" ? encodeFunctionData({
|
|
26087
|
+
abi: algebraIntegralPluginDataFactoryAbi,
|
|
26088
|
+
functionName: "createPool",
|
|
26089
|
+
args: [
|
|
26090
|
+
poolKey.token0,
|
|
26091
|
+
poolKey.token1,
|
|
26092
|
+
pluginData
|
|
26093
|
+
]
|
|
26094
|
+
}) : encodeFunctionData({
|
|
26095
|
+
abi: deployment.variant === "integral-v1" ? algebraIntegralPairFactoryAbi : algebraPairFactoryAbi,
|
|
26096
|
+
functionName: "createPool",
|
|
26097
|
+
args: [poolKey.token0, poolKey.token1]
|
|
26098
|
+
});
|
|
26099
|
+
} else {
|
|
26100
|
+
const pool = address$1(identity.poolAddress, "Algebra pool address");
|
|
26101
|
+
if (expected.pluginData !== null || typeof expected.sqrtPriceX96 !== "bigint" || preflight.status !== "uninitialized" || address$1(preflight.poolAddress, "Algebra preflight pool") !== pool || preflight.sqrtPriceX96 !== 0n) return invalid$1("Algebra initialize expectation is invalid.");
|
|
26102
|
+
try {
|
|
26103
|
+
validateSqrtPriceX96(expected.sqrtPriceX96);
|
|
26104
|
+
} catch (error) {
|
|
26105
|
+
return invalid$1(error instanceof Error ? error.message : "Invalid Algebra price.");
|
|
26106
|
+
}
|
|
26107
|
+
expectedTo = pool;
|
|
26108
|
+
expectedData = encodeFunctionData({
|
|
26109
|
+
abi: algebraPoolBaseAbi,
|
|
26110
|
+
functionName: "initialize",
|
|
26111
|
+
args: [expected.sqrtPriceX96]
|
|
26112
|
+
});
|
|
26113
|
+
}
|
|
26114
|
+
if (to !== expectedTo || data.toLowerCase() !== expectedData.toLowerCase()) return invalid$1("Algebra transaction does not match its trusted deployment and expectation.");
|
|
26115
|
+
return deployment;
|
|
26116
|
+
}
|
|
26117
|
+
function deserializePreparedAlgebraPoolAction(serialized) {
|
|
26118
|
+
const action = deserializePreparedPoolAction(serialized);
|
|
26119
|
+
validatePreparedAlgebraPoolAction(action);
|
|
26120
|
+
return action;
|
|
26121
|
+
}
|
|
26122
|
+
//#endregion
|
|
26123
|
+
//#region src/pool-lifecycle/algebra/simulate.ts
|
|
26124
|
+
async function simulateAlgebraPoolAction(params) {
|
|
26125
|
+
if (!isAddress(params.account, { strict: true }) || getAddress(params.account) === "0x0000000000000000000000000000000000000000") throw new PoolLifecycleError("INVALID_INPUT", "Simulation account must be a valid non-zero address.");
|
|
26126
|
+
const deployment = validatePreparedAlgebraPoolAction(params.action);
|
|
26127
|
+
const blockNumber = params.blockNumber ?? await params.publicClient.getBlockNumber();
|
|
26128
|
+
const snapshot = await inspectAlgebraPool({
|
|
26129
|
+
publicClient: params.publicClient,
|
|
26130
|
+
deployment,
|
|
26131
|
+
key: {
|
|
26132
|
+
tokenA: params.action.identity.key.token0,
|
|
26133
|
+
tokenB: params.action.identity.key.token1
|
|
26134
|
+
},
|
|
26135
|
+
blockNumber
|
|
26136
|
+
});
|
|
26137
|
+
if (params.action.kind === "algebra-create" && snapshot.status !== "absent") throw new PoolLifecycleError("POOL_STATE_MISMATCH", `Algebra pool already exists at ${snapshot.poolAddress}; refresh the action.`);
|
|
26138
|
+
if (params.action.kind === "algebra-initialize" && (snapshot.status !== "uninitialized" || snapshot.poolAddress !== params.action.identity.poolAddress)) throw new PoolLifecycleError("POOL_STATE_MISMATCH", "Algebra pool is no longer the uninitialized factory pool bound to this action.");
|
|
26139
|
+
const request = {
|
|
26140
|
+
account: getAddress(params.account),
|
|
26141
|
+
to: params.action.transaction.to,
|
|
26142
|
+
data: params.action.transaction.data,
|
|
26143
|
+
value: params.action.transaction.value,
|
|
26144
|
+
blockNumber
|
|
26145
|
+
};
|
|
26146
|
+
try {
|
|
26147
|
+
const [call, gasEstimate] = await Promise.all([params.publicClient.call({
|
|
26148
|
+
...request,
|
|
26149
|
+
batch: false
|
|
26150
|
+
}), params.publicClient.estimateGas(request)]);
|
|
26151
|
+
let returnedPoolAddress = null;
|
|
26152
|
+
if (params.action.kind === "algebra-create") {
|
|
26153
|
+
if (!call.data || call.data === "0x") throw new PoolLifecycleError("SIMULATION_FAILED", "Algebra create returned no pool address.");
|
|
26154
|
+
returnedPoolAddress = getAddress(decodeFunctionResult({
|
|
26155
|
+
abi: deployment.createPool === "pair-with-plugin-data" ? algebraIntegralPluginDataFactoryAbi : deployment.variant === "integral-v1" ? algebraIntegralPairFactoryAbi : algebraPairFactoryAbi,
|
|
26156
|
+
functionName: "createPool",
|
|
26157
|
+
data: call.data
|
|
26158
|
+
}));
|
|
26159
|
+
if (returnedPoolAddress === "0x0000000000000000000000000000000000000000") throw new PoolLifecycleError("SIMULATION_FAILED", "Algebra create simulation returned the zero pool address.");
|
|
26160
|
+
}
|
|
26161
|
+
return {
|
|
26162
|
+
transaction: params.action.transaction,
|
|
26163
|
+
blockNumber,
|
|
26164
|
+
returnData: call.data ?? null,
|
|
26165
|
+
returnedPoolAddress,
|
|
26166
|
+
gasEstimate
|
|
26167
|
+
};
|
|
26168
|
+
} catch (error) {
|
|
26169
|
+
if (error instanceof PoolLifecycleError) throw error;
|
|
26170
|
+
throw new PoolLifecycleError("SIMULATION_FAILED", error instanceof Error ? error.message : "Algebra simulation failed.", error);
|
|
26171
|
+
}
|
|
26172
|
+
}
|
|
26173
|
+
//#endregion
|
|
26174
|
+
//#region src/pool-lifecycle/algebra/verify.ts
|
|
26175
|
+
function assertReceiptLog(log, receipt) {
|
|
26176
|
+
if (log.transactionHash !== receipt.transactionHash || log.blockHash !== receipt.blockHash || log.blockNumber !== receipt.blockNumber || log.transactionIndex !== receipt.transactionIndex || log.removed !== false) throw new PoolLifecycleError("POOL_STATE_MISMATCH", "Algebra lifecycle log does not belong to the canonical receipt.");
|
|
26177
|
+
}
|
|
26178
|
+
function decodeAlgebraPoolActionReceipt(action, receipt) {
|
|
26179
|
+
validatePreparedAlgebraPoolAction(action);
|
|
26180
|
+
const created = [];
|
|
26181
|
+
const initialized = [];
|
|
26182
|
+
for (const log of receipt.logs) {
|
|
26183
|
+
if (getAddress(log.address) === action.identity.factory) try {
|
|
26184
|
+
const decoded = decodeEventLog({
|
|
26185
|
+
abi: algebraPairFactoryAbi,
|
|
26186
|
+
eventName: "Pool",
|
|
26187
|
+
data: log.data,
|
|
26188
|
+
topics: log.topics
|
|
26189
|
+
});
|
|
26190
|
+
if (getAddress(decoded.args.token0) === action.identity.key.token0 && getAddress(decoded.args.token1) === action.identity.key.token1) {
|
|
26191
|
+
assertReceiptLog(log, receipt);
|
|
26192
|
+
created.push({
|
|
26193
|
+
poolAddress: getAddress(decoded.args.pool),
|
|
26194
|
+
logIndex: log.logIndex
|
|
26195
|
+
});
|
|
26196
|
+
}
|
|
26197
|
+
} catch (error) {
|
|
26198
|
+
if (error instanceof PoolLifecycleError) throw error;
|
|
26199
|
+
}
|
|
26200
|
+
if (action.kind !== "algebra-initialize" || action.identity.poolAddress === null || getAddress(log.address) !== action.identity.poolAddress) continue;
|
|
26201
|
+
try {
|
|
26202
|
+
const decoded = decodeEventLog({
|
|
26203
|
+
abi: algebraPoolBaseAbi,
|
|
26204
|
+
eventName: "Initialize",
|
|
26205
|
+
data: log.data,
|
|
26206
|
+
topics: log.topics
|
|
26207
|
+
});
|
|
26208
|
+
assertReceiptLog(log, receipt);
|
|
26209
|
+
initialized.push({
|
|
26210
|
+
poolAddress: getAddress(log.address),
|
|
26211
|
+
sqrtPriceX96: decoded.args.price,
|
|
26212
|
+
tick: Number(decoded.args.tick),
|
|
26213
|
+
logIndex: log.logIndex
|
|
26214
|
+
});
|
|
26215
|
+
} catch (error) {
|
|
26216
|
+
if (error instanceof PoolLifecycleError) throw error;
|
|
26217
|
+
}
|
|
26218
|
+
}
|
|
26219
|
+
if (created.length > 1 || initialized.length > 1) throw new PoolLifecycleError("POOL_STATE_MISMATCH", "Receipt contains duplicate matching Algebra lifecycle events.");
|
|
26220
|
+
return {
|
|
26221
|
+
receiptStatus: receipt.status,
|
|
26222
|
+
poolCreated: created[0] ?? null,
|
|
26223
|
+
initialization: initialized[0] ?? null
|
|
26224
|
+
};
|
|
26225
|
+
}
|
|
26226
|
+
function result(action, evidence, snapshot, blockNumber) {
|
|
26227
|
+
const identity = {
|
|
26228
|
+
...action.identity,
|
|
26229
|
+
poolAddress: snapshot?.poolAddress ?? action.identity.poolAddress
|
|
26230
|
+
};
|
|
26231
|
+
if (evidence.receiptStatus === "reverted") return {
|
|
26232
|
+
verified: false,
|
|
26233
|
+
outcome: "reverted",
|
|
26234
|
+
blockNumber,
|
|
26235
|
+
identity,
|
|
26236
|
+
state: snapshot,
|
|
26237
|
+
evidence,
|
|
26238
|
+
warnings: []
|
|
26239
|
+
};
|
|
26240
|
+
if (!snapshot || snapshot.status === "absent" || !snapshot.poolAddress) return {
|
|
26241
|
+
verified: false,
|
|
26242
|
+
outcome: "not-initialized",
|
|
26243
|
+
blockNumber,
|
|
26244
|
+
identity,
|
|
26245
|
+
state: snapshot,
|
|
26246
|
+
evidence,
|
|
26247
|
+
warnings: []
|
|
26248
|
+
};
|
|
26249
|
+
if (action.kind === "algebra-create") {
|
|
26250
|
+
if (!evidence.poolCreated || evidence.poolCreated.poolAddress !== snapshot.poolAddress) return {
|
|
26251
|
+
verified: false,
|
|
26252
|
+
outcome: "wrong-deployment",
|
|
26253
|
+
blockNumber,
|
|
26254
|
+
identity,
|
|
26255
|
+
state: snapshot,
|
|
26256
|
+
evidence,
|
|
26257
|
+
warnings: ["Pool event does not match the factory pool at the receipt block."]
|
|
26258
|
+
};
|
|
26259
|
+
return {
|
|
26260
|
+
verified: true,
|
|
26261
|
+
outcome: "created",
|
|
26262
|
+
blockNumber,
|
|
26263
|
+
identity,
|
|
26264
|
+
state: snapshot,
|
|
26265
|
+
evidence,
|
|
26266
|
+
warnings: snapshot.status === "initialized" ? ["Pool was initialized by another call in the same block."] : []
|
|
26267
|
+
};
|
|
26268
|
+
}
|
|
26269
|
+
const initialization = evidence.initialization;
|
|
26270
|
+
if (!initialization || initialization.poolAddress !== snapshot.poolAddress) return {
|
|
26271
|
+
verified: false,
|
|
26272
|
+
outcome: "not-initialized",
|
|
26273
|
+
blockNumber,
|
|
26274
|
+
identity,
|
|
26275
|
+
state: snapshot,
|
|
26276
|
+
evidence,
|
|
26277
|
+
warnings: ["Receipt contains no Initialize event for the expected Algebra pool."]
|
|
26278
|
+
};
|
|
26279
|
+
if (initialization.sqrtPriceX96 !== action.expected.sqrtPriceX96) return {
|
|
26280
|
+
verified: false,
|
|
26281
|
+
outcome: "already-initialized-different-price",
|
|
26282
|
+
blockNumber,
|
|
26283
|
+
identity,
|
|
26284
|
+
state: snapshot,
|
|
26285
|
+
evidence,
|
|
26286
|
+
warnings: ["Initialize event used a different price."]
|
|
26287
|
+
};
|
|
26288
|
+
if (snapshot.status !== "initialized") return {
|
|
26289
|
+
verified: false,
|
|
26290
|
+
outcome: "not-initialized",
|
|
26291
|
+
blockNumber,
|
|
26292
|
+
identity,
|
|
26293
|
+
state: snapshot,
|
|
26294
|
+
evidence,
|
|
26295
|
+
warnings: []
|
|
26296
|
+
};
|
|
26297
|
+
if (snapshot.sqrtPriceX96 !== action.expected.sqrtPriceX96) return {
|
|
26298
|
+
verified: true,
|
|
26299
|
+
outcome: "initialized-then-price-moved",
|
|
26300
|
+
blockNumber,
|
|
26301
|
+
identity,
|
|
26302
|
+
state: snapshot,
|
|
26303
|
+
evidence,
|
|
26304
|
+
warnings: ["Pool price moved after initialization in the receipt block."]
|
|
26305
|
+
};
|
|
26306
|
+
return {
|
|
26307
|
+
verified: true,
|
|
26308
|
+
outcome: "initialized-existing",
|
|
26309
|
+
blockNumber,
|
|
26310
|
+
identity,
|
|
26311
|
+
state: snapshot,
|
|
26312
|
+
evidence,
|
|
26313
|
+
warnings: []
|
|
26314
|
+
};
|
|
26315
|
+
}
|
|
26316
|
+
function unavailable$1(action, receipt, warning) {
|
|
26317
|
+
return {
|
|
26318
|
+
verified: false,
|
|
26319
|
+
outcome: "verification-unavailable",
|
|
26320
|
+
blockNumber: receipt.blockNumber,
|
|
26321
|
+
identity: action.identity,
|
|
26322
|
+
state: null,
|
|
26323
|
+
evidence: {
|
|
26324
|
+
receiptStatus: receipt.status,
|
|
26325
|
+
poolCreated: null,
|
|
26326
|
+
initialization: null
|
|
26327
|
+
},
|
|
26328
|
+
warnings: [warning]
|
|
26329
|
+
};
|
|
26330
|
+
}
|
|
26331
|
+
async function verifyAlgebraPoolAction(params) {
|
|
26332
|
+
const deployment = validatePreparedAlgebraPoolAction(params.action);
|
|
26333
|
+
let chainId;
|
|
26334
|
+
let transaction;
|
|
26335
|
+
let receipt;
|
|
26336
|
+
try {
|
|
26337
|
+
[chainId, transaction, receipt] = await Promise.all([
|
|
26338
|
+
params.publicClient.getChainId(),
|
|
26339
|
+
params.publicClient.getTransaction({ hash: params.receipt.transactionHash }),
|
|
26340
|
+
params.publicClient.getTransactionReceipt({ hash: params.receipt.transactionHash })
|
|
26341
|
+
]);
|
|
26342
|
+
} catch (error) {
|
|
26343
|
+
return unavailable$1(params.action, params.receipt, error instanceof Error ? error.message : "Could not load canonical transaction evidence.");
|
|
26344
|
+
}
|
|
26345
|
+
const expectedTarget = getAddress(params.action.transaction.to);
|
|
26346
|
+
if (!(chainId === params.action.transaction.chainId && params.receipt.transactionHash === receipt.transactionHash && params.receipt.blockHash === receipt.blockHash && params.receipt.blockNumber === receipt.blockNumber && params.receipt.transactionIndex === receipt.transactionIndex && params.receipt.status === receipt.status && receipt.to !== null && getAddress(receipt.to) === expectedTarget && transaction.to !== null && getAddress(transaction.to) === expectedTarget && transaction.hash === params.receipt.transactionHash && transaction.hash === receipt.transactionHash && transaction.input.toLowerCase() === params.action.transaction.data.toLowerCase() && transaction.value === params.action.transaction.value && transaction.blockHash === receipt.blockHash && transaction.blockNumber === receipt.blockNumber && transaction.transactionIndex === receipt.transactionIndex && getAddress(transaction.from) === getAddress(receipt.from))) return {
|
|
26347
|
+
...unavailable$1(params.action, receipt, "Receipt, transaction, client, or prepared action do not match."),
|
|
26348
|
+
outcome: "wrong-deployment"
|
|
26349
|
+
};
|
|
26350
|
+
let evidence;
|
|
26351
|
+
try {
|
|
26352
|
+
evidence = decodeAlgebraPoolActionReceipt(params.action, receipt);
|
|
26353
|
+
} catch (error) {
|
|
26354
|
+
return {
|
|
26355
|
+
...unavailable$1(params.action, receipt, error instanceof Error ? error.message : "Receipt evidence is invalid."),
|
|
26356
|
+
outcome: "wrong-deployment"
|
|
26357
|
+
};
|
|
26358
|
+
}
|
|
26359
|
+
try {
|
|
26360
|
+
if ((await params.publicClient.getBlock({
|
|
26361
|
+
blockNumber: receipt.blockNumber,
|
|
26362
|
+
includeTransactions: false
|
|
26363
|
+
})).hash !== receipt.blockHash) return unavailable$1(params.action, receipt, "Receipt block is no longer canonical.");
|
|
26364
|
+
if (receipt.status === "reverted") return result(params.action, evidence, null, receipt.blockNumber);
|
|
26365
|
+
const snapshot = await inspectAlgebraPool({
|
|
26366
|
+
publicClient: params.publicClient,
|
|
26367
|
+
deployment,
|
|
26368
|
+
key: {
|
|
26369
|
+
tokenA: params.action.identity.key.token0,
|
|
26370
|
+
tokenB: params.action.identity.key.token1
|
|
26371
|
+
},
|
|
26372
|
+
blockNumber: receipt.blockNumber
|
|
26373
|
+
});
|
|
26374
|
+
if ((await params.publicClient.getBlock({
|
|
26375
|
+
blockNumber: receipt.blockNumber,
|
|
26376
|
+
includeTransactions: false
|
|
26377
|
+
})).hash !== receipt.blockHash) return unavailable$1(params.action, receipt, "Receipt block changed during verification.");
|
|
26378
|
+
return result(params.action, evidence, snapshot, receipt.blockNumber);
|
|
26379
|
+
} catch (error) {
|
|
26380
|
+
if (error instanceof PoolLifecycleError) return {
|
|
26381
|
+
...unavailable$1(params.action, receipt, error.message),
|
|
26382
|
+
outcome: "wrong-deployment",
|
|
26383
|
+
evidence
|
|
26384
|
+
};
|
|
26385
|
+
return {
|
|
26386
|
+
...unavailable$1(params.action, receipt, error instanceof Error ? error.message : "Pool state verification failed."),
|
|
26387
|
+
evidence
|
|
26388
|
+
};
|
|
26389
|
+
}
|
|
26390
|
+
}
|
|
26391
|
+
//#endregion
|
|
26392
|
+
//#region src/pool-lifecycle/v3/types.ts
|
|
26393
|
+
function invalidPreparedAction(message) {
|
|
26394
|
+
throw new PoolLifecycleError("INVALID_INPUT", message);
|
|
26395
|
+
}
|
|
26396
|
+
function asRecord(value, label) {
|
|
26397
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return invalidPreparedAction(`${label} must be an object.`);
|
|
26398
|
+
return value;
|
|
26399
|
+
}
|
|
26400
|
+
function asAddress(value, label, allowZero = false) {
|
|
26401
|
+
if (typeof value !== "string" || !isAddress(value, { strict: true })) return invalidPreparedAction(`${label} must be a valid EVM address.`);
|
|
26402
|
+
const address = getAddress(value);
|
|
26403
|
+
if (!allowZero && address === "0x0000000000000000000000000000000000000000") return invalidPreparedAction(`${label} must not be the zero address.`);
|
|
26404
|
+
return address;
|
|
26405
|
+
}
|
|
26406
|
+
function asNullableAddress(value, label) {
|
|
26407
|
+
return value === null ? null : asAddress(value, label);
|
|
26408
|
+
}
|
|
26409
|
+
function asNonNegativeBigInt(value, label) {
|
|
26410
|
+
if (typeof value !== "bigint" || value < 0n) return invalidPreparedAction(`${label} must be a non-negative bigint.`);
|
|
26411
|
+
return value;
|
|
26412
|
+
}
|
|
26413
|
+
function asPoolKey(value) {
|
|
26414
|
+
const key = asRecord(value, "V3 action identity key");
|
|
26415
|
+
const token0 = asAddress(key.token0, "V3 action token0");
|
|
26416
|
+
const token1 = asAddress(key.token1, "V3 action token1");
|
|
26417
|
+
if (BigInt(token0) >= BigInt(token1)) return invalidPreparedAction("V3 action tokens must be distinct and canonically ordered.");
|
|
26418
|
+
if (!Number.isSafeInteger(key.fee) || Number(key.fee) < 0 || Number(key.fee) >= 1e6) return invalidPreparedAction("V3 action fee must be an integer from 0 through 999999.");
|
|
26419
|
+
return {
|
|
26420
|
+
token0,
|
|
26421
|
+
token1,
|
|
26422
|
+
fee: Number(key.fee)
|
|
26423
|
+
};
|
|
26424
|
+
}
|
|
26425
|
+
function asExpectedSqrtPrice(value) {
|
|
26426
|
+
const sqrtPriceX96 = asNonNegativeBigInt(value, "V3 action expected sqrtPriceX96");
|
|
26427
|
+
try {
|
|
26428
|
+
return validateSqrtPriceX96(sqrtPriceX96);
|
|
26429
|
+
} catch (error) {
|
|
26430
|
+
return invalidPreparedAction(error instanceof Error ? error.message : "V3 action expected sqrtPriceX96 is invalid.");
|
|
26431
|
+
}
|
|
26432
|
+
}
|
|
26433
|
+
function validatePreflight(value) {
|
|
26434
|
+
const preflight = asRecord(value, "V3 action preflight");
|
|
26435
|
+
const blockNumber = asNonNegativeBigInt(preflight.blockNumber, "V3 preflight blockNumber");
|
|
26436
|
+
const sqrtPriceX96 = asNonNegativeBigInt(preflight.sqrtPriceX96, "V3 preflight sqrtPriceX96");
|
|
26437
|
+
if (preflight.status === "absent") {
|
|
26438
|
+
if (preflight.poolAddress !== null || sqrtPriceX96 !== 0n) return invalidPreparedAction("An absent V3 preflight must have no pool and zero price.");
|
|
26439
|
+
return {
|
|
26440
|
+
blockNumber,
|
|
26441
|
+
status: "absent",
|
|
26442
|
+
poolAddress: null,
|
|
26443
|
+
sqrtPriceX96: 0n
|
|
26444
|
+
};
|
|
26445
|
+
}
|
|
26446
|
+
const poolAddress = asAddress(preflight.poolAddress, "V3 preflight poolAddress");
|
|
26447
|
+
if (preflight.status === "uninitialized") {
|
|
26448
|
+
if (sqrtPriceX96 !== 0n) return invalidPreparedAction("An uninitialized V3 preflight must have zero price.");
|
|
26449
|
+
return {
|
|
26450
|
+
blockNumber,
|
|
26451
|
+
status: "uninitialized",
|
|
26452
|
+
poolAddress,
|
|
26453
|
+
sqrtPriceX96: 0n
|
|
26454
|
+
};
|
|
26455
|
+
}
|
|
26456
|
+
if (preflight.status === "initialized") {
|
|
26457
|
+
asExpectedSqrtPrice(sqrtPriceX96);
|
|
26458
|
+
return {
|
|
26459
|
+
blockNumber,
|
|
26460
|
+
status: "initialized",
|
|
26461
|
+
poolAddress,
|
|
26462
|
+
sqrtPriceX96
|
|
26463
|
+
};
|
|
26464
|
+
}
|
|
26465
|
+
return invalidPreparedAction("V3 action preflight status is unsupported.");
|
|
26466
|
+
}
|
|
26467
|
+
/**
|
|
26468
|
+
* Runtime validation for plans crossing JSON, UI/CLI, or signer boundaries.
|
|
26469
|
+
* It re-derives the exact target, value, and calldata from trusted capability
|
|
26470
|
+
* metadata plus the declared kind, key, and expectation.
|
|
26471
|
+
*/
|
|
26472
|
+
function validatePreparedV3PoolAction(value) {
|
|
26473
|
+
const action = asRecord(value, "Prepared V3 pool action");
|
|
26474
|
+
if (action.schemaVersion !== 1) return invalidPreparedAction("Prepared V3 pool action schemaVersion is unsupported.");
|
|
26475
|
+
if (action.kind !== "v3-create" && action.kind !== "v3-initialize" && action.kind !== "v3-create-and-initialize") return invalidPreparedAction("Prepared V3 pool action kind is unsupported.");
|
|
26476
|
+
const transaction = asRecord(action.transaction, "V3 action transaction");
|
|
26477
|
+
if (!Number.isSafeInteger(transaction.chainId) || Number(transaction.chainId) <= 0) return invalidPreparedAction("V3 action chainId must be a positive safe integer.");
|
|
26478
|
+
const chainId = Number(transaction.chainId);
|
|
26479
|
+
const to = asAddress(transaction.to, "V3 action transaction target");
|
|
26480
|
+
if (typeof transaction.data !== "string" || !/^0x(?:[0-9a-fA-F]{2})+$/.test(transaction.data)) return invalidPreparedAction("V3 action calldata must be non-empty hex bytes.");
|
|
26481
|
+
if (transaction.value !== 0n) return invalidPreparedAction("V3 pool lifecycle transactions must have zero value.");
|
|
26482
|
+
if (typeof action.protocol !== "string") return invalidPreparedAction("V3 action protocol must be a string.");
|
|
26483
|
+
const deployment = resolveV3LifecycleDeployment({
|
|
26484
|
+
chainId,
|
|
26485
|
+
protocol: action.protocol
|
|
26486
|
+
});
|
|
26487
|
+
if (!deployment) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", `No pool lifecycle deployment is configured for chain ${chainId} and protocol ${action.protocol}.`);
|
|
26488
|
+
const identity = asRecord(action.identity, "V3 action identity");
|
|
26489
|
+
const key = asPoolKey(identity.key);
|
|
26490
|
+
if (identity.family !== deployment.family || identity.adapter !== deployment.adapter || identity.version !== deployment.version || identity.chainId !== chainId || asAddress(identity.factory, "V3 action factory") !== getAddress(deployment.factory) || asNullableAddress(identity.initializer, "V3 action initializer") !== (deployment.initializer === null ? null : getAddress(deployment.initializer))) return invalidPreparedAction("V3 action identity does not match the configured deployment.");
|
|
26491
|
+
const expected = asRecord(action.expected, "V3 action expectation");
|
|
26492
|
+
const preflight = validatePreflight(action.preflight);
|
|
26493
|
+
let expectedTo;
|
|
26494
|
+
let expectedData;
|
|
26495
|
+
if (action.kind === "v3-create") {
|
|
26496
|
+
if (expected.sqrtPriceX96 !== null || identity.poolAddress !== null) return invalidPreparedAction("A V3 create action must expect no price and no existing pool.");
|
|
26497
|
+
if (preflight.status !== "absent") return invalidPreparedAction("A V3 create action requires an inspected absent-pool preflight.");
|
|
26498
|
+
expectedTo = getAddress(deployment.factory);
|
|
26499
|
+
expectedData = encodeFunctionData({
|
|
26500
|
+
abi: v3FactoryAbi,
|
|
26501
|
+
functionName: "createPool",
|
|
26502
|
+
args: [
|
|
26503
|
+
key.token0,
|
|
26504
|
+
key.token1,
|
|
26505
|
+
key.fee
|
|
26506
|
+
]
|
|
26507
|
+
});
|
|
26508
|
+
} else {
|
|
26509
|
+
const sqrtPriceX96 = asExpectedSqrtPrice(expected.sqrtPriceX96);
|
|
26510
|
+
if (action.kind === "v3-initialize") {
|
|
26511
|
+
const poolAddress = asAddress(identity.poolAddress, "V3 initialize poolAddress");
|
|
26512
|
+
if (preflight.status !== "uninitialized" || preflight.poolAddress !== poolAddress) return invalidPreparedAction("A V3 initialize action requires a matching uninitialized preflight.");
|
|
26513
|
+
expectedTo = poolAddress;
|
|
26514
|
+
expectedData = encodeFunctionData({
|
|
26515
|
+
abi: v3PoolAbi,
|
|
26516
|
+
functionName: "initialize",
|
|
26517
|
+
args: [sqrtPriceX96]
|
|
26518
|
+
});
|
|
26519
|
+
} else {
|
|
26520
|
+
if (!deployment.atomicCreateAndInitialize) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", `V3 deployment ${chainId}:${action.protocol} has no configured atomic initializer.`);
|
|
26521
|
+
const poolAddress = identity.poolAddress === null ? null : asAddress(identity.poolAddress, "V3 create-and-initialize poolAddress");
|
|
26522
|
+
if (preflight.status === "initialized") return invalidPreparedAction("A V3 create-and-initialize action requires an absent or uninitialized preflight.");
|
|
26523
|
+
if (preflight.status === "absent" && poolAddress !== null || preflight.status === "uninitialized" && preflight.poolAddress !== poolAddress) return invalidPreparedAction("V3 create-and-initialize identity does not match its preflight.");
|
|
26524
|
+
expectedTo = getAddress(deployment.initializer);
|
|
26525
|
+
expectedData = encodeFunctionData({
|
|
26526
|
+
abi: v3PoolInitializerAbi,
|
|
26527
|
+
functionName: "createAndInitializePoolIfNecessary",
|
|
26528
|
+
args: [
|
|
26529
|
+
key.token0,
|
|
26530
|
+
key.token1,
|
|
26531
|
+
key.fee,
|
|
26532
|
+
sqrtPriceX96
|
|
26533
|
+
]
|
|
26534
|
+
});
|
|
26535
|
+
}
|
|
26536
|
+
}
|
|
26537
|
+
if (to !== expectedTo || transaction.data.toLowerCase() !== expectedData.toLowerCase()) return invalidPreparedAction("V3 action transaction does not match its kind, identity, and expectation.");
|
|
26538
|
+
return deployment;
|
|
26539
|
+
}
|
|
26540
|
+
/** Assertion-form companion for consumers that need TypeScript narrowing. */
|
|
26541
|
+
function assertPreparedV3PoolAction(value) {
|
|
26542
|
+
validatePreparedV3PoolAction(value);
|
|
26543
|
+
}
|
|
26544
|
+
/** Deserialize and fully validate a versioned V3 prepared action. */
|
|
26545
|
+
function deserializePreparedV3PoolAction(serialized) {
|
|
26546
|
+
let value;
|
|
26547
|
+
try {
|
|
26548
|
+
value = deserializePreparedPoolAction(serialized);
|
|
26549
|
+
} catch (error) {
|
|
26550
|
+
throw new PoolLifecycleError("INVALID_INPUT", error instanceof Error ? error.message : "Serialized V3 pool action is invalid.", error);
|
|
26551
|
+
}
|
|
26552
|
+
assertPreparedV3PoolAction(value);
|
|
26553
|
+
return value;
|
|
26554
|
+
}
|
|
26555
|
+
//#endregion
|
|
26556
|
+
//#region src/pool-lifecycle/v3/key.ts
|
|
26557
|
+
const MAX_V3_FEE = 1e6;
|
|
26558
|
+
/** Validate and canonicalize a V3 key without assuming a hard-coded fee tier. */
|
|
26559
|
+
function canonicalizeV3PoolKey(input) {
|
|
26560
|
+
if (!Number.isSafeInteger(input.fee) || input.fee < 0 || input.fee >= MAX_V3_FEE) throw new PoolLifecycleError("INVALID_INPUT", "V3 fee must be an integer from 0 through 999999; deployment support is checked onchain.");
|
|
26561
|
+
let pair;
|
|
26562
|
+
try {
|
|
26563
|
+
pair = sortErc20Pair(input.tokenA, input.tokenB);
|
|
26564
|
+
} catch (error) {
|
|
26565
|
+
throw new PoolLifecycleError("INVALID_INPUT", error instanceof Error ? error.message : "Invalid V3 token pair.", error);
|
|
26566
|
+
}
|
|
26567
|
+
return {
|
|
26568
|
+
...pair,
|
|
26569
|
+
fee: input.fee
|
|
26570
|
+
};
|
|
26571
|
+
}
|
|
26572
|
+
/** Ensure an initial price is bound to the same canonical token pair as a V3 key. */
|
|
26573
|
+
function assertV3InitialPrice(key, price) {
|
|
26574
|
+
try {
|
|
26575
|
+
if (getAddress(price.token0) !== key.token0 || getAddress(price.token1) !== key.token1) throw new Error("Initial price token order does not match the canonical V3 pool key.");
|
|
26576
|
+
validateSqrtPriceX96(price.sqrtPriceX96);
|
|
26577
|
+
} catch (error) {
|
|
26578
|
+
throw new PoolLifecycleError("INVALID_INPUT", error instanceof Error ? error.message : "Invalid V3 initial price.", error);
|
|
26579
|
+
}
|
|
26580
|
+
return {
|
|
26581
|
+
token0: key.token0,
|
|
26582
|
+
token1: key.token1,
|
|
26583
|
+
sqrtPriceX96: price.sqrtPriceX96
|
|
26584
|
+
};
|
|
26585
|
+
}
|
|
26586
|
+
//#endregion
|
|
26587
|
+
//#region src/pool-lifecycle/v3/inspect.ts
|
|
26588
|
+
const ZERO_ADDRESS$1 = getAddress("0x0000000000000000000000000000000000000000");
|
|
26589
|
+
function hasCode$1(bytecode) {
|
|
26590
|
+
return bytecode !== void 0 && bytecode !== "0x";
|
|
26591
|
+
}
|
|
26592
|
+
async function requireContractCode$1(publicClient, address, label, blockNumber) {
|
|
26593
|
+
if (!hasCode$1(await publicClient.getCode({
|
|
26594
|
+
address,
|
|
26595
|
+
blockNumber
|
|
26596
|
+
}))) throw new PoolLifecycleError("CONTRACT_NOT_DEPLOYED", `${label} ${address} has no bytecode at block ${blockNumber}.`);
|
|
26597
|
+
}
|
|
26598
|
+
/**
|
|
26599
|
+
* Read a block-consistent V3 deployment and pool snapshot before building or
|
|
26600
|
+
* verifying a lifecycle transaction.
|
|
26601
|
+
*/
|
|
26602
|
+
async function inspectV3Pool(params) {
|
|
26603
|
+
const { publicClient, deployment } = params;
|
|
26604
|
+
const key = canonicalizeV3PoolKey(params.key);
|
|
26605
|
+
const activeChainId = await publicClient.getChainId();
|
|
26606
|
+
if (activeChainId !== deployment.chainId) throw new PoolLifecycleError("CHAIN_MISMATCH", `Public client chain ${activeChainId} does not match lifecycle deployment chain ${deployment.chainId}.`);
|
|
26607
|
+
const blockNumber = params.blockNumber ?? await publicClient.getBlockNumber();
|
|
26608
|
+
const factory = getAddress(deployment.factory);
|
|
26609
|
+
await Promise.all([
|
|
26610
|
+
requireContractCode$1(publicClient, factory, "V3 factory", blockNumber),
|
|
26611
|
+
...deployment.atomicCreateAndInitialize ? [requireContractCode$1(publicClient, getAddress(deployment.initializer), "V3 initializer", blockNumber)] : [],
|
|
26612
|
+
requireContractCode$1(publicClient, key.token0, "token0", blockNumber),
|
|
26613
|
+
requireContractCode$1(publicClient, key.token1, "token1", blockNumber)
|
|
26614
|
+
]);
|
|
26615
|
+
const [initializerFactoryResult, feeTickSpacingResult, poolResult] = await Promise.all([
|
|
26616
|
+
deployment.atomicCreateAndInitialize ? publicClient.readContract({
|
|
26617
|
+
address: getAddress(deployment.initializer),
|
|
26618
|
+
abi: v3PoolInitializerAbi,
|
|
26619
|
+
functionName: "factory",
|
|
26620
|
+
blockNumber
|
|
26621
|
+
}) : Promise.resolve(null),
|
|
26622
|
+
publicClient.readContract({
|
|
26623
|
+
address: factory,
|
|
26624
|
+
abi: v3FactoryAbi,
|
|
26625
|
+
functionName: "feeAmountTickSpacing",
|
|
26626
|
+
args: [key.fee],
|
|
26627
|
+
blockNumber
|
|
26628
|
+
}),
|
|
26629
|
+
publicClient.readContract({
|
|
26630
|
+
address: factory,
|
|
26631
|
+
abi: v3FactoryAbi,
|
|
26632
|
+
functionName: "getPool",
|
|
26633
|
+
args: [
|
|
26634
|
+
key.token0,
|
|
26635
|
+
key.token1,
|
|
26636
|
+
key.fee
|
|
26637
|
+
],
|
|
26638
|
+
blockNumber
|
|
26639
|
+
})
|
|
26640
|
+
]);
|
|
26641
|
+
if (deployment.atomicCreateAndInitialize && getAddress(initializerFactoryResult) !== factory) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", `V3 initializer factory ${getAddress(initializerFactoryResult)} does not match configured factory ${factory}.`);
|
|
26642
|
+
const feeTickSpacing = Number(feeTickSpacingResult);
|
|
26643
|
+
if (!Number.isInteger(feeTickSpacing) || feeTickSpacing <= 0) throw new PoolLifecycleError("DISABLED_FEE", `V3 fee ${key.fee} is not enabled by factory ${factory}.`);
|
|
26644
|
+
const poolAddress = getAddress(poolResult);
|
|
26645
|
+
if (poolAddress === ZERO_ADDRESS$1) return {
|
|
26646
|
+
schemaVersion: 1,
|
|
26647
|
+
blockNumber,
|
|
26648
|
+
deployment,
|
|
26649
|
+
key,
|
|
26650
|
+
feeTickSpacing,
|
|
26651
|
+
status: "absent",
|
|
26652
|
+
poolAddress: null,
|
|
26653
|
+
sqrtPriceX96: 0n,
|
|
26654
|
+
tick: null,
|
|
26655
|
+
tickSpacing: feeTickSpacing
|
|
26656
|
+
};
|
|
26657
|
+
await requireContractCode$1(publicClient, poolAddress, "V3 pool", blockNumber);
|
|
26658
|
+
const [actualFactoryResult, token0Result, token1Result, feeResult, tickSpacingResult, slot0] = await Promise.all([
|
|
26659
|
+
publicClient.readContract({
|
|
26660
|
+
address: poolAddress,
|
|
26661
|
+
abi: v3PoolAbi,
|
|
26662
|
+
functionName: "factory",
|
|
26663
|
+
blockNumber
|
|
26664
|
+
}),
|
|
26665
|
+
publicClient.readContract({
|
|
26666
|
+
address: poolAddress,
|
|
26667
|
+
abi: v3PoolAbi,
|
|
26668
|
+
functionName: "token0",
|
|
26669
|
+
blockNumber
|
|
26670
|
+
}),
|
|
26671
|
+
publicClient.readContract({
|
|
26672
|
+
address: poolAddress,
|
|
26673
|
+
abi: v3PoolAbi,
|
|
26674
|
+
functionName: "token1",
|
|
26675
|
+
blockNumber
|
|
26676
|
+
}),
|
|
26677
|
+
publicClient.readContract({
|
|
26678
|
+
address: poolAddress,
|
|
26679
|
+
abi: v3PoolAbi,
|
|
26680
|
+
functionName: "fee",
|
|
26681
|
+
blockNumber
|
|
26682
|
+
}),
|
|
26683
|
+
publicClient.readContract({
|
|
26684
|
+
address: poolAddress,
|
|
26685
|
+
abi: v3PoolAbi,
|
|
26686
|
+
functionName: "tickSpacing",
|
|
26687
|
+
blockNumber
|
|
26688
|
+
}),
|
|
26689
|
+
publicClient.readContract({
|
|
26690
|
+
address: poolAddress,
|
|
26691
|
+
abi: v3PoolAbi,
|
|
26692
|
+
functionName: "slot0",
|
|
26693
|
+
blockNumber
|
|
26694
|
+
})
|
|
26695
|
+
]);
|
|
26696
|
+
const actualFactory = getAddress(actualFactoryResult);
|
|
26697
|
+
const actualToken0 = getAddress(token0Result);
|
|
26698
|
+
const actualToken1 = getAddress(token1Result);
|
|
26699
|
+
const actualFee = Number(feeResult);
|
|
26700
|
+
const tickSpacing = Number(tickSpacingResult);
|
|
26701
|
+
if (actualFactory !== factory || actualToken0 !== key.token0 || actualToken1 !== key.token1 || actualFee !== key.fee || tickSpacing !== feeTickSpacing) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", `Pool ${poolAddress} immutables do not match the configured V3 deployment and key.`);
|
|
26702
|
+
const sqrtPriceX96 = slot0[0];
|
|
26703
|
+
const tick = Number(slot0[1]);
|
|
26704
|
+
if (sqrtPriceX96 === 0n) return {
|
|
26705
|
+
schemaVersion: 1,
|
|
26706
|
+
blockNumber,
|
|
26707
|
+
deployment,
|
|
26708
|
+
key,
|
|
26709
|
+
feeTickSpacing,
|
|
26710
|
+
status: "uninitialized",
|
|
26711
|
+
poolAddress,
|
|
26712
|
+
sqrtPriceX96: 0n,
|
|
26713
|
+
tick,
|
|
26714
|
+
tickSpacing
|
|
26715
|
+
};
|
|
26716
|
+
return {
|
|
26717
|
+
schemaVersion: 1,
|
|
26718
|
+
blockNumber,
|
|
26719
|
+
deployment,
|
|
26720
|
+
key,
|
|
26721
|
+
feeTickSpacing,
|
|
26722
|
+
status: "initialized",
|
|
26723
|
+
poolAddress,
|
|
26724
|
+
sqrtPriceX96,
|
|
26725
|
+
tick,
|
|
26726
|
+
tickSpacing
|
|
26727
|
+
};
|
|
26728
|
+
}
|
|
26729
|
+
//#endregion
|
|
26730
|
+
//#region src/pool-lifecycle/v3/actions.ts
|
|
26731
|
+
function preflightSummary(preflight) {
|
|
26732
|
+
if (preflight.status === "absent") return {
|
|
26733
|
+
blockNumber: preflight.blockNumber,
|
|
26734
|
+
status: "absent",
|
|
26735
|
+
poolAddress: null,
|
|
26736
|
+
sqrtPriceX96: 0n
|
|
26737
|
+
};
|
|
26738
|
+
if (preflight.status === "uninitialized") return {
|
|
26739
|
+
blockNumber: preflight.blockNumber,
|
|
26740
|
+
status: "uninitialized",
|
|
26741
|
+
poolAddress: preflight.poolAddress,
|
|
26742
|
+
sqrtPriceX96: 0n
|
|
26743
|
+
};
|
|
26744
|
+
return {
|
|
26745
|
+
blockNumber: preflight.blockNumber,
|
|
26746
|
+
status: "initialized",
|
|
26747
|
+
poolAddress: preflight.poolAddress,
|
|
26748
|
+
sqrtPriceX96: preflight.sqrtPriceX96
|
|
26749
|
+
};
|
|
26750
|
+
}
|
|
26751
|
+
function assertConfiguredDeployment(deployment) {
|
|
26752
|
+
let matches = false;
|
|
26753
|
+
try {
|
|
26754
|
+
const configured = resolveV3LifecycleDeployment({
|
|
26755
|
+
chainId: deployment.chainId,
|
|
26756
|
+
protocol: deployment.protocol
|
|
26757
|
+
});
|
|
26758
|
+
matches = configured !== void 0 && deployment.supported === true && deployment.schemaVersion === configured.schemaVersion && deployment.family === configured.family && deployment.adapter === configured.adapter && deployment.version === configured.version && getAddress(deployment.factory) === getAddress(configured.factory) && (deployment.initializer === null || configured.initializer === null ? deployment.initializer === configured.initializer : getAddress(deployment.initializer) === getAddress(configured.initializer)) && deployment.atomicCreateAndInitialize === configured.atomicCreateAndInitialize && deployment.poolInitCodeHash === configured.poolInitCodeHash;
|
|
26759
|
+
} catch {}
|
|
26760
|
+
if (!matches) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", `Pool lifecycle deployment is not configured for chain ${deployment.chainId} and protocol ${deployment.protocol}.`);
|
|
26761
|
+
}
|
|
26762
|
+
function assertAtomicDeployment(deployment) {
|
|
26763
|
+
if (!deployment.atomicCreateAndInitialize) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", `V3 deployment ${deployment.chainId}:${deployment.protocol} has no configured atomic initializer.`);
|
|
26764
|
+
}
|
|
26765
|
+
function assertPreflightMatches$1(deployment, key, preflight) {
|
|
26766
|
+
if (!preflight) throw new PoolLifecycleError("POOL_STATE_MISMATCH", "V3 transaction building requires an inspected preflight snapshot.");
|
|
26767
|
+
let matches = false;
|
|
26768
|
+
try {
|
|
26769
|
+
matches = preflight.schemaVersion === 1 && typeof preflight.blockNumber === "bigint" && preflight.blockNumber >= 0n && preflight.deployment.chainId === deployment.chainId && preflight.deployment.schemaVersion === deployment.schemaVersion && preflight.deployment.protocol === deployment.protocol && preflight.deployment.family === deployment.family && preflight.deployment.adapter === deployment.adapter && preflight.deployment.version === deployment.version && getAddress(preflight.deployment.factory) === getAddress(deployment.factory) && (preflight.deployment.initializer === null || deployment.initializer === null ? preflight.deployment.initializer === deployment.initializer : getAddress(preflight.deployment.initializer) === getAddress(deployment.initializer)) && preflight.deployment.atomicCreateAndInitialize === deployment.atomicCreateAndInitialize && preflight.deployment.poolInitCodeHash === deployment.poolInitCodeHash && preflight.key.token0 === key.token0 && preflight.key.token1 === key.token1 && preflight.key.fee === key.fee && Number.isSafeInteger(preflight.feeTickSpacing) && preflight.feeTickSpacing > 0 && preflight.feeTickSpacing <= 16383 && preflight.tickSpacing === preflight.feeTickSpacing;
|
|
26770
|
+
} catch {}
|
|
26771
|
+
if (!matches) throw new PoolLifecycleError("INVALID_INPUT", "V3 preflight snapshot does not match the requested deployment and pool key.");
|
|
26772
|
+
if (preflight.status !== "absent" && preflight.status !== "uninitialized" && preflight.status !== "initialized") throw new PoolLifecycleError("INVALID_INPUT", "V3 preflight status is unsupported.");
|
|
26773
|
+
if (preflight.status === "absent") {
|
|
26774
|
+
if (preflight.poolAddress !== null || preflight.sqrtPriceX96 !== 0n || preflight.tick !== null) throw new PoolLifecycleError("INVALID_INPUT", "Absent V3 preflight state is inconsistent.");
|
|
26775
|
+
return;
|
|
26776
|
+
}
|
|
26777
|
+
if (!isAddress(preflight.poolAddress, { strict: true }) || getAddress(preflight.poolAddress) === "0x0000000000000000000000000000000000000000") throw new PoolLifecycleError("INVALID_INPUT", "V3 preflight pool address is invalid.");
|
|
26778
|
+
if (preflight.status === "uninitialized" && preflight.sqrtPriceX96 !== 0n) throw new PoolLifecycleError("INVALID_INPUT", "Uninitialized V3 preflight state must have zero sqrtPriceX96.");
|
|
26779
|
+
if (!Number.isSafeInteger(preflight.tick) || preflight.tick < -887272 || preflight.tick > 887272) throw new PoolLifecycleError("INVALID_INPUT", "V3 preflight tick is invalid.");
|
|
26780
|
+
if (preflight.status === "initialized") try {
|
|
26781
|
+
validateSqrtPriceX96(preflight.sqrtPriceX96);
|
|
26782
|
+
} catch (error) {
|
|
26783
|
+
throw new PoolLifecycleError("INVALID_INPUT", error instanceof Error ? error.message : "Initialized V3 preflight price is invalid.", error);
|
|
26784
|
+
}
|
|
26785
|
+
}
|
|
26786
|
+
function assertCreatePreflight(preflight) {
|
|
26787
|
+
if (preflight.status !== "absent") throw new PoolLifecycleError("POOL_STATE_MISMATCH", "V3 factory creation requires an inspected, absent pool.");
|
|
26788
|
+
}
|
|
26789
|
+
function assertAtomicPreflight(preflight, sqrtPriceX96) {
|
|
26790
|
+
if (preflight.status === "initialized") throw new PoolLifecycleError("POOL_STATE_MISMATCH", `V3 pool is already initialized at a ${preflight.sqrtPriceX96 === sqrtPriceX96 ? "matching" : "different"} price; no initialization transaction was built.`);
|
|
26791
|
+
}
|
|
26792
|
+
function buildIdentity(deployment, key, poolAddress) {
|
|
26793
|
+
return {
|
|
26794
|
+
family: "uniswap-v3-compatible",
|
|
26795
|
+
adapter: deployment.adapter,
|
|
26796
|
+
version: deployment.version,
|
|
26797
|
+
chainId: deployment.chainId,
|
|
26798
|
+
factory: getAddress(deployment.factory),
|
|
26799
|
+
initializer: deployment.initializer === null ? null : getAddress(deployment.initializer),
|
|
26800
|
+
key,
|
|
26801
|
+
poolAddress
|
|
26802
|
+
};
|
|
26803
|
+
}
|
|
26804
|
+
/** Build the low-level V3 factory create transaction without signing it. */
|
|
26805
|
+
function buildV3CreatePoolTransaction(params) {
|
|
26806
|
+
assertConfiguredDeployment(params.deployment);
|
|
26807
|
+
const key = canonicalizeV3PoolKey(params.key);
|
|
26808
|
+
assertPreflightMatches$1(params.deployment, key, params.preflight);
|
|
26809
|
+
assertCreatePreflight(params.preflight);
|
|
26810
|
+
return {
|
|
26811
|
+
schemaVersion: 1,
|
|
26812
|
+
kind: "v3-create",
|
|
26813
|
+
protocol: params.deployment.protocol,
|
|
26814
|
+
transaction: {
|
|
26815
|
+
chainId: params.deployment.chainId,
|
|
26816
|
+
to: getAddress(params.deployment.factory),
|
|
26817
|
+
data: encodeFunctionData({
|
|
26818
|
+
abi: v3FactoryAbi,
|
|
26819
|
+
functionName: "createPool",
|
|
26820
|
+
args: [
|
|
26821
|
+
key.token0,
|
|
26822
|
+
key.token1,
|
|
26823
|
+
key.fee
|
|
26824
|
+
]
|
|
26825
|
+
}),
|
|
26826
|
+
value: 0n
|
|
26827
|
+
},
|
|
26828
|
+
identity: buildIdentity(params.deployment, key, null),
|
|
26829
|
+
expected: { sqrtPriceX96: null },
|
|
26830
|
+
preflight: preflightSummary(params.preflight)
|
|
26831
|
+
};
|
|
26832
|
+
}
|
|
26833
|
+
/** Build a direct one-time V3 pool initialize transaction without signing it. */
|
|
26834
|
+
function buildV3InitializePoolTransaction(params) {
|
|
26835
|
+
assertConfiguredDeployment(params.deployment);
|
|
26836
|
+
const key = canonicalizeV3PoolKey(params.key);
|
|
26837
|
+
const initialPrice = assertV3InitialPrice(key, params.initialPrice);
|
|
26838
|
+
if (!params.preflight || params.preflight.status !== "uninitialized") throw new PoolLifecycleError("POOL_STATE_MISMATCH", "Direct V3 initialize requires an inspected, uninitialized pool.");
|
|
26839
|
+
assertPreflightMatches$1(params.deployment, key, params.preflight);
|
|
26840
|
+
const poolAddress = getAddress(params.preflight.poolAddress);
|
|
26841
|
+
return {
|
|
26842
|
+
schemaVersion: 1,
|
|
26843
|
+
kind: "v3-initialize",
|
|
26844
|
+
protocol: params.deployment.protocol,
|
|
26845
|
+
transaction: {
|
|
26846
|
+
chainId: params.deployment.chainId,
|
|
26847
|
+
to: poolAddress,
|
|
26848
|
+
data: encodeFunctionData({
|
|
26849
|
+
abi: v3PoolAbi,
|
|
26850
|
+
functionName: "initialize",
|
|
26851
|
+
args: [initialPrice.sqrtPriceX96]
|
|
26852
|
+
}),
|
|
26853
|
+
value: 0n
|
|
26854
|
+
},
|
|
26855
|
+
identity: buildIdentity(params.deployment, key, poolAddress),
|
|
26856
|
+
expected: { sqrtPriceX96: initialPrice.sqrtPriceX96 },
|
|
26857
|
+
preflight: preflightSummary(params.preflight)
|
|
26858
|
+
};
|
|
26859
|
+
}
|
|
26860
|
+
/** Build the canonical atomic create-and-initialize V3 periphery transaction. */
|
|
26861
|
+
function buildV3CreateAndInitializeTransaction(params) {
|
|
26862
|
+
assertConfiguredDeployment(params.deployment);
|
|
26863
|
+
assertAtomicDeployment(params.deployment);
|
|
26864
|
+
const key = canonicalizeV3PoolKey(params.key);
|
|
26865
|
+
const initialPrice = assertV3InitialPrice(key, params.initialPrice);
|
|
26866
|
+
assertPreflightMatches$1(params.deployment, key, params.preflight);
|
|
26867
|
+
assertAtomicPreflight(params.preflight, initialPrice.sqrtPriceX96);
|
|
26868
|
+
return {
|
|
26869
|
+
schemaVersion: 1,
|
|
26870
|
+
kind: "v3-create-and-initialize",
|
|
26871
|
+
protocol: params.deployment.protocol,
|
|
26872
|
+
transaction: {
|
|
26873
|
+
chainId: params.deployment.chainId,
|
|
26874
|
+
to: getAddress(params.deployment.initializer),
|
|
26875
|
+
data: encodeFunctionData({
|
|
26876
|
+
abi: v3PoolInitializerAbi,
|
|
26877
|
+
functionName: "createAndInitializePoolIfNecessary",
|
|
26878
|
+
args: [
|
|
26879
|
+
key.token0,
|
|
26880
|
+
key.token1,
|
|
26881
|
+
key.fee,
|
|
26882
|
+
initialPrice.sqrtPriceX96
|
|
26883
|
+
]
|
|
26884
|
+
}),
|
|
26885
|
+
value: 0n
|
|
26886
|
+
},
|
|
26887
|
+
identity: buildIdentity(params.deployment, key, params.preflight.poolAddress),
|
|
26888
|
+
expected: { sqrtPriceX96: initialPrice.sqrtPriceX96 },
|
|
26889
|
+
preflight: preflightSummary(params.preflight)
|
|
26890
|
+
};
|
|
26891
|
+
}
|
|
26892
|
+
/**
|
|
26893
|
+
* Prepare only the factory-creation step. This is the first stage for
|
|
26894
|
+
* deployments without a configured atomic initializer and deliberately does
|
|
26895
|
+
* not claim that the irreversible initial price has been set.
|
|
26896
|
+
*/
|
|
26897
|
+
async function prepareV3CreatePool(params) {
|
|
26898
|
+
assertConfiguredDeployment(params.deployment);
|
|
26899
|
+
const snapshot = await inspectV3Pool({
|
|
26900
|
+
publicClient: params.publicClient,
|
|
26901
|
+
deployment: params.deployment,
|
|
26902
|
+
key: params.key,
|
|
26903
|
+
blockNumber: params.blockNumber
|
|
26904
|
+
});
|
|
26905
|
+
if (snapshot.status !== "absent") return {
|
|
26906
|
+
status: "already-exists",
|
|
26907
|
+
snapshot,
|
|
26908
|
+
action: null
|
|
26909
|
+
};
|
|
26910
|
+
return {
|
|
26911
|
+
status: "ready",
|
|
26912
|
+
snapshot,
|
|
26913
|
+
action: buildV3CreatePoolTransaction({
|
|
26914
|
+
deployment: params.deployment,
|
|
26915
|
+
key: {
|
|
26916
|
+
tokenA: snapshot.key.token0,
|
|
26917
|
+
tokenB: snapshot.key.token1,
|
|
26918
|
+
fee: snapshot.key.fee
|
|
26919
|
+
},
|
|
26920
|
+
preflight: snapshot
|
|
26921
|
+
})
|
|
26922
|
+
};
|
|
26923
|
+
}
|
|
26924
|
+
/**
|
|
26925
|
+
* Prepare only the direct, one-time pool initialization step. Callers using a
|
|
26926
|
+
* factory-only deployment must mine and verify creation, re-inspect the pool,
|
|
26927
|
+
* and then call this function; the SDK does not conceal the intervening race.
|
|
26928
|
+
*/
|
|
26929
|
+
async function prepareV3InitializePool(params) {
|
|
26930
|
+
assertConfiguredDeployment(params.deployment);
|
|
26931
|
+
const snapshot = await inspectV3Pool({
|
|
26932
|
+
publicClient: params.publicClient,
|
|
26933
|
+
deployment: params.deployment,
|
|
26934
|
+
key: params.key,
|
|
26935
|
+
blockNumber: params.blockNumber
|
|
26936
|
+
});
|
|
26937
|
+
const price = assertV3InitialPrice(snapshot.key, params.initialPrice);
|
|
26938
|
+
if (snapshot.status === "absent") throw new PoolLifecycleError("POOL_STATE_MISMATCH", "V3 pool does not exist; create and verify it before preparing direct initialization.");
|
|
26939
|
+
if (snapshot.status === "initialized") {
|
|
26940
|
+
if (snapshot.sqrtPriceX96 === price.sqrtPriceX96) return {
|
|
26941
|
+
status: "already-initialized-matching",
|
|
26942
|
+
snapshot,
|
|
26943
|
+
action: null
|
|
26944
|
+
};
|
|
26945
|
+
throw new PoolLifecycleError("POOL_STATE_MISMATCH", `V3 pool ${snapshot.poolAddress} is already initialized at a different price.`);
|
|
26946
|
+
}
|
|
26947
|
+
return {
|
|
26948
|
+
status: "ready",
|
|
26949
|
+
snapshot,
|
|
26950
|
+
action: buildV3InitializePoolTransaction({
|
|
26951
|
+
deployment: params.deployment,
|
|
26952
|
+
key: {
|
|
26953
|
+
tokenA: snapshot.key.token0,
|
|
26954
|
+
tokenB: snapshot.key.token1,
|
|
26955
|
+
fee: snapshot.key.fee
|
|
26956
|
+
},
|
|
26957
|
+
initialPrice: price,
|
|
26958
|
+
preflight: snapshot
|
|
26959
|
+
})
|
|
26960
|
+
};
|
|
26961
|
+
}
|
|
26962
|
+
/**
|
|
26963
|
+
* Safe default preparation flow for UI and CLI consumers. It returns no
|
|
26964
|
+
* transaction for an already initialized pool only when the exact price
|
|
26965
|
+
* matches, and rejects a conflicting existing price.
|
|
26966
|
+
*/
|
|
26967
|
+
async function prepareV3CreateAndInitialize(params) {
|
|
26968
|
+
assertConfiguredDeployment(params.deployment);
|
|
26969
|
+
assertAtomicDeployment(params.deployment);
|
|
26970
|
+
const snapshot = await inspectV3Pool({
|
|
26971
|
+
publicClient: params.publicClient,
|
|
26972
|
+
deployment: params.deployment,
|
|
26973
|
+
key: params.key,
|
|
26974
|
+
blockNumber: params.blockNumber
|
|
26975
|
+
});
|
|
26976
|
+
const price = assertV3InitialPrice(snapshot.key, params.initialPrice);
|
|
26977
|
+
if (snapshot.status === "initialized") {
|
|
26978
|
+
if (snapshot.sqrtPriceX96 === price.sqrtPriceX96) return {
|
|
26979
|
+
status: "already-initialized-matching",
|
|
26980
|
+
snapshot,
|
|
26981
|
+
action: null
|
|
26982
|
+
};
|
|
26983
|
+
throw new PoolLifecycleError("POOL_STATE_MISMATCH", `V3 pool ${snapshot.poolAddress} is already initialized at a different price.`);
|
|
26984
|
+
}
|
|
26985
|
+
return {
|
|
26986
|
+
status: "ready",
|
|
26987
|
+
snapshot,
|
|
26988
|
+
action: buildV3CreateAndInitializeTransaction({
|
|
26989
|
+
deployment: params.deployment,
|
|
26990
|
+
key: {
|
|
26991
|
+
tokenA: snapshot.key.token0,
|
|
26992
|
+
tokenB: snapshot.key.token1,
|
|
26993
|
+
fee: snapshot.key.fee
|
|
26994
|
+
},
|
|
26995
|
+
initialPrice: price,
|
|
26996
|
+
preflight: snapshot
|
|
26997
|
+
})
|
|
26998
|
+
};
|
|
26999
|
+
}
|
|
27000
|
+
//#endregion
|
|
27001
|
+
//#region src/pool-lifecycle/v3/simulate.ts
|
|
27002
|
+
const ZERO_ADDRESS = getAddress("0x0000000000000000000000000000000000000000");
|
|
27003
|
+
function decodeReturnedPool(action, returnData) {
|
|
27004
|
+
switch (action.kind) {
|
|
27005
|
+
case "v3-initialize": return null;
|
|
27006
|
+
case "v3-create":
|
|
27007
|
+
if (!returnData || returnData === "0x") throw new PoolLifecycleError("SIMULATION_FAILED", "V3 create simulation returned no pool address.");
|
|
27008
|
+
return getAddress(decodeFunctionResult({
|
|
27009
|
+
abi: v3FactoryAbi,
|
|
27010
|
+
functionName: "createPool",
|
|
27011
|
+
data: returnData
|
|
27012
|
+
}));
|
|
27013
|
+
case "v3-create-and-initialize":
|
|
27014
|
+
if (!returnData || returnData === "0x") throw new PoolLifecycleError("SIMULATION_FAILED", "V3 create-and-initialize simulation returned no pool address.");
|
|
27015
|
+
return getAddress(decodeFunctionResult({
|
|
27016
|
+
abi: v3PoolInitializerAbi,
|
|
27017
|
+
functionName: "createAndInitializePoolIfNecessary",
|
|
27018
|
+
data: returnData
|
|
27019
|
+
}));
|
|
27020
|
+
}
|
|
27021
|
+
}
|
|
27022
|
+
/** Simulate and estimate a prepared action with the exact eventual sender. */
|
|
27023
|
+
async function simulateV3PoolAction(params) {
|
|
27024
|
+
if (!isAddress(params.account, { strict: true }) || getAddress(params.account) === ZERO_ADDRESS) throw new PoolLifecycleError("INVALID_INPUT", "Simulation account must be a valid non-zero EVM address.");
|
|
27025
|
+
const { publicClient, action } = params;
|
|
27026
|
+
const deployment = validatePreparedV3PoolAction(action);
|
|
27027
|
+
const account = getAddress(params.account);
|
|
27028
|
+
const blockNumber = params.blockNumber ?? await publicClient.getBlockNumber();
|
|
27029
|
+
const snapshot = await inspectV3Pool({
|
|
27030
|
+
publicClient,
|
|
27031
|
+
deployment,
|
|
27032
|
+
key: {
|
|
27033
|
+
tokenA: action.identity.key.token0,
|
|
27034
|
+
tokenB: action.identity.key.token1,
|
|
27035
|
+
fee: action.identity.key.fee
|
|
27036
|
+
},
|
|
27037
|
+
blockNumber
|
|
27038
|
+
});
|
|
27039
|
+
if (action.kind === "v3-create" && snapshot.status !== "absent") throw new PoolLifecycleError("POOL_STATE_MISMATCH", `V3 pool already exists at ${snapshot.poolAddress}; refresh the prepared action.`);
|
|
27040
|
+
if (action.kind === "v3-initialize" && (snapshot.status !== "uninitialized" || snapshot.poolAddress !== action.identity.poolAddress)) throw new PoolLifecycleError("POOL_STATE_MISMATCH", "V3 pool is no longer the uninitialized factory pool bound to this action.");
|
|
27041
|
+
if (action.kind === "v3-create-and-initialize" && snapshot.status === "initialized") throw new PoolLifecycleError("POOL_STATE_MISMATCH", `V3 pool ${snapshot.poolAddress} is already initialized; refresh the prepared action.`);
|
|
27042
|
+
const targetCode = await publicClient.getCode({
|
|
27043
|
+
address: action.transaction.to,
|
|
27044
|
+
blockNumber
|
|
27045
|
+
});
|
|
27046
|
+
if (!targetCode || targetCode === "0x") throw new PoolLifecycleError("CONTRACT_NOT_DEPLOYED", `Pool action target ${action.transaction.to} has no bytecode at block ${blockNumber}.`);
|
|
27047
|
+
const baseRequest = {
|
|
27048
|
+
account,
|
|
27049
|
+
to: action.transaction.to,
|
|
27050
|
+
data: action.transaction.data,
|
|
27051
|
+
value: action.transaction.value
|
|
27052
|
+
};
|
|
27053
|
+
const callRequest = {
|
|
27054
|
+
...baseRequest,
|
|
27055
|
+
batch: false,
|
|
27056
|
+
blockNumber
|
|
27057
|
+
};
|
|
27058
|
+
const estimateRequest = {
|
|
27059
|
+
...baseRequest,
|
|
27060
|
+
blockNumber
|
|
27061
|
+
};
|
|
27062
|
+
try {
|
|
27063
|
+
const callResult = await publicClient.call(callRequest);
|
|
27064
|
+
const gasEstimate = await publicClient.estimateGas(estimateRequest);
|
|
27065
|
+
const returnedPoolAddress = decodeReturnedPool(action, callResult.data);
|
|
27066
|
+
if (action.identity.poolAddress && returnedPoolAddress && returnedPoolAddress !== action.identity.poolAddress) throw new PoolLifecycleError("POOL_STATE_MISMATCH", `Simulation returned pool ${returnedPoolAddress}, expected ${action.identity.poolAddress}.`);
|
|
27067
|
+
return {
|
|
27068
|
+
transaction: action.transaction,
|
|
27069
|
+
blockNumber,
|
|
27070
|
+
returnData: callResult.data ?? null,
|
|
27071
|
+
returnedPoolAddress,
|
|
27072
|
+
gasEstimate
|
|
27073
|
+
};
|
|
27074
|
+
} catch (error) {
|
|
27075
|
+
if (error instanceof PoolLifecycleError) throw error;
|
|
27076
|
+
throw new PoolLifecycleError("SIMULATION_FAILED", error instanceof Error ? error.message : "V3 pool action simulation failed.", error);
|
|
27077
|
+
}
|
|
27078
|
+
}
|
|
27079
|
+
//#endregion
|
|
27080
|
+
//#region src/pool-lifecycle/v3/verify.ts
|
|
27081
|
+
function assertLogBelongsToReceipt$1(log, receipt) {
|
|
27082
|
+
if (log.transactionHash !== receipt.transactionHash || log.blockHash !== receipt.blockHash || log.blockNumber !== receipt.blockNumber || log.transactionIndex !== receipt.transactionIndex || log.removed !== false) throw new PoolLifecycleError("POOL_STATE_MISMATCH", "Decoded V3 lifecycle log does not belong to the supplied receipt.");
|
|
27083
|
+
}
|
|
27084
|
+
function decodeMatchingPoolCreated(action, receipt) {
|
|
27085
|
+
const matches = [];
|
|
27086
|
+
for (const log of receipt.logs) {
|
|
27087
|
+
if (getAddress(log.address) !== action.identity.factory) continue;
|
|
27088
|
+
let decoded;
|
|
27089
|
+
try {
|
|
27090
|
+
decoded = decodeEventLog({
|
|
27091
|
+
abi: v3FactoryAbi,
|
|
27092
|
+
eventName: "PoolCreated",
|
|
27093
|
+
data: log.data,
|
|
27094
|
+
topics: log.topics
|
|
27095
|
+
});
|
|
27096
|
+
} catch {
|
|
27097
|
+
continue;
|
|
27098
|
+
}
|
|
27099
|
+
if (getAddress(decoded.args.token0) !== action.identity.key.token0 || getAddress(decoded.args.token1) !== action.identity.key.token1 || Number(decoded.args.fee) !== action.identity.key.fee) continue;
|
|
27100
|
+
assertLogBelongsToReceipt$1(log, receipt);
|
|
27101
|
+
matches.push({
|
|
27102
|
+
poolAddress: getAddress(decoded.args.pool),
|
|
27103
|
+
token0: getAddress(decoded.args.token0),
|
|
27104
|
+
token1: getAddress(decoded.args.token1),
|
|
27105
|
+
fee: Number(decoded.args.fee),
|
|
27106
|
+
tickSpacing: Number(decoded.args.tickSpacing),
|
|
27107
|
+
logIndex: log.logIndex
|
|
27108
|
+
});
|
|
27109
|
+
}
|
|
27110
|
+
if (matches.length > 1) throw new PoolLifecycleError("POOL_STATE_MISMATCH", "Receipt contains multiple matching V3 PoolCreated events.");
|
|
27111
|
+
return matches[0] ?? null;
|
|
27112
|
+
}
|
|
27113
|
+
function decodeInitializations(receipt) {
|
|
27114
|
+
const initializations = [];
|
|
27115
|
+
for (const log of receipt.logs) {
|
|
27116
|
+
let decoded;
|
|
27117
|
+
try {
|
|
27118
|
+
decoded = decodeEventLog({
|
|
27119
|
+
abi: v3PoolAbi,
|
|
27120
|
+
eventName: "Initialize",
|
|
27121
|
+
data: log.data,
|
|
27122
|
+
topics: log.topics
|
|
27123
|
+
});
|
|
27124
|
+
} catch {
|
|
27125
|
+
continue;
|
|
27126
|
+
}
|
|
27127
|
+
assertLogBelongsToReceipt$1(log, receipt);
|
|
27128
|
+
initializations.push({
|
|
27129
|
+
poolAddress: getAddress(log.address),
|
|
27130
|
+
sqrtPriceX96: decoded.args.sqrtPriceX96,
|
|
27131
|
+
tick: Number(decoded.args.tick),
|
|
27132
|
+
logIndex: log.logIndex
|
|
27133
|
+
});
|
|
27134
|
+
}
|
|
27135
|
+
return initializations;
|
|
27136
|
+
}
|
|
27137
|
+
/** Decode receipt evidence without making any RPC reads. */
|
|
27138
|
+
function decodeV3PoolActionReceipt(action, receipt) {
|
|
27139
|
+
validatePreparedV3PoolAction(action);
|
|
27140
|
+
return {
|
|
27141
|
+
receiptStatus: receipt.status,
|
|
27142
|
+
poolCreated: decodeMatchingPoolCreated(action, receipt),
|
|
27143
|
+
initializations: decodeInitializations(receipt)
|
|
27144
|
+
};
|
|
27145
|
+
}
|
|
27146
|
+
function withFinalPoolAddress(action, snapshot) {
|
|
27147
|
+
return {
|
|
27148
|
+
...action.identity,
|
|
27149
|
+
poolAddress: snapshot?.poolAddress ?? action.identity.poolAddress
|
|
27150
|
+
};
|
|
27151
|
+
}
|
|
27152
|
+
/** Evaluate decoded receipt evidence against a block-pinned V3 snapshot. */
|
|
27153
|
+
function evaluateV3PoolAction(action, evidence, snapshot, blockNumber) {
|
|
27154
|
+
const warnings = [];
|
|
27155
|
+
const identity = withFinalPoolAddress(action, snapshot);
|
|
27156
|
+
if (evidence.receiptStatus === "reverted") return {
|
|
27157
|
+
verified: false,
|
|
27158
|
+
outcome: "reverted",
|
|
27159
|
+
blockNumber,
|
|
27160
|
+
identity,
|
|
27161
|
+
state: snapshot,
|
|
27162
|
+
evidence,
|
|
27163
|
+
warnings
|
|
27164
|
+
};
|
|
27165
|
+
if (!snapshot || snapshot.status === "absent" || !snapshot.poolAddress) return {
|
|
27166
|
+
verified: false,
|
|
27167
|
+
outcome: "not-initialized",
|
|
27168
|
+
blockNumber,
|
|
27169
|
+
identity,
|
|
27170
|
+
state: snapshot,
|
|
27171
|
+
evidence,
|
|
27172
|
+
warnings
|
|
27173
|
+
};
|
|
27174
|
+
const created = evidence.poolCreated;
|
|
27175
|
+
const createdMatchesState = created !== null && created.poolAddress === snapshot.poolAddress && created.tickSpacing === snapshot.tickSpacing;
|
|
27176
|
+
const initializationsAtPool = evidence.initializations.filter((item) => item.poolAddress === snapshot.poolAddress);
|
|
27177
|
+
if (initializationsAtPool.length > 1) return {
|
|
27178
|
+
verified: false,
|
|
27179
|
+
outcome: "wrong-deployment",
|
|
27180
|
+
blockNumber,
|
|
27181
|
+
identity,
|
|
27182
|
+
state: snapshot,
|
|
27183
|
+
evidence,
|
|
27184
|
+
warnings: ["Receipt contains multiple Initialize events for the expected V3 pool."]
|
|
27185
|
+
};
|
|
27186
|
+
const initializationAtPool = initializationsAtPool[0];
|
|
27187
|
+
const exactInitialization = initializationsAtPool.find((item) => item.poolAddress === snapshot.poolAddress && action.expected.sqrtPriceX96 !== null && item.sqrtPriceX96 === action.expected.sqrtPriceX96);
|
|
27188
|
+
if (created && !createdMatchesState) return {
|
|
27189
|
+
verified: false,
|
|
27190
|
+
outcome: "wrong-deployment",
|
|
27191
|
+
blockNumber,
|
|
27192
|
+
identity,
|
|
27193
|
+
state: snapshot,
|
|
27194
|
+
evidence,
|
|
27195
|
+
warnings: ["PoolCreated evidence does not match the receipt-block pool state."]
|
|
27196
|
+
};
|
|
27197
|
+
if (action.kind === "v3-create") {
|
|
27198
|
+
if (!createdMatchesState) return {
|
|
27199
|
+
verified: false,
|
|
27200
|
+
outcome: "wrong-deployment",
|
|
27201
|
+
blockNumber,
|
|
27202
|
+
identity,
|
|
27203
|
+
state: snapshot,
|
|
27204
|
+
evidence,
|
|
27205
|
+
warnings
|
|
27206
|
+
};
|
|
27207
|
+
if (snapshot.status === "initialized") warnings.push("The pool was initialized after creation in the same block.");
|
|
27208
|
+
return {
|
|
27209
|
+
verified: true,
|
|
27210
|
+
outcome: "created",
|
|
27211
|
+
blockNumber,
|
|
27212
|
+
identity,
|
|
27213
|
+
state: snapshot,
|
|
27214
|
+
evidence,
|
|
27215
|
+
warnings
|
|
27216
|
+
};
|
|
27217
|
+
}
|
|
27218
|
+
if (exactInitialization) {
|
|
27219
|
+
if (snapshot.status !== "initialized") return {
|
|
27220
|
+
verified: false,
|
|
27221
|
+
outcome: "not-initialized",
|
|
27222
|
+
blockNumber,
|
|
27223
|
+
identity,
|
|
27224
|
+
state: snapshot,
|
|
27225
|
+
evidence,
|
|
27226
|
+
warnings
|
|
27227
|
+
};
|
|
27228
|
+
if (snapshot.sqrtPriceX96 !== action.expected.sqrtPriceX96) {
|
|
27229
|
+
warnings.push("Pool price moved after the matching Initialize event in the receipt block.");
|
|
27230
|
+
return {
|
|
27231
|
+
verified: true,
|
|
27232
|
+
outcome: "initialized-then-price-moved",
|
|
27233
|
+
blockNumber,
|
|
27234
|
+
identity,
|
|
27235
|
+
state: snapshot,
|
|
27236
|
+
evidence,
|
|
27237
|
+
warnings
|
|
27238
|
+
};
|
|
27239
|
+
}
|
|
27240
|
+
return {
|
|
27241
|
+
verified: true,
|
|
27242
|
+
outcome: action.kind === "v3-create-and-initialize" && createdMatchesState ? "created-and-initialized" : "initialized-existing",
|
|
27243
|
+
blockNumber,
|
|
27244
|
+
identity,
|
|
27245
|
+
state: snapshot,
|
|
27246
|
+
evidence,
|
|
27247
|
+
warnings
|
|
27248
|
+
};
|
|
27249
|
+
}
|
|
27250
|
+
if (initializationAtPool) {
|
|
27251
|
+
warnings.push("Receipt initialized the expected pool at a different price.");
|
|
27252
|
+
return {
|
|
27253
|
+
verified: false,
|
|
27254
|
+
outcome: "already-initialized-different-price",
|
|
27255
|
+
blockNumber,
|
|
27256
|
+
identity,
|
|
27257
|
+
state: snapshot,
|
|
27258
|
+
evidence,
|
|
27259
|
+
warnings
|
|
27260
|
+
};
|
|
27261
|
+
}
|
|
27262
|
+
if (action.kind === "v3-create-and-initialize" && createdMatchesState) return {
|
|
27263
|
+
verified: false,
|
|
27264
|
+
outcome: "wrong-deployment",
|
|
27265
|
+
blockNumber,
|
|
27266
|
+
identity,
|
|
27267
|
+
state: snapshot,
|
|
27268
|
+
evidence,
|
|
27269
|
+
warnings: ["PoolCreated evidence is missing the required same-receipt Initialize event."]
|
|
27270
|
+
};
|
|
27271
|
+
if (action.kind === "v3-create-and-initialize" && snapshot.status === "initialized") {
|
|
27272
|
+
if (snapshot.sqrtPriceX96 === action.expected.sqrtPriceX96) {
|
|
27273
|
+
warnings.push("The receipt contains no matching Initialize event; another transaction set the price.");
|
|
27274
|
+
return {
|
|
27275
|
+
verified: true,
|
|
27276
|
+
outcome: "already-initialized-matching",
|
|
27277
|
+
blockNumber,
|
|
27278
|
+
identity,
|
|
27279
|
+
state: snapshot,
|
|
27280
|
+
evidence,
|
|
27281
|
+
warnings
|
|
27282
|
+
};
|
|
27283
|
+
}
|
|
27284
|
+
return {
|
|
27285
|
+
verified: false,
|
|
27286
|
+
outcome: "already-initialized-different-price",
|
|
27287
|
+
blockNumber,
|
|
27288
|
+
identity,
|
|
27289
|
+
state: snapshot,
|
|
27290
|
+
evidence,
|
|
27291
|
+
warnings
|
|
27292
|
+
};
|
|
27293
|
+
}
|
|
27294
|
+
return {
|
|
27295
|
+
verified: false,
|
|
27296
|
+
outcome: "not-initialized",
|
|
27297
|
+
blockNumber,
|
|
27298
|
+
identity,
|
|
27299
|
+
state: snapshot,
|
|
27300
|
+
evidence,
|
|
27301
|
+
warnings
|
|
27302
|
+
};
|
|
27303
|
+
}
|
|
27304
|
+
/** Compose receipt decoding with receipt-block deployment and state verification. */
|
|
27305
|
+
async function verifyV3PoolAction(params) {
|
|
27306
|
+
const { publicClient, action, receipt } = params;
|
|
27307
|
+
const deployment = validatePreparedV3PoolAction(action);
|
|
27308
|
+
const emptyEvidence = {
|
|
27309
|
+
receiptStatus: receipt.status,
|
|
27310
|
+
poolCreated: null,
|
|
27311
|
+
initializations: []
|
|
27312
|
+
};
|
|
27313
|
+
let activeChainId;
|
|
27314
|
+
let transaction;
|
|
27315
|
+
let canonicalReceipt;
|
|
27316
|
+
try {
|
|
27317
|
+
[activeChainId, transaction, canonicalReceipt] = await Promise.all([
|
|
27318
|
+
publicClient.getChainId(),
|
|
27319
|
+
publicClient.getTransaction({ hash: receipt.transactionHash }),
|
|
27320
|
+
publicClient.getTransactionReceipt({ hash: receipt.transactionHash })
|
|
27321
|
+
]);
|
|
27322
|
+
} catch (error) {
|
|
27323
|
+
return {
|
|
27324
|
+
verified: false,
|
|
27325
|
+
outcome: "verification-unavailable",
|
|
27326
|
+
blockNumber: receipt.blockNumber,
|
|
27327
|
+
identity: action.identity,
|
|
27328
|
+
state: null,
|
|
27329
|
+
evidence: emptyEvidence,
|
|
27330
|
+
warnings: [error instanceof Error ? error.message : "Failed to load the canonical receipt and transaction."]
|
|
27331
|
+
};
|
|
27332
|
+
}
|
|
27333
|
+
const nullableAddressMatches = (left, right) => left === null || right === null ? left === right : getAddress(left) === getAddress(right);
|
|
27334
|
+
const target = getAddress(action.transaction.to);
|
|
27335
|
+
const suppliedReceiptMatchesCanonical = receipt.transactionHash === canonicalReceipt.transactionHash && receipt.blockHash === canonicalReceipt.blockHash && receipt.blockNumber === canonicalReceipt.blockNumber && receipt.transactionIndex === canonicalReceipt.transactionIndex && receipt.status === canonicalReceipt.status && nullableAddressMatches(receipt.to, canonicalReceipt.to);
|
|
27336
|
+
const receiptDestinationMatches = canonicalReceipt.to !== null && getAddress(canonicalReceipt.to) === target;
|
|
27337
|
+
const transactionDestinationMatches = transaction.to !== null && getAddress(transaction.to) === target;
|
|
27338
|
+
const transactionMatches = transaction.hash === canonicalReceipt.transactionHash && transactionDestinationMatches && transaction.input.toLowerCase() === action.transaction.data.toLowerCase() && transaction.value === action.transaction.value && transaction.blockHash === canonicalReceipt.blockHash && transaction.blockNumber === canonicalReceipt.blockNumber && transaction.transactionIndex === canonicalReceipt.transactionIndex && getAddress(transaction.from) === getAddress(canonicalReceipt.from);
|
|
27339
|
+
if (activeChainId !== action.transaction.chainId || !suppliedReceiptMatchesCanonical || !receiptDestinationMatches || !transactionMatches) return {
|
|
27340
|
+
verified: false,
|
|
27341
|
+
outcome: "wrong-deployment",
|
|
27342
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27343
|
+
identity: action.identity,
|
|
27344
|
+
state: null,
|
|
27345
|
+
evidence: emptyEvidence,
|
|
27346
|
+
warnings: ["Receipt, client, or lifecycle deployment does not match the prepared action."]
|
|
27347
|
+
};
|
|
27348
|
+
let evidence;
|
|
27349
|
+
try {
|
|
27350
|
+
evidence = decodeV3PoolActionReceipt(action, canonicalReceipt);
|
|
27351
|
+
} catch (error) {
|
|
27352
|
+
return {
|
|
27353
|
+
verified: false,
|
|
27354
|
+
outcome: "wrong-deployment",
|
|
27355
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27356
|
+
identity: action.identity,
|
|
27357
|
+
state: null,
|
|
27358
|
+
evidence: emptyEvidence,
|
|
27359
|
+
warnings: [error instanceof Error ? error.message : "Receipt log attribution failed."]
|
|
27360
|
+
};
|
|
27361
|
+
}
|
|
27362
|
+
let blockHashBefore;
|
|
27363
|
+
try {
|
|
27364
|
+
blockHashBefore = (await publicClient.getBlock({
|
|
27365
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27366
|
+
includeTransactions: false
|
|
27367
|
+
})).hash;
|
|
27368
|
+
} catch (error) {
|
|
27369
|
+
return {
|
|
27370
|
+
verified: false,
|
|
27371
|
+
outcome: "verification-unavailable",
|
|
27372
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27373
|
+
identity: action.identity,
|
|
27374
|
+
state: null,
|
|
27375
|
+
evidence,
|
|
27376
|
+
warnings: [error instanceof Error ? error.message : "Failed to load the receipt block."]
|
|
27377
|
+
};
|
|
27378
|
+
}
|
|
27379
|
+
if (blockHashBefore !== canonicalReceipt.blockHash) return {
|
|
27380
|
+
verified: false,
|
|
27381
|
+
outcome: "verification-unavailable",
|
|
27382
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27383
|
+
identity: action.identity,
|
|
27384
|
+
state: null,
|
|
27385
|
+
evidence,
|
|
27386
|
+
warnings: ["Receipt block is no longer canonical; retry verification with a fresh receipt."]
|
|
27387
|
+
};
|
|
27388
|
+
if (canonicalReceipt.status === "reverted") return evaluateV3PoolAction(action, evidence, null, canonicalReceipt.blockNumber);
|
|
27389
|
+
let snapshot;
|
|
27390
|
+
try {
|
|
27391
|
+
snapshot = await inspectV3Pool({
|
|
27392
|
+
publicClient,
|
|
27393
|
+
deployment,
|
|
27394
|
+
key: {
|
|
27395
|
+
tokenA: action.identity.key.token0,
|
|
27396
|
+
tokenB: action.identity.key.token1,
|
|
27397
|
+
fee: action.identity.key.fee
|
|
27398
|
+
},
|
|
27399
|
+
blockNumber: canonicalReceipt.blockNumber
|
|
27400
|
+
});
|
|
27401
|
+
} catch (error) {
|
|
27402
|
+
return {
|
|
27403
|
+
verified: false,
|
|
27404
|
+
outcome: error instanceof PoolLifecycleError ? "wrong-deployment" : "verification-unavailable",
|
|
27405
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27406
|
+
identity: action.identity,
|
|
27407
|
+
state: null,
|
|
27408
|
+
evidence,
|
|
27409
|
+
warnings: [error instanceof Error ? error.message : "Failed to verify V3 pool state."]
|
|
27410
|
+
};
|
|
27411
|
+
}
|
|
27412
|
+
try {
|
|
27413
|
+
if ((await publicClient.getBlock({
|
|
27414
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27415
|
+
includeTransactions: false
|
|
27416
|
+
})).hash !== canonicalReceipt.blockHash) return {
|
|
27417
|
+
verified: false,
|
|
27418
|
+
outcome: "verification-unavailable",
|
|
27419
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27420
|
+
identity: action.identity,
|
|
27421
|
+
state: null,
|
|
27422
|
+
evidence,
|
|
27423
|
+
warnings: ["Receipt block changed during verification; retry with a fresh receipt."]
|
|
27424
|
+
};
|
|
27425
|
+
} catch (error) {
|
|
27426
|
+
return {
|
|
27427
|
+
verified: false,
|
|
27428
|
+
outcome: "verification-unavailable",
|
|
27429
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27430
|
+
identity: action.identity,
|
|
27431
|
+
state: null,
|
|
27432
|
+
evidence,
|
|
27433
|
+
warnings: [error instanceof Error ? error.message : "Failed to confirm the canonical receipt block."]
|
|
27434
|
+
};
|
|
27435
|
+
}
|
|
27436
|
+
return evaluateV3PoolAction(action, evidence, snapshot, canonicalReceipt.blockNumber);
|
|
27437
|
+
}
|
|
27438
|
+
//#endregion
|
|
27439
|
+
//#region src/pool-lifecycle/v4/inspect.ts
|
|
27440
|
+
function hasCode(bytecode) {
|
|
27441
|
+
return bytecode !== void 0 && bytecode !== "0x";
|
|
27442
|
+
}
|
|
27443
|
+
async function requireContractCode(publicClient, address, label, blockNumber) {
|
|
27444
|
+
if (!hasCode(await publicClient.getCode({
|
|
27445
|
+
address,
|
|
27446
|
+
blockNumber
|
|
27447
|
+
}))) throw new PoolLifecycleError("CONTRACT_NOT_DEPLOYED", `${label} ${address} has no bytecode at block ${blockNumber}.`);
|
|
27448
|
+
}
|
|
27449
|
+
function asUint24(value, label) {
|
|
27450
|
+
const converted = Number(value);
|
|
27451
|
+
if (!Number.isSafeInteger(converted) || converted < 0 || converted > 16777215) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", `${label} returned by StateView is not a uint24.`);
|
|
27452
|
+
return converted;
|
|
27453
|
+
}
|
|
27454
|
+
function asTick(value) {
|
|
27455
|
+
const converted = Number(value);
|
|
27456
|
+
if (!Number.isSafeInteger(converted) || converted < -887272 || converted > 887272) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", "Tick returned by StateView is outside the TickMath range.");
|
|
27457
|
+
return converted;
|
|
27458
|
+
}
|
|
27459
|
+
/** Read PoolManager identity and pool state at one pinned block. */
|
|
27460
|
+
async function inspectV4Pool(params) {
|
|
27461
|
+
const { publicClient } = params;
|
|
27462
|
+
const deployment = validateV4LifecycleDeployment(params.deployment);
|
|
27463
|
+
const key = canonicalizeV4PoolKey(params.key);
|
|
27464
|
+
const activeChainId = await publicClient.getChainId();
|
|
27465
|
+
if (activeChainId !== deployment.chainId) throw new PoolLifecycleError("CHAIN_MISMATCH", `Public client chain ${activeChainId} does not match V4 deployment chain ${deployment.chainId}.`);
|
|
27466
|
+
const blockNumber = params.blockNumber ?? await publicClient.getBlockNumber();
|
|
27467
|
+
if (typeof blockNumber !== "bigint" || blockNumber < 0n) throw new PoolLifecycleError("INVALID_INPUT", "V4 inspection blockNumber must be non-negative.");
|
|
27468
|
+
const codeChecks = [requireContractCode(publicClient, deployment.poolManager, "V4 PoolManager", blockNumber), requireContractCode(publicClient, deployment.stateView, "V4 StateView", blockNumber)];
|
|
27469
|
+
if (key.currency0 !== V4_ZERO_ADDRESS) codeChecks.push(requireContractCode(publicClient, key.currency0, "currency0", blockNumber));
|
|
27470
|
+
codeChecks.push(requireContractCode(publicClient, key.currency1, "currency1", blockNumber));
|
|
27471
|
+
if (key.hooks !== V4_ZERO_ADDRESS) codeChecks.push(requireContractCode(publicClient, key.hooks, "V4 hooks", blockNumber));
|
|
27472
|
+
await Promise.all(codeChecks);
|
|
27473
|
+
const poolId = getV4PoolId(key);
|
|
27474
|
+
const [viewPoolManagerResult, slot0] = await Promise.all([publicClient.readContract({
|
|
27475
|
+
address: deployment.stateView,
|
|
27476
|
+
abi: v4StateViewAbi,
|
|
27477
|
+
functionName: "poolManager",
|
|
27478
|
+
blockNumber
|
|
27479
|
+
}), publicClient.readContract({
|
|
27480
|
+
address: deployment.stateView,
|
|
27481
|
+
abi: v4StateViewAbi,
|
|
27482
|
+
functionName: "getSlot0",
|
|
27483
|
+
args: [poolId],
|
|
27484
|
+
blockNumber
|
|
27485
|
+
})]);
|
|
27486
|
+
const viewPoolManager = getAddress(viewPoolManagerResult);
|
|
27487
|
+
if (viewPoolManager !== deployment.poolManager) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", `V4 StateView is bound to ${viewPoolManager}, not configured PoolManager ${deployment.poolManager}.`);
|
|
27488
|
+
const sqrtPriceX96 = slot0[0];
|
|
27489
|
+
const tick = asTick(slot0[1]);
|
|
27490
|
+
const protocolFee = asUint24(slot0[2], "protocolFee");
|
|
27491
|
+
const lpFee = asUint24(slot0[3], "lpFee");
|
|
27492
|
+
if (sqrtPriceX96 === 0n) {
|
|
27493
|
+
if (tick !== 0 || protocolFee !== 0 || lpFee !== 0) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", "Uninitialized V4 StateView slot contains non-zero state.");
|
|
27494
|
+
return {
|
|
27495
|
+
schemaVersion: 1,
|
|
27496
|
+
blockNumber,
|
|
27497
|
+
deployment,
|
|
27498
|
+
key,
|
|
27499
|
+
poolId,
|
|
27500
|
+
status: "uninitialized",
|
|
27501
|
+
sqrtPriceX96: 0n,
|
|
27502
|
+
tick: 0,
|
|
27503
|
+
protocolFee: 0,
|
|
27504
|
+
lpFee: 0
|
|
27505
|
+
};
|
|
27506
|
+
}
|
|
27507
|
+
try {
|
|
27508
|
+
validateSqrtPriceX96(sqrtPriceX96);
|
|
27509
|
+
} catch (error) {
|
|
27510
|
+
throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", error instanceof Error ? error.message : "StateView returned an invalid sqrtPriceX96.", error);
|
|
27511
|
+
}
|
|
27512
|
+
if (lpFee > 1e6) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", "StateView returned an invalid V4 LP fee.");
|
|
27513
|
+
if (key.fee !== 8388608 && lpFee !== key.fee) throw new PoolLifecycleError("DEPLOYMENT_MISMATCH", `Static V4 pool LP fee ${lpFee} does not match PoolKey fee ${key.fee}.`);
|
|
27514
|
+
return {
|
|
27515
|
+
schemaVersion: 1,
|
|
27516
|
+
blockNumber,
|
|
27517
|
+
deployment,
|
|
27518
|
+
key,
|
|
27519
|
+
poolId,
|
|
27520
|
+
status: "initialized",
|
|
27521
|
+
sqrtPriceX96,
|
|
27522
|
+
tick,
|
|
27523
|
+
protocolFee,
|
|
27524
|
+
lpFee
|
|
27525
|
+
};
|
|
27526
|
+
}
|
|
27527
|
+
//#endregion
|
|
27528
|
+
//#region src/pool-lifecycle/v4/actions.ts
|
|
27529
|
+
function assertPreflightMatches(deployment, key, preflight) {
|
|
27530
|
+
let matches = false;
|
|
27531
|
+
try {
|
|
27532
|
+
const snapshotDeployment = validateV4LifecycleDeployment(preflight?.deployment);
|
|
27533
|
+
matches = preflight.schemaVersion === 1 && preflight.status === "uninitialized" && typeof preflight.blockNumber === "bigint" && preflight.blockNumber >= 0n && snapshotDeployment === deployment && preflight.poolId === getV4PoolId(key) && v4PoolKeysEqual(preflight.key, key) && preflight.sqrtPriceX96 === 0n && preflight.tick === 0 && preflight.protocolFee === 0 && preflight.lpFee === 0;
|
|
27534
|
+
} catch {}
|
|
27535
|
+
if (!matches) throw new PoolLifecycleError("POOL_STATE_MISMATCH", "Direct V4 initialize requires a matching inspected, uninitialized PoolKey snapshot.");
|
|
27536
|
+
}
|
|
27537
|
+
function identity(deployment, key) {
|
|
27538
|
+
return {
|
|
27539
|
+
family: deployment.family,
|
|
27540
|
+
adapter: deployment.adapter,
|
|
27541
|
+
version: deployment.version,
|
|
27542
|
+
deploymentId: deployment.deploymentId,
|
|
27543
|
+
chainId: deployment.chainId,
|
|
27544
|
+
poolManager: deployment.poolManager,
|
|
27545
|
+
stateView: deployment.stateView,
|
|
27546
|
+
poolId: getV4PoolId(key),
|
|
27547
|
+
key
|
|
27548
|
+
};
|
|
27549
|
+
}
|
|
27550
|
+
/** Build a direct PoolManager.initialize transaction without signing it. */
|
|
27551
|
+
function buildV4InitializePoolTransaction(params) {
|
|
27552
|
+
const deployment = validateV4LifecycleDeployment(params.deployment);
|
|
27553
|
+
const key = canonicalizeV4PoolKey(params.key);
|
|
27554
|
+
const initialPrice = assertV4InitialPrice(key, params.initialPrice);
|
|
27555
|
+
if (!params.preflight || params.preflight.status !== "uninitialized") throw new PoolLifecycleError("POOL_STATE_MISMATCH", "Direct V4 initialize requires an inspected, uninitialized PoolKey.");
|
|
27556
|
+
assertPreflightMatches(deployment, key, params.preflight);
|
|
27557
|
+
const poolId = getV4PoolId(key);
|
|
27558
|
+
return {
|
|
27559
|
+
schemaVersion: 1,
|
|
27560
|
+
kind: "v4-initialize",
|
|
27561
|
+
protocol: deployment.protocol,
|
|
27562
|
+
transaction: {
|
|
27563
|
+
chainId: deployment.chainId,
|
|
27564
|
+
to: deployment.poolManager,
|
|
27565
|
+
data: encodeFunctionData({
|
|
27566
|
+
abi: v4PoolManagerAbi,
|
|
27567
|
+
functionName: "initialize",
|
|
27568
|
+
args: [key, initialPrice.sqrtPriceX96]
|
|
27569
|
+
}),
|
|
27570
|
+
value: 0n
|
|
27571
|
+
},
|
|
27572
|
+
identity: identity(deployment, key),
|
|
27573
|
+
expected: initialPrice,
|
|
27574
|
+
preflight: {
|
|
27575
|
+
blockNumber: params.preflight.blockNumber,
|
|
27576
|
+
deploymentId: deployment.deploymentId,
|
|
27577
|
+
status: "uninitialized",
|
|
27578
|
+
poolId,
|
|
27579
|
+
sqrtPriceX96: 0n
|
|
27580
|
+
}
|
|
27581
|
+
};
|
|
27582
|
+
}
|
|
27583
|
+
/** Inspect first, then return either a safe unsigned plan or a matching no-op. */
|
|
27584
|
+
async function prepareV4Initialize(params) {
|
|
27585
|
+
const snapshot = await inspectV4Pool(params);
|
|
27586
|
+
const initialPrice = assertV4InitialPrice(snapshot.key, params.initialPrice);
|
|
27587
|
+
if (snapshot.status === "initialized") {
|
|
27588
|
+
if (snapshot.sqrtPriceX96 === initialPrice.sqrtPriceX96) return {
|
|
27589
|
+
status: "already-initialized-matching",
|
|
27590
|
+
snapshot,
|
|
27591
|
+
action: null
|
|
27592
|
+
};
|
|
27593
|
+
throw new PoolLifecycleError("POOL_STATE_MISMATCH", `V4 pool ${snapshot.poolId} is already initialized at a different price.`);
|
|
27594
|
+
}
|
|
27595
|
+
return {
|
|
27596
|
+
status: "ready",
|
|
27597
|
+
snapshot,
|
|
27598
|
+
action: buildV4InitializePoolTransaction({
|
|
27599
|
+
deployment: snapshot.deployment,
|
|
27600
|
+
key: {
|
|
27601
|
+
currencyA: snapshot.key.currency0,
|
|
27602
|
+
currencyB: snapshot.key.currency1,
|
|
27603
|
+
fee: snapshot.key.fee,
|
|
27604
|
+
tickSpacing: snapshot.key.tickSpacing,
|
|
27605
|
+
hooks: snapshot.key.hooks
|
|
27606
|
+
},
|
|
27607
|
+
initialPrice,
|
|
27608
|
+
preflight: snapshot
|
|
27609
|
+
})
|
|
27610
|
+
};
|
|
27611
|
+
}
|
|
27612
|
+
//#endregion
|
|
27613
|
+
//#region src/pool-lifecycle/v4/integrity.ts
|
|
27614
|
+
function invalid(message, cause) {
|
|
27615
|
+
throw new PoolLifecycleError("INVALID_INPUT", message, cause);
|
|
27616
|
+
}
|
|
27617
|
+
function record(value, label) {
|
|
27618
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return invalid(`${label} must be an object.`);
|
|
27619
|
+
return value;
|
|
27620
|
+
}
|
|
27621
|
+
function address(value, label) {
|
|
27622
|
+
if (typeof value !== "string" || !isAddress(value, { strict: true })) return invalid(`${label} must be a valid EVM address.`);
|
|
27623
|
+
return getAddress(value);
|
|
27624
|
+
}
|
|
27625
|
+
function poolId(value, label) {
|
|
27626
|
+
if (typeof value !== "string" || !/^0x[0-9a-fA-F]{64}$/.test(value)) return invalid(`${label} must be 32-byte hex.`);
|
|
27627
|
+
return value;
|
|
27628
|
+
}
|
|
27629
|
+
/**
|
|
27630
|
+
* Fully validate a signer-boundary V4 action and return its canonical frozen
|
|
27631
|
+
* capability. The target, value, PoolId, and calldata are all re-derived.
|
|
27632
|
+
*/
|
|
27633
|
+
function validatePreparedV4PoolAction(value) {
|
|
27634
|
+
const action = record(value, "Prepared V4 pool action");
|
|
27635
|
+
if (action.schemaVersion !== 1 || action.kind !== "v4-initialize") return invalid("Prepared V4 pool action schema or kind is unsupported.");
|
|
27636
|
+
if (typeof action.protocol !== "string") return invalid("Prepared V4 pool action protocol must be a string.");
|
|
27637
|
+
const transaction = record(action.transaction, "V4 action transaction");
|
|
27638
|
+
if (!Number.isSafeInteger(transaction.chainId) || Number(transaction.chainId) <= 0) return invalid("V4 transaction chainId must be a positive safe integer.");
|
|
27639
|
+
const chainId = Number(transaction.chainId);
|
|
27640
|
+
const to = address(transaction.to, "V4 transaction target");
|
|
27641
|
+
if (typeof transaction.data !== "string" || !/^0x(?:[0-9a-fA-F]{2})+$/.test(transaction.data)) return invalid("V4 transaction calldata must be non-empty hex bytes.");
|
|
27642
|
+
if (transaction.value !== 0n) return invalid("V4 PoolManager.initialize transactions must have zero value.");
|
|
27643
|
+
const identity = record(action.identity, "V4 action identity");
|
|
27644
|
+
if (typeof identity.deploymentId !== "string") return invalid("V4 action identity deploymentId must be a string.");
|
|
27645
|
+
const deployment = resolveV4LifecycleDeploymentById(identity.deploymentId);
|
|
27646
|
+
if (!deployment) throw new PoolLifecycleError("UNSUPPORTED_DEPLOYMENT", `No V4 lifecycle deployment is configured for id ${identity.deploymentId}.`);
|
|
27647
|
+
const key = validateV4PoolKey(record(identity.key, "V4 identity key"));
|
|
27648
|
+
const expectedPoolId = getV4PoolId(key);
|
|
27649
|
+
if (action.protocol !== deployment.protocol || identity.family !== deployment.family || identity.adapter !== deployment.adapter || identity.version !== deployment.version || identity.deploymentId !== deployment.deploymentId || identity.chainId !== chainId || chainId !== deployment.chainId || address(identity.poolManager, "V4 identity PoolManager") !== deployment.poolManager || address(identity.stateView, "V4 identity StateView") !== deployment.stateView || poolId(identity.poolId, "V4 identity PoolId").toLowerCase() !== expectedPoolId.toLowerCase()) return invalid("V4 action identity does not match the configured deployment and PoolKey.");
|
|
27650
|
+
const expectationRecord = record(action.expected, "V4 action expectation");
|
|
27651
|
+
let expectation;
|
|
27652
|
+
try {
|
|
27653
|
+
expectation = assertV4InitialPrice(key, expectationRecord);
|
|
27654
|
+
} catch (error) {
|
|
27655
|
+
if (error instanceof PoolLifecycleError) throw error;
|
|
27656
|
+
return invalid("V4 action expectation is invalid.", error);
|
|
27657
|
+
}
|
|
27658
|
+
const preflight = record(action.preflight, "V4 action preflight");
|
|
27659
|
+
if (preflight.status !== "uninitialized" || preflight.deploymentId !== deployment.deploymentId || typeof preflight.blockNumber !== "bigint" || preflight.blockNumber < 0n || poolId(preflight.poolId, "V4 preflight PoolId").toLowerCase() !== expectedPoolId.toLowerCase() || preflight.sqrtPriceX96 !== 0n) return invalid("V4 action requires a matching uninitialized preflight.");
|
|
27660
|
+
const expectedData = encodeFunctionData({
|
|
27661
|
+
abi: v4PoolManagerAbi,
|
|
27662
|
+
functionName: "initialize",
|
|
27663
|
+
args: [key, expectation.sqrtPriceX96]
|
|
27664
|
+
});
|
|
27665
|
+
if (to !== deployment.poolManager || transaction.data.toLowerCase() !== expectedData.toLowerCase()) return invalid("V4 transaction does not match its identity and initialization expectation.");
|
|
27666
|
+
return deployment;
|
|
27667
|
+
}
|
|
27668
|
+
function assertPreparedV4PoolAction(value) {
|
|
27669
|
+
validatePreparedV4PoolAction(value);
|
|
27670
|
+
}
|
|
27671
|
+
/** Deserialize the shared versioned envelope, then perform adapter validation. */
|
|
27672
|
+
function deserializePreparedV4PoolAction(serialized) {
|
|
27673
|
+
let value;
|
|
27674
|
+
try {
|
|
27675
|
+
value = deserializePreparedPoolAction(serialized);
|
|
27676
|
+
} catch (error) {
|
|
27677
|
+
throw new PoolLifecycleError("INVALID_INPUT", error instanceof Error ? error.message : "Serialized V4 pool action is invalid.", error);
|
|
27678
|
+
}
|
|
27679
|
+
assertPreparedV4PoolAction(value);
|
|
27680
|
+
return value;
|
|
27681
|
+
}
|
|
27682
|
+
//#endregion
|
|
27683
|
+
//#region src/pool-lifecycle/v4/simulate.ts
|
|
27684
|
+
/** Re-inspect, call, and estimate with the exact eventual sender and envelope. */
|
|
27685
|
+
async function simulateV4PoolAction(params) {
|
|
27686
|
+
if (!isAddress(params.account, { strict: true }) || getAddress(params.account) === V4_ZERO_ADDRESS) throw new PoolLifecycleError("INVALID_INPUT", "V4 simulation account must be a valid non-zero EVM address.");
|
|
27687
|
+
const deployment = validatePreparedV4PoolAction(params.action);
|
|
27688
|
+
const blockNumber = params.blockNumber ?? await params.publicClient.getBlockNumber();
|
|
27689
|
+
if (typeof blockNumber !== "bigint" || blockNumber < 0n) throw new PoolLifecycleError("INVALID_INPUT", "V4 simulation blockNumber must be non-negative.");
|
|
27690
|
+
const snapshot = await inspectV4Pool({
|
|
27691
|
+
publicClient: params.publicClient,
|
|
27692
|
+
deployment,
|
|
27693
|
+
key: {
|
|
27694
|
+
currencyA: params.action.identity.key.currency0,
|
|
27695
|
+
currencyB: params.action.identity.key.currency1,
|
|
27696
|
+
fee: params.action.identity.key.fee,
|
|
27697
|
+
tickSpacing: params.action.identity.key.tickSpacing,
|
|
27698
|
+
hooks: params.action.identity.key.hooks
|
|
27699
|
+
},
|
|
27700
|
+
blockNumber
|
|
27701
|
+
});
|
|
27702
|
+
if (snapshot.status !== "uninitialized") throw new PoolLifecycleError("POOL_STATE_MISMATCH", `V4 pool ${snapshot.poolId} is already initialized; refresh the action.`);
|
|
27703
|
+
const baseRequest = {
|
|
27704
|
+
account: getAddress(params.account),
|
|
27705
|
+
to: params.action.transaction.to,
|
|
27706
|
+
data: params.action.transaction.data,
|
|
27707
|
+
value: params.action.transaction.value
|
|
27708
|
+
};
|
|
27709
|
+
try {
|
|
27710
|
+
const callResult = await params.publicClient.call({
|
|
27711
|
+
...baseRequest,
|
|
27712
|
+
batch: false,
|
|
27713
|
+
blockNumber
|
|
27714
|
+
});
|
|
27715
|
+
if (!callResult.data || callResult.data === "0x") throw new PoolLifecycleError("SIMULATION_FAILED", "V4 PoolManager.initialize simulation returned no initial tick.");
|
|
27716
|
+
const returnedTick = Number(decodeFunctionResult({
|
|
27717
|
+
abi: v4PoolManagerAbi,
|
|
27718
|
+
functionName: "initialize",
|
|
27719
|
+
data: callResult.data
|
|
27720
|
+
}));
|
|
27721
|
+
if (!Number.isSafeInteger(returnedTick) || returnedTick < -887272 || returnedTick > 887272) throw new PoolLifecycleError("SIMULATION_FAILED", "V4 PoolManager.initialize returned an invalid tick.");
|
|
27722
|
+
const gasEstimate = await params.publicClient.estimateGas({
|
|
27723
|
+
...baseRequest,
|
|
27724
|
+
blockNumber
|
|
27725
|
+
});
|
|
27726
|
+
return {
|
|
27727
|
+
transaction: params.action.transaction,
|
|
27728
|
+
blockNumber,
|
|
27729
|
+
returnData: callResult.data,
|
|
27730
|
+
returnedTick,
|
|
27731
|
+
gasEstimate
|
|
27732
|
+
};
|
|
27733
|
+
} catch (error) {
|
|
27734
|
+
if (error instanceof PoolLifecycleError) throw error;
|
|
27735
|
+
throw new PoolLifecycleError("SIMULATION_FAILED", error instanceof Error ? error.message : "V4 pool initialization simulation failed.", error);
|
|
27736
|
+
}
|
|
27737
|
+
}
|
|
27738
|
+
//#endregion
|
|
27739
|
+
//#region src/pool-lifecycle/v4/verify.ts
|
|
27740
|
+
function assertLogBelongsToReceipt(log, receipt) {
|
|
27741
|
+
if (log.transactionHash !== receipt.transactionHash || log.blockHash !== receipt.blockHash || log.blockNumber !== receipt.blockNumber || log.transactionIndex !== receipt.transactionIndex || log.removed !== false) throw new PoolLifecycleError("POOL_STATE_MISMATCH", "Decoded V4 lifecycle log does not belong to the canonical receipt.");
|
|
27742
|
+
}
|
|
27743
|
+
/** Decode transaction-attributed PoolManager Initialize evidence without RPC reads. */
|
|
27744
|
+
function decodeV4PoolActionReceipt(action, receipt) {
|
|
27745
|
+
validatePreparedV4PoolAction(action);
|
|
27746
|
+
const initializations = [];
|
|
27747
|
+
for (const log of receipt.logs) {
|
|
27748
|
+
assertLogBelongsToReceipt(log, receipt);
|
|
27749
|
+
if (getAddress(log.address) !== action.identity.poolManager) continue;
|
|
27750
|
+
let decoded;
|
|
27751
|
+
try {
|
|
27752
|
+
decoded = decodeEventLog({
|
|
27753
|
+
abi: v4PoolManagerAbi,
|
|
27754
|
+
eventName: "Initialize",
|
|
27755
|
+
data: log.data,
|
|
27756
|
+
topics: log.topics
|
|
27757
|
+
});
|
|
27758
|
+
} catch {
|
|
27759
|
+
continue;
|
|
27760
|
+
}
|
|
27761
|
+
if (decoded.args.id.toLowerCase() !== action.identity.poolId.toLowerCase()) continue;
|
|
27762
|
+
initializations.push({
|
|
27763
|
+
poolId: decoded.args.id,
|
|
27764
|
+
currency0: getAddress(decoded.args.currency0),
|
|
27765
|
+
currency1: getAddress(decoded.args.currency1),
|
|
27766
|
+
fee: Number(decoded.args.fee),
|
|
27767
|
+
tickSpacing: Number(decoded.args.tickSpacing),
|
|
27768
|
+
hooks: getAddress(decoded.args.hooks),
|
|
27769
|
+
sqrtPriceX96: decoded.args.sqrtPriceX96,
|
|
27770
|
+
tick: Number(decoded.args.tick),
|
|
27771
|
+
logIndex: log.logIndex
|
|
27772
|
+
});
|
|
27773
|
+
}
|
|
27774
|
+
return {
|
|
27775
|
+
receiptStatus: receipt.status,
|
|
27776
|
+
initializations
|
|
27777
|
+
};
|
|
27778
|
+
}
|
|
27779
|
+
function unavailable(action, evidence, blockNumber, error, fallback) {
|
|
27780
|
+
return {
|
|
27781
|
+
verified: false,
|
|
27782
|
+
outcome: "verification-unavailable",
|
|
27783
|
+
blockNumber,
|
|
27784
|
+
identity: action.identity,
|
|
27785
|
+
state: null,
|
|
27786
|
+
evidence,
|
|
27787
|
+
warnings: [error instanceof Error ? error.message : fallback]
|
|
27788
|
+
};
|
|
27789
|
+
}
|
|
27790
|
+
function evaluate(action, evidence, snapshot, blockNumber) {
|
|
27791
|
+
if (evidence.receiptStatus === "reverted") return {
|
|
27792
|
+
verified: false,
|
|
27793
|
+
outcome: "reverted",
|
|
27794
|
+
blockNumber,
|
|
27795
|
+
identity: action.identity,
|
|
27796
|
+
state: snapshot,
|
|
27797
|
+
evidence,
|
|
27798
|
+
warnings: []
|
|
27799
|
+
};
|
|
27800
|
+
if (!snapshot || snapshot.status !== "initialized") return {
|
|
27801
|
+
verified: false,
|
|
27802
|
+
outcome: "not-initialized",
|
|
27803
|
+
blockNumber,
|
|
27804
|
+
identity: action.identity,
|
|
27805
|
+
state: snapshot,
|
|
27806
|
+
evidence,
|
|
27807
|
+
warnings: []
|
|
27808
|
+
};
|
|
27809
|
+
if (evidence.initializations.length !== 1) return {
|
|
27810
|
+
verified: false,
|
|
27811
|
+
outcome: "wrong-deployment",
|
|
27812
|
+
blockNumber,
|
|
27813
|
+
identity: action.identity,
|
|
27814
|
+
state: snapshot,
|
|
27815
|
+
evidence,
|
|
27816
|
+
warnings: [evidence.initializations.length === 0 ? "Receipt contains no Initialize event for the expected V4 PoolId." : "Receipt contains multiple Initialize events for the expected V4 PoolId."]
|
|
27817
|
+
};
|
|
27818
|
+
const event = evidence.initializations[0];
|
|
27819
|
+
const key = action.identity.key;
|
|
27820
|
+
if (event.currency0 !== key.currency0 || event.currency1 !== key.currency1 || event.fee !== key.fee || event.tickSpacing !== key.tickSpacing || event.hooks !== key.hooks || event.poolId.toLowerCase() !== action.identity.poolId.toLowerCase()) return {
|
|
27821
|
+
verified: false,
|
|
27822
|
+
outcome: "wrong-deployment",
|
|
27823
|
+
blockNumber,
|
|
27824
|
+
identity: action.identity,
|
|
27825
|
+
state: snapshot,
|
|
27826
|
+
evidence,
|
|
27827
|
+
warnings: ["Initialize evidence does not match the complete prepared V4 PoolKey."]
|
|
27828
|
+
};
|
|
27829
|
+
if (event.sqrtPriceX96 !== action.expected.sqrtPriceX96) return {
|
|
27830
|
+
verified: false,
|
|
27831
|
+
outcome: "already-initialized-different-price",
|
|
27832
|
+
blockNumber,
|
|
27833
|
+
identity: action.identity,
|
|
27834
|
+
state: snapshot,
|
|
27835
|
+
evidence,
|
|
27836
|
+
warnings: ["Initialize evidence contains a different initial price."]
|
|
27837
|
+
};
|
|
27838
|
+
if (snapshot.poolId.toLowerCase() !== action.identity.poolId.toLowerCase()) return {
|
|
27839
|
+
verified: false,
|
|
27840
|
+
outcome: "wrong-deployment",
|
|
27841
|
+
blockNumber,
|
|
27842
|
+
identity: action.identity,
|
|
27843
|
+
state: snapshot,
|
|
27844
|
+
evidence,
|
|
27845
|
+
warnings: ["Receipt-block StateView state is for a different V4 PoolId."]
|
|
27846
|
+
};
|
|
27847
|
+
if (snapshot.sqrtPriceX96 !== action.expected.sqrtPriceX96) return {
|
|
27848
|
+
verified: true,
|
|
27849
|
+
outcome: "initialized-then-price-moved",
|
|
27850
|
+
blockNumber,
|
|
27851
|
+
identity: action.identity,
|
|
27852
|
+
state: snapshot,
|
|
27853
|
+
evidence,
|
|
27854
|
+
warnings: ["V4 pool price moved after initialization in the receipt block."]
|
|
27855
|
+
};
|
|
27856
|
+
if (snapshot.tick !== event.tick) return {
|
|
27857
|
+
verified: false,
|
|
27858
|
+
outcome: "wrong-deployment",
|
|
27859
|
+
blockNumber,
|
|
27860
|
+
identity: action.identity,
|
|
27861
|
+
state: snapshot,
|
|
27862
|
+
evidence,
|
|
27863
|
+
warnings: ["Initialize tick does not match the unchanged receipt-block V4 state."]
|
|
27864
|
+
};
|
|
27865
|
+
return {
|
|
27866
|
+
verified: true,
|
|
27867
|
+
outcome: "created-and-initialized",
|
|
27868
|
+
blockNumber,
|
|
27869
|
+
identity: action.identity,
|
|
27870
|
+
state: snapshot,
|
|
27871
|
+
evidence,
|
|
27872
|
+
warnings: []
|
|
27873
|
+
};
|
|
27874
|
+
}
|
|
27875
|
+
/** Verify exact calldata, canonical receipt/event, and receipt-block StateView state. */
|
|
27876
|
+
async function verifyV4PoolAction(params) {
|
|
27877
|
+
const { publicClient, action, receipt } = params;
|
|
27878
|
+
const deployment = validatePreparedV4PoolAction(action);
|
|
27879
|
+
const emptyEvidence = {
|
|
27880
|
+
receiptStatus: receipt.status,
|
|
27881
|
+
initializations: []
|
|
27882
|
+
};
|
|
27883
|
+
let activeChainId;
|
|
27884
|
+
let transaction;
|
|
27885
|
+
let canonicalReceipt;
|
|
27886
|
+
try {
|
|
27887
|
+
[activeChainId, transaction, canonicalReceipt] = await Promise.all([
|
|
27888
|
+
publicClient.getChainId(),
|
|
27889
|
+
publicClient.getTransaction({ hash: receipt.transactionHash }),
|
|
27890
|
+
publicClient.getTransactionReceipt({ hash: receipt.transactionHash })
|
|
27891
|
+
]);
|
|
27892
|
+
} catch (error) {
|
|
27893
|
+
return unavailable(action, emptyEvidence, receipt.blockNumber, error, "Failed to load the canonical V4 transaction and receipt.");
|
|
27894
|
+
}
|
|
27895
|
+
const nullableAddressMatches = (left, right) => left === null || right === null ? left === right : getAddress(left) === getAddress(right);
|
|
27896
|
+
const target = action.identity.poolManager;
|
|
27897
|
+
const suppliedMatchesCanonical = receipt.transactionHash === canonicalReceipt.transactionHash && receipt.blockHash === canonicalReceipt.blockHash && receipt.blockNumber === canonicalReceipt.blockNumber && receipt.transactionIndex === canonicalReceipt.transactionIndex && receipt.status === canonicalReceipt.status && getAddress(receipt.from) === getAddress(canonicalReceipt.from) && nullableAddressMatches(receipt.to, canonicalReceipt.to);
|
|
27898
|
+
const receiptDestinationMatches = canonicalReceipt.to !== null && getAddress(canonicalReceipt.to) === target;
|
|
27899
|
+
const transactionMatches = transaction.hash === canonicalReceipt.transactionHash && transaction.to !== null && getAddress(transaction.to) === target && transaction.input.toLowerCase() === action.transaction.data.toLowerCase() && transaction.value === action.transaction.value && transaction.blockHash === canonicalReceipt.blockHash && transaction.blockNumber === canonicalReceipt.blockNumber && transaction.transactionIndex === canonicalReceipt.transactionIndex && getAddress(transaction.from) === getAddress(canonicalReceipt.from);
|
|
27900
|
+
if (activeChainId !== action.transaction.chainId || !suppliedMatchesCanonical || !receiptDestinationMatches || !transactionMatches) return {
|
|
27901
|
+
verified: false,
|
|
27902
|
+
outcome: "wrong-deployment",
|
|
27903
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27904
|
+
identity: action.identity,
|
|
27905
|
+
state: null,
|
|
27906
|
+
evidence: emptyEvidence,
|
|
27907
|
+
warnings: ["Receipt, transaction, client, or V4 deployment does not match the action."]
|
|
27908
|
+
};
|
|
27909
|
+
let evidence;
|
|
27910
|
+
try {
|
|
27911
|
+
evidence = decodeV4PoolActionReceipt(action, canonicalReceipt);
|
|
27912
|
+
} catch (error) {
|
|
27913
|
+
return {
|
|
27914
|
+
verified: false,
|
|
27915
|
+
outcome: "wrong-deployment",
|
|
27916
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27917
|
+
identity: action.identity,
|
|
27918
|
+
state: null,
|
|
27919
|
+
evidence: emptyEvidence,
|
|
27920
|
+
warnings: [error instanceof Error ? error.message : "V4 receipt attribution failed."]
|
|
27921
|
+
};
|
|
27922
|
+
}
|
|
27923
|
+
let blockHashBefore;
|
|
27924
|
+
try {
|
|
27925
|
+
blockHashBefore = (await publicClient.getBlock({
|
|
27926
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27927
|
+
includeTransactions: false
|
|
27928
|
+
})).hash;
|
|
27929
|
+
} catch (error) {
|
|
27930
|
+
return unavailable(action, evidence, canonicalReceipt.blockNumber, error, "Failed to load the V4 receipt block.");
|
|
27931
|
+
}
|
|
27932
|
+
if (blockHashBefore !== canonicalReceipt.blockHash) return unavailable(action, evidence, canonicalReceipt.blockNumber, /* @__PURE__ */ new Error("Receipt block is no longer canonical; retry with a fresh receipt."), "Receipt block is no longer canonical.");
|
|
27933
|
+
if (canonicalReceipt.status === "reverted") return evaluate(action, evidence, null, canonicalReceipt.blockNumber);
|
|
27934
|
+
let snapshot;
|
|
27935
|
+
try {
|
|
27936
|
+
snapshot = await inspectV4Pool({
|
|
27937
|
+
publicClient,
|
|
27938
|
+
deployment,
|
|
27939
|
+
key: {
|
|
27940
|
+
currencyA: action.identity.key.currency0,
|
|
27941
|
+
currencyB: action.identity.key.currency1,
|
|
27942
|
+
fee: action.identity.key.fee,
|
|
27943
|
+
tickSpacing: action.identity.key.tickSpacing,
|
|
27944
|
+
hooks: action.identity.key.hooks
|
|
27945
|
+
},
|
|
27946
|
+
blockNumber: canonicalReceipt.blockNumber
|
|
27947
|
+
});
|
|
27948
|
+
} catch (error) {
|
|
27949
|
+
if (error instanceof PoolLifecycleError) return {
|
|
27950
|
+
verified: false,
|
|
27951
|
+
outcome: "wrong-deployment",
|
|
27952
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27953
|
+
identity: action.identity,
|
|
27954
|
+
state: null,
|
|
27955
|
+
evidence,
|
|
27956
|
+
warnings: [error.message]
|
|
27957
|
+
};
|
|
27958
|
+
return unavailable(action, evidence, canonicalReceipt.blockNumber, error, "Failed to read receipt-block V4 state.");
|
|
27959
|
+
}
|
|
27960
|
+
try {
|
|
27961
|
+
if ((await publicClient.getBlock({
|
|
27962
|
+
blockNumber: canonicalReceipt.blockNumber,
|
|
27963
|
+
includeTransactions: false
|
|
27964
|
+
})).hash !== canonicalReceipt.blockHash) return unavailable(action, evidence, canonicalReceipt.blockNumber, /* @__PURE__ */ new Error("Receipt block changed during verification; retry with a fresh receipt."), "Receipt block changed during verification.");
|
|
27965
|
+
} catch (error) {
|
|
27966
|
+
return unavailable(action, evidence, canonicalReceipt.blockNumber, error, "Failed to reconfirm the canonical V4 receipt block.");
|
|
27967
|
+
}
|
|
27968
|
+
return evaluate(action, evidence, snapshot, canonicalReceipt.blockNumber);
|
|
27969
|
+
}
|
|
27970
|
+
//#endregion
|
|
24051
27971
|
//#region src/index.ts
|
|
24052
27972
|
/**
|
|
24053
27973
|
* @packageDocumentation
|
|
@@ -24114,6 +28034,6 @@ var FeeManagerClient = class extends SubgraphClient {
|
|
|
24114
28034
|
* See {@link SmartRewards} for detailed API documentation.
|
|
24115
28035
|
*/
|
|
24116
28036
|
//#endregion
|
|
24117
|
-
export { AERODROME_PROTOCOLS, ALGEBRA_INTEGRAL_PROTOCOLS, ALGEBRA_INTEGRAL_V_2_0_PROTOCOLS, ALGEBRA_PROTOCOLS, AMMType, API_URLS, AlgebgraHookBeacons, Chain, ChainId, DIRECTIONAL_ALGEBRA_PROTOCOLS, FEE_MANAGER_ABI, FeeManagerClient, MultiPositionManagers, POOLSHARK_PROTOCOLS, PoolClient, Protocol, QuickSwapQuoterV2, QuoterV2AlgebgraIntegral, QuoterV2AlgebgraIntegral21, QuoterV2Factory, QuoterV2Shadow, QuoterV2Thick, SHADOW_PROTOCOLS, SingleAssetDepositClient, SmartRewards, StakingClient, StakingProtocol, SteerClient, StrykePositionManagers, SubgraphClient, SubgraphVaultClient, TEST_UNISWAP_JIT_HOOK_BEACON, UNISWAP_V4_BEACON_NAMES, UNISWAP_V4_HOOK_BEACON_NAMES, UNISWAP_V4_NO_ORACLE_BEACON, UniswapHookBeacons, UniswapV3PoolABI, UniswapV3QuoterABI, UniswapV4Beacons, VAULT_FEES_ABI, VaultClient, abis, apechainAddresses, arbitrumAddresses, arbitrumgoerliAddresses, arthswapConfig, astarAddresses, astarzkevmAddresses, avalancheAddresses, bartiotestAddresses, baseAddresses, baseSwapConfig, basexConfig, beraAddresses, bittensorAddresses, bittensorUniV3Config, blastAddresses, bscAddresses, calculateLimitPrice, calculateSwapAmount, camelotConfig, celoAddresses, chainIdToName, chainNameToId, crustConfig, deprecatedBundlesURL, determineSwapDirection, equilibreConfig, erc1155Abi, erc20Abi, erc721Abi, estimateLpTokens, ethAddresses, evmosAddresses, fantomAddresses, fenixConfig, filecoinAddresses, flareAddresses, forgeConfig, fusionxConfig, getAmmConfig, getAmmConfigByChainId, getApiUrl, getBeaconNameByProtocol, getContractAddressByChainIdAndContractName, getExpectedParamType, getFactoryAddress, getInitCodeHash, getNFTManagerAddress, getNetworkByChainId, getPoolHelperByChainId, getPoolSlot0, getProtcolTypeByAmmType, getProtocolBySubgraph, getProtocolConfigByBeacon, getProtocolContractAddresses, getProtocolInfoByChainId, getProtocolInfoByName, getProtocolSubgraphURL, getProtocolTypeByBeacon, getProtocolsForChainId, getQuoterV2Address, getStabilityVaultsPeripheryAddress, getStabilityVaultsSubgraphUrl, getSubgraphUrlByChainId, getSupportedChainByChainId, getSupportedChainIds, getSupportedChains, getSwapRouterAddress, getTheGraphResolverUrl, getTickLensAddress, getUniswapV4BeaconSupportedChains, getVaultExecutionContext, getVaultReserves, glyphConfig, goerliAddresses, hemiAddresses, henjinConfig, herculesConfig, horizaConfig, isAerodromeVault, isAlgebraDirectionProtocol, isAlgebraIntegral21QuoteParams, isAlgebraIntegralProtocol, isAlgebraIntegralV2Protocol, isAlgebraProtocol, isAlgebraProtocolBySubgraph, isAlgebraQuoteParams, isPoolSharkProtocol, isShadowProtocol, isShadowQuoteParams, isSingleAssetDepositSupported, isThickQuoteParams, isThickV2Protocol, isUniswapQuoteParams, isUniswapV4Beacon, isUniswapV4BeaconAvailableOnChain, isUniswapV4HookBeacon, isValidStakingProtocol, katanaAddresses, katanaConfig, kavaAddresses, kimConfig, kinetixConfig, lineaAddresses, linehubConfig, localhostAddresses, lynexConfig, maiaConfig, mantaAddresses, mantleAddresses, metaVaultConfig, metisAddresses, modeAddresses, moonbeamAddresses, mumbaiAddresses, nestVaultConfig, networks, normalizeProtocol, novaswapConfig, okxtestnetAddresses, optimismAddresses, optimismgoerliAddresses, pancakeSwapConfig, polygonAddresses, polyzkevmAddresses, poolsharkConfig, quickSwapAlgebraConfig, quickSwapConfig, quickSwapIntegralConfig, quickSwapUniv3Config, retroConfig, robinhoodAddresses, rootstockAddresses, sagaAddresses, scrollAddresses, seiAddresses, shadowConfig, shouldValidateUniswapV4VaultHook, simulateSwap, singleTokenDepositAbi, soneiumAddresses, sonicAddresses, spark32Config, sparkConfig, stabilityVaultsConfig, steerSubgraphConfig, supswapConfig, sushiConfig, swapmodeConfig, swapsicleConfig, taikoAddresses, telosAddresses, thenaConfig, thickConfig, thrusterConfig, thundercoreAddresses, uniAddresses, uniswapConfig, validateQuoteParams, validateSwapParams, xlayerAddresses, zetaAddresses, zircuitAddresses };
|
|
28037
|
+
export { AERODROME_PROTOCOLS, ALGEBRA_INTEGRAL_PROTOCOLS, ALGEBRA_INTEGRAL_V_2_0_PROTOCOLS, ALGEBRA_LIFECYCLE_DEPLOYMENTS, ALGEBRA_PROTOCOLS, AMMType, API_URLS, AlgebgraHookBeacons, CURRENT_V4_LIFECYCLE_DEPLOYMENTS, Chain, ChainId, DIRECTIONAL_ALGEBRA_PROTOCOLS, FEE_MANAGER_ABI, FeeManagerClient, MAX_SQRT_RATIO, MIN_SQRT_RATIO, MultiPositionManagers, POOLSHARK_PROTOCOLS, POOL_LIFECYCLE_DEPLOYMENTS, PREPARED_POOL_ACTION_SERIALIZATION_VERSION, PoolClient, PoolLifecycleError, Protocol, QuickSwapQuoterV2, QuoterV2AlgebgraIntegral, QuoterV2AlgebgraIntegral21, QuoterV2Factory, QuoterV2Shadow, QuoterV2Thick, SHADOW_PROTOCOLS, SingleAssetDepositClient, SmartRewards, StakingClient, StakingProtocol, SteerClient, StrykePositionManagers, SubgraphClient, SubgraphVaultClient, TEST_UNISWAP_JIT_HOOK_BEACON, UNISWAP_V4_BEACON_NAMES, UNISWAP_V4_HOOK_BEACON_NAMES, UNISWAP_V4_NO_ORACLE_BEACON, UniswapHookBeacons, UniswapV3PoolABI, UniswapV3QuoterABI, UniswapV4Beacons, V3_CONFIG_PROTOCOLS, V3_LIFECYCLE_DEPLOYMENTS, V4_ALL_HOOK_MASK, V4_DYNAMIC_FEE_FLAG, V4_LIFECYCLE_DEPLOYMENTS, V4_LIFECYCLE_DEPLOYMENTS_BY_ID, V4_MAX_STATIC_FEE, V4_MAX_TICK_SPACING, V4_ZERO_ADDRESS, VAULT_FEES_ABI, VaultClient, abis, algebraCustomPoolEntryPointAbi, algebraDirectionalPoolStateAbi, algebraIntegralPairFactoryAbi, algebraIntegralPluginDataFactoryAbi, algebraIntegralPoolStateAbi, algebraLegacyPoolStateAbi, algebraPairFactoryAbi, algebraPoolBaseAbi, apechainAddresses, arbitrumAddresses, arbitrumgoerliAddresses, arthswapConfig, assertAlgebraInitialPrice, assertPreparedV3PoolAction, assertPreparedV4PoolAction, assertV3InitialPrice, assertV4InitialPrice, astarAddresses, astarzkevmAddresses, avalancheAddresses, bartiotestAddresses, baseAddresses, baseSwapConfig, basexConfig, beraAddresses, bittensorAddresses, bittensorUniV3Config, blastAddresses, bscAddresses, buildAlgebraCreatePoolTransaction, buildAlgebraInitializePoolTransaction, buildV3CreateAndInitializeTransaction, buildV3CreatePoolTransaction, buildV3InitializePoolTransaction, buildV4InitializePoolTransaction, calculateLimitPrice, calculateSwapAmount, camelotConfig, canonicalizeAlgebraPoolKey, canonicalizeV3PoolKey, canonicalizeV4PoolKey, celoAddresses, chainIdToName, chainNameToId, crustConfig, decodeAlgebraPoolActionReceipt, decodeV3PoolActionReceipt, decodeV4PoolActionReceipt, deprecatedBundlesURL, deserializePreparedAlgebraPoolAction, deserializePreparedPoolAction, deserializePreparedV3PoolAction, deserializePreparedV4PoolAction, determineSwapDirection, encodeCurrencyInitialSqrtPriceX96, encodeInitialSqrtPriceX96, encodeSqrtRatioX96, equilibreConfig, erc1155Abi, erc20Abi, erc721Abi, estimateLpTokens, ethAddresses, evmosAddresses, fantomAddresses, fenixConfig, filecoinAddresses, flareAddresses, forgeConfig, fusionxConfig, getAmmConfig, getAmmConfigByChainId, getApiUrl, getBeaconNameByProtocol, getContractAddressByChainIdAndContractName, getExpectedParamType, getFactoryAddress, getInitCodeHash, getNFTManagerAddress, getNetworkByChainId, getPoolHelperByChainId, getPoolSlot0, getProtcolTypeByAmmType, getProtocolBySubgraph, getProtocolConfigByBeacon, getProtocolContractAddresses, getProtocolInfoByChainId, getProtocolInfoByName, getProtocolSubgraphURL, getProtocolTypeByBeacon, getProtocolsForChainId, getQuoterV2Address, getStabilityVaultsPeripheryAddress, getStabilityVaultsSubgraphUrl, getSubgraphUrlByChainId, getSupportedChainByChainId, getSupportedChainIds, getSupportedChains, getSwapRouterAddress, getTheGraphResolverUrl, getTickLensAddress, getUniswapV4BeaconSupportedChains, getV4LifecycleDeploymentId, getV4PoolId, getVaultExecutionContext, getVaultReserves, glyphConfig, goerliAddresses, hemiAddresses, henjinConfig, herculesConfig, horizaConfig, inspectAlgebraCustomPoolEntryPoint, inspectAlgebraPool, inspectV3Pool, inspectV4Pool, integerSqrt, isAerodromeVault, isAlgebraDirectionProtocol, isAlgebraIntegral21QuoteParams, isAlgebraIntegralProtocol, isAlgebraIntegralV2Protocol, isAlgebraProtocol, isAlgebraProtocolBySubgraph, isAlgebraQuoteParams, isPoolSharkProtocol, isShadowProtocol, isShadowQuoteParams, isSingleAssetDepositSupported, isThickQuoteParams, isThickV2Protocol, isUniswapQuoteParams, isUniswapV4Beacon, isUniswapV4BeaconAvailableOnChain, isUniswapV4HookBeacon, isValidStakingProtocol, katanaAddresses, katanaConfig, kavaAddresses, kimConfig, kinetixConfig, lineaAddresses, linehubConfig, localhostAddresses, lynexConfig, maiaConfig, mantaAddresses, mantleAddresses, metaVaultConfig, metisAddresses, modeAddresses, moonbeamAddresses, mumbaiAddresses, nestVaultConfig, networks, normalizeProtocol, novaswapConfig, okxtestnetAddresses, optimismAddresses, optimismgoerliAddresses, pancakeSwapConfig, parseExactDecimal, polygonAddresses, polyzkevmAddresses, poolsharkConfig, prepareAlgebraPool, prepareV3CreateAndInitialize, prepareV3CreatePool, prepareV3InitializePool, prepareV4Initialize, quickSwapAlgebraConfig, quickSwapConfig, quickSwapIntegralConfig, quickSwapUniv3Config, resolveAlgebraLifecycleDeployment, resolveCurrentV4LifecycleDeployment, resolvePoolLifecycleDeployment, resolveV3LifecycleDeployment, resolveV4LifecycleDeployment, resolveV4LifecycleDeploymentById, retroConfig, robinhoodAddresses, rootstockAddresses, sagaAddresses, scrollAddresses, seiAddresses, serializePreparedPoolAction, shadowConfig, shouldValidateUniswapV4VaultHook, simulateAlgebraPoolAction, simulateSwap, simulateV3PoolAction, simulateV4PoolAction, singleTokenDepositAbi, soneiumAddresses, sonicAddresses, sortErc20Pair, sortEvmCurrencyPair, spark32Config, sparkConfig, stabilityVaultsConfig, steerSubgraphConfig, supswapConfig, sushiConfig, swapmodeConfig, swapsicleConfig, taikoAddresses, telosAddresses, thenaConfig, thickConfig, thrusterConfig, thundercoreAddresses, uniAddresses, uniswapConfig, v3FactoryAbi, v3PoolAbi, v3PoolInitializerAbi, v4PoolKeysEqual, v4PoolManagerAbi, v4StateViewAbi, validateAlgebraLifecycleDeployment, validatePreparedAlgebraPoolAction, validatePreparedV3PoolAction, validatePreparedV4PoolAction, validateQuoteParams, validateSqrtPriceX96, validateSwapParams, validateV4LifecycleDeployment, validateV4PoolKey, verifyAlgebraPoolAction, verifyV3PoolAction, verifyV4PoolAction, xlayerAddresses, zetaAddresses, zircuitAddresses };
|
|
24118
28038
|
|
|
24119
28039
|
//# sourceMappingURL=index.mjs.map
|