Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -97,8 +97,11 @@ export function RedPacketConfirmDialog(props: ConfirmRedPacketFormProps) {
)!
const [{ loading: isCreating }, createCallback] = useCreateCallback(settings!, contract_version, publicKey)
const openShareTxDialog = useOpenShareTxDialog()
const connection = useWeb3Connection(NetworkPluginID.PLUGIN_EVM)
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,
Expand Down
26 changes: 9 additions & 17 deletions packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacketNft.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -258,35 +258,27 @@ 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))
}, [payload])

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()
Expand Down Expand Up @@ -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()}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
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

export function useClaimNftRedpacketCallback(id: string, totalAmount: number | undefined, signedMsg: string) {
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(NetworkPluginID.PLUGIN_EVM)
return useAsyncFn(async () => {
if (!nftRedPacketContract || !id || !signedMsg || !account || !totalAmount) {
setClaimState({
type: TransactionStateType.UNKNOWN,
})
return
}

Expand All @@ -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<void>(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])
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
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'

Expand Down Expand Up @@ -112,6 +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(NetworkPluginID.PLUGIN_EVM)

return useAsyncFn(async () => {
const { token } = redPacketSettings
Expand All @@ -133,23 +132,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<TransactionReceipt>(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])
}
Original file line number Diff line number Diff line change
@@ -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(NetworkPluginID.PLUGIN_EVM)

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<string>((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
}