diff --git a/src/components/v3/IncreaseLiquidityV3/index.tsx b/src/components/v3/IncreaseLiquidityV3/index.tsx index 9ac6c9f27..fb0e7ef12 100644 --- a/src/components/v3/IncreaseLiquidityV3/index.tsx +++ b/src/components/v3/IncreaseLiquidityV3/index.tsx @@ -32,6 +32,7 @@ import { ApprovalState, useApproveCallback } from 'hooks/useV3ApproveCallback'; import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, UNI_NFT_POSITION_MANAGER_ADDRESS, + ALGEBRA_INTEGRAL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, } from 'constants/v3/addresses'; import { useUSDCValue } from 'hooks/v3/useUSDCPrice'; import CurrencyInputPanel from 'components/v3/CurrencyInputPanel'; @@ -50,6 +51,7 @@ import { unwrappedToken } from 'utils/unwrappedToken'; import { useWeb3Modal } from '@web3modal/ethers5/react'; import { TransactionType } from 'models/enums'; import { wrappedCurrency } from 'utils/wrappedCurrency'; +import { GlobalConst } from 'constants/index'; interface IncreaseLiquidityV3Props { positionDetails: PositionPool; @@ -110,6 +112,7 @@ export default function IncreaseLiquidityV3({ depositBDisabled, ticksAtLimit, feeTier, + liquidityRangeType, } = useV3DerivedMintInfo( baseCurrency ?? undefined, quoteCurrency ?? undefined, @@ -120,9 +123,13 @@ export default function IncreaseLiquidityV3({ const positionManagerAddress = useMemo(() => { if (positionDetails.isUni) { return UNI_NFT_POSITION_MANAGER_ADDRESS[chainId]; + } else if ( + liquidityRangeType === GlobalConst.v3LiquidityRangeType.ALGEBRA_INTEGRAL + ) { + return ALGEBRA_INTEGRAL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId]; } return NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId]; - }, [chainId, positionDetails]); + }, [chainId, positionDetails, liquidityRangeType]); const { onFieldAInput, onFieldBInput } = useV3MintActionHandlers(noLiquidity); diff --git a/src/config/layerx.json b/src/config/layerx.json index a2d13d0ff..52ebbf50d 100644 --- a/src/config/layerx.json +++ b/src/config/layerx.json @@ -99,10 +99,14 @@ "ichi": { "available": false }, + "algebraIntegral": { + "available": true + }, "lpLock": { "available": false }, "maxChunks": 20, "blocksPerFetch": 25, - "poolInitCodeHash": "0xbce37a54eab2fcd71913a0d40723e04238970e7fc1159bfd58ad5b79531697e7" + "poolInitCodeHash": "0xbce37a54eab2fcd71913a0d40723e04238970e7fc1159bfd58ad5b79531697e7", + "algebraIntegralPoolInitCodeHash": "0x4b9e4a8044ce5695e06fce9421a63b6f5c3db8a561eebb30ea4c775469e36eaf" } diff --git a/src/constants/index.ts b/src/constants/index.ts index b02350879..3bfe65f26 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -328,6 +328,7 @@ export const GlobalConst = { UNIPILOT_RANGE: '2', DEFIEDGE_RANGE: '3', STEER_RANGE: '4', + ALGEBRA_INTEGRAL: '5', }, walletName: { METAMASK: 'Metamask', diff --git a/src/constants/v3/addresses.ts b/src/constants/v3/addresses.ts index da991b984..5b03ec60a 100644 --- a/src/constants/v3/addresses.ts +++ b/src/constants/v3/addresses.ts @@ -150,6 +150,9 @@ export const POOL_DEPLOYER_ADDRESS: AddressMap = { [ChainId.ZKEVM]: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', [ChainId.LAYERX]: '0x56c2162254b0E4417288786eE402c2B41d4e181e', }; +export const ALGEBRA_INTEGRAL_POOL_DEPLOYER_ADDRESS: AddressMap = { + [ChainId.LAYERX]: '0x9815e9311a13E5b0DC93E6255b8B45Cd8b6c9773', +}; export const QUOTER_ADDRESSES: AddressMap = { [ChainId.MATIC]: '0xa15F0D7377B2A0C0c10db057f641beD21028FC89', @@ -182,6 +185,10 @@ export const SWAP_ROUTER_ADDRESS: AddressMap = { [ChainId.MATIC]: '0xfaa746afc5ff7d5ef0aa469bb26ddd6cd8f13911', }; +export const ALGEBRA_INTEGRAL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: AddressMap = { + [ChainId.LAYERX]: '0x60cdF877e536F6384D8D5aA20c266A8Ad5AE0a4c', +}; + export const NONFUNGIBLE_POSITION_MANAGER_ADDRESSES: AddressMap = { [ChainId.MATIC]: '0x8eF88E4c7CfbbaC1C163f7eddd4B578792201de6', [ChainId.DOGECHAIN]: '0x0b012055F770AE7BB7a8303968A7Fb6088A2296e', diff --git a/src/hooks/v3/usePools.ts b/src/hooks/v3/usePools.ts index 37a265e54..d978fe77c 100644 --- a/src/hooks/v3/usePools.ts +++ b/src/hooks/v3/usePools.ts @@ -1,6 +1,7 @@ import { POOL_DEPLOYER_ADDRESS, UNI_V3_FACTORY_ADDRESS, + ALGEBRA_INTEGRAL_POOL_DEPLOYER_ADDRESS, } from 'constants/v3/addresses'; import { Currency, Token } from '@uniswap/sdk-core'; import { useMemo } from 'react'; @@ -32,6 +33,7 @@ export function usePools( FeeAmount | undefined, ][], isUni?: boolean, + isAlgebraIntegral?: boolean, ): [PoolState, Pool | null][] { const { chainId } = useActiveWeb3React(); @@ -57,6 +59,8 @@ export function usePools( const poolDeployerAddress = chainId && value && value[2] ? UNI_V3_FACTORY_ADDRESS[chainId] + : isAlgebraIntegral + ? ALGEBRA_INTEGRAL_POOL_DEPLOYER_ADDRESS[chainId] : POOL_DEPLOYER_ADDRESS[chainId]; if (!poolDeployerAddress || !value) return undefined; @@ -67,7 +71,7 @@ export function usePools( fee: value[2], }); }); - }, [chainId, transformed]); + }, [chainId, transformed, isAlgebraIntegral]); const globalState0s = useMultipleContractSingleData( poolAddresses, @@ -173,6 +177,7 @@ export function usePool( currencyB: Currency | undefined, feeAmount?: FeeAmount, isUni?: boolean, + isAlgebraIntegral?: boolean, ): [PoolState, Pool | null] { const poolKeys: [ Currency | undefined, @@ -184,7 +189,7 @@ export function usePool( feeAmount, ]); - return usePools(poolKeys, isUni)[0]; + return usePools(poolKeys, isUni, isAlgebraIntegral)[0]; } export function useTokensSymbols(token0: string, token1: string) { diff --git a/src/pages/PoolsPage/v3/SupplyLiquidityV3/components/PresetRanges/index.tsx b/src/pages/PoolsPage/v3/SupplyLiquidityV3/components/PresetRanges/index.tsx index d90079b85..8302b6e34 100644 --- a/src/pages/PoolsPage/v3/SupplyLiquidityV3/components/PresetRanges/index.tsx +++ b/src/pages/PoolsPage/v3/SupplyLiquidityV3/components/PresetRanges/index.tsx @@ -60,6 +60,7 @@ interface IPresetRanges { isDefiedge?: boolean; isSteer?: boolean; steerPairs?: SteerVault[]; + isAlgebraIntegral?: boolean; } enum PresetProfits { @@ -86,6 +87,7 @@ export function PresetRanges({ isDefiedge = false, defiedgeStrategies, isSteer = false, + isAlgebraIntegral = false, steerPairs, }: IPresetRanges) { const { chainId } = useActiveWeb3React(); @@ -317,6 +319,10 @@ export function PresetRanges({ : []; } + // if (isAlgebraIntegral) { + // return []; + // } + if (isStablecoinPair) return [ { @@ -377,6 +383,7 @@ export function PresetRanges({ isDefiedge, isSteer, isStablecoinPair, + isAlgebraIntegral, t, gammaPair, gammaValues, diff --git a/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/AddLiquidityButton/index.tsx b/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/AddLiquidityButton/index.tsx index d6d3b6a69..78de20e58 100644 --- a/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/AddLiquidityButton/index.tsx +++ b/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/AddLiquidityButton/index.tsx @@ -40,6 +40,7 @@ import { CurrencyAmount } from '@uniswap/sdk-core'; import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, UNI_NFT_POSITION_MANAGER_ADDRESS, + ALGEBRA_INTEGRAL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, } from 'constants/v3/addresses'; import { calculateGasMargin, @@ -106,9 +107,14 @@ export function AddLiquidityButton({ const positionManagerAddress = useMemo(() => { if (mintInfo.feeTier && mintInfo.feeTier.id.includes('uni')) { return UNI_NFT_POSITION_MANAGER_ADDRESS[chainId]; + } else if ( + mintInfo.liquidityRangeType === + GlobalConst.v3LiquidityRangeType.ALGEBRA_INTEGRAL + ) { + return ALGEBRA_INTEGRAL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId]; } return NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId]; - }, [chainId, mintInfo.feeTier]); + }, [chainId, mintInfo.feeTier, mintInfo.liquidityRangeType]); const wethContract = useWETHContract(); const deadline = useTransactionDeadline(); @@ -721,6 +727,138 @@ export function AddLiquidityButton({ setTxPending(false); setAddLiquidityErrorMessage(t('errorInTx')); } + } else if ( + mintInfo.liquidityRangeType === + GlobalConst.v3LiquidityRangeType.ALGEBRA_INTEGRAL + ) { + if (mintInfo.position && account && deadline) { + if (!positionManager) return; + const useNative = baseCurrency.isNative + ? baseCurrency + : quoteCurrency.isNative + ? quoteCurrency + : undefined; + + let callParams; + if (mintInfo.feeTier && mintInfo.feeTier.id.includes('uni')) { + callParams = UniV3NonFunPosMan.addCallParameters(mintInfo.position, { + slippageTolerance: allowedSlippagePercent, + recipient: account, + deadline: deadline.toString(), + useNative, + createPool: mintInfo.noLiquidity, + }); + } else if ( + mintInfo.liquidityRangeType === + GlobalConst.v3LiquidityRangeType.ALGEBRA_INTEGRAL + ) { + callParams = NonFunPosMan.addCallParameters(mintInfo.position, { + slippageTolerance: allowedSlippagePercent, + recipient: account, + deadline: deadline.toString(), + useNative, + createPool: mintInfo.noLiquidity, + }); + } else { + callParams = NonFunPosMan.addCallParameters(mintInfo.position, { + slippageTolerance: allowedSlippagePercent, + recipient: account, + deadline: deadline.toString(), + useNative, + createPool: mintInfo.noLiquidity, + }); + } + const { calldata, value } = callParams; + + const txn: { to: string; data: string; value: string } = { + to: positionManagerAddress, + data: calldata, + value, + }; + + setRejected && setRejected(false); + + setAttemptingTxn(true); + + library + .getSigner() + .estimateGas(txn) + .then((estimate) => { + const newTxn = { + ...txn, + gasLimit: calculateGasMarginV3(chainId, estimate), + }; + + return library + .getSigner() + .sendTransaction(newTxn) + .then(async (response: TransactionResponse) => { + setAttemptingTxn(false); + setTxPending(true); + const summary = mintInfo.noLiquidity + ? t('createPoolandaddLiquidity', { + symbolA: baseCurrency?.symbol, + symbolB: quoteCurrency?.symbol, + }) + : t('addLiquidityWithTokens', { + symbolA: baseCurrency?.symbol, + symbolB: quoteCurrency?.symbol, + }); + addTransaction(response, { + summary, + type: TransactionType.ADDED_LIQUIDITY, + tokens: [ + ((baseCurrency as unknown) as any)?.address ?? + wrappedCurrency(Token.ETHER[chainId], chainId), + ((quoteCurrency as unknown) as any)?.address ?? + wrappedCurrency(Token.ETHER[chainId], chainId), + ], + }); + + dispatch(setAddLiquidityTxHash({ txHash: response.hash })); + + try { + const receipt = await response.wait(); + finalizedTransaction(receipt, { + summary, + }); + setTxPending(false); + handleAddLiquidity(); + } catch (error) { + console.error('Failed to send transaction', error); + setTxPending(false); + setAddLiquidityErrorMessage( + error?.code === 'ACTION_REJECTED' + ? t('txRejected') + : t('errorInTx'), + ); + } + }) + .catch((err) => { + console.error('Failed to send transaction', err); + setAttemptingTxn(false); + setAddLiquidityErrorMessage( + err?.code === 'ACTION_REJECTED' + ? t('txRejected') + : t('errorInTx'), + ); + }); + }) + .catch((error) => { + console.error('Failed to send transaction', error); + // we only care if the error is something _other_ than the user rejected the tx + setRejected && setRejected(true); + setAttemptingTxn(false); + setAddLiquidityErrorMessage( + error?.code === 'ACTION_REJECTED' + ? t('txRejected') + : t('errorInTx'), + ); + if (error?.code !== 'ACTION_REJECTED') { + console.error(error); + } + }); + } } else { if (mintInfo.position && account && deadline) { if (!positionManager) return; diff --git a/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/EnterAmounts/index.tsx b/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/EnterAmounts/index.tsx index a48cd06cb..e0ef2d735 100644 --- a/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/EnterAmounts/index.tsx +++ b/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/EnterAmounts/index.tsx @@ -14,6 +14,7 @@ import { useUSDCValue } from 'hooks/v3/useUSDCPrice'; import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, UNI_NFT_POSITION_MANAGER_ADDRESS, + ALGEBRA_INTEGRAL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES, } from 'constants/v3/addresses'; import { halfAmountSpend, maxAmountSpend } from 'utils/v3/maxAmountSpend'; import { tryParseAmount } from 'state/swap/v3/hooks'; @@ -128,13 +129,17 @@ export function EnterAmounts({ isWithNative && currencyB && currencyB.isNative ? currencyB.wrapped : currencyB; - const positionManagerAddress = useMemo(() => { if (mintInfo.feeTier && mintInfo.feeTier.id.includes('uni')) { return UNI_NFT_POSITION_MANAGER_ADDRESS[chainId]; + } else if ( + mintInfo.liquidityRangeType === + GlobalConst.v3LiquidityRangeType.ALGEBRA_INTEGRAL + ) { + return ALGEBRA_INTEGRAL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId]; } return NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId]; - }, [chainId, mintInfo.feeTier]); + }, [chainId, mintInfo.feeTier, mintInfo.liquidityRangeType]); const steerPeripheryContract = useSteerPeripheryContract(); const [approvalA, approveACallback] = useApproveCallback( @@ -153,6 +158,9 @@ export function EnterAmounts({ : mintInfo.liquidityRangeType === GlobalConst.v3LiquidityRangeType.STEER_RANGE ? steerPeripheryContract?.address + : mintInfo.liquidityRangeType === + GlobalConst.v3LiquidityRangeType.ALGEBRA_INTEGRAL + ? ALGEBRA_INTEGRAL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId] : positionManagerAddress : undefined, ); @@ -172,6 +180,9 @@ export function EnterAmounts({ : mintInfo.liquidityRangeType === GlobalConst.v3LiquidityRangeType.STEER_RANGE ? steerPeripheryContract?.address + : mintInfo.liquidityRangeType === + GlobalConst.v3LiquidityRangeType.ALGEBRA_INTEGRAL + ? ALGEBRA_INTEGRAL_NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId] : positionManagerAddress : undefined, ); diff --git a/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/SelectRange/index.tsx b/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/SelectRange/index.tsx index eacf77266..2ff4ebd21 100644 --- a/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/SelectRange/index.tsx +++ b/src/pages/PoolsPage/v3/SupplyLiquidityV3/containers/SelectRange/index.tsx @@ -39,6 +39,7 @@ import { Trans, useTranslation } from 'react-i18next'; import { useSteerVaults } from 'hooks/v3/useSteerData'; import { useUnipilotFarmData } from 'hooks/v3/useUnipilotFarms'; import { useGammaData } from 'hooks/v3/useGammaData'; +import { getConfig } from 'config/index'; interface IRangeSelector { currencyA: Currency | null | undefined; @@ -65,6 +66,8 @@ export function SelectRange({ ); const { chainId } = useActiveWeb3React(); const chainIdToUse = chainId ? chainId : ChainId.MATIC; + const config = getConfig(chainId); + const algebraIntegralAvailable = config?.['algebraIntegral']?.['available']; const dispatch = useAppDispatch(); const activePreset = useActivePreset(); @@ -234,7 +237,9 @@ export function SelectRange({ onLeftRangeInput( preset ? liquidityRangeType !== - GlobalConst.v3LiquidityRangeType.MANUAL_RANGE + GlobalConst.v3LiquidityRangeType.MANUAL_RANGE && + liquidityRangeType !== + GlobalConst.v3LiquidityRangeType.ALGEBRA_INTEGRAL ? String(Number(priceObj.toSignificant()) * preset.min) : priceObj .quote( @@ -257,7 +262,9 @@ export function SelectRange({ onRightRangeInput( preset ? liquidityRangeType !== - GlobalConst.v3LiquidityRangeType.MANUAL_RANGE + GlobalConst.v3LiquidityRangeType.MANUAL_RANGE && + liquidityRangeType !== + GlobalConst.v3LiquidityRangeType.ALGEBRA_INTEGRAL ? String(Number(priceObj.toSignificant()) * preset.max) : priceObj .quote( @@ -415,6 +422,7 @@ export function SelectRange({ const steerVaultExists = steerVaultsForPair.length > 0; const [isAutomatic, setIsAutoMatic] = useState(false); + const [isAlgebraIntegral, setIsAlgebraIntegral] = useState(false); const selectVaultEnabled = (gammaPairExists && unipilotVaultExists) || @@ -430,6 +438,8 @@ export function SelectRange({ defiedgeStrategyExists || steerVaultExists; + const algebraIntegralEnabled = automaticEnabled || algebraIntegralAvailable; + const enabledVaults = useMemo(() => { const vaults: string[] = []; if (gammaPairExists) { @@ -485,6 +495,10 @@ export function SelectRange({ ); } } + } else if (isAlgebraIntegral) { + onChangeLiquidityRangeType( + GlobalConst.v3LiquidityRangeType.ALGEBRA_INTEGRAL, + ); } else { onChangeLiquidityRangeType(GlobalConst.v3LiquidityRangeType.MANUAL_RANGE); } @@ -492,6 +506,7 @@ export function SelectRange({ defiedgeStrategyExists, gammaPairExists, isAutomatic, + isAlgebraIntegral, onChangeLiquidityRangeType, selectVaultEnabled, steerVaultExists, @@ -553,20 +568,34 @@ export function SelectRange({ return ( {t('selectRange')} - {automaticEnabled && ( + {algebraIntegralEnabled && ( - + {automaticEnabled && ( + + )} + {algebraIntegralAvailable && ( + + )}