diff --git a/.github/workflows/lint-build-test.yaml b/.github/workflows/lint-build-test.yaml index 2671abbd..7a680637 100644 --- a/.github/workflows/lint-build-test.yaml +++ b/.github/workflows/lint-build-test.yaml @@ -16,10 +16,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version-file: .nvmrc cache: 'yarn' diff --git a/.github/workflows/test-e2e.yaml b/.github/workflows/test-e2e.yaml index e3850f57..371f33db 100644 --- a/.github/workflows/test-e2e.yaml +++ b/.github/workflows/test-e2e.yaml @@ -18,7 +18,7 @@ jobs: - name: Install Stable Chrome run: | wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - - sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' + sudo sh -c 'echo "deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' sudo apt-get update sudo apt-get install google-chrome-stable @@ -29,7 +29,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version-file: .nvmrc cache: 'yarn' diff --git a/examples/sample-angular-app/src/app/app.component.ts b/examples/sample-angular-app/src/app/app.component.ts index 9812fbf1..2d246bc5 100644 --- a/examples/sample-angular-app/src/app/app.component.ts +++ b/examples/sample-angular-app/src/app/app.component.ts @@ -26,7 +26,6 @@ export class AppComponent implements OnInit { DAppKitUI.configure({ nodeUrl: 'https://testnet.vechain.org/', - genesis: 'test', walletConnectOptions, usePersistence: true, }); diff --git a/examples/sample-next-app/src/app/layout.tsx b/examples/sample-next-app/src/app/layout.tsx index 0bb83fd2..da9a331f 100644 --- a/examples/sample-next-app/src/app/layout.tsx +++ b/examples/sample-next-app/src/app/layout.tsx @@ -46,7 +46,6 @@ export default function RootLayout({ diff --git a/examples/sample-react-app/test/welcome.test.tsx b/examples/sample-react-app/test/welcome.test.tsx index b5efbe0c..9359f69c 100644 --- a/examples/sample-react-app/test/welcome.test.tsx +++ b/examples/sample-react-app/test/welcome.test.tsx @@ -1,6 +1,6 @@ import renderer from 'react-test-renderer'; import React from 'react'; -import { test, expect } from 'vitest'; +import { expect, test } from 'vitest'; import App from '../src/App'; import { DAppKitProvider } from '@vechain/dapp-kit-react'; import { WalletConnectOptions } from '@vechain/dapp-kit'; @@ -19,7 +19,6 @@ test('Welcome', async () => { diff --git a/examples/sample-remix-app/app/.client/app.client.tsx b/examples/sample-remix-app/app/.client/app.client.tsx index 7742d8ff..22bd6f3b 100644 --- a/examples/sample-remix-app/app/.client/app.client.tsx +++ b/examples/sample-remix-app/app/.client/app.client.tsx @@ -1,9 +1,9 @@ import { DAppKitProvider, - WalletButton, - WalletConnectOptions, useWallet, useWalletModal, + WalletButton, + WalletConnectOptions, } from '@vechain/dapp-kit-react'; import { useEffect, useState } from 'react'; @@ -58,7 +58,6 @@ const walletConnectOptions: WalletConnectOptions = { export const App = () => { return ( import { defineComponent } from 'vue'; import { DAppKitUI } from '@vechain/dapp-kit-ui'; -import { Genesis } from '@vechain/dapp-kit'; const walletConnectOptions = { projectId: 'a0b855ceaf109dbc8426479a4c3d38d8', @@ -27,7 +26,6 @@ const walletConnectOptions = { const vechainDAppKitOptions = { nodeUrl: 'https://testnet.vechain.org/', - genesis: 'test' as Genesis, walletConnectOptions, usePersistence: true, }; @@ -78,9 +76,11 @@ body { align-items: center; justify-content: center; } + h2 { margin: 0; } + .container { display: flex; flex-direction: column; @@ -90,6 +90,7 @@ h2 { border-radius: 20px; padding: 20px; } + .label { margin-top: 20px; margin-bottom: 10px; diff --git a/packages/dapp-kit-react/README.md b/packages/dapp-kit-react/README.md index f0c9772a..dad6b829 100644 --- a/packages/dapp-kit-react/README.md +++ b/packages/dapp-kit-react/README.md @@ -1,6 +1,9 @@ # `@vechain/dapp-kit-react` -The Vechain DApp Kit serves as a sophisticated layer built upon @vechain/connex, providing a simplified and efficient avenue for engaging with a multitude of Vechain wallets. This innovative toolkit enhances the ease of interaction, offering developers a seamless bridge to connect with diverse Vechain wallet functionalities. For more information, please refer to the official [Vechain Docs](https://docs.vechain.org/developer-resources/sdks-and-providers/dapp-kit) +The Vechain DApp Kit serves as a sophisticated layer built upon @vechain/connex, providing a simplified and efficient +avenue for engaging with a multitude of Vechain wallets. This innovative toolkit enhances the ease of interaction, +offering developers a seamless bridge to connect with diverse Vechain wallet functionalities. For more information, +please refer to the official [Vechain Docs](https://docs.vechain.org/developer-resources/sdks-and-providers/dapp-kit) ## Installation @@ -37,8 +40,6 @@ ReactDOM.createRoot(document.getElementById('root')!).render( (undefined); export const DAppKitProvider: React.FC = ({ children, nodeUrl, - genesis, walletConnectOptions, usePersistence = false, logLevel, @@ -37,7 +36,6 @@ export const DAppKitProvider: React.FC = ({ () => DAppKitUI.configure({ nodeUrl, - genesis, walletConnectOptions, usePersistence, logLevel, @@ -52,7 +50,6 @@ export const DAppKitProvider: React.FC = ({ }), [ nodeUrl, - genesis, walletConnectOptions, usePersistence, logLevel, diff --git a/packages/dapp-kit-ui/README.md b/packages/dapp-kit-ui/README.md index 8977a523..5db2f136 100644 --- a/packages/dapp-kit-ui/README.md +++ b/packages/dapp-kit-ui/README.md @@ -1,6 +1,9 @@ # `@vechain/dapp-kit-ui` -The Vechain DApp Kit serves as a sophisticated layer built upon @vechain/connex, providing a simplified and efficient avenue for engaging with a multitude of Vechain wallets. This innovative toolkit enhances the ease of interaction, offering developers a seamless bridge to connect with diverse Vechain wallet functionalities. For more information, please refer to the official [Vechain Docs](https://docs.vechain.org/developer-resources/sdks-and-providers/dapp-kit) +The Vechain DApp Kit serves as a sophisticated layer built upon @vechain/connex, providing a simplified and efficient +avenue for engaging with a multitude of Vechain wallets. This innovative toolkit enhances the ease of interaction, +offering developers a seamless bridge to connect with diverse Vechain wallet functionalities. For more information, +please refer to the official [Vechain Docs](https://docs.vechain.org/developer-resources/sdks-and-providers/dapp-kit) ## Usage @@ -26,7 +29,6 @@ const walletConnectOptions: WalletConnectOptions = { const options: DAppKitOptions = { nodeUrl: 'https://testnet.vechain.org/', - genesis: 'test', walletConnectOptions, usePersistence: true, }; diff --git a/packages/dapp-kit-ui/src/constants/sources.ts b/packages/dapp-kit-ui/src/constants/sources.ts index c504f3eb..512ba70b 100644 --- a/packages/dapp-kit-ui/src/constants/sources.ts +++ b/packages/dapp-kit-ui/src/constants/sources.ts @@ -1,5 +1,5 @@ import type { WalletSource } from '@vechain/dapp-kit'; -import { VeWorldLogo, WalletConnectLogo } from '../assets/images'; +import { SyncLogo, VeWorldLogo, WalletConnectLogo } from '../assets/images'; export interface SourceInfo { id: WalletSource; @@ -18,4 +18,14 @@ export const WalletSources: Record = { name: 'VeWorld', logo: VeWorldLogo, }, + sync: { + id: 'sync', + name: 'Sync', + logo: SyncLogo, + }, + sync2: { + id: 'sync2', + name: 'Sync2', + logo: SyncLogo, + }, }; diff --git a/packages/dapp-kit/src/classes/certificate-wallet.ts b/packages/dapp-kit/src/classes/certificate-wallet.ts index 848c8c3c..0dbfc918 100644 --- a/packages/dapp-kit/src/classes/certificate-wallet.ts +++ b/packages/dapp-kit/src/classes/certificate-wallet.ts @@ -1,5 +1,5 @@ import { Certificate } from '@vechain/sdk-core'; -import type { BaseWallet, ConnectResponse, VechainWallet } from '../types'; +import type { ConnectResponse, VechainWallet } from '../types'; import { DEFAULT_CONNECT_CERT_MESSAGE } from '../constants'; import type { CertificateMessage, @@ -9,13 +9,14 @@ import type { TransactionOptions, TransactionResponse, } from '../types/requests'; +import type { WalletSigner } from '../types/types'; /** * A `VechainWallet` for wallet's that use a certificate connection */ class CertificateBasedWallet implements VechainWallet { constructor( - private readonly wallet: BaseWallet, + private readonly wallet: Promise, private readonly connectionCertificateData?: { message?: CertificateMessage; options?: CertificateOptions; @@ -60,14 +61,16 @@ class CertificateBasedWallet implements VechainWallet { signCert = ( msg: CertificateMessage, options: CertificateOptions, - ): Promise => this.wallet.signCert(msg, options); + ): Promise => + this.wallet.then((w) => w.signCert(msg, options)); signTx = ( msg: TransactionMessage[], options: TransactionOptions, - ): Promise => this.wallet.signTx(msg, options); + ): Promise => + this.wallet.then((w) => w.signTx(msg, options)); - disconnect = async (): Promise => this.wallet.disconnect?.(); + disconnect = () => Promise.resolve(); } export { CertificateBasedWallet }; diff --git a/packages/dapp-kit/src/classes/index.ts b/packages/dapp-kit/src/classes/index.ts index 1afba335..adcad61e 100644 --- a/packages/dapp-kit/src/classes/index.ts +++ b/packages/dapp-kit/src/classes/index.ts @@ -1,4 +1,3 @@ export * from './wallet-manager'; export * from './certificate-wallet'; -export * from './wc-wallet'; export * from './vechain-signer'; diff --git a/packages/dapp-kit/src/classes/wallet-manager.ts b/packages/dapp-kit/src/classes/wallet-manager.ts index c6b574fc..391f626e 100644 --- a/packages/dapp-kit/src/classes/wallet-manager.ts +++ b/packages/dapp-kit/src/classes/wallet-manager.ts @@ -1,6 +1,7 @@ import { proxy, subscribe } from 'valtio/vanilla'; import { subscribeKey } from 'valtio/vanilla/utils'; import { Certificate } from '@vechain/sdk-core'; +import type { ThorClient } from '@vechain/sdk-network'; import type { ConnectResponse, DAppKitOptions, @@ -23,7 +24,10 @@ class WalletManager { public readonly state: WalletManagerState; private wallets: Record = {}; - constructor(private readonly options: DAppKitOptions) { + constructor( + private readonly options: DAppKitOptions, + private readonly thor: ThorClient, + ) { this.state = this.initState(options.usePersistence ?? false); this.initPersistence(options.usePersistence ?? false); DAppKitLogger.debug('WalletManager', 'constructor', this.state); @@ -36,7 +40,7 @@ class WalletManager { } private get wallet(): VechainWallet { - let source = this.state.source; + const source = this.state.source; DAppKitLogger.debug( 'WalletManager', @@ -46,10 +50,7 @@ class WalletManager { ); if (!source) { - if (this.state.availableSources.length > 1) { - throw new Error('No wallet selected'); - } - source = this.state.availableSources[0]; + throw new Error('No wallet selected'); } let wallet = this.wallets[source]; @@ -70,6 +71,7 @@ class WalletManager { ...this.options, source, onDisconnected: () => this.disconnect(true), + thor: this.thor, }; wallet = createWallet(opts); @@ -288,6 +290,12 @@ class WalletManager { wallets.push('wallet-connect'); } + wallets.push('sync2'); + + if (window.connex) { + wallets.push('sync'); + } + return wallets; }; diff --git a/packages/dapp-kit/src/classes/wc-wallet.ts b/packages/dapp-kit/src/classes/wc-wallet.ts deleted file mode 100644 index 3689aa45..00000000 --- a/packages/dapp-kit/src/classes/wc-wallet.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { ConnectResponse, VechainWallet, WCSigner } from '../types'; -import type { - CertificateMessage, - CertificateOptions, - CertificateResponse, - TransactionMessage, - TransactionOptions, - TransactionResponse, -} from '../types/requests'; - -class WCWallet implements VechainWallet { - constructor(private readonly signer: WCSigner) {} - - connect = async (): Promise => { - const account = await this.signer.connect(); - - return { - account, - verified: false, - }; - }; - - signCert = ( - msg: CertificateMessage, - options: CertificateOptions, - ): Promise => this.signer.signCert(msg, options); - - signTx = ( - msg: TransactionMessage[], - options: TransactionOptions, - ): Promise => this.signer.signTx(msg, options); - - disconnect = (): Promise => this.signer.disconnect(); -} - -export { WCWallet }; diff --git a/packages/dapp-kit/src/constants/wallet-settings.ts b/packages/dapp-kit/src/constants/wallet-settings.ts index 4bdbc20f..bfbc9b81 100644 --- a/packages/dapp-kit/src/constants/wallet-settings.ts +++ b/packages/dapp-kit/src/constants/wallet-settings.ts @@ -13,6 +13,8 @@ const WalletMapping: Record = { requiresCertificate: false, }, veworld: DEFAULT_CONFIG, + sync2: DEFAULT_CONFIG, + sync: DEFAULT_CONFIG, }; const WalletSources = Object.keys(WalletMapping) as WalletSource[]; diff --git a/packages/dapp-kit/src/dapp-kit.ts b/packages/dapp-kit/src/dapp-kit.ts index 95eb902e..ca214c7c 100644 --- a/packages/dapp-kit/src/dapp-kit.ts +++ b/packages/dapp-kit/src/dapp-kit.ts @@ -15,12 +15,11 @@ class DAppKit { } const { nodeUrl } = options; - const walletManager = new WalletManager(options); this.thor = ThorClient.fromUrl(nodeUrl); - this.wallet = walletManager; + this.wallet = new WalletManager(options, this.thor); this.signer = new VeChainSignerDAppKit( - walletManager, + this.wallet, new VeChainProvider(this.thor), ); } diff --git a/packages/dapp-kit/src/types/types.d.ts b/packages/dapp-kit/src/types/types.d.ts index c08ffded..ff50f49b 100644 --- a/packages/dapp-kit/src/types/types.d.ts +++ b/packages/dapp-kit/src/types/types.d.ts @@ -11,28 +11,21 @@ import type { TransactionResponse, } from './requests'; -interface WalletSigner { - signTx: ( - msg: TransactionMessage[], - options: TransactionOptions, - ) => Promise; - signCert: ( - msg: CertificateMessage, - options: CertificateOptions, - ) => Promise; -} - declare global { interface Window { vechain?: { newConnexSigner: (genesisId: string) => WalletSigner; isInAppBrowser?: boolean; }; - connex?: unknown; + connex?: { + vendor: { + sign: (type: string) => any; + }; + }; } } -type WalletSource = 'wallet-connect' | 'veworld'; +type WalletSource = 'wallet-connect' | 'veworld' | 'sync' | 'sync2'; interface WalletConfig { requiresCertificate: boolean; @@ -52,7 +45,6 @@ type Genesis = 'main' | 'test' | CompressedBlockDetail; */ interface DAppKitOptions { nodeUrl: string; - genesis?: Genesis; walletConnectOptions?: WalletConnectOptions; usePersistence?: boolean; useFirstDetectedSource?: boolean; @@ -64,6 +56,17 @@ interface DAppKitOptions { }; } +interface WalletSigner { + signTx: ( + msg: TransactionMessage[], + options: TransactionOptions, + ) => Promise; + signCert: ( + msg: CertificateMessage, + options: CertificateOptions, + ) => Promise; +} + type BaseWallet = WalletSigner & { disconnect?: () => Promise | void; }; diff --git a/packages/dapp-kit/src/types/wc-types.d.ts b/packages/dapp-kit/src/types/wc-types.d.ts index 552fed5b..8df62919 100644 --- a/packages/dapp-kit/src/types/wc-types.d.ts +++ b/packages/dapp-kit/src/types/wc-types.d.ts @@ -1,6 +1,6 @@ import type { SignClientTypes } from '@walletconnect/types'; import type { SignClient } from '@walletconnect/sign-client'; -import type { WalletSigner } from './types'; +import type { ConnectResponse, WalletSigner } from './types'; export type ResolvedSignClient = Awaited>; @@ -14,15 +14,10 @@ export type WCSigner = WalletSigner & { */ disconnect: () => Promise; - /** - * The genesis ID of the current wallet - */ - genesisId: string; - /** * Connects to the Wallet and return the account address */ - connect: () => Promise; + connect: () => Promise; }; export interface WCClient { @@ -89,5 +84,5 @@ export interface WCSignerOptions { wcClient: WCClient; web3Modal: WCModal; onDisconnected: () => void; - genesisId: string; + genesisId: Promise; } diff --git a/packages/dapp-kit/src/utils/create-sync2.ts b/packages/dapp-kit/src/utils/create-sync2.ts new file mode 100644 index 00000000..41f4fa66 --- /dev/null +++ b/packages/dapp-kit/src/utils/create-sync2.ts @@ -0,0 +1,98 @@ +// eslint-disable-next-line eslint-comments/disable-enable-pair +/* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-return */ +import { Blake2b256, Secp256k1 } from '@vechain/sdk-core'; +import type { + CertificateMessage, + CertificateOptions, + CertificateResponse, + TransactionMessage, + TransactionOptions, + TransactionResponse, +} from '../types'; +import type { WalletSigner } from '../types/types'; + +export type NewSignerFunc = ( + genesisID: Promise, +) => Promise; + +const BUDDY_SRC = 'https://unpkg.com/@vechain/connex-wallet-buddy@0.1'; +const BUDDY_LIB_NAME = 'ConnexWalletBuddy'; + +const cache: Record> = {}; + +const loadLibrary = (src: string, libName: string): Promise => { + let lib = cache[src] as Promise | undefined; + if (!lib) { + const script = document.createElement('script'); + lib = new Promise((resolve, reject) => { + script.onload = () => resolve((window as never)[libName]); + script.onerror = (err) => reject(new Error(err.toString())); + }); + cache[src] = lib; + script.src = src; + document.body.appendChild(script); + } + return lib; +}; + +export const createSync2: NewSignerFunc = async (genesisID) => { + const genesis = await genesisID; + return loadLibrary(BUDDY_SRC, BUDDY_LIB_NAME).then((lib: any) => { + return lib.create( + genesis, + Buffer.from(Secp256k1.randomBytes(16)) + .toString('hex') + .replace('0x', ''), + (val: string | Uint8Array) => + Blake2b256.of(val).toString().replace('0x', ''), + ); + }); +}; + +export const createSync: NewSignerFunc = async () => { + if (!window.connex) { + throw new Error('Connex is not available'); + } + const v1 = window.connex.vendor; + return Promise.resolve({ + signTx: ( + msg: TransactionMessage[], + options: TransactionOptions = {}, + ): Promise => { + const s1 = v1.sign('tx'); + options.signer && s1.signer(options.signer); + options.gas && s1.gas(options.gas); + options.dependsOn && s1.dependsOn(options.dependsOn); + options.link && s1.link(options.link); + options.comment && s1.link(options.comment); + if (options.delegator) { + const url = options.delegator.url; + s1.delegate(async (unsignedTx: any) => { + const res = await fetch(url, { + method: 'POST', + body: JSON.stringify(unsignedTx), + headers: { + 'Content-Type': 'application/json', + }, + }); + + return res.json(); + }); + } + options.onAccepted?.(); + + return s1.request(msg); + }, + signCert: ( + msg: CertificateMessage, + options: CertificateOptions = {}, + ): Promise => { + const s1 = v1.sign('cert'); + options.signer && s1.signer(options.signer); + options.link && s1.link(options.link); + options.onAccepted?.(); + + return s1.request(msg); + }, + }); +}; diff --git a/packages/dapp-kit/src/utils/create-wallet.ts b/packages/dapp-kit/src/utils/create-wallet.ts index 6fe3f8d5..748cb9bd 100644 --- a/packages/dapp-kit/src/utils/create-wallet.ts +++ b/packages/dapp-kit/src/utils/create-wallet.ts @@ -1,3 +1,4 @@ +import type { ThorClient } from '@vechain/sdk-network'; import type { DAppKitOptions, VechainWallet, @@ -6,36 +7,65 @@ import type { WCModal, } from '../types'; import { CertificateBasedWallet } from '../classes/certificate-wallet'; -import { WCWallet } from '../classes/wc-wallet'; +import type { WalletSigner } from '../types/types'; import { createWcClient } from './create-wc-client'; import { createWcModal } from './create-wc-modal'; import { createWcSigner } from './create-wc-signer'; -import { normalizeGenesisId } from './genesis'; import { DAppKitLogger } from './logger'; +import { createSync, createSync2 } from './create-sync2'; type ICreateWallet = DAppKitOptions & { source: WalletSource; onDisconnected: () => void; + thor: ThorClient; }; export const createWallet = ({ source, - genesis, + thor, walletConnectOptions, onDisconnected, connectionCertificate, }: ICreateWallet): VechainWallet => { - const genesisId = normalizeGenesisId(genesis); - DAppKitLogger.debug('createWallet', source); + const genesisId = thor.blocks.getGenesisBlock().then((block) => { + if (!block) { + throw new Error('Failed to get genesis block'); + } + return block.id; + }); + switch (source) { + case 'sync': { + if (!window.connex) { + throw new Error('Connex is not available'); + } + + const signer = createSync(genesisId); + return new CertificateBasedWallet(signer, connectionCertificate); + } + case 'sync2': { + const signer = createSync2(genesisId); + return new CertificateBasedWallet(signer, connectionCertificate); + } case 'veworld': { if (!window.vechain) { throw new Error('VeWorld Extension is not installed'); } - const signer = window.vechain.newConnexSigner(genesisId); + const signer: Promise = genesisId + .then((genesis) => { + if (!window.vechain) { + throw new Error('VeWorld Extension is not installed'); + } + + return window.vechain.newConnexSigner(genesis); + }) + .catch((e) => { + DAppKitLogger.error('createWallet', 'veworld', e); + throw e; + }); return new CertificateBasedWallet(signer, connectionCertificate); } @@ -53,14 +83,12 @@ export const createWallet = ({ const web3Modal: WCModal = modal ?? createWcModal(projectId); - const wallet = createWcSigner({ + return createWcSigner({ genesisId, wcClient, web3Modal, onDisconnected, }); - - return new WCWallet(wallet); } } }; diff --git a/packages/dapp-kit/src/utils/create-wc-signer.ts b/packages/dapp-kit/src/utils/create-wc-signer.ts index ba5d2e95..e0251f30 100644 --- a/packages/dapp-kit/src/utils/create-wc-signer.ts +++ b/packages/dapp-kit/src/utils/create-wc-signer.ts @@ -5,16 +5,18 @@ import type { } from '@walletconnect/types'; import { getSdkError } from '@walletconnect/utils'; import type { SignClient } from '@walletconnect/sign-client/dist/types/client'; -import type { WCSigner, WCSignerOptions } from '../types'; import { DefaultMethods } from '../constants'; import type { CertificateMessage, CertificateOptions, CertificateResponse, + ConnectResponse, TransactionMessage, TransactionOptions, TransactionResponse, -} from '../types/requests'; + WCSigner, + WCSignerOptions, +} from '../types'; import { DAppKitLogger } from './logger'; interface SessionAccount { @@ -24,8 +26,8 @@ interface SessionAccount { } /** - * Creates a new WalletConnect wallet - * @param options - The wallet options. See {@link WCSignerOptions} + * Creates a new WalletConnect signer + * @param options - The signer options. See {@link WCSignerOptions} * @returns A new {@link WCSigner} */ export const createWcSigner = ({ @@ -34,14 +36,19 @@ export const createWcSigner = ({ web3Modal, onDisconnected, }: WCSignerOptions): WCSigner => { - const chainId = `vechain:${genesisId.slice(-32)}`; + const chainId = genesisId.then((id) => { + return `vechain:${id.slice(-32)}`; + }); + let session: SessionTypes.Struct | undefined; wcClient .get() .then((clientInstance) => { listenToEvents(clientInstance); - restoreSession(clientInstance); + restoreSession(clientInstance).catch((e) => { + throw e; + }); }) .catch(() => { throw new Error(`Failed to get the wallet connect sign client`); @@ -50,7 +57,7 @@ export const createWcSigner = ({ // listen for session updates const listenToEvents = (_client: SignClient): void => { _client.on('session_update', ({ topic, params }): void => { - DAppKitLogger.debug('wallet connect wallet', 'session_update', { + DAppKitLogger.debug('wallet connect signer', 'session_update', { topic, params, }); @@ -68,18 +75,20 @@ export const createWcSigner = ({ }; // restore a session if undefined - const restoreSession = (_client: SignClient): void => { + const restoreSession = async (_client: SignClient): Promise => { if (typeof session !== 'undefined') return; - DAppKitLogger.debug('wallet connect wallet', 'restore session'); + DAppKitLogger.debug('wallet connect signer', 'restore session'); const sessionKeys = _client.session.keys; + const _genesisId = await genesisId; + for (const key of sessionKeys) { const _session = _client.session.get(key); const accounts = _session.namespaces.vechain.accounts; for (const acc of accounts) { - if (acc.split(':')[1] === genesisId.slice(-32)) { + if (acc.split(':')[1] === _genesisId.slice(-32)) { session = _session; return; } @@ -91,11 +100,11 @@ export const createWcSigner = ({ * Validates the requested account and network against a request * @param requestedAddress - The optional requested account address */ - const validateSession = ( + const validateSession = async ( requestedAddress?: string, - ): SessionAccount | undefined => { + ): Promise => { if (!session) return; - DAppKitLogger.debug('wallet connect wallet', 'validate session'); + DAppKitLogger.debug('wallet connect signer', 'validate session'); const firstAccount = session.namespaces.vechain.accounts[0]; @@ -103,7 +112,7 @@ export const createWcSigner = ({ const networkIdentifier = firstAccount.split(':')[1]; // Return undefined if the network identifier doesn't match - if (networkIdentifier !== genesisId.slice(-32)) return; + if (networkIdentifier !== (await genesisId).slice(-32)) return; // Return undefined if the address doesn't match if ( @@ -120,12 +129,12 @@ export const createWcSigner = ({ }; const connect = async (): Promise => { - DAppKitLogger.debug('wallet connect wallet', 'connect'); + DAppKitLogger.debug('wallet connect signer', 'connect'); const signClient = await wcClient.get(); const namespace: ProposalTypes.RequiredNamespace = { methods: Object.values(DefaultMethods), - chains: [chainId], + chains: [await chainId], events: [], }; @@ -172,7 +181,7 @@ export const createWcSigner = ({ const getSessionTopic = async ( requestedAccount?: string, ): Promise => { - const validation = validateSession(requestedAccount); + const validation = await validateSession(requestedAccount); if (validation) return validation.topic; @@ -191,14 +200,14 @@ export const createWcSigner = ({ return signClient.request({ topic: sessionTopic, - chainId, + chainId: await chainId, request: params, }); }; const signTx = async ( message: TransactionMessage[], - options: TransactionOptions, + options: TransactionOptions = {}, ): Promise => { return makeRequest({ method: DefaultMethods.RequestTransaction, @@ -208,7 +217,7 @@ export const createWcSigner = ({ const signCert = async ( message: CertificateMessage, - options: CertificateOptions, + options: CertificateOptions = {}, ): Promise => { return makeRequest({ method: DefaultMethods.SignCertificate, @@ -234,7 +243,7 @@ export const createWcSigner = ({ } }; - const connectAccount = async (): Promise => { + const connectAccount = async (): Promise => { if (!session) { session = await connect(); } @@ -251,9 +260,14 @@ export const createWcSigner = ({ const firstAccount = vechainNamespace.accounts[0]; try { - return firstAccount.split(':')[2]; + return { + account: firstAccount.split(':')[2], + verified: false, + }; } catch (e) { - throw new Error('Failed to get account from session'); + throw new Error( + 'Failed to get account from wallet connect session', + ); } }; @@ -261,7 +275,6 @@ export const createWcSigner = ({ signTx, signCert, disconnect, - genesisId, connect: connectAccount, }; }; diff --git a/packages/dapp-kit/test/create-wallet.test.ts b/packages/dapp-kit/test/create-wallet.test.ts index e1fa3cd4..20d6343b 100644 --- a/packages/dapp-kit/test/create-wallet.test.ts +++ b/packages/dapp-kit/test/create-wallet.test.ts @@ -6,11 +6,14 @@ import type { WalletSource, } from '../src'; import { WalletSigner } from '../src/types/types'; +import { ThorClient } from '@vechain/sdk-network'; type ICreateWallet = DAppKitOptions & { source: WalletSource; onDisconnected: () => void; + thor: ThorClient; }; + const createOptions = ( source: WalletSource, wcOptions?: WalletConnectOptions, @@ -19,8 +22,8 @@ const createOptions = ( nodeUrl: 'https://testnet.veblocks.net/', source, walletConnectOptions: wcOptions, - genesis: 'main', onDisconnected: () => {}, + thor: ThorClient.fromUrl('https://testnet.vechain.org'), }; }; diff --git a/packages/dapp-kit/test/utils/signer.test.ts b/packages/dapp-kit/test/utils/signer.test.ts index 70707b07..02d1a22b 100644 --- a/packages/dapp-kit/test/utils/signer.test.ts +++ b/packages/dapp-kit/test/utils/signer.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it, vi } from 'vitest'; import { SignClient } from '@walletconnect/sign-client'; import type { SignClientTypes } from '@walletconnect/types'; import type { WCModal, WCSigner } from '../../src'; -import { createWcClient, createWcSigner, normalizeGenesisId } from '../../src'; +import { createWcClient, createWcSigner } from '../../src'; import { mockedSignClient } from '../helpers/mocked-sign-client'; import { address } from '../helpers/mocked-signer'; @@ -26,7 +26,7 @@ const customModal: WCModal = { const createNewSignClient = (): WCSigner => createWcSigner({ - genesisId: normalizeGenesisId('main'), + genesisId: Promise.resolve('main'), wcClient: createWcClient({ projectId, metadata }), onDisconnected: () => { console.log('disconnected'); @@ -40,7 +40,9 @@ describe('createWcSigner', () => { const res = await signer.connect(); - expect(res.toLowerCase()).toBe(address.toString().toLowerCase()); + expect(res.account.toLowerCase()).toBe( + address.toString().toLowerCase(), + ); }); it('can connect before signing TX', async () => { diff --git a/packages/dapp-kit/test/wallet-manager.test.ts b/packages/dapp-kit/test/wallet-manager.test.ts index 0b8e29f8..e1f65b87 100644 --- a/packages/dapp-kit/test/wallet-manager.test.ts +++ b/packages/dapp-kit/test/wallet-manager.test.ts @@ -2,13 +2,16 @@ import { describe, expect, it, vi } from 'vitest'; import type { WalletConnectOptions } from '../src'; import { WalletManager } from '../src'; import { mockedConnexSigner } from './helpers/mocked-signer'; +import { ThorClient } from '@vechain/sdk-network'; const newWalletManager = (wcOptions?: WalletConnectOptions): WalletManager => { - return new WalletManager({ - nodeUrl: 'https://testnet.veblocks.net/', - walletConnectOptions: wcOptions, - genesis: 'main', - }); + return new WalletManager( + { + nodeUrl: 'https://testnet.veblocks.net/', + walletConnectOptions: wcOptions, + }, + ThorClient.fromUrl('https://testnet.vechain.org'), + ); }; window.vechain = { @@ -34,10 +37,7 @@ describe('WalletManager', () => { describe('connect', () => { it('no source set', async () => { const walletManager = newWalletManager(); - const res = await walletManager.connect(); - expect(res.account).toBe( - '0xf077b491b355E64048cE21E3A6Fc4751eEeA77fa', - ); + expect(() => walletManager.connect()).throws(); }); });