diff --git a/README.md b/README.md index dc61672b7..6c72e390e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ Open Source Token Swap and Pool Liquidity Portal | | City | | --------------- | ------------------------------------------------------------------- | | Jan Langheimer | [Freiburg](https://www.timeanddate.com/worldclock/germany/freiburg) | -| Ran Cohen | [Tel Aviv](https://www.timeanddate.com/worldclock/israel/tel-aviv) | | Doron Z | [Tel Aviv](https://www.timeanddate.com/worldclock/israel/tel-aviv) | ## How to contribute diff --git a/src/components/button/Button.stories.tsx b/src/components/button/Button.stories.tsx index a564ee88f..f878bfd56 100644 --- a/src/components/button/Button.stories.tsx +++ b/src/components/button/Button.stories.tsx @@ -71,7 +71,7 @@ export const Playground: ComponentStory = (args) => ( Playground.args = { children: 'Primary Button', variant: ButtonVariant.Primary, - size: ButtonSize.Meduim, + size: ButtonSize.Medium, disabled: false, className: '', }; diff --git a/src/components/button/Button.tsx b/src/components/button/Button.tsx index 55b0b526f..e0588f1af 100644 --- a/src/components/button/Button.tsx +++ b/src/components/button/Button.tsx @@ -12,7 +12,7 @@ export enum ButtonSize { Full, ExtraLarge, Large, - Meduim, + Medium, Small, ExtraSmall, } @@ -45,7 +45,7 @@ const getSizeStyle = (size: ButtonSize) => { return 'w-[428px] h-[53px]'; case ButtonSize.Large: return 'w-[335px] h-[53px]'; - case ButtonSize.Meduim: + case ButtonSize.Medium: return 'w-[266px] h-[47px]'; case ButtonSize.Small: return 'w-[142px] h-[39px]'; diff --git a/src/elements/earn/portfolio/v3/pendingWithdraw/confirm/V3WithdrawConfirmInfo.tsx b/src/elements/earn/portfolio/v3/pendingWithdraw/confirm/V3WithdrawConfirmInfo.tsx index 9c91a774f..d867b92b3 100644 --- a/src/elements/earn/portfolio/v3/pendingWithdraw/confirm/V3WithdrawConfirmInfo.tsx +++ b/src/elements/earn/portfolio/v3/pendingWithdraw/confirm/V3WithdrawConfirmInfo.tsx @@ -22,7 +22,7 @@ export const V3WithdrawConfirmInfo = ({ handleCancelClick }: Props) => { diff --git a/src/elements/walletConnect/WalletConnectRequest.tsx b/src/elements/walletConnect/WalletConnectRequest.tsx index a5d4085e1..19e06439b 100644 --- a/src/elements/walletConnect/WalletConnectRequest.tsx +++ b/src/elements/walletConnect/WalletConnectRequest.tsx @@ -13,7 +13,7 @@ export const WalletConnectRequest = () => { -
-
{footer}
- - ); -}; - -export const Vote = () => { - const { chainId } = useWeb3React(); - const dispatch = useDispatch(); - const account = useAppSelector((state) => state.user.account); - const tokens = useAppSelector((state) => state.bancor.tokensV2); - const stakeAmount = useAppSelector( - (state) => state.gov.stakedAmount - ); - const unstakeTime = useAppSelector( - (state) => state.gov.unstakeTimer - ); - const [govToken, setGovToken] = useState(); - const [isUnlocked, setIsUnlocked] = useState(false); - const [stakeModal, setStakeModal] = useState(false); - const [isStake, setIsStake] = useState(false); - const { handleWalletButtonClick } = useWalletConnect(); - - useEffect(() => { - const networkVars = getNetworkVariables(); - setGovToken(tokens.find((x) => x.address === networkVars.govToken)); - }, [tokens, chainId]); - - const refresh = useCallback(async () => { - if (account) { - const [unstakeTimer, stakedAmount] = await Promise.all([ - getUnstakeTimer(account), - getStakedAmount(account), - ]); - - dispatch(setUnstakeTimer(unstakeTimer)); - dispatch(setStakedAmount(stakedAmount)); - } else { - dispatch(setUnstakeTimer(undefined)); - dispatch(setStakedAmount(undefined)); - } - }, [account, dispatch]); - - useEffect(() => { - refresh(); - }, [refresh]); - - const title = 'Vote'; - const subtitle = - 'Bancor is a DAO managed by vBNT stakers who determine the future of the protocol with their proposals.'; - const stakedVBNT = Number(stakeAmount) !== 0; - - return ( - - <> -
- { - if (!account) { - handleWalletButtonClick(); - return; - } - - setIsStake(true); - setStakeModal(true); - }} - footer={ -
-
- {!account || (govToken && govToken.balance) ? ( -
- {govToken && govToken.balance - ? `${prettifyNumber(govToken.balance)} ${ - govToken.symbol - }` - : '--'} -
- ) : ( -
- )} -
Unstaked Balance
-
-
- {!account || stakeAmount ? ( -
- {stakeAmount && govToken - ? `${prettifyNumber(stakeAmount)} ${govToken.symbol}` - : '--'} -
- ) : ( -
- )} -
Staked Balance
-
-
- } - /> - { - openNewTab('https://vote.bancor.network/'); - }} - footer={ -
- - How to Vote - -
- } - /> - -
-
-
- Unstake from Governance -
- -
- In order to remove vBNT from governance you would need to - unstake them first. -
-
- - {unstakeTime && !isUnlocked && ( -
- Unstake available in - setIsUnlocked(true)} - /> -
- )} -
-
-
-
-
- Legacy onchain contract -
- -
- View previous votes and decisions made onchain. -
- - - View Legacy Gov - -
-
-
- {govToken && ( - - )} - - - ); -}; diff --git a/src/pages/vote/LegacyVoteCard.tsx b/src/pages/vote/LegacyVoteCard.tsx new file mode 100644 index 000000000..f1c418884 --- /dev/null +++ b/src/pages/vote/LegacyVoteCard.tsx @@ -0,0 +1,32 @@ +import { ReactComponent as IconLink } from 'assets/icons/link.svg'; + +export interface LegacyVoteCardProps { + className?: string; +} + +export const LegacyVoteCard: React.FC = ({ + className, +}) => { + return ( +
+
+ Legacy onchain contract +
+ +
+ View previous votes and decisions made onchain. +
+ + + View Legacy Gov + +
+ ); +}; diff --git a/src/pages/vote/StakedCard.tsx b/src/pages/vote/StakedCard.tsx new file mode 100644 index 000000000..5ab13dd18 --- /dev/null +++ b/src/pages/vote/StakedCard.tsx @@ -0,0 +1,64 @@ +import { Button, ButtonSize, ButtonVariant } from 'components/button/Button'; +import { useWalletConnect } from 'elements/walletConnect/useWalletConnect'; +import { Token } from 'services/observables/tokens'; +import { VoteBalances } from 'pages/vote/VoteBalances'; + +export interface StakeCardProps { + stakeAmount: string | undefined; + symbol: string; + account: string | null | undefined; + govToken: Token | undefined; + setIsStake: (isStake: boolean) => void; + setStakeModal: (isOpen: boolean) => void; + className?: string; +} + +export const StakeCard: React.FC = ({ + stakeAmount, + symbol, + account, + govToken, + setIsStake, + setStakeModal, + className, +}) => { + const { handleWalletButtonClick } = useWalletConnect(); + return ( +
+
+
+ Stake {symbol} +
+ +
+ Participate in Bancor Governance activities by staking {symbol}. +
+
+ +
+
+ +
+ ); +}; diff --git a/src/pages/vote/UnstakedCard.tsx b/src/pages/vote/UnstakedCard.tsx new file mode 100644 index 000000000..ca65ff024 --- /dev/null +++ b/src/pages/vote/UnstakedCard.tsx @@ -0,0 +1,69 @@ +import { Button, ButtonSize, ButtonVariant } from 'components/button/Button'; +import { CountdownTimer } from 'components/countdownTimer/CountdownTimer'; + +export interface UnstakeCardProps { + stakeAmount: string | undefined; + symbol: string; + unstakeTime: number | undefined; + isUnlocked: boolean; + setIsStake: (isStake: boolean) => void; + setStakeModal: (isOpen: boolean) => void; + setIsUnlocked: (isUnlocked: boolean) => void; + className?: string; +} + +export const UnstakeCard: React.FC = ({ + stakeAmount, + symbol, + unstakeTime, + isUnlocked, + setIsStake, + setStakeModal, + setIsUnlocked, + className, +}) => { + return ( +
+
+ Unstake {symbol} +
+ +
+ In order to remove {symbol} from governance you would need to unstake + them first. +
+
+ +
+
+ ); +}; diff --git a/src/pages/vote/Vote.tsx b/src/pages/vote/Vote.tsx new file mode 100644 index 000000000..42da6ce42 --- /dev/null +++ b/src/pages/vote/Vote.tsx @@ -0,0 +1,164 @@ +import { useWeb3React } from '@web3-react/core'; +import { ModalVbnt } from 'elements/modalVbnt/ModalVbnt'; +import { useCallback, useState } from 'react'; +import { useEffect } from 'react'; +import { useAppSelector } from 'store'; +import { Token } from 'services/observables/tokens'; +import { getNetworkVariables } from 'services/web3/config'; +import { + getStakedAmount, + getUnstakeTimer, +} from 'services/web3/governance/governance'; +import { Page } from 'components/Page'; +import { useDispatch } from 'react-redux'; +import { + setStakedVbntAmount, + setUnstakeVbntTimer, + setStakedBntAmount, + setUnstakeBntTimer, +} from 'store/gov/gov'; +import { VoteCardDivided } from 'pages/vote/VoteCardDivided'; +import { UnstakeCard } from 'pages/vote/UnstakedCard'; +import { StakeCard } from 'pages/vote/StakedCard'; +import { VoteCard } from 'pages/vote/VoteCard'; +import { LegacyVoteCard } from './LegacyVoteCard'; + +export const Vote = () => { + const { chainId } = useWeb3React(); + const dispatch = useDispatch(); + const account = useAppSelector((state) => state.user.account); + const tokens = useAppSelector((state) => state.bancor.tokensV2); + const stakeVbntAmount = useAppSelector( + (state) => state.gov.stakedVbntAmount + ); + const unstakeVbntTime = useAppSelector( + (state) => state.gov.unstakeVbntTimer + ); + const stakeBntAmount = useAppSelector( + (state) => state.gov.stakedBntAmount + ); + const unstakeBntTime = useAppSelector( + (state) => state.gov.unstakeBntTimer + ); + const [vbntToken, setVbntToken] = useState(); + const [bntToken, setBntToken] = useState(); + const [isVbntUnlocked, setIsVbntUnlocked] = useState(false); + const [isBntUnlocked, setIsBntUnlocked] = useState(false); + const [stakeVbntModal, setStakeVbntModal] = useState(false); + const [stakeBntModal, setStakeBntModal] = useState(false); + const [isVbntStake, setIsVbntStake] = useState(false); + const [isBntStake, setIsBntStake] = useState(false); + + useEffect(() => { + const networkVars = getNetworkVariables(); + setVbntToken(tokens.find((x) => x.address === networkVars.govToken)); + setBntToken(tokens.find((x) => x.address === networkVars.bntToken)); + }, [tokens, chainId]); + + const refresh = useCallback(async () => { + if (account) { + const [ + unstakeVbntTimer, + stakedVbntAmount, + unstakeBntTimer, + stakedBntAmount, + ] = await Promise.all([ + getUnstakeTimer(account, false), + getStakedAmount(account, false), + getUnstakeTimer(account, true), + getStakedAmount(account, true), + ]); + + dispatch(setUnstakeVbntTimer(unstakeVbntTimer)); + dispatch(setStakedVbntAmount(stakedVbntAmount)); + dispatch(setUnstakeBntTimer(unstakeBntTimer)); + dispatch(setStakedBntAmount(stakedBntAmount)); + } else { + dispatch(setUnstakeVbntTimer(undefined)); + dispatch(setStakedVbntAmount(undefined)); + dispatch(setUnstakeBntTimer(undefined)); + dispatch(setStakedBntAmount(undefined)); + } + }, [account, dispatch]); + + useEffect(() => { + refresh(); + }, [refresh]); + + return ( + + <> +
+ + + + + + + + + + + + +
+ {vbntToken && ( + + )} + {bntToken && ( + + )} + +
+ ); +}; diff --git a/src/pages/vote/VoteBalances.tsx b/src/pages/vote/VoteBalances.tsx new file mode 100644 index 000000000..b18ff60e3 --- /dev/null +++ b/src/pages/vote/VoteBalances.tsx @@ -0,0 +1,44 @@ +import { Token } from 'services/observables/tokens'; +import { prettifyNumber } from 'utils/helperFunctions'; + +export interface VoteBalancesProps { + govToken: Token | undefined; + account: string | null | undefined; + stakeAmount: string | undefined; +} + +export const VoteBalances: React.FC = ({ + govToken, + account, + stakeAmount, +}) => { + return ( +
+
+
Available Balance
+ {!account || (govToken && govToken.balance) ? ( +
+ {govToken && govToken.balance + ? `${prettifyNumber(govToken.balance)} ${govToken.symbol}` + : '--'} +
+ ) : ( +
+ )} +
+
+
+
Staked Balance
+ {!account || stakeAmount ? ( +
+ {stakeAmount && govToken + ? `${prettifyNumber(stakeAmount)} ${govToken.symbol}` + : '--'} +
+ ) : ( +
+ )} +
+
+ ); +}; diff --git a/src/pages/vote/VoteCard.tsx b/src/pages/vote/VoteCard.tsx new file mode 100644 index 000000000..59dbf06ab --- /dev/null +++ b/src/pages/vote/VoteCard.tsx @@ -0,0 +1,40 @@ +import { Button, ButtonSize, ButtonVariant } from 'components/button/Button'; +import { Navigate } from 'components/navigate/Navigate'; +import { openNewTab } from 'utils/pureFunctions'; +import { ReactComponent as IconLink } from 'assets/icons/link.svg'; + +export interface VoteCardProps { + className?: string; +} + +export const VoteCard: React.FC = ({ className }) => { + return ( +
+
+ Voting on Bancor DAO +
+ +
+ Voting on Bancor DAO is free as it is using the Snapshot off-chain + infrastructure. Every user can vote on every available proposal and help + shape the future of the Bancor Protocol. +
+
+ + + How to Vote + +
+
+ ); +}; diff --git a/src/pages/vote/VoteCardDivided.tsx b/src/pages/vote/VoteCardDivided.tsx new file mode 100644 index 000000000..ba4dd9c22 --- /dev/null +++ b/src/pages/vote/VoteCardDivided.tsx @@ -0,0 +1,40 @@ +import { Children, ReactElement, cloneElement } from 'react'; + +export interface VoteCardDividedProps { + children: ReactElement[]; +} + +export const VoteCardDivided: React.FC = ({ + children, +}) => { + if (Children.count(children) !== 2) { + console.error('VoteCardDivided component expects exactly two children.'); + return null; // Or render a fallback UI + } + + // Extract children to an array for direct access + const childrenArray = Children.toArray(children) as ReactElement[]; + + // Append TailwindCSS classes to the first child's existing classes + const firstChildClasses = childrenArray[0].props.className || ''; + const firstChildWithClasses = cloneElement(childrenArray[0], { + className: `flex-1 lg:h-full lt-lg:w-full p-24 ${firstChildClasses}`.trim(), + }); + + // Append TailwindCSS classes to the second child's existing classes + const secondChildClasses = childrenArray[1].props.className || ''; + const secondChildWithClasses = cloneElement(childrenArray[1], { + className: + `flex-none lg:h-full lg:w-[350px] lt-lg:w-full p-24 ${secondChildClasses}`.trim(), + }); + + return ( +
+ {firstChildWithClasses} + {secondChildWithClasses} +
+ ); +}; diff --git a/src/router/useRoutesMain.tsx b/src/router/useRoutesMain.tsx index 4bc1d7351..2dd1ccd1a 100644 --- a/src/router/useRoutesMain.tsx +++ b/src/router/useRoutesMain.tsx @@ -1,7 +1,7 @@ import { Navigate, RouteObject } from 'react-router-dom'; import { Tokens } from 'pages/Tokens'; import { Fiat } from 'pages/Fiat'; -import { Vote } from 'pages/Vote'; +import { Vote } from 'pages/vote/Vote'; import { TermsOfUse } from 'pages/TermsOfUse'; import { PrivacyPolicy } from 'pages/PrivacyPolicy'; import { NotFound } from 'pages/NotFound'; diff --git a/src/services/notifications/notifications.ts b/src/services/notifications/notifications.ts index 2e6e15ea6..d44a052a1 100644 --- a/src/services/notifications/notifications.ts +++ b/src/services/notifications/notifications.ts @@ -22,19 +22,20 @@ export const rejectNotification = (dispatch: any) => export const stakeNotification = ( dispatch: any, amount: string, - txHash: string + txHash: string, + symbol: string ) => showNotification( { type: NotificationType.pending, title: 'Pending Confirmation', - msg: 'Staking vBNT is pending confirmation', + msg: `Staking ${symbol} is pending confirmation`, txHash, updatedInfo: { successTitle: 'Success!', - successMsg: `Your stake of ${amount} vBNT has been confirmed`, + successMsg: `Your stake of ${amount} ${symbol} has been confirmed`, errorTitle: 'Transaction Failed', - errorMsg: `Staking ${amount} vBNT had failed. Please try again or contact support.`, + errorMsg: `Staking ${amount} ${symbol} had failed. Please try again or contact support.`, }, }, dispatch @@ -43,40 +44,49 @@ export const stakeNotification = ( export const unstakeNotification = ( dispatch: any, amount: string, - txHash: string + txHash: string, + symbol: string ) => showNotification( { type: NotificationType.pending, title: 'Pending Confirmation', - msg: 'Unstaking vBNT is pending confirmation', + msg: `Unstaking ${symbol} is pending confirmation`, txHash, updatedInfo: { successTitle: 'Success!', - successMsg: `Unstaking ${amount} vBNT has been confirmed`, + successMsg: `Unstaking ${amount} ${symbol} has been confirmed`, errorTitle: 'Transaction Failed', - errorMsg: `Unstaking ${amount} vBNT had failed. Please try again or contact support.`, + errorMsg: `Unstaking ${amount} ${symbol} had failed. Please try again or contact support.`, }, }, dispatch ); -export const stakeFailedNotification = (dispatch: any, amount: string) => +export const stakeFailedNotification = ( + dispatch: any, + amount: string, + symbol: string +) => showNotification( { type: NotificationType.error, title: 'Transaction Failed', - msg: `Staking ${amount} vBNT had failed. Please try again or contact support.`, + msg: `Staking ${amount} ${symbol} had failed. Please try again or contact support.`, }, dispatch ); -export const unstakeFailedNotification = (dispatch: any, amount: string) => +export const unstakeFailedNotification = ( + dispatch: any, + amount: string, + symbol: string +) => showNotification( { type: NotificationType.error, title: 'Transaction Failed', - msg: `Staking ${amount} vBNT had failed. Please try again or contact support.`, + msg: `Staking ${amount} ${symbol} had failed. Please try again or contact support.`, }, dispatch ); diff --git a/src/services/observables/gov.ts b/src/services/observables/gov.ts index db997412f..4eaa2270c 100644 --- a/src/services/observables/gov.ts +++ b/src/services/observables/gov.ts @@ -5,16 +5,30 @@ import { getUnstakeTimer, } from 'services/web3/governance/governance'; -export const stakedAmount$ = user$.pipe( +export const stakedVbntAmount$ = user$.pipe( switchMap(async (user) => { - if (user) return await getStakedAmount(user); + if (user) return await getStakedAmount(user, false); }), shareReplay(1) ); -export const unstakeTimer$ = user$.pipe( +export const unstakeVbntTimer$ = user$.pipe( switchMap(async (user) => { - if (user) return await getUnstakeTimer(user); + if (user) return await getUnstakeTimer(user, false); + }), + shareReplay(1) +); + +export const stakedBntAmount$ = user$.pipe( + switchMap(async (user) => { + if (user) return await getStakedAmount(user, true); + }), + shareReplay(1) +); + +export const unstakeBntTimer$ = user$.pipe( + switchMap(async (user) => { + if (user) return await getUnstakeTimer(user, true); }), shareReplay(1) ); diff --git a/src/services/observables/triggers.ts b/src/services/observables/triggers.ts index b05a576ed..de2eafc07 100644 --- a/src/services/observables/triggers.ts +++ b/src/services/observables/triggers.ts @@ -58,8 +58,18 @@ import { } from 'services/observables/tokenLists'; import { allpoolsV3$, poolsV2$, poolsV3$ } from 'services/observables/pools'; import { poolTokens$ } from 'services/observables/poolTokensV1'; -import { setStakedAmount, setUnstakeTimer } from 'store/gov/gov'; -import { stakedAmount$, unstakeTimer$ } from './gov'; +import { + setStakedVbntAmount, + setUnstakeVbntTimer, + setStakedBntAmount, + setUnstakeBntTimer, +} from 'store/gov/gov'; +import { + stakedVbntAmount$, + unstakeVbntTimer$, + stakedBntAmount$, + unstakeBntTimer$, +} from './gov'; import { standardRewardPrograms$ } from 'services/observables/standardRewards'; export const subscribeToObservables = (dispatch: any) => { @@ -163,11 +173,17 @@ export const subscribeToObservables = (dispatch: any) => { dispatch(setProtocolBnBNTAmount(protocolBnBNTAmount)); }); - stakedAmount$.subscribe((stakedAmount) => { - dispatch(setStakedAmount(stakedAmount)); + stakedVbntAmount$.subscribe((stakedAmount) => { + dispatch(setStakedVbntAmount(stakedAmount)); + }); + unstakeVbntTimer$.subscribe((unstakeTimer) => { + dispatch(setUnstakeVbntTimer(unstakeTimer)); + }); + stakedBntAmount$.subscribe((stakedAmount) => { + dispatch(setStakedBntAmount(stakedAmount)); }); - unstakeTimer$.subscribe((unstakeTimer) => { - dispatch(setUnstakeTimer(unstakeTimer)); + unstakeBntTimer$.subscribe((unstakeTimer) => { + dispatch(setUnstakeBntTimer(unstakeTimer)); }); standardRewardPrograms$.subscribe((programs) => { dispatch(setAllStandardRewardsV3(programs)); diff --git a/src/services/web3/approval/index.ts b/src/services/web3/approval/index.ts index 7cc25789c..8f0e19728 100644 --- a/src/services/web3/approval/index.ts +++ b/src/services/web3/approval/index.ts @@ -25,7 +25,8 @@ export enum ApprovalContract { BancorNetworkV3, ExchangeProxy, LiquidityProtection, - Governance, + GovernanceVbnt, + GovernanceBnt, } const getApproval = async ( @@ -144,8 +145,10 @@ const getApprovalAddress = async ( return await exchangeProxy$.pipe(take(1)).toPromise(); case ApprovalContract.LiquidityProtection: return await liquidityProtection$.pipe(take(1)).toPromise(); - case ApprovalContract.Governance: - return getNetworkVariables().governanceContractAddress; + case ApprovalContract.GovernanceVbnt: + return getNetworkVariables().governanceVbntContractAddress; + case ApprovalContract.GovernanceBnt: + return getNetworkVariables().governanceBntContractAddress; } }; diff --git a/src/services/web3/config.ts b/src/services/web3/config.ts index 34f153ff0..8dada1c55 100644 --- a/src/services/web3/config.ts +++ b/src/services/web3/config.ts @@ -8,7 +8,8 @@ export interface EthNetworkVariables { contractRegistry: string; bntToken: string; converterContractForMaths: string; - governanceContractAddress: string; + governanceVbntContractAddress: string; + governanceBntContractAddress: string; etherscanUrl: string; govToken: string; } @@ -41,7 +42,8 @@ export const getNetworkVariables = (): EthNetworkVariables => { bntToken: '0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C', govToken: '0x48Fb253446873234F2fEBbF9BdeAA72d9d387f94', converterContractForMaths: '0xe870d00176b2c71afd4c43cea550228e22be4abd', - governanceContractAddress: '0x892f481bd6e9d7d26ae365211d9b45175d5d00e4', + governanceVbntContractAddress: '0x892f481bd6e9d7d26ae365211d9b45175d5d00e4', + governanceBntContractAddress: '0xebFaFc802533F3D2835Af7464Fcd4492e8F82eB2', etherscanUrl: 'https://etherscan.io', }; }; diff --git a/src/services/web3/governance/governance.ts b/src/services/web3/governance/governance.ts index 1fe92c4b0..0eb8b459b 100644 --- a/src/services/web3/governance/governance.ts +++ b/src/services/web3/governance/governance.ts @@ -4,7 +4,11 @@ import { web3, writeWeb3 } from 'services/web3'; import { ErrorCode } from '../types'; import { Governance__factory } from '../abis/types'; import dayjs from 'utils/dayjs'; -import { getNetworkVariables, vBntDecimals } from 'services/web3/config'; +import { + bntDecimals, + getNetworkVariables, + vBntDecimals, +} from 'services/web3/config'; export const stakeAmount = async ( amount: string, @@ -15,14 +19,15 @@ export const stakeAmount = async ( failed: (error: string) => void ) => { try { - const expandedAmount = expandToken(amount, govToken.decimals); - const networkVars = getNetworkVariables(); - const govContract = Governance__factory.connect( - networkVars.governanceContractAddress, - writeWeb3.signer - ); + const address = + govToken.symbol === 'BNT' + ? networkVars.governanceBntContractAddress + : networkVars.governanceVbntContractAddress; + + const govContract = Governance__factory.connect(address, writeWeb3.signer); + const expandedAmount = expandToken(amount, govToken.decimals); const tx = await govContract.stake(expandedAmount); onHash(tx.hash); await tx.wait(); @@ -42,14 +47,15 @@ export const unstakeAmount = async ( failed: (error: string) => void ) => { try { - const expandedAmount = expandToken(amount, govToken.decimals); - const networkVars = getNetworkVariables(); - const govContract = Governance__factory.connect( - networkVars.governanceContractAddress, - writeWeb3.signer - ); + const address = + govToken.symbol === 'BNT' + ? networkVars.governanceBntContractAddress + : networkVars.governanceVbntContractAddress; + + const govContract = Governance__factory.connect(address, writeWeb3.signer); + const expandedAmount = expandToken(amount, govToken.decimals); const tx = await govContract.unstake(expandedAmount); onHash(tx.hash); await tx.wait(); @@ -60,23 +66,28 @@ export const unstakeAmount = async ( } }; -export const getStakedAmount = async (user: string): Promise => { +export const getStakedAmount = async ( + user: string, + isBnt: boolean +): Promise => { const networkVars = getNetworkVariables(); - const govContract = Governance__factory.connect( - networkVars.governanceContractAddress, - web3.provider - ); + const address = isBnt + ? networkVars.governanceBntContractAddress + : networkVars.governanceVbntContractAddress; + const decimals = isBnt ? bntDecimals : vBntDecimals; + + const govContract = Governance__factory.connect(address, web3.provider); const amount = await govContract.votesOf(user); - return shrinkToken(amount.toString(), vBntDecimals); + return shrinkToken(amount.toString(), decimals); }; -export const getUnstakeTimer = async (user: string) => { +export const getUnstakeTimer = async (user: string, isBnt: boolean) => { const now = dayjs().unix() * 1000; const networkVars = getNetworkVariables(); - const govContract = Governance__factory.connect( - networkVars.governanceContractAddress, - web3.provider - ); + const address = isBnt + ? networkVars.governanceBntContractAddress + : networkVars.governanceVbntContractAddress; + const govContract = Governance__factory.connect(address, web3.provider); const locks = await govContract.voteLocks(user); const time = Number(locks) * 1000; if (time - now > 0) return time; diff --git a/src/store/gov/gov.ts b/src/store/gov/gov.ts index 7d2c81716..eed3a4299 100644 --- a/src/store/gov/gov.ts +++ b/src/store/gov/gov.ts @@ -1,28 +1,43 @@ import { createSlice } from '@reduxjs/toolkit'; export interface GovState { - stakedAmount?: string; - unstakeTimer?: number; + stakedVbntAmount?: string; + unstakeVbntTimer?: number; + stakedBntAmount?: string; + unstakeBntTimer?: number; } export const initialState: GovState = { - stakedAmount: undefined, - unstakeTimer: undefined, + stakedVbntAmount: undefined, + unstakeVbntTimer: undefined, + stakedBntAmount: undefined, + unstakeBntTimer: undefined, }; const govSlice = createSlice({ name: 'gov', initialState, reducers: { - setStakedAmount: (state, action) => { - state.stakedAmount = action.payload; + setStakedVbntAmount: (state, action) => { + state.stakedVbntAmount = action.payload; }, - setUnstakeTimer: (state, action) => { - state.unstakeTimer = action.payload; + setUnstakeVbntTimer: (state, action) => { + state.unstakeVbntTimer = action.payload; + }, + setStakedBntAmount: (state, action) => { + state.stakedBntAmount = action.payload; + }, + setUnstakeBntTimer: (state, action) => { + state.unstakeBntTimer = action.payload; }, }, }); -export const { setStakedAmount, setUnstakeTimer } = govSlice.actions; +export const { + setStakedVbntAmount, + setUnstakeVbntTimer, + setStakedBntAmount, + setUnstakeBntTimer, +} = govSlice.actions; export const gov = govSlice.reducer; diff --git a/tailwind.config.js b/tailwind.config.js index 4be21cae5..4b5198504 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -10,6 +10,7 @@ module.exports = { sm: '640px', md: '768px', lg: '1024px', + 'lt-lg': { max: '1023px' }, xl: '1280px', '2xl': '1536px', },