@hfunlabs/hypurr-connect 0.1.11 → 0.1.13
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 +27 -2
- package/dist/index.d.ts +174 -10
- package/dist/index.js +2732 -23
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/DeleteWalletModal.tsx +344 -0
- package/src/HypurrConnectProvider.tsx +205 -41
- package/src/RenameWalletModal.tsx +325 -0
- package/src/UserProfileModal.tsx +982 -0
- package/src/WalletSelectorDropdown.tsx +797 -0
- package/src/agent.ts +2 -2
- package/src/icons/lucide.tsx +197 -0
- package/src/index.ts +16 -0
- package/src/privateKeySigner.ts +32 -0
- package/src/profileStyles.ts +213 -0
- package/src/types.ts +48 -10
- package/src/TelegramLoginWidget.tsx +0 -62
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hfunlabs/hypurr-connect",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"format": "pnpm prettier --write ."
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@hfunlabs/hyperliquid": "0.30.2-hfunlabs.2",
|
|
27
|
+
"@hfunlabs/hyperliquid": ">=0.30.2-hfunlabs.2 <0.33.0",
|
|
28
28
|
"@protobuf-ts/grpcweb-transport": ">=2.0.0",
|
|
29
29
|
"@protobuf-ts/runtime-rpc": ">=2.0.0",
|
|
30
30
|
"framer-motion": ">=10.0.0",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@eslint/js": "^9.39.3",
|
|
35
|
-
"@hfunlabs/hyperliquid": "0.
|
|
35
|
+
"@hfunlabs/hyperliquid": "0.32.2-hfunlabs.2",
|
|
36
36
|
"@protobuf-ts/grpcweb-transport": "^2.11.1",
|
|
37
37
|
"@protobuf-ts/runtime-rpc": "^2.11.1",
|
|
38
38
|
"@types/react": "^19.2.14",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"typescript-eslint": "^8.56.1"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"hypurr-grpc": "github:Hypurr-Fun/hypurr-grpc#dev"
|
|
50
|
+
"hypurr-grpc": "github:Hypurr-Fun/hypurr-grpc#dev",
|
|
51
|
+
"viem": "^2.48.11"
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { AnimatePresence, motion } from "framer-motion";
|
|
2
|
+
import type { HyperliquidWallet } from "hypurr-grpc/ts/hypurr/wallet";
|
|
3
|
+
import {
|
|
4
|
+
useCallback,
|
|
5
|
+
useState,
|
|
6
|
+
type CSSProperties,
|
|
7
|
+
type ReactNode,
|
|
8
|
+
} from "react";
|
|
9
|
+
import {
|
|
10
|
+
AlertTriangle,
|
|
11
|
+
Loader2,
|
|
12
|
+
SpinKeyframes,
|
|
13
|
+
Trash2,
|
|
14
|
+
X,
|
|
15
|
+
} from "./icons/lucide";
|
|
16
|
+
import {
|
|
17
|
+
closeBtnStyle as makeCloseBtnStyle,
|
|
18
|
+
dangerOutlineButtonStyle,
|
|
19
|
+
fontFamily,
|
|
20
|
+
modalBackdropStyle,
|
|
21
|
+
modalHeaderStyle,
|
|
22
|
+
modalPanelStyle,
|
|
23
|
+
modalWrapperStyle,
|
|
24
|
+
profileColors,
|
|
25
|
+
titleStyle,
|
|
26
|
+
upperLabelStyle,
|
|
27
|
+
} from "./profileStyles";
|
|
28
|
+
|
|
29
|
+
export interface DeleteWalletModalProps {
|
|
30
|
+
isOpen: boolean;
|
|
31
|
+
onClose: () => void;
|
|
32
|
+
wallet: HyperliquidWallet | null;
|
|
33
|
+
onConfirm: (walletId: number) => Promise<void>;
|
|
34
|
+
/** Optional toast callback. Fires `{type:"success"}` on delete; errors are shown inline. */
|
|
35
|
+
onNotify?: (n: { type: "success" | "error"; message: string }) => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const DANGER_BG = "rgba(248,113,113,0.07)";
|
|
39
|
+
const DANGER_BORDER = "rgba(248,113,113,0.2)";
|
|
40
|
+
|
|
41
|
+
const backdropStyle = modalBackdropStyle(110);
|
|
42
|
+
const wrapperStyle = modalWrapperStyle(111, 16);
|
|
43
|
+
const panelStyle: CSSProperties = {
|
|
44
|
+
...modalPanelStyle(true),
|
|
45
|
+
border: `1px solid ${profileColors.surfaceBd}`,
|
|
46
|
+
};
|
|
47
|
+
const headerStyle: CSSProperties = {
|
|
48
|
+
...modalHeaderStyle,
|
|
49
|
+
borderBottom: "1px solid rgba(255,255,255,0.06)",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const bodyStyle: CSSProperties = {
|
|
53
|
+
padding: "20px 24px",
|
|
54
|
+
display: "flex",
|
|
55
|
+
flexDirection: "column",
|
|
56
|
+
gap: 16,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const warningBoxStyle: CSSProperties = {
|
|
60
|
+
display: "flex",
|
|
61
|
+
alignItems: "flex-start",
|
|
62
|
+
gap: 12,
|
|
63
|
+
padding: 14,
|
|
64
|
+
background: DANGER_BG,
|
|
65
|
+
border: `1px solid ${DANGER_BORDER}`,
|
|
66
|
+
borderRadius: 8,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const infoBoxStyle: CSSProperties = {
|
|
70
|
+
padding: "10px 12px",
|
|
71
|
+
background: "rgba(255,255,255,0.03)",
|
|
72
|
+
border: "1px solid rgba(255,255,255,0.06)",
|
|
73
|
+
borderRadius: 8,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const labelStyle: CSSProperties = {
|
|
77
|
+
display: "block",
|
|
78
|
+
fontSize: 12.5,
|
|
79
|
+
lineHeight: "1rem",
|
|
80
|
+
color: profileColors.muted,
|
|
81
|
+
marginBottom: 8,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const inputStyle = (disabled: boolean): CSSProperties => ({
|
|
85
|
+
width: "100%",
|
|
86
|
+
background: "rgba(13,18,25,0.9)",
|
|
87
|
+
border: `1px solid ${profileColors.surfaceBd}`,
|
|
88
|
+
borderRadius: 8,
|
|
89
|
+
padding: "10px 12px",
|
|
90
|
+
color: profileColors.text,
|
|
91
|
+
fontFamily: fontFamily.mono,
|
|
92
|
+
fontSize: 12.5,
|
|
93
|
+
lineHeight: "1rem",
|
|
94
|
+
outline: "none",
|
|
95
|
+
opacity: disabled ? 0.5 : 1,
|
|
96
|
+
boxSizing: "border-box",
|
|
97
|
+
transition: "border-color 150ms, background-color 150ms",
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const footerStyle: CSSProperties = {
|
|
101
|
+
padding: "0 24px 24px",
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const deleteButtonStyle = (
|
|
105
|
+
enabled: boolean,
|
|
106
|
+
hovered: boolean,
|
|
107
|
+
): CSSProperties => ({
|
|
108
|
+
...dangerOutlineButtonStyle(enabled, hovered),
|
|
109
|
+
width: "100%",
|
|
110
|
+
padding: "8px 0",
|
|
111
|
+
borderRadius: 8,
|
|
112
|
+
fontSize: 12.5,
|
|
113
|
+
lineHeight: "1rem",
|
|
114
|
+
fontWeight: 500,
|
|
115
|
+
display: "flex",
|
|
116
|
+
alignItems: "center",
|
|
117
|
+
justifyContent: "center",
|
|
118
|
+
gap: 8,
|
|
119
|
+
transition: "background-color 150ms, color 150ms, border-color 150ms",
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
export function DeleteWalletModal({
|
|
123
|
+
isOpen,
|
|
124
|
+
onClose,
|
|
125
|
+
wallet,
|
|
126
|
+
onConfirm,
|
|
127
|
+
onNotify,
|
|
128
|
+
}: DeleteWalletModalProps): ReactNode {
|
|
129
|
+
const [confirmName, setConfirmName] = useState("");
|
|
130
|
+
const [isDeleting, setIsDeleting] = useState(false);
|
|
131
|
+
const [error, setError] = useState<string | null>(null);
|
|
132
|
+
const [deleteHovered, setDeleteHovered] = useState(false);
|
|
133
|
+
|
|
134
|
+
const walletName = wallet?.name || "Unnamed Wallet";
|
|
135
|
+
const isNameMatch = confirmName === walletName;
|
|
136
|
+
const canDelete = isNameMatch && !isDeleting;
|
|
137
|
+
|
|
138
|
+
const handleClose = useCallback(() => {
|
|
139
|
+
if (isDeleting) return;
|
|
140
|
+
setConfirmName("");
|
|
141
|
+
setError(null);
|
|
142
|
+
onClose();
|
|
143
|
+
}, [isDeleting, onClose]);
|
|
144
|
+
|
|
145
|
+
const handleDelete = useCallback(async () => {
|
|
146
|
+
if (!wallet || !isNameMatch) return;
|
|
147
|
+
setError(null);
|
|
148
|
+
setIsDeleting(true);
|
|
149
|
+
try {
|
|
150
|
+
await onConfirm(wallet.id);
|
|
151
|
+
setConfirmName("");
|
|
152
|
+
onNotify?.({ type: "success", message: "Wallet deleted successfully" });
|
|
153
|
+
onClose();
|
|
154
|
+
} catch (e: unknown) {
|
|
155
|
+
setError(e instanceof Error ? e.message : "Failed to delete wallet");
|
|
156
|
+
} finally {
|
|
157
|
+
setIsDeleting(false);
|
|
158
|
+
}
|
|
159
|
+
}, [wallet, isNameMatch, onConfirm, onClose, onNotify]);
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<AnimatePresence>
|
|
163
|
+
{isOpen && wallet && (
|
|
164
|
+
<>
|
|
165
|
+
<SpinKeyframes />
|
|
166
|
+
<motion.div
|
|
167
|
+
key="backdrop"
|
|
168
|
+
style={backdropStyle}
|
|
169
|
+
initial={{ opacity: 0 }}
|
|
170
|
+
animate={{ opacity: 1 }}
|
|
171
|
+
exit={{ opacity: 0 }}
|
|
172
|
+
transition={{ duration: 0.15 }}
|
|
173
|
+
onClick={handleClose}
|
|
174
|
+
/>
|
|
175
|
+
<div style={wrapperStyle}>
|
|
176
|
+
<motion.div
|
|
177
|
+
key="panel"
|
|
178
|
+
style={panelStyle}
|
|
179
|
+
initial={{ opacity: 0, y: 8 }}
|
|
180
|
+
animate={{ opacity: 1, y: 0 }}
|
|
181
|
+
exit={{ opacity: 0, y: 8 }}
|
|
182
|
+
transition={{ duration: 0.18, ease: "easeOut" }}
|
|
183
|
+
onClick={(e) => e.stopPropagation()}
|
|
184
|
+
>
|
|
185
|
+
<div style={headerStyle}>
|
|
186
|
+
<h3 style={titleStyle}>Delete Wallet</h3>
|
|
187
|
+
<button
|
|
188
|
+
onClick={handleClose}
|
|
189
|
+
disabled={isDeleting}
|
|
190
|
+
style={makeCloseBtnStyle(isDeleting)}
|
|
191
|
+
aria-label="Close"
|
|
192
|
+
>
|
|
193
|
+
<X size={16} />
|
|
194
|
+
</button>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<div style={bodyStyle}>
|
|
198
|
+
<div style={warningBoxStyle}>
|
|
199
|
+
<AlertTriangle
|
|
200
|
+
size={15}
|
|
201
|
+
color={profileColors.danger}
|
|
202
|
+
style={{ flexShrink: 0, marginTop: 2 }}
|
|
203
|
+
/>
|
|
204
|
+
<div>
|
|
205
|
+
<p
|
|
206
|
+
style={{
|
|
207
|
+
margin: 0,
|
|
208
|
+
fontSize: 12.5,
|
|
209
|
+
lineHeight: "1rem",
|
|
210
|
+
color: profileColors.danger,
|
|
211
|
+
fontWeight: 500,
|
|
212
|
+
}}
|
|
213
|
+
>
|
|
214
|
+
This action cannot be undone
|
|
215
|
+
</p>
|
|
216
|
+
<p
|
|
217
|
+
style={{
|
|
218
|
+
margin: "2px 0 0",
|
|
219
|
+
fontSize: 12.5,
|
|
220
|
+
lineHeight: "1rem",
|
|
221
|
+
color: "rgba(248,113,113,0.7)",
|
|
222
|
+
}}
|
|
223
|
+
>
|
|
224
|
+
The private key will be permanently deleted. Any remaining
|
|
225
|
+
funds will be inaccessible.
|
|
226
|
+
</p>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<div style={infoBoxStyle}>
|
|
231
|
+
<p
|
|
232
|
+
style={{
|
|
233
|
+
margin: "0 0 4px",
|
|
234
|
+
color: profileColors.muted,
|
|
235
|
+
...upperLabelStyle,
|
|
236
|
+
}}
|
|
237
|
+
>
|
|
238
|
+
Wallet to delete
|
|
239
|
+
</p>
|
|
240
|
+
<p
|
|
241
|
+
style={{
|
|
242
|
+
margin: 0,
|
|
243
|
+
fontSize: 12.5,
|
|
244
|
+
lineHeight: "1rem",
|
|
245
|
+
fontWeight: 500,
|
|
246
|
+
color: profileColors.text,
|
|
247
|
+
}}
|
|
248
|
+
>
|
|
249
|
+
{walletName}
|
|
250
|
+
</p>
|
|
251
|
+
<p
|
|
252
|
+
style={{
|
|
253
|
+
margin: "2px 0 0",
|
|
254
|
+
fontSize: 12.5,
|
|
255
|
+
lineHeight: "1rem",
|
|
256
|
+
color: profileColors.muted,
|
|
257
|
+
fontFamily: fontFamily.mono,
|
|
258
|
+
wordBreak: "break-all",
|
|
259
|
+
}}
|
|
260
|
+
>
|
|
261
|
+
{wallet.ethereumAddress}
|
|
262
|
+
</p>
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
<div>
|
|
266
|
+
<label style={labelStyle}>
|
|
267
|
+
Type{" "}
|
|
268
|
+
<span
|
|
269
|
+
style={{
|
|
270
|
+
color: profileColors.text,
|
|
271
|
+
fontWeight: 500,
|
|
272
|
+
}}
|
|
273
|
+
>
|
|
274
|
+
"{walletName}"
|
|
275
|
+
</span>{" "}
|
|
276
|
+
to confirm
|
|
277
|
+
</label>
|
|
278
|
+
<input
|
|
279
|
+
type="text"
|
|
280
|
+
value={confirmName}
|
|
281
|
+
onChange={(e) => setConfirmName(e.target.value)}
|
|
282
|
+
placeholder={walletName}
|
|
283
|
+
disabled={isDeleting}
|
|
284
|
+
style={inputStyle(isDeleting)}
|
|
285
|
+
/>
|
|
286
|
+
</div>
|
|
287
|
+
|
|
288
|
+
{error && (
|
|
289
|
+
<div
|
|
290
|
+
style={{
|
|
291
|
+
display: "flex",
|
|
292
|
+
alignItems: "flex-start",
|
|
293
|
+
gap: 8,
|
|
294
|
+
padding: 12,
|
|
295
|
+
background: "rgba(248,113,113,0.08)",
|
|
296
|
+
border: `1px solid ${DANGER_BORDER}`,
|
|
297
|
+
borderRadius: 8,
|
|
298
|
+
}}
|
|
299
|
+
>
|
|
300
|
+
<AlertTriangle
|
|
301
|
+
size={14}
|
|
302
|
+
color={profileColors.danger}
|
|
303
|
+
style={{ flexShrink: 0, marginTop: 2 }}
|
|
304
|
+
/>
|
|
305
|
+
<p
|
|
306
|
+
style={{
|
|
307
|
+
margin: 0,
|
|
308
|
+
fontSize: 12.5,
|
|
309
|
+
lineHeight: "1rem",
|
|
310
|
+
color: profileColors.danger,
|
|
311
|
+
}}
|
|
312
|
+
>
|
|
313
|
+
{error}
|
|
314
|
+
</p>
|
|
315
|
+
</div>
|
|
316
|
+
)}
|
|
317
|
+
</div>
|
|
318
|
+
|
|
319
|
+
<div style={footerStyle}>
|
|
320
|
+
<button
|
|
321
|
+
onClick={handleDelete}
|
|
322
|
+
disabled={!canDelete}
|
|
323
|
+
onMouseEnter={() => setDeleteHovered(true)}
|
|
324
|
+
onMouseLeave={() => setDeleteHovered(false)}
|
|
325
|
+
style={deleteButtonStyle(canDelete, deleteHovered)}
|
|
326
|
+
>
|
|
327
|
+
{isDeleting ? (
|
|
328
|
+
<>
|
|
329
|
+
<Loader2 size={14} /> Deleting...
|
|
330
|
+
</>
|
|
331
|
+
) : (
|
|
332
|
+
<>
|
|
333
|
+
<Trash2 size={14} /> Delete Wallet
|
|
334
|
+
</>
|
|
335
|
+
)}
|
|
336
|
+
</button>
|
|
337
|
+
</div>
|
|
338
|
+
</motion.div>
|
|
339
|
+
</div>
|
|
340
|
+
</>
|
|
341
|
+
)}
|
|
342
|
+
</AnimatePresence>
|
|
343
|
+
);
|
|
344
|
+
}
|