diff --git a/src/assets/images/gas-refund/knc-dropping.png b/src/assets/images/gas-refund/knc-dropping.png
new file mode 100644
index 0000000000..901fb34e74
Binary files /dev/null and b/src/assets/images/gas-refund/knc-dropping.png differ
diff --git a/src/assets/images/gas-refund/kncs.png b/src/assets/images/gas-refund/kncs.png
new file mode 100644
index 0000000000..ee21ecd56e
Binary files /dev/null and b/src/assets/images/gas-refund/kncs.png differ
diff --git a/src/assets/images/gas-refund/ringwave.gif b/src/assets/images/gas-refund/ringwave.gif
new file mode 100644
index 0000000000..2d7169d7dd
Binary files /dev/null and b/src/assets/images/gas-refund/ringwave.gif differ
diff --git a/src/assets/images/gas-refund/ringwave.png b/src/assets/images/gas-refund/ringwave.png
new file mode 100644
index 0000000000..b436932293
Binary files /dev/null and b/src/assets/images/gas-refund/ringwave.png differ
diff --git a/src/assets/svg/crystals.svg b/src/assets/svg/crystals.svg
new file mode 100644
index 0000000000..3614ba2aa2
--- /dev/null
+++ b/src/assets/svg/crystals.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/svg/knc_black.svg b/src/assets/svg/knc_black.svg
index b65e010aaa..a0a93e6c13 100644
--- a/src/assets/svg/knc_black.svg
+++ b/src/assets/svg/knc_black.svg
@@ -1,4 +1,4 @@
-
+
@@ -11,4 +11,4 @@
-
+
\ No newline at end of file
diff --git a/src/assets/svg/refund1.svg b/src/assets/svg/refund1.svg
new file mode 100644
index 0000000000..6a39a97216
--- /dev/null
+++ b/src/assets/svg/refund1.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/assets/svg/refund2.svg b/src/assets/svg/refund2.svg
new file mode 100644
index 0000000000..e54beb0434
--- /dev/null
+++ b/src/assets/svg/refund2.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/assets/svg/refund3.svg b/src/assets/svg/refund3.svg
new file mode 100644
index 0000000000..e9b45a34b5
--- /dev/null
+++ b/src/assets/svg/refund3.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/assets/wallets/browser-wallet-dark.svg b/src/assets/wallets/browser-wallet-dark.svg
index af517ca597..97efc9f867 100644
--- a/src/assets/wallets/browser-wallet-dark.svg
+++ b/src/assets/wallets/browser-wallet-dark.svg
@@ -1,4 +1,7 @@
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/src/assets/wallets/browser-wallet-light.svg b/src/assets/wallets/browser-wallet-light.svg
index d557a1f4e0..d445239d55 100644
--- a/src/assets/wallets/browser-wallet-light.svg
+++ b/src/assets/wallets/browser-wallet-light.svg
@@ -1,5 +1,7 @@
-
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx
index 351afa8010..b15f94def7 100644
--- a/src/components/Button/index.tsx
+++ b/src/components/Button/index.tsx
@@ -4,7 +4,7 @@ import React, { ReactNode, useRef } from 'react'
import { ChevronDown, Info } from 'react-feather'
import { Flex, Text } from 'rebass'
import { ButtonProps, Button as RebassButton } from 'rebass/styled-components'
-import styled from 'styled-components'
+import styled, { css } from 'styled-components'
import Loader from 'components/Loader'
import { MouseoverTooltip } from 'components/Tooltip'
@@ -12,7 +12,14 @@ import { ApprovalState } from 'hooks/useApproveCallback'
import { RowBetween } from '../Row'
+const disabledBase = css`
+ cursor: auto;
+`
+const disabledHoverBase = css`
+ filter: none;
+`
const Base = styled(RebassButton)<{
+ color?: string
padding?: string
margin?: string
width?: string
@@ -20,6 +27,7 @@ const Base = styled(RebassButton)<{
borderRadius?: string
altDisabledStyle?: boolean
gap?: string
+ $disabled?: boolean // use this for disabled button with MouseoverTooltip
}>`
padding: ${({ padding }) => (padding ? padding : '12px')};
width: ${({ width }) => (width ? width : '100%')};
@@ -32,7 +40,7 @@ const Base = styled(RebassButton)<{
border-radius: ${({ borderRadius }) => (borderRadius ? borderRadius : '999px')};
outline: none;
border: 1px solid transparent;
- color: white;
+ color: ${({ color }) => color || 'white'};
text-decoration: none;
display: flex;
justify-content: center;
@@ -45,16 +53,33 @@ const Base = styled(RebassButton)<{
filter: brightness(0.8);
}
&:disabled {
- cursor: auto;
+ ${disabledBase}
}
- &:hover:disabled {
- filter: none;
+ ${({ $disabled }) => $disabled && disabledBase}
+
+ &:hover {
+ &:disabled {
+ ${disabledHoverBase}
+ }
+ ${({ $disabled }) => $disabled && disabledHoverBase}
}
+
& > * {
user-select: none;
}
`
+const disabledPrimary = css<{
+ altDisabledStyle?: boolean
+}>`
+ background-color: ${({ theme, altDisabledStyle }) =>
+ altDisabledStyle ? theme.primary : theme.buttonGray} !important;
+ color: ${({ theme, altDisabledStyle }) => (altDisabledStyle ? 'white' : theme.border)};
+ box-shadow: none !important;
+ border: 1px solid transparent;
+ outline: none;
+ opacity: ${({ altDisabledStyle }) => (altDisabledStyle ? '0.7' : '1')};
+`
export const ButtonPrimary = styled(Base)`
background-color: ${({ theme }) => theme.primary};
color: ${({ theme }) => theme.textReverse};
@@ -63,16 +88,16 @@ export const ButtonPrimary = styled(Base)`
background-color: ${({ theme }) => darken(0.1, theme.primary)};
}
&:disabled {
- background-color: ${({ theme, altDisabledStyle }) => (altDisabledStyle ? theme.primary : theme.buttonGray)};
- color: ${({ theme, altDisabledStyle }) => (altDisabledStyle ? 'white' : theme.border)};
- cursor: auto;
- box-shadow: none;
- border: 1px solid transparent;
- outline: none;
- opacity: ${({ altDisabledStyle }) => (altDisabledStyle ? '0.7' : '1')};
+ ${disabledPrimary}
}
+ ${({ $disabled }) => $disabled && disabledPrimary}
`
+const disabledWarning = css`
+ background-color: ${({ theme }) => rgba(theme.warning, 0.2)};
+ cursor: auto;
+ color: ${({ theme }) => theme.warning};
+`
export const ButtonWarning = styled(Base)`
background-color: ${({ theme }) => theme.warning};
color: ${({ theme }) => theme.textReverse};
@@ -85,17 +110,27 @@ export const ButtonWarning = styled(Base)`
background-color: ${({ theme }) => darken(0.1, theme.warning)};
}
&:disabled {
+ ${disabledWarning}
background-color: ${({ theme }) => rgba(theme.warning, 0.2)};
cursor: auto;
color: ${({ theme }) => theme.warning};
}
+ ${({ $disabled }) => $disabled && disabledWarning}
`
-export const ButtonLight = styled(Base)<{ color?: string }>`
+const disabledLight = css`
+ cursor: not-allowed;
+ background-color: ${({ theme }) => `${theme.buttonGray}`};
+ color: ${({ theme }) => theme.border};
+ box-shadow: none;
+ border: 1px solid transparent;
+ outline: none;
+`
+export const ButtonLight = styled(Base)<{ color?: string; fontSize?: number }>`
background-color: ${({ theme, color }) => `${color || theme.primary}4d`};
min-width: unset;
color: ${({ color, theme }) => color || theme.primary};
- font-size: 14px;
+ font-size: ${({ fontSize }) => fontSize || 14}px;
font-weight: 500;
&:hover {
background-color: ${({ theme, disabled, color }) => !disabled && darken(0.03, `${color || theme.primary}4d`)};
@@ -105,13 +140,9 @@ export const ButtonLight = styled(Base)<{ color?: string }>`
background-color: ${({ theme, disabled, color }) => !disabled && darken(0.05, `${color || theme.primary}4d`)};
}
:disabled {
- cursor: not-allowed;
- background-color: ${({ theme }) => `${theme.buttonGray}`};
- color: ${({ theme }) => theme.border};
- box-shadow: none;
- border: 1px solid transparent;
- outline: none;
+ ${disabledLight}
}
+ ${({ $disabled }) => $disabled && disabledLight}
`
export const ButtonGray = styled(Base)`
@@ -128,6 +159,10 @@ export const ButtonGray = styled(Base)`
}
`
+const disabledSecondary = css`
+ opacity: 50%;
+ cursor: auto;
+`
export const ButtonSecondary = styled(Base)`
border: 1px solid ${({ theme }) => theme.primary};
color: ${({ theme }) => theme.primary};
@@ -145,14 +180,23 @@ export const ButtonSecondary = styled(Base)`
border: 1px solid ${({ theme }) => theme.primary};
}
&:disabled {
- opacity: 50%;
- cursor: auto;
+ ${disabledSecondary}
}
+ ${({ $disabled }) => $disabled && disabledSecondary}
+
a:hover {
text-decoration: none;
}
`
+const disabledOutlined = css<{
+ altDisabledStyle?: boolean
+}>`
+ color: ${({ theme, altDisabledStyle }) => (altDisabledStyle ? 'white' : theme.border)};
+ cursor: auto;
+ box-shadow: none;
+ border: 1px solid ${({ theme, altDisabledStyle }) => (altDisabledStyle ? 'white' : theme.border)};
+`
export const ButtonOutlined = styled(Base)<{ color?: string }>`
border: 1px solid ${({ theme, color }) => color || theme.subText};
background-color: transparent;
@@ -169,13 +213,15 @@ export const ButtonOutlined = styled(Base)<{ color?: string }>`
box-shadow: 0 0 0 1px ${({ theme, color }) => color || theme.subText};
}
&:disabled {
- color: ${({ theme, altDisabledStyle }) => (altDisabledStyle ? 'white' : theme.border)};
- cursor: auto;
- box-shadow: none;
- border: 1px solid ${({ theme, altDisabledStyle }) => (altDisabledStyle ? 'white' : theme.border)};
+ ${disabledOutlined}
}
+ ${({ $disabled }) => $disabled && disabledOutlined}
`
+const disabledEmpty = css`
+ opacity: 50%;
+ cursor: not-allowed;
+`
export const ButtonEmpty = styled(Base)`
background-color: transparent;
color: ${({ theme }) => theme.primary};
@@ -184,20 +230,31 @@ export const ButtonEmpty = styled(Base)`
align-items: center;
&:disabled {
- opacity: 50%;
- cursor: not-allowed;
+ ${disabledEmpty}
}
+ ${({ $disabled }) => $disabled && disabledEmpty}
`
+const disabledConfirmed = css`
+ cursor: auto;
+`
const ButtonConfirmedStyle = styled(Base)`
background-color: ${({ theme }) => rgba(theme.apr, 0.2)};
color: ${({ theme }) => theme.green};
&:disabled {
- cursor: auto;
+ ${disabledConfirmed}
}
+ ${({ $disabled }) => $disabled && disabledConfirmed}
`
+const disabledError = css`
+ opacity: 50%;
+ cursor: auto;
+ box-shadow: none;
+ background-color: ${({ theme }) => theme.red};
+ border: 1px solid ${({ theme }) => theme.red};
+`
export const ButtonErrorStyle = styled(Base)`
background-color: ${({ theme }) => theme.red};
border: 1px solid ${({ theme }) => theme.red};
@@ -211,12 +268,9 @@ export const ButtonErrorStyle = styled(Base)`
background-color: ${({ theme }) => darken(0.1, theme.red)};
}
&:disabled {
- opacity: 50%;
- cursor: auto;
- box-shadow: none;
- background-color: ${({ theme }) => theme.red};
- border: 1px solid ${({ theme }) => theme.red};
+ ${disabledError}
}
+ ${({ $disabled }) => $disabled && disabledError}
`
export function ButtonConfirmed({
diff --git a/src/components/Copy/index.tsx b/src/components/Copy/index.tsx
index 82b98bdcf8..d0441a66fb 100644
--- a/src/components/Copy/index.tsx
+++ b/src/components/Copy/index.tsx
@@ -8,7 +8,7 @@ import useCopyClipboard from 'hooks/useCopyClipboard'
const Wrapper = styled.div<{ margin?: string; size?: string }>`
flex-shrink: 0;
- margin-left: 4px;
+ margin-left: ${({ margin }) => margin || '4px'};
text-decoration: none;
cursor: pointer;
position: relative;
diff --git a/src/components/Header/groups/KyberDaoGroup.tsx b/src/components/Header/groups/KyberDaoGroup.tsx
index 1b93af968e..38165fe4db 100644
--- a/src/components/Header/groups/KyberDaoGroup.tsx
+++ b/src/components/Header/groups/KyberDaoGroup.tsx
@@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro'
import { useLocation } from 'react-router-dom'
import styled from 'styled-components'
+import { ReactComponent as KyberLogo } from 'assets/svg/knc_black.svg'
import Column from 'components/Column'
import LightBulb from 'components/Icons/LightBulb'
import StakeIcon from 'components/Icons/Stake'
@@ -36,17 +37,21 @@ const KyberDAONavGroup = () => {
}
dropdownContent={
-
+
Stake KNC
-
+
Vote
+
+
+ KNC Utility
+
{
diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx
index c105986bf1..4d1383051a 100644
--- a/src/components/Menu/index.tsx
+++ b/src/components/Menu/index.tsx
@@ -13,7 +13,7 @@ import {
PieChart,
Share2,
} from 'react-feather'
-import { useLocation, useNavigate } from 'react-router-dom'
+import { NavLink, useLocation, useNavigate } from 'react-router-dom'
import { useMedia } from 'react-use'
import { Text } from 'rebass'
import styled, { css } from 'styled-components'
@@ -35,11 +35,12 @@ import Row, { AutoRow } from 'components/Row'
import Toggle from 'components/Toggle'
import ThemeToggle from 'components/Toggle/ThemeToggle'
import { TutorialIds } from 'components/Tutorial/TutorialSwap/constant'
-import { TAG } from 'constants/env'
+import { ENV_LEVEL, TAG } from 'constants/env'
import { AGGREGATOR_ANALYTICS_URL, APP_PATHS, DMM_ANALYTICS_URL, TERM_FILES_PATH } from 'constants/index'
import { getLocaleLabel } from 'constants/locales'
import { FAUCET_NETWORKS } from 'constants/networks'
import { EVMNetworkInfo } from 'constants/networks/type'
+import { ENV_TYPE } from 'constants/type'
import { useActiveWeb3React } from 'hooks'
import useClaimReward from 'hooks/useClaimReward'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
@@ -414,6 +415,7 @@ export default function Menu() {
options={[
{ link: '/kyberdao/stake-knc', label: t`Stake KNC` },
{ link: '/kyberdao/vote', label: t`Vote` },
+ { link: APP_PATHS.KYBERDAO_KNC_UTILITY, label: t`KNC Utility` },
{ link: 'https://kyberswap.canny.io/feature-request', label: t`Feature Request`, external: true },
]}
/>
@@ -517,7 +519,14 @@ export default function Menu() {
Help
-
+ {ENV_LEVEL === ENV_TYPE.LOCAL && (
+
+
+
+ Icons
+
+
+ )}
diff --git a/src/components/SwapForm/SwapModal/SwapDetails/index.tsx b/src/components/SwapForm/SwapModal/SwapDetails/index.tsx
index ae2b109937..0ddb21e76c 100644
--- a/src/components/SwapForm/SwapModal/SwapDetails/index.tsx
+++ b/src/components/SwapForm/SwapModal/SwapDetails/index.tsx
@@ -7,6 +7,7 @@ import { Flex, Text } from 'rebass'
import { BuildRouteData } from 'services/route/types/buildRoute'
import { TruncatedText } from 'components'
+import { ButtonLight } from 'components/Button'
import { AutoColumn } from 'components/Column'
import CopyHelper from 'components/Copy'
import Divider from 'components/Divider'
@@ -19,6 +20,7 @@ import { MouseoverTooltip, TextDashed } from 'components/Tooltip'
import { StyledBalanceMaxMini } from 'components/swapv2/styleds'
import { CHAINS_SUPPORT_FEE_CONFIGS } from 'constants/index'
import { useActiveWeb3React } from 'hooks'
+import { isSupportKyberDao, useGasRefundTier } from 'hooks/kyberdao'
import useTheme from 'hooks/useTheme'
import { useIsDarkMode } from 'state/user/hooks'
import { ExternalLink, TYPE } from 'theme'
@@ -71,11 +73,12 @@ export default function SwapDetails({
priceImpact,
buildData,
}: Props) {
- const { isEVM, chainId, networkInfo } = useActiveWeb3React()
+ const { isEVM, chainId, networkInfo, account } = useActiveWeb3React()
const [showInverted, setShowInverted] = useState(false)
const theme = useTheme()
const isDarkMode = useIsDarkMode()
const { slippage, routeSummary } = useSwapFormContext()
+ const { gasRefundPerCentage } = useGasRefundTier()
const currencyIn = routeSummary?.parsedAmountIn?.currency
const currencyOut = routeSummary?.parsedAmountOut?.currency
@@ -325,6 +328,41 @@ export default function SwapDetails({
+ {isSupportKyberDao(chainId) && account && Number(routeSummary?.amountInUsd || 0) > 200 && (
+
+
+
+
+
+ Stake KNC in KyberDAO to get gas refund. Read more{' '}
+
+ here ↗
+
+
+
+ }
+ placement="right"
+ >
+ Gas Refund
+
+
+
+
+
+ {gasRefundPerCentage * 100}% Refund
+
+
+ )}
+
diff --git a/src/components/SwapForm/TradeSummary.tsx b/src/components/SwapForm/TradeSummary.tsx
index 7d99558319..034410a078 100644
--- a/src/components/SwapForm/TradeSummary.tsx
+++ b/src/components/SwapForm/TradeSummary.tsx
@@ -1,16 +1,19 @@
import { Trans } from '@lingui/macro'
import React, { useEffect, useState } from 'react'
+import { NavLink } from 'react-router-dom'
import { Text } from 'rebass'
import styled from 'styled-components'
import { ReactComponent as DropdownSVG } from 'assets/svg/down.svg'
+import { ButtonLight } from 'components/Button'
import { AutoColumn } from 'components/Column'
import Divider from 'components/Divider'
import { RowBetween, RowFixed } from 'components/Row'
import { useSwapFormContext } from 'components/SwapForm/SwapFormContext'
import { MouseoverTooltip, TextDashed } from 'components/Tooltip'
-import { BIPS_BASE, CHAINS_SUPPORT_FEE_CONFIGS } from 'constants/index'
+import { APP_PATHS, BIPS_BASE, CHAINS_SUPPORT_FEE_CONFIGS } from 'constants/index'
import { useActiveWeb3React } from 'hooks'
+import { isSupportKyberDao, useGasRefundTier } from 'hooks/kyberdao'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import useTheme from 'hooks/useTheme'
import { ExternalLink, TYPE } from 'theme'
@@ -143,7 +146,9 @@ type Props = {
slippage: number
}
const TradeSummary: React.FC = ({ routeSummary, slippage }) => {
+ const { account, chainId } = useActiveWeb3React()
const theme = useTheme()
+ const { gasRefundPerCentage } = useGasRefundTier()
const [expanded, setExpanded] = useState(true)
const [alreadyVisible, setAlreadyVisible] = useState(false)
const { parsedAmountOut, priceImpact, gasUsd } = routeSummary || {}
@@ -261,6 +266,32 @@ const TradeSummary: React.FC = ({ routeSummary, slippage }) => {
+ {isSupportKyberDao(chainId) && (
+
+
+
+
+ Stake KNC in KyberDAO to get gas refund. Read more{' '}
+
+ here ↗
+
+
+ }
+ placement="right"
+ >
+ Gas Refund
+
+
+
+
+
+ {account ? gasRefundPerCentage * 100 : '--'}% Refund
+
+
+
+ )}
diff --git a/src/components/Tooltip/index.tsx b/src/components/Tooltip/index.tsx
index c418961d03..704af63ba2 100644
--- a/src/components/Tooltip/index.tsx
+++ b/src/components/Tooltip/index.tsx
@@ -55,7 +55,6 @@ export default function Tooltip({ text, width, maxWidth, size, onMouseEnter, onM
export function MouseoverTooltip({ children, disableTooltip, delay, ...rest }: Omit) {
const [show, setShow] = useState(false)
const [closeTimeout, setCloseTimeout] = useState(null)
- const ref = useRef(null)
const hovering = useRef(false)
const open = useCallback(() => {
if (!!rest.text) {
@@ -83,7 +82,7 @@ export function MouseoverTooltip({ children, disableTooltip, delay, ...rest }: O
if (disableTooltip) return <>{children}>
return (
-
+
{children}
diff --git a/src/constants/index.ts b/src/constants/index.ts
index af2de18100..191046c877 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -221,12 +221,13 @@ export const APP_PATHS = {
KYBERDAO: '/kyberdao',
KYBERDAO_STAKE: '/kyberdao/stake-knc',
KYBERDAO_VOTE: '/kyberdao/vote',
+ KYBERDAO_KNC_UTILITY: '/kyberdao/knc-utility',
LIMIT: '/limit',
GRANT_PROGRAMS: '/inter-project-trading-campaigns',
PROFILE_MANAGE: '/manage',
ELASTIC_LEGACY: '/elastic-legacy',
VERIFY_AUTH: '/auth',
-}
+} as const
export const TERM_FILES_PATH = {
KYBERSWAP_TERMS: '/files/Kyber - Terms of Service - 14 June 2023.pdf',
diff --git a/src/constants/tokens.ts b/src/constants/tokens.ts
index 67c2ee63b3..b109ca388f 100644
--- a/src/constants/tokens.ts
+++ b/src/constants/tokens.ts
@@ -678,7 +678,7 @@ export const KNC: { [chainId in ChainId]: Token } = {
18,
'KNC',
'Kyber Network Crystal',
- ), // todo namgold: not exists yet
+ ), // todo: not exists yet
[ChainId.SOLANA_DEVNET]: new Token(
ChainId.SOLANA_DEVNET,
'KNCkfGAnBUvoG5EJipAzSBjjaF8iNL4ivYsBS14DKdg',
diff --git a/src/hooks/kyberdao/index.tsx b/src/hooks/kyberdao/index.tsx
index 818bda530b..bf6613808a 100644
--- a/src/hooks/kyberdao/index.tsx
+++ b/src/hooks/kyberdao/index.tsx
@@ -11,25 +11,37 @@ import MigrateABI from 'constants/abis/kyberdao/migrate.json'
import RewardDistributorABI from 'constants/abis/kyberdao/reward_distributor.json'
import StakingABI from 'constants/abis/kyberdao/staking.json'
import { CONTRACT_NOT_FOUND_MSG } from 'constants/messages'
-import { NETWORKS_INFO, NETWORKS_INFO_CONFIG, isEVM } from 'constants/networks'
+import { NETWORKS_INFO_CONFIG, isEVM } from 'constants/networks'
+import ethereumInfo from 'constants/networks/ethereum'
import { EVMNetworkInfo } from 'constants/networks/type'
import { useActiveWeb3React } from 'hooks'
import { useContract, useContractForReading, useTokenContractForReading } from 'hooks/useContract'
import useTokenBalance from 'hooks/useTokenBalance'
+import { KNCUtilityTabs } from 'pages/KyberDAO/KNCUtility/type'
import { useSingleCallResult } from 'state/multicall/hooks'
import { useTransactionAdder } from 'state/transactions/hooks'
import { TRANSACTION_TYPE } from 'state/transactions/type'
import { calculateGasMargin } from 'utils'
-import { ProposalDetail, ProposalStatus, RewardStats, StakerAction, StakerInfo, VoteInfo } from './types'
+import {
+ EligibleTxsInfo,
+ GasRefundTierInfo,
+ ProposalDetail,
+ ProposalStatus,
+ RewardInfo,
+ RewardStats,
+ StakerAction,
+ StakerInfo,
+ VoteInfo,
+} from './types'
export function isSupportKyberDao(chainId: ChainId) {
- return isEVM(chainId) && (NETWORKS_INFO_CONFIG[chainId] as EVMNetworkInfo).kyberDAO
+ return isEVM(chainId) && NETWORKS_INFO_CONFIG[chainId].kyberDAO
}
export function useKyberDAOInfo() {
- const { chainId } = useActiveWeb3React()
- const kyberDaoInfo = NETWORKS_INFO[chainId !== ChainId.GÖRLI ? ChainId.MAINNET : ChainId.GÖRLI].kyberDAO
+ const { chainId, networkInfo } = useActiveWeb3React()
+ const kyberDaoInfo = (isSupportKyberDao(chainId) ? (networkInfo as EVMNetworkInfo) : ethereumInfo).kyberDAO
return kyberDaoInfo
}
@@ -336,7 +348,7 @@ export function useStakingInfo() {
kncContract
?.totalSupply()
.then((res: any) => setTotalSupply(res))
- .catch((err: any) => console.log(err))
+ .catch((error: any) => console.error('Get KNC totalSupply error:', { error }))
}, [kncContract])
return {
@@ -518,6 +530,93 @@ export function useVotingInfo() {
}
}
+const aggregateValue = (
+ values: ({ [key in T]: string | number } | undefined)[],
+ field: T,
+): number => {
+ return values.reduce((acc, cur) => {
+ const value = cur?.[field] ?? 0
+ return (typeof value === 'number' ? value : parseFloat(value)) + acc
+ }, 0)
+}
+
+export function useGasRefundTier(): GasRefundTierInfo {
+ const { account, chainId } = useActiveWeb3React()
+ const kyberDaoInfo = useKyberDAOInfo()
+
+ const { data } = useSWR(
+ account && isSupportKyberDao(chainId) && kyberDaoInfo?.daoStatsApi + '/api/v1/stakers/' + account + '/refund-info',
+ url => fetcher(url).then(res => res.refundInfo),
+ )
+
+ return data || { userTier: 0, gasRefundPerCentage: 0 }
+}
+
+export function useGasRefundInfo({ rewardStatus = KNCUtilityTabs.Available }: { rewardStatus?: KNCUtilityTabs }) {
+ const { account, chainId } = useActiveWeb3React()
+ const kyberDaoInfo = useKyberDAOInfo()
+
+ const { data: claimableReward } = useSWR(
+ account &&
+ isSupportKyberDao(chainId) &&
+ kyberDaoInfo?.daoStatsApi + '/api/v1/stakers/' + account + '/refunds/total?rewardStatus=claimable',
+ url =>
+ fetcher(url)
+ .then(res => res.total)
+ .then(({ knc, usd }) => ({ knc: parseFloat(knc), usd: parseFloat(usd) })),
+ )
+ const { data: pendingReward } = useSWR(
+ account &&
+ isSupportKyberDao(chainId) &&
+ kyberDaoInfo?.daoStatsApi + '/api/v1/stakers/' + account + '/refunds/total?rewardStatus=pending',
+ url =>
+ fetcher(url)
+ .then(res => res.total)
+ .then(({ knc, usd }) => ({ knc: parseFloat(knc), usd: parseFloat(usd) })),
+ )
+ const { data: claimedReward } = useSWR(
+ account &&
+ isSupportKyberDao(chainId) &&
+ kyberDaoInfo?.daoStatsApi + '/api/v1/stakers/' + account + '/refunds/total?rewardStatus=claimed',
+ url =>
+ fetcher(url)
+ .then(res => res.total)
+ .then(({ knc, usd }) => ({ knc: parseFloat(knc), usd: parseFloat(usd) })),
+ )
+ return {
+ reward:
+ rewardStatus === KNCUtilityTabs.Available
+ ? claimableReward
+ : rewardStatus === KNCUtilityTabs.Pending
+ ? pendingReward
+ : rewardStatus === KNCUtilityTabs.Claimed
+ ? claimedReward
+ : undefined,
+ claimableReward,
+ totalReward: {
+ usd: aggregateValue([claimableReward, pendingReward, claimedReward], 'usd'),
+ knc: aggregateValue([claimableReward, pendingReward, claimedReward], 'knc'),
+ },
+ }
+}
+
+export const useEligibleTransactions = (page = 1, pageSize = 100): EligibleTxsInfo | undefined => {
+ const { account, chainId } = useActiveWeb3React()
+ const kyberDaoInfo = useKyberDAOInfo()
+
+ const { data: eligibleTransactions } = useSWR(
+ account &&
+ isSupportKyberDao(chainId) &&
+ kyberDaoInfo?.daoStatsApi +
+ '/api/v1/stakers/' +
+ account +
+ `/refunds/eligible-transactions?pageSize=${pageSize}&page=${page}`,
+ fetcher,
+ )
+
+ return eligibleTransactions
+}
+
export function useProposalInfoById(id?: number): { proposalInfo?: ProposalDetail } {
const kyberDaoInfo = useKyberDAOInfo()
const { data } = useSWRImmutable(
diff --git a/src/hooks/kyberdao/types.ts b/src/hooks/kyberdao/types.ts
index 243019f7f9..50073ae43e 100644
--- a/src/hooks/kyberdao/types.ts
+++ b/src/hooks/kyberdao/types.ts
@@ -66,6 +66,39 @@ export interface StakerInfo {
stake_amount: number
}
+export interface GasRefundTierInfo {
+ userTier: number
+ gasRefundPerCentage: number
+}
+
+export interface RewardInfo {
+ knc: number
+ usd: number
+}
+
+interface TransactionInfo {
+ tx: string
+ timestamp: number
+ gasRefundInKNC: string
+ gasRefundInUSD: string
+ gasFeeInUSD: string
+ gasFeeInNativeToken: string
+ epoch: number
+ userTier: number
+ gasRefundPerCentage: string
+ userWallet: string
+}
+
+export interface EligibleTxsInfo {
+ transactions: TransactionInfo[]
+ pagination: {
+ totalOfPages: number
+ currentPage: number
+ pageSize: number
+ hasMore: boolean
+ }
+}
+
export interface StakerAction {
timestamp: number
epoch: number
diff --git a/src/pages/App.tsx b/src/pages/App.tsx
index 737dd84aa2..cf5711d63b 100644
--- a/src/pages/App.tsx
+++ b/src/pages/App.tsx
@@ -68,6 +68,7 @@ const RemoveLiquidity = lazy(() => import('pages/RemoveLiquidity'))
const KyberDAOStakeKNC = lazy(() => import('pages/KyberDAO/StakeKNC'))
const KyberDAOVote = lazy(() => import('pages/KyberDAO/Vote'))
+const KNCUtility = lazy(() => import('pages/KyberDAO/KNCUtility'))
const AboutKyberSwap = lazy(() => import('pages//About/AboutKyberSwap'))
const AboutKNC = lazy(() => import('pages/About/AboutKNC'))
const BuyCrypto = lazy(() => import('pages/BuyCrypto'))
@@ -355,6 +356,7 @@ export default function App() {
} />
} />
+ } />
} />
} />
} />
diff --git a/src/pages/KyberDAO/KNCUtility/EligibleTxModal.tsx b/src/pages/KyberDAO/KNCUtility/EligibleTxModal.tsx
new file mode 100644
index 0000000000..2ab6171d07
--- /dev/null
+++ b/src/pages/KyberDAO/KNCUtility/EligibleTxModal.tsx
@@ -0,0 +1,163 @@
+import { Trans } from '@lingui/macro'
+import { useState } from 'react'
+import { X } from 'react-feather'
+import { useMedia } from 'react-use'
+import { Flex, Text } from 'rebass'
+import styled from 'styled-components'
+
+import CopyHelper from 'components/Copy'
+import Modal from 'components/Modal'
+import Pagination from 'components/Pagination'
+import { RowBetween } from 'components/Row'
+import { NativeCurrencies } from 'constants/tokens'
+import { useActiveWeb3React } from 'hooks'
+import { useEligibleTransactions } from 'hooks/kyberdao'
+import useTheme from 'hooks/useTheme'
+import { ExternalLinkIcon, MEDIA_WIDTHS } from 'theme'
+import { formattedNum, getEtherscanLink } from 'utils'
+
+import { HeaderCell, Table, TableHeader, TableRow } from './TxTable'
+
+const Wrapper = styled.div`
+ width: 100%;
+ border-radius: 20px;
+ padding: 24px 24px 30px;
+ background-color: ${({ theme }) => theme.tableHeader};
+ min-width: 550px;
+ ${({ theme }) => theme.mediaWidth.upToExtraSmall`
+ min-width: unset;
+ `}
+`
+
+const IconWrapper = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: transparent;
+
+ & > img,
+ span {
+ height: 16px;
+ width: 16px;
+ }
+ ${({ theme }) => theme.mediaWidth.upToMedium`
+ align-items: flex-end;
+ `};
+`
+
+const CloseButton = styled.div`
+ svg {
+ display: block;
+ }
+ :hover {
+ filter: brightness(0.8);
+ }
+`
+
+export default function EligibleTxModal({ isOpen, closeModal }: { isOpen: boolean; closeModal: () => void }) {
+ const { chainId, networkInfo } = useActiveWeb3React()
+ const [currentPage, setCurrentPage] = useState(1)
+ const eligibleTxs = useEligibleTransactions(currentPage, 10)
+ const theme = useTheme()
+ const upToExtraSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToExtraSmall}px)`)
+
+ return (
+
+
+
+
+
+
+ Your transactions
+
+
+
+
+
+
+
+
+ TXN HASH
+
+ {upToExtraSmall ? null : (
+ <>
+
+ LOCAL TIME
+
+
+ GAS FEE
+
+ >
+ )}
+
+ GAS REFUND REWARDS
+
+
+ {eligibleTxs?.transactions?.map(tx => {
+ const time = new Date(tx.timestamp * 1000)
+ return (
+
+
+
+
+
+
+
+ {tx.tx.slice(0, 6)}...{tx.tx.slice(-4)}
+
+
+
+
+
+ {upToExtraSmall ? null : (
+ <>
+
+
+ {time.toLocaleDateString()}
+
+ {time.toLocaleTimeString()}
+
+
+
+
+
+
+ {formattedNum(tx.gasFeeInNativeToken)} {NativeCurrencies[chainId].symbol}
+
+
+ {formattedNum(tx.gasFeeInUSD, true)}
+
+
+
+ >
+ )}
+
+
+
+ {formattedNum(tx.gasRefundInKNC)} KNC
+
+ Tier {tx.userTier} - {Number(tx.gasRefundPerCentage) * 100}%
+
+
+
+
+ )
+ })}
+
+
+
+
+
+
+ )
+}
diff --git a/src/pages/KyberDAO/KNCUtility/FAQ.tsx b/src/pages/KyberDAO/KNCUtility/FAQ.tsx
new file mode 100644
index 0000000000..c724f332f2
--- /dev/null
+++ b/src/pages/KyberDAO/KNCUtility/FAQ.tsx
@@ -0,0 +1,251 @@
+import { Trans, t } from '@lingui/macro'
+import { rgba } from 'polished'
+import { ReactNode, useState } from 'react'
+import { ChevronDown } from 'react-feather'
+import { NavLink } from 'react-router-dom'
+import { Flex, Text } from 'rebass'
+import styled from 'styled-components'
+
+import { APP_PATHS, TERM_FILES_PATH } from 'constants/index'
+import useTheme from 'hooks/useTheme'
+import { ExternalLink } from 'theme'
+
+const Title = styled.span`
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 20px;
+ color: ${({ theme }) => theme.text};
+ max-width: calc(100% - 20px - 8px);
+`
+
+enum Panel {
+ Q_Join,
+ Q_Chain,
+ Q_When,
+ Q_Deadline,
+ Q_Vote,
+ Q_LimitOrder,
+ Q_Limit,
+ Q_Term,
+ Q_Other,
+}
+
+type PanelProps = {
+ isExpanded: boolean
+ toggleExpand: () => void
+ title: string
+ content: ReactNode
+}
+
+const DetailPanel: React.FC = ({ isExpanded, title, content, toggleExpand }) => {
+ const theme = useTheme()
+
+ return (
+ <>
+ {
+ toggleExpand()
+ }}
+ sx={{
+ height: '56px',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ cursor: 'pointer',
+ }}
+ >
+ {title}
+
+
+
+
+
+
+ {isExpanded && (
+
+ {content}
+
+ )}
+ >
+ )
+}
+
+const DetailsContainer = styled.div`
+ padding: 16px 24px;
+ height: fit-content;
+ display: flex;
+ flex-direction: column;
+ background: ${({ theme }) => rgba(theme.background, 0.8)};
+ border-radius: 20px;
+`
+
+const Separator = styled.div`
+ width: 100%;
+ height: 0;
+ border-bottom: 1px solid ${({ theme }) => theme.border};
+ margin: 8px 0;
+`
+
+const FAQ: React.FC = () => {
+ const [expandedPanel, setExpandedPanel] = useState()
+
+ const handleToggleExpand = (panel?: Panel) => {
+ if (expandedPanel === panel) {
+ setExpandedPanel(undefined)
+ } else {
+ setExpandedPanel(panel)
+ }
+ }
+
+ return (
+
+ handleToggleExpand(Panel.Q_Join)}
+ isExpanded={expandedPanel === Panel.Q_Join}
+ title={t`Can I participate in the Gas Refund Program if I am not staking in KyberDAO?`}
+ content={
+
+ No. You have to stake a minimum of 500 KNC in KyberDAO (on Ethereum) here, and meet the eligibility criteria
+ by completing swap(s) on KyberSwap, with a minimum trading volume of ≥$200 per swap.
+
+ }
+ />
+
+ handleToggleExpand(Panel.Q_Chain)}
+ isExpanded={expandedPanel === Panel.Q_Chain}
+ title={t`Are swaps on all chains eligible for gas refunds?`}
+ content={
+
+ During this beta phase, only swaps on Ethereum are eligible for gas refunds. We may expand the gas refund
+ program to other chains in the future.
+
+ }
+ />
+
+ handleToggleExpand(Panel.Q_When)}
+ isExpanded={expandedPanel === Panel.Q_When}
+ title={t`When will rewards be available to claim?`}
+ content={
+
+ On the “Pending” tab, there is a countdown timer showing when pending refunds become available for claiming.
+ Refunds become available for claiming at the start of n+2 epoch. Each epoch lasts approximately 2 weeks. You
+ can claim your rewards in the KNC Utility page or in the Wallet widget.
+
+ }
+ />
+
+ handleToggleExpand(Panel.Q_Deadline)}
+ isExpanded={expandedPanel === Panel.Q_Deadline}
+ title={t`Is there a deadline to claim your gas refunds?`}
+ content={
+
+ There is no deadline to claim your gas refunds. You can wait for more KNC to be accumulated before claiming
+ them in order to save on gas fees.
+
+ }
+ />
+
+ handleToggleExpand(Panel.Q_LimitOrder)}
+ isExpanded={expandedPanel === Panel.Q_LimitOrder}
+ title={t`Are limit orders and cross-chain swaps eligible for gas refunds?`}
+ content={
+
+ No. Limit orders and cross-chain swaps are not eligible for gas refunds. Only standard swaps on KyberSwap
+ are eligible.
+
+ }
+ />
+
+ handleToggleExpand(Panel.Q_Vote)}
+ isExpanded={expandedPanel === Panel.Q_Vote}
+ title={t`How can I vote on KIPs with my staked KNC to earn voting rewards?`}
+ content={
+
+ Once you have staked KNC, you can vote on active KyberDAO KIPs (Kyber Improvement Proposals) on the{' '}
+ Vote page to earn voting rewards. Users who stake KNC can
+ enjoy gas refunds + vote on KIPs to and earn even more rewards. For more information on how to vote, please
+ visit{' '}
+
+ https://docs.kyberswap.com/governance/kyberdao
+
+ .
+
+ }
+ />
+
+ handleToggleExpand(Panel.Q_Limit)}
+ isExpanded={expandedPanel === Panel.Q_Limit}
+ title={t`What is the maximum gas refund limit for a user?`}
+ content={
+ Each user wallet address is eligible for gas refund of up to $200 within two epoch cycles.
+ }
+ />
+
+ handleToggleExpand(Panel.Q_Term)}
+ isExpanded={expandedPanel === Panel.Q_Term}
+ title={t`Terms and Conditions`}
+ content={
+ <>
+
+
+ These Terms and Conditions (Terms )
+ should be read in conjunction with the KyberSwap Terms of Use, which lay out the terms and conditions
+ that apply to all KyberSwap activities.
+
+
+
+
+
+ Currently, only trades on Ethereum are eligible for gas refunds. Gas refunds amount is based on the
+ users’ KNC staking tier and the value of each trade.
+
+
+
+
+
+ For a trade to be eligible for gas refunds (after staking KNC), the trade value has to be ≥$200;
+ calculated by KyberSwap at the point of trade.
+
+
+
+
+ Each address has a maximum limit of $200 in gas refunds per month.
+
+
+
+
+ KyberSwap retains the right to amend the gas refund program's end date with reasonable notice.
+
+
+
+
+
+ KyberSwap maintains the right, at its sole discretion, to remove rewards for any user who violates,
+ cheats, or exploits the program.
+
+
+ >
+ }
+ />
+
+ )
+}
+
+export default FAQ
diff --git a/src/pages/KyberDAO/KNCUtility/GasRefundBox.tsx b/src/pages/KyberDAO/KNCUtility/GasRefundBox.tsx
new file mode 100644
index 0000000000..a7aa37f75d
--- /dev/null
+++ b/src/pages/KyberDAO/KNCUtility/GasRefundBox.tsx
@@ -0,0 +1,322 @@
+import { Trans, t } from '@lingui/macro'
+import axios from 'axios'
+import { BigNumber } from 'ethers'
+import { darken } from 'polished'
+import { useCallback, useState } from 'react'
+import { useMedia } from 'react-use'
+import { Flex, Text } from 'rebass'
+import styled, { css } from 'styled-components'
+
+import { NotificationType } from 'components/Announcement/type'
+import { ButtonLight, ButtonPrimary } from 'components/Button'
+import Dots from 'components/Dots'
+import { RowBetween } from 'components/Row'
+import { MouseoverTooltip, TextDashed } from 'components/Tooltip'
+import { REWARD_SERVICE_API } from 'constants/env'
+import { KNC } from 'constants/tokens'
+import { useActiveWeb3React, useWeb3React } from 'hooks'
+import {
+ isSupportKyberDao,
+ useEligibleTransactions,
+ useGasRefundInfo,
+ useGasRefundTier,
+ useVotingInfo,
+} from 'hooks/kyberdao'
+import useTheme from 'hooks/useTheme'
+import { useNotify, useOpenNetworkModal, useWalletModalToggle } from 'state/application/hooks'
+import { useTransactionAdder } from 'state/transactions/hooks'
+import { TRANSACTION_TYPE } from 'state/transactions/type'
+import { LinkStyledButton, MEDIA_WIDTHS } from 'theme'
+import { formattedNum } from 'utils'
+import { sendEVMTransaction } from 'utils/sendTransaction'
+
+import TimerCountdown from '../TimerCountdown'
+import EligibleTxModal from './EligibleTxModal'
+import { KNCUtilityTabs } from './type'
+
+const Hr = styled.hr`
+ width: 100%;
+ border: none;
+ height: 1px;
+ background-color: ${({ theme }) => theme.border};
+ margin: 0;
+`
+
+const Wrapper = styled(Flex)`
+ width: 100%;
+ border-radius: 20px;
+ padding: 20px;
+ background-color: ${({ theme }) => theme.tableHeader};
+ gap: 28px;
+ flex-direction: column;
+`
+
+const Tab = styled(Text)<{ active?: boolean }>`
+ ${({ theme }) => theme.flexRowNoWrap}
+ align-items: left;
+ border-radius: 3rem;
+ outline: none;
+ cursor: pointer;
+ text-decoration: none;
+ color: ${({ theme }) => theme.subText};
+ font-size: 14px;
+ line-height: 20px;
+ font-weight: 500;
+
+ ${({ active, theme }) =>
+ active &&
+ css`
+ border-radius: 12px;
+ font-weight: 600;
+ color: ${theme.primary};
+ `}
+
+ :hover {
+ color: ${({ theme }) => darken(0.1, theme.primary)};
+ }
+`
+
+export default function GasRefundBox() {
+ const { account, chainId } = useActiveWeb3React()
+ const { library } = useWeb3React()
+ const [selectedTab, setSelectedTab] = useState(KNCUtilityTabs.Available)
+ const theme = useTheme()
+ const { totalReward, reward, claimableReward } = useGasRefundInfo({ rewardStatus: selectedTab })
+ const toggleWalletModal = useWalletModalToggle()
+ const [isShowEligibleTx, setShowEligibleTx] = useState(false)
+ const openNetworkModal = useOpenNetworkModal()
+ const notify = useNotify()
+ const [claiming, setClaiming] = useState(false)
+ const addTransactionWithType = useTransactionAdder()
+ const eligibleTxs = useEligibleTransactions(1, 1)
+ const upToXXSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToXXSmall}px)`)
+ const upToExtraSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToExtraSmall}px)`)
+ const { userTier, gasRefundPerCentage } = useGasRefundTier()
+ const { daoInfo: { first_epoch_start_timestamp = 0, current_epoch = 0, epoch_period_in_seconds = 0 } = {} } =
+ useVotingInfo()
+
+ const claimRewards = useCallback(async () => {
+ if (!account || !library || !claimableReward || claimableReward.knc <= 0) return
+
+ setClaiming(true)
+
+ const url = REWARD_SERVICE_API + '/rewards/claim'
+ const data = {
+ wallet: account,
+ chainId: chainId.toString(),
+ clientCode: 'gas-refund',
+ ref: '',
+ }
+ let response: any
+ try {
+ response = await axios({ method: 'POST', url, data })
+ if (response?.data?.code !== 200000) throw new Error(response?.data?.message)
+ } catch (error) {
+ console.error('Claim error:', { error })
+ notify({
+ title: t`Claim Error`,
+ summary: error?.response?.data?.message || error?.message || 'Unknown error',
+ type: NotificationType.ERROR,
+ })
+ setClaiming(false)
+ return
+ }
+
+ const rewardContractAddress = response.data.data.ContractAddress
+ const encodedData = response.data.data.EncodedData
+ try {
+ const tx = await sendEVMTransaction(
+ account,
+ library,
+ rewardContractAddress,
+ encodedData,
+ BigNumber.from(0),
+ async transactionResponse => {
+ const transactionReceipt = await transactionResponse.wait()
+ if (transactionReceipt.status === 1) {
+ setClaiming(false)
+ }
+ },
+ )
+ if (!tx) throw new Error()
+ addTransactionWithType({
+ hash: tx.hash,
+ type: TRANSACTION_TYPE.CLAIM_REWARD,
+ extraInfo: {
+ tokenAddress: KNC[chainId].address,
+ tokenAmount: claimableReward.knc.toString(),
+ tokenSymbol: 'KNC',
+ },
+ })
+ } catch (error) {
+ console.error('Claim error:', { error })
+ notify({
+ title: t`Claim Error`,
+ summary: error.message || 'Unknown error',
+ type: NotificationType.ERROR,
+ })
+ } finally {
+ setClaiming(false)
+ }
+ }, [account, addTransactionWithType, chainId, claimableReward, library, notify])
+
+ return (
+
+
+
+
+
+ Rewards available to claim} placement="top">
+ setSelectedTab(KNCUtilityTabs.Available)}
+ >
+ Available
+
+
+
+ |
+
+ Rewards to claim after the end of the countdown period}
+ placement="top"
+ >
+ setSelectedTab(KNCUtilityTabs.Pending)}
+ >
+ Pending
+
+
+
+ |
+
+ Rewards successfully claimed} placement="top">
+ setSelectedTab(KNCUtilityTabs.Claimed)}
+ >
+ Claimed
+
+
+
+
+ {!!userTier && !!gasRefundPerCentage && (
+
+
+ Tier {userTier} - {gasRefundPerCentage * 100}% Gas Refund
+
+
+ )}
+
+
+
+
+ {account ? formattedNum(reward?.knc.toString() || '0') : '--'} KNC
+
+
+ {account ? (reward?.usd ? '~' : '') + formattedNum(reward?.usd.toString() || '0', true) : '$ --'}
+
+
+
+ {selectedTab === KNCUtilityTabs.Available ? (
+ account ? (
+ isSupportKyberDao(chainId) ? (
+ claiming ? (
+
+
+ Claiming
+
+
+ ) : (
+
+ Claim
+
+ )
+ ) : (
+
+ Gas Refund Rewards is only available on Ethereum chain. Switch your network to continue{' '}
+ here
+
+ }
+ width="244px"
+ >
+
+ Claim
+
+
+ )
+ ) : (
+
+ Connect Wallet
+
+ )
+ ) : selectedTab === KNCUtilityTabs.Pending ? (
+
+
+ Available to claim in{' '}
+
+
+
+ ) : null}
+
+
+
+
+
+
+
+ Total Gas Refund = Available + Pending + Claimed Gas Refund}
+ placement="top"
+ >
+ Total Gas Refund
+
+
+
+
+ {account ? formattedNum(totalReward?.knc.toString() ?? '0') : '--'} KNC
+
+
+ {account
+ ? (totalReward?.usd ? '~' : '') + formattedNum(totalReward?.usd.toString() ?? '0', true)
+ : '$ --'}
+
+
+
+
+ {!!account && !!eligibleTxs?.transactions.length && (
+ setShowEligibleTx(isShowEligibleTx => !isShowEligibleTx)}
+ style={{ whiteSpace: 'nowrap' }}
+ width="max-content"
+ >
+
+ Your Transactions
+
+
+ )}
+
+
+ setShowEligibleTx(false)} />
+
+ )
+}
diff --git a/src/pages/KyberDAO/KNCUtility/Table.tsx b/src/pages/KyberDAO/KNCUtility/Table.tsx
new file mode 100644
index 0000000000..c07dfbedca
--- /dev/null
+++ b/src/pages/KyberDAO/KNCUtility/Table.tsx
@@ -0,0 +1,60 @@
+import { rgba, transparentize } from 'polished'
+import styled from 'styled-components'
+
+export const TableWrapper = styled.div`
+ width: 100%;
+ padding: 20px;
+ ${({ theme }) => theme.mediaWidth.upToExtraSmall`
+ padding: 16px 0;
+ `}
+
+ display: flex;
+ flex-direction: column;
+ background: ${({ theme }) => rgba(theme.buttonGray, 0.8)};
+ border-radius: 20px;
+`
+
+export const Table = styled.div`
+ display: flex;
+ width: 100%;
+ flex-direction: column;
+`
+export const Row = styled.div<{ $background?: string }>`
+ width: 100%;
+ height: 36px;
+ padding: 0 20px;
+ background: unset;
+
+ display: grid;
+ align-items: center;
+ grid-template-columns: 48px 1fr 96px 24px;
+ column-gap: 16px;
+ border-top: 1px solid ${({ theme }) => theme.border};
+
+ ${({ theme }) => theme.mediaWidth.upToExtraSmall`
+ column-gap: 8px;
+ `}
+
+ &[role="button"] {
+ cursor: pointer;
+ }
+`
+
+export const TableHeader = styled(Row)`
+ border-top: none;
+ background: linear-gradient(0deg, #134134 0%, #0f221e 100%);
+ background: linear-gradient(
+ 0deg,
+ ${({ theme }) => transparentize(0.5, theme.primary)} 0%,
+ ${({ theme }) => transparentize(0.8, theme.primary)} 100%
+ );
+`
+export const TableRow = styled(Row)``
+
+export const HeaderCell = styled.span<{ textAlign?: 'left' | 'center' | 'right' }>`
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 36px;
+ color: ${({ theme }) => theme.text};
+ text-align: ${({ textAlign }) => textAlign || 'left'};
+`
diff --git a/src/pages/KyberDAO/KNCUtility/TxTable.tsx b/src/pages/KyberDAO/KNCUtility/TxTable.tsx
new file mode 100644
index 0000000000..759035d652
--- /dev/null
+++ b/src/pages/KyberDAO/KNCUtility/TxTable.tsx
@@ -0,0 +1,66 @@
+import { rgba } from 'polished'
+import styled from 'styled-components'
+
+export const TableWrapper = styled.div`
+ width: 100%;
+ padding: 20px;
+ ${({ theme }) => theme.mediaWidth.upToExtraSmall`
+ padding: 16px 0;
+ `}
+
+ display: flex;
+ flex-direction: column;
+ background: ${({ theme }) => rgba(theme.buttonGray, 0.8)};
+ border-radius: 20px;
+`
+
+export const Table = styled.div`
+ display: flex;
+ width: 100%;
+ flex-direction: column;
+`
+export const Row = styled.div<{ $background?: string }>`
+ width: 100%;
+ height: 46px;
+ padding: 0 20px;
+ background: unset;
+
+ display: grid;
+ align-items: center;
+ grid-template-columns: 2fr 1fr 1fr 1.5fr;
+ column-gap: 16px;
+ border-top: 1px solid ${({ theme }) => theme.border};
+
+ ${({ theme }) => theme.mediaWidth.upToMedium`
+ grid-template-columns: 2fr 1fr 1fr 1fr;
+ column-gap: 8px;
+ `}
+
+ ${({ theme }) => theme.mediaWidth.upToExtraSmall`
+ grid-template-columns: 1fr 1fr;
+ `}
+
+ &[role="button"] {
+ cursor: pointer;
+ }
+`
+
+export const TableHeader = styled(Row)`
+ border-top: none;
+ background-color: ${({ theme }) => theme.background};
+ border-radius: 8px 8px 0px 0px;
+ color: ${({ theme }) => theme.subText};
+`
+export const TableRow = styled(Row)``
+
+export const Cell = styled.span<{ textAlign?: 'left' | 'center' | 'right' }>`
+ font-size: 12px;
+ font-weight: 500;
+ line-height: 16px;
+ text-align: ${({ textAlign }) => textAlign || 'left'};
+`
+export const HeaderCell = styled(Cell)``
+
+export const RowCell = styled(Cell)`
+ color: ${({ theme }) => theme.text};
+`
diff --git a/src/pages/KyberDAO/KNCUtility/index.tsx b/src/pages/KyberDAO/KNCUtility/index.tsx
new file mode 100644
index 0000000000..1deb13ff50
--- /dev/null
+++ b/src/pages/KyberDAO/KNCUtility/index.tsx
@@ -0,0 +1,287 @@
+import { Trans } from '@lingui/macro'
+import { formatUnits } from 'ethers/lib/utils'
+import { NavLink } from 'react-router-dom'
+import { useMedia } from 'react-use'
+import { Flex, Text } from 'rebass'
+import styled from 'styled-components'
+
+import bgimg from 'assets/images/about_background.png'
+import kncDropping from 'assets/images/gas-refund/knc-dropping.png'
+import kncs from 'assets/images/gas-refund/kncs.png'
+import ringwaveGif from 'assets/images/gas-refund/ringwave.gif'
+import ringwave from 'assets/images/gas-refund/ringwave.png'
+import crystals from 'assets/svg/crystals.svg'
+import { ButtonLight } from 'components/Button'
+import Column from 'components/Column'
+import { RowBetween } from 'components/Row'
+import { APP_PATHS } from 'constants/index'
+import { useActiveWeb3React } from 'hooks'
+import { useStakingInfo } from 'hooks/kyberdao'
+import useTheme from 'hooks/useTheme'
+import { ExternalLink, MEDIA_WIDTHS } from 'theme'
+
+import KNCLogo from '../kncLogo'
+import FAQ from './FAQ'
+import GasRefundBox from './GasRefundBox'
+import { HeaderCell, Table, TableHeader, TableRow } from './Table'
+
+const Wrapper = styled.div`
+ width: 100%;
+ background-image: url(${bgimg});
+ background-size: 100% auto;
+ background-repeat: repeat-y;
+ z-index: 1;
+ background-color: transparent;
+ background-position: top;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ padding: 24px 48px;
+ ${({ theme }) => theme.mediaWidth.upToMedium`
+ padding: 16px;
+ `}
+`
+
+const Container = styled.div`
+ max-width: 1224px;
+`
+
+const Row = styled.div`
+ width: 100%;
+ margin: auto;
+ display: flex;
+ justify-content: space-between;
+ gap: 48px;
+ padding: 24px 0;
+ align-items: flex-start;
+
+ ${({ theme }) => theme.mediaWidth.upToMedium`
+ width: 100%;
+ flex-direction: column;
+ align-items: center;
+ gap: 48px;
+ `}
+
+ & > * {
+ flex: 1 1 0px;
+ max-width: 588px;
+ ${({ theme }) => theme.mediaWidth.upToMedium`
+ max-width: 700px;
+ `}
+ width: 100%;
+ }
+`
+
+// todo: will add again, dont remove this
+// const EndedTag = styled.div`
+// padding: 2px 12px;
+// width: fit-content;
+// border-radius: 12px;
+// background: ${({ theme }) => transparentize(0.8, theme.red)};
+// color: ${({ theme }) => theme.red};
+// font-size: 12px;
+// font-weight: 500;
+// `
+
+const FormWrapper = styled.div`
+ background-color: ${({ theme }) => theme.background};
+ border-radius: 20px;
+ padding: 16px;
+ width: 100%;
+`
+
+const YourStakedKNC = styled(FormWrapper)`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 8px;
+ border: 1px solid ${({ theme }) => theme.primary};
+`
+
+export default function KNCUtility() {
+ const { account } = useActiveWeb3React()
+ const theme = useTheme()
+ const { stakedBalance } = useStakingInfo()
+ const upToMedium = useMedia(`(max-width: ${MEDIA_WIDTHS.upToMedium}px)`)
+
+ return (
+
+
+
+
+
+ KNC Utility
+
+
+
+
+ Your Staked KNC
+
+
+ {account ? formatUnits(stakedBalance) : '--'} KNC
+
+
+
+
+
+
+ Stake here ↗
+
+
+
+
+
+
+
+ Stake your KNC (Kyber Network Crystal) tokens to vote on KIP proposals, plus enjoy multiple benefits
+ such as saving on gas fees, earning rewards, and more.
+
+
+
+
+
+
+ {
+ currentTarget.onerror = null // prevents looping
+ currentTarget.src = ringwave
+ }}
+ />
+
+
+
+
+
+ Gas Refund Program
+
+ {/*
+
+ Ended
+
+ */}
+
+ {upToMedium ||
}
+
+
+
+
+ {upToMedium || }
+
+
+
+ How to participate
+
+
+
+ To participate in KyberSwap's Gas Refund Program, you must first stake KNC and then meet the
+ necessary trading requirements:
+
+
+
+
+ Step 1 - Stake KNC on KyberDAO
+
+ Step 2 - Trade on KyberSwap
+
+
+
+
+
+
+ Value of each trade (calculated at the point of the trade) on KyberSwap has to be ≥ $200
+
+
+
+
+
+ Trades only on Ethereum chain are applicable
+
+
+
+
+
+ The amount of the gas refunded will depend on your tier displayed below. Read more{' '}
+
+ here ↗
+
+
+
+
+
+
+
+
+ Tier
+
+
+ KNC Staked
+
+
+ Gas Refund
+
+
+
+ Tier 1
+ 500 KNC
+ 10%
+
+
+ Tier 2
+ 5,000 KNC
+ 15%
+
+
+ Tier 3
+ 10,000 KNC
+ 20%
+
+
+
+
+
+
+
+ FAQ
+
+
+
+
+
+ {upToMedium ? null : (
+
+
+
+ )}
+
+
+
+ )
+}
diff --git a/src/pages/KyberDAO/KNCUtility/type.ts b/src/pages/KyberDAO/KNCUtility/type.ts
new file mode 100644
index 0000000000..236c4ce5f2
--- /dev/null
+++ b/src/pages/KyberDAO/KNCUtility/type.ts
@@ -0,0 +1,5 @@
+export enum KNCUtilityTabs {
+ Available = 'claimable',
+ Pending = 'pending',
+ Claimed = 'claimed',
+}
diff --git a/src/pages/KyberDAO/StakeKNC/index.tsx b/src/pages/KyberDAO/StakeKNC/index.tsx
index 5227ddaa60..7fdaf3e892 100644
--- a/src/pages/KyberDAO/StakeKNC/index.tsx
+++ b/src/pages/KyberDAO/StakeKNC/index.tsx
@@ -4,7 +4,7 @@ import { isMobile } from 'react-device-detect'
import Skeleton from 'react-loading-skeleton'
import { NavLink, useNavigate } from 'react-router-dom'
import { Text } from 'rebass'
-import styled from 'styled-components'
+import styled, { css } from 'styled-components'
import bgimg from 'assets/images/about_background.png'
import governancePNG from 'assets/images/kyberdao/governance.png'
@@ -13,11 +13,15 @@ import kyberCrystal from 'assets/images/kyberdao/kyber_crystal.png'
import kyberdaoPNG from 'assets/images/kyberdao/kyberdao.png'
import migratePNG from 'assets/images/kyberdao/migrate.png'
import stakevotePNG from 'assets/images/kyberdao/stake_vote.png'
+import GasRefundTier1 from 'assets/svg/refund1.svg'
+import GasRefundTier2 from 'assets/svg/refund2.svg'
+import GasRefundTier3 from 'assets/svg/refund3.svg'
import { ButtonLight, ButtonPrimary } from 'components/Button'
import Divider from 'components/Divider'
import Row, { RowBetween, RowFit } from 'components/Row'
+import { MouseoverTooltip } from 'components/Tooltip'
import { APP_PATHS } from 'constants/index'
-import { useStakingInfo } from 'hooks/kyberdao'
+import { useGasRefundTier, useStakingInfo } from 'hooks/kyberdao'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import useTheme from 'hooks/useTheme'
import { ApplicationModal } from 'state/application/actions'
@@ -75,18 +79,25 @@ const CardGroup = styled.div`
width: 772px;
order: 3;
- ${({ theme }) => theme.mediaWidth.upToExtraSmall`
+ ${({ theme }) => theme.mediaWidth.upToSmall`
width: 100vw;
padding: 0 16px;
`}
`
-const Card = styled.div`
+const Card = styled.div<{ background?: string }>`
display: flex;
border: 1px solid ${({ theme }) => theme.border};
border-radius: 20px;
gap: 12px;
width: 100%;
padding: 24px 16px;
+ backdrop-filter: blur(25px);
+ ${({ background }) =>
+ background &&
+ css`
+ background: ${background};
+ `}
+ backdrop-filter: blur(25px);
`
const Image = styled.img`
height: 44px;
@@ -121,6 +132,7 @@ export default function StakeKNC() {
})
}
const kncPrice = useKNCPrice()
+ const { userTier, gasRefundPerCentage } = useGasRefundTier()
return (
@@ -219,6 +231,38 @@ export default function StakeKNC() {
Migrate
+
+
+
+
+ KNC Utility
+
+
+
+
+ Discover more staking KNC utility and benefits{' '}
+ here ↗
+
+
+
+
+
+ Tier {userTier} - You are eligible for{' '}
+ {gasRefundPerCentage * 100}% gas refund .
+
+ }
+ >
+ {userTier === 1 ? (
+
+ ) : userTier === 2 ? (
+
+ ) : userTier === 3 ? (
+
+ ) : null}
+
+
@@ -235,20 +279,6 @@ export default function StakeKNC() {
-
-
-
-
- KNC Utility
-
-
- Coming soon
-
-
-
-
- Note: Staking KNC is only available on Ethereum chain
-
diff --git a/src/pages/KyberDAO/TimerCountdown.tsx b/src/pages/KyberDAO/TimerCountdown.tsx
index 4b5ede74a1..b26cd26ab1 100644
--- a/src/pages/KyberDAO/TimerCountdown.tsx
+++ b/src/pages/KyberDAO/TimerCountdown.tsx
@@ -1,59 +1,71 @@
import { transparentize } from 'polished'
import { useEffect, useState } from 'react'
import { Clock } from 'react-feather'
-import { Text } from 'rebass'
+import { SxStyleProp, Text } from 'rebass'
import { useTheme } from 'styled-components'
import { RowFit } from 'components/Row'
-export default function TimerCountdown({ endTime }: { endTime: number }) {
+export default function TimerCountdown({
+ endTime,
+ maxLength = Number.MAX_SAFE_INTEGER,
+ sx,
+}: {
+ endTime: number
+ maxLength?: number
+ sx?: SxStyleProp
+}) {
const theme = useTheme()
- const [timeString, setTimeString] = useState('')
+ const [timeString, setTimeString] = useState('--')
+
useEffect(() => {
- const interval = setInterval(() => {
+ const calculate = () => {
const seconds = endTime - Math.floor(Date.now() / 1000)
if (seconds < 0) return setTimeString('')
if (seconds < 60) return setTimeString(Math.floor(seconds) + 's')
+
const levels = [
[Math.floor(seconds / 31536000), 'years'],
[Math.floor((seconds % 31536000) / 86400), ' days'],
- [Math.floor(((seconds % 31536000) % 86400) / 3600), 'h'],
- [Math.floor((((seconds % 31536000) % 86400) % 3600) / 60), 'm'],
- [seconds - Math.floor(seconds / 60) * 60, 's'],
+ [Math.floor((seconds % 86400) / 3600), 'h'],
+ [Math.floor((seconds % 3600) / 60), 'm'],
+ [seconds % 60, 's'],
]
- let returntext = ''
- let hideZero = true
- for (let i = 0, max = levels.length; i < max; i++) {
+ const texts: string[] = []
+ let hideZero = true // hide leading zero, e.g: 0 days 0h 10min -> 10min
+ for (let i = 0, count = 0; i < levels.length && count < maxLength; i++) {
if (levels[i][0] === 0 && hideZero) {
continue
} else {
hideZero = false
}
- returntext += ' ' + levels[i][0] + levels[i][1]
+ count++
+ texts.push(String(levels[i][0]) + levels[i][1])
}
- setTimeString(returntext.trim())
- }, 1000)
+ setTimeString(texts.join(' '))
+ }
+ calculate()
+ const intervalId = setInterval(calculate, 1000)
return () => {
- clearInterval(interval)
+ clearInterval(intervalId)
}
- }, [endTime])
+ }, [endTime, maxLength])
return (
- <>
-
- {' '}
-
- {timeString || '--'}
-
-
- >
+
+ {' '}
+
+ {timeString}
+
+
)
}
diff --git a/src/theme/color.ts b/src/theme/color.ts
new file mode 100644
index 0000000000..b742e55b7c
--- /dev/null
+++ b/src/theme/color.ts
@@ -0,0 +1,109 @@
+const white = '#FFFFFF'
+const black = '#000000'
+
+export function colors(darkMode: boolean) {
+ return {
+ // base
+ white,
+ black,
+
+ // text
+ text: darkMode ? '#ffffff' : '#222222',
+ darkText: '#222222',
+ textReverse: darkMode ? '#222222' : '#ffffff',
+ subText: darkMode ? '#A9A9A9' : '#5E5E5E',
+ disableText: darkMode ? '#373737' : '#B6B6B6',
+
+ // backgrounds
+ background: darkMode ? '#1C1C1C' : '#ffffff',
+ background2: darkMode ? '#1C1C1C' : '#f5f5f5',
+ tabActive: darkMode ? '#313131' : '#ffffff',
+ tabBackground: darkMode ? '#0F0F0F' : '#E2E2E2',
+
+ tableHeader: darkMode ? '#313131' : '#FBFBFB',
+ buttonBlack: darkMode ? '#0F0F0F' : '#f5f5f5',
+ buttonGray: darkMode ? '#292929' : '#E2E2E2',
+
+ text2: darkMode ? '#C3C5CB' : '#565A69',
+ text3: darkMode ? '#6C7284' : '#888D9B',
+ text4: darkMode ? '#565A69' : '#C3C5CB',
+ text6: darkMode ? '#6d8591' : '#565A69',
+ text7: darkMode ? '#c9d2d7' : '#565A69',
+ text9: darkMode ? '#859aa5' : '#859aa5',
+ text10: darkMode ? '#00a2f7' : '#00a2f7',
+ text11: darkMode ? '#f4f4f4' : '#565A69',
+ text13: darkMode ? '#f5f5f5' : '#333333',
+ text15: darkMode ? '#3b3b3b' : '#8A8A8A',
+ text16: darkMode ? '#D8D8D8' : '#212121',
+
+ // backgrounds
+ bg1: darkMode ? '#212429' : '#FFFFFF',
+ bg2: darkMode ? '#222c31' : '#F7F8FA',
+ bg3: darkMode ? '#40444F' : '#dcdbdc',
+ bg3Opacity4: darkMode ? '#40444F69' : '#69dcdbdc69',
+ bg4: darkMode ? '#565A69' : '#CED0D9',
+ bg5: darkMode ? '#6C7284' : '#888D9B',
+ bg7: darkMode ? '#31CB9E' : '#98e5ce',
+ bg8: darkMode ? '#1d7a5f' : '#31CB9E',
+ bg9: darkMode ? '#1d2a32' : '#ecebeb',
+ bg10: darkMode ? '#263239' : '#f5f5f5',
+ bg11: darkMode ? '#1b2226' : '#ebeaea',
+ bg13: darkMode ? '#1f292e' : '#e8e9ed',
+ bg14: darkMode ? '#40505a' : '#a9a9a9',
+ bg15: darkMode ? '#1f292e' : '#f5f5f5',
+ bg16: darkMode ? '#1f292e' : '#ffffff',
+ bg17: darkMode ? '#31cb9e33' : '#31cb9e1a',
+ bg18: darkMode ? '#1a4052' : '#ecebeb',
+ bg19: darkMode ? '#222c31' : '#ffffff',
+ bg20: darkMode ? '#243036' : '#F5F5F5',
+ bg21: darkMode
+ ? 'linear-gradient(90deg, rgba(29, 122, 95, 0.5) 0%, rgba(29, 122, 95, 0) 100%)'
+ : 'linear-gradient(90deg, rgba(49, 203, 158, 0.15) 0%, rgba(49, 203, 158, 0) 100%)', // success
+ bg22: darkMode
+ ? 'linear-gradient(90deg, rgba(255, 83, 123, 0.4) 0%, rgba(255, 83, 123, 0) 100%)'
+ : 'linear-gradient(90deg, rgba(255, 83, 123, 0.15) 0%, rgba(255, 83, 123, 0) 100%)', // error
+ bg23: darkMode
+ ? 'linear-gradient(90deg, rgba(255, 153, 1, 0.5) 0%, rgba(255, 153, 1, 0) 100%)'
+ : 'linear-gradient(90deg, rgba(255, 153, 1, 0.5) 0%, rgba(255, 153, 1, 0) 100%)', // warning
+ radialGradient: darkMode ? 'radial-gradient(#095143, #06291d)' : 'radial-gradient(#DAEBE6, #DAF1EC)',
+
+ //specialty colors
+ modalBG: darkMode ? 'rgba(0,0,0,.425)' : 'rgba(0,0,0,0.3)',
+ advancedBG: darkMode ? '#1d272b' : '#ecebeb',
+ advancedBorder: darkMode ? '#303e46' : '#dcdbdc',
+
+ //primary colors
+ primary: '#31CB9E',
+ primary30: darkMode ? '#1D4D3D' : '#C7E9DC',
+
+ // border colors
+ border: darkMode ? '#505050' : '#C1C1C1',
+ btnOutline: darkMode ? '#31cb9e' : '#333333',
+
+ // table colors
+ oddRow: darkMode ? '#283339' : '#ffffff',
+ evenRow: darkMode ? '#303e46' : '#f4f4f4',
+
+ // other
+ red: darkMode ? '#FF537B' : '#FF6871',
+ warning: '#FF9901',
+ apr: '#0faaa2',
+ lightGreen: '#98E5CE',
+ darkerGreen: '#1D7A5F',
+ red1: '#FF6871',
+ red2: '#F82D3A',
+ red3: '#D60000',
+ darkGreen: '#1D7A5F',
+ green: '#31CB9E',
+ green1: '#27AE60',
+ yellow1: '#FFE270',
+ yellow2: '#F3841E',
+ blue1: '#31cb9e',
+ lightBlue: '#78d5ff',
+ darkBlue: '#1183b7',
+ blue: darkMode ? '#08A1E7' : '#31cb9e',
+ shadow: darkMode ? 'rgba(0, 0, 0, 0.2)' : 'rgba(0, 0, 0, 0.04)',
+ } as const
+}
+
+export type Colors = ReturnType
diff --git a/src/theme/components.tsx b/src/theme/components.tsx
index 8055f6ad90..1b8bcb7af9 100644
--- a/src/theme/components.tsx
+++ b/src/theme/components.tsx
@@ -87,7 +87,9 @@ export const LinkStyledButton = styled.button<{ disabled?: boolean }>`
cursor: ${({ disabled }) => (disabled ? 'default' : 'pointer')};
color: ${({ theme, disabled }) => (disabled ? theme.text2 : theme.primary)};
- font-weight: 500;
+ font-weight: inherit;
+ font-size: inherit;
+ padding: 0;
:hover {
text-decoration: ${({ disabled }) => (disabled ? null : 'underline')};
diff --git a/src/theme/index.tsx b/src/theme/index.tsx
index 66af6f5b1f..8df6296c1f 100644
--- a/src/theme/index.tsx
+++ b/src/theme/index.tsx
@@ -10,7 +10,7 @@ import styled, {
import { useIsDarkMode } from 'state/user/hooks'
-import { Colors } from './styled'
+import { Colors, colors } from './color'
export * from './components'
@@ -35,114 +35,6 @@ const mediaWidthTemplates: { [width in keyof typeof MEDIA_WIDTHS]: typeof css }
return accumulator
}, {} as { [width in keyof typeof MEDIA_WIDTHS]: typeof css })
-const white = '#FFFFFF'
-const black = '#000000'
-
-function colors(darkMode: boolean): Colors {
- return {
- // base
- white,
- black,
-
- // text
- text: darkMode ? '#ffffff' : '#222222',
- darkText: '#222222',
- textReverse: darkMode ? '#222222' : '#ffffff',
- subText: darkMode ? '#A9A9A9' : '#5E5E5E',
- disableText: darkMode ? '#373737' : '#B6B6B6',
-
- // backgrounds
- background: darkMode ? '#1C1C1C' : '#ffffff',
- background2: darkMode ? '#1C1C1C' : '#f5f5f5',
- tabActive: darkMode ? '#313131' : '#ffffff',
- tabBackground: darkMode ? '#0F0F0F' : '#E2E2E2',
-
- tableHeader: darkMode ? '#313131' : '#FBFBFB',
- buttonBlack: darkMode ? '#0F0F0F' : '#f5f5f5',
- buttonGray: darkMode ? '#292929' : '#E2E2E2',
-
- text2: darkMode ? '#C3C5CB' : '#565A69',
- text3: darkMode ? '#6C7284' : '#888D9B',
- text4: darkMode ? '#565A69' : '#C3C5CB',
- text6: darkMode ? '#6d8591' : '#565A69',
- text7: darkMode ? '#c9d2d7' : '#565A69',
- text9: darkMode ? '#859aa5' : '#859aa5',
- text10: darkMode ? '#00a2f7' : '#00a2f7',
- text11: darkMode ? '#f4f4f4' : '#565A69',
- text13: darkMode ? '#f5f5f5' : '#333333',
- text15: darkMode ? '#3b3b3b' : '#8A8A8A',
- text16: darkMode ? '#D8D8D8' : '#212121',
-
- // backgrounds
- bg1: darkMode ? '#212429' : '#FFFFFF',
- bg2: darkMode ? '#222c31' : '#F7F8FA',
- bg3: darkMode ? '#40444F' : '#dcdbdc',
- bg3Opacity4: darkMode ? '#40444F69' : '#69dcdbdc69',
- bg4: darkMode ? '#565A69' : '#CED0D9',
- bg5: darkMode ? '#6C7284' : '#888D9B',
- bg7: darkMode ? '#31CB9E' : '#98e5ce',
- bg8: darkMode ? '#1d7a5f' : '#31CB9E',
- bg9: darkMode ? '#1d2a32' : '#ecebeb',
- bg10: darkMode ? '#263239' : '#f5f5f5',
- bg11: darkMode ? '#1b2226' : '#ebeaea',
- bg13: darkMode ? '#1f292e' : '#e8e9ed',
- bg14: darkMode ? '#40505a' : '#a9a9a9',
- bg15: darkMode ? '#1f292e' : '#f5f5f5',
- bg16: darkMode ? '#1f292e' : '#ffffff',
- bg17: darkMode ? '#31cb9e33' : '#31cb9e1a',
- bg18: darkMode ? '#1a4052' : '#ecebeb',
- bg19: darkMode ? '#222c31' : '#ffffff',
- bg20: darkMode ? '#243036' : '#F5F5F5',
- bg21: darkMode
- ? 'linear-gradient(90deg, rgba(29, 122, 95, 0.5) 0%, rgba(29, 122, 95, 0) 100%)'
- : 'linear-gradient(90deg, rgba(49, 203, 158, 0.15) 0%, rgba(49, 203, 158, 0) 100%)', // success
- bg22: darkMode
- ? 'linear-gradient(90deg, rgba(255, 83, 123, 0.4) 0%, rgba(255, 83, 123, 0) 100%)'
- : 'linear-gradient(90deg, rgba(255, 83, 123, 0.15) 0%, rgba(255, 83, 123, 0) 100%)', // error
- bg23: darkMode
- ? 'linear-gradient(90deg, rgba(255, 153, 1, 0.5) 0%, rgba(255, 153, 1, 0) 100%)'
- : 'linear-gradient(90deg, rgba(255, 153, 1, 0.5) 0%, rgba(255, 153, 1, 0) 100%)', // warning
- radialGradient: darkMode ? 'radial-gradient(#095143, #06291d)' : 'radial-gradient(#DAEBE6, #DAF1EC)',
-
- //specialty colors
- modalBG: darkMode ? 'rgba(0,0,0,.425)' : 'rgba(0,0,0,0.3)',
- advancedBG: darkMode ? '#1d272b' : '#ecebeb',
- advancedBorder: darkMode ? '#303e46' : '#dcdbdc',
-
- //primary colors
- primary: '#31CB9E',
- primary30: darkMode ? '#1D4D3D' : '#C7E9DC',
-
- // border colors
- border: darkMode ? '#505050' : '#C1C1C1',
- btnOutline: darkMode ? '#31cb9e' : '#333333',
-
- // table colors
- oddRow: darkMode ? '#283339' : '#ffffff',
- evenRow: darkMode ? '#303e46' : '#f4f4f4',
-
- // other
- red: darkMode ? '#FF537B' : '#FF6871',
- warning: '#FF9901',
- apr: '#0faaa2',
- lightGreen: '#98E5CE',
- darkerGreen: '#1D7A5F',
- red1: '#FF6871',
- red2: '#F82D3A',
- red3: '#D60000',
- darkGreen: '#1D7A5F',
- green: '#31CB9E',
- green1: '#27AE60',
- yellow1: '#FFE270',
- yellow2: '#F3841E',
- blue1: '#31cb9e',
- lightBlue: '#78d5ff',
- darkBlue: '#1183b7',
- blue: darkMode ? '#08A1E7' : '#31cb9e',
- shadow: darkMode ? 'rgba(0, 0, 0, 0.2)' : 'rgba(0, 0, 0, 0.04)',
- }
-}
-
function theme(darkMode: boolean): DefaultTheme {
return {
...colors(darkMode),
diff --git a/src/theme/styled.d.ts b/src/theme/styled.d.ts
index 3cd50824fe..b72002ba88 100644
--- a/src/theme/styled.d.ts
+++ b/src/theme/styled.d.ts
@@ -1,97 +1,8 @@
import { FlattenSimpleInterpolation, ThemedCssFunction } from 'styled-components'
-export type Color = string
-export interface Colors {
- // base
- white: Color
- black: Color
-
- // text
- text: Color
- darkText: Color
- textReverse: Color
- subText: Color
- text2: Color
- text3: Color
- text4: Color
- text6: Color
- text7: Color
- text9: Color
- text10: Color
- text11: Color
- text13: Color
- text15: Color
- text16: Color
- disableText: Color
-
- // backgrounds / greys
- tableHeader: Color
- background: Color
- background2: Color
- tabActive: Color
- tabBackground: Color
- bg1: Color
- bg2: Color
- bg3: Color
- bg3Opacity4: Color
- bg4: Color
- bg5: Color
- bg7: Color
- bg8: Color
- bg9: Color
- bg10: Color
- bg11: Color
- bg13: Color
- bg14: Color
- bg15: Color
- bg16: Color
- bg17: Color
- bg18: Color
- bg19: Color
- bg20: Color
- bg21: Color
- bg22: Color
- bg23: Color
- buttonBlack: Color
- buttonGray: Color
- radialGradient: Color
-
- modalBG: Color
- advancedBG: Color
- advancedBorder: Color
-
- //blues
- primary: Color
- primary30: Color
+import { Colors } from './color'
- // border colors
- border: Color
- btnOutline: Color
-
- // table colors
- oddRow: Color
- evenRow: Color
-
- // other
- red: Color
- red1: Color
- red2: Color
- red3: Color
- green: Color
- darkGreen: Color
- green1: Color
- yellow1: Color
- yellow2: Color
- blue1: Color
- warning: Color
- lightBlue: Color
- darkBlue: Color
- blue: Color
- lightGreen: Color
- darkerGreen: Color
- apr: Color
- shadow: Color
-}
+export type Color = string
interface Grids {
sm: number