Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module's `init` method. You will need to pass the controller class as an argumen
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',
Expand Down
15 changes: 9 additions & 6 deletions src/context/WalletConnectContext.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import { Address, 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 } from '../types.ts';
import type { OPWallet } from '../wallets/opwallet/interface';
import type { WalletBalance, WalletConnectNetwork, WalletInformation, WalletChainType, WalletNetwork } from '../types.ts';
import { SupportedWallets } from '../wallets';

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;
openConnectModal: () => void;
connectToWallet: (wallet: SupportedWallets) => void;
connectToWallet: (wallet: SupportedWallets) => Promise<void>;
connecting: boolean;
disconnect: () => void;
disconnect: () => Promise<void>;
provider: AbstractRpcProvider | null;
signer: UnisatSigner | null;
signer: null;
walletBalance: WalletBalance | null;
mldsaPublicKey: string | null;
hashedMLDSAKey: string | null;
switchNetwork: (network: WalletNetwork|WalletChainType) => Promise<void>;
signMessage: (message: string, messageType?: MessageType) => Promise<string | null>;
signMLDSAMessage: (message: string) => Promise<MLDSASignature | null>;
verifyMLDSASignature: (message: string, signature: MLDSASignature) => Promise<boolean>;
};
Expand Down
33 changes: 28 additions & 5 deletions src/provider/WalletConnectProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { Address, 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';
import type { WalletBalance, WalletConnectNetwork, WalletInformation } 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 { OPWallet } from '../wallets/opwallet/interface';
import { SupportedWallets, WalletController } from '../wallets';
import type {
ControllerConnectAccounts,
Expand Down Expand Up @@ -35,9 +42,9 @@ const WalletConnectProvider: React.FC<WalletConnectProviderProps> = ({ theme, ch
const [walletAddress, setWalletAddress] = useState<string | null>(null);
const [publicKey, setPublicKey] = useState<string | null>(null);
const [walletType, setWalletType] = useState<SupportedWallets | null>(null);
const [walletInstance, setWalletInstance] = useState<Unisat | null>(null);
const [walletInstance, setWalletInstance] = useState<OPWallet | null>(null);
const [provider, setProvider] = useState<AbstractRpcProvider | null>(null);
const [signer, setSigner] = useState<UnisatSigner | null>(null);
const [signer, setSigner] = useState<null>(null);
const [walletBalance, setWalletBalance] = useState<WalletBalance | null>(null);

const [mldsaPublicKey, setMldsaPublicKey] = useState<string | null>(null);
Expand Down Expand Up @@ -250,7 +257,7 @@ const WalletConnectProvider: React.FC<WalletConnectProviderProps> = ({ 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);
Expand Down Expand Up @@ -279,6 +286,20 @@ const WalletConnectProvider: React.FC<WalletConnectProviderProps> = ({ theme, ch
void fetchMLDSAKeys();
}, [publicKey]);

const switchNetwork = useCallback(
async (network: WalletNetwork|WalletChainType): Promise<void> => {
return WalletController.switchNetwork(network);
},
[],
);

const signMessage = useCallback(
async (message: string, messageType?: MessageType): Promise<string | null> => {
return WalletController.signMessage(message, messageType);
},
[],
);

const signMLDSAMessage = useCallback(
async (message: string): Promise<MLDSASignature | null> => {
return WalletController.signMLDSAMessage(message);
Expand Down Expand Up @@ -325,6 +346,8 @@ const WalletConnectProvider: React.FC<WalletConnectProviderProps> = ({ theme, ch
walletType,
mldsaPublicKey,
hashedMLDSAKey,
switchNetwork,
signMessage,
signMLDSAMessage,
verifyMLDSASignature,
}}>
Expand Down
29 changes: 25 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
import { type Network } from '@btc-vision/bitcoin';
import { UnisatChainType } from '@btc-vision/transaction';
import { SupportedWallets } from './wallets/supported-wallets';
import { 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 {
regtest = 'regtest',
testnet = 'testnet',
mainnet = 'mainnet',
}

export enum WalletChainType {
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;
network: string;
chainType: WalletChainType;
network: WalletNetwork;
}

export interface WalletInformation {
Expand Down
59 changes: 41 additions & 18 deletions src/wallets/controller.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { type Network, networks } from '@btc-vision/bitcoin';
import { type MLDSASignature, type Unisat, UnisatChainType, UnisatSigner, } from '@btc-vision/transaction';
import { type MessageType, type MLDSASignature } from '@btc-vision/transaction';
import { AbstractRpcProvider } from 'opnet';
import { type WalletConnectNetwork } from '../types';
import { type WalletBalance, type WalletConnectNetwork, WalletChainType, WalletNetwork } from '../types';
import { _e } from '../utils/accessibility/errorDecoder';
import type { OPWallet } from './opwallet/interface';
import { SupportedWallets } from './supported-wallets';
import type {
ControllerConnectAccounts,
Expand All @@ -25,7 +26,7 @@ class WalletController {
return WalletController.currentWallet?.name || null;
}

static getWalletInstance(): Unisat | null {
static getWalletInstance(): OPWallet | null {
const wallet = this.currentWallet;
if (!wallet) {
return null;
Expand All @@ -45,7 +46,7 @@ class WalletController {
return provider ? new Proxy(provider, {}) : null;
}

static async getSigner(): Promise<UnisatSigner | null> {
static async getSigner(): Promise<null> {
const wallet = this.currentWallet;
if (!wallet) {
return null;
Expand All @@ -55,22 +56,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 {
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 UnisatChainType.BITCOIN_REGTEST:
return walletNetwork(networks.regtest, 'regtest');
case UnisatChainType.BITCOIN_TESTNET:
return walletNetwork(networks.testnet, 'testnet');
case UnisatChainType.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 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;
}
Expand All @@ -94,6 +95,14 @@ class WalletController {
return wallet.controller.getPublicKey();
}

static async getBalance(): Promise<WalletBalance | null> {
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;
Expand Down Expand Up @@ -171,7 +180,7 @@ class WalletController {
return;
}
wallet.controller.removeChainChangedHook();
wallet.controller.setChainChangedHook((chainType: UnisatChainType) => {
wallet.controller.setChainChangedHook((chainType: WalletChainType) => {
const network = this.convertChainTypeToNetwork(chainType);
if (network) {
fn(network);
Expand Down Expand Up @@ -228,6 +237,20 @@ class WalletController {
this.removeAccountsChangedHook();
}

static async switchNetwork(network: WalletNetwork|WalletChainType): Promise<void> {
const wallet = this.currentWallet;
if (!wallet) return;

return wallet.controller.switchNetwork(network);
}

static async signMessage(message: string, messageType?: MessageType): Promise<string | null> {
const wallet = this.currentWallet;
if (!wallet) return null;

return wallet.controller.signMessage(message, messageType);
}

static async getMLDSAPublicKey(): Promise<string | null> {
const wallet = this.currentWallet;
if (!wallet) return null;
Expand Down
16 changes: 5 additions & 11 deletions src/wallets/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { WalletController } from './controller';
import OPWallet from './opwallet/controller';
import { logo as OPWalletLogo } from './opwallet/interface';
import OPWalletInstance from './opwallet/controller';

import { SupportedWallets } from './supported-wallets';
import UniSatWallet from './unisat/controller';
import { logo as UnisatLogo } from './unisat/interface';

WalletController.registerWallet({
WalletController.registerWallet(
{
name: SupportedWallets.OP_WALLET,
icon: OPWalletLogo,
controller: new OPWallet(),
});

WalletController.registerWallet({
name: SupportedWallets.UNISAT,
icon: UnisatLogo,
controller: new UniSatWallet(),
controller: new OPWalletInstance(),
});

export { WalletController, SupportedWallets };
Loading