From 945b85809734edada382fce82e5d0734d74667ba Mon Sep 17 00:00:00 2001 From: Jack Works <5390719+Jack-Works@users.noreply.github.com> Date: Fri, 27 Feb 2026 08:49:40 +0000 Subject: [PATCH] wip --- eslint.config.js | 1 - .../services/identity/persona/sign.ts | 63 +++++++++---------- .../services/wallet/services/send.ts | 40 +++++++----- .../services/wallet/services/wallet/index.ts | 6 +- .../components/ConnectedWallet/index.tsx | 3 +- .../pages/Personas/AccountDetail/index.tsx | 3 +- .../pages/Personas/ConnectWallet/index.tsx | 3 +- .../Personas/PersonaAvatarSetting/index.tsx | 3 +- .../Personas/PersonaSignRequest/index.tsx | 3 +- packages/mask/shared-ui/initUIContext.ts | 2 +- .../shared-ui/initialization/walletSetup.ts | 1 - packages/plugin-infra/src/dom/context.ts | 4 +- .../NextID/src/hooks/usePersonaSign.ts | 2 +- .../hooks/useClaimNftRedpacketCallback.ts | 10 ++- .../src/SiteAdaptor/hooks/useSignedMessage.ts | 3 +- packages/shared-base/src/types/Account.ts | 13 ++++ packages/shared/src/hooks/useVerifyContent.ts | 6 +- packages/shared/src/hooks/useVerifyNextID.ts | 6 +- .../src/Web3/Base/state/Provider.ts | 5 +- .../src/Web3/EVM/apis/ComposerAPI.ts | 5 +- .../src/Web3/EVM/apis/RequestAPI.ts | 2 +- .../src/Web3/EVM/apis/SignerAPI.ts | 15 ++--- .../src/Web3/EVM/middleware/Interceptor.ts | 3 +- .../src/Web3/EVM/state/Provider.ts | 2 +- .../src/Web3/Flow/apis/Web3StateAPI.ts | 2 +- .../src/Web3/Flow/state/Provider.ts | 8 +-- .../src/Web3/Solana/apis/Web3StateAPI.ts | 2 +- .../src/Web3/Solana/state/Provider.ts | 8 +-- packages/web3-providers/src/types/Wallet.ts | 7 +-- packages/web3-shared/base/src/specs/index.ts | 5 -- packages/web3-shared/evm/package.json | 1 - .../evm/src/helpers/createAccount.ts | 12 ++-- .../evm/src/helpers/signMessage.ts | 13 ++-- .../evm/src/helpers/signTransaction.ts | 12 ++-- .../evm/src/libs/AccountTransaction.ts | 2 - .../web3-shared/evm/src/libs/PayloadEditor.ts | 58 ++++++++++------- packages/web3-shared/evm/src/libs/Signer.ts | 21 ------- packages/web3-shared/evm/src/libs/index.ts | 1 - packages/web3-shared/evm/src/types/index.ts | 14 ++--- pnpm-lock.yaml | 3 - 40 files changed, 174 insertions(+), 199 deletions(-) delete mode 100644 packages/web3-shared/evm/src/libs/Signer.ts diff --git a/eslint.config.js b/eslint.config.js index 7d5d4e1e1d93..20cbdb7c37e2 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -21,7 +21,6 @@ const deferPackages = [ '@metamask/eth-sig-util', '@masknet/gun-utils', 'web3-eth', - 'web3-eth-accounts', 'twitter-text', 'web3-utils', '@solana/web3.js', diff --git a/packages/mask/background/services/identity/persona/sign.ts b/packages/mask/background/services/identity/persona/sign.ts index bb64692a2bd7..7392136c8c3e 100644 --- a/packages/mask/background/services/identity/persona/sign.ts +++ b/packages/mask/background/services/identity/persona/sign.ts @@ -5,53 +5,50 @@ import { fromBase64URL, PopupRoutes, type ECKeyIdentifier, - type SignType, MaskMessages, + type SignMessage, } from '@masknet/shared-base' import { queryPersonasWithPrivateKey } from '../../../database/persona/web.js' import { openPopupWindow } from '../../helper/popup-opener.js' +async function getIdentifier(message: unknown, identifier?: ECKeyIdentifier, source?: string, silent = false) { + if (!identifier || !silent) { + const requestID = crypto.randomUUID() + await openPopupWindow(PopupRoutes.PersonaSignRequest, { + message: JSON.stringify(message), + requestID, + identifier: identifier?.toText(), + source, + }) + + return timeout( + new Promise((resolve, reject) => { + MaskMessages.events.personaSignRequest.on((approval) => { + if (approval.requestID !== requestID) return + if (!approval.selectedPersona) reject(new Error('The user refused to sign message with persona.')) + resolve(approval.selectedPersona!) + }) + }), + 60 * 1000, + 'Timeout of signing with persona.', + ) + } + return identifier +} /** * Generate a signature w or w/o confirmation from user */ export async function signWithPersona( - type: SignType, - message: unknown, + message: SignMessage, identifier?: ECKeyIdentifier, - source?: string, + origin?: string, silent = false, ): Promise { - const getIdentifier = async () => { - if (!identifier || !silent) { - const requestID = crypto.randomUUID() - await openPopupWindow(PopupRoutes.PersonaSignRequest, { - message: JSON.stringify(message), - requestID, - identifier: identifier?.toText(), - source, - }) - - return timeout( - new Promise((resolve, reject) => { - MaskMessages.events.personaSignRequest.on((approval) => { - if (approval.requestID !== requestID) return - if (!approval.selectedPersona) - reject(new Error('The user refused to sign message with persona.')) - resolve(approval.selectedPersona!) - }) - }), - 60 * 1000, - 'Timeout of signing with persona.', - ) - } - return identifier - } - - const identifier_ = await getIdentifier() + identifier = await getIdentifier(message.data, identifier, origin, silent) // find the persona with the signer's identifier - const persona = (await queryPersonasWithPrivateKey()).find((x) => x.identifier === identifier_) + const persona = (await queryPersonasWithPrivateKey()).find((x) => x.identifier === identifier) if (!persona?.privateKey.d) throw new Error('Persona not found') - return Signer.sign(type, Buffer.from(fromBase64URL(persona.privateKey.d)), message) + return Signer.sign(message, Buffer.from(fromBase64URL(persona.privateKey.d))) } diff --git a/packages/mask/background/services/wallet/services/send.ts b/packages/mask/background/services/wallet/services/send.ts index f6fea576f4c6..aa3475e3c542 100644 --- a/packages/mask/background/services/wallet/services/send.ts +++ b/packages/mask/background/services/wallet/services/send.ts @@ -1,5 +1,5 @@ import type { JsonRpcRequest } from 'web3-types' -import { ECKeyIdentifier, type SignType } from '@masknet/shared-base' +import { ECKeyIdentifier, SignType } from '@masknet/shared-base' import { EVMRequestReadonly, EVMWeb3Readonly } from '@masknet/web3-providers' import { ChainId, @@ -8,10 +8,10 @@ import { EthereumMethodType, PayloadEditor, type TransactionOptions, - Signer, } from '@masknet/web3-shared-evm' import { signWithWallet } from './wallet/index.js' import { signWithPersona } from '../../identity/persona/sign.js' +import type { TransactionSerializable } from 'viem' /** * The entrance of all RPC requests to MaskWallet. @@ -23,25 +23,35 @@ export async function send(payload: JsonRpcRequest, options?: TransactionOptions from, chainId = options?.chainId ?? ChainId.Mainnet, signableMessage, - signableConfig, + signableTransaction, } = PayloadEditor.fromPayload(payload, options) const identifier = ECKeyIdentifier.from(options?.identifier).unwrapOr(undefined) - const signer = - identifier ? - new Signer(identifier, (type: SignType, message: T, identifier?: ECKeyIdentifier) => - signWithPersona(type, message, identifier, undefined, true), - ) - : new Signer(owner || from!, signWithWallet) + const signTransaction = async (transaction: TransactionSerializable) => { + const message = { type: SignType.Transaction as const, data: transaction } + if (identifier) { + return signWithPersona(message, identifier) + } else { + return signWithWallet(message, owner || from!) + } + } + const signMessageOrTypedData = async (type: SignType.Message | SignType.TypedData, message: string) => { + const msg = { type, data: message } + if (identifier) { + return signWithPersona(msg, identifier) + } else { + return signWithWallet(msg, owner || from!) + } + } switch (payload.method) { case EthereumMethodType.eth_sendTransaction: case EthereumMethodType.MASK_REPLACE_TRANSACTION: - if (!signableConfig) throw new Error('No transaction to be sent.') + if (!signableTransaction) throw new Error('No transaction to be sent.') try { return createJsonRpcResponse( pid, - await EVMWeb3Readonly.sendSignedTransaction(await signer.signTransaction(signableConfig), { + await EVMWeb3Readonly.sendSignedTransaction(await signTransaction(signableTransaction), { chainId, providerURL, }), @@ -53,21 +63,21 @@ export async function send(payload: JsonRpcRequest, options?: TransactionOptions case EthereumMethodType.personal_sign: try { if (!signableMessage) throw new Error('No message to be signed.') - return createJsonRpcResponse(pid, await signer.signMessage(signableMessage)) + return createJsonRpcResponse(pid, await signMessageOrTypedData(SignType.Message, signableMessage)) } catch (error) { throw ErrorEditor.from(error, null, 'Failed to sign message.').error } case EthereumMethodType.eth_signTypedData_v4: try { if (!signableMessage) throw new Error('No typed data to be signed.') - return createJsonRpcResponse(pid, await signer.signTypedData(signableMessage)) + return createJsonRpcResponse(pid, await signMessageOrTypedData(SignType.TypedData, signableMessage)) } catch (error) { throw ErrorEditor.from(error, null, 'Failed to sign typed data.').error } case EthereumMethodType.eth_signTransaction: try { - if (!signableConfig) throw new Error('No transaction to be signed.') - return createJsonRpcResponse(pid, await signer.signTransaction(signableConfig)) + if (!signableTransaction) throw new Error('No transaction to be signed.') + return createJsonRpcResponse(pid, await signTransaction(signableTransaction)) } catch (error) { throw ErrorEditor.from(error, null, 'Failed to sign transaction.').error } diff --git a/packages/mask/background/services/wallet/services/wallet/index.ts b/packages/mask/background/services/wallet/services/wallet/index.ts index 8a89579b6ee3..280a6fde1ee2 100644 --- a/packages/mask/background/services/wallet/services/wallet/index.ts +++ b/packages/mask/background/services/wallet/services/wallet/index.ts @@ -4,7 +4,7 @@ import defer * as web3_utils from 'web3-utils' import { toBytes } from '@ethereumjs/util' import { api } from '@dimensiondev/mask-wallet-core/proto' import { Signer } from '@masknet/web3-providers' -import { ImportSource, type SignType, type Wallet } from '@masknet/shared-base' +import { ImportSource, type SignMessage, type Wallet } from '@masknet/shared-base' import { HD_PATH_WITHOUT_INDEX_ETHEREUM } from '@masknet/web3-shared-base' import * as Mask from '../maskwallet/index.js' import * as database from './database/index.js' @@ -249,8 +249,8 @@ export async function resetAllWallets() { await database.resetAllWallets() } -export async function signWithWallet(type: SignType, message: T, address: string) { - return Signer.sign(type, Buffer.from(toBytes(`0x${await exportPrivateKey(address)}`)), message) +export async function signWithWallet(message: SignMessage, address: string) { + return Signer.sign(message, Buffer.from(toBytes(`0x${await exportPrivateKey(address)}`))) } export async function exportMnemonicWords(address: string, unverifiedPassword?: string) { diff --git a/packages/mask/popups/components/ConnectedWallet/index.tsx b/packages/mask/popups/components/ConnectedWallet/index.tsx index c3b17ddf32e5..9cdd196af62c 100644 --- a/packages/mask/popups/components/ConnectedWallet/index.tsx +++ b/packages/mask/popups/components/ConnectedWallet/index.tsx @@ -117,8 +117,7 @@ export const ConnectedWallet = memo(function ConnectedWallet() { if (!result) return const signature = await Services.Identity.signWithPersona( - SignType.Message, - result.signPayload, + { type: SignType.Message, data: result.signPayload }, persona.identifier, location.origin, true, diff --git a/packages/mask/popups/pages/Personas/AccountDetail/index.tsx b/packages/mask/popups/pages/Personas/AccountDetail/index.tsx index 05552a27e955..70f4f608f0a8 100644 --- a/packages/mask/popups/pages/Personas/AccountDetail/index.tsx +++ b/packages/mask/popups/pages/Personas/AccountDetail/index.tsx @@ -77,8 +77,7 @@ export const Component = memo(() => { if (!result) return const signature = await Service.Identity.signWithPersona( - SignType.Message, - result.signPayload, + { type: SignType.Message, data: result.signPayload }, currentPersona.identifier, location.origin, true, diff --git a/packages/mask/popups/pages/Personas/ConnectWallet/index.tsx b/packages/mask/popups/pages/Personas/ConnectWallet/index.tsx index a8c6baa69321..469844309e39 100644 --- a/packages/mask/popups/pages/Personas/ConnectWallet/index.tsx +++ b/packages/mask/popups/pages/Personas/ConnectWallet/index.tsx @@ -172,8 +172,7 @@ export const Component = memo(function ConnectWalletPage() { if (!payload) return const personaSignature = await Services.Identity.signWithPersona( - SignType.Message, - payload.signPayload, + { type: SignType.Message, data: payload.signPayload }, currentPersona.identifier, location.origin, true, diff --git a/packages/mask/popups/pages/Personas/PersonaAvatarSetting/index.tsx b/packages/mask/popups/pages/Personas/PersonaAvatarSetting/index.tsx index 0e8bc1f57a06..0c6937be990c 100644 --- a/packages/mask/popups/pages/Personas/PersonaAvatarSetting/index.tsx +++ b/packages/mask/popups/pages/Personas/PersonaAvatarSetting/index.tsx @@ -132,8 +132,7 @@ const PersonaAvatarSetting = memo(function PersonaAvatar() { // Verify Wallet sign with persona if (bindingWallets.some((x) => isSameAddress(x.identity, account))) { sign = await Services.Identity.signWithPersona( - SignType.Message, - JSON.stringify(data), + { type: SignType.Message, data: JSON.stringify(data) }, currentPersona.identifier, location.origin, true, diff --git a/packages/mask/popups/pages/Personas/PersonaSignRequest/index.tsx b/packages/mask/popups/pages/Personas/PersonaSignRequest/index.tsx index 17546c92d1dd..f166c3c61c9b 100644 --- a/packages/mask/popups/pages/Personas/PersonaSignRequest/index.tsx +++ b/packages/mask/popups/pages/Personas/PersonaSignRequest/index.tsx @@ -60,8 +60,7 @@ export const Component = memo(function PersonaSignRequest() { case MethodAfterPersonaSign.DISCONNECT_NEXT_ID: if (!message) break const signature = await Services.Identity.signWithPersona( - SignType.Message, - message, + { type: SignType.Message, data: message }, selectedPersona, location.origin, true, diff --git a/packages/mask/shared-ui/initUIContext.ts b/packages/mask/shared-ui/initUIContext.ts index bfbd57509e2d..a17d72547e4d 100644 --- a/packages/mask/shared-ui/initUIContext.ts +++ b/packages/mask/shared-ui/initUIContext.ts @@ -40,7 +40,7 @@ export function setupUIContext() { queryPersonaByProfile: Services.Identity.queryPersonaByProfile, openDashboard: Services.Helper.openDashboard, openPopupWindow, - signWithPersona: (a, b, c, d) => Services.Identity.signWithPersona(a, b, c, location.origin, d), + signWithPersona: (a, b, c) => Services.Identity.signWithPersona(a, b, location.origin, c), hasPaymentPassword: Services.Wallet.hasPassword, createPersona: () => Services.Helper.openDashboard(DashboardRoutes.SignUpPersona), attachProfile: Services.Identity.attachProfile, diff --git a/packages/mask/shared-ui/initialization/walletSetup.ts b/packages/mask/shared-ui/initialization/walletSetup.ts index 8a1ca131501c..47847302d047 100644 --- a/packages/mask/shared-ui/initialization/walletSetup.ts +++ b/packages/mask/shared-ui/initialization/walletSetup.ts @@ -7,7 +7,6 @@ import { delay } from '@masknet/kit' import { openPopupWindow } from '../utils/openPopup.js' await initWallet({ - signWithPersona: (a, b, c, d) => Services.Identity.signWithPersona(a, b, c, location.origin, d), WalletConnectContext: { openWalletConnectDialog: async (uri: string) => { if (Sniffings.is_popup_page) { diff --git a/packages/plugin-infra/src/dom/context.ts b/packages/plugin-infra/src/dom/context.ts index d1b94e32e749..b098f517f5fe 100644 --- a/packages/plugin-infra/src/dom/context.ts +++ b/packages/plugin-infra/src/dom/context.ts @@ -10,7 +10,7 @@ import type { PopupRoutes, PopupRoutesParamsMap, ProfileIdentifier, - SignType, + SignMessage, SocialIdentity, } from '@masknet/shared-base' import type { Subscription } from 'use-subscription' @@ -41,7 +41,7 @@ export interface __UIContext__ { params: T extends keyof PopupRoutesParamsMap ? PopupRoutesParamsMap[T] : undefined, ): Promise /** Sign a message with persona (w or w/o popups) */ - signWithPersona(type: SignType, message: unknown, identifier?: ECKeyIdentifier, silent?: boolean): Promise + signWithPersona(message: SignMessage, identifier?: ECKeyIdentifier, silent?: boolean): Promise hasPaymentPassword(): Promise createPersona: () => void setCurrentPersonaIdentifier: ((x?: PersonaIdentifier) => Promise) | undefined diff --git a/packages/plugins/NextID/src/hooks/usePersonaSign.ts b/packages/plugins/NextID/src/hooks/usePersonaSign.ts index cb16fb5e8258..72c229e96fbf 100644 --- a/packages/plugins/NextID/src/hooks/usePersonaSign.ts +++ b/packages/plugins/NextID/src/hooks/usePersonaSign.ts @@ -6,7 +6,7 @@ export function usePersonaSign(message?: string, currentIdentifier?: ECKeyIdenti return useAsyncFn(async () => { if (!message || !currentIdentifier) return try { - return await signWithPersona?.(SignType.Message, message, currentIdentifier) + return await signWithPersona?.({ type: SignType.Message, data: message }, currentIdentifier) } catch { return } diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useClaimNftRedpacketCallback.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useClaimNftRedpacketCallback.ts index 16d594a2d363..74e8844ca652 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useClaimNftRedpacketCallback.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useClaimNftRedpacketCallback.ts @@ -7,7 +7,7 @@ import { EVMWeb3 } from '@masknet/web3-providers' import { useNftRedPacketContract } from './useNftRedPacketContract.js' import type { RedPacketNftJSONPayload } from '@masknet/web3-providers/types' import { useSignedMessage } from './useSignedMessage.js' -import { useMemo } from 'react' +import type { Hex } from 'viem' const EXTRA_GAS_PER_NFT = 335 @@ -16,12 +16,10 @@ export function useClaimNftRedpacketCallback(payload: RedPacketNftJSONPayload, t const nftRedPacketContract = useNftRedPacketContract(chainId) const { refetch } = useSignedMessage(account, payload) const id = payload.id - const signedMsg = useMemo(() => { - return signMessage(account, payload.privateKey).signature ?? '' - }, [account, payload.privateKey]) return useAsyncFn(async () => { - if (!nftRedPacketContract || !id || !account || !totalAmount || !signedMsg) return + if (!nftRedPacketContract || !id || !account || !totalAmount || !payload.privateKey) return + const signedMsg = await signMessage(account, payload.privateKey as Hex) const transaction = nftRedPacketContract.methods.claim(id, signedMsg, account) const estimatedGas = await transaction.estimateGas({ from: account }) const tx = await new ContractTransaction(nftRedPacketContract).fillAll(transaction, { @@ -30,5 +28,5 @@ export function useClaimNftRedpacketCallback(payload: RedPacketNftJSONPayload, t chainId, }) return EVMWeb3.sendTransaction(tx, { chainId }) - }, [id, refetch, account, chainId, totalAmount, signedMsg]) + }, [id, refetch, account, chainId, totalAmount, account, payload.privateKey]) } diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useSignedMessage.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useSignedMessage.ts index c94569d85859..ad58a7d79811 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useSignedMessage.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useSignedMessage.ts @@ -4,6 +4,7 @@ import { type RedPacketJSONPayload, type RedPacketNftJSONPayload } from '@maskne import { signMessage } from '@masknet/web3-shared-evm' import { useQuery } from '@tanstack/react-query' import { usePlatformType } from './usePlatformType.js' +import type { Hex } from 'viem' // TODO NFT redpacket is not supported by the API yet. export function useSignedMessage( @@ -34,7 +35,7 @@ export function useSignedMessage( queryKey: ['red-packet', 'signed-message', rpid, version, password, account, profile, isTokenRedPacket], queryFn: async () => { if (isTokenRedPacket && version <= 3) return password ?? null - if (password) return signMessage(account, password).signature + if (password) return signMessage(account, password as Hex) if (!profile) return '' return ( (await FireflyRedPacket.createClaimSignature({ diff --git a/packages/shared-base/src/types/Account.ts b/packages/shared-base/src/types/Account.ts index cefde04d0226..32e8cc9d5149 100644 --- a/packages/shared-base/src/types/Account.ts +++ b/packages/shared-base/src/types/Account.ts @@ -1,3 +1,4 @@ +import type { TransactionSerializable } from 'viem' export interface Account { account: string chainId: ChainId @@ -10,3 +11,15 @@ export enum SignType { TypedData = 'typedData', Transaction = 'transaction', } + +export type SignMessage = SignMessage_String | SignMessage_Transaction + +export interface SignMessage_String { + type: SignType.Message | SignType.TypedData + data: string +} + +export interface SignMessage_Transaction { + type: SignType.Transaction + data: TransactionSerializable +} diff --git a/packages/shared/src/hooks/useVerifyContent.ts b/packages/shared/src/hooks/useVerifyContent.ts index b063c780c368..b401d3b88cac 100644 --- a/packages/shared/src/hooks/useVerifyContent.ts +++ b/packages/shared/src/hooks/useVerifyContent.ts @@ -32,7 +32,11 @@ export function useVerifyContent(personaIdentifier: PersonaIdentifier | undefine ) if (!payload) throw new Error('Failed to create persona payload.') - const signature = await signWithPersona(SignType.Message, payload.signPayload, personaIdentifier, true) + const signature = await signWithPersona( + { type: SignType.Message, data: payload.signPayload }, + personaIdentifier, + true, + ) const post = payload.postContent.replace('%SIG_BASE64%', toBase64(fromHex(signature))) return { post, diff --git a/packages/shared/src/hooks/useVerifyNextID.ts b/packages/shared/src/hooks/useVerifyNextID.ts index 6094fd2bff07..1e7da047411b 100644 --- a/packages/shared/src/hooks/useVerifyNextID.ts +++ b/packages/shared/src/hooks/useVerifyNextID.ts @@ -23,7 +23,11 @@ async function createAndSignMessage(platform: NextIDPlatform, persona: PersonaIn ) if (!payload) throw new Error('Failed to create persona payload.') - const signature = await signWithPersona(SignType.Message, payload.signPayload, persona.identifier, true) + const signature = await signWithPersona( + { type: SignType.Message, data: payload.signPayload }, + persona.identifier, + true, + ) if (!signature) throw new Error('Failed to sign by persona.') return { payload, signature } } diff --git a/packages/web3-providers/src/Web3/Base/state/Provider.ts b/packages/web3-providers/src/Web3/Base/state/Provider.ts index ed6c2c2f2801..06478d54ddda 100644 --- a/packages/web3-providers/src/Web3/Base/state/Provider.ts +++ b/packages/web3-providers/src/Web3/Base/state/Provider.ts @@ -29,10 +29,7 @@ export abstract class ProviderState, ProviderType>>, - ) {} + constructor(protected storage: StorageObject, ProviderType>>) {} protected init() { this.setupSubscriptions() this.setupProviders() diff --git a/packages/web3-providers/src/Web3/EVM/apis/ComposerAPI.ts b/packages/web3-providers/src/Web3/EVM/apis/ComposerAPI.ts index 085a20694672..844065068f12 100644 --- a/packages/web3-providers/src/Web3/EVM/apis/ComposerAPI.ts +++ b/packages/web3-providers/src/Web3/EVM/apis/ComposerAPI.ts @@ -5,19 +5,18 @@ import { Interceptor } from '../middleware/Interceptor.js' import { RecentTransaction } from '../middleware/RecentTransaction.js' import { TransactionWatcher } from '../middleware/TransactionWatcher.js' import type { ConnectionContext } from '../libs/ConnectionContext.js' -import type { WalletAPI } from '../../../entry-types.js' import { Permit } from '../middleware/Permit.js' let instance: EVMComposer | undefined export class Composer { - static compose(signWithPersona: WalletAPI.SignWithPersona) { + static compose() { if (instance) return instance instance = EVMComposer.from( new Permit(), Nonce, new Translator(), - new Interceptor(signWithPersona), + new Interceptor(), new RecentTransaction(), new TransactionWatcher(), ) diff --git a/packages/web3-providers/src/Web3/EVM/apis/RequestAPI.ts b/packages/web3-providers/src/Web3/EVM/apis/RequestAPI.ts index 88f7c6d0b3e6..2ad2d0a3ec9e 100644 --- a/packages/web3-providers/src/Web3/EVM/apis/RequestAPI.ts +++ b/packages/web3-providers/src/Web3/EVM/apis/RequestAPI.ts @@ -28,7 +28,7 @@ export class EVMRequestAPI extends EVMRequestReadonlyAPI { const context = createContext(requestArguments, options) try { - await Composer.compose(this.Provider.signWithPersona).dispatch(context, async () => { + await Composer.compose().dispatch(context, async () => { if (!context.writable) return try { switch (context.method) { diff --git a/packages/web3-providers/src/Web3/EVM/apis/SignerAPI.ts b/packages/web3-providers/src/Web3/EVM/apis/SignerAPI.ts index 4da41b4ed21c..00bbdd10e7b4 100644 --- a/packages/web3-providers/src/Web3/EVM/apis/SignerAPI.ts +++ b/packages/web3-providers/src/Web3/EVM/apis/SignerAPI.ts @@ -1,29 +1,30 @@ import defer * as _metamask_eth_sig_util from '@metamask/eth-sig-util' -import { signTransaction, type Transaction } from '@masknet/web3-shared-evm' -import { SignType, toHex } from '@masknet/shared-base' +import { signTransaction } from '@masknet/web3-shared-evm' +import { type SignMessage, SignType, toHex } from '@masknet/shared-base' import { unreachable } from '@masknet/kit' +import type { Hex } from 'viem' export class Signer { - static async sign(type: SignType, key: Buffer, message: unknown): Promise { + static async sign({ type, data }: SignMessage, key: Buffer): Promise { switch (type) { case SignType.Message: return _metamask_eth_sig_util.personalSign({ privateKey: key, - data: message as string, + data, }) case SignType.TypedData: return _metamask_eth_sig_util.signTypedData({ privateKey: key, - data: JSON.parse(message as string), + data: JSON.parse(data), version: _metamask_eth_sig_util.SignTypedDataVersion.V4, }) case SignType.Transaction: - const transaction = message as Transaction + const transaction = data const chainId = transaction.chainId if (!chainId) throw new Error('Invalid chain id.') - const { rawTransaction } = await signTransaction(transaction, toHex(key)) + const rawTransaction = await signTransaction(transaction, toHex(key) as Hex) if (!rawTransaction) throw new Error('Failed to sign transaction.') return rawTransaction diff --git a/packages/web3-providers/src/Web3/EVM/middleware/Interceptor.ts b/packages/web3-providers/src/Web3/EVM/middleware/Interceptor.ts index 9e59e87e3f96..3009d44a0f74 100644 --- a/packages/web3-providers/src/Web3/EVM/middleware/Interceptor.ts +++ b/packages/web3-providers/src/Web3/EVM/middleware/Interceptor.ts @@ -6,10 +6,9 @@ import { WalletConnect } from '../interceptors/WalletConnect.js' import { MetaMaskLike } from '../interceptors/MetaMaskLike.js' import { Popups } from '../interceptors/Popups.js' import { CustomNetwork } from '../interceptors/CustomNetwork.js' -import type { WalletAPI } from '../../../entry-types.js' export class Interceptor implements Middleware { - constructor(private signWithPersona: WalletAPI.SignWithPersona) { + constructor() { this.composers = { [ProviderType.None]: Composer.from(new NoneWallet()), [ProviderType.BitGet]: Composer.from(new MetaMaskLike(ProviderType.BitGet)), diff --git a/packages/web3-providers/src/Web3/EVM/state/Provider.ts b/packages/web3-providers/src/Web3/EVM/state/Provider.ts index 5d1de6ded710..89dc96112cad 100644 --- a/packages/web3-providers/src/Web3/EVM/state/Provider.ts +++ b/packages/web3-providers/src/Web3/EVM/state/Provider.ts @@ -23,7 +23,7 @@ export class EVMProvider extends ProviderState, ProviderType>>, hostedProviderStorage: BaseHostedStorage, ) { - super(context.signWithPersona, storage) + super(storage) this.providers = createEVMWalletProviders(context, hostedProviderStorage) this.init() } diff --git a/packages/web3-providers/src/Web3/Flow/apis/Web3StateAPI.ts b/packages/web3-providers/src/Web3/Flow/apis/Web3StateAPI.ts index f11e570c716f..7aaa3d7b29f0 100644 --- a/packages/web3-providers/src/Web3/Flow/apis/Web3StateAPI.ts +++ b/packages/web3-providers/src/Web3/Flow/apis/Web3StateAPI.ts @@ -31,7 +31,7 @@ export async function createFlowState(context: WalletAPI.IOContext): Promise new Provider.FlowProvider(context.signWithPersona, provider), + Provider: () => new Provider.FlowProvider(provider), AddressBook: () => new AddressBook.FlowAddressBook(address), IdentityService: () => new IdentityService.FlowIdentityService(), Settings: () => new Settings.FlowSettings(settings), diff --git a/packages/web3-providers/src/Web3/Flow/state/Provider.ts b/packages/web3-providers/src/Web3/Flow/state/Provider.ts index c673e62a31f5..da03d98bd182 100644 --- a/packages/web3-providers/src/Web3/Flow/state/Provider.ts +++ b/packages/web3-providers/src/Web3/Flow/state/Provider.ts @@ -13,15 +13,11 @@ import { import { createFlowWalletProviders } from '../providers/index.js' import { FlowChainResolver } from '../apis/ResolverAPI.js' import { ProviderState, type ProviderStorage } from '../../Base/state/Provider.js' -import type { WalletAPI } from '../../../entry-types.js' import type { Account, StorageObject } from '@masknet/shared-base' export class FlowProvider extends ProviderState { - constructor( - signWithPersona: WalletAPI.SignWithPersona, - storage: StorageObject, ProviderType>>, - ) { - super(signWithPersona, storage) + constructor(storage: StorageObject, ProviderType>>) { + super(storage) this.init() } public providers = createFlowWalletProviders() diff --git a/packages/web3-providers/src/Web3/Solana/apis/Web3StateAPI.ts b/packages/web3-providers/src/Web3/Solana/apis/Web3StateAPI.ts index 9253febb3621..9472f5dfa17c 100644 --- a/packages/web3-providers/src/Web3/Solana/apis/Web3StateAPI.ts +++ b/packages/web3-providers/src/Web3/Solana/apis/Web3StateAPI.ts @@ -31,7 +31,7 @@ export async function createSolanaState(context: WalletAPI.IOContext): Promise new Provider.SolanaProvider(context.signWithPersona, provider), + Provider: () => new Provider.SolanaProvider(provider), AddressBook: () => new AddressBook.SolanaAddressBook(address), IdentityService: () => new IdentityService.SolanaIdentityService(), Settings: () => new Settings.SolanaSettings(settings), diff --git a/packages/web3-providers/src/Web3/Solana/state/Provider.ts b/packages/web3-providers/src/Web3/Solana/state/Provider.ts index 5c2a2b63498d..9800690c822e 100644 --- a/packages/web3-providers/src/Web3/Solana/state/Provider.ts +++ b/packages/web3-providers/src/Web3/Solana/state/Provider.ts @@ -13,15 +13,11 @@ import { import { createSolanaWalletProviders } from '../providers/index.js' import { SolanaChainResolver } from '../apis/ResolverAPI.js' import { ProviderState, type ProviderStorage } from '../../Base/state/Provider.js' -import type { WalletAPI } from '../../../entry-types.js' import type { Account, StorageObject } from '@masknet/shared-base' export class SolanaProvider extends ProviderState { - constructor( - signWithPersona: WalletAPI.SignWithPersona, - storage: StorageObject, ProviderType>>, - ) { - super(signWithPersona, storage) + constructor(storage: StorageObject, ProviderType>>) { + super(storage) this.init() } public providers = createSolanaWalletProviders() diff --git a/packages/web3-providers/src/types/Wallet.ts b/packages/web3-providers/src/types/Wallet.ts index c79b2df03cb1..2eecc77e634d 100644 --- a/packages/web3-providers/src/types/Wallet.ts +++ b/packages/web3-providers/src/types/Wallet.ts @@ -4,11 +4,11 @@ import type { ECKeyIdentifier, Account, Wallet, - SignType, PopupRoutes, PopupRoutesParamsMap, PersonaInformation, ImportSource, + SignMessage, } from '@masknet/shared-base' import type { JsonRpcResponse, JsonRpcRequest } from 'web3-types' import type { ChainId, TransactionOptions } from '@masknet/web3-shared-evm' @@ -67,8 +67,7 @@ export namespace WalletAPI { disconnectAllWalletsFromOrigin(origin: string, type: 'any' | 'sdk' | 'internal'): Promise } export type SignWithPersona = ( - type: SignType, - message: unknown, + message: SignMessage, identifier?: ECKeyIdentifier, silent?: boolean, ) => Promise @@ -86,8 +85,6 @@ export namespace WalletAPI { MaskWalletContext: MaskWalletIOContext MessageContext: MessageIOContext WalletConnectContext: WalletConnectIOContext - /** Sign a message with persona (w or w/o popups) */ - signWithPersona: SignWithPersona } export interface Provider { readonly ready: boolean diff --git a/packages/web3-shared/base/src/specs/index.ts b/packages/web3-shared/base/src/specs/index.ts index 6d7e892bc3ce..0af249ddcef3 100644 --- a/packages/web3-shared/base/src/specs/index.ts +++ b/packages/web3-shared/base/src/specs/index.ts @@ -3,7 +3,6 @@ import type { Subscription } from 'use-subscription' import type { JsonRpcRequest } from 'web3-types' import type { Emitter } from '@servie/events' import type { - ECKeyIdentifier, EnhanceableSite, ExtensionSite, NetworkPluginID, @@ -12,7 +11,6 @@ import type { SocialAddress, SocialIdentity, SocialAccount, - SignType, Web3BioProfile, } from '@masknet/shared-base' @@ -1294,9 +1292,6 @@ export interface ProviderState { ) => Promise> /** Disconnect with the provider. */ disconnect: (providerType: ProviderType) => Promise - /** Sign a message with persona (w or w/o popups) */ - // TODO: this is not the best place to put this signature, but to avoid IOContext leaked as a global variable, we'll put it here for now. - signWithPersona(type: SignType, message: unknown, identifier?: ECKeyIdentifier, silent?: boolean): Promise } export interface BalanceNotifierState { diff --git a/packages/web3-shared/evm/package.json b/packages/web3-shared/evm/package.json index 0cb6bba888c2..1db18c8f71b1 100644 --- a/packages/web3-shared/evm/package.json +++ b/packages/web3-shared/evm/package.json @@ -24,7 +24,6 @@ "punycode": "^2.3.1", "web3-core": "1.10.4", "web3-eth": "1.10.4", - "web3-eth-accounts": "1.10.4", "web3-eth-contract": "1.10.4", "web3-utils": "1.10.4", "web3-types": "1.10.0", diff --git a/packages/web3-shared/evm/src/helpers/createAccount.ts b/packages/web3-shared/evm/src/helpers/createAccount.ts index b527902e6afb..66b01e92ba54 100644 --- a/packages/web3-shared/evm/src/helpers/createAccount.ts +++ b/packages/web3-shared/evm/src/helpers/createAccount.ts @@ -1,9 +1,7 @@ -import type { Account } from 'web3-core' -import defer * as Web3Accounts from 'web3-eth-accounts' -import type { Accounts } from 'web3-eth-accounts' +import { generatePrivateKey, privateKeyToAddress } from 'viem/accounts' -export function createAccount(): Account { - const Accounts_ = Web3Accounts.default as unknown as typeof Accounts - const accounts = new Accounts_() - return accounts.create() +export function createAccount() { + const privateKey = generatePrivateKey() + const address = privateKeyToAddress(privateKey) + return { privateKey, address } } diff --git a/packages/web3-shared/evm/src/helpers/signMessage.ts b/packages/web3-shared/evm/src/helpers/signMessage.ts index f6cb889203ce..27d0dbf75c27 100644 --- a/packages/web3-shared/evm/src/helpers/signMessage.ts +++ b/packages/web3-shared/evm/src/helpers/signMessage.ts @@ -1,8 +1,9 @@ -import defer * as Web3Accounts from 'web3-eth-accounts' -import type { Accounts } from 'web3-eth-accounts' +import type { Hex } from 'viem' +import { signMessage as viem_sign } from 'viem/accounts' -export function signMessage(message: string, privateKey: string): Web3Accounts.Sign { - const Accounts_ = Web3Accounts.default as unknown as typeof Accounts - const accounts = new Accounts_() - return accounts.sign(message, privateKey) +export function signMessage(message: string, privateKey: Hex): Promise { + return viem_sign({ + message: message.startsWith('0x') ? { raw: message as Hex } : message, + privateKey, + }) } diff --git a/packages/web3-shared/evm/src/helpers/signTransaction.ts b/packages/web3-shared/evm/src/helpers/signTransaction.ts index 69ea4b572ed4..973a20e14ab2 100644 --- a/packages/web3-shared/evm/src/helpers/signTransaction.ts +++ b/packages/web3-shared/evm/src/helpers/signTransaction.ts @@ -1,10 +1,6 @@ -import defer * as Web3Accounts from 'web3-eth-accounts' -import type { Accounts } from 'web3-eth-accounts' -import type { Transaction } from '../types/index.js' +import { signTransaction as viem_signTransaction } from 'viem/accounts' +import type { Hex, TransactionSerializable } from 'viem' -export function signTransaction(transaction: Transaction, privateKey: string) { - if (typeof transaction.nonce === 'undefined') throw new Error('Nonce is required.') - const Accounts_ = Web3Accounts.default as unknown as typeof Accounts - const accounts = new Accounts_() - return accounts.signTransaction(transaction, privateKey) +export function signTransaction(transaction: TransactionSerializable, privateKey: Hex) { + return viem_signTransaction({ privateKey, transaction }) } diff --git a/packages/web3-shared/evm/src/libs/AccountTransaction.ts b/packages/web3-shared/evm/src/libs/AccountTransaction.ts index 64b3c7c1db98..977513ffb3f3 100644 --- a/packages/web3-shared/evm/src/libs/AccountTransaction.ts +++ b/packages/web3-shared/evm/src/libs/AccountTransaction.ts @@ -57,7 +57,6 @@ export class AccountTransaction { maxFeePerGas, data, nonce, - _disableExceptionSnackbar, _disableSuccessSnackbar, _disableSnackbar, } = { @@ -76,7 +75,6 @@ export class AccountTransaction { maxPriorityFeePerGas: maxPriorityFeePerGas ? normalizeHex(maxPriorityFeePerGas) : undefined, maxFeePerGas: maxFeePerGas ? normalizeHex(maxFeePerGas) : undefined, nonce, - _disableExceptionSnackbar, _disableSuccessSnackbar, _disableSnackbar, }, diff --git a/packages/web3-shared/evm/src/libs/PayloadEditor.ts b/packages/web3-shared/evm/src/libs/PayloadEditor.ts index ba1e85d8eea2..bc91a9ffb9d0 100644 --- a/packages/web3-shared/evm/src/libs/PayloadEditor.ts +++ b/packages/web3-shared/evm/src/libs/PayloadEditor.ts @@ -1,8 +1,6 @@ import { first, isUndefined, omitBy } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' import type { JsonRpcRequest } from 'web3-types' import type { Wallet } from '@masknet/shared-base' -import { formatEthereumAddress } from '../helpers/formatter.js' import { parseChainId } from '../helpers/parseChainId.js' import { createJsonRpcRequest } from '../helpers/createJsonRpcRequest.js' import { @@ -14,6 +12,7 @@ import { import { readonlyMethodType } from '../helpers/isReadonlyMethodType.js' import { riskyMethodType } from '../helpers/isRiskyMethodType.js' import { gasConsumingMethodType } from '../helpers/isGasConsumingMethodType.js' +import { hexToBigInt, hexToNumber, isHex, type Hex, type TransactionSerializable } from 'viem' type Options = Pick @@ -87,7 +86,7 @@ export class PayloadEditor { return omitBy( { ...raw, - nonce: parseHexNumber(raw?.nonce), + nonce: toNumber(raw?.nonce), from: raw?.from ?? this.options?.account, chainId: parseChainId(raw?.chainId) ?? this.options?.chainId, }, @@ -124,24 +123,27 @@ export class PayloadEditor { } } - get signableConfig() { + get signableTransaction(): TransactionSerializable | undefined { if (!this.config) return - return omitBy( - { - ...this.config, - from: this.config.from ? formatEthereumAddress(this.config.from) : '', - value: parseHexNumberString(this.config.value), - gas: parseHexNumberString(this.config.gas), - gasPrice: parseHexNumberString(this.config.gasPrice), - maxFeePerGas: parseHexNumberString(this.config.maxFeePerGas), - maxPriorityFeePerGas: parseHexNumberString(this.config.maxPriorityFeePerGas), - // TODO: revert to parseHexNumberString after updating MaskCore - chainId: parseHexNumber(this.config.chainId), - nonce: parseHexNumberString(this.config.nonce), - }, - isUndefined, - ) as Transaction + const tx = { + ...this.config, + type: + this.config.type === '0x0' ? 'legacy' + : this.config.type === '0x1' ? 'eip2930' + : this.config.type === '0x2' ? 'eip1559' + : undefined, + to: this.config.to as Hex, + data: this.config.data as Hex, + value: toBigInt(this.config.value), + gas: toBigInt(this.config.gas), + gasPrice: toBigInt(this.config.gasPrice), + maxFeePerGas: toBigInt(this.config.maxFeePerGas), + maxPriorityFeePerGas: toBigInt(this.config.maxPriorityFeePerGas), + chainId: toNumber(this.config.chainId), + nonce: toNumber(this.config.nonce), + } as TransactionSerializable + return omitBy(tx, isUndefined) } get risky() { @@ -179,10 +181,20 @@ export class PayloadEditor { } } -function parseHexNumberString(hex: string | number | undefined) { - return typeof hex !== 'undefined' ? web3_utils.hexToNumberString(hex ?? '0x0') : undefined +function toBigInt(hex: string | number | undefined) { + if (typeof hex === 'number') return BigInt(hex) + if (typeof hex === 'string') { + if (isHex(hex)) return hexToBigInt(hex) + return BigInt(hex) + } + return undefined } -function parseHexNumber(hex: string | number | undefined) { - return typeof hex !== 'undefined' ? (web3_utils.hexToNumber(hex) as number) : undefined +function toNumber(hex: string | number | undefined) { + if (typeof hex === 'number') return hex + if (typeof hex === 'string') { + if (isHex(hex)) return Number(hexToNumber(hex)) + return Number(hex) + } + return undefined } diff --git a/packages/web3-shared/evm/src/libs/Signer.ts b/packages/web3-shared/evm/src/libs/Signer.ts deleted file mode 100644 index e3e5555a7a24..000000000000 --- a/packages/web3-shared/evm/src/libs/Signer.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { SignType } from '@masknet/shared-base' -import type { Transaction } from '@masknet/web3-shared-evm' - -export class Signer { - constructor( - private identifier: T, - private sign: (type: SignType, message: string | Transaction, identifier: T) => Promise, - ) {} - - signMessage(message: string): Promise { - return this.sign(SignType.Message, message, this.identifier) - } - - signTypedData(data: string): Promise { - return this.sign(SignType.TypedData, data, this.identifier) - } - - signTransaction(transaction: Transaction): Promise { - return this.sign(SignType.Transaction, transaction, this.identifier) - } -} diff --git a/packages/web3-shared/evm/src/libs/index.ts b/packages/web3-shared/evm/src/libs/index.ts index 0191b7bc38b7..a8b5ba6e1c2b 100644 --- a/packages/web3-shared/evm/src/libs/index.ts +++ b/packages/web3-shared/evm/src/libs/index.ts @@ -8,5 +8,4 @@ export * from './GasEditor.js' export * from './PayloadEditor.js' export * from './ProviderURL.js' export * from './RequestID.js' -export * from './Signer.js' export * from './Web3.js' diff --git a/packages/web3-shared/evm/src/types/index.ts b/packages/web3-shared/evm/src/types/index.ts index 2041ee92185c..e73e1169806e 100644 --- a/packages/web3-shared/evm/src/types/index.ts +++ b/packages/web3-shared/evm/src/types/index.ts @@ -406,7 +406,11 @@ export interface Transaction { from?: string to?: string value?: string - /** gasLimit */ + // value?: bigint + // gas?: bigint + // gasPrice?: bigint + // maxPriorityFeePerGas?: bigint + // maxFeePerGas?: bigint gas?: string gasPrice?: string maxPriorityFeePerGas?: string @@ -416,16 +420,8 @@ export interface Transaction { chainId?: number type?: '0x0' | '0x1' | '0x2' - // CELO - feeCurrency?: string // address of the ERC20 contract to use to pay for gas and the gateway fee - gatewayFeeRecipient?: string // coinbase address of the full serving the light client's transactions - gatewayFee?: string // value paid to the gateway fee recipient, denominated in the fee currency - _disableSnackbar?: boolean _disableSuccessSnackbar?: boolean - _disableExceptionSnackbar?: boolean - - _isOKXSwap?: boolean } export type TransactionReceipt = Web3TransactionReceipt export type TransactionDetailed = Web3Transaction diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba7959d79e73..049b437e62d2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2967,9 +2967,6 @@ importers: web3-eth: specifier: 1.10.4 version: 1.10.4(encoding@0.1.13) - web3-eth-accounts: - specifier: 1.10.4 - version: 1.10.4(encoding@0.1.13) web3-eth-contract: specifier: 1.10.4 version: 1.10.4(encoding@0.1.13)