From 56e269eb96828af4936b95e0719f276709dcf908 Mon Sep 17 00:00:00 2001 From: unclebill Date: Tue, 14 Jun 2022 22:11:32 +0800 Subject: [PATCH 1/3] fix: send red packet tx --- .../SNSAdaptor/RedPacketConfirmDialog.tsx | 7 ++-- .../SNSAdaptor/hooks/useCreateCallback.tsx | 35 +++++++++---------- .../SNSAdaptor/hooks/useRefundCallback.ts | 35 +++++-------------- 3 files changed, 31 insertions(+), 46 deletions(-) diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketConfirmDialog.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketConfirmDialog.tsx index 00e2c25b6088..91e64c8dd6b7 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketConfirmDialog.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketConfirmDialog.tsx @@ -9,7 +9,7 @@ import { FormattedBalance, useOpenShareTxDialog } from '@masknet/shared' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import { useI18N } from '../locales' import { RedPacketSettings, useCreateCallback } from './hooks/useCreateCallback' -import { useAccount, useChainId, useNetworkType, useWeb3 } from '@masknet/plugin-infra/web3' +import { useAccount, useChainId, useNetworkType, useWeb3, useWeb3Connection } from '@masknet/plugin-infra/web3' import { NetworkPluginID, formatBalance } from '@masknet/web3-shared-base' import type { RedPacketJSONPayload, RedPacketRecord } from '../types' import { RedPacketRPC } from '../messages' @@ -97,8 +97,11 @@ export function RedPacketConfirmDialog(props: ConfirmRedPacketFormProps) { )! const [{ loading: isCreating }, createCallback] = useCreateCallback(settings!, contract_version, publicKey) const openShareTxDialog = useOpenShareTxDialog() + const connection = useWeb3Connection() const createRedpacket = useCallback(async () => { - const receipt = await createCallback() + const hash = await createCallback() + if (typeof hash !== 'string') return + const receipt = await connection.getTransactionReceipt(hash) if (typeof receipt?.transactionHash !== 'string') return await openShareTxDialog({ hash: receipt.transactionHash, diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useCreateCallback.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useCreateCallback.tsx index 8e8792fbf12f..3a1750f7936f 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useCreateCallback.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useCreateCallback.tsx @@ -1,12 +1,15 @@ import { useCallback } from 'react' import { useAsyncFn } from 'react-use' import Web3Utils from 'web3-utils' -import type { TransactionReceipt } from 'web3-core' -import { useAccount, useChainId } from '@masknet/plugin-infra/web3' +import { useAccount, useChainId, useWeb3Connection } from '@masknet/plugin-infra/web3' import type { HappyRedPacketV4 } from '@masknet/web3-contracts/types/HappyRedPacketV4' -import type { PayableTx } from '@masknet/web3-contracts/types/types' import { FungibleToken, isLessThan, NetworkPluginID, toFixed } from '@masknet/web3-shared-base' -import { ChainId, SchemaType, TransactionEventType, useTokenConstants } from '@masknet/web3-shared-evm' +import { + ChainId, + encodeTransaction, + SchemaType, + useTokenConstants, +} from '@masknet/web3-shared-evm' import { omit } from 'lodash-unified' import { useRedPacketContract } from './useRedPacketContract' @@ -112,6 +115,7 @@ export function useCreateCallback(redPacketSettings: RedPacketSettings, version: const chainId = useChainId(NetworkPluginID.PLUGIN_EVM) const redPacketContract = useRedPacketContract(chainId, version) const getCreateParams = useCreateParams(redPacketSettings, version, publicKey) + const connection = useWeb3Connection() return useAsyncFn(async () => { const { token } = redPacketSettings @@ -133,23 +137,18 @@ export function useCreateCallback(redPacketSettings: RedPacketSettings, version: // estimate gas and compose transaction const value = toFixed(token.schema === SchemaType.Native ? paramsObj.total : 0) - const config: PayableTx = { + const config = { from: account, value, gas, } - // send transaction and wait for hash - return new Promise(async (resolve, reject) => { - redPacketContract.methods - .create_red_packet(...params) - .send(config) - .on(TransactionEventType.CONFIRMATION, (no, receipt) => { - resolve(receipt) - }) - .on(TransactionEventType.ERROR, (error: Error) => { - reject(error) - }) - }) - }, [account, redPacketContract, redPacketSettings, chainId, getCreateParams]) + const tx = await encodeTransaction( + redPacketContract, + redPacketContract.methods.create_red_packet(...params), + config, + ) + + return connection.sendTransaction(tx) + }, [account, connection, redPacketContract, redPacketSettings, chainId, getCreateParams]) } diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRefundCallback.ts b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRefundCallback.ts index 819bf6550d9e..04d03b7ae0f0 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRefundCallback.ts +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRefundCallback.ts @@ -1,45 +1,28 @@ +import { useChainId, useWeb3Connection } from '@masknet/plugin-infra/web3' +import { NetworkPluginID } from '@masknet/web3-shared-base' +import { encodeTransaction } from '@masknet/web3-shared-evm' import { useState } from 'react' import { useAsyncFn } from 'react-use' import { useRedPacketContract } from './useRedPacketContract' -import { TransactionEventType } from '@masknet/web3-shared-evm' -import type { NonPayableTx } from '@masknet/web3-contracts/types/types' -import { useChainId } from '@masknet/plugin-infra/web3' -import { NetworkPluginID } from '@masknet/web3-shared-base' export function useRefundCallback(version: number, from: string, id?: string) { const chainId = useChainId(NetworkPluginID.PLUGIN_EVM) const [isRefunded, setIsRefunded] = useState(false) const redPacketContract = useRedPacketContract(chainId, version) + const connection = useWeb3Connection() const [state, refundCallback] = useAsyncFn(async () => { if (!redPacketContract || !id) return setIsRefunded(false) - // estimate gas and compose transaction const config = { from, - gas: await redPacketContract.methods - .refund(id) - .estimateGas({ - from, - }) - .catch((error) => { - throw error - }), } - - // step 2: blocking - return new Promise((resolve, reject) => { - redPacketContract.methods - .refund(id) - .send(config as NonPayableTx) - .once(TransactionEventType.CONFIRMATION, (_, receipt) => { - resolve(receipt.transactionHash) - setIsRefunded(true) - }) - .once(TransactionEventType.ERROR, reject) - }) - }, [id, redPacketContract, from]) + const tx = await encodeTransaction(redPacketContract, redPacketContract.methods.refund(id), config) + const hash = await connection.sendTransaction(tx) + setIsRefunded(true) + return hash + }, [id, redPacketContract, from, connection]) return [state, isRefunded, refundCallback] as const } From 4ccca3ad19958f54d3ba51dae9a2f5097a10e12c Mon Sep 17 00:00:00 2001 From: unclebill Date: Tue, 14 Jun 2022 22:22:25 +0800 Subject: [PATCH 2/3] fix: simplify nft redpacket --- .../RedPacket/SNSAdaptor/RedPacketNft.tsx | 26 +++----- .../hooks/useClaimNftRedpacketCallback.ts | 65 +++---------------- 2 files changed, 18 insertions(+), 73 deletions(-) diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNft.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNft.tsx index 7a755fcde1ec..5abe095bada5 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNft.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNft.tsx @@ -1,5 +1,5 @@ import { makeStyles } from '@masknet/theme' -import { explorerResolver, TransactionStateType, networkResolver } from '@masknet/web3-shared-evm' +import { explorerResolver, networkResolver } from '@masknet/web3-shared-evm' import LaunchIcon from '@mui/icons-material/Launch' import { Card, CardHeader, Typography, Link, CardMedia, CardContent, Button, Box, Skeleton } from '@mui/material' import { useCallback, useEffect, useMemo, useState } from 'react' @@ -258,13 +258,18 @@ export function RedPacketNft({ payload }: RedPacketNftProps) { retry: retryAvailability, error: availabilityError, } = useAvailabilityNftRedPacket(payload.id, account, payload.chainId) - const [claimState, claimCallback, resetCallback] = useClaimNftRedpacketCallback( + const [{ loading: isClaiming }, claimCallback] = useClaimNftRedpacketCallback( payload.id, availability?.totalAmount, web3?.eth.accounts.sign(account, payload.privateKey).signature ?? '', ) - const isClaiming = claimState.type === TransactionStateType.WAIT_FOR_CONFIRMING + const claim = useCallback(async () => { + const hash = await claimCallback() + if (typeof hash === 'string') { + retryAvailability() + } + }, [claimCallback, retryAvailability]) const openAddressLinkOnExplorer = useCallback(() => { openWindow(explorerResolver.addressLink(payload.chainId, payload.contractAddress)) @@ -272,21 +277,8 @@ export function RedPacketNft({ payload }: RedPacketNftProps) { const [sourceType, setSourceType] = useState('') - useEffect(() => { - if (![TransactionStateType.CONFIRMED, TransactionStateType.FAILED].includes(claimState.type)) { - return - } - - if (claimState.type === TransactionStateType.CONFIRMED && claimState.no === 0) { - retryAvailability() - } - - resetCallback() - }, [claimState.type, retryAvailability]) - useEffect(() => { retryAvailability() - resetCallback() }, [account]) const rpNftImg = new URL('./assets/redpacket.nft.png', import.meta.url).toString() @@ -452,7 +444,7 @@ export function RedPacketNft({ payload }: RedPacketNftProps) { variant="contained" loading={isClaiming} disabled={isClaiming} - onClick={claimCallback} + onClick={claim} className={classes.button} fullWidth> {isClaiming ? t.claiming() : t.claim()} diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useClaimNftRedpacketCallback.ts b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useClaimNftRedpacketCallback.ts index af9a8d12cfce..b1175d2bf16c 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useClaimNftRedpacketCallback.ts +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useClaimNftRedpacketCallback.ts @@ -1,12 +1,9 @@ -import { useCallback } from 'react' -import type { TransactionReceipt } from 'web3-core' -import { useAccount, useChainId } from '@masknet/plugin-infra/web3' +import { useAccount, useChainId, useWeb3Connection } from '@masknet/plugin-infra/web3' +import type { NftRedPacket } from '@masknet/web3-contracts/types/NftRedPacket' import { NetworkPluginID } from '@masknet/web3-shared-base' -import { TransactionStateType, TransactionEventType } from '@masknet/web3-shared-evm' +import { encodeTransaction } from '@masknet/web3-shared-evm' +import { useAsyncFn } from 'react-use' import { useNftRedPacketContract } from './useNftRedPacketContract' -import type { NonPayableTx } from '@masknet/web3-contracts/types/types' -import type { NftRedPacket } from '@masknet/web3-contracts/types/NftRedPacket' -import { useTransactionState } from '@masknet/plugin-infra/web3-evm' const EXTRA_GAS_PER_NFT = 335 @@ -14,12 +11,9 @@ export function useClaimNftRedpacketCallback(id: string, totalAmount: number | u const account = useAccount(NetworkPluginID.PLUGIN_EVM) const chainId = useChainId(NetworkPluginID.PLUGIN_EVM) const nftRedPacketContract = useNftRedPacketContract(chainId) - const [claimState, setClaimState] = useTransactionState() - const claimCallback = useCallback(async () => { + const connection = useWeb3Connection() + return useAsyncFn(async () => { if (!nftRedPacketContract || !id || !signedMsg || !account || !totalAmount) { - setClaimState({ - type: TransactionStateType.UNKNOWN, - }) return } @@ -34,54 +28,13 @@ export function useClaimNftRedpacketCallback(id: string, totalAmount: number | u .claim(...params) .estimateGas({ from: account }) .catch((error) => { - setClaimState({ type: TransactionStateType.FAILED, error }) throw error })) + EXTRA_GAS_PER_NFT * totalAmount, chainId, } - setClaimState({ - type: TransactionStateType.WAIT_FOR_CONFIRMING, - }) - - return new Promise(async (resolve, reject) => { - nftRedPacketContract.methods - .claim(...params) - .send(config as NonPayableTx) - .on(TransactionEventType.RECEIPT, (receipt: TransactionReceipt) => { - setClaimState({ - type: TransactionStateType.CONFIRMED, - no: 0, - receipt, - }) - resolve() - }) - .on(TransactionEventType.CONFIRMATION, (no: number, receipt: TransactionReceipt) => { - if (claimState.type === TransactionStateType.CONFIRMED) return - - setClaimState({ - type: TransactionStateType.CONFIRMED, - no: 0, - receipt, - }) - resolve() - }) - .on(TransactionEventType.ERROR, (error: Error) => { - setClaimState({ - type: TransactionStateType.FAILED, - error, - }) - reject(error) - }) - }) - }, [id, signedMsg, account, chainId, totalAmount, claimState]) - - const resetCallback = useCallback(() => { - setClaimState({ - type: TransactionStateType.UNKNOWN, - }) - }, [account]) - - return [claimState, claimCallback, resetCallback] as const + const tx = await encodeTransaction(nftRedPacketContract, nftRedPacketContract.methods.claim(...params), config) + return connection.sendTransaction(tx) + }, [id, connection, signedMsg, account, chainId, totalAmount]) } From 94d478413a4bb19fe1fa151e9decaafca1b91b77 Mon Sep 17 00:00:00 2001 From: unclebill Date: Tue, 14 Jun 2022 22:31:45 +0800 Subject: [PATCH 3/3] fixup! fix: simplify nft redpacket --- .../RedPacket/SNSAdaptor/RedPacketConfirmDialog.tsx | 2 +- .../SNSAdaptor/hooks/useClaimNftRedpacketCallback.ts | 2 +- .../RedPacket/SNSAdaptor/hooks/useCreateCallback.tsx | 9 ++------- .../RedPacket/SNSAdaptor/hooks/useRefundCallback.ts | 2 +- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketConfirmDialog.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketConfirmDialog.tsx index 91e64c8dd6b7..db3918f4badb 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketConfirmDialog.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketConfirmDialog.tsx @@ -97,7 +97,7 @@ export function RedPacketConfirmDialog(props: ConfirmRedPacketFormProps) { )! const [{ loading: isCreating }, createCallback] = useCreateCallback(settings!, contract_version, publicKey) const openShareTxDialog = useOpenShareTxDialog() - const connection = useWeb3Connection() + const connection = useWeb3Connection(NetworkPluginID.PLUGIN_EVM) const createRedpacket = useCallback(async () => { const hash = await createCallback() if (typeof hash !== 'string') return diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useClaimNftRedpacketCallback.ts b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useClaimNftRedpacketCallback.ts index b1175d2bf16c..a686c8434448 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useClaimNftRedpacketCallback.ts +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useClaimNftRedpacketCallback.ts @@ -11,7 +11,7 @@ export function useClaimNftRedpacketCallback(id: string, totalAmount: number | u const account = useAccount(NetworkPluginID.PLUGIN_EVM) const chainId = useChainId(NetworkPluginID.PLUGIN_EVM) const nftRedPacketContract = useNftRedPacketContract(chainId) - const connection = useWeb3Connection() + const connection = useWeb3Connection(NetworkPluginID.PLUGIN_EVM) return useAsyncFn(async () => { if (!nftRedPacketContract || !id || !signedMsg || !account || !totalAmount) { return diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useCreateCallback.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useCreateCallback.tsx index 3a1750f7936f..b7af97327970 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useCreateCallback.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useCreateCallback.tsx @@ -4,12 +4,7 @@ import Web3Utils from 'web3-utils' import { useAccount, useChainId, useWeb3Connection } from '@masknet/plugin-infra/web3' import type { HappyRedPacketV4 } from '@masknet/web3-contracts/types/HappyRedPacketV4' import { FungibleToken, isLessThan, NetworkPluginID, toFixed } from '@masknet/web3-shared-base' -import { - ChainId, - encodeTransaction, - SchemaType, - useTokenConstants, -} from '@masknet/web3-shared-evm' +import { ChainId, encodeTransaction, SchemaType, useTokenConstants } from '@masknet/web3-shared-evm' import { omit } from 'lodash-unified' import { useRedPacketContract } from './useRedPacketContract' @@ -115,7 +110,7 @@ export function useCreateCallback(redPacketSettings: RedPacketSettings, version: const chainId = useChainId(NetworkPluginID.PLUGIN_EVM) const redPacketContract = useRedPacketContract(chainId, version) const getCreateParams = useCreateParams(redPacketSettings, version, publicKey) - const connection = useWeb3Connection() + const connection = useWeb3Connection(NetworkPluginID.PLUGIN_EVM) return useAsyncFn(async () => { const { token } = redPacketSettings diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRefundCallback.ts b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRefundCallback.ts index 04d03b7ae0f0..c77012aa468f 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRefundCallback.ts +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRefundCallback.ts @@ -9,7 +9,7 @@ export function useRefundCallback(version: number, from: string, id?: string) { const chainId = useChainId(NetworkPluginID.PLUGIN_EVM) const [isRefunded, setIsRefunded] = useState(false) const redPacketContract = useRedPacketContract(chainId, version) - const connection = useWeb3Connection() + const connection = useWeb3Connection(NetworkPluginID.PLUGIN_EVM) const [state, refundCallback] = useAsyncFn(async () => { if (!redPacketContract || !id) return