diff --git a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC20.tsx b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC20.tsx index 0eaae705acd2..fff3deab3488 100644 --- a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC20.tsx +++ b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC20.tsx @@ -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(({ token }) => { const t = useDashboardI18N() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants() @@ -101,7 +102,7 @@ export const TransferERC20 = memo(({ 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 @@ -111,15 +112,18 @@ export const TransferERC20 = memo(({ 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, @@ -177,7 +181,7 @@ export const TransferERC20 = memo(({ token }) => { if (resolveDomainLoading) return if (registeredAddress) { return ( - + (({ token }) => { + ) } diff --git a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx index 61be82825afd..b633d6fcf3db 100644 --- a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx +++ b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx @@ -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: { @@ -226,7 +227,7 @@ export const TransferERC721 = memo(() => { if (resolveDomainLoading) return if (registeredAddress) { return ( - + { + ) } diff --git a/packages/mask/src/components/shared/ApplicationBoard.tsx b/packages/mask/src/components/shared/ApplicationBoard.tsx index aa4ffb7f5b37..dc840e89e457 100644 --- a/packages/mask/src/components/shared/ApplicationBoard.tsx +++ b/packages/mask/src/components/shared/ApplicationBoard.tsx @@ -408,9 +408,7 @@ export function ApplicationBoard({ secondEntries, secondEntryChainTabs }: MaskAp {isFindTrumanDialogOpen ? : null} {isSwapDialogOpen ? : null} - {isSavingsDialogOpen ? ( - - ) : null} + {isSavingsDialogOpen ? : null} ) } diff --git a/packages/mask/src/extension/background-script/EthereumServices/request.ts b/packages/mask/src/extension/background-script/EthereumServices/request.ts index 8e7ebbc9264a..319bb6f04810 100644 --- a/packages/mask/src/extension/background-script/EthereumServices/request.ts +++ b/packages/mask/src/extension/background-script/EthereumServices/request.ts @@ -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_ = { diff --git a/packages/mask/src/extension/popups/pages/Wallet/Transfer/Prior1559Transfer.tsx b/packages/mask/src/extension/popups/pages/Wallet/Transfer/Prior1559Transfer.tsx index 4ba9ee1ec033..3a5e48a587db 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/Transfer/Prior1559Transfer.tsx +++ b/packages/mask/src/extension/popups/pages/Wallet/Transfer/Prior1559Transfer.tsx @@ -263,7 +263,7 @@ export const Prior1559Transfer = memo(({ 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 diff --git a/packages/mask/src/extension/popups/pages/Wallet/Transfer/Transfer1559.tsx b/packages/mask/src/extension/popups/pages/Wallet/Transfer/Transfer1559.tsx index a77cdd03d5b4..4d475d858488 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/Transfer/Transfer1559.tsx +++ b/packages/mask/src/extension/popups/pages/Wallet/Transfer/Transfer1559.tsx @@ -365,11 +365,10 @@ export const Transfer1559 = memo(({ 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 @@ -398,7 +397,7 @@ export const Transfer1559 = memo(({ selectedAsset, openAssetM methods.setValue('amount', maxAmount) }, [methods.setValue, maxAmount]) - const [{ loading }, onSubmit] = useAsyncFn( + const [{ loading, error }, onSubmit] = useAsyncFn( async (data: zod.infer) => { const transferAmount = rightShift(data.amount || '0', selectedAsset?.token.decimals).toFixed() diff --git a/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx b/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx index efeab7b60eb3..dfa2dd5b16be 100644 --- a/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx +++ b/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsDialog.tsx @@ -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 }) @@ -120,7 +119,6 @@ export function SavingsDialog({ open, onClose, onSwapDialogOpen }: SavingsDialog chainId={chainId} selectedProtocol={selectedProtocol} onClose={onClose} - onSwapDialogOpen={onSwapDialogOpen} /> )} diff --git a/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsForm.tsx b/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsForm.tsx index 893430dc27ee..27e8febf9945 100644 --- a/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsForm.tsx +++ b/packages/mask/src/plugins/Savings/SNSAdaptor/SavingsForm.tsx @@ -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 { @@ -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' @@ -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] @@ -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]) @@ -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 ( @@ -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))) { diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx index 8fc5fbd41435..2033d99fb959 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx @@ -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() const wallet = useWallet() @@ -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 @@ -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, diff --git a/packages/web3-shared/evm/hooks/useContract.ts b/packages/web3-shared/evm/hooks/useContract.ts index f850eff62c6c..6fa0ced8fc55 100644 --- a/packages/web3-shared/evm/hooks/useContract.ts +++ b/packages/web3-shared/evm/hooks/useContract.ts @@ -19,9 +19,10 @@ export function createContract(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(address = '', ABI: AbiItem[] = [], chainId?: ChainId) { - const web3 = useWeb3({ chainId }) + const web3 = useWeb3(chainId ? { chainId } : {}) return useMemo(() => createContract(web3, address, ABI), [web3, address, ABI]) } @@ -29,9 +30,10 @@ export function useContract(address = '', ABI: AbiItem[] * Create many contracts with same ABI * @param listOfAddress * @param ABI + * @param chainId */ export function useContracts(listOfAddress: string[], ABI: AbiItem[] = [], chainId?: ChainId) { - const web3 = useWeb3({ chainId }) + const web3 = useWeb3(chainId ? { chainId } : {}) const contracts = useMemo( () => listOfAddress.map((address) => createContract(web3, address, ABI)), [web3, JSON.stringify(listOfAddress), ABI],