diff --git a/packages/core/src/types/coreTypesTx.ts b/packages/core/src/types/coreTypesTx.ts index 9dced02d5ec..376c45d276e 100644 --- a/packages/core/src/types/coreTypesTx.ts +++ b/packages/core/src/types/coreTypesTx.ts @@ -2,7 +2,7 @@ import type { IApproveInfo, ITransferInfo, } from '@onekeyhq/kit-bg/src/vaults/types'; -import type { IFeeInfoUnit } from '@onekeyhq/shared/types/fee'; +import type { IFeeInfoUnit, IFeesInfoUnit } from '@onekeyhq/shared/types/fee'; import type { IEncodedTxLightning } from '@onekeyhq/shared/types/lightning'; import type { IStakingInfo } from '@onekeyhq/shared/types/staking'; import type { ISwapTxInfo } from '@onekeyhq/shared/types/swap/types'; @@ -107,6 +107,7 @@ export type IUnsignedTx = { export type IUnsignedTxPro = IUnsignedTx & { encodedTx: IEncodedTx; feeInfo?: IFeeInfoUnit | undefined; + feesInfo?: IFeesInfoUnit | undefined; swapInfo?: ISwapTxInfo | undefined; approveInfo?: IApproveInfo | undefined; stakingInfo?: IStakingInfo; diff --git a/packages/kit/src/hooks/useSendConfirm.ts b/packages/kit/src/hooks/useSendConfirm.ts index ee4fa971caa..03e769ca1b5 100644 --- a/packages/kit/src/hooks/useSendConfirm.ts +++ b/packages/kit/src/hooks/useSendConfirm.ts @@ -116,8 +116,12 @@ function useSendConfirm(params: IParams) { ); } + const target = params.isInternalSwap + ? EModalSendRoutes.SendConfirmFromSwap + : EModalSendRoutes.SendConfirm; + if (sameModal) { - navigation.push(EModalSendRoutes.SendConfirm, { + navigation.push(target, { accountId, networkId, unsignedTxs, @@ -131,7 +135,7 @@ function useSendConfirm(params: IParams) { }); } else { navigation.pushModal(EModalRoutes.SendModal, { - screen: EModalSendRoutes.SendConfirm, + screen: target, params: { accountId, networkId, diff --git a/packages/kit/src/views/Developer/pages/Gallery/Components/stories/Toast.tsx b/packages/kit/src/views/Developer/pages/Gallery/Components/stories/Toast.tsx index c1f498b2703..444b60769ff 100644 --- a/packages/kit/src/views/Developer/pages/Gallery/Components/stories/Toast.tsx +++ b/packages/kit/src/views/Developer/pages/Gallery/Components/stories/Toast.tsx @@ -41,7 +41,8 @@ const ToastGallery = () => ( onPress={() => { Toast.success({ title: 'url!', - message: 'look, OneKey here. aaa', + message: + 'look, OneKey here. aaa', }); }} > diff --git a/packages/kit/src/views/Send/pages/SendConfirm/SendConfirmActionsContainer.tsx b/packages/kit/src/views/Send/pages/SendConfirm/SendConfirmActionsContainer.tsx index 336f42181df..6919012c2e7 100644 --- a/packages/kit/src/views/Send/pages/SendConfirm/SendConfirmActionsContainer.tsx +++ b/packages/kit/src/views/Send/pages/SendConfirm/SendConfirmActionsContainer.tsx @@ -52,6 +52,7 @@ type IProps = { transferPayload: ITransferPayload | undefined; useFeeInTx?: boolean; feeInfoEditable?: boolean; + popStack?: boolean; }; function SendConfirmActionsContainer(props: IProps) { @@ -66,6 +67,7 @@ function SendConfirmActionsContainer(props: IProps) { transferPayload, useFeeInTx, feeInfoEditable, + popStack = true, } = props; const intl = useIntl(); const isSubmitted = useRef(false); @@ -243,7 +245,11 @@ function SendConfirmActionsContainer(props: IProps) { void dappApprove.resolve({ result: signedTx }); - navigation.popStack(); + if (popStack) { + navigation.popStack(); + } else { + navigation.pop(); + } updateSendTxStatus({ isSubmitting: false }); onSuccess?.(result); } catch (e: any) { @@ -276,8 +282,9 @@ function SendConfirmActionsContainer(props: IProps) { sourceInfo, transferPayload, intl, - navigation, + popStack, onSuccess, + navigation, ]); const cancelCalledRef = useRef(false); diff --git a/packages/kit/src/views/Send/pages/SendConfirm/SendConfirmContainer.tsx b/packages/kit/src/views/Send/pages/SendConfirm/SendConfirmContainer.tsx index efb5d16520c..9dc0859d7c1 100644 --- a/packages/kit/src/views/Send/pages/SendConfirm/SendConfirmContainer.tsx +++ b/packages/kit/src/views/Send/pages/SendConfirm/SendConfirmContainer.tsx @@ -64,6 +64,7 @@ function SendConfirmContainer() { useFeeInTx, transferPayload, feeInfoEditable, + popStack, } = route.params; const dappApprove = useDappApproveAction({ @@ -208,6 +209,7 @@ function SendConfirmContainer() { /> unsignedTxs.length === 1 && unsignedTxs[0].feesInfo, + [unsignedTxs], + ); + const isSecondApproveTxWithFeeInfo = useMemo( () => unsignedTxs.length === 1 && @@ -185,6 +190,21 @@ function TxFeeContainer(props: IProps) { encodedTx: unsignedTxs[0].encodedTx, }); + if (isSingleTxWithFeesInfo) { + const r = unsignedTxs[0].feesInfo; + updateSendFeeStatus({ + status: ESendFeeStatus.Success, + errMessage: '', + }); + setTxFeeInit(true); + updateTxAdvancedSettings({ dataChanged: false }); + return { + r, + e, + m: undefined, + }; + } + if ( (isLastSwapTxWithFeeInfo || isSecondApproveTxWithFeeInfo) && unsignedTxs[0].feeInfo @@ -256,6 +276,7 @@ function TxFeeContainer(props: IProps) { isLastSwapTxWithFeeInfo, isMultiTxs, isSecondApproveTxWithFeeInfo, + isSingleTxWithFeesInfo, networkId, unsignedTxs, updateSendFeeStatus, diff --git a/packages/kit/src/views/Send/pages/SendConfirmFromSwap/SendConfirmFromSwap.tsx b/packages/kit/src/views/Send/pages/SendConfirmFromSwap/SendConfirmFromSwap.tsx new file mode 100644 index 00000000000..6827021d3c4 --- /dev/null +++ b/packages/kit/src/views/Send/pages/SendConfirmFromSwap/SendConfirmFromSwap.tsx @@ -0,0 +1,160 @@ +import { useCallback, useEffect, useRef } from 'react'; + +import { useRoute } from '@react-navigation/core'; +import { StackActions, useNavigation } from '@react-navigation/native'; +import { AppState } from 'react-native'; + +import { Page, Spinner, Stack } from '@onekeyhq/components'; +import backgroundApiProxy from '@onekeyhq/kit/src/background/instance/backgroundApiProxy'; +import useAppNavigation from '@onekeyhq/kit/src/hooks/useAppNavigation'; +import type { IModalSendParamList } from '@onekeyhq/shared/src/routes'; +import { EModalSendRoutes } from '@onekeyhq/shared/src/routes'; +import accountUtils from '@onekeyhq/shared/src/utils/accountUtils'; +import type { IGasEIP1559, IGasLegacy } from '@onekeyhq/shared/types/fee'; +import type { ISendTxOnSuccessData } from '@onekeyhq/shared/types/tx'; + +import type { RouteProp } from '@react-navigation/core'; +import type { StackActionType } from '@react-navigation/native'; + +function SendConfirmFromSwap() { + const pendingAction = useRef(); + const navigation = useNavigation(); + const appNavigation = useAppNavigation(); + + const route = + useRoute< + RouteProp + >(); + + const { networkId, accountId, unsignedTxs, onSuccess, onFail, onCancel } = + route.params; + + const handleConfirmMultiTxsOnHwOrExternal = useCallback( + async (multiTxsFeeResult: { + common: { + baseFee: string | undefined; + feeDecimals: number; + feeSymbol: string; + nativeDecimals: number; + nativeSymbol: string; + nativeTokenPrice: number | undefined; + }; + txFees: { + gas: IGasLegacy[]; + gasEIP1559: IGasEIP1559[]; + }[]; + }) => { + for (let i = 0, len = unsignedTxs.length; i < len; i += 1) { + const unsignedTx = unsignedTxs[i]; + unsignedTx.feesInfo = { + common: multiTxsFeeResult.common, + gas: multiTxsFeeResult.txFees[i].gas, + gasEIP1559: multiTxsFeeResult.txFees[i].gasEIP1559, + }; + const isLastTx = i === len - 1; + + await new Promise((resolve) => { + appNavigation.push(EModalSendRoutes.SendConfirm, { + ...route.params, + popStack: false, + unsignedTxs: [unsignedTx], + onSuccess: (data: ISendTxOnSuccessData[]) => { + if (isLastTx) { + onSuccess?.(data); + appNavigation.popStack(); + } + resolve(data); + }, + onFail: (error: Error) => { + onFail?.(error); + + appNavigation.popStack(); + }, + onCancel: () => { + onCancel?.(); + appNavigation.popStack(); + }, + }); + }); + } + }, + [unsignedTxs, appNavigation, route.params, onSuccess, onFail, onCancel], + ); + + const navigationToSendConfirm = useCallback(async () => { + let action: any; + let batchEstimateButSingleConfirm = false; + const isMultiTxs = unsignedTxs.length > 1; + if ( + isMultiTxs && + (accountUtils.isHwAccount({ accountId }) || + accountUtils.isExternalAccount({ accountId })) + ) { + const vaultSettings = + await backgroundApiProxy.serviceNetwork.getVaultSettings({ + networkId, + }); + if (vaultSettings.supportBatchEstimateFee?.[networkId]) { + try { + const encodedTxList = unsignedTxs.map((tx) => tx.encodedTx); + const multiTxsFeeResult = + await backgroundApiProxy.serviceGas.batchEstimateFee({ + accountId, + networkId, + encodedTxs: encodedTxList, + }); + if (multiTxsFeeResult.txFees.length === unsignedTxs.length) { + await handleConfirmMultiTxsOnHwOrExternal(multiTxsFeeResult); + batchEstimateButSingleConfirm = true; + } else { + batchEstimateButSingleConfirm = false; + } + } catch (e) { + batchEstimateButSingleConfirm = false; + } + } + } + + if (!batchEstimateButSingleConfirm) { + action = StackActions.replace(EModalSendRoutes.SendConfirm, { + ...route.params, + // @ts-ignore + _disabledAnimationOfNavigate: true, + }); + } + + if (action) { + if (AppState.currentState === 'active') { + setTimeout(() => navigation.dispatch(action)); + } else { + pendingAction.current = action; + } + } + }, [ + accountId, + handleConfirmMultiTxsOnHwOrExternal, + navigation, + networkId, + route.params, + unsignedTxs, + ]); + + const handleOnClose = () => { + onCancel?.(); + }; + + useEffect(() => { + void navigationToSendConfirm(); + }, [navigation, navigationToSendConfirm, route.params, unsignedTxs]); + + return ( + + + + + + + + ); +} +export { SendConfirmFromSwap }; diff --git a/packages/kit/src/views/Send/router/index.ts b/packages/kit/src/views/Send/router/index.ts index da1b72b799d..3cf487062ac 100644 --- a/packages/kit/src/views/Send/router/index.ts +++ b/packages/kit/src/views/Send/router/index.ts @@ -9,6 +9,7 @@ import { EModalSendRoutes } from '@onekeyhq/shared/src/routes'; import { LazyLoadPage } from '../../../components/LazyLoadPage'; import { SendConfirmFromDApp } from '../pages/SendConfirmFromDApp/SendConfirmFromDApp'; +import { SendConfirmFromSwap } from '../pages/SendConfirmFromSwap/SendConfirmFromSwap'; const LnurlPayRequestModal = LazyLoadPage( () => @@ -63,6 +64,10 @@ export const ModalSendStack: IModalFlowNavigatorConfig< name: EModalSendRoutes.SendConfirmFromDApp, component: SendConfirmFromDApp, }, + { + name: EModalSendRoutes.SendConfirmFromSwap, + component: SendConfirmFromSwap, + }, { name: EModalSendRoutes.SendReplaceTx, component: SendReplaceTx, diff --git a/packages/kit/src/views/Swap/hooks/useSwapBuiltTx.ts b/packages/kit/src/views/Swap/hooks/useSwapBuiltTx.ts index 2898043646e..afc55f0612c 100644 --- a/packages/kit/src/views/Swap/hooks/useSwapBuiltTx.ts +++ b/packages/kit/src/views/Swap/hooks/useSwapBuiltTx.ts @@ -18,7 +18,6 @@ import type { } from '@onekeyhq/kit-bg/src/vaults/types'; import { ETranslations } from '@onekeyhq/shared/src/locale'; import { defaultLogger } from '@onekeyhq/shared/src/logger/logger'; -import accountUtils from '@onekeyhq/shared/src/utils/accountUtils'; import { numberFormat, toBigIntHex, @@ -571,12 +570,6 @@ export function useSwapBuildTx() { const createBuildTxRes = await createBuildTx(); if (createBuildTxRes) { if ( - accountUtils.isHwAccount({ - accountId: swapFromAddressInfo.accountInfo.account.id, - }) || - accountUtils.isExternalAccount({ - accountId: swapFromAddressInfo.accountInfo.account.id, - }) || SwapBuildUseMultiplePopoversNetworkIds.includes( fromToken.networkId, ) diff --git a/packages/shared/src/routes/send.ts b/packages/shared/src/routes/send.ts index d351cfdf20d..4b757548380 100644 --- a/packages/shared/src/routes/send.ts +++ b/packages/shared/src/routes/send.ts @@ -23,6 +23,7 @@ import type { EReplaceTxType, ISendTxOnSuccessData } from '../../types/tx'; export enum EModalSendRoutes { SendDataInput = 'SendDataInput', SendConfirmFromDApp = 'SendConfirmFromDApp', + SendConfirmFromSwap = 'SendConfirmFromSwap', SendConfirm = 'SendConfirm', SendFeedback = 'SendFeedback', SendReplaceTx = 'SendReplaceTx', @@ -63,8 +64,22 @@ export type IModalSendParamList = { onFail?: (error: Error) => void; onCancel?: () => void; transferPayload?: ITransferPayload; + popStack?: boolean; }; [EModalSendRoutes.SendConfirmFromDApp]: undefined; + [EModalSendRoutes.SendConfirmFromSwap]: { + networkId: string; + accountId: string; + unsignedTxs: IUnsignedTxPro[]; + sourceInfo?: IDappSourceInfo; + signOnly?: boolean; + useFeeInTx?: boolean; + feeInfoEditable?: boolean; + onSuccess?: (txs: ISendTxOnSuccessData[]) => void; + onFail?: (error: Error) => void; + onCancel?: () => void; + transferPayload?: ITransferPayload; + }; [EModalSendRoutes.SendReplaceTx]: { networkId: string; accountId: string; diff --git a/packages/shared/types/fee.ts b/packages/shared/types/fee.ts index c0061ed5e43..4750c99164c 100644 --- a/packages/shared/types/fee.ts +++ b/packages/shared/types/fee.ts @@ -89,6 +89,26 @@ export type IEstimateGasParams = { encodedTx?: IEncodedTx; }; +export type IFeesInfoUnit = { + common: { + baseFee?: string; + feeDecimals: number; + feeSymbol: string; + nativeDecimals: number; + nativeSymbol: string; + nativeTokenPrice?: number; + }; + gas?: IGasLegacy[]; + gasEIP1559?: IGasEIP1559[]; + feeUTXO?: IFeeUTXO[]; + feeTron?: IFeeTron[]; + feeSol?: IFeeSol[]; + feeCkb?: IFeeCkb[]; + feeAlgo?: IFeeAlgo[]; + feeDot?: IFeeDot[]; + feeBudget?: IFeeSui[]; +}; + export type IFeeInfoUnit = { common: { baseFee?: string;