From 9bb348de0e58addb97101246c1958afce6a1f96f Mon Sep 17 00:00:00 2001 From: esaminu Date: Wed, 19 Jan 2022 04:54:44 +0400 Subject: [PATCH] feat: display accrued token rewards for farm validators --- .../staking/components/BalanceBox.js | 58 ++++++++++++++++++- .../components/staking/components/Staking.js | 20 ++----- .../staking/components/Validator.js | 58 +++++++++++++++++-- .../src/hooks/fungibleTokensIncludingNEAR.js | 2 +- .../frontend/src/redux/slices/tokens/index.js | 14 +++-- packages/frontend/src/utils/staking.js | 4 +- 6 files changed, 125 insertions(+), 31 deletions(-) diff --git a/packages/frontend/src/components/staking/components/BalanceBox.js b/packages/frontend/src/components/staking/components/BalanceBox.js index d04ee2e340..0cee28299a 100644 --- a/packages/frontend/src/components/staking/components/BalanceBox.js +++ b/packages/frontend/src/components/staking/components/BalanceBox.js @@ -7,6 +7,8 @@ import classNames from '../../../utils/classNames'; import Balance from '../../common/balance/Balance'; import FormButton from '../../common/FormButton'; import Tooltip from '../../common/Tooltip'; +import TokenIcon from '../../send/components/TokenIcon'; +import TokenAmount from '../../wallet/TokenAmount'; const Container = styled.div` border-bottom: 2px solid #F2F2F2; @@ -23,6 +25,14 @@ const Container = styled.div` color: #24272a; font-size: 16px; font-weight: 700; + + .fiat-amount { + font-size: 14px; + font-weight: 400; + margin-top: 6px; + color: #72727A; + line-height: normal; + } } .title { @@ -64,11 +74,34 @@ const Container = styled.div` margin: 0px -14px 0 -14px; border-radius: 0; } + + .token-balance { + display: flex; + .icon { + width: 32px; + height: 32px; + min-width: 32px; + min-height: 32px; + margin-right: 10px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + border-radius: 50%; + box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.15); + align-self: center; + + img, svg { + height: 32px; + width: 32px; + } + } + } `; export default function BalanceBox({ title, - amount, + token, info, onClick, button, @@ -86,7 +119,26 @@ export default function BalanceBox({ - +
+
+ +
+ {token.onChainFTMetadata?.symbol === "NEAR" && + !token.contractName ? ( + + ) : ( + + )} +
+ {disclaimer &&
@@ -96,7 +148,7 @@ export default function BalanceBox({ {button && (onClick || linkTo) && @@ -70,27 +72,17 @@ export default function Staking({ - } @@ -99,13 +91,13 @@ export default function Staking({ { + const getFarms = async () => { + const farms = await validator.contract.get_farms({from_index: 0, limit: 300}); + setFarmList(await Promise.all(farms.map(({ token_id }, i) => { + dispatch(fetchToken({contractName: token_id})); + return validator.contract + .get_unclaimed_reward({ account_id: accountId, farm_id: i }) + .catch(() => "0") + .then((balance) => ({ token_id, balance, farm_id: i })); + }))); + }; + if(validator && validator.version === ValidatorVersion[PROJECT_VALIDATOR_VERSION]) { + getFarms(); + } + },[validator]); + const handleStakeAction = async () => { if (showConfirmModal && !loading) { await onWithdraw('withdraw', selectedValidator || validator.accountId); @@ -62,7 +89,7 @@ export default function Validator({ { dispatch(redirectTo(`/staking/${match.params.validator}/unstake`)); Mixpanel.track("UNSTAKE Click unstake button"); @@ -74,18 +101,37 @@ export default function Validator({ + {farmList.map(({ token_id, balance, farm_id }) => ( + { + // TODO claim accrued rewards and redirect home where tokens will be fetched + return validator.contract.claim({account_id: accountId, token_id, farm_id}).then(() => dispatch(redirectTo('/'))); + }} + button="staking.balanceBox.farm.button" + buttonColor='gray-red' + /> + ))} { setConfirm('withdraw'); Mixpanel.track("WITHDRAW Click withdraw button"); diff --git a/packages/frontend/src/hooks/fungibleTokensIncludingNEAR.js b/packages/frontend/src/hooks/fungibleTokensIncludingNEAR.js index d71f89826a..8f54f58f32 100644 --- a/packages/frontend/src/hooks/fungibleTokensIncludingNEAR.js +++ b/packages/frontend/src/hooks/fungibleTokensIncludingNEAR.js @@ -4,7 +4,7 @@ import { selectAccountId, selectBalance } from "../redux/slices/account"; import { selectNearTokenFiatValueUSD } from "../redux/slices/tokenFiatValues"; import { selectTokensWithMetadataForAccountId } from "../redux/slices/tokens"; -const useNEARAsTokenWithMetadata = () => { +export const useNEARAsTokenWithMetadata = () => { const nearBalance = useSelector(selectBalance); const nearTokenFiatValueUSD = useSelector(selectNearTokenFiatValueUSD); diff --git a/packages/frontend/src/redux/slices/tokens/index.js b/packages/frontend/src/redux/slices/tokens/index.js index fbd463ea00..b80c118cc3 100644 --- a/packages/frontend/src/redux/slices/tokens/index.js +++ b/packages/frontend/src/redux/slices/tokens/index.js @@ -25,12 +25,12 @@ const initialOwnedTokenState = { error: initialErrorState }; -async function getCachedContractMetadataOrFetch(contractName, accountId, state) { +async function getCachedContractMetadataOrFetch(contractName, state) { let contractMetadata = selectOneContractMetadata(state, { contractName }); if (contractMetadata) { return contractMetadata; } - return FungibleTokens.getMetadata({ contractName, accountId }); + return FungibleTokens.getMetadata({ contractName }); } const fetchOwnedTokensForContract = createAsyncThunk( @@ -63,11 +63,11 @@ const fetchTokens = createAsyncThunk( await Promise.all(likelyContracts.map(async contractName => { const { actions: { setContractMetadata } } = tokensSlice; try { - const contractMetadata = await getCachedContractMetadataOrFetch(contractName, accountId, getState()); + const contractMetadata = await getCachedContractMetadataOrFetch(contractName, getState()); if (!selectOneContractMetadata(getState(), { contractName })) { dispatch(setContractMetadata({ contractName, metadata: contractMetadata })); } - await dispatch(fetchOwnedTokensForContract({ accountId, contractName, contractMetadata })); + await dispatch(fetchOwnedTokensForContract({ accountId, contractName })); } catch (e) { // Continue loading other likely contracts on failures console.warn(`Failed to load FT for ${contractName}`, e); @@ -82,11 +82,13 @@ const fetchToken = createAsyncThunk( const { dispatch, getState } = thunkAPI; const { actions: { setContractMetadata } } = tokensSlice; try { - const contractMetadata = await getCachedContractMetadataOrFetch(contractName, accountId, getState()); + const contractMetadata = await getCachedContractMetadataOrFetch(contractName, getState()); if (!selectOneContractMetadata(getState(), { contractName })) { dispatch(setContractMetadata({ contractName, metadata: contractMetadata })); } - await dispatch(fetchOwnedTokensForContract({ accountId, contractName, contractMetadata })); + if(accountId) { + await dispatch(fetchOwnedTokensForContract({ accountId, contractName })); + } } catch (e) { // Continue loading other likely contracts on failures console.warn(`Failed to load FT for ${contractName}`, e); diff --git a/packages/frontend/src/utils/staking.js b/packages/frontend/src/utils/staking.js index 33bfd9f172..3c7c0c7af4 100644 --- a/packages/frontend/src/utils/staking.js +++ b/packages/frontend/src/utils/staking.js @@ -40,7 +40,9 @@ export const stakingMethods = { 'get_reward_fee_fraction', 'get_farms', 'get_farm', - 'get_active_farms' + 'get_active_farms', + 'get_unclaimed_reward', + 'claim' ], changeMethods: [ 'ping',