From 4ea8c2dfa5c39cbe8464c85deed62bdf552610ed Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 2 Feb 2026 22:53:12 +0300 Subject: [PATCH 01/32] feat: added wallet connect integration via api --- package.json | 6 +- packages/wallets/package.json | 3 +- packages/wallets/src/wallet.page.ts | 7 + packages/wallets/src/walletConnect/index.ts | 0 .../wallets/src/walletConnect/wc.service.ts | 358 ++++++++++++ packages/wallets/src/wallets.constants.ts | 21 + yarn.lock | 514 +++++++++++++++++- 7 files changed, 894 insertions(+), 15 deletions(-) create mode 100644 packages/wallets/src/walletConnect/index.ts create mode 100644 packages/wallets/src/walletConnect/wc.service.ts diff --git a/package.json b/package.json index 46b4c3ea..013e18dd 100644 --- a/package.json +++ b/package.json @@ -41,9 +41,9 @@ "branches": [ "main", { - "name": "develop", - "channel": "alpha", - "prerelease": "alpha" + "name": "feat/add-wc-wallet", + "channel": "alpha-add-wc-wallet", + "prerelease": "alpha-add-wc-wallet" } ] } diff --git a/packages/wallets/package.json b/packages/wallets/package.json index 1f405d39..a07fdc57 100644 --- a/packages/wallets/package.json +++ b/packages/wallets/package.json @@ -29,6 +29,7 @@ "access": "public" }, "dependencies": { + "@walletconnect/sign-client": "2.23.4", "big.js": "^6.2.1", "expect": "^28.1.3", "reflect-metadata": "^0.1.13", @@ -38,4 +39,4 @@ "peerDependencies": { "@playwright/test": "^1.51.1" } -} +} \ No newline at end of file diff --git a/packages/wallets/src/wallet.page.ts b/packages/wallets/src/wallet.page.ts index d7c0d11f..8b76647f 100644 --- a/packages/wallets/src/wallet.page.ts +++ b/packages/wallets/src/wallet.page.ts @@ -7,6 +7,7 @@ import { WalletConnectType, WalletConnectTypes, } from './wallets.constants'; +import { WCSessionRequest } from './walletConnect/wc.service'; /** Required options to manage wallet */ export interface WalletPageOptions { @@ -56,8 +57,14 @@ export interface WalletPage { assertTxAmount(page: Page, expectedAmount: string): Promise; + confirmTx(req: WCSessionRequest): Promise; confirmTx(page: Page, setAggressiveGas?: boolean): Promise; + cancelTx( + req: WCSessionRequest, + message?: string, + code?: number, + ): Promise; cancelTx(page: Page): Promise; approveTokenTx?(page: Page): Promise; diff --git a/packages/wallets/src/walletConnect/index.ts b/packages/wallets/src/walletConnect/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts new file mode 100644 index 00000000..8834cc18 --- /dev/null +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -0,0 +1,358 @@ +import SignClient from '@walletconnect/sign-client'; +import { createPublicClient, createWalletClient, HDAccount, http } from 'viem'; +import { mainnet } from 'viem/chains'; +import { WalletPage, WalletPageOptions } from '../wallet.page'; +import { + NetworkConfig, + WalletConnectTypes, + WCApproveNamespaces, +} from '../wallets.constants'; +import { Page } from '@playwright/test'; +import { mnemonicToAccount } from 'viem/accounts'; + +export type WCSessionRequest = { + topic: string; + id: number; + params: { + chainId: string; + request: { + method: string; + params: any[]; + }; + }; +}; + +export class WCTestWallet implements WalletPage { + private client?: SignClient; + // @ts-error TS2564: Property 'walletClient' has no initializer and is not definitely assigned in the constructor. + private walletClient?: ReturnType; + private publicClient?: ReturnType; + private hdAccount: HDAccount; + + private requestQueue: WCSessionRequest[] = []; + private waiters: Array<(req: WCSessionRequest) => void> = []; + page?: Page; // not used for WC wallet but required by interface + + constructor(public options: WalletPageOptions) { + this.hdAccount = mnemonicToAccount( + this.options.accountConfig.SECRET_PHRASE, + ); + + this.options.walletConfig.walletConnectConfig = { + requestHandleTimeoutMs: 30_000, + metadata: { + name: 'E2E Test Wallet', + description: 'WalletConnect test wallet for e2e', + url: 'https://example.wallet', + icons: ['https://example.wallet/icon.png'], + }, + namespaces: { + eip155: { + accounts: [ + `eip155:${this.options.standConfig.chainId}:${this.hdAccount.address}`, + ], + methods: [ + 'eth_sendTransaction', + 'personal_sign', + 'eth_signTypedData_v4', + 'wallet_switchEthereumChain', + 'wallet_addEthereumChain', + ], + events: ['accountsChanged', 'chainChanged'], + }, + }, + ...options.walletConfig?.walletConnectConfig, + }; + } + + async setup(): Promise { + if (this.client) return; + + this.client = await SignClient.init({ + projectId: this.options.walletConfig.walletConnectConfig.projectId, + metadata: this.options.walletConfig.walletConnectConfig.metadata, + }); + + this.walletClient = createWalletClient({ + account: this.hdAccount, + chain: mainnet, + transport: http(this.options.standConfig.rpcUrl), + }); + + this.publicClient = createPublicClient({ + chain: mainnet, + transport: http(this.options.standConfig.rpcUrl), + }); + // Collect incoming requests into an async queue + this.client.on('session_request', (event) => { + const req = event as unknown as WCSessionRequest; + console.log(`WC: session_request received: ${req.params.request.method}`); + const waiter = this.waiters.shift(); + if (waiter) waiter(req); + else this.requestQueue.push(req); + }); + } + + async connectWallet(uri: string): Promise { + await this.setup(); + if (!this.client) throw new Error('WC client not initialized'); + + const [proposal] = await Promise.all([ + this.waitForProposalOnce( + this.options.walletConfig.walletConnectConfig.requestHandleTimeoutMs || + 30000, + ), + this.client.core.pairing.pair({ uri }), + ]); + const { id, params } = proposal; + + const namespaces = + this.options.walletConfig.walletConnectConfig.namespaces ?? + this.buildNamespacesFromProposal(params); + + const { acknowledged } = await this.client.approve({ id, namespaces }); + await acknowledged(); + } + + async disconnect(): Promise { + if (!this.client) throw new Error('WC client not initialized'); + + const sessions = this.client.session.getAll(); + for (const sess of sessions) { + console.log('WC: disconnecting session', sess.topic); + await this.client.disconnect({ + topic: sess.topic, + reason: { + code: 6000, + message: 'Session disconnected by test wallet', + }, + }); + } + await this.client.core.relayer.transportClose(); + this.client = undefined; + this.requestQueue = []; + this.waiters = []; + } + + async nextRequest( + timeoutMs = this.options.walletConfig.walletConnectConfig + .requestHandleTimeoutMs, + ): Promise { + const queued = this.requestQueue.shift(); + if (queued) return queued; + + return await new Promise((resolve, reject) => { + const t = setTimeout(() => { + const idx = this.waiters.indexOf(resolve); + if (idx >= 0) this.waiters.splice(idx, 1); + reject(new Error(`WC: session_request timeout after ${timeoutMs}ms`)); + }, timeoutMs); + + this.waiters.push((req) => { + clearTimeout(t); + resolve(req); + }); + }); + } + + isWCSessionRequest(x: any): x is WCSessionRequest { + return ( + x && typeof x === 'object' && 'topic' in x && 'id' in x && 'params' in x + ); + } + + async confirmTx(req: WCSessionRequest | Page): Promise { + if (!this.isWCSessionRequest(req)) { + throw new Error( + 'WC: confirmTx with Page parameter is not supported in WC wallet', + ); + } + + if (!this.client) throw new Error('WC client not initialized'); + + const method = req.params.request.method; + if (method === 'eth_sendTransaction') { + const fees = await this.publicClient.estimateFeesPerGas(); + const value = req.params.request.params[0].value + ? BigInt(req.params.request.params[0].value) + : undefined; + const hash = await this.walletClient.sendTransaction({ + ...req.params.request.params[0], + value, + gas: BigInt(req.params.request.params[0].gas), + maxFeePerGas: fees.maxFeePerGas, + maxPriorityFeePerGas: fees.maxPriorityFeePerGas, + }); + + await this.client.respond({ + topic: req.topic, + response: { id: req.id, jsonrpc: '2.0', result: hash }, + }); + } else if (method === 'eth_signTypedData_v4') { + const typed = req.params.request.params[1]; + const typedData = typeof typed === 'string' ? JSON.parse(typed) : typed; + + const signature = await this.walletClient.signTypedData({ + account: this.hdAccount, + domain: { + ...typedData.domain, + chainId: Number(typedData.domain.chainId), + }, + types: typedData.types, + primaryType: typedData.primaryType, + message: { + ...typedData.message, + value: BigInt(typedData.message.value), + nonce: BigInt(typedData.message.nonce), + deadline: BigInt(typedData.message.deadline), + }, + }); + console.log('Signature was created.'); + + await this.client.respond({ + topic: req.topic, + response: { id: req.id, jsonrpc: '2.0', result: signature }, + }); + } else { + throw new Error(`WC: approveRequest unsupported method: ${method}`); + } + } + + async cancelTx( + req: WCSessionRequest | Page, + message = 'User rejected the request', + code = 4001, + ): Promise { + if (!this.isWCSessionRequest(req)) { + throw new Error( + 'WC: confirmTx with Page parameter is not supported in WC wallet', + ); + } + if (!this.client) throw new Error('WC client not initialized'); + + await this.client.respond({ + topic: req.topic, + response: { + id: req.id, + jsonrpc: '2.0', + error: { code, message }, + }, + }); + } + + getTx(req: WCSessionRequest, index = 0): any { + return req.params?.request?.params?.[index]; + } + + private async waitForProposalOnce(timeoutMs: number) { + if (!this.client) throw new Error('WC client not initialized'); + + return await new Promise((resolve, reject) => { + const t = setTimeout( + () => + reject( + new Error(`WC: session_proposal timeout after ${timeoutMs}ms`), + ), + timeoutMs, + ); + + this.client.once('session_proposal', (proposal) => { + clearTimeout(t); + resolve(proposal); + }); + }); + } + + private buildNamespacesFromProposal(params: any): WCApproveNamespaces { + const required = params?.requiredNamespaces ?? {}; + const eip155 = required?.eip155; + + if (!eip155) { + throw new Error(`WC: requiredNamespaces.eip155 missing in proposal`); + } + + const chains: string[] = eip155.chains ?? []; + const methods: string[] = eip155.methods ?? []; + const events: string[] = eip155.events ?? []; + + // If dApp didn't specify chains (rare), you must provide at least one. + if (!chains.length) { + throw new Error( + `WC: proposal has no chains in requiredNamespaces.eip155`, + ); + } + + const accounts = ( + this.options.walletConfig.walletConnectConfig.namespaces?.eip155 + ?.accounts ?? [] + ).length + ? this.options.walletConfig.walletConnectConfig.namespaces.eip155.accounts + : []; + + if (!accounts.length) { + throw new Error( + `WC: cannot auto-build accounts. Pass namespaces with accounts (e.g. eip155:1:0x...).`, + ); + } + + return { + eip155: { + accounts, + methods, + events, + }, + }; + } + + importKey(secretKey: string, withChecks?: boolean): Promise { + throw new Error('Method not implemented.'); + } + assertTxAmount(page: Page, expectedAmount: string): Promise { + throw new Error('Method not implemented.'); + } + approveTokenTx?(page: Page): Promise { + throw new Error('Method not implemented.'); + } + openLastTxInEthplorer?(txIndex?: number): Promise { + throw new Error('Method not implemented.'); + } + getTokenBalance?(tokenName: string): Promise { + throw new Error('Method not implemented.'); + } + confirmAddTokenToWallet?(page: Page): Promise { + throw new Error('Method not implemented.'); + } + assertReceiptAddress(page: Page, expectedAddress: string): Promise { + throw new Error('Method not implemented.'); + } + getWalletAddress?(): Promise { + throw new Error('Method not implemented.'); + } + setupNetwork?(networkConfig: NetworkConfig): Promise { + throw new Error('Method not implemented.'); + } + addNetwork( + networkConfig: NetworkConfig, + isClosePage?: boolean, + ): Promise { + throw new Error('Method not implemented.'); + } + changeNetwork?(networkName: string): Promise { + throw new Error('Method not implemented.'); + } + changeWalletAccountByName?( + accountName: string, + isClosePage?: boolean, + ): Promise { + throw new Error('Method not implemented.'); + } + changeWalletAccountByAddress?( + address: string, + isClosePage?: boolean, + ): Promise { + throw new Error('Method not implemented.'); + } + isWalletAddressExist?(address: string): Promise { + throw new Error('Method not implemented.'); + } +} diff --git a/packages/wallets/src/wallets.constants.ts b/packages/wallets/src/wallets.constants.ts index d1edfa4b..1d6cdecb 100644 --- a/packages/wallets/src/wallets.constants.ts +++ b/packages/wallets/src/wallets.constants.ts @@ -1,3 +1,12 @@ +export type WCApproveNamespaces = Record< + string, + { + accounts: string[]; + methods: string[]; + events: string[]; + } +>; + export interface CommonWalletConfig { WALLET_NAME: string; // Name of the wallet being tested EXTENSION_WALLET_NAME: string; // Wallet name for install extension @@ -7,6 +16,18 @@ export interface CommonWalletConfig { WALLET_TYPE: WalletConnectType; LATEST_STABLE_DOWNLOAD_LINK?: string; // Link to stable wallet extension version for test (optional) EXTENSION_START_PATH: string; // Start path for wallet setup + // Only for WalletConnect wallets via API @walletconnect/sign-client + walletConnectConfig?: { + projectId: string; + metadata?: { + name: string; + description: string; + url: string; + icons: string[]; + }; + namespaces?: WCApproveNamespaces; + requestHandleTimeoutMs?: number; + }; } export enum WalletConnectTypes { diff --git a/yarn.lock b/yarn.lock index 8fe8e4e3..837278fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,6 +12,11 @@ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz#42cc67c5baa407ac25059fcd7d405cc5ecdb0c33" integrity sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg== +"@adraffy/ens-normalize@^1.11.0": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz#6c2d657d4b2dfb37f8ea811dcb3e60843d4ac24a" + integrity sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ== + "@ampproject/remapping@^2.2.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" @@ -1253,6 +1258,11 @@ resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe" integrity sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA== +"@msgpack/msgpack@3.1.3": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@msgpack/msgpack/-/msgpack-3.1.3.tgz#c4bff2b9539faf0882f3ee03537a7e9a4b3a7864" + integrity sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA== + "@nestjs/cli@^10.0.0": version "10.4.9" resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-10.4.9.tgz#ac3a23096a4725465360d8d60810f3e857f4a803" @@ -1298,11 +1308,18 @@ jsonc-parser "3.3.1" pluralize "8.0.0" -"@noble/ciphers@^1.3.0": +"@noble/ciphers@1.3.0", "@noble/ciphers@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-1.3.0.tgz#f64b8ff886c240e644e5573c097f86e5b43676dc" integrity sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw== +"@noble/curves@1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.0.tgz#fe035a23959e6aeadf695851b51a87465b5ba8f7" + integrity sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ== + dependencies: + "@noble/hashes" "1.7.0" + "@noble/curves@1.8.2", "@noble/curves@~1.8.1": version "1.8.2" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.2.tgz#8f24c037795e22b90ae29e222a856294c1d9ffc7" @@ -1317,6 +1334,13 @@ dependencies: "@noble/hashes" "1.8.0" +"@noble/curves@1.9.7": + version "1.9.7" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.7.tgz#79d04b4758a43e4bca2cbdc62e7771352fa6b951" + integrity sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw== + dependencies: + "@noble/hashes" "1.8.0" + "@noble/curves@^1.6.0", "@noble/curves@~1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.0.tgz#13e0ca8be4a0ce66c113693a94514e5599f40cfc" @@ -1324,12 +1348,17 @@ dependencies: "@noble/hashes" "1.8.0" +"@noble/hashes@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.0.tgz#5d9e33af2c7d04fee35de1519b80c958b2e35e39" + integrity sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w== + "@noble/hashes@1.7.2", "@noble/hashes@~1.7.1": version "1.7.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.2.tgz#d53c65a21658fb02f3303e7ee3ba89d6754c64b4" integrity sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ== -"@noble/hashes@1.8.0", "@noble/hashes@^1.1.5", "@noble/hashes@^1.5.0", "@noble/hashes@~1.8.0": +"@noble/hashes@1.8.0", "@noble/hashes@^1.1.5", "@noble/hashes@^1.5.0", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": version "1.8.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== @@ -1703,6 +1732,11 @@ signale "^1.4.0" stream-buffers "^3.0.2" +"@scure/base@1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.6.tgz#ca917184b8231394dd8847509c67a0be522e59f6" + integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== + "@scure/base@~1.2.2", "@scure/base@~1.2.4", "@scure/base@~1.2.5": version "1.2.5" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.5.tgz#f9d1b232425b367d0dcb81c96611dcc651d58671" @@ -1717,7 +1751,7 @@ "@noble/hashes" "~1.7.1" "@scure/base" "~1.2.2" -"@scure/bip32@1.7.0", "@scure/bip32@^1.5.0": +"@scure/bip32@1.7.0", "@scure/bip32@^1.5.0", "@scure/bip32@^1.7.0": version "1.7.0" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.7.0.tgz#b8683bab172369f988f1589640e53c4606984219" integrity sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== @@ -1734,7 +1768,7 @@ "@noble/hashes" "~1.7.1" "@scure/base" "~1.2.4" -"@scure/bip39@1.6.0", "@scure/bip39@^1.4.0": +"@scure/bip39@1.6.0", "@scure/bip39@^1.4.0", "@scure/bip39@^1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.6.0.tgz#475970ace440d7be87a6086cbee77cb8f1a684f9" integrity sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A== @@ -2301,6 +2335,206 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== +"@walletconnect/core@2.23.4": + version "2.23.4" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.23.4.tgz#f51cad2749cf3141d95372011830559ea9381a45" + integrity sha512-qkzNvRfibl+r2GoPqKl+2MJLYA7ApEWyCmECJoK6IExeWyjKawAUC6Eo4cN0geCBefk9VSFRFEIVQ17vYWp0jQ== + dependencies: + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-provider" "1.0.14" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/jsonrpc-ws-connection" "1.0.16" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "3.0.2" + "@walletconnect/relay-api" "1.0.11" + "@walletconnect/relay-auth" "1.1.0" + "@walletconnect/safe-json" "1.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.23.4" + "@walletconnect/utils" "2.23.4" + "@walletconnect/window-getters" "1.0.1" + es-toolkit "1.44.0" + events "3.3.0" + uint8arrays "3.1.1" + +"@walletconnect/environment@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@walletconnect/environment/-/environment-1.0.1.tgz#1d7f82f0009ab821a2ba5ad5e5a7b8ae3b214cd7" + integrity sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg== + dependencies: + tslib "1.14.1" + +"@walletconnect/events@1.0.1", "@walletconnect/events@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@walletconnect/events/-/events-1.0.1.tgz#2b5f9c7202019e229d7ccae1369a9e86bda7816c" + integrity sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ== + dependencies: + keyvaluestorage-interface "^1.0.0" + tslib "1.14.1" + +"@walletconnect/heartbeat@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@walletconnect/heartbeat/-/heartbeat-1.2.2.tgz#e8dc5179db7769950c6f9cf59b23516d9b95227d" + integrity sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw== + dependencies: + "@walletconnect/events" "^1.0.1" + "@walletconnect/time" "^1.0.2" + events "^3.3.0" + +"@walletconnect/jsonrpc-provider@1.0.14": + version "1.0.14" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.14.tgz#696f3e3b6d728b361f2e8b853cfc6afbdf2e4e3e" + integrity sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow== + dependencies: + "@walletconnect/jsonrpc-utils" "^1.0.8" + "@walletconnect/safe-json" "^1.0.2" + events "^3.3.0" + +"@walletconnect/jsonrpc-types@1.0.4", "@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz#ce1a667d79eadf2a2d9d002c152ceb68739c230c" + integrity sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ== + dependencies: + events "^3.3.0" + keyvaluestorage-interface "^1.0.0" + +"@walletconnect/jsonrpc-utils@1.0.8", "@walletconnect/jsonrpc-utils@^1.0.6", "@walletconnect/jsonrpc-utils@^1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz#82d0cc6a5d6ff0ecc277cb35f71402c91ad48d72" + integrity sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw== + dependencies: + "@walletconnect/environment" "^1.0.1" + "@walletconnect/jsonrpc-types" "^1.0.3" + tslib "1.14.1" + +"@walletconnect/jsonrpc-ws-connection@1.0.16": + version "1.0.16" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.16.tgz#666bb13fbf32a2d4f7912d5b4d0bdef26a1d057b" + integrity sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q== + dependencies: + "@walletconnect/jsonrpc-utils" "^1.0.6" + "@walletconnect/safe-json" "^1.0.2" + events "^3.3.0" + ws "^7.5.1" + +"@walletconnect/keyvaluestorage@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz#dd2caddabfbaf80f6b8993a0704d8b83115a1842" + integrity sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA== + dependencies: + "@walletconnect/safe-json" "^1.0.1" + idb-keyval "^6.2.1" + unstorage "^1.9.0" + +"@walletconnect/logger@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@walletconnect/logger/-/logger-3.0.2.tgz#dab84d27ff32687f60c7bbe4d2e930c7460ddf2b" + integrity sha512-7wR3wAwJTOmX4gbcUZcFMov8fjftY05+5cO/d4cpDD8wDzJ+cIlKdYOXaXfxHLSYeDazMXIsxMYjHYVDfkx+nA== + dependencies: + "@walletconnect/safe-json" "^1.0.2" + pino "10.0.0" + +"@walletconnect/relay-api@1.0.11": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@walletconnect/relay-api/-/relay-api-1.0.11.tgz#80ab7ef2e83c6c173be1a59756f95e515fb63224" + integrity sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q== + dependencies: + "@walletconnect/jsonrpc-types" "^1.0.2" + +"@walletconnect/relay-auth@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@walletconnect/relay-auth/-/relay-auth-1.1.0.tgz#c3c5f54abd44a5138ea7d4fe77970597ba66c077" + integrity sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ== + dependencies: + "@noble/curves" "1.8.0" + "@noble/hashes" "1.7.0" + "@walletconnect/safe-json" "^1.0.1" + "@walletconnect/time" "^1.0.2" + uint8arrays "^3.0.0" + +"@walletconnect/safe-json@1.0.2", "@walletconnect/safe-json@^1.0.1", "@walletconnect/safe-json@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.2.tgz#7237e5ca48046e4476154e503c6d3c914126fa77" + integrity sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA== + dependencies: + tslib "1.14.1" + +"@walletconnect/sign-client@2.23.4": + version "2.23.4" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.23.4.tgz#d10bf3718c83e5b73158a0f2e05ee0ce86dab101" + integrity sha512-Q3hM8YmO+RHdT3R0MWyRBmekK5SNwpeheQQ+rWbu2dZFm9NyqfxJqwr6ZEhrZltFGTzCHrajTaFPrQnMb/LxuA== + dependencies: + "@walletconnect/core" "2.23.4" + "@walletconnect/events" "1.0.1" + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/logger" "3.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.23.4" + "@walletconnect/utils" "2.23.4" + events "3.3.0" + +"@walletconnect/time@1.0.2", "@walletconnect/time@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@walletconnect/time/-/time-1.0.2.tgz#6c5888b835750ecb4299d28eecc5e72c6d336523" + integrity sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g== + dependencies: + tslib "1.14.1" + +"@walletconnect/types@2.23.4": + version "2.23.4" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.23.4.tgz#6b08a47fb9efa54a6cda9b88762798966dad94eb" + integrity sha512-6M+9JEXbZdnvdPc4tleXOFTV9al1brKojBpL5uzNCbzCxqvq273wWtW/eqPgTqH7BJam1nDVK8D02o63ECIooQ== + dependencies: + "@walletconnect/events" "1.0.1" + "@walletconnect/heartbeat" "1.2.2" + "@walletconnect/jsonrpc-types" "1.0.4" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "3.0.2" + events "3.3.0" + +"@walletconnect/utils@2.23.4": + version "2.23.4" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.23.4.tgz#d6bc935991d32f7b048356af57a863f97f6e227a" + integrity sha512-J2QTS1rga3/FE+REJUAk1HNnZZ2ubAA3VRZehsT3bfOn+OzT2+skQXVzU6ZFaiwPWsLtIOF3aSodZoc5bUrLyw== + dependencies: + "@msgpack/msgpack" "3.1.3" + "@noble/ciphers" "1.3.0" + "@noble/curves" "1.9.7" + "@noble/hashes" "1.8.0" + "@scure/base" "1.2.6" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/keyvaluestorage" "1.1.1" + "@walletconnect/logger" "3.0.2" + "@walletconnect/relay-api" "1.0.11" + "@walletconnect/relay-auth" "1.1.0" + "@walletconnect/safe-json" "1.0.2" + "@walletconnect/time" "1.0.2" + "@walletconnect/types" "2.23.4" + "@walletconnect/window-getters" "1.0.1" + "@walletconnect/window-metadata" "1.0.1" + blakejs "1.2.1" + bs58 "6.0.0" + detect-browser "5.3.0" + ox "0.9.3" + uint8arrays "3.1.1" + +"@walletconnect/window-getters@1.0.1", "@walletconnect/window-getters@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@walletconnect/window-getters/-/window-getters-1.0.1.tgz#f36d1c72558a7f6b87ecc4451fc8bd44f63cbbdc" + integrity sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q== + dependencies: + tslib "1.14.1" + +"@walletconnect/window-metadata@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz#2124f75447b7e989e4e4e1581d55d25bc75f7be5" + integrity sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA== + dependencies: + "@walletconnect/window-getters" "^1.0.1" + tslib "1.14.1" + "@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1": version "1.14.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6" @@ -2455,6 +2689,11 @@ abitype@1.0.8, abitype@^1.0.6: resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.8.tgz#3554f28b2e9d6e9f35eb59878193eabd1b9f46ba" integrity sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg== +abitype@^1.0.9: + version "1.2.3" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.2.3.tgz#bec3e09dea97d99ef6c719140bee663a329ad1f4" + integrity sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg== + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -2626,7 +2865,7 @@ ansicolors@~0.3.2: resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" integrity sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg== -anymatch@^3.0.3, anymatch@~3.1.2: +anymatch@^3.0.3, anymatch@^3.1.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -2714,6 +2953,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +atomic-sleep@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== + axios@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/axios/-/axios-1.10.0.tgz#af320aee8632eaf2a400b6a1979fa75856f38d54" @@ -2791,6 +3035,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base-x@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-5.0.1.tgz#16bf35254be1df8aca15e36b7c1dda74b2aa6b03" + integrity sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg== + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" @@ -2858,6 +3107,11 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" +blakejs@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + blork@^9.3.0: version "9.3.0" resolved "https://registry.yarnpkg.com/blork/-/blork-9.3.0.tgz#6c0b4fbb6b754998ae5460c26463d95c635e4a35" @@ -2927,6 +3181,13 @@ bs-logger@0.x: dependencies: fast-json-stable-stringify "2.x" +bs58@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-6.0.0.tgz#a2cda0130558535dd281a2f8697df79caaf425d8" + integrity sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw== + dependencies: + base-x "^5.0.0" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -3121,6 +3382,13 @@ chokidar@3.6.0, chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chokidar@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-5.0.0.tgz#949c126a9238a80792be9a0265934f098af369a5" + integrity sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw== + dependencies: + readdirp "^5.0.0" + chownr@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" @@ -3417,6 +3685,11 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +cookie-es@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.2.2.tgz#18ceef9eb513cac1cb6c14bcbf8bdb2679b34821" + integrity sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg== + cookiejar@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" @@ -3464,6 +3737,13 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crossws@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.3.5.tgz#daad331d44148ea6500098bc858869f3a5ab81a6" + integrity sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA== + dependencies: + uncrypto "^0.1.3" + crypto-random-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-4.0.0.tgz#5a3cc53d7dd86183df5da0312816ceeeb5bb1fc2" @@ -3556,6 +3836,11 @@ define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" +defu@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" + integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -3571,6 +3856,16 @@ deprecation@^2.0.0: resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== +destr@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.5.tgz#7d112ff1b925fb8d2079fac5bdb4a90973b51fdb" + integrity sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA== + +detect-browser@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" + integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== + detect-indent@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-7.0.1.tgz#cbb060a12842b9c4d333f1cac4aa4da1bb66bc25" @@ -3761,6 +4056,11 @@ es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: dependencies: es-errors "^1.3.0" +es-toolkit@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/es-toolkit/-/es-toolkit-1.44.0.tgz#b363b436b6115c3cc9cc21954c1e08ecdaa51c8c" + integrity sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg== + esbuild@~0.25.0: version "0.25.4" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.4.tgz#bb9a16334d4ef2c33c7301a924b8b863351a0854" @@ -4001,7 +4301,7 @@ eventemitter3@5.0.1: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== -events@^3.2.0: +events@3.3.0, events@^3.2.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -4606,6 +4906,21 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +h3@^1.15.5: + version "1.15.5" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.15.5.tgz#e2f28d4a66a249973bb050eaddb06b9ab55506f8" + integrity sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg== + dependencies: + cookie-es "^1.2.2" + crossws "^0.3.5" + defu "^6.1.4" + destr "^2.0.5" + iron-webcrypto "^1.2.1" + node-mock-http "^1.0.4" + radix3 "^1.1.2" + ufo "^1.6.3" + uncrypto "^0.1.3" + handlebars@^4.7.7: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" @@ -4801,6 +5116,11 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +idb-keyval@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.2.tgz#b0171b5f73944854a3291a5cdba8e12768c4854a" + integrity sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg== + ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -4960,6 +5280,11 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== +iron-webcrypto@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz#aa60ff2aa10550630f4c0b11fd2442becdb35a6f" + integrity sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg== + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -5733,6 +6058,11 @@ keccak@3.0.2: node-gyp-build "^4.2.0" readable-stream "^3.6.0" +keyvaluestorage-interface@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz#13ebdf71f5284ad54be94bd1ad9ed79adad515ff" + integrity sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g== + kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -6039,6 +6369,11 @@ lru-cache@^10.0.1, lru-cache@^10.2.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== +lru-cache@^11.2.0: + version "11.2.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.2.5.tgz#6811ae01652ae5d749948cdd80bcc22218c6744f" + integrity sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -6420,6 +6755,11 @@ ms@^2.0.0, ms@^2.1.2, ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +multiformats@^9.4.2: + version "9.9.0" + resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37" + integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg== + mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -6472,6 +6812,11 @@ node-emoji@1.11.0, node-emoji@^1.11.0: dependencies: lodash "^4.17.21" +node-fetch-native@^1.6.7: + version "1.6.7" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.7.tgz#9d09ca63066cc48423211ed4caf5d70075d76a71" + integrity sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q== + node-fetch@^2.6.9: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -6533,6 +6878,11 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== +node-mock-http@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.4.tgz#21f2ab4ce2fe4fbe8a660d7c5195a1db85e042a4" + integrity sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ== + node-releases@^2.0.19: version "2.0.19" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" @@ -6798,6 +7148,20 @@ object-inspect@^1.13.3: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== +ofetch@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.5.1.tgz#5c43cc56e03398b273014957060344254505c5c7" + integrity sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA== + dependencies: + destr "^2.0.5" + node-fetch-native "^1.6.7" + ufo "^1.6.1" + +on-exit-leak-free@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" + integrity sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA== + once@^1.3.0, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -6878,6 +7242,20 @@ ox@0.7.1: abitype "^1.0.6" eventemitter3 "5.0.1" +ox@0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.9.3.tgz#92cc1008dcd913e919364fd4175c860b3eeb18db" + integrity sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg== + dependencies: + "@adraffy/ens-normalize" "^1.11.0" + "@noble/ciphers" "^1.3.0" + "@noble/curves" "1.9.1" + "@noble/hashes" "^1.8.0" + "@scure/bip32" "^1.7.0" + "@scure/bip39" "^1.6.0" + abitype "^1.0.9" + eventemitter3 "5.0.1" + p-each-series@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-3.0.0.tgz#d1aed5e96ef29864c897367a7d2a628fdc960806" @@ -7143,6 +7521,35 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== +pino-abstract-transport@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz#de241578406ac7b8a33ce0d77ae6e8a0b3b68a60" + integrity sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw== + dependencies: + split2 "^4.0.0" + +pino-std-serializers@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz#a7b0cd65225f29e92540e7853bd73b07479893fc" + integrity sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw== + +pino@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-10.0.0.tgz#3d1a8abc7a700142edebf02a7b291834da199fbe" + integrity sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA== + dependencies: + atomic-sleep "^1.0.0" + on-exit-leak-free "^2.1.0" + pino-abstract-transport "^2.0.0" + pino-std-serializers "^7.0.0" + process-warning "^5.0.0" + quick-format-unescaped "^4.0.3" + real-require "^0.2.0" + safe-stable-stringify "^2.3.1" + slow-redact "^0.3.0" + sonic-boom "^4.0.1" + thread-stream "^3.0.0" + pirates@^4.0.4: version "4.0.7" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" @@ -7241,6 +7648,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process-warning@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-5.0.0.tgz#566e0bf79d1dff30a72d8bbbe9e8ecefe8d378d7" + integrity sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA== + prom-client@^15.1.3: version "15.1.3" resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-15.1.3.tgz#69fa8de93a88bc9783173db5f758dc1c69fa8fc2" @@ -7329,11 +7741,21 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +quick-format-unescaped@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" + integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== + quick-lru@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +radix3@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.2.tgz#fd27d2af3896c6bf4bcdfab6427c69c2afc69ec0" + integrity sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA== + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -7475,6 +7897,11 @@ readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-5.0.0.tgz#fbf1f71a727891d685bb1786f9ba74084f6e2f91" + integrity sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ== + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -7482,6 +7909,11 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +real-require@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" + integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== + redent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -7654,6 +8086,11 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-stable-stringify@^2.3.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== + "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -7929,6 +8366,11 @@ slice-ansi@^5.0.0: ansi-styles "^6.0.0" is-fullwidth-code-point "^4.0.0" +slow-redact@^0.3.0: + version "0.3.2" + resolved "https://registry.yarnpkg.com/slow-redact/-/slow-redact-0.3.2.tgz#d06e25195aa5c492d32631c53d9ae86043b8b0e2" + integrity sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw== + smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" @@ -7951,6 +8393,13 @@ socks@^2.6.2: ip "^2.0.0" smart-buffer "^4.2.0" +sonic-boom@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-4.2.0.tgz#e59a525f831210fa4ef1896428338641ac1c124d" + integrity sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww== + dependencies: + atomic-sleep "^1.0.0" + source-map-support@0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" @@ -8339,6 +8788,13 @@ text-table@^0.2.0, text-table@~0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +thread-stream@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-3.1.0.tgz#4b2ef252a7c215064507d4ef70c05a5e2d34c4f1" + integrity sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A== + dependencies: + real-require "^0.2.0" + through2@~2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -8483,16 +8939,16 @@ tsconfig-paths@4.2.0, tsconfig-paths@^4.1.2: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@1.14.1, tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + tslib@2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - tslib@^2.1.0, tslib@^2.4.1: version "2.5.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" @@ -8596,6 +9052,11 @@ typescript@5.7.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6" integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg== +ufo@^1.6.1, ufo@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.3.tgz#799666e4e88c122a9659805e30b9dc071c3aed4f" + integrity sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q== + uglify-js@^3.1.4: version "3.17.4" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" @@ -8608,6 +9069,18 @@ uid@2.0.2: dependencies: "@lukeed/csprng" "^1.0.0" +uint8arrays@3.1.1, uint8arrays@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0" + integrity sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg== + dependencies: + multiformats "^9.4.2" + +uncrypto@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/uncrypto/-/uncrypto-0.1.3.tgz#e1288d609226f2d02d8d69ee861fa20d8348ef2b" + integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q== + undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" @@ -8663,6 +9136,20 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unstorage@^1.9.0: + version "1.17.4" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.17.4.tgz#92a0bca7ea3781ba80b492939c6bed17418b12f2" + integrity sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw== + dependencies: + anymatch "^3.1.3" + chokidar "^5.0.0" + destr "^2.0.5" + h3 "^1.15.5" + lru-cache "^11.2.0" + node-fetch-native "^1.6.7" + ofetch "^1.5.1" + ufo "^1.6.3" + unzipper@^0.10.11: version "0.10.11" resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.11.tgz#0b4991446472cbdb92ee7403909f26c2419c782e" @@ -8971,6 +9458,11 @@ ws@8.18.2: resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a" integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== +ws@^7.5.1: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== + xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" From d5b5106e352f915bdc5a62c07120244d16dd08b3 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 3 Feb 2026 02:58:41 +0300 Subject: [PATCH 02/32] feat: added wallet connect integration via api --- .../browser-service/src/browser.constants.ts | 2 ++ .../browser-service/src/browser.service.ts | 12 +++++++++++- packages/wallets/src/coin98/coin98.page.ts | 5 +++-- packages/wallets/src/coinbase/coinbase.page.ts | 7 +++++-- packages/wallets/src/exodus/exodus.page.ts | 5 +++-- packages/wallets/src/index.ts | 1 + .../metamask/metamask-latest/metamask.page.ts | 11 +++++++---- .../metamask-stable/metamask.constants.ts | 18 ++++++++++++++++++ .../metamask/metamask-stable/metamask.page.ts | 11 +++++++---- packages/wallets/src/okx/okx.page.ts | 9 +++++---- packages/wallets/src/safe/safeIframe.page.ts | 5 +++-- .../src/trustwallet/trustWallet.page.ts | 9 +++++---- .../wallets/src/walletConnect/wc.service.ts | 5 +++-- packages/wallets/src/wallets.constants.ts | 2 ++ 14 files changed, 75 insertions(+), 27 deletions(-) diff --git a/packages/browser-service/src/browser.constants.ts b/packages/browser-service/src/browser.constants.ts index 5b0d6b3b..030a668d 100644 --- a/packages/browser-service/src/browser.constants.ts +++ b/packages/browser-service/src/browser.constants.ts @@ -11,6 +11,7 @@ import { SafeWcPage, TrustWalletPage, } from '@lidofinance/wallets-testing-wallets'; +import { WCSDKWallet } from '@lidofinance/wallets-testing-wallets/src/walletConnect/wc.service'; export const WALLET_PAGES = { metamaskStable: MetamaskStablePage, @@ -24,6 +25,7 @@ export const WALLET_PAGES = { bitget: BitgetPage, safeWc: SafeWcPage, safeIframe: SafeIframePage, + wcSDK: WCSDKWallet, }; export const DEFAULT_BROWSER_CONTEXT_DIR_NAME = '.browser_context'; diff --git a/packages/browser-service/src/browser.service.ts b/packages/browser-service/src/browser.service.ts index 9a58c12f..7737f0c8 100644 --- a/packages/browser-service/src/browser.service.ts +++ b/packages/browser-service/src/browser.service.ts @@ -53,7 +53,10 @@ type BrowserServiceOptions = { export class BrowserService { private logger = new ConsoleLogger(BrowserService.name); private walletPage: WalletPage< - WalletConnectTypes.WC | WalletConnectTypes.EOA | WalletConnectTypes.IFRAME + | WalletConnectTypes.WC + | WalletConnectTypes.WC_SDK + | WalletConnectTypes.EOA + | WalletConnectTypes.IFRAME >; private browserContextService: BrowserContextService; public ethereumNodeService: EthereumNodeService; @@ -118,6 +121,11 @@ export class BrowserService { } async setup() { + if (this.options.walletConfig.WALLET_TYPE === WalletConnectTypes.WC_SDK) { + this.setWalletPage(); + await this.walletPage.setup(); + return; + } const extensionService = new ExtensionService(); const extensionPath = await extensionService.getExtensionDirFromId( @@ -128,6 +136,7 @@ export class BrowserService { const contextDataDir = `${DEFAULT_BROWSER_CONTEXT_DIR_NAME}_${ mnemonicToAccount(this.options.accountConfig.SECRET_PHRASE).address }_isFork-${this.isFork}_${this.options.walletConfig.WALLET_NAME}`; + this.browserContextService = new BrowserContextService(extensionPath, { contextDataDir, browserOptions: this.options.browserOptions, @@ -160,6 +169,7 @@ export class BrowserService { switch (this.options.walletConfig.WALLET_TYPE) { case WalletConnectTypes.WC: + case WalletConnectTypes.WC_SDK: case WalletConnectTypes.IFRAME: this.walletPage = new WALLET_PAGES[ this.options.walletConfig.WALLET_NAME diff --git a/packages/wallets/src/coin98/coin98.page.ts b/packages/wallets/src/coin98/coin98.page.ts index 7ee40989..9ad17af6 100644 --- a/packages/wallets/src/coin98/coin98.page.ts +++ b/packages/wallets/src/coin98/coin98.page.ts @@ -2,6 +2,7 @@ import { WalletConnectTypes } from '../wallets.constants'; import { WalletPage, WalletPageOptions } from '../wallet.page'; import { test, Page } from '@playwright/test'; import { ConsoleLogger } from '@nestjs/common'; +import { WCSessionRequest } from '../walletConnect/wc.service'; export class Coin98 implements WalletPage { logger = new ConsoleLogger(Coin98.name); @@ -137,9 +138,9 @@ export class Coin98 implements WalletPage { throw new Error('Method not implemented.'); } - async confirmTx(page: Page) { + async confirmTx(page: Page | WCSessionRequest) { await test.step('Confirm TX', async () => { - await page.click('button:has-text("Confirm")'); + await (page as Page).click('button:has-text("Confirm")'); }); } diff --git a/packages/wallets/src/coinbase/coinbase.page.ts b/packages/wallets/src/coinbase/coinbase.page.ts index 1b01ab6f..42d4b037 100644 --- a/packages/wallets/src/coinbase/coinbase.page.ts +++ b/packages/wallets/src/coinbase/coinbase.page.ts @@ -3,6 +3,7 @@ import { WalletPage, WalletPageOptions } from '../wallet.page'; import expect from 'expect'; import { test, Page } from '@playwright/test'; import { ConsoleLogger } from '@nestjs/common'; +import { WCSessionRequest } from '../walletConnect/wc.service'; export class CoinbasePage implements WalletPage { logger = new ConsoleLogger(CoinbasePage.name); @@ -134,10 +135,12 @@ export class CoinbasePage implements WalletPage { }); } - async confirmTx(page: Page) { + async confirmTx(page: Page | WCSessionRequest) { await test.step('Confirm TX', async () => { await this.closeTransactionPopover(); - await page.click('button[data-testid="request-confirm-button"]'); + await (page as Page).click( + 'button[data-testid="request-confirm-button"]', + ); }); } diff --git a/packages/wallets/src/exodus/exodus.page.ts b/packages/wallets/src/exodus/exodus.page.ts index bd2b41ab..822821d2 100644 --- a/packages/wallets/src/exodus/exodus.page.ts +++ b/packages/wallets/src/exodus/exodus.page.ts @@ -3,6 +3,7 @@ import { WalletPage, WalletPageOptions } from '../wallet.page'; import { test, Page } from '@playwright/test'; import { OnboardingPage } from './pages'; import { ConsoleLogger } from '@nestjs/common'; +import { WCSessionRequest } from '../walletConnect/wc.service'; export class ExodusPage implements WalletPage { logger = new ConsoleLogger(ExodusPage.name); @@ -74,9 +75,9 @@ export class ExodusPage implements WalletPage { } /** Click `Confirm` button on the transaction `page` */ - async confirmTx(page: Page) { + async confirmTx(page: Page | WCSessionRequest) { await test.step('Confirm TX', async () => { - await page.getByText('Confirm').click(); + await (page as Page).getByText('Confirm').click(); }); } diff --git a/packages/wallets/src/index.ts b/packages/wallets/src/index.ts index 87bb9bfc..c544cf00 100644 --- a/packages/wallets/src/index.ts +++ b/packages/wallets/src/index.ts @@ -11,6 +11,7 @@ export * from './exodus'; export * from './okx'; export * from './bitget'; export * from './ctrl'; +export * from './walletConnect/wc.service'; // export WC and IFRAME WalletConnectTypes export * from './safe'; diff --git a/packages/wallets/src/metamask/metamask-latest/metamask.page.ts b/packages/wallets/src/metamask/metamask-latest/metamask.page.ts index 70cdeeb2..ca5cb2cb 100644 --- a/packages/wallets/src/metamask/metamask-latest/metamask.page.ts +++ b/packages/wallets/src/metamask/metamask-latest/metamask.page.ts @@ -18,6 +18,7 @@ import { } from './pages/elements'; import { getAddress } from 'viem'; import { isPopularMainnetNetwork, isPopularTestnetNetwork } from './helper'; +import { WCSessionRequest } from '../../walletConnect/wc.service'; export class MetamaskPage implements WalletPage { page: Page | undefined; @@ -213,15 +214,17 @@ export class MetamaskPage implements WalletPage { }); } - async confirmTx(page: Page, setAggressiveGas?: boolean) { + async confirmTx(page: Page | WCSessionRequest, setAggressiveGas?: boolean) { await test.step('Confirm TX', async () => { - await new WalletOperationPage(page).confirmTransaction(setAggressiveGas); + await new WalletOperationPage(page as Page).confirmTransaction( + setAggressiveGas, + ); }); } - async cancelTx(page: Page) { + async cancelTx(page: Page | WCSessionRequest) { await test.step('Reject TX', async () => { - await new WalletOperationPage(page).cancelTransaction(); + await new WalletOperationPage(page as Page).cancelTransaction(); }); } diff --git a/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts b/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts index 613c5f31..cf6c45c7 100644 --- a/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts +++ b/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts @@ -16,3 +16,21 @@ export const METAMASK_STABLE_COMMON_CONFIG: CommonWalletConfig = { 'https://github.com/MetaMask/metamask-extension/releases/download/v12.10.4/metamask-chrome-12.10.4.zip', EXTENSION_START_PATH: '/home.html', }; + +export const WC_SDK_COMMON_CONFIG: CommonWalletConfig = { + WALLET_NAME: 'wcSDK', + EXTENSION_WALLET_NAME: 'wcSDK', + CONNECTED_WALLET_NAME: 'wcSDK', + CONNECT_BUTTON_NAME: 'WalletConnect', + STORE_EXTENSION_ID: 'nkbihfbeogaeaoehlefnkodbefgpgknn', + WALLET_TYPE: WalletConnectTypes.WC_SDK, + // Metamask stable version + // https://github.com/MetaMask/metamask-extension/releases/tag/v12.10.4 + LATEST_STABLE_DOWNLOAD_LINK: + 'https://github.com/MetaMask/metamask-extension/releases/download/v12.10.4/metamask-chrome-12.10.4.zip', + EXTENSION_START_PATH: '/home.html', + walletConnectConfig: { + projectId: '6a172e2af5847c798046bddf0c024fdc', + requestHandleTimeoutMs: 30000, + }, +}; diff --git a/packages/wallets/src/metamask/metamask-stable/metamask.page.ts b/packages/wallets/src/metamask/metamask-stable/metamask.page.ts index 3bf4e11b..6fd7ee84 100644 --- a/packages/wallets/src/metamask/metamask-stable/metamask.page.ts +++ b/packages/wallets/src/metamask/metamask-stable/metamask.page.ts @@ -22,6 +22,7 @@ import { isPopularTestnetNetwork, } from './helper'; import { privateKeyToAccount } from 'viem/accounts'; +import { WCSessionRequest } from '../../walletConnect/wc.service'; export class MetamaskStablePage implements WalletPage { page: Page | undefined; @@ -234,15 +235,17 @@ export class MetamaskStablePage implements WalletPage { }); } - async confirmTx(page: Page, setAggressiveGas?: boolean) { + async confirmTx(page: Page | WCSessionRequest, setAggressiveGas?: boolean) { await test.step('Confirm TX', async () => { - await new WalletOperationPage(page).confirmTransaction(setAggressiveGas); + await new WalletOperationPage(page as Page).confirmTransaction( + setAggressiveGas, + ); }); } - async cancelTx(page: Page) { + async cancelTx(page: Page | WCSessionRequest) { await test.step('Reject TX', async () => { - await new WalletOperationPage(page).cancelTransaction(); + await new WalletOperationPage(page as Page).cancelTransaction(); }); } diff --git a/packages/wallets/src/okx/okx.page.ts b/packages/wallets/src/okx/okx.page.ts index 3b50bedc..e02527d7 100644 --- a/packages/wallets/src/okx/okx.page.ts +++ b/packages/wallets/src/okx/okx.page.ts @@ -17,6 +17,7 @@ import { } from './helper'; import { ConsoleLogger } from '@nestjs/common'; import { WalletPageOptions } from '../wallet.page'; +import { WCSessionRequest } from '../walletConnect/wc.service'; export class OkxPage implements WalletPage { logger = new ConsoleLogger(OkxPage.name); @@ -189,16 +190,16 @@ export class OkxPage implements WalletPage { } /** Cancel transaction */ - async cancelTx(page: Page) { + async cancelTx(page: Page | WCSessionRequest) { await test.step('Cancel TX', async () => { - await new WalletOperations(page).cancelTxButton.click(); + await new WalletOperations(page as Page).cancelTxButton.click(); }); } /** Confirm transaction */ - async confirmTx(page: Page) { + async confirmTx(page: Page | WCSessionRequest) { await test.step('Confirm TX', async () => { - await new WalletOperations(page).confirmTxButton.click({ + await new WalletOperations(page as Page).confirmTxButton.click({ timeout: 30000, // sometimes button is disabled awaits rpc }); }); diff --git a/packages/wallets/src/safe/safeIframe.page.ts b/packages/wallets/src/safe/safeIframe.page.ts index 213c3741..e3ab6fb1 100644 --- a/packages/wallets/src/safe/safeIframe.page.ts +++ b/packages/wallets/src/safe/safeIframe.page.ts @@ -3,6 +3,7 @@ import { WalletPage, WalletPageOptions } from '../wallet.page'; import { NetworkConfig, WalletConnectTypes } from '../wallets.constants'; import { ConsoleLogger } from '@nestjs/common'; import { SetupPage, SettingPage, TransactionPage } from './pages'; +import { WCSessionRequest } from '../walletConnect/wc.service'; export class SafeIframePage implements WalletPage { logger = new ConsoleLogger(SafeIframePage.name); @@ -114,10 +115,10 @@ export class SafeIframePage implements WalletPage { }); } - async confirmTx(page: Page) { + async confirmTx(page: Page | WCSessionRequest) { await test.step('Confirm transaction', async () => { const transactionPage = new TransactionPage( - page, + page as Page, this.options.extensionPage, ); await transactionPage.confirmTransaction(); diff --git a/packages/wallets/src/trustwallet/trustWallet.page.ts b/packages/wallets/src/trustwallet/trustWallet.page.ts index 03e93445..d77d4c62 100644 --- a/packages/wallets/src/trustwallet/trustWallet.page.ts +++ b/packages/wallets/src/trustwallet/trustWallet.page.ts @@ -10,6 +10,7 @@ import { LoginPage, } from './pages'; import { closeUnnecessaryPages } from '../okx/helper'; +import { WCSessionRequest } from '../walletConnect/wc.service'; export class TrustWalletPage implements WalletPage { logger = new ConsoleLogger(TrustWalletPage.name); @@ -132,18 +133,18 @@ export class TrustWalletPage implements WalletPage { } /** Confirm transaction */ - async confirmTx(page: Page) { + async confirmTx(page: Page | WCSessionRequest) { await test.step('Confirm TX', async () => { - const txPage = new WalletOperations(page); + const txPage = new WalletOperations(page as Page); await expect(txPage.confirmBtn).toBeEnabled(); await txPage.confirmBtn.click(); }); } /** Reject transaction */ - async cancelTx(page: Page) { + async cancelTx(page: Page | WCSessionRequest) { await test.step('Cancel TX', async () => { - const txPage = new WalletOperations(page); + const txPage = new WalletOperations(page as Page); await expect(txPage.rejectBtn).toBeEnabled(); await txPage.rejectBtn.click(); }); diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 8834cc18..ab3728ed 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ import SignClient from '@walletconnect/sign-client'; import { createPublicClient, createWalletClient, HDAccount, http } from 'viem'; import { mainnet } from 'viem/chains'; @@ -22,9 +23,9 @@ export type WCSessionRequest = { }; }; -export class WCTestWallet implements WalletPage { +export class WCSDKWallet implements WalletPage { private client?: SignClient; - // @ts-error TS2564: Property 'walletClient' has no initializer and is not definitely assigned in the constructor. + // @ts-ignore private walletClient?: ReturnType; private publicClient?: ReturnType; private hdAccount: HDAccount; diff --git a/packages/wallets/src/wallets.constants.ts b/packages/wallets/src/wallets.constants.ts index 1d6cdecb..da994f30 100644 --- a/packages/wallets/src/wallets.constants.ts +++ b/packages/wallets/src/wallets.constants.ts @@ -33,11 +33,13 @@ export interface CommonWalletConfig { export enum WalletConnectTypes { EOA = 'EOA', WC = 'WC', + WC_SDK = 'WC_SDK', IFRAME = 'IFRAME', } export type WalletConnectType = | WalletConnectTypes.WC + | WalletConnectTypes.WC_SDK | WalletConnectTypes.EOA | WalletConnectTypes.IFRAME; From 93fe6717a2a4acfaa68993ceddc1c07b1f214f96 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 3 Feb 2026 03:33:20 +0300 Subject: [PATCH 03/32] feat: update BrowserContextService and BrowserService for WalletConnect integration --- .../browser-service/src/browser.constants.ts | 2 +- .../src/browser.context.service.ts | 16 +++++++------ .../browser-service/src/browser.service.ts | 23 ++++++++++++++++++- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/packages/browser-service/src/browser.constants.ts b/packages/browser-service/src/browser.constants.ts index 030a668d..315307fc 100644 --- a/packages/browser-service/src/browser.constants.ts +++ b/packages/browser-service/src/browser.constants.ts @@ -10,8 +10,8 @@ import { SafeIframePage, SafeWcPage, TrustWalletPage, + WCSDKWallet, } from '@lidofinance/wallets-testing-wallets'; -import { WCSDKWallet } from '@lidofinance/wallets-testing-wallets/src/walletConnect/wc.service'; export const WALLET_PAGES = { metamaskStable: MetamaskStablePage, diff --git a/packages/browser-service/src/browser.context.service.ts b/packages/browser-service/src/browser.context.service.ts index e8eb3c27..cdc7f3ba 100644 --- a/packages/browser-service/src/browser.context.service.ts +++ b/packages/browser-service/src/browser.context.service.ts @@ -29,7 +29,7 @@ export type BrowserOptions = { type OptionsBrowserContext = { // If contextDataDir is undefined - will be created temp dir for context data. // Else contextDataDir is not undefined - will be created user dir for context data in current folder. - contextDataDir: string; + contextDataDir?: string; browserOptions?: BrowserOptions; }; @@ -41,7 +41,7 @@ export class BrowserContextService { private readonly logger = new ConsoleLogger(BrowserContextService.name); constructor( - public walletExtensionStartPath: string, + public walletExtensionStartPath: string | null, public options: OptionsBrowserContext, ) { this.defaultBrowserOptions = { @@ -50,7 +50,9 @@ export class BrowserContextService { args: [ '--lang=en-US', '--disable-dev-shm-usage', - `--disable-extensions-except=${this.walletExtensionStartPath}`, + this.walletExtensionStartPath + ? `--disable-extensions-except=${this.walletExtensionStartPath}` + : '', '--js-flags="--max-old-space-size=2048"', ], permissions: ['clipboard-read', 'clipboard-write'], @@ -63,10 +65,6 @@ export class BrowserContextService { } async initBrowserContext() { - this.logger.debug( - `Starting a new browser context (temp context: ${!this.options - .contextDataDir})`, - ); let browserContextPath = ''; if (this.options.contextDataDir) { @@ -80,6 +78,10 @@ export class BrowserContextService { }); } + this.logger.debug( + `Starting a new browser context (temp context: ${browserContextPath})`, + ); + let attemptsLeft = 3; while (attemptsLeft > 0) { try { diff --git a/packages/browser-service/src/browser.service.ts b/packages/browser-service/src/browser.service.ts index 7737f0c8..4e167efa 100644 --- a/packages/browser-service/src/browser.service.ts +++ b/packages/browser-service/src/browser.service.ts @@ -122,6 +122,11 @@ export class BrowserService { async setup() { if (this.options.walletConfig.WALLET_TYPE === WalletConnectTypes.WC_SDK) { + this.browserContextService = new BrowserContextService(null, { + browserOptions: this.options.browserOptions, + }); + + await this.browserContextService.initBrowserContext(); this.setWalletPage(); await this.walletPage.setup(); return; @@ -157,6 +162,23 @@ export class BrowserService { } private setWalletPage() { + if (this.options.walletConfig.WALLET_TYPE === WalletConnectTypes.WC_SDK) { + this.walletPage = new WALLET_PAGES[this.options.walletConfig.WALLET_NAME]( + { + browserContext: this.browserContextService.browserContext, + walletConfig: this.options.walletConfig, + standConfig: { + chainId: this.options.networkConfig.chainId, + standUrl: this.options.standUrl, + rpcUrl: + this.ethereumNodeService?.state.nodeUrl || + this.options.networkConfig.rpcUrl, + }, + }, + ); + return; + } + const extension = new Extension(this.browserContextService.extensionId); const extensionWalletPage = new WALLET_PAGES[ this.options.walletConfig.EXTENSION_WALLET_NAME @@ -169,7 +191,6 @@ export class BrowserService { switch (this.options.walletConfig.WALLET_TYPE) { case WalletConnectTypes.WC: - case WalletConnectTypes.WC_SDK: case WalletConnectTypes.IFRAME: this.walletPage = new WALLET_PAGES[ this.options.walletConfig.WALLET_NAME From 2c12df53bc4304678bc76d1658f575adc9c4e9d0 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 3 Feb 2026 10:52:44 +0300 Subject: [PATCH 04/32] fix: add missing param --- .../browser-service/src/browser.context.service.ts | 10 ++++++---- packages/browser-service/src/browser.service.ts | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/browser-service/src/browser.context.service.ts b/packages/browser-service/src/browser.context.service.ts index cdc7f3ba..7330c26e 100644 --- a/packages/browser-service/src/browser.context.service.ts +++ b/packages/browser-service/src/browser.context.service.ts @@ -113,10 +113,12 @@ export class BrowserContextService { await this.browserContext.addCookies(this.options.browserOptions.cookies); } - let [background] = this.browserContext.serviceWorkers(); - if (!background) - background = await this.browserContext.waitForEvent('serviceworker'); - this.extensionId = background.url().split('/')[2]; + if (this.walletExtensionStartPath) { + let [background] = this.browserContext.serviceWorkers(); + if (!background) + background = await this.browserContext.waitForEvent('serviceworker'); + this.extensionId = background.url().split('/')[2]; + } } async closePages() { diff --git a/packages/browser-service/src/browser.service.ts b/packages/browser-service/src/browser.service.ts index 4e167efa..ba786f78 100644 --- a/packages/browser-service/src/browser.service.ts +++ b/packages/browser-service/src/browser.service.ts @@ -167,6 +167,7 @@ export class BrowserService { { browserContext: this.browserContextService.browserContext, walletConfig: this.options.walletConfig, + accountConfig: this.options.accountConfig, standConfig: { chainId: this.options.networkConfig.chainId, standUrl: this.options.standUrl, From 76921bfb5839545e0f48accc5524edfa1ed6da9b Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 3 Feb 2026 12:13:49 +0300 Subject: [PATCH 05/32] fix: enhance WalletConnect integration and update dependencies --- .../browser-service/src/browser.service.ts | 10 +- packages/wallets/package.json | 4 +- .../wallets/src/walletConnect/wc.service.ts | 12 +- yarn.lock | 130 ++++-------------- 4 files changed, 43 insertions(+), 113 deletions(-) diff --git a/packages/browser-service/src/browser.service.ts b/packages/browser-service/src/browser.service.ts index ba786f78..51e93368 100644 --- a/packages/browser-service/src/browser.service.ts +++ b/packages/browser-service/src/browser.service.ts @@ -87,9 +87,13 @@ export class BrowserService { await this.setupWithNode(); } else { await this.setup(); - await this.walletPage.setupNetwork(this.options.networkConfig); - await this.walletPage.changeNetwork(this.options.networkConfig.chainName); - await this.browserContextService.closePages(); + if (this.options.walletConfig.WALLET_TYPE !== WalletConnectTypes.WC_SDK) { + await this.walletPage.setupNetwork(this.options.networkConfig); + await this.walletPage.changeNetwork( + this.options.networkConfig.chainName, + ); + await this.browserContextService.closePages(); + } } } diff --git a/packages/wallets/package.json b/packages/wallets/package.json index a07fdc57..21f71964 100644 --- a/packages/wallets/package.json +++ b/packages/wallets/package.json @@ -34,9 +34,9 @@ "expect": "^28.1.3", "reflect-metadata": "^0.1.13", "rxjs": "^7.5.6", - "viem": "^2.28.4" + "viem": "^2.31.4" }, "peerDependencies": { "@playwright/test": "^1.51.1" } -} \ No newline at end of file +} diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index ab3728ed..3fc28ef5 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import SignClient from '@walletconnect/sign-client'; import { createPublicClient, createWalletClient, HDAccount, http } from 'viem'; -import { mainnet } from 'viem/chains'; +import * as chains from 'viem/chains'; import { WalletPage, WalletPageOptions } from '../wallet.page'; import { NetworkConfig, @@ -68,6 +68,9 @@ export class WCSDKWallet implements WalletPage { async setup(): Promise { if (this.client) return; + const chain = Object.values(chains).find( + (c) => c.id === this.options.standConfig.chainId, + ); this.client = await SignClient.init({ projectId: this.options.walletConfig.walletConnectConfig.projectId, @@ -76,12 +79,12 @@ export class WCSDKWallet implements WalletPage { this.walletClient = createWalletClient({ account: this.hdAccount, - chain: mainnet, + chain, transport: http(this.options.standConfig.rpcUrl), }); this.publicClient = createPublicClient({ - chain: mainnet, + chain: chain as chains.Chain, transport: http(this.options.standConfig.rpcUrl), }); // Collect incoming requests into an async queue @@ -100,8 +103,7 @@ export class WCSDKWallet implements WalletPage { const [proposal] = await Promise.all([ this.waitForProposalOnce( - this.options.walletConfig.walletConnectConfig.requestHandleTimeoutMs || - 30000, + this.options.walletConfig.walletConnectConfig.requestHandleTimeoutMs, ), this.client.core.pairing.pair({ uri }), ]); diff --git a/yarn.lock b/yarn.lock index 837278fb..f3ff9729 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,11 +7,6 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== -"@adraffy/ens-normalize@^1.10.1": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz#42cc67c5baa407ac25059fcd7d405cc5ecdb0c33" - integrity sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg== - "@adraffy/ens-normalize@^1.11.0": version "1.11.1" resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz#6c2d657d4b2dfb37f8ea811dcb3e60843d4ac24a" @@ -1320,13 +1315,6 @@ dependencies: "@noble/hashes" "1.7.0" -"@noble/curves@1.8.2", "@noble/curves@~1.8.1": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.2.tgz#8f24c037795e22b90ae29e222a856294c1d9ffc7" - integrity sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g== - dependencies: - "@noble/hashes" "1.7.2" - "@noble/curves@1.9.1": version "1.9.1" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.1.tgz#9654a0bc6c13420ae252ddcf975eaf0f58f0a35c" @@ -1341,7 +1329,7 @@ dependencies: "@noble/hashes" "1.8.0" -"@noble/curves@^1.6.0", "@noble/curves@~1.9.0": +"@noble/curves@~1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.0.tgz#13e0ca8be4a0ce66c113693a94514e5599f40cfc" integrity sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg== @@ -1353,12 +1341,7 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.0.tgz#5d9e33af2c7d04fee35de1519b80c958b2e35e39" integrity sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w== -"@noble/hashes@1.7.2", "@noble/hashes@~1.7.1": - version "1.7.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.2.tgz#d53c65a21658fb02f3303e7ee3ba89d6754c64b4" - integrity sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ== - -"@noble/hashes@1.8.0", "@noble/hashes@^1.1.5", "@noble/hashes@^1.5.0", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": +"@noble/hashes@1.8.0", "@noble/hashes@^1.1.5", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": version "1.8.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== @@ -1737,21 +1720,12 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.6.tgz#ca917184b8231394dd8847509c67a0be522e59f6" integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== -"@scure/base@~1.2.2", "@scure/base@~1.2.4", "@scure/base@~1.2.5": +"@scure/base@~1.2.5": version "1.2.5" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.5.tgz#f9d1b232425b367d0dcb81c96611dcc651d58671" integrity sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw== -"@scure/bip32@1.6.2": - version "1.6.2" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.6.2.tgz#093caa94961619927659ed0e711a6e4bf35bffd0" - integrity sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw== - dependencies: - "@noble/curves" "~1.8.1" - "@noble/hashes" "~1.7.1" - "@scure/base" "~1.2.2" - -"@scure/bip32@1.7.0", "@scure/bip32@^1.5.0", "@scure/bip32@^1.7.0": +"@scure/bip32@1.7.0", "@scure/bip32@^1.7.0": version "1.7.0" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.7.0.tgz#b8683bab172369f988f1589640e53c4606984219" integrity sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== @@ -1760,15 +1734,7 @@ "@noble/hashes" "~1.8.0" "@scure/base" "~1.2.5" -"@scure/bip39@1.5.4": - version "1.5.4" - resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.5.4.tgz#07fd920423aa671be4540d59bdd344cc1461db51" - integrity sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA== - dependencies: - "@noble/hashes" "~1.7.1" - "@scure/base" "~1.2.4" - -"@scure/bip39@1.6.0", "@scure/bip39@^1.4.0", "@scure/bip39@^1.6.0": +"@scure/bip39@1.6.0", "@scure/bip39@^1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.6.0.tgz#475970ace440d7be87a6086cbee77cb8f1a684f9" integrity sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A== @@ -2684,12 +2650,7 @@ abbrev@^2.0.0: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== -abitype@1.0.8, abitype@^1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.8.tgz#3554f28b2e9d6e9f35eb59878193eabd1b9f46ba" - integrity sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg== - -abitype@^1.0.9: +abitype@1.2.3, abitype@^1.0.9, abitype@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.2.3.tgz#bec3e09dea97d99ef6c719140bee663a329ad1f4" integrity sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg== @@ -5419,11 +5380,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isows@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.6.tgz#0da29d706fa51551c663c627ace42769850f86e7" - integrity sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw== - isows@1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.7.tgz#1c06400b7eed216fbba3bcbd68f12490fc342915" @@ -7215,31 +7171,18 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -ox@0.6.9: - version "0.6.9" - resolved "https://registry.yarnpkg.com/ox/-/ox-0.6.9.tgz#da1ee04fa10de30c8d04c15bfb80fe58b1f554bd" - integrity sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug== - dependencies: - "@adraffy/ens-normalize" "^1.10.1" - "@noble/curves" "^1.6.0" - "@noble/hashes" "^1.5.0" - "@scure/bip32" "^1.5.0" - "@scure/bip39" "^1.4.0" - abitype "^1.0.6" - eventemitter3 "5.0.1" - -ox@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/ox/-/ox-0.7.1.tgz#fb23a770dd966c051ad916d4e2e655a6f995e1cf" - integrity sha512-+k9fY9PRNuAMHRFIUbiK9Nt5seYHHzSQs9Bj+iMETcGtlpS7SmBzcGSVUQO3+nqGLEiNK4598pHNFlVRaZbRsg== +ox@0.11.3: + version "0.11.3" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.11.3.tgz#f50be1cae88822f5111b1e3f4a324c4c07eed422" + integrity sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw== dependencies: - "@adraffy/ens-normalize" "^1.10.1" + "@adraffy/ens-normalize" "^1.11.0" "@noble/ciphers" "^1.3.0" - "@noble/curves" "^1.6.0" - "@noble/hashes" "^1.5.0" - "@scure/bip32" "^1.5.0" - "@scure/bip39" "^1.4.0" - abitype "^1.0.6" + "@noble/curves" "1.9.1" + "@noble/hashes" "^1.8.0" + "@scure/bip32" "^1.7.0" + "@scure/bip39" "^1.6.0" + abitype "^1.2.3" eventemitter3 "5.0.1" ox@0.9.3: @@ -9223,33 +9166,19 @@ validate-npm-package-name@^5.0.0: resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== -viem@^2.21.40: - version "2.31.0" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.31.0.tgz#2263426cce091d440e283b88183dff6f1d8bae5c" - integrity sha512-U7OMQ6yqK+bRbEIarf2vqxL7unSEQvNxvML/1zG7suAmKuJmipqdVTVJGKBCJiYsm/EremyO2FS4dHIPpGv+eA== +viem@^2.31.4: + version "2.45.1" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.45.1.tgz#c1c373efcf2a0b30f5e454cfb4a9c18ac5bb5452" + integrity sha512-LN6Pp7vSfv50LgwhkfSbIXftAM5J89lP9x8TeDa8QM7o41IxlHrDh0F9X+FfnCWtsz11pEVV5sn+yBUoOHNqYA== dependencies: "@noble/curves" "1.9.1" "@noble/hashes" "1.8.0" "@scure/bip32" "1.7.0" "@scure/bip39" "1.6.0" - abitype "1.0.8" + abitype "1.2.3" isows "1.0.7" - ox "0.7.1" - ws "8.18.2" - -viem@^2.28.4: - version "2.29.2" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.29.2.tgz#e3033f68d6baf95c412593b213865e91634ac35e" - integrity sha512-cukRxab90jvQ+TDD84sU3qB3UmejYqgCw4cX8SfWzvh7JPfZXI3kAMUaT5OSR2As1Mgvx1EJawccwPjGqkSSwA== - dependencies: - "@noble/curves" "1.8.2" - "@noble/hashes" "1.7.2" - "@scure/bip32" "1.6.2" - "@scure/bip39" "1.5.4" - abitype "1.0.8" - isows "1.0.6" - ox "0.6.9" - ws "8.18.1" + ox "0.11.3" + ws "8.18.3" walk-up-path@^3.0.1: version "3.0.1" @@ -9448,15 +9377,10 @@ ws@8.18.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== -ws@8.18.1: - version "8.18.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" - integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== - -ws@8.18.2: - version "8.18.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a" - integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== +ws@8.18.3: + version "8.18.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" + integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== ws@^7.5.1: version "7.5.10" From cefadbecdab3e05ca4d0408e8bb98dd93321a428 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 3 Feb 2026 13:47:06 +0300 Subject: [PATCH 06/32] fix: enhance WalletConnect integration and update dependencies --- packages/wallets/package.json | 2 +- .../wallets/src/walletConnect/wc.service.ts | 44 ++++++++++++++----- yarn.lock | 2 +- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/packages/wallets/package.json b/packages/wallets/package.json index 21f71964..9b3f958f 100644 --- a/packages/wallets/package.json +++ b/packages/wallets/package.json @@ -34,7 +34,7 @@ "expect": "^28.1.3", "reflect-metadata": "^0.1.13", "rxjs": "^7.5.6", - "viem": "^2.31.4" + "viem": "^2.22.0" }, "peerDependencies": { "@playwright/test": "^1.51.1" diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 3fc28ef5..d24c306d 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -1,7 +1,15 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ import SignClient from '@walletconnect/sign-client'; -import { createPublicClient, createWalletClient, HDAccount, http } from 'viem'; -import * as chains from 'viem/chains'; +import { + createPublicClient, + createWalletClient, + HDAccount, + http, + PublicClient, + WalletClient, + Transport, + Chain, + Account, +} from 'viem'; import { WalletPage, WalletPageOptions } from '../wallet.page'; import { NetworkConfig, @@ -11,6 +19,23 @@ import { import { Page } from '@playwright/test'; import { mnemonicToAccount } from 'viem/accounts'; +export declare enum CHAINS { + Mainnet = 1, + Holesky = 17000, + Hoodi = 560048, + Sepolia = 11155111, + Optimism = 10, + OptimismSepolia = 11155420, + Soneium = 1868, + SoneiumMinato = 1946, + Unichain = 130, + UnichainSepolia = 1301, +} + +export declare const VIEM_CHAINS: { + [key in CHAINS]: Chain; +}; + export type WCSessionRequest = { topic: string; id: number; @@ -25,9 +50,8 @@ export type WCSessionRequest = { export class WCSDKWallet implements WalletPage { private client?: SignClient; - // @ts-ignore - private walletClient?: ReturnType; - private publicClient?: ReturnType; + private publicClient?: PublicClient; + private walletClient?: WalletClient; private hdAccount: HDAccount; private requestQueue: WCSessionRequest[] = []; @@ -68,9 +92,6 @@ export class WCSDKWallet implements WalletPage { async setup(): Promise { if (this.client) return; - const chain = Object.values(chains).find( - (c) => c.id === this.options.standConfig.chainId, - ); this.client = await SignClient.init({ projectId: this.options.walletConfig.walletConnectConfig.projectId, @@ -79,12 +100,13 @@ export class WCSDKWallet implements WalletPage { this.walletClient = createWalletClient({ account: this.hdAccount, - chain, + chain: VIEM_CHAINS[this.options.standConfig.chainId], transport: http(this.options.standConfig.rpcUrl), }); + // @ts-ignore this.publicClient = createPublicClient({ - chain: chain as chains.Chain, + chain: VIEM_CHAINS[this.options.standConfig.chainId], transport: http(this.options.standConfig.rpcUrl), }); // Collect incoming requests into an async queue diff --git a/yarn.lock b/yarn.lock index f3ff9729..1ed9e66c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9166,7 +9166,7 @@ validate-npm-package-name@^5.0.0: resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== -viem@^2.31.4: +viem@^2.21.40, viem@^2.22.0: version "2.45.1" resolved "https://registry.yarnpkg.com/viem/-/viem-2.45.1.tgz#c1c373efcf2a0b30f5e454cfb4a9c18ac5bb5452" integrity sha512-LN6Pp7vSfv50LgwhkfSbIXftAM5J89lP9x8TeDa8QM7o41IxlHrDh0F9X+FfnCWtsz11pEVV5sn+yBUoOHNqYA== From 74143e40b1e54a6f344596a13c4c9b55f76a1f05 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 3 Feb 2026 15:26:45 +0300 Subject: [PATCH 07/32] fix: enhance WalletConnect integration and update dependencies --- packages/browser-service/package.json | 2 +- packages/wallets/package.json | 2 +- .../wallets/src/walletConnect/constants.ts | 26 ++++ .../wallets/src/walletConnect/wc.service.ts | 31 ++--- yarn.lock | 130 ++++++++++++++---- 5 files changed, 139 insertions(+), 52 deletions(-) create mode 100644 packages/wallets/src/walletConnect/constants.ts diff --git a/packages/browser-service/package.json b/packages/browser-service/package.json index 523e5b74..42253ecf 100644 --- a/packages/browser-service/package.json +++ b/packages/browser-service/package.json @@ -36,4 +36,4 @@ "peerDependencies": { "@playwright/test": "^1.51.1" } -} \ No newline at end of file +} diff --git a/packages/wallets/package.json b/packages/wallets/package.json index 9b3f958f..66a59c18 100644 --- a/packages/wallets/package.json +++ b/packages/wallets/package.json @@ -34,7 +34,7 @@ "expect": "^28.1.3", "reflect-metadata": "^0.1.13", "rxjs": "^7.5.6", - "viem": "^2.22.0" + "viem": "^2.28.4" }, "peerDependencies": { "@playwright/test": "^1.51.1" diff --git a/packages/wallets/src/walletConnect/constants.ts b/packages/wallets/src/walletConnect/constants.ts new file mode 100644 index 00000000..ee1df8e9 --- /dev/null +++ b/packages/wallets/src/walletConnect/constants.ts @@ -0,0 +1,26 @@ +import type { Chain } from 'viem'; +import { + mainnet, + holesky, + hoodi, + sepolia, + optimismSepolia, + optimism, + soneiumMinato, + soneium, + unichain, + unichainSepolia, +} from 'viem/chains'; + +export const SUPPORTED_CHAINS: Record = { + 1: mainnet as Chain, + 17000: holesky as Chain, + 560048: hoodi as Chain, + 11155111: sepolia as Chain, + 10: optimism as Chain, + 11155420: optimismSepolia as Chain, + 1868: soneium as Chain, + 1946: soneiumMinato as Chain, + 130: unichain as Chain, + 1301: unichainSepolia as Chain, +}; diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index d24c306d..118489bf 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -10,6 +10,8 @@ import { Chain, Account, } from 'viem'; +import { mnemonicToAccount } from 'viem/accounts'; + import { WalletPage, WalletPageOptions } from '../wallet.page'; import { NetworkConfig, @@ -17,24 +19,7 @@ import { WCApproveNamespaces, } from '../wallets.constants'; import { Page } from '@playwright/test'; -import { mnemonicToAccount } from 'viem/accounts'; - -export declare enum CHAINS { - Mainnet = 1, - Holesky = 17000, - Hoodi = 560048, - Sepolia = 11155111, - Optimism = 10, - OptimismSepolia = 11155420, - Soneium = 1868, - SoneiumMinato = 1946, - Unichain = 130, - UnichainSepolia = 1301, -} - -export declare const VIEM_CHAINS: { - [key in CHAINS]: Chain; -}; +import { SUPPORTED_CHAINS } from './constants'; export type WCSessionRequest = { topic: string; @@ -50,8 +35,9 @@ export type WCSessionRequest = { export class WCSDKWallet implements WalletPage { private client?: SignClient; - private publicClient?: PublicClient; - private walletClient?: WalletClient; + // @ts-ignore + private publicClient?: ReturnType; + private walletClient?: ReturnType; private hdAccount: HDAccount; private requestQueue: WCSessionRequest[] = []; @@ -100,13 +86,12 @@ export class WCSDKWallet implements WalletPage { this.walletClient = createWalletClient({ account: this.hdAccount, - chain: VIEM_CHAINS[this.options.standConfig.chainId], + chain: SUPPORTED_CHAINS[this.options.standConfig.chainId], transport: http(this.options.standConfig.rpcUrl), }); - // @ts-ignore this.publicClient = createPublicClient({ - chain: VIEM_CHAINS[this.options.standConfig.chainId], + chain: SUPPORTED_CHAINS[this.options.standConfig.chainId], transport: http(this.options.standConfig.rpcUrl), }); // Collect incoming requests into an async queue diff --git a/yarn.lock b/yarn.lock index 1ed9e66c..837278fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== +"@adraffy/ens-normalize@^1.10.1": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz#42cc67c5baa407ac25059fcd7d405cc5ecdb0c33" + integrity sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg== + "@adraffy/ens-normalize@^1.11.0": version "1.11.1" resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz#6c2d657d4b2dfb37f8ea811dcb3e60843d4ac24a" @@ -1315,6 +1320,13 @@ dependencies: "@noble/hashes" "1.7.0" +"@noble/curves@1.8.2", "@noble/curves@~1.8.1": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.2.tgz#8f24c037795e22b90ae29e222a856294c1d9ffc7" + integrity sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g== + dependencies: + "@noble/hashes" "1.7.2" + "@noble/curves@1.9.1": version "1.9.1" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.1.tgz#9654a0bc6c13420ae252ddcf975eaf0f58f0a35c" @@ -1329,7 +1341,7 @@ dependencies: "@noble/hashes" "1.8.0" -"@noble/curves@~1.9.0": +"@noble/curves@^1.6.0", "@noble/curves@~1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.0.tgz#13e0ca8be4a0ce66c113693a94514e5599f40cfc" integrity sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg== @@ -1341,7 +1353,12 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.0.tgz#5d9e33af2c7d04fee35de1519b80c958b2e35e39" integrity sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w== -"@noble/hashes@1.8.0", "@noble/hashes@^1.1.5", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": +"@noble/hashes@1.7.2", "@noble/hashes@~1.7.1": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.2.tgz#d53c65a21658fb02f3303e7ee3ba89d6754c64b4" + integrity sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ== + +"@noble/hashes@1.8.0", "@noble/hashes@^1.1.5", "@noble/hashes@^1.5.0", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": version "1.8.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== @@ -1720,12 +1737,21 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.6.tgz#ca917184b8231394dd8847509c67a0be522e59f6" integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== -"@scure/base@~1.2.5": +"@scure/base@~1.2.2", "@scure/base@~1.2.4", "@scure/base@~1.2.5": version "1.2.5" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.5.tgz#f9d1b232425b367d0dcb81c96611dcc651d58671" integrity sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw== -"@scure/bip32@1.7.0", "@scure/bip32@^1.7.0": +"@scure/bip32@1.6.2": + version "1.6.2" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.6.2.tgz#093caa94961619927659ed0e711a6e4bf35bffd0" + integrity sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw== + dependencies: + "@noble/curves" "~1.8.1" + "@noble/hashes" "~1.7.1" + "@scure/base" "~1.2.2" + +"@scure/bip32@1.7.0", "@scure/bip32@^1.5.0", "@scure/bip32@^1.7.0": version "1.7.0" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.7.0.tgz#b8683bab172369f988f1589640e53c4606984219" integrity sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== @@ -1734,7 +1760,15 @@ "@noble/hashes" "~1.8.0" "@scure/base" "~1.2.5" -"@scure/bip39@1.6.0", "@scure/bip39@^1.6.0": +"@scure/bip39@1.5.4": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.5.4.tgz#07fd920423aa671be4540d59bdd344cc1461db51" + integrity sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA== + dependencies: + "@noble/hashes" "~1.7.1" + "@scure/base" "~1.2.4" + +"@scure/bip39@1.6.0", "@scure/bip39@^1.4.0", "@scure/bip39@^1.6.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.6.0.tgz#475970ace440d7be87a6086cbee77cb8f1a684f9" integrity sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A== @@ -2650,7 +2684,12 @@ abbrev@^2.0.0: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== -abitype@1.2.3, abitype@^1.0.9, abitype@^1.2.3: +abitype@1.0.8, abitype@^1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.8.tgz#3554f28b2e9d6e9f35eb59878193eabd1b9f46ba" + integrity sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg== + +abitype@^1.0.9: version "1.2.3" resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.2.3.tgz#bec3e09dea97d99ef6c719140bee663a329ad1f4" integrity sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg== @@ -5380,6 +5419,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isows@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.6.tgz#0da29d706fa51551c663c627ace42769850f86e7" + integrity sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw== + isows@1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.7.tgz#1c06400b7eed216fbba3bcbd68f12490fc342915" @@ -7171,18 +7215,31 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -ox@0.11.3: - version "0.11.3" - resolved "https://registry.yarnpkg.com/ox/-/ox-0.11.3.tgz#f50be1cae88822f5111b1e3f4a324c4c07eed422" - integrity sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw== +ox@0.6.9: + version "0.6.9" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.6.9.tgz#da1ee04fa10de30c8d04c15bfb80fe58b1f554bd" + integrity sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug== + dependencies: + "@adraffy/ens-normalize" "^1.10.1" + "@noble/curves" "^1.6.0" + "@noble/hashes" "^1.5.0" + "@scure/bip32" "^1.5.0" + "@scure/bip39" "^1.4.0" + abitype "^1.0.6" + eventemitter3 "5.0.1" + +ox@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.7.1.tgz#fb23a770dd966c051ad916d4e2e655a6f995e1cf" + integrity sha512-+k9fY9PRNuAMHRFIUbiK9Nt5seYHHzSQs9Bj+iMETcGtlpS7SmBzcGSVUQO3+nqGLEiNK4598pHNFlVRaZbRsg== dependencies: - "@adraffy/ens-normalize" "^1.11.0" + "@adraffy/ens-normalize" "^1.10.1" "@noble/ciphers" "^1.3.0" - "@noble/curves" "1.9.1" - "@noble/hashes" "^1.8.0" - "@scure/bip32" "^1.7.0" - "@scure/bip39" "^1.6.0" - abitype "^1.2.3" + "@noble/curves" "^1.6.0" + "@noble/hashes" "^1.5.0" + "@scure/bip32" "^1.5.0" + "@scure/bip39" "^1.4.0" + abitype "^1.0.6" eventemitter3 "5.0.1" ox@0.9.3: @@ -9166,19 +9223,33 @@ validate-npm-package-name@^5.0.0: resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== -viem@^2.21.40, viem@^2.22.0: - version "2.45.1" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.45.1.tgz#c1c373efcf2a0b30f5e454cfb4a9c18ac5bb5452" - integrity sha512-LN6Pp7vSfv50LgwhkfSbIXftAM5J89lP9x8TeDa8QM7o41IxlHrDh0F9X+FfnCWtsz11pEVV5sn+yBUoOHNqYA== +viem@^2.21.40: + version "2.31.0" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.31.0.tgz#2263426cce091d440e283b88183dff6f1d8bae5c" + integrity sha512-U7OMQ6yqK+bRbEIarf2vqxL7unSEQvNxvML/1zG7suAmKuJmipqdVTVJGKBCJiYsm/EremyO2FS4dHIPpGv+eA== dependencies: "@noble/curves" "1.9.1" "@noble/hashes" "1.8.0" "@scure/bip32" "1.7.0" "@scure/bip39" "1.6.0" - abitype "1.2.3" + abitype "1.0.8" isows "1.0.7" - ox "0.11.3" - ws "8.18.3" + ox "0.7.1" + ws "8.18.2" + +viem@^2.28.4: + version "2.29.2" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.29.2.tgz#e3033f68d6baf95c412593b213865e91634ac35e" + integrity sha512-cukRxab90jvQ+TDD84sU3qB3UmejYqgCw4cX8SfWzvh7JPfZXI3kAMUaT5OSR2As1Mgvx1EJawccwPjGqkSSwA== + dependencies: + "@noble/curves" "1.8.2" + "@noble/hashes" "1.7.2" + "@scure/bip32" "1.6.2" + "@scure/bip39" "1.5.4" + abitype "1.0.8" + isows "1.0.6" + ox "0.6.9" + ws "8.18.1" walk-up-path@^3.0.1: version "3.0.1" @@ -9377,10 +9448,15 @@ ws@8.18.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== -ws@8.18.3: - version "8.18.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" - integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== +ws@8.18.1: + version "8.18.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" + integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== + +ws@8.18.2: + version "8.18.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.2.tgz#42738b2be57ced85f46154320aabb51ab003705a" + integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== ws@^7.5.1: version "7.5.10" From 05fc39610a28a035b34cfd065785376805d213f5 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 3 Feb 2026 19:44:12 +0300 Subject: [PATCH 08/32] feat: update approveTokenTx and nextRequest methods for improved WalletConnect handling --- packages/wallets/src/wallet.page.ts | 7 +- .../wallets/src/walletConnect/wc.service.ts | 70 +++++-------------- 2 files changed, 23 insertions(+), 54 deletions(-) diff --git a/packages/wallets/src/wallet.page.ts b/packages/wallets/src/wallet.page.ts index 8b76647f..4304f310 100644 --- a/packages/wallets/src/wallet.page.ts +++ b/packages/wallets/src/wallet.page.ts @@ -67,7 +67,9 @@ export interface WalletPage { ): Promise; cancelTx(page: Page): Promise; - approveTokenTx?(page: Page): Promise; + approveTokenTx?( + page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page, + ): Promise; openLastTxInEthplorer?(txIndex?: number): Promise; @@ -97,4 +99,7 @@ export interface WalletPage { isClosePage?: boolean, ): Promise; isWalletAddressExist?(address: string): Promise; + + // WC SDK + nextRequest?(timeoutMs?: number): Promise; } diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 118489bf..96d482e6 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -1,15 +1,5 @@ import SignClient from '@walletconnect/sign-client'; -import { - createPublicClient, - createWalletClient, - HDAccount, - http, - PublicClient, - WalletClient, - Transport, - Chain, - Account, -} from 'viem'; +import { createPublicClient, createWalletClient, HDAccount, http } from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; import { WalletPage, WalletPageOptions } from '../wallet.page'; @@ -144,10 +134,12 @@ export class WCSDKWallet implements WalletPage { this.waiters = []; } - async nextRequest( - timeoutMs = this.options.walletConfig.walletConnectConfig - .requestHandleTimeoutMs, - ): Promise { + async nextRequest(timeoutMs?: number): Promise { + if (!timeoutMs) { + timeoutMs = + this.options.walletConfig.walletConnectConfig.requestHandleTimeoutMs; + } + const queued = this.requestQueue.shift(); if (queued) return queued; @@ -171,7 +163,11 @@ export class WCSDKWallet implements WalletPage { ); } - async confirmTx(req: WCSessionRequest | Page): Promise { + async confirmTx(req?: WCSessionRequest | Page): Promise { + if (!req) { + req = await this.nextRequest(); + } + if (!this.isWCSessionRequest(req)) { throw new Error( 'WC: confirmTx with Page parameter is not supported in WC wallet', @@ -229,10 +225,13 @@ export class WCSDKWallet implements WalletPage { } async cancelTx( - req: WCSessionRequest | Page, + req?: WCSessionRequest | Page, message = 'User rejected the request', code = 4001, ): Promise { + if (!req) { + req = await this.nextRequest(); + } if (!this.isWCSessionRequest(req)) { throw new Error( 'WC: confirmTx with Page parameter is not supported in WC wallet', @@ -320,49 +319,14 @@ export class WCSDKWallet implements WalletPage { assertTxAmount(page: Page, expectedAmount: string): Promise { throw new Error('Method not implemented.'); } - approveTokenTx?(page: Page): Promise { - throw new Error('Method not implemented.'); - } - openLastTxInEthplorer?(txIndex?: number): Promise { - throw new Error('Method not implemented.'); - } - getTokenBalance?(tokenName: string): Promise { - throw new Error('Method not implemented.'); - } - confirmAddTokenToWallet?(page: Page): Promise { - throw new Error('Method not implemented.'); - } assertReceiptAddress(page: Page, expectedAddress: string): Promise { throw new Error('Method not implemented.'); } - getWalletAddress?(): Promise { - throw new Error('Method not implemented.'); - } - setupNetwork?(networkConfig: NetworkConfig): Promise { - throw new Error('Method not implemented.'); - } + addNetwork( networkConfig: NetworkConfig, isClosePage?: boolean, ): Promise { throw new Error('Method not implemented.'); } - changeNetwork?(networkName: string): Promise { - throw new Error('Method not implemented.'); - } - changeWalletAccountByName?( - accountName: string, - isClosePage?: boolean, - ): Promise { - throw new Error('Method not implemented.'); - } - changeWalletAccountByAddress?( - address: string, - isClosePage?: boolean, - ): Promise { - throw new Error('Method not implemented.'); - } - isWalletAddressExist?(address: string): Promise { - throw new Error('Method not implemented.'); - } } From 374928f0de684e72792541b1c8c6b319d09fac50 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 3 Feb 2026 19:54:48 +0300 Subject: [PATCH 09/32] feat: update approveTokenTx and nextRequest methods for improved WalletConnect handling --- packages/wallets/src/wallet.page.ts | 10 ++++++++-- packages/wallets/src/walletConnect/wc.service.ts | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/wallets/src/wallet.page.ts b/packages/wallets/src/wallet.page.ts index 4304f310..1ad88b13 100644 --- a/packages/wallets/src/wallet.page.ts +++ b/packages/wallets/src/wallet.page.ts @@ -55,7 +55,10 @@ export interface WalletPage { param?: T extends WalletConnectTypes.EOA ? Page : string, ): Promise; - assertTxAmount(page: Page, expectedAmount: string): Promise; + assertTxAmount( + page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page, + expectedAmount: string, + ): Promise; confirmTx(req: WCSessionRequest): Promise; confirmTx(page: Page, setAggressiveGas?: boolean): Promise; @@ -77,7 +80,10 @@ export interface WalletPage { confirmAddTokenToWallet?(page: Page): Promise; - assertReceiptAddress(page: Page, expectedAddress: string): Promise; + assertReceiptAddress( + page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page, + expectedAddress: string, + ): Promise; getWalletAddress?(): Promise; diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 96d482e6..057fc803 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -316,10 +316,10 @@ export class WCSDKWallet implements WalletPage { importKey(secretKey: string, withChecks?: boolean): Promise { throw new Error('Method not implemented.'); } - assertTxAmount(page: Page, expectedAmount: string): Promise { + assertTxAmount(req: WCSessionRequest, expectedAmount: string): Promise { throw new Error('Method not implemented.'); } - assertReceiptAddress(page: Page, expectedAddress: string): Promise { + assertReceiptAddress(req: WCSessionRequest, expectedAddress: string): Promise { throw new Error('Method not implemented.'); } From 74b3a05b9662c311a40975b3ff3042a3c8e83646 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Wed, 4 Feb 2026 18:48:24 +0300 Subject: [PATCH 10/32] feat: update assertTxAmount and assertReceiptAddress methods to return void and enhance transaction validation --- packages/wallets/src/wallet.page.ts | 4 ++-- .../wallets/src/walletConnect/wc.service.ts | 23 ++++++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/wallets/src/wallet.page.ts b/packages/wallets/src/wallet.page.ts index 1ad88b13..4f4f7285 100644 --- a/packages/wallets/src/wallet.page.ts +++ b/packages/wallets/src/wallet.page.ts @@ -58,7 +58,7 @@ export interface WalletPage { assertTxAmount( page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page, expectedAmount: string, - ): Promise; + ): Promise | void; confirmTx(req: WCSessionRequest): Promise; confirmTx(page: Page, setAggressiveGas?: boolean): Promise; @@ -83,7 +83,7 @@ export interface WalletPage { assertReceiptAddress( page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page, expectedAddress: string, - ): Promise; + ): Promise | void; getWalletAddress?(): Promise; diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 057fc803..de612092 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -1,14 +1,14 @@ import SignClient from '@walletconnect/sign-client'; import { createPublicClient, createWalletClient, HDAccount, http } from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; - +import { formatEther } from 'viem/utils'; import { WalletPage, WalletPageOptions } from '../wallet.page'; import { NetworkConfig, WalletConnectTypes, WCApproveNamespaces, } from '../wallets.constants'; -import { Page } from '@playwright/test'; +import { Page, except } from '@playwright/test'; import { SUPPORTED_CHAINS } from './constants'; export type WCSessionRequest = { @@ -316,11 +316,22 @@ export class WCSDKWallet implements WalletPage { importKey(secretKey: string, withChecks?: boolean): Promise { throw new Error('Method not implemented.'); } - assertTxAmount(req: WCSessionRequest, expectedAmount: string): Promise { - throw new Error('Method not implemented.'); + + assertTxAmount(req: WCSessionRequest, expectedAmount: string): void { + const tx = this.getTx(req); + + if (tx.method === 'eth_sendTransaction') { + const txAmount = formatEther(BigInt(tx.value)); + expect(txAmount).toEqual(expectedAmount); + } } - assertReceiptAddress(req: WCSessionRequest, expectedAddress: string): Promise { - throw new Error('Method not implemented.'); + + assertReceiptAddress(req: WCSessionRequest, expectedAddress: string): void { + const tx = this.getTx(req); + + if (tx.method === 'eth_sendTransaction') { + expect(tx.to).toEqual(expectedAddress); + } } addNetwork( From c042e313d8bbdbf86e7775e628776774d106579d Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Wed, 4 Feb 2026 18:50:30 +0300 Subject: [PATCH 11/32] feat: update assertTxAmount and assertReceiptAddress methods to return void and enhance transaction validation --- packages/wallets/src/walletConnect/wc.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index de612092..238fc432 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -8,7 +8,7 @@ import { WalletConnectTypes, WCApproveNamespaces, } from '../wallets.constants'; -import { Page, except } from '@playwright/test'; +import { Page, expect } from '@playwright/test'; import { SUPPORTED_CHAINS } from './constants'; export type WCSessionRequest = { From 11458415cf39d84e1cda23ab6105245028f20b61 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Wed, 4 Feb 2026 23:41:05 +0300 Subject: [PATCH 12/32] feat: enhance transaction request handling and validation methods in WCSDKWallet --- .../wallets/src/walletConnect/wc.service.ts | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 238fc432..8ce8e850 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -1,7 +1,13 @@ import SignClient from '@walletconnect/sign-client'; -import { createPublicClient, createWalletClient, HDAccount, http } from 'viem'; +import { + createPublicClient, + createWalletClient, + HDAccount, + http, + formatEther, +} from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; -import { formatEther } from 'viem/utils'; + import { WalletPage, WalletPageOptions } from '../wallet.page'; import { NetworkConfig, @@ -253,6 +259,14 @@ export class WCSDKWallet implements WalletPage { return req.params?.request?.params?.[index]; } + getRequestInfo(req) { + const tx = this.getTx(req); + return { + method: req.params.request.method, + params: tx, + }; + } + private async waitForProposalOnce(timeoutMs: number) { if (!this.client) throw new Error('WC client not initialized'); @@ -318,19 +332,19 @@ export class WCSDKWallet implements WalletPage { } assertTxAmount(req: WCSessionRequest, expectedAmount: string): void { - const tx = this.getTx(req); + const requestInfo = this.getRequestInfo(req); - if (tx.method === 'eth_sendTransaction') { - const txAmount = formatEther(BigInt(tx.value)); + if (requestInfo.method === 'eth_sendTransaction') { + const txAmount = formatEther(BigInt(requestInfo.params.value)); expect(txAmount).toEqual(expectedAmount); } } assertReceiptAddress(req: WCSessionRequest, expectedAddress: string): void { - const tx = this.getTx(req); + const requestInfo = this.getRequestInfo(req); - if (tx.method === 'eth_sendTransaction') { - expect(tx.to).toEqual(expectedAddress); + if (requestInfo.method === 'eth_sendTransaction') { + expect(requestInfo.params.to).toEqual(expectedAddress); } } From 561016ace7f844149110d693064c3a2861b46599 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 9 Feb 2026 21:02:04 +0300 Subject: [PATCH 13/32] feat: enhance WCSDKWallet to support wallet_watchAsset and getTokenBalance methods --- .../wallets/src/walletConnect/wc.service.ts | 84 ++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 8ce8e850..cde76ba5 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -29,6 +29,12 @@ export type WCSessionRequest = { }; }; +type WatchedToken = { + address: `0x${string}`; + symbol?: string; + decimals?: number; +}; + export class WCSDKWallet implements WalletPage { private client?: SignClient; // @ts-ignore @@ -38,6 +44,8 @@ export class WCSDKWallet implements WalletPage { private requestQueue: WCSessionRequest[] = []; private waiters: Array<(req: WCSessionRequest) => void> = []; + private watchedTokensByAccount: Map = new Map(); + page?: Page; // not used for WC wallet but required by interface constructor(public options: WalletPageOptions) { @@ -64,6 +72,8 @@ export class WCSDKWallet implements WalletPage { 'eth_signTypedData_v4', 'wallet_switchEthereumChain', 'wallet_addEthereumChain', + 'wallet_watchAsset', + 'wallet_getCapabilities', ], events: ['accountsChanged', 'chainChanged'], }, @@ -91,8 +101,27 @@ export class WCSDKWallet implements WalletPage { transport: http(this.options.standConfig.rpcUrl), }); // Collect incoming requests into an async queue - this.client.on('session_request', (event) => { + this.client.on('session_request', async (event) => { const req = event as unknown as WCSessionRequest; + const method = req.params.request.method; + + if (method === 'wallet_getCapabilities') { + console.log( + 'Responding to wallet_getCapabilities with wallet_watchAsset support', + ); + await this.client.respond({ + topic: req.topic, + response: { + id: req.id, + jsonrpc: '2.0', + result: { + wallet_watchAsset: true, + }, + }, + }); + return; + } + console.log(`WC: session_request received: ${req.params.request.method}`); const waiter = this.waiters.shift(); if (waiter) waiter(req); @@ -225,6 +254,34 @@ export class WCSDKWallet implements WalletPage { topic: req.topic, response: { id: req.id, jsonrpc: '2.0', result: signature }, }); + } else if (method === 'wallet_watchAsset') { + console.log( + 'Token watch request received, auto-approving for test purposes.', + ); + const params = req.params.request.params?.[0]; + + const account = this.hdAccount.address.toLowerCase(); + + if (params?.type === 'ERC20' && params?.options?.address) { + const list = this.watchedTokensByAccount.get(account) ?? []; + + list.push({ + address: params.options.address.toLowerCase(), + symbol: params.options.symbol, + decimals: params.options.decimals, + }); + + this.watchedTokensByAccount.set(account, list); + } + + await this.client.respond({ + topic: req.topic, + response: { + id: req.id, + jsonrpc: '2.0', + result: true, + }, + }); } else { throw new Error(`WC: approveRequest unsupported method: ${method}`); } @@ -327,6 +384,31 @@ export class WCSDKWallet implements WalletPage { }; } + async getTokenBalance(tokenName: string): Promise { + const contractAddress = this.watchedTokensByAccount + .get(this.hdAccount.address.toLowerCase()) + ?.find((t) => t.symbol === tokenName)?.address; + + if (!contractAddress) { + const balance = await this.publicClient.readContract({ + address: contractAddress, + abi: [ + { + name: 'balanceOf', + type: 'function', + stateMutability: 'view', + inputs: [{ name: 'owner', type: 'address' }], + outputs: [{ name: '', type: 'uint256' }], + }, + ], + functionName: 'balanceOf', + args: [this.hdAccount.address], + }); + return balance; + } + throw new Error(`Token ${tokenName} not found in watched tokens`); + } + importKey(secretKey: string, withChecks?: boolean): Promise { throw new Error('Method not implemented.'); } From e3e835e031270d48c7bd0ea75a39279f5a575cda Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 9 Feb 2026 21:06:16 +0300 Subject: [PATCH 14/32] feat: enhance WCSDKWallet to support wallet_watchAsset and getTokenBalance methods --- packages/wallets/src/walletConnect/wc.service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index cde76ba5..9c521adb 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -5,6 +5,7 @@ import { HDAccount, http, formatEther, + formatUnits, } from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; @@ -404,7 +405,7 @@ export class WCSDKWallet implements WalletPage { functionName: 'balanceOf', args: [this.hdAccount.address], }); - return balance; + return Number(formatUnits(balance, 18)); } throw new Error(`Token ${tokenName} not found in watched tokens`); } From c3cb9947a23e956540729a4a6f2bb6eb35a3bc35 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 9 Feb 2026 21:15:39 +0300 Subject: [PATCH 15/32] feat: enhance WCSDKWallet to support wallet_watchAsset and getTokenBalance methods --- packages/wallets/src/walletConnect/wc.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 9c521adb..55e213bb 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -259,7 +259,7 @@ export class WCSDKWallet implements WalletPage { console.log( 'Token watch request received, auto-approving for test purposes.', ); - const params = req.params.request.params?.[0]; + const params = req.params.request.params; const account = this.hdAccount.address.toLowerCase(); @@ -390,7 +390,7 @@ export class WCSDKWallet implements WalletPage { .get(this.hdAccount.address.toLowerCase()) ?.find((t) => t.symbol === tokenName)?.address; - if (!contractAddress) { + if (contractAddress) { const balance = await this.publicClient.readContract({ address: contractAddress, abi: [ From 89fddcd0cac005bf4ec712e065e503abbe05ab4e Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 9 Feb 2026 21:19:24 +0300 Subject: [PATCH 16/32] feat: enhance WCSDKWallet to support wallet_watchAsset and getTokenBalance methods --- packages/wallets/src/walletConnect/wc.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 55e213bb..8b46053b 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -25,7 +25,7 @@ export type WCSessionRequest = { chainId: string; request: { method: string; - params: any[]; + params: any[] | any; }; }; }; From c4e65a44c87b3663dec7c29965db218d302d6849 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 9 Feb 2026 21:24:54 +0300 Subject: [PATCH 17/32] feat: update confirmAddTokenToWallet method to handle WCSessionRequest type --- packages/wallets/src/wallet.page.ts | 4 +- .../wallets/src/walletConnect/wc.service.ts | 66 ++++++++++++------- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/packages/wallets/src/wallet.page.ts b/packages/wallets/src/wallet.page.ts index 4f4f7285..3bc5660c 100644 --- a/packages/wallets/src/wallet.page.ts +++ b/packages/wallets/src/wallet.page.ts @@ -78,7 +78,9 @@ export interface WalletPage { getTokenBalance?(tokenName: string): Promise; - confirmAddTokenToWallet?(page: Page): Promise; + confirmAddTokenToWallet?( + page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page, + ): Promise; assertReceiptAddress( page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page, diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 8b46053b..f334c244 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -255,37 +255,57 @@ export class WCSDKWallet implements WalletPage { topic: req.topic, response: { id: req.id, jsonrpc: '2.0', result: signature }, }); - } else if (method === 'wallet_watchAsset') { - console.log( - 'Token watch request received, auto-approving for test purposes.', + } else { + throw new Error(`WC: unsupported method: ${method}`); + } + } + + async confirmAddTokenToWallet(req?: WCSessionRequest): Promise { + if (!req) { + req = await this.nextRequest(); + } + + if (!this.isWCSessionRequest(req)) { + throw new Error( + 'WC: confirmAddTokenToWallet with Page parameter is not supported in WC wallet', ); - const params = req.params.request.params; + } - const account = this.hdAccount.address.toLowerCase(); + if (!this.client) throw new Error('WC client not initialized'); - if (params?.type === 'ERC20' && params?.options?.address) { - const list = this.watchedTokensByAccount.get(account) ?? []; + const method = req.params.request.method; - list.push({ - address: params.options.address.toLowerCase(), - symbol: params.options.symbol, - decimals: params.options.decimals, - }); + if (method !== 'wallet_watchAsset') { + throw new Error( + `WC: unsupported method for confirm add token to wallet: ${method}`, + ); + } - this.watchedTokensByAccount.set(account, list); - } + console.log('Try to add token to wallet'); + const params = req.params.request.params; - await this.client.respond({ - topic: req.topic, - response: { - id: req.id, - jsonrpc: '2.0', - result: true, - }, + const account = this.hdAccount.address.toLowerCase(); + + if (params?.type === 'ERC20' && params?.options?.address) { + const list = this.watchedTokensByAccount.get(account) ?? []; + + list.push({ + address: params.options.address.toLowerCase(), + symbol: params.options.symbol, + decimals: params.options.decimals, }); - } else { - throw new Error(`WC: approveRequest unsupported method: ${method}`); + + this.watchedTokensByAccount.set(account, list); } + + await this.client.respond({ + topic: req.topic, + response: { + id: req.id, + jsonrpc: '2.0', + result: true, + }, + }); } async cancelTx( From a910cac76e70c48ab72004613e76dc2ec0e71968 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 10 Feb 2026 00:37:59 +0300 Subject: [PATCH 18/32] feat: add processed flag to WCSessionRequest and prevent reprocessing of requests --- .../wallets/src/walletConnect/wc.service.ts | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index f334c244..8aad2a88 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -28,6 +28,7 @@ export type WCSessionRequest = { params: any[] | any; }; }; + processed: boolean; // custom field to track if request was handled }; type WatchedToken = { @@ -209,7 +210,10 @@ export class WCSDKWallet implements WalletPage { 'WC: confirmTx with Page parameter is not supported in WC wallet', ); } - + if (req.processed) { + console.log('Request already processed'); + return; + } if (!this.client) throw new Error('WC client not initialized'); const method = req.params.request.method; @@ -258,6 +262,8 @@ export class WCSDKWallet implements WalletPage { } else { throw new Error(`WC: unsupported method: ${method}`); } + + req.processed = true; } async confirmAddTokenToWallet(req?: WCSessionRequest): Promise { @@ -270,7 +276,10 @@ export class WCSDKWallet implements WalletPage { 'WC: confirmAddTokenToWallet with Page parameter is not supported in WC wallet', ); } - + if (req.processed) { + console.log('Request already processed'); + return; + } if (!this.client) throw new Error('WC client not initialized'); const method = req.params.request.method; @@ -306,6 +315,7 @@ export class WCSDKWallet implements WalletPage { result: true, }, }); + req.processed = true; } async cancelTx( @@ -316,11 +326,16 @@ export class WCSDKWallet implements WalletPage { if (!req) { req = await this.nextRequest(); } + if (!this.isWCSessionRequest(req)) { throw new Error( - 'WC: confirmTx with Page parameter is not supported in WC wallet', + 'WC: cancelTx with Page parameter is not supported in WC wallet', ); } + if (req.processed) { + console.log('Request already processed'); + return; + } if (!this.client) throw new Error('WC client not initialized'); await this.client.respond({ @@ -331,6 +346,7 @@ export class WCSDKWallet implements WalletPage { error: { code, message }, }, }); + req.processed = true; } getTx(req: WCSessionRequest, index = 0): any { From 4cee8a17e6e3558192691148442c062a5a20c253 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 10 Feb 2026 01:42:33 +0300 Subject: [PATCH 19/32] feat: update WC_SDK_COMMON_CONFIG to correct CONNECTED_WALLET_NAME --- .../wallets/src/metamask/metamask-stable/metamask.constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts b/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts index cf6c45c7..71920465 100644 --- a/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts +++ b/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts @@ -20,7 +20,7 @@ export const METAMASK_STABLE_COMMON_CONFIG: CommonWalletConfig = { export const WC_SDK_COMMON_CONFIG: CommonWalletConfig = { WALLET_NAME: 'wcSDK', EXTENSION_WALLET_NAME: 'wcSDK', - CONNECTED_WALLET_NAME: 'wcSDK', + CONNECTED_WALLET_NAME: 'WalletConnect', CONNECT_BUTTON_NAME: 'WalletConnect', STORE_EXTENSION_ID: 'nkbihfbeogaeaoehlefnkodbefgpgknn', WALLET_TYPE: WalletConnectTypes.WC_SDK, From 2bad439cec3bf0933d3c0515c655b149feec3449 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 10 Feb 2026 14:12:20 +0300 Subject: [PATCH 20/32] feat: refactor confirmTx and cancelTx methods to remove WCSessionRequest type --- packages/wallets/src/coin98/coin98.page.ts | 5 ++--- packages/wallets/src/coinbase/coinbase.page.ts | 7 ++----- packages/wallets/src/exodus/exodus.page.ts | 5 ++--- .../src/metamask/metamask-latest/metamask.page.ts | 11 ++++------- .../src/metamask/metamask-stable/metamask.page.ts | 11 ++++------- packages/wallets/src/okx/okx.page.ts | 9 ++++----- packages/wallets/src/safe/safeIframe.page.ts | 5 ++--- packages/wallets/src/trustwallet/trustWallet.page.ts | 9 ++++----- packages/wallets/src/wallet.page.ts | 11 +++++------ packages/wallets/src/walletConnect/wc.service.ts | 8 +++----- 10 files changed, 32 insertions(+), 49 deletions(-) diff --git a/packages/wallets/src/coin98/coin98.page.ts b/packages/wallets/src/coin98/coin98.page.ts index 9ad17af6..7ee40989 100644 --- a/packages/wallets/src/coin98/coin98.page.ts +++ b/packages/wallets/src/coin98/coin98.page.ts @@ -2,7 +2,6 @@ import { WalletConnectTypes } from '../wallets.constants'; import { WalletPage, WalletPageOptions } from '../wallet.page'; import { test, Page } from '@playwright/test'; import { ConsoleLogger } from '@nestjs/common'; -import { WCSessionRequest } from '../walletConnect/wc.service'; export class Coin98 implements WalletPage { logger = new ConsoleLogger(Coin98.name); @@ -138,9 +137,9 @@ export class Coin98 implements WalletPage { throw new Error('Method not implemented.'); } - async confirmTx(page: Page | WCSessionRequest) { + async confirmTx(page: Page) { await test.step('Confirm TX', async () => { - await (page as Page).click('button:has-text("Confirm")'); + await page.click('button:has-text("Confirm")'); }); } diff --git a/packages/wallets/src/coinbase/coinbase.page.ts b/packages/wallets/src/coinbase/coinbase.page.ts index 42d4b037..1b01ab6f 100644 --- a/packages/wallets/src/coinbase/coinbase.page.ts +++ b/packages/wallets/src/coinbase/coinbase.page.ts @@ -3,7 +3,6 @@ import { WalletPage, WalletPageOptions } from '../wallet.page'; import expect from 'expect'; import { test, Page } from '@playwright/test'; import { ConsoleLogger } from '@nestjs/common'; -import { WCSessionRequest } from '../walletConnect/wc.service'; export class CoinbasePage implements WalletPage { logger = new ConsoleLogger(CoinbasePage.name); @@ -135,12 +134,10 @@ export class CoinbasePage implements WalletPage { }); } - async confirmTx(page: Page | WCSessionRequest) { + async confirmTx(page: Page) { await test.step('Confirm TX', async () => { await this.closeTransactionPopover(); - await (page as Page).click( - 'button[data-testid="request-confirm-button"]', - ); + await page.click('button[data-testid="request-confirm-button"]'); }); } diff --git a/packages/wallets/src/exodus/exodus.page.ts b/packages/wallets/src/exodus/exodus.page.ts index 822821d2..bd2b41ab 100644 --- a/packages/wallets/src/exodus/exodus.page.ts +++ b/packages/wallets/src/exodus/exodus.page.ts @@ -3,7 +3,6 @@ import { WalletPage, WalletPageOptions } from '../wallet.page'; import { test, Page } from '@playwright/test'; import { OnboardingPage } from './pages'; import { ConsoleLogger } from '@nestjs/common'; -import { WCSessionRequest } from '../walletConnect/wc.service'; export class ExodusPage implements WalletPage { logger = new ConsoleLogger(ExodusPage.name); @@ -75,9 +74,9 @@ export class ExodusPage implements WalletPage { } /** Click `Confirm` button on the transaction `page` */ - async confirmTx(page: Page | WCSessionRequest) { + async confirmTx(page: Page) { await test.step('Confirm TX', async () => { - await (page as Page).getByText('Confirm').click(); + await page.getByText('Confirm').click(); }); } diff --git a/packages/wallets/src/metamask/metamask-latest/metamask.page.ts b/packages/wallets/src/metamask/metamask-latest/metamask.page.ts index ca5cb2cb..70cdeeb2 100644 --- a/packages/wallets/src/metamask/metamask-latest/metamask.page.ts +++ b/packages/wallets/src/metamask/metamask-latest/metamask.page.ts @@ -18,7 +18,6 @@ import { } from './pages/elements'; import { getAddress } from 'viem'; import { isPopularMainnetNetwork, isPopularTestnetNetwork } from './helper'; -import { WCSessionRequest } from '../../walletConnect/wc.service'; export class MetamaskPage implements WalletPage { page: Page | undefined; @@ -214,17 +213,15 @@ export class MetamaskPage implements WalletPage { }); } - async confirmTx(page: Page | WCSessionRequest, setAggressiveGas?: boolean) { + async confirmTx(page: Page, setAggressiveGas?: boolean) { await test.step('Confirm TX', async () => { - await new WalletOperationPage(page as Page).confirmTransaction( - setAggressiveGas, - ); + await new WalletOperationPage(page).confirmTransaction(setAggressiveGas); }); } - async cancelTx(page: Page | WCSessionRequest) { + async cancelTx(page: Page) { await test.step('Reject TX', async () => { - await new WalletOperationPage(page as Page).cancelTransaction(); + await new WalletOperationPage(page).cancelTransaction(); }); } diff --git a/packages/wallets/src/metamask/metamask-stable/metamask.page.ts b/packages/wallets/src/metamask/metamask-stable/metamask.page.ts index 6fd7ee84..3bf4e11b 100644 --- a/packages/wallets/src/metamask/metamask-stable/metamask.page.ts +++ b/packages/wallets/src/metamask/metamask-stable/metamask.page.ts @@ -22,7 +22,6 @@ import { isPopularTestnetNetwork, } from './helper'; import { privateKeyToAccount } from 'viem/accounts'; -import { WCSessionRequest } from '../../walletConnect/wc.service'; export class MetamaskStablePage implements WalletPage { page: Page | undefined; @@ -235,17 +234,15 @@ export class MetamaskStablePage implements WalletPage { }); } - async confirmTx(page: Page | WCSessionRequest, setAggressiveGas?: boolean) { + async confirmTx(page: Page, setAggressiveGas?: boolean) { await test.step('Confirm TX', async () => { - await new WalletOperationPage(page as Page).confirmTransaction( - setAggressiveGas, - ); + await new WalletOperationPage(page).confirmTransaction(setAggressiveGas); }); } - async cancelTx(page: Page | WCSessionRequest) { + async cancelTx(page: Page) { await test.step('Reject TX', async () => { - await new WalletOperationPage(page as Page).cancelTransaction(); + await new WalletOperationPage(page).cancelTransaction(); }); } diff --git a/packages/wallets/src/okx/okx.page.ts b/packages/wallets/src/okx/okx.page.ts index e02527d7..3b50bedc 100644 --- a/packages/wallets/src/okx/okx.page.ts +++ b/packages/wallets/src/okx/okx.page.ts @@ -17,7 +17,6 @@ import { } from './helper'; import { ConsoleLogger } from '@nestjs/common'; import { WalletPageOptions } from '../wallet.page'; -import { WCSessionRequest } from '../walletConnect/wc.service'; export class OkxPage implements WalletPage { logger = new ConsoleLogger(OkxPage.name); @@ -190,16 +189,16 @@ export class OkxPage implements WalletPage { } /** Cancel transaction */ - async cancelTx(page: Page | WCSessionRequest) { + async cancelTx(page: Page) { await test.step('Cancel TX', async () => { - await new WalletOperations(page as Page).cancelTxButton.click(); + await new WalletOperations(page).cancelTxButton.click(); }); } /** Confirm transaction */ - async confirmTx(page: Page | WCSessionRequest) { + async confirmTx(page: Page) { await test.step('Confirm TX', async () => { - await new WalletOperations(page as Page).confirmTxButton.click({ + await new WalletOperations(page).confirmTxButton.click({ timeout: 30000, // sometimes button is disabled awaits rpc }); }); diff --git a/packages/wallets/src/safe/safeIframe.page.ts b/packages/wallets/src/safe/safeIframe.page.ts index e3ab6fb1..213c3741 100644 --- a/packages/wallets/src/safe/safeIframe.page.ts +++ b/packages/wallets/src/safe/safeIframe.page.ts @@ -3,7 +3,6 @@ import { WalletPage, WalletPageOptions } from '../wallet.page'; import { NetworkConfig, WalletConnectTypes } from '../wallets.constants'; import { ConsoleLogger } from '@nestjs/common'; import { SetupPage, SettingPage, TransactionPage } from './pages'; -import { WCSessionRequest } from '../walletConnect/wc.service'; export class SafeIframePage implements WalletPage { logger = new ConsoleLogger(SafeIframePage.name); @@ -115,10 +114,10 @@ export class SafeIframePage implements WalletPage { }); } - async confirmTx(page: Page | WCSessionRequest) { + async confirmTx(page: Page) { await test.step('Confirm transaction', async () => { const transactionPage = new TransactionPage( - page as Page, + page, this.options.extensionPage, ); await transactionPage.confirmTransaction(); diff --git a/packages/wallets/src/trustwallet/trustWallet.page.ts b/packages/wallets/src/trustwallet/trustWallet.page.ts index d77d4c62..03e93445 100644 --- a/packages/wallets/src/trustwallet/trustWallet.page.ts +++ b/packages/wallets/src/trustwallet/trustWallet.page.ts @@ -10,7 +10,6 @@ import { LoginPage, } from './pages'; import { closeUnnecessaryPages } from '../okx/helper'; -import { WCSessionRequest } from '../walletConnect/wc.service'; export class TrustWalletPage implements WalletPage { logger = new ConsoleLogger(TrustWalletPage.name); @@ -133,18 +132,18 @@ export class TrustWalletPage implements WalletPage { } /** Confirm transaction */ - async confirmTx(page: Page | WCSessionRequest) { + async confirmTx(page: Page) { await test.step('Confirm TX', async () => { - const txPage = new WalletOperations(page as Page); + const txPage = new WalletOperations(page); await expect(txPage.confirmBtn).toBeEnabled(); await txPage.confirmBtn.click(); }); } /** Reject transaction */ - async cancelTx(page: Page | WCSessionRequest) { + async cancelTx(page: Page) { await test.step('Cancel TX', async () => { - const txPage = new WalletOperations(page as Page); + const txPage = new WalletOperations(page); await expect(txPage.rejectBtn).toBeEnabled(); await txPage.rejectBtn.click(); }); diff --git a/packages/wallets/src/wallet.page.ts b/packages/wallets/src/wallet.page.ts index 3bc5660c..5308b2f6 100644 --- a/packages/wallets/src/wallet.page.ts +++ b/packages/wallets/src/wallet.page.ts @@ -60,15 +60,14 @@ export interface WalletPage { expectedAmount: string, ): Promise | void; - confirmTx(req: WCSessionRequest): Promise; - confirmTx(page: Page, setAggressiveGas?: boolean): Promise; + confirmTx( + page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page, + setAggressiveGas?: boolean, + ): Promise; cancelTx( - req: WCSessionRequest, - message?: string, - code?: number, + page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page, ): Promise; - cancelTx(page: Page): Promise; approveTokenTx?( page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page, diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 8aad2a88..5f9799b8 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -318,11 +318,9 @@ export class WCSDKWallet implements WalletPage { req.processed = true; } - async cancelTx( - req?: WCSessionRequest | Page, - message = 'User rejected the request', - code = 4001, - ): Promise { + async cancelTx(req?: WCSessionRequest): Promise { + const message = 'User rejected the request'; + const code = 4001; if (!req) { req = await this.nextRequest(); } From 8bc20549fc705fe3b9ad7d9156301486d58a76b1 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 10 Feb 2026 15:36:10 +0300 Subject: [PATCH 21/32] feat: add cancelAllTxRequests method to WCSDKWallet for batch transaction cancellation --- packages/wallets/src/wallet.page.ts | 1 + .../wallets/src/walletConnect/wc.service.ts | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/wallets/src/wallet.page.ts b/packages/wallets/src/wallet.page.ts index 5308b2f6..ba3dad52 100644 --- a/packages/wallets/src/wallet.page.ts +++ b/packages/wallets/src/wallet.page.ts @@ -109,4 +109,5 @@ export interface WalletPage { // WC SDK nextRequest?(timeoutMs?: number): Promise; + cancelAllTxRequests?(): Promise; } diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 5f9799b8..262016f9 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -45,6 +45,7 @@ export class WCSDKWallet implements WalletPage { private hdAccount: HDAccount; private requestQueue: WCSessionRequest[] = []; + private pendingRequests: WCSessionRequest[] = []; private waiters: Array<(req: WCSessionRequest) => void> = []; private watchedTokensByAccount: Map = new Map(); @@ -178,7 +179,10 @@ export class WCSDKWallet implements WalletPage { } const queued = this.requestQueue.shift(); - if (queued) return queued; + if (queued) { + this.pendingRequests.push(queued); + return queued; + } return await new Promise((resolve, reject) => { const t = setTimeout(() => { @@ -189,6 +193,7 @@ export class WCSDKWallet implements WalletPage { this.waiters.push((req) => { clearTimeout(t); + this.pendingRequests.push(req); resolve(req); }); }); @@ -264,6 +269,7 @@ export class WCSDKWallet implements WalletPage { } req.processed = true; + this.pendingRequests = this.pendingRequests.filter((r) => r.id !== req.id); } async confirmAddTokenToWallet(req?: WCSessionRequest): Promise { @@ -316,6 +322,7 @@ export class WCSDKWallet implements WalletPage { }, }); req.processed = true; + this.pendingRequests = this.pendingRequests.filter((r) => r.id !== req.id); } async cancelTx(req?: WCSessionRequest): Promise { @@ -345,6 +352,7 @@ export class WCSDKWallet implements WalletPage { }, }); req.processed = true; + this.pendingRequests = this.pendingRequests.filter((r) => r.id !== req.id); } getTx(req: WCSessionRequest, index = 0): any { @@ -471,4 +479,12 @@ export class WCSDKWallet implements WalletPage { ): Promise { throw new Error('Method not implemented.'); } + + async cancelAllTxRequests() { + while (this.requestQueue.length > 0 || this.pendingRequests.length > 0) { + const req = + this.requestQueue.shift() || this.pendingRequests.shift() || null; + if (req) await this.cancelTx(req); + } + } } From e22cc85312888f6e3bf3ab71087ca1cd36abd357 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Tue, 10 Feb 2026 17:29:59 +0300 Subject: [PATCH 22/32] feat: add cancelAllTxRequests method to WCSDKWallet for batch transaction cancellation --- packages/wallets/src/walletConnect/wc.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 262016f9..ea85f7f8 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -205,7 +205,7 @@ export class WCSDKWallet implements WalletPage { ); } - async confirmTx(req?: WCSessionRequest | Page): Promise { + async confirmTx(req?: WCSessionRequest): Promise { if (!req) { req = await this.nextRequest(); } From b86f9ed50cde4aabcb9081247022934b9decba56 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Wed, 11 Feb 2026 14:41:11 +0300 Subject: [PATCH 23/32] feat: setup fork --- packages/browser-service/src/browser.service.ts | 9 +++++++++ packages/wallets/src/walletConnect/wc.service.ts | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/browser-service/src/browser.service.ts b/packages/browser-service/src/browser.service.ts index 51e93368..d4a80eb1 100644 --- a/packages/browser-service/src/browser.service.ts +++ b/packages/browser-service/src/browser.service.ts @@ -105,6 +105,15 @@ export class BrowserService { const account = this.ethereumNodeService.getAccount(); await this.setup(); + if (this.options.walletConfig.WALLET_TYPE === WalletConnectTypes.WC_SDK) { + await this.ethereumNodeService.mockRoute( + this.options.nodeConfig.rpcUrlToMock, + this.browserContextService.browserContext, + ); + + return; + } + if (!(await this.walletPage.isWalletAddressExist(account.address))) { await this.walletPage.importKey(account.secretKey); } else { diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index ea85f7f8..03fbca50 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -469,7 +469,9 @@ export class WCSDKWallet implements WalletPage { const requestInfo = this.getRequestInfo(req); if (requestInfo.method === 'eth_sendTransaction') { - expect(requestInfo.params.to).toEqual(expectedAddress); + expect(requestInfo.params.to.toLowerCase()).toEqual( + expectedAddress.toLowerCase(), + ); } } From b652178f28979098056f1dc477f9e8622d5c3bc8 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Thu, 12 Feb 2026 00:58:12 +0300 Subject: [PATCH 24/32] feat: setup add/change network for wc --- .../browser-service/src/browser.service.ts | 3 +- .../wallets/src/walletConnect/constants.ts | 21 ++++ .../wallets/src/walletConnect/wc.service.ts | 108 +++++++++++++++++- 3 files changed, 125 insertions(+), 7 deletions(-) diff --git a/packages/browser-service/src/browser.service.ts b/packages/browser-service/src/browser.service.ts index d4a80eb1..e508238e 100644 --- a/packages/browser-service/src/browser.service.ts +++ b/packages/browser-service/src/browser.service.ts @@ -87,8 +87,9 @@ export class BrowserService { await this.setupWithNode(); } else { await this.setup(); + await this.walletPage.setupNetwork(this.options.networkConfig); + if (this.options.walletConfig.WALLET_TYPE !== WalletConnectTypes.WC_SDK) { - await this.walletPage.setupNetwork(this.options.networkConfig); await this.walletPage.changeNetwork( this.options.networkConfig.chainName, ); diff --git a/packages/wallets/src/walletConnect/constants.ts b/packages/wallets/src/walletConnect/constants.ts index ee1df8e9..e4a95433 100644 --- a/packages/wallets/src/walletConnect/constants.ts +++ b/packages/wallets/src/walletConnect/constants.ts @@ -11,6 +11,7 @@ import { unichain, unichainSepolia, } from 'viem/chains'; +import { NetworkConfig } from '../wallets.constants'; export const SUPPORTED_CHAINS: Record = { 1: mainnet as Chain, @@ -24,3 +25,23 @@ export const SUPPORTED_CHAINS: Record = { 130: unichain as Chain, 1301: unichainSepolia as Chain, }; + +export function buildChainFromNetwork(network: NetworkConfig): Chain { + return { + id: network.chainId, + name: network.chainName, + nativeCurrency: { + name: network.tokenSymbol, + symbol: network.tokenSymbol, + decimals: 18, + }, + rpcUrls: { + default: { + http: [network.rpcUrl], + }, + public: { + http: [network.rpcUrl], + }, + }, + } as const satisfies Chain; +} diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 03fbca50..3d5d29d7 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -6,6 +6,7 @@ import { http, formatEther, formatUnits, + Chain, } from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; @@ -16,7 +17,7 @@ import { WCApproveNamespaces, } from '../wallets.constants'; import { Page, expect } from '@playwright/test'; -import { SUPPORTED_CHAINS } from './constants'; +import { SUPPORTED_CHAINS, buildChainFromNetwork } from './constants'; export type WCSessionRequest = { topic: string; @@ -49,6 +50,11 @@ export class WCSDKWallet implements WalletPage { private waiters: Array<(req: WCSessionRequest) => void> = []; private watchedTokensByAccount: Map = new Map(); + // network settings + private activeChainId: number; + private networksByChainId = new Map(); + private chainIdByName = new Map(); + page?: Page; // not used for WC wallet but required by interface constructor(public options: WalletPageOptions) { @@ -475,11 +481,101 @@ export class WCSDKWallet implements WalletPage { } } - addNetwork( - networkConfig: NetworkConfig, - isClosePage?: boolean, - ): Promise { - throw new Error('Method not implemented.'); + async setupNetwork(networkConfig: NetworkConfig): Promise { + this.networksByChainId.set(networkConfig.chainId, networkConfig); + this.chainIdByName.set( + this.normalizeChainName(networkConfig.chainName), + networkConfig.chainId, + ); + } + + private getActiveSession() { + if (!this.client) throw new Error('WC client not initialized'); + const sessions = this.client.session.getAll(); + const session = sessions[0]; + if (!session) throw new Error('No active WC session'); + return session; + } + + private normalizeChainName(name: string) { + return name.trim().toLowerCase(); + } + + async addNetwork(networkConfig: NetworkConfig): Promise { + if (!this.client) throw new Error('WC client not initialized'); + + const session = this.getActiveSession(); + const ns = session.namespaces?.eip155; + if (!ns) throw new Error('Session has no eip155 namespace'); + + const addr = this.hdAccount.address; + const newAccount = `eip155:${networkConfig.chainId}:${addr}`; + + const nextNamespaces = { + ...session.namespaces, + eip155: { + accounts: Array.from(new Set([...(ns.accounts ?? []), newAccount])), + methods: ns.methods ?? [], + events: ns.events ?? [], + }, + }; + + await this.client.update({ + topic: session.topic, + namespaces: nextNamespaces, + }); + + this.networksByChainId.set(networkConfig.chainId, networkConfig); + this.chainIdByName.set( + this.normalizeChainName(networkConfig.chainName), + networkConfig.chainId, + ); + } + + private rebuildViemClients(chain: Chain) { + const net = this.networksByChainId.get(chain.id); + if (!net?.rpcUrl) + throw new Error(`No rpcUrl registered for chainId=${chain.id}`); + + //@ts-ignore + this.walletClient = createWalletClient({ + account: this.hdAccount, + chain, + transport: http(net.rpcUrl), + }); + + this.publicClient = createPublicClient({ + chain, + transport: http(net.rpcUrl), + }); + + this.activeChainId = chain.id; + } + + async changeNetwork(networkName: string): Promise { + if (!this.client) throw new Error('WC client not initialized'); + + const normalized = this.normalizeChainName(networkName); + const chainId = this.chainIdByName.get(normalized); + const networkConfig = this.networksByChainId.get(chainId); + + if (!chainId) { + const known = Array.from(this.chainIdByName.keys()).sort(); + throw new Error( + `Unknown network "${networkName}". Registered networks: ${known.join( + ', ', + )}`, + ); + } + const chain = buildChainFromNetwork(networkConfig); + this.rebuildViemClients(chain); + + const session = this.getActiveSession(); + await this.client.emit({ + topic: session.topic, + chainId: `eip155:${chainId}`, + event: { name: 'chainChanged', data: `0x${chainId.toString(16)}` }, + }); } async cancelAllTxRequests() { From d100d42f6014aded06ef937a13cacf2ecfaee130 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Thu, 12 Feb 2026 01:03:06 +0300 Subject: [PATCH 25/32] feat: setup add/change network for wc --- .../wallets/src/walletConnect/wc.service.ts | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 3d5d29d7..08e25be9 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -534,20 +534,22 @@ export class WCSDKWallet implements WalletPage { private rebuildViemClients(chain: Chain) { const net = this.networksByChainId.get(chain.id); - if (!net?.rpcUrl) - throw new Error(`No rpcUrl registered for chainId=${chain.id}`); - - //@ts-ignore - this.walletClient = createWalletClient({ - account: this.hdAccount, - chain, - transport: http(net.rpcUrl), - }); + if (net?.rpcUrl) { + //@ts-ignore + this.walletClient = createWalletClient({ + account: this.hdAccount, + chain, + transport: http(net.rpcUrl), + }); - this.publicClient = createPublicClient({ - chain, - transport: http(net.rpcUrl), - }); + this.publicClient = createPublicClient({ + chain, + transport: http(net.rpcUrl), + }); + } else { + this.walletClient = null; + this.publicClient = null; + } this.activeChainId = chain.id; } @@ -567,7 +569,8 @@ export class WCSDKWallet implements WalletPage { )}`, ); } - const chain = buildChainFromNetwork(networkConfig); + const chain = + SUPPORTED_CHAINS[chainId] ?? buildChainFromNetwork(networkConfig); this.rebuildViemClients(chain); const session = this.getActiveSession(); From aea5079e1403bba3905299e09cf891c2c845e94d Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Thu, 12 Feb 2026 01:14:45 +0300 Subject: [PATCH 26/32] feat: setup network for fork --- .../browser-service/src/browser.service.ts | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/packages/browser-service/src/browser.service.ts b/packages/browser-service/src/browser.service.ts index e508238e..94b6b164 100644 --- a/packages/browser-service/src/browser.service.ts +++ b/packages/browser-service/src/browser.service.ts @@ -106,19 +106,12 @@ export class BrowserService { const account = this.ethereumNodeService.getAccount(); await this.setup(); - if (this.options.walletConfig.WALLET_TYPE === WalletConnectTypes.WC_SDK) { - await this.ethereumNodeService.mockRoute( - this.options.nodeConfig.rpcUrlToMock, - this.browserContextService.browserContext, - ); - - return; - } - - if (!(await this.walletPage.isWalletAddressExist(account.address))) { - await this.walletPage.importKey(account.secretKey); - } else { - await this.walletPage.changeWalletAccountByAddress(account.address); + if (this.options.walletConfig.WALLET_TYPE !== WalletConnectTypes.WC_SDK) { + if (!(await this.walletPage.isWalletAddressExist(account.address))) { + await this.walletPage.importKey(account.secretKey); + } else { + await this.walletPage.changeWalletAccountByAddress(account.address); + } } await this.walletPage.setupNetwork({ @@ -131,7 +124,9 @@ export class BrowserService { this.options.nodeConfig.rpcUrlToMock, this.browserContextService.browserContext, ); - await this.browserContextService.closePages(); + if (this.options.walletConfig.WALLET_TYPE !== WalletConnectTypes.WC_SDK) { + await this.browserContextService.closePages(); + } } async setup() { From 7a56cfa396ec5b158b145a0ae240c684a58710ef Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Thu, 12 Feb 2026 21:22:35 +0300 Subject: [PATCH 27/32] feat: refactoring all code --- packages/pg-reporter/src/reportRuntime.ts | 2 +- .../src/walletConnect/components/index.ts | 2 + .../src/walletConnect/components/network.ts | 91 +++++ .../components/requestManager.ts | 71 ++++ .../methods/eth_sendTransaction.ts | 24 ++ .../methods/eth_signTypedData_v4.ts | 31 ++ .../src/walletConnect/methods/index.ts | 3 + .../methods/wallet_watchAsset.ts | 32 ++ .../wallets/src/walletConnect/wc.service.ts | 344 ++++-------------- 9 files changed, 332 insertions(+), 268 deletions(-) create mode 100644 packages/wallets/src/walletConnect/components/index.ts create mode 100644 packages/wallets/src/walletConnect/components/network.ts create mode 100644 packages/wallets/src/walletConnect/components/requestManager.ts create mode 100644 packages/wallets/src/walletConnect/methods/eth_sendTransaction.ts create mode 100644 packages/wallets/src/walletConnect/methods/eth_signTypedData_v4.ts create mode 100644 packages/wallets/src/walletConnect/methods/index.ts create mode 100644 packages/wallets/src/walletConnect/methods/wallet_watchAsset.ts diff --git a/packages/pg-reporter/src/reportRuntime.ts b/packages/pg-reporter/src/reportRuntime.ts index f2b3388b..4055d405 100644 --- a/packages/pg-reporter/src/reportRuntime.ts +++ b/packages/pg-reporter/src/reportRuntime.ts @@ -251,7 +251,7 @@ export class ReporterRuntime { }); } - const suite = suiteStats.get(suiteKey)!; + const suite = suiteStats.get(suiteKey); suite.total++; if (testCase.status === 'passed') suite.passed++; diff --git a/packages/wallets/src/walletConnect/components/index.ts b/packages/wallets/src/walletConnect/components/index.ts new file mode 100644 index 00000000..655515b0 --- /dev/null +++ b/packages/wallets/src/walletConnect/components/index.ts @@ -0,0 +1,2 @@ +export * from './network'; +export * from './requestManager'; diff --git a/packages/wallets/src/walletConnect/components/network.ts b/packages/wallets/src/walletConnect/components/network.ts new file mode 100644 index 00000000..8aa945b5 --- /dev/null +++ b/packages/wallets/src/walletConnect/components/network.ts @@ -0,0 +1,91 @@ +import { Chain, HDAccount } from 'viem'; +import { NetworkConfig } from '../../wallets.constants'; +import { SUPPORTED_CHAINS, buildChainFromNetwork } from '../constants'; +import { SignClient } from '@walletconnect/sign-client/dist/types/client'; + +export class NetworkSettings { + public activeChainId: number; + public networksByChainId = new Map(); + public chainIdByName = new Map(); + + constructor(private client: SignClient, private hdAccount: HDAccount) {} + + private normalizeChainName(name: string) { + return name.trim().toLowerCase(); + } + + private getActiveSession() { + if (!this.client) throw new Error('WC client not initialized'); + const sessions = this.client.session.getAll(); + const session = sessions[0]; + if (!session) throw new Error('No active WC session'); + return session; + } + + async setupNetwork(networkConfig: NetworkConfig): Promise { + this.networksByChainId.set(networkConfig.chainId, networkConfig); + this.chainIdByName.set( + this.normalizeChainName(networkConfig.chainName), + networkConfig.chainId, + ); + } + + async addNetwork(networkConfig: NetworkConfig): Promise { + if (!this.client) throw new Error('WC client not initialized'); + + const session = this.getActiveSession(); + const ns = session.namespaces?.eip155; + if (!ns) throw new Error('Session has no eip155 namespace'); + + const addr = this.hdAccount.address; + const newAccount = `eip155:${networkConfig.chainId}:${addr}`; + + const newNamespaces = { + ...session.namespaces, + eip155: { + accounts: Array.from(new Set([...(ns.accounts ?? []), newAccount])), + methods: ns.methods ?? [], + events: ns.events ?? [], + }, + }; + + await this.client.update({ + topic: session.topic, + namespaces: newNamespaces, + }); + + this.networksByChainId.set(networkConfig.chainId, networkConfig); + this.chainIdByName.set( + this.normalizeChainName(networkConfig.chainName), + networkConfig.chainId, + ); + } + + async changeNetwork(networkName: string): Promise { + if (!this.client) throw new Error('WC client not initialized'); + + const normalized = this.normalizeChainName(networkName); + const chainId = this.chainIdByName.get(normalized); + const networkConfig = this.networksByChainId.get(chainId); + + if (!chainId) { + const known = Array.from(this.chainIdByName.keys()).sort(); + throw new Error( + `Unknown network "${networkName}". Registered networks: ${known.join( + ', ', + )}`, + ); + } + const session = this.getActiveSession(); + await this.client.emit({ + topic: session.topic, + chainId: `eip155:${chainId}`, + event: { name: 'chainChanged', data: `0x${chainId.toString(16)}` }, + }); + const chain = + SUPPORTED_CHAINS[chainId] ?? buildChainFromNetwork(networkConfig); + this.activeChainId = chain.id; + + return chain; + } +} diff --git a/packages/wallets/src/walletConnect/components/requestManager.ts b/packages/wallets/src/walletConnect/components/requestManager.ts new file mode 100644 index 00000000..3047db82 --- /dev/null +++ b/packages/wallets/src/walletConnect/components/requestManager.ts @@ -0,0 +1,71 @@ +import { WCSessionRequest } from '../wc.service'; + +export class RequestManager { + public queue: WCSessionRequest[] = []; + public pendings: WCSessionRequest[] = []; + public waiters: Array<(req: WCSessionRequest) => void> = []; + + async nextRequest(timeoutMs?: number): Promise { + const queued = this.queue.shift(); + if (queued) { + this.pendings.push(queued); + return queued; + } + + return await new Promise((resolve, reject) => { + const t = setTimeout(() => { + const idx = this.waiters.indexOf(resolve); + if (idx >= 0) this.waiters.splice(idx, 1); + reject(new Error(`WC: session_request timeout after ${timeoutMs}ms`)); + }, timeoutMs); + + this.waiters.push((req) => { + clearTimeout(t); + this.pendings.push(req); + resolve(req); + }); + }); + } + + isWCSessionRequest(x: any): x is WCSessionRequest { + return ( + x && typeof x === 'object' && 'topic' in x && 'id' in x && 'params' in x + ); + } + + getTx(req: WCSessionRequest, index = 0): any { + return req.params?.request?.params?.[index]; + } + + getRequestInfo(req) { + const tx = this.getTx(req); + return { + method: req.params.request.method, + params: tx, + }; + } + + async validateRequest( + req: WCSessionRequest, + ): Promise { + if (!req) { + return this.nextRequest(); + } + + if (!this.isWCSessionRequest(req)) { + throw new Error( + 'WC: Page parameter instead WCSessionRequest is not supported in WC wallet', + ); + } + if (req.processed) { + console.log('Request already processed'); + return undefined; + } + return req; + } + + resolveRequest(req: WCSessionRequest) { + req.processed = true; + this.pendings = this.pendings.filter((r) => r.id !== req.id); + } +} diff --git a/packages/wallets/src/walletConnect/methods/eth_sendTransaction.ts b/packages/wallets/src/walletConnect/methods/eth_sendTransaction.ts new file mode 100644 index 00000000..88f43b9c --- /dev/null +++ b/packages/wallets/src/walletConnect/methods/eth_sendTransaction.ts @@ -0,0 +1,24 @@ +import { WCSDKWallet, WCSessionRequest } from '../wc.service'; + +export async function eth_sendTransaction( + this: WCSDKWallet, + req: WCSessionRequest, +) { + // @ts-expect-error - it will be work + const fees = await this.publicClient.estimateFeesPerGas(); + const value = req.params.request.params[0].value + ? BigInt(req.params.request.params[0].value) + : undefined; + const hash = await this.walletClient.sendTransaction({ + ...req.params.request.params[0], + value, + gas: BigInt(req.params.request.params[0].gas), + maxFeePerGas: fees.maxFeePerGas, + maxPriorityFeePerGas: fees.maxPriorityFeePerGas, + }); + + await this.signClient.respond({ + topic: req.topic, + response: { id: req.id, jsonrpc: '2.0', result: hash }, + }); +} diff --git a/packages/wallets/src/walletConnect/methods/eth_signTypedData_v4.ts b/packages/wallets/src/walletConnect/methods/eth_signTypedData_v4.ts new file mode 100644 index 00000000..6a744b51 --- /dev/null +++ b/packages/wallets/src/walletConnect/methods/eth_signTypedData_v4.ts @@ -0,0 +1,31 @@ +import { WCSDKWallet, WCSessionRequest } from '../wc.service'; + +export async function eth_signTypedData_v4( + this: WCSDKWallet, + req: WCSessionRequest, +) { + const typed = req.params.request.params[1]; + const typedData = typeof typed === 'string' ? JSON.parse(typed) : typed; + + const signature = await this.walletClient.signTypedData({ + account: this.hdAccount, + domain: { + ...typedData.domain, + chainId: Number(typedData.domain.chainId), + }, + types: typedData.types, + primaryType: typedData.primaryType, + message: { + ...typedData.message, + value: BigInt(typedData.message.value), + nonce: BigInt(typedData.message.nonce), + deadline: BigInt(typedData.message.deadline), + }, + }); + console.log('Signature was created.'); + + await this.signClient.respond({ + topic: req.topic, + response: { id: req.id, jsonrpc: '2.0', result: signature }, + }); +} diff --git a/packages/wallets/src/walletConnect/methods/index.ts b/packages/wallets/src/walletConnect/methods/index.ts new file mode 100644 index 00000000..3ba98685 --- /dev/null +++ b/packages/wallets/src/walletConnect/methods/index.ts @@ -0,0 +1,3 @@ +export * from './eth_sendTransaction'; +export * from './wallet_watchAsset'; +export * from './eth_signTypedData_v4'; diff --git a/packages/wallets/src/walletConnect/methods/wallet_watchAsset.ts b/packages/wallets/src/walletConnect/methods/wallet_watchAsset.ts new file mode 100644 index 00000000..af2ec74d --- /dev/null +++ b/packages/wallets/src/walletConnect/methods/wallet_watchAsset.ts @@ -0,0 +1,32 @@ +import { WCSDKWallet, WCSessionRequest } from '../wc.service'; + +export async function wallet_watchAsset( + this: WCSDKWallet, + req: WCSessionRequest, +) { + console.log('Try to add token to wallet'); + const params = req.params.request.params; + + const account = this.hdAccount.address.toLowerCase(); + + if (params?.type === 'ERC20' && params?.options?.address) { + const list = this.watchedTokensByAccount.get(account) ?? []; + + list.push({ + address: params.options.address.toLowerCase(), + symbol: params.options.symbol, + decimals: params.options.decimals, + }); + + this.watchedTokensByAccount.set(account, list); + } + + await this.signClient.respond({ + topic: req.topic, + response: { + id: req.id, + jsonrpc: '2.0', + result: true, + }, + }); +} diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 08e25be9..12e539c0 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -16,8 +16,14 @@ import { WalletConnectTypes, WCApproveNamespaces, } from '../wallets.constants'; -import { Page, expect } from '@playwright/test'; -import { SUPPORTED_CHAINS, buildChainFromNetwork } from './constants'; +import { expect } from '@playwright/test'; +import { SUPPORTED_CHAINS } from './constants'; +import { NetworkSettings, RequestManager } from './components'; +import { + eth_sendTransaction, + eth_signTypedData_v4, + wallet_watchAsset, +} from './methods'; export type WCSessionRequest = { topic: string; @@ -38,24 +44,24 @@ type WatchedToken = { decimals?: number; }; +const handlers: Record Promise> = { + eth_sendTransaction: eth_sendTransaction, + eth_signTypedData_v4: eth_signTypedData_v4, + wallet_watchAsset: wallet_watchAsset, +}; + export class WCSDKWallet implements WalletPage { - private client?: SignClient; - // @ts-ignore - private publicClient?: ReturnType; - private walletClient?: ReturnType; - private hdAccount: HDAccount; + protected signClient?: SignClient; + // @ts-expect-error - it will be work + protected publicClient?: ReturnType; + protected walletClient?: ReturnType; + protected hdAccount: HDAccount; - private requestQueue: WCSessionRequest[] = []; - private pendingRequests: WCSessionRequest[] = []; - private waiters: Array<(req: WCSessionRequest) => void> = []; - private watchedTokensByAccount: Map = new Map(); + protected watchedTokensByAccount: Map = new Map(); // network settings - private activeChainId: number; - private networksByChainId = new Map(); - private chainIdByName = new Map(); - - page?: Page; // not used for WC wallet but required by interface + private networkSettings: NetworkSettings; + private requestManager: RequestManager; constructor(public options: WalletPageOptions) { this.hdAccount = mnemonicToAccount( @@ -92,13 +98,16 @@ export class WCSDKWallet implements WalletPage { } async setup(): Promise { - if (this.client) return; + if (this.signClient) return; - this.client = await SignClient.init({ + this.signClient = await SignClient.init({ projectId: this.options.walletConfig.walletConnectConfig.projectId, metadata: this.options.walletConfig.walletConnectConfig.metadata, }); + this.networkSettings = new NetworkSettings(this.signClient, this.hdAccount); + this.requestManager = new RequestManager(); + this.walletClient = createWalletClient({ account: this.hdAccount, chain: SUPPORTED_CHAINS[this.options.standConfig.chainId], @@ -109,8 +118,9 @@ export class WCSDKWallet implements WalletPage { chain: SUPPORTED_CHAINS[this.options.standConfig.chainId], transport: http(this.options.standConfig.rpcUrl), }); + // Collect incoming requests into an async queue - this.client.on('session_request', async (event) => { + this.signClient.on('session_request', async (event) => { const req = event as unknown as WCSessionRequest; const method = req.params.request.method; @@ -118,7 +128,7 @@ export class WCSDKWallet implements WalletPage { console.log( 'Responding to wallet_getCapabilities with wallet_watchAsset support', ); - await this.client.respond({ + await this.signClient.respond({ topic: req.topic, response: { id: req.id, @@ -132,21 +142,21 @@ export class WCSDKWallet implements WalletPage { } console.log(`WC: session_request received: ${req.params.request.method}`); - const waiter = this.waiters.shift(); + const waiter = this.requestManager.waiters.shift(); if (waiter) waiter(req); - else this.requestQueue.push(req); + else this.requestManager.queue.push(req); }); } async connectWallet(uri: string): Promise { await this.setup(); - if (!this.client) throw new Error('WC client not initialized'); + if (!this.signClient) throw new Error('WC client not initialized'); const [proposal] = await Promise.all([ this.waitForProposalOnce( this.options.walletConfig.walletConnectConfig.requestHandleTimeoutMs, ), - this.client.core.pairing.pair({ uri }), + this.signClient.core.pairing.pair({ uri }), ]); const { id, params } = proposal; @@ -154,17 +164,17 @@ export class WCSDKWallet implements WalletPage { this.options.walletConfig.walletConnectConfig.namespaces ?? this.buildNamespacesFromProposal(params); - const { acknowledged } = await this.client.approve({ id, namespaces }); + const { acknowledged } = await this.signClient.approve({ id, namespaces }); await acknowledged(); } async disconnect(): Promise { - if (!this.client) throw new Error('WC client not initialized'); + if (!this.signClient) throw new Error('WC client not initialized'); - const sessions = this.client.session.getAll(); + const sessions = this.signClient.session.getAll(); for (const sess of sessions) { console.log('WC: disconnecting session', sess.topic); - await this.client.disconnect({ + await this.signClient.disconnect({ topic: sess.topic, reason: { code: 6000, @@ -172,10 +182,10 @@ export class WCSDKWallet implements WalletPage { }, }); } - await this.client.core.relayer.transportClose(); - this.client = undefined; - this.requestQueue = []; - this.waiters = []; + await this.signClient.core.relayer.transportClose(); + this.signClient = undefined; + this.requestManager.queue = []; + this.requestManager.waiters = []; } async nextRequest(timeoutMs?: number): Promise { @@ -183,116 +193,27 @@ export class WCSDKWallet implements WalletPage { timeoutMs = this.options.walletConfig.walletConnectConfig.requestHandleTimeoutMs; } - - const queued = this.requestQueue.shift(); - if (queued) { - this.pendingRequests.push(queued); - return queued; - } - - return await new Promise((resolve, reject) => { - const t = setTimeout(() => { - const idx = this.waiters.indexOf(resolve); - if (idx >= 0) this.waiters.splice(idx, 1); - reject(new Error(`WC: session_request timeout after ${timeoutMs}ms`)); - }, timeoutMs); - - this.waiters.push((req) => { - clearTimeout(t); - this.pendingRequests.push(req); - resolve(req); - }); - }); - } - - isWCSessionRequest(x: any): x is WCSessionRequest { - return ( - x && typeof x === 'object' && 'topic' in x && 'id' in x && 'params' in x - ); + return this.requestManager.nextRequest(timeoutMs); } async confirmTx(req?: WCSessionRequest): Promise { - if (!req) { - req = await this.nextRequest(); - } - - if (!this.isWCSessionRequest(req)) { - throw new Error( - 'WC: confirmTx with Page parameter is not supported in WC wallet', - ); - } - if (req.processed) { - console.log('Request already processed'); - return; - } - if (!this.client) throw new Error('WC client not initialized'); + req = await this.requestManager.validateRequest(req); + if (!this.signClient) throw new Error('WC client not initialized'); const method = req.params.request.method; - if (method === 'eth_sendTransaction') { - const fees = await this.publicClient.estimateFeesPerGas(); - const value = req.params.request.params[0].value - ? BigInt(req.params.request.params[0].value) - : undefined; - const hash = await this.walletClient.sendTransaction({ - ...req.params.request.params[0], - value, - gas: BigInt(req.params.request.params[0].gas), - maxFeePerGas: fees.maxFeePerGas, - maxPriorityFeePerGas: fees.maxPriorityFeePerGas, - }); - await this.client.respond({ - topic: req.topic, - response: { id: req.id, jsonrpc: '2.0', result: hash }, - }); - } else if (method === 'eth_signTypedData_v4') { - const typed = req.params.request.params[1]; - const typedData = typeof typed === 'string' ? JSON.parse(typed) : typed; - - const signature = await this.walletClient.signTypedData({ - account: this.hdAccount, - domain: { - ...typedData.domain, - chainId: Number(typedData.domain.chainId), - }, - types: typedData.types, - primaryType: typedData.primaryType, - message: { - ...typedData.message, - value: BigInt(typedData.message.value), - nonce: BigInt(typedData.message.nonce), - deadline: BigInt(typedData.message.deadline), - }, - }); - console.log('Signature was created.'); - - await this.client.respond({ - topic: req.topic, - response: { id: req.id, jsonrpc: '2.0', result: signature }, - }); - } else { + const handler = handlers[method]; + if (!handler) { throw new Error(`WC: unsupported method: ${method}`); } + await handler.call(this, req); - req.processed = true; - this.pendingRequests = this.pendingRequests.filter((r) => r.id !== req.id); + this.requestManager.resolveRequest(req); } async confirmAddTokenToWallet(req?: WCSessionRequest): Promise { - if (!req) { - req = await this.nextRequest(); - } - - if (!this.isWCSessionRequest(req)) { - throw new Error( - 'WC: confirmAddTokenToWallet with Page parameter is not supported in WC wallet', - ); - } - if (req.processed) { - console.log('Request already processed'); - return; - } - if (!this.client) throw new Error('WC client not initialized'); + req = await this.requestManager.validateRequest(req); + if (!this.signClient) throw new Error('WC client not initialized'); const method = req.params.request.method; @@ -302,79 +223,30 @@ export class WCSDKWallet implements WalletPage { ); } - console.log('Try to add token to wallet'); - const params = req.params.request.params; - - const account = this.hdAccount.address.toLowerCase(); - - if (params?.type === 'ERC20' && params?.options?.address) { - const list = this.watchedTokensByAccount.get(account) ?? []; + await handlers[method].call(this, req); - list.push({ - address: params.options.address.toLowerCase(), - symbol: params.options.symbol, - decimals: params.options.decimals, - }); - - this.watchedTokensByAccount.set(account, list); - } - - await this.client.respond({ - topic: req.topic, - response: { - id: req.id, - jsonrpc: '2.0', - result: true, - }, - }); - req.processed = true; - this.pendingRequests = this.pendingRequests.filter((r) => r.id !== req.id); + this.requestManager.resolveRequest(req); } async cancelTx(req?: WCSessionRequest): Promise { - const message = 'User rejected the request'; - const code = 4001; - if (!req) { - req = await this.nextRequest(); - } + req = await this.requestManager.validateRequest(req); - if (!this.isWCSessionRequest(req)) { - throw new Error( - 'WC: cancelTx with Page parameter is not supported in WC wallet', - ); - } - if (req.processed) { - console.log('Request already processed'); - return; - } - if (!this.client) throw new Error('WC client not initialized'); + if (!this.signClient) throw new Error('WC client not initialized'); - await this.client.respond({ + await this.signClient.respond({ topic: req.topic, response: { id: req.id, jsonrpc: '2.0', - error: { code, message }, + error: { code: 4001, message: 'User rejected the request' }, }, }); - req.processed = true; - this.pendingRequests = this.pendingRequests.filter((r) => r.id !== req.id); - } - getTx(req: WCSessionRequest, index = 0): any { - return req.params?.request?.params?.[index]; - } - - getRequestInfo(req) { - const tx = this.getTx(req); - return { - method: req.params.request.method, - params: tx, - }; + this.requestManager.resolveRequest(req); } private async waitForProposalOnce(timeoutMs: number) { - if (!this.client) throw new Error('WC client not initialized'); + if (!this.signClient) throw new Error('WC client not initialized'); return await new Promise((resolve, reject) => { const t = setTimeout( @@ -385,7 +257,7 @@ export class WCSDKWallet implements WalletPage { timeoutMs, ); - this.client.once('session_proposal', (proposal) => { + this.signClient.once('session_proposal', (proposal) => { clearTimeout(t); resolve(proposal); }); @@ -458,12 +330,13 @@ export class WCSDKWallet implements WalletPage { throw new Error(`Token ${tokenName} not found in watched tokens`); } + // eslint-disable-next-line @typescript-eslint/no-unused-vars importKey(secretKey: string, withChecks?: boolean): Promise { throw new Error('Method not implemented.'); } assertTxAmount(req: WCSessionRequest, expectedAmount: string): void { - const requestInfo = this.getRequestInfo(req); + const requestInfo = this.requestManager.getRequestInfo(req); if (requestInfo.method === 'eth_sendTransaction') { const txAmount = formatEther(BigInt(requestInfo.params.value)); @@ -472,7 +345,7 @@ export class WCSDKWallet implements WalletPage { } assertReceiptAddress(req: WCSessionRequest, expectedAddress: string): void { - const requestInfo = this.getRequestInfo(req); + const requestInfo = this.requestManager.getRequestInfo(req); if (requestInfo.method === 'eth_sendTransaction') { expect(requestInfo.params.to.toLowerCase()).toEqual( @@ -482,60 +355,21 @@ export class WCSDKWallet implements WalletPage { } async setupNetwork(networkConfig: NetworkConfig): Promise { - this.networksByChainId.set(networkConfig.chainId, networkConfig); - this.chainIdByName.set( - this.normalizeChainName(networkConfig.chainName), - networkConfig.chainId, - ); - } - - private getActiveSession() { - if (!this.client) throw new Error('WC client not initialized'); - const sessions = this.client.session.getAll(); - const session = sessions[0]; - if (!session) throw new Error('No active WC session'); - return session; - } - - private normalizeChainName(name: string) { - return name.trim().toLowerCase(); + await this.networkSettings.setupNetwork(networkConfig); } async addNetwork(networkConfig: NetworkConfig): Promise { - if (!this.client) throw new Error('WC client not initialized'); - - const session = this.getActiveSession(); - const ns = session.namespaces?.eip155; - if (!ns) throw new Error('Session has no eip155 namespace'); - - const addr = this.hdAccount.address; - const newAccount = `eip155:${networkConfig.chainId}:${addr}`; - - const nextNamespaces = { - ...session.namespaces, - eip155: { - accounts: Array.from(new Set([...(ns.accounts ?? []), newAccount])), - methods: ns.methods ?? [], - events: ns.events ?? [], - }, - }; - - await this.client.update({ - topic: session.topic, - namespaces: nextNamespaces, - }); + await this.networkSettings.addNetwork(networkConfig); + } - this.networksByChainId.set(networkConfig.chainId, networkConfig); - this.chainIdByName.set( - this.normalizeChainName(networkConfig.chainName), - networkConfig.chainId, - ); + async changeNetwork(networkName: string): Promise { + const chain = await this.networkSettings.changeNetwork(networkName); + this.rebuildViemClients(chain); } private rebuildViemClients(chain: Chain) { - const net = this.networksByChainId.get(chain.id); + const net = this.networkSettings.networksByChainId.get(chain.id); if (net?.rpcUrl) { - //@ts-ignore this.walletClient = createWalletClient({ account: this.hdAccount, chain, @@ -550,41 +384,17 @@ export class WCSDKWallet implements WalletPage { this.walletClient = null; this.publicClient = null; } - - this.activeChainId = chain.id; - } - - async changeNetwork(networkName: string): Promise { - if (!this.client) throw new Error('WC client not initialized'); - - const normalized = this.normalizeChainName(networkName); - const chainId = this.chainIdByName.get(normalized); - const networkConfig = this.networksByChainId.get(chainId); - - if (!chainId) { - const known = Array.from(this.chainIdByName.keys()).sort(); - throw new Error( - `Unknown network "${networkName}". Registered networks: ${known.join( - ', ', - )}`, - ); - } - const chain = - SUPPORTED_CHAINS[chainId] ?? buildChainFromNetwork(networkConfig); - this.rebuildViemClients(chain); - - const session = this.getActiveSession(); - await this.client.emit({ - topic: session.topic, - chainId: `eip155:${chainId}`, - event: { name: 'chainChanged', data: `0x${chainId.toString(16)}` }, - }); } async cancelAllTxRequests() { - while (this.requestQueue.length > 0 || this.pendingRequests.length > 0) { + while ( + this.requestManager.queue.length > 0 || + this.requestManager.pendings.length > 0 + ) { const req = - this.requestQueue.shift() || this.pendingRequests.shift() || null; + this.requestManager.queue.shift() || + this.requestManager.pendings.shift() || + null; if (req) await this.cancelTx(req); } } From 7d03734e14e5bf23088ee88f9ac7f2a68fcd1aba Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Thu, 12 Feb 2026 21:54:24 +0300 Subject: [PATCH 28/32] feat: refactoring all code --- packages/wallets/src/wallet.page.ts | 2 +- .../components/requestManager.ts | 13 +++- .../methods/eth_sendTransaction.ts | 6 +- .../methods/eth_signTypedData_v4.ts | 3 +- .../methods/wallet_getCapabilities.ts | 21 ++++++ .../methods/wallet_watchAsset.ts | 3 +- .../wallets/src/walletConnect/wc.service.ts | 74 ++++++------------- 7 files changed, 65 insertions(+), 57 deletions(-) create mode 100644 packages/wallets/src/walletConnect/methods/wallet_getCapabilities.ts diff --git a/packages/wallets/src/wallet.page.ts b/packages/wallets/src/wallet.page.ts index ba3dad52..16a597f8 100644 --- a/packages/wallets/src/wallet.page.ts +++ b/packages/wallets/src/wallet.page.ts @@ -7,7 +7,7 @@ import { WalletConnectType, WalletConnectTypes, } from './wallets.constants'; -import { WCSessionRequest } from './walletConnect/wc.service'; +import { WCSessionRequest } from './walletConnect/components'; /** Required options to manage wallet */ export interface WalletPageOptions { diff --git a/packages/wallets/src/walletConnect/components/requestManager.ts b/packages/wallets/src/walletConnect/components/requestManager.ts index 3047db82..04da27b5 100644 --- a/packages/wallets/src/walletConnect/components/requestManager.ts +++ b/packages/wallets/src/walletConnect/components/requestManager.ts @@ -1,4 +1,15 @@ -import { WCSessionRequest } from '../wc.service'; +export type WCSessionRequest = { + topic: string; + id: number; + params: { + chainId: string; + request: { + method: string; + params: any[] | any; + }; + }; + processed: boolean; // custom field to track if request was handled +}; export class RequestManager { public queue: WCSessionRequest[] = []; diff --git a/packages/wallets/src/walletConnect/methods/eth_sendTransaction.ts b/packages/wallets/src/walletConnect/methods/eth_sendTransaction.ts index 88f43b9c..4b7f32aa 100644 --- a/packages/wallets/src/walletConnect/methods/eth_sendTransaction.ts +++ b/packages/wallets/src/walletConnect/methods/eth_sendTransaction.ts @@ -1,10 +1,12 @@ -import { WCSDKWallet, WCSessionRequest } from '../wc.service'; +import { WCSessionRequest } from '../components'; +import { WCSDKWallet } from '../wc.service'; export async function eth_sendTransaction( this: WCSDKWallet, req: WCSessionRequest, ) { - // @ts-expect-error - it will be work + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const fees = await this.publicClient.estimateFeesPerGas(); const value = req.params.request.params[0].value ? BigInt(req.params.request.params[0].value) diff --git a/packages/wallets/src/walletConnect/methods/eth_signTypedData_v4.ts b/packages/wallets/src/walletConnect/methods/eth_signTypedData_v4.ts index 6a744b51..720bcbfc 100644 --- a/packages/wallets/src/walletConnect/methods/eth_signTypedData_v4.ts +++ b/packages/wallets/src/walletConnect/methods/eth_signTypedData_v4.ts @@ -1,4 +1,5 @@ -import { WCSDKWallet, WCSessionRequest } from '../wc.service'; +import { WCSessionRequest } from '../components'; +import { WCSDKWallet } from '../wc.service'; export async function eth_signTypedData_v4( this: WCSDKWallet, diff --git a/packages/wallets/src/walletConnect/methods/wallet_getCapabilities.ts b/packages/wallets/src/walletConnect/methods/wallet_getCapabilities.ts new file mode 100644 index 00000000..49b2be99 --- /dev/null +++ b/packages/wallets/src/walletConnect/methods/wallet_getCapabilities.ts @@ -0,0 +1,21 @@ +import { WCSessionRequest } from '../components'; +import { WCSDKWallet } from '../wc.service'; + +export async function wallet_getCapabilities( + this: WCSDKWallet, + req: WCSessionRequest, +) { + console.log( + 'Responding to wallet_getCapabilities with wallet_watchAsset support', + ); + await this.signClient.respond({ + topic: req.topic, + response: { + id: req.id, + jsonrpc: '2.0', + result: { + wallet_watchAsset: true, + }, + }, + }); +} diff --git a/packages/wallets/src/walletConnect/methods/wallet_watchAsset.ts b/packages/wallets/src/walletConnect/methods/wallet_watchAsset.ts index af2ec74d..3dd2343f 100644 --- a/packages/wallets/src/walletConnect/methods/wallet_watchAsset.ts +++ b/packages/wallets/src/walletConnect/methods/wallet_watchAsset.ts @@ -1,4 +1,5 @@ -import { WCSDKWallet, WCSessionRequest } from '../wc.service'; +import { WCSessionRequest } from '../components'; +import { WCSDKWallet } from '../wc.service'; export async function wallet_watchAsset( this: WCSDKWallet, diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 12e539c0..abe76f7e 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -18,25 +18,17 @@ import { } from '../wallets.constants'; import { expect } from '@playwright/test'; import { SUPPORTED_CHAINS } from './constants'; -import { NetworkSettings, RequestManager } from './components'; +import { + NetworkSettings, + RequestManager, + WCSessionRequest, +} from './components'; import { eth_sendTransaction, eth_signTypedData_v4, wallet_watchAsset, } from './methods'; - -export type WCSessionRequest = { - topic: string; - id: number; - params: { - chainId: string; - request: { - method: string; - params: any[] | any; - }; - }; - processed: boolean; // custom field to track if request was handled -}; +import { wallet_getCapabilities } from './methods/wallet_getCapabilities'; type WatchedToken = { address: `0x${string}`; @@ -52,7 +44,8 @@ const handlers: Record Promise> = { export class WCSDKWallet implements WalletPage { protected signClient?: SignClient; - // @ts-expect-error - it will be work + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore protected publicClient?: ReturnType; protected walletClient?: ReturnType; protected hdAccount: HDAccount; @@ -70,12 +63,6 @@ export class WCSDKWallet implements WalletPage { this.options.walletConfig.walletConnectConfig = { requestHandleTimeoutMs: 30_000, - metadata: { - name: 'E2E Test Wallet', - description: 'WalletConnect test wallet for e2e', - url: 'https://example.wallet', - icons: ['https://example.wallet/icon.png'], - }, namespaces: { eip155: { accounts: [ @@ -85,8 +72,6 @@ export class WCSDKWallet implements WalletPage { 'eth_sendTransaction', 'personal_sign', 'eth_signTypedData_v4', - 'wallet_switchEthereumChain', - 'wallet_addEthereumChain', 'wallet_watchAsset', 'wallet_getCapabilities', ], @@ -102,7 +87,6 @@ export class WCSDKWallet implements WalletPage { this.signClient = await SignClient.init({ projectId: this.options.walletConfig.walletConnectConfig.projectId, - metadata: this.options.walletConfig.walletConnectConfig.metadata, }); this.networkSettings = new NetworkSettings(this.signClient, this.hdAccount); @@ -125,19 +109,7 @@ export class WCSDKWallet implements WalletPage { const method = req.params.request.method; if (method === 'wallet_getCapabilities') { - console.log( - 'Responding to wallet_getCapabilities with wallet_watchAsset support', - ); - await this.signClient.respond({ - topic: req.topic, - response: { - id: req.id, - jsonrpc: '2.0', - result: { - wallet_watchAsset: true, - }, - }, - }); + await wallet_getCapabilities.call(this, req); return; } @@ -245,10 +217,23 @@ export class WCSDKWallet implements WalletPage { this.requestManager.resolveRequest(req); } + async cancelAllTxRequests() { + while ( + this.requestManager.queue.length > 0 || + this.requestManager.pendings.length > 0 + ) { + const req = + this.requestManager.queue.shift() || + this.requestManager.pendings.shift() || + null; + if (req) await this.cancelTx(req); + } + } + private async waitForProposalOnce(timeoutMs: number) { if (!this.signClient) throw new Error('WC client not initialized'); - return await new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const t = setTimeout( () => reject( @@ -385,17 +370,4 @@ export class WCSDKWallet implements WalletPage { this.publicClient = null; } } - - async cancelAllTxRequests() { - while ( - this.requestManager.queue.length > 0 || - this.requestManager.pendings.length > 0 - ) { - const req = - this.requestManager.queue.shift() || - this.requestManager.pendings.shift() || - null; - if (req) await this.cancelTx(req); - } - } } From 1aaeb98f5ce2eb1ebd2f7cfc9a7e2387330e1be5 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 16 Feb 2026 18:32:36 +0300 Subject: [PATCH 29/32] feat: rename nextRequest to waitForTransaction in WCSDKWallet --- packages/wallets/src/wallet.page.ts | 2 +- packages/wallets/src/walletConnect/wc.service.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/wallets/src/wallet.page.ts b/packages/wallets/src/wallet.page.ts index 16a597f8..6e14fa06 100644 --- a/packages/wallets/src/wallet.page.ts +++ b/packages/wallets/src/wallet.page.ts @@ -108,6 +108,6 @@ export interface WalletPage { isWalletAddressExist?(address: string): Promise; // WC SDK - nextRequest?(timeoutMs?: number): Promise; + waitForTransaction?(timeoutMs?: number): Promise; cancelAllTxRequests?(): Promise; } diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index abe76f7e..65118bec 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -160,7 +160,7 @@ export class WCSDKWallet implements WalletPage { this.requestManager.waiters = []; } - async nextRequest(timeoutMs?: number): Promise { + async waitForTransaction(timeoutMs?: number): Promise { if (!timeoutMs) { timeoutMs = this.options.walletConfig.walletConnectConfig.requestHandleTimeoutMs; From 2f6622cf82d254be46ffe7e7b18e3d687f0d229a Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 16 Feb 2026 20:08:20 +0300 Subject: [PATCH 30/32] feat: update WC_SDK_COMMON_CONFIG and modify CommonWalletConfig structure --- .../metamask-stable/metamask.constants.ts | 18 ------------------ .../wallets/src/walletConnect/constants.ts | 18 +++++++++++++++++- packages/wallets/src/wallets.constants.ts | 12 +----------- 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts b/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts index 71920465..613c5f31 100644 --- a/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts +++ b/packages/wallets/src/metamask/metamask-stable/metamask.constants.ts @@ -16,21 +16,3 @@ export const METAMASK_STABLE_COMMON_CONFIG: CommonWalletConfig = { 'https://github.com/MetaMask/metamask-extension/releases/download/v12.10.4/metamask-chrome-12.10.4.zip', EXTENSION_START_PATH: '/home.html', }; - -export const WC_SDK_COMMON_CONFIG: CommonWalletConfig = { - WALLET_NAME: 'wcSDK', - EXTENSION_WALLET_NAME: 'wcSDK', - CONNECTED_WALLET_NAME: 'WalletConnect', - CONNECT_BUTTON_NAME: 'WalletConnect', - STORE_EXTENSION_ID: 'nkbihfbeogaeaoehlefnkodbefgpgknn', - WALLET_TYPE: WalletConnectTypes.WC_SDK, - // Metamask stable version - // https://github.com/MetaMask/metamask-extension/releases/tag/v12.10.4 - LATEST_STABLE_DOWNLOAD_LINK: - 'https://github.com/MetaMask/metamask-extension/releases/download/v12.10.4/metamask-chrome-12.10.4.zip', - EXTENSION_START_PATH: '/home.html', - walletConnectConfig: { - projectId: '6a172e2af5847c798046bddf0c024fdc', - requestHandleTimeoutMs: 30000, - }, -}; diff --git a/packages/wallets/src/walletConnect/constants.ts b/packages/wallets/src/walletConnect/constants.ts index e4a95433..59f1bef2 100644 --- a/packages/wallets/src/walletConnect/constants.ts +++ b/packages/wallets/src/walletConnect/constants.ts @@ -11,7 +11,23 @@ import { unichain, unichainSepolia, } from 'viem/chains'; -import { NetworkConfig } from '../wallets.constants'; +import { + CommonWalletConfig, + NetworkConfig, + WalletConnectTypes, +} from '../wallets.constants'; + +export const WC_SDK_COMMON_CONFIG: CommonWalletConfig = { + WALLET_NAME: 'wcSDK', + EXTENSION_WALLET_NAME: null, + CONNECTED_WALLET_NAME: 'WalletConnect', + CONNECT_BUTTON_NAME: 'WalletConnect', + STORE_EXTENSION_ID: null, + WALLET_TYPE: WalletConnectTypes.WC_SDK, + LATEST_STABLE_DOWNLOAD_LINK: null, + EXTENSION_START_PATH: '/home.html', + WC_PROJECT_ID: process.env.WC_PROJECT_ID, +}; export const SUPPORTED_CHAINS: Record = { 1: mainnet as Chain, diff --git a/packages/wallets/src/wallets.constants.ts b/packages/wallets/src/wallets.constants.ts index da994f30..c76ea6b2 100644 --- a/packages/wallets/src/wallets.constants.ts +++ b/packages/wallets/src/wallets.constants.ts @@ -17,17 +17,7 @@ export interface CommonWalletConfig { LATEST_STABLE_DOWNLOAD_LINK?: string; // Link to stable wallet extension version for test (optional) EXTENSION_START_PATH: string; // Start path for wallet setup // Only for WalletConnect wallets via API @walletconnect/sign-client - walletConnectConfig?: { - projectId: string; - metadata?: { - name: string; - description: string; - url: string; - icons: string[]; - }; - namespaces?: WCApproveNamespaces; - requestHandleTimeoutMs?: number; - }; + WC_PROJECT_ID?: string; // WalletConnect Cloud project ID } export enum WalletConnectTypes { From 2b74b330bfe78e80cfb3fbe8a749aa2a785a241d Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 16 Feb 2026 20:32:42 +0300 Subject: [PATCH 31/32] feat: refactor WCSDKWallet to streamline timeout and namespace handling --- .../wallets/src/walletConnect/wc.service.ts | 53 ++++++++----------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/packages/wallets/src/walletConnect/wc.service.ts b/packages/wallets/src/walletConnect/wc.service.ts index 65118bec..0bf4ad23 100644 --- a/packages/wallets/src/walletConnect/wc.service.ts +++ b/packages/wallets/src/walletConnect/wc.service.ts @@ -49,6 +49,8 @@ export class WCSDKWallet implements WalletPage { protected publicClient?: ReturnType; protected walletClient?: ReturnType; protected hdAccount: HDAccount; + protected defaultTimeoutMs: number; + protected namespaces?: WCApproveNamespaces; protected watchedTokensByAccount: Map = new Map(); @@ -60,25 +62,21 @@ export class WCSDKWallet implements WalletPage { this.hdAccount = mnemonicToAccount( this.options.accountConfig.SECRET_PHRASE, ); - - this.options.walletConfig.walletConnectConfig = { - requestHandleTimeoutMs: 30_000, - namespaces: { - eip155: { - accounts: [ - `eip155:${this.options.standConfig.chainId}:${this.hdAccount.address}`, - ], - methods: [ - 'eth_sendTransaction', - 'personal_sign', - 'eth_signTypedData_v4', - 'wallet_watchAsset', - 'wallet_getCapabilities', - ], - events: ['accountsChanged', 'chainChanged'], - }, + this.defaultTimeoutMs = 30000; + this.namespaces = { + eip155: { + accounts: [ + `eip155:${this.options.standConfig.chainId}:${this.hdAccount.address}`, + ], + methods: [ + 'eth_sendTransaction', + 'personal_sign', + 'eth_signTypedData_v4', + 'wallet_watchAsset', + 'wallet_getCapabilities', + ], + events: ['accountsChanged', 'chainChanged'], }, - ...options.walletConfig?.walletConnectConfig, }; } @@ -86,7 +84,7 @@ export class WCSDKWallet implements WalletPage { if (this.signClient) return; this.signClient = await SignClient.init({ - projectId: this.options.walletConfig.walletConnectConfig.projectId, + projectId: this.options.walletConfig.WC_PROJECT_ID, }); this.networkSettings = new NetworkSettings(this.signClient, this.hdAccount); @@ -125,16 +123,13 @@ export class WCSDKWallet implements WalletPage { if (!this.signClient) throw new Error('WC client not initialized'); const [proposal] = await Promise.all([ - this.waitForProposalOnce( - this.options.walletConfig.walletConnectConfig.requestHandleTimeoutMs, - ), + this.waitForProposalOnce(this.defaultTimeoutMs), this.signClient.core.pairing.pair({ uri }), ]); const { id, params } = proposal; const namespaces = - this.options.walletConfig.walletConnectConfig.namespaces ?? - this.buildNamespacesFromProposal(params); + this.namespaces ?? this.buildNamespacesFromProposal(params); const { acknowledged } = await this.signClient.approve({ id, namespaces }); await acknowledged(); @@ -162,8 +157,7 @@ export class WCSDKWallet implements WalletPage { async waitForTransaction(timeoutMs?: number): Promise { if (!timeoutMs) { - timeoutMs = - this.options.walletConfig.walletConnectConfig.requestHandleTimeoutMs; + timeoutMs = this.defaultTimeoutMs; } return this.requestManager.nextRequest(timeoutMs); } @@ -268,11 +262,8 @@ export class WCSDKWallet implements WalletPage { ); } - const accounts = ( - this.options.walletConfig.walletConnectConfig.namespaces?.eip155 - ?.accounts ?? [] - ).length - ? this.options.walletConfig.walletConnectConfig.namespaces.eip155.accounts + const accounts = (this.namespaces?.eip155?.accounts ?? []).length + ? this.namespaces.eip155.accounts : []; if (!accounts.length) { From bfffabd34d2aada92d1c4fc900112c361a1a9513 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Mon, 16 Feb 2026 20:44:38 +0300 Subject: [PATCH 32/32] feat: update walletConnect exports for improved structure --- packages/wallets/src/index.ts | 2 +- packages/wallets/src/walletConnect/index.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/wallets/src/index.ts b/packages/wallets/src/index.ts index c544cf00..5b6fc147 100644 --- a/packages/wallets/src/index.ts +++ b/packages/wallets/src/index.ts @@ -11,7 +11,7 @@ export * from './exodus'; export * from './okx'; export * from './bitget'; export * from './ctrl'; -export * from './walletConnect/wc.service'; +export * from './walletConnect'; // export WC and IFRAME WalletConnectTypes export * from './safe'; diff --git a/packages/wallets/src/walletConnect/index.ts b/packages/wallets/src/walletConnect/index.ts index e69de29b..c3a11f49 100644 --- a/packages/wallets/src/walletConnect/index.ts +++ b/packages/wallets/src/walletConnect/index.ts @@ -0,0 +1,2 @@ +export * from './constants'; +export * from './wc.service';