+
{isActive && icon}
)
@@ -55,4 +58,8 @@ export default styled(Toggle)<{ backgroundColor?: string }>`
left: 32px;
}
}
+
+ &[data-highlight='true'] {
+ animation: ${({ theme }) => highlight(theme)} 2s 2 alternate ease-in-out;
+ }
`
diff --git a/src/components/TransactionConfirmationModal/index.tsx b/src/components/TransactionConfirmationModal/index.tsx
index ff03ecc600..446ac03ae1 100644
--- a/src/components/TransactionConfirmationModal/index.tsx
+++ b/src/components/TransactionConfirmationModal/index.tsx
@@ -55,7 +55,7 @@ export function ConfirmationPendingContent({
}: {
onDismiss: () => void
pendingText: string | React.ReactNode
- startedTime: number | undefined
+ startedTime?: number | undefined
}) {
const theme = useTheme()
diff --git a/src/components/TransactionSettings/index.tsx b/src/components/TransactionSettings/index.tsx
index 1ba2b6ccd0..05b27bee73 100644
--- a/src/components/TransactionSettings/index.tsx
+++ b/src/components/TransactionSettings/index.tsx
@@ -1,19 +1,21 @@
-import { t } from '@lingui/macro'
+import { Trans, t } from '@lingui/macro'
import { rgba } from 'polished'
-import { useCallback, useState } from 'react'
+import { useCallback, useEffect, useState } from 'react'
+import { useSearchParams } from 'react-router-dom'
+import { Flex } from 'rebass'
import styled, { css } from 'styled-components'
import TransactionSettingsIcon from 'components/Icons/TransactionSettingsIcon'
import MenuFlyout from 'components/MenuFlyout'
import Toggle from 'components/Toggle'
-import Tooltip from 'components/Tooltip'
+import Tooltip, { MouseoverTooltip, TextDashed } from 'components/Tooltip'
import SlippageSetting from 'components/swapv2/SwapSettingsPanel/SlippageSetting'
import TransactionTimeLimitSetting from 'components/swapv2/SwapSettingsPanel/TransactionTimeLimitSetting'
import { StyledActionButtonSwapForm } from 'components/swapv2/styleds'
import useTheme from 'hooks/useTheme'
import { ApplicationModal } from 'state/application/actions'
import { useModalOpen, useToggleTransactionSettingsMenu } from 'state/application/hooks'
-import { useDegenModeManager } from 'state/user/hooks'
+import { useAggregatorForZapSetting, useDegenModeManager } from 'state/user/hooks'
import AdvanceModeModal from './AdvanceModeModal'
@@ -64,16 +66,43 @@ type Props = {
export default function TransactionSettings({ hoverBg }: Props) {
const theme = useTheme()
- const [isDegenMode] = useDegenModeManager()
+ const [isDegenMode, toggleDegenMode] = useDegenModeManager()
+ const [isUseAggregatorForZap, toggleAggregatorForZap] = useAggregatorForZapSetting()
const toggle = useToggleTransactionSettingsMenu()
// show confirmation view before turning on
const [showConfirmation, setShowConfirmation] = useState(false)
const open = useModalOpen(ApplicationModal.TRANSACTION_SETTINGS)
+ const [searchParams, setSearchParams] = useSearchParams()
+
+ const showSetting = searchParams.get('showSetting')
+ useEffect(() => {
+ if (showSetting === 'true') {
+ toggle()
+ }
+ // only toggle one
+ // eslint-disable-next-line
+ }, [showSetting])
+
const [isShowTooltip, setIsShowTooltip] = useState
(false)
const showTooltip = useCallback(() => setIsShowTooltip(true), [setIsShowTooltip])
const hideTooltip = useCallback(() => setIsShowTooltip(false), [setIsShowTooltip])
+ const handleToggleAdvancedMode = () => {
+ if (isDegenMode /* is already ON */) {
+ toggleDegenMode()
+ setShowConfirmation(false)
+ return
+ }
+
+ toggle()
+ if (showSetting === 'true') {
+ searchParams.delete('showSetting')
+ setSearchParams(searchParams, { replace: true })
+ }
+
+ setShowConfirmation(true)
+ }
return (
<>
@@ -102,7 +131,13 @@ export default function TransactionSettings({ hoverBg }: Props) {
}
customStyle={MenuFlyoutBrowserStyle}
isOpen={open}
- toggle={toggle}
+ toggle={() => {
+ toggle()
+ if (showSetting === 'true') {
+ searchParams.delete('showSetting')
+ setSearchParams(searchParams, { replace: true })
+ }
+ }}
title={t`Advanced Settings`}
mobileCustomStyle={{ paddingBottom: '40px' }}
hasArrow
@@ -110,6 +145,36 @@ export default function TransactionSettings({ hoverBg }: Props) {
+
+
+
+
+
+ Degen Mode
+
+
+
+
+
+
+
+
+
+
+ Use Aggregator for Zaps
+
+
+
+
+
diff --git a/src/components/WalletPopup/Transactions/PoolFarmLink.tsx b/src/components/WalletPopup/Transactions/PoolFarmLink.tsx
index 374f8db25f..d4d2a55752 100644
--- a/src/components/WalletPopup/Transactions/PoolFarmLink.tsx
+++ b/src/components/WalletPopup/Transactions/PoolFarmLink.tsx
@@ -21,6 +21,7 @@ const PoolFarmLink = ({ transaction }: { transaction: TransactionDetails }) => {
TRANSACTION_TYPE.ELASTIC_REMOVE_LIQUIDITY,
TRANSACTION_TYPE.ELASTIC_COLLECT_FEE,
TRANSACTION_TYPE.ELASTIC_INCREASE_LIQUIDITY,
+ TRANSACTION_TYPE.ELASTIC_ZAP_IN_LIQUIDITY,
TRANSACTION_TYPE.HARVEST,
].includes(type)
diff --git a/src/components/WalletPopup/Transactions/TransactionItem.tsx b/src/components/WalletPopup/Transactions/TransactionItem.tsx
index ad22aa1f7d..c7ea998c3d 100644
--- a/src/components/WalletPopup/Transactions/TransactionItem.tsx
+++ b/src/components/WalletPopup/Transactions/TransactionItem.tsx
@@ -87,6 +87,7 @@ const Description2Token = (transaction: TransactionDetails) => {
TRANSACTION_TYPE.CLASSIC_CREATE_POOL,
TRANSACTION_TYPE.ELASTIC_CREATE_POOL,
TRANSACTION_TYPE.ELASTIC_INCREASE_LIQUIDITY,
+ TRANSACTION_TYPE.ELASTIC_ZAP_IN_LIQUIDITY,
].includes(type)
const signTokenIn = [
@@ -371,6 +372,7 @@ const DESCRIPTION_MAP: {
[TRANSACTION_TYPE.CLASSIC_REMOVE_LIQUIDITY]: DescriptionLiquidity,
[TRANSACTION_TYPE.ELASTIC_REMOVE_LIQUIDITY]: DescriptionLiquidity,
[TRANSACTION_TYPE.ELASTIC_INCREASE_LIQUIDITY]: DescriptionLiquidity,
+ [TRANSACTION_TYPE.ELASTIC_ZAP_IN_LIQUIDITY]: DescriptionLiquidity,
[TRANSACTION_TYPE.ELASTIC_COLLECT_FEE]: DescriptionLiquidity,
[TRANSACTION_TYPE.HARVEST]: DescriptionHarvestFarmReward,
diff --git a/src/components/WarningNote/index.tsx b/src/components/WarningNote/index.tsx
index 894681061c..e4b5a8ae03 100644
--- a/src/components/WarningNote/index.tsx
+++ b/src/components/WarningNote/index.tsx
@@ -29,6 +29,7 @@ const Wrapper = styled.div<{ $level: SeverityLevel }>`
font-size: 12px;
line-height: 16px;
padding: 12px 16px;
+ width: 100%;
`
type Props = {
diff --git a/src/constants/abis/elastic-zap/router.json b/src/constants/abis/elastic-zap/router.json
new file mode 100644
index 0000000000..897d083c04
--- /dev/null
+++ b/src/constants/abis/elastic-zap/router.json
@@ -0,0 +1,662 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_weth",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "bytes",
+ "name": "_clientData",
+ "type": "bytes"
+ }
+ ],
+ "name": "ClientData",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "reason",
+ "type": "string"
+ }
+ ],
+ "name": "Error",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "_executor",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "bool",
+ "name": "_grantOrRevoke",
+ "type": "bool"
+ }
+ ],
+ "name": "ExecutorWhitelisted",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "Paused",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "contract IERC20",
+ "name": "_token",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_amount",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "bool",
+ "name": "_isNative",
+ "type": "bool"
+ },
+ {
+ "indexed": false,
+ "internalType": "bool",
+ "name": "_isPermit",
+ "type": "bool"
+ }
+ ],
+ "name": "TokenCollected",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "Unpaused",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "user",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "bool",
+ "name": "grantOrRevoke",
+ "type": "bool"
+ }
+ ],
+ "name": "UpdateGuardian",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "user",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "bool",
+ "name": "grantOrRevoke",
+ "type": "bool"
+ }
+ ],
+ "name": "UpdateOperator",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "_validator",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "bool",
+ "name": "_grantOrRevoke",
+ "type": "bool"
+ }
+ ],
+ "name": "ValidatorWhitelisted",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint8",
+ "name": "_dexType",
+ "type": "uint8"
+ },
+ {
+ "indexed": true,
+ "internalType": "contract IERC20",
+ "name": "_srcToken",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "_srcAmount",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "_validator",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "_executor",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "bytes",
+ "name": "_zapInfo",
+ "type": "bytes"
+ },
+ {
+ "indexed": false,
+ "internalType": "bytes",
+ "name": "_extraData",
+ "type": "bytes"
+ },
+ {
+ "indexed": false,
+ "internalType": "bytes",
+ "name": "_initialData",
+ "type": "bytes"
+ },
+ {
+ "indexed": false,
+ "internalType": "bytes",
+ "name": "_zapResults",
+ "type": "bytes"
+ }
+ ],
+ "name": "ZapExecuted",
+ "type": "event"
+ },
+ {
+ "inputs": [],
+ "name": "disableLogic",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "enableLogic",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "guardians",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "operators",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "paused",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ }
+ ],
+ "name": "rescueFunds",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "user",
+ "type": "address"
+ },
+ {
+ "internalType": "bool",
+ "name": "grantOrRevoke",
+ "type": "bool"
+ }
+ ],
+ "name": "updateGuardian",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "user",
+ "type": "address"
+ },
+ {
+ "internalType": "bool",
+ "name": "grantOrRevoke",
+ "type": "bool"
+ }
+ ],
+ "name": "updateOperator",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "weth",
+ "outputs": [
+ {
+ "internalType": "contract IWETH",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "_executors",
+ "type": "address[]"
+ },
+ {
+ "internalType": "bool",
+ "name": "_grantOrRevoke",
+ "type": "bool"
+ }
+ ],
+ "name": "whitelistExecutors",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "_validators",
+ "type": "address[]"
+ },
+ {
+ "internalType": "bool",
+ "name": "_grantOrRevoke",
+ "type": "bool"
+ }
+ ],
+ "name": "whitelistValidators",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "whitelistedExecutor",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "whitelistedValidator",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "uint8",
+ "name": "dexType",
+ "type": "uint8"
+ },
+ {
+ "internalType": "contract IERC20",
+ "name": "srcToken",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "srcAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bytes",
+ "name": "zapInfo",
+ "type": "bytes"
+ },
+ {
+ "internalType": "bytes",
+ "name": "extraData",
+ "type": "bytes"
+ },
+ {
+ "internalType": "bytes",
+ "name": "permitData",
+ "type": "bytes"
+ }
+ ],
+ "internalType": "struct IKSZapRouter.ZapDescription",
+ "name": "_desc",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "validator",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "executor",
+ "type": "address"
+ },
+ {
+ "internalType": "uint32",
+ "name": "deadline",
+ "type": "uint32"
+ },
+ {
+ "internalType": "bytes",
+ "name": "executorData",
+ "type": "bytes"
+ },
+ {
+ "internalType": "bytes",
+ "name": "clientData",
+ "type": "bytes"
+ }
+ ],
+ "internalType": "struct IKSZapRouter.ZapExecutionData",
+ "name": "_exe",
+ "type": "tuple"
+ }
+ ],
+ "name": "zapIn",
+ "outputs": [
+ {
+ "internalType": "bytes",
+ "name": "zapResults",
+ "type": "bytes"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "uint8",
+ "name": "dexType",
+ "type": "uint8"
+ },
+ {
+ "internalType": "contract IERC20",
+ "name": "srcToken",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "srcAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bytes",
+ "name": "zapInfo",
+ "type": "bytes"
+ },
+ {
+ "internalType": "bytes",
+ "name": "extraData",
+ "type": "bytes"
+ },
+ {
+ "internalType": "bytes",
+ "name": "permitData",
+ "type": "bytes"
+ }
+ ],
+ "internalType": "struct IKSZapRouter.ZapDescription",
+ "name": "_desc",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "validator",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "executor",
+ "type": "address"
+ },
+ {
+ "internalType": "uint32",
+ "name": "deadline",
+ "type": "uint32"
+ },
+ {
+ "internalType": "bytes",
+ "name": "executorData",
+ "type": "bytes"
+ },
+ {
+ "internalType": "bytes",
+ "name": "clientData",
+ "type": "bytes"
+ }
+ ],
+ "internalType": "struct IKSZapRouter.ZapExecutionData",
+ "name": "_exe",
+ "type": "tuple"
+ }
+ ],
+ "name": "zapInWithNative",
+ "outputs": [
+ {
+ "internalType": "bytes",
+ "name": "zapResults",
+ "type": "bytes"
+ }
+ ],
+ "stateMutability": "payable",
+ "type": "function"
+ }
+]
diff --git a/src/constants/abis/elastic-zap/zap-helper.json b/src/constants/abis/elastic-zap/zap-helper.json
new file mode 100644
index 0000000000..7435182913
--- /dev/null
+++ b/src/constants/abis/elastic-zap/zap-helper.json
@@ -0,0 +1,286 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "quoterAddress",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [],
+ "name": "InvalidZapParams",
+ "type": "error"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "contract IPool",
+ "name": "pool",
+ "type": "address"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount0Desired",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount1Desired",
+ "type": "uint256"
+ }
+ ],
+ "name": "getAddLiquidityAmounts",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "qty0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "qty1",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "contract IPool",
+ "name": "pool",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "tokenIn",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amountIn",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amountOut",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "precision",
+ "type": "uint256"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ }
+ ],
+ "name": "getOptimalSwapAmountToZapIn",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "uint256",
+ "name": "swapAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "returnedAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint160",
+ "name": "sqrtP",
+ "type": "uint160"
+ },
+ {
+ "internalType": "uint256",
+ "name": "baseL",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "reinvestL",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IKSElasticZapHelper.GetOptimalSwapAmountResults",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "contract IPool",
+ "name": "pool",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "tokenIn",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amountIn",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amountOut",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "precision",
+ "type": "uint256"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ }
+ ],
+ "name": "getZapInPoolResults",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "uint128",
+ "name": "liquidity",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "int24",
+ "name": "currentTick",
+ "type": "int24"
+ },
+ {
+ "internalType": "uint160",
+ "name": "sqrtP",
+ "type": "uint160"
+ },
+ {
+ "internalType": "uint256",
+ "name": "baseL",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "reinvestL",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IKSElasticZapHelper.ZapInResults",
+ "name": "results",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "positionManager",
+ "type": "address"
+ },
+ {
+ "internalType": "contract IPool",
+ "name": "pool",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "positionId",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint128",
+ "name": "liquidity",
+ "type": "uint128"
+ },
+ {
+ "internalType": "address",
+ "name": "receivedToken",
+ "type": "address"
+ }
+ ],
+ "name": "getZapOutPoolResults",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "returnAmount",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "quoter",
+ "outputs": [
+ {
+ "internalType": "contract IQuoterV2",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ }
+]
diff --git a/src/constants/abis/elastic-zap/zap-in.json b/src/constants/abis/elastic-zap/zap-in.json
new file mode 100644
index 0000000000..9f4f029b5c
--- /dev/null
+++ b/src/constants/abis/elastic-zap/zap-in.json
@@ -0,0 +1,846 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "helperAddress",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [],
+ "name": "AllowanceRemains",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "InvalidAmounts",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "InvalidFeeConfig",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "InvalidSwap",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "InvalidZapParams",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotEnoughReturnedLiquidity",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotEnoughReturnedToken",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "NotWhitelistAggregator",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "RemainTooMuch",
+ "type": "error"
+ },
+ {
+ "inputs": [],
+ "name": "RemoveZeroLiquidity",
+ "type": "error"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [],
+ "name": "ZapAgainFailed",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "uint128",
+ "name": "liquidity",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount1",
+ "type": "uint256"
+ }
+ ],
+ "indexed": false,
+ "internalType": "struct IZapHelper.ZapInResults",
+ "name": "ZapInResults",
+ "type": "tuple"
+ }
+ ],
+ "name": "ZapInToAddLiquidity",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ },
+ {
+ "components": [
+ {
+ "internalType": "uint128",
+ "name": "liquidity",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount1",
+ "type": "uint256"
+ }
+ ],
+ "indexed": false,
+ "internalType": "struct IZapHelper.ZapInResults",
+ "name": "ZapInResults",
+ "type": "tuple"
+ }
+ ],
+ "name": "ZapInToMint",
+ "type": "event"
+ },
+ {
+ "inputs": [],
+ "name": "feeGlobalBps",
+ "outputs": [
+ {
+ "internalType": "uint24",
+ "name": "",
+ "type": "uint24"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "feePerPoolBps",
+ "outputs": [
+ {
+ "internalType": "uint24",
+ "name": "",
+ "type": "uint24"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "feeRecipient",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_feeRecipient",
+ "type": "address"
+ }
+ ],
+ "name": "setFeeRecipient",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint24",
+ "name": "fee",
+ "type": "uint24"
+ }
+ ],
+ "name": "setGlobalFee",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "pool",
+ "type": "address"
+ },
+ {
+ "internalType": "uint24",
+ "name": "fee",
+ "type": "uint24"
+ }
+ ],
+ "name": "setfeePerPoolBps",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "int256",
+ "name": "deltaQty0",
+ "type": "int256"
+ },
+ {
+ "internalType": "int256",
+ "name": "deltaQty1",
+ "type": "int256"
+ },
+ {
+ "internalType": "bytes",
+ "name": "path",
+ "type": "bytes"
+ }
+ ],
+ "name": "swapCallback",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "aggregator",
+ "type": "address"
+ },
+ {
+ "internalType": "bool",
+ "name": "value",
+ "type": "bool"
+ }
+ ],
+ "name": "updateWhitelistAggregator",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "zapHelper",
+ "outputs": [
+ {
+ "internalType": "contract IZapHelper",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "positionManager",
+ "type": "address"
+ },
+ {
+ "internalType": "contract IPool",
+ "name": "pool",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "tokenIn",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "positionId",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "minLiquidity",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxRemainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxRemainingAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "deadline",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IZapIn.ZapAddLiqParams",
+ "name": "params",
+ "type": "tuple"
+ },
+ {
+ "internalType": "uint256",
+ "name": "precision",
+ "type": "uint256"
+ }
+ ],
+ "name": "zapInPoolToAddLiquidity",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "uint128",
+ "name": "liquidity",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount1",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IZapHelper.ZapInResults",
+ "name": "results",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "positionManager",
+ "type": "address"
+ },
+ {
+ "internalType": "contract IPool",
+ "name": "pool",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "tokenIn",
+ "type": "address"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24[2]",
+ "name": "ticksPrevious",
+ "type": "int24[2]"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "minLiquidity",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxRemainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxRemainingAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "deadline",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IZapIn.ZapMintParams",
+ "name": "params",
+ "type": "tuple"
+ },
+ {
+ "internalType": "uint256",
+ "name": "precision",
+ "type": "uint256"
+ }
+ ],
+ "name": "zapInPoolToMint",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ },
+ {
+ "components": [
+ {
+ "internalType": "uint128",
+ "name": "liquidity",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount1",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IZapHelper.ZapInResults",
+ "name": "results",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "positionManager",
+ "type": "address"
+ },
+ {
+ "internalType": "contract IPool",
+ "name": "pool",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "tokenIn",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "positionId",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "minLiquidity",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxRemainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxRemainingAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "deadline",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IZapIn.ZapAddLiqParams",
+ "name": "params",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "aggregator",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "swapAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bytes",
+ "name": "swapData",
+ "type": "bytes"
+ }
+ ],
+ "internalType": "struct IZapIn.AggregationParams",
+ "name": "aggregationParams",
+ "type": "tuple"
+ },
+ {
+ "internalType": "uint256",
+ "name": "zapAgainPrecision",
+ "type": "uint256"
+ }
+ ],
+ "name": "zapToAddLiqByAggregator",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "uint128",
+ "name": "liquidity",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount1",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IZapHelper.ZapInResults",
+ "name": "results",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "positionManager",
+ "type": "address"
+ },
+ {
+ "internalType": "contract IPool",
+ "name": "pool",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "tokenIn",
+ "type": "address"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24[2]",
+ "name": "ticksPrevious",
+ "type": "int24[2]"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "minLiquidity",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxRemainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxRemainingAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "deadline",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IZapIn.ZapMintParams",
+ "name": "params",
+ "type": "tuple"
+ },
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "aggregator",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "swapAmount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bytes",
+ "name": "swapData",
+ "type": "bytes"
+ }
+ ],
+ "internalType": "struct IZapIn.AggregationParams",
+ "name": "aggregationParams",
+ "type": "tuple"
+ },
+ {
+ "internalType": "uint256",
+ "name": "zapAgainPrecision",
+ "type": "uint256"
+ }
+ ],
+ "name": "zapToMintByAggregator",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "tokenId",
+ "type": "uint256"
+ },
+ {
+ "components": [
+ {
+ "internalType": "uint128",
+ "name": "liquidity",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "usedAmount1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "remainingAmount1",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IZapHelper.ZapInResults",
+ "name": "results",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
diff --git a/src/constants/abis/v2/ProAmmPoolState.json b/src/constants/abis/v2/ProAmmPoolState.json
index a74f22d01d..4b6dc3ae9c 100644
--- a/src/constants/abis/v2/ProAmmPoolState.json
+++ b/src/constants/abis/v2/ProAmmPoolState.json
@@ -3,29 +3,841 @@
"contractName": "IUniswapV3PoolState",
"sourceName": "contracts/interfaces/pool/IUniswapV3PoolState.sol",
"abi": [
+ {
+ "inputs": [],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "indexed": true,
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint128",
+ "name": "qty",
+ "type": "uint128"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "qty0",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "qty1",
+ "type": "uint256"
+ }
+ ],
+ "name": "Burn",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "qty",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "qty0",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "qty1",
+ "type": "uint256"
+ }
+ ],
+ "name": "BurnRTokens",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "qty0",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "qty1",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "paid0",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "paid1",
+ "type": "uint256"
+ }
+ ],
+ "name": "Flash",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint160",
+ "name": "sqrtP",
+ "type": "uint160"
+ },
+ {
+ "indexed": false,
+ "internalType": "int24",
+ "name": "tick",
+ "type": "int24"
+ }
+ ],
+ "name": "Initialize",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "indexed": true,
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint128",
+ "name": "qty",
+ "type": "uint128"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "qty0",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "qty1",
+ "type": "uint256"
+ }
+ ],
+ "name": "Mint",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "int256",
+ "name": "deltaQty0",
+ "type": "int256"
+ },
+ {
+ "indexed": false,
+ "internalType": "int256",
+ "name": "deltaQty1",
+ "type": "int256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint160",
+ "name": "sqrtP",
+ "type": "uint160"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint128",
+ "name": "liquidity",
+ "type": "uint128"
+ },
+ {
+ "indexed": false,
+ "internalType": "int24",
+ "name": "currentTick",
+ "type": "int24"
+ }
+ ],
+ "name": "Swap",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ }
+ ],
+ "name": "allowance",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "approve",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ },
+ {
+ "internalType": "uint128",
+ "name": "qty",
+ "type": "uint128"
+ }
+ ],
+ "name": "burn",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "qty0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "qty1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "feeGrowthInsideLast",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_qty",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bool",
+ "name": "isLogicalBurn",
+ "type": "bool"
+ }
+ ],
+ "name": "burnRTokens",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "qty0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "qty1",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [
+ {
+ "internalType": "uint8",
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "subtractedValue",
+ "type": "uint256"
+ }
+ ],
+ "name": "decreaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "factory",
+ "outputs": [
+ {
+ "internalType": "contract IFactory",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "qty0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "qty1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "bytes",
+ "name": "data",
+ "type": "bytes"
+ }
+ ],
+ "name": "flash",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getFeeGrowthGlobal",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getLiquidityState",
+ "outputs": [
+ {
+ "internalType": "uint128",
+ "name": "baseL",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint128",
+ "name": "reinvestL",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint128",
+ "name": "reinvestLLast",
+ "type": "uint128"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [],
"name": "getPoolState",
"outputs": [
{
- "internalType": "uint160",
- "name": "sqrtP",
- "type": "uint160"
+ "internalType": "uint160",
+ "name": "sqrtP",
+ "type": "uint160"
+ },
+ {
+ "internalType": "int24",
+ "name": "currentTick",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24",
+ "name": "nearestCurrentTick",
+ "type": "int24"
+ },
+ {
+ "internalType": "bool",
+ "name": "locked",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ }
+ ],
+ "name": "getPositions",
+ "outputs": [
+ {
+ "internalType": "uint128",
+ "name": "liquidity",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint256",
+ "name": "feeGrowthInsideLast",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getSecondsPerLiquidityData",
+ "outputs": [
+ {
+ "internalType": "uint128",
+ "name": "secondsPerLiquidityGlobal",
+ "type": "uint128"
+ },
+ {
+ "internalType": "uint32",
+ "name": "lastUpdateTime",
+ "type": "uint32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ }
+ ],
+ "name": "getSecondsPerLiquidityInside",
+ "outputs": [
+ {
+ "internalType": "uint128",
+ "name": "secondsPerLiquidityInside",
+ "type": "uint128"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "addedValue",
+ "type": "uint256"
+ }
+ ],
+ "name": "increaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "int24",
+ "name": "",
+ "type": "int24"
+ }
+ ],
+ "name": "initializedTicks",
+ "outputs": [
+ {
+ "internalType": "int24",
+ "name": "previous",
+ "type": "int24"
},
{
"internalType": "int24",
- "name": "currentTick",
+ "name": "next",
+ "type": "int24"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "maxTickLiquidity",
+ "outputs": [
+ {
+ "internalType": "uint128",
+ "name": "",
+ "type": "uint128"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickLower",
"type": "int24"
},
{
"internalType": "int24",
- "name": "nearestCurrentTick",
+ "name": "tickUpper",
"type": "int24"
},
+ {
+ "internalType": "int24[2]",
+ "name": "ticksPrevious",
+ "type": "int24[2]"
+ },
+ {
+ "internalType": "uint128",
+ "name": "qty",
+ "type": "uint128"
+ },
+ {
+ "internalType": "bytes",
+ "name": "data",
+ "type": "bytes"
+ }
+ ],
+ "name": "mint",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "qty0",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "qty1",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "feeGrowthInsideLast",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "poolOracle",
+ "outputs": [
+ {
+ "internalType": "contract IPoolOracle",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "int256",
+ "name": "swapQty",
+ "type": "int256"
+ },
{
"internalType": "bool",
- "name": "locked",
+ "name": "isToken0",
"type": "bool"
+ },
+ {
+ "internalType": "uint160",
+ "name": "limitSqrtP",
+ "type": "uint160"
+ },
+ {
+ "internalType": "bytes",
+ "name": "data",
+ "type": "bytes"
+ }
+ ],
+ "name": "swap",
+ "outputs": [
+ {
+ "internalType": "int256",
+ "name": "deltaQty0",
+ "type": "int256"
+ },
+ {
+ "internalType": "int256",
+ "name": "deltaQty1",
+ "type": "int256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "swapFeeUnits",
+ "outputs": [
+ {
+ "internalType": "uint24",
+ "name": "",
+ "type": "uint24"
}
],
"stateMutability": "view",
@@ -33,49 +845,197 @@
},
{
"inputs": [],
- "name": "getLiquidityState",
+ "name": "symbol",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "tickDistance",
+ "outputs": [
+ {
+ "internalType": "int24",
+ "name": "",
+ "type": "int24"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "int24",
+ "name": "",
+ "type": "int24"
+ }
+ ],
+ "name": "ticks",
"outputs": [
{
"internalType": "uint128",
- "name": "baseL",
+ "name": "liquidityGross",
"type": "uint128"
},
{
- "internalType": "uint128",
- "name": "reinvestL",
- "type": "uint128"
+ "internalType": "int128",
+ "name": "liquidityNet",
+ "type": "int128"
+ },
+ {
+ "internalType": "uint256",
+ "name": "feeGrowthOutside",
+ "type": "uint256"
},
{
"internalType": "uint128",
- "name": "reinvestLLast",
+ "name": "secondsPerLiquidityOutside",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
+ {
+ "inputs": [],
+ "name": "token0",
+ "outputs": [
+ {
+ "internalType": "contract IERC20",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "token1",
+ "outputs": [
+ {
+ "internalType": "contract IERC20",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
{
"inputs": [
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
{
"internalType": "uint256",
- "name": "_qty",
+ "name": "amount",
"type": "uint256"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
},
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferFrom",
+ "outputs": [
{
"internalType": "bool",
- "name": "isLogicalBurn",
+ "name": "",
"type": "bool"
}
],
- "name": "burnRTokens",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "int24",
+ "name": "tickLower",
+ "type": "int24"
+ },
+ {
+ "internalType": "int24",
+ "name": "tickUpper",
+ "type": "int24"
+ }
+ ],
+ "name": "tweakPosZeroLiq",
"outputs": [
{
- "internalType": "uint128",
+ "internalType": "uint256",
+ "name": "feeGrowthInsideLast",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint160",
+ "name": "initialSqrtP",
+ "type": "uint160"
+ }
+ ],
+ "name": "unlockPool",
+ "outputs": [
+ {
+ "internalType": "uint256",
"name": "qty0",
"type": "uint256"
},
{
- "internalType": "uint128",
+ "internalType": "uint256",
"name": "qty1",
"type": "uint256"
}
diff --git a/src/constants/networks/arbitrum.ts b/src/constants/networks/arbitrum.ts
index c8b8c84025..9447f8dc53 100644
--- a/src/constants/networks/arbitrum.ts
+++ b/src/constants/networks/arbitrum.ts
@@ -65,6 +65,12 @@ const arbitrumInfo: EVMNetworkInfo = {
'0x3D6AfE2fB73fFEd2E3dD00c501A174554e147a43',
'0xf2BcDf38baA52F6b0C1Db5B025DfFf01Ae1d6dBd',
],
+ zap: {
+ router: '0x30C5322E4e08AD500c348007f92f120ab4E2b79e',
+ validator: '0xf0096e5B4AAfeEA1DF557264091569ba125c1172',
+ executor: '0x4f097F7074D52952006a0763312724929Ff95Cf0',
+ helper: '0x4E8419EFa0b0A149Dad77b689D37AF17f762f20A',
+ },
},
limitOrder: '*',
averageBlockTimeInSeconds: 1, // TODO: check these info
diff --git a/src/constants/networks/avax.ts b/src/constants/networks/avax.ts
index 08b9ae26f3..d740a0fe44 100644
--- a/src/constants/networks/avax.ts
+++ b/src/constants/networks/avax.ts
@@ -74,6 +74,12 @@ const avaxInfo: EVMNetworkInfo = {
'0x3d6afe2fb73ffed2e3dd00c501a174554e147a43',
'0xf2BcDf38baA52F6b0C1Db5B025DfFf01Ae1d6dBd',
],
+ zap: {
+ router: '0x30C5322E4e08AD500c348007f92f120ab4E2b79e',
+ validator: '0xf0096e5B4AAfeEA1DF557264091569ba125c1172',
+ executor: '0x4f097F7074D52952006a0763312724929Ff95Cf0',
+ helper: '0x4E8419EFa0b0A149Dad77b689D37AF17f762f20A',
+ },
},
limitOrder: '*',
averageBlockTimeInSeconds: 1.85,
diff --git a/src/constants/networks/base.ts b/src/constants/networks/base.ts
index 22ec8a9ce4..e664d90540 100644
--- a/src/constants/networks/base.ts
+++ b/src/constants/networks/base.ts
@@ -57,6 +57,12 @@ const base: EVMNetworkInfo = {
farms: ['0x7D5ba536ab244aAA1EA42aB88428847F25E3E676'],
farmv2Quoter: '0x6AFeb9EDd6Cf44fA8E89b1eee28284e6dD7705C8',
farmV2S: ['0x3D6AfE2fB73fFEd2E3dD00c501A174554e147a43', '0xf2BcDf38baA52F6b0C1Db5B025DfFf01Ae1d6dBd'],
+ zap: {
+ router: '0x30C5322E4e08AD500c348007f92f120ab4E2b79e',
+ validator: '0xf0096e5B4AAfeEA1DF557264091569ba125c1172',
+ executor: '0x4f097F7074D52952006a0763312724929Ff95Cf0',
+ helper: '0x4E8419EFa0b0A149Dad77b689D37AF17f762f20A',
+ },
},
limitOrder: NOT_SUPPORT,
averageBlockTimeInSeconds: 2, // dont use for base
diff --git a/src/constants/networks/matic.ts b/src/constants/networks/matic.ts
index 04d1a80533..5f5eb8c2f4 100644
--- a/src/constants/networks/matic.ts
+++ b/src/constants/networks/matic.ts
@@ -69,6 +69,12 @@ const maticInfo: EVMNetworkInfo = {
'0x3D6AfE2fB73fFEd2E3dD00c501A174554e147a43',
'0xf2BcDf38baA52F6b0C1Db5B025DfFf01Ae1d6dBd',
],
+ zap: {
+ router: '0x30C5322E4e08AD500c348007f92f120ab4E2b79e',
+ validator: '0xf0096e5B4AAfeEA1DF557264091569ba125c1172',
+ executor: '0x4f097F7074D52952006a0763312724929Ff95Cf0',
+ helper: '0x4E8419EFa0b0A149Dad77b689D37AF17f762f20A',
+ },
'farmV2.1S': [],
},
limitOrder: '*',
diff --git a/src/constants/networks/optimism.ts b/src/constants/networks/optimism.ts
index 8985db510e..514ed20974 100644
--- a/src/constants/networks/optimism.ts
+++ b/src/constants/networks/optimism.ts
@@ -60,6 +60,12 @@ const optimismInfo: EVMNetworkInfo = {
'0x3D6AfE2fB73fFEd2E3dD00c501A174554e147a43',
'0xf2BcDf38baA52F6b0C1Db5B025DfFf01Ae1d6dBd',
],
+ zap: {
+ router: '0x30C5322E4e08AD500c348007f92f120ab4E2b79e',
+ validator: '0xf0096e5B4AAfeEA1DF557264091569ba125c1172',
+ executor: '0x4f097F7074D52952006a0763312724929Ff95Cf0',
+ helper: '0x4E8419EFa0b0A149Dad77b689D37AF17f762f20A',
+ },
},
limitOrder: '*',
averageBlockTimeInSeconds: 120,
diff --git a/src/constants/networks/scroll.ts b/src/constants/networks/scroll.ts
index d05ed1a6a8..289fd46cf4 100644
--- a/src/constants/networks/scroll.ts
+++ b/src/constants/networks/scroll.ts
@@ -59,6 +59,12 @@ const scroll: EVMNetworkInfo = {
farmv2Quoter: '0x6AFeb9EDd6Cf44fA8E89b1eee28284e6dD7705C8',
farmV2S: [],
'farmV2.1S': ['0x3D6AfE2fB73fFEd2E3dD00c501A174554e147a43', '0xf2BcDf38baA52F6b0C1Db5B025DfFf01Ae1d6dBd'],
+ zap: {
+ router: '0x30C5322E4e08AD500c348007f92f120ab4E2b79e',
+ validator: '0xf0096e5B4AAfeEA1DF557264091569ba125c1172',
+ executor: '0x4f097F7074D52952006a0763312724929Ff95Cf0',
+ helper: '0x4E8419EFa0b0A149Dad77b689D37AF17f762f20A',
+ },
},
limitOrder: NOT_SUPPORT,
averageBlockTimeInSeconds: 8.4, // dont use for base
diff --git a/src/constants/networks/type.ts b/src/constants/networks/type.ts
index 1a5344c250..25370186b2 100644
--- a/src/constants/networks/type.ts
+++ b/src/constants/networks/type.ts
@@ -77,6 +77,12 @@ export interface EVMNetworkInfo extends NetworkInfo {
readonly farms: string[]
readonly farmv2Quoter?: string
readonly farmV2S?: string[]
+ readonly zap?: {
+ helper: string
+ router: string
+ executor: string
+ validator: string
+ }
readonly 'farmV2.1S'?: string[]
}
readonly limitOrder: null | '*' | EnvKeys[]
diff --git a/src/hooks/elasticZap/index.ts b/src/hooks/elasticZap/index.ts
new file mode 100644
index 0000000000..52638f6d2c
--- /dev/null
+++ b/src/hooks/elasticZap/index.ts
@@ -0,0 +1,392 @@
+import { Currency, CurrencyAmount, Percent } from '@kyberswap/ks-sdk-core'
+import { BigNumber } from 'ethers'
+import { Interface, defaultAbiCoder as abiEncoder } from 'ethers/lib/utils'
+import JSBI from 'jsbi'
+import { useCallback, useEffect, useMemo, useState } from 'react'
+import { useBuildRouteMutation, useLazyGetRouteQuery } from 'services/route'
+import { RouteSummary } from 'services/route/types/getRoute'
+
+import { BuildRouteResult } from 'components/SwapForm/hooks/useBuildRoute'
+import ZAP_ROUTER_ABI from 'constants/abis/elastic-zap/router.json'
+import ZAP_HELPER_ABI from 'constants/abis/elastic-zap/zap-helper.json'
+import { AGGREGATOR_API_PATHS } from 'constants/index'
+import { NETWORKS_INFO } from 'constants/networks'
+import { EVMNetworkInfo } from 'constants/networks/type'
+import { useActiveWeb3React, useWeb3React } from 'hooks'
+import { useReadingContract, useSigningContract } from 'hooks/useContract'
+import { useKyberswapGlobalConfig } from 'hooks/useKyberSwapConfig'
+import useTransactionDeadline from 'hooks/useTransactionDeadline'
+import { useSingleContractMultipleData } from 'state/multicall/hooks'
+import { useAggregatorForZapSetting, useUserSlippageTolerance } from 'state/user/hooks'
+import { calculateGasMargin } from 'utils'
+
+export interface ZapResult {
+ liquidity: BigNumber
+ usedAmount0: BigNumber
+ usedAmount1: BigNumber
+ remainingAmount0: BigNumber
+ remainingAmount1: BigNumber
+ currentTick: number
+ sqrtP: BigNumber
+ baseL: BigNumber
+ reinvestL: BigNumber
+}
+
+const zapRouterInterface = new Interface(ZAP_ROUTER_ABI)
+
+export function useZapInPoolResult(params?: {
+ poolAddress: string
+ tokenIn: string
+ tokenOut: string
+ amountIn: CurrencyAmount
+ tickLower: number
+ tickUpper: number
+}): {
+ loading: boolean
+ aggregatorData: RouteSummary | null
+ result: ZapResult | undefined
+} {
+ const { networkInfo, chainId } = useActiveWeb3React()
+ const zapHelperContract = useReadingContract((networkInfo as EVMNetworkInfo).elastic.zap?.helper, ZAP_HELPER_ABI)
+
+ const [useAggregatorForZap] = useAggregatorForZapSetting()
+
+ const [loadingAggregator, setLoadingAggregator] = useState(false)
+ const [getRoute] = useLazyGetRouteQuery()
+
+ const { aggregatorDomain } = useKyberswapGlobalConfig()
+ const url = `${aggregatorDomain}/${NETWORKS_INFO[chainId].aggregatorRoute}${AGGREGATOR_API_PATHS.GET_ROUTE}`
+
+ const splitedAmount = useMemo(() => {
+ if (!params?.amountIn) return []
+ const percent = [10, 20, 30, 40, 50, 60, 70, 80, 90]
+ const percents = percent.map(item => new Percent(item, 100))
+ return percents.map(item => params.amountIn.multiply(item))
+ }, [params?.amountIn])
+
+ const [aggregatorOutputs, setAggregatorOutputs] = useState>([])
+
+ const { tokenIn, tokenOut, poolAddress } = params || {}
+ useEffect(() => {
+ if (tokenIn && tokenOut && poolAddress) {
+ setAggregatorOutputs([])
+ if (useAggregatorForZap) {
+ setLoadingAggregator(true)
+
+ Promise.all(
+ splitedAmount.map(item => {
+ return getRoute({
+ url,
+ authentication: false,
+ params: {
+ tokenIn,
+ tokenOut,
+ saveGas: '',
+ amountIn: item.quotient.toString(),
+ excludedPools: poolAddress,
+ },
+ clientId: 'kyberswap-zap',
+ })
+ }),
+ )
+ .then(res => res?.map(item => item?.data?.data?.routeSummary) || [])
+ .then(res => setAggregatorOutputs(res.filter(Boolean) as Array))
+ .finally(() => {
+ setTimeout(() => setLoadingAggregator(false), 100)
+ })
+ }
+ }
+ }, [tokenIn, tokenOut, poolAddress, splitedAmount, getRoute, url, useAggregatorForZap])
+
+ const callParams = useMemo(
+ () =>
+ params && !loadingAggregator && params.tickLower < params.tickUpper
+ ? [
+ [
+ params.poolAddress,
+ params.tokenIn,
+ params.amountIn.quotient.toString(),
+ '0',
+ 1,
+ params.tickLower,
+ params.tickUpper,
+ ],
+ ...aggregatorOutputs
+ .filter(item => JSBI.greaterThan(params.amountIn.quotient, JSBI.BigInt(item.amountIn)))
+ .map(item => [
+ params.poolAddress,
+ params.tokenIn,
+ JSBI.subtract(params.amountIn.quotient, JSBI.BigInt(item.amountIn)).toString(),
+ item.amountOut,
+ 1,
+ params.tickLower,
+ params.tickUpper,
+ ]),
+ ]
+ : undefined,
+ [params, aggregatorOutputs, loadingAggregator],
+ )
+
+ const data = useSingleContractMultipleData(
+ params ? zapHelperContract : undefined,
+ 'getZapInPoolResults',
+ callParams || [],
+ )
+
+ const bestRes = useMemo(() => {
+ let index = -1
+ let res = undefined
+ let maxLiq = BigNumber.from('0')
+ data.forEach((item, idx) => {
+ const l = BigNumber.from(item?.result?.results?.liquidity?.toString() || '0')
+ if (l.gt(maxLiq)) {
+ maxLiq = l
+ index = idx
+ res = item?.result?.results
+ }
+ })
+
+ return {
+ result: res,
+ loading: data?.some(item => item?.loading) || loadingAggregator,
+ // index = 0 => dont need to use aggregator
+ aggregatorData:
+ index === 0 || !params
+ ? null
+ : aggregatorOutputs?.filter(item => JSBI.greaterThan(params.amountIn.quotient, JSBI.BigInt(item.amountIn)))?.[
+ index - 1
+ ],
+ }
+ }, [data, loadingAggregator, aggregatorOutputs, params])
+
+ return bestRes
+}
+
+export function useZapInAction() {
+ const { networkInfo, account, chainId } = useActiveWeb3React()
+ const { library } = useWeb3React()
+ const { router: zapRouterAddress, validator, executor } = (networkInfo as EVMNetworkInfo).elastic?.zap || {}
+ const zapRouterContract = useSigningContract(zapRouterAddress, ZAP_ROUTER_ABI)
+
+ const posManagerAddress = (networkInfo as EVMNetworkInfo).elastic.nonfungiblePositionManager
+ const [slippage] = useUserSlippageTolerance()
+ const deadline = useTransactionDeadline() // custom from users settings
+
+ const [useAggregatorForZap] = useAggregatorForZapSetting()
+ const [buildRoute] = useBuildRouteMutation()
+
+ const { aggregatorDomain } = useKyberswapGlobalConfig()
+ const url = `${aggregatorDomain}/${NETWORKS_INFO[chainId].aggregatorRoute}${AGGREGATOR_API_PATHS.BUILD_ROUTE}`
+
+ const zapIn = useCallback(
+ async (
+ {
+ tokenId = 0,
+ tokenIn,
+ amountIn,
+ equivalentQuoteAmount,
+ poolAddress,
+ tickUpper,
+ tickLower,
+ poolInfo,
+ tickPrevious,
+ liquidity,
+ aggregatorRoute,
+ }: {
+ tokenId?: number | string
+ tokenIn: string
+ amountIn: string
+ equivalentQuoteAmount: string
+ poolAddress: string
+ tickLower: number
+ tickUpper: number
+ poolInfo: {
+ token0: string
+ token1: string
+ fee: number
+ }
+ tickPrevious: [number, number]
+ liquidity: string
+ aggregatorRoute: RouteSummary | null
+ },
+ options: {
+ zapWithNative: boolean
+ estimateOnly?: boolean
+ },
+ ) => {
+ if (zapRouterContract && account && library && executor) {
+ let aggregatorRes = null
+ if (aggregatorRoute && useAggregatorForZap) {
+ aggregatorRes = (await buildRoute({
+ url,
+ payload: {
+ routeSummary: aggregatorRoute,
+ deadline: +(deadline?.toString() || (Math.floor(Date.now() / 1000) + 1200).toString()),
+ slippageTolerance: slippage,
+ sender: account,
+ recipient: executor,
+ source: 'kyberswap-zap',
+ skipSimulateTx: false,
+ },
+ authentication: false,
+ })) as { data: BuildRouteResult }
+ }
+
+ const minLiquidity = JSBI.divide(
+ JSBI.multiply(JSBI.BigInt(liquidity), JSBI.BigInt(10000 - slippage)),
+ JSBI.BigInt(10000),
+ ).toString()
+
+ const zapInfo = abiEncoder.encode(['address', 'address', 'uint256'], [poolAddress, posManagerAddress, tokenId])
+ const extraData = tokenId
+ ? abiEncoder.encode(['uint128'], [minLiquidity])
+ : abiEncoder.encode(['address', 'int24', 'int24', 'uint128'], [account, tickLower, tickUpper, minLiquidity])
+
+ const zeros = '0'.repeat(128)
+ const minZapAmount0 = JSBI.divide(
+ JSBI.multiply(JSBI.BigInt(amountIn), JSBI.BigInt(slippage)),
+ JSBI.BigInt(10000),
+ ).toString(2)
+
+ const minZapAmount1 = JSBI.divide(
+ JSBI.multiply(JSBI.BigInt(equivalentQuoteAmount), JSBI.BigInt(slippage)),
+ JSBI.BigInt(10000),
+ ).toString(2)
+
+ const minZapAmount = JSBI.BigInt(
+ parseInt((zeros + minZapAmount0).slice(-128) + (zeros + minZapAmount1).slice(-128), 2),
+ ).toString()
+
+ const zapExecutorData = abiEncoder.encode(
+ [
+ 'address',
+ 'address',
+ 'tupple(address token0,int24 fee,address token1)',
+ 'uint256',
+ 'address',
+ 'uint256',
+ 'uint256',
+ 'int24',
+ 'int24',
+ 'int24[2]',
+ 'uint128',
+ 'bytes',
+ ],
+ [
+ posManagerAddress,
+ poolAddress,
+ { token0: poolInfo.token0, fee: poolInfo.fee, token1: poolInfo.token1 },
+ tokenId,
+ account,
+ 1,
+ minZapAmount,
+ tickLower,
+ tickUpper,
+ tickPrevious,
+ minLiquidity,
+ '0x',
+ ],
+ )
+
+ let aggregatorInfo = '0x'
+ if (aggregatorRes?.data?.data) {
+ aggregatorInfo =
+ '0x0000000000000000000000000000000000000000000000000000000000000020' +
+ abiEncoder
+ .encode(
+ ['address', 'uint256', 'bytes'],
+ [aggregatorRes.data.data.routerAddress, aggregatorRes.data.data.amountIn, aggregatorRes.data.data.data],
+ )
+ .slice(2)
+ }
+
+ const executorData = abiEncoder.encode(
+ ['uint8', 'address', 'uint256', 'bytes', 'bytes', 'bytes'],
+ [
+ 0,
+ tokenIn,
+ amountIn,
+ '0x', // feeInfo
+ aggregatorInfo,
+ // hardcode for dynamic field (poolInfo) in contract
+ '0x0000000000000000000000000000000000000000000000000000000000000020' + zapExecutorData.slice(2),
+ ],
+ )
+
+ const params = [
+ [
+ 0, //dextype: elastic
+ tokenIn,
+ amountIn,
+ zapInfo,
+ extraData,
+ '0x',
+ ],
+ [validator, executor, deadline?.toString(), executorData, '0x'],
+ ]
+
+ const callData = zapRouterInterface.encodeFunctionData(
+ options.zapWithNative ? 'zapInWithNative' : 'zapIn',
+ params,
+ )
+
+ console.debug('zap data', {
+ value: options.zapWithNative ? amountIn : undefined,
+ data: callData,
+ to: zapRouterAddress,
+ })
+
+ const gasEstimated = await zapRouterContract.estimateGas[options.zapWithNative ? 'zapInWithNative' : 'zapIn'](
+ ...params,
+ {
+ value: options.zapWithNative ? amountIn : undefined,
+ },
+ )
+
+ if (options.estimateOnly) {
+ return {
+ gasEstimated,
+ hash: '',
+ }
+ }
+
+ const txn = {
+ value: options.zapWithNative ? amountIn : undefined,
+ data: callData,
+ to: zapRouterAddress,
+ gasLimit: calculateGasMargin(gasEstimated),
+ }
+
+ const { hash } = await library.getSigner().sendTransaction(txn)
+
+ return {
+ gasEstimated,
+ hash,
+ }
+ }
+
+ return {
+ gasEstimated: 0,
+ hash: '',
+ }
+ },
+ [
+ account,
+ deadline,
+ executor,
+ validator,
+ posManagerAddress,
+ zapRouterContract,
+ slippage,
+ buildRoute,
+ useAggregatorForZap,
+ url,
+ library,
+ zapRouterAddress,
+ ],
+ )
+
+ return {
+ zapIn,
+ }
+}
diff --git a/src/hooks/useApproveCallback.ts b/src/hooks/useApproveCallback.ts
index 976cb0d799..d770f2f6b0 100644
--- a/src/hooks/useApproveCallback.ts
+++ b/src/hooks/useApproveCallback.ts
@@ -19,10 +19,10 @@ import { useActiveWeb3React } from './index'
import { useTokenSigningContract } from './useContract'
export enum ApprovalState {
- UNKNOWN,
- NOT_APPROVED,
- PENDING,
- APPROVED,
+ UNKNOWN = 'UNKNOWN',
+ NOT_APPROVED = 'NOT_APPROVED',
+ PENDING = 'PENDING',
+ APPROVED = 'APPROVED',
}
// returns a variable indicating the state of the approval and a function which approves if necessary or early returns
diff --git a/src/hooks/useProAmmDerivedPositionInfo.ts b/src/hooks/useProAmmDerivedPositionInfo.ts
index 011dd57c96..5875a2cae0 100644
--- a/src/hooks/useProAmmDerivedPositionInfo.ts
+++ b/src/hooks/useProAmmDerivedPositionInfo.ts
@@ -1,4 +1,5 @@
import { Pool, Position } from '@kyberswap/ks-sdk-elastic'
+import { useMemo } from 'react'
import { PositionDetails } from 'types/position'
@@ -16,15 +17,21 @@ export function useProAmmDerivedPositionInfo(positionDetails: PositionDetails |
// construct pool data
const [poolState, pool] = usePool(currency0 ?? undefined, currency1 ?? undefined, positionDetails?.fee)
- let position = undefined
- if (pool && positionDetails) {
- position = new Position({
- pool,
- liquidity: positionDetails.liquidity.toString(),
- tickLower: positionDetails.tickLower,
- tickUpper: positionDetails.tickUpper,
- })
- }
+ const liquidity = positionDetails?.liquidity.toString()
+ const tickLower = positionDetails?.tickLower
+ const tickUpper = positionDetails?.tickUpper
+ const position = useMemo(() => {
+ if (pool && liquidity && tickUpper !== undefined && tickLower !== undefined) {
+ return new Position({
+ pool,
+ liquidity,
+ tickLower,
+ tickUpper,
+ })
+ }
+ return undefined
+ }, [pool, liquidity, tickLower, tickUpper])
+
return {
position,
pool: pool ?? undefined,
diff --git a/src/hooks/useProAmmPreviousTicks.ts b/src/hooks/useProAmmPreviousTicks.ts
index 46f7a14c3c..0dbef916b0 100644
--- a/src/hooks/useProAmmPreviousTicks.ts
+++ b/src/hooks/useProAmmPreviousTicks.ts
@@ -42,6 +42,7 @@ export default function useProAmmPreviousTicks(
return undefined
}, [results, loading, error, pool])
}
+
export function useProAmmMultiplePreviousTicks(
pool: Pool | null | undefined,
positions: (Position | undefined)[],
diff --git a/src/pages/AddLiquidityV2/components/DisclaimerERC20.tsx b/src/pages/AddLiquidityV2/components/DisclaimerERC20.tsx
index eab3e5f91f..68adfcc800 100644
--- a/src/pages/AddLiquidityV2/components/DisclaimerERC20.tsx
+++ b/src/pages/AddLiquidityV2/components/DisclaimerERC20.tsx
@@ -11,7 +11,7 @@ import { ExternalLink } from 'theme'
export default function DisclaimerERC20({ href, token0, token1 }: { href?: string; token0: string; token1: string }) {
const theme = useTheme()
const { chainId } = useActiveWeb3React()
- const { data } = useGetTokenListQuery(
+ const { data, isLoading } = useGetTokenListQuery(
{
chainId,
addresses: `${token0},${token1}`,
@@ -22,28 +22,29 @@ export default function DisclaimerERC20({ href, token0, token1 }: { href?: strin
)
const hide = data?.data?.tokens?.[0]?.isStandardERC20 && data?.data?.tokens?.[1]?.isStandardERC20
- if (hide) return null
- return (
-
-
-
-
-
- Disclaimer: KyberSwap is a permissionless protocol optimized for the standard ERC20 implementation only.
- Please do your own research before you provide liquidity using tokens with unique mechanics (e.g. FOT,
- Rebase, LP tokens, contract deposits, etc.). More info{' '}
-
- here
-
-
-
-
-
- )
+ if (!hide && !isLoading)
+ return (
+
+
+
+
+
+ Disclaimer: KyberSwap is a permissionless protocol optimized for the standard ERC20 implementation only.
+ Please do your own research before you provide liquidity using tokens with unique mechanics (e.g. FOT,
+ Rebase, LP tokens, contract deposits, etc.). More info{' '}
+
+ here
+
+
+
+
+
+ )
+ return null
}
diff --git a/src/pages/AddLiquidityV2/index.tsx b/src/pages/AddLiquidityV2/index.tsx
index 170fa347b1..2ce9bff4db 100644
--- a/src/pages/AddLiquidityV2/index.tsx
+++ b/src/pages/AddLiquidityV2/index.tsx
@@ -12,7 +12,7 @@ import {
import { Trans, t } from '@lingui/macro'
import { BigNumber } from 'ethers'
import JSBI from 'jsbi'
-import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { AlertTriangle, Repeat } from 'react-feather'
import { Navigate, useNavigate, useParams, useSearchParams } from 'react-router-dom'
import { useMedia } from 'react-use'
@@ -24,6 +24,8 @@ import { ButtonError, ButtonLight, ButtonPrimary } from 'components/Button'
import { OutlineCard, SubTextCard, WarningCard } from 'components/Card'
import { AutoColumn } from 'components/Column'
import CurrencyInputPanel from 'components/CurrencyInputPanel'
+import CurrencyLogo from 'components/CurrencyLogo'
+import { useZapDetail } from 'components/ElasticZap/ZapDetail'
import FeeSelector from 'components/FeeSelector'
import HoverInlineText from 'components/HoverInlineText'
import { Swap as SwapIcon, TwoWayArrow } from 'components/Icons'
@@ -41,8 +43,13 @@ import Rating from 'components/Rating'
import Row, { RowBetween, RowFixed } from 'components/Row'
import ShareModal from 'components/ShareModal'
import { SLIPPAGE_EXPLANATION_URL } from 'components/SlippageWarningNote'
+import PriceImpactNote, { ZapHighPriceImpact } from 'components/SwapForm/PriceImpactNote'
+import useParsedAmount from 'components/SwapForm/hooks/useParsedAmount'
import Tooltip, { MouseoverTooltip } from 'components/Tooltip'
-import TransactionConfirmationModal, { ConfirmationModalContent } from 'components/TransactionConfirmationModal'
+import TransactionConfirmationModal, {
+ ConfirmationModalContent,
+ TransactionErrorContent,
+} from 'components/TransactionConfirmationModal'
import { TutorialType } from 'components/Tutorial'
import { Dots } from 'components/swapv2/styleds'
import { APP_PATHS, ETHER_ADDRESS } from 'constants/index'
@@ -51,8 +58,10 @@ import { EVMNetworkInfo } from 'constants/networks/type'
import { NativeCurrencies } from 'constants/tokens'
import { useActiveWeb3React, useWeb3React } from 'hooks'
import { useCurrency } from 'hooks/Tokens'
+import { useZapInAction, useZapInPoolResult } from 'hooks/elasticZap'
import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback'
-import { useProAmmNFTPositionManagerReadingContract } from 'hooks/useContract'
+import { useProAmmNFTPositionManagerReadingContract, useProAmmTickReader } from 'hooks/useContract'
+import useDebounce from 'hooks/useDebounce'
import useInterval from 'hooks/useInterval'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import useProAmmPoolInfo from 'hooks/useProAmmPoolInfo'
@@ -73,6 +82,7 @@ import {
useRangeHopCallbacks,
} from 'state/mint/proamm/hooks'
import { Bound, Field, RANGE } from 'state/mint/proamm/type'
+import { useSingleContractMultipleData } from 'state/multicall/hooks'
import { useUserProMMPositions } from 'state/prommPools/hooks'
import useGetElasticPools from 'state/prommPools/useGetElasticPools'
import { useTokenPricesWithLoading } from 'state/tokenPrices/hooks'
@@ -80,13 +90,16 @@ import { usePairFactor } from 'state/topTokens/hooks'
import { useTransactionAdder } from 'state/transactions/hooks'
import { TRANSACTION_TYPE } from 'state/transactions/type'
import { useDegenModeManager, useUserSlippageTolerance } from 'state/user/hooks'
+import { useCurrencyBalances } from 'state/wallet/hooks'
import { ExternalLink, MEDIA_WIDTHS, StyledInternalLink, TYPE } from 'theme'
import { basisPointsToPercent, calculateGasMargin, formattedNum } from 'utils'
import { currencyId } from 'utils/currencyId'
import { friendlyError } from 'utils/errorMessage'
import { maxAmountSpend } from 'utils/maxAmountSpend'
import { formatDisplayNumber, toString } from 'utils/numbers'
-import { SLIPPAGE_STATUS, checkRangeSlippage } from 'utils/slippage'
+import { SLIPPAGE_STATUS, checkRangeSlippage, formatSlippage } from 'utils/slippage'
+import { getTokenSymbolWithHardcode } from 'utils/tokenInfo'
+import { unwrappedToken } from 'utils/wrappedCurrency'
import DisclaimerERC20 from './components/DisclaimerERC20'
import NewPoolNote from './components/NewPoolNote'
@@ -98,6 +111,7 @@ import {
Container,
DynamicSection,
FlexLeft,
+ MethodSelector,
PageWrapper,
RangeBtn,
RangeTab,
@@ -239,11 +253,26 @@ export default function AddLiquidity() {
const defaultFId = Number(searchParams.get('fId') || '0')
const range = activeRanges.find(i => i.index === activeRangeIndex && i.farm.fId === defaultFId)
+ const isZapAvailable = !!(networkInfo as EVMNetworkInfo).elastic.zap
+ const [method, setMethod] = useState<'pair' | 'zap'>(() => (isZapAvailable ? 'zap' : 'pair'))
+
+ useEffect(() => {
+ if (!isZapAvailable) {
+ setMethod('pair')
+ }
+ }, [isZapAvailable])
+
const canJoinFarm =
isFarmV2Available &&
positions.some(pos => activeRanges.some(r => pos && pos.tickLower <= r.tickLower && pos.tickUpper >= r.tickUpper))
- const farmPosWarning = positions.every(Boolean) && isFarmV2Available && !canJoinFarm
+ const farmPosWarning =
+ method === 'pair'
+ ? positions.every(Boolean) && isFarmV2Available && !canJoinFarm
+ : isFarmV2Available &&
+ tickUpper !== undefined &&
+ tickLower !== undefined &&
+ activeRanges.every(r => r.tickLower < tickLower || r.tickUpper > tickUpper)
const previousTicks: number[] | undefined = useProAmmPreviousTicks(pool, position)
const mutiplePreviousTicks: number[][] | undefined = useProAmmMultiplePreviousTicks(pool, positions)
@@ -606,7 +635,9 @@ export default function AddLiquidity() {
)
const handleDismissConfirmation = useCallback(() => {
- setShowConfirm(false)
+ if (method === 'zap') setShowZapConfirmation(false)
+ else setShowConfirm(false)
+ setZapError('')
// if there was a tx hash, we want to clear the input
if (txHash) {
onFieldAInput('')
@@ -614,7 +645,7 @@ export default function AddLiquidity() {
navigate(`${APP_PATHS.MY_POOLS}/${networkInfo.route}?tab=elastic`)
}
setTxHash('')
- }, [navigate, networkInfo.route, onFieldAInput, txHash])
+ }, [navigate, networkInfo.route, onFieldAInput, txHash, method])
const handleDismissConfirmationRef = useRef(handleDismissConfirmation)
@@ -816,9 +847,25 @@ export default function AddLiquidity() {
const [allowedSlippage] = useUserSlippageTolerance()
const slippageStatus = checkRangeSlippage(allowedSlippage, false)
- const warnings = (
-
- {noLiquidity && (
+ useEffect(() => {
+ if (noLiquidity) {
+ setMethod('pair')
+ }
+ }, [noLiquidity])
+
+ const showWarning =
+ noLiquidity ||
+ isPriceDeviated ||
+ errorLabel ||
+ invalidRange ||
+ isFullRange ||
+ outOfRange ||
+ slippageStatus === SLIPPAGE_STATUS.HIGH ||
+ farmPosWarning
+
+ const warnings = !!showWarning && (
+
+ {!!noLiquidity && (
@@ -840,7 +887,7 @@ export default function AddLiquidity() {
)}
- {isPriceDeviated && (
+ {!!isPriceDeviated && (
@@ -853,7 +900,7 @@ export default function AddLiquidity() {
{formatDisplayNumber(usdPrices[tokenA.wrapped.address] / usdPrices[tokenB.wrapped.address], {
significantDigits: 4,
})}{' '}
- {quoteCurrency.symbol}). You might have high impermanent loss after the pool is created
+ {quoteCurrency.symbol}). You might have high impermanent loss after the pool is created.
) : (
@@ -865,7 +912,7 @@ export default function AddLiquidity() {
})}{' '}
{quoteCurrency.symbol}) by {(priceDiff * 100).toFixed(2)}%. Please consider the{' '}
- impermanent loss
+ impermanent loss.
)}
@@ -873,7 +920,7 @@ export default function AddLiquidity() {
)}
- {errorLabel && (
+ {errorLabel && method === 'pair' && (
@@ -883,7 +930,7 @@ export default function AddLiquidity() {
)}
- {invalidRange ? (
+ {!!invalidRange ? (
@@ -913,7 +960,7 @@ export default function AddLiquidity() {
) : null}
- {farmPosWarning && (
+ {!!farmPosWarning && (
@@ -960,282 +1007,651 @@ export default function AddLiquidity() {
const isReverseWithFarm = baseCurrency?.wrapped.address !== farmV2S?.[0]?.token0.wrapped.address
- const chart = (
-
- {hasTab && (
- setPositionIndex(index)}
- onAddTab={onAddPositionEvent}
- onRemoveTab={onRemovePositionEvent}
- showChart={showChart}
- onToggleChart={(newShowChart: boolean | undefined) => {
- const newValue = typeof newShowChart !== 'undefined' ? newShowChart : !showChart
- if (newValue && tokenA?.symbol && tokenB?.symbol) {
- mixpanelHandler(MIXPANEL_TYPE.ELASTIC_ADD_LIQUIDITY_CLICK_PRICE_CHART, {
- token_1: tokenA?.symbol,
- token_2: tokenB?.symbol,
- })
- }
- setShowChart(newValue)
- }}
- />
- )}
-
- {hasTab && (
-
+ const handleSwitch = (isQuote?: boolean) => {
+ const param1 = isQuote
+ ? currencyIdA
+ : baseCurrencyIsETHER
+ ? WETH[chainId].address
+ : NativeCurrencies[chainId].symbol
+ const param2 = isQuote
+ ? quoteCurrencyIsETHER
+ ? WETH[chainId].address
+ : NativeCurrencies[chainId].symbol
+ : currencyIdB
+ return (
+ chainId &&
+ navigate(`/${networkInfo.route}${APP_PATHS.ELASTIC_CREATE_POOL}/${param1}/${param2}/${feeAmount}`, {
+ replace: true,
+ })
+ )
+ }
+
+ // ZAP state
+ const [zapValue, setZapValue] = useState('')
+ const [isReverse, setIsReverse] = useState(false)
+ const [useWrapped, setUseWrapped] = useState(false)
+
+ const selectedCurrency = useMemo(() => {
+ const currency = isReverse ? currencies[Field.CURRENCY_B] : currencies[Field.CURRENCY_A]
+ if (useWrapped) return currency?.wrapped
+ return currency ? unwrappedToken(currency) : currency
+ }, [isReverse, currencies, useWrapped])
+
+ const quoteZapCurrency = useMemo(() => {
+ return isReverse ? currencies[Field.CURRENCY_A] : currencies[Field.CURRENCY_B]
+ }, [isReverse, currencies])
+
+ const debouncedValue = useDebounce(zapValue, 300)
+ const amountIn = useParsedAmount(selectedCurrency, debouncedValue)
+
+ const equivalentQuoteAmount =
+ amountIn && pool && selectedCurrency && amountIn.multiply(pool.priceOf(selectedCurrency.wrapped))
+
+ const params = useMemo(() => {
+ return poolAddress &&
+ amountIn?.greaterThan('0') &&
+ selectedCurrency &&
+ tickLower !== undefined &&
+ tickUpper !== undefined &&
+ quoteZapCurrency
+ ? {
+ poolAddress,
+ tokenIn: selectedCurrency.wrapped.address,
+ tokenOut: quoteZapCurrency.wrapped.address,
+ amountIn,
+ tickLower,
+ tickUpper,
+ }
+ : undefined
+ }, [amountIn, poolAddress, selectedCurrency, quoteZapCurrency, tickLower, tickUpper])
+
+ const { loading: zapLoading, result: zapResult, aggregatorData } = useZapInPoolResult(params)
+ const zapInContractAddress = (networkInfo as EVMNetworkInfo).elastic.zap?.router
+ const [zapApprovalState, zapApprove] = useApproveCallback(amountIn, zapInContractAddress)
+ const { zapIn } = useZapInAction()
+ const [showZapConfirmation, setShowZapConfirmation] = useState(false)
+ const [zapError, setZapError] = useState('')
+
+ const zapBalances = useCurrencyBalances(
+ useMemo(
+ () => [
+ currencies[Field.CURRENCY_A]
+ ? unwrappedToken(currencies[Field.CURRENCY_A] as Currency)
+ : currencies[Field.CURRENCY_A],
+ currencies[Field.CURRENCY_B]
+ ? unwrappedToken(currencies[Field.CURRENCY_B] as Currency)
+ : currencies[Field.CURRENCY_B],
+ currencies[Field.CURRENCY_A]?.wrapped,
+ currencies[Field.CURRENCY_B]?.wrapped,
+ ],
+ [currencies],
+ ),
+ )
+
+ const balanceIndex = useWrapped ? (isReverse ? 3 : 2) : isReverse ? 1 : 0
+ const balance = zapBalances[balanceIndex]
+ let error: ReactElement | null = null
+ if (!zapValue) error = Enter an amount
+ else if (!amountIn) error = Invalid Input
+ else if (balance && amountIn?.greaterThan(balance)) error = Insufficient Balance
+ else if (!zapResult) error = Insufficient Liquidity
+
+ const tickReader = useProAmmTickReader()
+
+ const results = useSingleContractMultipleData(
+ poolAddress && tickLower !== undefined && tickUpper !== undefined ? tickReader : undefined,
+ 'getNearestInitializedTicks',
+ [
+ [poolAddress, tickLower],
+ [poolAddress, tickUpper],
+ ],
+ )
+
+ const tickPreviousForZap = useMemo(() => {
+ return results.map(call => call.result?.previous)
+ }, [results])
+
+ const zapDetail = useZapDetail({
+ pool,
+ tokenIn: selectedCurrency?.wrapped?.address,
+ position: undefined,
+ zapResult,
+ amountIn,
+ poolAddress,
+ tickLower,
+ tickUpper,
+ previousTicks: tickPreviousForZap,
+ aggregatorRoute: aggregatorData,
+ })
+
+ const { newPosDraft } = zapDetail
+
+ const handleZap = async () => {
+ if (zapApprovalState === ApprovalState.NOT_APPROVED) {
+ zapApprove()
+ return
+ }
+
+ if (
+ tickUpper !== undefined &&
+ tickLower !== undefined &&
+ selectedCurrency &&
+ zapResult &&
+ amountIn?.quotient &&
+ tickPreviousForZap.length == 2 &&
+ pool
+ ) {
+ try {
+ setAttemptingTxn(true)
+ const { hash: txHash } = await zapIn(
+ {
+ tokenId: 0,
+ tokenIn: selectedCurrency.wrapped.address,
+ amountIn: amountIn.quotient.toString(),
+ equivalentQuoteAmount: equivalentQuoteAmount?.quotient.toString() || '0',
+ poolAddress,
+ tickLower,
+ tickUpper,
+ tickPrevious: [tickPreviousForZap[0], tickPreviousForZap[1]],
+ poolInfo: {
+ token0: pool.token0.wrapped.address,
+ fee: pool.fee,
+ token1: pool.token1.wrapped.address,
+ },
+ liquidity: zapResult.liquidity.toString(),
+ aggregatorRoute: aggregatorData,
+ },
+ {
+ zapWithNative: selectedCurrency.isNative,
+ },
+ )
+ setTxHash(txHash)
+ setAttemptingTxn(false)
+ const tokenSymbolIn = newPosDraft ? unwrappedToken(newPosDraft.amount0.currency).symbol : ''
+ const tokenSymbolOut = newPosDraft ? unwrappedToken(newPosDraft.amount1.currency).symbol : ''
+ addTransactionWithType({
+ hash: txHash,
+ type: TRANSACTION_TYPE.ELASTIC_ZAP_IN_LIQUIDITY,
+ extraInfo: {
+ zapAmountIn: amountIn.toSignificant(6) || '0',
+ zapSymbolIn: selectedCurrency?.symbol || '',
+ tokenAmountIn: newPosDraft?.amount0.toSignificant(6) || '',
+ tokenAmountOut: newPosDraft?.amount1.toSignificant(6) || '',
+ tokenAddressIn: newPosDraft?.amount0.currency.wrapped.address || '',
+ tokenAddressOut: newPosDraft?.amount1.currency.wrapped.address || '',
+ tokenSymbolIn,
+ tokenSymbolOut,
+ arbitrary: {
+ token_1: tokenSymbolIn,
+ token_2: tokenSymbolOut,
+ },
+ },
+ })
+ } catch (e) {
+ console.error('zap error', e)
+ setAttemptingTxn(false)
+ setZapError(e?.message || JSON.stringify(e))
+ }
+ }
+ }
+
+ const handleDissmissZap = () => {
+ setShowZapConfirmation(false)
+ setTxHash('')
+ setZapError('')
+ setAttemptingTxn(false)
+ }
+
+ const zapPriceImpactNote = method === 'zap' &&
+ !!(zapDetail.priceImpact?.isVeryHigh || zapDetail.priceImpact?.isHigh || zapDetail.priceImpact?.isInvalid) &&
+ zapResult &&
+ !zapLoading && (
+ <>
+ {zapDetail.priceImpact.isVeryHigh ? (
+
+ ) : (
+
)}
- {hasTab && showChart ? null : (
- <>
-
-
-
- setShowFarmRangeSelect(false)}>
- {isFarmV2Available ? Custom Ranges : Select a Range}
-
-
-
- {isFarmV2Available && (
- <>
-
- |
-
+ >
+ )
-
-
- Add your liquidity into one of the farming ranges to participate in Elastic Static Farm.
- Only positions that cover the range of the farm will earn maximum rewards. Learn more{' '}
-
- here ↗
-
-
-
- }
- >
- {
- range && onFarmRangeSelected(range.tickLower, range.tickUpper)
- setShowFarmRangeSelect(true)
- }}
+ const ZapButton = (
+ {
+ if (zapApprovalState === ApprovalState.NOT_APPROVED) {
+ zapApprove()
+ return
+ }
+
+ setShowZapConfirmation(true)
+ }}
+ color={zapDetail.priceImpact?.isVeryHigh ? theme.text : undefined}
+ backgroundColor={
+ zapApprovalState !== ApprovalState.APPROVED
+ ? undefined
+ : zapDetail.priceImpact.isVeryHigh
+ ? theme.red
+ : zapDetail.priceImpact.isHigh
+ ? theme.warning
+ : undefined
+ }
+ disabled={
+ !!error ||
+ zapApprovalState === ApprovalState.PENDING ||
+ zapLoading ||
+ (zapApprovalState === ApprovalState.APPROVED && !isDegenMode && zapDetail.priceImpact?.isVeryHigh)
+ }
+ style={{ width: upToMedium ? '100%' : 'fit-content', minWidth: '164px' }}
+ >
+ {(() => {
+ if (error) return error
+ if (zapApprovalState === ApprovalState.PENDING)
+ return (
+
+ Approving
+
+ )
+ if (zapApprovalState !== ApprovalState.APPROVED) return Approve
+
+ if (zapLoading)
+ return (
+
+ Loading
+
+ )
+ return Preview
+ })()}
+
+ )
+
+ const token0IsNative =
+ selectedCurrency?.isNative && selectedCurrency?.wrapped.address.toLowerCase() === pool?.token0.address.toLowerCase()
+ const zapSymbol0 = token0IsNative ? selectedCurrency.symbol : pool?.token0.symbol
+ const token1IsNative =
+ selectedCurrency?.isNative && selectedCurrency?.wrapped.address.toLowerCase() === pool?.token1.address.toLowerCase()
+ const zapSymbol1 = token1IsNative ? selectedCurrency.symbol : pool?.token1.symbol
+
+ const chart = (
+ <>
+ {!noLiquidity && }
+
+ {hasTab && method !== 'zap' && (
+ setPositionIndex(index)}
+ onAddTab={onAddPositionEvent}
+ onRemoveTab={onRemovePositionEvent}
+ showChart={showChart}
+ onToggleChart={(newShowChart: boolean | undefined) => {
+ const newValue = typeof newShowChart !== 'undefined' ? newShowChart : !showChart
+ if (newValue && tokenA?.symbol && tokenB?.symbol) {
+ mixpanelHandler(MIXPANEL_TYPE.ELASTIC_ADD_LIQUIDITY_CLICK_PRICE_CHART, {
+ token_1: tokenA?.symbol,
+ token_2: tokenB?.symbol,
+ })
+ }
+ setShowChart(newValue)
+ }}
+ />
+ )}
+
+ {hasTab && (
+
+ )}
+ {hasTab && showChart ? null : (
+ <>
+
+
+
+ setShowFarmRangeSelect(false)}>
+ {isFarmV2Available ? Custom Ranges : Select a Range}
+
+
+
+ {isFarmV2Available && (
+ <>
+
+ |
+
+
+
+
+ Add your liquidity into one of the farming ranges to participate in Elastic Static Farm.
+ Only positionsthat cover the range of the farm will earn maximum rewards. Learn more{' '}
+
+ here ↗
+
+
+
+ }
>
- Farming Ranges
-
-
- >
+ {
+ range && onFarmRangeSelected(range.tickLower, range.tickUpper)
+ setShowFarmRangeSelect(true)
+ }}
+ >
+ Farming Ranges
+
+
+ >
+ )}
+
+ {showFarmRangeSelect && !!activeRanges.length && farmV2S?.[0] && (
+
+ {activeRanges.map(range => {
+ if (range.isRemoved) return null
+ return (
+ {
+ searchParams.set('farmRange', range.index.toString())
+ searchParams.set('fId', range.farm.fId.toString())
+ setSearchParams(searchParams)
+ onFarmRangeSelected(+range.tickLower, +range.tickUpper)
+ }}
+ isSelected={activeRangeIndex === range.index && defaultFId === range.farm.fId}
+ >
+
+ {convertTickToPrice(
+ isReverseWithFarm ? farmV2S[0].token1 : farmV2S[0].token0,
+ isReverseWithFarm ? farmV2S[0].token0 : farmV2S[0].token1,
+ isReverseWithFarm ? range.tickUpper : range.tickLower,
+ farmV2S[0].pool.fee,
+ )}
+
+ {convertTickToPrice(
+ isReverseWithFarm ? farmV2S[0].token1 : farmV2S[0].token0,
+ isReverseWithFarm ? farmV2S[0].token0 : farmV2S[0].token1,
+ isReverseWithFarm ? range.tickLower : range.tickUpper,
+ farmV2S[0].pool.fee,
+ )}
+
+
+ )
+ })}
+
)}
-
- {showFarmRangeSelect && !!activeRanges.length && farmV2S?.[0] && (
-
- {activeRanges.map(range => {
- if (range.isRemoved) return null
+ {!showFarmRangeSelect &&
+ (() => {
+ const gap = '16px'
+ const buttonColumn = upToMedium ? 2 : 4
+ const buttonWidth = `calc((100% - ${gap} * (${buttonColumn} - 1)) / ${buttonColumn})`
return (
- {
- searchParams.set('farmRange', range.index.toString())
- searchParams.set('fId', range.farm.fId.toString())
- setSearchParams(searchParams)
- onFarmRangeSelected(+range.tickLower, +range.tickUpper)
- }}
- isSelected={activeRangeIndex === range.index && defaultFId === range.farm.fId}
- >
-
- {convertTickToPrice(
- isReverseWithFarm ? farmV2S[0].token1 : farmV2S[0].token0,
- isReverseWithFarm ? farmV2S[0].token0 : farmV2S[0].token1,
- isReverseWithFarm ? range.tickUpper : range.tickLower,
- farmV2S[0].pool.fee,
- )}
-
- {convertTickToPrice(
- isReverseWithFarm ? farmV2S[0].token1 : farmV2S[0].token0,
- isReverseWithFarm ? farmV2S[0].token0 : farmV2S[0].token1,
- isReverseWithFarm ? range.tickLower : range.tickUpper,
- farmV2S[0].pool.fee,
- )}
-
-
- )
- })}
-
- )}
- {!showFarmRangeSelect &&
- (() => {
- const gap = '16px'
- const buttonColumn = upToMedium ? 2 : 4
- const buttonWidth = `calc((100% - ${gap} * (${buttonColumn} - 1)) / ${buttonColumn})`
- return (
-
- {RANGE_LIST.map(range => (
-
-
- setRange(range)}
- isSelected={range === activeRange}
- onMouseEnter={() => setShownTooltip(range)}
- onMouseLeave={() => setShownTooltip(null)}
+
+ {RANGE_LIST.map(range => (
+
+
- {rangeData[range].title}
-
-
-
- ))}
-
- )
- })()}
-
-
-
- Estimated Risk
-
-
-
- Estimated Profit
-
-
-
- {price && baseCurrency && quoteCurrency && !noLiquidity && (
-
-
- Current Price
-
-
-
+ setRange(range)}
+ isSelected={range === activeRange}
+ onMouseEnter={() => setShownTooltip(range)}
+ onMouseLeave={() => setShownTooltip(null)}
+ >
+ {rangeData[range].title}
+
+
+
+ ))}
+
+ )
+ })()}
+
+
+
+ Estimated Risk
-
- {quoteCurrency?.symbol} per {baseCurrency.symbol}
+
+
+ Estimated Profit
-
- )}
-
-
-
-
-
-
-
+
+
+ {price && baseCurrency && quoteCurrency && !noLiquidity && (
+
+
+ Current Price
+
+
+
+
+
+ {quoteCurrency?.symbol} per {baseCurrency.symbol}
+
+
+ )}
+
+
+
+
+
+
+
+
-
-
-
- Deposit Amounts
-
-
-
- {
- onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
- }}
- onHalf={() => {
- onFieldAInput(currencyBalanceA?.divide(2).toExact() ?? '')
- }}
- currency={currencies_A ?? null}
- id="add-liquidity-input-tokena"
- showCommonBases
- positionMax="top"
- locked={depositADisabled}
- estimatedUsd={formattedNum(estimatedUsdCurrencyA.toString(), true) || undefined}
- disableCurrencySelect={!baseCurrencyIsETHER && !baseCurrencyIsWETH}
- isSwitchMode={baseCurrencyIsETHER || baseCurrencyIsWETH}
- onSwitchCurrency={() => {
- chainId &&
- navigate(
- `/${networkInfo.route}${APP_PATHS.ELASTIC_CREATE_POOL}/${
- baseCurrencyIsETHER ? WETH[chainId].address : NativeCurrencies[chainId].symbol
- }/${currencyIdB}/${feeAmount}`,
- { replace: true },
- )
- }}
- outline
- />
-
-
- {
- onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
- }}
- onHalf={() => {
- onFieldBInput(currencyBalanceB?.divide(2).toExact() ?? '')
- }}
- currency={currencies_B ?? null}
- id="add-liquidity-input-tokenb"
- showCommonBases
- positionMax="top"
- locked={depositBDisabled}
- estimatedUsd={formattedNum(estimatedUsdCurrencyB.toString(), true) || undefined}
- disableCurrencySelect={!quoteCurrencyIsETHER && !quoteCurrencyIsWETH}
- isSwitchMode={quoteCurrencyIsETHER || quoteCurrencyIsWETH}
- onSwitchCurrency={() => {
- chainId &&
- navigate(
- `/${networkInfo.route}${APP_PATHS.ELASTIC_CREATE_POOL}/${currencyIdA}/${
- quoteCurrencyIsETHER ? WETH[chainId].address : NativeCurrencies[chainId].symbol
- }/${feeAmount}`,
- { replace: true },
- )
- }}
- outline
- />
-
-
-
- >
- )}
-
-
+
+
+ Deposit Amounts
+
+
+ {method === 'pair' ? (
+
+
+ {
+ onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
+ }}
+ onHalf={() => {
+ onFieldAInput(currencyBalanceA?.divide(2).toExact() ?? '')
+ }}
+ currency={currencies_A ?? null}
+ id="add-liquidity-input-tokena"
+ showCommonBases
+ positionMax="top"
+ locked={depositADisabled}
+ estimatedUsd={formattedNum(estimatedUsdCurrencyA.toString(), true) || undefined}
+ disableCurrencySelect={!baseCurrencyIsETHER && !baseCurrencyIsWETH}
+ isSwitchMode={baseCurrencyIsETHER || baseCurrencyIsWETH}
+ onSwitchCurrency={() => handleSwitch(false)}
+ outline
+ />
+
+
+ {
+ onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
+ }}
+ onHalf={() => {
+ onFieldBInput(currencyBalanceB?.divide(2).toExact() ?? '')
+ }}
+ currency={currencies_B ?? null}
+ id="add-liquidity-input-tokenb"
+ showCommonBases
+ positionMax="top"
+ locked={depositBDisabled}
+ estimatedUsd={formattedNum(estimatedUsdCurrencyB.toString(), true) || undefined}
+ disableCurrencySelect={!quoteCurrencyIsETHER && !quoteCurrencyIsWETH}
+ isSwitchMode={quoteCurrencyIsETHER || quoteCurrencyIsWETH}
+ onSwitchCurrency={() => handleSwitch(true)}
+ outline
+ />
+
+
+ ) : (
+
+
+ {
+ setZapValue(v)
+ }}
+ onMax={() => {
+ const amount = zapBalances[balanceIndex]
+ if (amount) setZapValue(maxAmountSpend(amount)?.toExact() || '')
+ }}
+ onHalf={() => {
+ setZapValue(zapBalances[balanceIndex]?.divide('2').toExact() || '')
+ }}
+ currency={selectedCurrency}
+ positionMax="top"
+ showCommonBases
+ estimatedUsd={formattedNum(zapDetail.amountInUsd, true)}
+ isSwitchMode
+ onSwitchCurrency={() => {
+ if (selectedCurrency?.isNative) {
+ setUseWrapped(true)
+ } else {
+ setUseWrapped(false)
+ setIsReverse(prev => !prev)
+ }
+ }}
+ outline
+ />
+
+
+
+ Est. Pooled {zapSymbol0}
+ {zapLoading ? (
+ zapDetail.skeleton()
+ ) : !zapResult || !pool ? (
+ '--'
+ ) : (
+
+
+
+ {zapDetail.newPooledAmount0?.toSignificant(10)} {zapSymbol0}
+
+
+ )}
+
+
+
+ Est. Pooled {zapSymbol1}
+ {zapLoading ? (
+ zapDetail.skeleton()
+ ) : !zapResult || !pool ? (
+ '--'
+ ) : (
+
+
+
+ {zapDetail.newPooledAmount1?.toSignificant(10)} {zapSymbol1}
+
+
+ )}
+
+
+
+ Max Slippage
+ {formatSlippage(allowedSlippage)}
+
+
+
+ Price Impact
+ {zapLoading ? (
+ zapDetail.skeleton(40)
+ ) : !zapResult ? (
+ '--'
+ ) : (
+
+ {zapDetail.priceImpact.isInvalid
+ ? '--'
+ : zapDetail.priceImpact.value < 0.01
+ ? '<0.01%'
+ : zapDetail.priceImpact.value.toFixed(2) + '%'}
+
+ )}
+
+
+
+ )}
+
+ >
+ )}
+
+
+
+
+ {warnings}
+ {tokenA && tokenB && }
+
+ {zapPriceImpactNote}
+ {method === 'pair' || !account ? : ZapButton}
+
+ >
)
const [rotated, setRotated] = useState(false)
@@ -1346,9 +1762,19 @@ export default function AddLiquidity() {
onFarmRangeSelected(range.tickLower, range.tickUpper)
}
}, [isFarmV2Available, range?.tickUpper, range?.tickLower, onFarmRangeSelected, positionsState, pIndex])
-
if (!isEVM) return
+ const symbol0 = getTokenSymbolWithHardcode(
+ chainId,
+ pool?.token0?.wrapped.address,
+ useWrapped ? pool?.token0?.wrapped.symbol : (pool?.token0 ? unwrappedToken(pool.token0) : pool?.token0)?.symbol,
+ )
+ const symbol1 = getTokenSymbolWithHardcode(
+ chainId,
+ pool?.token1?.wrapped.address,
+ useWrapped ? pool?.token1?.wrapped.symbol : (pool?.token1 ? unwrappedToken(pool.token1) : pool?.token1)?.symbol,
+ )
+
return (
<>
{!upToMedium && {chart}}
-
- {warnings && (
-
- {warnings}
-
- )}
- {tokenA && tokenB && (
-
-
-
- )}
-
-
-
-
-
>
)}
+
+
+ Zapping {amountIn?.toSignificant(6)} {selectedCurrency?.symbol} into {newPosDraft?.amount0.toSignificant(6)}{' '}
+ {symbol0} and {newPosDraft?.amount1.toSignificant(6)} {symbol1} of liquidity to the pool
+
+ }
+ content={() => (
+
+ {zapError ? (
+
+ ) : (
+ (
+
+ {!!zapDetail.newPosDraft &&
}
+
+ {!!zapDetail.newPosDraft && (
+
+ )}
+
+ )}
+ showGridListOption={false}
+ bottomContent={() => (
+
+ {warnings}
+ {zapPriceImpactNote}
+
+
+ Supply
+
+
+
+ )}
+ />
+ )}
+
+ )}
+ />
>
)
}
diff --git a/src/pages/AddLiquidityV2/styled.tsx b/src/pages/AddLiquidityV2/styled.tsx
index 95d90a6134..2a4672f85f 100644
--- a/src/pages/AddLiquidityV2/styled.tsx
+++ b/src/pages/AddLiquidityV2/styled.tsx
@@ -1,9 +1,16 @@
-import { Flex } from 'rebass'
-import styled, { css, keyframes, useTheme } from 'styled-components'
+import { Trans } from '@lingui/macro'
+import { useMedia } from 'react-use'
+import { Flex, Text } from 'rebass'
+import styled, { CSSProperties, css, keyframes, useTheme } from 'styled-components'
+import { ReactComponent as ZapIcon } from 'assets/svg/zap.svg'
import { ButtonOutlined } from 'components/Button'
import { AutoColumn } from 'components/Column'
+import InfoHelper from 'components/InfoHelper'
import Input from 'components/NumericalInput'
+import { EVMNetworkInfo } from 'constants/networks/type'
+import { useActiveWeb3React } from 'hooks'
+import { MEDIA_WIDTHS } from 'theme'
export const PageWrapper = styled(AutoColumn)`
padding: 0 2rem 1rem;
@@ -209,3 +216,104 @@ export const RangeTab = styled.div<{ active: boolean }>`
color: ${({ theme, active }) => (active ? theme.primary : theme.subText)};
cursor: pointer;
`
+
+const MethodTabs = styled.div`
+ border-radius: 999px;
+ border: 1px solid ${({ theme }) => theme.border};
+ background: ${({ theme }) => theme.buttonBlack};
+ padding: 2px;
+ display: flex;
+`
+
+const MethodTab = styled.div<{ active: boolean; disabled?: boolean }>`
+ background: ${({ theme, active }) => (active ? theme.tabActive : theme.buttonBlack)};
+ opacity: ${({ active }) => (active ? 1 : 0.6)};
+ cursor: pointer;
+ border-radius: 999px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 20px;
+ padding: 2px;
+ min-width: 96px;
+
+ ${({ disabled }) =>
+ disabled
+ ? css`
+ opacity: 0.6;
+ cursor: not-allowed;
+ `
+ : undefined}
+`
+
+export const MethodSelector = ({
+ method,
+ setMethod,
+ sx,
+}: {
+ method: 'zap' | 'pair'
+ setMethod: (method: 'pair' | 'zap') => void
+ sx?: CSSProperties
+}) => {
+ const theme = useTheme()
+ const upToExtraSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToExtraSmall}px)`)
+
+ const { networkInfo } = useActiveWeb3React()
+ const isZapAvailable = !!(networkInfo as EVMNetworkInfo).elastic.zap
+
+ return (
+
+ {!upToExtraSmall && (
+
+ Your Position
+
+ )}
+
+
+ Add liquidity by:
+
+
+ setMethod('pair')} active={method === 'pair'}>
+ Token Pair
+
+ isZapAvailable && setMethod('zap')}
+ active={method === 'zap'}
+ disabled={!isZapAvailable}
+ >
+
+
+
+ Zap In
+
+ Add liquidity instantly using only one token!
+ ) : (
+ Zap will be available soon.
+ )
+ }
+ />
+
+
+
+
+
+ )
+}
diff --git a/src/pages/IncreaseLiquidity/Chart.tsx b/src/pages/IncreaseLiquidity/Chart.tsx
index 4bf050a9bf..7b970f18a3 100644
--- a/src/pages/IncreaseLiquidity/Chart.tsx
+++ b/src/pages/IncreaseLiquidity/Chart.tsx
@@ -1,6 +1,6 @@
import { Position } from '@kyberswap/ks-sdk-elastic'
import { Trans, t } from '@lingui/macro'
-import { useCallback, useState } from 'react'
+import React, { useCallback, useState } from 'react'
import { Flex, Text } from 'rebass'
import { AutoColumn } from 'components/Column'
@@ -13,7 +13,7 @@ import { Bound } from 'state/mint/proamm/type'
import { formatTickPrice } from 'utils/formatTickPrice'
import { unwrappedToken } from 'utils/wrappedCurrency'
-export default function Chart({
+function Chart({
position,
ticksAtLimit,
}: {
@@ -114,3 +114,5 @@ export default function Chart({
)
}
+
+export default React.memo(Chart)
diff --git a/src/pages/IncreaseLiquidity/index.tsx b/src/pages/IncreaseLiquidity/index.tsx
index eb309e0a55..231891ae24 100644
--- a/src/pages/IncreaseLiquidity/index.tsx
+++ b/src/pages/IncreaseLiquidity/index.tsx
@@ -4,7 +4,7 @@ import { FeeAmount, NonfungiblePositionManager } from '@kyberswap/ks-sdk-elastic
import { Trans, t } from '@lingui/macro'
import { BigNumber } from 'ethers'
import JSBI from 'jsbi'
-import { useCallback, useEffect, useState } from 'react'
+import { ReactElement, useCallback, useEffect, useMemo, useState } from 'react'
import { AlertTriangle } from 'react-feather'
import { Link, Navigate, useNavigate, useParams } from 'react-router-dom'
import { useMedia, usePrevious } from 'react-use'
@@ -15,10 +15,13 @@ import RangeBadge from 'components/Badge/RangeBadge'
import { ButtonError, ButtonLight, ButtonPrimary } from 'components/Button'
import { BlackCard, WarningCard } from 'components/Card'
import { AutoColumn } from 'components/Column'
+import Copy from 'components/Copy'
import CurrencyInputPanel from 'components/CurrencyInputPanel'
import CurrencyLogo from 'components/CurrencyLogo'
import Divider from 'components/Divider'
import Dots from 'components/Dots'
+import DoubleCurrencyLogo from 'components/DoubleLogo'
+import { useZapDetail } from 'components/ElasticZap/ZapDetail'
import FormattedCurrencyAmount from 'components/FormattedCurrencyAmount'
import Loader from 'components/Loader'
import { AddRemoveTabs, LiquidityAction } from 'components/NavigationTabs'
@@ -28,24 +31,31 @@ import ProAmmPriceRangeConfirm from 'components/ProAmm/ProAmmPriceRangeConfirm'
import Rating from 'components/Rating'
import { RowBetween } from 'components/Row'
import { SLIPPAGE_EXPLANATION_URL } from 'components/SlippageWarningNote'
+import PriceImpactNote, { ZapHighPriceImpact } from 'components/SwapForm/PriceImpactNote'
+import useParsedAmount from 'components/SwapForm/hooks/useParsedAmount'
import TransactionConfirmationModal, {
ConfirmationModalContent,
TransactionErrorContent,
} from 'components/TransactionConfirmationModal'
import { TutorialType } from 'components/Tutorial'
+import { FeeTag } from 'components/YieldPools/ElasticFarmGroup/styleds'
import { didUserReject } from 'constants/connectors/utils'
-import { APP_PATHS } from 'constants/index'
+import { APP_PATHS, ELASTIC_BASE_FEE_UNIT } from 'constants/index'
import { EVMNetworkInfo } from 'constants/networks/type'
import { NativeCurrencies } from 'constants/tokens'
import { useActiveWeb3React, useWeb3React } from 'hooks'
import { useCurrency } from 'hooks/Tokens'
+import { useZapInAction, useZapInPoolResult } from 'hooks/elasticZap'
import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback'
import { useProAmmNFTPositionManagerReadingContract } from 'hooks/useContract'
+import useDebounce from 'hooks/useDebounce'
import { useProAmmDerivedPositionInfo } from 'hooks/useProAmmDerivedPositionInfo'
+import useProAmmPoolInfo from 'hooks/useProAmmPoolInfo'
import { useProAmmPositionsFromTokenId } from 'hooks/useProAmmPositions'
import useProAmmPreviousTicks from 'hooks/useProAmmPreviousTicks'
import useTheme from 'hooks/useTheme'
import useTransactionDeadline from 'hooks/useTransactionDeadline'
+import { MethodSelector } from 'pages/AddLiquidityV2/styled'
import {
Container,
Content,
@@ -63,11 +73,13 @@ import { useTokenPrices } from 'state/tokenPrices/hooks'
import { useTransactionAdder } from 'state/transactions/hooks'
import { TRANSACTION_TYPE } from 'state/transactions/type'
import { useDegenModeManager, useUserSlippageTolerance } from 'state/user/hooks'
+import { useCurrencyBalances } from 'state/wallet/hooks'
import { MEDIA_WIDTHS, TYPE } from 'theme'
-import { calculateGasMargin, formattedNum, isAddressString } from 'utils'
+import { calculateGasMargin, formattedNum, isAddressString, shortenAddress } from 'utils'
import { maxAmountSpend } from 'utils/maxAmountSpend'
import { formatDollarAmount } from 'utils/numbers'
-import { SLIPPAGE_STATUS, checkRangeSlippage } from 'utils/slippage'
+import { SLIPPAGE_STATUS, checkRangeSlippage, formatSlippage } from 'utils/slippage'
+import { getTokenSymbolWithHardcode } from 'utils/tokenInfo'
import { unwrappedToken } from 'utils/wrappedCurrency'
import Chart from './Chart'
@@ -88,8 +100,16 @@ const TextUnderlineTransparent = styled(Text)`
`
export default function IncreaseLiquidity() {
- const { currencyIdB, currencyIdA, feeAmount: feeAmountFromUrl, tokenId } = useParams()
const { account, chainId, isEVM, networkInfo } = useActiveWeb3React()
+ const [method, setMethod] = useState<'pair' | 'zap'>('zap')
+ const isZapAvailable = !!(networkInfo as EVMNetworkInfo).elastic.zap
+ useEffect(() => {
+ if (!isZapAvailable) {
+ setMethod('pair')
+ }
+ }, [isZapAvailable])
+
+ const { currencyIdB, currencyIdA, feeAmount: feeAmountFromUrl, tokenId } = useParams()
const { library } = useWeb3React()
const navigate = useNavigate()
const theme = useTheme()
@@ -175,6 +195,12 @@ export default function IncreaseLiquidity() {
const address1 = quoteCurrency?.wrapped.address || ''
const usdPrices = useTokenPrices([address0, address1])
+ const poolAddress = useProAmmPoolInfo(
+ existingPosition?.pool.token0,
+ existingPosition?.pool.token1,
+ existingPosition?.pool.fee as FeeAmount,
+ )
+
const estimatedUsdCurrencyA =
parsedAmounts[Field.CURRENCY_A] && usdPrices[address0]
? parseFloat(parsedAmounts[Field.CURRENCY_A]?.toExact() || '0') * usdPrices[address0]
@@ -197,7 +223,7 @@ export default function IncreaseLiquidity() {
const previousTicks =
// : number[] = []
- useProAmmPreviousTicks(pool, position)
+ useProAmmPreviousTicks(pool, existingPosition)
const { onFieldAInput, onFieldBInput, onResetMintState } = useProAmmMintActionHandlers(noLiquidity, 0)
useEffect(() => {
@@ -331,7 +357,9 @@ export default function IncreaseLiquidity() {
}
const handleDismissConfirmation = useCallback(() => {
- setShowConfirm(false)
+ if (method === 'zap') setShowZapConfirmation(false)
+ else setShowConfirm(false)
+ setZapError('')
// if there was a tx hash, we want to clear the input
if (txHash) {
onFieldAInput('')
@@ -339,7 +367,7 @@ export default function IncreaseLiquidity() {
navigate('/myPools')
}
setTxHash('')
- }, [navigate, onFieldAInput, txHash])
+ }, [navigate, onFieldAInput, txHash, method])
const addIsUnsupported = false
@@ -427,10 +455,343 @@ export default function IncreaseLiquidity() {
const slippageStatus = checkRangeSlippage(allowedSlippage, false)
+ // ZAP STATE
+ const [value, setValue] = useState('')
+ const [isReverse, setIsReverse] = useState(false)
+ const [useWrapped, setUseWrapped] = useState(false)
+
+ const selectedCurrency = useMemo(() => {
+ const currency = isReverse ? currencies[Field.CURRENCY_B] : currencies[Field.CURRENCY_A]
+ if (useWrapped) return currency?.wrapped
+ return currency ? unwrappedToken(currency) : currency
+ }, [isReverse, currencies, useWrapped])
+
+ const quoteZapCurrency = useMemo(() => {
+ return isReverse ? currencies[Field.CURRENCY_A] : currencies[Field.CURRENCY_B]
+ }, [isReverse, currencies])
+
+ const debouncedValue = useDebounce(value, 300)
+ const amountIn = useParsedAmount(selectedCurrency, debouncedValue)
+
+ const equivalentQuoteAmount =
+ amountIn && pool && selectedCurrency && amountIn.multiply(pool.priceOf(selectedCurrency.wrapped))
+
+ const tickLower = existingPosition?.tickLower
+ const tickUpper = existingPosition?.tickUpper
+
+ const params = useMemo(() => {
+ return poolAddress &&
+ amountIn?.greaterThan('0') &&
+ selectedCurrency &&
+ quoteZapCurrency &&
+ tickLower !== undefined &&
+ tickUpper !== undefined
+ ? {
+ poolAddress,
+ tokenIn: selectedCurrency.wrapped.address,
+ tokenOut: quoteZapCurrency.wrapped.address,
+ amountIn,
+ tickLower,
+ tickUpper,
+ }
+ : undefined
+ }, [amountIn, poolAddress, selectedCurrency, quoteZapCurrency, tickLower, tickUpper])
+
+ const { loading: zapLoading, result: zapResult, aggregatorData } = useZapInPoolResult(params)
+ const zapInContractAddress = (networkInfo as EVMNetworkInfo).elastic.zap?.router
+ const [zapApprovalState, zapApprove] = useApproveCallback(amountIn, zapInContractAddress)
+ const { zapIn } = useZapInAction()
+ const [showZapConfirmation, setShowZapConfirmation] = useState(false)
+ const [zapError, setZapError] = useState('')
+
+ const zapBalances = useCurrencyBalances(
+ useMemo(
+ () => [
+ currencies[Field.CURRENCY_A]
+ ? unwrappedToken(currencies[Field.CURRENCY_A] as Currency)
+ : currencies[Field.CURRENCY_A],
+ currencies[Field.CURRENCY_B]
+ ? unwrappedToken(currencies[Field.CURRENCY_B] as Currency)
+ : currencies[Field.CURRENCY_B],
+ currencies[Field.CURRENCY_A]?.wrapped,
+ currencies[Field.CURRENCY_B]?.wrapped,
+ ],
+ [currencies],
+ ),
+ )
+
+ const balanceIndex = useWrapped ? (isReverse ? 3 : 2) : isReverse ? 1 : 0
+ const balance = zapBalances[balanceIndex]
+ let error: ReactElement | null = null
+ if (!value) error = Enter an amount
+ else if (!amountIn) error = Invalid Input
+ else if (balance && amountIn?.greaterThan(balance)) error = Insufficient Balance
+
+ const zapDetail = useZapDetail({
+ pool: existingPosition?.pool,
+ position: existingPosition,
+ tokenIn: selectedCurrency?.wrapped.address,
+ tokenId,
+ amountIn,
+ zapResult,
+ poolAddress,
+ tickLower: existingPosition?.tickLower,
+ tickUpper: existingPosition?.tickUpper,
+ previousTicks: previousTicks,
+ aggregatorRoute: aggregatorData,
+ })
+
+ const handleZap = async () => {
+ if (zapApprovalState === ApprovalState.NOT_APPROVED) {
+ zapApprove()
+ return
+ }
+
+ if (selectedCurrency && tokenId && zapResult && amountIn?.quotient && existingPosition && previousTicks?.length) {
+ try {
+ setAttemptingTxn(true)
+ const { hash: txHash } = await zapIn(
+ {
+ tokenId: tokenId.toString(),
+ tokenIn: selectedCurrency.wrapped.address,
+ amountIn: amountIn.quotient.toString(),
+ equivalentQuoteAmount: equivalentQuoteAmount?.quotient.toString() || '0',
+ poolAddress,
+ tickLower: existingPosition.tickLower,
+ tickUpper: existingPosition.tickUpper,
+ tickPrevious: [previousTicks[0], previousTicks[1]],
+ poolInfo: {
+ token0: existingPosition.pool.token0.wrapped.address,
+ fee: existingPosition.pool.fee,
+ token1: existingPosition.pool.token1.wrapped.address,
+ },
+ liquidity: zapResult.liquidity.toString(),
+ aggregatorRoute: aggregatorData,
+ },
+ {
+ zapWithNative: selectedCurrency.isNative,
+ },
+ )
+
+ setTxHash(txHash)
+ setAttemptingTxn(false)
+ const tokenSymbolIn = zapDetail.newPosDraft ? unwrappedToken(zapDetail.newPosDraft.amount0.currency).symbol : ''
+ const tokenSymbolOut = zapDetail.newPosDraft
+ ? unwrappedToken(zapDetail.newPosDraft?.amount1.currency).symbol
+ : ''
+ addTransactionWithType({
+ hash: txHash,
+ type: TRANSACTION_TYPE.ELASTIC_ZAP_IN_LIQUIDITY,
+ extraInfo: {
+ zapAmountIn: amountIn.toSignificant(6) || '0',
+ zapSymbolIn: selectedCurrency?.symbol || '',
+ tokenAmountIn: zapDetail.newPosDraft?.amount0.toSignificant(6) || '',
+ tokenAmountOut: zapDetail.newPosDraft?.amount1.toSignificant(6) || '',
+ tokenAddressIn: zapDetail.newPosDraft?.amount0.currency.wrapped.address || '',
+ tokenAddressOut: zapDetail.newPosDraft?.amount1.currency.wrapped.address || '',
+ tokenSymbolIn,
+ tokenSymbolOut,
+ nftId: tokenId,
+ arbitrary: {
+ token_1: tokenSymbolIn,
+ token_2: tokenSymbolOut,
+ },
+ },
+ })
+ } catch (e) {
+ console.error('zap error', e)
+ setAttemptingTxn(false)
+ setZapError(e?.message || JSON.stringify(e))
+ }
+ }
+ }
+
+ const ZapButton = (
+ {
+ if (zapApprovalState === ApprovalState.NOT_APPROVED) {
+ zapApprove()
+ return
+ }
+
+ setShowZapConfirmation(true)
+ }}
+ backgroundColor={
+ zapApprovalState !== ApprovalState.APPROVED
+ ? undefined
+ : zapDetail.priceImpact.isVeryHigh
+ ? theme.red
+ : zapDetail.priceImpact.isHigh
+ ? theme.warning
+ : undefined
+ }
+ disabled={
+ !!error ||
+ zapApprovalState === ApprovalState.PENDING ||
+ zapLoading ||
+ (zapApprovalState === ApprovalState.APPROVED && !isDegenMode && zapDetail.priceImpact?.isVeryHigh)
+ }
+ style={{ width: upToMedium ? '100%' : 'fit-content', minWidth: '164px' }}
+ >
+ {(() => {
+ if (error) return error
+ if (zapApprovalState === ApprovalState.PENDING)
+ return (
+
+ Approving
+
+ )
+ if (zapApprovalState !== ApprovalState.APPROVED) return Approve
+
+ if (zapLoading)
+ return (
+
+ Loading
+
+ )
+ return Preview
+ })()}
+
+ )
+
if (!isEVM) return
+ const inputAmountStyle = {
+ flex: 1,
+ border: `1px solid ${theme.border}`,
+ borderRadius: '1rem',
+ overflow: 'hidden',
+ }
+
+ const handleSwitch = (isQuote?: boolean) => {
+ const param1 = isQuote
+ ? currencyIdA
+ : baseCurrencyIsETHER
+ ? WETH[chainId].address
+ : NativeCurrencies[chainId].symbol
+ const param2 = isQuote
+ ? quoteCurrencyIsETHER
+ ? WETH[chainId].address
+ : NativeCurrencies[chainId].symbol
+ : currencyIdB
+ return (
+ chainId &&
+ navigate(`/${networkInfo.route}${APP_PATHS.ELASTIC_INCREASE_LIQ}/${param1}/${param2}/${feeAmount}/${tokenId}`, {
+ replace: true,
+ })
+ )
+ }
+
+ const handleDissmissZap = () => {
+ setShowZapConfirmation(false)
+ setTxHash('')
+ setZapError('')
+ setAttemptingTxn(false)
+ }
+
+ const token0 = existingPosition?.pool.token0
+ const token1 = existingPosition?.pool.token1
+
+ const symbol0 = getTokenSymbolWithHardcode(
+ chainId,
+ token0?.wrapped.address,
+ useWrapped ? token0?.wrapped.symbol : (token0 ? unwrappedToken(token0) : token0)?.symbol,
+ )
+ const symbol1 = getTokenSymbolWithHardcode(
+ chainId,
+ token1?.wrapped.address,
+ useWrapped ? token1?.wrapped.symbol : (token1 ? unwrappedToken(token1) : token1)?.symbol,
+ )
+
+ const zapPriceImpactNote = method === 'zap' &&
+ !!(zapDetail.priceImpact?.isVeryHigh || zapDetail.priceImpact?.isHigh || zapDetail.priceImpact?.isInvalid) &&
+ zapResult &&
+ !zapLoading && (
+ <>
+ {zapDetail.priceImpact.isVeryHigh ? (
+
+ ) : (
+
+ )}
+
+ >
+ )
+
+ const token0IsNative =
+ selectedCurrency?.isNative && selectedCurrency?.wrapped.address.toLowerCase() === pool?.token0.address.toLowerCase()
+ const zapSymbol0 = token0IsNative ? selectedCurrency.symbol : pool?.token0.symbol
+ const token1IsNative =
+ selectedCurrency?.isNative && selectedCurrency?.wrapped.address.toLowerCase() === pool?.token1.address.toLowerCase()
+ const zapSymbol1 = token1IsNative ? selectedCurrency.symbol : pool?.token1.symbol
+
return (
<>
+
+ Zapping {amountIn?.toSignificant(6)} {selectedCurrency?.symbol} into{' '}
+ {zapDetail.newPosDraft?.amount0.toSignificant(6)} {symbol0} and{' '}
+ {zapDetail.newPosDraft?.amount1.toSignificant(6)} {symbol1} of liquidity to the pool
+
+ }
+ content={() => (
+
+ {zapError ? (
+
+ ) : (
+ (
+
+ {!!zapDetail.newPosDraft &&
}
+
+ {!!zapDetail.newPosDraft && (
+
+ )}
+
+ )}
+ showGridListOption={false}
+ bottomContent={() => (
+
+ {zapPriceImpactNote}
+
+
+ Supply
+
+
+
+ )}
+ />
+ )}
+
+ )}
+ />
+
-
+
+
+
+
+ {unwrappedToken(existingPosition.pool.token0).symbol} -{' '}
+ {unwrappedToken(existingPosition.pool.token1).symbol}
+
+ FEE {(existingPosition?.pool.fee * 100) / ELASTIC_BASE_FEE_UNIT}%
+
+
+ {shortenAddress(chainId, poolAddress)}{' '}
+
+ }
+ />
+
@@ -570,6 +959,7 @@ export default function IncreaseLiquidity() {
+
-
- {
- onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
- }}
- onHalf={() => {
- onFieldAInput(currencyBalances[Field.CURRENCY_A]?.divide(2)?.toExact() ?? '')
- }}
- currency={currencies[Field.CURRENCY_A] ?? null}
- id="add-liquidity-input-tokena"
- showCommonBases
- positionMax="top"
- locked={depositADisabled}
- estimatedUsd={formattedNum(estimatedUsdCurrencyA.toString(), true) || undefined}
- disableCurrencySelect={!baseCurrencyIsETHER && !baseCurrencyIsWETH}
- isSwitchMode={baseCurrencyIsETHER || baseCurrencyIsWETH}
- onSwitchCurrency={() => {
- chainId &&
- navigate(
- `/${networkInfo.route}${APP_PATHS.ELASTIC_INCREASE_LIQ}/${
- baseCurrencyIsETHER ? WETH[chainId].address : NativeCurrencies[chainId].symbol
- }/${currencyIdB}/${feeAmount}/${tokenId}`,
- {
- replace: true,
- },
- )
- }}
- />
-
-
-
- {
- onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
- }}
- onHalf={() => {
- onFieldBInput(currencyBalances[Field.CURRENCY_B]?.divide(2).toExact() ?? '')
- }}
- currency={currencies[Field.CURRENCY_B] ?? null}
- id="add-liquidity-input-tokenb"
- showCommonBases
- positionMax="top"
- locked={depositBDisabled}
- estimatedUsd={formattedNum(estimatedUsdCurrencyB.toString(), true) || undefined}
- disableCurrencySelect={!quoteCurrencyIsETHER && !quoteCurrencyIsWETH}
- isSwitchMode={quoteCurrencyIsETHER || quoteCurrencyIsWETH}
- onSwitchCurrency={() => {
- chainId &&
- navigate(
- `/${networkInfo.route}${APP_PATHS.ELASTIC_INCREASE_LIQ}/${currencyIdA}/${
- quoteCurrencyIsETHER ? WETH[chainId].address : NativeCurrencies[chainId].symbol
- }/${feeAmount}/${tokenId}`,
- { replace: true },
- )
- }}
- />
-
+ {method === 'pair' ? (
+ <>
+
+ {
+ onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
+ }}
+ onHalf={() => {
+ onFieldAInput(currencyBalances[Field.CURRENCY_A]?.divide(2)?.toExact() ?? '')
+ }}
+ currency={currencies[Field.CURRENCY_A] ?? null}
+ id="add-liquidity-input-tokena"
+ showCommonBases
+ positionMax="top"
+ locked={depositADisabled}
+ estimatedUsd={formattedNum(estimatedUsdCurrencyA.toString(), true) || undefined}
+ disableCurrencySelect={!baseCurrencyIsETHER && !baseCurrencyIsWETH}
+ isSwitchMode={baseCurrencyIsETHER || baseCurrencyIsWETH}
+ onSwitchCurrency={() => handleSwitch(false)}
+ />
+
+
+
+ {
+ onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
+ }}
+ onHalf={() => {
+ onFieldBInput(currencyBalances[Field.CURRENCY_B]?.divide(2).toExact() ?? '')
+ }}
+ currency={currencies[Field.CURRENCY_B] ?? null}
+ id="add-liquidity-input-tokenb"
+ showCommonBases
+ positionMax="top"
+ locked={depositBDisabled}
+ estimatedUsd={formattedNum(estimatedUsdCurrencyB.toString(), true) || undefined}
+ disableCurrencySelect={!quoteCurrencyIsETHER && !quoteCurrencyIsWETH}
+ isSwitchMode={quoteCurrencyIsETHER || quoteCurrencyIsWETH}
+ onSwitchCurrency={() => handleSwitch(true)}
+ />
+
+ >
+ ) : (
+
+
+ {
+ setValue(v)
+ }}
+ onMax={() => {
+ const amount = zapBalances[balanceIndex]
+ if (amount) setValue(maxAmountSpend(amount)?.toExact() || '')
+ }}
+ onHalf={() => {
+ setValue(zapBalances[balanceIndex]?.divide('2').toExact() || '')
+ }}
+ currency={selectedCurrency}
+ positionMax="top"
+ showCommonBases
+ estimatedUsd={formattedNum(zapDetail.amountInUsd, true)}
+ isSwitchMode
+ onSwitchCurrency={() => {
+ if (selectedCurrency?.isNative) {
+ setUseWrapped(true)
+ } else {
+ setUseWrapped(false)
+ setIsReverse(prev => !prev)
+ }
+ }}
+ />
+
+
+
+ Est. Pooled {zapSymbol0}
+ {zapLoading ? (
+ zapDetail.skeleton()
+ ) : !zapResult || !pool ? (
+ '--'
+ ) : (
+
+
+
+ {zapDetail.newPooledAmount0?.toSignificant(10)} {zapSymbol0}
+
+
+ )}
+
+
+
+ Est. Pooled {zapSymbol1}
+ {zapLoading ? (
+ zapDetail.skeleton()
+ ) : !zapResult || !pool ? (
+ '--'
+ ) : (
+
+
+
+ {zapDetail.newPooledAmount1?.toSignificant(10)} {zapSymbol1}
+
+
+ )}
+
+
+
+ Max Slippage
+ {formatSlippage(allowedSlippage)}
+
+
+
+ Price Impact
+ {zapLoading ? (
+ zapDetail.skeleton(40)
+ ) : !zapResult ? (
+ '--'
+ ) : (
+
+ {zapDetail.priceImpact.isInvalid
+ ? '--'
+ : zapDetail.priceImpact.value < 0.01
+ ? '<0.01%'
+ : zapDetail.priceImpact.value.toFixed(2) + '%'}
+
+ )}
+
+
+
+ )}
@@ -692,9 +1163,9 @@ export default function IncreaseLiquidity() {
)}
-
-
-
+ {zapPriceImpactNote}
+
+ {method === 'pair' || !account ? : ZapButton}
diff --git a/src/pages/MyEarnings/ElasticPools/SinglePool/index.tsx b/src/pages/MyEarnings/ElasticPools/SinglePool/index.tsx
index 4a47727948..79ef78e71c 100644
--- a/src/pages/MyEarnings/ElasticPools/SinglePool/index.tsx
+++ b/src/pages/MyEarnings/ElasticPools/SinglePool/index.tsx
@@ -13,6 +13,7 @@ import { ButtonLight } from 'components/Button'
import CopyHelper from 'components/Copy'
import Divider from 'components/Divider'
import DoubleCurrencyLogo from 'components/DoubleLogo'
+import QuickZap, { QuickZapButton } from 'components/ElasticZap/QuickZap'
import { FarmTag } from 'components/FarmTag'
import Loader from 'components/Loader'
import { MouseoverTooltip, TextDashed } from 'components/Tooltip'
@@ -57,6 +58,7 @@ export const StatItem = ({ label, value }: { label: ReactNode | string; value: R
const SinglePool: React.FC = ({ poolEarning, chainId, positionEarnings, pendingFees, tokenPrices }) => {
const theme = useTheme()
+ const [showQuickZap, setShowQuickZap] = useState(false)
const { mixpanelHandler } = useMixpanel()
const [isExpanded, setExpanded] = useState(false)
const tabletView = useMedia(`(max-width: ${WIDTHS[3]}px)`)
@@ -238,6 +240,13 @@ const SinglePool: React.FC = ({ poolEarning, chainId, positionEarnings, p
borderRadius: mobileView ? 0 : '1rem',
}}
>
+ setShowQuickZap(false)}
+ expectedChainId={chainId}
+ />
+
= ({ poolEarning, chainId, positionEarnings, p
+ Add Liquidity
) : (
- {
- e.stopPropagation()
- }}
- to={
- currency0Slug && currency1Slug
- ? `/${NETWORKS_INFO[chainId].route}${APP_PATHS.ELASTIC_CREATE_POOL}/${currency0Slug}/${currency1Slug}/${feeAmount}`
- : '#'
- }
- >
- + Add Liquidity
-
+
+ {
+ e.stopPropagation()
+ }}
+ to={
+ currency0Slug && currency1Slug
+ ? `/${NETWORKS_INFO[chainId].route}${APP_PATHS.ELASTIC_CREATE_POOL}/${currency0Slug}/${currency1Slug}/${feeAmount}`
+ : '#'
+ }
+ >
+ + Add Liquidity
+
+
+ {
+ e.stopPropagation()
+ setShowQuickZap(true)
+ }}
+ />
+
)}
@@ -493,26 +511,43 @@ const SinglePool: React.FC = ({ poolEarning, chainId, positionEarnings, p
) : (
- e.stopPropagation()}
- >
-
-
+ <>
+ {
+ e.stopPropagation()
+ setShowQuickZap(true)
+ }}
+ size="small"
+ />
+
+ e.stopPropagation()}
+ >
+
+
+ >
)}
{isExpanded && isExpandable && positions}
+
+ setShowQuickZap(false)}
+ expectedChainId={chainId}
+ />
)
}
diff --git a/src/pages/MyEarnings/ElasticPools/SinglePosition/ActionButtons.tsx b/src/pages/MyEarnings/ElasticPools/SinglePosition/ActionButtons.tsx
index a967c727b0..f09a8e0889 100644
--- a/src/pages/MyEarnings/ElasticPools/SinglePosition/ActionButtons.tsx
+++ b/src/pages/MyEarnings/ElasticPools/SinglePosition/ActionButtons.tsx
@@ -1,25 +1,28 @@
import { ChainId, Currency } from '@kyberswap/ks-sdk-core'
import { FeeAmount } from '@kyberswap/ks-sdk-elastic'
import { Trans } from '@lingui/macro'
+import { useState } from 'react'
import { ChevronsUp, Minus } from 'react-feather'
import { Link, useNavigate } from 'react-router-dom'
import styled from 'styled-components'
+import QuickZap, { QuickZapButton } from 'components/ElasticZap/QuickZap'
import { APP_PATHS } from 'constants/index'
import { NETWORKS_INFO } from 'constants/networks'
import { useActiveWeb3React } from 'hooks'
+import useProAmmPoolInfo from 'hooks/useProAmmPoolInfo'
import { useChangeNetwork } from 'hooks/web3/useChangeNetwork'
import { ActionButton } from 'pages/MyEarnings/ActionButton'
const ActionButtonsWrapper = styled.div`
display: flex;
align-items: center;
- justify-content: space-between;
- gap: 16px;
+ gap: 8px;
${ActionButton} {
flex: 1;
gap: 4px;
+ height: 36px;
}
${({ theme }) => theme.mediaWidth.upToExtraSmall`
@@ -52,6 +55,7 @@ const ActionButtons: React.FC = ({
isLegacy,
onRemoveLiquidityFromLegacyPosition,
}) => {
+ const [showQuickZap, setShowQuickZap] = useState(false)
const { chainId: currentChainId } = useActiveWeb3React()
const chainRoute = NETWORKS_INFO[chainId].route
@@ -61,6 +65,7 @@ const ActionButtons: React.FC = ({
const { changeNetwork } = useChangeNetwork()
const navigate = useNavigate()
+ const poolAddress = useProAmmPoolInfo(currency0.wrapped, currency1.wrapped, feeAmount)
const target = `/${chainRoute}${APP_PATHS.ELASTIC_INCREASE_LIQ}/${currency0Slug}/${currency1Slug}/${feeAmount}/${nftId}`
const onIncreaseClick = (e: any) => {
@@ -87,14 +92,14 @@ const ActionButtons: React.FC = ({
if (!liquidity || isLegacy) {
return (
- Remove Liquidity
+ Remove
)
}
return (
- Remove Liquidity
+ Remove
)
}
@@ -103,14 +108,14 @@ const ActionButtons: React.FC = ({
if (isLegacy) {
return (
- Increase Liquidity
+ Increase
)
}
return (
- Increase Liquidity
+ Increase
)
}
@@ -119,6 +124,21 @@ const ActionButtons: React.FC = ({
{renderRemoveButton()}
{renderIncreaseButton()}
+ {!isLegacy && (
+ {
+ e.stopPropagation()
+ setShowQuickZap(true)
+ }}
+ />
+ )}
+ setShowQuickZap(false)}
+ />
)
}
diff --git a/src/pages/ProAmmPool/PositionGrid.tsx b/src/pages/ProAmmPool/PositionGrid.tsx
index cfb0438b39..e7465caf92 100644
--- a/src/pages/ProAmmPool/PositionGrid.tsx
+++ b/src/pages/ProAmmPool/PositionGrid.tsx
@@ -1,27 +1,16 @@
import { gql, useQuery } from '@apollo/client'
import { useScroll } from '@use-gesture/react'
-import { Interface } from 'ethers/lib/utils'
import memoizeOne from 'memoize-one'
-import React, {
- CSSProperties,
- ComponentType,
- forwardRef,
- memo,
- useCallback,
- useEffect,
- useMemo,
- useRef,
- useState,
-} from 'react'
+import React, { CSSProperties, ComponentType, forwardRef, memo, useMemo, useRef } from 'react'
import { useMedia } from 'react-use'
import { FixedSizeGrid as FixedSizeGridRW, GridChildComponentProps, areEqual } from 'react-window'
import styled from 'styled-components'
-import TickReaderABI from 'constants/abis/v2/ProAmmTickReader.json'
import { EVMNetworkInfo } from 'constants/networks/type'
import { useActiveWeb3React } from 'hooks'
-import { useMulticallContract } from 'hooks/useContract'
+import { useProAmmTickReader } from 'hooks/useContract'
import { useKyberSwapConfig } from 'state/application/hooks'
+import { useSingleContractMultipleData } from 'state/multicall/hooks'
import { MEDIA_WIDTHS } from 'theme'
import { PositionDetails } from 'types/position'
@@ -65,8 +54,6 @@ export const PositionCardGrid = styled.div`
`};
`
-const tickReaderInterface = new Interface(TickReaderABI.abi)
-
const queryPositionLastCollectedTimes = gql`
query positions($ids: [String]!) {
positions(where: { id_in: $ids }) {
@@ -80,17 +67,11 @@ const queryPositionLastCollectedTimes = gql`
function PositionGrid({ positions, refe }: { positions: PositionDetails[]; refe?: React.MutableRefObject }) {
const { isEVM, networkInfo, chainId } = useActiveWeb3React()
- const multicallContract = useMulticallContract()
const { elasticClient } = useKyberSwapConfig(chainId)
const upToSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToSmall}px)`)
const upToLarge = useMedia(`(max-width: ${MEDIA_WIDTHS.upToLarge}px)`)
- // raw
- const [feeRewards, setFeeRewards] = useState<{
- [tokenId: string]: [string, string]
- }>(() => positions.reduce((acc, item) => ({ ...acc, [item.tokenId.toString()]: ['0', '0'] }), {}))
-
const positionIds = useMemo(() => positions.map(pos => pos.tokenId.toString()), [positions])
const { data } = useQuery(queryPositionLastCollectedTimes, {
client: elasticClient,
@@ -137,45 +118,30 @@ function PositionGrid({ positions, refe }: { positions: PositionDetails[]; refe?
[data],
)
- const getPositionFee = useCallback(async () => {
- if (!multicallContract) return
- const fragment = tickReaderInterface.getFunction('getTotalFeesOwedToPosition')
- const callParams = positions.map(item => {
+ const tickReaderContract = useProAmmTickReader()
+ const rewardRes = useSingleContractMultipleData(
+ tickReaderContract,
+ 'getTotalFeesOwedToPosition',
+ positions.map(item => [
+ (networkInfo as EVMNetworkInfo).elastic.nonfungiblePositionManager,
+ item.poolId,
+ item.tokenId,
+ ]),
+ )
+
+ const feeRewards = useMemo(() => {
+ return positions.reduce<{ [tokenId: string]: [string, string] }>((acc, item, index) => {
return {
- target: (networkInfo as EVMNetworkInfo).elastic.tickReader,
- callData: tickReaderInterface.encodeFunctionData(fragment, [
- (networkInfo as EVMNetworkInfo).elastic.nonfungiblePositionManager,
- item.poolId,
- item.tokenId,
- ]),
+ ...acc,
+ [item.tokenId.toString()]: rewardRes[index].result
+ ? [
+ rewardRes[index].result?.token0Owed?.toString() || '0',
+ rewardRes[index].result?.token1Owed.toString() || '0',
+ ]
+ : ['0', '0'],
}
- })
-
- const { returnData } = await multicallContract?.callStatic.tryBlockAndAggregate(false, callParams)
- setFeeRewards(
- returnData.reduce(
- (
- acc: { [tokenId: string]: [string, string] },
- item: { success: boolean; returnData: string },
- index: number,
- ) => {
- if (item.success) {
- const tmp = tickReaderInterface.decodeFunctionResult(fragment, item.returnData)
- return {
- ...acc,
- [positions[index].tokenId.toString()]: [tmp.token0Owed.toString(), tmp.token1Owed.toString()],
- }
- }
- return { ...acc, [positions[index].tokenId.toString()]: ['0', '0'] }
- },
- {} as { [tokenId: string]: [string, string] },
- ),
- )
- }, [multicallContract, positions, networkInfo])
-
- useEffect(() => {
- getPositionFee()
- }, [getPositionFee])
+ }, {})
+ }, [positions, rewardRes])
const itemData = createItemData(positions, liquidityTimes, farmingTimes, feeRewards, createdAts, refe)
diff --git a/src/pages/ProAmmPool/PositionListItem.tsx b/src/pages/ProAmmPool/PositionListItem.tsx
index f57f8b8ae5..10366542d4 100644
--- a/src/pages/ProAmmPool/PositionListItem.tsx
+++ b/src/pages/ProAmmPool/PositionListItem.tsx
@@ -11,6 +11,7 @@ import styled from 'styled-components'
import { ButtonEmpty, ButtonOutlined, ButtonPrimary } from 'components/Button'
import { LightCard } from 'components/Card'
import Divider from 'components/Divider'
+import QuickZap, { QuickZapButton } from 'components/ElasticZap/QuickZap'
import ProAmmFee from 'components/ProAmm/ProAmmFee'
import ProAmmPoolInfo from 'components/ProAmm/ProAmmPoolInfo'
import ProAmmPooledTokens from 'components/ProAmm/ProAmmPooledTokens'
@@ -303,10 +304,18 @@ function PositionListItem({
return ''
})()
+ const [showQuickZap, setShowQuickZap] = useState(false)
+
if (!position || !priceLower || !priceUpper) return
return (
+ setShowQuickZap(false)}
+ />
<>
Increase Liquidity
+
+ setShowQuickZap(true)} />
)}
diff --git a/src/pages/ProAmmPools/CardItem.tsx b/src/pages/ProAmmPools/CardItem.tsx
index 19b61aaddd..7c782d5ab9 100644
--- a/src/pages/ProAmmPools/CardItem.tsx
+++ b/src/pages/ProAmmPools/CardItem.tsx
@@ -1,6 +1,6 @@
import { ChainId, Token, WETH } from '@kyberswap/ks-sdk-core'
import { Trans } from '@lingui/macro'
-import { useMemo } from 'react'
+import { useMemo, useState } from 'react'
import { BarChart2, MoreHorizontal, Plus, Share2 } from 'react-feather'
import { Link, useNavigate } from 'react-router-dom'
import { Flex, Text } from 'rebass'
@@ -12,6 +12,7 @@ import { ButtonLight, ButtonOutlined } from 'components/Button'
import CopyHelper from 'components/Copy'
import Divider from 'components/Divider'
import DoubleCurrencyLogo from 'components/DoubleLogo'
+import QuickZap, { QuickZapButton } from 'components/ElasticZap/QuickZap'
import { FarmTag } from 'components/FarmTag'
import { MouseoverTooltip } from 'components/Tooltip'
import { FeeTag } from 'components/YieldPools/ElasticFarmGroup/styleds'
@@ -61,6 +62,8 @@ export default function ProAmmPoolCardItem({ pool, onShared, userPositions }: Li
const theme = useTheme()
const navigate = useNavigate()
+ const [showQuickZap, setShowQuickZap] = useState(false)
+
const { farms: farmsV2 } = useElasticFarmsV2()
const allTokens = useAllTokens()
@@ -93,6 +96,7 @@ export default function ProAmmPoolCardItem({ pool, onShared, userPositions }: Li
!item.isSettled &&
item.poolAddress.toLowerCase() === pool.address.toLowerCase(),
)
+
const isFarmV2 = !!farmV2
const maxFarmV2Apr = Math.max(...(farmV2?.ranges.map(item => item.apr || 0) || []))
@@ -120,6 +124,8 @@ export default function ProAmmPoolCardItem({ pool, onShared, userPositions }: Li
return (
+ setShowQuickZap(false)} />
+
Add Liquidity
+
+ setShowQuickZap(true)} />
)
diff --git a/src/pages/ProAmmPools/ListItem.tsx b/src/pages/ProAmmPools/ListItem.tsx
index cd65570d58..57f44cb10b 100644
--- a/src/pages/ProAmmPools/ListItem.tsx
+++ b/src/pages/ProAmmPools/ListItem.tsx
@@ -1,6 +1,7 @@
import { ChainId, Token, WETH } from '@kyberswap/ks-sdk-core'
import { Trans, t } from '@lingui/macro'
import { rgba } from 'polished'
+import { useState } from 'react'
import { BarChart2, Plus, Share2 } from 'react-feather'
import { Link, useNavigate } from 'react-router-dom'
import { Flex, Text } from 'rebass'
@@ -10,6 +11,7 @@ import { ReactComponent as ViewPositionIcon } from 'assets/svg/view_positions.sv
import { ButtonEmpty } from 'components/Button'
import CopyHelper from 'components/Copy'
import DoubleCurrencyLogo from 'components/DoubleLogo'
+import QuickZap, { QuickZapButton } from 'components/ElasticZap/QuickZap'
import { FarmTag } from 'components/FarmTag'
import { MouseoverTooltip } from 'components/Tooltip'
import { FeeTag } from 'components/YieldPools/ElasticFarmGroup/styleds'
@@ -79,6 +81,7 @@ export default function ProAmmPoolListItem({ pool, onShared, userPositions }: Li
const { chainId, networkInfo } = useActiveWeb3React()
const theme = useTheme()
const navigate = useNavigate()
+ const [showQuickZap, setShowQuickZap] = useState(false)
const allTokens = useAllTokens()
@@ -150,6 +153,7 @@ export default function ProAmmPoolListItem({ pool, onShared, userPositions }: Li
return (
+ setShowQuickZap(false)} />
{myLiquidity ? formatDollarAmount(Number(myLiquidity)) : '-'}
+ setShowQuickZap(true)} size="small" />
Add liquidity } placement={'top'} width={'fit-content'}>
({
query: ({ url, payload, signal, authentication }) => ({
url,
@@ -47,3 +47,5 @@ const routeApi = createApi({
})
export default routeApi
+
+export const { useLazyGetRouteQuery, useBuildRouteMutation } = routeApi
diff --git a/src/services/route/types/getRoute.ts b/src/services/route/types/getRoute.ts
index 9a4445852e..46b054b0d4 100644
--- a/src/services/route/types/getRoute.ts
+++ b/src/services/route/types/getRoute.ts
@@ -5,14 +5,15 @@ export type GetRouteParams = {
tokenOut: string
amountIn: string
saveGas: string
- includedSources: string
+ includedSources?: string
excludedSources?: string
- gasInclude: string
- gasPrice: string
- feeAmount: string
- chargeFeeBy: ChargeFeeBy
- isInBps: string
- feeReceiver: string
+ excludedPools?: string
+ gasInclude?: string
+ gasPrice?: string
+ feeAmount?: string
+ chargeFeeBy?: ChargeFeeBy
+ isInBps?: string
+ feeReceiver?: string
debug?: string
}
diff --git a/src/state/mint/proamm/utils.ts b/src/state/mint/proamm/utils.ts
index 2472844f84..403ef0c8b4 100644
--- a/src/state/mint/proamm/utils.ts
+++ b/src/state/mint/proamm/utils.ts
@@ -83,13 +83,19 @@ export const getRecommendedRangeTicks = (
tokenB: Token,
currentTick: number,
pairFactor: PairFactor,
-) => {
+): [number, number] => {
const rangeFactor = rangeData[range].factor
const leftRange = 1 - (pairFactor * rangeFactor) / 10000
const rightRange = 1 + (pairFactor * rangeFactor) / 10000
- const result1 = [currentTick + Math.floor(log10001(leftRange)), currentTick + Math.ceil(log10001(rightRange))]
- const result2 = [currentTick + Math.floor(log10001(1 / leftRange)), currentTick + Math.ceil(log10001(1 / rightRange))]
+ const result1: [number, number] = [
+ currentTick + Math.floor(log10001(leftRange)),
+ currentTick + Math.ceil(log10001(rightRange)),
+ ]
+ const result2: [number, number] = [
+ currentTick + Math.floor(log10001(1 / leftRange)),
+ currentTick + Math.ceil(log10001(1 / rightRange)),
+ ]
const result = tokenA.sortsBefore(tokenB) ? result1 : result2
return result
diff --git a/src/state/prommPools/useGetElasticPools/useGetElasticPoolsV1.ts b/src/state/prommPools/useGetElasticPools/useGetElasticPoolsV1.ts
index a51893f346..71c7043993 100644
--- a/src/state/prommPools/useGetElasticPools/useGetElasticPoolsV1.ts
+++ b/src/state/prommPools/useGetElasticPools/useGetElasticPoolsV1.ts
@@ -1,6 +1,6 @@
import { useQuery } from '@apollo/client'
import dayjs from 'dayjs'
-import { useEffect, useState } from 'react'
+import { useEffect, useRef, useState } from 'react'
import { PROMM_POOLS_BULK, ProMMPoolFields } from 'apollo/queries/promm'
import { ELASTIC_BASE_FEE_UNIT } from 'constants/index'
@@ -145,13 +145,19 @@ const useGetElasticPoolsV1 = (poolAddresses: string[]): CommonReturn => {
skip: isEnableKNProtocol,
})
+ const data24Ref = useRef(data24)
+
+ if (data24) data24Ref.current = data24
+
const anyError = error24?.message.includes('Failed to decode `block.number`')
? Boolean(error)
: Boolean(error || error24)
const anyLoading = Boolean(loading || loading24)
+ const formatted = parsedPoolData(poolAddresses, data, data24Ref.current)
+
// return early if not all data yet
- if (anyError || anyLoading) {
+ if ((anyError || anyLoading) && !formatted) {
return {
isLoading: anyLoading,
isError: anyError,
@@ -159,7 +165,6 @@ const useGetElasticPoolsV1 = (poolAddresses: string[]): CommonReturn => {
}
}
- const formatted = parsedPoolData(poolAddresses, data, data24)
return {
isLoading: anyLoading,
isError: anyError,
diff --git a/src/state/transactions/type.ts b/src/state/transactions/type.ts
index be0dc920f6..6c7be021e1 100644
--- a/src/state/transactions/type.ts
+++ b/src/state/transactions/type.ts
@@ -29,6 +29,8 @@ export type TransactionExtraInfo2Token = {
chainIdIn?: ChainId
chainIdOut?: ChainId
nftId?: string
+ zapAmountIn?: string
+ zapSymbolIn?: string
}
export type TransactionExtraInfoHarvestFarm = {
@@ -132,6 +134,7 @@ export enum TRANSACTION_TYPE {
CLASSIC_REMOVE_LIQUIDITY = 'Classic Remove Liquidity',
ELASTIC_REMOVE_LIQUIDITY = 'Elastic Remove Liquidity',
ELASTIC_INCREASE_LIQUIDITY = 'Elastic Increase Liquidity',
+ ELASTIC_ZAP_IN_LIQUIDITY = 'Elastic Zap-in Liquidity',
ELASTIC_COLLECT_FEE = 'Elastic Collect Fee',
STAKE = 'Stake Into Farm',
@@ -173,6 +176,7 @@ export const GROUP_TRANSACTION_BY_TYPE = {
TRANSACTION_TYPE.CLASSIC_REMOVE_LIQUIDITY,
TRANSACTION_TYPE.ELASTIC_REMOVE_LIQUIDITY,
TRANSACTION_TYPE.ELASTIC_INCREASE_LIQUIDITY,
+ TRANSACTION_TYPE.ELASTIC_ZAP_IN_LIQUIDITY,
TRANSACTION_TYPE.ELASTIC_DEPOSIT_LIQUIDITY,
TRANSACTION_TYPE.ELASTIC_WITHDRAW_LIQUIDITY,
TRANSACTION_TYPE.STAKE,
diff --git a/src/state/user/actions.ts b/src/state/user/actions.ts
index 9e3bdb54f5..dec2df2baa 100644
--- a/src/state/user/actions.ts
+++ b/src/state/user/actions.ts
@@ -22,6 +22,7 @@ export interface SerializedPair {
export const updateUserDegenMode = createAction<{ userDegenMode: boolean; isStablePairSwap: boolean }>(
'user/updateUserDegenMode',
)
+export const toggleUseAggregatorForZap = createAction('user/toggleUseAggregatorForZap')
export const updateUserLocale = createAction<{ userLocale: SupportedLocale }>('user/updateUserLocale')
export const updateUserSlippageTolerance = createAction<{ userSlippageTolerance: number }>(
'user/updateUserSlippageTolerance',
diff --git a/src/state/user/hooks.tsx b/src/state/user/hooks.tsx
index f231cdaa48..73f1d70937 100644
--- a/src/state/user/hooks.tsx
+++ b/src/state/user/hooks.tsx
@@ -41,6 +41,7 @@ import {
toggleMyEarningChart,
toggleTopTrendingTokens,
toggleTradeRoutes,
+ toggleUseAggregatorForZap,
updateAcceptedTermVersion,
updateTokenAnalysisSettings,
updateUserDeadline,
@@ -131,6 +132,19 @@ export function useDegenModeManager(): [boolean, () => void] {
return [degenMode, toggleSetDegenMode]
}
+export function useAggregatorForZapSetting(): [boolean, () => void] {
+ const dispatch = useDispatch()
+ const isUseAggregatorForZap = useSelector(
+ state => state.user.useAggregatorForZap,
+ )
+
+ const toggle = useCallback(() => {
+ dispatch(toggleUseAggregatorForZap())
+ }, [dispatch])
+
+ return [isUseAggregatorForZap === undefined ? true : isUseAggregatorForZap, toggle]
+}
+
export function useUserSlippageTolerance(): [number, (slippage: number) => void] {
const dispatch = useDispatch()
const userSlippageTolerance = useSelector(state => {
diff --git a/src/state/user/reducer.ts b/src/state/user/reducer.ts
index c24e88dda0..75e1d0ab09 100644
--- a/src/state/user/reducer.ts
+++ b/src/state/user/reducer.ts
@@ -32,6 +32,7 @@ import {
toggleLiveChart,
toggleMyEarningChart,
toggleTradeRoutes,
+ toggleUseAggregatorForZap,
updateAcceptedTermVersion,
updateChainId,
updateTokenAnalysisSettings,
@@ -63,6 +64,7 @@ export interface UserState {
userDegenMode: boolean
userDegenModeAutoDisableTimestamp: number
+ useAggregatorForZap: boolean
// user defined slippage tolerance in bips, used in all txns
userSlippageTolerance: number
@@ -148,6 +150,7 @@ export const CROSS_CHAIN_SETTING_DEFAULT = {
const initialState: UserState = {
userDegenMode: false,
+ useAggregatorForZap: true,
userDegenModeAutoDisableTimestamp: 0,
userLocale: null,
userSlippageTolerance: INITIAL_ALLOWED_SLIPPAGE,
@@ -356,5 +359,12 @@ export default createReducer(initialState, builder =>
})
.addCase(toggleMyEarningChart, state => {
state.myEarningChart = !state.myEarningChart
+ })
+ .addCase(toggleUseAggregatorForZap, state => {
+ if (state.useAggregatorForZap === undefined) {
+ state.useAggregatorForZap = false
+ } else {
+ state.useAggregatorForZap = !state.useAggregatorForZap
+ }
}),
)
diff --git a/src/utils/errorMessage.ts b/src/utils/errorMessage.ts
index 30f41b3083..9fe781cd8e 100644
--- a/src/utils/errorMessage.ts
+++ b/src/utils/errorMessage.ts
@@ -21,6 +21,7 @@ function parseKnownPattern(text: string): string | undefined {
'return amount is not enough',
'code=call_exception',
'none of the calls threw an error',
+ 'failed to swap with aggr',
],
error,
)