📄 src/web3/session/writeClient.test.ts
D-OPEN SOVEREIGN
1import { describe, it, expect, vi, beforeEach } from 'vitest';
2
3const mocks = vi.hoisted(() => ({
4 getReadyEvmClient: vi.fn(),
5 addressFromPrivateKey: vi.fn(),
6 createPrivateKeyWalletClient: vi.fn(),
7 EvmWriteClient: vi.fn(),
8}));
9
10vi.mock('../client/registry', () => ({ getReadyEvmClient: mocks.getReadyEvmClient }));
11vi.mock('../wallet/PrivateKeyConnector', () => ({
12 addressFromPrivateKey: mocks.addressFromPrivateKey,
13 createPrivateKeyWalletClient: mocks.createPrivateKeyWalletClient,
14}));
15vi.mock('../client/EvmWriteClient', () => ({ EvmWriteClient: mocks.EvmWriteClient }));
16
17import { createWriteClient, createPrivateKeyWriteClient } from './writeClient';
18
19const FAKE_EVM_CLIENT = { chainId: 1116 };
20const FAKE_WALLET_CLIENT = { account: { address: '0xacc' } };
21
22beforeEach(() => {
23 Object.values(mocks).forEach((m) => m.mockReset());
24 mocks.getReadyEvmClient.mockResolvedValue(FAKE_EVM_CLIENT);
25 mocks.EvmWriteClient.mockImplementation(function (this: any, ...args: any[]) {
26 Object.assign(this, { args });
27 });
28});
29
30function fakeConnector(overrides: any = {}) {
31 return {
32 type: 'metamask',
33 getAccounts: vi.fn().mockResolvedValue(['0xAccount1']),
34 getWalletClient: vi.fn().mockResolvedValue(FAKE_WALLET_CLIENT),
35 ...overrides,
36 };
37}
38
39describe('createWriteClient', () => {
40 it('throws when the connector does not implement getWalletClient', async () => {
41 const connector = fakeConnector({ getWalletClient: undefined, type: 'walletconnect' });
42 await expect(createWriteClient(connector as any, 1116)).rejects.toThrow(
43 "Connector 'walletconnect' does not support EVM write operations"
44 );
45 });
46
47 it('throws when the connector has no accounts', async () => {
48 const connector = fakeConnector({ getAccounts: vi.fn().mockResolvedValue([]) });
49 await expect(createWriteClient(connector as any, 1116)).rejects.toThrow(
50 "No account available for wallet 'metamask' — connect() first"
51 );
52 });
53
54 it('defaults environment to production and wires the ready EvmClient + walletClient + first account into EvmWriteClient', async () => {
55 const connector = fakeConnector();
56 await createWriteClient(connector as any, 1116);
57
58 expect(mocks.getReadyEvmClient).toHaveBeenCalledWith(1116, 'production');
59 expect(connector.getWalletClient).toHaveBeenCalledWith(1116);
60 expect(mocks.EvmWriteClient).toHaveBeenCalledWith('metamask', FAKE_EVM_CLIENT, FAKE_WALLET_CLIENT, '0xAccount1');
61 });
62
63 it('passes a non-default environment straight through to getReadyEvmClient', async () => {
64 const connector = fakeConnector();
65 await createWriteClient(connector as any, 1114, 'staging');
66 expect(mocks.getReadyEvmClient).toHaveBeenCalledWith(1114, 'staging');
67 });
68
69 it('uses only the first account when the connector exposes multiple', async () => {
70 const connector = fakeConnector({ getAccounts: vi.fn().mockResolvedValue(['0xFirst', '0xSecond']) });
71 await createWriteClient(connector as any, 1116);
72 expect(mocks.EvmWriteClient).toHaveBeenCalledWith('metamask', FAKE_EVM_CLIENT, FAKE_WALLET_CLIENT, '0xFirst');
73 });
74});
75
76describe('createPrivateKeyWriteClient', () => {
77 it('derives the account from the private key and wires everything into EvmWriteClient with wallet type "private_key"', async () => {
78 mocks.createPrivateKeyWalletClient.mockReturnValue(FAKE_WALLET_CLIENT);
79 mocks.addressFromPrivateKey.mockReturnValue('0xDerivedAddress');
80
81 await createPrivateKeyWriteClient(1116, '0xabc');
82
83 expect(mocks.getReadyEvmClient).toHaveBeenCalledWith(1116, 'production');
84 expect(mocks.createPrivateKeyWalletClient).toHaveBeenCalledWith(1116, '0xabc');
85 expect(mocks.addressFromPrivateKey).toHaveBeenCalledWith('0xabc');
86 expect(mocks.EvmWriteClient).toHaveBeenCalledWith('private_key', FAKE_EVM_CLIENT, FAKE_WALLET_CLIENT, '0xDerivedAddress');
87 });
88
89 it('passes a non-default environment straight through to getReadyEvmClient', async () => {
90 mocks.createPrivateKeyWalletClient.mockReturnValue(FAKE_WALLET_CLIENT);
91 mocks.addressFromPrivateKey.mockReturnValue('0xDerivedAddress');
92
93 await createPrivateKeyWriteClient(1114, '0xabc', 'staging');
94 expect(mocks.getReadyEvmClient).toHaveBeenCalledWith(1114, 'staging');
95 });
96});
97