@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
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
/// <reference types="vitest" />
|
|
2
|
-
/// @vitest-environment jsdom
|
|
3
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
4
|
-
import { renderHook, act } from "@testing-library/react";
|
|
5
|
-
|
|
6
|
-
import { useEmbeddedWallet } from "./useEmbeddedWallet";
|
|
7
|
-
|
|
8
|
-
// -- Mocks --
|
|
9
|
-
|
|
10
|
-
const mockUseWeb3 = vi.fn();
|
|
11
|
-
vi.mock("../provider/Web3ConnectProvider", () => ({
|
|
12
|
-
useWeb3: () => mockUseWeb3(),
|
|
13
|
-
Web3ConnectProvider: ({ children }: { children: React.ReactNode }) => children,
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
const mockGetClient = vi.fn();
|
|
17
|
-
vi.mock("../client", () => ({
|
|
18
|
-
getClient: () => mockGetClient(),
|
|
19
|
-
}));
|
|
20
|
-
|
|
21
|
-
const mockConnector = {
|
|
22
|
-
load: vi.fn(),
|
|
23
|
-
getWallet: vi.fn(),
|
|
24
|
-
generateWallet: vi.fn(),
|
|
25
|
-
importFromMnemonic: vi.fn(),
|
|
26
|
-
importFromPrivateKey: vi.fn(),
|
|
27
|
-
wipe: vi.fn(),
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
function mockStandardEmbedded() {
|
|
31
|
-
mockGetClient.mockReturnValue({ embeddedConnector: mockConnector });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
describe("useEmbeddedWallet", () => {
|
|
35
|
-
beforeEach(() => {
|
|
36
|
-
vi.clearAllMocks();
|
|
37
|
-
mockStandardEmbedded();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it("should have initial idle state", () => {
|
|
41
|
-
mockUseWeb3.mockReturnValue({
|
|
42
|
-
connectEmbedded: vi.fn(),
|
|
43
|
-
status: "disconnected",
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const { result } = renderHook(() => useEmbeddedWallet());
|
|
47
|
-
|
|
48
|
-
expect(result.current.hasWallet).toBe(false);
|
|
49
|
-
expect(result.current.address).toBeNull();
|
|
50
|
-
expect(result.current.seedPhrase).toBeNull();
|
|
51
|
-
expect(result.current.backupPending).toBe(false);
|
|
52
|
-
expect(result.current.isBusy).toBe(false);
|
|
53
|
-
expect(result.current.error).toBeNull();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("connectEmbedded should call provider and set wallet", async () => {
|
|
57
|
-
const providerConnect = vi.fn().mockResolvedValue(undefined);
|
|
58
|
-
mockUseWeb3.mockReturnValue({
|
|
59
|
-
connectEmbedded: providerConnect,
|
|
60
|
-
status: "disconnected",
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const fakeWallet = {
|
|
64
|
-
mnemonic: "test mnemonic phrase",
|
|
65
|
-
privateKey: "0xfake",
|
|
66
|
-
address: "0xfakeAddress",
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
mockConnector.load.mockReturnValue(false);
|
|
70
|
-
mockConnector.getWallet.mockReturnValue(fakeWallet);
|
|
71
|
-
|
|
72
|
-
const { result } = renderHook(() => useEmbeddedWallet());
|
|
73
|
-
|
|
74
|
-
await act(async () => {
|
|
75
|
-
await result.current.connectEmbedded();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
expect(providerConnect).toHaveBeenCalled();
|
|
79
|
-
expect(mockConnector.getWallet).toHaveBeenCalled();
|
|
80
|
-
expect(result.current.wallet).toEqual(fakeWallet);
|
|
81
|
-
expect(result.current.hasWallet).toBe(true);
|
|
82
|
-
expect(result.current.address).toBe("0xfakeAddress");
|
|
83
|
-
expect(result.current.isBusy).toBe(false);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it("generateWallet should create a new wallet and set backup pending", async () => {
|
|
87
|
-
mockUseWeb3.mockReturnValue({
|
|
88
|
-
connectEmbedded: vi.fn(),
|
|
89
|
-
status: "disconnected",
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const newWallet = {
|
|
93
|
-
mnemonic: "actual random mnemonic",
|
|
94
|
-
privateKey: "0xnewPrivateKey",
|
|
95
|
-
address: "0xnewAddress",
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
mockConnector.generateWallet.mockResolvedValue({
|
|
99
|
-
mnemonic: newWallet.mnemonic,
|
|
100
|
-
privateKey: newWallet.privateKey,
|
|
101
|
-
address: newWallet.address,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
const { result } = renderHook(() => useEmbeddedWallet());
|
|
105
|
-
|
|
106
|
-
await act(async () => {
|
|
107
|
-
await result.current.generateWallet();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
expect(mockConnector.generateWallet).toHaveBeenCalled();
|
|
111
|
-
expect(result.current.wallet).toEqual(newWallet);
|
|
112
|
-
expect(result.current.seedPhrase).toBe(newWallet.mnemonic);
|
|
113
|
-
expect(result.current.backupPending).toBe(true);
|
|
114
|
-
expect(result.current.isBusy).toBe(false);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("importFromMnemonic should import from seed phrase", async () => {
|
|
118
|
-
mockUseWeb3.mockReturnValue({
|
|
119
|
-
connectEmbedded: vi.fn(),
|
|
120
|
-
status: "disconnected",
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const imported = {
|
|
124
|
-
mnemonic: "",
|
|
125
|
-
privateKey: "0ximportedKey",
|
|
126
|
-
address: "0ximportedAddr",
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
mockConnector.importFromMnemonic.mockResolvedValue({
|
|
130
|
-
mnemonic: imported.mnemonic,
|
|
131
|
-
privateKey: imported.privateKey,
|
|
132
|
-
address: imported.address,
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
const { result } = renderHook(() => useEmbeddedWallet());
|
|
136
|
-
|
|
137
|
-
await act(async () => {
|
|
138
|
-
await result.current.importFromMnemonic("my seed phrase");
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
expect(mockConnector.importFromMnemonic).toHaveBeenCalledWith("my seed phrase");
|
|
142
|
-
expect(result.current.wallet).toEqual(imported);
|
|
143
|
-
expect(result.current.seedPhrase).toBeNull();
|
|
144
|
-
expect(result.current.backupPending).toBe(false);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it("wipe should clear wallet and seed phrase", () => {
|
|
148
|
-
mockUseWeb3.mockReturnValue({
|
|
149
|
-
connectEmbedded: vi.fn(),
|
|
150
|
-
status: "disconnected",
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
mockConnector.getWallet.mockReturnValue({
|
|
154
|
-
mnemonic: "some mnemonic",
|
|
155
|
-
privateKey: "0xpk",
|
|
156
|
-
address: "0xaddr",
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
const { result } = renderHook(() => useEmbeddedWallet());
|
|
160
|
-
|
|
161
|
-
act(() => {
|
|
162
|
-
result.current.wipe();
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
expect(mockConnector.wipe).toHaveBeenCalled();
|
|
166
|
-
expect(result.current.hasWallet).toBe(false);
|
|
167
|
-
expect(result.current.seedPhrase).toBeNull();
|
|
168
|
-
expect(result.current.backupPending).toBe(false);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it("confirmBackup should clear seed phrase from react state", async () => {
|
|
172
|
-
mockUseWeb3.mockReturnValue({
|
|
173
|
-
connectEmbedded: vi.fn(),
|
|
174
|
-
status: "disconnected",
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
mockConnector.getWallet.mockReturnValue({
|
|
178
|
-
mnemonic: "some mnemonic",
|
|
179
|
-
privateKey: "0xpk",
|
|
180
|
-
address: "0xaddr",
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
const { result } = renderHook(() => useEmbeddedWallet());
|
|
184
|
-
|
|
185
|
-
await act(async () => {
|
|
186
|
-
await result.current.connectEmbedded();
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
act(() => {
|
|
190
|
-
result.current.confirmBackup();
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
expect(result.current.seedPhrase).toBeNull();
|
|
194
|
-
expect(result.current.backupPending).toBe(false);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it("should handle error when embedded not enabled", async () => {
|
|
198
|
-
mockUseWeb3.mockReturnValue({
|
|
199
|
-
connectEmbedded: vi.fn(),
|
|
200
|
-
status: "disconnected",
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
mockGetClient.mockReturnValue({ embeddedConnector: null });
|
|
204
|
-
|
|
205
|
-
const { result } = renderHook(() => useEmbeddedWallet());
|
|
206
|
-
|
|
207
|
-
await act(async () => {
|
|
208
|
-
await result.current.connectEmbedded();
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
expect(result.current.error).not.toBeNull();
|
|
212
|
-
expect(result.current.isBusy).toBe(false);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it("clearError should reset error state", async () => {
|
|
216
|
-
mockUseWeb3.mockReturnValue({
|
|
217
|
-
connectEmbedded: vi.fn(),
|
|
218
|
-
status: "disconnected",
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
mockGetClient.mockReturnValue({ embeddedConnector: null });
|
|
222
|
-
|
|
223
|
-
const { result } = renderHook(() => useEmbeddedWallet());
|
|
224
|
-
|
|
225
|
-
await act(async () => {
|
|
226
|
-
await result.current.connectEmbedded();
|
|
227
|
-
});
|
|
228
|
-
expect(result.current.error).not.toBeNull();
|
|
229
|
-
|
|
230
|
-
act(() => {
|
|
231
|
-
result.current.clearError();
|
|
232
|
-
});
|
|
233
|
-
expect(result.current.error).toBeNull();
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
it("should set isBusy during operations", async () => {
|
|
237
|
-
mockUseWeb3.mockReturnValue({
|
|
238
|
-
connectEmbedded: vi.fn(),
|
|
239
|
-
status: "disconnected",
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
let resolveGen: (value: any) => void;
|
|
243
|
-
const genPromise = new Promise<any>((resolve) => { resolveGen = resolve; });
|
|
244
|
-
mockConnector.generateWallet.mockReturnValue(genPromise);
|
|
245
|
-
|
|
246
|
-
const { result } = renderHook(() => useEmbeddedWallet());
|
|
247
|
-
|
|
248
|
-
let callPromise: Promise<any>;
|
|
249
|
-
act(() => {
|
|
250
|
-
callPromise = result.current.generateWallet();
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
expect(result.current.isBusy).toBe(true);
|
|
254
|
-
|
|
255
|
-
await act(async () => {
|
|
256
|
-
resolveGen!({
|
|
257
|
-
mnemonic: "test",
|
|
258
|
-
privateKey: "0xtest",
|
|
259
|
-
address: "0xtest",
|
|
260
|
-
});
|
|
261
|
-
await callPromise!;
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
expect(result.current.isBusy).toBe(false);
|
|
265
|
-
});
|
|
266
|
-
});
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { useCallback, useRef, useState } from "react";
|
|
2
|
-
import { useWeb3 } from "../provider/Web3ConnectProvider";
|
|
3
|
-
import { getClient } from "../client";
|
|
4
|
-
import type { WalletData } from "@naculus/connector-embedded";
|
|
5
|
-
import { WalletError } from "@naculus/connect-core";
|
|
6
|
-
|
|
7
|
-
export interface UseEmbeddedWalletReturn {
|
|
8
|
-
connectEmbedded: () => Promise<void>;
|
|
9
|
-
generateWallet: () => Promise<WalletData | null>;
|
|
10
|
-
importFromMnemonic: (mnemonic: string) => Promise<WalletData | null>;
|
|
11
|
-
importFromPrivateKey: (pk: `0x${string}`) => Promise<WalletData | null>;
|
|
12
|
-
wipe: () => void;
|
|
13
|
-
wallet: WalletData | null;
|
|
14
|
-
hasWallet: boolean;
|
|
15
|
-
address: string | null;
|
|
16
|
-
/** @deprecated Use getSeedPhrase() instead. This field will be removed. */
|
|
17
|
-
seedPhrase: string | null;
|
|
18
|
-
/** Get seed phrase once and clear from memory. Returns mnemonic or null. */
|
|
19
|
-
getSeedPhrase: () => string | null;
|
|
20
|
-
backupPending: boolean;
|
|
21
|
-
confirmBackup: () => void;
|
|
22
|
-
isBusy: boolean;
|
|
23
|
-
error: Error | null;
|
|
24
|
-
clearError: () => void;
|
|
25
|
-
/**
|
|
26
|
-
* Storage security tier (1-4).
|
|
27
|
-
* 1 = IndexedDB + AES-GCM, 2 = IndexedDB,
|
|
28
|
-
* 3 = localStorage + AES-GCM, 4 = localStorage plaintext
|
|
29
|
-
*/
|
|
30
|
-
storageSecurityLevel: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function useEmbeddedWallet(): UseEmbeddedWalletReturn {
|
|
34
|
-
const { connectEmbedded: providerConnectEmbedded } = useWeb3();
|
|
35
|
-
const [wallet, setWallet] = useState<WalletData | null>(null);
|
|
36
|
-
const seedPhraseRef = useRef<string | null>(null);
|
|
37
|
-
const [backupPending, setBackupPending] = useState(false);
|
|
38
|
-
const [isBusy, setIsBusy] = useState(false);
|
|
39
|
-
const [error, setError] = useState<Error | null>(null);
|
|
40
|
-
|
|
41
|
-
const clearError = () => setError(null);
|
|
42
|
-
|
|
43
|
-
/** Get seed phrase once and immediately clear from memory */
|
|
44
|
-
const getSeedPhrase = useCallback(() => {
|
|
45
|
-
const phrase = seedPhraseRef.current;
|
|
46
|
-
seedPhraseRef.current = null; // Clear immediately
|
|
47
|
-
return phrase;
|
|
48
|
-
}, []);
|
|
49
|
-
|
|
50
|
-
const getEmbeddedConnector = () => {
|
|
51
|
-
const client = getClient();
|
|
52
|
-
if (!client?.embeddedConnector) {
|
|
53
|
-
throw new WalletError("wallet_unavailable", "Embedded wallet not enabled.");
|
|
54
|
-
}
|
|
55
|
-
return client.embeddedConnector;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const handleConnectEmbedded = async () => {
|
|
59
|
-
setIsBusy(true);
|
|
60
|
-
setError(null);
|
|
61
|
-
try {
|
|
62
|
-
const connector = getEmbeddedConnector();
|
|
63
|
-
const loaded = await connector.load();
|
|
64
|
-
const w = connector.getWallet();
|
|
65
|
-
if (loaded && w) {
|
|
66
|
-
setWallet(w);
|
|
67
|
-
seedPhraseRef.current = w.mnemonic || null;
|
|
68
|
-
setBackupPending(!w.mnemonic);
|
|
69
|
-
}
|
|
70
|
-
await providerConnectEmbedded();
|
|
71
|
-
const w2 = connector.getWallet();
|
|
72
|
-
if (w2) {
|
|
73
|
-
setWallet(w2);
|
|
74
|
-
if (w2.mnemonic && !loaded) {
|
|
75
|
-
seedPhraseRef.current = w2.mnemonic;
|
|
76
|
-
setBackupPending(true);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
} catch (err) {
|
|
80
|
-
setError(err instanceof Error ? err : new Error("Embedded wallet connection failed"));
|
|
81
|
-
} finally {
|
|
82
|
-
setIsBusy(false);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const handleGenerateWallet = async (): Promise<WalletData | null> => {
|
|
87
|
-
setIsBusy(true);
|
|
88
|
-
setError(null);
|
|
89
|
-
try {
|
|
90
|
-
const connector = getEmbeddedConnector();
|
|
91
|
-
const w = await connector.generateWallet();
|
|
92
|
-
setWallet(w);
|
|
93
|
-
seedPhraseRef.current = w.mnemonic;
|
|
94
|
-
setBackupPending(true);
|
|
95
|
-
return w;
|
|
96
|
-
} catch (err) {
|
|
97
|
-
setError(err instanceof Error ? err : new Error("Failed to generate wallet"));
|
|
98
|
-
return null;
|
|
99
|
-
} finally {
|
|
100
|
-
setIsBusy(false);
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const handleImportFromMnemonic = async (mnemonic: string): Promise<WalletData | null> => {
|
|
105
|
-
setIsBusy(true);
|
|
106
|
-
setError(null);
|
|
107
|
-
try {
|
|
108
|
-
const connector = getEmbeddedConnector();
|
|
109
|
-
const w = await connector.importFromMnemonic(mnemonic);
|
|
110
|
-
setWallet(w);
|
|
111
|
-
seedPhraseRef.current = null;
|
|
112
|
-
setBackupPending(false);
|
|
113
|
-
return w;
|
|
114
|
-
} catch (err) {
|
|
115
|
-
setError(err instanceof Error ? err : new Error("Failed to import wallet"));
|
|
116
|
-
return null;
|
|
117
|
-
} finally {
|
|
118
|
-
setIsBusy(false);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const handleImportFromPrivateKey = async (pk: `0x${string}`): Promise<WalletData | null> => {
|
|
123
|
-
setIsBusy(true);
|
|
124
|
-
setError(null);
|
|
125
|
-
try {
|
|
126
|
-
const connector = getEmbeddedConnector();
|
|
127
|
-
const w = await connector.importFromPrivateKey(pk);
|
|
128
|
-
setWallet(w);
|
|
129
|
-
seedPhraseRef.current = null;
|
|
130
|
-
setBackupPending(false);
|
|
131
|
-
return w;
|
|
132
|
-
} catch (err) {
|
|
133
|
-
setError(err instanceof Error ? err : new Error("Failed to import wallet"));
|
|
134
|
-
return null;
|
|
135
|
-
} finally {
|
|
136
|
-
setIsBusy(false);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const handleWipe = () => {
|
|
141
|
-
try {
|
|
142
|
-
const connector = getEmbeddedConnector();
|
|
143
|
-
connector.wipe();
|
|
144
|
-
setWallet(null);
|
|
145
|
-
seedPhraseRef.current = null;
|
|
146
|
-
setBackupPending(false);
|
|
147
|
-
} catch (err) {
|
|
148
|
-
setError(err instanceof Error ? err : new Error("Failed to wipe wallet"));
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const handleConfirmBackup = () => {
|
|
153
|
-
seedPhraseRef.current = null;
|
|
154
|
-
setBackupPending(false);
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
return {
|
|
158
|
-
connectEmbedded: handleConnectEmbedded,
|
|
159
|
-
generateWallet: handleGenerateWallet,
|
|
160
|
-
importFromMnemonic: handleImportFromMnemonic,
|
|
161
|
-
importFromPrivateKey: handleImportFromPrivateKey,
|
|
162
|
-
wipe: handleWipe,
|
|
163
|
-
wallet,
|
|
164
|
-
hasWallet: wallet !== null,
|
|
165
|
-
address: wallet?.address ?? null,
|
|
166
|
-
seedPhrase: seedPhraseRef.current, // backward compat (deprecated)
|
|
167
|
-
getSeedPhrase,
|
|
168
|
-
backupPending,
|
|
169
|
-
confirmBackup: handleConfirmBackup,
|
|
170
|
-
isBusy,
|
|
171
|
-
error,
|
|
172
|
-
clearError,
|
|
173
|
-
storageSecurityLevel: (() => {
|
|
174
|
-
try {
|
|
175
|
-
return getEmbeddedConnector().getStorageSecurityLevel?.() ?? 4;
|
|
176
|
-
} catch {
|
|
177
|
-
return 4;
|
|
178
|
-
}
|
|
179
|
-
})(),
|
|
180
|
-
};
|
|
181
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
3
|
-
import { renderHook, act } from "@testing-library/react";
|
|
4
|
-
import { useLastTx } from "./useLastTx";
|
|
5
|
-
import type { TxMonitorLike, TxStatusEntry } from "./useTxMonitor";
|
|
6
|
-
|
|
7
|
-
class MockMonitor implements TxMonitorLike {
|
|
8
|
-
private listeners = new Map<string, Set<Function>>();
|
|
9
|
-
|
|
10
|
-
async watchTx(): Promise<TxStatusEntry> { throw new Error("not implemented"); }
|
|
11
|
-
stopWatching(): void {}
|
|
12
|
-
getTxStatus(): TxStatusEntry | null { return null; }
|
|
13
|
-
async getTxHistory(): Promise<TxStatusEntry[]> { return []; }
|
|
14
|
-
async refreshTx(): Promise<void> {}
|
|
15
|
-
|
|
16
|
-
on(event: string, listener: Function): this {
|
|
17
|
-
const set = this.listeners.get(event) ?? new Set();
|
|
18
|
-
set.add(listener);
|
|
19
|
-
this.listeners.set(event, set);
|
|
20
|
-
return this;
|
|
21
|
-
}
|
|
22
|
-
off(event: string, listener: Function): this {
|
|
23
|
-
const set = this.listeners.get(event);
|
|
24
|
-
if (set) set.delete(listener);
|
|
25
|
-
return this;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
emitConfirmed(entry: TxStatusEntry): void {
|
|
29
|
-
const set = this.listeners.get("confirmed");
|
|
30
|
-
if (set) set.forEach(fn => fn(entry));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
emitFailed(entry: TxStatusEntry): void {
|
|
34
|
-
const set = this.listeners.get("failed");
|
|
35
|
-
if (set) set.forEach(fn => fn(entry));
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
describe("useLastTx", () => {
|
|
40
|
-
let monitor: MockMonitor;
|
|
41
|
-
|
|
42
|
-
beforeEach(() => {
|
|
43
|
-
monitor = new MockMonitor();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("returns null initially", () => {
|
|
47
|
-
const { result } = renderHook(() => useLastTx(monitor));
|
|
48
|
-
expect(result.current.lastTx).toBeNull();
|
|
49
|
-
expect(result.current.lastConfirmedTx).toBeNull();
|
|
50
|
-
expect(result.current.lastFailedTx).toBeNull();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it("updates lastConfirmedTx on confirmed event", () => {
|
|
54
|
-
const { result } = renderHook(() => useLastTx(monitor));
|
|
55
|
-
|
|
56
|
-
const now = Date.now();
|
|
57
|
-
const entry: TxStatusEntry = {
|
|
58
|
-
hash: "0x" + "a".repeat(64), chainId: 1,
|
|
59
|
-
from: "", to: "", value: "0x0",
|
|
60
|
-
status: "confirmed", createdAt: now, updatedAt: now,
|
|
61
|
-
replacementCount: 0, confirmedAt: now,
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
act(() => {
|
|
65
|
-
monitor.emitConfirmed(entry);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
expect(result.current.lastTx).not.toBeNull();
|
|
69
|
-
expect(result.current.lastTx!.hash).toBe(entry.hash);
|
|
70
|
-
expect(result.current.lastConfirmedTx).not.toBeNull();
|
|
71
|
-
expect(result.current.lastConfirmedTx!.hash).toBe(entry.hash);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("updates lastFailedTx on failed event", () => {
|
|
75
|
-
const { result } = renderHook(() => useLastTx(monitor));
|
|
76
|
-
|
|
77
|
-
const now = Date.now();
|
|
78
|
-
const entry: TxStatusEntry = {
|
|
79
|
-
hash: "0x" + "b".repeat(64), chainId: 1,
|
|
80
|
-
from: "", to: "", value: "0x0",
|
|
81
|
-
status: "failed", createdAt: now, updatedAt: now,
|
|
82
|
-
replacementCount: 0, error: "reverted",
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
act(() => {
|
|
86
|
-
monitor.emitFailed(entry);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
expect(result.current.lastTx).not.toBeNull();
|
|
90
|
-
expect(result.current.lastTx!.hash).toBe(entry.hash);
|
|
91
|
-
expect(result.current.lastFailedTx).not.toBeNull();
|
|
92
|
-
expect(result.current.lastFailedTx!.hash).toBe(entry.hash);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it("clears on clear() call", () => {
|
|
96
|
-
const { result } = renderHook(() => useLastTx(monitor));
|
|
97
|
-
|
|
98
|
-
const now = Date.now();
|
|
99
|
-
act(() => {
|
|
100
|
-
monitor.emitConfirmed({
|
|
101
|
-
hash: "0x" + "c".repeat(64), chainId: 1,
|
|
102
|
-
from: "", to: "", value: "0x0",
|
|
103
|
-
status: "confirmed", createdAt: now, updatedAt: now,
|
|
104
|
-
replacementCount: 0, confirmedAt: now,
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
expect(result.current.lastTx).not.toBeNull();
|
|
109
|
-
|
|
110
|
-
act(() => {
|
|
111
|
-
result.current.clear();
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
expect(result.current.lastTx).toBeNull();
|
|
115
|
-
expect(result.current.lastConfirmedTx).toBeNull();
|
|
116
|
-
});
|
|
117
|
-
});
|
package/src/hooks/useLastTx.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback, useRef } from "react";
|
|
2
|
-
import type { TxMonitorLike, TxStatusEntry } from "./useTxMonitor";
|
|
3
|
-
import { useTxMonitorProvider } from "./useTxMonitor";
|
|
4
|
-
|
|
5
|
-
// ── Hook ──────────────────────────────────────────────────────────
|
|
6
|
-
|
|
7
|
-
export interface UseLastTxResult {
|
|
8
|
-
/** Most recent transaction by createdAt */
|
|
9
|
-
lastTx: TxStatusEntry | null;
|
|
10
|
-
/** Most recent confirmed transaction */
|
|
11
|
-
lastConfirmedTx: TxStatusEntry | null;
|
|
12
|
-
/** Most recent failed transaction */
|
|
13
|
-
lastFailedTx: TxStatusEntry | null;
|
|
14
|
-
/** Clear cached lastTx state */
|
|
15
|
-
clear: () => void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Track the most recent transaction.
|
|
20
|
-
* Automatically updates when a new transaction is sent (via statusChange events).
|
|
21
|
-
*/
|
|
22
|
-
export function useLastTx(monitor?: TxMonitorLike): UseLastTxResult {
|
|
23
|
-
const ctxMonitor = useTxMonitorProvider();
|
|
24
|
-
const effectiveMonitor = monitor ?? ctxMonitor;
|
|
25
|
-
|
|
26
|
-
const [lastTx, setLastTx] = useState<TxStatusEntry | null>(null);
|
|
27
|
-
const [lastConfirmedTx, setLastConfirmedTx] = useState<TxStatusEntry | null>(null);
|
|
28
|
-
const [lastFailedTx, setLastFailedTx] = useState<TxStatusEntry | null>(null);
|
|
29
|
-
const lastTxRef = useRef<{ createdAt: number } | null>(null);
|
|
30
|
-
|
|
31
|
-
// Track confirmed and failed events
|
|
32
|
-
const confirmedHandlerRef = useRef<((entry: TxStatusEntry) => void) | null>(null);
|
|
33
|
-
const failedHandlerRef = useRef<((entry: TxStatusEntry) => void) | null>(null);
|
|
34
|
-
|
|
35
|
-
// Set up listeners
|
|
36
|
-
if (effectiveMonitor) {
|
|
37
|
-
if (!confirmedHandlerRef.current) {
|
|
38
|
-
confirmedHandlerRef.current = (entry: TxStatusEntry) => {
|
|
39
|
-
setLastConfirmedTx(entry);
|
|
40
|
-
if (!lastTxRef.current || entry.createdAt >= lastTxRef.current.createdAt) {
|
|
41
|
-
setLastTx(entry);
|
|
42
|
-
lastTxRef.current = entry;
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
effectiveMonitor.on("confirmed", confirmedHandlerRef.current);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!failedHandlerRef.current) {
|
|
49
|
-
failedHandlerRef.current = (entry: TxStatusEntry) => {
|
|
50
|
-
setLastFailedTx(entry);
|
|
51
|
-
if (!lastTxRef.current || entry.createdAt >= lastTxRef.current.createdAt) {
|
|
52
|
-
setLastTx(entry);
|
|
53
|
-
lastTxRef.current = entry;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
effectiveMonitor.on("failed", failedHandlerRef.current);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const clear = useCallback(() => {
|
|
61
|
-
setLastTx(null);
|
|
62
|
-
setLastConfirmedTx(null);
|
|
63
|
-
setLastFailedTx(null);
|
|
64
|
-
lastTxRef.current = null;
|
|
65
|
-
}, []);
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
lastTx,
|
|
69
|
-
lastConfirmedTx,
|
|
70
|
-
lastFailedTx,
|
|
71
|
-
clear,
|
|
72
|
-
};
|
|
73
|
-
}
|