@tomo-inc/wallet-adaptor-base 0.0.20 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +18 -22
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +18 -22
- package/package.json +7 -2
- package/project.json +1 -1
- package/src/__tests__/WalletConnectProvider.test.ts +535 -0
- package/src/__tests__/WalletConnectSolanaProvider.test.ts +537 -0
- package/src/__tests__/browsers.test.ts +263 -0
- package/src/__tests__/chainId.test.ts +66 -0
- package/src/__tests__/chains-utils.test.ts +49 -0
- package/src/__tests__/defaultConnectors.test.ts +8 -5
- package/src/__tests__/detector.test.ts +402 -0
- package/src/__tests__/index.test.ts +275 -0
- package/src/__tests__/isMobile.test.ts +187 -0
- package/src/__tests__/log.test.ts +40 -0
- package/src/__tests__/utils.test.ts +66 -0
- package/src/__tests__/wallet-api.test.ts +1755 -0
- package/src/__tests__/wallet-config.test.ts +75 -0
- package/src/__tests__/wallet-eip6963.test.ts +377 -0
- package/src/__tests__/wallet-standard.test.ts +41 -3
- package/src/__tests__/wallet-walletconnect.test.ts +370 -0
- package/src/__tests__/wallets/index.test.ts +42 -0
- package/src/type.ts +4 -0
- package/src/utils/chainId.ts +6 -5
- package/src/utils/wallet-config.ts +2 -9
- package/src/wallet-api/connect.ts +4 -2
- package/src/wallets/detector.ts +3 -4
- package/src/wallets/providers/WalletConnectProvider.ts +5 -4
- package/src/wallets/providers/WalletConnectSolanaProvider.ts +1 -1
- package/src/wallets/wallet-eip6963.ts +1 -1
- package/vitest.config.ts +20 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { ProviderProtocol } from "@tomo-inc/wallet-utils";
|
|
3
|
+
|
|
4
|
+
// Mock providers - use vi.hoisted to create mock classes
|
|
5
|
+
const { MockWalletConnectProvider, MockWalletConnectSolanaProvider } = vi.hoisted(() => {
|
|
6
|
+
// Create mock instances factory
|
|
7
|
+
const createMockInstance = () => ({
|
|
8
|
+
initialize: vi.fn().mockResolvedValue(undefined),
|
|
9
|
+
connect: vi.fn().mockResolvedValue(["0x123"]),
|
|
10
|
+
disconnect: vi.fn().mockResolvedValue(undefined),
|
|
11
|
+
request: vi.fn().mockResolvedValue("result"),
|
|
12
|
+
on: vi.fn(),
|
|
13
|
+
off: vi.fn(),
|
|
14
|
+
uri: "wc:test-uri",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const createMockSolanaInstance = () => ({
|
|
18
|
+
initialize: vi.fn().mockResolvedValue(undefined),
|
|
19
|
+
connect: vi.fn().mockResolvedValue({ publicKey: "SolanaKey123" }),
|
|
20
|
+
disconnect: vi.fn().mockResolvedValue(undefined),
|
|
21
|
+
request: vi.fn().mockResolvedValue("result"),
|
|
22
|
+
on: vi.fn(),
|
|
23
|
+
off: vi.fn(),
|
|
24
|
+
uri: "wc:test-uri",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Create constructor functions that return mock instances
|
|
28
|
+
// Using function declaration so they can be used with 'new'
|
|
29
|
+
function MockProvider() {
|
|
30
|
+
return createMockInstance();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function MockSolanaProvider() {
|
|
34
|
+
return createMockSolanaInstance();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Wrap with vi.fn() to make them spyable while preserving constructor behavior
|
|
38
|
+
const MockProviderSpy = vi.fn(MockProvider);
|
|
39
|
+
const MockSolanaProviderSpy = vi.fn(MockSolanaProvider);
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
MockWalletConnectProvider: MockProviderSpy,
|
|
43
|
+
MockWalletConnectSolanaProvider: MockSolanaProviderSpy,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
vi.mock("../wallets/providers/WalletConnectProvider", () => ({
|
|
48
|
+
WalletConnectProvider: MockWalletConnectProvider,
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
vi.mock("../wallets/providers/WalletConnectSolanaProvider", () => ({
|
|
52
|
+
WalletConnectSolanaProvider: MockWalletConnectSolanaProvider,
|
|
53
|
+
}));
|
|
54
|
+
|
|
55
|
+
describe("wallet-walletconnect", () => {
|
|
56
|
+
let originalFetch: typeof fetch;
|
|
57
|
+
|
|
58
|
+
beforeEach(async () => {
|
|
59
|
+
originalFetch = global.fetch;
|
|
60
|
+
vi.clearAllMocks();
|
|
61
|
+
// Reset module cache before each test
|
|
62
|
+
vi.resetModules();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
afterEach(() => {
|
|
66
|
+
global.fetch = originalFetch;
|
|
67
|
+
vi.restoreAllMocks();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("setWalletConnectConfig", () => {
|
|
71
|
+
it("should set wallet connect configuration", async () => {
|
|
72
|
+
const { setWalletConnectConfig } = await import("../wallets/wallet-walletconnect");
|
|
73
|
+
const config = {
|
|
74
|
+
projectId: "test-project-id",
|
|
75
|
+
metadata: {
|
|
76
|
+
name: "Test App",
|
|
77
|
+
description: "Test Description",
|
|
78
|
+
url: "https://test.com",
|
|
79
|
+
icons: ["https://test.com/icon.png"],
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
setWalletConnectConfig(config);
|
|
84
|
+
|
|
85
|
+
// Config is set internally, verify by calling walletConnectWallets
|
|
86
|
+
expect(() => setWalletConnectConfig(config)).not.toThrow();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("walletConnectWallets", () => {
|
|
91
|
+
it("should fetch and return WalletConnect wallets", async () => {
|
|
92
|
+
const { walletConnectWallets } = await import("../wallets/wallet-walletconnect");
|
|
93
|
+
const mockWallets = [
|
|
94
|
+
{
|
|
95
|
+
id: "walletconnect",
|
|
96
|
+
name: "WalletConnect",
|
|
97
|
+
icon: "wc-icon.png",
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
102
|
+
json: vi.fn().mockResolvedValue({ data: mockWallets }),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const result = await walletConnectWallets();
|
|
106
|
+
|
|
107
|
+
expect(global.fetch).toHaveBeenCalledWith("https://web3-assets.tomo.inc/api/wallets?walletId=walletConnect");
|
|
108
|
+
expect(result).toHaveLength(1);
|
|
109
|
+
expect(result[0].info.name).toBe("WalletConnect");
|
|
110
|
+
expect(result[0].info.isWalletConnect).toBe(true);
|
|
111
|
+
expect(result[0].connectors.evm).toBeDefined();
|
|
112
|
+
expect(result[0].connectors.solana).toBeDefined();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should use custom baseUrl", async () => {
|
|
116
|
+
const { walletConnectWallets } = await import("../wallets/wallet-walletconnect");
|
|
117
|
+
const mockWallets = [
|
|
118
|
+
{
|
|
119
|
+
id: "walletconnect",
|
|
120
|
+
name: "WalletConnect",
|
|
121
|
+
icon: "wc-icon.png",
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
126
|
+
json: vi.fn().mockResolvedValue({ data: mockWallets }),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const customBaseUrl = "https://custom-api.example.com";
|
|
130
|
+
await walletConnectWallets(customBaseUrl);
|
|
131
|
+
|
|
132
|
+
expect(global.fetch).toHaveBeenCalledWith(`${customBaseUrl}/api/wallets?walletId=walletConnect`);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should return cached wallets on second call", async () => {
|
|
136
|
+
const { walletConnectWallets } = await import("../wallets/wallet-walletconnect");
|
|
137
|
+
const mockWallets = [
|
|
138
|
+
{
|
|
139
|
+
id: "walletconnect",
|
|
140
|
+
name: "WalletConnect",
|
|
141
|
+
icon: "wc-icon.png",
|
|
142
|
+
},
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
146
|
+
json: vi.fn().mockResolvedValue({ data: mockWallets }),
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const result1 = await walletConnectWallets();
|
|
150
|
+
const result2 = await walletConnectWallets();
|
|
151
|
+
|
|
152
|
+
expect(global.fetch).toHaveBeenCalledTimes(1);
|
|
153
|
+
// Compare by info properties since provider objects are recreated
|
|
154
|
+
expect(result1.length).toBe(result2.length);
|
|
155
|
+
expect(result1[0].info.uuid).toBe(result2[0].info.uuid);
|
|
156
|
+
expect(result1[0].info.name).toBe(result2[0].info.name);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should return empty array when no wallets found", async () => {
|
|
160
|
+
const { walletConnectWallets } = await import("../wallets/wallet-walletconnect");
|
|
161
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
162
|
+
json: vi.fn().mockResolvedValue({ data: [] }),
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const result = await walletConnectWallets();
|
|
166
|
+
|
|
167
|
+
expect(result).toEqual([]);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should create connectors with correct structure", async () => {
|
|
171
|
+
const { walletConnectWallets } = await import("../wallets/wallet-walletconnect");
|
|
172
|
+
const mockWallets = [
|
|
173
|
+
{
|
|
174
|
+
id: "walletconnect",
|
|
175
|
+
name: "WalletConnect",
|
|
176
|
+
icon: "wc-icon.png",
|
|
177
|
+
iconBackground: "#000000",
|
|
178
|
+
},
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
182
|
+
json: vi.fn().mockResolvedValue({ data: mockWallets }),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const result = await walletConnectWallets();
|
|
186
|
+
|
|
187
|
+
expect(result[0].info.uuid).toBe("walletconnect");
|
|
188
|
+
expect(result[0].info.name).toBe("WalletConnect");
|
|
189
|
+
expect(result[0].info.icon).toBe("wc-icon.png");
|
|
190
|
+
if (result[0].info.iconBackground) {
|
|
191
|
+
expect(result[0].info.iconBackground).toBe("#000000");
|
|
192
|
+
}
|
|
193
|
+
expect(result[0].info.links.homepage).toBe("https://walletconnect.com");
|
|
194
|
+
expect(result[0].isInstalled).toBe(true);
|
|
195
|
+
expect(result[0].connectors.evm?.protocol).toBe(ProviderProtocol.WALLET_CONNECT);
|
|
196
|
+
expect(result[0].connectors.solana?.protocol).toBe(ProviderProtocol.WALLET_CONNECT);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe("createWalletConnectEVMProvider", () => {
|
|
201
|
+
beforeEach(async () => {
|
|
202
|
+
const { setWalletConnectConfig } = await import("../wallets/wallet-walletconnect");
|
|
203
|
+
setWalletConnectConfig({
|
|
204
|
+
projectId: "test-project-id",
|
|
205
|
+
metadata: {
|
|
206
|
+
name: "Test App",
|
|
207
|
+
description: "Test Description",
|
|
208
|
+
url: "https://test.com",
|
|
209
|
+
icons: ["https://test.com/icon.png"],
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("should create EVM provider with lazy initialization", async () => {
|
|
215
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
216
|
+
const provider = createWalletConnectEVMProvider();
|
|
217
|
+
|
|
218
|
+
expect(provider.isWalletConnect).toBe(true);
|
|
219
|
+
expect(provider.getProvider).toBeDefined();
|
|
220
|
+
expect(provider.request).toBeDefined();
|
|
221
|
+
expect(provider.connect).toBeDefined();
|
|
222
|
+
expect(provider.disconnect).toBeDefined();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("should initialize provider on first getProvider call", async () => {
|
|
226
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
227
|
+
const provider = createWalletConnectEVMProvider();
|
|
228
|
+
const providerInstance = await provider.getProvider();
|
|
229
|
+
|
|
230
|
+
expect(MockWalletConnectProvider).toHaveBeenCalled();
|
|
231
|
+
expect(providerInstance).toBeDefined();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("should reuse provider instance on subsequent calls", async () => {
|
|
235
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
236
|
+
const provider = createWalletConnectEVMProvider();
|
|
237
|
+
const provider1 = await provider.getProvider();
|
|
238
|
+
const provider2 = await provider.getProvider();
|
|
239
|
+
|
|
240
|
+
expect(provider1).toBe(provider2);
|
|
241
|
+
expect(MockWalletConnectProvider).toHaveBeenCalledTimes(1);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it("should throw error when config is not set", async () => {
|
|
245
|
+
// Reset modules to clear config
|
|
246
|
+
vi.resetModules();
|
|
247
|
+
|
|
248
|
+
// Re-import to get fresh module state
|
|
249
|
+
const { createWalletConnectEVMProvider: createProvider } = await import("../wallets/wallet-walletconnect");
|
|
250
|
+
|
|
251
|
+
const provider = createProvider();
|
|
252
|
+
await expect(provider.getProvider()).rejects.toThrow("WalletConnect not configured");
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("should handle request method", async () => {
|
|
256
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
257
|
+
const provider = createWalletConnectEVMProvider();
|
|
258
|
+
const result = await provider.request({ method: "eth_chainId" });
|
|
259
|
+
|
|
260
|
+
expect(result).toBeDefined();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("should handle connect method", async () => {
|
|
264
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
265
|
+
const provider = createWalletConnectEVMProvider();
|
|
266
|
+
const result = await provider.connect();
|
|
267
|
+
|
|
268
|
+
expect(result).toBeDefined();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("should handle disconnect method", async () => {
|
|
272
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
273
|
+
const provider = createWalletConnectEVMProvider();
|
|
274
|
+
await provider.getProvider(); // Initialize first
|
|
275
|
+
await provider.disconnect();
|
|
276
|
+
|
|
277
|
+
// Should not throw
|
|
278
|
+
expect(true).toBe(true);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("should return connectUri getter", async () => {
|
|
282
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
283
|
+
const provider = createWalletConnectEVMProvider();
|
|
284
|
+
await provider.getProvider(); // Initialize first
|
|
285
|
+
|
|
286
|
+
expect(provider.connectUri).toBe("wc:test-uri");
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("should handle event listeners", async () => {
|
|
290
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
291
|
+
const provider = createWalletConnectEVMProvider();
|
|
292
|
+
const listener = vi.fn();
|
|
293
|
+
|
|
294
|
+
provider.on("test-event", listener);
|
|
295
|
+
provider.off("test-event", listener);
|
|
296
|
+
|
|
297
|
+
expect(provider.on).toBeDefined();
|
|
298
|
+
expect(provider.off).toBeDefined();
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("should call providerInstance.on and off when provider already initialized", async () => {
|
|
302
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
303
|
+
const provider = createWalletConnectEVMProvider();
|
|
304
|
+
await provider.getProvider();
|
|
305
|
+
const listener = vi.fn();
|
|
306
|
+
provider.on("accountsChanged", listener);
|
|
307
|
+
provider.off("accountsChanged", listener);
|
|
308
|
+
const mockInstance = MockWalletConnectProvider.mock.results[0]?.value;
|
|
309
|
+
expect(mockInstance?.on).toHaveBeenCalledWith("accountsChanged", listener);
|
|
310
|
+
expect(mockInstance?.off).toHaveBeenCalledWith("accountsChanged", listener);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("should no-op on/off when provider not yet initialized", async () => {
|
|
314
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
315
|
+
const provider = createWalletConnectEVMProvider();
|
|
316
|
+
expect(provider.connectUri).toBeNull();
|
|
317
|
+
provider.on("e", () => {});
|
|
318
|
+
provider.off("e", () => {});
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("should pass custom namespaces to createWalletConnectEVMProvider", async () => {
|
|
322
|
+
const { createWalletConnectEVMProvider } = await import("../wallets/wallet-walletconnect");
|
|
323
|
+
const provider = createWalletConnectEVMProvider({ eip155: { methods: ["eth_sign"] } } as any);
|
|
324
|
+
const p = await provider.getProvider();
|
|
325
|
+
expect(p).toBeDefined();
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
describe("createWalletConnectSolanaProvider (via connector)", () => {
|
|
330
|
+
beforeEach(async () => {
|
|
331
|
+
const { setWalletConnectConfig } = await import("../wallets/wallet-walletconnect");
|
|
332
|
+
setWalletConnectConfig({
|
|
333
|
+
projectId: "test-project-id",
|
|
334
|
+
metadata: {
|
|
335
|
+
name: "Test App",
|
|
336
|
+
description: "Test Description",
|
|
337
|
+
url: "https://test.com",
|
|
338
|
+
icons: ["https://test.com/icon.png"],
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it("should create Solana provider with getProvider, request, connect, disconnect", async () => {
|
|
344
|
+
const { walletConnectWallets } = await import("../wallets/wallet-walletconnect");
|
|
345
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
346
|
+
json: vi.fn().mockResolvedValue({
|
|
347
|
+
data: [{ id: "wc", name: "WalletConnect", icon: "/icon.png" }],
|
|
348
|
+
}),
|
|
349
|
+
});
|
|
350
|
+
const connectors = await walletConnectWallets();
|
|
351
|
+
const solanaProvider = connectors[0].connectors.solana?.provider;
|
|
352
|
+
expect(solanaProvider).toBeDefined();
|
|
353
|
+
expect(solanaProvider.isWalletConnect).toBe(true);
|
|
354
|
+
expect(solanaProvider.connectUri).toBeNull();
|
|
355
|
+
solanaProvider.on("event", () => {});
|
|
356
|
+
solanaProvider.off("event", () => {});
|
|
357
|
+
const result = await solanaProvider.request({ method: "solana_signMessage" });
|
|
358
|
+
expect(result).toBeDefined();
|
|
359
|
+
await solanaProvider.connect();
|
|
360
|
+
expect(solanaProvider.connectUri).toBe("wc:test-uri");
|
|
361
|
+
const solanaListener = vi.fn();
|
|
362
|
+
solanaProvider.on("event", solanaListener);
|
|
363
|
+
solanaProvider.off("event", solanaListener);
|
|
364
|
+
const mockSolanaInstance = MockWalletConnectSolanaProvider.mock.results[0]?.value;
|
|
365
|
+
expect(mockSolanaInstance?.on).toHaveBeenCalledWith("event", solanaListener);
|
|
366
|
+
expect(mockSolanaInstance?.off).toHaveBeenCalledWith("event", solanaListener);
|
|
367
|
+
await solanaProvider.disconnect();
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
|
|
3
|
+
describe("wallets/index", () => {
|
|
4
|
+
let originalFetch: typeof fetch;
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
vi.resetModules();
|
|
8
|
+
originalFetch = global.fetch;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
global.fetch = originalFetch;
|
|
13
|
+
vi.restoreAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("getAllWallets", () => {
|
|
17
|
+
it("should fetch wallets from default URL", async () => {
|
|
18
|
+
const mockWallets = [{ id: "1", name: "Wallet 1" }];
|
|
19
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
20
|
+
json: vi.fn().mockResolvedValue({ data: mockWallets }),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const { getAllWallets } = await import("../../wallets/index");
|
|
24
|
+
const result = await getAllWallets();
|
|
25
|
+
expect(global.fetch).toHaveBeenCalledWith("https://web3-assets.tomo.inc/api/wallets");
|
|
26
|
+
expect(result).toEqual(mockWallets);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should fetch wallets from custom base URL", async () => {
|
|
30
|
+
const mockWallets = [{ id: "2", name: "Wallet 2" }];
|
|
31
|
+
global.fetch = vi.fn().mockResolvedValue({
|
|
32
|
+
json: vi.fn().mockResolvedValue({ data: mockWallets }),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const { getAllWallets } = await import("../../wallets/index");
|
|
36
|
+
const customBaseUrl = "https://custom-api.example.com";
|
|
37
|
+
const result = await getAllWallets(customBaseUrl);
|
|
38
|
+
expect(global.fetch).toHaveBeenCalledWith(`${customBaseUrl}/api/wallets`);
|
|
39
|
+
expect(result).toEqual(mockWallets);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
package/src/type.ts
CHANGED
|
@@ -17,6 +17,9 @@ export interface WalletInfo {
|
|
|
17
17
|
mobile?: {
|
|
18
18
|
getUri?: (uri: string) => string;
|
|
19
19
|
getDeeplink?: (dappUrl?: string, chainId?: number) => string | Promise<string>;
|
|
20
|
+
deeplinkTemplate?: {
|
|
21
|
+
deeplink?: string;
|
|
22
|
+
};
|
|
20
23
|
};
|
|
21
24
|
links: {
|
|
22
25
|
homepage?: string;
|
|
@@ -45,6 +48,7 @@ export interface ConnectorProvider {
|
|
|
45
48
|
|
|
46
49
|
export type ConnectorProviders = Partial<Record<ChainTypeEnum, ConnectorProvider | null>>;
|
|
47
50
|
export interface Connector {
|
|
51
|
+
providers?: any;
|
|
48
52
|
info: WalletInfo;
|
|
49
53
|
isInstalled?: boolean;
|
|
50
54
|
recommoned?: boolean;
|
package/src/utils/chainId.ts
CHANGED
|
@@ -11,17 +11,18 @@ export const isSameAddress = (addr1: "0x${string}", addr2: "0x${string}") => {
|
|
|
11
11
|
export const getAllTypeChainIds = ({ chainId, chainType }: { chainId: string | number; chainType: string }) => {
|
|
12
12
|
if (isHex(chainId)) {
|
|
13
13
|
const chainIdHex = chainId;
|
|
14
|
-
|
|
14
|
+
const chainIdStr = fromHex(chainId, "number").toString();
|
|
15
15
|
return {
|
|
16
|
-
chainId,
|
|
16
|
+
chainId: chainIdStr,
|
|
17
17
|
chainIdHex,
|
|
18
|
-
chainUid: `${chainType}:${
|
|
18
|
+
chainUid: `${chainType}:${chainIdStr}`,
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
+
const chainIdStr = String(chainId);
|
|
21
22
|
const chainIdHex = toHex(Number(chainId));
|
|
22
23
|
return {
|
|
23
|
-
chainId,
|
|
24
|
+
chainId: chainIdStr,
|
|
24
25
|
chainIdHex,
|
|
25
|
-
chainUid: `${chainType}:${
|
|
26
|
+
chainUid: `${chainType}:${chainIdStr}`,
|
|
26
27
|
};
|
|
27
28
|
};
|
|
@@ -5,11 +5,7 @@ import { WagmiWalletConfig, WalletConfig } from "../wallets/types";
|
|
|
5
5
|
* WalletConfig requires: id, name, icon, iconBackground
|
|
6
6
|
*/
|
|
7
7
|
function hasWalletConfigProperties(config: any): boolean {
|
|
8
|
-
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// Check for required WalletConfig properties
|
|
8
|
+
// Caller ensures config is non-null object
|
|
13
9
|
return (
|
|
14
10
|
typeof config.id === "string" &&
|
|
15
11
|
typeof config.name === "string" &&
|
|
@@ -25,10 +21,7 @@ function hasWalletConfigProperties(config: any): boolean {
|
|
|
25
21
|
* 2. An object with createConnector method
|
|
26
22
|
*/
|
|
27
23
|
function hasWagmiConnectorProperties(config: any): boolean {
|
|
28
|
-
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
|
|
24
|
+
// Caller ensures config is non-null object
|
|
32
25
|
// Check if it has createConnector method (wagmi connector wrapper)
|
|
33
26
|
if (typeof config.createConnector === "function") {
|
|
34
27
|
return true;
|
|
@@ -59,6 +59,7 @@ export const connect = async (
|
|
|
59
59
|
address = res?.accounts?.[0]?.address || "";
|
|
60
60
|
}
|
|
61
61
|
network = "mainnet-beta";
|
|
62
|
+
chainId = `solana:${network}`;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
if (chainType === "aptos") {
|
|
@@ -197,8 +198,9 @@ export const connectMobile = async ({
|
|
|
197
198
|
};
|
|
198
199
|
if (useWalletConnect) {
|
|
199
200
|
return connectWithWalletConnect();
|
|
200
|
-
} else if (mobile?.
|
|
201
|
-
|
|
201
|
+
} else if (mobile?.deeplinkTemplate?.deeplink) {
|
|
202
|
+
// example phantom deeplink `https://phantom.app/ul/browse/${encodeURIComponent(dappLink)}?ref=${encodeURIComponent(dappLink)}`;
|
|
203
|
+
const deeplink = mobile?.deeplinkTemplate?.deeplink.replace("{dappUrl}", encodeURIComponent(dappLink));
|
|
202
204
|
if (deeplink) {
|
|
203
205
|
openUri(deeplink);
|
|
204
206
|
}
|
package/src/wallets/detector.ts
CHANGED
|
@@ -47,7 +47,6 @@ export function getInjectedProvider({ flag, namespace }: { flag?: WalletProvider
|
|
|
47
47
|
const _window = typeof window !== "undefined" ? (window as WindowProvider) : undefined;
|
|
48
48
|
if (typeof _window === "undefined") {
|
|
49
49
|
throw new Error("Window is not defined");
|
|
50
|
-
return;
|
|
51
50
|
}
|
|
52
51
|
if (namespace) {
|
|
53
52
|
// prefer custom eip1193 namespaces
|
|
@@ -174,7 +173,7 @@ export function walletConfigAdapter(
|
|
|
174
173
|
}
|
|
175
174
|
}
|
|
176
175
|
|
|
177
|
-
function tomoConnectorDector(wallet: WalletConfig): Connector {
|
|
176
|
+
function tomoConnectorDector(wallet: WalletConfig & { links: any }): Connector {
|
|
178
177
|
const evmNS = {
|
|
179
178
|
namespace: wallet?.namespace || "",
|
|
180
179
|
flag: wallet?.flag || "",
|
|
@@ -247,7 +246,7 @@ function tomoConnectorDector(wallet: WalletConfig): Connector {
|
|
|
247
246
|
rdns: wallet?.rdns,
|
|
248
247
|
deeplink: wallet?.deeplink,
|
|
249
248
|
mobile: wallet?.mobile,
|
|
250
|
-
links: {
|
|
249
|
+
links: wallet?.links || {
|
|
251
250
|
homepage: wallet?.downloadUrls?.qrCode || "",
|
|
252
251
|
ios_install: wallet?.downloadUrls?.ios || "",
|
|
253
252
|
android_install: wallet?.downloadUrls?.android || "",
|
|
@@ -299,5 +298,5 @@ export function connectorDector(wallet: WalletConfig, connectorType: WalletConne
|
|
|
299
298
|
if (connectorType === "wagmi") {
|
|
300
299
|
return wagmiConnectorDector(wallet as WagmiWalletConfig);
|
|
301
300
|
}
|
|
302
|
-
return tomoConnectorDector(wallet);
|
|
301
|
+
return tomoConnectorDector(wallet as unknown as WalletConfig & { links: any });
|
|
303
302
|
}
|
|
@@ -217,14 +217,15 @@ export class WalletConnectProvider {
|
|
|
217
217
|
return this.connect();
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
throw new Error("Not connected. Please call connect() first.");
|
|
222
|
-
}
|
|
223
|
-
|
|
220
|
+
// eth_chainId doesn't require a session
|
|
224
221
|
if (args.method === "eth_chainId") {
|
|
225
222
|
return this.chainId || "0x1"; // default to Ethereum mainnet
|
|
226
223
|
}
|
|
227
224
|
|
|
225
|
+
if (!this.session) {
|
|
226
|
+
throw new Error("Not connected. Please call connect() first.");
|
|
227
|
+
}
|
|
228
|
+
|
|
228
229
|
try {
|
|
229
230
|
const result = await this.client.sendRequest({
|
|
230
231
|
topic: this.session.topic,
|
|
@@ -209,7 +209,7 @@ export class WalletConnectSolanaProvider {
|
|
|
209
209
|
// solana_requestAccounts
|
|
210
210
|
if (args.method === "solana_requestAccounts") {
|
|
211
211
|
if (this.accounts.length > 0) {
|
|
212
|
-
return
|
|
212
|
+
return this.accounts[0];
|
|
213
213
|
}
|
|
214
214
|
const accounts = await this.connect();
|
|
215
215
|
return accounts;
|
|
@@ -26,7 +26,7 @@ export async function eip6963Wallets(): Promise<Connector[]> {
|
|
|
26
26
|
typeof wallet?.uuid === "string" &&
|
|
27
27
|
typeof wallet?.name === "string" &&
|
|
28
28
|
typeof wallet?.icon === "string" &&
|
|
29
|
-
typeof wallet?.rdns === "string";
|
|
29
|
+
(wallet?.rdns === undefined || typeof wallet?.rdns === "string");
|
|
30
30
|
|
|
31
31
|
if (wallet && provider && isInfoValid && typeof provider.request === "function") {
|
|
32
32
|
const existingWallet = evmWallets.find((w) => w.info.uuid === wallet.uuid);
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
resolve: {
|
|
6
|
+
alias: {
|
|
7
|
+
utils: path.resolve(__dirname, "./src/utils"),
|
|
8
|
+
type: path.resolve(__dirname, "./src/type"),
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
test: {
|
|
12
|
+
globals: true,
|
|
13
|
+
environment: "jsdom",
|
|
14
|
+
coverage: {
|
|
15
|
+
provider: "v8",
|
|
16
|
+
reporter: ["text", "json", "html"],
|
|
17
|
+
exclude: ["node_modules/", "dist/", "**/*.config.*", "**/__tests__/**", "**/*.test.ts", "**/*.spec.ts"],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|