import Web3 from 'web3' ; import type { provider as Provider } from 'web3-core' ; import { first } from 'lodash-unified' ; import createMetaMaskProvider , { MetaMaskInpageProvider } from '@dimensiondev/metamask-extension-provider' ; import { ChainId , ProviderType } from '@masknet/web3-shared-evm' ; import { delay } from '@masknet/shared-base' ; import { updateAccount } from '../../../../plugins/Wallet/services' ; import { currentChainIdSettings , currentProviderSettings } from '../../../../plugins/Wallet/settings' ; import { replaceRecentTransaction } from '../../../../plugins/Wallet/services/transaction/database' ; let provider = null ; let web3 = null ; async function onAccountsChanged ( accounts ) { if ( currentProviderSettings . value !== ProviderType . MetaMask ) return ; await updateAccount ( { account : first ( accounts ) , providerType : ProviderType . MetaMask , chainId : typeof provider ?. chainId === 'string' ? Number . parseInt ( provider . chainId , 16 ) : undefined , } ) ; } async function onChainIdChanged ( id ) { if ( currentProviderSettings . value !== ProviderType . MetaMask ) return ; const chainId = Number . parseInt ( id , 16 ) || ChainId . Mainnet ; if ( currentChainIdSettings . value === chainId ) return ; await updateAccount ( { chainId , } ) ; } async function onMessage ( message ) { if ( message . type !== 'tx_replacement' ) return ; await replaceRecentTransaction ( currentChainIdSettings . value , message . data . from , message . data . oldTx , message . data . newTx ) ; } export async function createProvider ( ) { if ( provider && provider . chainId !== null ) return provider ; provider = createMetaMaskProvider ( ) ; await delay ( 1000 ) ; if ( ! provider || provider . chainId === null ) { provider = null ; throw new Error ( 'Unable to create provider.' ) ; } provider . on ( 'accountsChanged' , onAccountsChanged as ( ... args : unknown [ ] ) => void ) ; provider . on ( 'chainChanged' , onChainIdChanged as ( ... args : unknown [ ] ) => void ) ; provider . on ( 'message' , onMessage as ( ... args : unknown [ ] ) => void ) ; return provider ; } export async function createWeb3 ( ) { const provider_ = ( await createProvider ( ) ) as Provider ; if ( ! web3 ) web3 = new Web3 ( provider_ ) ; else web3 . setProvider ( provider_ ) ; return web3 ; } export async function requestAccounts ( ) { const web3 = await createWeb3 ( ) ; const chainId = await web3 . eth . getChainId ( ) ; const accounts = await web3 . eth . requestAccounts ( ) ; return { chainId , accounts , } ; } export async function ensureConnectedAndUnlocked ( ) { const web3 = await createWeb3 ( ) ; try { const accounts = await web3 . eth . requestAccounts ( ) ; throw accounts ; } catch ( error ) { const accounts = error ; if ( Array . isArray ( accounts ) ) { if ( accounts . length === 0 ) throw new Error ( 'MetaMask is locked or it has not connected any accounts.' ) ; else if ( accounts . length > 0 ) return ; } throw new Error ( 'Failed to connect to MetaMask.' ) ; } } export async function isUnlocked ( ) { try { return provider ?. _metamask ?. isUnlocked ( ) ?? false ; } catch { return false ; } }