From 17430bbb71c21b7c9735d9e2d0923c5be1f6e2a9 Mon Sep 17 00:00:00 2001 From: savardd Date: Thu, 18 Dec 2025 17:31:27 -0500 Subject: [PATCH 1/3] Added signMessage, switchNetwork, WalletNetwork --- src/context/WalletConnectContext.ts | 10 +++--- src/provider/WalletConnectProvider.tsx | 32 ++++++++++++----- src/types.ts | 14 ++++++-- src/wallets/controller.ts | 48 ++++++++++++++++--------- src/wallets/opwallet/controller.ts | 49 +++++++++++++++++++++++--- src/wallets/opwallet/interface.ts | 3 +- src/wallets/types.ts | 9 +++-- src/wallets/unisat/controller.ts | 49 +++++++++++++++++++++++--- src/wallets/unisat/interface.ts | 3 +- 9 files changed, 173 insertions(+), 44 deletions(-) diff --git a/src/context/WalletConnectContext.ts b/src/context/WalletConnectContext.ts index 2f3383d..f53ad5e 100644 --- a/src/context/WalletConnectContext.ts +++ b/src/context/WalletConnectContext.ts @@ -1,7 +1,7 @@ -import { Address, type MLDSASignature, type Unisat, UnisatSigner } from '@btc-vision/transaction'; +import { Address, type MessageType, type MLDSASignature, type Unisat, UnisatSigner } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; import { createContext } from 'react'; -import type { WalletBalance, WalletConnectNetwork, WalletInformation } from '../types.ts'; +import type { WalletBalance, WalletConnectNetwork, WalletInformation, WalletNetwork } from '../types.ts'; import { type SupportedWallets } from '../wallets'; export type WalletConnectContextType = { @@ -13,14 +13,16 @@ export type WalletConnectContextType = { publicKey: string | null; address: Address | null; openConnectModal: () => void; - connectToWallet: (wallet: SupportedWallets) => void; + connectToWallet: (wallet: SupportedWallets) => Promise; connecting: boolean; - disconnect: () => void; + disconnect: () => Promise; provider: AbstractRpcProvider | null; signer: UnisatSigner | null; walletBalance: WalletBalance | null; mldsaPublicKey: string | null; hashedMLDSAKey: string | null; + switchNetwork: (network: WalletNetwork) => Promise; + signMessage: (message: string, messageType?: MessageType) => Promise; signMLDSAMessage: (message: string) => Promise; verifyMLDSASignature: (message: string, signature: MLDSASignature) => Promise; }; diff --git a/src/provider/WalletConnectProvider.tsx b/src/provider/WalletConnectProvider.tsx index a54da08..a8109d7 100644 --- a/src/provider/WalletConnectProvider.tsx +++ b/src/provider/WalletConnectProvider.tsx @@ -1,17 +1,17 @@ -import { Address, type MLDSASignature, type Unisat, UnisatSigner } from '@btc-vision/transaction'; +import { Address, type MessageType, type MLDSASignature, type Unisat, UnisatSigner } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; import React, { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { WalletConnectContext } from '../context/WalletConnectContext'; -import type { WalletBalance, WalletConnectNetwork, WalletInformation } from '../types.ts'; +import type { WalletBalance, WalletConnectNetwork, WalletInformation, WalletNetwork } from '../types.ts'; import '../utils/style.css'; import '../utils/theme.css'; import { type SupportedWallets, WalletController } from '../wallets'; -import type { - ControllerConnectAccounts, - ControllerErrorResponse, - ControllerResponse, - WalletConnectWallet, -} from '../wallets/types.ts'; +import { + type ControllerConnectAccounts, + type ControllerErrorResponse, + type ControllerResponse, + type WalletConnectWallet +} from '../wallets/types'; const AUTO_RECONNECT_RETRIES = 5; @@ -279,6 +279,20 @@ const WalletConnectProvider: React.FC = ({ theme, ch void fetchMLDSAKeys(); }, [publicKey]); + const switchNetwork = useCallback( + async (network: WalletNetwork): Promise => { + return WalletController.switchNetwork(network); + }, + [], + ); + + const signMessage = useCallback( + async (message: string, messageType?: MessageType): Promise => { + return WalletController.signMessage(message, messageType); + }, + [], + ); + const signMLDSAMessage = useCallback( async (message: string): Promise => { return WalletController.signMLDSAMessage(message); @@ -325,6 +339,8 @@ const WalletConnectProvider: React.FC = ({ theme, ch walletType, mldsaPublicKey, hashedMLDSAKey, + switchNetwork, + signMessage, signMLDSAMessage, verifyMLDSASignature, }}> diff --git a/src/types.ts b/src/types.ts index ee99ab0..770f685 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,9 +1,19 @@ import { type Network } from '@btc-vision/bitcoin'; -import { UnisatChainType } from '@btc-vision/transaction'; import type { SupportedWallets } from './wallets'; +export type { MessageType } from '@btc-vision/transaction'; + +export enum WalletNetwork { + BITCOIN_MAINNET = 'BITCOIN_MAINNET', + BITCOIN_TESTNET4 = 'BITCOIN_TESTNET4', + BITCOIN_TESTNET = 'BITCOIN_TESTNET', + BITCOIN_REGTEST = 'BITCOIN_REGTEST', + BITCOIN_SIGNET = 'BITCOIN_SIGNET', + FRACTAL_BITCOIN_TESTNET = 'FRACTAL_BITCOIN_TESTNET', + FRACTAL_BITCOIN_MAINNET = 'FRACTAL_BITCOIN_MAINNET', +} export interface WalletConnectNetwork extends Network { - chainType: UnisatChainType; + chainType: WalletNetwork; network: string; } diff --git a/src/wallets/controller.ts b/src/wallets/controller.ts index 3de0986..dbaa2bf 100644 --- a/src/wallets/controller.ts +++ b/src/wallets/controller.ts @@ -1,20 +1,20 @@ import { type Network, networks } from '@btc-vision/bitcoin'; import { + type MessageType, type MLDSASignature, type Unisat, - UnisatChainType, UnisatSigner, } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; -import { type WalletConnectNetwork } from '../types'; +import { type WalletConnectNetwork, WalletNetwork } from '../types'; import { _e } from '../utils/accessibility/errorDecoder'; import { type SupportedWallets } from './index'; -import type { - ControllerConnectAccounts, - ControllerErrorResponse, - ControllerResponse, - WalletConnectWallet, -} from './types.ts'; +import { + type ControllerConnectAccounts, + type ControllerErrorResponse, + type ControllerResponse, + type WalletConnectWallet, +} from './types'; class WalletController { private static wallets: Map = new Map(); @@ -60,22 +60,22 @@ class WalletController { //TODO: check if we really want to return a default network here // instead of null. Default is there: DefaultWalletConnectChain.network - static convertChainTypeToNetwork(chainType: UnisatChainType): WalletConnectNetwork | null { + static convertChainTypeToNetwork(chainType: WalletNetwork): WalletConnectNetwork | null { const walletNetwork = (network: Network, name: string): WalletConnectNetwork => { return { ...network, chainType: chainType, network: name }; }; switch (chainType) { - case UnisatChainType.BITCOIN_REGTEST: + case WalletNetwork.BITCOIN_REGTEST: return walletNetwork(networks.regtest, 'regtest'); - case UnisatChainType.BITCOIN_TESTNET: + case WalletNetwork.BITCOIN_TESTNET: return walletNetwork(networks.testnet, 'testnet'); - case UnisatChainType.BITCOIN_MAINNET: + case WalletNetwork.BITCOIN_MAINNET: return walletNetwork(networks.bitcoin, 'mainnet'); - case UnisatChainType.BITCOIN_TESTNET4: - case UnisatChainType.BITCOIN_SIGNET: - case UnisatChainType.FRACTAL_BITCOIN_TESTNET: - case UnisatChainType.FRACTAL_BITCOIN_MAINNET: + case WalletNetwork.BITCOIN_TESTNET4: + case WalletNetwork.BITCOIN_SIGNET: + case WalletNetwork.FRACTAL_BITCOIN_TESTNET: + case WalletNetwork.FRACTAL_BITCOIN_MAINNET: default: return null; } @@ -176,7 +176,7 @@ class WalletController { return; } wallet.controller.removeChainChangedHook(); - wallet.controller.setChainChangedHook((chainType: UnisatChainType) => { + wallet.controller.setChainChangedHook((chainType: WalletNetwork) => { const network = this.convertChainTypeToNetwork(chainType); if (network) { fn(network); @@ -233,6 +233,20 @@ class WalletController { this.removeAccountsChangedHook(); } + static async switchNetwork(network: WalletNetwork): Promise { + const wallet = this.currentWallet; + if (!wallet) return; + + return wallet.controller.switchNetwork(network); + } + + static async signMessage(message: string, messageType?: MessageType): Promise { + const wallet = this.currentWallet; + if (!wallet) return null; + + return wallet.controller.signMessage(message, messageType); + } + static async getMLDSAPublicKey(): Promise { const wallet = this.currentWallet; if (!wallet) return null; diff --git a/src/wallets/opwallet/controller.ts b/src/wallets/opwallet/controller.ts index bae5cf8..c170c6b 100644 --- a/src/wallets/opwallet/controller.ts +++ b/src/wallets/opwallet/controller.ts @@ -1,6 +1,7 @@ import { networks } from '@btc-vision/bitcoin'; import { MessageSigner, + MessageType, type MLDSASignature, type Unisat, type UnisatChainInfo, @@ -9,6 +10,7 @@ import { import { AbstractRpcProvider, JSONRpcProvider } from 'opnet'; import { type WalletBase } from '../types'; import { type OPWalletInterface } from './interface'; +import { WalletNetwork } from '../../types'; interface OPWalletWindow extends Window { opnet?: OPWalletInterface; @@ -97,7 +99,7 @@ class OPWallet implements WalletBase { return this.walletBase.getPublicKey(); } - async getNetwork(): Promise { + async getNetwork(): Promise { if (!this.isInstalled() || !this.walletBase) { throw new Error(notInstalledError); } @@ -107,7 +109,7 @@ class OPWallet implements WalletBase { throw new Error('Failed to retrieve chain information'); } - return chainInfo.enum; + return this.unisatChainToWalletNetwork(chainInfo.enum); } setAccountsChangedHook(fn: (accounts: string[]) => void): void { @@ -175,7 +177,7 @@ class OPWallet implements WalletBase { } } - setChainChangedHook(fn: (chainType: UnisatChainType) => void): void { + setChainChangedHook(fn: (chainType: WalletNetwork) => void): void { console.log('Setting chain changed hook for OPWallet'); if (!this.isInstalled() || !this.walletBase) { throw new Error(notInstalledError); @@ -183,7 +185,7 @@ class OPWallet implements WalletBase { this.chainChangedHookWrapper = (chainInfo: UnisatChainInfo) => { console.log('OPWallet ChainChanged Hook', chainInfo); - fn(chainInfo.enum); + fn(this.unisatChainToWalletNetwork(chainInfo.enum)); }; this.walletBase.on('chainChanged', this.chainChangedHookWrapper); @@ -216,6 +218,45 @@ class OPWallet implements WalletBase { return hash.toString('hex'); } + unisatChainToWalletNetwork = (chainType: UnisatChainType): WalletNetwork => { + switch (chainType) { + case UnisatChainType.BITCOIN_MAINNET: return WalletNetwork.BITCOIN_MAINNET; + case UnisatChainType.BITCOIN_TESTNET: return WalletNetwork.BITCOIN_TESTNET; + case UnisatChainType.BITCOIN_REGTEST: return WalletNetwork.BITCOIN_REGTEST; + case UnisatChainType.BITCOIN_TESTNET4: return WalletNetwork.BITCOIN_TESTNET4; + case UnisatChainType.FRACTAL_BITCOIN_MAINNET: return WalletNetwork.FRACTAL_BITCOIN_MAINNET; + case UnisatChainType.FRACTAL_BITCOIN_TESTNET: return WalletNetwork.FRACTAL_BITCOIN_TESTNET; + case UnisatChainType.BITCOIN_SIGNET: return WalletNetwork.BITCOIN_SIGNET; + default: return WalletNetwork.BITCOIN_REGTEST; + } + } + + walletNetworkToUnisatChain = (network: WalletNetwork): UnisatChainType => { + switch (network) { + case 'BITCOIN_MAINNET': return UnisatChainType.BITCOIN_MAINNET; + case 'BITCOIN_TESTNET': return UnisatChainType.BITCOIN_TESTNET; + case 'BITCOIN_REGTEST': return UnisatChainType.BITCOIN_REGTEST; + case 'BITCOIN_TESTNET4': return UnisatChainType.BITCOIN_TESTNET4; + case 'FRACTAL_BITCOIN_MAINNET': return UnisatChainType.FRACTAL_BITCOIN_MAINNET; + case 'FRACTAL_BITCOIN_TESTNET': return UnisatChainType.FRACTAL_BITCOIN_TESTNET; + case 'BITCOIN_SIGNET': return UnisatChainType.BITCOIN_SIGNET; + default: return UnisatChainType.BITCOIN_REGTEST; + } + } + + async switchNetwork(network: WalletNetwork): Promise { + if (!this._isConnected || !this.walletBase) return; + + const unisatChainType = this.walletNetworkToUnisatChain(network) + await this.walletBase.switchChain(unisatChainType); + } + + async signMessage(message: string, messageType?: MessageType): Promise { + if (!this._isConnected || !this.walletBase) return null; + + return this.walletBase.signMessage(message, messageType); + } + async signMLDSAMessage(message: string): Promise { if (!this._isConnected || !this.walletBase?.web3) return null; diff --git a/src/wallets/opwallet/interface.ts b/src/wallets/opwallet/interface.ts index 23fed47..a91ba0c 100644 --- a/src/wallets/opwallet/interface.ts +++ b/src/wallets/opwallet/interface.ts @@ -1,7 +1,8 @@ -import { type Unisat } from '@btc-vision/transaction'; +import { type Unisat, type UnisatChainType } from '@btc-vision/transaction'; export interface OPWalletInterface extends Unisat { disconnect: () => Promise; + switchChain: (chain: UnisatChainType) => Promise<{enum: UnisatChainType, name: string, network: string}>; } export const logo = diff --git a/src/wallets/types.ts b/src/wallets/types.ts index 143ae4b..6e20a9e 100644 --- a/src/wallets/types.ts +++ b/src/wallets/types.ts @@ -1,11 +1,12 @@ import { + type MessageType, type MLDSASignature, type Unisat, - UnisatChainType, UnisatSigner, } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; import { type SupportedWallets } from './index'; +import type { WalletNetwork } from '../types'; export { type AbstractRpcProvider } from 'opnet'; export interface WalletBase { @@ -18,16 +19,18 @@ export interface WalletBase { connect(): Promise; disconnect(): Promise; getPublicKey(): Promise; - getNetwork(): Promise; + getNetwork(): Promise; setAccountsChangedHook(fn: (accounts: string[]) => void): void; removeAccountsChangedHook(): void; setDisconnectHook(fn: () => void): void; removeDisconnectHook(): void; - setChainChangedHook(fn: (network: UnisatChainType) => void): void; + setChainChangedHook(fn: (network: WalletNetwork) => void): void; removeChainChangedHook(): void; getChainId(): void; getMLDSAPublicKey(): Promise; getHashedMLDSAKey(): Promise; + switchNetwork(network: string): Promise; + signMessage(message: string, messageType?: MessageType): Promise; signMLDSAMessage(message: string): Promise; verifyMLDSASignature(message: string, signature: MLDSASignature): Promise; } diff --git a/src/wallets/unisat/controller.ts b/src/wallets/unisat/controller.ts index 06121bc..6a39af1 100644 --- a/src/wallets/unisat/controller.ts +++ b/src/wallets/unisat/controller.ts @@ -1,5 +1,6 @@ import { networks } from '@btc-vision/bitcoin'; import { + type MessageType, type MLDSASignature, type Unisat, type UnisatChainInfo, @@ -9,6 +10,7 @@ import { import { AbstractRpcProvider, JSONRpcProvider } from 'opnet'; import { type WalletBase } from '../types'; import { type UnisatWalletInterface } from './interface'; +import { WalletNetwork } from '../../types'; interface UnisatWalletWindow extends Window { unisat?: UnisatWalletInterface; @@ -99,7 +101,7 @@ class UnisatWallet implements WalletBase { return this.walletBase.getPublicKey(); } - async getNetwork(): Promise { + async getNetwork(): Promise { if (!this.isInstalled() || !this.walletBase) { throw new Error(notInstalledError); } @@ -109,7 +111,7 @@ class UnisatWallet implements WalletBase { throw new Error('Failed to retrieve chain information'); } - return chainInfo.enum; + return this.unisatChainToWalletNetwork(chainInfo.enum); } setAccountsChangedHook(fn: (accounts: string[]) => void): void { @@ -177,7 +179,7 @@ class UnisatWallet implements WalletBase { } } - setChainChangedHook(fn: (chainType: UnisatChainType) => void): void { + setChainChangedHook(fn: (chainType: WalletNetwork) => void): void { console.log('Setting chain changed hook for Unisat'); if (!this.isInstalled() || !this.walletBase) { throw new Error(notInstalledError); @@ -185,7 +187,7 @@ class UnisatWallet implements WalletBase { this.chainChangedHookWrapper = (chainInfo: UnisatChainInfo) => { console.log('Unisat ChainChanged Hook', chainInfo); - fn(chainInfo.enum); + fn(this.unisatChainToWalletNetwork(chainInfo.enum)); }; this.walletBase.on('chainChanged', this.chainChangedHookWrapper); @@ -203,6 +205,45 @@ class UnisatWallet implements WalletBase { } } + unisatChainToWalletNetwork = (chainType: UnisatChainType): WalletNetwork => { + switch (chainType) { + case UnisatChainType.BITCOIN_MAINNET: return WalletNetwork.BITCOIN_MAINNET; + case UnisatChainType.BITCOIN_TESTNET: return WalletNetwork.BITCOIN_TESTNET; + case UnisatChainType.BITCOIN_REGTEST: return WalletNetwork.BITCOIN_REGTEST; + case UnisatChainType.BITCOIN_TESTNET4: return WalletNetwork.BITCOIN_TESTNET4; + case UnisatChainType.FRACTAL_BITCOIN_MAINNET: return WalletNetwork.FRACTAL_BITCOIN_MAINNET; + case UnisatChainType.FRACTAL_BITCOIN_TESTNET: return WalletNetwork.FRACTAL_BITCOIN_TESTNET; + case UnisatChainType.BITCOIN_SIGNET: return WalletNetwork.BITCOIN_SIGNET; + default: return WalletNetwork.BITCOIN_REGTEST; + } + } + + walletNetworkToUnisatChain = (network: WalletNetwork): UnisatChainType => { + switch (network) { + case 'BITCOIN_MAINNET': return UnisatChainType.BITCOIN_MAINNET; + case 'BITCOIN_TESTNET': return UnisatChainType.BITCOIN_TESTNET; + case 'BITCOIN_REGTEST': return UnisatChainType.BITCOIN_REGTEST; + case 'BITCOIN_TESTNET4': return UnisatChainType.BITCOIN_TESTNET4; + case 'FRACTAL_BITCOIN_MAINNET': return UnisatChainType.FRACTAL_BITCOIN_MAINNET; + case 'FRACTAL_BITCOIN_TESTNET': return UnisatChainType.FRACTAL_BITCOIN_TESTNET; + case 'BITCOIN_SIGNET': return UnisatChainType.BITCOIN_SIGNET; + default: return UnisatChainType.BITCOIN_REGTEST; + } + } + + async switchNetwork(network: WalletNetwork): Promise { + if (!this._isConnected || !this.walletBase) return; + + const unisatChainType = this.walletNetworkToUnisatChain(network); + await this.walletBase.switchChain(unisatChainType); + } + + async signMessage(message: string, messageType?: MessageType): Promise { + if (!this._isConnected || !this.walletBase) return null; + + return this.walletBase.signMessage(message, messageType); + } + // Unisat doesn't support MLDSA so these methods return null or false getMLDSAPublicKey(): Promise { return Promise.resolve(null); diff --git a/src/wallets/unisat/interface.ts b/src/wallets/unisat/interface.ts index 2605d26..ea2fbca 100644 --- a/src/wallets/unisat/interface.ts +++ b/src/wallets/unisat/interface.ts @@ -1,7 +1,8 @@ -import { type Unisat } from '@btc-vision/transaction'; +import { type Unisat, type UnisatChainType } from '@btc-vision/transaction'; export interface UnisatWalletInterface extends Unisat { disconnect: () => Promise; + switchChain: (chain: UnisatChainType) => Promise<{enum: UnisatChainType, name: string, network: string}>; } export const logo = From 0c0d62b1feae01e011009b35b8214ada9bd99991 Mon Sep 17 00:00:00 2001 From: savardd Date: Thu, 18 Dec 2025 23:31:05 -0500 Subject: [PATCH 2/3] Removed Unisat, some refactorisation --- src/README.md | 2 +- src/context/WalletConnectContext.ts | 7 +- src/provider/WalletConnectProvider.tsx | 9 +- src/types.ts | 5 + src/wallets/controller.ts | 17 +- src/wallets/index.ts | 14 +- src/wallets/opwallet/controller.ts | 22 +- src/wallets/opwallet/interface.ts | 2 +- src/wallets/types.ts | 10 +- src/wallets/unisat/controller.ts | 262 ---------------------- src/wallets/unisat/interface.ts | 293 ------------------------- 11 files changed, 50 insertions(+), 593 deletions(-) delete mode 100644 src/wallets/unisat/controller.ts delete mode 100644 src/wallets/unisat/interface.ts diff --git a/src/README.md b/src/README.md index 7cf61b4..b69105b 100644 --- a/src/README.md +++ b/src/README.md @@ -14,7 +14,7 @@ Once you have created the controller class, you will need to add its name to the import { WalletController } from './controller.ts'; import myWallet from './mywallet/controller.ts'; -type SupportedWallets = 'OP_WALLET' | 'UNISAT' | 'My Wallet'; +type SupportedWallets = 'OP_WALLET' | 'My Wallet'; WalletController.registerWallet({ name: 'My Wallet', diff --git a/src/context/WalletConnectContext.ts b/src/context/WalletConnectContext.ts index f53ad5e..191c04c 100644 --- a/src/context/WalletConnectContext.ts +++ b/src/context/WalletConnectContext.ts @@ -1,14 +1,15 @@ -import { Address, type MessageType, type MLDSASignature, type Unisat, UnisatSigner } from '@btc-vision/transaction'; +import { Address, type MessageType, type MLDSASignature } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; import { createContext } from 'react'; import type { WalletBalance, WalletConnectNetwork, WalletInformation, WalletNetwork } from '../types.ts'; import { type SupportedWallets } from '../wallets'; +import type { OPWallet } from '../wallets/opwallet/interface'; export type WalletConnectContextType = { allWallets: WalletInformation[]; walletType: string | null; walletAddress: string | null; - walletInstance: Unisat | null; + walletInstance: OPWallet | null; network: WalletConnectNetwork | null; publicKey: string | null; address: Address | null; @@ -17,7 +18,7 @@ export type WalletConnectContextType = { connecting: boolean; disconnect: () => Promise; provider: AbstractRpcProvider | null; - signer: UnisatSigner | null; + signer: null; walletBalance: WalletBalance | null; mldsaPublicKey: string | null; hashedMLDSAKey: string | null; diff --git a/src/provider/WalletConnectProvider.tsx b/src/provider/WalletConnectProvider.tsx index a8109d7..9765cb5 100644 --- a/src/provider/WalletConnectProvider.tsx +++ b/src/provider/WalletConnectProvider.tsx @@ -1,4 +1,4 @@ -import { Address, type MessageType, type MLDSASignature, type Unisat, UnisatSigner } from '@btc-vision/transaction'; +import { Address, type MessageType, type MLDSASignature } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; import React, { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { WalletConnectContext } from '../context/WalletConnectContext'; @@ -12,6 +12,7 @@ import { type ControllerResponse, type WalletConnectWallet } from '../wallets/types'; +import type { OPWallet } from '../wallets/opwallet/interface'; const AUTO_RECONNECT_RETRIES = 5; @@ -35,9 +36,9 @@ const WalletConnectProvider: React.FC = ({ theme, ch const [walletAddress, setWalletAddress] = useState(null); const [publicKey, setPublicKey] = useState(null); const [walletType, setWalletType] = useState(null); - const [walletInstance, setWalletInstance] = useState(null); + const [walletInstance, setWalletInstance] = useState(null); const [provider, setProvider] = useState(null); - const [signer, setSigner] = useState(null); + const [signer, setSigner] = useState(null); const [walletBalance, setWalletBalance] = useState(null); const [mldsaPublicKey, setMldsaPublicKey] = useState(null); @@ -250,7 +251,7 @@ const WalletConnectProvider: React.FC = ({ theme, ch const fetchBalance = async () => { if (walletAddress && walletInstance) { try { - const balance = (await walletInstance.getBalance()) as WalletBalance | null; + const balance = await WalletController.getBalance(); setWalletBalance(balance); } catch (error) { console.error('Error fetching balance:', error); diff --git a/src/types.ts b/src/types.ts index 770f685..e251501 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,12 @@ import { type Network } from '@btc-vision/bitcoin'; import type { SupportedWallets } from './wallets'; +import type { OPWallet } from './wallets/opwallet/interface'; export type { MessageType } from '@btc-vision/transaction'; +export function isOPWallet(walletInstance: OPWallet|null): walletInstance is OPWallet { + return typeof walletInstance == 'object' && (walletInstance as OPWallet)?.web3 !== undefined; +} + export enum WalletNetwork { BITCOIN_MAINNET = 'BITCOIN_MAINNET', BITCOIN_TESTNET4 = 'BITCOIN_TESTNET4', diff --git a/src/wallets/controller.ts b/src/wallets/controller.ts index dbaa2bf..164a92b 100644 --- a/src/wallets/controller.ts +++ b/src/wallets/controller.ts @@ -2,11 +2,9 @@ import { type Network, networks } from '@btc-vision/bitcoin'; import { type MessageType, type MLDSASignature, - type Unisat, - UnisatSigner, } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; -import { type WalletConnectNetwork, WalletNetwork } from '../types'; +import { type WalletBalance, type WalletConnectNetwork, WalletNetwork } from '../types'; import { _e } from '../utils/accessibility/errorDecoder'; import { type SupportedWallets } from './index'; import { @@ -15,6 +13,7 @@ import { type ControllerResponse, type WalletConnectWallet, } from './types'; +import type { OPWallet } from './opwallet/interface'; class WalletController { private static wallets: Map = new Map(); @@ -30,7 +29,7 @@ class WalletController { return WalletController.currentWallet?.name || null; } - static getWalletInstance(): Unisat | null { + static getWalletInstance(): OPWallet | null { const wallet = this.currentWallet; if (!wallet) { return null; @@ -50,7 +49,7 @@ class WalletController { return provider ? new Proxy(provider, {}) : null; } - static async getSigner(): Promise { + static async getSigner(): Promise { const wallet = this.currentWallet; if (!wallet) { return null; @@ -99,6 +98,14 @@ class WalletController { return wallet.controller.getPublicKey(); } + static async getBalance(): Promise { + const wallet = this.currentWallet; + if (!wallet) { + return null; + } + return wallet.controller.getBalance(); + } + static async canAutoConnect(walletName: string) { const wallet = this.wallets.get(walletName); return (wallet && (await wallet.controller.canAutoConnect())) || false; diff --git a/src/wallets/index.ts b/src/wallets/index.ts index b9bdd47..93263b6 100644 --- a/src/wallets/index.ts +++ b/src/wallets/index.ts @@ -1,21 +1,13 @@ import { WalletController } from './controller'; -import OPWallet from './opwallet/controller'; import { logo as OPWalletLogo } from './opwallet/interface'; -import UniSatWallet from './unisat/controller'; -import { logo as UnisatLogo } from './unisat/interface'; +import OPWalletInstance from './opwallet/controller'; -type SupportedWallets = 'OP_WALLET' | 'UNISAT'; +type SupportedWallets = 'OP_WALLET'; WalletController.registerWallet({ name: 'OP_WALLET', icon: OPWalletLogo, - controller: new OPWallet(), -}); - -WalletController.registerWallet({ - name: 'UNISAT', - icon: UnisatLogo, - controller: new UniSatWallet(), + controller: new OPWalletInstance(), }); export { WalletController }; diff --git a/src/wallets/opwallet/controller.ts b/src/wallets/opwallet/controller.ts index c170c6b..05e893b 100644 --- a/src/wallets/opwallet/controller.ts +++ b/src/wallets/opwallet/controller.ts @@ -3,22 +3,21 @@ import { MessageSigner, MessageType, type MLDSASignature, - type Unisat, type UnisatChainInfo, UnisatChainType, } from '@btc-vision/transaction'; import { AbstractRpcProvider, JSONRpcProvider } from 'opnet'; import { type WalletBase } from '../types'; -import { type OPWalletInterface } from './interface'; -import { WalletNetwork } from '../../types'; +import { type OPWallet } from './interface'; +import { type WalletBalance, WalletNetwork } from '../../types'; interface OPWalletWindow extends Window { - opnet?: OPWalletInterface; + opnet?: OPWallet; } const notInstalledError = 'OP_WALLET is not installed'; -class OPWallet implements WalletBase { +class OPWalletInstance implements WalletBase { private walletBase: OPWalletWindow['opnet']; private accountsChangedHookWrapper?: (accounts: Array) => void; private chainChangedHookWrapper?: (network: UnisatChainInfo) => void; @@ -67,7 +66,7 @@ class OPWallet implements WalletBase { : undefined; } - getWalletInstance(): Unisat | null { + getWalletInstance(): OPWallet | null { return (this._isConnected && this.walletBase) || null; } @@ -92,13 +91,20 @@ class OPWallet implements WalletBase { return Promise.resolve(null); } - getPublicKey(): Promise { + async getPublicKey(): Promise { if (!this.isInstalled() || !this.walletBase) { throw new Error(notInstalledError); } return this.walletBase.getPublicKey(); } + async getBalance(): Promise { + if (!this.isInstalled() || !this.walletBase) { + throw new Error(notInstalledError); + } + return (await this.walletBase.getBalance()) as WalletBalance | null; + } + async getNetwork(): Promise { if (!this.isInstalled() || !this.walletBase) { throw new Error(notInstalledError); @@ -270,4 +276,4 @@ class OPWallet implements WalletBase { } } -export default OPWallet; +export default OPWalletInstance; diff --git a/src/wallets/opwallet/interface.ts b/src/wallets/opwallet/interface.ts index a91ba0c..110bbd6 100644 --- a/src/wallets/opwallet/interface.ts +++ b/src/wallets/opwallet/interface.ts @@ -1,6 +1,6 @@ import { type Unisat, type UnisatChainType } from '@btc-vision/transaction'; -export interface OPWalletInterface extends Unisat { +export interface OPWallet extends Unisat { disconnect: () => Promise; switchChain: (chain: UnisatChainType) => Promise<{enum: UnisatChainType, name: string, network: string}>; } diff --git a/src/wallets/types.ts b/src/wallets/types.ts index 6e20a9e..78a8071 100644 --- a/src/wallets/types.ts +++ b/src/wallets/types.ts @@ -1,24 +1,24 @@ import { type MessageType, type MLDSASignature, - type Unisat, - UnisatSigner, } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; import { type SupportedWallets } from './index'; -import type { WalletNetwork } from '../types'; +import type { WalletBalance, WalletNetwork } from '../types'; +import type { OPWallet } from './opwallet/interface'; export { type AbstractRpcProvider } from 'opnet'; export interface WalletBase { isInstalled(): boolean; isConnected(): boolean; canAutoConnect(): Promise; - getWalletInstance(): Unisat | null; + getWalletInstance(): OPWallet | null; getProvider(): Promise; - getSigner(): Promise; + getSigner(): Promise; connect(): Promise; disconnect(): Promise; getPublicKey(): Promise; + getBalance(): Promise; getNetwork(): Promise; setAccountsChangedHook(fn: (accounts: string[]) => void): void; removeAccountsChangedHook(): void; diff --git a/src/wallets/unisat/controller.ts b/src/wallets/unisat/controller.ts deleted file mode 100644 index 6a39af1..0000000 --- a/src/wallets/unisat/controller.ts +++ /dev/null @@ -1,262 +0,0 @@ -import { networks } from '@btc-vision/bitcoin'; -import { - type MessageType, - type MLDSASignature, - type Unisat, - type UnisatChainInfo, - UnisatChainType, - UnisatSigner, -} from '@btc-vision/transaction'; -import { AbstractRpcProvider, JSONRpcProvider } from 'opnet'; -import { type WalletBase } from '../types'; -import { type UnisatWalletInterface } from './interface'; -import { WalletNetwork } from '../../types'; - -interface UnisatWalletWindow extends Window { - unisat?: UnisatWalletInterface; -} - -const notInstalledError = 'UNISAT is not installed'; - -class UnisatWallet implements WalletBase { - private walletBase: UnisatWalletWindow['unisat']; - private accountsChangedHookWrapper?: (accounts: Array) => void; - private chainChangedHookWrapper?: (network: UnisatChainInfo) => void; - private disconnectHookWrapper?: () => void; - private _isConnected: boolean = false; - - isInstalled() { - if (typeof window === 'undefined') { - return false; - } - this.walletBase = (window as unknown as UnisatWalletWindow).unisat; - return !!this.walletBase; - } - isConnected() { - return !!this.walletBase && this._isConnected; - } - async canAutoConnect(): Promise { - // getAccounts returns empty array if not connected, - // without launching connection modal window. - const accounts = (await this.walletBase?.getAccounts()) || []; - return accounts.length > 0; - } - - getWalletInstance(): Unisat | null { - return (this._isConnected && this.walletBase) || null; - } - - public async getProvider(): Promise { - if (!this._isConnected || !this.walletBase) return null; - - const chain = await this.walletBase.getChain(); - switch (chain.enum) { - case UnisatChainType.BITCOIN_MAINNET: - return new JSONRpcProvider('https://mainnet.opnet.org', networks.bitcoin); - case UnisatChainType.BITCOIN_TESTNET: - return new JSONRpcProvider('https://testnet.opnet.org', networks.testnet); - case UnisatChainType.BITCOIN_REGTEST: - return new JSONRpcProvider('https://regtest.opnet.org', networks.regtest); - // TODO: Add Fractal Mainnet & Testnet when available - default: - return null; - } - } - - async getSigner(): Promise { - const signer = new UnisatSigner(); - await signer.init(); - return signer; - } - - getChainId(): void { - throw new Error('Method not implemented.'); - } - - async connect(): Promise { - if (!this.isInstalled() || !this.walletBase) { - throw new Error(notInstalledError); - } - return this.walletBase.requestAccounts().then((accounts: string[]) => { - this._isConnected = accounts.length > 0; - return accounts; - }); - } - - async disconnect() { - if (!this.isInstalled() || !this.walletBase) { - throw new Error(notInstalledError); - } - return this._isConnected - ? await this.walletBase.disconnect().then(() => { - this._isConnected = false; - }) - : undefined; - } - - getPublicKey(): Promise { - if (!this.isInstalled() || !this.walletBase) { - throw new Error(notInstalledError); - } - return this.walletBase.getPublicKey(); - } - - async getNetwork(): Promise { - if (!this.isInstalled() || !this.walletBase) { - throw new Error(notInstalledError); - } - - const chainInfo = await this.walletBase.getChain(); - if (!chainInfo) { - throw new Error('Failed to retrieve chain information'); - } - - return this.unisatChainToWalletNetwork(chainInfo.enum); - } - - setAccountsChangedHook(fn: (accounts: string[]) => void): void { - console.log('Setting account changed hook for Unisat'); - - if (!this.isInstalled() || !this.walletBase) { - throw new Error(notInstalledError); - } - - this.accountsChangedHookWrapper = (accounts: string[]) => { - console.log('Unisat Account Changed Hook', accounts, accounts.length); - - if (accounts.length > 0) { - fn(accounts); - } else { - console.log( - 'Unisat Account Changed Hook --> Disconnect', - accounts.length, - !!this.disconnectHookWrapper, - ); - this._isConnected = false; - this.disconnectHookWrapper?.(); - } - }; - - this.walletBase.on('accountsChanged', this.accountsChangedHookWrapper); - } - - removeAccountsChangedHook(): void { - if (!this.isInstalled() || !this.walletBase) { - throw new Error(notInstalledError); - } - - if (this.accountsChangedHookWrapper) { - console.log('Removing account changed hook for Unisat'); - this.walletBase.removeListener('accountsChanged', this.accountsChangedHookWrapper); - this.accountsChangedHookWrapper = undefined; - } - } - - setDisconnectHook(fn: () => void): void { - console.log('Setting disconnect hook for Unisat'); - - if (!this.isInstalled() || !this.walletBase) { - throw new Error(notInstalledError); - } - - this.disconnectHookWrapper = () => { - console.log('Unisat Disconnecting Hook'); - fn(); - }; - - this.walletBase.on('disconnect', this.disconnectHookWrapper); - } - - removeDisconnectHook(): void { - if (!this.isInstalled() || !this.walletBase) { - throw new Error(notInstalledError); - } - - if (this.disconnectHookWrapper) { - console.log('Removing disconnect hook for Unisat'); - this.walletBase.removeListener('disconnect', this.disconnectHookWrapper); - this.disconnectHookWrapper = undefined; - } - } - - setChainChangedHook(fn: (chainType: WalletNetwork) => void): void { - console.log('Setting chain changed hook for Unisat'); - if (!this.isInstalled() || !this.walletBase) { - throw new Error(notInstalledError); - } - - this.chainChangedHookWrapper = (chainInfo: UnisatChainInfo) => { - console.log('Unisat ChainChanged Hook', chainInfo); - fn(this.unisatChainToWalletNetwork(chainInfo.enum)); - }; - - this.walletBase.on('chainChanged', this.chainChangedHookWrapper); - } - - removeChainChangedHook(): void { - if (!this.isInstalled() || !this.walletBase) { - throw new Error(notInstalledError); - } - - if (this.chainChangedHookWrapper) { - console.log('Removing chain changed hook for Unisat'); - this.walletBase.removeListener('chainChanged', this.chainChangedHookWrapper); - this.chainChangedHookWrapper = undefined; - } - } - - unisatChainToWalletNetwork = (chainType: UnisatChainType): WalletNetwork => { - switch (chainType) { - case UnisatChainType.BITCOIN_MAINNET: return WalletNetwork.BITCOIN_MAINNET; - case UnisatChainType.BITCOIN_TESTNET: return WalletNetwork.BITCOIN_TESTNET; - case UnisatChainType.BITCOIN_REGTEST: return WalletNetwork.BITCOIN_REGTEST; - case UnisatChainType.BITCOIN_TESTNET4: return WalletNetwork.BITCOIN_TESTNET4; - case UnisatChainType.FRACTAL_BITCOIN_MAINNET: return WalletNetwork.FRACTAL_BITCOIN_MAINNET; - case UnisatChainType.FRACTAL_BITCOIN_TESTNET: return WalletNetwork.FRACTAL_BITCOIN_TESTNET; - case UnisatChainType.BITCOIN_SIGNET: return WalletNetwork.BITCOIN_SIGNET; - default: return WalletNetwork.BITCOIN_REGTEST; - } - } - - walletNetworkToUnisatChain = (network: WalletNetwork): UnisatChainType => { - switch (network) { - case 'BITCOIN_MAINNET': return UnisatChainType.BITCOIN_MAINNET; - case 'BITCOIN_TESTNET': return UnisatChainType.BITCOIN_TESTNET; - case 'BITCOIN_REGTEST': return UnisatChainType.BITCOIN_REGTEST; - case 'BITCOIN_TESTNET4': return UnisatChainType.BITCOIN_TESTNET4; - case 'FRACTAL_BITCOIN_MAINNET': return UnisatChainType.FRACTAL_BITCOIN_MAINNET; - case 'FRACTAL_BITCOIN_TESTNET': return UnisatChainType.FRACTAL_BITCOIN_TESTNET; - case 'BITCOIN_SIGNET': return UnisatChainType.BITCOIN_SIGNET; - default: return UnisatChainType.BITCOIN_REGTEST; - } - } - - async switchNetwork(network: WalletNetwork): Promise { - if (!this._isConnected || !this.walletBase) return; - - const unisatChainType = this.walletNetworkToUnisatChain(network); - await this.walletBase.switchChain(unisatChainType); - } - - async signMessage(message: string, messageType?: MessageType): Promise { - if (!this._isConnected || !this.walletBase) return null; - - return this.walletBase.signMessage(message, messageType); - } - - // Unisat doesn't support MLDSA so these methods return null or false - getMLDSAPublicKey(): Promise { - return Promise.resolve(null); - } - getHashedMLDSAKey(): Promise { - return Promise.resolve(null); - } - signMLDSAMessage(_message: string): Promise { - return Promise.resolve(null); - } - verifyMLDSASignature(_message: string, _signature: MLDSASignature): Promise { - return Promise.resolve(false); - } -} - -export default UnisatWallet; diff --git a/src/wallets/unisat/interface.ts b/src/wallets/unisat/interface.ts deleted file mode 100644 index ea2fbca..0000000 --- a/src/wallets/unisat/interface.ts +++ /dev/null @@ -1,293 +0,0 @@ -import { type Unisat, type UnisatChainType } from '@btc-vision/transaction'; - -export interface UnisatWalletInterface extends Unisat { - disconnect: () => Promise; - switchChain: (chain: UnisatChainType) => Promise<{enum: UnisatChainType, name: string, network: string}>; -} - -export const logo = - 'data:image/png;base64,' + - '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'; From 27cf14fa9a4e5b7a9b2fdca48b7eb1db38f697d1 Mon Sep 17 00:00:00 2001 From: savardd Date: Fri, 19 Dec 2025 00:05:33 -0500 Subject: [PATCH 3/3] Added WalletChainType / WalletNetwork to switchNetwork --- src/context/WalletConnectContext.ts | 10 ++++-- src/provider/WalletConnectProvider.tsx | 10 ++++-- src/types.ts | 10 ++++-- src/wallets/controller.ts | 32 +++++++++--------- src/wallets/opwallet/controller.ts | 45 ++++++++++++++------------ src/wallets/types.ts | 8 ++--- 6 files changed, 68 insertions(+), 47 deletions(-) diff --git a/src/context/WalletConnectContext.ts b/src/context/WalletConnectContext.ts index 191c04c..aa5f908 100644 --- a/src/context/WalletConnectContext.ts +++ b/src/context/WalletConnectContext.ts @@ -1,7 +1,13 @@ import { Address, type MessageType, type MLDSASignature } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; import { createContext } from 'react'; -import type { WalletBalance, WalletConnectNetwork, WalletInformation, WalletNetwork } from '../types.ts'; +import { + type WalletBalance, + type WalletConnectNetwork, + type WalletInformation, + type WalletChainType, + WalletNetwork, +} from '../types'; import { type SupportedWallets } from '../wallets'; import type { OPWallet } from '../wallets/opwallet/interface'; @@ -22,7 +28,7 @@ export type WalletConnectContextType = { walletBalance: WalletBalance | null; mldsaPublicKey: string | null; hashedMLDSAKey: string | null; - switchNetwork: (network: WalletNetwork) => Promise; + switchNetwork: (network: WalletNetwork|WalletChainType) => Promise; signMessage: (message: string, messageType?: MessageType) => Promise; signMLDSAMessage: (message: string) => Promise; verifyMLDSASignature: (message: string, signature: MLDSASignature) => Promise; diff --git a/src/provider/WalletConnectProvider.tsx b/src/provider/WalletConnectProvider.tsx index 9765cb5..a93026d 100644 --- a/src/provider/WalletConnectProvider.tsx +++ b/src/provider/WalletConnectProvider.tsx @@ -2,7 +2,13 @@ import { Address, type MessageType, type MLDSASignature } from '@btc-vision/tran import { AbstractRpcProvider } from 'opnet'; import React, { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { WalletConnectContext } from '../context/WalletConnectContext'; -import type { WalletBalance, WalletConnectNetwork, WalletInformation, WalletNetwork } from '../types.ts'; +import { + type WalletBalance, + type WalletConnectNetwork, + type WalletInformation, + type WalletChainType, + WalletNetwork, +} from '../types'; import '../utils/style.css'; import '../utils/theme.css'; import { type SupportedWallets, WalletController } from '../wallets'; @@ -281,7 +287,7 @@ const WalletConnectProvider: React.FC = ({ theme, ch }, [publicKey]); const switchNetwork = useCallback( - async (network: WalletNetwork): Promise => { + async (network: WalletNetwork|WalletChainType): Promise => { return WalletController.switchNetwork(network); }, [], diff --git a/src/types.ts b/src/types.ts index e251501..13675ef 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,6 +8,12 @@ export function isOPWallet(walletInstance: OPWallet|null): walletInstance is OPW } export enum WalletNetwork { + regtest = 'regtest', + testnet = 'testnet', + mainnet = 'mainnet', +} + +export enum WalletChainType { BITCOIN_MAINNET = 'BITCOIN_MAINNET', BITCOIN_TESTNET4 = 'BITCOIN_TESTNET4', BITCOIN_TESTNET = 'BITCOIN_TESTNET', @@ -18,8 +24,8 @@ export enum WalletNetwork { } export interface WalletConnectNetwork extends Network { - chainType: WalletNetwork; - network: string; + chainType: WalletChainType; + network: WalletNetwork; } export interface WalletInformation { diff --git a/src/wallets/controller.ts b/src/wallets/controller.ts index 164a92b..562d2f6 100644 --- a/src/wallets/controller.ts +++ b/src/wallets/controller.ts @@ -4,7 +4,7 @@ import { type MLDSASignature, } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; -import { type WalletBalance, type WalletConnectNetwork, WalletNetwork } from '../types'; +import { type WalletBalance, type WalletConnectNetwork, WalletChainType, WalletNetwork } from '../types'; import { _e } from '../utils/accessibility/errorDecoder'; import { type SupportedWallets } from './index'; import { @@ -59,22 +59,22 @@ class WalletController { //TODO: check if we really want to return a default network here // instead of null. Default is there: DefaultWalletConnectChain.network - static convertChainTypeToNetwork(chainType: WalletNetwork): WalletConnectNetwork | null { - const walletNetwork = (network: Network, name: string): WalletConnectNetwork => { + static convertChainTypeToNetwork(chainType: WalletChainType): WalletConnectNetwork | null { + const walletNetwork = (network: Network, name: WalletNetwork): WalletConnectNetwork => { return { ...network, chainType: chainType, network: name }; }; switch (chainType) { - case WalletNetwork.BITCOIN_REGTEST: - return walletNetwork(networks.regtest, 'regtest'); - case WalletNetwork.BITCOIN_TESTNET: - return walletNetwork(networks.testnet, 'testnet'); - case WalletNetwork.BITCOIN_MAINNET: - return walletNetwork(networks.bitcoin, 'mainnet'); - - case WalletNetwork.BITCOIN_TESTNET4: - case WalletNetwork.BITCOIN_SIGNET: - case WalletNetwork.FRACTAL_BITCOIN_TESTNET: - case WalletNetwork.FRACTAL_BITCOIN_MAINNET: + case WalletChainType.BITCOIN_REGTEST: + return walletNetwork(networks.regtest, WalletNetwork.regtest); + case WalletChainType.BITCOIN_TESTNET: + return walletNetwork(networks.testnet, WalletNetwork.testnet); + case WalletChainType.BITCOIN_MAINNET: + return walletNetwork(networks.bitcoin, WalletNetwork.mainnet); + + case WalletChainType.BITCOIN_TESTNET4: + case WalletChainType.BITCOIN_SIGNET: + case WalletChainType.FRACTAL_BITCOIN_TESTNET: + case WalletChainType.FRACTAL_BITCOIN_MAINNET: default: return null; } @@ -183,7 +183,7 @@ class WalletController { return; } wallet.controller.removeChainChangedHook(); - wallet.controller.setChainChangedHook((chainType: WalletNetwork) => { + wallet.controller.setChainChangedHook((chainType: WalletChainType) => { const network = this.convertChainTypeToNetwork(chainType); if (network) { fn(network); @@ -240,7 +240,7 @@ class WalletController { this.removeAccountsChangedHook(); } - static async switchNetwork(network: WalletNetwork): Promise { + static async switchNetwork(network: WalletNetwork|WalletChainType): Promise { const wallet = this.currentWallet; if (!wallet) return; diff --git a/src/wallets/opwallet/controller.ts b/src/wallets/opwallet/controller.ts index 05e893b..b6402c7 100644 --- a/src/wallets/opwallet/controller.ts +++ b/src/wallets/opwallet/controller.ts @@ -9,7 +9,7 @@ import { import { AbstractRpcProvider, JSONRpcProvider } from 'opnet'; import { type WalletBase } from '../types'; import { type OPWallet } from './interface'; -import { type WalletBalance, WalletNetwork } from '../../types'; +import { type WalletBalance, WalletChainType, WalletNetwork } from '../../types'; interface OPWalletWindow extends Window { opnet?: OPWallet; @@ -105,7 +105,7 @@ class OPWalletInstance implements WalletBase { return (await this.walletBase.getBalance()) as WalletBalance | null; } - async getNetwork(): Promise { + async getNetwork(): Promise { if (!this.isInstalled() || !this.walletBase) { throw new Error(notInstalledError); } @@ -183,7 +183,7 @@ class OPWalletInstance implements WalletBase { } } - setChainChangedHook(fn: (chainType: WalletNetwork) => void): void { + setChainChangedHook(fn: (chainType: WalletChainType) => void): void { console.log('Setting chain changed hook for OPWallet'); if (!this.isInstalled() || !this.walletBase) { throw new Error(notInstalledError); @@ -224,33 +224,36 @@ class OPWalletInstance implements WalletBase { return hash.toString('hex'); } - unisatChainToWalletNetwork = (chainType: UnisatChainType): WalletNetwork => { + unisatChainToWalletNetwork = (chainType: UnisatChainType): WalletChainType => { switch (chainType) { - case UnisatChainType.BITCOIN_MAINNET: return WalletNetwork.BITCOIN_MAINNET; - case UnisatChainType.BITCOIN_TESTNET: return WalletNetwork.BITCOIN_TESTNET; - case UnisatChainType.BITCOIN_REGTEST: return WalletNetwork.BITCOIN_REGTEST; - case UnisatChainType.BITCOIN_TESTNET4: return WalletNetwork.BITCOIN_TESTNET4; - case UnisatChainType.FRACTAL_BITCOIN_MAINNET: return WalletNetwork.FRACTAL_BITCOIN_MAINNET; - case UnisatChainType.FRACTAL_BITCOIN_TESTNET: return WalletNetwork.FRACTAL_BITCOIN_TESTNET; - case UnisatChainType.BITCOIN_SIGNET: return WalletNetwork.BITCOIN_SIGNET; - default: return WalletNetwork.BITCOIN_REGTEST; + case UnisatChainType.BITCOIN_MAINNET: return WalletChainType.BITCOIN_MAINNET; + case UnisatChainType.BITCOIN_TESTNET: return WalletChainType.BITCOIN_TESTNET; + case UnisatChainType.BITCOIN_REGTEST: return WalletChainType.BITCOIN_REGTEST; + case UnisatChainType.BITCOIN_TESTNET4: return WalletChainType.BITCOIN_TESTNET4; + case UnisatChainType.FRACTAL_BITCOIN_MAINNET: return WalletChainType.FRACTAL_BITCOIN_MAINNET; + case UnisatChainType.FRACTAL_BITCOIN_TESTNET: return WalletChainType.FRACTAL_BITCOIN_TESTNET; + case UnisatChainType.BITCOIN_SIGNET: return WalletChainType.BITCOIN_SIGNET; + default: return WalletChainType.BITCOIN_REGTEST; } } - walletNetworkToUnisatChain = (network: WalletNetwork): UnisatChainType => { + walletNetworkToUnisatChain = (network: WalletNetwork|WalletChainType): UnisatChainType => { switch (network) { - case 'BITCOIN_MAINNET': return UnisatChainType.BITCOIN_MAINNET; - case 'BITCOIN_TESTNET': return UnisatChainType.BITCOIN_TESTNET; - case 'BITCOIN_REGTEST': return UnisatChainType.BITCOIN_REGTEST; - case 'BITCOIN_TESTNET4': return UnisatChainType.BITCOIN_TESTNET4; - case 'FRACTAL_BITCOIN_MAINNET': return UnisatChainType.FRACTAL_BITCOIN_MAINNET; - case 'FRACTAL_BITCOIN_TESTNET': return UnisatChainType.FRACTAL_BITCOIN_TESTNET; - case 'BITCOIN_SIGNET': return UnisatChainType.BITCOIN_SIGNET; + case WalletNetwork.mainnet: + case WalletChainType.BITCOIN_MAINNET: return UnisatChainType.BITCOIN_MAINNET; + case WalletNetwork.testnet: + case WalletChainType.BITCOIN_TESTNET: return UnisatChainType.BITCOIN_TESTNET; + case WalletNetwork.regtest: + case WalletChainType.BITCOIN_REGTEST: return UnisatChainType.BITCOIN_REGTEST; + case WalletChainType.BITCOIN_TESTNET4: return UnisatChainType.BITCOIN_TESTNET4; + case WalletChainType.FRACTAL_BITCOIN_MAINNET: return UnisatChainType.FRACTAL_BITCOIN_MAINNET; + case WalletChainType.FRACTAL_BITCOIN_TESTNET: return UnisatChainType.FRACTAL_BITCOIN_TESTNET; + case WalletChainType.BITCOIN_SIGNET: return UnisatChainType.BITCOIN_SIGNET; default: return UnisatChainType.BITCOIN_REGTEST; } } - async switchNetwork(network: WalletNetwork): Promise { + async switchNetwork(network: WalletNetwork|WalletChainType): Promise { if (!this._isConnected || !this.walletBase) return; const unisatChainType = this.walletNetworkToUnisatChain(network) diff --git a/src/wallets/types.ts b/src/wallets/types.ts index 78a8071..5c0bf92 100644 --- a/src/wallets/types.ts +++ b/src/wallets/types.ts @@ -4,7 +4,7 @@ import { } from '@btc-vision/transaction'; import { AbstractRpcProvider } from 'opnet'; import { type SupportedWallets } from './index'; -import type { WalletBalance, WalletNetwork } from '../types'; +import { type WalletBalance, type WalletChainType, WalletNetwork } from '../types'; import type { OPWallet } from './opwallet/interface'; export { type AbstractRpcProvider } from 'opnet'; @@ -19,17 +19,17 @@ export interface WalletBase { disconnect(): Promise; getPublicKey(): Promise; getBalance(): Promise; - getNetwork(): Promise; + getNetwork(): Promise; setAccountsChangedHook(fn: (accounts: string[]) => void): void; removeAccountsChangedHook(): void; setDisconnectHook(fn: () => void): void; removeDisconnectHook(): void; - setChainChangedHook(fn: (network: WalletNetwork) => void): void; + setChainChangedHook(fn: (network: WalletChainType) => void): void; removeChainChangedHook(): void; getChainId(): void; getMLDSAPublicKey(): Promise; getHashedMLDSAKey(): Promise; - switchNetwork(network: string): Promise; + switchNetwork(network: WalletNetwork|WalletChainType): Promise; signMessage(message: string, messageType?: MessageType): Promise; signMLDSAMessage(message: string): Promise; verifyMLDSASignature(message: string, signature: MLDSASignature): Promise;