Skip to content

Commit

Permalink
Integrate kn-protocol FarmV2 (#2221)
Browse files Browse the repository at this point in the history
* feat(my-earnings): handle collect fee + harvest in case position in farm v2

* integrate kn protocol farm v2

* fix: can not claim reward

* update env to prod

* fix: minor

* fix: mixpanel

* fix: data is not refresh when switch change

* fix: farms is reset

* enable base + linea

* fix: minor issue

* enable zksync

* revert env
  • Loading branch information
viet-nv authored Sep 20, 2023
1 parent 37fdd3b commit c3cba5b
Show file tree
Hide file tree
Showing 26 changed files with 225 additions and 147 deletions.
2 changes: 1 addition & 1 deletion src/components/YieldPools/FarmingPoolAPRCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ const FarmingPoolAPRCell: React.FC<Props> = ({
<MouseoverTooltip
width="fit-content"
placement={tooltipPlacement}
text={<APRTooltipContent farmAPR={farmAPR} farmV2APR={farmV2APR} poolAPR={poolAPR} />}
text={<APRTooltipContent farmAPR={maxFarmAPR} poolAPR={poolAPR} />}
>
<Text as="span" marginRight="4px">
{formatDisplayNumber((poolAPR + maxFarmAPR) / 100, { style: 'percent', fractionDigits: 2 })}
Expand Down
18 changes: 3 additions & 15 deletions src/constants/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,6 @@ export function isSupportedChainId(chainId?: number): chainId is ChainId {
}

export const FAUCET_NETWORKS = [ChainId.BTTC]
export const CHAINS_SUPPORT_NEW_POOL_FARM_API: readonly ChainId[] = [
ChainId.MAINNET,
// ChainId.MUMBAI,
// ChainId.MATIC,
// ChainId.BSCTESTNET,
ChainId.BSCMAINNET,
// ChainId.AVAXTESTNET,
ChainId.AVAXMAINNET,
ChainId.FANTOM,
ChainId.CRONOS,
ChainId.BTTC,
ChainId.ARBITRUM,
ChainId.AURORA,
ChainId.OPTIMISM,
]

// Fee options instead of dynamic fee
export const STATIC_FEE_OPTIONS: { [chainId: number]: number[] | undefined } = {
Expand Down Expand Up @@ -197,6 +182,9 @@ export const SUPPORTED_NETWORKS_FOR_MY_EARNINGS = [
ChainId.ARBITRUM,
ChainId.OPTIMISM,
ChainId.MATIC,
ChainId.LINEA,
ChainId.BASE,
ChainId.ZKSYNC,
ChainId.BSCMAINNET,
ChainId.AVAXMAINNET,
ChainId.FANTOM,
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useKyberSwapConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ const parseResponse = (

return {
rpc,
prochart: data?.prochart || false,
isEnableBlockService: data?.isEnableBlockService || false,
isEnableKNProtocol: data?.isEnableKNProtocol || false,
blockClient: isEVM(defaultChainId)
? createClient(data?.blockSubgraph || NETWORKS_INFO[defaultChainId].defaultBlockSubgraph)
: createClient(ethereumInfo.defaultBlockSubgraph),
Expand Down
1 change: 1 addition & 0 deletions src/hooks/useMixpanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1739,6 +1739,7 @@ export const useGlobalMixpanelEvents = () => {
'notification-center': 'Notification',
[APP_PATHS.KYBERAI_ABOUT]: 'KyberAI About',
[APP_PATHS.KYBERDAO_KNC_UTILITY]: 'Gas refund - KNC Utility',
[APP_PATHS.MY_EARNINGS]: 'Earning Dashboard',
}
const protectedPaths: { [key: string]: string } = {
[APP_PATHS.KYBERAI_RANKINGS]: 'KyberAI Rankings',
Expand Down
24 changes: 14 additions & 10 deletions src/pages/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import Snowfall from 'components/Snowflake/Snowfall'
import Web3ReactManager from 'components/Web3ReactManager'
import { ENV_LEVEL } from 'constants/env'
import { APP_PATHS, BLACKLIST_WALLETS, CHAINS_SUPPORT_CROSS_CHAIN } from 'constants/index'
import { CLASSIC_NOT_SUPPORTED, NETWORKS_INFO, SUPPORTED_NETWORKS } from 'constants/networks'
import { CLASSIC_NOT_SUPPORTED, ELASTIC_NOT_SUPPORTED, NETWORKS_INFO, SUPPORTED_NETWORKS } from 'constants/networks'
import { ENV_TYPE } from 'constants/type'
import { useActiveWeb3React } from 'hooks'
import { useAutoLogin } from 'hooks/useLogin'
Expand Down Expand Up @@ -191,15 +191,19 @@ const RoutesWithNetworkPrefix = () => {
</>
)}

<Route
path={`${APP_PATHS.ELASTIC_CREATE_POOL}/:currencyIdA?/:currencyIdB?/:feeAmount?`}
element={<RedirectElasticCreatePool />}
/>
<Route
path={`${APP_PATHS.ELASTIC_INCREASE_LIQ}/:currencyIdA?/:currencyIdB?/:feeAmount?/:tokenId?`}
element={<ElasticIncreaseLiquidity />}
/>
<Route path={`${APP_PATHS.ELASTIC_REMOVE_POOL}/:tokenId`} element={<ElasticRemoveLiquidity />} />
{!ELASTIC_NOT_SUPPORTED[chainId] && (
<>
<Route
path={`${APP_PATHS.ELASTIC_CREATE_POOL}/:currencyIdA?/:currencyIdB?/:feeAmount?`}
element={<RedirectElasticCreatePool />}
/>
<Route
path={`${APP_PATHS.ELASTIC_INCREASE_LIQ}/:currencyIdA?/:currencyIdB?/:feeAmount?/:tokenId?`}
element={<ElasticIncreaseLiquidity />}
/>
<Route path={`${APP_PATHS.ELASTIC_REMOVE_POOL}/:tokenId`} element={<ElasticRemoveLiquidity />} />
</>
)}

<Route path="*" element={<Navigate to="/" />} />
</Routes>
Expand Down
31 changes: 3 additions & 28 deletions src/pages/Farm/ElasticFarmv2/components/FarmCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,34 +262,9 @@ function FarmCard({
</RowBetween>

<RowBetween>
<MouseoverTooltip
placement="bottom"
width="fit-content"
text={
farm.tvl ? (
<>
<Flex alignItems="center" sx={{ gap: '4px' }}>
<CurrencyLogo currency={farm.token0} size="16px" />
{farm.tvlToken0.toSignificant(6)} {farm.token0.symbol}
</Flex>

<Flex alignItems="center" sx={{ gap: '4px' }} marginTop="4px">
<CurrencyLogo currency={farm.token1} size="16px" />
{farm.tvlToken1.toSignificant(6)} {farm.token1.symbol}
</Flex>
</>
) : (
''
)
}
>
<Text fontSize="16px" fontWeight="500" color={theme.text} data-testid="tvl-value">
{farm.tvl ? formatDollarAmount(farm.tvl) : '--'}
</Text>

{!!farm.tvl && <DownSvg />}
</MouseoverTooltip>

<Text fontSize="16px" fontWeight="500" color={theme.text} data-testid="tvl-value">
{farm.tvl ? formatDollarAmount(farm.tvl) : '--'}
</Text>
<Text fontSize="14px" fontWeight="500" color={theme.text}>
{isEnded || farm.isSettled ? (
isEnded ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ButtonOutlined } from 'components/Button'
import CurrencyLogo from 'components/CurrencyLogo'
import { MouseoverTooltip } from 'components/Tooltip'
import PROMM_FARM_ABI from 'constants/abis/v2/farm.json'
import FarmV2ABI from 'constants/abis/v2/farmv2.json'
import { useActiveWeb3React, useWeb3React } from 'hooks'
import { useProAmmNFTPositionManagerContract } from 'hooks/useContract'
import { config } from 'hooks/useElasticLegacy'
Expand All @@ -31,6 +32,7 @@ import { formatDollarAmount } from 'utils/numbers'

type Props = {
nftId: string
fId: string
feeValue0: CurrencyAmount<Currency>
feeValue1: CurrencyAmount<Currency>
feeUsd: number
Expand All @@ -43,9 +45,11 @@ type Props = {
}

const FarmInterface = new Interface(PROMM_FARM_ABI)
const FarmV2Interface = new Interface(FarmV2ABI)

const CollectFeesPanel: React.FC<Props> = ({
nftId,
fId,
chainId,
feeUsd,
feeValue0,
Expand Down Expand Up @@ -140,14 +144,19 @@ const CollectFeesPanel: React.FC<Props> = ({
const amount0Min = feeValue0.subtract(feeValue0.multiply(basisPointsToPercent(allowedSlippage)))
const amount1Min = feeValue1.subtract(feeValue1.multiply(basisPointsToPercent(allowedSlippage)))
try {
const encoded = FarmInterface.encodeFunctionData('claimFee', [
[nftId],
amount0Min.quotient.toString(),
amount1Min.quotient.toString(),
poolAddress,
true,
deadline?.toString(),
])
const encoded = (fId ? FarmV2Interface : FarmInterface).encodeFunctionData(
'claimFee',
fId
? [fId, [nftId], amount0Min.quotient.toString(), amount1Min.quotient.toString(), deadline?.toString(), true]
: [
[nftId],
amount0Min.quotient.toString(),
amount1Min.quotient.toString(),
poolAddress,
true,
deadline?.toString(),
],
)

sendTransaction({
to: farmAddress,
Expand Down
62 changes: 50 additions & 12 deletions src/pages/MyEarnings/ElasticPools/SinglePosition/PositionView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Divider from 'components/Divider'
import FormattedCurrencyAmount from 'components/FormattedCurrencyAmount'
import { MouseoverTooltip } from 'components/Tooltip'
import PROMM_FARM_ABI from 'constants/abis/v2/farm.json'
import FarmV2ABI from 'constants/abis/v2/farmv2.json'
import { VERSION } from 'constants/v2'
import { useActiveWeb3React, useWeb3React } from 'hooks'
import { useAllTokens } from 'hooks/Tokens'
Expand All @@ -39,6 +40,7 @@ import { formatDisplayNumber } from 'utils/numbers'
import ActionButtons from './ActionButtons'

const FarmInterface = new Interface(PROMM_FARM_ABI)
const FarmV2Interface = new Interface(FarmV2ABI)

const PositionView: React.FC<CommonProps> = props => {
const { positionEarning, position, pendingFee, tokenPrices: prices, chainId, currency0, currency1 } = props
Expand All @@ -65,9 +67,14 @@ const PositionView: React.FC<CommonProps> = props => {
parseFloat(position.amount0.toExact() || '0') * prices[currency0.wrapped.address || ''] +
parseFloat(position.amount1.toExact() || '0') * prices[currency1.wrapped.address || '']

const stakedLiqFarmv2 = positionEarning.farmV2DepositedPositions?.[0]?.liquidity || '0'
const weight = positionEarning.farmV2DepositedPositions?.[0]?.range?.weight || '1'

const stakedPosition = new Position({
pool: position.pool,
liquidity: positionEarning.joinedPositions?.[0]?.liquidity || '0',
liquidity:
positionEarning.joinedPositions?.[0]?.liquidity ||
BigNumber.from(stakedLiqFarmv2).div(BigNumber.from(weight)).toString(),
tickLower: position.tickLower,
tickUpper: position.tickUpper,
})
Expand Down Expand Up @@ -114,35 +121,61 @@ const PositionView: React.FC<CommonProps> = props => {
const theme = useTheme()
const tokens = useAllTokens(true, chainId)

const farmRewards = positionEarning.joinedPositions?.[0]?.farmingPool?.rewardTokensIds?.map((rwId, index) => {
const token = tokens[rwId] || new Token(chainId, rwId, 18, '', '')
let farmRewards =
positionEarning.joinedPositions?.[0]?.farmingPool?.rewardTokensIds?.map((rwId, index) => {
const token = tokens[rwId] || new Token(chainId, rwId, 18, '', '')

return CurrencyAmount.fromRawAmount(token, positionEarning.joinedPositions?.[0]?.pendingRewards?.[index] || '0')
})
return CurrencyAmount.fromRawAmount(token, positionEarning.joinedPositions?.[0]?.pendingRewards?.[index] || '0')
}) || []

const farmV2Rewards =
positionEarning.farmV2DepositedPositions?.[0].pendingRewards.map((amount, index) => {
const tokenId = positionEarning.farmV2DepositedPositions?.[0].farmV2.rewards[index].tokenID || ''
const token = tokens[tokenId] || new Token(chainId, tokenId, 18, '', '')

return CurrencyAmount.fromRawAmount(token, amount)
}) || []

farmRewards = farmRewards.concat(farmV2Rewards)

const disabledHarvest =
!positionEarning.joinedPositions?.[0]?.pendingRewards?.some(item => item !== '0') &&
!positionEarning.farmV2DepositedPositions?.[0].pendingRewards?.some(item => item !== '0')

const addTransactionWithType = useTransactionAdder()

const handleHarvest = () => {
const farmContract = positionEarning.joinedPositions?.[0]?.farmId
const farmContract =
positionEarning.joinedPositions?.[0]?.farmId ||
positionEarning.farmV2DepositedPositions?.[0].farmV2.id.split('_')[0]
const isInFarmV2 = !!positionEarning.farmV2DepositedPositions?.[0]
const pId = positionEarning.joinedPositions?.[0]?.pid
const fId = positionEarning?.farmV2DepositedPositions?.[0].farmV2.id.split('_')[1]

const library = libraryRef.current

dispatch(setShowPendingModal(MODAL_PENDING_TEXTS.HARVEST))
dispatch(setAttemptingTxn(true))

if (!library || !pId || !farmContract) {
if (!library || (isInFarmV2 ? !fId : !pId) || !farmContract) {
dispatch(setAttemptingTxn(false))
dispatch(setTxError('Something went wrong!'))
return
}

const encodedPid = defaultAbiCoder.encode(['tupple(uint256[] pIds)'], [{ pIds: [pId] }])
const encodedData = FarmInterface.encodeFunctionData('harvestMultiplePools', [[positionEarning.id], [encodedPid]])
let encodedData = ''
if (isInFarmV2) {
encodedData = FarmV2Interface.encodeFunctionData('claimReward', [fId, [positionEarning.id]])
} else {
const encodedPid = defaultAbiCoder.encode(['tupple(uint256[] pIds)'], [{ pIds: [pId] }])
encodedData = FarmInterface.encodeFunctionData('harvestMultiplePools', [[positionEarning.id], [encodedPid]])
}

const txn = {
to: farmContract,
data: encodedData,
}

library
.getSigner()
.estimateGas(txn)
Expand Down Expand Up @@ -253,12 +286,17 @@ const PositionView: React.FC<CommonProps> = props => {

<CollectFeesPanel
nftId={positionEarning.id}
fId={positionEarning?.farmV2DepositedPositions?.[0].farmV2.id.split('_')[1]}
chainId={chainId}
feeUsd={feeUsd}
feeValue0={feeReward0}
feeValue1={feeReward1}
hasUserDepositedInFarm={positionEarning.owner !== positionEarning.ownerOriginal}
farmAddress={positionEarning.depositedPosition?.farm || positionEarning.joinedPositions?.[0]?.farmId}
farmAddress={
positionEarning?.farmV2DepositedPositions?.[0].farmV2.id.split('_')[0] ||
positionEarning.depositedPosition?.farm ||
positionEarning.joinedPositions?.[0]?.farmId
}
poolAddress={positionEarning.pool.id}
position={position}
isLegacy={isLegacyPosition}
Expand All @@ -268,7 +306,7 @@ const PositionView: React.FC<CommonProps> = props => {

<Flex justifyContent="space-between">
<Flex flexDirection="column" sx={{ gap: '4px' }}>
<Text fontSize={12} fontWeight="500" color={theme.subText}>
<Text fontSize={12} fontWeight="500" color={theme.subText} textAlign="left">
<Trans>Farm Rewards</Trans>
</Text>

Expand Down Expand Up @@ -303,7 +341,7 @@ const PositionView: React.FC<CommonProps> = props => {
</Flex>

<ButtonOutlined
disabled={!positionEarning.joinedPositions?.[0]?.pendingRewards?.some(item => item !== '0')}
disabled={disabledHarvest}
style={{
height: '36px',
width: 'fit-content',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ const PriceRangeChart: React.FC<Props> = ({ position, disabled }) => {
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
':hover': {
overflow: 'visible',
whiteSpace: 'normal',
height: 'auto',
},
}}
>
<Trans>Current Price</Trans>:
Expand Down
2 changes: 2 additions & 0 deletions src/pages/Pools/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { Instruction } from 'pages/Pools/InstructionAndGlobalData'
import ProAmmPoolList from 'pages/ProAmmPools'
import { ApplicationModal } from 'state/application/actions'
import { useOpenModal } from 'state/application/hooks'
import ElasticFarmV2Updater from 'state/farms/elasticv2/updater'
import { Field } from 'state/pair/actions'
import { MEDIA_WIDTHS } from 'theme'
import { currencyId } from 'utils/currencyId'
Expand Down Expand Up @@ -370,6 +371,7 @@ const Pools = () => {
)}
</PoolsPageWrapper>
<SwitchLocaleLink />
<ElasticFarmV2Updater interval={false} />
</>
)
}
Expand Down
13 changes: 3 additions & 10 deletions src/pages/ProAmmPools/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export default function ProAmmPoolListItem({ pool, onShared, userPositions }: Li
.find(farm => farm.poolAddress.toLowerCase() === pool.address.toLowerCase())
const isFarmV2 = !!farmV2

const isFarmingPool = isFarmV1 || isFarmV2
const isFarmingPool = isFarmV1 || isFarmV2 || !!pool.farmAPR

const maxFarmV2Apr = Math.max(...(farmV2?.ranges.map(item => item.apr || 0) || []), 0)

Expand All @@ -145,14 +145,7 @@ export default function ProAmmPoolListItem({ pool, onShared, userPositions }: Li
)
}

return (
<Flex
alignItems="center"
paddingRight="20px" // to make all the APR numbers vertically align
>
{pool.apr.toFixed(2)}%
</Flex>
)
return <Flex alignItems="center">{pool.apr.toFixed(2)}%</Flex>
}

return (
Expand Down Expand Up @@ -190,7 +183,7 @@ export default function ProAmmPoolListItem({ pool, onShared, userPositions }: Li
<FeeTag>Fee {(pool.feeTier * 100) / ELASTIC_BASE_FEE_UNIT}%</FeeTag>

<Flex alignItems="center" marginLeft="4px" sx={{ gap: '4px' }}>
{isFarmingPool && <FarmTag address={pool.address} />}
{isFarmingPool && <FarmTag address={pool.address} noText />}
</Flex>
</Flex>
</Link>
Expand Down
Loading

0 comments on commit c3cba5b

Please sign in to comment.