@cfxdevkit/react 1.0.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/dist/index.js ADDED
@@ -0,0 +1,573 @@
1
+ // src/hooks/useBalance.ts
2
+ import { useCallback, useEffect, useState } from "react";
3
+
4
+ // src/providers/DevKitProvider.tsx
5
+ import { createContext, useContext } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ var DevKitContext = createContext(void 0);
8
+ function DevKitProvider({
9
+ apiUrl,
10
+ wsUrl,
11
+ network = "local",
12
+ debug = false,
13
+ children
14
+ }) {
15
+ const value = {
16
+ apiUrl,
17
+ wsUrl,
18
+ network,
19
+ debug
20
+ };
21
+ return /* @__PURE__ */ jsx(DevKitContext.Provider, { value, children });
22
+ }
23
+ function useDevKitContext() {
24
+ const context = useContext(DevKitContext);
25
+ if (!context) {
26
+ throw new Error("useDevKitContext must be used within DevKitProvider");
27
+ }
28
+ return context;
29
+ }
30
+
31
+ // src/hooks/useBalance.ts
32
+ function useBalance(options) {
33
+ const { address, enabled = true, refreshInterval } = options;
34
+ useDevKitContext();
35
+ const [balance, setBalance] = useState();
36
+ const [isLoading, setIsLoading] = useState(false);
37
+ const [error, setError] = useState();
38
+ const fetchBalance = useCallback(async () => {
39
+ if (!address || !enabled) return;
40
+ setIsLoading(true);
41
+ setError(void 0);
42
+ try {
43
+ const mockBalance = "1000000000000000000";
44
+ setBalance(mockBalance);
45
+ } catch (err) {
46
+ setError(
47
+ err instanceof Error ? err : new Error("Failed to fetch balance")
48
+ );
49
+ } finally {
50
+ setIsLoading(false);
51
+ }
52
+ }, [address, enabled]);
53
+ useEffect(() => {
54
+ void fetchBalance();
55
+ if (refreshInterval) {
56
+ const interval = setInterval(() => {
57
+ void fetchBalance();
58
+ }, refreshInterval);
59
+ return () => clearInterval(interval);
60
+ }
61
+ }, [fetchBalance, refreshInterval]);
62
+ return {
63
+ balance,
64
+ isLoading,
65
+ error,
66
+ refetch: fetchBalance
67
+ };
68
+ }
69
+
70
+ // src/providers/WalletProvider.tsx
71
+ import { createContext as createContext2, useContext as useContext2, useState as useState2 } from "react";
72
+ import { jsx as jsx2 } from "react/jsx-runtime";
73
+ var WalletContext = createContext2(void 0);
74
+ function WalletProvider({ children }) {
75
+ const [isConnected, setIsConnected] = useState2(false);
76
+ const [coreAddress, setCoreAddress] = useState2();
77
+ const [evmAddress, setEvmAddress] = useState2();
78
+ const [chain, setChain] = useState2("evm");
79
+ const [accountIndex, setAccountIndex] = useState2();
80
+ const connect = async (index) => {
81
+ setAccountIndex(index);
82
+ setCoreAddress(`cfx:account${index}`);
83
+ setEvmAddress(`0xaccount${index}`);
84
+ setIsConnected(true);
85
+ };
86
+ const disconnect = () => {
87
+ setIsConnected(false);
88
+ setCoreAddress(void 0);
89
+ setEvmAddress(void 0);
90
+ setAccountIndex(void 0);
91
+ };
92
+ const switchChain = (newChain) => {
93
+ setChain(newChain);
94
+ };
95
+ const value = {
96
+ isConnected,
97
+ address: chain === "core" ? coreAddress : evmAddress,
98
+ coreAddress,
99
+ evmAddress,
100
+ chain,
101
+ accountIndex,
102
+ connect,
103
+ disconnect,
104
+ switchChain
105
+ };
106
+ return /* @__PURE__ */ jsx2(WalletContext.Provider, { value, children });
107
+ }
108
+ function useWalletContext() {
109
+ const context = useContext2(WalletContext);
110
+ if (!context) {
111
+ throw new Error("useWalletContext must be used within WalletProvider");
112
+ }
113
+ return context;
114
+ }
115
+
116
+ // src/components/account-display/AccountCard.tsx
117
+ import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
118
+ function AccountCard({
119
+ showBalance = true,
120
+ children,
121
+ className
122
+ }) {
123
+ const { isConnected, coreAddress, evmAddress } = useWalletContext();
124
+ const { balance: coreBalance, isLoading: isLoadingCore } = useBalance({
125
+ address: coreAddress,
126
+ chain: "core",
127
+ enabled: showBalance && isConnected
128
+ });
129
+ const { balance: evmBalance, isLoading: isLoadingEvm } = useBalance({
130
+ address: evmAddress,
131
+ chain: "evm",
132
+ enabled: showBalance && isConnected
133
+ });
134
+ const renderProps = {
135
+ isConnected,
136
+ coreAddress,
137
+ evmAddress,
138
+ coreBalance,
139
+ evmBalance,
140
+ isLoadingBalance: isLoadingCore || isLoadingEvm
141
+ };
142
+ if (typeof children === "function") {
143
+ return /* @__PURE__ */ jsx3(Fragment, { children: children(renderProps) });
144
+ }
145
+ if (!isConnected) {
146
+ return children ? /* @__PURE__ */ jsx3("div", { className, children }) : null;
147
+ }
148
+ return /* @__PURE__ */ jsxs("div", { className: className || "p-4 bg-gray-100 rounded-lg space-y-2", children: [
149
+ /* @__PURE__ */ jsxs("div", { children: [
150
+ /* @__PURE__ */ jsx3("span", { className: "font-semibold", children: "Core Space:" }),
151
+ /* @__PURE__ */ jsx3("span", { className: "ml-2 font-mono text-sm", children: coreAddress }),
152
+ showBalance && /* @__PURE__ */ jsx3("span", { className: "ml-2 text-gray-600", children: isLoadingCore ? "Loading..." : `${coreBalance} CFX` })
153
+ ] }),
154
+ /* @__PURE__ */ jsxs("div", { children: [
155
+ /* @__PURE__ */ jsx3("span", { className: "font-semibold", children: "eSpace:" }),
156
+ /* @__PURE__ */ jsx3("span", { className: "ml-2 font-mono text-sm", children: evmAddress }),
157
+ showBalance && /* @__PURE__ */ jsx3("span", { className: "ml-2 text-gray-600", children: isLoadingEvm ? "Loading..." : `${evmBalance} CFX` })
158
+ ] })
159
+ ] });
160
+ }
161
+
162
+ // src/components/connect-wallet/ConnectButton.tsx
163
+ import React from "react";
164
+ import { Fragment as Fragment2, jsx as jsx4 } from "react/jsx-runtime";
165
+ function ConnectButton({
166
+ accountIndex = 0,
167
+ onConnect,
168
+ onDisconnect,
169
+ children,
170
+ className
171
+ }) {
172
+ const {
173
+ isConnected,
174
+ address,
175
+ connect: contextConnect,
176
+ disconnect: contextDisconnect
177
+ } = useWalletContext();
178
+ const [isLoading, setIsLoading] = React.useState(false);
179
+ const connect = async () => {
180
+ setIsLoading(true);
181
+ try {
182
+ await contextConnect(accountIndex);
183
+ onConnect?.();
184
+ } catch (error) {
185
+ console.error("Connection failed:", error);
186
+ } finally {
187
+ setIsLoading(false);
188
+ }
189
+ };
190
+ const disconnect = () => {
191
+ contextDisconnect();
192
+ onDisconnect?.();
193
+ };
194
+ const renderProps = {
195
+ isConnected,
196
+ address,
197
+ connect,
198
+ disconnect,
199
+ isLoading
200
+ };
201
+ if (typeof children === "function") {
202
+ return /* @__PURE__ */ jsx4(Fragment2, { children: children(renderProps) });
203
+ }
204
+ if (children) {
205
+ return /* @__PURE__ */ jsx4(
206
+ "button",
207
+ {
208
+ onClick: isConnected ? disconnect : connect,
209
+ disabled: isLoading,
210
+ className,
211
+ type: "button",
212
+ children
213
+ }
214
+ );
215
+ }
216
+ return /* @__PURE__ */ jsx4(
217
+ "button",
218
+ {
219
+ onClick: isConnected ? disconnect : connect,
220
+ disabled: isLoading,
221
+ className: className || "px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:opacity-50",
222
+ type: "button",
223
+ children: isLoading ? "Connecting..." : isConnected ? `Connected: ${address?.slice(0, 6)}...${address?.slice(-4)}` : "Connect Wallet"
224
+ }
225
+ );
226
+ }
227
+
228
+ // src/components/contract/ContractReader.tsx
229
+ import { useState as useState4 } from "react";
230
+
231
+ // src/hooks/useContract.ts
232
+ import { useState as useState3 } from "react";
233
+ function useContract() {
234
+ useDevKitContext();
235
+ const { accountIndex } = useWalletContext();
236
+ const [isLoading, setIsLoading] = useState3(false);
237
+ const [error, setError] = useState3();
238
+ const read = async (_options) => {
239
+ setIsLoading(true);
240
+ setError(void 0);
241
+ try {
242
+ return {};
243
+ } catch (err) {
244
+ const errorObj = err instanceof Error ? err : new Error("Contract read failed");
245
+ setError(errorObj);
246
+ throw errorObj;
247
+ } finally {
248
+ setIsLoading(false);
249
+ }
250
+ };
251
+ const write = async (_options) => {
252
+ if (accountIndex === void 0) {
253
+ throw new Error("Wallet not connected");
254
+ }
255
+ setIsLoading(true);
256
+ setError(void 0);
257
+ try {
258
+ const hash = `0x${Array.from(
259
+ { length: 64 },
260
+ () => Math.floor(Math.random() * 16).toString(16)
261
+ ).join("")}`;
262
+ return hash;
263
+ } catch (err) {
264
+ const errorObj = err instanceof Error ? err : new Error("Contract write failed");
265
+ setError(errorObj);
266
+ throw errorObj;
267
+ } finally {
268
+ setIsLoading(false);
269
+ }
270
+ };
271
+ return {
272
+ read,
273
+ write,
274
+ isLoading,
275
+ error
276
+ };
277
+ }
278
+
279
+ // src/components/contract/ContractReader.tsx
280
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
281
+ function ContractReader({
282
+ address,
283
+ abi,
284
+ functionName,
285
+ chain,
286
+ children,
287
+ className
288
+ }) {
289
+ const { read: readContract, isLoading, error } = useContract();
290
+ const [result, setResult] = useState4();
291
+ const read = async (args) => {
292
+ const data = await readContract({
293
+ address,
294
+ abi,
295
+ functionName,
296
+ args,
297
+ chain
298
+ });
299
+ setResult(data);
300
+ };
301
+ const renderProps = {
302
+ read,
303
+ result,
304
+ isLoading,
305
+ error
306
+ };
307
+ if (typeof children === "function") {
308
+ return /* @__PURE__ */ jsx5(Fragment3, { children: children(renderProps) });
309
+ }
310
+ return /* @__PURE__ */ jsxs2("div", { className: className || "p-4 border rounded", children: [
311
+ /* @__PURE__ */ jsxs2("h3", { className: "font-semibold mb-2", children: [
312
+ "Read: ",
313
+ functionName
314
+ ] }),
315
+ /* @__PURE__ */ jsx5(
316
+ "button",
317
+ {
318
+ onClick: () => read(),
319
+ disabled: isLoading,
320
+ className: "px-3 py-1 bg-blue-500 text-white rounded disabled:opacity-50",
321
+ type: "button",
322
+ children: isLoading ? "Reading..." : "Read"
323
+ }
324
+ ),
325
+ result && /* @__PURE__ */ jsx5("div", { className: "mt-2", children: /* @__PURE__ */ jsx5("pre", { className: "bg-gray-100 p-2 rounded text-sm", children: JSON.stringify(result, null, 2) }) }),
326
+ error && /* @__PURE__ */ jsx5("p", { className: "mt-2 text-red-500", children: error.message }),
327
+ children
328
+ ] });
329
+ }
330
+
331
+ // src/components/contract/ContractWriter.tsx
332
+ import { useState as useState5 } from "react";
333
+ import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
334
+ function ContractWriter({
335
+ address,
336
+ abi,
337
+ functionName,
338
+ chain,
339
+ onSuccess,
340
+ children,
341
+ className
342
+ }) {
343
+ const { write: writeContract, isLoading, error } = useContract();
344
+ const [hash, setHash] = useState5();
345
+ const write = async (args, value) => {
346
+ const txHash = await writeContract({
347
+ address,
348
+ abi,
349
+ functionName,
350
+ args,
351
+ chain,
352
+ value
353
+ });
354
+ setHash(txHash);
355
+ onSuccess?.(txHash);
356
+ };
357
+ const reset = () => {
358
+ setHash(void 0);
359
+ };
360
+ const renderProps = {
361
+ write,
362
+ hash,
363
+ isLoading,
364
+ error,
365
+ reset
366
+ };
367
+ if (typeof children === "function") {
368
+ return /* @__PURE__ */ jsx6(Fragment4, { children: children(renderProps) });
369
+ }
370
+ return /* @__PURE__ */ jsxs3("div", { className: className || "p-4 border rounded", children: [
371
+ /* @__PURE__ */ jsxs3("h3", { className: "font-semibold mb-2", children: [
372
+ "Write: ",
373
+ functionName
374
+ ] }),
375
+ /* @__PURE__ */ jsx6(
376
+ "button",
377
+ {
378
+ onClick: () => write(),
379
+ disabled: isLoading,
380
+ className: "px-3 py-1 bg-green-500 text-white rounded disabled:opacity-50",
381
+ type: "button",
382
+ children: isLoading ? "Sending..." : "Execute"
383
+ }
384
+ ),
385
+ hash && /* @__PURE__ */ jsxs3("div", { className: "mt-2", children: [
386
+ /* @__PURE__ */ jsx6("p", { className: "text-sm text-gray-600", children: "Transaction Hash:" }),
387
+ /* @__PURE__ */ jsx6("p", { className: "font-mono text-xs break-all", children: hash }),
388
+ /* @__PURE__ */ jsx6(
389
+ "button",
390
+ {
391
+ onClick: reset,
392
+ className: "mt-1 text-sm text-blue-500 hover:underline",
393
+ type: "button",
394
+ children: "Reset"
395
+ }
396
+ )
397
+ ] }),
398
+ error && /* @__PURE__ */ jsx6("p", { className: "mt-2 text-red-500", children: error.message }),
399
+ children
400
+ ] });
401
+ }
402
+
403
+ // src/components/swap/SwapWidget.tsx
404
+ import { useState as useState6 } from "react";
405
+ import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
406
+ function SwapWidget({
407
+ defaultSlippage = 0.5,
408
+ onSuccess,
409
+ children,
410
+ className
411
+ }) {
412
+ useDevKitContext();
413
+ const { isConnected, accountIndex } = useWalletContext();
414
+ const [quote, setQuote] = useState6();
415
+ const [isLoadingQuote, setIsLoadingQuote] = useState6(false);
416
+ const [isExecutingSwap, setIsExecutingSwap] = useState6(false);
417
+ const [error, setError] = useState6();
418
+ const [hash, setHash] = useState6();
419
+ const [currentQuoteParams, setCurrentQuoteParams] = useState6();
420
+ const getQuote = async (tokenIn, tokenOut, amountIn) => {
421
+ if (!isConnected) {
422
+ setError(new Error("Wallet not connected"));
423
+ return;
424
+ }
425
+ setIsLoadingQuote(true);
426
+ setError(void 0);
427
+ try {
428
+ const mockQuote = {
429
+ amountIn,
430
+ amountOut: (parseFloat(amountIn) * 0.997).toString(),
431
+ // 0.3% fee
432
+ amountOutMin: (parseFloat(amountIn) * 0.997 * 0.995).toString(),
433
+ // With slippage
434
+ priceImpact: "0.3",
435
+ slippage: defaultSlippage
436
+ };
437
+ setQuote(mockQuote);
438
+ setCurrentQuoteParams({ tokenIn, tokenOut, amountIn });
439
+ } catch (err) {
440
+ setError(err instanceof Error ? err : new Error("Failed to get quote"));
441
+ } finally {
442
+ setIsLoadingQuote(false);
443
+ }
444
+ };
445
+ const executeSwap = async () => {
446
+ if (!quote || !currentQuoteParams || !isConnected || accountIndex === void 0) {
447
+ setError(new Error("Missing required data for swap"));
448
+ return;
449
+ }
450
+ setIsExecutingSwap(true);
451
+ setError(void 0);
452
+ try {
453
+ const mockHash = `0x${Array.from(
454
+ { length: 64 },
455
+ () => Math.floor(Math.random() * 16).toString(16)
456
+ ).join("")}`;
457
+ setHash(mockHash);
458
+ onSuccess?.(mockHash);
459
+ } catch (err) {
460
+ setError(err instanceof Error ? err : new Error("Swap failed"));
461
+ } finally {
462
+ setIsExecutingSwap(false);
463
+ }
464
+ };
465
+ const renderProps = {
466
+ getQuote,
467
+ executeSwap,
468
+ quote,
469
+ isLoadingQuote,
470
+ isExecutingSwap,
471
+ error,
472
+ hash
473
+ };
474
+ if (typeof children === "function") {
475
+ return /* @__PURE__ */ jsx7(Fragment5, { children: children(renderProps) });
476
+ }
477
+ return /* @__PURE__ */ jsxs4("div", { className: className || "p-4 border rounded-lg", children: [
478
+ /* @__PURE__ */ jsx7("h2", { className: "text-xl font-bold mb-4", children: "Swap (Swappi)" }),
479
+ !isConnected && /* @__PURE__ */ jsx7("p", { className: "text-gray-600", children: "Connect wallet to start swapping" }),
480
+ quote && /* @__PURE__ */ jsxs4("div", { className: "mt-4 p-3 bg-gray-100 rounded", children: [
481
+ /* @__PURE__ */ jsxs4("p", { children: [
482
+ "Amount In: ",
483
+ quote.amountIn
484
+ ] }),
485
+ /* @__PURE__ */ jsxs4("p", { children: [
486
+ "Amount Out: ",
487
+ quote.amountOut
488
+ ] }),
489
+ /* @__PURE__ */ jsxs4("p", { children: [
490
+ "Min Amount: ",
491
+ quote.amountOutMin
492
+ ] }),
493
+ /* @__PURE__ */ jsxs4("p", { children: [
494
+ "Slippage: ",
495
+ quote.slippage,
496
+ "%"
497
+ ] })
498
+ ] }),
499
+ hash && /* @__PURE__ */ jsxs4("div", { className: "mt-4 p-3 bg-green-100 rounded", children: [
500
+ /* @__PURE__ */ jsx7("p", { className: "text-sm font-semibold", children: "Swap Successful!" }),
501
+ /* @__PURE__ */ jsx7("p", { className: "text-xs font-mono break-all", children: hash })
502
+ ] }),
503
+ error && /* @__PURE__ */ jsx7("div", { className: "mt-4 p-3 bg-red-100 rounded", children: /* @__PURE__ */ jsx7("p", { className: "text-red-700", children: error.message }) }),
504
+ children
505
+ ] });
506
+ }
507
+
508
+ // src/hooks/useTransaction.ts
509
+ import { useState as useState7 } from "react";
510
+ function useTransaction() {
511
+ useDevKitContext();
512
+ const { accountIndex } = useWalletContext();
513
+ const [isLoading, setIsLoading] = useState7(false);
514
+ const [error, setError] = useState7();
515
+ const [transaction, setTransaction] = useState7();
516
+ const send = async (_options) => {
517
+ if (accountIndex === void 0) {
518
+ throw new Error("Wallet not connected");
519
+ }
520
+ setIsLoading(true);
521
+ setError(void 0);
522
+ try {
523
+ const result = {
524
+ hash: `0x${Array.from(
525
+ { length: 64 },
526
+ () => Math.floor(Math.random() * 16).toString(16)
527
+ ).join("")}`,
528
+ status: "pending"
529
+ };
530
+ setTransaction(result);
531
+ setTimeout(() => {
532
+ setTransaction({ ...result, status: "success" });
533
+ }, 2e3);
534
+ return result;
535
+ } catch (err) {
536
+ const errorObj = err instanceof Error ? err : new Error("Transaction failed");
537
+ setError(errorObj);
538
+ throw errorObj;
539
+ } finally {
540
+ setIsLoading(false);
541
+ }
542
+ };
543
+ const reset = () => {
544
+ setTransaction(void 0);
545
+ setError(void 0);
546
+ };
547
+ return {
548
+ send,
549
+ isLoading,
550
+ error,
551
+ transaction,
552
+ reset
553
+ };
554
+ }
555
+
556
+ // src/index.ts
557
+ var VERSION = "1.0.0";
558
+ export {
559
+ AccountCard,
560
+ ConnectButton,
561
+ ContractReader,
562
+ ContractWriter,
563
+ DevKitProvider,
564
+ SwapWidget,
565
+ VERSION,
566
+ WalletProvider,
567
+ useBalance,
568
+ useContract,
569
+ useDevKitContext,
570
+ useTransaction,
571
+ useWalletContext
572
+ };
573
+ //# sourceMappingURL=index.js.map