Display contribution values (#5527)

* Show contribution values

* Remove parathread API ping
This commit is contained in:
Jaco 2021-06-09 13:42:13 +03:00 committed by GitHub
parent 428cf56bcf
commit 2b797cf95e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 113 additions and 49 deletions

View File

@ -2,21 +2,19 @@
// SPDX-License-Identifier: Apache-2.0
import type BN from 'bn.js';
import type { StorageKey } from '@polkadot/types';
import type { EventRecord, ParaId } from '@polkadot/types/interfaces';
import type { Campaign, LeasePeriod } from '../types';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useMemo } from 'react';
import { AddressMini, Expander, Icon, ParaLink, TxButton } from '@polkadot/react-components';
import { useAccounts, useApi, useEventTrigger, useParaEndpoints } from '@polkadot/react-hooks';
import { useAccounts, useApi, useParaEndpoints } from '@polkadot/react-hooks';
import { BlockToTime, FormatBalance } from '@polkadot/react-query';
import { formatNumber } from '@polkadot/util';
import { encodeAddress } from '@polkadot/util-crypto';
import { useTranslation } from '../translate';
import Contribute from './Contribute';
import Refund from './Refund';
import useContributions from './useContributions';
interface Props {
bestNumber?: BN;
@ -27,48 +25,12 @@ interface Props {
value: Campaign;
}
interface Contributions {
contributors: string[];
myAccounts: string[];
}
const NO_CONTRIB: Contributions = { contributors: [], myAccounts: [] };
function extractContributors (allAccountsHex: string[], keys: StorageKey[], ss58Format?: number): Contributions {
const contributors = keys.map((k) => k.toHex());
return {
contributors,
myAccounts: contributors
.filter((c) => allAccountsHex.includes(c))
.map((a) => encodeAddress(a, ss58Format))
};
}
function Fund ({ bestNumber, className, isOdd, isOngoing, leasePeriod, value: { childKey, info: { cap, depositor, end, firstPeriod, lastPeriod, raised, verifier }, isCapped, isEnded, isWinner, paraId } }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { allAccountsHex, isAccount } = useAccounts();
const { isAccount } = useAccounts();
const endpoints = useParaEndpoints(paraId);
const [{ contributors, myAccounts }, setContributors] = useState<Contributions>(NO_CONTRIB);
const trigger = useEventTrigger([api.events.crowdloan.Contributed, api.events.crowdloan.Withdrew, api.events.crowdloan.AllRefunded, api.events.crowdloan.PartiallyRefunded], useCallback(
({ event: { data } }: EventRecord) =>
((data.length === 1
? data[0] // AllRefunded, PartiallyRefunded [ParaId]
: data[1] // Contributed, Withdrew [AccountId, ParaId, Balance]
) as ParaId).eq(paraId),
[paraId]
));
useEffect((): void => {
trigger &&
api.rpc.childstate
.getKeys(childKey, '0x')
.then((keys) => setContributors(
extractContributors(allAccountsHex, keys, api.registry.chainSS58))
)
.catch(console.error);
}, [allAccountsHex, api, childKey, trigger]);
const { contributorsHex, myAccounts, myAccountsHex, myContributions } = useContributions(paraId, childKey);
const isDepositor = useMemo(
() => isAccount(depositor.toString()),
@ -139,8 +101,8 @@ function Fund ({ bestNumber, className, isOdd, isOngoing, leasePeriod, value: {
<div>{percentage}</div>
</td>
<td className='number media--1100'>
{contributors.length !== 0 && (
formatNumber(contributors.length)
{contributorsHex.length !== 0 && (
formatNumber(contributorsHex.length)
)}
</td>
<td className='badge media--1000'>
@ -150,7 +112,7 @@ function Fund ({ bestNumber, className, isOdd, isOngoing, leasePeriod, value: {
/>
</td>
<td className='button media--1000'>
{canWithdraw && contributors.length !== 0 && (
{canWithdraw && contributorsHex.length !== 0 && (
<Refund paraId={paraId} />
)}
{canDissolve && (
@ -185,10 +147,12 @@ function Fund ({ bestNumber, className, isOdd, isOngoing, leasePeriod, value: {
<td className='no-pad-top media--1400'>
{myAccounts.length !== 0 && (
<Expander summary={t<string>('My contributions ({{count}})', { replace: { count: myAccounts.length } })}>
{myAccounts.map((a) => (
{myAccounts.map((a, index) => (
<AddressMini
balance={myContributions[myAccountsHex[index]]}
key={a}
value={a}
withBalance
/>
))}
</Expander>

View File

@ -0,0 +1,100 @@
// Copyright 2017-2021 @polkadot/app-parachains authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { StorageKey } from '@polkadot/types';
import type { Balance, EventRecord, ParaId } from '@polkadot/types/interfaces';
import { useCallback, useEffect, useState } from 'react';
import { useAccounts, useApi, useEventTrigger } from '@polkadot/react-hooks';
import { encodeAddress } from '@polkadot/util-crypto';
interface Contributions {
contributorsHex: string[];
myAccounts: string[];
myAccountsHex: string[];
myContributions: Record<string, Balance>;
}
const NO_CONTRIB: Contributions = {
contributorsHex: [],
myAccounts: [],
myAccountsHex: [],
myContributions: {}
};
function extractContributors (allAccountsHex: string[], keys: StorageKey[], ss58Format?: number): Partial<Contributions> {
const contributorsHex = keys.map((k) => k.toHex());
const myAccountsHex = contributorsHex.filter((c) => allAccountsHex.includes(c));
return {
contributorsHex,
myAccounts: myAccountsHex.map((a) => encodeAddress(a, ss58Format)),
myAccountsHex
};
}
function useMyContributions (childKey: string, keys: string[]): Record<string, Balance> {
const { api } = useApi();
const [state, setState] = useState<Record<string, Balance>>({});
useEffect((): void => {
keys.length &&
Promise
.all(keys.map((k) => api.rpc.childstate.getStorage(childKey, k)))
.then((values) => setState(
values
.map((v) => api.createType('Option<StorageData>', v))
.map((o) =>
o.isSome
? api.createType('Balance', o.unwrap())
: api.createType('Balance')
)
.reduce((all, b, index) => ({ ...all, [keys[index]]: b }), {})
))
.catch(console.error);
}, [api, childKey, keys]);
return state;
}
export default function useContributions (paraId: ParaId, childKey: string): Contributions {
const { api } = useApi();
const { allAccountsHex } = useAccounts();
const [state, setState] = useState<Contributions>(() => NO_CONTRIB);
const myContributions = useMyContributions(childKey, state.myAccountsHex);
const trigger = useEventTrigger([
api.events.crowdloan.Contributed,
api.events.crowdloan.Withdrew,
api.events.crowdloan.AllRefunded,
api.events.crowdloan.PartiallyRefunded
], useCallback(
({ event: { data } }: EventRecord) =>
((data.length === 1
? data[0] // AllRefunded, PartiallyRefunded [ParaId]
: data[1] // Contributed, Withdrew [AccountId, ParaId, Balance]
) as ParaId).eq(paraId),
[paraId]
));
useEffect((): void => {
trigger &&
api.rpc.childstate
.getKeys(childKey, '0x')
.then((keys) => setState((prev) => ({
...prev,
...extractContributors(allAccountsHex, keys, api.registry.chainSS58)
})))
.catch(console.error);
}, [allAccountsHex, api, childKey, trigger]);
useEffect((): void => {
setState((prev) => ({
...prev,
myContributions
}));
}, [myContributions]);
return state;
}

View File

@ -12,7 +12,7 @@ import { useAccounts, useApi, useCallMulti } from '@polkadot/react-hooks';
import { formatNumber } from '@polkadot/util';
import Lifecycle from '../Overview/Lifecycle';
import ParachainInfo from '../Overview/ParachainInfo';
// import ParachainInfo from '../Overview/ParachainInfo';
import Periods from '../Overview/Periods';
import { useTranslation } from '../translate';
import { sliceHex } from '../util';
@ -82,7 +82,7 @@ function Upcoming ({ id, leasePeriod, leases, nextAction }: Props): React.ReactE
</td>
<td className='all' />
<td className='number no-pad-left'>
<ParachainInfo id={id} />
{/* <!-- ParachainInfo id={id} /--> */}
</td>
<td className='number together'>
{leasePeriod && leases && periods && (