From d4e61d4f3f95b9e9d51932904fd03464fafa2d23 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Tue, 6 Apr 2021 16:27:13 +0300 Subject: [PATCH] Support for crowdloan refund (#4982) * Support for crowdloan refund * Cleanup ending checks * Remove old comment * Withdrawal type only on non-refund * Additional events support * Additional comments * Update packages/page-parachains/src/Crowdloan/Fund.tsx --- .../page-parachains/src/Crowdloan/Fund.tsx | 72 +++++++------------ .../page-parachains/src/Crowdloan/Funds.tsx | 1 - .../page-parachains/src/Crowdloan/Refund.tsx | 46 +++++++----- packages/page-parachains/src/types.ts | 2 - packages/page-parachains/src/useFunds.ts | 25 +++---- 5 files changed, 63 insertions(+), 83 deletions(-) diff --git a/packages/page-parachains/src/Crowdloan/Fund.tsx b/packages/page-parachains/src/Crowdloan/Fund.tsx index 9a8e5cb39d..a9bf3416d9 100644 --- a/packages/page-parachains/src/Crowdloan/Fund.tsx +++ b/packages/page-parachains/src/Crowdloan/Fund.tsx @@ -43,14 +43,17 @@ function extractContributors (allAccounts: string[], keys: StorageKey[]): Contri }; } -function Fund ({ bestNumber, className, isOngoing, leasePeriod, value: { childKey, info: { cap, depositor, end, firstSlot, lastSlot, raised, retiring }, isCapped, isEnded, isRetired, isWinner, paraId, retireEnd } }: Props): React.ReactElement { +function Fund ({ bestNumber, className, isOngoing, leasePeriod, value: { childKey, info: { cap, depositor, end, firstSlot, lastSlot, raised }, isCapped, isEnded, isWinner, paraId } }: Props): React.ReactElement { const { t } = useTranslation(); const { api } = useApi(); const { allAccounts, isAccount } = useAccounts(); const [{ myAccounts, uniqueKeys }, setContributors] = useState(NO_CONTRIB); - const trigger = useEventTrigger([api.events.crowdloan?.Contributed, api.events.crowdloan?.Withdrew], useCallback( - ({ event: { data: [, fundIndex] } }: EventRecord) => - (fundIndex as ParaId).eq(paraId), + 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] )); @@ -69,22 +72,13 @@ function Fund ({ bestNumber, className, isOngoing, leasePeriod, value: { childKe [depositor, isAccount] ); - const [blocksLeft, retiringLeft] = useMemo( - () => bestNumber - ? [ - end.gt(bestNumber) - ? end.sub(bestNumber) - : null, - retireEnd?.gt(bestNumber) - ? retireEnd.sub(bestNumber) - : null - ] - : [null, null], - [bestNumber, end, retireEnd] + const blocksLeft = useMemo( + () => bestNumber && end.gt(bestNumber) + ? end.sub(bestNumber) + : null, + [bestNumber, end] ); - // TODO Dissolve should look at retirement and the actual period - const percentage = useMemo( () => cap.isZero() ? '100.00%' @@ -92,14 +86,14 @@ function Fund ({ bestNumber, className, isOngoing, leasePeriod, value: { childKe [cap, raised] ); - const isLeaseOver = !blocksLeft && !!leasePeriod && ( + const hasEnded = !blocksLeft && !!leasePeriod && ( isWinner ? leasePeriod.currentPeriod.gt(lastSlot) : leasePeriod.currentPeriod.gt(firstSlot) ); - const canContribute = !!blocksLeft && isOngoing && !isCapped && !isWinner && retiring.isFalse; - const canDissolve = raised.isZero() || (retiring.isTrue && isLeaseOver); - const canWithdraw = !raised.isZero() && isLeaseOver; + const canContribute = isOngoing && !isCapped && !isWinner && !!blocksLeft; + const canDissolve = raised.isZero() || hasEnded; + const canWithdraw = !raised.isZero() && hasEnded; return ( @@ -108,35 +102,17 @@ function Fund ({ bestNumber, className, isOngoing, leasePeriod, value: { childKe {isWinner ? t('Winner') - : isRetired - ? retiring.isTrue - ? t('Retired') - : t('Completed') - : retiring.isTrue - ? t('Retiring') - : blocksLeft - ? isCapped - ? t('Capped') - : isOngoing - ? t('Active') - : t('Past') - : t('Ended') + : blocksLeft + ? isCapped + ? t('Capped') + : isOngoing + ? t('Active') + : t('Past') + : t('Ended') } - {!isOngoing && ( - - {(isRetired || retiring.isTrue) && ( - <> - {retiringLeft && ( - - )} - #{formatNumber(retireEnd)} - - )} - - )} - + {blocksLeft && ( )} diff --git a/packages/page-parachains/src/Crowdloan/Funds.tsx b/packages/page-parachains/src/Crowdloan/Funds.tsx index e8af826e39..ea7ed3de4d 100644 --- a/packages/page-parachains/src/Crowdloan/Funds.tsx +++ b/packages/page-parachains/src/Crowdloan/Funds.tsx @@ -76,7 +76,6 @@ function Funds ({ bestNumber, className, leasePeriod, value }: Props): React.Rea [t('completed'), 'start', 2], [undefined, 'media--800'], [undefined, 'media--1400'], - [t('retired'), 'media--1000'], [t('ending'), 'media--1000'], [t('leases')], [t('raised')], diff --git a/packages/page-parachains/src/Crowdloan/Refund.tsx b/packages/page-parachains/src/Crowdloan/Refund.tsx index c7b398a836..2955251991 100644 --- a/packages/page-parachains/src/Crowdloan/Refund.tsx +++ b/packages/page-parachains/src/Crowdloan/Refund.tsx @@ -79,24 +79,38 @@ function Refund ({ allAccounts, className, myAccounts, paraId }: Props): React.R value={accountId} /> - ('The type of withdrawal, all accounts or only own accounts (if available)')}> - ('withdrawal type')} - onChange={setWithdrawType} - options={typeOptions} - value={withdrawType} - /> - + {!api.tx.crowdloan.refund && ( + ('The type of withdrawal, all accounts or only own accounts (if available)')}> + ('withdrawal type')} + onChange={setWithdrawType} + options={typeOptions} + value={withdrawType} + /> + + )} - ('Refund')} - onStart={toggleOpen} - /> + {api.tx.crowdloan.refund + ? ( + ('Refund')} + onStart={toggleOpen} + tx={api.tx.crowdloan.refund} + /> + ) + : ( + ('Refund')} + onStart={toggleOpen} + /> + )} )} diff --git a/packages/page-parachains/src/types.ts b/packages/page-parachains/src/types.ts index 2a0eaeb67f..36e4142cf2 100644 --- a/packages/page-parachains/src/types.ts +++ b/packages/page-parachains/src/types.ts @@ -53,9 +53,7 @@ export interface Campaign extends WinnerData { info: FundInfo; isCapped?: boolean; isEnded?: boolean; - isRetired?: boolean; isWinner?: boolean; - retireEnd?: BN; } export interface LeasePeriod { diff --git a/packages/page-parachains/src/useFunds.ts b/packages/page-parachains/src/useFunds.ts index 207bdde6d7..0c57cf365d 100644 --- a/packages/page-parachains/src/useFunds.ts +++ b/packages/page-parachains/src/useFunds.ts @@ -49,28 +49,25 @@ function createChildKey (trieIndex: TrieIndex): string { } // map into a campaign -function updateFund (bestNumber: BN, minContribution: BN, retirementPeriod: BN, data: Campaign, leased: ParaId[]): Campaign { +function updateFund (bestNumber: BN, minContribution: BN, data: Campaign, leased: ParaId[]): Campaign { data.isCapped = data.info.cap.sub(data.info.raised).lt(minContribution); data.isEnded = bestNumber.gt(data.info.end); - data.retireEnd = data.info.end.add(retirementPeriod); - data.isRetired = bestNumber.gt(data.retireEnd); data.isWinner = hasLease(data.paraId, leased); return data; } -function isFundUpdated (bestNumber: BlockNumber, minContribution: BN, retirementPeriod: BN, { info: { cap, end, raised }, paraId }: Campaign, leased: ParaId[], allPrev: Campaigns): boolean { +function isFundUpdated (bestNumber: BlockNumber, minContribution: BN, { info: { cap, end, raised }, paraId }: Campaign, leased: ParaId[], allPrev: Campaigns): boolean { const prev = allPrev.funds?.find((p) => p.paraId.eq(paraId)); return !prev || (!prev.isEnded && bestNumber.gt(end)) || (!prev.isCapped && cap.sub(raised).lt(minContribution)) || - (!prev.isRetired && bestNumber.gt(end.add(retirementPeriod))) || (!prev.isWinner && hasLease(paraId, leased)); } // compare the current campaigns against the previous, manually adding ending and calculating the new totals -function createResult (bestNumber: BlockNumber, minContribution: BN, retirementPeriod: BN, funds: Campaign[], leased: ParaId[], prev: Campaigns): Campaigns { +function createResult (bestNumber: BlockNumber, minContribution: BN, funds: Campaign[], leased: ParaId[], prev: Campaigns): Campaigns { const [activeRaised, activeCap, totalRaised, totalCap] = funds.reduce(([ar, ac, tr, tc], { info: { cap, end, raised } }) => [ bestNumber.gt(end) ? ar : ar.iadd(raised), bestNumber.gt(end) ? ac : ac.iadd(cap), @@ -84,7 +81,7 @@ function createResult (bestNumber: BlockNumber, minContribution: BN, retirementP const hasChanged = !prev.funds || prev.funds.length !== funds.length || hasNewActiveCap || hasNewActiveRaised || hasNewTotalCap || hasNewTotalRaised || - funds.some((c) => isFundUpdated(bestNumber, minContribution, retirementPeriod, c, leased, prev)); + funds.some((c) => isFundUpdated(bestNumber, minContribution, c, leased, prev)); if (!hasChanged) { return prev; @@ -98,7 +95,7 @@ function createResult (bestNumber: BlockNumber, minContribution: BN, retirementP ? activeRaised : prev.activeRaised, funds: funds - .map((c) => updateFund(bestNumber, minContribution, retirementPeriod, c, leased)) + .map((c) => updateFund(bestNumber, minContribution, c, leased)) .sort((a, b) => a.isWinner !== b.isWinner ? a.isWinner @@ -108,15 +105,11 @@ function createResult (bestNumber: BlockNumber, minContribution: BN, retirementP ? a.isCapped ? -1 : 1 - : a.isRetired !== b.isRetired - ? a.isRetired + : a.isEnded !== b.isEnded + ? a.isEnded ? 1 : -1 - : a.isEnded !== b.isEnded - ? a.isEnded - ? 1 - : -1 - : 0 + : 0 ), totalCap: hasNewTotalCap ? totalCap @@ -187,7 +180,7 @@ export default function useFunds (): Campaigns { // here we manually add the actual ending status and calculate the totals useEffect((): void => { bestNumber && campaigns && leases && setResult((prev) => - createResult(bestNumber, api.consts.crowdloan.minContribution as BlockNumber, api.consts.crowdloan.retirementPeriod as BlockNumber, campaigns, leases, prev) + createResult(bestNumber, api.consts.crowdloan.minContribution as BlockNumber, campaigns, leases, prev) ); }, [api, bestNumber, campaigns, leases]);