From 3e9aa02264dc16692ee2aa0da6d783d94dfca9cf Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Mon, 6 Jun 2022 16:06:29 +0100 Subject: [PATCH] set up compound rewards --- .../Delegation/DelegationActions.tsx | 15 ++-- .../components/Delegation/DelegationList.tsx | 10 ++- .../components/Delegation/DelegationModal.tsx | 2 +- .../src/components/Rewards/CompoundModal.tsx | 62 ++++++++++++++++ nym-wallet/src/context/delegations.tsx | 22 +++++- nym-wallet/src/context/mocks/delegations.tsx | 5 ++ nym-wallet/src/pages/delegation/index.tsx | 73 ++++++++++--------- 7 files changed, 142 insertions(+), 47 deletions(-) create mode 100644 nym-wallet/src/components/Rewards/CompoundModal.tsx diff --git a/nym-wallet/src/components/Delegation/DelegationActions.tsx b/nym-wallet/src/components/Delegation/DelegationActions.tsx index 3fe1a9f6f5..82cf2a5719 100644 --- a/nym-wallet/src/components/Delegation/DelegationActions.tsx +++ b/nym-wallet/src/components/Delegation/DelegationActions.tsx @@ -142,14 +142,6 @@ export const DelegationsActionsMenu: React.FC<{ onClick={() => handleActionSelect?.('undelegate')} disabled={false} /> - C} - onClick={() => handleActionSelect?.('compound')} - disabled={disableRedeemingRewards} - /> - handleActionSelect?.('redeem')} disabled={disableRedeemingRewards} /> + C} + onClick={() => handleActionSelect?.('compound')} + disabled={disableRedeemingRewards} + /> ); diff --git a/nym-wallet/src/components/Delegation/DelegationList.tsx b/nym-wallet/src/components/Delegation/DelegationList.tsx index f396fa8463..84193b0848 100644 --- a/nym-wallet/src/components/Delegation/DelegationList.tsx +++ b/nym-wallet/src/components/Delegation/DelegationList.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Box, + Chip, CircularProgress, Link, Table, @@ -172,10 +173,15 @@ export const DelegationList: React.FC<{ (onItemActionClick ? onItemActionClick(item, action) : undefined)} - disableRedeemingRewards={!item.accumulated_rewards} + disableRedeemingRewards={!item.accumulated_rewards || item.accumulated_rewards.amount === '0'} /> ) : ( - 'Pending events..' + + + )} diff --git a/nym-wallet/src/components/Delegation/DelegationModal.tsx b/nym-wallet/src/components/Delegation/DelegationModal.tsx index 6bba3b4d08..91fd474730 100644 --- a/nym-wallet/src/components/Delegation/DelegationModal.tsx +++ b/nym-wallet/src/components/Delegation/DelegationModal.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Box, Button, CircularProgress, Link, Modal, Stack, Typography } from '@mui/material'; import { modalStyle } from '../Modals/styles'; -export type ActionType = 'delegate' | 'undelegate' | 'redeem' | 'redeem-all'; +export type ActionType = 'delegate' | 'undelegate' | 'redeem' | 'redeem-all' | 'compound'; const actionToHeader = (action: ActionType): string => { // eslint-disable-next-line default-case diff --git a/nym-wallet/src/components/Rewards/CompoundModal.tsx b/nym-wallet/src/components/Rewards/CompoundModal.tsx new file mode 100644 index 0000000000..b01139ab9e --- /dev/null +++ b/nym-wallet/src/components/Rewards/CompoundModal.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { Alert, AlertTitle, Stack, Typography } from '@mui/material'; +import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField'; +import WarningIcon from '@mui/icons-material/Warning'; +import { SimpleModal } from '../Modals/SimpleModal'; + +export const CompoundModal: React.FC<{ + open: boolean; + onClose?: () => void; + onOk?: (identityKey: string) => void; + identityKey: string; + amount: number; + fee: number; + minimum?: number; + currency: string; + message: string; +}> = ({ open, onClose, onOk, identityKey, amount, fee, currency, message }) => { + const handleOk = () => { + if (onOk) { + onOk(identityKey); + } + }; + return ( + + {identityKey && } + + + Rewards amount: + + {amount} {currency} + + + + + Rewards will be transferred to account you are logged in with now + + + + theme.palette.nym.fee}> + Fee for this transaction: + + theme.palette.nym.fee}> + {fee} {currency} + + + + {amount < fee && ( + }> + Warning: fees are greater than the reward + The fees for redeeming rewards will cost more than the rewards. Are you sure you want to continue? + + )} + + ); +}; diff --git a/nym-wallet/src/context/delegations.tsx b/nym-wallet/src/context/delegations.tsx index c8f29c23b0..b19b617476 100644 --- a/nym-wallet/src/context/delegations.tsx +++ b/nym-wallet/src/context/delegations.tsx @@ -9,9 +9,11 @@ import { import type { Network } from 'src/types'; import { claimDelegatorRewards, + compoundDelegatorRewards, delegateToMixnode, getAllPendingDelegations, vestingClaimDelegatorRewards, + vestingCompoundDelegatorRewards, vestingDelegateToMixnode, vestingUndelegateFromMixnode, } from 'src/requests'; @@ -31,6 +33,7 @@ export type TDelegationContext = { ) => Promise; undelegate: (identity: string, proxy: string | null) => Promise; redeemRewards: (identity: string, proxy: string | null) => Promise; + compoundRewards: (identity: string, proxy: string | null) => Promise; }; export type TDelegationTransaction = { @@ -49,6 +52,9 @@ export const DelegationContext = createContext({ redeemRewards: async () => { throw new Error('Not implemented'); }, + compoundRewards: async () => { + throw new Error('Not implemented'); + }, }); export const DelegationContextProvider: FC<{ @@ -100,7 +106,20 @@ export const DelegationContextProvider: FC<{ await vestingClaimDelegatorRewards(identity); } } catch (e) { - console.log(e); + throw new Error(e as string); + } + }; + + const compoundRewards = async (identity: string, proxy: string | null) => { + try { + if ((proxy || '').trim().length === 0) { + // the owner of the delegation is main account (the owner of the vesting account), so it is delegation with unlocked tokens + await compoundDelegatorRewards(identity); + } else { + // the delegation is with locked tokens, so use the vesting contract + await vestingCompoundDelegatorRewards(identity); + } + } catch (e) { throw new Error(e as string); } }; @@ -145,6 +164,7 @@ export const DelegationContextProvider: FC<{ addDelegation, undelegate, redeemRewards, + compoundRewards, }), [isLoading, error, delegations, pendingDelegations, totalDelegations], ); diff --git a/nym-wallet/src/context/mocks/delegations.tsx b/nym-wallet/src/context/mocks/delegations.tsx index c5ee512ff7..4a159ee643 100644 --- a/nym-wallet/src/context/mocks/delegations.tsx +++ b/nym-wallet/src/context/mocks/delegations.tsx @@ -176,6 +176,10 @@ export const MockDelegationContextProvider: FC<{}> = ({ children }) => { throw new Error('Not implemented'); }; + const compoundRewards = async () => { + throw new Error('Not implemented'); + }; + const resetState = () => { setIsLoading(true); setError(undefined); @@ -214,6 +218,7 @@ export const MockDelegationContextProvider: FC<{}> = ({ children }) => { updateDelegation, undelegate, redeemRewards, + compoundRewards, }), [isLoading, error, delegations, totalDelegations, trigger], ); diff --git a/nym-wallet/src/pages/delegation/index.tsx b/nym-wallet/src/pages/delegation/index.tsx index 60bd38d933..b978a3829b 100644 --- a/nym-wallet/src/pages/delegation/index.tsx +++ b/nym-wallet/src/pages/delegation/index.tsx @@ -14,6 +14,7 @@ import { UndelegateModal } from '../../components/Delegation/UndelegateModal'; import { DelegationListItemActions } from '../../components/Delegation/DelegationActions'; import { RedeemModal } from '../../components/Rewards/RedeemModal'; import { DelegationModal, DelegationModalProps } from '../../components/Delegation/DelegationModal'; +import { CompoundModal } from 'src/components/Rewards/CompoundModal'; const explorerUrl = 'https://sandbox-explorer.nymtech.net'; @@ -22,6 +23,7 @@ export const Delegation: FC = () => { const [showDelegateMoreModal, setShowDelegateMoreModal] = useState(false); const [showUndelegateModal, setShowUndelegateModal] = useState(false); const [showRedeemRewardsModal, setShowRedeemRewardsModal] = useState(false); + const [showCompoundRewardsModal, setShowCompoundRewardsModal] = useState(false); const [confirmationModalProps, setConfirmationModalProps] = useState(); const [currentDelegationListActionItem, setCurrentDelegationListActionItem] = useState(); @@ -40,6 +42,7 @@ export const Delegation: FC = () => { addDelegation, undelegate, redeemRewards, + compoundRewards, refresh, } = useDelegationContext(); @@ -67,7 +70,7 @@ export const Delegation: FC = () => { setShowRedeemRewardsModal(true); break; case 'compound': - setShowRedeemRewardsModal(true); + setShowCompoundRewardsModal(true); break; } }; @@ -144,7 +147,8 @@ export const Delegation: FC = () => { setConfirmationModalProps({ status: 'success', action: 'delegate', - balance: tokenPool === 'locked' ? `${spendableLocked} ${clientDetails?.denom}` : bal?.printable_balance || '-', + balance: + tokenPool === 'locked' ? `${spendableLocked?.amount} ${clientDetails?.denom}` : bal?.printable_balance || '-', transactionUrl: `${urls(network).blockExplorer}/transaction/${tx.transaction_hash}`, }); } catch (e) { @@ -208,32 +212,30 @@ export const Delegation: FC = () => { } }; - // const handleRedeemAll = async () => { - // setConfirmationModalProps({ - // status: 'loading', - // action: 'redeem-all', - // }); - // setShowRedeemAllRewardsModal(false); - // setCurrentDelegationListActionItem(undefined); - // try { - // const tx = await redeemAllRewards(); - // const bal = await userBalance(); + const handleCompound = async (identityKey: string, proxy: string | null) => { + setConfirmationModalProps({ + status: 'loading', + action: 'compound', + }); + setShowCompoundRewardsModal(false); + setCurrentDelegationListActionItem(undefined); - // setConfirmationModalProps({ - // status: 'success', - // action: 'redeem-all', - // balance: bal?.printable_balance || '-', - // recipient: clientDetails?.client_address, - // transactionUrl: tx.transactionUrl, - // }); - // } catch (e) { - // setConfirmationModalProps({ - // status: 'error', - // action: 'redeem-all', - // message: (e as Error).message, - // }); - // } - // }; + try { + await compoundRewards(identityKey, proxy); + const bal = await userBalance(); + setConfirmationModalProps({ + status: 'success', + action: 'compound', + balance: bal?.printable_balance || '-', + }); + } catch (e) { + setConfirmationModalProps({ + status: 'error', + action: 'redeem', + message: (e as Error).message, + }); + } + }; return ( <> @@ -342,17 +344,18 @@ export const Delegation: FC = () => { /> )} - {/* {currentDelegationListActionItem && showRedeemAllRewardsModal && ( - setShowRedeemAllRewardsModal(false)} - onOk={handleRedeemAll} + {currentDelegationListActionItem?.accumulated_rewards && showCompoundRewardsModal && ( + setShowCompoundRewardsModal(false)} + onOk={(identity) => handleCompound(identity, currentDelegationListActionItem.proxy)} message="Compound rewards" - currency="NYM" + currency={clientDetails!.denom} + identityKey={currentDelegationListActionItem?.node_identity} fee={0.004375} - amount={currentDelegationListActionItem?.amount.amount} + amount={+currentDelegationListActionItem.accumulated_rewards.amount} /> - )} */} + )} {confirmationModalProps && (