diff --git a/packages/page-parachains/src/Auctions/Auction.tsx b/packages/page-parachains/src/Auctions/Auction.tsx index 39460ec590..f1d03ca921 100644 --- a/packages/page-parachains/src/Auctions/Auction.tsx +++ b/packages/page-parachains/src/Auctions/Auction.tsx @@ -6,7 +6,6 @@ import type { AuctionIndex, BlockNumber, LeasePeriodOf } from '@polkadot/types/i import React, { useRef } from 'react'; import { Table } from '@polkadot/react-components'; -import { BN_ZERO } from '@polkadot/util'; import { useTranslation } from '../translate'; import useWinningData from './useWinningData'; @@ -14,14 +13,13 @@ import WinBlock from './WinBlock'; interface Props { auctionInfo: [LeasePeriodOf, BlockNumber] | null; - bestNumber?: BlockNumber; className?: string; numAuctions: AuctionIndex | null; } -function Auction ({ auctionInfo, bestNumber, className, numAuctions }: Props): React.ReactElement { +function Auction ({ auctionInfo, className, numAuctions }: Props): React.ReactElement { const { t } = useTranslation(); - const winningData = useWinningData(); + const winningData = useWinningData(auctionInfo); const headerRef = useRef([ [t('winners'), 'start', 4], @@ -29,26 +27,21 @@ function Auction ({ auctionInfo, bestNumber, className, numAuctions }: Props): R [t('value'), 'number'] ]); - const offset = auctionInfo && bestNumber && bestNumber.gt(auctionInfo[1]) - ? bestNumber.sub(auctionInfo[1]) - : BN_ZERO; - return ( ('No winners in this auction') - : t('No ongoing auction') - } + empty={numAuctions && winningData && ( + auctionInfo && !winningData.length + ? t('No winners in this auction') + : t('No ongoing auction') + )} header={headerRef.current} > - {offset && bestNumber && winningData?.map((value, count) => ( + {winningData?.map((value, count) => ( ))} diff --git a/packages/page-parachains/src/Auctions/Bid.tsx b/packages/page-parachains/src/Auctions/Bid.tsx index 51068d5e3f..e50dacc966 100644 --- a/packages/page-parachains/src/Auctions/Bid.tsx +++ b/packages/page-parachains/src/Auctions/Bid.tsx @@ -22,10 +22,10 @@ function Bid ({ className, id }: Props): React.ReactElement { const { api } = useApi(); const { hasAccounts } = useAccounts(); const [accountId, setAccountId] = useState(null); - const [amount, setAmount] = useState(); - const [firstSlot, setFirstSlot] = useState(); - const [lastSlot, setLastSlot] = useState(); - const [paraId, setParaId] = useState(); + const [amount, setAmount] = useState(BN_ZERO); + const [firstSlot, setFirstSlot] = useState(BN_ZERO); + const [lastSlot, setLastSlot] = useState(BN_ZERO); + const [paraId, setParaId] = useState(BN_ZERO); const [isOpen, toggleOpen] = useToggle(); const isLastError = !lastSlot || !firstSlot || lastSlot.lt(firstSlot) || lastSlot.gt(firstSlot.addn(3)); @@ -62,6 +62,7 @@ function Bid ({ className, id }: Props): React.ReactElement { ('parachain id')} onChange={setParaId} @@ -86,10 +87,12 @@ function Bid ({ className, id }: Props): React.ReactElement { ('first slot')} onChange={setFirstSlot} /> ('last slot')} onChange={setLastSlot} diff --git a/packages/page-parachains/src/Auctions/Summary.tsx b/packages/page-parachains/src/Auctions/Summary.tsx index 88cfa111bd..07fb04ba00 100644 --- a/packages/page-parachains/src/Auctions/Summary.tsx +++ b/packages/page-parachains/src/Auctions/Summary.tsx @@ -6,19 +6,21 @@ import type { AuctionIndex, BlockNumber, LeasePeriodOf } from '@polkadot/types/i import React from 'react'; import { CardSummary, SummaryBox } from '@polkadot/react-components'; +import { useApi, useCall } from '@polkadot/react-hooks'; import { formatNumber } from '@polkadot/util'; import { useTranslation } from '../translate'; interface Props { auctionInfo: [LeasePeriodOf, BlockNumber] | null; - bestNumber?: BlockNumber; className?: string; numAuctions?: AuctionIndex | null; } -function Summary ({ auctionInfo, bestNumber, className, numAuctions }: Props): React.ReactElement { +function Summary ({ auctionInfo, className, numAuctions }: Props): React.ReactElement { const { t } = useTranslation(); + const { api } = useApi(); + const bestNumber = useCall(api.derive.chain.bestNumber); const [period, ending] = auctionInfo || []; return ( diff --git a/packages/page-parachains/src/Auctions/WinBlock.tsx b/packages/page-parachains/src/Auctions/WinBlock.tsx index 3cff9adc12..f0759edef7 100644 --- a/packages/page-parachains/src/Auctions/WinBlock.tsx +++ b/packages/page-parachains/src/Auctions/WinBlock.tsx @@ -1,8 +1,6 @@ // Copyright 2017-2021 @polkadot/app-crowdloan authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type BN from 'bn.js'; -import type { BlockNumber } from '@polkadot/types/interfaces'; import type { Winning } from './types'; import React from 'react'; @@ -10,26 +8,22 @@ import React from 'react'; import WinRange from './WinRange'; interface Props { - bestNumber: BlockNumber; className?: string; isEven: boolean; isLatest: boolean; - offset: BN; value: Winning; } -function WinBlock ({ bestNumber, className = '', isEven, isLatest, offset, value: { blockNumber, winners } }: Props): React.ReactElement { +function WinBlock ({ className = '', isEven, isLatest, value: { blockNumber, winners } }: Props): React.ReactElement { return ( <> {winners.map((value, index) => ( ))} diff --git a/packages/page-parachains/src/Auctions/WinRange.tsx b/packages/page-parachains/src/Auctions/WinRange.tsx index 132f79d1af..56695bbd3e 100644 --- a/packages/page-parachains/src/Auctions/WinRange.tsx +++ b/packages/page-parachains/src/Auctions/WinRange.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 import type BN from 'bn.js'; -import type { BlockNumber } from '@polkadot/types/interfaces'; import type { WinnerData } from './types'; import React from 'react'; @@ -14,16 +13,14 @@ import { formatNumber } from '@polkadot/util'; import { useTranslation } from '../translate'; interface Props { - bestNumber: BlockNumber; - blockNumber: BlockNumber; + blockNumber: BN; className?: string; isFirst: boolean; isLatest: boolean; - offset: BN; value: WinnerData; } -function WinRanges ({ bestNumber, blockNumber, className = '', isFirst, isLatest, offset, value: { accountId, paraId, range, value } }: Props): React.ReactElement { +function WinRanges ({ blockNumber, className = '', isFirst, isLatest, value: { accountId, paraId, range, value } }: Props): React.ReactElement { const { t } = useTranslation(); return ( @@ -33,7 +30,7 @@ function WinRanges ({ bestNumber, blockNumber, className = '', isFirst, isLatest

{isLatest ? t('latest') - : <>#{formatNumber(bestNumber.sub(offset).iadd(blockNumber))} + : <>#{formatNumber(blockNumber)} }

)} diff --git a/packages/page-parachains/src/Auctions/index.tsx b/packages/page-parachains/src/Auctions/index.tsx index 28c9a41a11..a408bc1feb 100644 --- a/packages/page-parachains/src/Auctions/index.tsx +++ b/packages/page-parachains/src/Auctions/index.tsx @@ -8,7 +8,7 @@ import type { ITuple } from '@polkadot/types/types'; import React from 'react'; import { Button } from '@polkadot/react-components'; -import { useApi, useCall, useCallMulti } from '@polkadot/react-hooks'; +import { useApi, useCallMulti } from '@polkadot/react-hooks'; import Auction from './Auction'; import Bid from './Bid'; @@ -36,7 +36,6 @@ const optionsMulti = { function Auctions ({ className }: Props): React.ReactElement { const { api } = useApi(); - const bestNumber = useCall(api.derive.chain.bestNumber); const { auctionInfo, numAuctions } = useCallMulti([ api.query.auctions.auctionCounter, api.query.auctions.auctionInfo @@ -46,7 +45,6 @@ function Auctions ({ className }: Props): React.ReactElement {
@@ -54,7 +52,6 @@ function Auctions ({ className }: Props): React.ReactElement {
diff --git a/packages/page-parachains/src/Auctions/types.ts b/packages/page-parachains/src/Auctions/types.ts index 6c127a579a..97fa9b45e1 100644 --- a/packages/page-parachains/src/Auctions/types.ts +++ b/packages/page-parachains/src/Auctions/types.ts @@ -1,7 +1,8 @@ // Copyright 2017-2021 @polkadot/app-crowdloan authors & contributors // SPDX-License-Identifier: Apache-2.0 -import type { AccountId, BalanceOf, BlockNumber, ParaId } from '@polkadot/types/interfaces'; +import type BN from 'bn.js'; +import type { AccountId, BalanceOf, ParaId } from '@polkadot/types/interfaces'; export interface WinnerData { accountId: AccountId; @@ -11,6 +12,6 @@ export interface WinnerData { } export interface Winning { - blockNumber: BlockNumber; + blockNumber: BN; winners: WinnerData[]; } diff --git a/packages/page-parachains/src/Auctions/useWinningData.ts b/packages/page-parachains/src/Auctions/useWinningData.ts index 0983607ce6..653f6c1dc5 100644 --- a/packages/page-parachains/src/Auctions/useWinningData.ts +++ b/packages/page-parachains/src/Auctions/useWinningData.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import type { Option, StorageKey } from '@polkadot/types'; -import type { BlockNumber, WinningData } from '@polkadot/types/interfaces'; +import type { BlockNumber, LeasePeriodOf, WinningData } from '@polkadot/types/interfaces'; import type { WinnerData, Winning } from './types'; import { useEffect, useState } from 'react'; @@ -16,18 +16,10 @@ const RANGES = [ '3-3' ]; -function flattenData (winning: Winning[]): Winning[] { - return winning - .sort((a, b) => b.blockNumber.cmp(a.blockNumber)) - .filter(({ winners }, index, winning) => - index === 0 || - JSON.stringify({ winners }) !== JSON.stringify({ winners: winning[index - 1].winners }) - ); -} - -function extractData (values: [StorageKey<[BlockNumber]>, Option][]): Winning[] { - return flattenData( - values.reduce((winning, [{ args: [blockNumber] }, optData]): Winning[] => { +function extractData (endBlock: BlockNumber | null, values: [StorageKey<[BlockNumber]>, Option][]): Winning[] { + return values + .sort(([{ args: [a] }], [{ args: [b] }]) => a.cmp(b)) + .reduce((all: Winning[], [{ args: [blockOffset] }, optData]): Winning[] => { if (optData.isSome) { const winners = optData.unwrap().reduce((winners, optEntry, index): WinnerData[] => { if (optEntry.isSome) { @@ -39,17 +31,23 @@ function extractData (values: [StorageKey<[BlockNumber]>, Option][] return winners; }, []); - if (winners.length) { - winning.push({ blockNumber, winners }); - } + winners.length && ( + all.length === 0 || + JSON.stringify({ winners }) !== JSON.stringify({ winners: all[all.length - 1].winners }) + ) && all.push({ + blockNumber: endBlock + ? blockOffset.add(endBlock) + : blockOffset, + winners + }); } - return winning; + return all; }, []) - ); + .reverse(); } -export default function useWinningData (): Winning[] | null { +export default function useWinningData (auctionInfo: [LeasePeriodOf, BlockNumber] | null): Winning[] | null { const { api } = useApi(); const [winning, setWinning] = useState(null); const trigger = useEventTrigger([api.events.auctions.BidAccepted]); @@ -58,9 +56,11 @@ export default function useWinningData (): Winning[] | null { trigger && api.query.auctions.winning .entries, [BlockNumber]>() - .then((values) => setWinning(extractData(values))) + .then((values) => setWinning( + extractData(auctionInfo && auctionInfo[1], values)) + ) .catch(console.error); - }, [api, trigger]); + }, [api, auctionInfo, trigger]); return winning; } diff --git a/packages/page-parachains/src/Crowdloan/FundContribute.tsx b/packages/page-parachains/src/Crowdloan/FundContribute.tsx index 027ae992b1..0475c3e63f 100644 --- a/packages/page-parachains/src/Crowdloan/FundContribute.tsx +++ b/packages/page-parachains/src/Crowdloan/FundContribute.tsx @@ -5,11 +5,11 @@ import type BN from 'bn.js'; import type { UInt } from '@polkadot/types'; import type { Balance, ParaId } from '@polkadot/types/interfaces'; -import React, { useMemo, useState } from 'react'; +import React, { useState } from 'react'; import { Button, InputAddress, InputBalance, MarkWarning, Modal, TxButton } from '@polkadot/react-components'; import { useAccounts, useApi, useToggle } from '@polkadot/react-hooks'; -import { BN_ZERO, formatBalance } from '@polkadot/util'; +import { formatBalance } from '@polkadot/util'; import { useTranslation } from '../translate'; @@ -28,21 +28,19 @@ function FundContribute ({ cap, className, paraId, raised }: Props): React.React const [accountId, setAccountId] = useState(null); const [amount, setAmount] = useState(); - const maxAmount = useMemo( - () => cap.sub(raised), - [cap, raised] - ); - // TODO verifier signature + const remaining = cap.sub(raised); + const allowContribute = remaining.gte(api.consts.crowdloan.minContribution as UInt); const isAmountBelow = !amount || amount.lt(api.consts.crowdloan.minContribution as UInt); - const isAmountError = !amount || !amount.gt(BN_ZERO) || isAmountBelow; + const isAmountOver = !!(amount && amount.gt(remaining)); + const isAmountError = isAmountBelow || isAmountOver; return ( <>