From 8fd44c0e774fbd8c6e7b5700b8f0b0f7ef1b678f Mon Sep 17 00:00:00 2001 From: viet-nv Date: Mon, 15 Aug 2022 16:45:07 +0700 Subject: [PATCH] feat(farm): elastic --- src/components/YieldPools/ProMMFarmGroup.tsx | 208 +++++++++++-------- src/components/YieldPools/ProMMFarms.tsx | 39 +++- src/components/YieldPools/styleds.tsx | 13 +- src/constants/networks/aurora.ts | 2 +- src/constants/networks/matic.ts | 2 +- src/constants/networks/oasis.ts | 2 +- src/constants/v2.ts | 3 + src/state/farms/promm/hooks.ts | 10 +- src/state/farms/promm/types.ts | 3 + 9 files changed, 178 insertions(+), 104 deletions(-) diff --git a/src/components/YieldPools/ProMMFarmGroup.tsx b/src/components/YieldPools/ProMMFarmGroup.tsx index 9382238f60..534d5354f1 100644 --- a/src/components/YieldPools/ProMMFarmGroup.tsx +++ b/src/components/YieldPools/ProMMFarmGroup.tsx @@ -1,10 +1,10 @@ -import { CurrencyAmount, Fraction, Token } from '@kyberswap/ks-sdk-core' +import { CurrencyAmount, Token } from '@kyberswap/ks-sdk-core' import { Pool, Position } from '@kyberswap/ks-sdk-elastic' import { Trans, t } from '@lingui/macro' import { BigNumber } from 'ethers' import { rgba } from 'polished' import React, { useCallback, useEffect, useMemo, useState } from 'react' -import { Clock, Edit2, Info, Minus, Plus } from 'react-feather' +import { Clock, Edit2, Minus, Plus } from 'react-feather' import { useMedia } from 'react-use' import { Flex, Text } from 'rebass' import styled from 'styled-components' @@ -21,14 +21,13 @@ import Deposit from 'components/Icons/Deposit' import Harvest from 'components/Icons/Harvest' import Withdraw from 'components/Icons/Withdraw' import InfoHelper from 'components/InfoHelper' -import Loader from 'components/Loader' import Modal from 'components/Modal' import { MouseoverTooltip, MouseoverTooltipDesktopOnly } from 'components/Tooltip' import { ELASTIC_BASE_FEE_UNIT, ZERO_ADDRESS } from 'constants/index' import { VERSION } from 'constants/v2' import { useActiveWeb3React } from 'hooks' import { useToken, useTokens } from 'hooks/Tokens' -import { useProAmmNFTPositionManagerContract, useProMMFarmContract } from 'hooks/useContract' +import { useProAmmNFTPositionManagerContract } from 'hooks/useContract' import useParsedQueryString from 'hooks/useParsedQueryString' import useTheme from 'hooks/useTheme' import { Dots } from 'pages/Pool/styleds' @@ -100,39 +99,39 @@ const Reward = ({ token: address, amount }: { token: string; amount?: BigNumber ) } -const FeeTargetWrapper = styled.div<{ fullUnlock: boolean }>` - border-radius: 999px; - display: flex; - font-size: 12px; - background: ${({ theme, fullUnlock }) => (fullUnlock ? theme.primary : theme.subText)}; - position: relative; - color: ${({ theme }) => theme.textReverse}; - height: 20px; - align-items: center; - min-width: 120px; -` - -const FeeArchive = styled.div<{ width: number }>` - width: ${({ width }) => `${width}%`}; - height: 100%; - background: ${({ theme, width }) => (width === 100 ? theme.primary : theme.warning)}; - border-radius: 999px; -` -const FeeText = styled.div` - position: absolute; - left: 50%; - transform: translateX(-50%); -` - -const FeeTarget = ({ percent }: { percent: string }) => { - const p = Number(percent) * 100 - return ( - = 1}> - - {p.toFixed(2)}% - - ) -} +// const FeeTargetWrapper = styled.div<{ fullUnlock: boolean }>` +// border-radius: 999px; +// display: flex; +// font-size: 12px; +// background: ${({ theme, fullUnlock }) => (fullUnlock ? theme.primary : theme.subText)}; +// position: relative; +// color: ${({ theme }) => theme.textReverse}; +// height: 20px; +// align-items: center; +// min-width: 120px; +// ` + +// const FeeArchive = styled.div<{ width: number }>` +// width: ${({ width }) => `${width}%`}; +// height: 100%; +// background: ${({ theme, width }) => (width === 100 ? theme.primary : theme.warning)}; +// border-radius: 999px; +// ` +// const FeeText = styled.div` +// position: absolute; +// left: 50%; +// transform: translateX(-50%); +// ` + +// const FeeTarget = ({ percent }: { percent: string }) => { +// const p = Number(percent) * 100 +// return ( +// = 1}> +// +// {p.toFixed(2)}% +// +// ) +// } const Row = ({ isApprovedForAll, @@ -229,39 +228,41 @@ const Row = ({ }) }, [position, farm.pid, onUpdateDepositedInfo]) - const contract = useProMMFarmContract(fairlaunchAddress) - - const [targetPercent, setTargetPercent] = useState('') - const [loading, setLoading] = useState(false) - - useEffect(() => { - const getFeeTargetInfos = async () => { - if (!contract) return - setLoading(true) - const res = await Promise.all( - farm.userDepositedNFTs.map(async pos => { - const res = await contract.getRewardCalculationData(pos.tokenId, farm.pid) - return new Fraction(res.vestingVolume.toString(), BigNumber.from(1e12).toString()) - }), - ) - - const totalLiquidity = farm.userDepositedNFTs.reduce( - (acc, cur) => acc.add(cur.stakedLiquidity), - BigNumber.from(0), - ) - const targetLiqid = farm.userDepositedNFTs.reduce( - (acc, cur, index) => acc.add(res[index].multiply(cur.stakedLiquidity.toString())), - new Fraction(0, 1), - ) - - if (totalLiquidity.gt(0)) { - const targetPercent = targetLiqid.divide(totalLiquidity.toString()) - setTargetPercent(targetPercent.toFixed(2)) - } - setLoading(false) - } - getFeeTargetInfos() - }, [contract, farm]) + // TODO: this is temporary hide target volume, an ad-hoc request from Product team. will enable soon if we have this kind of farm + + // const contract = useProMMFarmContract(fairlaunchAddress) + + // const [targetPercent, setTargetPercent] = useState('') + // const [loading, setLoading] = useState(false) + + // useEffect(() => { + // const getFeeTargetInfos = async () => { + // if (!contract) return + // setLoading(true) + // const res = await Promise.all( + // farm.userDepositedNFTs.map(async pos => { + // const res = await contract.getRewardCalculationData(pos.tokenId, farm.pid) + // return new Fraction(res.vestingVolume.toString(), BigNumber.from(1e12).toString()) + // }), + // ) + + // const totalLiquidity = farm.userDepositedNFTs.reduce( + // (acc, cur) => acc.add(cur.stakedLiquidity), + // BigNumber.from(0), + // ) + // const targetLiqid = farm.userDepositedNFTs.reduce( + // (acc, cur, index) => acc.add(res[index].multiply(cur.stakedLiquidity.toString())), + // new Fraction(0, 1), + // ) + + // if (totalLiquidity.gt(0)) { + // const targetPercent = targetLiqid.divide(totalLiquidity.toString()) + // setTargetPercent(targetPercent.toFixed(2)) + // } + // setLoading(false) + // } + // getFeeTargetInfos() + // }, [contract, farm]) const [showTargetVolInfo, setShowTargetVolInfo] = useState(false) @@ -328,6 +329,7 @@ const Row = ({ + {/* setShowTargetVolInfo(true)}> Target volume @@ -335,6 +337,7 @@ const Row = ({ {farm.feeTarget.gt(0) ? loading ? : : '--'} + */} @@ -370,6 +373,33 @@ const Row = ({ {getFormattedTimeFromSecond(farm.vestingDuration, true)} + + + Ending In + + + + + {farm.startTime > currentTimestamp ? ( + <> + + New phase will start in + + {getFormattedTimeFromSecond(farm.startTime - currentTimestamp)} + + ) : farm.endTime > currentTimestamp ? ( + <> + + Current phase will end in + + {getFormattedTimeFromSecond(farm.endTime - currentTimestamp)} + + ) : ( + ENDED + )} + + + My Deposit @@ -436,16 +466,6 @@ const Row = ({ {token0?.symbol} - {token1?.symbol} - - {farm.startTime > currentTimestamp && ( - - - - )} - + {/* {farm.feeTarget.gt(0) ? loading ? : : '--'} - - {formatDollarAmount(tvl)} + */} + {formatDollarAmount(tvl)} {(farmAPR + poolAPY).toFixed(2)}% - - {getFormattedTimeFromSecond(farm.vestingDuration, true)} + {/*{getFormattedTimeFromSecond(farm.vestingDuration, true)}*/} + + {farm.startTime > currentTimestamp ? ( + <> + + New phase will start in + + {getFormattedTimeFromSecond(farm.startTime - currentTimestamp)} + + ) : farm.endTime > currentTimestamp ? ( + <> + + Current phase will end in + + {getFormattedTimeFromSecond(farm.endTime - currentTimestamp)} + + ) : ( + ENDED + )} + {!!position?.amountUsd ? formatDollarAmount(position.amountUsd) : '--'} diff --git a/src/components/YieldPools/ProMMFarms.tsx b/src/components/YieldPools/ProMMFarms.tsx index 12fe69577a..85c4d264e7 100644 --- a/src/components/YieldPools/ProMMFarms.tsx +++ b/src/components/YieldPools/ProMMFarms.tsx @@ -1,12 +1,11 @@ import { Trans, t } from '@lingui/macro' import { stringify } from 'querystring' -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { Info, Search } from 'react-feather' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { Search } from 'react-feather' import { useHistory, useLocation } from 'react-router-dom' import { useMedia } from 'react-use' import { Flex, Text } from 'rebass' -import HoverDropdown from 'components/HoverDropdown' import InfoHelper from 'components/InfoHelper' import LocalLoader from 'components/LocalLoader' import Toggle from 'components/Toggle' @@ -17,7 +16,7 @@ import useTheme from 'hooks/useTheme' import { useBlockNumber } from 'state/application/hooks' import { useGetProMMFarms, useProMMFarms } from 'state/farms/promm/hooks' import { ProMMFarm } from 'state/farms/promm/types' -import { ExternalLink, StyledInternalLink } from 'theme' +import { StyledInternalLink } from 'theme' import ProMMFarmGroup from './ProMMFarmGroup' import { DepositModal, StakeUnstakeModal } from './ProMMFarmModals' @@ -82,7 +81,11 @@ function ProMMFarms({ active }: { active: boolean }) { const filterSearchText = search ? farm.token0.toLowerCase().includes(search) || farm.token1.toLowerCase().includes(search) || - farm.poolAddress.toLowerCase() === search + farm.poolAddress.toLowerCase() === search || + farm?.token0Info?.symbol?.toLowerCase().includes(search) || + farm?.token1Info?.symbol?.toLowerCase().includes(search) || + farm?.token0Info?.name?.toLowerCase().includes(search) || + farm?.token1Info?.name?.toLowerCase().includes(search) : true let filterStaked = true @@ -165,6 +168,21 @@ function ProMMFarms({ active }: { active: boolean }) { )} + {qs.type === 'active' && qs.tab !== VERSION.CLASSIC && ( + <> + + Farms will run in multiple phases. + + + + Once the current phase ends, you can harvest your rewards from the farm in the{' '} + Ended tab. To continue earning rewards in + the new phase, you must restake your NFT position into the active farm. + + + + )} + {above1000 && ( @@ -173,7 +191,7 @@ function ProMMFarms({ active }: { active: boolean }) { - + {/* + */} - + Staked TVL @@ -221,11 +240,11 @@ function ProMMFarms({ active }: { active: boolean }) { /> - + - Vesting + Ending In - + diff --git a/src/components/YieldPools/styleds.tsx b/src/components/YieldPools/styleds.tsx index 71076326e9..f1067eab01 100644 --- a/src/components/YieldPools/styleds.tsx +++ b/src/components/YieldPools/styleds.tsx @@ -155,7 +155,6 @@ export const StakedOnlyToggleWrapper = styled.div` ` export const StakedOnlyToggleText = styled.div` - margin-left: 10px; font-size: 14px; font-weight: 500; color: ${({ theme }) => theme.subText}; @@ -366,9 +365,14 @@ export const TableHeader = styled.div<{ fade?: boolean; oddRow?: boolean }>` ` export const ProMMFarmTableHeader = styled(TableHeader)` - grid-template-columns: 150px 120px 1fr 0.75fr 0.75fr 0.75fr 1fr 1fr; - grid-template-areas: 'token_pairs pool_fee staked_tvl ending_in apr vesting my_deposit reward action'; + grid-template-columns: 200px 0.5fr 0.75fr 1fr 0.5fr 0.75fr 0.75fr; + grid-template-areas: 'token_pairs staked_tvl apr ending_in my_deposit reward action'; grid-gap: 2rem; + + ${({ theme }) => theme.mediaWidth.upToLarge` + grid-template-columns: 170px 0.5fr 0.75fr 1fr 0.5fr 0.75fr 0.75fr; + grid-gap: 1rem; + `}; ` export const ProMMFarmTableRow = styled(ProMMFarmTableHeader)` @@ -574,8 +578,7 @@ export const ProMMFarmTableRowMobile = styled.div` export const InfoRow = styled.div` display: flex; justify-content: space-between; - align-items: center; - margin-top: 8px; + margin-top: 12px; font-size: 12px; ` diff --git a/src/constants/networks/aurora.ts b/src/constants/networks/aurora.ts index 6e07944800..eeb513701b 100644 --- a/src/constants/networks/aurora.ts +++ b/src/constants/networks/aurora.ts @@ -29,7 +29,7 @@ const auroraInfo: NetworkInfo = { logo: EthereumLogo, decimal: 18, }, - rpcUrl: 'https://mainnet.aurora.dev/GvfzNcGULXzWqaVahC8WPTdqEuSmwNCu3Nu3rtcVv9MD', + rpcUrl: 'https://aurora.kyberengineering.io', routerUri: `${process.env.REACT_APP_AGGREGATOR_API}/aurora/route/encode`, classic: { static: { diff --git a/src/constants/networks/matic.ts b/src/constants/networks/matic.ts index 6ebff6a72a..d0478f02ee 100644 --- a/src/constants/networks/matic.ts +++ b/src/constants/networks/matic.ts @@ -27,7 +27,7 @@ const maticInfo: NetworkInfo = { logo: Polygon, decimal: 18, }, - rpcUrl: 'https://polygon.kyberengineering.io/v1/mainnet/geth?appId=prod-dmm', + rpcUrl: 'https://proxy.kyberengineering.io/polygon', routerUri: `${process.env.REACT_APP_AGGREGATOR_API}/polygon/route/encode`, classic: { static: { diff --git a/src/constants/networks/oasis.ts b/src/constants/networks/oasis.ts index 77ba80222f..7b5e49492a 100644 --- a/src/constants/networks/oasis.ts +++ b/src/constants/networks/oasis.ts @@ -32,7 +32,7 @@ const oasisInfo: NetworkInfo = { logo: OASIS, decimal: 18, }, - rpcUrl: 'https://emerald.oasis.dev', + rpcUrl: 'https://oasis.kyberengineering.io', routerUri: `${process.env.REACT_APP_AGGREGATOR_API}/oasis/route/encode`, classic: { static: { diff --git a/src/constants/v2.ts b/src/constants/v2.ts index 04945ac50e..6fa96c58cf 100644 --- a/src/constants/v2.ts +++ b/src/constants/v2.ts @@ -6,6 +6,9 @@ export const FARM_CONTRACTS: { readonly [chainId in ChainId]?: Array } = [ChainId.RINKEBY]: ['0x13c8F670d3bbd4456870a2C49Bb927F166A977Bd'], [ChainId.ROPSTEN]: [], [ChainId.MATIC]: ['0x5C503D4b7DE0633f031229bbAA6A5e4A31cc35d8'], + [ChainId.MAINNET]: ['0x5C503D4b7DE0633f031229bbAA6A5e4A31cc35d8'], + [ChainId.AVAXMAINNET]: ['0x5C503D4b7DE0633f031229bbAA6A5e4A31cc35d8'], + [ChainId.ARBITRUM]: ['0x3227AE2ab4C2ACF2eE5202311C07731d3be9637B'], } export const ELASTIC_NOT_SUPPORTED: { [key: string]: string } = { diff --git a/src/state/farms/promm/hooks.ts b/src/state/farms/promm/hooks.ts index 97aae4f12c..c01a561858 100644 --- a/src/state/farms/promm/hooks.ts +++ b/src/state/farms/promm/hooks.ts @@ -16,7 +16,7 @@ import { CONTRACT_NOT_FOUND_MSG } from 'constants/messages' import { NETWORKS_INFO } from 'constants/networks' import { FARM_CONTRACTS, VERSION } from 'constants/v2' import { providers, useActiveWeb3React } from 'hooks' -import { useTokens } from 'hooks/Tokens' +import { useAllTokens, useTokens } from 'hooks/Tokens' import { useProAmmNFTPositionManagerContract, useProMMFarmContract, useProMMFarmContracts } from 'hooks/useContract' import { usePools } from 'hooks/usePools' import usePrevious from 'hooks/usePrevious' @@ -39,6 +39,12 @@ export const useGetProMMFarms = () => { const dispatch = useAppDispatch() const { chainId, account } = useActiveWeb3React() const prommFarmContracts = useProMMFarmContracts() + const tokens = useAllTokens() + + // dont need all tokens on dependency + const allTokensRef = useRef(tokens) + allTokensRef.current = tokens + const positionManager = useProAmmNFTPositionManagerContract() const prevChainId = usePrevious(chainId) @@ -143,6 +149,8 @@ export const useGetProMMFarms = () => { pid: pid, userDepositedNFTs: userNFTInfo, rewardLocker, + token0Info: allTokensRef.current?.[token0], + token1Info: allTokensRef.current?.[token1], } }), ) diff --git a/src/state/farms/promm/types.ts b/src/state/farms/promm/types.ts index 0a44404566..321686d7a2 100644 --- a/src/state/farms/promm/types.ts +++ b/src/state/farms/promm/types.ts @@ -1,3 +1,4 @@ +import { Token } from '@kyberswap/ks-sdk-core' import { BigNumber } from 'ethers' import { ProMMPoolData } from 'state/prommPools/hooks' @@ -27,6 +28,8 @@ export interface ProMMFarm { currentTick: number rewardLocker: string feeTarget: BigNumber + token0Info?: Token + token1Info?: Token } export interface ProMMFarmResponse {