From 9addb75024daf924257a93c3e4e0a96f72b33992 Mon Sep 17 00:00:00 2001 From: unclebill Date: Tue, 28 Dec 2021 12:07:35 +0800 Subject: [PATCH 1/6] fix: guarding gas config in useTransactionCallback --- .../plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx | 2 -- packages/mask/src/plugins/MaskBox/hooks/useContext.ts | 4 ++-- packages/web3-shared/evm/hooks/useTransactionCallback.ts | 8 ++++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx b/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx index e05288356c76..9fc88406b310 100644 --- a/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx +++ b/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx @@ -9,7 +9,6 @@ import { formatBalance, formatEthereumAddress, useAccount, - useProviderType, useChainId, useMaskBoxConstants, EthereumTokenType, @@ -115,7 +114,6 @@ export function DrawDialog(props: DrawDialogProps) { const providerDescriptor = useProviderDescriptor() const account = useAccount() const chainId = useChainId() - const providerType = useProviderType() const onCount = useCallback( (step: number) => { diff --git a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts index 771da1cbee62..fa2401af8bba 100644 --- a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts +++ b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts @@ -253,8 +253,8 @@ function useContext(initialState?: { boxId: string }) { const canPurchase = !isBalanceInsufficient && isQualified && !!boxInfo?.personalRemaining const allowToPurchase = boxState === BoxState.READY const isAllowanceEnough = isNativeToken ? true : costAmount.lte(erc20Allowance ?? '0') - const { value: openBoxTransactionGasLimit = 0 } = useAsyncRetry(async () => { - if (!openBoxTransaction || !canPurchase || !allowToPurchase || !isAllowanceEnough) return 0 + const { value: openBoxTransactionGasLimit } = useAsyncRetry(async () => { + if (!openBoxTransaction || !canPurchase || !allowToPurchase || !isAllowanceEnough) return const estimatedGas = await openBoxTransaction.method.estimateGas(omit(openBoxTransaction.config, 'gas')) return new BigNumber(estimatedGas).toNumber() }, [openBoxTransaction, canPurchase, allowToPurchase, isAllowanceEnough]) diff --git a/packages/web3-shared/evm/hooks/useTransactionCallback.ts b/packages/web3-shared/evm/hooks/useTransactionCallback.ts index 5d9cb51d6e75..327fb64f6694 100644 --- a/packages/web3-shared/evm/hooks/useTransactionCallback.ts +++ b/packages/web3-shared/evm/hooks/useTransactionCallback.ts @@ -21,9 +21,13 @@ export function useTransactionCallback( setState({ type: TransactionStateType.WAIT_FOR_CONFIRMING, }) + const gasExpectedConfig = { ...config } try { - await method.estimateGas(config) + const estimatedGas = await method.estimateGas(config) + if (!gasExpectedConfig.gas && estimatedGas) { + gasExpectedConfig.gas = estimatedGas + } } catch (error) { try { await method.call(config) @@ -38,7 +42,7 @@ export function useTransactionCallback( return new Promise(async (resolve, reject) => { method - .send(config) + .send(gasExpectedConfig) .once(TransactionEventType.TRANSACTION_HASH, (hash) => { if (type !== TransactionStateType.HASH) return setState({ From 4a0a8427ef271e27f8dc499eb5872ec90b28e9df Mon Sep 17 00:00:00 2001 From: unclebill Date: Tue, 28 Dec 2021 12:36:00 +0800 Subject: [PATCH 2/6] fixup! fix: guarding gas config in useTransactionCallback --- .../src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx b/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx index 9fc88406b310..496a222f8589 100644 --- a/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx +++ b/packages/mask/src/plugins/MaskBox/SNSAdaptor/components/DrawDialog.tsx @@ -254,7 +254,7 @@ export function DrawDialog(props: DrawDialogProps) { From c98784ab257b860de3b85e697ade3aa8d6f7a6db Mon Sep 17 00:00:00 2001 From: unclebill Date: Tue, 28 Dec 2021 13:08:18 +0800 Subject: [PATCH 3/6] refactor: formatCoutdown show tailing 0 time --- .../MaskBox/helpers/formatCountdown.ts | 20 ++++++++----------- .../src/plugins/MaskBox/hooks/useContext.ts | 6 +++--- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts b/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts index 5eccf880a8bb..fa63b74a4cc0 100644 --- a/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts +++ b/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts @@ -13,20 +13,16 @@ const units = [ export function formatCountdown(countdown: number) { if (countdown <= 0) return '' - const amounts: number[] = [] + const segs: string[] = [] - ;[msPerDay, msPerHour, msPerMinute, msPerSecond].reduce((accumulator, x) => { - amounts.push(Math.floor(accumulator / x)) + ;[msPerDay, msPerHour, msPerMinute, msPerSecond].reduce((accumulator, x, index, list) => { + const isLast = index === list.length - 1 + const value = isLast ? Math.ceil(accumulator / x) : Math.floor(accumulator / x) + if (segs.length !== 0 || value !== 0) { + segs.push(`${value} ${units[index][value === 1 ? 0 : 1]}`) + } return accumulator % x }, countdown) - return amounts - .map((x, i) => { - if (x <= 0) return '' - if (x === 1) return `${x} ${units[i][0]}` - return `${x} ${units[i][1]}` - }) - .filter(Boolean) - .join(' ') - .trim() + return segs.join(' ') } diff --git a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts index fa2401af8bba..95d3ef85db9b 100644 --- a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts +++ b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts @@ -92,8 +92,8 @@ function useContext(initialState?: { boxId: string }) { const totalComputed = total && remaining && remaining > total ? remaining : total const sold = Math.max(0, totalComputed - remaining) const personalRemaining = Math.max(0, personalLimit - purchasedTokens.length) - const startAt = Number.parseInt(maskBoxCreationSuccessEvent?.returnValues.start_time ?? '0', 10) - const endAt = Number.parseInt(maskBoxCreationSuccessEvent?.returnValues.end_time ?? '0', 10) + const startAt = Number.parseInt(maskBoxCreationSuccessEvent?.returnValues.start_time || '0', 10) + const endAt = Number.parseInt(maskBoxCreationSuccessEvent?.returnValues.end_time || '0', 10) const info: BoxInfo = { boxId, creator: maskBoxInfo.creator, @@ -186,7 +186,7 @@ function useContext(initialState?: { boxId: string }) { default: unreachable(boxState) } - }, [boxState, heartBit]) + }, [boxState, boxInfo?.startAt, heartBit]) //#endregion //#region the box metadata From c46d2abaa203cc6bc168487ab867a6a4275bde2b Mon Sep 17 00:00:00 2001 From: unclebill Date: Tue, 28 Dec 2021 13:19:41 +0800 Subject: [PATCH 4/6] fixup! refactor: formatCoutdown show tailing 0 time --- .../MaskBox/helpers/formatCountdown.ts | 31 +++---------------- .../src/plugins/MaskBox/hooks/useContext.ts | 2 +- 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts b/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts index fa63b74a4cc0..cc3936e9e087 100644 --- a/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts +++ b/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts @@ -1,28 +1,7 @@ -const msPerSecond = 1000 -const msPerMinute = msPerSecond * 60 -const msPerHour = msPerMinute * 60 -const msPerDay = msPerHour * 24 +import formatDuration from 'date-fns/formatDuration' +import intervalToDuration from 'date-fns/intervalToDuration' -const units = [ - ['day', 'days'], - ['hour', 'hours'], - ['minute', 'minutes'], - ['second', 'seconds'], -] - -export function formatCountdown(countdown: number) { - if (countdown <= 0) return '' - - const segs: string[] = [] - - ;[msPerDay, msPerHour, msPerMinute, msPerSecond].reduce((accumulator, x, index, list) => { - const isLast = index === list.length - 1 - const value = isLast ? Math.ceil(accumulator / x) : Math.floor(accumulator / x) - if (segs.length !== 0 || value !== 0) { - segs.push(`${value} ${units[index][value === 1 ? 0 : 1]}`) - } - return accumulator % x - }, countdown) - - return segs.join(' ') +export function formatCountdown(from: number, to: number) { + const duration = intervalToDuration({ start: from, end: to }) + return formatDuration(duration, { zero: true }) } diff --git a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts index 95d3ef85db9b..393d52385ea5 100644 --- a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts +++ b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts @@ -173,7 +173,7 @@ function useContext(initialState?: { boxId: string }) { const now = Date.now() const startAt = boxInfo?.startAt.getTime() ?? 0 if (startAt <= now) return 'Loading...' - const countdown = formatCountdown(startAt - now) + const countdown = formatCountdown(startAt, now) return countdown ? `Start sale in ${countdown}` : 'Loading...' case BoxState.SOLD_OUT: return 'Sold Out' From ae0f8bb3ba94fd80f03fb36bd06b3f2477051279 Mon Sep 17 00:00:00 2001 From: guanbinrui <52657989+guanbinrui@users.noreply.github.com> Date: Tue, 28 Dec 2021 16:51:54 +0800 Subject: [PATCH 5/6] refactor: compact code (#5333) * refactor: move now out of hooks * refactor: remove gas * refactor: heartBit to heartBeat --- .../mask/src/plugins/MaskBox/hooks/useContext.ts | 16 ++++++++-------- .../hooks/{useHeartBit.ts => useHeartBeat.ts} | 2 +- .../evm/hooks/useTransactionCallback.ts | 3 ++- 3 files changed, 11 insertions(+), 10 deletions(-) rename packages/mask/src/plugins/MaskBox/hooks/{useHeartBit.ts => useHeartBeat.ts} (85%) diff --git a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts index 393d52385ea5..ce8a8aba6ab7 100644 --- a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts +++ b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts @@ -35,12 +35,13 @@ import { useMaskBoxPurchasedTokens } from './useMaskBoxPurchasedTokens' import { formatCountdown } from '../helpers/formatCountdown' import { useOpenBoxTransaction } from './useOpenBoxTransaction' import { useMaskBoxMetadata } from './useMaskBoxMetadata' -import { useHeartBit } from './useHeartBit' +import { useHeartBeat } from './useHeartBeat' import { useIsWhitelisted } from './useIsWhitelisted' import { isGreaterThanOrEqualTo, isLessThanOrEqualTo, isZero, multipliedBy } from '@masknet/web3-shared-base' function useContext(initialState?: { boxId: string }) { - const heartBit = useHeartBit() + const now = new Date() + const heartBeat = useHeartBeat() const account = useAccount() const chainId = useChainId() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants(ChainId.Mainnet) @@ -139,13 +140,12 @@ function useContext(initialState?: { boxId: string }) { if (maskBoxInfo && !boxInfo) return BoxState.UNKNOWN if (!maskBoxInfo || !maskBoxStatus || !boxInfo) return BoxState.NOT_FOUND if (maskBoxStatus.canceled) return BoxState.CANCELED - const now = new Date() if (isGreaterThanOrEqualTo(boxInfo.tokenIdsPurchased.length, boxInfo.personalLimit)) return BoxState.DRAWED_OUT if (isLessThanOrEqualTo(boxInfo.remaining, 0)) return BoxState.SOLD_OUT if (boxInfo.startAt > now) return BoxState.NOT_READY if (boxInfo.endAt < now || maskBoxStatus?.expired) return BoxState.EXPIRED return BoxState.READY - }, [boxInfo, loadingBoxInfo, errorBoxInfo, maskBoxInfo, loadingMaskBoxInfo, errorMaskBoxInfo, heartBit]) + }, [boxInfo, loadingBoxInfo, errorBoxInfo, maskBoxInfo, loadingMaskBoxInfo, errorMaskBoxInfo, heartBeat]) const isWhitelisted = useIsWhitelisted(boxInfo?.qualificationAddress, account) const isQualifiedByContract = @@ -170,10 +170,10 @@ function useContext(initialState?: { boxId: string }) { case BoxState.EXPIRED: return 'Ended' case BoxState.NOT_READY: - const now = Date.now() + const nowAt = now.getTime() const startAt = boxInfo?.startAt.getTime() ?? 0 - if (startAt <= now) return 'Loading...' - const countdown = formatCountdown(startAt, now) + if (startAt <= nowAt) return 'Loading...' + const countdown = formatCountdown(startAt, nowAt) return countdown ? `Start sale in ${countdown}` : 'Loading...' case BoxState.SOLD_OUT: return 'Sold Out' @@ -186,7 +186,7 @@ function useContext(initialState?: { boxId: string }) { default: unreachable(boxState) } - }, [boxState, boxInfo?.startAt, heartBit]) + }, [boxState, boxInfo?.startAt, heartBeat]) //#endregion //#region the box metadata diff --git a/packages/mask/src/plugins/MaskBox/hooks/useHeartBit.ts b/packages/mask/src/plugins/MaskBox/hooks/useHeartBeat.ts similarity index 85% rename from packages/mask/src/plugins/MaskBox/hooks/useHeartBit.ts rename to packages/mask/src/plugins/MaskBox/hooks/useHeartBeat.ts index 13d5662e5b61..8d476c76cb68 100644 --- a/packages/mask/src/plugins/MaskBox/hooks/useHeartBit.ts +++ b/packages/mask/src/plugins/MaskBox/hooks/useHeartBeat.ts @@ -1,7 +1,7 @@ import { useState } from 'react' import { useTimeoutFn } from 'react-use' -export function useHeartBit(delay = 1000) { +export function useHeartBeat(delay = 1000) { const [bit, setBit] = useState(0) const [, , reset] = useTimeoutFn(() => { setBit((x) => (x + 1) % Number.MAX_SAFE_INTEGER) diff --git a/packages/web3-shared/evm/hooks/useTransactionCallback.ts b/packages/web3-shared/evm/hooks/useTransactionCallback.ts index 327fb64f6694..7bb891671b27 100644 --- a/packages/web3-shared/evm/hooks/useTransactionCallback.ts +++ b/packages/web3-shared/evm/hooks/useTransactionCallback.ts @@ -1,4 +1,5 @@ import { useCallback } from 'react' +import { omit } from 'lodash-unified' import type { PayableTransactionObject, PayableTx } from '@masknet/web3-contracts/types/types' import { useTransactionState } from './useTransactionState' import { TransactionStateType, TransactionEventType } from '../types' @@ -24,7 +25,7 @@ export function useTransactionCallback( const gasExpectedConfig = { ...config } try { - const estimatedGas = await method.estimateGas(config) + const estimatedGas = await method.estimateGas(omit(config, 'gas')) if (!gasExpectedConfig.gas && estimatedGas) { gasExpectedConfig.gas = estimatedGas } From 7ad838bfd3d4988dc11e6e4c406eda7d78dc3e13 Mon Sep 17 00:00:00 2001 From: unclebill Date: Tue, 28 Dec 2021 16:24:30 +0800 Subject: [PATCH 6/6] fixup! fixup! refactor: formatCoutdown show tailing 0 time --- .../plugins/MaskBox/helpers/formatCountdown.ts | 2 +- .../src/plugins/MaskBox/hooks/useContext.ts | 18 +++++++++++++++--- packages/mask/src/plugins/MaskBox/type.ts | 1 + 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts b/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts index cc3936e9e087..8822c226016a 100644 --- a/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts +++ b/packages/mask/src/plugins/MaskBox/helpers/formatCountdown.ts @@ -3,5 +3,5 @@ import intervalToDuration from 'date-fns/intervalToDuration' export function formatCountdown(from: number, to: number) { const duration = intervalToDuration({ start: from, end: to }) - return formatDuration(duration, { zero: true }) + return formatDuration(duration) } diff --git a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts index ce8a8aba6ab7..6307de000073 100644 --- a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts +++ b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts @@ -106,6 +106,7 @@ function useContext(initialState?: { boxId: string }) { availableAmount: Math.min(personalRemaining, remaining), startAt: startAt === 0 ? subDays(new Date(), 1) : fromUnixTime(startAt), endAt: endAt === 0 ? addDays(new Date(), 1) : fromUnixTime(endAt), + started: maskBoxStatus.started, total: totalComputed, sold, canceled: maskBoxStatus.canceled, @@ -136,13 +137,15 @@ function useContext(initialState?: { boxId: string }) { const boxState = useMemo(() => { if (errorMaskBoxInfo || errorMaskBoxStatus || errorBoxInfo) return BoxState.ERROR - if (loadingMaskBoxInfo || loadingMaskBoxStatus || loadingBoxInfo) return BoxState.UNKNOWN + if (loadingMaskBoxInfo || loadingMaskBoxStatus || loadingBoxInfo) { + if (!maskBoxInfo && !boxInfo) return BoxState.UNKNOWN + } if (maskBoxInfo && !boxInfo) return BoxState.UNKNOWN if (!maskBoxInfo || !maskBoxStatus || !boxInfo) return BoxState.NOT_FOUND if (maskBoxStatus.canceled) return BoxState.CANCELED if (isGreaterThanOrEqualTo(boxInfo.tokenIdsPurchased.length, boxInfo.personalLimit)) return BoxState.DRAWED_OUT if (isLessThanOrEqualTo(boxInfo.remaining, 0)) return BoxState.SOLD_OUT - if (boxInfo.startAt > now) return BoxState.NOT_READY + if (boxInfo.startAt > now || !boxInfo.started) return BoxState.NOT_READY if (boxInfo.endAt < now || maskBoxStatus?.expired) return BoxState.EXPIRED return BoxState.READY }, [boxInfo, loadingBoxInfo, errorBoxInfo, maskBoxInfo, loadingMaskBoxInfo, errorMaskBoxInfo, heartBeat]) @@ -172,7 +175,7 @@ function useContext(initialState?: { boxId: string }) { case BoxState.NOT_READY: const nowAt = now.getTime() const startAt = boxInfo?.startAt.getTime() ?? 0 - if (startAt <= nowAt) return 'Loading...' + if (startAt <= nowAt) return 'Syncing status...' const countdown = formatCountdown(startAt, nowAt) return countdown ? `Start sale in ${countdown}` : 'Loading...' case BoxState.SOLD_OUT: @@ -187,6 +190,15 @@ function useContext(initialState?: { boxId: string }) { unreachable(boxState) } }, [boxState, boxInfo?.startAt, heartBeat]) + + useEffect(() => { + if (!boxInfo || boxInfo.started) return + + if (boxInfo.startAt < now) { + retryMaskBoxStatus() + } + }, [boxInfo, heartBeat]) + //#endregion //#region the box metadata diff --git a/packages/mask/src/plugins/MaskBox/type.ts b/packages/mask/src/plugins/MaskBox/type.ts index 7f9426a78aa3..3e0bb2b64368 100644 --- a/packages/mask/src/plugins/MaskBox/type.ts +++ b/packages/mask/src/plugins/MaskBox/type.ts @@ -47,6 +47,7 @@ export interface BoxInfo { sold: number startAt: Date endAt: Date + started: boolean tokenIds: string[] tokenIdsPurchased: string[] tokenAddress: string