@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.
- 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
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
/// <reference types="vitest" />
|
|
2
|
-
/// @vitest-environment jsdom
|
|
3
|
-
|
|
4
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
5
|
-
import { renderHook, act } from "@testing-library/react";
|
|
6
|
-
|
|
7
|
-
// ── Mocks ────────────────────────────────────────────────────────
|
|
8
|
-
|
|
9
|
-
// Mock @naculus/connect-core to avoid @noble/hashes issues
|
|
10
|
-
vi.mock("@naculus/connect-core", async () => {
|
|
11
|
-
// Import actual types for proper resolves, but provide a stub implementation
|
|
12
|
-
const mod: any = {};
|
|
13
|
-
// We'll just provide the class name so instanceof checks pass in tests
|
|
14
|
-
return Object.assign(mod, {
|
|
15
|
-
WalletError: class WalletError extends Error {
|
|
16
|
-
code: string;
|
|
17
|
-
constructor(code: string, message: string) {
|
|
18
|
-
super(message);
|
|
19
|
-
this.name = "WalletError";
|
|
20
|
-
this.code = code;
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
|
|
24
|
-
LocalStorageAdapter: vi.fn().mockImplementation(() => ({
|
|
25
|
-
get: vi.fn(),
|
|
26
|
-
set: vi.fn(),
|
|
27
|
-
remove: vi.fn(),
|
|
28
|
-
clear: vi.fn(),
|
|
29
|
-
isAvailable: vi.fn(() => true),
|
|
30
|
-
})),
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// Mock @naculus/siwx to avoid transitive dependency chain issues with @noble/hashes
|
|
35
|
-
vi.mock("@naculus/siwx", () => {
|
|
36
|
-
const mockCreateSiwxMessage = vi.fn((params) => {
|
|
37
|
-
const lines = [
|
|
38
|
-
`${params.domain} wants you to sign in with your ${params.blockchain ?? "blockchain"} account:`,
|
|
39
|
-
params.address,
|
|
40
|
-
...(params.statement ? ["", params.statement] : []),
|
|
41
|
-
"",
|
|
42
|
-
`URI: ${params.uri}`,
|
|
43
|
-
`Version: ${params.version ?? 1}`,
|
|
44
|
-
`Chain ID: ${params.chainId}`,
|
|
45
|
-
`Nonce: ${params.nonce}`,
|
|
46
|
-
`Issued At: ${params.issuedAt}`,
|
|
47
|
-
];
|
|
48
|
-
return lines.join("\n");
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
createSiwxMessage: mockCreateSiwxMessage,
|
|
53
|
-
generateNonce: vi.fn(() => "mockNonce123"),
|
|
54
|
-
nowISO: vi.fn(() => new Date().toISOString()),
|
|
55
|
-
getBlockchainName: vi.fn((chainId) => {
|
|
56
|
-
if (chainId.startsWith("eip155:")) return "Ethereum";
|
|
57
|
-
if (chainId.startsWith("solana:")) return "Solana";
|
|
58
|
-
if (chainId.startsWith("xrpl:")) return "XRP Ledger";
|
|
59
|
-
return "blockchain";
|
|
60
|
-
}),
|
|
61
|
-
// Type-only exports — provide minimal stubs
|
|
62
|
-
checkSessionExpired: vi.fn((session) => {
|
|
63
|
-
if (!session) return true;
|
|
64
|
-
if (!session.expiresAt) return false;
|
|
65
|
-
return new Date(session.expiresAt).getTime() <= Date.now();
|
|
66
|
-
}),
|
|
67
|
-
createLocalStorageSiwxSessionStorage: vi.fn((key) => ({
|
|
68
|
-
async get() {
|
|
69
|
-
const raw = localStorage.getItem(key);
|
|
70
|
-
if (!raw) return null;
|
|
71
|
-
try {
|
|
72
|
-
const session = JSON.parse(raw);
|
|
73
|
-
if (session.expiresAt && new Date(session.expiresAt).getTime() <= Date.now()) {
|
|
74
|
-
localStorage.removeItem(key);
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
return session;
|
|
78
|
-
} catch {
|
|
79
|
-
localStorage.removeItem(key);
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
async set(session: any) { localStorage.setItem(key, JSON.stringify(session)); },
|
|
84
|
-
async remove() { localStorage.removeItem(key); },
|
|
85
|
-
async has() { return localStorage.getItem(key) !== null; },
|
|
86
|
-
async clear() { localStorage.removeItem(key); },
|
|
87
|
-
})),
|
|
88
|
-
createMemorySiwxSessionStorage: vi.fn(() => {
|
|
89
|
-
const store = new Map();
|
|
90
|
-
return {
|
|
91
|
-
async get() { return store.get("default") ?? null; },
|
|
92
|
-
async set(session: any) { store.set("default", JSON.stringify(session)); },
|
|
93
|
-
async remove() { store.delete("default"); },
|
|
94
|
-
async has() { return store.has("default"); },
|
|
95
|
-
async clear() { store.clear(); },
|
|
96
|
-
};
|
|
97
|
-
}),
|
|
98
|
-
SiwxSessionManager: vi.fn(),
|
|
99
|
-
DEFAULT_SESSION_EXPIRY_SECONDS: 86_400,
|
|
100
|
-
DEFAULT_SESSION_STORAGE_KEY: "naculus_siwx_session",
|
|
101
|
-
};
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
const mockUseWeb3 = vi.fn();
|
|
105
|
-
vi.mock("../provider/Web3ConnectProvider", () => ({
|
|
106
|
-
useWeb3: () => mockUseWeb3(),
|
|
107
|
-
Web3ConnectProvider: ({ children }: { children: React.ReactNode }) => children,
|
|
108
|
-
}));
|
|
109
|
-
|
|
110
|
-
const mockSignMessage = vi.fn();
|
|
111
|
-
const mockGetClient = vi.fn();
|
|
112
|
-
vi.mock("../client", () => ({
|
|
113
|
-
getClient: () => mockGetClient(),
|
|
114
|
-
}));
|
|
115
|
-
|
|
116
|
-
import { useSIWxLogin } from "./useSIWxLogin";
|
|
117
|
-
|
|
118
|
-
// ── Fixtures ─────────────────────────────────────────────────────
|
|
119
|
-
|
|
120
|
-
function createEvmSession() {
|
|
121
|
-
return {
|
|
122
|
-
topic: "test-topic",
|
|
123
|
-
namespaces: {
|
|
124
|
-
eip155: {
|
|
125
|
-
chains: ["eip155:1"],
|
|
126
|
-
accounts: ["eip155:1:0x1234567890123456789012345678901234567890"],
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function createSolanaSession() {
|
|
133
|
-
return {
|
|
134
|
-
topic: "test-topic",
|
|
135
|
-
namespaces: {
|
|
136
|
-
solana: {
|
|
137
|
-
chains: ["solana:4sGjMW1s"],
|
|
138
|
-
accounts: ["solana:4sGjMW1s:5JG7DPRQAxJVCLx3GxsHTxP1KZbSyLmPQBLkLhFZPGrH"],
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
describe("useSIWxLogin", () => {
|
|
145
|
-
beforeEach(() => {
|
|
146
|
-
vi.clearAllMocks();
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it("should have initial idle state", () => {
|
|
150
|
-
mockUseWeb3.mockReturnValue({ session: null, chainId: null });
|
|
151
|
-
mockGetClient.mockReturnValue(null);
|
|
152
|
-
|
|
153
|
-
const { result } = renderHook(() => useSIWxLogin());
|
|
154
|
-
|
|
155
|
-
expect(result.current.isSigningIn).toBe(false);
|
|
156
|
-
expect(result.current.error).toBeNull();
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it("should throw when no session", async () => {
|
|
160
|
-
mockUseWeb3.mockReturnValue({ session: null, chainId: null });
|
|
161
|
-
mockGetClient.mockReturnValue({ signMessage: mockSignMessage });
|
|
162
|
-
|
|
163
|
-
const { result } = renderHook(() => useSIWxLogin());
|
|
164
|
-
|
|
165
|
-
await expect(result.current.signIn()).rejects.toThrow("No active session");
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it("should throw when client not initialized", async () => {
|
|
169
|
-
mockUseWeb3.mockReturnValue({
|
|
170
|
-
session: createEvmSession(),
|
|
171
|
-
chainId: "eip155:1",
|
|
172
|
-
});
|
|
173
|
-
mockGetClient.mockReturnValue(null);
|
|
174
|
-
|
|
175
|
-
const { result } = renderHook(() => useSIWxLogin());
|
|
176
|
-
|
|
177
|
-
await expect(result.current.signIn()).rejects.toThrow("Client not initialized");
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it("should sign in with EVM account and return SiwxResult", async () => {
|
|
181
|
-
const mockSignature = "0xevm_signature";
|
|
182
|
-
mockSignMessage.mockResolvedValue(mockSignature);
|
|
183
|
-
mockUseWeb3.mockReturnValue({
|
|
184
|
-
session: createEvmSession(),
|
|
185
|
-
chainId: "eip155:1",
|
|
186
|
-
});
|
|
187
|
-
mockGetClient.mockReturnValue({ signMessage: mockSignMessage });
|
|
188
|
-
|
|
189
|
-
const { result } = renderHook(() => useSIWxLogin());
|
|
190
|
-
|
|
191
|
-
let siwxResult: Awaited<ReturnType<typeof result.current.signIn>> | undefined;
|
|
192
|
-
|
|
193
|
-
await act(async () => {
|
|
194
|
-
siwxResult = await result.current.signIn({
|
|
195
|
-
statement: "Sign in to test",
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
expect(siwxResult).toBeDefined();
|
|
200
|
-
expect(siwxResult!.signature).toBe(mockSignature);
|
|
201
|
-
// jsdom sets location to localhost:3000 by default
|
|
202
|
-
expect(siwxResult!.message.domain).toBe("localhost:3000");
|
|
203
|
-
expect(siwxResult!.message.chainId).toBe("eip155:1");
|
|
204
|
-
expect(siwxResult!.message.statement).toBe("Sign in to test");
|
|
205
|
-
expect(siwxResult!.message.expirationTime).toBeDefined();
|
|
206
|
-
expect(mockSignMessage).toHaveBeenCalledTimes(1);
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it("should sign in with Solana account", async () => {
|
|
210
|
-
const mockSignature = "solana_sig";
|
|
211
|
-
mockSignMessage.mockResolvedValue(mockSignature);
|
|
212
|
-
mockUseWeb3.mockReturnValue({
|
|
213
|
-
session: createSolanaSession(),
|
|
214
|
-
chainId: "solana:4sGjMW1s",
|
|
215
|
-
});
|
|
216
|
-
mockGetClient.mockReturnValue({ signMessage: mockSignMessage });
|
|
217
|
-
|
|
218
|
-
const { result } = renderHook(() => useSIWxLogin());
|
|
219
|
-
|
|
220
|
-
let siwxResult: Awaited<ReturnType<typeof result.current.signIn>> | undefined;
|
|
221
|
-
|
|
222
|
-
await act(async () => {
|
|
223
|
-
siwxResult = await result.current.signIn();
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
expect(siwxResult!.message.chainId).toBe("solana:4sGjMW1s");
|
|
227
|
-
expect(siwxResult!.message.blockchain).toBe("Solana");
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it("should set loading state during signing", async () => {
|
|
231
|
-
let resolvePromise: (v: string) => void;
|
|
232
|
-
const signPromise = new Promise<string>((resolve) => {
|
|
233
|
-
resolvePromise = resolve;
|
|
234
|
-
});
|
|
235
|
-
mockSignMessage.mockReturnValue(signPromise);
|
|
236
|
-
mockUseWeb3.mockReturnValue({
|
|
237
|
-
session: createEvmSession(),
|
|
238
|
-
chainId: "eip155:1",
|
|
239
|
-
});
|
|
240
|
-
mockGetClient.mockReturnValue({ signMessage: mockSignMessage });
|
|
241
|
-
|
|
242
|
-
const { result } = renderHook(() => useSIWxLogin());
|
|
243
|
-
|
|
244
|
-
let callPromise: Promise<unknown>;
|
|
245
|
-
act(() => {
|
|
246
|
-
callPromise = result.current.signIn();
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
expect(result.current.isSigningIn).toBe(true);
|
|
250
|
-
|
|
251
|
-
await act(async () => {
|
|
252
|
-
resolvePromise!("0xsig");
|
|
253
|
-
await callPromise!;
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
expect(result.current.isSigningIn).toBe(false);
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
it("should capture error on failed signing", async () => {
|
|
260
|
-
mockSignMessage.mockRejectedValue(new Error("User rejected"));
|
|
261
|
-
mockUseWeb3.mockReturnValue({
|
|
262
|
-
session: createEvmSession(),
|
|
263
|
-
chainId: "eip155:1",
|
|
264
|
-
});
|
|
265
|
-
mockGetClient.mockReturnValue({ signMessage: mockSignMessage });
|
|
266
|
-
|
|
267
|
-
const { result } = renderHook(() => useSIWxLogin());
|
|
268
|
-
|
|
269
|
-
await act(async () => {
|
|
270
|
-
try {
|
|
271
|
-
await result.current.signIn();
|
|
272
|
-
} catch {
|
|
273
|
-
// Expected
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
expect(result.current.error).not.toBeNull();
|
|
278
|
-
expect(result.current.error!.message).toBe("User rejected");
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
it("should clear error via clearError", async () => {
|
|
282
|
-
mockSignMessage.mockRejectedValue(new Error("Some error"));
|
|
283
|
-
mockUseWeb3.mockReturnValue({
|
|
284
|
-
session: createEvmSession(),
|
|
285
|
-
chainId: "eip155:1",
|
|
286
|
-
});
|
|
287
|
-
mockGetClient.mockReturnValue({ signMessage: mockSignMessage });
|
|
288
|
-
|
|
289
|
-
const { result } = renderHook(() => useSIWxLogin());
|
|
290
|
-
|
|
291
|
-
await act(async () => {
|
|
292
|
-
try {
|
|
293
|
-
await result.current.signIn();
|
|
294
|
-
} catch {
|
|
295
|
-
// Expected
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
expect(result.current.error).not.toBeNull();
|
|
300
|
-
|
|
301
|
-
act(() => {
|
|
302
|
-
result.current.clearError();
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
expect(result.current.error).toBeNull();
|
|
306
|
-
});
|
|
307
|
-
});
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useSIWxLogin — Trigger a SIWx sign-in flow.
|
|
3
|
-
*
|
|
4
|
-
* A simplified hook for initiating wallet sign-in.
|
|
5
|
-
* Returns a `signIn()` function and loading/error state.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { useState, useCallback } from "react";
|
|
9
|
-
import { useWeb3 } from "../provider/Web3ConnectProvider";
|
|
10
|
-
import { getClient } from "../client";
|
|
11
|
-
import { WalletError } from "@naculus/connect-core";
|
|
12
|
-
import {
|
|
13
|
-
createSiwxMessage,
|
|
14
|
-
generateNonce,
|
|
15
|
-
nowISO,
|
|
16
|
-
getBlockchainName,
|
|
17
|
-
type SiwxResult,
|
|
18
|
-
type SiwxMessage,
|
|
19
|
-
} from "@naculus/siwx";
|
|
20
|
-
|
|
21
|
-
// ── Types ────────────────────────────────────────────────────────
|
|
22
|
-
|
|
23
|
-
export interface UseSIWxLoginOptions {
|
|
24
|
-
/** Originating domain (default: window.location.host) */
|
|
25
|
-
domain?: string;
|
|
26
|
-
/** Human-readable statement */
|
|
27
|
-
statement?: string;
|
|
28
|
-
/** RFC 3986 URI (default: window.location.origin) */
|
|
29
|
-
uri?: string;
|
|
30
|
-
/** CAIP-2 chain ID (default: current chain from Web3 context) */
|
|
31
|
-
chainId?: string;
|
|
32
|
-
/** Session lifetime in seconds (default: 86400 = 24h) */
|
|
33
|
-
expirySeconds?: number;
|
|
34
|
-
/** URIs of resources the identity wishes to access */
|
|
35
|
-
resources?: string[];
|
|
36
|
-
/** CAIP-74 request ID */
|
|
37
|
-
requestId?: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface UseSIWxLoginReturn {
|
|
41
|
-
/** Trigger the SIWx sign-in flow */
|
|
42
|
-
signIn: (options?: UseSIWxLoginOptions) => Promise<SiwxResult>;
|
|
43
|
-
/** Whether a sign-in is in progress */
|
|
44
|
-
isSigningIn: boolean;
|
|
45
|
-
/** Last sign-in error */
|
|
46
|
-
error: Error | null;
|
|
47
|
-
/** Clear the last error */
|
|
48
|
-
clearError: () => void;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// ── Defaults ─────────────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
const DEFAULT_EXPIRY_SECONDS = 86_400; // 24h
|
|
54
|
-
|
|
55
|
-
function getDefaultDomain(): string {
|
|
56
|
-
if (typeof window !== "undefined") return window.location.host;
|
|
57
|
-
return "localhost";
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function getDefaultUri(): string {
|
|
61
|
-
if (typeof window !== "undefined") return window.location.origin;
|
|
62
|
-
return "http://localhost";
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ── Hook ─────────────────────────────────────────────────────────
|
|
66
|
-
|
|
67
|
-
export function useSIWxLogin(): UseSIWxLoginReturn {
|
|
68
|
-
const { session, chainId: currentChainId } = useWeb3();
|
|
69
|
-
const [isSigningIn, setIsSigningIn] = useState(false);
|
|
70
|
-
const [error, setError] = useState<Error | null>(null);
|
|
71
|
-
|
|
72
|
-
const clearError = useCallback(() => setError(null), []);
|
|
73
|
-
|
|
74
|
-
const signIn = useCallback(
|
|
75
|
-
async (options?: UseSIWxLoginOptions): Promise<SiwxResult> => {
|
|
76
|
-
if (!session) {
|
|
77
|
-
throw new WalletError("wallet_unavailable", "No active session");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const client = getClient();
|
|
81
|
-
if (!client) {
|
|
82
|
-
throw new WalletError("wallet_unavailable", "Client not initialized");
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Resolve the first available account and chain
|
|
86
|
-
const allAccounts = Object.entries(session.namespaces).flatMap(
|
|
87
|
-
([ns, info]) =>
|
|
88
|
-
info.accounts.map((acc: string) => ({ ns, acc }))
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
if (allAccounts.length === 0) {
|
|
92
|
-
throw new WalletError("wallet_unavailable", "No account found");
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const { acc: address } = allAccounts[0];
|
|
96
|
-
const chainId = options?.chainId ?? currentChainId ?? "eip155:1";
|
|
97
|
-
const domain = options?.domain ?? getDefaultDomain();
|
|
98
|
-
const uri = options?.uri ?? getDefaultUri();
|
|
99
|
-
const nonce = generateNonce();
|
|
100
|
-
const issuedAt = nowISO();
|
|
101
|
-
const expirySeconds = options?.expirySeconds ?? DEFAULT_EXPIRY_SECONDS;
|
|
102
|
-
const expirationTime = new Date(Date.now() + expirySeconds * 1000).toISOString();
|
|
103
|
-
|
|
104
|
-
// Build the CAIP-122 message string
|
|
105
|
-
const message = createSiwxMessage({
|
|
106
|
-
domain,
|
|
107
|
-
address,
|
|
108
|
-
uri,
|
|
109
|
-
version: 1,
|
|
110
|
-
chainId,
|
|
111
|
-
nonce,
|
|
112
|
-
issuedAt,
|
|
113
|
-
expirationTime,
|
|
114
|
-
statement: options?.statement,
|
|
115
|
-
resources: options?.resources,
|
|
116
|
-
requestId: options?.requestId,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
setIsSigningIn(true);
|
|
120
|
-
setError(null);
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
const signature = (await client.signMessage(session, {
|
|
124
|
-
message,
|
|
125
|
-
address,
|
|
126
|
-
chainId: chainId ?? undefined,
|
|
127
|
-
})) as string;
|
|
128
|
-
|
|
129
|
-
const siwxResult: SiwxResult = {
|
|
130
|
-
message: {
|
|
131
|
-
raw: message,
|
|
132
|
-
domain,
|
|
133
|
-
address,
|
|
134
|
-
statement: options?.statement ?? null,
|
|
135
|
-
uri,
|
|
136
|
-
version: 1,
|
|
137
|
-
chainId,
|
|
138
|
-
nonce,
|
|
139
|
-
issuedAt,
|
|
140
|
-
blockchain: getBlockchainName(chainId),
|
|
141
|
-
expirationTime,
|
|
142
|
-
notBefore: null,
|
|
143
|
-
resources: options?.resources ?? [],
|
|
144
|
-
requestId: options?.requestId ?? null,
|
|
145
|
-
},
|
|
146
|
-
signature,
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
setIsSigningIn(false);
|
|
150
|
-
return siwxResult;
|
|
151
|
-
} catch (err) {
|
|
152
|
-
const wrappedErr =
|
|
153
|
-
err instanceof Error ? err : new Error("SIWx sign-in failed");
|
|
154
|
-
setError(wrappedErr);
|
|
155
|
-
setIsSigningIn(false);
|
|
156
|
-
throw wrappedErr;
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
[session, currentChainId]
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
return { signIn, isSigningIn, error, clearError };
|
|
163
|
-
}
|