Fix Funding Progress calculation

Fix BN types
Add contributors tab
Adjust UserRow to optionally show amount as secondary text
Add contributionAmount to contributors in crowdFund
General cleanup
This commit is contained in:
Daniel Ternyak 2018-09-16 01:46:40 -05:00
parent 329319692a
commit 3862b18670
No known key found for this signature in database
GPG Key ID: DF212D2DC5D0E245
9 changed files with 75 additions and 24 deletions

View File

@ -12,11 +12,11 @@ import { RadioChangeEvent } from 'antd/lib/radio';
import TrusteeFields from './TrusteeFields';
import MilestoneFields, { Milestone } from './MilestoneFields';
import CreateSuccess from './CreateSuccess';
import { computePercentage } from 'utils/helpers';
import { getAmountError } from 'utils/validators';
import MarkdownEditor from 'components/MarkdownEditor';
import * as Styled from './styled';
import { Wei, toWei } from 'utils/units';
import BN from 'bn.js';
interface StateProps {
crowdFundLoading: AppState['web3']['crowdFundLoading'];
crowdFundError: AppState['web3']['crowdFundError'];
@ -74,8 +74,8 @@ const DEFAULT_STATE: State = {
milestoneDeadline: 60 * 60 * 24 * 7,
};
function milestoneToMilestoneAmount(milestone: Milestone, raiseGoal: number) {
return computePercentage(raiseGoal, milestone.payoutPercent);
function milestoneToMilestoneAmount(milestone: Milestone, raiseGoal: Wei) {
return raiseGoal.divn(100).mul(new BN(milestone.payoutPercent));
}
class CreateProposal extends React.Component<Props, State> {
@ -159,7 +159,7 @@ class CreateProposal extends React.Component<Props, State> {
};
createCrowdFund = async () => {
const { contract, createCrowdFund, web3 } = this.props;
const { contract, createCrowdFund } = this.props;
const {
title,
proposalBody,
@ -173,11 +173,11 @@ class CreateProposal extends React.Component<Props, State> {
} = this.state;
const backendData = { content: proposalBody, title, category };
const targetInWei = web3.utils.toWei(String(amountToRaise), 'ether');
const targetInWei = toWei(amountToRaise, 'ether');
const milestoneAmounts = milestones.map(milestone =>
milestoneToMilestoneAmount(milestone, targetInWei),
Wei(milestoneToMilestoneAmount(milestone, targetInWei)),
);
console.log('milestoneAmounts', milestoneAmounts);
const immediateFirstMilestonePayout = milestones[0].immediatePayout;
const contractData = {

View File

@ -0,0 +1,33 @@
import React from 'react';
import { Spin } from 'antd';
import { CrowdFund } from 'modules/proposals/reducers';
import UserRow from 'components/UserRow';
import * as ProposalStyled from '../styled';
interface Props {
crowdFund: CrowdFund;
}
const ContributorsBlock = ({ crowdFund }: Props) => {
let content;
if (crowdFund) {
content = crowdFund.contributors.map(contributor => (
<UserRow
key={contributor.address}
address={contributor.address}
amount={contributor.contributionAmount}
/>
));
} else {
content = <Spin />;
}
return (
<ProposalStyled.SideBlock>
<ProposalStyled.BlockTitle>Contributors</ProposalStyled.BlockTitle>
<ProposalStyled.Block>{content}</ProposalStyled.Block>
</ProposalStyled.SideBlock>
);
};
export default ContributorsBlock;

View File

@ -15,6 +15,7 @@ import Milestones from './Milestones';
import CommentsTab from './Comments';
import UpdatesTab from './Updates';
import GovernanceTab from './Governance';
import ContributorsTab from './Contributors';
// import CommunityTab from './Community';
import * as Styled from './styled';
import { withRouter } from 'next/router';
@ -113,9 +114,12 @@ class ProposalDetail extends React.Component<Props, State> {
<div style={{ marginTop: '1.5rem' }} />
<UpdatesTab proposalId={proposal.proposalId} />
</Tabs.TabPane>
<Tabs.TabPane tab="Governance" key="governanc">
<Tabs.TabPane tab="Governance" key="governance">
<GovernanceTab proposal={proposal} />
</Tabs.TabPane>
<Tabs.TabPane tab="Contributors" key="contributors">
<ContributorsTab crowdFund={proposal.crowdFund} />
</Tabs.TabPane>
</Tabs>
)}
</Styled.Container>

View File

@ -2,14 +2,14 @@ import React from 'react';
import ShortAddress from 'components/ShortAddress';
import Identicon from 'components/Identicon';
import * as Styled from './styled';
import { Wei, fromWei } from 'utils/units';
interface Props {
address: string;
amount?: Wei;
}
// TODO - don't hardcode monero image
const UserRow = ({ address }: Props) => (
const UserRow = ({ address, amount }: Props) => (
<Styled.Container>
<Styled.Avatar>
<Identicon address={address} />
@ -18,7 +18,9 @@ const UserRow = ({ address }: Props) => (
<Styled.InfoMain>
<ShortAddress address={address} />
</Styled.InfoMain>
<Styled.InfoSecondary>{/* user.title */}</Styled.InfoSecondary>
{amount && (
<Styled.InfoSecondary>{fromWei(amount, 'ether')} ETH</Styled.InfoSecondary>
)}
</Styled.Info>
</Styled.Container>
);

View File

@ -14,7 +14,7 @@ export interface User {
export interface Contributor {
address: string;
contributionAmount: string;
contributionAmount: Wei;
refundVote: boolean;
refunded: boolean;
proportionalContribution: string;

View File

@ -7,6 +7,7 @@ import { sleep } from 'utils/helpers';
import { fetchProposal, fetchProposals } from 'modules/proposals/actions';
import { PROPOSAL_CATEGORY } from 'api/constants';
import { AppState } from 'store/reducers';
import { Wei } from 'utils/units';
type GetState = () => AppState;
@ -97,10 +98,10 @@ interface MilestoneData {
}
interface ProposalContractData {
ethAmount: number | string; // TODO: BigNumber
ethAmount: Wei;
payOutAddress: string;
trusteesAddresses: string[];
milestoneAmounts: number[] | string[]; // TODO: BigNumber
milestoneAmounts: Wei[];
milestones: MilestoneData[];
durationInMinutes: number;
milestoneVotingPeriodInMinutes: number;

View File

@ -5,7 +5,3 @@ export function isNumeric(n: any) {
export async function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
export function computePercentage(num: number, percent: number) {
return (num / 100) * percent;
}

View File

@ -38,7 +38,7 @@ export const Units = {
gether: '1000000000000000000000000000',
tether: '1000000000000000000000000000000',
};
const handleValues = (input: string | BN) => {
const handleValues = (input: string | BN | number) => {
if (typeof input === 'string') {
return input.startsWith('0x') ? new BN(stripHexPrefix(input), 16) : new BN(input);
}
@ -58,7 +58,7 @@ const Data = (input: string) => toBuffer(addHexPrefix(input));
const Nonce = (input: string | BN) => handleValues(input);
const Wei = (input: string | BN): Wei => handleValues(input);
const Wei = (input: string | BN | number): Wei => handleValues(input);
const TokenValue = (input: string | BN) => handleValues(input);
@ -93,7 +93,13 @@ const fromWei = (wei: Wei, unit: UnitKey) => {
return baseToConvertedUnit(wei.toString(), decimal);
};
const toWei = (value: string, decimal: number): Wei => {
const toWei = (value: string, unitType: number | UnitKey): Wei => {
let decimal;
if (typeof unitType === 'number') {
decimal = unitType;
} else if (typeof unitType === 'string') {
decimal = getDecimalFromEtherUnit(unitType);
}
const wei = convertedToBaseUnit(value, decimal);
return Wei(wei);
};

View File

@ -2,6 +2,7 @@ import Web3 from 'web3';
import { CrowdFund, Milestone, MILESTONE_STATE } from 'modules/proposals/reducers';
import { collectArrayElements } from 'utils/web3Utils';
import { Wei } from 'utils/units';
import BN from 'bn.js';
export async function getCrowdFundState(
crowdFundContract: any,
@ -26,7 +27,10 @@ export async function getCrowdFundState(
? 100
: balance.divn(100).isZero()
? 0
: target.div(balance.divn(100)).toNumber();
: balance
.mul(new BN(100))
.divRound(target)
.toNumber();
const amountVotingForRefund = isRaiseGoalReached
? Wei(await crowdFundContract.methods.amountVotingForRefund().call({ from: account }))
: Wei('0');
@ -103,6 +107,11 @@ export async function getCrowdFundState(
.call({ form: account }),
),
);
contributor.contributionAmount = Wei(
await crowdFundContract.methods
.getContributorContributionAmount(addr)
.call({ from: account }),
);
return contributor;
}),
);