@naculus/connect-appkit-react 0.1.9 → 0.2.1

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.
Files changed (94) hide show
  1. package/README.md +4 -4
  2. package/dist/client.cjs +1 -1
  3. package/dist/client.cjs.map +1 -1
  4. package/dist/client.d.cts +144 -0
  5. package/dist/client.d.ts +144 -0
  6. package/dist/client.js +1 -1
  7. package/dist/client.js.map +1 -1
  8. package/dist/index.cjs +2 -1
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +2270 -0
  11. package/dist/index.d.ts +2270 -0
  12. package/dist/index.js +2 -1
  13. package/dist/index.js.map +1 -1
  14. package/package.json +30 -12
  15. package/api-extractor.json +0 -21
  16. package/src/chain-abstraction/index.ts +0 -8
  17. package/src/chain-abstraction/useCompareCosts.ts +0 -137
  18. package/src/chain-abstraction/useExecuteRoute.ts +0 -129
  19. package/src/chain-abstraction/useRouteQuote.ts +0 -168
  20. package/src/client.test.ts +0 -242
  21. package/src/client.ts +0 -265
  22. package/src/hooks/useAccount.test.ts +0 -67
  23. package/src/hooks/useAccount.ts +0 -37
  24. package/src/hooks/useBalance.test.ts +0 -459
  25. package/src/hooks/useBalance.ts +0 -170
  26. package/src/hooks/useChain.test.ts +0 -160
  27. package/src/hooks/useChain.ts +0 -53
  28. package/src/hooks/useConnect.test.ts +0 -112
  29. package/src/hooks/useConnect.ts +0 -29
  30. package/src/hooks/useDisconnect.test.ts +0 -75
  31. package/src/hooks/useDisconnect.ts +0 -32
  32. package/src/hooks/useERC20Allowance.ts +0 -93
  33. package/src/hooks/useERC20Approve.ts +0 -220
  34. package/src/hooks/useERC20Transfer.ts +0 -134
  35. package/src/hooks/useERC20TransferSimulation.ts +0 -147
  36. package/src/hooks/useEmbeddedWallet.test.ts +0 -266
  37. package/src/hooks/useEmbeddedWallet.ts +0 -181
  38. package/src/hooks/useLastTx.test.ts +0 -117
  39. package/src/hooks/useLastTx.ts +0 -73
  40. package/src/hooks/useLookupAddress.ts +0 -131
  41. package/src/hooks/useNotification.ts +0 -308
  42. package/src/hooks/useResolveName.ts +0 -128
  43. package/src/hooks/useSIWxLogin.test.ts +0 -307
  44. package/src/hooks/useSIWxLogin.ts +0 -163
  45. package/src/hooks/useSIWxSession.test.ts +0 -481
  46. package/src/hooks/useSIWxSession.ts +0 -290
  47. package/src/hooks/useSendCalls.ts +0 -103
  48. package/src/hooks/useSendTransaction.test.ts +0 -175
  49. package/src/hooks/useSendTransaction.ts +0 -80
  50. package/src/hooks/useSendUserOperation.ts +0 -313
  51. package/src/hooks/useSession.ts +0 -96
  52. package/src/hooks/useSessionKeys.ts +0 -356
  53. package/src/hooks/useSignInWithEthereum.test.ts +0 -224
  54. package/src/hooks/useSignInWithEthereum.ts +0 -46
  55. package/src/hooks/useSignInWithX.test.ts +0 -210
  56. package/src/hooks/useSignInWithX.ts +0 -141
  57. package/src/hooks/useSignMessage.test.ts +0 -151
  58. package/src/hooks/useSignMessage.ts +0 -65
  59. package/src/hooks/useSimulateTransfer.ts +0 -165
  60. package/src/hooks/useSiwxAuthSession.test.ts +0 -456
  61. package/src/hooks/useSiwxAuthSession.ts +0 -163
  62. package/src/hooks/useSmartAccount.ts +0 -194
  63. package/src/hooks/useSwitchChain.ts +0 -68
  64. package/src/hooks/useTokenBalance.test.ts +0 -337
  65. package/src/hooks/useTokenBalance.ts +0 -210
  66. package/src/hooks/useTransactionSimulation.ts +0 -401
  67. package/src/hooks/useTxHistory.test.ts +0 -108
  68. package/src/hooks/useTxHistory.ts +0 -83
  69. package/src/hooks/useTxMonitor.test.ts +0 -127
  70. package/src/hooks/useTxMonitor.ts +0 -178
  71. package/src/hooks/useUserOpStatus.ts +0 -245
  72. package/src/hooks/useValidateDestination.test.ts +0 -96
  73. package/src/hooks/useValidateDestination.ts +0 -72
  74. package/src/hooks/useViemClient.test.ts +0 -155
  75. package/src/hooks/useViemClient.ts +0 -65
  76. package/src/hooks/useWallet.test.ts +0 -133
  77. package/src/hooks/useWallet.ts +0 -39
  78. package/src/hooks/useWeb3ErrorHandler.ts +0 -102
  79. package/src/index.ts +0 -186
  80. package/src/provider/Web3ConnectProvider.test.tsx +0 -178
  81. package/src/provider/Web3ConnectProvider.tsx +0 -530
  82. package/src/token-list/TokenSelector.tsx +0 -351
  83. package/src/token-list/defaults.ts +0 -39
  84. package/src/token-list/index.ts +0 -14
  85. package/src/token-list/useTokenList.ts +0 -119
  86. package/src/token-list/useTokenSearch.ts +0 -99
  87. package/src/types/index.ts +0 -99
  88. package/src/utils/chains.ts +0 -115
  89. package/src/utils/errorMessages.ts +0 -142
  90. package/src/utils/i18n.ts +0 -90
  91. package/src/wc-generated/components.ts +0 -377
  92. package/test/setup.ts +0 -17
  93. package/test/test-utils.tsx +0 -78
  94. package/tsup.config.ts +0 -18
@@ -1,242 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
3
-
4
- // Need vi.hoisted because vi.mock is hoisted above variable declarations
5
- const { mockWalletConnectConnector, mockEmbeddedConnector, mockSolanaConnector } = vi.hoisted(() => {
6
- const wc = {
7
- id: "walletconnect",
8
- name: "WalletConnect",
9
- kind: "walletconnect",
10
- connect: vi.fn().mockResolvedValue({ id: "wc-session" }),
11
- disconnect: vi.fn().mockResolvedValue(undefined),
12
- reconnect: vi.fn().mockResolvedValue({ id: "wc-session" }),
13
- startPairing: vi.fn().mockResolvedValue("wc://uri?key=test"),
14
- completePairing: vi.fn().mockResolvedValue({ id: "wc-session" }),
15
- switchChain: vi.fn().mockResolvedValue(undefined),
16
- getAccounts: vi.fn().mockResolvedValue([]),
17
- signMessage: vi.fn(),
18
- };
19
-
20
- const embedded = {
21
- id: "embedded",
22
- name: "Embedded Wallet",
23
- kind: "embedded",
24
- connect: vi.fn().mockResolvedValue({ id: "embedded-session", walletType: "embedded" }),
25
- disconnect: vi.fn().mockResolvedValue(undefined),
26
- getAccounts: vi.fn().mockResolvedValue([]),
27
- };
28
-
29
- const solana = {
30
- id: "solana",
31
- name: "Solana",
32
- kind: "solana" as const,
33
- connect: vi.fn(),
34
- disconnect: vi.fn().mockResolvedValue(undefined),
35
- reconnect: vi.fn(),
36
- startPairing: vi.fn(),
37
- completePairing: vi.fn(),
38
- switchChain: vi.fn(),
39
- getAccounts: vi.fn().mockResolvedValue([]),
40
- signMessage: vi.fn().mockResolvedValue("signed-message"),
41
- sendTransaction: vi.fn().mockResolvedValue("tx-hash"),
42
- };
43
-
44
- return { mockWalletConnectConnector: wc, mockEmbeddedConnector: embedded, mockSolanaConnector: solana };
45
- });
46
-
47
- vi.mock("@naculus/connector-walletconnect", () => ({
48
- createWalletConnectConnector: vi.fn(() => mockWalletConnectConnector),
49
- WalletConnectConnector: vi.fn(),
50
- }));
51
-
52
- vi.mock("@naculus/connector-embedded", () => ({
53
- createPocketConnector: vi.fn(() => mockEmbeddedConnector),
54
- }));
55
-
56
- vi.mock("@naculus/connector-solana", () => ({
57
- solanaConnector: mockSolanaConnector,
58
- }));
59
-
60
- import {
61
- createClient,
62
- clearClient,
63
- getClient,
64
- } from "./client";
65
-
66
- const defaultConfig = {
67
- projectId: "test-project-id",
68
- metadata: {
69
- name: "Test App",
70
- description: "Test Description",
71
- url: "https://test.com",
72
- icons: ["https://test.com/icon.png"],
73
- },
74
- };
75
-
76
- describe("createClient", () => {
77
- beforeEach(() => {
78
- clearClient();
79
- vi.clearAllMocks();
80
- });
81
-
82
- afterEach(() => {
83
- clearClient();
84
- });
85
-
86
- describe("basic client", () => {
87
- it("should create a client", () => {
88
- const client = createClient(defaultConfig);
89
- expect(client).toBeDefined();
90
- expect(client.connector).toBeDefined();
91
- });
92
-
93
- it("should return singleton", () => {
94
- const client1 = createClient(defaultConfig);
95
- const client2 = createClient(defaultConfig);
96
- expect(client1).toBe(client2);
97
- });
98
-
99
- it("getClient should return null before creation", () => {
100
- expect(getClient()).toBeNull();
101
- });
102
-
103
- it("getClient should return instance after creation", () => {
104
- const client = createClient(defaultConfig);
105
- expect(getClient()).toBe(client);
106
- });
107
-
108
- it("clearClient allows fresh instance", () => {
109
- const client1 = createClient(defaultConfig);
110
- clearClient();
111
- expect(getClient()).toBeNull();
112
- const client2 = createClient(defaultConfig);
113
- expect(client2).not.toBe(client1);
114
- });
115
-
116
- it("should delegate connect() to WalletConnect", async () => {
117
- const client = createClient(defaultConfig);
118
- const session = await client.connect();
119
- expect(mockWalletConnectConnector.connect).toHaveBeenCalledOnce();
120
- expect(session).toEqual({ id: "wc-session" });
121
- });
122
-
123
- it("should delegate disconnect()", async () => {
124
- const client = createClient(defaultConfig);
125
- const session = { id: "test" } as any;
126
- await client.disconnect(session);
127
- expect(mockWalletConnectConnector.disconnect).toHaveBeenCalledWith(session);
128
- });
129
-
130
- it("should delegate reconnect()", async () => {
131
- const client = createClient(defaultConfig);
132
- const session = { id: "test" } as any;
133
- const result = await client.reconnect(session);
134
- expect(mockWalletConnectConnector.reconnect).toHaveBeenCalledWith(session);
135
- expect(result).toEqual({ id: "wc-session" });
136
- });
137
-
138
- it("should delegate startPairing/completePairing", async () => {
139
- const client = createClient(defaultConfig);
140
- const uri = await client.startPairing();
141
- expect(uri).toBe("wc://uri?key=test");
142
- expect(await client.completePairing()).toEqual({ id: "wc-session" });
143
- });
144
-
145
- it("should throw on connectEmbedded when not enabled", async () => {
146
- const client = createClient(defaultConfig);
147
- await expect(client.connectEmbedded()).rejects.toThrow("not enabled");
148
- });
149
-
150
- it("should return 1 connector from getAllConnectors", () => {
151
- const client = createClient(defaultConfig);
152
- expect(client.getAllConnectors()).toHaveLength(1);
153
- });
154
- });
155
-
156
- describe("with Embedded Wallet enabled", () => {
157
- it("should connect embedded wallet", async () => {
158
- const client = createClient({ ...defaultConfig, enableEmbedded: true });
159
- const session = await client.connectEmbedded();
160
- expect(session).toEqual({ id: "embedded-session", walletType: "embedded" });
161
- });
162
-
163
- it("should set embeddedConnector after connect", async () => {
164
- const client = createClient({ ...defaultConfig, enableEmbedded: true });
165
- await client.connectEmbedded();
166
- expect(client.embeddedConnector).not.toBeNull();
167
- expect(client.embeddedConnector!.id).toBe("embedded");
168
- });
169
-
170
- it("should include embedded in getAllConnectors", async () => {
171
- const client = createClient({ ...defaultConfig, enableEmbedded: true });
172
- await client.connectEmbedded();
173
- const connectors = client.getAllConnectors();
174
- expect(connectors.find((c) => c.kind === "embedded")).toBeDefined();
175
- });
176
- });
177
-
178
- describe("with Solana enabled", () => {
179
- it("signMessage routes to solana connector", async () => {
180
- const client = createClient({ ...defaultConfig, enableSolana: false });
181
- client._setSolanaConnector(mockSolanaConnector as any);
182
-
183
- const session = { walletType: "solana", id: "sol-session", namespaces: {} } as any;
184
- const result = await client.signMessage(session, { message: "hello" });
185
-
186
- expect(mockSolanaConnector.signMessage).toHaveBeenCalledWith(session, { message: "hello" });
187
- expect(result).toBe("signed-message");
188
- });
189
-
190
- it("signMessage awaits solanaInit before routing", async () => {
191
- const client = createClient({ ...defaultConfig, enableSolana: true });
192
-
193
- const session = { walletType: "solana", id: "sol-session", namespaces: {} } as any;
194
- const result = await client.signMessage(session, { message: "hello" });
195
-
196
- expect(mockSolanaConnector.signMessage).toHaveBeenCalled();
197
- expect(result).toBe("signed-message");
198
- expect(client.solanaConnector).toBe(mockSolanaConnector);
199
- });
200
-
201
- it("signMessage with no solana connector throws WalletError", async () => {
202
- const client = createClient(defaultConfig);
203
-
204
- const session = { walletType: "solana", id: "sol-session", namespaces: {} } as any;
205
- await expect(
206
- client.signMessage(session, { message: "hello" })
207
- ).rejects.toThrow("Solana connector not available");
208
- });
209
-
210
- it("sendTransaction routes to solana connector", async () => {
211
- const client = createClient({ ...defaultConfig, enableSolana: false });
212
- client._setSolanaConnector(mockSolanaConnector as any);
213
-
214
- const session = { walletType: "solana", id: "sol-session", namespaces: {} } as any;
215
- const tx = { transaction: { from: "abc" } };
216
- const result = await client.sendTransaction(session, tx);
217
-
218
- expect(mockSolanaConnector.sendTransaction).toHaveBeenCalledWith(session, tx);
219
- expect(result).toBe("tx-hash");
220
- });
221
-
222
- it("disconnect routes to solana connector", async () => {
223
- const client = createClient({ ...defaultConfig, enableSolana: false });
224
- client._setSolanaConnector(mockSolanaConnector as any);
225
-
226
- const session = { walletType: "solana", id: "sol-session", namespaces: {} } as any;
227
- await client.disconnect(session);
228
-
229
- expect(mockSolanaConnector.disconnect).toHaveBeenCalledWith(session);
230
- });
231
-
232
- it("reconnect with solana walletType returns session as-is", async () => {
233
- const client = createClient({ ...defaultConfig, enableSolana: false });
234
- client._setSolanaConnector(mockSolanaConnector as any);
235
-
236
- const session = { walletType: "solana", id: "sol-session", namespaces: {} } as any;
237
- const result = await client.reconnect(session);
238
-
239
- expect(result).toBe(session);
240
- });
241
- });
242
- });
package/src/client.ts DELETED
@@ -1,265 +0,0 @@
1
- import { WalletConnectConnector, createWalletConnectConnector } from "@naculus/connector-walletconnect";
2
- import { eip6963Connector } from "@naculus/connector-evm-injected";
3
- import { logger, WalletError } from "@naculus/connect-core";
4
- import type { UniversalConnector, UniversalWalletSession, BatchCall, CallsStatus } from "@naculus/connect-core";
5
- import type { PocketConnectorClass as EmbeddedWalletConnector } from "@naculus/connector-embedded";
6
- import type PasskeysConnectorImpl from "@naculus/connector-passkeys";
7
-
8
- export type ClientConfig = {
9
- projectId: string;
10
- metadata: {
11
- name: string;
12
- description: string;
13
- url: string;
14
- icons: string[];
15
- };
16
- /** Enable embedded (self-custodial) wallet */
17
- enableEmbedded?: boolean;
18
-
19
- /** Enable passkeys (WebAuthn) connector */
20
- enablePasskeys?: boolean;
21
-
22
- /** Enable Solana injected wallet connector (Phantom, Solflare) */
23
- enableSolana?: boolean;
24
- /** Default Solana chain (e.g. "solana:0"). Only used when enableSolana is true. */
25
- solanaDefaultChain?: string;
26
- };
27
-
28
- export interface Web3Client {
29
- connector: WalletConnectConnector;
30
- embeddedConnector: EmbeddedWalletConnector | null;
31
- /** The Passkeys connector if enabled */
32
- passkeysConnector: PasskeysConnectorImpl | null;
33
- /** The Solana injected wallet connector if enabled */
34
- solanaConnector: UniversalConnector | null;
35
- connect: () => Promise<UniversalWalletSession>;
36
- /** Connect via EIP-6963 injected wallet */
37
- connectInjected: (walletId?: string) => Promise<UniversalWalletSession>;
38
- connectEmbedded: () => Promise<UniversalWalletSession>;
39
- /** Connect via passkeys (WebAuthn) */
40
- connectPasskeys: () => Promise<UniversalWalletSession>;
41
- reconnect: (session: UniversalWalletSession) => Promise<UniversalWalletSession>;
42
- disconnect: (session: UniversalWalletSession) => Promise<void>;
43
- /** Sign a message via the appropriate connector for the session */
44
- signMessage: (session: UniversalWalletSession, input: { message: string; address?: string; chainId?: string }) => Promise<unknown>;
45
- /** Send a transaction via the appropriate connector for the session */
46
- sendTransaction: (session: UniversalWalletSession, input: { transaction: Record<string, unknown>; chainId?: string }) => Promise<unknown>;
47
- /** Send batched calls (EIP-5792 wallet_sendCalls) via the appropriate connector */
48
- sendCalls: (session: UniversalWalletSession, calls: BatchCall[], chainId?: string) => Promise<string>;
49
- getCallsStatus: (session: UniversalWalletSession, bundleHash: string) => Promise<CallsStatus>;
50
- startPairing: () => Promise<string>;
51
- completePairing: () => Promise<UniversalWalletSession>;
52
- getAllConnectors: () => UniversalConnector[];
53
- /** @internal set embedded connector after lazy init */
54
- _setEmbeddedConnector: (conn: EmbeddedWalletConnector) => void;
55
- /** @internal set passkeys connector after lazy init */
56
- _setPasskeysConnector: (conn: PasskeysConnectorImpl) => void;
57
- /** @internal set solana connector after lazy init */
58
- _setSolanaConnector: (conn: UniversalConnector) => void;
59
- }
60
-
61
- let clientInstance: Web3Client | null = null;
62
-
63
- export function createClient(config: ClientConfig): Web3Client {
64
- if (clientInstance) return clientInstance;
65
-
66
- const connector = createWalletConnectConnector({
67
- projectId: config.projectId,
68
- metadata: config.metadata
69
- });
70
-
71
- let _embeddedConnector: EmbeddedWalletConnector | null = null;
72
- let embeddedInit: Promise<void> | null = null;
73
-
74
- if (config.enableEmbedded) {
75
- embeddedInit = import("@naculus/connector-embedded").then((mod) => {
76
- const conn = mod.createPocketConnector();
77
- _embeddedConnector = conn;
78
- if (clientInstance) clientInstance._setEmbeddedConnector(_embeddedConnector);
79
- }).catch((err) => {
80
- logger.warn("react/client", "Embedded wallet connector not available:", err);
81
- _embeddedConnector = null;
82
- });
83
- }
84
-
85
- let _passkeysConnector: PasskeysConnectorImpl | null = null;
86
- let passkeysInit: Promise<void> | null = null;
87
-
88
- if (config.enablePasskeys) {
89
- passkeysInit = import("@naculus/connector-passkeys").then((mod) => {
90
- const conn = mod.createPasskeysConnector();
91
- _passkeysConnector = conn;
92
- if (clientInstance) clientInstance._setPasskeysConnector(_passkeysConnector);
93
- }).catch((err) => {
94
- logger.warn("react/client", "Passkeys connector not available:", err);
95
- _passkeysConnector = null;
96
- });
97
- }
98
-
99
- let _solanaConnector: UniversalConnector | null = null;
100
- let solanaInit: Promise<void> | null = null;
101
-
102
- if (config.enableSolana) {
103
- solanaInit = import("@naculus/connector-solana").then((mod: any) => {
104
- // Use the singleton instance so hooks (useSolanaAccount, etc.) and
105
- // the client routing share the same activeSession state.
106
- const conn = mod.solanaConnector as UniversalConnector;
107
- if (config.solanaDefaultChain && "configure" in conn) {
108
- (conn as any).configure({ defaultChain: config.solanaDefaultChain });
109
- }
110
- _solanaConnector = conn;
111
- if (typeof window !== "undefined" && "startDiscovery" in conn) {
112
- (conn as any).startDiscovery();
113
- }
114
- if (clientInstance) clientInstance._setSolanaConnector(_solanaConnector);
115
- }).catch((err) => {
116
- logger.warn("react/client", "Solana connector not available:", err);
117
- _solanaConnector = null;
118
- });
119
- }
120
-
121
- // Start EIP-6963 discovery eagerly so wallets are available when user clicks connect
122
- if (typeof window !== "undefined") {
123
- eip6963Connector.startDiscovery();
124
- }
125
-
126
- clientInstance = {
127
- connector,
128
- get embeddedConnector() { return _embeddedConnector; },
129
- get passkeysConnector() { return _passkeysConnector; },
130
- get solanaConnector() { return _solanaConnector; },
131
- connect: () => connector.connect(),
132
- connectInjected: async (walletId?: string) => {
133
- return eip6963Connector.connect(walletId);
134
- },
135
- connectEmbedded: async () => {
136
- if (embeddedInit) await embeddedInit;
137
- if (!_embeddedConnector) {
138
- throw new Error("Embedded wallet not enabled. Set enableEmbedded: true in config.");
139
- }
140
- return _embeddedConnector.connect();
141
- },
142
- connectPasskeys: async () => {
143
- if (passkeysInit) await passkeysInit;
144
- if (!_passkeysConnector) {
145
- throw new Error("Passkeys connector not enabled. Set enablePasskeys: true in config.");
146
- }
147
- return _passkeysConnector.connect();
148
- },
149
- startPairing: () => connector.startPairing(),
150
- completePairing: () => connector.completePairing(),
151
- signMessage: async (session, input) => {
152
- if (session.id?.startsWith("eip6963-")) {
153
- return eip6963Connector.signMessage(session as any, input);
154
- }
155
- if (session.walletType === "passkeys" && _passkeysConnector) {
156
- return _passkeysConnector.signMessage(session as any, input);
157
- }
158
- if (session.walletType === "solana") {
159
- if (solanaInit) await solanaInit;
160
- if (_solanaConnector) {
161
- return (_solanaConnector as any).signMessage(session as any, input);
162
- }
163
- throw new WalletError("wallet_unavailable", "Solana connector not available. Ensure enableSolana is true and @naculus/connector-solana is installed.");
164
- }
165
- return connector.signMessage(session, input);
166
- },
167
- sendTransaction: async (session, input) => {
168
- if (session.id?.startsWith("eip6963-")) {
169
- return eip6963Connector.sendTransaction(session as any, input);
170
- }
171
- if (session.walletType === "passkeys" && _passkeysConnector) {
172
- return _passkeysConnector.sendTransaction(session as any, input);
173
- }
174
- if (session.walletType === "solana") {
175
- if (solanaInit) await solanaInit;
176
- if (_solanaConnector) {
177
- return (_solanaConnector as any).sendTransaction(session as any, input);
178
- }
179
- throw new WalletError("wallet_unavailable", "Solana connector not available. Ensure enableSolana is true and @naculus/connector-solana is installed.");
180
- }
181
- return connector.sendTransaction(session, input);
182
- },
183
- sendCalls: async (session, calls, chainId) => {
184
- if (session.id?.startsWith("eip6963-")) {
185
- return eip6963Connector.sendCalls!(session as any, calls, chainId);
186
- }
187
- if (session.walletType === "passkeys" && _passkeysConnector) {
188
- return _passkeysConnector.sendCalls(session as any, calls, chainId);
189
- }
190
- if (session.walletType === "solana") {
191
- if (solanaInit) await solanaInit;
192
- if (_solanaConnector) {
193
- return (_solanaConnector as any).sendCalls(session as any, calls, chainId);
194
- }
195
- throw new WalletError("wallet_unavailable", "Solana connector not available. Ensure enableSolana is true and @naculus/connector-solana is installed.");
196
- }
197
- if (session.walletType === "embedded" && _embeddedConnector && _embeddedConnector.sendCalls) {
198
- return _embeddedConnector.sendCalls(session as any, calls, chainId);
199
- }
200
- if (!connector.sendCalls) {
201
- throw new WalletError("method_not_allowed", "sendCalls not supported by this connector");
202
- }
203
- return connector.sendCalls(session, calls, chainId);
204
- },
205
- getCallsStatus: async (session, bundleHash) => {
206
- if (session.id?.startsWith("eip6963-") && eip6963Connector.getCallsStatus) {
207
- return eip6963Connector.getCallsStatus(session as any, bundleHash);
208
- }
209
- if (session.walletType === "passkeys" && _passkeysConnector?.getCallsStatus) {
210
- return _passkeysConnector.getCallsStatus(session as any, bundleHash);
211
- }
212
- if (!connector.getCallsStatus) {
213
- throw new WalletError("method_not_allowed", "getCallsStatus not supported by this connector");
214
- }
215
- return connector.getCallsStatus(session, bundleHash);
216
- },
217
- reconnect: async (session) => {
218
- if (session.walletType === "eip6963") {
219
- return eip6963Connector.reconnect(session);
220
- }
221
- if (session.walletType === "embedded") {
222
- if (_embeddedConnector) {
223
- return _embeddedConnector.reconnect(session);
224
- }
225
- return session;
226
- }
227
- if (session.walletType === "solana") {
228
- // Solana injected wallet doesn't support reconnect (no persisted session).
229
- // Return the saved session as-is; signing ops require wallet reconnection.
230
- return session;
231
- }
232
- return connector.reconnect(session);
233
- },
234
- disconnect: async (session) => {
235
- if (session.walletType === "solana") {
236
- if (solanaInit) await solanaInit;
237
- if (_solanaConnector) {
238
- return _solanaConnector.disconnect(session);
239
- }
240
- throw new WalletError("wallet_unavailable", "Solana connector not available. Ensure enableSolana is true and @naculus/connector-solana is installed.");
241
- }
242
- return connector.disconnect(session);
243
- },
244
- getAllConnectors: () => {
245
- const connectors: UniversalConnector[] = [connector];
246
- if (_embeddedConnector) connectors.push(_embeddedConnector);
247
- if (_passkeysConnector) connectors.push(_passkeysConnector);
248
- if (_solanaConnector) connectors.push(_solanaConnector);
249
- return connectors;
250
- },
251
- _setEmbeddedConnector: (conn: EmbeddedWalletConnector) => { _embeddedConnector = conn; },
252
- _setPasskeysConnector: (conn: PasskeysConnectorImpl) => { _passkeysConnector = conn; },
253
- _setSolanaConnector: (conn: UniversalConnector) => { _solanaConnector = conn; },
254
- };
255
-
256
- return clientInstance;
257
- }
258
-
259
- export function getClient(): Web3Client | null {
260
- return clientInstance;
261
- }
262
-
263
- export function clearClient(): void {
264
- clientInstance = null;
265
- }
@@ -1,67 +0,0 @@
1
- /// <reference types="vitest" />
2
- /// @vitest-environment jsdom
3
-
4
- import { describe, it, expect, vi, beforeEach } from "vitest";
5
- import { renderHook } from "@testing-library/react";
6
-
7
- const mockUseWeb3 = vi.fn();
8
- vi.mock("../provider/Web3ConnectProvider", () => ({
9
- useWeb3: () => mockUseWeb3(),
10
- Web3ConnectProvider: ({ children }: { children: React.ReactNode }) => children,
11
- }));
12
-
13
- import { useAccount } from "./useAccount";
14
-
15
- describe("useAccount", () => {
16
- beforeEach(() => {
17
- vi.clearAllMocks();
18
- });
19
-
20
- it("should return null accounts when not connected", () => {
21
- mockUseWeb3.mockReturnValue({
22
- accounts: [],
23
- session: null,
24
- isConnected: false,
25
- });
26
- const { result } = renderHook(() => useAccount());
27
-
28
- expect(result.current.accounts).toBeNull();
29
- expect(result.current.evmAccount).toBeNull();
30
- expect(result.current.isConnected).toBe(false);
31
- });
32
-
33
- it("should return null when accounts array is empty even if connected", () => {
34
- mockUseWeb3.mockReturnValue({
35
- accounts: [],
36
- session: { topic: "test" },
37
- isConnected: true,
38
- });
39
- const { result } = renderHook(() => useAccount());
40
-
41
- expect(result.current.accounts).toBeNull();
42
- expect(result.current.evmAccount).toBeNull();
43
- });
44
-
45
- it("should identify EVM accounts", () => {
46
- mockUseWeb3.mockReturnValue({
47
- accounts: ["eip155:1:0x1234567890123456789012345678901234567890"],
48
- session: { topic: "test" },
49
- isConnected: true,
50
- });
51
- const { result } = renderHook(() => useAccount());
52
-
53
- expect(result.current.accounts).toHaveLength(1);
54
- expect(result.current.evmAccount).toBe("eip155:1:0x1234567890123456789012345678901234567890");
55
- });
56
-
57
- it("should identify plain 0x addresses as EVM", () => {
58
- mockUseWeb3.mockReturnValue({
59
- accounts: ["0xabcdef1234567890abcdef1234567890abcdef12"],
60
- session: { topic: "test" },
61
- isConnected: true,
62
- });
63
- const { result } = renderHook(() => useAccount());
64
-
65
- expect(result.current.evmAccount).toBe("0xabcdef1234567890abcdef1234567890abcdef12");
66
- });
67
- });
@@ -1,37 +0,0 @@
1
- import { useMemo } from "react";
2
- import { useWeb3 } from "../provider/Web3ConnectProvider";
3
-
4
- export function useAccount() {
5
- const { accounts, session, isConnected } = useWeb3();
6
-
7
- const accountData = useMemo(() => {
8
- if (!isConnected || accounts.length === 0) {
9
- return null;
10
- }
11
-
12
- return accounts.map((address) => {
13
- // H12: Strengthened CAIP-10 / address detection
14
- // Valid formats:
15
- // CAIP-10: "eip155:1:0x1234...5678" (namespace:chainId:address)
16
- // Plain: "0x1234...5678" (42-char hex, 0x + 40 hex chars)
17
- const isCaip10 = /^eip155:\d+:0x[0-9a-fA-F]{40}$/.test(address);
18
- const isPlainHex = /^0x[0-9a-fA-F]{40}$/.test(address);
19
- const isEvm = isCaip10 || isPlainHex;
20
-
21
- return {
22
- address,
23
- isEVM: isEvm,
24
- };
25
- });
26
- }, [accounts, isConnected]);
27
-
28
- const evmAccount = accountData?.find((a) => a.isEVM)?.address ?? null;
29
-
30
- return {
31
- accounts: accountData,
32
- evmAccount,
33
- primaryAccount: accounts[0] ?? null,
34
- isConnected,
35
- count: accounts.length
36
- };
37
- }