Skip to content

Commit

Permalink
fix: transfer bugfix (DimensionDev#5646)
Browse files Browse the repository at this point in the history
* fix: bugfix

* feat: add default input coin in trader

* fix: bugfix

* fix: add gas margin with max amount

* fix: ui style

* fix: add right icon
  • Loading branch information
albert-0229 authored Feb 15, 2022
1 parent 0222a8f commit 7a67211
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ import { useUpdateEffect } from 'react-use'
import { v4 as uuid } from 'uuid'
import { PluginMessages } from '../../../../API'
import type { SelectTokenDialogEvent } from '@masknet/plugin-wallet'
import { RightIcon } from '@masknet/icons'

interface TransferERC20Props {
token: FungibleTokenDetailed
}

const GAS_LIMIT = 30000
const GAS_LIMIT = 21000
export const TransferERC20 = memo<TransferERC20Props>(({ token }) => {
const t = useDashboardI18N()
const { NATIVE_TOKEN_ADDRESS } = useTokenConstants()
Expand Down Expand Up @@ -101,7 +102,7 @@ export const TransferERC20 = memo<TransferERC20Props>(({ token }) => {
transferAmount,
EthereumAddress.isValid(address) ? address : registeredAddress,
)
const { gasConfig, onCustomGasSetting, gasLimit, maxFee } = useGasConfig(gasLimit_, 30000)
const { gasConfig, onCustomGasSetting, gasLimit, maxFee } = useGasConfig(gasLimit_, GAS_LIMIT)

const gasPrice = gasConfig.gasPrice || defaultGasPrice

Expand All @@ -111,15 +112,18 @@ export const TransferERC20 = memo<TransferERC20Props>(({ token }) => {

const gasFee = useMemo(() => {
const price = is1559Supported && maxFee ? new BigNumber(maxFee) : gasPrice
return multipliedBy(addGasMargin(gasLimit), price)
return multipliedBy(gasLimit, price)
}, [gasLimit, gasPrice, maxFee, is1559Supported])
const gasFeeInUsd = formatWeiToEther(gasFee).multipliedBy(nativeTokenPrice)

const maxAmount = useMemo(() => {
const price = is1559Supported && maxFee ? new BigNumber(maxFee) : gasPrice
const gasFee = multipliedBy(addGasMargin(gasLimit), price)

let amount_ = new BigNumber(tokenBalance || '0')
amount_ = selectedToken.type === EthereumTokenType.Native ? amount_.minus(gasFee) : amount_
return BigNumber.max(0, amount_).toFixed()
}, [tokenBalance, gasPrice, selectedToken?.type, amount])
}, [tokenBalance, gasPrice, selectedToken?.type, amount, gasLimit, maxFee, is1559Supported])

const [transferState, transferCallback, resetTransferCallback] = useTokenTransferCallback(
tokenType,
Expand Down Expand Up @@ -177,7 +181,7 @@ export const TransferERC20 = memo<TransferERC20Props>(({ token }) => {
if (resolveDomainLoading) return
if (registeredAddress) {
return (
<Box style={{ padding: 10 }}>
<Box style={{ padding: 10, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Link
href={Utils?.resolveDomainLink?.(address)}
target="_blank"
Expand All @@ -195,6 +199,7 @@ export const TransferERC20 = memo<TransferERC20Props>(({ token }) => {
<FormattedAddress address={registeredAddress} size={4} formatter={Utils?.formatAddress} />
</Typography>
</Link>
<RightIcon />
</Box>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { NetworkType } from '@masknet/public-api'
import { useAsync, useUpdateEffect } from 'react-use'
import { multipliedBy } from '@masknet/web3-shared-base'
import { Services } from '../../../../API'
import { RightIcon } from '@masknet/icons'

const useStyles = makeStyles()((theme) => ({
disabled: {
Expand Down Expand Up @@ -226,7 +227,7 @@ export const TransferERC721 = memo(() => {
if (resolveDomainLoading) return
if (registeredAddress) {
return (
<Box style={{ padding: 10 }}>
<Box style={{ padding: 10, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Link
href={Utils?.resolveDomainLink?.(allFormFields.recipient)}
target="_blank"
Expand All @@ -243,6 +244,7 @@ export const TransferERC721 = memo(() => {
<FormattedAddress address={registeredAddress} size={4} formatter={Utils?.formatAddress} />
</Typography>
</Link>
<RightIcon />
</Box>
)
}
Expand Down
4 changes: 1 addition & 3 deletions packages/mask/src/components/shared/ApplicationBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,7 @@ export function ApplicationBoard({ secondEntries, secondEntryChainTabs }: MaskAp
{isFindTrumanDialogOpen ? <FindTrumanDialog open onClose={onFindTrumanDialogClose} /> : null}
{isSwapDialogOpen ? <TraderDialog open onClose={onSwapDialogClose} /> : null}

{isSavingsDialogOpen ? (
<SavingsDialog open onClose={onSavingsDialogClose} onSwapDialogOpen={onSwapDialogOpen} />
) : null}
{isSavingsDialogOpen ? <SavingsDialog open onClose={onSavingsDialogClose} /> : null}
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,13 @@ async function requestSend(
) {
id += 1
const notifyProgress = isSendMethod(payload.method as EthereumMethodType)
const { providerType = currentProviderSettings.value, chainId = currentChainIdSettings.value } = overrides ?? {}
const { providerType = currentProviderSettings.value } = overrides ?? {}

const chainId =
overrides?.chainId ?? providerType === ProviderType.MaskWallet
? currentMaskWalletChainIdSettings.value
: currentChainIdSettings.value

const { popupsWindow = true } = options ?? {}

const payload_ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ export const Prior1559Transfer = memo<Prior1559TransferProps>(({ selectedAsset,
? amount_.minus(multipliedBy(30000, gasPrice))
: amount_

return amount_.toFixed()
return BigNumber.max(0, amount_).toFixed()
}, [selectedAsset?.balance, gasPrice, selectedAsset?.token.type, tokenBalance])

// #region set default gasLimit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,11 +365,10 @@ export const Transfer1559 = memo<Transfer1559Props>(({ selectedAsset, openAssetM
)

const maxAmount = useMemo(() => {
const gasFee = formatGweiToWei(new BigNumber(maxFeePerGas ?? 0)).multipliedBy(addGasMargin(MIN_GAS_LIMIT))

const gasFee = formatGweiToWei(maxFeePerGas ?? 0).multipliedBy(addGasMargin(minGasLimit ?? MIN_GAS_LIMIT))
let amount_ = new BigNumber(tokenBalance ?? 0)
amount_ = selectedAsset?.token.type === EthereumTokenType.Native ? amount_.minus(gasFee) : amount_
return formatBalance(amount_.toFixed(), selectedAsset?.token.decimals)
return formatBalance(BigNumber.max(0, amount_).toFixed(), selectedAsset?.token.decimals)
}, [selectedAsset, maxFeePerGas, minGasLimit, tokenBalance])

// #region set default gasLimit
Expand Down Expand Up @@ -398,7 +397,7 @@ export const Transfer1559 = memo<Transfer1559Props>(({ selectedAsset, openAssetM
methods.setValue('amount', maxAmount)
}, [methods.setValue, maxAmount])

const [{ loading }, onSubmit] = useAsyncFn(
const [{ loading, error }, onSubmit] = useAsyncFn(
async (data: zod.infer<typeof schema>) => {
const transferAmount = rightShift(data.amount || '0', selectedAsset?.token.decimals).toFixed()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ import { SavingsForm } from './SavingsForm'
interface SavingsDialogProps {
open: boolean
onClose?: () => void
onSwapDialogOpen?: () => void
}

export function SavingsDialog({ open, onClose, onSwapDialogOpen }: SavingsDialogProps) {
export function SavingsDialog({ open, onClose }: SavingsDialogProps) {
const { t } = useI18N()
const isDashboard = isDashboardPage()
const { classes } = useStyles({ isDashboard })
Expand Down Expand Up @@ -120,7 +119,6 @@ export function SavingsDialog({ open, onClose, onSwapDialogOpen }: SavingsDialog
chainId={chainId}
selectedProtocol={selectedProtocol}
onClose={onClose}
onSwapDialogOpen={onSwapDialogOpen}
/>
)}
</DialogContent>
Expand Down
41 changes: 24 additions & 17 deletions packages/mask/src/plugins/Savings/SNSAdaptor/SavingsForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import BigNumber from 'bignumber.js'
import { Typography } from '@mui/material'
import { useState, useMemo } from 'react'
import { useState, useMemo, useCallback } from 'react'
import { useAsync } from 'react-use'
import { unreachable } from '@dimensiondev/kit'
import {
Expand All @@ -12,7 +12,7 @@ import {
formatCurrency,
formatBalance,
} from '@masknet/web3-shared-evm'
import { TokenAmountPanel, FormattedCurrency, LoadingAnimation } from '@masknet/shared'
import { TokenAmountPanel, FormattedCurrency, LoadingAnimation, useRemoteControlledDialog } from '@masknet/shared'
import { useTokenPrice } from '../../Wallet/hooks/useTokenPrice'
import { useI18N } from '../../../utils'
import { useStyles } from './SavingsFormStyles'
Expand All @@ -23,17 +23,17 @@ import { isLessThan, rightShift } from '@masknet/web3-shared-base'
import { EthereumWalletConnectedBoundary } from '../../../web3/UI/EthereumWalletConnectedBoundary'
import { EthereumChainBoundary } from '../../../web3/UI/EthereumChainBoundary'
import { ActionButtonPromise } from '../../../extension/options-page/DashboardComponents/ActionButton'
import { AllProviderTradeActionType, AllProviderTradeContext } from '../../Trader/trader/useAllProviderTradeContext'
import { PluginTraderMessages } from '../../Trader/messages'
import type { Coin } from '../../Trader/types'

export interface SavingsFormProps {
chainId: number
selectedProtocol: ProtocolType
tab: TabType
onClose?: () => void
onSwapDialogOpen?: () => void
}

export function SavingsForm({ chainId, selectedProtocol, tab, onClose, onSwapDialogOpen }: SavingsFormProps) {
export function SavingsForm({ chainId, selectedProtocol, tab, onClose }: SavingsFormProps) {
const { t } = useI18N()
const { classes } = useStyles()
const protocol = SavingsProtocols[selectedProtocol]
Expand All @@ -49,6 +49,24 @@ export function SavingsForm({ chainId, selectedProtocol, tab, onClose, onSwapDia

const { value: nativeTokenBalance } = useFungibleTokenBalance(EthereumTokenType.Native, '', targetChainId)

const { setDialog: openSwapDialog } = useRemoteControlledDialog(PluginTraderMessages.swapDialogUpdated)

const onConvertClick = useCallback(() => {
const token = protocol.getFungibleTokenDetails(targetChainId)
openSwapDialog({
open: true,
traderProps: {
defaultInputCoin: {
id: token.address,
name: token.name ?? '',
symbol: token.symbol ?? '',
contract_address: token.address,
decimals: token.decimals,
} as Coin,
},
})
}, [protocol, targetChainId, openSwapDialog])

// #region form variables
const tokenAmount = useMemo(() => new BigNumber(rightShift(inputAmount || '0', 18)), [inputAmount])
const inputAsBN = useMemo(() => new BigNumber(rightShift(inputAmount, 18)), [inputAmount])
Expand Down Expand Up @@ -91,12 +109,6 @@ export function SavingsForm({ chainId, selectedProtocol, tab, onClose, onSwapDia
)
// #endregion

// #region trade state
const {
tradeState: [_, dispatchTradeStore],
} = AllProviderTradeContext.useContainer()
// #endregion

const needsSwap = protocol.type === ProtocolType.Lido && tab === TabType.Withdraw

return (
Expand Down Expand Up @@ -188,13 +200,8 @@ export function SavingsForm({ chainId, selectedProtocol, tab, onClose, onSwapDia
case TabType.Withdraw:
switch (protocol.type) {
case ProtocolType.Lido:
dispatchTradeStore({
type: AllProviderTradeActionType.UPDATE_INPUT_TOKEN,
token: protocol.getFungibleTokenDetails(targetChainId),
})

onClose?.()
onSwapDialogOpen?.()
onConvertClick()
return
default:
if (!(await protocol.withdraw(account, targetChainId, web3, tokenAmount))) {
Expand Down
35 changes: 24 additions & 11 deletions packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ const useStyles = makeStyles()(() => {

export interface TraderProps extends withClasses<'root'> {
coin?: Coin
defaultInputCoin?: Coin
tokenDetailed?: FungibleTokenDetailed
chainId?: ChainId
}

export function Trader(props: TraderProps) {
const { coin, tokenDetailed, chainId: targetChainId } = props
const { coin, tokenDetailed, chainId: targetChainId, defaultInputCoin } = props
const { decimals } = tokenDetailed ?? coin ?? {}
const [focusedTrade, setFocusTrade] = useState<TradeInfo>()
const wallet = useWallet()
Expand Down Expand Up @@ -83,15 +84,11 @@ export function Trader(props: TraderProps) {
// #region if chain id be changed, update input token be native token
useEffect(() => {
if (!chainIdValid) return
if (!inputToken) {
dispatchTradeStore({
type: AllProviderTradeActionType.UPDATE_INPUT_TOKEN,
token:
chainId === ChainId.Mainnet && coin?.is_mirrored
? UST[ChainId.Mainnet]
: createNativeToken(chainId),
})
}

dispatchTradeStore({
type: AllProviderTradeActionType.UPDATE_INPUT_TOKEN,
token: chainId === ChainId.Mainnet && coin?.is_mirrored ? UST[ChainId.Mainnet] : createNativeToken(chainId),
})
}, [chainId, chainIdValid])
// #endregion

Expand All @@ -114,12 +111,28 @@ export function Trader(props: TraderProps) {
dispatchTradeStore({
type: AllProviderTradeActionType.UPDATE_OUTPUT_TOKEN,
token: coin.contract_address
? createERC20Token(chainId, coin.contract_address, decimals, coin.name, coin.symbol)
? createERC20Token(chainId, coin.contract_address, coin.decimals, coin.name, coin.symbol)
: undefined,
})
}
}, [coin, NATIVE_TOKEN_ADDRESS, inputToken, outputToken, currentChainId, targetChainId, decimals])

useEffect(() => {
if (!defaultInputCoin) return
dispatchTradeStore({
type: AllProviderTradeActionType.UPDATE_INPUT_TOKEN,
token: defaultInputCoin.contract_address
? createERC20Token(
chainId,
defaultInputCoin.contract_address,
defaultInputCoin.decimals,
defaultInputCoin.name,
defaultInputCoin.symbol,
)
: undefined,
})
}, [defaultInputCoin, chainId])

const onInputAmountChange = useCallback((amount: string) => {
dispatchTradeStore({
type: AllProviderTradeActionType.UPDATE_INPUT_AMOUNT,
Expand Down
6 changes: 4 additions & 2 deletions packages/web3-shared/evm/hooks/useContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,21 @@ export function createContract<T extends BaseContract>(web3: Web3, address: stri
* EthereumService in the background page and decode the result of calls automatically
* @param address
* @param ABI
* @param chainId
*/
export function useContract<T extends BaseContract>(address = '', ABI: AbiItem[] = [], chainId?: ChainId) {
const web3 = useWeb3({ chainId })
const web3 = useWeb3(chainId ? { chainId } : {})
return useMemo(() => createContract<T>(web3, address, ABI), [web3, address, ABI])
}

/**
* Create many contracts with same ABI
* @param listOfAddress
* @param ABI
* @param chainId
*/
export function useContracts<T extends BaseContract>(listOfAddress: string[], ABI: AbiItem[] = [], chainId?: ChainId) {
const web3 = useWeb3({ chainId })
const web3 = useWeb3(chainId ? { chainId } : {})
const contracts = useMemo(
() => listOfAddress.map((address) => createContract<T>(web3, address, ABI)),
[web3, JSON.stringify(listOfAddress), ABI],
Expand Down

0 comments on commit 7a67211

Please sign in to comment.