@naculus/connect-appkit-react 0.1.8 → 0.2.0
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/README.md +4 -4
- package/dist/client.cjs +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +144 -0
- package/dist/client.d.ts +144 -0
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2270 -0
- package/dist/index.d.ts +2270 -0
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +30 -12
- package/api-extractor.json +0 -21
- package/src/chain-abstraction/index.ts +0 -8
- package/src/chain-abstraction/useCompareCosts.ts +0 -137
- package/src/chain-abstraction/useExecuteRoute.ts +0 -129
- package/src/chain-abstraction/useRouteQuote.ts +0 -168
- package/src/client.test.ts +0 -242
- package/src/client.ts +0 -265
- package/src/hooks/useAccount.test.ts +0 -67
- package/src/hooks/useAccount.ts +0 -37
- package/src/hooks/useBalance.test.ts +0 -459
- package/src/hooks/useBalance.ts +0 -170
- package/src/hooks/useChain.test.ts +0 -160
- package/src/hooks/useChain.ts +0 -53
- package/src/hooks/useConnect.test.ts +0 -112
- package/src/hooks/useConnect.ts +0 -29
- package/src/hooks/useDisconnect.test.ts +0 -75
- package/src/hooks/useDisconnect.ts +0 -32
- package/src/hooks/useERC20Allowance.ts +0 -93
- package/src/hooks/useERC20Approve.ts +0 -220
- package/src/hooks/useERC20Transfer.ts +0 -134
- package/src/hooks/useERC20TransferSimulation.ts +0 -147
- package/src/hooks/useEmbeddedWallet.test.ts +0 -266
- package/src/hooks/useEmbeddedWallet.ts +0 -181
- package/src/hooks/useLastTx.test.ts +0 -117
- package/src/hooks/useLastTx.ts +0 -73
- package/src/hooks/useLookupAddress.ts +0 -131
- package/src/hooks/useNotification.ts +0 -308
- package/src/hooks/useResolveName.ts +0 -128
- package/src/hooks/useSIWxLogin.test.ts +0 -307
- package/src/hooks/useSIWxLogin.ts +0 -163
- package/src/hooks/useSIWxSession.test.ts +0 -481
- package/src/hooks/useSIWxSession.ts +0 -290
- package/src/hooks/useSendCalls.ts +0 -103
- package/src/hooks/useSendTransaction.test.ts +0 -175
- package/src/hooks/useSendTransaction.ts +0 -80
- package/src/hooks/useSendUserOperation.ts +0 -313
- package/src/hooks/useSession.ts +0 -96
- package/src/hooks/useSessionKeys.ts +0 -356
- package/src/hooks/useSignInWithEthereum.test.ts +0 -224
- package/src/hooks/useSignInWithEthereum.ts +0 -46
- package/src/hooks/useSignInWithX.test.ts +0 -210
- package/src/hooks/useSignInWithX.ts +0 -141
- package/src/hooks/useSignMessage.test.ts +0 -151
- package/src/hooks/useSignMessage.ts +0 -65
- package/src/hooks/useSimulateTransfer.ts +0 -165
- package/src/hooks/useSiwxAuthSession.test.ts +0 -456
- package/src/hooks/useSiwxAuthSession.ts +0 -163
- package/src/hooks/useSmartAccount.ts +0 -194
- package/src/hooks/useSwitchChain.ts +0 -68
- package/src/hooks/useTokenBalance.test.ts +0 -337
- package/src/hooks/useTokenBalance.ts +0 -210
- package/src/hooks/useTransactionSimulation.ts +0 -401
- package/src/hooks/useTxHistory.test.ts +0 -108
- package/src/hooks/useTxHistory.ts +0 -83
- package/src/hooks/useTxMonitor.test.ts +0 -127
- package/src/hooks/useTxMonitor.ts +0 -178
- package/src/hooks/useUserOpStatus.ts +0 -245
- package/src/hooks/useValidateDestination.test.ts +0 -96
- package/src/hooks/useValidateDestination.ts +0 -72
- package/src/hooks/useViemClient.test.ts +0 -155
- package/src/hooks/useViemClient.ts +0 -65
- package/src/hooks/useWallet.test.ts +0 -133
- package/src/hooks/useWallet.ts +0 -39
- package/src/hooks/useWeb3ErrorHandler.ts +0 -102
- package/src/index.ts +0 -186
- package/src/provider/Web3ConnectProvider.test.tsx +0 -178
- package/src/provider/Web3ConnectProvider.tsx +0 -530
- package/src/token-list/TokenSelector.tsx +0 -351
- package/src/token-list/defaults.ts +0 -39
- package/src/token-list/index.ts +0 -14
- package/src/token-list/useTokenList.ts +0 -119
- package/src/token-list/useTokenSearch.ts +0 -99
- package/src/types/index.ts +0 -99
- package/src/utils/chains.ts +0 -115
- package/src/utils/errorMessages.ts +0 -142
- package/src/utils/i18n.ts +0 -90
- package/src/wc-generated/components.ts +0 -377
- package/test/setup.ts +0 -17
- package/test/test-utils.tsx +0 -78
- package/tsup.config.ts +0 -18
package/src/client.test.ts
DELETED
|
@@ -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
|
-
});
|
package/src/hooks/useAccount.ts
DELETED
|
@@ -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
|
-
}
|