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