diff --git a/apps/sample-react-app/src/App.tsx b/apps/sample-react-app/src/App.tsx index ec4e7372..e5c24ef8 100644 --- a/apps/sample-react-app/src/App.tsx +++ b/apps/sample-react-app/src/App.tsx @@ -15,7 +15,7 @@ const nodeOptions: Omit = { }; const walletConnectOptions: WalletConnectOptions = { - projectId: '8dfc5cac972ee656e6edeb8309ab30ec', + projectId: 'a0b855ceaf109dbc8426479a4c3d38d8', metadata: { name: 'Sample VeChain dApp', description: 'A sample VeChain dApp', diff --git a/apps/sample-react-app/src/Components/ConnectWalletModal.tsx b/apps/sample-react-app/src/Components/ConnectWalletModal.tsx index fd0030d4..089d7fa8 100644 --- a/apps/sample-react-app/src/Components/ConnectWalletModal.tsx +++ b/apps/sample-react-app/src/Components/ConnectWalletModal.tsx @@ -68,6 +68,8 @@ const ConnectedWalletBody: React.FC = ({ }, }; + if (!vendor) throw new Error('Vendor not available'); + const certResponse = await vendor.sign('cert', message).request(); const cert: Certificate = { diff --git a/apps/sample-react-app/src/Hooks/useCounter.ts b/apps/sample-react-app/src/Hooks/useCounter.ts index 30963155..628d349e 100644 --- a/apps/sample-react-app/src/Hooks/useCounter.ts +++ b/apps/sample-react-app/src/Hooks/useCounter.ts @@ -34,7 +34,7 @@ interface UseCounter { } export const useCounter = (): UseCounter => { - const { vendor, thor } = useConnex(); + const { thor } = useConnex(); const [count, setCount] = useState(0); const [status, setStatus] = useState('idle'); @@ -55,12 +55,11 @@ export const useCounter = (): UseCounter => { }, [setValue]); const increment = useCallback(async (): Promise => { - const clause = contract.method(_increment).asClause(); - setStatus('in-wallet'); - await vendor - .sign('tx', [clause]) + await contract + .method(_increment) + .transact() .delegate('https://sponsor-testnet.vechain.energy/by/90') .request(); @@ -71,7 +70,7 @@ export const useCounter = (): UseCounter => { await setValue() .then(() => setStatus('idle')) .catch(() => setStatus('error')); - }, [thor, vendor, contract, setValue]); + }, [thor, contract, setValue]); return { count, increment, status, address: contract.address }; }; diff --git a/packages/react-wallet-kit/src/ConnexProvider.tsx b/packages/react-wallet-kit/src/ConnexProvider.tsx index 4e29ec79..af7b4c65 100644 --- a/packages/react-wallet-kit/src/ConnexProvider.tsx +++ b/packages/react-wallet-kit/src/ConnexProvider.tsx @@ -2,20 +2,11 @@ import React, { createContext, useCallback, useContext, - useEffect, useMemo, useReducer, - useRef, } from 'react'; -import { Connex } from '@vechain/connex'; -import { newVendor } from '@vechain/connex-framework'; -import type { WalletConnectOptions, WCSigner } from '@vechain/wallet-connect'; -import { - newWcClient, - newWcSigner, - newWeb3Modal, -} from '@vechain/wallet-connect'; -import { WalletSource } from '@vechain/wallet-kit'; +import type { ConnexInstance } from '@vechain/wallet-kit'; +import { createConnexInstance, WalletSource } from '@vechain/wallet-kit'; import { accountReducer, defaultAccountState } from './AccountReducer'; import type { ConnexContext, @@ -40,18 +31,35 @@ export const ConnexProvider: React.FC = ({ defaultAccountState, ); - const wcSignerRef = useRef(); + const onDisconnected = useCallback((): void => { + dispatch({ type: 'clear' }); + }, []); - const disconnectMobile = useCallback(() => { - const client = wcSignerRef.current; + const connexInstance: ConnexInstance = useMemo( + () => + createConnexInstance({ + nodeUrl: nodeOptions.node, + genesis: nodeOptions.network, + source: accountState.source ?? undefined, + walletConnectOptions, + onDisconnected, + }), + //eslint-disable-next-line react-hooks/exhaustive-deps + [ + nodeOptions.node, + nodeOptions.network, + walletConnectOptions, + onDisconnected, + ], + ); - if (client) { - client.disconnect().catch((err) => { - throw err; - }); - wcSignerRef.current = undefined; - } - }, []); + const disconnect = useCallback((): void => { + dispatch({ type: 'clear' }); + + connexInstance.disconnect().catch(() => { + // do nothing + }); + }, [connexInstance]); const availableWallets = useMemo(() => { const wallets: WalletSource[] = [WalletSource.Sync2]; @@ -71,132 +79,19 @@ export const ConnexProvider: React.FC = ({ return wallets; }, [walletConnectOptions]); - const onDisconnected = useCallback((): void => { - if (accountState.source === WalletSource.WalletConnect) { - disconnectMobile(); - } - - dispatch({ type: 'clear' }); - }, [disconnectMobile, accountState]); - - useEffect(() => { - if ( - accountState.source === WalletSource.WalletConnect && - !walletConnectOptions - ) { - onDisconnected(); - } - - if ( - accountState.source === WalletSource.VeWorldExtension && - !window.vechain - ) { - onDisconnected(); - } - }, [accountState, walletConnectOptions, onDisconnected]); - - const updateSource: SetSource = useCallback( + const setSource: SetSource = useCallback( (wallet: WalletSource): void => { - // We can't set VeWorld Mobile if there is no Wallet Connect config - if ( - wallet === WalletSource.WalletConnect && - !walletConnectOptions - ) { - throw new Error('Wallet Connect config not found'); - } - - // We can't set VeWorld Extension if there is no VeChain extension - if (wallet === WalletSource.VeWorldExtension && !window.vechain) { - throw new Error('VeWorld extension not found'); - } + connexInstance.setSource(wallet); dispatch({ type: 'set-wallet-source', payload: { source: wallet, persist: persistState }, }); }, - [walletConnectOptions, persistState], - ); - - const thor: Connex.Thor = useMemo( - () => new Connex.Thor(nodeOptions), - [nodeOptions], + [connexInstance, persistState], ); - const createWalletConnectVendor = useCallback( - (options: WalletConnectOptions) => { - const { projectId, metadata } = options; - - const wcClient = newWcClient({ - projectId, - metadata, - }); - - const web3Modal = newWeb3Modal(projectId); - - const wcSigner: WCSigner = newWcSigner({ - genesisId: thor.genesis.id, - wcClient, - web3Modal, - onDisconnected, - }); - - wcSignerRef.current = wcSigner; - - return newVendor(wcSigner); - }, - [onDisconnected, thor.genesis.id], - ); - - /** - * Create the vendor - * Create a vendor for the provided options. If that vendor is not available, the priority is: - * 1. Wallet Connect - If the options are provided - * 2. VeWorld Extension - If the extension is available - * 3. Sync2 - As a fallback, as it is always available - */ - const vendor: Connex.Vendor = useMemo(() => { - const { source } = accountState; - - if (source === WalletSource.WalletConnect && walletConnectOptions) { - return createWalletConnectVendor(walletConnectOptions); - } - - if (source === WalletSource.Sync2 || source === WalletSource.Sync) { - return new Connex.Vendor(thor.genesis.id, source); - } - - if (source === WalletSource.VeWorldExtension && window.vechain) { - const extensionSigner = window.vechain.newConnexSigner( - thor.genesis.id, - ); - - return newVendor(extensionSigner); - } - - // We've exhausted all options, so default to Wallet Connect if the options are provided - if (walletConnectOptions) { - return createWalletConnectVendor(walletConnectOptions); - } - - // No wallet connect options, so use the extension if it's available - if (window.vechain) { - const extensionSigner: Connex.Signer = - window.vechain.newConnexSigner(thor.genesis.id); - - return newVendor(extensionSigner); - } - - // Default to Sync2 - return new Connex.Vendor(thor.genesis.id, WalletSource.Sync2); - }, [ - createWalletConnectVendor, - thor.genesis.id, - walletConnectOptions, - accountState, - ]); - - const updateAccount: SetAccount = useCallback( + const setAccount: SetAccount = useCallback( (address: string) => { dispatch({ type: 'set-address', @@ -206,40 +101,34 @@ export const ConnexProvider: React.FC = ({ [persistState], ); - const wallets: WalletSource[] = useMemo(() => { - return Object.values(WalletSource); - }, []); - const context: ConnexContext = useMemo(() => { return { connex: { - thor, - vendor, + thor: connexInstance.thor, + vendor: connexInstance.vendor, }, wallet: { - setSource: updateSource, - setAccount: updateAccount, + setSource, + setAccount, availableWallets, - wallets, + wallets: Object.values(WalletSource), accountState, - disconnect: onDisconnected, + disconnect, }, }; }, [ - onDisconnected, - updateAccount, accountState, - thor, - vendor, - updateSource, - wallets, + connexInstance, + setAccount, + setSource, availableWallets, + disconnect, ]); return {children}; }; -export const useConnex = (): Connex => { +export const useConnex = (): ConnexContext['connex'] => { const context = useContext(Context); return context.connex; }; diff --git a/packages/react-wallet-kit/src/types.ts b/packages/react-wallet-kit/src/types.ts index dfa00253..49acc306 100644 --- a/packages/react-wallet-kit/src/types.ts +++ b/packages/react-wallet-kit/src/types.ts @@ -38,17 +38,13 @@ export interface ConnexProviderOptions { * Connex Context * This context is used to provide the Connex instance and the Connex Vendor instance * to the application. - * - * @param thor - {@link Connex.Thor}: used to interact with the blockchain - * @param vendor - {@link Connex.Vendor}: used to interact with the wallet - * @param setWallet - used to set the wallet source - * @param availableWallets - list of available wallets - * @param accountState - current account state - * @param dispatch - used to dispatch account actions */ export interface ConnexContext { - connex: Connex; + connex: { + thor: Connex.Thor; + vendor?: Connex.Vendor; + }; wallet: { setSource: SetSource; setAccount: SetAccount; diff --git a/packages/wallet-connect/src/signer.ts b/packages/wallet-connect/src/signer.ts index 7c4932f7..f6d794f6 100644 --- a/packages/wallet-connect/src/signer.ts +++ b/packages/wallet-connect/src/signer.ts @@ -5,7 +5,7 @@ import type { EngineTypes } from '@walletconnect/types/dist/types/sign-client/en import { getSdkError } from '@walletconnect/utils'; import type { SignClient } from '@walletconnect/sign-client/dist/types/client'; import type { WCSigner, WCSignerOptions } from './types'; -import { DefaultEvents, DefaultMethods } from './constants'; +import { DefaultMethods } from './constants'; interface SessionAccount { networkIdentifier: string; @@ -136,7 +136,7 @@ export const newWcSigner = ({ const namespace: ProposalTypes.RequiredNamespace = { methods: Object.values(DefaultMethods), chains: [chainId], - events: Object.values(DefaultEvents), + events: [], }; try { diff --git a/packages/wallet-kit/src/connex.ts b/packages/wallet-kit/src/connex.ts index ceebdd12..699f4591 100644 --- a/packages/wallet-kit/src/connex.ts +++ b/packages/wallet-kit/src/connex.ts @@ -1,66 +1,57 @@ -import { Framework } from '@vechain/connex-framework'; -import type { WalletConnectOptions } from '@vechain/wallet-connect'; -import type { Genesis } from './types'; -import { WalletSource } from './wallet'; -import { createSigner } from './signer'; +import { createNoVendor } from '@vechain/connex/esm/driver'; +import { newThor } from '@vechain/connex-framework/dist/thor'; +import type { DriverNoVendor } from '@vechain/connex-driver'; +import { newVendor } from '@vechain/connex-framework'; +import type { ConnexInstance, ConnexOptions } from './types'; import { normalizeGenesisBlock } from './genesis'; -import { createVendorDriver } from './vendor-driver'; -import { createDriverNoVendor } from './thor-driver'; +import { WalletSource } from './wallet'; +import { FullDriver } from './full-driver'; +import { SignerManager } from './signer-manager'; -interface BaseConnexOptions { - nodeUrl: string; - genesis: Genesis; -} +const createConnexInstance = (options: ConnexOptions): ConnexInstance => { + const { nodeUrl, genesis, source, walletConnectOptions } = options; -interface NoWalletConfigOptions extends BaseConnexOptions { - source: - | WalletSource.VeWorldExtension - | WalletSource.Sync - | WalletSource.Sync2; -} + const genesisBlock = normalizeGenesisBlock(genesis); -interface WalletConnectConfigOptions extends BaseConnexOptions { - source: WalletSource.WalletConnect; - options: WalletConnectOptions; - onDisconnected: () => void; -} + const thorOnlyDriver: DriverNoVendor = createNoVendor( + nodeUrl, + genesisBlock, + ); -type ConnexOptions = NoWalletConfigOptions | WalletConnectConfigOptions; + const _source = source; -const createConnexInstance = (options: ConnexOptions): Connex => { - const { source, genesis } = options; + const signerManager: SignerManager = new SignerManager(options, source); + const fullDriver = new FullDriver(thorOnlyDriver, signerManager); - const genesisBlock = normalizeGenesisBlock(genesis); + const thor = newThor(fullDriver); + const vendor = newVendor(fullDriver); - let signer: Promise; - - if (source === WalletSource.WalletConnect) { - signer = createSigner({ - source: options.source, - genesis: options.genesis, - options: options.options, - onDisconnected: options.onDisconnected, - }); - } else { - signer = createSigner({ - source: options.source, - genesis: options.genesis, - }); - } + const disconnect = async (): Promise => { + await signerManager.disconnect(); + }; - // This is cached, so the `DriverNoVendor` is shared between wallet sources - const driverNoVendor = createDriverNoVendor(options.nodeUrl, genesisBlock); + const setSource = (src: WalletSource): void => { + if (src === WalletSource.WalletConnect && !walletConnectOptions) { + throw new Error('WalletConnect options are not provided'); + } - // This is also cached based on the source - const vendorDriver = createVendorDriver(signer, source); + if (src === WalletSource.VeWorldExtension && !window.vechain) { + throw new Error('VeWorld Extension is not installed'); + } - vendorDriver.setNoVendor(driverNoVendor); + if (src === WalletSource.Sync && !window.connex) { + throw new Error('User is not in a Sync wallet'); + } - const framework = new Framework(vendorDriver); + signerManager.setSigner(src); + }; return { - thor: framework.thor, - vendor: framework.vendor, + setSource, + thor, + vendor, + disconnect, + source: _source, }; }; diff --git a/packages/wallet-kit/src/full-driver.ts b/packages/wallet-kit/src/full-driver.ts new file mode 100644 index 00000000..b82f0b26 --- /dev/null +++ b/packages/wallet-kit/src/full-driver.ts @@ -0,0 +1,85 @@ +import type { DriverNoVendor } from '@vechain/connex-driver'; + +export class FullDriver implements Connex.Driver { + constructor( + private readonly driver: DriverNoVendor, + private signer: Connex.Signer, + ) {} + + get genesis(): Connex.Thor.Block { + return this.driver.genesis; + } + + get head(): Connex.Thor.Status['head'] { + return this.driver.head; + } + + pollHead(): Promise { + return this.driver.pollHead(); + } + + getBlock(revision: string | number): Promise { + return this.driver.getBlock(revision); + } + + getTransaction( + id: string, + allowPending: boolean, + ): Promise { + return this.driver.getTransaction(id, allowPending); + } + + getReceipt(id: string): Promise { + return this.driver.getReceipt(id); + } + + getAccount(addr: string, revision: string): Promise { + return this.driver.getAccount(addr, revision); + } + + getCode(addr: string, revision: string): Promise { + return this.driver.getCode(addr, revision); + } + + getStorage( + addr: string, + key: string, + revision: string, + ): Promise { + return this.driver.getStorage(addr, key, revision); + } + + explain( + arg: Connex.Driver.ExplainArg, + revision: string, + cacheHints?: string[], + ): Promise { + return this.driver.explain(arg, revision, cacheHints); + } + + filterEventLogs( + arg: Connex.Driver.FilterEventLogsArg, + ): Promise[]> { + return this.driver.filterEventLogs(arg); + } + + filterTransferLogs( + arg: Connex.Driver.FilterTransferLogsArg, + ): Promise[]> { + return this.driver.filterTransferLogs(arg); + } + + async signTx( + msg: Connex.Vendor.TxMessage, + options: Connex.Signer.TxOptions, + ): Promise { + return this.signer.signTx(msg, options); + } + + async signCert( + msg: Connex.Vendor.CertMessage, + options: Connex.Signer.CertOptions, + ): Promise { + return this.signer.signCert(msg, options); + } +} diff --git a/packages/wallet-kit/src/genesis.ts b/packages/wallet-kit/src/genesis.ts index e50705a1..7a38e739 100644 --- a/packages/wallet-kit/src/genesis.ts +++ b/packages/wallet-kit/src/genesis.ts @@ -1,14 +1,18 @@ import { genesisBlocks } from '@vechain/connex/esm/config'; import type { Genesis } from './types'; -const normalizeGenesisId = (genesis: Genesis): string => { +const normalizeGenesisId = (genesis?: Genesis): string => { + if (!genesis) return genesisBlocks.main.id; + if (genesis === 'main' || genesis === 'test') return genesisBlocks[genesis].id; return genesis.id; }; -const normalizeGenesisBlock = (genesis: Genesis): Connex.Thor.Block => { +const normalizeGenesisBlock = (genesis?: Genesis): Connex.Thor.Block => { + if (!genesis) return genesisBlocks.main; + if (genesis === 'main' || genesis === 'test') return genesisBlocks[genesis]; return genesis; diff --git a/packages/wallet-kit/src/index.ts b/packages/wallet-kit/src/index.ts index 4684031f..cae1ca4f 100644 --- a/packages/wallet-kit/src/index.ts +++ b/packages/wallet-kit/src/index.ts @@ -1,2 +1,4 @@ export * from './connex'; export * from './wallet'; + +export type { ConnexOptions, ConnexInstance, ConnexSigner } from './types'; diff --git a/packages/wallet-kit/src/signer-manager.ts b/packages/wallet-kit/src/signer-manager.ts new file mode 100644 index 00000000..08b2aa36 --- /dev/null +++ b/packages/wallet-kit/src/signer-manager.ts @@ -0,0 +1,81 @@ +import type { ConnexOptions, ConnexSigner } from './types'; +import { WalletSource } from './wallet'; +import { createSigner } from './signer'; + +class SignerManager implements ConnexSigner { + private signers: Record = { + [WalletSource.WalletConnect]: undefined, + [WalletSource.VeWorldExtension]: undefined, + [WalletSource.Sync]: undefined, + [WalletSource.Sync2]: undefined, + }; + + private currentSource: WalletSource | undefined; + + constructor( + private readonly connexOptions: ConnexOptions, + initialSource?: WalletSource, + ) { + this.currentSource = initialSource; + } + + public setSigner(source: WalletSource): void { + this.currentSource = source; + } + + public async disconnect(): Promise { + if (!this.currentSource) { + return; + } + + const signer = this.signers[this.currentSource]; + + if (signer) { + await signer.disconnect?.(); + } + } + + async signTx( + msg: Connex.Vendor.TxMessage, + options: Connex.Signer.TxOptions, + ): Promise { + const signer = await this.getSigner(); + + return signer.signTx(msg, options); + } + + public async signCert( + msg: Connex.Vendor.CertMessage, + options: Connex.Signer.CertOptions, + ): Promise { + const signer = await this.getSigner(); + + return signer.signCert(msg, options); + } + + private async getSigner(): Promise { + if (!this.currentSource) { + throw new Error('No wallet has been selected'); + } + + let signer = this.signers[this.currentSource]; + + if (!signer) { + const opts = { ...this.connexOptions, source: this.currentSource }; + const newSigner = createSigner(opts); + + if (newSigner) { + signer = await newSigner; + this.signers[this.currentSource] = signer; + } + } + + if (!signer) { + throw new Error('Signer is not initialized'); + } + + return signer; + } +} + +export { SignerManager }; diff --git a/packages/wallet-kit/src/signer.ts b/packages/wallet-kit/src/signer.ts index 90f29deb..367d478a 100644 --- a/packages/wallet-kit/src/signer.ts +++ b/packages/wallet-kit/src/signer.ts @@ -1,79 +1,70 @@ -import type { - WalletConnectOptions, - WCSigner, -} from '@vechain/wallet-connect/dist'; +import type { WCSigner } from '@vechain/wallet-connect/dist'; import { newWcClient, newWcSigner, newWeb3Modal, } from '@vechain/wallet-connect/dist'; -import type { Connex } from '@vechain/connex'; import { createSync, createSync2 } from '@vechain/connex/esm/signer'; import { WalletSource } from './wallet'; -import type { Genesis } from './types'; +import type { ConnexOptions, ConnexSigner } from './types'; import { normalizeGenesisId } from './genesis'; -interface WCOptions { - source: WalletSource.WalletConnect; - genesis: Genesis; - options: WalletConnectOptions; - onDisconnected: () => void; -} - -interface DefaultOptions { - source: - | WalletSource.Sync - | WalletSource.Sync2 - | WalletSource.VeWorldExtension; - genesis: Genesis; -} - -type ICreateVendor = DefaultOptions | WCOptions; - -export const createSigner = (params: ICreateVendor): Promise => { +export const createSigner = ( + params: ConnexOptions, +): Promise | undefined => { const { source, genesis } = params; + if (!source) { + return; + } + const genesisId = normalizeGenesisId(genesis); - if (source === WalletSource.VeWorldExtension) { - if (!window.vechain) { - throw new Error('VeWorld Extension is not installed'); - } + switch (source) { + case WalletSource.Sync: { + if (!window.connex) { + throw new Error('User is not in a Sync wallet'); + } - const signer = window.vechain.newConnexSigner(genesisId); + return createSync(genesisId); + } + case WalletSource.Sync2: { + return createSync2(genesisId); + } + case WalletSource.VeWorldExtension: { + if (!window.vechain) { + throw new Error('VeWorld Extension is not installed'); + } - return Promise.resolve(signer); - } + const signer = window.vechain.newConnexSigner(genesisId); - if (source === WalletSource.WalletConnect) { - const { onDisconnected, options } = params; + return Promise.resolve(signer); + } + case WalletSource.WalletConnect: { + const { walletConnectOptions, onDisconnected } = params; - const { projectId, metadata } = options; + if (!walletConnectOptions) { + onDisconnected(); + return; + } - const wcClient = newWcClient({ - projectId, - metadata, - }); + const { projectId, metadata } = walletConnectOptions; - const web3Modal = newWeb3Modal(projectId); + const wcClient = newWcClient({ + projectId, + metadata, + }); - const wcSigner: WCSigner = newWcSigner({ - genesisId, - wcClient, - web3Modal, - onDisconnected, - }); + const web3Modal = newWeb3Modal(projectId); - return Promise.resolve(wcSigner); - } + const wcSigner: WCSigner = newWcSigner({ + genesisId, + wcClient, + web3Modal, + onDisconnected, + }); - if (source === WalletSource.Sync) { - if (!window.connex) { - throw new Error('User is not in a Sync wallet'); + return Promise.resolve(wcSigner); } - - return createSync(genesisId); } - - return createSync2(genesisId); }; diff --git a/packages/wallet-kit/src/thor-driver.ts b/packages/wallet-kit/src/thor-driver.ts deleted file mode 100644 index f36068f8..00000000 --- a/packages/wallet-kit/src/thor-driver.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DriverNoVendor } from '@vechain/connex-driver/dist/driver-no-vendor'; -import { SimpleNet } from '@vechain/connex-driver'; -import type { Genesis } from './types'; -import { normalizeGenesisBlock } from './genesis'; - -let previousDriver: DriverNoVendor | undefined; - -const createDriverNoVendor = ( - nodeUrl: string, - genesis: Genesis, -): DriverNoVendor => { - const genesisBlock = normalizeGenesisBlock(genesis); - - if (previousDriver && previousDriver.genesis.id === genesisBlock.id) { - return previousDriver; - } - - const net = new SimpleNet(nodeUrl); - - const driver = new DriverNoVendor(net, genesisBlock); - - previousDriver = driver; - - return driver; -}; - -export { createDriverNoVendor }; diff --git a/packages/wallet-kit/src/types.d.ts b/packages/wallet-kit/src/types.d.ts index 0f6e4507..68e92aaa 100644 --- a/packages/wallet-kit/src/types.d.ts +++ b/packages/wallet-kit/src/types.d.ts @@ -1,4 +1,6 @@ import type { Connex1 } from '@vechain/connex/esm/signer'; +import type { WalletConnectOptions } from '@vechain/wallet-connect'; +import type { WalletSource } from './wallet'; declare global { interface Window { @@ -10,3 +12,28 @@ declare global { } export type Genesis = 'main' | 'test' | Connex.Thor.Block; + +interface ConnexOptions { + nodeUrl: string; + genesis?: Genesis; + onDisconnected: () => void; + source?: WalletSource; + walletConnectOptions?: WalletConnectOptions; +} + +interface ConnexInstance { + thor: Connex.Thor; + vendor?: Connex.Vendor; + setSource: (source: WalletSource) => void; + disconnect: () => Promise; + source: WalletSource | undefined; +} + +/** + * Modifies the Connex.Signer interface to include a disconnect method + */ +type ConnexSigner = Connex.Signer & { + disconnect?: () => Promise; +}; + +export type { ConnexOptions, ConnexInstance, ConnexSigner };