diff --git a/src/assets/svg/dollar.svg b/src/assets/svg/dollar.svg
index 088d261c8d..55a87b5560 100644
--- a/src/assets/svg/dollar.svg
+++ b/src/assets/svg/dollar.svg
@@ -1,10 +1,12 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/assets/svg/sprite.svg b/src/assets/svg/sprite.svg
index 449d60d81f..1cf67b5582 100644
--- a/src/assets/svg/sprite.svg
+++ b/src/assets/svg/sprite.svg
@@ -3,23 +3,19 @@
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
@@ -30,41 +26,33 @@
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
@@ -76,8 +64,7 @@
+ fill="currentcolor" />
@@ -85,12 +72,23 @@
+
+
+
+
+
+
+
+
+ fill="currentcolor" />
@@ -101,45 +99,36 @@
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
@@ -147,17 +136,8 @@
-
+
@@ -165,41 +145,22 @@
-
+
-
+ stroke="currentcolor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />
+
+ stroke="currentcolor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" />
+ fill="currentcolor" />
@@ -211,8 +172,7 @@
+ fill="#A9A9A9" />
@@ -223,24 +183,18 @@
+ fill="currentcolor" />
+ stroke="#A9A9A9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
+ fill="currentcolor" />
@@ -252,8 +206,7 @@
+ fill="#222222" />
@@ -265,8 +218,7 @@
+ fill="currentcolor" />
@@ -278,8 +230,7 @@
+ fill="currentcolor" />
@@ -291,8 +242,7 @@
+ fill="currentcolor" />
@@ -300,35 +250,26 @@
-
+
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
@@ -355,96 +296,72 @@
-
+ fill="#E84142" />
-
-
+
+ fill="white" />
+ fill="white" />
-
+
-
-
-
-
+
+
+
+
+ fill="white" />
+ fill="white" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
@@ -453,49 +370,39 @@
-
+
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
+ fill="currentcolor" />
@@ -516,4 +423,4 @@
-
+
\ No newline at end of file
diff --git a/src/components/Announcement/Popups/TransactionPopup.tsx b/src/components/Announcement/Popups/TransactionPopup.tsx
index 8ab9e21076..d1c3d5e057 100644
--- a/src/components/Announcement/Popups/TransactionPopup.tsx
+++ b/src/components/Announcement/Popups/TransactionPopup.tsx
@@ -166,6 +166,7 @@ const SUMMARY: { [type in TRANSACTION_TYPE]: SummaryFunction } = {
[TRANSACTION_TYPE.CANCEL_LIMIT_ORDER]: summaryCancelLimitOrder,
[TRANSACTION_TYPE.TRANSFER_TOKEN]: summaryTransferToken,
+ [TRANSACTION_TYPE.KYBERDAO_CLAIM_GAS_REFUND]: summary1Token, //todo namgold
[TRANSACTION_TYPE.KYBERDAO_CLAIM]: summary1Token,
[TRANSACTION_TYPE.KYBERDAO_UNDELEGATE]: summaryDelegateDao,
[TRANSACTION_TYPE.KYBERDAO_MIGRATE]: summary2Token,
diff --git a/src/components/Header/groups/KyberDaoGroup.tsx b/src/components/Header/groups/KyberDaoGroup.tsx
index 38165fe4db..11efd6414c 100644
--- a/src/components/Header/groups/KyberDaoGroup.tsx
+++ b/src/components/Header/groups/KyberDaoGroup.tsx
@@ -45,7 +45,14 @@ const KyberDAONavGroup = () => {
Vote
-
+ {
+ mixpanelHandler(MIXPANEL_TYPE.GAS_REFUND_SOURCE_CLICK, { source: 'KyberDAO_tab' })
+ }}
+ >
KNC Utility
diff --git a/src/components/Icons/Icon.tsx b/src/components/Icons/Icon.tsx
index 43e126e02b..08c51f9056 100644
--- a/src/components/Icons/Icon.tsx
+++ b/src/components/Icons/Icon.tsx
@@ -1,21 +1,24 @@
import React from 'react'
import sprite from 'assets/svg/sprite.svg'
+import { ICON_ID } from 'constants/index'
export default function Icon({
id,
size,
style,
+ color,
...rest
}: {
- id: string
+ id: ICON_ID
size?: number | string
+ color?: string
style?: React.CSSProperties
title?: string
}) {
return (
-
diff --git a/src/components/SwapForm/TradeSummary.tsx b/src/components/SwapForm/TradeSummary.tsx
index 034410a078..47bf50ce49 100644
--- a/src/components/SwapForm/TradeSummary.tsx
+++ b/src/components/SwapForm/TradeSummary.tsx
@@ -285,7 +285,12 @@ const TradeSummary: React.FC = ({ routeSummary, slippage }) => {
-
+ {
+ mixpanelHandler(MIXPANEL_TYPE.GAS_REFUND_SOURCE_CLICK, { source: 'Swap_page_more_info' })
+ }}
+ >
{account ? gasRefundPerCentage * 100 : '--'}% Refund
diff --git a/src/components/WalletPopup/AccountInfo/ActionButtonGroup.tsx b/src/components/WalletPopup/AccountInfo/ActionButtonGroup.tsx
index 8ab430229b..e14573d6b3 100644
--- a/src/components/WalletPopup/AccountInfo/ActionButtonGroup.tsx
+++ b/src/components/WalletPopup/AccountInfo/ActionButtonGroup.tsx
@@ -6,6 +6,7 @@ import { ReactComponent as DollarIcon } from 'assets/svg/dollar.svg'
import { ButtonLight } from 'components/Button'
import SendIcon from 'components/Icons/SendIcon'
import { ClickHandlerProps } from 'components/WalletPopup/AccountInfo'
+import useTheme from 'hooks/useTheme'
const ActionButton = styled(ButtonLight)`
flex: 0 1 105px;
@@ -17,6 +18,7 @@ type Props = {
className?: string
} & ClickHandlerProps
const ActionButtonGroup: React.FC = ({ onClickBuy, onClickReceive, onClickSend, className, disabledSend }) => {
+ const theme = useTheme()
return (
= ({ onClickBuy, onClickReceive, onClic
}}
>
-
+
Buy
diff --git a/src/components/WalletPopup/AccountInfo/MinimalActionButtonGroup.tsx b/src/components/WalletPopup/AccountInfo/MinimalActionButtonGroup.tsx
index fcda480fd8..3d275ef7b3 100644
--- a/src/components/WalletPopup/AccountInfo/MinimalActionButtonGroup.tsx
+++ b/src/components/WalletPopup/AccountInfo/MinimalActionButtonGroup.tsx
@@ -5,6 +5,7 @@ import { ReactComponent as DollarIcon } from 'assets/svg/dollar.svg'
import { ButtonLight } from 'components/Button'
import SendIcon from 'components/Icons/SendIcon'
import { ClickHandlerProps } from 'components/WalletPopup/AccountInfo'
+import useTheme from 'hooks/useTheme'
const MinimalActionButton = styled(ButtonLight)`
flex: 0 0 36px;
@@ -23,6 +24,7 @@ const MinimalActionButtonGroup: React.FC = ({
className,
disabledSend,
}) => {
+ const theme = useTheme()
return (
= ({
}}
>
-
+
diff --git a/src/components/WalletPopup/AccountInfo/Settings.tsx b/src/components/WalletPopup/AccountInfo/Settings.tsx
deleted file mode 100644
index 7c3e230d35..0000000000
--- a/src/components/WalletPopup/AccountInfo/Settings.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import { ChainId } from '@kyberswap/ks-sdk-core'
-import { Trans } from '@lingui/macro'
-import { rgba } from 'polished'
-import { BarChart2, LogOut, Settings as SettingsIcon } from 'react-feather'
-import { Text } from 'rebass'
-import styled, { css } from 'styled-components'
-
-import Column from 'components/Column'
-import MenuFlyout from 'components/MenuFlyout'
-import { PROMM_ANALYTICS_URL } from 'constants/index'
-import { useActiveWeb3React } from 'hooks'
-import useDisconnectWallet from 'hooks/web3/useDisconnectWallet'
-import { ExternalLink } from 'theme'
-
-const shareStyleMenuItem = css`
- display: flex;
- align-items: center;
- gap: 4px;
- font-weight: 400;
- cursor: pointer;
- padding: 8px 12px;
- color: ${({ theme }) => theme.text};
- :hover {
- color: ${({ theme }) => theme.primary};
- text-decoration: none;
- background-color: ${({ theme }) => rgba(theme.background, 0.2)};
- }
-`
-
-const MenuItem = styled.div`
- ${shareStyleMenuItem}
-`
-
-const MenuItemLink = styled(ExternalLink)`
- ${shareStyleMenuItem}
-`
-
-const IconWrapper = styled.div`
- display: flex;
- width: 20px;
- height: 20px;
- justify-content: center;
- align-items: center;
-`
-
-const customStyleMenu = { padding: '8px 0px' }
-
-const Settings: React.FC = () => {
- const disconnectWallet = useDisconnectWallet()
- const { chainId, account = '' } = useActiveWeb3React()
-
- return (
-
-
-
- }
- modalWhenMobile={false}
- customStyle={customStyleMenu}
- >
-
- {chainId !== ChainId.SOLANA && (
-
-
- Analytics ↗
-
- )}
-
-
-
- )
-}
-
-export default Settings
diff --git a/src/components/WalletPopup/AccountInfo/index.tsx b/src/components/WalletPopup/AccountInfo/index.tsx
index e36260ef26..380567c1e7 100644
--- a/src/components/WalletPopup/AccountInfo/index.tsx
+++ b/src/components/WalletPopup/AccountInfo/index.tsx
@@ -1,26 +1,26 @@
import { Trans } from '@lingui/macro'
-import { Eye, EyeOff } from 'react-feather'
+import { ChevronRight, Eye, EyeOff, Star } from 'react-feather'
import { Flex, Text } from 'rebass'
-import styled from 'styled-components'
+import styled, { css } from 'styled-components'
-import CopyHelper from 'components/Copy'
import Loader from 'components/Loader'
-import Row from 'components/Row'
import ActionButtonGroup from 'components/WalletPopup/AccountInfo/ActionButtonGroup'
import CardBackground from 'components/WalletPopup/AccountInfo/CardBackground'
import MinimalActionButtonGroup from 'components/WalletPopup/AccountInfo/MinimalActionButtonGroup'
-import Settings from 'components/WalletPopup/AccountInfo/Settings'
-import { SUPPORTED_WALLETS } from 'constants/wallets'
-import { useActiveWeb3React } from 'hooks'
+import { useRewards } from 'hooks/useRewards'
import useTheme from 'hooks/useTheme'
-import { useIsDarkMode } from 'state/user/hooks'
-import { ExternalLinkIcon } from 'theme'
-import { formatNumberWithPrecisionRange, getEtherscanLink, shortenAddress } from 'utils'
+import { formatNumberWithPrecisionRange } from 'utils'
+
+import { View } from '../type'
const ContentWrapper = styled.div`
position: relative;
width: 100%;
- height: 160px;
+`
+
+const RewardWrapper = styled.div`
+ position: relative;
+ width: 100%;
`
const Content = styled.div`
@@ -29,9 +29,10 @@ const Content = styled.div`
width: 100%;
height: 100%;
- padding: 20px;
+ padding: 12px 16px;
display: flex;
+ gap: 4px;
flex-direction: column;
justify-content: space-between;
`
@@ -39,6 +40,7 @@ const Content = styled.div`
const BalanceTitle = styled.span`
font-size: 12px;
font-weight: 500;
+ line-height: 16px;
color: ${({ theme }) => theme.subText};
`
@@ -68,32 +70,25 @@ const Wrapper = styled.div.attrs(props => ({
display: none;
}
- &[data-minimal='true'] {
- ${MinimalActionButtonGroup} {
- display: flex;
- align-self: flex-end;
- }
- ${ActionButtonGroup} {
- display: none;
- }
- ${ContentWrapper} {
- height: 120px;
- }
- ${Content} {
- padding: 12px;
- }
- ${BalanceValue} {
- font-size: 20px;
- }
- }
-`
-
-const IconWrapper = styled.div`
- display: flex;
- width: 20px;
- height: 20px;
- justify-content: center;
- align-items: center;
+ ${({ $minimal }) =>
+ $minimal &&
+ css`
+ & {
+ ${MinimalActionButtonGroup} {
+ display: flex;
+ align-self: flex-end;
+ }
+ ${ActionButtonGroup} {
+ display: none;
+ }
+ ${Content} {
+ padding: 12px;
+ }
+ ${BalanceValue} {
+ font-size: 20px;
+ }
+ }
+ `}
`
type Props = {
@@ -101,6 +96,7 @@ type Props = {
isMinimal: boolean
toggleShowBalance: () => void
showBalance: boolean
+ setView: React.Dispatch>
} & ClickHandlerProps
export type ClickHandlerProps = {
@@ -119,37 +115,18 @@ export default function AccountInfo({
isMinimal,
showBalance,
toggleShowBalance,
+ setView,
}: Props) {
- const { chainId, account = '', walletKey } = useActiveWeb3React()
const theme = useTheme()
- const isDarkMode = useIsDarkMode()
+ const {
+ totalReward: { usd },
+ } = useRewards()
return (
-
-
- {walletKey && (
-
-
-
- )}
-
- {shortenAddress(chainId, account, 5, false)}
-
-
-
-
-
-
-
-
-
+
Total Balance
{showBalance ? : }
-
+
{typeof totalBalanceInUsd === 'number' ? (
@@ -193,7 +170,31 @@ export default function AccountInfo({
-
+
+
+
+
+
+
+
+
+ Total Available Rewards
+
+
+ setView(View.REWARD_CENTER)}
+ >
+
+ ${formatNumberWithPrecisionRange(usd, 0, 8)}
+
+
+
+
+
+
+
Your Wallet Address
-
+
theme.subText};
+`
+
+const Wrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 100%;
+ gap: 16px;
+ overflow-y: scroll;
+`
+
+const Content = styled.div`
+ position: relative;
+ z-index: 2;
+
+ width: 100%;
+ height: 100%;
+ padding: 12px 16px;
+
+ display: flex;
+ gap: 4px;
+ flex-direction: column;
+ justify-content: space-between;
+`
+const BalanceValue = styled.span`
+ font-size: 36px;
+ font-weight: 500;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+`
+
+const RewardWrapper = styled.div`
+ display: flex;
+ border-radius: 44px;
+ background-color: ${({ theme }) => theme.background};
+ width: 100%;
+ padding: 6px 12px;
+ align-items: center;
+ gap: 4px;
+`
+
+const TABS = [
+ {
+ title: t`Voting Rewards`,
+ value: REWARD_TYPE.VOTING_REWARDS,
+ },
+ {
+ title: t`Gas Refund`,
+ value: REWARD_TYPE.GAS_REFUND,
+ },
+] as { title: string; value: REWARD_TYPE }[]
+
+export default function RewardCenter() {
+ const { mixpanelHandler } = useMixpanel()
+ const theme = useTheme()
+ const [activeTab, setActiveTab] = useState(REWARD_TYPE.VOTING_REWARDS)
+ const { rewards, totalReward } = useRewards()
+ const currentReward = rewards[activeTab]
+
+ const [claiming, setClaiming] = useState(false)
+ const claimRewards = useCallback(async () => {
+ try {
+ setClaiming(true)
+ mixpanelHandler(MIXPANEL_TYPE.GAS_REFUND_CLAIM_CLICK, { source: 'wallet UI', token_amount: currentReward.knc })
+ await currentReward.claim()
+ } finally {
+ setClaiming(false)
+ }
+ }, [currentReward, mixpanelHandler])
+
+ return (
+
+
+
+
+
+
+
+
+ Total Available Rewards
+
+
+
+ {formatNumberWithPrecisionRange(totalReward.knc, 0, 8)} KNC
+
+ {totalReward.usd ? `~ $${formatNumberWithPrecisionRange(totalReward.usd, 0, 8)}` : '$ --'}
+
+
+
+
+
+ activeTab={activeTab} setActiveTab={setActiveTab} tabs={TABS} />
+
+
+ Your Reward
+
+
+
+
+
+ {currentReward.knc} KNC
+
+
+
+
+ Claim
+
+
+
+
+
+ )
+}
diff --git a/src/components/WalletPopup/Transactions/Icon.tsx b/src/components/WalletPopup/Transactions/Icon.tsx
index 254ee76d69..f018e038b6 100644
--- a/src/components/WalletPopup/Transactions/Icon.tsx
+++ b/src/components/WalletPopup/Transactions/Icon.tsx
@@ -1,5 +1,6 @@
import { ReactNode } from 'react'
import { Repeat } from 'react-feather'
+import { DefaultTheme } from 'styled-components'
import { ReactComponent as ApproveIcon } from 'assets/svg/approve_icon.svg'
import { ReactComponent as BridgeIcon } from 'assets/svg/bridge_icon.svg'
@@ -8,9 +9,11 @@ import { ReactComponent as LiquidityIcon } from 'assets/svg/liquidity_icon.svg'
import { ReactComponent as ThunderIcon } from 'assets/svg/thunder_icon.svg'
import { MoneyBag } from 'components/Icons'
import IconFailure from 'components/Icons/Failed'
+import IconSprite from 'components/Icons/Icon'
import SendIcon from 'components/Icons/SendIcon'
import StakeIcon from 'components/Icons/Stake'
import VoteIcon from 'components/Icons/Vote'
+import useTheme from 'hooks/useTheme'
import { TRANSACTION_GROUP, TRANSACTION_TYPE, TransactionDetails } from 'state/transactions/type'
const MAP_ICON_BY_GROUP: { [group in TRANSACTION_GROUP]: ReactNode } = {
@@ -20,7 +23,10 @@ const MAP_ICON_BY_GROUP: { [group in TRANSACTION_GROUP]: ReactNode } = {
[TRANSACTION_GROUP.OTHER]: null,
}
-const MAP_ICON_BY_TYPE: Partial> = {
+const MAP_ICON_BY_TYPE: (theme: DefaultTheme) => Partial> = (
+ theme: DefaultTheme,
+) => ({
+ [TRANSACTION_TYPE.KYBERDAO_CLAIM_GAS_REFUND]: , //todo namgold: test this
[TRANSACTION_TYPE.CANCEL_LIMIT_ORDER]: ,
[TRANSACTION_TYPE.BRIDGE]: ,
[TRANSACTION_TYPE.CROSS_CHAIN_SWAP]: ,
@@ -30,10 +36,11 @@ const MAP_ICON_BY_TYPE: Partial> = {
[TRANSACTION_TYPE.KYBERDAO_STAKE]: ,
[TRANSACTION_TYPE.KYBERDAO_MIGRATE]: ,
[TRANSACTION_TYPE.KYBERDAO_UNSTAKE]: ,
-}
+})
const Icon = ({ txs }: { txs: TransactionDetails }) => {
- const icon = MAP_ICON_BY_TYPE[txs.type] || MAP_ICON_BY_GROUP[txs.group] ||
+ const theme = useTheme()
+ const icon = MAP_ICON_BY_TYPE(theme)[txs.type] || MAP_ICON_BY_GROUP[txs.group] ||
return icon as JSX.Element
}
export default Icon
diff --git a/src/components/WalletPopup/Transactions/Tab.tsx b/src/components/WalletPopup/Transactions/Tab.tsx
index 15548e492e..265795e721 100644
--- a/src/components/WalletPopup/Transactions/Tab.tsx
+++ b/src/components/WalletPopup/Transactions/Tab.tsx
@@ -1,12 +1,7 @@
-import { ChainId } from '@kyberswap/ks-sdk-core'
-import { t } from '@lingui/macro'
-import { memo, useLayoutEffect, useMemo, useRef, useState } from 'react'
+import { useCallback, useLayoutEffect, useState } from 'react'
import styled, { css } from 'styled-components'
import Row from 'components/Row'
-import { useActiveWeb3React } from 'hooks'
-import { isSupportKyberDao } from 'hooks/kyberdao'
-import { TRANSACTION_GROUP } from 'state/transactions/type'
const ListTab = styled.div`
display: flex;
@@ -31,7 +26,7 @@ const TabWrapper = styled(Row).attrs(props => ({
position: relative;
width: 100%;
- background-color: ${({ theme }) => theme.background};
+ background-color: ${({ theme }) => theme.buttonBlack};
border-radius: 20px;
justify-content: center;
@@ -93,13 +88,8 @@ const TabWrapper = styled(Row).attrs(props => ({
}
`
-const tabActiveCSS = css`
- border-radius: 20px;
- color: ${({ theme }) => theme.text};
- background-color: ${({ theme }) => (theme.darkMode ? theme.tabActive : theme.buttonGray)};
-`
-
const TabItem = styled.div<{ active: boolean }>`
+ width: 100%;
padding: 6px;
font-weight: 500;
font-size: 12px;
@@ -108,92 +98,67 @@ const TabItem = styled.div<{ active: boolean }>`
cursor: pointer;
user-select: none;
color: ${({ theme }) => theme.subText};
+ border-radius: 20px;
:hover {
- ${tabActiveCSS}
+ color: ${({ theme }) => theme.text};
+ background-color: ${({ theme }) => theme.tabActive};
}
- ${({ active }) => (active ? tabActiveCSS : '')}
+ ${({ active }) =>
+ active
+ ? css`
+ color: ${({ theme }) => theme.text};
+ background-color: ${({ theme }) => theme.border} !important;
+ `
+ : null}
`
-const listTab = [
- { text: t`All`, value: '' },
- { text: t`Swaps`, value: TRANSACTION_GROUP.SWAP },
- { text: t`Liquidity`, value: TRANSACTION_GROUP.LIQUIDITY },
- { text: t`KyberDAO`, value: TRANSACTION_GROUP.KYBERDAO },
- { text: t`Others`, value: TRANSACTION_GROUP.OTHER },
-] as const
-
-type Props = {
- activeTab: string
- setActiveTab: React.Dispatch>
+
+interface TabProps {
+ activeTab: T
+ setActiveTab: React.Dispatch>
+ tabs: readonly { readonly title: string; readonly value: T }[]
}
-const Tab: React.FC = ({ activeTab, setActiveTab }) => {
+function Tab({ activeTab, setActiveTab, tabs }: TabProps) {
const [isScrollable, setScrollable] = useState(false)
const [scrollLeft, setScrollLeft] = useState(false)
const [scrollRight, setScrollRight] = useState(false)
- const { chainId } = useActiveWeb3React()
-
- const listRef = useRef(null)
-
- const handleScroll = () => {
- const node = listRef.current
- if (!node) {
- return
- }
+ const [listRef, setListRef] = useState(null)
- const { clientWidth, scrollWidth, scrollLeft } = node
+ const handleScroll = useCallback(() => {
+ if (!listRef) return
+ const { clientWidth, scrollWidth, scrollLeft } = listRef
setScrollable(clientWidth < scrollWidth)
setScrollLeft(scrollLeft > 0)
setScrollRight(scrollLeft < scrollWidth - clientWidth)
- }
+ }, [listRef])
useLayoutEffect(() => {
- const { ResizeObserver } = window
- const node = listRef.current
- if (!node) {
- return
- }
-
+ if (!listRef) return
const resizeHandler = () => {
- const { clientWidth, scrollWidth, scrollLeft } = node
+ const { clientWidth, scrollWidth, scrollLeft } = listRef
setScrollable(clientWidth < scrollWidth)
setScrollLeft(scrollLeft > 0)
setScrollRight(scrollLeft < scrollWidth - clientWidth)
}
+ const { ResizeObserver } = window
if (typeof ResizeObserver === 'function') {
const resizeObserver = new ResizeObserver(resizeHandler)
- resizeObserver.observe(node)
+ resizeObserver.observe(listRef)
return () => resizeObserver.disconnect()
} else {
window.addEventListener('resize', resizeHandler)
return () => window.removeEventListener('resize', resizeHandler)
}
- }, [])
-
- const filterTab = useMemo(() => {
- return listTab.filter(tab => {
- if (tab.value === TRANSACTION_GROUP.KYBERDAO) {
- return isSupportKyberDao(chainId)
- }
- if (tab.value === TRANSACTION_GROUP.LIQUIDITY) {
- return chainId !== ChainId.SOLANA
- }
- return true
- })
- }, [chainId])
+ }, [listRef])
return (
-
- {filterTab.map(tab => (
- setActiveTab(tab.value)}
- >
- {tab.text}
+ setListRef(listRef)} onScroll={handleScroll}>
+ {tabs.map(tab => (
+ setActiveTab(tab.value)}>
+ {tab.title}
))}
@@ -201,4 +166,4 @@ const Tab: React.FC = ({ activeTab, setActiveTab }) => {
)
}
-export default memo(Tab)
+export default Tab
diff --git a/src/components/WalletPopup/Transactions/TransactionItem.tsx b/src/components/WalletPopup/Transactions/TransactionItem.tsx
index e2045d2e0f..c955375de8 100644
--- a/src/components/WalletPopup/Transactions/TransactionItem.tsx
+++ b/src/components/WalletPopup/Transactions/TransactionItem.tsx
@@ -70,7 +70,7 @@ const Description1Token = (transaction: TransactionDetails) => {
const { extraInfo = {}, type } = transaction
const { tokenSymbol, tokenAmount, tokenAddress } = extraInfo as TransactionExtraInfo1Token
// +10KNC or -10KNC
- const plus = [TRANSACTION_TYPE.KYBERDAO_CLAIM].includes(type)
+ const plus = [TRANSACTION_TYPE.KYBERDAO_CLAIM, TRANSACTION_TYPE.KYBERDAO_CLAIM_GAS_REFUND].includes(type)
return
}
@@ -342,13 +342,14 @@ const DESCRIPTION_MAP: {
[TRANSACTION_TYPE.ELASTIC_DEPOSIT_LIQUIDITY]: DescriptionStakeFarm,
[TRANSACTION_TYPE.ELASTIC_WITHDRAW_LIQUIDITY]: DescriptionStakeFarm,
- [TRANSACTION_TYPE.KYBERDAO_CLAIM]: Description1Token,
-
[TRANSACTION_TYPE.APPROVE]: DescriptionApproveClaim,
[TRANSACTION_TYPE.CLAIM_REWARD]: DescriptionApproveClaim,
[TRANSACTION_TYPE.KYBERDAO_STAKE]: DescriptionKyberDaoStake,
[TRANSACTION_TYPE.KYBERDAO_UNSTAKE]: DescriptionKyberDaoStake,
+ [TRANSACTION_TYPE.KYBERDAO_CLAIM]: Description1Token,
+ [TRANSACTION_TYPE.KYBERDAO_CLAIM_GAS_REFUND]: Description1Token, //todo namgold: test this
+
[TRANSACTION_TYPE.TRANSFER_TOKEN]: Description1Token,
[TRANSACTION_TYPE.UNWRAP_TOKEN]: Description2Token,
diff --git a/src/components/WalletPopup/Transactions/index.tsx b/src/components/WalletPopup/Transactions/index.tsx
index 223892b72f..cc38ea1e58 100644
--- a/src/components/WalletPopup/Transactions/index.tsx
+++ b/src/components/WalletPopup/Transactions/index.tsx
@@ -1,4 +1,5 @@
-import { Trans } from '@lingui/macro'
+import { ChainId } from '@kyberswap/ks-sdk-core'
+import { Trans, t } from '@lingui/macro'
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Info } from 'react-feather'
import AutoSizer from 'react-virtualized-auto-sizer'
@@ -11,6 +12,7 @@ import { NUMBERS } from 'components/WalletPopup/Transactions/helper'
import useCancellingOrders, { CancellingOrderInfo } from 'components/swapv2/LimitOrder/useCancellingOrders'
import { useActiveWeb3React } from 'hooks'
import { fetchListTokenByAddresses, findCacheToken, useIsLoadedTokenDefault } from 'hooks/Tokens'
+import { isSupportKyberDao } from 'hooks/kyberdao'
import useTheme from 'hooks/useTheme'
import { useSortRecentTransactions } from 'state/transactions/hooks'
import {
@@ -103,6 +105,13 @@ function RowItem({
/>
)
}
+const listTab = [
+ { title: t`All`, value: '' },
+ { title: t`Swaps`, value: TRANSACTION_GROUP.SWAP },
+ { title: t`Liquidity`, value: TRANSACTION_GROUP.LIQUIDITY },
+ { title: t`KyberDAO`, value: TRANSACTION_GROUP.KYBERDAO },
+ { title: t`Others`, value: TRANSACTION_GROUP.OTHER },
+] as const
// This is intentional, we don't need to persist in localStorage
let storedActiveTab = ''
@@ -165,9 +174,21 @@ function ListTransaction({ isMinimal }: { isMinimal: boolean }) {
storedActiveTab = activeTab
}, [activeTab])
+ const filterTab = useMemo(() => {
+ return listTab.filter(tab => {
+ if (tab.value === TRANSACTION_GROUP.KYBERDAO) {
+ return isSupportKyberDao(chainId)
+ }
+ if (tab.value === TRANSACTION_GROUP.LIQUIDITY) {
+ return chainId !== ChainId.SOLANA
+ }
+ return true
+ })
+ }, [chainId])
+
return (
-
+ activeTab={activeTab} setActiveTab={setActiveTab} tabs={filterTab} />
{formatTransactions.length === 0 ? (
diff --git a/src/components/WalletPopup/WalletView.tsx b/src/components/WalletPopup/WalletView.tsx
index ab82b8aae6..6456c9c52e 100644
--- a/src/components/WalletPopup/WalletView.tsx
+++ b/src/components/WalletPopup/WalletView.tsx
@@ -1,12 +1,13 @@
-import { Trans, t } from '@lingui/macro'
+import { Trans } from '@lingui/macro'
import { rgba } from 'polished'
import { useEffect, useLayoutEffect, useRef, useState } from 'react'
-import { ChevronLeft, FileText, StopCircle, X } from 'react-feather'
+import { ChevronLeft, FileText, LogOut, StopCircle, X } from 'react-feather'
import { useNavigate } from 'react-router-dom'
import { Flex, Text } from 'rebass'
import styled from 'styled-components'
import { ReactComponent as DragHandleIcon } from 'assets/svg/wallet_drag_handle.svg'
+import CopyHelper from 'components/Copy'
import SendIcon from 'components/Icons/SendIcon'
import Row from 'components/Row'
import AccountInfo from 'components/WalletPopup/AccountInfo'
@@ -14,15 +15,40 @@ import MyAssets from 'components/WalletPopup/MyAssets'
import PinButton from 'components/WalletPopup/PinButton'
import SendToken from 'components/WalletPopup/SendToken'
import { APP_PATHS } from 'constants/index'
+import { SUPPORTED_WALLETS } from 'constants/wallets'
+import { useActiveWeb3React } from 'hooks'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import useTheme from 'hooks/useTheme'
+import useDisconnectWallet from 'hooks/web3/useDisconnectWallet'
+import { useIsDarkMode } from 'state/user/hooks'
import { useTokensHasBalance } from 'state/wallet/hooks'
+import { ExternalLinkIcon } from 'theme'
+import { getEtherscanLink, shortenAddress } from 'utils'
import ReceiveToken from './ReceiveToken'
+import RewardCenter from './RewardCenter'
import ListTransaction from './Transactions'
+import { View } from './type'
export const HANDLE_CLASS_NAME = 'walletPopupDragHandle'
+const IconWrapper = styled.div`
+ display: flex;
+ width: 20px;
+ height: 20px;
+ justify-content: center;
+ align-items: center;
+`
+
+const LogOutIcon = styled(LogOut)`
+ cursor: pointer;
+ color: ${({ theme }) => theme.subText};
+ :hover {
+ opacity: 0.8;
+ text-decoration: none;
+ }
+`
+
type WrapperProps = { $pinned: boolean; $blur: boolean }
const Wrapper = styled.div.attrs(props => ({
'data-pinned': props.$pinned,
@@ -76,13 +102,6 @@ const ContentWrapper = styled.div`
gap: 14px;
`
-const View = {
- ASSETS: t`Assets`,
- SEND_TOKEN: t`Send`,
- RECEIVE_TOKEN: t`Receive`,
- TRANSACTIONS: t`Transactions`,
-} as const
-
type Props = {
onDismiss: () => void
onPin?: () => void
@@ -110,6 +129,9 @@ export default function WalletView({
const navigate = useNavigate()
const nodeRef = useRef(null)
const [isMinimal, setMinimal] = useState(false)
+ const { chainId, account = '', walletKey } = useActiveWeb3React()
+ const isDarkMode = useIsDarkMode()
+ const disconnectWallet = useDisconnectWallet()
const {
loading: loadingTokens,
@@ -167,6 +189,7 @@ export default function WalletView({
onClickSend={handleClickSend}
isMinimal={isMinimal}
disabledSend={!currencies.length}
+ setView={setView}
/>
)
}
@@ -200,12 +223,15 @@ export default function WalletView({
return
case View.RECEIVE_TOKEN:
return
+ case View.REWARD_CENTER:
+ return
}
return null
}
const isSendTab = view === View.SEND_TOKEN
- const isExchangeTokenTab = isSendTab || view === View.RECEIVE_TOKEN
+ const isShowArrow = isSendTab || view === View.RECEIVE_TOKEN
+ const isShowBack = isShowArrow || view === View.REWARD_CENTER
useLayoutEffect(() => {
// handle minimal mode when width & height become small
@@ -286,17 +312,34 @@ export default function WalletView({
justifyContent: 'space-between',
}}
>
- {isExchangeTokenTab ? (
+ {isShowBack ? (
<>
setView(View.ASSETS)} color={theme.subText} />
- {view}
+ {isShowArrow && (
+
+ )}{' '}
+ {view}
>
) : (
-
- Your Account
-
+
+ {walletKey && (
+
+
+
+ )}
+
+ {shortenAddress(chainId, account, 5, false)}
+
+
+
+
+
)}
{onPin && onUnpin && }
diff --git a/src/components/WalletPopup/index.tsx b/src/components/WalletPopup/index.tsx
index 255819cba1..aa2fef74e8 100644
--- a/src/components/WalletPopup/index.tsx
+++ b/src/components/WalletPopup/index.tsx
@@ -125,11 +125,10 @@ const WalletPopup: React.FC = ({ isModalOpen, onDismissModal, isPinned, s
zIndex: isPinned ? Z_INDEXS.WALLET_POPUP : Z_INDEXS.MODAL + 1,
cursor: 'auto',
transition: 'top 150ms, left 150ms',
- top,
- left,
}}
enableResizing={isPinned}
disableDragging={!isPinned}
+ bounds="body"
>
{
- if (!rewardDistributorContract) {
- throw new Error(CONTRACT_NOT_FOUND_MSG)
- }
- try {
- const isValidClaim = await rewardDistributorContract.isValidClaim(
- cycle,
- index,
- address,
- tokens,
- cumulativeAmounts,
- merkleProof,
- )
- if (!isValidClaim) {
- throw new Error('Invalid claim')
- }
- const estimateGas = await rewardDistributorContract.estimateGas.claim(
- cycle,
- index,
- address,
- tokens,
- cumulativeAmounts,
- merkleProof,
- )
- const tx = await rewardDistributorContract.claim(
- cycle,
- index,
- address,
- tokens,
- cumulativeAmounts,
- merkleProof,
- {
- gasLimit: calculateGasMargin(estimateGas),
- },
- )
- addTransactionWithType({
- hash: tx.hash,
- type: TRANSACTION_TYPE.KYBERDAO_CLAIM,
- extraInfo: {
- contract: kyberDaoInfo?.rewardsDistributor,
- tokenAmount: formatAmount,
- tokenSymbol: 'KNC',
- tokenAddress: kyberDaoInfo?.KNCAddress,
- },
- })
- return tx.hash
- } catch (error) {
- if (error?.code === 4001 || error?.code === 'ACTION_REJECTED') {
- throw new Error('Transaction rejected.')
- } else {
- throw error
- }
+ const claimVotingRewards = useCallback(async () => {
+ if (!userRewards || !userRewards.userReward || !account) throw new Error(t`Invalid claim`)
+ const { cycle, userReward } = userRewards
+ const { index, tokens, cumulativeAmounts, proof } = userReward
+ const address = account
+ const merkleProof = proof
+ const formatAmount = formatUnitsToFixed(remainingCumulativeAmount)
+
+ if (!rewardDistributorContract) {
+ throw new Error(CONTRACT_NOT_FOUND_MSG)
+ }
+ try {
+ const isValidClaim = await rewardDistributorContract.isValidClaim(
+ cycle,
+ index,
+ address,
+ tokens,
+ cumulativeAmounts,
+ merkleProof,
+ )
+ if (!isValidClaim) throw new Error(t`Invalid claim`)
+ const estimateGas = await rewardDistributorContract.estimateGas.claim(
+ cycle,
+ index,
+ address,
+ tokens,
+ cumulativeAmounts,
+ merkleProof,
+ )
+ const tx = await rewardDistributorContract.claim(cycle, index, address, tokens, cumulativeAmounts, merkleProof, {
+ gasLimit: calculateGasMargin(estimateGas),
+ })
+ addTransactionWithType({
+ hash: tx.hash,
+ type: TRANSACTION_TYPE.KYBERDAO_CLAIM,
+ extraInfo: {
+ contract: kyberDaoInfo?.rewardsDistributor,
+ tokenAmount: formatAmount,
+ tokenSymbol: 'KNC',
+ tokenAddress: kyberDaoInfo?.KNCAddress,
+ },
+ })
+ return tx.hash as string
+ } catch (error) {
+ if (error?.code === 4001 || error?.code === 'ACTION_REJECTED') {
+ throw new Error('Transaction rejected.')
+ } else {
+ throw error
}
- },
- [rewardDistributorContract, addTransactionWithType, kyberDaoInfo],
- )
- return { claim }
+ }
+ }, [
+ userRewards,
+ account,
+ remainingCumulativeAmount,
+ rewardDistributorContract,
+ addTransactionWithType,
+ kyberDaoInfo?.rewardsDistributor,
+ kyberDaoInfo?.KNCAddress,
+ ])
+ return claimVotingRewards
}
export const useVotingActions = () => {
@@ -426,15 +424,8 @@ export function useVotingInfo() {
if (!userRewards?.userReward?.tokens || !claimedRewardAmounts?.[0]) return BigNumber.from(0)
return (
userRewards?.userReward?.tokens?.map((_: string, index: number) => {
- const cummulativeAmount =
- userRewards.userReward &&
- userRewards.userReward.cumulativeAmounts &&
- userRewards.userReward.cumulativeAmounts[index]
-
- if (!cummulativeAmount) {
- return BigNumber.from(0)
- }
-
+ const cummulativeAmount = userRewards.userReward?.cumulativeAmounts?.[index]
+ if (cummulativeAmount) return BigNumber.from(0)
return BigNumber.from(cummulativeAmount).sub(BigNumber.from(claimedRewardAmounts[0]))
})[0] || BigNumber.from(0)
)
@@ -512,7 +503,7 @@ export function useVotingInfo() {
fetcher(url).then(res => res.rewardStats),
)
- return {
+ const result = {
daoInfo: daoInfo || localStoredDaoInfo || undefined,
userRewards,
calculateVotingPower,
@@ -528,16 +519,7 @@ export function useVotingInfo() {
usd: rewardStats ? +rewardStats.pending?.totalAmountInUSD + +rewardStats.liquidated?.totalAmountInUSD : 0,
},
}
-}
-
-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)
+ return result
}
export function useGasRefundTier(): GasRefundTierInfo {
@@ -600,6 +582,74 @@ export function useGasRefundInfo({ rewardStatus = KNCUtilityTabs.Available }: {
}
}
+export function useClaimGasRefundRewards() {
+ const { account, chainId } = useActiveWeb3React()
+ const { library, connector } = useWeb3React()
+ const addTransactionWithType = useTransactionAdder()
+ const { claimableReward } = useGasRefundInfo({})
+ const notify = useNotify()
+
+ const claimGasRefundRewards = useCallback(async (): Promise => {
+ if (!account || !library || !claimableReward || claimableReward.knc <= 0) throw new Error(t`Invalid claim`)
+
+ 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,
+ })
+ throw error
+ }
+
+ const rewardContractAddress = response.data.data.ContractAddress
+ const encodedData = response.data.data.EncodedData
+ try {
+ const tx = await sendEVMTransaction(account, library, rewardContractAddress, encodedData, BigNumber.from(0))
+ if (!tx) throw new Error()
+ addTransactionWithType({
+ hash: tx.hash,
+ type: TRANSACTION_TYPE.KYBERDAO_CLAIM_GAS_REFUND,
+ extraInfo: {
+ tokenAddress: KNC[chainId].address,
+ tokenAmount: claimableReward.knc.toString(),
+ tokenSymbol: 'KNC',
+ },
+ })
+ return tx.hash as string
+ } catch (error) {
+ if (didUserReject(connector, error)) {
+ notify({
+ title: t`Transaction rejected`,
+ summary: t`In order to claim, you must accept in your wallet.`,
+ type: NotificationType.ERROR,
+ })
+ throw new Error('Transaction rejected.')
+ } else {
+ console.error('Claim error:', { error })
+ notify({
+ title: t`Claim Error`,
+ summary: error.message || 'Unknown error',
+ type: NotificationType.ERROR,
+ })
+ throw error
+ }
+ }
+ }, [account, addTransactionWithType, chainId, claimableReward, library, notify, connector])
+ return claimGasRefundRewards
+}
+
export const useEligibleTransactions = (page = 1, pageSize = 100): EligibleTxsInfo | undefined => {
const { account, chainId } = useActiveWeb3React()
const kyberDaoInfo = useKyberDAOInfo()
diff --git a/src/hooks/useMixpanel.ts b/src/hooks/useMixpanel.ts
index 7e4bca5b85..6f074f504f 100644
--- a/src/hooks/useMixpanel.ts
+++ b/src/hooks/useMixpanel.ts
@@ -174,6 +174,8 @@ export enum MIXPANEL_TYPE {
KYBER_DAO_VOTE_CLICK,
KYBER_DAO_CLAIM_CLICK,
KYBER_DAO_FEATURE_REQUEST_CLICK,
+ GAS_REFUND_CLAIM_CLICK,
+ GAS_REFUND_SOURCE_CLICK,
// notification
NOTIFICATION_CLICK_MENU,
@@ -1067,6 +1069,16 @@ export default function useMixpanel(currencies?: { [field in Field]?: Currency }
mixpanel.track('KyberDAO - Feature Request Click', payload)
break
}
+ case MIXPANEL_TYPE.GAS_REFUND_CLAIM_CLICK: {
+ const { token_amount, source } = payload
+ mixpanel.track('Gas refund - Click claim reward', { token_amount, source })
+ break
+ }
+ case MIXPANEL_TYPE.GAS_REFUND_SOURCE_CLICK: {
+ const { source } = payload
+ mixpanel.track('Gas refund - KNC Utility source click', { source })
+ break
+ }
case MIXPANEL_TYPE.LO_CLICK_PLACE_ORDER: {
mixpanel.track('Limit Order - Place Order Click', payload)
break
@@ -1726,6 +1738,7 @@ export const useGlobalMixpanelEvents = () => {
'cross-chain': 'Cross Chain',
'notification-center': 'Notification',
[APP_PATHS.KYBERAI_ABOUT]: 'KyberAI About',
+ [APP_PATHS.KYBERDAO_KNC_UTILITY]: 'Gas refund - KNC Utility',
}
const protectedPaths: { [key: string]: string } = {
[APP_PATHS.KYBERAI_RANKINGS]: 'KyberAI Rankings',
diff --git a/src/hooks/useRewards.ts b/src/hooks/useRewards.ts
new file mode 100644
index 0000000000..d1314bd0f5
--- /dev/null
+++ b/src/hooks/useRewards.ts
@@ -0,0 +1,44 @@
+import { useMemo } from 'react'
+
+import { REWARD_TYPE } from 'components/WalletPopup/type'
+import { useKNCPrice } from 'state/application/hooks'
+import { aggregateValue } from 'utils/array'
+
+import { useClaimGasRefundRewards, useClaimVotingRewards, useGasRefundInfo, useVotingInfo } from './kyberdao'
+
+export const useRewards = () => {
+ const kncPrice = useKNCPrice()
+ const { claimableReward } = useGasRefundInfo({})
+ const { knc, usd } = claimableReward || {}
+ const { remainingCumulativeAmount } = useVotingInfo()
+
+ const claimGasRefund = useClaimGasRefundRewards()
+ const claimVotingRewards = useClaimVotingRewards()
+
+ const rewards: { [key in REWARD_TYPE]: { knc: number; usd: number; claim: () => Promise } } = useMemo(() => {
+ return {
+ [REWARD_TYPE.GAS_REFUND]: { knc: knc || 0, usd: usd || 0, claim: claimGasRefund },
+ [REWARD_TYPE.VOTING_REWARDS]: {
+ knc: remainingCumulativeAmount.toNumber(),
+ usd: remainingCumulativeAmount.toNumber() * kncPrice,
+ claim: claimVotingRewards,
+ },
+ }
+ }, [knc, kncPrice, remainingCumulativeAmount, usd, claimVotingRewards, claimGasRefund])
+
+ const totalReward = useMemo(() => {
+ const rewardsValues = Object.values(rewards)
+ return {
+ usd: aggregateValue(rewardsValues, 'usd'),
+ knc: aggregateValue(rewardsValues, 'knc'),
+ }
+ }, [rewards])
+
+ return useMemo(
+ () => ({
+ rewards,
+ totalReward,
+ }),
+ [rewards, totalReward],
+ )
+}
diff --git a/src/pages/Icons/index.tsx b/src/pages/Icons/index.tsx
index f30b54b9a9..110b3d11d5 100644
--- a/src/pages/Icons/index.tsx
+++ b/src/pages/Icons/index.tsx
@@ -1,6 +1,7 @@
import styled from 'styled-components'
import sprite from 'assets/svg/sprite.svg'
+import { ICON_IDS } from 'constants/index'
const Wrapper = styled.div`
display: flex;
@@ -32,36 +33,11 @@ const IconWrapper = styled.div`
flex: 1;
}
`
-const iconIds = [
- 'truesight-v2',
- 'notification-2',
- 'bullish',
- 'bearish',
- 'trending-soon',
- 'flame',
- 'download',
- 'upload',
- 'coin-bag',
- 'speaker',
- 'share',
- 'swap',
- 'copy',
- 'open-link',
- 'star',
- 'fullscreen',
- 'leaderboard',
- 'liquid',
- 'alarm',
- 'on-chain',
- 'technical-analysis',
- 'news',
- 'arrow',
-]
export default function Icons() {
return (
- {iconIds.map((id: string) => (
+ {ICON_IDS.map(id => (
diff --git a/src/pages/KyberDAO/KNCUtility/GasRefundBox.tsx b/src/pages/KyberDAO/KNCUtility/GasRefundBox.tsx
index 60c820484a..5c123a6f4c 100644
--- a/src/pages/KyberDAO/KNCUtility/GasRefundBox.tsx
+++ b/src/pages/KyberDAO/KNCUtility/GasRefundBox.tsx
@@ -1,34 +1,28 @@
-import { Trans, t } from '@lingui/macro'
-import axios from 'axios'
-import { BigNumber } from 'ethers'
+import { Trans } from '@lingui/macro'
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 { useActiveWeb3React } from 'hooks'
import {
isSupportKyberDao,
+ useClaimGasRefundRewards,
useEligibleTransactions,
useGasRefundInfo,
useGasRefundTier,
useVotingInfo,
} from 'hooks/kyberdao'
+import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
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 { useOpenNetworkModal, useWalletModalToggle } from 'state/application/hooks'
import { LinkStyledButton, MEDIA_WIDTHS } from 'theme'
import { formattedNum } from 'utils'
-import { sendEVMTransaction } from 'utils/sendTransaction'
import TimerCountdown from '../TimerCountdown'
import EligibleTxModal from './EligibleTxModal'
@@ -77,87 +71,35 @@ const Tab = styled(Text)<{ active?: boolean }>`
`
export default function GasRefundBox() {
+ const { mixpanelHandler } = useMixpanel()
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
+ const claimReward = useClaimGasRefundRewards()
+ const [claiming, setClaiming] = useState(false)
+ const handleClaimReward = useCallback(async () => {
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,
+ setClaiming(true)
+ mixpanelHandler(MIXPANEL_TYPE.GAS_REFUND_CLAIM_CLICK, {
+ source: 'KNC Utility page',
+ token_amount: claimableReward?.knc,
})
+ await claimReward()
} finally {
setClaiming(false)
}
- }, [account, addTransactionWithType, chainId, claimableReward, library, notify])
+ }, [claimReward, claimableReward?.knc, mixpanelHandler])
return (
@@ -228,7 +170,11 @@ export default function GasRefundBox() {
account ? (
isSupportKyberDao(chainId) ? (
claiming ? (
-
+
Claiming
@@ -236,7 +182,7 @@ export default function GasRefundBox() {
) : (
Claim
diff --git a/src/pages/KyberDAO/StakeKNC/index.tsx b/src/pages/KyberDAO/StakeKNC/index.tsx
index 7fdaf3e892..9ad3efce8a 100644
--- a/src/pages/KyberDAO/StakeKNC/index.tsx
+++ b/src/pages/KyberDAO/StakeKNC/index.tsx
@@ -241,7 +241,14 @@ export default function StakeKNC() {
Discover more staking KNC utility and benefits{' '}
- here ↗
+ {
+ mixpanelHandler(MIXPANEL_TYPE.GAS_REFUND_SOURCE_CLICK, { source: 'StakeKNC_page_KNC_utility' })
+ }}
+ >
+ here ↗
+
@@ -250,7 +257,17 @@ export default function StakeKNC() {
text={
Tier {userTier} - You are eligible for{' '}
- {gasRefundPerCentage * 100}% gas refund.
+ {
+ mixpanelHandler(MIXPANEL_TYPE.GAS_REFUND_SOURCE_CLICK, {
+ source: 'StakeKNC_page_KNC_utility_tier',
+ })
+ }}
+ >
+ {gasRefundPerCentage * 100}% gas refund
+
+ .
}
>
diff --git a/src/pages/KyberDAO/Vote/index.tsx b/src/pages/KyberDAO/Vote/index.tsx
index 2c99b87af2..f6138f0101 100644
--- a/src/pages/KyberDAO/Vote/index.tsx
+++ b/src/pages/KyberDAO/Vote/index.tsx
@@ -15,7 +15,7 @@ import { AutoRow, RowBetween, RowFit } from 'components/Row'
import { MouseoverTooltip } from 'components/Tooltip'
import TransactionConfirmationModal, { TransactionErrorContent } from 'components/TransactionConfirmationModal'
import { useActiveWeb3React } from 'hooks'
-import { useClaimRewardActions, useVotingActions, useVotingInfo } from 'hooks/kyberdao'
+import { useClaimVotingRewards, useVotingActions, useVotingInfo } from 'hooks/kyberdao'
import useMixpanel, { MIXPANEL_TYPE } from 'hooks/useMixpanel'
import useTheme from 'hooks/useTheme'
import { ApplicationModal } from 'state/application/actions'
@@ -119,7 +119,6 @@ export default function Vote() {
daoInfo,
remainingCumulativeAmount,
claimedRewardAmount,
- userRewards,
stakerInfo,
stakerInfoNextEpoch,
rewardStats: { knc, usd },
@@ -127,7 +126,7 @@ export default function Vote() {
const kncPrice = useKNCPrice()
- const { claim } = useClaimRewardActions()
+ const claimVotingRewards = useClaimVotingRewards()
const { vote } = useVotingActions()
const { switchToEthereum } = useSwitchToEthereum()
@@ -175,34 +174,21 @@ export default function Vote() {
}, [toggleClaimConfirmModal, mixpanelHandler, switchToEthereum])
const handleConfirmClaim = useCallback(async () => {
- if (!userRewards || !userRewards.userReward || !account) return
- const { cycle, userReward } = userRewards
- const { index, tokens, cumulativeAmounts, proof } = userReward
setPendingText(t`Claming ${formatUnitsToFixed(remainingCumulativeAmount)} KNC`)
setShowConfirm(true)
setAttemptingTxn(true)
toggleClaimConfirmModal()
- const params = {
- cycle,
- index,
- address: account,
- tokens,
- cumulativeAmounts,
- merkleProof: proof,
- formatAmount: formatUnitsToFixed(remainingCumulativeAmount),
+ try {
+ const tx = await claimVotingRewards()
+ setTxHash(tx)
+ } catch (error) {
+ setTransactionError(error?.message)
+ setTxHash(undefined)
+ } finally {
+ setAttemptingTxn(false)
}
- claim(params)
- .then(tx => {
- setAttemptingTxn(false)
- setTxHash(tx)
- })
- .catch(error => {
- setTransactionError(error?.message)
- setAttemptingTxn(false)
- setTxHash(undefined)
- })
- }, [userRewards, account, claim, remainingCumulativeAmount, toggleClaimConfirmModal])
+ }, [claimVotingRewards, remainingCumulativeAmount, toggleClaimConfirmModal])
const handleVote = useCallback(
async (proposal_id: number, option: number) => {
diff --git a/src/pages/TrueSightV2/components/MultipleChainDropdown.tsx b/src/pages/TrueSightV2/components/MultipleChainDropdown.tsx
index e7f7b3d1e1..4f42cc20c0 100644
--- a/src/pages/TrueSightV2/components/MultipleChainDropdown.tsx
+++ b/src/pages/TrueSightV2/components/MultipleChainDropdown.tsx
@@ -7,6 +7,7 @@ import Column from 'components/Column'
import Icon from 'components/Icons/Icon'
import Modal from 'components/Modal'
import Row, { RowFit } from 'components/Row'
+import { ICON_ID } from 'constants/index'
import useTheme from 'hooks/useTheme'
import SimpleTooltip from './SimpleTooltip'
@@ -46,7 +47,7 @@ const StyledMobileChainIcon = styled.div`
gap: 6px;
padding: 10px 8px;
`
-const ChainIcon = ({ id, name, onClick }: { id: string; name: string; onClick: () => void }) => {
+const ChainIcon = ({ id, name, onClick }: { id: ICON_ID; name: string; onClick: () => void }) => {
return (
@@ -56,7 +57,7 @@ const ChainIcon = ({ id, name, onClick }: { id: string; name: string; onClick: (
)
}
-const MobileChainIcon = ({ id, name, onClick }: { id: string; name: string; onClick: () => void }) => {
+const MobileChainIcon = ({ id, name, onClick }: { id: ICON_ID; name: string; onClick: () => void }) => {
const theme = useTheme()
return (
diff --git a/src/pages/TrueSightV2/pages/SingleToken.tsx b/src/pages/TrueSightV2/pages/SingleToken.tsx
index 03ce90efa1..29de65834e 100644
--- a/src/pages/TrueSightV2/pages/SingleToken.tsx
+++ b/src/pages/TrueSightV2/pages/SingleToken.tsx
@@ -582,8 +582,8 @@ export default function SingleToken() {
ReactNode
title: string
}[] = [
diff --git a/src/state/transactions/type.ts b/src/state/transactions/type.ts
index 234363df98..be0dc920f6 100644
--- a/src/state/transactions/type.ts
+++ b/src/state/transactions/type.ts
@@ -151,6 +151,7 @@ export enum TRANSACTION_TYPE {
KYBERDAO_MIGRATE = 'KyberDAO Migrate',
KYBERDAO_VOTE = 'KyberDAO Vote',
KYBERDAO_CLAIM = 'KyberDAO Claim Voting Reward',
+ KYBERDAO_CLAIM_GAS_REFUND = 'Gas Refund',
CANCEL_LIMIT_ORDER = 'Cancel Limit Order',
TRANSFER_TOKEN = 'Send',
@@ -188,6 +189,7 @@ export const GROUP_TRANSACTION_BY_TYPE = {
TRANSACTION_TYPE.KYBERDAO_MIGRATE,
TRANSACTION_TYPE.KYBERDAO_VOTE,
TRANSACTION_TYPE.KYBERDAO_CLAIM,
+ TRANSACTION_TYPE.KYBERDAO_CLAIM_GAS_REFUND,
],
OTHER: [
// to make sure you don't forgot
diff --git a/src/utils/array.ts b/src/utils/array.ts
index ac36e2698c..bdaa63450f 100644
--- a/src/utils/array.ts
+++ b/src/utils/array.ts
@@ -27,3 +27,13 @@ export const uniqueArray = (array: T[], keySelector = (item: T): U => item
})
return result
}
+
+export 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)
+}