Amplification Parameter
diff --git a/packages/nextjs/hooks/gyro/index.ts b/packages/nextjs/hooks/gyro/index.ts
index 4854d9c9..2c57dd6a 100644
--- a/packages/nextjs/hooks/gyro/index.ts
+++ b/packages/nextjs/hooks/gyro/index.ts
@@ -4,3 +4,5 @@ export * from "./drawLiquidityECLP";
export * from "./useValidateEclpParams";
export * from "./useAutofillStarterParams";
export * from "./useEclpSpotPrice";
+export * from "./useEclpInitAmountsRatio";
+export * from "./useInvertEclpParams";
diff --git a/packages/nextjs/hooks/gyro/useEclpInitAmountsRatio.ts b/packages/nextjs/hooks/gyro/useEclpInitAmountsRatio.ts
new file mode 100644
index 00000000..1f96ed5b
--- /dev/null
+++ b/packages/nextjs/hooks/gyro/useEclpInitAmountsRatio.ts
@@ -0,0 +1,38 @@
+import { useEclpSpotPrice } from "./useEclpSpotPrice";
+
+type UseEclpInitAmountsRatio = {
+ alpha: number;
+ beta: number;
+ c: number;
+ s: number;
+ lambda: number;
+ rateA: number;
+ rateB: number;
+};
+
+/**
+ * helper function for calculation of proper token amounts for ECLP initialization
+ * logic provided by @joaobrunoah
+ */
+export function useEclpInitAmountsRatio({ alpha, beta, c, s, lambda, rateA, rateB }: UseEclpInitAmountsRatio) {
+ const { poolSpotPrice: spotPriceWithoutRate } = useEclpSpotPrice();
+ if (!spotPriceWithoutRate || !alpha || !beta || !c || !s || !lambda || !rateA || !rateB) return undefined;
+
+ const rHint = 1000;
+ const tauAlpha = getTau(alpha, c, s, lambda);
+ const tauBeta = getTau(beta, c, s, lambda);
+ const tauSpotPrice = getTau(spotPriceWithoutRate, c, s, lambda);
+
+ const amountTokenA =
+ rateA * rHint * (c * lambda * tauBeta[0] + s * tauBeta[1]) - (c * lambda * tauSpotPrice[0] + s * tauSpotPrice[1]);
+ const amountTokenB =
+ rateB * rHint * (-s * lambda * tauAlpha[0] + c * tauAlpha[1]) -
+ (-s * lambda * tauSpotPrice[0] + c * tauSpotPrice[1]);
+ const ratio = amountTokenA / amountTokenB;
+
+ return ratio;
+}
+
+function getTau(price: number, c: number, s: number, lambda: number) {
+ return [price * c - s, (c + s * price) / lambda];
+}
diff --git a/packages/nextjs/hooks/gyro/useInvertEclpParams.ts b/packages/nextjs/hooks/gyro/useInvertEclpParams.ts
new file mode 100644
index 00000000..488d351b
--- /dev/null
+++ b/packages/nextjs/hooks/gyro/useInvertEclpParams.ts
@@ -0,0 +1,36 @@
+import { useCallback } from "react";
+import { usePoolCreationStore } from "../v3";
+import { formatUnits, parseUnits } from "viem";
+import { formatEclpParamValues } from "~~/utils/gryo";
+
+const D18 = 10n ** 18n;
+
+export function useInvertEclpParams() {
+ const { eclpParams, updateEclpParam, updatePool, tokenConfigs } = usePoolCreationStore();
+
+ const invertEclpParams = useCallback(() => {
+ const { alpha, beta, peakPrice, c, s, usdPerTokenInput0, usdPerTokenInput1 } = eclpParams;
+
+ const invertedAlpha = Number(formatUnits((D18 * D18) / parseUnits(alpha, 18), 18));
+ const invertedBeta = Number(formatUnits((D18 * D18) / parseUnits(beta, 18), 18));
+ const invertedPeakPrice = Number(formatUnits((D18 * D18) / parseUnits(peakPrice, 18), 18));
+
+ const invertedParams = {
+ alpha: formatEclpParamValues(invertedBeta), // flip alpha to inverted beta
+ beta: formatEclpParamValues(invertedAlpha), // flip beta to inverted alpha
+ peakPrice: formatEclpParamValues(invertedPeakPrice),
+ c: s, // flip c to s
+ s: c, // flip s to c
+ usdPerTokenInput0: usdPerTokenInput1,
+ usdPerTokenInput1: usdPerTokenInput0,
+ };
+
+ // Use a timeout to ensure this update happens after other effects
+ setTimeout(() => {
+ updateEclpParam(invertedParams);
+ updatePool({ tokenConfigs: [...tokenConfigs].reverse() });
+ }, 0);
+ }, [eclpParams, updateEclpParam, updatePool, tokenConfigs]);
+
+ return { invertEclpParams };
+}
diff --git a/packages/nextjs/hooks/v3/usePoolCreationStore.ts b/packages/nextjs/hooks/v3/usePoolCreationStore.ts
index 76ccd020..fee49d5d 100644
--- a/packages/nextjs/hooks/v3/usePoolCreationStore.ts
+++ b/packages/nextjs/hooks/v3/usePoolCreationStore.ts
@@ -70,8 +70,6 @@ export interface PoolCreationStore {
swapToBoostedTx: TransactionDetails;
eclpParams: EclpParams;
reClammParams: ReClammParams;
- isChooseTokenAmountsModalOpen: boolean;
- setIsChooseTokenAmountsModalOpen: (isOpen: boolean) => void;
updatePool: (updates: Partial
) => void;
updateTokenConfig: (index: number, updates: Partial) => void;
updateEclpParam: (updates: Partial) => void;
@@ -149,8 +147,6 @@ export const usePoolCreationStore = create(
set => ({
...initialPoolCreationState,
updatePool: (updates: Partial) => set(state => ({ ...state, ...updates })),
- setIsChooseTokenAmountsModalOpen: (isOpen: boolean) =>
- set(state => ({ ...state, isChooseTokenAmountsModalOpen: isOpen })),
updateTokenConfig: (index: number, updates: Partial) =>
set(state => {
const newTokenConfigs = [...state.tokenConfigs];
diff --git a/packages/nextjs/hooks/v3/useValidateCreationInputs.ts b/packages/nextjs/hooks/v3/useValidateCreationInputs.ts
index b8f314ed..653aac0c 100644
--- a/packages/nextjs/hooks/v3/useValidateCreationInputs.ts
+++ b/packages/nextjs/hooks/v3/useValidateCreationInputs.ts
@@ -2,7 +2,7 @@ import { PoolType, STABLE_POOL_CONSTRAINTS, TokenType } from "@balancer/sdk";
import { useQueryClient } from "@tanstack/react-query";
import { isAddress } from "viem";
import { useEclpParamValidations } from "~~/hooks/gyro";
-import { usePoolCreationStore, useValidateHooksContract } from "~~/hooks/v3";
+import { usePoolCreationStore, useValidateHooksContract, useValidateInitializationInputs } from "~~/hooks/v3";
import { MAX_POOL_NAME_LENGTH, MAX_POOL_SYMBOL_LENGTH } from "~~/utils/constants";
export function useValidateCreationInputs() {
@@ -26,6 +26,8 @@ export function useValidateCreationInputs() {
const { baseParamsError, derivedParamsError } = useEclpParamValidations(eclpParams);
+ const { isInitializePoolInputsValid } = useValidateInitializationInputs();
+
const isTypeValid = poolType !== undefined;
const isValidTokenWeights =
@@ -47,7 +49,6 @@ export function useValidateCreationInputs() {
}
return true;
}) && isValidTokenWeights;
-
// Check tanstack query cache for pool hooks contract validity
const { isValidPoolHooksContract } = useValidateHooksContract(poolHooksContract);
@@ -79,7 +80,8 @@ export function useValidateCreationInputs() {
symbol.length <= MAX_POOL_SYMBOL_LENGTH &&
isValidTokenWeights;
- const isPoolCreationInputValid = isTypeValid && isTokensValid && isParametersValid && isInfoValid;
+ const isPoolCreationInputValid =
+ isTypeValid && isTokensValid && isParametersValid && isInfoValid && isInitializePoolInputsValid;
return { isParametersValid, isTypeValid, isInfoValid, isTokensValid, isPoolCreationInputValid, isValidTokenWeights };
}