import { type GetAccountResult, type SendTransactionArgs, type SendTransactionResult, type SignMessageArgs, type SignMessageResult, type watchAccount } from '@wagmi/core' import type { Listing, ThemeCtrlState } from '@web3modal/core' import { CoreUtil, ExplorerCtrl, RouterCtrl, ThemeCtrl, WcConnectionCtrl } from '@web3modal/core' import { handleDesktopLinking, handleMobileLinking } from './utils' import { CustomWalletLogin } from './CustomWalletLogin' import type { AuthcWalletOptions } from './types' export { getAccount, getConfig, getWalletClient, watchNetwork, watchAccount, watchContractEvent, signMessage, signTypedData, sendTransaction, watchReadContract, watchReadContracts, watchWalletClient, getContract, } from '@wagmi/core' export type { SignMessageArgs, SignMessageResult, SendTransactionArgs, SendTransactionResult, } export * from './types' export class AuthcWalletLogin extends CustomWalletLogin { connectorNames = { metamask: 'metaMask', coinbase: 'coinbaseWallet', } constructor(config: AuthcWalletOptions) { super(config) // DO NOT NEED THIS CoreUtil.setWalletConnectDeepLink = () => {} } private async onMobilePlatform(uri: string, listing: Listing) { return handleMobileLinking(uri, listing) } private async onAndroidPlatform(uri: string, listing: Listing) { return handleMobileLinking(uri, listing) } private async onConnectPlatformDesktop(uri: string, listing: Listing) { return handleDesktopLinking(uri, listing) } private async onConnectConnector(name: string) { const { ready } = await this.client().getConnectorById(name) if (ready) return await this.client().connectConnector(name, this.options.state.selectedChain?.id) return false } async getWalletInfo(walletName: string) { const { listings } = await ExplorerCtrl.getWallets({ page: 1, entries: 1, search: walletName, }) if (listings.length === 0) throw new Error(`Cannot find "${walletName}" wallet`) return listings[0] } async connectWalletByWalletName(walletName: string) { const connectorName = this.connectorNames[walletName.toLocaleLowerCase() as keyof typeof this.connectorNames] if (connectorName) { const res = await this.onConnectConnector(connectorName) if (res) return res } if (walletName.toLowerCase() === 'walletconnect') return this.onWalletConnect() const uri = await this.getWalletConnectUri() if (CoreUtil.isAndroid()) return this.onAndroidPlatform(uri, await this.getWalletInfo(walletName)) else if (CoreUtil.isMobile()) return this.onMobilePlatform(uri, await this.getWalletInfo(walletName)) else return this.onConnectPlatformDesktop(uri, await this.getWalletInfo(walletName)) } // Support connect wallet with message onConnectWalletByPostMessage(postMessage?: Window['postMessage']) { const cancelLogin = (err: Error) => { postMessage({ type: 'authcWallet', data: { type: 'cancelLogin', error: err?.message, }, }, '*') this.cancelLogin() } this.addMessageListener('connectWalletByWalletName', async (data) => { if (this.client().getAccount().isConnected) await this.cancelLogin() const postConnectedMessage = async () => { const address = await this.client().getAccount().address postMessage({ type: 'authcWallet', data: { type: 'walletConnected', data: { walletAddress: address, }, }, }, '*') } let close = () => {} this.connectWalletByWalletName(data.name).then(async () => { // In metamask app, the network maybe change close = this.client().watchNetwork((network) => { // maybe the wallet is not connected if (!network.chain) return console.warn('SignMessage: Cannot get wallet address') postConnectedMessage().finally(() => { close() }) }) postConnectedMessage().finally(() => { close() }) }).catch((err) => { cancelLogin(err) throw err }).finally(() => { close() }) }) this.addMessageListener('signingMessage', async (data) => { if (this.client().getAccount().isConnected) await this.cancelLogin() const signMessageAndPost = async () => { const address = await this.client().getAccount().address const walletClient: any = await this.getWalletClient() const message = await walletClient.signMessage({ message: data.message, }).catch((err: any) => { cancelLogin(err) throw err }) postMessage({ type: 'authcWallet', data: { type: 'walletLogin', data: { walletAddress: address, sid: data.sid, signatureResult: message, }, }, }, '*') } let close = () => {} this.connectWalletByWalletName(data.name).then(async () => { // In metamask app, the network maybe change close = this.client().watchNetwork((network) => { // maybe the wallet is not connected if (!network.chain) return console.warn('SignMessage: Cannot get wallet address') signMessageAndPost().finally(() => { close() }) }) signMessageAndPost().finally(() => { close() }) }).catch((err) => { cancelLogin(err) throw err }).finally(() => { close() }) }) } async onWalletConnect(theme?: ThemeCtrlState) { await this.importUi() const uri = await this.getWalletConnectUri() WcConnectionCtrl.setPairingUri(uri) const qrcode = document.createElement('div') RouterCtrl.push('Qrcode') // 创建新的样式规则并添加至文档中 const style = document.createElement('style') ThemeCtrl.setThemeConfig({ themeMode: 'light', ...theme, themeVariables: { '--w3m-accent-color': 'rgb(16, 19, 20)', ...theme?.themeVariables, }, }) style.innerHTML = `:root { --aw-walletconnect-mask-bg: rgba(16, 19, 20, 0.7); --aw-walletconnect-backdrop-filter: blur(12px); --aw-walletconnect-z-index: 10000; --aw-walletconnect-max-width: 456px; --aw-walletconnect-qrcode-bg: #fff; --aw-walletconnect-qrcode-radius: 14px; --aw-walletconnect-qrcode-padding: 10px; }` qrcode.innerHTML = `
` document.head.appendChild(style) document.body.appendChild(qrcode) return new Promise((resolve, reject) => { RouterCtrl.goBack = () => { qrcode.remove() reject(new Error('User rejected the connection')) } this.watchAccount((account) => { if (account.isConnected) { qrcode.remove() resolve(account) } else if (account.isDisconnected) { RouterCtrl.goBack() } }) }) } async importUi() { return import('@web3modal/ui') } } export type AccountType = Parameters[0]>[0]