diff --git a/src/background/controller/wallet.ts b/src/background/controller/wallet.ts index bbed540c122..5b2cc7e8560 100644 --- a/src/background/controller/wallet.ts +++ b/src/background/controller/wallet.ts @@ -5008,6 +5008,12 @@ export class WalletController extends BaseController { throw e; } }; + ethPersonalSign = async ( + ...args: Parameters + ) => { + return providerController.personalSign(...args); + }; + tryOpenOrActiveUserGuide = async () => { if (this.isBooted()) { return false; diff --git a/src/ui/utils/sendPersonalMessage.ts b/src/ui/utils/sendPersonalMessage.ts new file mode 100644 index 00000000000..03911062c00 --- /dev/null +++ b/src/ui/utils/sendPersonalMessage.ts @@ -0,0 +1,122 @@ +import { EVENTS, INTERNAL_REQUEST_SESSION } from '@/constant'; +import { WalletControllerType } from '@/ui/utils'; +import { getKRCategoryByType } from '@/utils/transaction'; +import eventBus from '@/eventBus'; +import { matomoRequestEvent } from '@/utils/matomo-request'; + +// fail code +export enum FailedCode { + SubmitTxFailed = 'SubmitTxFailed', + DefaultFailed = 'DefaultFailed', +} + +const report = async ({ + action, + wallet, + currentAccount, + extra, +}: { + action: + | 'createSignText' + | 'startSignText' + | 'cancelSignText' + | 'completeSignText'; + currentAccount; + wallet: WalletControllerType; + extra?: Record; +}) => { + if (!currentAccount) { + return; + } + matomoRequestEvent({ + category: 'SignText', + action: action, + label: [ + getKRCategoryByType(currentAccount.type), + currentAccount.brandName, + ].join('|'), + transport: 'beacon', + }); + await wallet.reportStats(action, { + type: currentAccount.brandName, + category: getKRCategoryByType(currentAccount.type), + method: 'personalSign', + ...extra, + }); +}; + +type ProgressStatus = 'building' | 'builded' | 'signed' | 'submitted'; + +/** + * send personal message without rpcFlow + * @param data + * @param wallet + * @param onProgress callback + */ +export const sendPersonalMessage = async ({ + data, + wallet, + onProgress, + ga, +}: { + data: string[]; + wallet: WalletControllerType; + onProgress?: (status: ProgressStatus) => void; + ga?: Record; +}) => { + onProgress?.('building'); + const { address, ...currentAccount } = (await wallet.getCurrentAccount())!; + + report({ + action: 'createSignText', + wallet, + currentAccount, + }); + + onProgress?.('builded'); + + const handleSendAfter = async () => { + report({ + action: 'completeSignText', + wallet, + currentAccount, + }); + }; + + report({ action: 'startSignText', wallet, currentAccount }); + + // submit tx + let hash = ''; + try { + hash = await wallet.ethPersonalSign({ + data: { + $ctx: { + ga, + }, + params: data, + }, + session: INTERNAL_REQUEST_SESSION, + approvalRes: { + type: currentAccount.type, + address: address, + extra: { + brandName: currentAccount.brandName, + signTextMethod: 'personalSign', + }, + }, + }); + await handleSendAfter(); + } catch (e) { + await handleSendAfter(); + const err = new Error(e.message); + err.name = FailedCode.SubmitTxFailed; + eventBus.emit(EVENTS.COMMON_HARDWARE.REJECTED, e.message); + throw err; + } + + onProgress?.('signed'); + + return { + txHash: hash, + }; +}; diff --git a/src/ui/views/Dashboard/components/Settings/index.tsx b/src/ui/views/Dashboard/components/Settings/index.tsx index f858d4513ce..5f7b2b17672 100644 --- a/src/ui/views/Dashboard/components/Settings/index.tsx +++ b/src/ui/views/Dashboard/components/Settings/index.tsx @@ -58,6 +58,7 @@ import ThemeIcon from '@/ui/component/ThemeMode/ThemeIcon'; import FeedbackPopup from '../Feedback'; import { getChainList } from '@/utils/chain'; import { SvgIconCross } from '@/ui/assets'; +import { sendPersonalMessage } from '@/ui/utils/sendPersonalMessage'; const useAutoLockOptions = () => { const { t } = useTranslation(); @@ -926,6 +927,27 @@ const SettingsInner = ({ ), }, + { + leftIcon: RcIconSettingsGitForkCC, + content: 'Test sendPersonalMessage', + onClick: async () => { + const currentAddress = + (await wallet.getCurrentAccount())?.address || ''; + + const result = await sendPersonalMessage({ + data: [ + '0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765', + currentAddress, + 'Example password', + ], + wallet, + onProgress: (progress) => { + message.success('sendPersonalMessage progress: ' + progress); + }, + }); + message.success('sendPersonalMessage result: ' + result.txHash); + }, + }, ] as SettingItem[], }, about: { diff --git a/src/ui/views/GasAccount/components/LoginPopup.tsx b/src/ui/views/GasAccount/components/LoginPopup.tsx index 719e4ba62a2..42103b7669b 100644 --- a/src/ui/views/GasAccount/components/LoginPopup.tsx +++ b/src/ui/views/GasAccount/components/LoginPopup.tsx @@ -102,7 +102,7 @@ const GasAccountLoginContent = ({ setToConfirm(true); }; - const confirmAddress = () => { + const confirmAddress = async () => { login(); }; diff --git a/src/ui/views/GasAccount/hooks/index.ts b/src/ui/views/GasAccount/hooks/index.ts index e77f006e90b..8ee07567911 100644 --- a/src/ui/views/GasAccount/hooks/index.ts +++ b/src/ui/views/GasAccount/hooks/index.ts @@ -7,6 +7,10 @@ import React, { useRef } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useAsync } from 'react-use'; import { useGasAccountRefreshId, useGasAccountSetRefreshId } from './context'; +import { preferenceService } from '@/background/service'; +import { sendPersonalMessage } from '@/ui/utils/sendPersonalMessage'; +import { KEYRING_CLASS } from '@/constant'; +import pRetry from 'p-retry'; export const useGasAccountRefresh = () => { const refreshId = useGasAccountRefreshId(); @@ -58,14 +62,55 @@ export const useGasAccountInfo = () => { export const useGasAccountMethods = () => { const wallet = useWallet(); + const account = useRabbySelector((s) => s.account.currentAccount); const dispatch = useRabbyDispatch(); const { sig, accountId } = useGasAccountSign(); + const { refresh } = useGasAccountRefresh(); + + const handleNoSignLogin = useCallback(async () => { + if (account) { + try { + const { text } = await wallet.openapi.getGasAccountSignText( + account.address + ); + + const { txHash: signature } = await sendPersonalMessage({ + data: [text, account.address], + wallet, + }); + + const result = await pRetry( + async () => + wallet.openapi.loginGasAccount({ + sig: signature, + account_id: account.address, + }), + { + retries: 2, + } + ); + if (result?.success) { + dispatch.gasAccount.setGasAccountSig({ sig: signature, account }); + refresh(); + } + } catch (e) { + message.error('Login in error, Please retry'); + } + } + }, [account]); const login = useCallback(async () => { - wallet.signGasAccount(); - window.close(); - }, []); + const noSignType = + account?.type === KEYRING_CLASS.PRIVATE_KEY || + account?.type === KEYRING_CLASS.MNEMONIC; + if (noSignType) { + handleNoSignLogin(); + } else { + wallet.signGasAccount(); + window.close(); + } + }, [account, handleNoSignLogin]); const logout = useCallback(async () => { if (sig && accountId) { diff --git a/src/ui/views/GasAccount/index.tsx b/src/ui/views/GasAccount/index.tsx index 3f07ec37cf9..22568f1189a 100644 --- a/src/ui/views/GasAccount/index.tsx +++ b/src/ui/views/GasAccount/index.tsx @@ -109,6 +109,8 @@ const GasAccountInner = () => { useEffect(() => { if (!isLogin) { setLoginVisible(true); + } else { + setLoginVisible(false); } }, [isLogin]);