@cfxdevkit/wallet-connect 0.1.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 +94 -0
- package/dist/index.cjs +577 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +192 -0
- package/dist/index.d.ts +192 -0
- package/dist/index.js +550 -0
- package/dist/index.js.map +1 -0
- package/package.json +89 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @cfxdevkit/wallet-connect
|
|
2
|
+
|
|
3
|
+
Wagmi v2 + ConnectKit + SIWE wallet connection layer for Conflux applications.
|
|
4
|
+
|
|
5
|
+
This package provides:
|
|
6
|
+
- A pre-configured `wagmiConfig` with Conflux eSpace mainnet / testnet / local chains
|
|
7
|
+
- `<WalletConnect />` — a modal-based connect button (ConnectKit)
|
|
8
|
+
- `<AuthProvider />` — SIWE session management
|
|
9
|
+
- `useAuthContext()` — access the current authenticated user anywhere in the tree
|
|
10
|
+
- `useNetworkSwitch()` — helper to switch between Conflux networks
|
|
11
|
+
|
|
12
|
+
Previously named `@conflux-cas/wallet-ui`. Renamed to `@cfxdevkit/wallet-connect`
|
|
13
|
+
because it is not CAS-specific and is used by both the CAS frontend and the
|
|
14
|
+
DevKit dashboard.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add @cfxdevkit/wallet-connect
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Peer dependencies** (install separately in your app):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm add wagmi viem @tanstack/react-query connectkit siwe
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
### Wrap your app
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { AuthProvider } from '@cfxdevkit/wallet-connect';
|
|
38
|
+
|
|
39
|
+
export default function RootLayout({ children }) {
|
|
40
|
+
return <AuthProvider>{children}</AuthProvider>;
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Connect button
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { WalletConnect } from '@cfxdevkit/wallet-connect';
|
|
48
|
+
|
|
49
|
+
export function NavBar() {
|
|
50
|
+
return <WalletConnect />;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Auth context
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { useAuthContext } from '@cfxdevkit/wallet-connect';
|
|
58
|
+
|
|
59
|
+
export function UserPanel() {
|
|
60
|
+
const { address, isAuthenticated, signIn, signOut } = useAuthContext();
|
|
61
|
+
// …
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Wagmi config (for custom wiring)
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { wagmiConfig, confluxESpace, confluxESpaceTestnet } from '@cfxdevkit/wallet-connect';
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Customisation
|
|
74
|
+
|
|
75
|
+
For project-specific chain sets or WalletConnect project IDs, import the config
|
|
76
|
+
primitives and re-compose them in your app:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// apps/my-app/src/wagmi.ts
|
|
80
|
+
import { createConfig, http } from 'wagmi';
|
|
81
|
+
import { confluxESpace } from '@cfxdevkit/wallet-connect';
|
|
82
|
+
|
|
83
|
+
export const myConfig = createConfig({
|
|
84
|
+
chains: [confluxESpace],
|
|
85
|
+
transports: { [confluxESpace.id]: http('https://my-rpc.example.com') },
|
|
86
|
+
// …
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
Apache-2.0 — see [LICENSE](./LICENSE).
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
AuthProvider: () => AuthProvider,
|
|
24
|
+
EXPECTED_CHAIN_ID: () => EXPECTED_CHAIN_ID,
|
|
25
|
+
EXPECTED_CHAIN_NAME: () => EXPECTED_CHAIN_NAME,
|
|
26
|
+
IS_MAINNET: () => IS_MAINNET,
|
|
27
|
+
WalletConnect: () => WalletConnect,
|
|
28
|
+
confluxCore: () => confluxCore,
|
|
29
|
+
confluxCoreTestnet: () => confluxCoreTestnet,
|
|
30
|
+
confluxESpace: () => confluxESpace,
|
|
31
|
+
confluxESpaceTestnet: () => confluxESpaceTestnet,
|
|
32
|
+
confluxLocalCore: () => confluxLocalCore,
|
|
33
|
+
confluxLocalESpace: () => confluxLocalESpace,
|
|
34
|
+
useAuthContext: () => useAuthContext,
|
|
35
|
+
useAuthFetch: () => useAuthFetch,
|
|
36
|
+
useNetworkSwitch: () => useNetworkSwitch,
|
|
37
|
+
wagmiConfig: () => wagmiConfig
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(src_exports);
|
|
40
|
+
|
|
41
|
+
// src/auth-context.tsx
|
|
42
|
+
var import_react = require("react");
|
|
43
|
+
var import_siwe = require("siwe");
|
|
44
|
+
var import_wagmi = require("wagmi");
|
|
45
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
46
|
+
var AuthContext = (0, import_react.createContext)(null);
|
|
47
|
+
var API_BASE = process.env.NEXT_PUBLIC_API_URL ?? "/api";
|
|
48
|
+
var TOKEN_KEY = "cas_jwt";
|
|
49
|
+
function getJwtExpiry(token) {
|
|
50
|
+
try {
|
|
51
|
+
const payload = JSON.parse(atob(token.split(".")[1]));
|
|
52
|
+
return payload.exp ? payload.exp * 1e3 : 0;
|
|
53
|
+
} catch {
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function validToken(token) {
|
|
58
|
+
if (!token) return null;
|
|
59
|
+
const exp = getJwtExpiry(token);
|
|
60
|
+
return exp === 0 || exp > Date.now() ? token : null;
|
|
61
|
+
}
|
|
62
|
+
function AuthProvider({ children }) {
|
|
63
|
+
const { address, isConnected, chainId } = (0, import_wagmi.useAccount)();
|
|
64
|
+
const { signMessageAsync } = (0, import_wagmi.useSignMessage)();
|
|
65
|
+
const { disconnect } = (0, import_wagmi.useDisconnect)();
|
|
66
|
+
const [token, setToken] = (0, import_react.useState)(() => {
|
|
67
|
+
if (typeof window === "undefined") return null;
|
|
68
|
+
const stored = localStorage.getItem(TOKEN_KEY);
|
|
69
|
+
const valid = validToken(stored);
|
|
70
|
+
if (stored && !valid) {
|
|
71
|
+
localStorage.removeItem(TOKEN_KEY);
|
|
72
|
+
}
|
|
73
|
+
return valid;
|
|
74
|
+
});
|
|
75
|
+
const [isLoading, setIsLoading] = (0, import_react.useState)(false);
|
|
76
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
77
|
+
const autoSignedForRef = (0, import_react.useRef)(null);
|
|
78
|
+
const prevAddressRef = (0, import_react.useRef)(null);
|
|
79
|
+
const mountedRef = (0, import_react.useRef)(false);
|
|
80
|
+
(0, import_react.useEffect)(() => {
|
|
81
|
+
if (!mountedRef.current) {
|
|
82
|
+
mountedRef.current = true;
|
|
83
|
+
if (address) prevAddressRef.current = address;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (address) {
|
|
87
|
+
if (prevAddressRef.current && prevAddressRef.current !== address) {
|
|
88
|
+
setToken(null);
|
|
89
|
+
localStorage.removeItem(TOKEN_KEY);
|
|
90
|
+
autoSignedForRef.current = null;
|
|
91
|
+
}
|
|
92
|
+
prevAddressRef.current = address;
|
|
93
|
+
}
|
|
94
|
+
}, [address]);
|
|
95
|
+
const login = (0, import_react.useCallback)(async () => {
|
|
96
|
+
if (!address) {
|
|
97
|
+
setError("No wallet connected");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
setIsLoading(true);
|
|
101
|
+
setError(null);
|
|
102
|
+
try {
|
|
103
|
+
const nonceRes = await fetch(
|
|
104
|
+
`${API_BASE}/auth/nonce?address=${encodeURIComponent(address)}`
|
|
105
|
+
);
|
|
106
|
+
if (!nonceRes.ok) throw new Error("Failed to fetch nonce");
|
|
107
|
+
const { nonce } = await nonceRes.json();
|
|
108
|
+
const message = new import_siwe.SiweMessage({
|
|
109
|
+
domain: window.location.host,
|
|
110
|
+
address,
|
|
111
|
+
statement: "Sign in to Conflux Automation Service",
|
|
112
|
+
uri: window.location.origin,
|
|
113
|
+
version: "1",
|
|
114
|
+
chainId: chainId ?? (process.env.NEXT_PUBLIC_NETWORK === "mainnet" ? 1030 : 71),
|
|
115
|
+
nonce
|
|
116
|
+
});
|
|
117
|
+
const prepared = message.prepareMessage();
|
|
118
|
+
const signature = await signMessageAsync({ message: prepared });
|
|
119
|
+
const verifyRes = await fetch(`${API_BASE}/auth/verify`, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: { "Content-Type": "application/json" },
|
|
122
|
+
body: JSON.stringify({ message: prepared, signature })
|
|
123
|
+
});
|
|
124
|
+
if (!verifyRes.ok) {
|
|
125
|
+
const body = await verifyRes.json().catch(() => ({}));
|
|
126
|
+
throw new Error(body.error ?? "Verification failed");
|
|
127
|
+
}
|
|
128
|
+
const { token: jwt } = await verifyRes.json();
|
|
129
|
+
localStorage.setItem(TOKEN_KEY, jwt);
|
|
130
|
+
setToken(jwt);
|
|
131
|
+
setError(null);
|
|
132
|
+
} catch (err) {
|
|
133
|
+
const msg = err instanceof Error ? err.message : "Login failed";
|
|
134
|
+
if (msg.includes("getChainId is not a function")) {
|
|
135
|
+
setError(
|
|
136
|
+
"Wallet connection issue. Please reconnect your wallet or try a different provider."
|
|
137
|
+
);
|
|
138
|
+
} else {
|
|
139
|
+
setError(
|
|
140
|
+
msg.toLowerCase().includes("rejected") ? "Signature rejected \u2014 try again." : msg
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
} finally {
|
|
144
|
+
setIsLoading(false);
|
|
145
|
+
}
|
|
146
|
+
}, [address, chainId, signMessageAsync]);
|
|
147
|
+
(0, import_react.useEffect)(() => {
|
|
148
|
+
if (isConnected && address && !token && !isLoading && autoSignedForRef.current !== address) {
|
|
149
|
+
autoSignedForRef.current = address;
|
|
150
|
+
void login();
|
|
151
|
+
}
|
|
152
|
+
}, [isConnected, address, token, isLoading, login]);
|
|
153
|
+
const refreshAuth = (0, import_react.useCallback)(() => {
|
|
154
|
+
setToken(null);
|
|
155
|
+
setError(null);
|
|
156
|
+
localStorage.removeItem(TOKEN_KEY);
|
|
157
|
+
autoSignedForRef.current = null;
|
|
158
|
+
}, []);
|
|
159
|
+
const logout = (0, import_react.useCallback)(() => {
|
|
160
|
+
setToken(null);
|
|
161
|
+
setError(null);
|
|
162
|
+
localStorage.removeItem(TOKEN_KEY);
|
|
163
|
+
autoSignedForRef.current = null;
|
|
164
|
+
disconnect();
|
|
165
|
+
}, [disconnect]);
|
|
166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
167
|
+
AuthContext.Provider,
|
|
168
|
+
{
|
|
169
|
+
value: {
|
|
170
|
+
token,
|
|
171
|
+
address: address ?? null,
|
|
172
|
+
isLoading,
|
|
173
|
+
isAuthenticated: Boolean(token && address),
|
|
174
|
+
error,
|
|
175
|
+
login,
|
|
176
|
+
logout,
|
|
177
|
+
refreshAuth
|
|
178
|
+
},
|
|
179
|
+
children
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
function useAuthContext() {
|
|
184
|
+
const ctx = (0, import_react.useContext)(AuthContext);
|
|
185
|
+
if (!ctx)
|
|
186
|
+
throw new Error("useAuthContext must be used inside <AuthProvider>");
|
|
187
|
+
return ctx;
|
|
188
|
+
}
|
|
189
|
+
function useAuthFetch() {
|
|
190
|
+
const { token, refreshAuth } = useAuthContext();
|
|
191
|
+
return (0, import_react.useCallback)(
|
|
192
|
+
async (input, init) => {
|
|
193
|
+
const headers = new Headers(init?.headers);
|
|
194
|
+
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
195
|
+
const res = await fetch(input, { ...init, headers });
|
|
196
|
+
if (res.status === 401) {
|
|
197
|
+
refreshAuth();
|
|
198
|
+
}
|
|
199
|
+
return res;
|
|
200
|
+
},
|
|
201
|
+
[token, refreshAuth]
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/useNetworkSwitch.ts
|
|
206
|
+
var import_react2 = require("react");
|
|
207
|
+
var import_wagmi2 = require("wagmi");
|
|
208
|
+
var IS_MAINNET = process.env.NEXT_PUBLIC_NETWORK === "mainnet";
|
|
209
|
+
var EXPECTED_CHAIN_ID = IS_MAINNET ? 1030 : 71;
|
|
210
|
+
var EXPECTED_CHAIN_NAME = IS_MAINNET ? "Conflux eSpace" : "Conflux eSpace Testnet";
|
|
211
|
+
var CHAIN_PARAMS = IS_MAINNET ? {
|
|
212
|
+
chainId: "0x406",
|
|
213
|
+
// 1030
|
|
214
|
+
chainName: "Conflux eSpace",
|
|
215
|
+
nativeCurrency: { name: "CFX", symbol: "CFX", decimals: 18 },
|
|
216
|
+
rpcUrls: ["https://evm.confluxrpc.com"],
|
|
217
|
+
blockExplorerUrls: ["https://evm.confluxscan.org"]
|
|
218
|
+
} : {
|
|
219
|
+
chainId: "0x47",
|
|
220
|
+
// 71
|
|
221
|
+
chainName: "Conflux eSpace Testnet",
|
|
222
|
+
nativeCurrency: { name: "CFX", symbol: "CFX", decimals: 18 },
|
|
223
|
+
rpcUrls: ["https://evmtestnet.confluxrpc.com"],
|
|
224
|
+
blockExplorerUrls: ["https://evmtestnet.confluxscan.org"]
|
|
225
|
+
};
|
|
226
|
+
function useNetworkSwitch() {
|
|
227
|
+
const { isConnected, chainId } = (0, import_wagmi2.useAccount)();
|
|
228
|
+
const { switchChain, isPending: isSwitching } = (0, import_wagmi2.useSwitchChain)();
|
|
229
|
+
const [switchError, setSwitchError] = (0, import_react2.useState)(null);
|
|
230
|
+
const isWrongNetwork = isConnected && chainId !== EXPECTED_CHAIN_ID;
|
|
231
|
+
(0, import_react2.useEffect)(() => {
|
|
232
|
+
if (!isWrongNetwork) setSwitchError(null);
|
|
233
|
+
}, [isWrongNetwork]);
|
|
234
|
+
const handleSwitchNetwork = (0, import_react2.useCallback)(async () => {
|
|
235
|
+
setSwitchError(null);
|
|
236
|
+
try {
|
|
237
|
+
switchChain({ chainId: EXPECTED_CHAIN_ID });
|
|
238
|
+
} catch {
|
|
239
|
+
const provider = window.ethereum;
|
|
240
|
+
if (!provider) {
|
|
241
|
+
setSwitchError(
|
|
242
|
+
"No wallet found \u2014 add the network manually in MetaMask."
|
|
243
|
+
);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
await provider.request({
|
|
248
|
+
method: "wallet_addEthereumChain",
|
|
249
|
+
params: [CHAIN_PARAMS]
|
|
250
|
+
});
|
|
251
|
+
} catch (addErr) {
|
|
252
|
+
const msg = addErr instanceof Error ? addErr.message : String(addErr);
|
|
253
|
+
if (!msg.toLowerCase().includes("user rejected")) {
|
|
254
|
+
setSwitchError(`Could not switch: ${msg}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}, [switchChain]);
|
|
259
|
+
return { isWrongNetwork, isSwitching, switchError, handleSwitchNetwork };
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/WalletConnect.tsx
|
|
263
|
+
var import_lucide_react = require("lucide-react");
|
|
264
|
+
var import_react3 = require("react");
|
|
265
|
+
var import_wagmi3 = require("wagmi");
|
|
266
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
267
|
+
function AddressChip({
|
|
268
|
+
address,
|
|
269
|
+
status
|
|
270
|
+
}) {
|
|
271
|
+
const [copied, setCopied] = (0, import_react3.useState)(false);
|
|
272
|
+
function handleCopy() {
|
|
273
|
+
void navigator.clipboard.writeText(address).then(() => {
|
|
274
|
+
setCopied(true);
|
|
275
|
+
setTimeout(() => setCopied(false), 1800);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
const dotEl = status === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
279
|
+
"svg",
|
|
280
|
+
{
|
|
281
|
+
className: "h-2.5 w-2.5 animate-spin text-slate-400 flex-shrink-0",
|
|
282
|
+
viewBox: "0 0 24 24",
|
|
283
|
+
fill: "none",
|
|
284
|
+
stroke: "currentColor",
|
|
285
|
+
strokeWidth: "2.5",
|
|
286
|
+
children: [
|
|
287
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("title", { children: "Loading" }),
|
|
288
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
289
|
+
"path",
|
|
290
|
+
{
|
|
291
|
+
d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83",
|
|
292
|
+
strokeLinecap: "round"
|
|
293
|
+
}
|
|
294
|
+
)
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
) : status === "signed" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "h-2 w-2 rounded-full bg-green-400 shadow-[0_0_5px_#4ade80] flex-shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "h-2 w-2 rounded-full bg-orange-400 shadow-[0_0_5px_#fb923c] flex-shrink-0" });
|
|
298
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
299
|
+
"button",
|
|
300
|
+
{
|
|
301
|
+
type: "button",
|
|
302
|
+
onClick: handleCopy,
|
|
303
|
+
title: copied ? "Copied!" : address,
|
|
304
|
+
className: "group flex items-center gap-1.5 rounded-lg border border-slate-600 bg-slate-800\n px-2.5 py-1 transition-colors hover:border-conflux-500 hover:bg-slate-700",
|
|
305
|
+
children: [
|
|
306
|
+
dotEl,
|
|
307
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-mono text-xs text-slate-200", children: [
|
|
308
|
+
address.slice(0, 6),
|
|
309
|
+
"\u2026",
|
|
310
|
+
address.slice(-4)
|
|
311
|
+
] }),
|
|
312
|
+
copied ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
313
|
+
import_lucide_react.Check,
|
|
314
|
+
{
|
|
315
|
+
className: "h-3 w-3 text-green-400 flex-shrink-0",
|
|
316
|
+
strokeWidth: 3
|
|
317
|
+
}
|
|
318
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Copy, { className: "h-3 w-3 text-slate-500 group-hover:text-conflux-400 flex-shrink-0 transition-colors" })
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
function WalletConnect() {
|
|
324
|
+
const { isConnected } = (0, import_wagmi3.useAccount)();
|
|
325
|
+
const { connect } = (0, import_wagmi3.useConnect)();
|
|
326
|
+
const { address, token, isLoading, error, login, logout } = useAuthContext();
|
|
327
|
+
const { isWrongNetwork, isSwitching, switchError, handleSwitchNetwork } = useNetworkSwitch();
|
|
328
|
+
if (!isConnected) {
|
|
329
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
330
|
+
"button",
|
|
331
|
+
{
|
|
332
|
+
type: "button",
|
|
333
|
+
onClick: () => connect({ connector: (0, import_wagmi3.injected)() }),
|
|
334
|
+
className: "group flex items-center gap-2 bg-conflux-600 hover:bg-conflux-500 text-white text-sm font-semibold py-2 px-4 rounded-xl transition-all shadow-[0_0_20px_-5px_rgba(0,120,200,0.5)] hover:shadow-[0_0_25px_-5px_rgba(0,120,200,0.7)]",
|
|
335
|
+
children: [
|
|
336
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Wallet, { className: "h-4 w-4 group-hover:scale-110 transition-transform" }),
|
|
337
|
+
"Connect Wallet"
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
343
|
+
address && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
344
|
+
AddressChip,
|
|
345
|
+
{
|
|
346
|
+
address,
|
|
347
|
+
status: isLoading ? "loading" : token ? "signed" : "unsigned"
|
|
348
|
+
}
|
|
349
|
+
),
|
|
350
|
+
isWrongNetwork ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-end gap-1", children: [
|
|
351
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
352
|
+
"button",
|
|
353
|
+
{
|
|
354
|
+
type: "button",
|
|
355
|
+
onClick: handleSwitchNetwork,
|
|
356
|
+
disabled: isSwitching,
|
|
357
|
+
className: "flex items-center gap-1.5 text-xs bg-amber-600/20 border border-amber-600/50 hover:bg-amber-600/30\n disabled:opacity-50 text-amber-500 py-1.5 px-3 rounded-lg transition-colors whitespace-nowrap font-medium",
|
|
358
|
+
title: `Switch wallet to ${EXPECTED_CHAIN_NAME}`,
|
|
359
|
+
children: [
|
|
360
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.AlertTriangle, { className: "h-3.5 w-3.5" }),
|
|
361
|
+
isSwitching ? "Switching\u2026" : `Switch to ${EXPECTED_CHAIN_NAME}`
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
),
|
|
365
|
+
switchError && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-xs text-red-400 max-w-[180px] text-right leading-tight", children: switchError })
|
|
366
|
+
] }) : isLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
367
|
+
"button",
|
|
368
|
+
{
|
|
369
|
+
type: "button",
|
|
370
|
+
disabled: true,
|
|
371
|
+
className: "flex items-center gap-1.5 text-xs border border-slate-700/50 bg-slate-800/50 text-slate-500\n py-1.5 px-3 rounded-lg cursor-not-allowed",
|
|
372
|
+
children: [
|
|
373
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Loader2, { className: "h-3.5 w-3.5 animate-spin text-slate-400" }),
|
|
374
|
+
"Signing\u2026"
|
|
375
|
+
]
|
|
376
|
+
}
|
|
377
|
+
) : !token ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
378
|
+
"button",
|
|
379
|
+
{
|
|
380
|
+
type: "button",
|
|
381
|
+
onClick: () => void login(),
|
|
382
|
+
title: error ?? "Sign a message to authenticate",
|
|
383
|
+
className: "text-xs bg-conflux-600 hover:bg-conflux-500 text-white py-1.5 px-4 rounded-lg transition-colors font-medium shadow-[0_0_15px_-5px_rgba(0,120,200,0.5)]",
|
|
384
|
+
children: "Sign In"
|
|
385
|
+
}
|
|
386
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
387
|
+
"button",
|
|
388
|
+
{
|
|
389
|
+
type: "button",
|
|
390
|
+
onClick: () => logout(),
|
|
391
|
+
title: "Disconnect wallet",
|
|
392
|
+
className: "flex items-center gap-1.5 text-xs border border-slate-700 bg-slate-800 hover:bg-red-500/10 hover:border-red-500/50\n text-slate-400 hover:text-red-400 py-1.5 px-2.5 rounded-lg transition-colors",
|
|
393
|
+
children: [
|
|
394
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Power, { className: "h-3.5 w-3.5 flex-shrink-0" }),
|
|
395
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "hidden sm:inline font-medium", children: "Disconnect" })
|
|
396
|
+
]
|
|
397
|
+
}
|
|
398
|
+
)
|
|
399
|
+
] });
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/wagmi.ts
|
|
403
|
+
var import_connectkit = require("connectkit");
|
|
404
|
+
var import_wagmi4 = require("wagmi");
|
|
405
|
+
var import_chains = require("wagmi/chains");
|
|
406
|
+
var confluxCore = {
|
|
407
|
+
id: 1029,
|
|
408
|
+
name: "Conflux Core",
|
|
409
|
+
network: "conflux-core",
|
|
410
|
+
nativeCurrency: {
|
|
411
|
+
decimals: 18,
|
|
412
|
+
name: "CFX",
|
|
413
|
+
symbol: "CFX"
|
|
414
|
+
},
|
|
415
|
+
rpcUrls: {
|
|
416
|
+
default: {
|
|
417
|
+
http: ["https://main.confluxrpc.com"]
|
|
418
|
+
},
|
|
419
|
+
public: {
|
|
420
|
+
http: ["https://main.confluxrpc.com"]
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
blockExplorers: {
|
|
424
|
+
default: { name: "ConfluxScan", url: "https://confluxscan.io" }
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
var confluxESpace = {
|
|
428
|
+
id: 1030,
|
|
429
|
+
name: "Conflux eSpace",
|
|
430
|
+
network: "conflux-espace",
|
|
431
|
+
nativeCurrency: {
|
|
432
|
+
decimals: 18,
|
|
433
|
+
name: "CFX",
|
|
434
|
+
symbol: "CFX"
|
|
435
|
+
},
|
|
436
|
+
rpcUrls: {
|
|
437
|
+
default: {
|
|
438
|
+
http: ["https://evm.confluxrpc.com"]
|
|
439
|
+
},
|
|
440
|
+
public: {
|
|
441
|
+
http: ["https://evm.confluxrpc.com"]
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
blockExplorers: {
|
|
445
|
+
default: { name: "ConfluxScan", url: "https://evmtestnet.confluxscan.io" }
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
var confluxCoreTestnet = {
|
|
449
|
+
id: 1001,
|
|
450
|
+
name: "Conflux Core Testnet",
|
|
451
|
+
network: "conflux-core-testnet",
|
|
452
|
+
nativeCurrency: {
|
|
453
|
+
decimals: 18,
|
|
454
|
+
name: "CFX",
|
|
455
|
+
symbol: "CFX"
|
|
456
|
+
},
|
|
457
|
+
rpcUrls: {
|
|
458
|
+
default: {
|
|
459
|
+
http: ["https://test.confluxrpc.com"]
|
|
460
|
+
},
|
|
461
|
+
public: {
|
|
462
|
+
http: ["https://test.confluxrpc.com"]
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
blockExplorers: {
|
|
466
|
+
default: { name: "ConfluxScan", url: "https://testnet.confluxscan.io" }
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
var confluxESpaceTestnet = {
|
|
470
|
+
id: 71,
|
|
471
|
+
name: "Conflux eSpace Testnet",
|
|
472
|
+
network: "conflux-espace-testnet",
|
|
473
|
+
nativeCurrency: {
|
|
474
|
+
decimals: 18,
|
|
475
|
+
name: "CFX",
|
|
476
|
+
symbol: "CFX"
|
|
477
|
+
},
|
|
478
|
+
rpcUrls: {
|
|
479
|
+
default: {
|
|
480
|
+
http: ["https://evmtestnet.confluxrpc.com"]
|
|
481
|
+
},
|
|
482
|
+
public: {
|
|
483
|
+
http: ["https://evmtestnet.confluxrpc.com"]
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
blockExplorers: {
|
|
487
|
+
default: { name: "ConfluxScan", url: "https://evmtestnet.confluxscan.io" }
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
var confluxLocalCore = {
|
|
491
|
+
id: 2029,
|
|
492
|
+
name: "Conflux Local Core",
|
|
493
|
+
network: "conflux-local-core",
|
|
494
|
+
nativeCurrency: {
|
|
495
|
+
decimals: 18,
|
|
496
|
+
name: "CFX",
|
|
497
|
+
symbol: "CFX"
|
|
498
|
+
},
|
|
499
|
+
rpcUrls: {
|
|
500
|
+
default: {
|
|
501
|
+
http: ["http://localhost:12537"]
|
|
502
|
+
},
|
|
503
|
+
public: {
|
|
504
|
+
http: ["http://localhost:12537"]
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
var confluxLocalESpace = {
|
|
509
|
+
id: 2030,
|
|
510
|
+
name: "Conflux Local eSpace",
|
|
511
|
+
network: "conflux-local-espace",
|
|
512
|
+
nativeCurrency: {
|
|
513
|
+
decimals: 18,
|
|
514
|
+
name: "CFX",
|
|
515
|
+
symbol: "CFX"
|
|
516
|
+
},
|
|
517
|
+
rpcUrls: {
|
|
518
|
+
default: {
|
|
519
|
+
http: ["http://localhost:8545"]
|
|
520
|
+
},
|
|
521
|
+
public: {
|
|
522
|
+
http: ["http://localhost:8545"]
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
var wagmiConfig = (0, import_wagmi4.createConfig)(
|
|
527
|
+
(0, import_connectkit.getDefaultConfig)({
|
|
528
|
+
// Prioritize EVM-compatible chains (most wallets support these)
|
|
529
|
+
// Conflux eSpace uses standard EVM wallet infrastructure
|
|
530
|
+
chains: [
|
|
531
|
+
confluxESpace,
|
|
532
|
+
// Conflux eSpace Mainnet (primary - EVM compatible)
|
|
533
|
+
confluxLocalESpace,
|
|
534
|
+
// Local dev node eSpace
|
|
535
|
+
confluxESpaceTestnet,
|
|
536
|
+
// Testnet eSpace
|
|
537
|
+
import_chains.mainnet,
|
|
538
|
+
// Ethereum mainnet
|
|
539
|
+
import_chains.sepolia
|
|
540
|
+
// Ethereum testnet
|
|
541
|
+
// Note: Core chains removed from default list as few wallets support non-EVM chains
|
|
542
|
+
// Users can manually add confluxCore via network settings if their wallet supports it
|
|
543
|
+
],
|
|
544
|
+
transports: {
|
|
545
|
+
[confluxESpace.id]: (0, import_wagmi4.http)(),
|
|
546
|
+
[confluxLocalESpace.id]: (0, import_wagmi4.http)(),
|
|
547
|
+
[confluxESpaceTestnet.id]: (0, import_wagmi4.http)(),
|
|
548
|
+
[import_chains.mainnet.id]: (0, import_wagmi4.http)(),
|
|
549
|
+
[import_chains.sepolia.id]: (0, import_wagmi4.http)()
|
|
550
|
+
},
|
|
551
|
+
walletConnectProjectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID || "conflux-devkit-local",
|
|
552
|
+
appName: "Conflux DevKit",
|
|
553
|
+
appDescription: "Development toolkit for Conflux blockchain",
|
|
554
|
+
appUrl: "https://conflux-devkit.dev",
|
|
555
|
+
appIcon: "https://conflux-devkit.dev/icon.png"
|
|
556
|
+
// Note: Get a real project ID from https://cloud.walletconnect.com/ for production
|
|
557
|
+
})
|
|
558
|
+
);
|
|
559
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
560
|
+
0 && (module.exports = {
|
|
561
|
+
AuthProvider,
|
|
562
|
+
EXPECTED_CHAIN_ID,
|
|
563
|
+
EXPECTED_CHAIN_NAME,
|
|
564
|
+
IS_MAINNET,
|
|
565
|
+
WalletConnect,
|
|
566
|
+
confluxCore,
|
|
567
|
+
confluxCoreTestnet,
|
|
568
|
+
confluxESpace,
|
|
569
|
+
confluxESpaceTestnet,
|
|
570
|
+
confluxLocalCore,
|
|
571
|
+
confluxLocalESpace,
|
|
572
|
+
useAuthContext,
|
|
573
|
+
useAuthFetch,
|
|
574
|
+
useNetworkSwitch,
|
|
575
|
+
wagmiConfig
|
|
576
|
+
});
|
|
577
|
+
//# sourceMappingURL=index.cjs.map
|