Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4ea8c2d
feat: added wallet connect integration via api
Vorobeyko Feb 2, 2026
d5b5106
feat: added wallet connect integration via api
Vorobeyko Feb 2, 2026
93fe671
feat: update BrowserContextService and BrowserService for WalletConne…
Vorobeyko Feb 3, 2026
2c12df5
fix: add missing param
Vorobeyko Feb 3, 2026
76921bf
fix: enhance WalletConnect integration and update dependencies
Vorobeyko Feb 3, 2026
cefadbe
fix: enhance WalletConnect integration and update dependencies
Vorobeyko Feb 3, 2026
74143e4
fix: enhance WalletConnect integration and update dependencies
Vorobeyko Feb 3, 2026
05fc396
feat: update approveTokenTx and nextRequest methods for improved Wall…
Vorobeyko Feb 3, 2026
374928f
feat: update approveTokenTx and nextRequest methods for improved Wall…
Vorobeyko Feb 3, 2026
74b3a05
feat: update assertTxAmount and assertReceiptAddress methods to retur…
Vorobeyko Feb 4, 2026
c042e31
feat: update assertTxAmount and assertReceiptAddress methods to retur…
Vorobeyko Feb 4, 2026
1145841
feat: enhance transaction request handling and validation methods in …
Vorobeyko Feb 4, 2026
561016a
feat: enhance WCSDKWallet to support wallet_watchAsset and getTokenBa…
Vorobeyko Feb 9, 2026
e3e835e
feat: enhance WCSDKWallet to support wallet_watchAsset and getTokenBa…
Vorobeyko Feb 9, 2026
c3cb994
feat: enhance WCSDKWallet to support wallet_watchAsset and getTokenBa…
Vorobeyko Feb 9, 2026
89fddcd
feat: enhance WCSDKWallet to support wallet_watchAsset and getTokenBa…
Vorobeyko Feb 9, 2026
c4e65a4
feat: update confirmAddTokenToWallet method to handle WCSessionReques…
Vorobeyko Feb 9, 2026
a910cac
feat: add processed flag to WCSessionRequest and prevent reprocessing…
Vorobeyko Feb 9, 2026
4cee8a1
feat: update WC_SDK_COMMON_CONFIG to correct CONNECTED_WALLET_NAME
Vorobeyko Feb 9, 2026
2bad439
feat: refactor confirmTx and cancelTx methods to remove WCSessionRequ…
Vorobeyko Feb 10, 2026
8bc2054
feat: add cancelAllTxRequests method to WCSDKWallet for batch transac…
Vorobeyko Feb 10, 2026
e22cc85
feat: add cancelAllTxRequests method to WCSDKWallet for batch transac…
Vorobeyko Feb 10, 2026
b86f9ed
feat: setup fork
Vorobeyko Feb 11, 2026
b652178
feat: setup add/change network for wc
Vorobeyko Feb 11, 2026
d100d42
feat: setup add/change network for wc
Vorobeyko Feb 11, 2026
aea5079
feat: setup network for fork
Vorobeyko Feb 11, 2026
7a56cfa
feat: refactoring all code
Vorobeyko Feb 12, 2026
7d03734
feat: refactoring all code
Vorobeyko Feb 12, 2026
1aaeb98
feat: rename nextRequest to waitForTransaction in WCSDKWallet
Vorobeyko Feb 16, 2026
2f6622c
feat: update WC_SDK_COMMON_CONFIG and modify CommonWalletConfig struc…
Vorobeyko Feb 16, 2026
2b74b33
feat: refactor WCSDKWallet to streamline timeout and namespace handling
Vorobeyko Feb 16, 2026
bfffabd
feat: update walletConnect exports for improved structure
Vorobeyko Feb 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
]
}
Expand Down
2 changes: 1 addition & 1 deletion packages/browser-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@
"peerDependencies": {
"@playwright/test": "^1.51.1"
}
}
}
2 changes: 2 additions & 0 deletions packages/browser-service/src/browser.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SafeIframePage,
SafeWcPage,
TrustWalletPage,
WCSDKWallet,
} from '@lidofinance/wallets-testing-wallets';

export const WALLET_PAGES = {
Expand All @@ -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';
26 changes: 15 additions & 11 deletions packages/browser-service/src/browser.context.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand All @@ -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 = {
Expand All @@ -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'],
Expand All @@ -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) {
Expand All @@ -80,6 +78,10 @@ export class BrowserContextService {
});
}

this.logger.debug(
`Starting a new browser context (temp context: ${browserContextPath})`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you print the path instead of the previous value?

Image

);

let attemptsLeft = 3;
while (attemptsLeft > 0) {
try {
Expand Down Expand Up @@ -111,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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can use the WalletConnectTypes here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, browser context doesn’t know anything about wallets

let [background] = this.browserContext.serviceWorkers();
if (!background)
background = await this.browserContext.waitForEvent('serviceworker');
this.extensionId = background.url().split('/')[2];
}
}

async closePages() {
Expand Down
57 changes: 49 additions & 8 deletions packages/browser-service/src/browser.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we unite the WC and WC_SDK?

| WalletConnectTypes.EOA
| WalletConnectTypes.IFRAME
>;
private browserContextService: BrowserContextService;
public ethereumNodeService: EthereumNodeService;
Expand Down Expand Up @@ -85,8 +88,13 @@ export class BrowserService {
} 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) {
Copy link
Contributor

@jake4take jake4take Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move it to the private method?

await this.walletPage.changeNetwork(
this.options.networkConfig.chainName,
);
await this.browserContextService.closePages();
}
}
}

Expand All @@ -98,10 +106,12 @@ export class BrowserService {
const account = this.ethereumNodeService.getAccount();
await this.setup();

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({
Expand All @@ -114,10 +124,22 @@ 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() {
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;
}
const extensionService = new ExtensionService();

const extensionPath = await extensionService.getExtensionDirFromId(
Expand All @@ -128,6 +150,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,
Expand All @@ -148,6 +171,24 @@ 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,
accountConfig: this.options.accountConfig,
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
Expand Down
2 changes: 1 addition & 1 deletion packages/pg-reporter/src/reportRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
Expand Down
1 change: 1 addition & 0 deletions packages/wallets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions packages/wallets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './exodus';
export * from './okx';
export * from './bitget';
export * from './ctrl';
export * from './walletConnect';

// export WC and IFRAME WalletConnectTypes
export * from './safe';
32 changes: 26 additions & 6 deletions packages/wallets/src/wallet.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
WalletConnectType,
WalletConnectTypes,
} from './wallets.constants';
import { WCSessionRequest } from './walletConnect/components';

/** Required options to manage wallet */
export interface WalletPageOptions {
Expand Down Expand Up @@ -54,21 +55,36 @@ export interface WalletPage<T extends WalletConnectType> {
param?: T extends WalletConnectTypes.EOA ? Page : string,
): Promise<void>;

assertTxAmount(page: Page, expectedAmount: string): Promise<void>;
assertTxAmount(
page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page,
expectedAmount: string,
): Promise<void> | void;

confirmTx(page: Page, setAggressiveGas?: boolean): Promise<void>;
confirmTx(
page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page,
setAggressiveGas?: boolean,
): Promise<void>;

cancelTx(page: Page): Promise<void>;
cancelTx(
page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page,
): Promise<void>;

approveTokenTx?(page: Page): Promise<void>;
approveTokenTx?(
page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page,
): Promise<void>;

openLastTxInEthplorer?(txIndex?: number): Promise<Page>;

getTokenBalance?(tokenName: string): Promise<number>;

confirmAddTokenToWallet?(page: Page): Promise<void>;
confirmAddTokenToWallet?(
page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page,
): Promise<void>;

assertReceiptAddress(page: Page, expectedAddress: string): Promise<void>;
assertReceiptAddress(
page: T extends WalletConnectTypes.WC_SDK ? WCSessionRequest : Page,
expectedAddress: string,
): Promise<void> | void;

getWalletAddress?(): Promise<string>;

Expand All @@ -90,4 +106,8 @@ export interface WalletPage<T extends WalletConnectType> {
isClosePage?: boolean,
): Promise<void>;
isWalletAddressExist?(address: string): Promise<boolean>;

// WC SDK
waitForTransaction?(timeoutMs?: number): Promise<WCSessionRequest>;
cancelAllTxRequests?(): Promise<void>;
}
2 changes: 2 additions & 0 deletions packages/wallets/src/walletConnect/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './network';
export * from './requestManager';
91 changes: 91 additions & 0 deletions packages/wallets/src/walletConnect/components/network.ts
Original file line number Diff line number Diff line change
@@ -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<number, NetworkConfig>();
public chainIdByName = new Map<string, number>();

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<void> {
this.networksByChainId.set(networkConfig.chainId, networkConfig);
this.chainIdByName.set(
this.normalizeChainName(networkConfig.chainName),
networkConfig.chainId,
);
}

async addNetwork(networkConfig: NetworkConfig): Promise<void> {
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<Chain> {
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;
}
}
Loading
Loading