From c530aa3f51c3377fd10e56d516bbaaefa0db1021 Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Wed, 29 Jan 2020 06:51:01 -0800 Subject: [PATCH] Don't show ContributionReward beneficiaries rewards for ExpiredInQueue proposals (#1334) We were showing the rewards as redeemable if the proposal had more pass votes than fail. There is still a small bug here, the proposal will still appear in the Redeem menu though it wont show any rewards as actually available. This has to be fixed by https://github.com/daostack/subgraph/issues/455 Also fix little UI bug on voting buttons with overlapping text --- src/components/Proposal/ActionButton.tsx | 4 +- src/components/Proposal/RedemptionsString.tsx | 41 ++++++++++--------- .../Proposal/Voting/VoteButtons.tsx | 2 +- .../Redemptions/RedemptionsMenu.tsx | 5 +-- src/lib/util.ts | 10 ++++- 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/components/Proposal/ActionButton.tsx b/src/components/Proposal/ActionButton.tsx index d6a31ff20..460755e27 100644 --- a/src/components/Proposal/ActionButton.tsx +++ b/src/components/Proposal/ActionButton.tsx @@ -137,12 +137,12 @@ class ActionButton extends React.Component { /** * unredeemed by the beneficiary */ - contributionRewards = getCRRewards(proposalState.contributionReward); + contributionRewards = getCRRewards(proposalState); beneficiaryNumUnredeemedCrRewards = Object.keys(contributionRewards).length; /** * unredeemed and available to the beneficiary */ - const availableCrRewards = getCRRewards(proposalState.contributionReward, daoBalances); + const availableCrRewards = getCRRewards(proposalState, daoBalances); // only true if there are rewards and the DAO can't pay them. false if there are no rewards or they can be paid. daoLacksRequiredCrRewards = Object.keys(availableCrRewards).length < beneficiaryNumUnredeemedCrRewards; daoLacksAllRequiredCrRewards = (Object.keys(availableCrRewards).length === 0) && (beneficiaryNumUnredeemedCrRewards > 0); diff --git a/src/components/Proposal/RedemptionsString.tsx b/src/components/Proposal/RedemptionsString.tsx index c73f0c2a5..26e0906f0 100644 --- a/src/components/Proposal/RedemptionsString.tsx +++ b/src/components/Proposal/RedemptionsString.tsx @@ -2,14 +2,14 @@ import { Address, IDAOState, IProposalState, IRewardState } from "@daostack/clie import BN = require("bn.js"); import Reputation from "components/Account/Reputation"; -import { formatTokens, tokenDecimals, tokenSymbol } from "lib/util"; +import { getCRRewards, getGpRewards, formatTokens, tokenDecimals, tokenSymbol } from "lib/util"; import * as React from "react"; interface IProps { currentAccountAddress: Address; dao: IDAOState; proposal: IProposalState; - rewards: IRewardState[]; + rewards: IRewardState; separator?: string; } @@ -23,32 +23,35 @@ export default class RedemptionsString extends React.Component { let reputation = new BN(0); let gen = new BN(0); - for (const reward of rewards) { - if (reward.reputationForProposer.gt(zero)) { - reputation = reputation.add(reward.reputationForProposer); - } else if (reward.reputationForVoter.gt(zero)) { - reputation = reputation.add(reward.reputationForVoter); - } else if (reward.tokensForStaker.gt(zero)) { - gen = gen.add(reward.tokensForStaker); - } else if (reward.daoBountyForStaker.gt(zero)) { - gen = gen.add(reward.daoBountyForStaker); + const gpRewards = getGpRewards(rewards); + + if (gpRewards) { + if (gpRewards.reputationForProposer) { + reputation = reputation.add(gpRewards.reputationForProposer); + } else if (gpRewards.reputationForVoter) { + reputation = reputation.add(gpRewards.reputationForVoter); + } else if (gpRewards.tokensForStaker) { + gen = gen.add(gpRewards.tokensForStaker); + } else if (gpRewards.daoBountyForStaker) { + gen = gen.add(gpRewards.daoBountyForStaker); } } const contributionReward = proposal.contributionReward; if (contributionReward && currentAccountAddress === contributionReward.beneficiary) { - if (contributionReward.ethReward.gt(zero)) { - rewardComponents.push(formatTokens(contributionReward.ethReward, "ETH")); + const rewards = getCRRewards(proposal); + if (rewards.ethReward) { + rewardComponents.push(formatTokens(rewards.ethReward, "ETH")); } - if (contributionReward.externalTokenReward.gt(zero)) { - rewardComponents.push(formatTokens(contributionReward.externalTokenReward, tokenSymbol(contributionReward.externalToken), tokenDecimals(contributionReward.externalToken))); + if (rewards.externalTokenReward) { + rewardComponents.push(formatTokens(rewards.externalTokenReward, tokenSymbol(contributionReward.externalToken), tokenDecimals(contributionReward.externalToken))); } - if (contributionReward.nativeTokenReward.gt(zero)) { - rewardComponents.push(formatTokens(contributionReward.nativeTokenReward, dao.tokenSymbol)); + if (rewards.nativeTokenReward) { + rewardComponents.push(formatTokens(rewards.nativeTokenReward, dao.tokenSymbol)); } - if (!contributionReward.reputationReward.isZero()) { - reputation.add(contributionReward.reputationReward); + if (rewards.reputationReward) { + reputation.add(rewards.reputationReward); } } diff --git a/src/components/Proposal/Voting/VoteButtons.tsx b/src/components/Proposal/Voting/VoteButtons.tsx index c21fd8b41..2d6cd4a27 100644 --- a/src/components/Proposal/Voting/VoteButtons.tsx +++ b/src/components/Proposal/Voting/VoteButtons.tsx @@ -94,7 +94,7 @@ class VoteButtons extends React.Component { ((currentVote === IProposalOutcome.Pass) || (currentVote === IProposalOutcome.Fail)) ? "Can't change your vote" : (currentAccountState && currentAccountState.reputation.eq(new BN(0))) ? - "Voting requires reputation in this DAO" : + "Requires reputation in this DAO" : proposal.stage === IProposalStage.ExpiredInQueue || (proposal.stage === IProposalStage.Boosted && expired) || (proposal.stage === IProposalStage.QuietEndingPeriod && expired) || diff --git a/src/components/Redemptions/RedemptionsMenu.tsx b/src/components/Redemptions/RedemptionsMenu.tsx index 914995c27..778d75047 100644 --- a/src/components/Redemptions/RedemptionsMenu.tsx +++ b/src/components/Redemptions/RedemptionsMenu.tsx @@ -153,8 +153,7 @@ type IMenuItemContentProps = IMenuItemProps & IMenuItemContentStateProps & ISubs class MenuItemContent extends React.Component { public render(): RenderOutput { const { beneficiaryProfile, currentAccountAddress, data, proposal } = this.props; - const [dao, daoEthBalance, reward] = data; - const rewards = reward && [reward] || []; + const [dao, daoEthBalance, rewards] = data; return { expanded expired proposalState={proposal} - rewards={reward} + rewards={rewards} /> ; diff --git a/src/lib/util.ts b/src/lib/util.ts index 5135004e0..ec5ffeebb 100644 --- a/src/lib/util.ts +++ b/src/lib/util.ts @@ -2,7 +2,7 @@ import { promisify } from "util"; import { Address, IContractInfo, - IContributionReward, + IProposalStage, IProposalState, IRewardState, ISchemeState } from "@daostack/client"; @@ -409,8 +409,14 @@ export function hasGpRewards(reward: IRewardState) { * @param reward unredeemed CR rewards * @param daoBalances */ -export function getCRRewards(reward: IContributionReward, daoBalances: { [key: string]: BN|null } = {}): AccountClaimableRewardsType { +export function getCRRewards(proposalState: IProposalState, daoBalances: { [key: string]: BN|null } = {}): AccountClaimableRewardsType { const result: AccountClaimableRewardsType = {}; + + if (proposalState.stage === IProposalStage.ExpiredInQueue) { + return {}; + } + + const reward = proposalState.contributionReward; if ( reward.ethReward && !reward.ethReward.isZero()