access-layers-wallet 1.0.2
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 +213 -0
- package/dist/index.d.mts +168 -0
- package/dist/index.d.ts +168 -0
- package/dist/index.js +3392 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3346 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +80 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,3346 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __spreadValues = (a, b) => {
|
|
10
|
+
for (var prop in b || (b = {}))
|
|
11
|
+
if (__hasOwnProp.call(b, prop))
|
|
12
|
+
__defNormalProp(a, prop, b[prop]);
|
|
13
|
+
if (__getOwnPropSymbols)
|
|
14
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
+
if (__propIsEnum.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
}
|
|
18
|
+
return a;
|
|
19
|
+
};
|
|
20
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
21
|
+
var __objRest = (source, exclude) => {
|
|
22
|
+
var target = {};
|
|
23
|
+
for (var prop in source)
|
|
24
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
25
|
+
target[prop] = source[prop];
|
|
26
|
+
if (source != null && __getOwnPropSymbols)
|
|
27
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
28
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
29
|
+
target[prop] = source[prop];
|
|
30
|
+
}
|
|
31
|
+
return target;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/components/ConnectWalletHandler.tsx
|
|
35
|
+
import { useEffect as useEffect2, useState as useState2, useCallback as useCallback2 } from "react";
|
|
36
|
+
|
|
37
|
+
// components/ui/dialog.tsx
|
|
38
|
+
import * as React from "react";
|
|
39
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
40
|
+
import { X } from "lucide-react";
|
|
41
|
+
|
|
42
|
+
// lib/utils.ts
|
|
43
|
+
import { clsx } from "clsx";
|
|
44
|
+
import { twMerge } from "tailwind-merge";
|
|
45
|
+
function cn(...inputs) {
|
|
46
|
+
return twMerge(clsx(inputs));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// components/ui/dialog.tsx
|
|
50
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
51
|
+
var Dialog = DialogPrimitive.Root;
|
|
52
|
+
var DialogPortal = DialogPrimitive.Portal;
|
|
53
|
+
var DialogOverlay = React.forwardRef((_a, ref) => {
|
|
54
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
55
|
+
return /* @__PURE__ */ jsx(DialogPortal, { children: /* @__PURE__ */ jsx(
|
|
56
|
+
DialogPrimitive.Overlay,
|
|
57
|
+
__spreadValues({
|
|
58
|
+
ref,
|
|
59
|
+
className: cn(
|
|
60
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
61
|
+
className
|
|
62
|
+
)
|
|
63
|
+
}, props)
|
|
64
|
+
) });
|
|
65
|
+
});
|
|
66
|
+
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
67
|
+
var DialogContent = React.forwardRef((_a, ref) => {
|
|
68
|
+
var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
69
|
+
return /* @__PURE__ */ jsxs(DialogPortal, { children: [
|
|
70
|
+
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
71
|
+
/* @__PURE__ */ jsxs(
|
|
72
|
+
DialogPrimitive.Content,
|
|
73
|
+
__spreadProps(__spreadValues({
|
|
74
|
+
ref,
|
|
75
|
+
className: cn(
|
|
76
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
|
77
|
+
className
|
|
78
|
+
)
|
|
79
|
+
}, props), {
|
|
80
|
+
children: [
|
|
81
|
+
children,
|
|
82
|
+
/* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
|
|
83
|
+
/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
|
|
84
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
85
|
+
] })
|
|
86
|
+
]
|
|
87
|
+
})
|
|
88
|
+
)
|
|
89
|
+
] });
|
|
90
|
+
});
|
|
91
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
92
|
+
var DialogHeader = (_a) => {
|
|
93
|
+
var _b = _a, {
|
|
94
|
+
className
|
|
95
|
+
} = _b, props = __objRest(_b, [
|
|
96
|
+
"className"
|
|
97
|
+
]);
|
|
98
|
+
return /* @__PURE__ */ jsx(
|
|
99
|
+
"div",
|
|
100
|
+
__spreadValues({
|
|
101
|
+
className: cn(
|
|
102
|
+
"flex flex-col space-y-1.5 text-center sm:text-left",
|
|
103
|
+
className
|
|
104
|
+
)
|
|
105
|
+
}, props)
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
DialogHeader.displayName = "DialogHeader";
|
|
109
|
+
var DialogFooter = (_a) => {
|
|
110
|
+
var _b = _a, {
|
|
111
|
+
className
|
|
112
|
+
} = _b, props = __objRest(_b, [
|
|
113
|
+
"className"
|
|
114
|
+
]);
|
|
115
|
+
return /* @__PURE__ */ jsx(
|
|
116
|
+
"div",
|
|
117
|
+
__spreadValues({
|
|
118
|
+
className: cn(
|
|
119
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
120
|
+
className
|
|
121
|
+
)
|
|
122
|
+
}, props)
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
DialogFooter.displayName = "DialogFooter";
|
|
126
|
+
var DialogTitle = React.forwardRef((_a, ref) => {
|
|
127
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
128
|
+
return /* @__PURE__ */ jsx(
|
|
129
|
+
DialogPrimitive.Title,
|
|
130
|
+
__spreadValues({
|
|
131
|
+
ref,
|
|
132
|
+
className: cn(
|
|
133
|
+
"text-lg font-semibold leading-none tracking-tight",
|
|
134
|
+
className
|
|
135
|
+
)
|
|
136
|
+
}, props)
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
140
|
+
var DialogDescription = React.forwardRef((_a, ref) => {
|
|
141
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
142
|
+
return /* @__PURE__ */ jsx(
|
|
143
|
+
DialogPrimitive.Description,
|
|
144
|
+
__spreadValues({
|
|
145
|
+
ref,
|
|
146
|
+
className: cn("text-sm text-muted-foreground", className)
|
|
147
|
+
}, props)
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
151
|
+
|
|
152
|
+
// src/components/ConnectWalletHandler.tsx
|
|
153
|
+
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
|
|
154
|
+
import { toast as toast2 } from "sonner";
|
|
155
|
+
|
|
156
|
+
// components/ui/button.tsx
|
|
157
|
+
import * as React2 from "react";
|
|
158
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
159
|
+
import { cva } from "class-variance-authority";
|
|
160
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
161
|
+
var buttonVariants = cva(
|
|
162
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
163
|
+
{
|
|
164
|
+
variants: {
|
|
165
|
+
variant: {
|
|
166
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
167
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
168
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
169
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
170
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
171
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
172
|
+
},
|
|
173
|
+
size: {
|
|
174
|
+
default: "h-10 px-4 py-2",
|
|
175
|
+
sm: "h-9 rounded-md px-3",
|
|
176
|
+
lg: "h-11 rounded-md px-8",
|
|
177
|
+
icon: "h-10 w-10"
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
defaultVariants: {
|
|
181
|
+
variant: "default",
|
|
182
|
+
size: "default"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
var Button = React2.forwardRef(
|
|
187
|
+
(_a, ref) => {
|
|
188
|
+
var _b = _a, { className, variant, size, asChild = false } = _b, props = __objRest(_b, ["className", "variant", "size", "asChild"]);
|
|
189
|
+
const Comp = asChild ? Slot : "button";
|
|
190
|
+
return /* @__PURE__ */ jsx2(
|
|
191
|
+
Comp,
|
|
192
|
+
__spreadValues({
|
|
193
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
194
|
+
ref
|
|
195
|
+
}, props)
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
Button.displayName = "Button";
|
|
200
|
+
|
|
201
|
+
// src/components/ConnectWalletHandler.tsx
|
|
202
|
+
import { motion } from "framer-motion";
|
|
203
|
+
import {
|
|
204
|
+
Loader2,
|
|
205
|
+
X as X2,
|
|
206
|
+
ExternalLink
|
|
207
|
+
} from "lucide-react";
|
|
208
|
+
|
|
209
|
+
// hooks/useSupraMultiWallet.ts
|
|
210
|
+
import { useState, useEffect, useCallback } from "react";
|
|
211
|
+
import nacl from "tweetnacl";
|
|
212
|
+
import { useRouter } from "next/navigation";
|
|
213
|
+
import { toast } from "sonner";
|
|
214
|
+
import {
|
|
215
|
+
SupraChainId,
|
|
216
|
+
initSdk
|
|
217
|
+
} from "ribbit-wallet-connect";
|
|
218
|
+
|
|
219
|
+
// lib/logger.ts
|
|
220
|
+
var Logger = class {
|
|
221
|
+
constructor() {
|
|
222
|
+
this.isDevelopment = process.env.NODE_ENV === "development";
|
|
223
|
+
}
|
|
224
|
+
log(level, message, context, error) {
|
|
225
|
+
if (!this.isDevelopment && level === "debug") {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const entry = {
|
|
229
|
+
level,
|
|
230
|
+
message,
|
|
231
|
+
timestamp: Date.now(),
|
|
232
|
+
context,
|
|
233
|
+
error
|
|
234
|
+
};
|
|
235
|
+
const logMethod = level === "error" ? console.error : level === "warn" ? console.warn : console.log;
|
|
236
|
+
if (error) {
|
|
237
|
+
logMethod(`[${level.toUpperCase()}] ${message}`, __spreadProps(__spreadValues({}, context), {
|
|
238
|
+
error: {
|
|
239
|
+
name: error.name,
|
|
240
|
+
message: error.message,
|
|
241
|
+
stack: error.stack
|
|
242
|
+
}
|
|
243
|
+
}));
|
|
244
|
+
} else {
|
|
245
|
+
logMethod(`[${level.toUpperCase()}] ${message}`, context || {});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
debug(message, context) {
|
|
249
|
+
this.log("debug", message, context);
|
|
250
|
+
}
|
|
251
|
+
info(message, context) {
|
|
252
|
+
this.log("info", message, context);
|
|
253
|
+
}
|
|
254
|
+
warn(message, context) {
|
|
255
|
+
this.log("warn", message, context);
|
|
256
|
+
}
|
|
257
|
+
error(message, error, context) {
|
|
258
|
+
this.log("error", message, context, error);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
var logger = new Logger();
|
|
262
|
+
|
|
263
|
+
// lib/errors.ts
|
|
264
|
+
var WalletError = class _WalletError extends Error {
|
|
265
|
+
constructor(message, code, cause) {
|
|
266
|
+
super(message);
|
|
267
|
+
this.code = code;
|
|
268
|
+
this.cause = cause;
|
|
269
|
+
this.name = "WalletError";
|
|
270
|
+
Object.setPrototypeOf(this, _WalletError.prototype);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
var WalletConnectionError = class _WalletConnectionError extends WalletError {
|
|
274
|
+
constructor(message, cause) {
|
|
275
|
+
super(message, "WALLET_CONNECTION_ERROR", cause);
|
|
276
|
+
this.name = "WalletConnectionError";
|
|
277
|
+
Object.setPrototypeOf(this, _WalletConnectionError.prototype);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
var TransactionError = class _TransactionError extends WalletError {
|
|
281
|
+
constructor(message, txHash, cause) {
|
|
282
|
+
super(message, "TRANSACTION_ERROR", cause);
|
|
283
|
+
this.txHash = txHash;
|
|
284
|
+
this.name = "TransactionError";
|
|
285
|
+
Object.setPrototypeOf(this, _TransactionError.prototype);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
var SignMessageError = class _SignMessageError extends WalletError {
|
|
289
|
+
constructor(message, cause) {
|
|
290
|
+
super(message, "SIGN_MESSAGE_ERROR", cause);
|
|
291
|
+
this.name = "SignMessageError";
|
|
292
|
+
Object.setPrototypeOf(this, _SignMessageError.prototype);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
var WalletNotInstalledError = class _WalletNotInstalledError extends WalletError {
|
|
296
|
+
constructor(walletType) {
|
|
297
|
+
super(`Wallet ${walletType} is not installed`, "WALLET_NOT_INSTALLED");
|
|
298
|
+
this.name = "WalletNotInstalledError";
|
|
299
|
+
Object.setPrototypeOf(this, _WalletNotInstalledError.prototype);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
var NetworkError = class _NetworkError extends WalletError {
|
|
303
|
+
constructor(message, cause) {
|
|
304
|
+
super(message, "NETWORK_ERROR", cause);
|
|
305
|
+
this.name = "NetworkError";
|
|
306
|
+
Object.setPrototypeOf(this, _NetworkError.prototype);
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
// lib/storage.ts
|
|
311
|
+
function setStorageItem(key, value, preferredType = "localStorage") {
|
|
312
|
+
const types = preferredType === "localStorage" ? ["localStorage", "sessionStorage", "cookie"] : preferredType === "sessionStorage" ? ["sessionStorage", "localStorage", "cookie"] : ["cookie", "localStorage", "sessionStorage"];
|
|
313
|
+
for (const type of types) {
|
|
314
|
+
try {
|
|
315
|
+
switch (type) {
|
|
316
|
+
case "localStorage":
|
|
317
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
318
|
+
window.localStorage.setItem(key, value);
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
break;
|
|
322
|
+
case "sessionStorage":
|
|
323
|
+
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
324
|
+
window.sessionStorage.setItem(key, value);
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
break;
|
|
328
|
+
case "cookie":
|
|
329
|
+
if (typeof document !== "undefined") {
|
|
330
|
+
document.cookie = `${key}=${encodeURIComponent(value)}; path=/; max-age=${60 * 60 * 24 * 30}; SameSite=Lax`;
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
} catch (error) {
|
|
336
|
+
logger.warn(`Failed to set ${key} in ${type}`, { error });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
function getStorageItem(key) {
|
|
342
|
+
try {
|
|
343
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
344
|
+
const value = window.localStorage.getItem(key);
|
|
345
|
+
if (value !== null) return value;
|
|
346
|
+
}
|
|
347
|
+
} catch (error) {
|
|
348
|
+
logger.warn(`Failed to read ${key} from localStorage`, { error });
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
352
|
+
const value = window.sessionStorage.getItem(key);
|
|
353
|
+
if (value !== null) return value;
|
|
354
|
+
}
|
|
355
|
+
} catch (error) {
|
|
356
|
+
logger.warn(`Failed to read ${key} from sessionStorage`, { error });
|
|
357
|
+
}
|
|
358
|
+
try {
|
|
359
|
+
if (typeof document !== "undefined") {
|
|
360
|
+
const match = document.cookie.split("; ").find((r) => r.startsWith(key + "="));
|
|
361
|
+
if (match) {
|
|
362
|
+
return decodeURIComponent(match.split("=").slice(1).join("="));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
} catch (error) {
|
|
366
|
+
logger.warn(`Failed to read ${key} from cookie`, { error });
|
|
367
|
+
}
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
function removeStorageItem(key) {
|
|
371
|
+
try {
|
|
372
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
373
|
+
window.localStorage.removeItem(key);
|
|
374
|
+
}
|
|
375
|
+
} catch (error) {
|
|
376
|
+
}
|
|
377
|
+
try {
|
|
378
|
+
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
379
|
+
window.sessionStorage.removeItem(key);
|
|
380
|
+
}
|
|
381
|
+
} catch (error) {
|
|
382
|
+
}
|
|
383
|
+
try {
|
|
384
|
+
if (typeof document !== "undefined") {
|
|
385
|
+
document.cookie = `${key}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
|
|
386
|
+
}
|
|
387
|
+
} catch (error) {
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// lib/constants.ts
|
|
392
|
+
var STORAGE_KEYS = {
|
|
393
|
+
SELECTED_WALLET: "multiwallet.selectedWallet",
|
|
394
|
+
RECENT_WALLET: "recent_wallet_type",
|
|
395
|
+
USER_PROFILE_CACHE: "user_profile_cache",
|
|
396
|
+
USER_PROFILE_CACHE_TIMESTAMP: "user_profile_cache_timestamp",
|
|
397
|
+
IS_SIGNING_WALLET: "isSigningWallet",
|
|
398
|
+
STARKEY_ACCOUNTS: "starkey.accounts.0"
|
|
399
|
+
};
|
|
400
|
+
var CACHE_TTL = {
|
|
401
|
+
PROFILE: 600 * 1e3,
|
|
402
|
+
// 10 minutes
|
|
403
|
+
BALANCE: 30 * 1e3
|
|
404
|
+
// 30 seconds
|
|
405
|
+
};
|
|
406
|
+
var TIMEOUTS = {
|
|
407
|
+
WALLET_DETECTION_POLL: 3e3,
|
|
408
|
+
// 3 seconds (reduced from 5s)
|
|
409
|
+
WALLET_CHECK_INTERVAL: 2e3,
|
|
410
|
+
// 2 seconds
|
|
411
|
+
WALLET_CHECK_MAX_DURATION: 3e4,
|
|
412
|
+
// 30 seconds
|
|
413
|
+
CONNECTION_TIMEOUT: 3e4,
|
|
414
|
+
// 30 seconds
|
|
415
|
+
BALANCE_POLL_INTERVAL: 3e4,
|
|
416
|
+
// 30 seconds
|
|
417
|
+
MODAL_CLOSE_DELAY: 2500,
|
|
418
|
+
// 2.5 seconds
|
|
419
|
+
CLICK_OUTSIDE_DELAY: 2e3
|
|
420
|
+
// 2 seconds
|
|
421
|
+
};
|
|
422
|
+
var WALLET_DOWNLOAD_URLS = {
|
|
423
|
+
starkey: "https://chromewebstore.google.com/detail/starkey-wallet-the-offici/hcjhpkgbmechpabifbggldplacolbkoh",
|
|
424
|
+
ribbit: "https://ribbitwallet.com"
|
|
425
|
+
};
|
|
426
|
+
var DEFAULT_CHAIN_IDS = {
|
|
427
|
+
TESTNET: "6",
|
|
428
|
+
MAINNET: "8"
|
|
429
|
+
};
|
|
430
|
+
var ERROR_MESSAGES = {
|
|
431
|
+
WALLET_NOT_INSTALLED: "Wallet extension not installed",
|
|
432
|
+
CONNECTION_FAILED: "Failed to connect wallet",
|
|
433
|
+
CONNECTION_REJECTED: "Connection rejected by user",
|
|
434
|
+
NO_ACCOUNT_FOUND: "No account found",
|
|
435
|
+
SIGNING_FAILED: "Message signing failed",
|
|
436
|
+
SIGNING_REJECTED: "Message signing rejected",
|
|
437
|
+
TRANSACTION_FAILED: "Transaction failed",
|
|
438
|
+
TRANSACTION_REJECTED: "Transaction rejected",
|
|
439
|
+
NETWORK_ERROR: "Network error occurred",
|
|
440
|
+
UNSUPPORTED_WALLET: "Unsupported wallet type",
|
|
441
|
+
INVALID_ADDRESS: "Invalid wallet address"
|
|
442
|
+
};
|
|
443
|
+
var CONNECTION_MESSAGES = {
|
|
444
|
+
CONNECTING: "Connecting to wallet...",
|
|
445
|
+
SIGNING: "Please sign the message to verify your account",
|
|
446
|
+
SUCCESS: "Successfully connected",
|
|
447
|
+
ERROR: "Connection failed",
|
|
448
|
+
CONNECTED_NOT_SIGNED: "Connected but signature rejected"
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
// lib/crypto.ts
|
|
452
|
+
function generateNonce() {
|
|
453
|
+
if (typeof window !== "undefined" && window.crypto && window.crypto.getRandomValues) {
|
|
454
|
+
const array = new Uint32Array(1);
|
|
455
|
+
window.crypto.getRandomValues(array);
|
|
456
|
+
return array[0].toString(36) + Date.now().toString(36);
|
|
457
|
+
}
|
|
458
|
+
return Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// lib/config.ts
|
|
462
|
+
var defaultConfig = {
|
|
463
|
+
rpcUrl: {
|
|
464
|
+
testnet: "https://rpc-testnet.supra.com",
|
|
465
|
+
mainnet: "https://rpc-mainnet.supra.com"
|
|
466
|
+
},
|
|
467
|
+
chainId: process.env.NEXT_PUBLIC_SUPRA_CHAIN_ID || DEFAULT_CHAIN_IDS.TESTNET,
|
|
468
|
+
enableLogging: process.env.NODE_ENV === "development",
|
|
469
|
+
balancePollInterval: 3e4,
|
|
470
|
+
walletDetectionTimeout: 3e3
|
|
471
|
+
};
|
|
472
|
+
var config = __spreadValues({}, defaultConfig);
|
|
473
|
+
function initConfig(userConfig) {
|
|
474
|
+
var _a, _b, _c;
|
|
475
|
+
config = {
|
|
476
|
+
rpcUrl: {
|
|
477
|
+
testnet: ((_a = userConfig == null ? void 0 : userConfig.rpcUrl) == null ? void 0 : _a.testnet) || defaultConfig.rpcUrl.testnet,
|
|
478
|
+
mainnet: ((_b = userConfig == null ? void 0 : userConfig.rpcUrl) == null ? void 0 : _b.mainnet) || defaultConfig.rpcUrl.mainnet
|
|
479
|
+
},
|
|
480
|
+
chainId: (userConfig == null ? void 0 : userConfig.chainId) || defaultConfig.chainId,
|
|
481
|
+
enableLogging: (_c = userConfig == null ? void 0 : userConfig.enableLogging) != null ? _c : defaultConfig.enableLogging,
|
|
482
|
+
balancePollInterval: (userConfig == null ? void 0 : userConfig.balancePollInterval) || defaultConfig.balancePollInterval,
|
|
483
|
+
walletDetectionTimeout: (userConfig == null ? void 0 : userConfig.walletDetectionTimeout) || defaultConfig.walletDetectionTimeout
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
function getRpcUrl(chainId) {
|
|
487
|
+
const targetChainId = chainId || config.chainId;
|
|
488
|
+
const isMainnet = targetChainId === DEFAULT_CHAIN_IDS.MAINNET;
|
|
489
|
+
return isMainnet ? config.rpcUrl.mainnet : config.rpcUrl.testnet;
|
|
490
|
+
}
|
|
491
|
+
function getChainId() {
|
|
492
|
+
return config.chainId;
|
|
493
|
+
}
|
|
494
|
+
initConfig();
|
|
495
|
+
|
|
496
|
+
// hooks/useSupraMultiWallet.ts
|
|
497
|
+
var WALLET_CONFIGS = {
|
|
498
|
+
starkey: {
|
|
499
|
+
capabilities: {
|
|
500
|
+
signMessage: true,
|
|
501
|
+
accountSwitching: true,
|
|
502
|
+
networkSwitching: true,
|
|
503
|
+
rawTransactions: true,
|
|
504
|
+
eventListeners: true,
|
|
505
|
+
tokenRevalidation: true
|
|
506
|
+
},
|
|
507
|
+
provider: () => {
|
|
508
|
+
var _a;
|
|
509
|
+
return typeof window !== "undefined" && ((_a = window == null ? void 0 : window.starkey) == null ? void 0 : _a.supra);
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
ribbit: {
|
|
513
|
+
capabilities: {
|
|
514
|
+
signMessage: true,
|
|
515
|
+
accountSwitching: false,
|
|
516
|
+
// Ribbit doesn't support account switching
|
|
517
|
+
networkSwitching: false,
|
|
518
|
+
// Ribbit network switching happens in-app
|
|
519
|
+
rawTransactions: true,
|
|
520
|
+
eventListeners: false,
|
|
521
|
+
tokenRevalidation: false
|
|
522
|
+
// Ribbit doesn't support token revalidation
|
|
523
|
+
},
|
|
524
|
+
provider: () => initSdk()
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
var WALLET_EVENTS = {
|
|
528
|
+
CONNECTED: "wallet-connected",
|
|
529
|
+
PRESIGNED_STATE: "presigned-state",
|
|
530
|
+
POSTSIGNED_STATE: "postsigned-state",
|
|
531
|
+
ERROR: "wallet-error"
|
|
532
|
+
};
|
|
533
|
+
var setStoredWalletType = (walletType) => {
|
|
534
|
+
setStorageItem(STORAGE_KEYS.SELECTED_WALLET, walletType);
|
|
535
|
+
};
|
|
536
|
+
var getStoredWalletType = () => {
|
|
537
|
+
const stored = getStorageItem(STORAGE_KEYS.SELECTED_WALLET);
|
|
538
|
+
if (stored && ["starkey", "ribbit"].includes(stored)) {
|
|
539
|
+
return stored;
|
|
540
|
+
}
|
|
541
|
+
return "starkey";
|
|
542
|
+
};
|
|
543
|
+
var clearStoredWalletType = () => {
|
|
544
|
+
removeStorageItem(STORAGE_KEYS.SELECTED_WALLET);
|
|
545
|
+
};
|
|
546
|
+
var useSupraMultiWallet = () => {
|
|
547
|
+
const router = useRouter();
|
|
548
|
+
const [selectedWallet, setSelectedWallet] = useState("starkey");
|
|
549
|
+
const [walletCapabilities, setWalletCapabilities] = useState(
|
|
550
|
+
WALLET_CONFIGS["starkey"].capabilities
|
|
551
|
+
);
|
|
552
|
+
useEffect(() => {
|
|
553
|
+
const stored = getStoredWalletType();
|
|
554
|
+
if (stored !== "starkey") {
|
|
555
|
+
setSelectedWallet(stored);
|
|
556
|
+
setWalletCapabilities(WALLET_CONFIGS[stored].capabilities);
|
|
557
|
+
}
|
|
558
|
+
}, []);
|
|
559
|
+
const [supraProvider, setSupraProvider] = useState(
|
|
560
|
+
WALLET_CONFIGS.starkey.provider()
|
|
561
|
+
);
|
|
562
|
+
const [ribbitProvider, setRibbitProvider] = useState(
|
|
563
|
+
WALLET_CONFIGS.ribbit.provider()
|
|
564
|
+
);
|
|
565
|
+
const [isExtensionInstalled, setIsExtensionInstalled] = useState(false);
|
|
566
|
+
const [accounts, setAccounts] = useState([]);
|
|
567
|
+
const [networkData, setNetworkData] = useState();
|
|
568
|
+
const [balance, setBalance] = useState("");
|
|
569
|
+
const [loading, setLoading] = useState(false);
|
|
570
|
+
const [justRequestedRelative, setJustRequestedRelative] = useState(false);
|
|
571
|
+
const [transactions, setTransactions] = useState([]);
|
|
572
|
+
const [selectedChainId, setSelectedChainId] = useState("");
|
|
573
|
+
const addTransactions = (hash) => {
|
|
574
|
+
setTransactions((prev) => [{ hash }, ...prev]);
|
|
575
|
+
};
|
|
576
|
+
const getCurrentProvider = () => {
|
|
577
|
+
switch (selectedWallet) {
|
|
578
|
+
case "starkey": {
|
|
579
|
+
return supraProvider;
|
|
580
|
+
}
|
|
581
|
+
case "ribbit": {
|
|
582
|
+
return ribbitProvider;
|
|
583
|
+
}
|
|
584
|
+
default: {
|
|
585
|
+
return supraProvider;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
const checkExtensionInstalled = useCallback(async () => {
|
|
590
|
+
switch (selectedWallet) {
|
|
591
|
+
case "starkey": {
|
|
592
|
+
const provider = WALLET_CONFIGS.starkey.provider();
|
|
593
|
+
setSupraProvider(provider);
|
|
594
|
+
setIsExtensionInstalled(!!provider);
|
|
595
|
+
return !!provider;
|
|
596
|
+
}
|
|
597
|
+
case "ribbit": {
|
|
598
|
+
const provider = WALLET_CONFIGS.ribbit.provider();
|
|
599
|
+
if (!provider) {
|
|
600
|
+
setRibbitProvider(null);
|
|
601
|
+
setIsExtensionInstalled(false);
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
try {
|
|
605
|
+
setRibbitProvider(provider);
|
|
606
|
+
setIsExtensionInstalled(true);
|
|
607
|
+
return true;
|
|
608
|
+
} catch (error) {
|
|
609
|
+
logger.error("Error checking Ribbit wallet readiness", error);
|
|
610
|
+
setRibbitProvider(null);
|
|
611
|
+
setIsExtensionInstalled(false);
|
|
612
|
+
return false;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
default: {
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}, [selectedWallet]);
|
|
620
|
+
const updateAccounts = useCallback(async () => {
|
|
621
|
+
const provider = getCurrentProvider();
|
|
622
|
+
if (!provider) return;
|
|
623
|
+
try {
|
|
624
|
+
switch (selectedWallet) {
|
|
625
|
+
case "starkey": {
|
|
626
|
+
const responseAcc = await provider.account();
|
|
627
|
+
const newAccounts = responseAcc.length > 0 ? responseAcc : [];
|
|
628
|
+
setAccounts(newAccounts);
|
|
629
|
+
if (responseAcc.length > 0) {
|
|
630
|
+
setStorageItem(STORAGE_KEYS.STARKEY_ACCOUNTS, responseAcc[0]);
|
|
631
|
+
}
|
|
632
|
+
if (newAccounts.length > 0) {
|
|
633
|
+
const balance2 = await provider.balance();
|
|
634
|
+
if (balance2) {
|
|
635
|
+
setBalance(`${balance2.formattedBalance} ${balance2.displayUnit}`);
|
|
636
|
+
}
|
|
637
|
+
const networkData2 = await provider.getChainId();
|
|
638
|
+
setNetworkData(networkData2 || {});
|
|
639
|
+
}
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
case "ribbit": {
|
|
643
|
+
const wallet = provider.getWalletInfo();
|
|
644
|
+
if (wallet == null ? void 0 : wallet.connected) {
|
|
645
|
+
setAccounts([wallet.walletAddress]);
|
|
646
|
+
const walletBalanceRequest = {
|
|
647
|
+
chainId: parseInt(getChainId()),
|
|
648
|
+
resourceType: "0x1::supra_coin::SupraCoin",
|
|
649
|
+
decimals: 8
|
|
650
|
+
};
|
|
651
|
+
const balanceStr = await provider.getWalletBalance(walletBalanceRequest);
|
|
652
|
+
logger.debug("Ribbit balance response", { balance: balanceStr });
|
|
653
|
+
setBalance(`${(balanceStr == null ? void 0 : balanceStr.balance) || 0} SUPRA`);
|
|
654
|
+
} else {
|
|
655
|
+
setAccounts([]);
|
|
656
|
+
}
|
|
657
|
+
break;
|
|
658
|
+
}
|
|
659
|
+
default: {
|
|
660
|
+
setAccounts([]);
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
} catch (error) {
|
|
665
|
+
logger.error("Failed to update accounts", error, { walletType: selectedWallet });
|
|
666
|
+
setAccounts([]);
|
|
667
|
+
switch (selectedWallet) {
|
|
668
|
+
case "starkey": {
|
|
669
|
+
removeStorageItem(STORAGE_KEYS.STARKEY_ACCOUNTS);
|
|
670
|
+
break;
|
|
671
|
+
}
|
|
672
|
+
case "ribbit": {
|
|
673
|
+
break;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}, [selectedWallet]);
|
|
678
|
+
useEffect(() => {
|
|
679
|
+
let mounted = true;
|
|
680
|
+
const initProvider = async () => {
|
|
681
|
+
const isInstalled = await checkExtensionInstalled();
|
|
682
|
+
if (mounted && isInstalled) {
|
|
683
|
+
updateAccounts();
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
initProvider();
|
|
687
|
+
return () => {
|
|
688
|
+
mounted = false;
|
|
689
|
+
};
|
|
690
|
+
}, [selectedWallet, checkExtensionInstalled, updateAccounts]);
|
|
691
|
+
useEffect(() => {
|
|
692
|
+
const checkExtension = async () => {
|
|
693
|
+
return await checkExtensionInstalled();
|
|
694
|
+
};
|
|
695
|
+
checkExtension().then((isInstalled) => {
|
|
696
|
+
if (isInstalled && selectedWallet === "ribbit") {
|
|
697
|
+
updateAccounts();
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
const intv = setInterval(async () => {
|
|
701
|
+
const isInstalled = await checkExtension();
|
|
702
|
+
if (isInstalled) {
|
|
703
|
+
clearInterval(intv);
|
|
704
|
+
if (selectedWallet === "ribbit") {
|
|
705
|
+
updateAccounts();
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}, 1e3);
|
|
709
|
+
setTimeout(() => {
|
|
710
|
+
clearInterval(intv);
|
|
711
|
+
}, TIMEOUTS.WALLET_DETECTION_POLL);
|
|
712
|
+
return () => clearInterval(intv);
|
|
713
|
+
}, [selectedWallet, updateAccounts, checkExtensionInstalled]);
|
|
714
|
+
const checkIsExtensionInstalled = useCallback(() => {
|
|
715
|
+
const intervalId = setInterval(async () => {
|
|
716
|
+
const isInstalled = await checkExtensionInstalled();
|
|
717
|
+
if (isInstalled) {
|
|
718
|
+
clearInterval(intervalId);
|
|
719
|
+
updateAccounts();
|
|
720
|
+
}
|
|
721
|
+
}, 500);
|
|
722
|
+
setTimeout(() => clearInterval(intervalId), TIMEOUTS.WALLET_DETECTION_POLL);
|
|
723
|
+
}, [updateAccounts, checkExtensionInstalled]);
|
|
724
|
+
const updateBalance = useCallback(async () => {
|
|
725
|
+
const provider = getCurrentProvider();
|
|
726
|
+
if (!provider || !accounts.length) {
|
|
727
|
+
setBalance("");
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
try {
|
|
731
|
+
switch (selectedWallet) {
|
|
732
|
+
case "starkey": {
|
|
733
|
+
const balance2 = await provider.balance();
|
|
734
|
+
if (balance2) {
|
|
735
|
+
setBalance(`${balance2.formattedBalance} ${balance2.displayUnit}`);
|
|
736
|
+
}
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
case "ribbit": {
|
|
740
|
+
const walletBalanceRequest = {
|
|
741
|
+
chainId: parseInt(getChainId()),
|
|
742
|
+
resourceType: "0x1::supra_coin::SupraCoin",
|
|
743
|
+
decimals: 8
|
|
744
|
+
};
|
|
745
|
+
const balanceStr = await provider.getWalletBalance(
|
|
746
|
+
walletBalanceRequest
|
|
747
|
+
);
|
|
748
|
+
logger.debug("Ribbit balance response", { balance: balanceStr });
|
|
749
|
+
setBalance(`${(balanceStr == null ? void 0 : balanceStr.balance) || 0} SUPRA`);
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
default: {
|
|
753
|
+
setBalance("");
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
} catch (error) {
|
|
758
|
+
logger.error("Failed to update balance", error, { walletType: selectedWallet });
|
|
759
|
+
setBalance("");
|
|
760
|
+
}
|
|
761
|
+
}, [selectedWallet, accounts]);
|
|
762
|
+
const getNetworkData = useCallback(async () => {
|
|
763
|
+
const provider = getCurrentProvider();
|
|
764
|
+
if (!provider) return {};
|
|
765
|
+
try {
|
|
766
|
+
switch (selectedWallet) {
|
|
767
|
+
case "starkey": {
|
|
768
|
+
const data = await provider.getChainId();
|
|
769
|
+
setNetworkData(data || {});
|
|
770
|
+
return data || {};
|
|
771
|
+
}
|
|
772
|
+
case "ribbit": {
|
|
773
|
+
const chainId = parseInt(getChainId());
|
|
774
|
+
const mockNetworkData = { chainId: chainId.toString() };
|
|
775
|
+
setNetworkData(mockNetworkData);
|
|
776
|
+
return mockNetworkData;
|
|
777
|
+
}
|
|
778
|
+
default: {
|
|
779
|
+
setNetworkData({});
|
|
780
|
+
return {};
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
} catch (error) {
|
|
784
|
+
logger.error("Failed to get network data", error, { walletType: selectedWallet });
|
|
785
|
+
setNetworkData({});
|
|
786
|
+
return {};
|
|
787
|
+
}
|
|
788
|
+
}, [selectedWallet]);
|
|
789
|
+
const connectWallet = async (walletType) => {
|
|
790
|
+
if (walletType) {
|
|
791
|
+
updateSelectedWallet(walletType);
|
|
792
|
+
}
|
|
793
|
+
const provider = walletType ? WALLET_CONFIGS[walletType].provider() : getCurrentProvider();
|
|
794
|
+
if (!provider) {
|
|
795
|
+
const error = new WalletNotInstalledError(walletType || selectedWallet);
|
|
796
|
+
logger.warn("Wallet not installed", { walletType: walletType || selectedWallet });
|
|
797
|
+
toast.error(ERROR_MESSAGES.WALLET_NOT_INSTALLED, {
|
|
798
|
+
description: `Please install the ${walletType || selectedWallet} extension`
|
|
799
|
+
});
|
|
800
|
+
return false;
|
|
801
|
+
}
|
|
802
|
+
setLoading(true);
|
|
803
|
+
try {
|
|
804
|
+
switch (walletType || selectedWallet) {
|
|
805
|
+
case "starkey": {
|
|
806
|
+
await provider.connect();
|
|
807
|
+
logger.info("Starkey wallet connection approved");
|
|
808
|
+
await updateAccounts();
|
|
809
|
+
const responseAcc = await provider.account();
|
|
810
|
+
if (responseAcc.length === 0) {
|
|
811
|
+
throw new WalletConnectionError(ERROR_MESSAGES.NO_ACCOUNT_FOUND);
|
|
812
|
+
}
|
|
813
|
+
if (responseAcc.length) {
|
|
814
|
+
setAccounts(responseAcc);
|
|
815
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
816
|
+
setStorageItem(STORAGE_KEYS.STARKEY_ACCOUNTS, responseAcc[0]);
|
|
817
|
+
window.dispatchEvent(
|
|
818
|
+
new CustomEvent(WALLET_EVENTS.PRESIGNED_STATE, {
|
|
819
|
+
detail: {
|
|
820
|
+
timestamp: Date.now(),
|
|
821
|
+
account: responseAcc[0]
|
|
822
|
+
}
|
|
823
|
+
})
|
|
824
|
+
);
|
|
825
|
+
window.dispatchEvent(
|
|
826
|
+
new CustomEvent(WALLET_EVENTS.CONNECTED, {
|
|
827
|
+
detail: {
|
|
828
|
+
timestamp: Date.now(),
|
|
829
|
+
account: responseAcc[0],
|
|
830
|
+
wallet: "starkey"
|
|
831
|
+
}
|
|
832
|
+
})
|
|
833
|
+
);
|
|
834
|
+
try {
|
|
835
|
+
const message = "To verify your account, please sign this message.";
|
|
836
|
+
const nonce = generateNonce();
|
|
837
|
+
const hexMessage = "0x" + Buffer.from(message, "utf8").toString("hex");
|
|
838
|
+
logger.debug("Signature request initiated", { account: responseAcc[0] });
|
|
839
|
+
const signatureResponse = await provider.signMessage({
|
|
840
|
+
message: hexMessage,
|
|
841
|
+
nonce
|
|
842
|
+
});
|
|
843
|
+
if (signatureResponse) {
|
|
844
|
+
logger.info("Signature approved", { account: responseAcc[0] });
|
|
845
|
+
window.dispatchEvent(
|
|
846
|
+
new CustomEvent(WALLET_EVENTS.POSTSIGNED_STATE, {
|
|
847
|
+
detail: {
|
|
848
|
+
timestamp: Date.now(),
|
|
849
|
+
account: responseAcc[0]
|
|
850
|
+
}
|
|
851
|
+
})
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
} catch (signError) {
|
|
855
|
+
const error = new SignMessageError(ERROR_MESSAGES.SIGNING_FAILED, signError);
|
|
856
|
+
logger.error("Signing failed", error, { account: responseAcc[0] });
|
|
857
|
+
window.dispatchEvent(
|
|
858
|
+
new CustomEvent(WALLET_EVENTS.ERROR, {
|
|
859
|
+
detail: {
|
|
860
|
+
timestamp: Date.now(),
|
|
861
|
+
error
|
|
862
|
+
}
|
|
863
|
+
})
|
|
864
|
+
);
|
|
865
|
+
throw error;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
case "ribbit": {
|
|
871
|
+
const dappMetadata = {
|
|
872
|
+
name: "multiwallet",
|
|
873
|
+
description: "NFT Marketplace and Lootbox Platform",
|
|
874
|
+
logo: window.location.origin + "/favicon.ico",
|
|
875
|
+
url: window.location.origin
|
|
876
|
+
};
|
|
877
|
+
const response = await provider.connectToWallet(
|
|
878
|
+
dappMetadata
|
|
879
|
+
);
|
|
880
|
+
if (response == null ? void 0 : response.connected) {
|
|
881
|
+
logger.info("Ribbit wallet connection approved");
|
|
882
|
+
}
|
|
883
|
+
if (response.walletAddress == null) {
|
|
884
|
+
throw new WalletConnectionError(ERROR_MESSAGES.NO_ACCOUNT_FOUND);
|
|
885
|
+
}
|
|
886
|
+
if (response == null ? void 0 : response.connected) {
|
|
887
|
+
await updateAccounts();
|
|
888
|
+
if (response.walletAddress) {
|
|
889
|
+
setAccounts([response.walletAddress]);
|
|
890
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
891
|
+
window.dispatchEvent(
|
|
892
|
+
new CustomEvent(WALLET_EVENTS.PRESIGNED_STATE, {
|
|
893
|
+
detail: {
|
|
894
|
+
timestamp: Date.now(),
|
|
895
|
+
account: response.walletAddress
|
|
896
|
+
}
|
|
897
|
+
})
|
|
898
|
+
);
|
|
899
|
+
window.dispatchEvent(
|
|
900
|
+
new CustomEvent(WALLET_EVENTS.CONNECTED, {
|
|
901
|
+
detail: {
|
|
902
|
+
timestamp: Date.now(),
|
|
903
|
+
account: response.walletAddress,
|
|
904
|
+
wallet: "ribbit"
|
|
905
|
+
}
|
|
906
|
+
})
|
|
907
|
+
);
|
|
908
|
+
try {
|
|
909
|
+
const message = "To verify your account, please sign this message.";
|
|
910
|
+
const nonce = generateNonce();
|
|
911
|
+
const hexMessage = "0x" + Buffer.from(message, "utf8").toString("hex");
|
|
912
|
+
logger.debug("Signature request initiated", { account: response.walletAddress });
|
|
913
|
+
const signatureResponse = await provider.signMessage({
|
|
914
|
+
message: hexMessage,
|
|
915
|
+
nonce: parseInt(nonce),
|
|
916
|
+
chainId: parseInt(getChainId())
|
|
917
|
+
});
|
|
918
|
+
if (signatureResponse && signatureResponse.approved) {
|
|
919
|
+
logger.info("Signature approved", { account: response.walletAddress });
|
|
920
|
+
window.dispatchEvent(
|
|
921
|
+
new CustomEvent(WALLET_EVENTS.POSTSIGNED_STATE, {
|
|
922
|
+
detail: {
|
|
923
|
+
timestamp: Date.now(),
|
|
924
|
+
account: response.walletAddress
|
|
925
|
+
}
|
|
926
|
+
})
|
|
927
|
+
);
|
|
928
|
+
} else {
|
|
929
|
+
throw new SignMessageError(signatureResponse.error || ERROR_MESSAGES.SIGNING_REJECTED);
|
|
930
|
+
}
|
|
931
|
+
} catch (signError) {
|
|
932
|
+
const error = new SignMessageError(ERROR_MESSAGES.SIGNING_FAILED, signError);
|
|
933
|
+
logger.error("Signing failed", error, { account: response.walletAddress });
|
|
934
|
+
window.dispatchEvent(
|
|
935
|
+
new CustomEvent(WALLET_EVENTS.ERROR, {
|
|
936
|
+
detail: {
|
|
937
|
+
timestamp: Date.now(),
|
|
938
|
+
error
|
|
939
|
+
}
|
|
940
|
+
})
|
|
941
|
+
);
|
|
942
|
+
throw error;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
} else {
|
|
946
|
+
throw new WalletConnectionError(ERROR_MESSAGES.CONNECTION_REJECTED);
|
|
947
|
+
}
|
|
948
|
+
break;
|
|
949
|
+
}
|
|
950
|
+
default: {
|
|
951
|
+
throw new WalletConnectionError(
|
|
952
|
+
`${ERROR_MESSAGES.UNSUPPORTED_WALLET}: ${walletType || selectedWallet}`
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
return true;
|
|
957
|
+
} catch (error) {
|
|
958
|
+
const walletError = error instanceof WalletConnectionError ? error : new WalletConnectionError(ERROR_MESSAGES.CONNECTION_FAILED, error);
|
|
959
|
+
logger.error("Wallet connection failed", walletError, {
|
|
960
|
+
walletType: walletType || selectedWallet
|
|
961
|
+
});
|
|
962
|
+
window.dispatchEvent(
|
|
963
|
+
new CustomEvent(WALLET_EVENTS.ERROR, {
|
|
964
|
+
detail: {
|
|
965
|
+
timestamp: Date.now(),
|
|
966
|
+
error: walletError
|
|
967
|
+
}
|
|
968
|
+
})
|
|
969
|
+
);
|
|
970
|
+
return false;
|
|
971
|
+
} finally {
|
|
972
|
+
setLoading(false);
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
const disconnectWallet = async () => {
|
|
976
|
+
const provider = getCurrentProvider();
|
|
977
|
+
if (!provider) return;
|
|
978
|
+
try {
|
|
979
|
+
switch (selectedWallet) {
|
|
980
|
+
case "starkey": {
|
|
981
|
+
await provider.disconnect();
|
|
982
|
+
break;
|
|
983
|
+
}
|
|
984
|
+
case "ribbit": {
|
|
985
|
+
await provider.disconnect();
|
|
986
|
+
break;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
resetWalletData();
|
|
990
|
+
clearStoredWalletType();
|
|
991
|
+
router.push("/");
|
|
992
|
+
} catch (error) {
|
|
993
|
+
logger.error("Wallet disconnect failed", error, { walletType: selectedWallet });
|
|
994
|
+
resetWalletData();
|
|
995
|
+
clearStoredWalletType();
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
const resetWalletData = () => {
|
|
999
|
+
setAccounts([]);
|
|
1000
|
+
setBalance("");
|
|
1001
|
+
setNetworkData({});
|
|
1002
|
+
switch (selectedWallet) {
|
|
1003
|
+
case "starkey": {
|
|
1004
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
1005
|
+
removeStorageItem(STORAGE_KEYS.STARKEY_ACCOUNTS);
|
|
1006
|
+
break;
|
|
1007
|
+
}
|
|
1008
|
+
case "ribbit": {
|
|
1009
|
+
break;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
const getSequenceNumber = async (address) => {
|
|
1014
|
+
const rpcUrl = getRpcUrl();
|
|
1015
|
+
const data = await fetch(`${rpcUrl}/rpc/v1/accounts/${address}`);
|
|
1016
|
+
if (!data.ok) {
|
|
1017
|
+
throw new NetworkError(`Failed to fetch sequence number for ${address}`);
|
|
1018
|
+
}
|
|
1019
|
+
const accountData = await data.json();
|
|
1020
|
+
return accountData.sequence_number;
|
|
1021
|
+
};
|
|
1022
|
+
const sendRawTransaction = async (moduleAddress, moduleName, functionName, params, runTimeParams = [], txExpiryTime = Math.ceil(Date.now() / 1e3) + 3e3) => {
|
|
1023
|
+
const provider = getCurrentProvider();
|
|
1024
|
+
if (!provider || !accounts.length || !moduleAddress || !moduleName || !functionName)
|
|
1025
|
+
return;
|
|
1026
|
+
try {
|
|
1027
|
+
switch (selectedWallet) {
|
|
1028
|
+
case "starkey": {
|
|
1029
|
+
if (!walletCapabilities.rawTransactions) {
|
|
1030
|
+
throw new TransactionError("Raw transactions not supported by current wallet");
|
|
1031
|
+
}
|
|
1032
|
+
let networkData2 = await getNetworkData();
|
|
1033
|
+
const currentChainId = getChainId();
|
|
1034
|
+
if (networkData2.chainId !== currentChainId) {
|
|
1035
|
+
setSelectedChainId(currentChainId);
|
|
1036
|
+
await provider.changeNetwork({
|
|
1037
|
+
chainId: currentChainId
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
const rawTxPayload = [
|
|
1041
|
+
accounts[0],
|
|
1042
|
+
0,
|
|
1043
|
+
// sequence number
|
|
1044
|
+
moduleAddress,
|
|
1045
|
+
moduleName,
|
|
1046
|
+
functionName,
|
|
1047
|
+
runTimeParams,
|
|
1048
|
+
params,
|
|
1049
|
+
{}
|
|
1050
|
+
];
|
|
1051
|
+
const data = await provider.createRawTransactionData(rawTxPayload);
|
|
1052
|
+
const txHash = await provider.sendTransaction({
|
|
1053
|
+
data,
|
|
1054
|
+
from: accounts[0],
|
|
1055
|
+
to: moduleAddress,
|
|
1056
|
+
chainId: currentChainId,
|
|
1057
|
+
value: ""
|
|
1058
|
+
});
|
|
1059
|
+
addTransactions(txHash || "failed");
|
|
1060
|
+
logger.info("Transaction sent successfully", { txHash, walletType: "starkey" });
|
|
1061
|
+
return txHash;
|
|
1062
|
+
}
|
|
1063
|
+
case "ribbit": {
|
|
1064
|
+
if (!walletCapabilities.rawTransactions) {
|
|
1065
|
+
throw new TransactionError("Raw transactions not supported by current wallet");
|
|
1066
|
+
}
|
|
1067
|
+
const currentChainId = getChainId();
|
|
1068
|
+
let chainId = SupraChainId.TESTNET;
|
|
1069
|
+
if (currentChainId === DEFAULT_CHAIN_IDS.TESTNET) {
|
|
1070
|
+
chainId = SupraChainId.TESTNET;
|
|
1071
|
+
} else if (currentChainId === DEFAULT_CHAIN_IDS.MAINNET) {
|
|
1072
|
+
chainId = SupraChainId.MAINNET;
|
|
1073
|
+
}
|
|
1074
|
+
const rawTxnRequest = {
|
|
1075
|
+
sender: accounts[0],
|
|
1076
|
+
// Use actual sender address
|
|
1077
|
+
moduleAddress,
|
|
1078
|
+
// Use provided module address
|
|
1079
|
+
moduleName,
|
|
1080
|
+
// Use provided module name
|
|
1081
|
+
functionName,
|
|
1082
|
+
// Use provided function name
|
|
1083
|
+
typeArgs: runTimeParams,
|
|
1084
|
+
// Use converted runtime parameters
|
|
1085
|
+
args: params || [],
|
|
1086
|
+
// Use provided parameters
|
|
1087
|
+
chainId
|
|
1088
|
+
};
|
|
1089
|
+
const rawTxnBase64 = await provider.createRawTransactionBuffer(rawTxnRequest);
|
|
1090
|
+
const response = await provider.signAndSendRawTransaction({
|
|
1091
|
+
rawTxn: rawTxnBase64,
|
|
1092
|
+
chainId,
|
|
1093
|
+
meta: {
|
|
1094
|
+
description: `Call ${moduleName}::${functionName}`
|
|
1095
|
+
// Dynamic description
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
if (response.approved) {
|
|
1099
|
+
const txHash = response.txHash || response.result || "success";
|
|
1100
|
+
addTransactions(txHash);
|
|
1101
|
+
logger.info("Transaction sent successfully", { txHash, walletType: "ribbit" });
|
|
1102
|
+
return txHash;
|
|
1103
|
+
} else {
|
|
1104
|
+
throw new TransactionError(response.error || ERROR_MESSAGES.TRANSACTION_REJECTED);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
default: {
|
|
1108
|
+
throw new TransactionError(
|
|
1109
|
+
`Raw transactions not supported for wallet: ${selectedWallet}`
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
} catch (error) {
|
|
1114
|
+
const txError = error instanceof TransactionError ? error : new TransactionError(ERROR_MESSAGES.TRANSACTION_FAILED, void 0, error);
|
|
1115
|
+
logger.error("Transaction failed", txError, {
|
|
1116
|
+
walletType: selectedWallet,
|
|
1117
|
+
moduleAddress,
|
|
1118
|
+
moduleName,
|
|
1119
|
+
functionName
|
|
1120
|
+
});
|
|
1121
|
+
throw txError;
|
|
1122
|
+
}
|
|
1123
|
+
};
|
|
1124
|
+
const signMessage = async (message, nonce, account, forceSign = false) => {
|
|
1125
|
+
const provider = getCurrentProvider();
|
|
1126
|
+
if (!provider) return;
|
|
1127
|
+
const secureNonce = nonce || generateNonce();
|
|
1128
|
+
switch (selectedWallet) {
|
|
1129
|
+
case "starkey": {
|
|
1130
|
+
if (!walletCapabilities.signMessage) {
|
|
1131
|
+
throw new SignMessageError("Message signing not supported by current wallet");
|
|
1132
|
+
}
|
|
1133
|
+
if (!accounts.length && !account) return;
|
|
1134
|
+
if (!accounts.length && account) {
|
|
1135
|
+
accounts[0] = account;
|
|
1136
|
+
}
|
|
1137
|
+
if (getStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET) === "true" && !forceSign) {
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "true");
|
|
1141
|
+
try {
|
|
1142
|
+
const hexMessage = "0x" + Buffer.from(message, "utf8").toString("hex");
|
|
1143
|
+
const response = await provider.signMessage({
|
|
1144
|
+
message: hexMessage,
|
|
1145
|
+
nonce: secureNonce
|
|
1146
|
+
});
|
|
1147
|
+
const { publicKey, signature } = response;
|
|
1148
|
+
const verified = nacl.sign.detached.verify(
|
|
1149
|
+
new TextEncoder().encode(message),
|
|
1150
|
+
Uint8Array.from(Buffer.from(signature.slice(2), "hex")),
|
|
1151
|
+
Uint8Array.from(Buffer.from(publicKey.slice(2), "hex"))
|
|
1152
|
+
);
|
|
1153
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
1154
|
+
logger.info("Message signed successfully", { walletType: "starkey" });
|
|
1155
|
+
return __spreadProps(__spreadValues({}, response), { verified });
|
|
1156
|
+
} catch (error) {
|
|
1157
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
1158
|
+
throw new SignMessageError(ERROR_MESSAGES.SIGNING_FAILED, error);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
case "ribbit": {
|
|
1162
|
+
if (!walletCapabilities.signMessage) {
|
|
1163
|
+
throw new SignMessageError("Message signing not supported by current wallet");
|
|
1164
|
+
}
|
|
1165
|
+
if (!accounts.length && !account) return;
|
|
1166
|
+
if (!accounts.length && account) {
|
|
1167
|
+
accounts[0] = account;
|
|
1168
|
+
}
|
|
1169
|
+
if (getStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET) === "true" && !forceSign) {
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "true");
|
|
1173
|
+
try {
|
|
1174
|
+
const hexMessage = "0x" + Buffer.from(message, "utf8").toString("hex");
|
|
1175
|
+
const response = await provider.signMessage({
|
|
1176
|
+
message: hexMessage,
|
|
1177
|
+
nonce: parseInt(secureNonce),
|
|
1178
|
+
chainId: parseInt(getChainId())
|
|
1179
|
+
});
|
|
1180
|
+
if (response.approved && response.publicKey && response.signature) {
|
|
1181
|
+
const { publicKey, signature } = response;
|
|
1182
|
+
const verified = nacl.sign.detached.verify(
|
|
1183
|
+
new TextEncoder().encode(message),
|
|
1184
|
+
Uint8Array.from(Buffer.from(signature.slice(2), "hex")),
|
|
1185
|
+
Uint8Array.from(Buffer.from(publicKey.slice(2), "hex"))
|
|
1186
|
+
);
|
|
1187
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
1188
|
+
logger.info("Message signed successfully", { walletType: "ribbit" });
|
|
1189
|
+
return __spreadProps(__spreadValues({}, response), { verified });
|
|
1190
|
+
} else {
|
|
1191
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
1192
|
+
throw new SignMessageError(response.error || ERROR_MESSAGES.SIGNING_REJECTED);
|
|
1193
|
+
}
|
|
1194
|
+
} catch (error) {
|
|
1195
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
1196
|
+
throw new SignMessageError(ERROR_MESSAGES.SIGNING_FAILED, error);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
default: {
|
|
1200
|
+
throw new SignMessageError(
|
|
1201
|
+
`Message signing not supported for wallet: ${selectedWallet}`
|
|
1202
|
+
);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
useEffect(() => {
|
|
1207
|
+
if (selectedWallet === "starkey" && walletCapabilities.eventListeners) {
|
|
1208
|
+
const handleExtensionEvents = (event) => {
|
|
1209
|
+
var _a, _b, _c;
|
|
1210
|
+
if ((_b = (_a = event == null ? void 0 : event.data) == null ? void 0 : _a.name) == null ? void 0 : _b.startsWith("starkey-")) {
|
|
1211
|
+
switch ((_c = event == null ? void 0 : event.data) == null ? void 0 : _c.name) {
|
|
1212
|
+
case "starkey-extension-installed": {
|
|
1213
|
+
checkIsExtensionInstalled();
|
|
1214
|
+
break;
|
|
1215
|
+
}
|
|
1216
|
+
case "starkey-wallet-updated": {
|
|
1217
|
+
(async () => {
|
|
1218
|
+
const responseAcc = await supraProvider.account();
|
|
1219
|
+
if (responseAcc.length) {
|
|
1220
|
+
setAccounts(responseAcc);
|
|
1221
|
+
window.dispatchEvent(
|
|
1222
|
+
new CustomEvent(WALLET_EVENTS.CONNECTED, {
|
|
1223
|
+
detail: {
|
|
1224
|
+
timestamp: Date.now(),
|
|
1225
|
+
account: responseAcc[0]
|
|
1226
|
+
}
|
|
1227
|
+
})
|
|
1228
|
+
);
|
|
1229
|
+
await updateBalance();
|
|
1230
|
+
await getNetworkData();
|
|
1231
|
+
} else {
|
|
1232
|
+
logger.debug("Starkey wallet updated: No accounts found - Resetting");
|
|
1233
|
+
resetWalletData();
|
|
1234
|
+
}
|
|
1235
|
+
setLoading(false);
|
|
1236
|
+
})();
|
|
1237
|
+
break;
|
|
1238
|
+
}
|
|
1239
|
+
case "starkey-wallet-disconnected": {
|
|
1240
|
+
resetWalletData();
|
|
1241
|
+
router.push("/");
|
|
1242
|
+
setLoading(false);
|
|
1243
|
+
break;
|
|
1244
|
+
}
|
|
1245
|
+
case "starkey-window-removed": {
|
|
1246
|
+
setLoading(false);
|
|
1247
|
+
break;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
};
|
|
1252
|
+
checkIsExtensionInstalled();
|
|
1253
|
+
window.addEventListener("message", handleExtensionEvents);
|
|
1254
|
+
return () => window.removeEventListener("message", handleExtensionEvents);
|
|
1255
|
+
}
|
|
1256
|
+
}, [selectedWallet, walletCapabilities, supraProvider]);
|
|
1257
|
+
const getAvailableWallets = useCallback(() => {
|
|
1258
|
+
const availableWallets = [];
|
|
1259
|
+
Object.entries(WALLET_CONFIGS).forEach(([walletType, config2]) => {
|
|
1260
|
+
const provider = config2.provider();
|
|
1261
|
+
const isInstalled = !!provider;
|
|
1262
|
+
switch (walletType) {
|
|
1263
|
+
case "starkey": {
|
|
1264
|
+
availableWallets.push({
|
|
1265
|
+
type: "starkey",
|
|
1266
|
+
name: "Starkey Wallet",
|
|
1267
|
+
isInstalled,
|
|
1268
|
+
capabilities: config2.capabilities
|
|
1269
|
+
});
|
|
1270
|
+
break;
|
|
1271
|
+
}
|
|
1272
|
+
case "ribbit": {
|
|
1273
|
+
availableWallets.push({
|
|
1274
|
+
type: "ribbit",
|
|
1275
|
+
name: "Ribbit Wallet",
|
|
1276
|
+
isInstalled,
|
|
1277
|
+
capabilities: config2.capabilities
|
|
1278
|
+
});
|
|
1279
|
+
break;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
});
|
|
1283
|
+
return availableWallets;
|
|
1284
|
+
}, []);
|
|
1285
|
+
const updateSelectedWallet = (walletType) => {
|
|
1286
|
+
setSelectedWallet(walletType);
|
|
1287
|
+
setWalletCapabilities(WALLET_CONFIGS[walletType].capabilities);
|
|
1288
|
+
setStoredWalletType(walletType);
|
|
1289
|
+
};
|
|
1290
|
+
return {
|
|
1291
|
+
// New wallet selection functionality
|
|
1292
|
+
selectedWallet,
|
|
1293
|
+
walletCapabilities,
|
|
1294
|
+
getAvailableWallets,
|
|
1295
|
+
// Add this new function
|
|
1296
|
+
// Existing interface (unchanged)
|
|
1297
|
+
getCurrentProvider,
|
|
1298
|
+
isExtensionInstalled,
|
|
1299
|
+
accounts,
|
|
1300
|
+
networkData,
|
|
1301
|
+
balance,
|
|
1302
|
+
transactions,
|
|
1303
|
+
selectedChainId,
|
|
1304
|
+
connectWallet,
|
|
1305
|
+
// Now accepts optional walletType parameter
|
|
1306
|
+
disconnectWallet,
|
|
1307
|
+
sendRawTransaction,
|
|
1308
|
+
signMessage,
|
|
1309
|
+
setSelectedChainId,
|
|
1310
|
+
// switchToChain,
|
|
1311
|
+
loading
|
|
1312
|
+
// authFetch,
|
|
1313
|
+
// checkAndRevalidateToken,
|
|
1314
|
+
// signIn,
|
|
1315
|
+
};
|
|
1316
|
+
};
|
|
1317
|
+
var useSupraMultiWallet_default = useSupraMultiWallet;
|
|
1318
|
+
|
|
1319
|
+
// src/assets/walletIcons/Starkey.png
|
|
1320
|
+
var Starkey_default = "data:image/png;base64,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";
|
|
1321
|
+
|
|
1322
|
+
// src/assets/walletIcons/Ribbit.jpg
|
|
1323
|
+
var Ribbit_default = "data:image/jpeg;base64,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XgUI/Cojt9XIq+0ORb6HugAg2KoXeUjjgUFiuBhegVf2soPalH3iGy1MdeAQjvEhlQZGa6UlbArMZbhRt2mXIkRhKkSO197XztIncgu5vVOXIhEu/mqFIAoYZbcdfW2JpWja8llrSm2ZdpJES5KC1gmj7uTSkkSEy3eybKcy/OazhtEuSwAvoMGuF1TCmwpeXRMauXQSipW+MY879q9qv84xrBnofuj33gCjGoDhVhnekocsnAVLWN7bxnba4FTExP2dDDUQGLRa5QXVMKTDrxdExpQ4GES7YKMl9X+rMZSzkdx3a7RZ5tXKArQJ97TRWZuCx/Z7RpyMGS56eKWa2R3g+vllRZoNUr6o2chJmvennaSq2MxFz+y2pH9xX0u7Fbg8BPqlduK2pWQgLMufW2MEUgyAg8vSke6dZ9fKwdxXc9VPICdQiHwddsNBlZkXHva9pnDzH00YX1Duopc3Uin9bW9eds6iSOejVnicQ8Mas8bgPjU0KW5GhR+2NPxx5/LMz/ANfNTxpZro1x8YPhVljcA8alxS3TQ22WR05bvdCBcrvut53JyLWhwsBShj7iwff8XvyluMwNM6AAQFx8p43FYjTVC4D3a/x+nm5qBiRAYUGcKDXdbIjMmL+DrsvYehTpaLz0iufDd7oCJGSA91A2bbuflok7QCA+cRFQORoaM7cE4UeHGu90JLHIAoU6NHmb3tRtfgEBs/DAHrf13QEZHxloirGNdflaLZbgAibeZTK5CWCMPikYuE+JVBW/Dm2JsefyqcMSwF1IiISzc7hw7QvzGjLBGwRzLpoKjmVIlaEsqzfmFqBH13MbieSzfwYSrwTuafBlGDUJGGMMR130/OD7Cll3RzEtVu/wB99lavaLsTpd13UqFkLT62u945LD8NLLLu8IvsvuPmVckWWTeLuWBt+1p9LZRtXebXM1eIU6S7v32USVrpBunHf65VFzWssbPVw4FY75qMtaEEG/7BQsZyR6Grg4xp0JSTzR88KNHzwiVLQkYLQ6AMIHY+6dsHifdBNr8lM2boPtTsaUfOKjQTk9BOuTZo2S9MqXndfrTozn/0dqw0lD/TpSJavSV/8OXOp+HUal/sB//aAAwDAQACAAMAAAAQ888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888880V0ms888jqr9788888888888pzDl+e9A8k/hDxo8888888888d8+o/9999959q848888888888bmL999999950m+m888888888D+PNN994109989f/APPPPPPPPPE//ffffb3fffffffv/ADzzzzzzzzz3333333333333jzzzzzzzzzyXT333333333337PzzzzzzzzzzzQrPjTLvfnfaZDzzzzzzzzzzzzzzyyzzzyw1zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz/8QAJhEBAAIBAgQHAQEAAAAAAAAAAQARITFBIDBRYRBwcZGhscFAgf/aAAgBAwEBPxDzOPELehE5o9o1C9yI0V32g3wALYY0L7ymP4mUuP8ALh9j0deZUo1dIcG26jEG/wAjstSVNr6j1fid99p3fiNsPtGM7wDFr9htu4LneWHLtHYvg07jBgmLt9cQNfSNO4xV4ezHl+k8NJiaTzFss734lA7Q18ppPMZJiXbvXKWsx2hDOYNCKW78QAZYJjzpHGoeKGcwaEQtxDdt+VfF0eNHapgjJmIrdeIl6305TIbbc5RNjXmHEaTHXmURlJa78wBQsmUdTZ79JqC9oM0E0/8AEOzNuuaqEE0mkqIyq9JVmv4a4aPLn//EACkRAQACAAMGBgMBAAAAAAAAAAEAESExQTBRYXGBsRAgkaHR4XDB8ED/2gAIAQIBAT8Q/JztDuD97piRjoveX4x3IRYC2/SCJZ5AClEZpvi/EtRbwD4mOgOYP90mkomY4O0YAZuBBKM9XfDLqjkQ8dSIM4lXO0O76iX0Zxn0mBm9GLou6ZzDAZNd2GXZCxamTKl67OzdE+4eCy0VXKoUtWfKEKOHbzAcW5jWaMuUCWq75V4B0D6n1s6E3Y8rYfexlfTE1M4497ny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";
|
|
1324
|
+
|
|
1325
|
+
// src/components/ConnectWalletHandler.tsx
|
|
1326
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1327
|
+
var PROFILE_CACHE_KEY = STORAGE_KEYS.USER_PROFILE_CACHE;
|
|
1328
|
+
var PROFILE_CACHE_TIMESTAMP_KEY = STORAGE_KEYS.USER_PROFILE_CACHE_TIMESTAMP;
|
|
1329
|
+
var WALLET_INFO = {
|
|
1330
|
+
starkey: {
|
|
1331
|
+
name: "Starkey Wallet",
|
|
1332
|
+
icon: /* @__PURE__ */ jsx3(
|
|
1333
|
+
"img",
|
|
1334
|
+
{
|
|
1335
|
+
src: Starkey_default,
|
|
1336
|
+
alt: "Starkey Wallet",
|
|
1337
|
+
className: "w-10 h-10 rounded-full"
|
|
1338
|
+
}
|
|
1339
|
+
),
|
|
1340
|
+
downloadUrl: WALLET_DOWNLOAD_URLS.starkey
|
|
1341
|
+
},
|
|
1342
|
+
ribbit: {
|
|
1343
|
+
name: "Ribbit Wallet",
|
|
1344
|
+
icon: /* @__PURE__ */ jsx3(
|
|
1345
|
+
"img",
|
|
1346
|
+
{
|
|
1347
|
+
src: Ribbit_default,
|
|
1348
|
+
alt: "Ribbit Wallet",
|
|
1349
|
+
className: "w-10 h-10 rounded-full"
|
|
1350
|
+
}
|
|
1351
|
+
),
|
|
1352
|
+
downloadUrl: WALLET_DOWNLOAD_URLS.ribbit
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
var ConnectWalletHandler = ({
|
|
1356
|
+
onConnect,
|
|
1357
|
+
onDisconnect,
|
|
1358
|
+
children
|
|
1359
|
+
}) => {
|
|
1360
|
+
const starKeyWalletHook = useSupraMultiWallet_default();
|
|
1361
|
+
const getAvailableWallets = starKeyWalletHook.getAvailableWallets;
|
|
1362
|
+
const [loading, setLoading] = useState2(false);
|
|
1363
|
+
const [showWalletModal, setShowWalletModal] = useState2(false);
|
|
1364
|
+
const [userProfile, setUserProfile] = useState2(null);
|
|
1365
|
+
const [walletBalance, setWalletBalance] = useState2("0.00");
|
|
1366
|
+
const [availableWallets, setAvailableWallets] = useState2([]);
|
|
1367
|
+
const [recentWallet, setRecentWallet] = useState2(null);
|
|
1368
|
+
const [selectedWallet, setSelectedWallet] = useState2(null);
|
|
1369
|
+
const [hoveredWallet, setHoveredWallet] = useState2(null);
|
|
1370
|
+
const [connectionStage, setConnectionStage] = useState2("idle");
|
|
1371
|
+
const [connectionStageStartTime, setConnectionStageStartTime] = useState2(null);
|
|
1372
|
+
const [canClickOutside, setCanClickOutside] = useState2(false);
|
|
1373
|
+
const getProfileFromCache = useCallback2(() => {
|
|
1374
|
+
try {
|
|
1375
|
+
if (typeof window === "undefined") return null;
|
|
1376
|
+
const cachedData = getStorageItem(PROFILE_CACHE_KEY);
|
|
1377
|
+
const timestamp = getStorageItem(PROFILE_CACHE_TIMESTAMP_KEY);
|
|
1378
|
+
if (!cachedData || !timestamp) return null;
|
|
1379
|
+
const now = Date.now();
|
|
1380
|
+
const cacheTime = parseInt(timestamp);
|
|
1381
|
+
if (now - cacheTime > CACHE_TTL.PROFILE) {
|
|
1382
|
+
return null;
|
|
1383
|
+
}
|
|
1384
|
+
return JSON.parse(cachedData);
|
|
1385
|
+
} catch (error) {
|
|
1386
|
+
logger.error("Failed to read profile from cache", error);
|
|
1387
|
+
return null;
|
|
1388
|
+
}
|
|
1389
|
+
}, []);
|
|
1390
|
+
const updateWalletBalance = useCallback2(async () => {
|
|
1391
|
+
const provider = starKeyWalletHook.getCurrentProvider();
|
|
1392
|
+
if (!provider) return;
|
|
1393
|
+
try {
|
|
1394
|
+
await new Promise((resolve) => setTimeout(resolve, 1));
|
|
1395
|
+
switch (starKeyWalletHook.selectedWallet) {
|
|
1396
|
+
case "starkey": {
|
|
1397
|
+
const balance = await provider.balance();
|
|
1398
|
+
if (balance && balance.formattedBalance) {
|
|
1399
|
+
setWalletBalance(balance.formattedBalance);
|
|
1400
|
+
}
|
|
1401
|
+
break;
|
|
1402
|
+
}
|
|
1403
|
+
case "ribbit": {
|
|
1404
|
+
const walletBalanceRequest = {
|
|
1405
|
+
chainId: parseInt(process.env.NEXT_PUBLIC_SUPRA_CHAIN_ID || "6"),
|
|
1406
|
+
resourceType: "0x1::supra_coin::SupraCoin",
|
|
1407
|
+
decimals: 8
|
|
1408
|
+
};
|
|
1409
|
+
try {
|
|
1410
|
+
const balance = await provider.getWalletBalance(walletBalanceRequest);
|
|
1411
|
+
const balanceStr = balance.balance;
|
|
1412
|
+
logger.debug("Ribbit balance fetched", { balance: balanceStr });
|
|
1413
|
+
if (balanceStr) {
|
|
1414
|
+
setWalletBalance(balanceStr);
|
|
1415
|
+
}
|
|
1416
|
+
} catch (error) {
|
|
1417
|
+
logger.error("Failed to fetch Ribbit balance", error);
|
|
1418
|
+
}
|
|
1419
|
+
break;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
} catch (error) {
|
|
1423
|
+
logger.error("Failed to update wallet balance", error);
|
|
1424
|
+
}
|
|
1425
|
+
}, [starKeyWalletHook.selectedWallet, starKeyWalletHook.getCurrentProvider]);
|
|
1426
|
+
const connectWallet = useCallback2(async (walletType) => {
|
|
1427
|
+
if (walletType) {
|
|
1428
|
+
setLoading(true);
|
|
1429
|
+
setSelectedWallet(walletType);
|
|
1430
|
+
setConnectionStage("connecting");
|
|
1431
|
+
try {
|
|
1432
|
+
const success = await starKeyWalletHook.connectWallet(walletType);
|
|
1433
|
+
if (success) {
|
|
1434
|
+
setStorageItem(STORAGE_KEYS.RECENT_WALLET, walletType);
|
|
1435
|
+
setRecentWallet(walletType);
|
|
1436
|
+
if (starKeyWalletHook.accounts.length > 0) {
|
|
1437
|
+
onConnect == null ? void 0 : onConnect(starKeyWalletHook.accounts[0]);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
} catch (error) {
|
|
1441
|
+
logger.error("Failed to connect wallet", error, { walletType });
|
|
1442
|
+
toast2.error(`Connection failed: ${error.message || "Unknown error"}`);
|
|
1443
|
+
setConnectionStage("idle");
|
|
1444
|
+
} finally {
|
|
1445
|
+
setLoading(false);
|
|
1446
|
+
}
|
|
1447
|
+
} else {
|
|
1448
|
+
handleConnectClick();
|
|
1449
|
+
}
|
|
1450
|
+
}, [starKeyWalletHook, onConnect]);
|
|
1451
|
+
const handleConnectClick = () => {
|
|
1452
|
+
const installedWallets = availableWallets.filter((w) => w.isInstalled);
|
|
1453
|
+
if (installedWallets.length === 0) {
|
|
1454
|
+
setShowWalletModal(true);
|
|
1455
|
+
} else if (installedWallets.length === 1) {
|
|
1456
|
+
setShowWalletModal(true);
|
|
1457
|
+
} else {
|
|
1458
|
+
setShowWalletModal(true);
|
|
1459
|
+
}
|
|
1460
|
+
};
|
|
1461
|
+
const handleDisconnectWallet = useCallback2(async () => {
|
|
1462
|
+
setLoading(true);
|
|
1463
|
+
try {
|
|
1464
|
+
await starKeyWalletHook.disconnectWallet();
|
|
1465
|
+
setUserProfile(null);
|
|
1466
|
+
setWalletBalance("0.00");
|
|
1467
|
+
onDisconnect == null ? void 0 : onDisconnect();
|
|
1468
|
+
} catch (error) {
|
|
1469
|
+
logger.error("Failed to disconnect wallet", error);
|
|
1470
|
+
} finally {
|
|
1471
|
+
setLoading(false);
|
|
1472
|
+
}
|
|
1473
|
+
}, [starKeyWalletHook, onDisconnect]);
|
|
1474
|
+
const getConnectionStageInfo = useCallback2(() => {
|
|
1475
|
+
const wallet = selectedWallet ? WALLET_INFO[selectedWallet] : null;
|
|
1476
|
+
switch (connectionStage) {
|
|
1477
|
+
case "connecting":
|
|
1478
|
+
return {
|
|
1479
|
+
title: `Waiting for ${(wallet == null ? void 0 : wallet.name) || "Wallet"}`,
|
|
1480
|
+
subtitle: CONNECTION_MESSAGES.CONNECTING,
|
|
1481
|
+
buttonText: "Connecting"
|
|
1482
|
+
};
|
|
1483
|
+
case "signing":
|
|
1484
|
+
return {
|
|
1485
|
+
title: "Sign to verify",
|
|
1486
|
+
subtitle: CONNECTION_MESSAGES.SIGNING,
|
|
1487
|
+
buttonText: "Signing"
|
|
1488
|
+
};
|
|
1489
|
+
case "success":
|
|
1490
|
+
return {
|
|
1491
|
+
title: `Connected to ${(wallet == null ? void 0 : wallet.name.replace(" Wallet", "")) || "Wallet"}`,
|
|
1492
|
+
subtitle: CONNECTION_MESSAGES.SUCCESS,
|
|
1493
|
+
buttonText: "Connected"
|
|
1494
|
+
};
|
|
1495
|
+
case "error":
|
|
1496
|
+
return {
|
|
1497
|
+
title: "Error",
|
|
1498
|
+
subtitle: CONNECTION_MESSAGES.ERROR,
|
|
1499
|
+
buttonText: "Close"
|
|
1500
|
+
};
|
|
1501
|
+
case "connected-not-signed":
|
|
1502
|
+
return {
|
|
1503
|
+
title: `Connected to ${(wallet == null ? void 0 : wallet.name.replace(" Wallet", "")) || "Wallet"}`,
|
|
1504
|
+
subtitle: CONNECTION_MESSAGES.CONNECTED_NOT_SIGNED,
|
|
1505
|
+
buttonText: "Connected"
|
|
1506
|
+
};
|
|
1507
|
+
default:
|
|
1508
|
+
return null;
|
|
1509
|
+
}
|
|
1510
|
+
}, [connectionStage, selectedWallet]);
|
|
1511
|
+
useEffect2(() => {
|
|
1512
|
+
const recent = getStorageItem(STORAGE_KEYS.RECENT_WALLET);
|
|
1513
|
+
if (recent && ["starkey", "ribbit"].includes(recent)) {
|
|
1514
|
+
setRecentWallet(recent);
|
|
1515
|
+
}
|
|
1516
|
+
}, []);
|
|
1517
|
+
useEffect2(() => {
|
|
1518
|
+
const checkWallets = () => {
|
|
1519
|
+
const wallets = getAvailableWallets();
|
|
1520
|
+
setAvailableWallets(wallets);
|
|
1521
|
+
};
|
|
1522
|
+
checkWallets();
|
|
1523
|
+
const interval = setInterval(checkWallets, TIMEOUTS.WALLET_CHECK_INTERVAL);
|
|
1524
|
+
const timeout = setTimeout(() => clearInterval(interval), TIMEOUTS.WALLET_CHECK_MAX_DURATION);
|
|
1525
|
+
return () => {
|
|
1526
|
+
clearInterval(interval);
|
|
1527
|
+
clearTimeout(timeout);
|
|
1528
|
+
};
|
|
1529
|
+
}, [getAvailableWallets]);
|
|
1530
|
+
useEffect2(() => {
|
|
1531
|
+
if (starKeyWalletHook.accounts.length > 0) {
|
|
1532
|
+
updateWalletBalance();
|
|
1533
|
+
}
|
|
1534
|
+
}, [starKeyWalletHook.accounts, starKeyWalletHook.selectedWallet]);
|
|
1535
|
+
useEffect2(() => {
|
|
1536
|
+
const handlePresignedState = () => {
|
|
1537
|
+
setConnectionStage(() => "signing");
|
|
1538
|
+
};
|
|
1539
|
+
const handlePostsignedState = () => {
|
|
1540
|
+
setConnectionStage("success");
|
|
1541
|
+
setTimeout(() => {
|
|
1542
|
+
setConnectionStage("idle");
|
|
1543
|
+
setShowWalletModal(false);
|
|
1544
|
+
updateWalletBalance();
|
|
1545
|
+
}, TIMEOUTS.MODAL_CLOSE_DELAY);
|
|
1546
|
+
};
|
|
1547
|
+
const handleWalletError = () => {
|
|
1548
|
+
if (connectionStage == "signing") {
|
|
1549
|
+
setConnectionStage(() => "connected-not-signed");
|
|
1550
|
+
} else {
|
|
1551
|
+
setConnectionStage(() => "error");
|
|
1552
|
+
}
|
|
1553
|
+
setTimeout(() => {
|
|
1554
|
+
setShowWalletModal(false);
|
|
1555
|
+
setSelectedWallet(null);
|
|
1556
|
+
setConnectionStage("idle");
|
|
1557
|
+
setLoading(false);
|
|
1558
|
+
}, TIMEOUTS.MODAL_CLOSE_DELAY);
|
|
1559
|
+
};
|
|
1560
|
+
const handleStarkeyEvents = (event) => {
|
|
1561
|
+
var _a, _b, _c;
|
|
1562
|
+
if ((_b = (_a = event == null ? void 0 : event.data) == null ? void 0 : _a.name) == null ? void 0 : _b.startsWith("starkey-")) {
|
|
1563
|
+
switch ((_c = event == null ? void 0 : event.data) == null ? void 0 : _c.name) {
|
|
1564
|
+
case "starkey-wallet-updated":
|
|
1565
|
+
case "starkey-wallet-connected":
|
|
1566
|
+
setTimeout(updateWalletBalance, 1);
|
|
1567
|
+
break;
|
|
1568
|
+
case "starkey-wallet-disconnected":
|
|
1569
|
+
setWalletBalance("0.00");
|
|
1570
|
+
break;
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
};
|
|
1574
|
+
window.addEventListener("presigned-state", handlePresignedState);
|
|
1575
|
+
window.addEventListener("postsigned-state", handlePostsignedState);
|
|
1576
|
+
window.addEventListener("wallet-error", handleWalletError);
|
|
1577
|
+
window.addEventListener("message", handleStarkeyEvents);
|
|
1578
|
+
return () => {
|
|
1579
|
+
window.removeEventListener("presigned-state", handlePresignedState);
|
|
1580
|
+
window.removeEventListener("postsigned-state", handlePostsignedState);
|
|
1581
|
+
window.removeEventListener("wallet-error", handleWalletError);
|
|
1582
|
+
window.removeEventListener("message", handleStarkeyEvents);
|
|
1583
|
+
};
|
|
1584
|
+
}, [connectionStage]);
|
|
1585
|
+
useEffect2(() => {
|
|
1586
|
+
const handleProfileUpdated = (event) => {
|
|
1587
|
+
const { address, username, profileImage } = event.detail;
|
|
1588
|
+
if (starKeyWalletHook.accounts[0] === address) {
|
|
1589
|
+
setUserProfile({ address, username, profileImage });
|
|
1590
|
+
}
|
|
1591
|
+
};
|
|
1592
|
+
window.addEventListener("profile-updated", handleProfileUpdated);
|
|
1593
|
+
return () => {
|
|
1594
|
+
window.removeEventListener("profile-updated", handleProfileUpdated);
|
|
1595
|
+
};
|
|
1596
|
+
}, [starKeyWalletHook.accounts]);
|
|
1597
|
+
useEffect2(() => {
|
|
1598
|
+
if (starKeyWalletHook.accounts.length > 0) {
|
|
1599
|
+
const handleVisibilityChange = () => {
|
|
1600
|
+
if (!document.hidden) {
|
|
1601
|
+
updateWalletBalance();
|
|
1602
|
+
}
|
|
1603
|
+
};
|
|
1604
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
1605
|
+
const balanceInterval = setInterval(() => {
|
|
1606
|
+
if (!document.hidden) {
|
|
1607
|
+
updateWalletBalance();
|
|
1608
|
+
}
|
|
1609
|
+
}, TIMEOUTS.BALANCE_POLL_INTERVAL);
|
|
1610
|
+
return () => {
|
|
1611
|
+
clearInterval(balanceInterval);
|
|
1612
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
}, [starKeyWalletHook.accounts, updateWalletBalance]);
|
|
1616
|
+
useEffect2(() => {
|
|
1617
|
+
if (connectionStage === "connecting" || connectionStage === "signing") {
|
|
1618
|
+
setConnectionStageStartTime(Date.now());
|
|
1619
|
+
setCanClickOutside(false);
|
|
1620
|
+
const timer = setTimeout(() => {
|
|
1621
|
+
setCanClickOutside(true);
|
|
1622
|
+
}, TIMEOUTS.CLICK_OUTSIDE_DELAY);
|
|
1623
|
+
return () => clearTimeout(timer);
|
|
1624
|
+
} else {
|
|
1625
|
+
setConnectionStageStartTime(null);
|
|
1626
|
+
setCanClickOutside(false);
|
|
1627
|
+
}
|
|
1628
|
+
}, [connectionStage]);
|
|
1629
|
+
const handleModalClose = useCallback2((open) => {
|
|
1630
|
+
if (!open) {
|
|
1631
|
+
if (connectionStage === "idle" || connectionStage === "success" || connectionStage === "connected-not-signed" || connectionStage === "error" || canClickOutside && (connectionStage === "connecting" || connectionStage === "signing")) {
|
|
1632
|
+
setShowWalletModal(false);
|
|
1633
|
+
setSelectedWallet(null);
|
|
1634
|
+
setLoading(false);
|
|
1635
|
+
setCanClickOutside(false);
|
|
1636
|
+
setConnectionStageStartTime(null);
|
|
1637
|
+
setTimeout(() => {
|
|
1638
|
+
setConnectionStage("idle");
|
|
1639
|
+
}, 100);
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
}, [connectionStage, canClickOutside]);
|
|
1643
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1644
|
+
children({
|
|
1645
|
+
isConnected: starKeyWalletHook.accounts.length > 0,
|
|
1646
|
+
accounts: starKeyWalletHook.accounts,
|
|
1647
|
+
loading: loading || starKeyWalletHook.loading,
|
|
1648
|
+
balance: walletBalance,
|
|
1649
|
+
userProfile,
|
|
1650
|
+
handleConnect: handleConnectClick,
|
|
1651
|
+
handleDisconnect: handleDisconnectWallet
|
|
1652
|
+
}),
|
|
1653
|
+
/* @__PURE__ */ jsxs2(
|
|
1654
|
+
Dialog,
|
|
1655
|
+
{
|
|
1656
|
+
open: showWalletModal,
|
|
1657
|
+
onOpenChange: handleModalClose,
|
|
1658
|
+
children: [
|
|
1659
|
+
/* @__PURE__ */ jsx3(VisuallyHidden, { asChild: true, children: /* @__PURE__ */ jsx3(DialogTitle, { children: "Select a wallet" }) }),
|
|
1660
|
+
/* @__PURE__ */ jsx3(VisuallyHidden, { asChild: true, children: /* @__PURE__ */ jsx3(DialogDescription, { children: "Select a wallet to connect to MyDApp" }) }),
|
|
1661
|
+
/* @__PURE__ */ jsxs2(
|
|
1662
|
+
DialogContent,
|
|
1663
|
+
{
|
|
1664
|
+
className: "z-[100] px-4 py-6 w-[90%] mx-auto max-w-sm bg-gradient-to-br from-brand-dark via-gray-900 to-brand-dark border border-brand-dark sm:rounded-3xl rounded-3xl",
|
|
1665
|
+
children: [
|
|
1666
|
+
canClickOutside && (connectionStage === "connecting" || connectionStage === "signing") && /* @__PURE__ */ jsx3("div", { className: "absolute top-4 right-4", children: /* @__PURE__ */ jsx3(X2, { className: "h-5 w-5" }) }),
|
|
1667
|
+
/* @__PURE__ */ jsx3("div", { className: "", children: connectionStage === "idle" ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1668
|
+
/* @__PURE__ */ jsx3("p", { className: "text-center text-sm text-brand-light/75 mb-6 text-white", children: "Select Wallet" }),
|
|
1669
|
+
/* @__PURE__ */ jsx3("div", { className: "space-y-3", children: availableWallets.map((wallet) => {
|
|
1670
|
+
return /* @__PURE__ */ jsx3("div", { className: "w-full relative", children: /* @__PURE__ */ jsxs2(
|
|
1671
|
+
motion.button,
|
|
1672
|
+
{
|
|
1673
|
+
initial: { opacity: 0, y: 20 },
|
|
1674
|
+
animate: { opacity: 1, y: 0 },
|
|
1675
|
+
transition: { duration: 0.05, ease: "easeInOut" },
|
|
1676
|
+
onClick: () => {
|
|
1677
|
+
wallet.isInstalled ? connectWallet(wallet.type) : window.open(WALLET_INFO[wallet.type].downloadUrl, "_blank");
|
|
1678
|
+
},
|
|
1679
|
+
type: "button",
|
|
1680
|
+
disabled: loading && wallet.isInstalled,
|
|
1681
|
+
onMouseEnter: () => setHoveredWallet(wallet.type),
|
|
1682
|
+
onMouseLeave: () => setHoveredWallet(null),
|
|
1683
|
+
className: "w-full px-4 py-2 rounded-2xl border border-gray-950/60 hover:border-gray-800/80 bg-gray-950/20 hover:bg-gray-900/40 transition-all duration-300 flex items-center gap-4 group",
|
|
1684
|
+
children: [
|
|
1685
|
+
/* @__PURE__ */ jsx3("div", { className: "flex-shrink-0", children: WALLET_INFO[wallet.type].icon }),
|
|
1686
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex-1 text-left", children: [
|
|
1687
|
+
/* @__PURE__ */ jsx3("h3", { className: "font-medium text-white", children: WALLET_INFO[wallet.type].name }),
|
|
1688
|
+
!wallet.isInstalled && /* @__PURE__ */ jsx3("p", { className: "text-sm text-gray-400", children: "Not installed - Click to download" })
|
|
1689
|
+
] }),
|
|
1690
|
+
/* @__PURE__ */ jsx3("div", { className: "flex-shrink-0", children: recentWallet === wallet.type && wallet.isInstalled ? /* @__PURE__ */ jsx3("span", { className: "bg-gray-800/60 text-gray-300 text-xs px-3 py-1 rounded-full border border-gray-700/40", children: "Recent" }) : wallet.isInstalled ? loading && wallet.type === selectedWallet ? /* @__PURE__ */ jsx3(Loader2, { className: "h-4 w-4 animate-spin text-gray-400" }) : hoveredWallet === wallet.type && /* @__PURE__ */ jsx3("span", { className: "text-gray-400 text-sm font-medium", children: "Connect" }) : /* @__PURE__ */ jsx3(ExternalLink, { className: "h-4 w-4 text-gray-500" }) })
|
|
1691
|
+
]
|
|
1692
|
+
}
|
|
1693
|
+
) }, wallet.type);
|
|
1694
|
+
}) })
|
|
1695
|
+
] }) : /* @__PURE__ */ jsx3("div", { className: "w-full text-center py-8", children: (() => {
|
|
1696
|
+
const stageInfo = getConnectionStageInfo();
|
|
1697
|
+
const wallet = selectedWallet ? WALLET_INFO[selectedWallet] : null;
|
|
1698
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1699
|
+
/* @__PURE__ */ jsx3("div", { className: "relative flex justify-center mb-6", children: connectionStage === "success" || connectionStage === "connected-not-signed" ? /* @__PURE__ */ jsx3("div", { className: "w-20 h-20 rounded-full border-4 border-green-500 flex items-center justify-center", children: wallet && /* @__PURE__ */ jsx3("div", { className: "w-12 h-12 flex items-center justify-center", children: wallet.icon }) }) : connectionStage === "error" ? /* @__PURE__ */ jsx3("div", { className: "w-20 h-20 rounded-full border-4 border-red-500 flex items-center justify-center", children: wallet && /* @__PURE__ */ jsx3("div", { className: "w-12 h-12 flex items-center justify-center", children: wallet.icon }) }) : /* @__PURE__ */ jsxs2("div", { className: "relative", children: [
|
|
1700
|
+
/* @__PURE__ */ jsx3("div", { className: "w-20 h-20 rounded-full border-4 border-gray-600 border-t-gray-400 animate-spin" }),
|
|
1701
|
+
/* @__PURE__ */ jsx3("div", { className: "absolute inset-0 flex items-center justify-center", children: wallet && /* @__PURE__ */ jsx3("div", { className: "w-12 h-12 flex items-center justify-center", children: wallet.icon }) })
|
|
1702
|
+
] }) }),
|
|
1703
|
+
/* @__PURE__ */ jsx3("h3", { className: "text-lg font-semibold text-white mb-2", children: stageInfo == null ? void 0 : stageInfo.title }),
|
|
1704
|
+
/* @__PURE__ */ jsx3("p", { className: "text-sm text-gray-400 mb-6", children: stageInfo == null ? void 0 : stageInfo.subtitle }),
|
|
1705
|
+
/* @__PURE__ */ jsx3(
|
|
1706
|
+
Button,
|
|
1707
|
+
{
|
|
1708
|
+
disabled: true,
|
|
1709
|
+
className: "w-full bg-gray-700 text-gray-400 cursor-not-allowed rounded-2xl py-3",
|
|
1710
|
+
children: stageInfo == null ? void 0 : stageInfo.buttonText
|
|
1711
|
+
}
|
|
1712
|
+
)
|
|
1713
|
+
] });
|
|
1714
|
+
})() }) })
|
|
1715
|
+
]
|
|
1716
|
+
}
|
|
1717
|
+
)
|
|
1718
|
+
]
|
|
1719
|
+
}
|
|
1720
|
+
)
|
|
1721
|
+
] });
|
|
1722
|
+
};
|
|
1723
|
+
|
|
1724
|
+
// src/hooks/useSupraMultiWallet.ts
|
|
1725
|
+
import { useState as useState3, useEffect as useEffect3, useCallback as useCallback3 } from "react";
|
|
1726
|
+
import nacl2 from "tweetnacl";
|
|
1727
|
+
import { useRouter as useRouter2 } from "next/navigation";
|
|
1728
|
+
import { toast as toast3 } from "sonner";
|
|
1729
|
+
import {
|
|
1730
|
+
SupraChainId as SupraChainId2,
|
|
1731
|
+
initSdk as initSdk2
|
|
1732
|
+
} from "ribbit-wallet-connect";
|
|
1733
|
+
var WALLET_CONFIGS2 = {
|
|
1734
|
+
starkey: {
|
|
1735
|
+
capabilities: {
|
|
1736
|
+
signMessage: true,
|
|
1737
|
+
accountSwitching: true,
|
|
1738
|
+
networkSwitching: true,
|
|
1739
|
+
rawTransactions: true,
|
|
1740
|
+
eventListeners: true,
|
|
1741
|
+
tokenRevalidation: true
|
|
1742
|
+
},
|
|
1743
|
+
provider: () => {
|
|
1744
|
+
var _a;
|
|
1745
|
+
return typeof window !== "undefined" && ((_a = window == null ? void 0 : window.starkey) == null ? void 0 : _a.supra);
|
|
1746
|
+
}
|
|
1747
|
+
},
|
|
1748
|
+
ribbit: {
|
|
1749
|
+
capabilities: {
|
|
1750
|
+
signMessage: true,
|
|
1751
|
+
accountSwitching: false,
|
|
1752
|
+
// Ribbit doesn't support account switching
|
|
1753
|
+
networkSwitching: false,
|
|
1754
|
+
// Ribbit network switching happens in-app
|
|
1755
|
+
rawTransactions: true,
|
|
1756
|
+
eventListeners: false,
|
|
1757
|
+
tokenRevalidation: false
|
|
1758
|
+
// Ribbit doesn't support token revalidation
|
|
1759
|
+
},
|
|
1760
|
+
provider: () => initSdk2()
|
|
1761
|
+
}
|
|
1762
|
+
};
|
|
1763
|
+
var WALLET_EVENTS2 = {
|
|
1764
|
+
CONNECTED: "wallet-connected",
|
|
1765
|
+
PRESIGNED_STATE: "presigned-state",
|
|
1766
|
+
POSTSIGNED_STATE: "postsigned-state",
|
|
1767
|
+
ERROR: "wallet-error"
|
|
1768
|
+
};
|
|
1769
|
+
var setStoredWalletType2 = (walletType) => {
|
|
1770
|
+
setStorageItem(STORAGE_KEYS.SELECTED_WALLET, walletType);
|
|
1771
|
+
};
|
|
1772
|
+
var getStoredWalletType2 = () => {
|
|
1773
|
+
const stored = getStorageItem(STORAGE_KEYS.SELECTED_WALLET);
|
|
1774
|
+
if (stored && ["starkey", "ribbit"].includes(stored)) {
|
|
1775
|
+
return stored;
|
|
1776
|
+
}
|
|
1777
|
+
return "starkey";
|
|
1778
|
+
};
|
|
1779
|
+
var clearStoredWalletType2 = () => {
|
|
1780
|
+
removeStorageItem(STORAGE_KEYS.SELECTED_WALLET);
|
|
1781
|
+
};
|
|
1782
|
+
var useSupraMultiWallet2 = () => {
|
|
1783
|
+
const router = useRouter2();
|
|
1784
|
+
const [selectedWallet, setSelectedWallet] = useState3("starkey");
|
|
1785
|
+
const [walletCapabilities, setWalletCapabilities] = useState3(
|
|
1786
|
+
WALLET_CONFIGS2["starkey"].capabilities
|
|
1787
|
+
);
|
|
1788
|
+
useEffect3(() => {
|
|
1789
|
+
const stored = getStoredWalletType2();
|
|
1790
|
+
if (stored !== "starkey") {
|
|
1791
|
+
setSelectedWallet(stored);
|
|
1792
|
+
setWalletCapabilities(WALLET_CONFIGS2[stored].capabilities);
|
|
1793
|
+
}
|
|
1794
|
+
}, []);
|
|
1795
|
+
const [supraProvider, setSupraProvider] = useState3(
|
|
1796
|
+
WALLET_CONFIGS2.starkey.provider()
|
|
1797
|
+
);
|
|
1798
|
+
const [ribbitProvider, setRibbitProvider] = useState3(
|
|
1799
|
+
WALLET_CONFIGS2.ribbit.provider()
|
|
1800
|
+
);
|
|
1801
|
+
const [isExtensionInstalled, setIsExtensionInstalled] = useState3(false);
|
|
1802
|
+
const [accounts, setAccounts] = useState3([]);
|
|
1803
|
+
const [networkData, setNetworkData] = useState3();
|
|
1804
|
+
const [balance, setBalance] = useState3("");
|
|
1805
|
+
const [loading, setLoading] = useState3(false);
|
|
1806
|
+
const [justRequestedRelative, setJustRequestedRelative] = useState3(false);
|
|
1807
|
+
const [transactions, setTransactions] = useState3([]);
|
|
1808
|
+
const [selectedChainId, setSelectedChainId] = useState3("");
|
|
1809
|
+
const addTransactions = (hash) => {
|
|
1810
|
+
setTransactions((prev) => [{ hash }, ...prev]);
|
|
1811
|
+
};
|
|
1812
|
+
const getCurrentProvider = () => {
|
|
1813
|
+
switch (selectedWallet) {
|
|
1814
|
+
case "starkey": {
|
|
1815
|
+
return supraProvider;
|
|
1816
|
+
}
|
|
1817
|
+
case "ribbit": {
|
|
1818
|
+
return ribbitProvider;
|
|
1819
|
+
}
|
|
1820
|
+
default: {
|
|
1821
|
+
return supraProvider;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
};
|
|
1825
|
+
const checkExtensionInstalled = useCallback3(async () => {
|
|
1826
|
+
switch (selectedWallet) {
|
|
1827
|
+
case "starkey": {
|
|
1828
|
+
const provider = WALLET_CONFIGS2.starkey.provider();
|
|
1829
|
+
setSupraProvider(provider);
|
|
1830
|
+
setIsExtensionInstalled(!!provider);
|
|
1831
|
+
return !!provider;
|
|
1832
|
+
}
|
|
1833
|
+
case "ribbit": {
|
|
1834
|
+
const provider = WALLET_CONFIGS2.ribbit.provider();
|
|
1835
|
+
if (!provider) {
|
|
1836
|
+
setRibbitProvider(null);
|
|
1837
|
+
setIsExtensionInstalled(false);
|
|
1838
|
+
return false;
|
|
1839
|
+
}
|
|
1840
|
+
try {
|
|
1841
|
+
setRibbitProvider(provider);
|
|
1842
|
+
setIsExtensionInstalled(true);
|
|
1843
|
+
return true;
|
|
1844
|
+
} catch (error) {
|
|
1845
|
+
logger.error("Error checking Ribbit wallet readiness", error);
|
|
1846
|
+
setRibbitProvider(null);
|
|
1847
|
+
setIsExtensionInstalled(false);
|
|
1848
|
+
return false;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
default: {
|
|
1852
|
+
return false;
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
}, [selectedWallet]);
|
|
1856
|
+
const updateAccounts = useCallback3(async () => {
|
|
1857
|
+
const provider = getCurrentProvider();
|
|
1858
|
+
if (!provider) return;
|
|
1859
|
+
try {
|
|
1860
|
+
switch (selectedWallet) {
|
|
1861
|
+
case "starkey": {
|
|
1862
|
+
const responseAcc = await provider.account();
|
|
1863
|
+
const newAccounts = responseAcc.length > 0 ? responseAcc : [];
|
|
1864
|
+
setAccounts(newAccounts);
|
|
1865
|
+
if (responseAcc.length > 0) {
|
|
1866
|
+
setStorageItem(STORAGE_KEYS.STARKEY_ACCOUNTS, responseAcc[0]);
|
|
1867
|
+
}
|
|
1868
|
+
if (newAccounts.length > 0) {
|
|
1869
|
+
const balance2 = await provider.balance();
|
|
1870
|
+
if (balance2) {
|
|
1871
|
+
setBalance(`${balance2.formattedBalance} ${balance2.displayUnit}`);
|
|
1872
|
+
}
|
|
1873
|
+
const networkData2 = await provider.getChainId();
|
|
1874
|
+
setNetworkData(networkData2 || {});
|
|
1875
|
+
}
|
|
1876
|
+
break;
|
|
1877
|
+
}
|
|
1878
|
+
case "ribbit": {
|
|
1879
|
+
const wallet = provider.getWalletInfo();
|
|
1880
|
+
if (wallet == null ? void 0 : wallet.connected) {
|
|
1881
|
+
setAccounts([wallet.walletAddress]);
|
|
1882
|
+
const walletBalanceRequest = {
|
|
1883
|
+
chainId: parseInt(getChainId()),
|
|
1884
|
+
resourceType: "0x1::supra_coin::SupraCoin",
|
|
1885
|
+
decimals: 8
|
|
1886
|
+
};
|
|
1887
|
+
const balanceStr = await provider.getWalletBalance(walletBalanceRequest);
|
|
1888
|
+
logger.debug("Ribbit balance response", { balance: balanceStr });
|
|
1889
|
+
setBalance(`${(balanceStr == null ? void 0 : balanceStr.balance) || 0} SUPRA`);
|
|
1890
|
+
} else {
|
|
1891
|
+
setAccounts([]);
|
|
1892
|
+
}
|
|
1893
|
+
break;
|
|
1894
|
+
}
|
|
1895
|
+
default: {
|
|
1896
|
+
setAccounts([]);
|
|
1897
|
+
break;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
} catch (error) {
|
|
1901
|
+
logger.error("Failed to update accounts", error, { walletType: selectedWallet });
|
|
1902
|
+
setAccounts([]);
|
|
1903
|
+
switch (selectedWallet) {
|
|
1904
|
+
case "starkey": {
|
|
1905
|
+
removeStorageItem(STORAGE_KEYS.STARKEY_ACCOUNTS);
|
|
1906
|
+
break;
|
|
1907
|
+
}
|
|
1908
|
+
case "ribbit": {
|
|
1909
|
+
break;
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
}, [selectedWallet]);
|
|
1914
|
+
useEffect3(() => {
|
|
1915
|
+
let mounted = true;
|
|
1916
|
+
const initProvider = async () => {
|
|
1917
|
+
const isInstalled = await checkExtensionInstalled();
|
|
1918
|
+
if (mounted && isInstalled) {
|
|
1919
|
+
updateAccounts();
|
|
1920
|
+
}
|
|
1921
|
+
};
|
|
1922
|
+
initProvider();
|
|
1923
|
+
return () => {
|
|
1924
|
+
mounted = false;
|
|
1925
|
+
};
|
|
1926
|
+
}, [selectedWallet, checkExtensionInstalled, updateAccounts]);
|
|
1927
|
+
useEffect3(() => {
|
|
1928
|
+
const checkExtension = async () => {
|
|
1929
|
+
return await checkExtensionInstalled();
|
|
1930
|
+
};
|
|
1931
|
+
checkExtension().then((isInstalled) => {
|
|
1932
|
+
if (isInstalled && selectedWallet === "ribbit") {
|
|
1933
|
+
updateAccounts();
|
|
1934
|
+
}
|
|
1935
|
+
});
|
|
1936
|
+
const intv = setInterval(async () => {
|
|
1937
|
+
const isInstalled = await checkExtension();
|
|
1938
|
+
if (isInstalled) {
|
|
1939
|
+
clearInterval(intv);
|
|
1940
|
+
if (selectedWallet === "ribbit") {
|
|
1941
|
+
updateAccounts();
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
}, 1e3);
|
|
1945
|
+
setTimeout(() => {
|
|
1946
|
+
clearInterval(intv);
|
|
1947
|
+
}, TIMEOUTS.WALLET_DETECTION_POLL);
|
|
1948
|
+
return () => clearInterval(intv);
|
|
1949
|
+
}, [selectedWallet, updateAccounts, checkExtensionInstalled]);
|
|
1950
|
+
const checkIsExtensionInstalled = useCallback3(() => {
|
|
1951
|
+
const intervalId = setInterval(async () => {
|
|
1952
|
+
const isInstalled = await checkExtensionInstalled();
|
|
1953
|
+
if (isInstalled) {
|
|
1954
|
+
clearInterval(intervalId);
|
|
1955
|
+
updateAccounts();
|
|
1956
|
+
}
|
|
1957
|
+
}, 500);
|
|
1958
|
+
setTimeout(() => clearInterval(intervalId), TIMEOUTS.WALLET_DETECTION_POLL);
|
|
1959
|
+
}, [updateAccounts, checkExtensionInstalled]);
|
|
1960
|
+
const updateBalance = useCallback3(async () => {
|
|
1961
|
+
const provider = getCurrentProvider();
|
|
1962
|
+
if (!provider || !accounts.length) {
|
|
1963
|
+
setBalance("");
|
|
1964
|
+
return;
|
|
1965
|
+
}
|
|
1966
|
+
try {
|
|
1967
|
+
switch (selectedWallet) {
|
|
1968
|
+
case "starkey": {
|
|
1969
|
+
const balance2 = await provider.balance();
|
|
1970
|
+
if (balance2) {
|
|
1971
|
+
setBalance(`${balance2.formattedBalance} ${balance2.displayUnit}`);
|
|
1972
|
+
}
|
|
1973
|
+
break;
|
|
1974
|
+
}
|
|
1975
|
+
case "ribbit": {
|
|
1976
|
+
const walletBalanceRequest = {
|
|
1977
|
+
chainId: parseInt(getChainId()),
|
|
1978
|
+
resourceType: "0x1::supra_coin::SupraCoin",
|
|
1979
|
+
decimals: 8
|
|
1980
|
+
};
|
|
1981
|
+
const balanceStr = await provider.getWalletBalance(
|
|
1982
|
+
walletBalanceRequest
|
|
1983
|
+
);
|
|
1984
|
+
logger.debug("Ribbit balance response", { balance: balanceStr });
|
|
1985
|
+
setBalance(`${(balanceStr == null ? void 0 : balanceStr.balance) || 0} SUPRA`);
|
|
1986
|
+
break;
|
|
1987
|
+
}
|
|
1988
|
+
default: {
|
|
1989
|
+
setBalance("");
|
|
1990
|
+
break;
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
} catch (error) {
|
|
1994
|
+
logger.error("Failed to update balance", error, { walletType: selectedWallet });
|
|
1995
|
+
setBalance("");
|
|
1996
|
+
}
|
|
1997
|
+
}, [selectedWallet, accounts]);
|
|
1998
|
+
const getNetworkData = useCallback3(async () => {
|
|
1999
|
+
const provider = getCurrentProvider();
|
|
2000
|
+
if (!provider) return {};
|
|
2001
|
+
try {
|
|
2002
|
+
switch (selectedWallet) {
|
|
2003
|
+
case "starkey": {
|
|
2004
|
+
const data = await provider.getChainId();
|
|
2005
|
+
setNetworkData(data || {});
|
|
2006
|
+
return data || {};
|
|
2007
|
+
}
|
|
2008
|
+
case "ribbit": {
|
|
2009
|
+
const chainId = parseInt(getChainId());
|
|
2010
|
+
const mockNetworkData = { chainId: chainId.toString() };
|
|
2011
|
+
setNetworkData(mockNetworkData);
|
|
2012
|
+
return mockNetworkData;
|
|
2013
|
+
}
|
|
2014
|
+
default: {
|
|
2015
|
+
setNetworkData({});
|
|
2016
|
+
return {};
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
} catch (error) {
|
|
2020
|
+
logger.error("Failed to get network data", error, { walletType: selectedWallet });
|
|
2021
|
+
setNetworkData({});
|
|
2022
|
+
return {};
|
|
2023
|
+
}
|
|
2024
|
+
}, [selectedWallet]);
|
|
2025
|
+
const connectWallet = async (walletType) => {
|
|
2026
|
+
if (walletType) {
|
|
2027
|
+
updateSelectedWallet(walletType);
|
|
2028
|
+
}
|
|
2029
|
+
const provider = walletType ? WALLET_CONFIGS2[walletType].provider() : getCurrentProvider();
|
|
2030
|
+
if (!provider) {
|
|
2031
|
+
const error = new WalletNotInstalledError(walletType || selectedWallet);
|
|
2032
|
+
logger.warn("Wallet not installed", { walletType: walletType || selectedWallet });
|
|
2033
|
+
toast3.error(ERROR_MESSAGES.WALLET_NOT_INSTALLED, {
|
|
2034
|
+
description: `Please install the ${walletType || selectedWallet} extension`
|
|
2035
|
+
});
|
|
2036
|
+
return false;
|
|
2037
|
+
}
|
|
2038
|
+
setLoading(true);
|
|
2039
|
+
try {
|
|
2040
|
+
switch (walletType || selectedWallet) {
|
|
2041
|
+
case "starkey": {
|
|
2042
|
+
await provider.connect();
|
|
2043
|
+
logger.info("Starkey wallet connection approved");
|
|
2044
|
+
await updateAccounts();
|
|
2045
|
+
const responseAcc = await provider.account();
|
|
2046
|
+
if (responseAcc.length === 0) {
|
|
2047
|
+
throw new WalletConnectionError(ERROR_MESSAGES.NO_ACCOUNT_FOUND);
|
|
2048
|
+
}
|
|
2049
|
+
if (responseAcc.length) {
|
|
2050
|
+
setAccounts(responseAcc);
|
|
2051
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
2052
|
+
setStorageItem(STORAGE_KEYS.STARKEY_ACCOUNTS, responseAcc[0]);
|
|
2053
|
+
window.dispatchEvent(
|
|
2054
|
+
new CustomEvent(WALLET_EVENTS2.PRESIGNED_STATE, {
|
|
2055
|
+
detail: {
|
|
2056
|
+
timestamp: Date.now(),
|
|
2057
|
+
account: responseAcc[0]
|
|
2058
|
+
}
|
|
2059
|
+
})
|
|
2060
|
+
);
|
|
2061
|
+
window.dispatchEvent(
|
|
2062
|
+
new CustomEvent(WALLET_EVENTS2.CONNECTED, {
|
|
2063
|
+
detail: {
|
|
2064
|
+
timestamp: Date.now(),
|
|
2065
|
+
account: responseAcc[0],
|
|
2066
|
+
wallet: "starkey"
|
|
2067
|
+
}
|
|
2068
|
+
})
|
|
2069
|
+
);
|
|
2070
|
+
try {
|
|
2071
|
+
const message = "To verify your account, please sign this message.";
|
|
2072
|
+
const nonce = generateNonce();
|
|
2073
|
+
const hexMessage = "0x" + Buffer.from(message, "utf8").toString("hex");
|
|
2074
|
+
logger.debug("Signature request initiated", { account: responseAcc[0] });
|
|
2075
|
+
const signatureResponse = await provider.signMessage({
|
|
2076
|
+
message: hexMessage,
|
|
2077
|
+
nonce
|
|
2078
|
+
});
|
|
2079
|
+
if (signatureResponse) {
|
|
2080
|
+
logger.info("Signature approved", { account: responseAcc[0] });
|
|
2081
|
+
window.dispatchEvent(
|
|
2082
|
+
new CustomEvent(WALLET_EVENTS2.POSTSIGNED_STATE, {
|
|
2083
|
+
detail: {
|
|
2084
|
+
timestamp: Date.now(),
|
|
2085
|
+
account: responseAcc[0]
|
|
2086
|
+
}
|
|
2087
|
+
})
|
|
2088
|
+
);
|
|
2089
|
+
}
|
|
2090
|
+
} catch (signError) {
|
|
2091
|
+
const error = new SignMessageError(ERROR_MESSAGES.SIGNING_FAILED, signError);
|
|
2092
|
+
logger.error("Signing failed", error, { account: responseAcc[0] });
|
|
2093
|
+
window.dispatchEvent(
|
|
2094
|
+
new CustomEvent(WALLET_EVENTS2.ERROR, {
|
|
2095
|
+
detail: {
|
|
2096
|
+
timestamp: Date.now(),
|
|
2097
|
+
error
|
|
2098
|
+
}
|
|
2099
|
+
})
|
|
2100
|
+
);
|
|
2101
|
+
throw error;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
break;
|
|
2105
|
+
}
|
|
2106
|
+
case "ribbit": {
|
|
2107
|
+
const dappMetadata = {
|
|
2108
|
+
name: "multiwallet",
|
|
2109
|
+
description: "NFT Marketplace and Lootbox Platform",
|
|
2110
|
+
logo: window.location.origin + "/favicon.ico",
|
|
2111
|
+
url: window.location.origin
|
|
2112
|
+
};
|
|
2113
|
+
const response = await provider.connectToWallet(
|
|
2114
|
+
dappMetadata
|
|
2115
|
+
);
|
|
2116
|
+
if (response == null ? void 0 : response.connected) {
|
|
2117
|
+
logger.info("Ribbit wallet connection approved");
|
|
2118
|
+
}
|
|
2119
|
+
if (response.walletAddress == null) {
|
|
2120
|
+
throw new WalletConnectionError(ERROR_MESSAGES.NO_ACCOUNT_FOUND);
|
|
2121
|
+
}
|
|
2122
|
+
if (response == null ? void 0 : response.connected) {
|
|
2123
|
+
await updateAccounts();
|
|
2124
|
+
if (response.walletAddress) {
|
|
2125
|
+
setAccounts([response.walletAddress]);
|
|
2126
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
2127
|
+
window.dispatchEvent(
|
|
2128
|
+
new CustomEvent(WALLET_EVENTS2.PRESIGNED_STATE, {
|
|
2129
|
+
detail: {
|
|
2130
|
+
timestamp: Date.now(),
|
|
2131
|
+
account: response.walletAddress
|
|
2132
|
+
}
|
|
2133
|
+
})
|
|
2134
|
+
);
|
|
2135
|
+
window.dispatchEvent(
|
|
2136
|
+
new CustomEvent(WALLET_EVENTS2.CONNECTED, {
|
|
2137
|
+
detail: {
|
|
2138
|
+
timestamp: Date.now(),
|
|
2139
|
+
account: response.walletAddress,
|
|
2140
|
+
wallet: "ribbit"
|
|
2141
|
+
}
|
|
2142
|
+
})
|
|
2143
|
+
);
|
|
2144
|
+
try {
|
|
2145
|
+
const message = "To verify your account, please sign this message.";
|
|
2146
|
+
const nonce = generateNonce();
|
|
2147
|
+
const hexMessage = "0x" + Buffer.from(message, "utf8").toString("hex");
|
|
2148
|
+
logger.debug("Signature request initiated", { account: response.walletAddress });
|
|
2149
|
+
const signatureResponse = await provider.signMessage({
|
|
2150
|
+
message: hexMessage,
|
|
2151
|
+
nonce: parseInt(nonce),
|
|
2152
|
+
chainId: parseInt(getChainId())
|
|
2153
|
+
});
|
|
2154
|
+
if (signatureResponse && signatureResponse.approved) {
|
|
2155
|
+
logger.info("Signature approved", { account: response.walletAddress });
|
|
2156
|
+
window.dispatchEvent(
|
|
2157
|
+
new CustomEvent(WALLET_EVENTS2.POSTSIGNED_STATE, {
|
|
2158
|
+
detail: {
|
|
2159
|
+
timestamp: Date.now(),
|
|
2160
|
+
account: response.walletAddress
|
|
2161
|
+
}
|
|
2162
|
+
})
|
|
2163
|
+
);
|
|
2164
|
+
} else {
|
|
2165
|
+
throw new SignMessageError(signatureResponse.error || ERROR_MESSAGES.SIGNING_REJECTED);
|
|
2166
|
+
}
|
|
2167
|
+
} catch (signError) {
|
|
2168
|
+
const error = new SignMessageError(ERROR_MESSAGES.SIGNING_FAILED, signError);
|
|
2169
|
+
logger.error("Signing failed", error, { account: response.walletAddress });
|
|
2170
|
+
window.dispatchEvent(
|
|
2171
|
+
new CustomEvent(WALLET_EVENTS2.ERROR, {
|
|
2172
|
+
detail: {
|
|
2173
|
+
timestamp: Date.now(),
|
|
2174
|
+
error
|
|
2175
|
+
}
|
|
2176
|
+
})
|
|
2177
|
+
);
|
|
2178
|
+
throw error;
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
} else {
|
|
2182
|
+
throw new WalletConnectionError(ERROR_MESSAGES.CONNECTION_REJECTED);
|
|
2183
|
+
}
|
|
2184
|
+
break;
|
|
2185
|
+
}
|
|
2186
|
+
default: {
|
|
2187
|
+
throw new WalletConnectionError(
|
|
2188
|
+
`${ERROR_MESSAGES.UNSUPPORTED_WALLET}: ${walletType || selectedWallet}`
|
|
2189
|
+
);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
return true;
|
|
2193
|
+
} catch (error) {
|
|
2194
|
+
const walletError = error instanceof WalletConnectionError ? error : new WalletConnectionError(ERROR_MESSAGES.CONNECTION_FAILED, error);
|
|
2195
|
+
logger.error("Wallet connection failed", walletError, {
|
|
2196
|
+
walletType: walletType || selectedWallet
|
|
2197
|
+
});
|
|
2198
|
+
window.dispatchEvent(
|
|
2199
|
+
new CustomEvent(WALLET_EVENTS2.ERROR, {
|
|
2200
|
+
detail: {
|
|
2201
|
+
timestamp: Date.now(),
|
|
2202
|
+
error: walletError
|
|
2203
|
+
}
|
|
2204
|
+
})
|
|
2205
|
+
);
|
|
2206
|
+
return false;
|
|
2207
|
+
} finally {
|
|
2208
|
+
setLoading(false);
|
|
2209
|
+
}
|
|
2210
|
+
};
|
|
2211
|
+
const disconnectWallet = async () => {
|
|
2212
|
+
const provider = getCurrentProvider();
|
|
2213
|
+
if (!provider) return;
|
|
2214
|
+
try {
|
|
2215
|
+
switch (selectedWallet) {
|
|
2216
|
+
case "starkey": {
|
|
2217
|
+
await provider.disconnect();
|
|
2218
|
+
break;
|
|
2219
|
+
}
|
|
2220
|
+
case "ribbit": {
|
|
2221
|
+
await provider.disconnect();
|
|
2222
|
+
break;
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
resetWalletData();
|
|
2226
|
+
clearStoredWalletType2();
|
|
2227
|
+
router.push("/");
|
|
2228
|
+
} catch (error) {
|
|
2229
|
+
logger.error("Wallet disconnect failed", error, { walletType: selectedWallet });
|
|
2230
|
+
resetWalletData();
|
|
2231
|
+
clearStoredWalletType2();
|
|
2232
|
+
}
|
|
2233
|
+
};
|
|
2234
|
+
const resetWalletData = () => {
|
|
2235
|
+
setAccounts([]);
|
|
2236
|
+
setBalance("");
|
|
2237
|
+
setNetworkData({});
|
|
2238
|
+
switch (selectedWallet) {
|
|
2239
|
+
case "starkey": {
|
|
2240
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
2241
|
+
removeStorageItem(STORAGE_KEYS.STARKEY_ACCOUNTS);
|
|
2242
|
+
break;
|
|
2243
|
+
}
|
|
2244
|
+
case "ribbit": {
|
|
2245
|
+
break;
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
};
|
|
2249
|
+
const getSequenceNumber = async (address) => {
|
|
2250
|
+
const rpcUrl = getRpcUrl();
|
|
2251
|
+
const data = await fetch(`${rpcUrl}/rpc/v1/accounts/${address}`);
|
|
2252
|
+
if (!data.ok) {
|
|
2253
|
+
throw new NetworkError(`Failed to fetch sequence number for ${address}`);
|
|
2254
|
+
}
|
|
2255
|
+
const accountData = await data.json();
|
|
2256
|
+
return accountData.sequence_number;
|
|
2257
|
+
};
|
|
2258
|
+
const sendRawTransaction = async (moduleAddress, moduleName, functionName, params, runTimeParams = [], txExpiryTime = Math.ceil(Date.now() / 1e3) + 3e3) => {
|
|
2259
|
+
const provider = getCurrentProvider();
|
|
2260
|
+
if (!provider || !accounts.length || !moduleAddress || !moduleName || !functionName)
|
|
2261
|
+
return;
|
|
2262
|
+
try {
|
|
2263
|
+
switch (selectedWallet) {
|
|
2264
|
+
case "starkey": {
|
|
2265
|
+
if (!walletCapabilities.rawTransactions) {
|
|
2266
|
+
throw new TransactionError("Raw transactions not supported by current wallet");
|
|
2267
|
+
}
|
|
2268
|
+
let networkData2 = await getNetworkData();
|
|
2269
|
+
const currentChainId = getChainId();
|
|
2270
|
+
if (networkData2.chainId !== currentChainId) {
|
|
2271
|
+
setSelectedChainId(currentChainId);
|
|
2272
|
+
await provider.changeNetwork({
|
|
2273
|
+
chainId: currentChainId
|
|
2274
|
+
});
|
|
2275
|
+
}
|
|
2276
|
+
const rawTxPayload = [
|
|
2277
|
+
accounts[0],
|
|
2278
|
+
0,
|
|
2279
|
+
// sequence number
|
|
2280
|
+
moduleAddress,
|
|
2281
|
+
moduleName,
|
|
2282
|
+
functionName,
|
|
2283
|
+
runTimeParams,
|
|
2284
|
+
params,
|
|
2285
|
+
{}
|
|
2286
|
+
];
|
|
2287
|
+
const data = await provider.createRawTransactionData(rawTxPayload);
|
|
2288
|
+
const txHash = await provider.sendTransaction({
|
|
2289
|
+
data,
|
|
2290
|
+
from: accounts[0],
|
|
2291
|
+
to: moduleAddress,
|
|
2292
|
+
chainId: currentChainId,
|
|
2293
|
+
value: ""
|
|
2294
|
+
});
|
|
2295
|
+
addTransactions(txHash || "failed");
|
|
2296
|
+
logger.info("Transaction sent successfully", { txHash, walletType: "starkey" });
|
|
2297
|
+
return txHash;
|
|
2298
|
+
}
|
|
2299
|
+
case "ribbit": {
|
|
2300
|
+
if (!walletCapabilities.rawTransactions) {
|
|
2301
|
+
throw new TransactionError("Raw transactions not supported by current wallet");
|
|
2302
|
+
}
|
|
2303
|
+
const currentChainId = getChainId();
|
|
2304
|
+
let chainId = SupraChainId2.TESTNET;
|
|
2305
|
+
if (currentChainId === DEFAULT_CHAIN_IDS.TESTNET) {
|
|
2306
|
+
chainId = SupraChainId2.TESTNET;
|
|
2307
|
+
} else if (currentChainId === DEFAULT_CHAIN_IDS.MAINNET) {
|
|
2308
|
+
chainId = SupraChainId2.MAINNET;
|
|
2309
|
+
}
|
|
2310
|
+
const rawTxnRequest = {
|
|
2311
|
+
sender: accounts[0],
|
|
2312
|
+
// Use actual sender address
|
|
2313
|
+
moduleAddress,
|
|
2314
|
+
// Use provided module address
|
|
2315
|
+
moduleName,
|
|
2316
|
+
// Use provided module name
|
|
2317
|
+
functionName,
|
|
2318
|
+
// Use provided function name
|
|
2319
|
+
typeArgs: runTimeParams,
|
|
2320
|
+
// Use converted runtime parameters
|
|
2321
|
+
args: params || [],
|
|
2322
|
+
// Use provided parameters
|
|
2323
|
+
chainId
|
|
2324
|
+
};
|
|
2325
|
+
const rawTxnBase64 = await provider.createRawTransactionBuffer(rawTxnRequest);
|
|
2326
|
+
const response = await provider.signAndSendRawTransaction({
|
|
2327
|
+
rawTxn: rawTxnBase64,
|
|
2328
|
+
chainId,
|
|
2329
|
+
meta: {
|
|
2330
|
+
description: `Call ${moduleName}::${functionName}`
|
|
2331
|
+
// Dynamic description
|
|
2332
|
+
}
|
|
2333
|
+
});
|
|
2334
|
+
if (response.approved) {
|
|
2335
|
+
const txHash = response.txHash || response.result || "success";
|
|
2336
|
+
addTransactions(txHash);
|
|
2337
|
+
logger.info("Transaction sent successfully", { txHash, walletType: "ribbit" });
|
|
2338
|
+
return txHash;
|
|
2339
|
+
} else {
|
|
2340
|
+
throw new TransactionError(response.error || ERROR_MESSAGES.TRANSACTION_REJECTED);
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
default: {
|
|
2344
|
+
throw new TransactionError(
|
|
2345
|
+
`Raw transactions not supported for wallet: ${selectedWallet}`
|
|
2346
|
+
);
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
} catch (error) {
|
|
2350
|
+
const txError = error instanceof TransactionError ? error : new TransactionError(ERROR_MESSAGES.TRANSACTION_FAILED, void 0, error);
|
|
2351
|
+
logger.error("Transaction failed", txError, {
|
|
2352
|
+
walletType: selectedWallet,
|
|
2353
|
+
moduleAddress,
|
|
2354
|
+
moduleName,
|
|
2355
|
+
functionName
|
|
2356
|
+
});
|
|
2357
|
+
throw txError;
|
|
2358
|
+
}
|
|
2359
|
+
};
|
|
2360
|
+
const signMessage = async (message, nonce, account, forceSign = false) => {
|
|
2361
|
+
const provider = getCurrentProvider();
|
|
2362
|
+
if (!provider) return;
|
|
2363
|
+
const secureNonce = nonce || generateNonce();
|
|
2364
|
+
switch (selectedWallet) {
|
|
2365
|
+
case "starkey": {
|
|
2366
|
+
if (!walletCapabilities.signMessage) {
|
|
2367
|
+
throw new SignMessageError("Message signing not supported by current wallet");
|
|
2368
|
+
}
|
|
2369
|
+
if (!accounts.length && !account) return;
|
|
2370
|
+
if (!accounts.length && account) {
|
|
2371
|
+
accounts[0] = account;
|
|
2372
|
+
}
|
|
2373
|
+
if (getStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET) === "true" && !forceSign) {
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "true");
|
|
2377
|
+
try {
|
|
2378
|
+
const hexMessage = "0x" + Buffer.from(message, "utf8").toString("hex");
|
|
2379
|
+
const response = await provider.signMessage({
|
|
2380
|
+
message: hexMessage,
|
|
2381
|
+
nonce: secureNonce
|
|
2382
|
+
});
|
|
2383
|
+
const { publicKey, signature } = response;
|
|
2384
|
+
const verified = nacl2.sign.detached.verify(
|
|
2385
|
+
new TextEncoder().encode(message),
|
|
2386
|
+
Uint8Array.from(Buffer.from(signature.slice(2), "hex")),
|
|
2387
|
+
Uint8Array.from(Buffer.from(publicKey.slice(2), "hex"))
|
|
2388
|
+
);
|
|
2389
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
2390
|
+
logger.info("Message signed successfully", { walletType: "starkey" });
|
|
2391
|
+
return __spreadProps(__spreadValues({}, response), { verified });
|
|
2392
|
+
} catch (error) {
|
|
2393
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
2394
|
+
throw new SignMessageError(ERROR_MESSAGES.SIGNING_FAILED, error);
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
case "ribbit": {
|
|
2398
|
+
if (!walletCapabilities.signMessage) {
|
|
2399
|
+
throw new SignMessageError("Message signing not supported by current wallet");
|
|
2400
|
+
}
|
|
2401
|
+
if (!accounts.length && !account) return;
|
|
2402
|
+
if (!accounts.length && account) {
|
|
2403
|
+
accounts[0] = account;
|
|
2404
|
+
}
|
|
2405
|
+
if (getStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET) === "true" && !forceSign) {
|
|
2406
|
+
return;
|
|
2407
|
+
}
|
|
2408
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "true");
|
|
2409
|
+
try {
|
|
2410
|
+
const hexMessage = "0x" + Buffer.from(message, "utf8").toString("hex");
|
|
2411
|
+
const response = await provider.signMessage({
|
|
2412
|
+
message: hexMessage,
|
|
2413
|
+
nonce: parseInt(secureNonce),
|
|
2414
|
+
chainId: parseInt(getChainId())
|
|
2415
|
+
});
|
|
2416
|
+
if (response.approved && response.publicKey && response.signature) {
|
|
2417
|
+
const { publicKey, signature } = response;
|
|
2418
|
+
const verified = nacl2.sign.detached.verify(
|
|
2419
|
+
new TextEncoder().encode(message),
|
|
2420
|
+
Uint8Array.from(Buffer.from(signature.slice(2), "hex")),
|
|
2421
|
+
Uint8Array.from(Buffer.from(publicKey.slice(2), "hex"))
|
|
2422
|
+
);
|
|
2423
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
2424
|
+
logger.info("Message signed successfully", { walletType: "ribbit" });
|
|
2425
|
+
return __spreadProps(__spreadValues({}, response), { verified });
|
|
2426
|
+
} else {
|
|
2427
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
2428
|
+
throw new SignMessageError(response.error || ERROR_MESSAGES.SIGNING_REJECTED);
|
|
2429
|
+
}
|
|
2430
|
+
} catch (error) {
|
|
2431
|
+
setStorageItem(STORAGE_KEYS.IS_SIGNING_WALLET, "false");
|
|
2432
|
+
throw new SignMessageError(ERROR_MESSAGES.SIGNING_FAILED, error);
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
default: {
|
|
2436
|
+
throw new SignMessageError(
|
|
2437
|
+
`Message signing not supported for wallet: ${selectedWallet}`
|
|
2438
|
+
);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
};
|
|
2442
|
+
useEffect3(() => {
|
|
2443
|
+
if (selectedWallet === "starkey" && walletCapabilities.eventListeners) {
|
|
2444
|
+
const handleExtensionEvents = (event) => {
|
|
2445
|
+
var _a, _b, _c;
|
|
2446
|
+
if ((_b = (_a = event == null ? void 0 : event.data) == null ? void 0 : _a.name) == null ? void 0 : _b.startsWith("starkey-")) {
|
|
2447
|
+
switch ((_c = event == null ? void 0 : event.data) == null ? void 0 : _c.name) {
|
|
2448
|
+
case "starkey-extension-installed": {
|
|
2449
|
+
checkIsExtensionInstalled();
|
|
2450
|
+
break;
|
|
2451
|
+
}
|
|
2452
|
+
case "starkey-wallet-updated": {
|
|
2453
|
+
(async () => {
|
|
2454
|
+
const responseAcc = await supraProvider.account();
|
|
2455
|
+
if (responseAcc.length) {
|
|
2456
|
+
setAccounts(responseAcc);
|
|
2457
|
+
window.dispatchEvent(
|
|
2458
|
+
new CustomEvent(WALLET_EVENTS2.CONNECTED, {
|
|
2459
|
+
detail: {
|
|
2460
|
+
timestamp: Date.now(),
|
|
2461
|
+
account: responseAcc[0]
|
|
2462
|
+
}
|
|
2463
|
+
})
|
|
2464
|
+
);
|
|
2465
|
+
await updateBalance();
|
|
2466
|
+
await getNetworkData();
|
|
2467
|
+
} else {
|
|
2468
|
+
logger.debug("Starkey wallet updated: No accounts found - Resetting");
|
|
2469
|
+
resetWalletData();
|
|
2470
|
+
}
|
|
2471
|
+
setLoading(false);
|
|
2472
|
+
})();
|
|
2473
|
+
break;
|
|
2474
|
+
}
|
|
2475
|
+
case "starkey-wallet-disconnected": {
|
|
2476
|
+
resetWalletData();
|
|
2477
|
+
router.push("/");
|
|
2478
|
+
setLoading(false);
|
|
2479
|
+
break;
|
|
2480
|
+
}
|
|
2481
|
+
case "starkey-window-removed": {
|
|
2482
|
+
setLoading(false);
|
|
2483
|
+
break;
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
};
|
|
2488
|
+
checkIsExtensionInstalled();
|
|
2489
|
+
window.addEventListener("message", handleExtensionEvents);
|
|
2490
|
+
return () => window.removeEventListener("message", handleExtensionEvents);
|
|
2491
|
+
}
|
|
2492
|
+
}, [selectedWallet, walletCapabilities, supraProvider]);
|
|
2493
|
+
const getAvailableWallets = useCallback3(() => {
|
|
2494
|
+
const availableWallets = [];
|
|
2495
|
+
Object.entries(WALLET_CONFIGS2).forEach(([walletType, config2]) => {
|
|
2496
|
+
const provider = config2.provider();
|
|
2497
|
+
const isInstalled = !!provider;
|
|
2498
|
+
switch (walletType) {
|
|
2499
|
+
case "starkey": {
|
|
2500
|
+
availableWallets.push({
|
|
2501
|
+
type: "starkey",
|
|
2502
|
+
name: "Starkey Wallet",
|
|
2503
|
+
isInstalled,
|
|
2504
|
+
capabilities: config2.capabilities
|
|
2505
|
+
});
|
|
2506
|
+
break;
|
|
2507
|
+
}
|
|
2508
|
+
case "ribbit": {
|
|
2509
|
+
availableWallets.push({
|
|
2510
|
+
type: "ribbit",
|
|
2511
|
+
name: "Ribbit Wallet",
|
|
2512
|
+
isInstalled,
|
|
2513
|
+
capabilities: config2.capabilities
|
|
2514
|
+
});
|
|
2515
|
+
break;
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
});
|
|
2519
|
+
return availableWallets;
|
|
2520
|
+
}, []);
|
|
2521
|
+
const updateSelectedWallet = (walletType) => {
|
|
2522
|
+
setSelectedWallet(walletType);
|
|
2523
|
+
setWalletCapabilities(WALLET_CONFIGS2[walletType].capabilities);
|
|
2524
|
+
setStoredWalletType2(walletType);
|
|
2525
|
+
};
|
|
2526
|
+
return {
|
|
2527
|
+
// New wallet selection functionality
|
|
2528
|
+
selectedWallet,
|
|
2529
|
+
walletCapabilities,
|
|
2530
|
+
getAvailableWallets,
|
|
2531
|
+
// Add this new function
|
|
2532
|
+
// Existing interface (unchanged)
|
|
2533
|
+
getCurrentProvider,
|
|
2534
|
+
isExtensionInstalled,
|
|
2535
|
+
accounts,
|
|
2536
|
+
networkData,
|
|
2537
|
+
balance,
|
|
2538
|
+
transactions,
|
|
2539
|
+
selectedChainId,
|
|
2540
|
+
connectWallet,
|
|
2541
|
+
// Now accepts optional walletType parameter
|
|
2542
|
+
disconnectWallet,
|
|
2543
|
+
sendRawTransaction,
|
|
2544
|
+
signMessage,
|
|
2545
|
+
setSelectedChainId,
|
|
2546
|
+
// switchToChain,
|
|
2547
|
+
loading
|
|
2548
|
+
// authFetch,
|
|
2549
|
+
// checkAndRevalidateToken,
|
|
2550
|
+
// signIn,
|
|
2551
|
+
};
|
|
2552
|
+
};
|
|
2553
|
+
var useSupraMultiWallet_default2 = useSupraMultiWallet2;
|
|
2554
|
+
|
|
2555
|
+
// src/hooks/useConversionUtils.ts
|
|
2556
|
+
import { useCallback as useCallback4 } from "react";
|
|
2557
|
+
import { BCS as BCS3, TxnBuilderTypes } from "supra-l1-sdk-core";
|
|
2558
|
+
|
|
2559
|
+
// src/lib/abis/supra_account.ts
|
|
2560
|
+
var supraAccountABI = {
|
|
2561
|
+
address: "0x1",
|
|
2562
|
+
name: "supra_account",
|
|
2563
|
+
friends: [
|
|
2564
|
+
"0x1::genesis",
|
|
2565
|
+
"0x1::resource_account",
|
|
2566
|
+
"0x1::transaction_fee",
|
|
2567
|
+
"0x1::transaction_validation"
|
|
2568
|
+
],
|
|
2569
|
+
exposed_functions: [
|
|
2570
|
+
{
|
|
2571
|
+
name: "assert_account_exists",
|
|
2572
|
+
visibility: "public",
|
|
2573
|
+
is_entry: false,
|
|
2574
|
+
is_view: false,
|
|
2575
|
+
generic_type_params: [],
|
|
2576
|
+
params: ["address"],
|
|
2577
|
+
return: []
|
|
2578
|
+
},
|
|
2579
|
+
{
|
|
2580
|
+
name: "assert_account_is_registered_for_apt",
|
|
2581
|
+
visibility: "public",
|
|
2582
|
+
is_entry: false,
|
|
2583
|
+
is_view: false,
|
|
2584
|
+
generic_type_params: [],
|
|
2585
|
+
params: ["address"],
|
|
2586
|
+
return: []
|
|
2587
|
+
},
|
|
2588
|
+
{
|
|
2589
|
+
name: "assert_account_is_registered_for_supra",
|
|
2590
|
+
visibility: "public",
|
|
2591
|
+
is_entry: false,
|
|
2592
|
+
is_view: false,
|
|
2593
|
+
generic_type_params: [],
|
|
2594
|
+
params: ["address"],
|
|
2595
|
+
return: []
|
|
2596
|
+
},
|
|
2597
|
+
{
|
|
2598
|
+
name: "batch_transfer",
|
|
2599
|
+
visibility: "public",
|
|
2600
|
+
is_entry: true,
|
|
2601
|
+
is_view: false,
|
|
2602
|
+
generic_type_params: [],
|
|
2603
|
+
params: ["&signer", "vector<address>", "vector<u64>"],
|
|
2604
|
+
return: []
|
|
2605
|
+
},
|
|
2606
|
+
{
|
|
2607
|
+
name: "batch_transfer_coins",
|
|
2608
|
+
visibility: "public",
|
|
2609
|
+
is_entry: true,
|
|
2610
|
+
is_view: false,
|
|
2611
|
+
generic_type_params: [{ constraints: [] }],
|
|
2612
|
+
params: ["&signer", "vector<address>", "vector<u64>"],
|
|
2613
|
+
return: []
|
|
2614
|
+
},
|
|
2615
|
+
{
|
|
2616
|
+
name: "burn_from_fungible_store",
|
|
2617
|
+
visibility: "friend",
|
|
2618
|
+
is_entry: false,
|
|
2619
|
+
is_view: false,
|
|
2620
|
+
generic_type_params: [],
|
|
2621
|
+
params: ["&0x1::fungible_asset::BurnRef", "address", "u64"],
|
|
2622
|
+
return: []
|
|
2623
|
+
},
|
|
2624
|
+
{
|
|
2625
|
+
name: "can_receive_direct_coin_transfers",
|
|
2626
|
+
visibility: "public",
|
|
2627
|
+
is_entry: false,
|
|
2628
|
+
is_view: true,
|
|
2629
|
+
generic_type_params: [],
|
|
2630
|
+
params: ["address"],
|
|
2631
|
+
return: ["bool"]
|
|
2632
|
+
},
|
|
2633
|
+
{
|
|
2634
|
+
name: "create_account",
|
|
2635
|
+
visibility: "public",
|
|
2636
|
+
is_entry: true,
|
|
2637
|
+
is_view: false,
|
|
2638
|
+
generic_type_params: [],
|
|
2639
|
+
params: ["address"],
|
|
2640
|
+
return: []
|
|
2641
|
+
},
|
|
2642
|
+
{
|
|
2643
|
+
name: "deposit_coins",
|
|
2644
|
+
visibility: "public",
|
|
2645
|
+
is_entry: false,
|
|
2646
|
+
is_view: false,
|
|
2647
|
+
generic_type_params: [{ constraints: [] }],
|
|
2648
|
+
params: ["address", "0x1::coin::Coin<T0>"],
|
|
2649
|
+
return: []
|
|
2650
|
+
},
|
|
2651
|
+
{
|
|
2652
|
+
name: "is_fungible_balance_at_least",
|
|
2653
|
+
visibility: "friend",
|
|
2654
|
+
is_entry: false,
|
|
2655
|
+
is_view: false,
|
|
2656
|
+
generic_type_params: [],
|
|
2657
|
+
params: ["address", "u64"],
|
|
2658
|
+
return: ["bool"]
|
|
2659
|
+
},
|
|
2660
|
+
{
|
|
2661
|
+
name: "register_supra",
|
|
2662
|
+
visibility: "friend",
|
|
2663
|
+
is_entry: false,
|
|
2664
|
+
is_view: false,
|
|
2665
|
+
generic_type_params: [],
|
|
2666
|
+
params: ["&signer"],
|
|
2667
|
+
return: []
|
|
2668
|
+
},
|
|
2669
|
+
{
|
|
2670
|
+
name: "set_allow_direct_coin_transfers",
|
|
2671
|
+
visibility: "public",
|
|
2672
|
+
is_entry: true,
|
|
2673
|
+
is_view: false,
|
|
2674
|
+
generic_type_params: [],
|
|
2675
|
+
params: ["&signer", "bool"],
|
|
2676
|
+
return: []
|
|
2677
|
+
},
|
|
2678
|
+
{
|
|
2679
|
+
name: "transfer",
|
|
2680
|
+
visibility: "public",
|
|
2681
|
+
is_entry: true,
|
|
2682
|
+
is_view: false,
|
|
2683
|
+
generic_type_params: [],
|
|
2684
|
+
params: ["&signer", "address", "u64"],
|
|
2685
|
+
return: []
|
|
2686
|
+
},
|
|
2687
|
+
{
|
|
2688
|
+
name: "transfer_coins",
|
|
2689
|
+
visibility: "public",
|
|
2690
|
+
is_entry: true,
|
|
2691
|
+
is_view: false,
|
|
2692
|
+
generic_type_params: [{ constraints: [] }],
|
|
2693
|
+
params: ["&signer", "address", "u64"],
|
|
2694
|
+
return: []
|
|
2695
|
+
}
|
|
2696
|
+
],
|
|
2697
|
+
structs: [
|
|
2698
|
+
{
|
|
2699
|
+
name: "DirectCoinTransferConfigUpdated",
|
|
2700
|
+
is_native: false,
|
|
2701
|
+
abilities: ["drop", "store"],
|
|
2702
|
+
generic_type_params: [],
|
|
2703
|
+
fields: [
|
|
2704
|
+
{ name: "account", type: "address" },
|
|
2705
|
+
{ name: "new_allow_direct_transfers", type: "bool" }
|
|
2706
|
+
]
|
|
2707
|
+
},
|
|
2708
|
+
{
|
|
2709
|
+
name: "DirectCoinTransferConfigUpdatedEvent",
|
|
2710
|
+
is_native: false,
|
|
2711
|
+
abilities: ["drop", "store"],
|
|
2712
|
+
generic_type_params: [],
|
|
2713
|
+
fields: [{ name: "new_allow_direct_transfers", type: "bool" }]
|
|
2714
|
+
},
|
|
2715
|
+
{
|
|
2716
|
+
name: "DirectTransferConfig",
|
|
2717
|
+
is_native: false,
|
|
2718
|
+
abilities: ["key"],
|
|
2719
|
+
generic_type_params: [],
|
|
2720
|
+
fields: [
|
|
2721
|
+
{ name: "allow_arbitrary_coin_transfers", type: "bool" },
|
|
2722
|
+
{
|
|
2723
|
+
name: "update_coin_transfer_events",
|
|
2724
|
+
type: "0x1::event::EventHandle<0x1::supra_account::DirectCoinTransferConfigUpdatedEvent>"
|
|
2725
|
+
}
|
|
2726
|
+
]
|
|
2727
|
+
}
|
|
2728
|
+
]
|
|
2729
|
+
};
|
|
2730
|
+
|
|
2731
|
+
// src/lib/utils.ts
|
|
2732
|
+
import { clsx as clsx2 } from "clsx";
|
|
2733
|
+
import { twMerge as twMerge2 } from "tailwind-merge";
|
|
2734
|
+
function cn2(...inputs) {
|
|
2735
|
+
return twMerge2(clsx2(inputs));
|
|
2736
|
+
}
|
|
2737
|
+
function standardizeAddress(address) {
|
|
2738
|
+
let cleanAddress = address.replace(/^0x/, "");
|
|
2739
|
+
if (cleanAddress.length < 64) {
|
|
2740
|
+
cleanAddress = cleanAddress.padStart(64, "0");
|
|
2741
|
+
}
|
|
2742
|
+
if (cleanAddress.length > 64) {
|
|
2743
|
+
throw new Error(`Address ${address} is not a valid address`);
|
|
2744
|
+
}
|
|
2745
|
+
return `0x${cleanAddress}`;
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
// src/lib/abiStorage.ts
|
|
2749
|
+
var abiStorage = {
|
|
2750
|
+
[standardizeAddress("0x1")]: {
|
|
2751
|
+
supra_account: supraAccountABI
|
|
2752
|
+
}
|
|
2753
|
+
};
|
|
2754
|
+
function getStoredABI(moduleAddress, moduleName) {
|
|
2755
|
+
var _a;
|
|
2756
|
+
const standardizedAddress = standardizeAddress(moduleAddress);
|
|
2757
|
+
const normalizedName = moduleName;
|
|
2758
|
+
if ((_a = abiStorage[standardizedAddress]) == null ? void 0 : _a[normalizedName]) {
|
|
2759
|
+
return abiStorage[standardizedAddress][normalizedName];
|
|
2760
|
+
}
|
|
2761
|
+
return null;
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
// src/hooks/useConversionUtils.ts
|
|
2765
|
+
var useConversionUtils = () => {
|
|
2766
|
+
const stringToUint8Array = useCallback4((humanReadableStr) => {
|
|
2767
|
+
return BCS3.bcsToBytes(new TxnBuilderTypes.Identifier(humanReadableStr));
|
|
2768
|
+
}, []);
|
|
2769
|
+
const serializeString = useCallback4((humanReadableStr) => {
|
|
2770
|
+
return BCS3.bcsSerializeStr(humanReadableStr);
|
|
2771
|
+
}, []);
|
|
2772
|
+
const addressToUint8Array = useCallback4((cryptoAddress) => {
|
|
2773
|
+
return BCS3.bcsToBytes(TxnBuilderTypes.AccountAddress.fromHex(cryptoAddress));
|
|
2774
|
+
}, []);
|
|
2775
|
+
const deserializeString = (uint8Array) => {
|
|
2776
|
+
return BCS3.bcsSerializeStr(uint8Array);
|
|
2777
|
+
};
|
|
2778
|
+
const deserializeVector = (uint8Array) => {
|
|
2779
|
+
const deserializer = new BCS3.Deserializer(uint8Array);
|
|
2780
|
+
return BCS3.deserializeVector(deserializer, BCS3.bcsSerializeU8);
|
|
2781
|
+
};
|
|
2782
|
+
const serializeUint8 = useCallback4((value) => {
|
|
2783
|
+
const num = typeof value === "string" ? parseInt(value, 10) : value;
|
|
2784
|
+
if (num < 0 || num > 255) {
|
|
2785
|
+
throw new Error(`u8 value out of range: ${num}`);
|
|
2786
|
+
}
|
|
2787
|
+
return BCS3.bcsSerializeU8(num);
|
|
2788
|
+
}, []);
|
|
2789
|
+
const serializeUint16 = useCallback4((value) => {
|
|
2790
|
+
let num;
|
|
2791
|
+
if (typeof value === "string") {
|
|
2792
|
+
num = parseInt(value, 10);
|
|
2793
|
+
} else if (typeof value === "bigint") {
|
|
2794
|
+
num = Number(value);
|
|
2795
|
+
} else {
|
|
2796
|
+
num = value;
|
|
2797
|
+
}
|
|
2798
|
+
if (num < 0 || num > 65535) {
|
|
2799
|
+
throw new Error(`u16 value out of range: ${num}`);
|
|
2800
|
+
}
|
|
2801
|
+
return BCS3.bcsSerializeU16(num);
|
|
2802
|
+
}, []);
|
|
2803
|
+
const serializeUint32 = useCallback4((value) => {
|
|
2804
|
+
let num;
|
|
2805
|
+
if (typeof value === "string") {
|
|
2806
|
+
num = parseInt(value, 10);
|
|
2807
|
+
} else if (typeof value === "bigint") {
|
|
2808
|
+
num = Number(value);
|
|
2809
|
+
} else {
|
|
2810
|
+
num = value;
|
|
2811
|
+
}
|
|
2812
|
+
if (num < 0 || num > 4294967295) {
|
|
2813
|
+
throw new Error(`u32 value out of range: ${num}`);
|
|
2814
|
+
}
|
|
2815
|
+
return BCS3.bcsSerializeU32(num);
|
|
2816
|
+
}, []);
|
|
2817
|
+
const serializeUint64 = useCallback4((value) => {
|
|
2818
|
+
let num;
|
|
2819
|
+
if (typeof value === "string") {
|
|
2820
|
+
num = BigInt(value);
|
|
2821
|
+
} else if (typeof value === "number") {
|
|
2822
|
+
num = BigInt(value);
|
|
2823
|
+
} else {
|
|
2824
|
+
num = value;
|
|
2825
|
+
}
|
|
2826
|
+
if (num < 0) {
|
|
2827
|
+
throw new Error(`u64 value cannot be negative: ${num}`);
|
|
2828
|
+
}
|
|
2829
|
+
return BCS3.bcsSerializeUint64(num);
|
|
2830
|
+
}, []);
|
|
2831
|
+
const serializeUint128 = useCallback4((value) => {
|
|
2832
|
+
let num;
|
|
2833
|
+
if (typeof value === "string") {
|
|
2834
|
+
num = BigInt(value);
|
|
2835
|
+
} else if (typeof value === "number") {
|
|
2836
|
+
num = BigInt(value);
|
|
2837
|
+
} else {
|
|
2838
|
+
num = value;
|
|
2839
|
+
}
|
|
2840
|
+
if (num < 0) {
|
|
2841
|
+
throw new Error(`u128 value cannot be negative: ${num}`);
|
|
2842
|
+
}
|
|
2843
|
+
return BCS3.bcsSerializeU128(num);
|
|
2844
|
+
}, []);
|
|
2845
|
+
const serializeU256 = useCallback4((value) => {
|
|
2846
|
+
return BCS3.bcsSerializeU256(value);
|
|
2847
|
+
}, []);
|
|
2848
|
+
const serializeBool = useCallback4((value) => {
|
|
2849
|
+
return BCS3.bcsSerializeBool(value);
|
|
2850
|
+
}, []);
|
|
2851
|
+
const serializeVector = useCallback4((values, type) => {
|
|
2852
|
+
const serializer = new BCS3.Serializer();
|
|
2853
|
+
serializer.serializeU32AsUleb128(values.length);
|
|
2854
|
+
values.forEach((value) => {
|
|
2855
|
+
if (type === "u64") {
|
|
2856
|
+
serializer.serializeU64(value);
|
|
2857
|
+
} else if (type === "bool") {
|
|
2858
|
+
serializer.serializeBool(value);
|
|
2859
|
+
} else if (type === "string") {
|
|
2860
|
+
serializer.serializeStr(value);
|
|
2861
|
+
} else if (type === "address") {
|
|
2862
|
+
const accountAddress = TxnBuilderTypes.AccountAddress.fromHex(value);
|
|
2863
|
+
serializer.serializeFixedBytes(accountAddress.address);
|
|
2864
|
+
} else {
|
|
2865
|
+
serializer.serializeStr(value);
|
|
2866
|
+
}
|
|
2867
|
+
});
|
|
2868
|
+
return serializer.getBytes();
|
|
2869
|
+
}, []);
|
|
2870
|
+
const hexToString = (hex, type) => {
|
|
2871
|
+
if (!hex) {
|
|
2872
|
+
return "";
|
|
2873
|
+
}
|
|
2874
|
+
if (type !== "String") {
|
|
2875
|
+
try {
|
|
2876
|
+
return BigInt(hex).toString();
|
|
2877
|
+
} catch (error) {
|
|
2878
|
+
console.error("Error converting hex to string:", error);
|
|
2879
|
+
return hex;
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
try {
|
|
2883
|
+
const cleanHex = hex.slice(2);
|
|
2884
|
+
return Buffer.from(cleanHex, "hex").toString().slice(1);
|
|
2885
|
+
} catch (error) {
|
|
2886
|
+
console.error("Error converting hex to string:", error);
|
|
2887
|
+
return hex;
|
|
2888
|
+
}
|
|
2889
|
+
};
|
|
2890
|
+
const stringToHex = (str) => {
|
|
2891
|
+
const encoder = new TextEncoder();
|
|
2892
|
+
const bytes = encoder.encode(str);
|
|
2893
|
+
let hexString = "";
|
|
2894
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2895
|
+
const hex = bytes[i].toString(16).padStart(2, "0");
|
|
2896
|
+
hexString += hex;
|
|
2897
|
+
}
|
|
2898
|
+
return hexString;
|
|
2899
|
+
};
|
|
2900
|
+
const serializeValueByType = useCallback4(
|
|
2901
|
+
(value, type, serializer) => {
|
|
2902
|
+
var _a;
|
|
2903
|
+
const ser = serializer || new BCS3.Serializer();
|
|
2904
|
+
const shouldReturnBytes = !serializer;
|
|
2905
|
+
if (type.startsWith("0x1::option::Option<")) {
|
|
2906
|
+
if (value === null || value === void 0) {
|
|
2907
|
+
ser.serializeU8(0);
|
|
2908
|
+
} else {
|
|
2909
|
+
ser.serializeU8(1);
|
|
2910
|
+
const innerType = type.slice(21, -1);
|
|
2911
|
+
serializeValueByType(value, innerType, ser);
|
|
2912
|
+
}
|
|
2913
|
+
return shouldReturnBytes ? ser.getBytes() : new Uint8Array(0);
|
|
2914
|
+
}
|
|
2915
|
+
if (type.startsWith("vector<")) {
|
|
2916
|
+
const vectorMatch = type.match(/vector<(.+)>$/);
|
|
2917
|
+
if (!vectorMatch) {
|
|
2918
|
+
throw new Error(`Invalid vector type format: ${type}`);
|
|
2919
|
+
}
|
|
2920
|
+
const innerType = vectorMatch[1];
|
|
2921
|
+
if (innerType === "u8") {
|
|
2922
|
+
let bytes;
|
|
2923
|
+
if (typeof value === "string") {
|
|
2924
|
+
const cleanHex = value.startsWith("0x") ? value.slice(2) : value;
|
|
2925
|
+
bytes = new Uint8Array(
|
|
2926
|
+
((_a = cleanHex.match(/.{1,2}/g)) == null ? void 0 : _a.map((byte) => parseInt(byte, 16))) || []
|
|
2927
|
+
);
|
|
2928
|
+
} else if (value instanceof Uint8Array) {
|
|
2929
|
+
bytes = value;
|
|
2930
|
+
} else if (Array.isArray(value)) {
|
|
2931
|
+
bytes = new Uint8Array(
|
|
2932
|
+
value.map((item) => {
|
|
2933
|
+
const u8 = typeof item === "string" ? parseInt(item, 10) : item;
|
|
2934
|
+
if (u8 < 0 || u8 > 255) {
|
|
2935
|
+
throw new Error(`u8 value out of range in vector: ${u8}`);
|
|
2936
|
+
}
|
|
2937
|
+
return u8;
|
|
2938
|
+
})
|
|
2939
|
+
);
|
|
2940
|
+
} else {
|
|
2941
|
+
throw new Error(
|
|
2942
|
+
`Expected string, Uint8Array, or number[] for vector<u8>, got ${typeof value}`
|
|
2943
|
+
);
|
|
2944
|
+
}
|
|
2945
|
+
ser.serializeU32AsUleb128(bytes.length);
|
|
2946
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2947
|
+
ser.serializeU8(bytes[i]);
|
|
2948
|
+
}
|
|
2949
|
+
} else {
|
|
2950
|
+
if (!Array.isArray(value)) {
|
|
2951
|
+
throw new Error(
|
|
2952
|
+
`Expected array for vector<${innerType}>, got ${typeof value}`
|
|
2953
|
+
);
|
|
2954
|
+
}
|
|
2955
|
+
ser.serializeU32AsUleb128(value.length);
|
|
2956
|
+
for (const item of value) {
|
|
2957
|
+
serializeValueByType(item, innerType, ser);
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
return shouldReturnBytes ? ser.getBytes() : new Uint8Array(0);
|
|
2961
|
+
}
|
|
2962
|
+
if (type.startsWith("0x1::object::Object")) {
|
|
2963
|
+
if (typeof value !== "string") {
|
|
2964
|
+
throw new Error(`Expected string for Object, got ${typeof value}`);
|
|
2965
|
+
}
|
|
2966
|
+
const objectAddress = TxnBuilderTypes.AccountAddress.fromHex(value);
|
|
2967
|
+
ser.serializeFixedBytes(objectAddress.address);
|
|
2968
|
+
return shouldReturnBytes ? ser.getBytes() : new Uint8Array(0);
|
|
2969
|
+
}
|
|
2970
|
+
switch (type) {
|
|
2971
|
+
case "address":
|
|
2972
|
+
if (typeof value !== "string") {
|
|
2973
|
+
throw new Error(`Expected string for address, got ${typeof value}`);
|
|
2974
|
+
}
|
|
2975
|
+
const accountAddress = TxnBuilderTypes.AccountAddress.fromHex(value);
|
|
2976
|
+
ser.serializeFixedBytes(accountAddress.address);
|
|
2977
|
+
break;
|
|
2978
|
+
case "u8":
|
|
2979
|
+
const u8 = typeof value === "string" ? parseInt(value, 10) : value;
|
|
2980
|
+
if (u8 < 0 || u8 > 255) {
|
|
2981
|
+
throw new Error(`u8 value out of range: ${u8}`);
|
|
2982
|
+
}
|
|
2983
|
+
ser.serializeU8(u8);
|
|
2984
|
+
break;
|
|
2985
|
+
case "u16":
|
|
2986
|
+
const u16 = typeof value === "string" ? parseInt(value, 10) : typeof value === "bigint" ? Number(value) : value;
|
|
2987
|
+
if (u16 < 0 || u16 > 65535) {
|
|
2988
|
+
throw new Error(`u16 value out of range: ${u16}`);
|
|
2989
|
+
}
|
|
2990
|
+
ser.serializeU16(u16);
|
|
2991
|
+
break;
|
|
2992
|
+
case "u32":
|
|
2993
|
+
const u32 = typeof value === "string" ? parseInt(value, 10) : typeof value === "bigint" ? Number(value) : value;
|
|
2994
|
+
if (u32 < 0 || u32 > 4294967295) {
|
|
2995
|
+
throw new Error(`u32 value out of range: ${u32}`);
|
|
2996
|
+
}
|
|
2997
|
+
ser.serializeU32(u32);
|
|
2998
|
+
break;
|
|
2999
|
+
case "u64":
|
|
3000
|
+
const u64 = typeof value === "string" ? BigInt(value) : typeof value === "number" ? BigInt(value) : value;
|
|
3001
|
+
if (u64 < 0) {
|
|
3002
|
+
throw new Error(`u64 value cannot be negative: ${u64}`);
|
|
3003
|
+
}
|
|
3004
|
+
ser.serializeU64(u64);
|
|
3005
|
+
break;
|
|
3006
|
+
case "u128":
|
|
3007
|
+
const u128 = typeof value === "string" ? BigInt(value) : typeof value === "number" ? BigInt(value) : value;
|
|
3008
|
+
if (u128 < 0) {
|
|
3009
|
+
throw new Error(`u128 value cannot be negative: ${u128}`);
|
|
3010
|
+
}
|
|
3011
|
+
ser.serializeU128(u128);
|
|
3012
|
+
break;
|
|
3013
|
+
case "u256":
|
|
3014
|
+
if (typeof value !== "bigint") {
|
|
3015
|
+
throw new Error(`Expected bigint for u256, got ${typeof value}`);
|
|
3016
|
+
}
|
|
3017
|
+
ser.serializeU256(value);
|
|
3018
|
+
break;
|
|
3019
|
+
case "bool":
|
|
3020
|
+
if (typeof value !== "boolean") {
|
|
3021
|
+
throw new Error(`Expected boolean, got ${typeof value}`);
|
|
3022
|
+
}
|
|
3023
|
+
ser.serializeBool(value);
|
|
3024
|
+
break;
|
|
3025
|
+
case "0x1::string::String":
|
|
3026
|
+
if (typeof value !== "string") {
|
|
3027
|
+
throw new Error(`Expected string, got ${typeof value}`);
|
|
3028
|
+
}
|
|
3029
|
+
ser.serializeStr(value);
|
|
3030
|
+
break;
|
|
3031
|
+
default:
|
|
3032
|
+
throw new Error(`Unsupported type: ${type}`);
|
|
3033
|
+
}
|
|
3034
|
+
return shouldReturnBytes ? ser.getBytes() : new Uint8Array(0);
|
|
3035
|
+
},
|
|
3036
|
+
[]
|
|
3037
|
+
);
|
|
3038
|
+
const serializeArgsFromTypes = useCallback4(
|
|
3039
|
+
(args, paramTypes) => {
|
|
3040
|
+
if (args.length !== paramTypes.length) {
|
|
3041
|
+
throw new Error(
|
|
3042
|
+
`Argument count mismatch: expected ${paramTypes.length}, got ${args.length}`
|
|
3043
|
+
);
|
|
3044
|
+
}
|
|
3045
|
+
return args.map((arg, index) => {
|
|
3046
|
+
try {
|
|
3047
|
+
const paramType = paramTypes[index].replace("&signer", "").trim();
|
|
3048
|
+
return serializeValueByType(arg, paramType);
|
|
3049
|
+
} catch (error) {
|
|
3050
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3051
|
+
throw new Error(
|
|
3052
|
+
`Failed to serialize argument ${index} (${paramTypes[index]}): ${errorMessage}`
|
|
3053
|
+
);
|
|
3054
|
+
}
|
|
3055
|
+
});
|
|
3056
|
+
},
|
|
3057
|
+
[serializeValueByType]
|
|
3058
|
+
);
|
|
3059
|
+
const fetchModuleABI = useCallback4(
|
|
3060
|
+
async (moduleAddress, moduleName, rpcUrl) => {
|
|
3061
|
+
const storedABI = getStoredABI(moduleAddress, moduleName);
|
|
3062
|
+
if (storedABI) {
|
|
3063
|
+
return storedABI;
|
|
3064
|
+
}
|
|
3065
|
+
const baseUrl = rpcUrl || (process.env.NEXT_PUBLIC_SUPRA_CHAIN_ID === "8" ? "https://rpc-mainnet.supra.com" : "https://rpc-testnet.supra.com");
|
|
3066
|
+
const url = `${baseUrl}/rpc/v3/accounts/${moduleAddress}/modules/${moduleName}`;
|
|
3067
|
+
try {
|
|
3068
|
+
const response = await fetch(url);
|
|
3069
|
+
if (!response.ok) {
|
|
3070
|
+
throw new Error(`Failed to fetch ABI: ${response.statusText}`);
|
|
3071
|
+
}
|
|
3072
|
+
const data = await response.json();
|
|
3073
|
+
return data.abi;
|
|
3074
|
+
} catch (error) {
|
|
3075
|
+
console.error("Error fetching module ABI:", error);
|
|
3076
|
+
throw new Error(
|
|
3077
|
+
`Failed to fetch module ABI: ${error instanceof Error ? error.message : String(error)}`
|
|
3078
|
+
);
|
|
3079
|
+
}
|
|
3080
|
+
},
|
|
3081
|
+
[]
|
|
3082
|
+
);
|
|
3083
|
+
const getFunctionParamTypes = useCallback4(
|
|
3084
|
+
async (moduleAddress, moduleName, functionName, rpcUrl) => {
|
|
3085
|
+
const moduleABI = await fetchModuleABI(moduleAddress, moduleName, rpcUrl);
|
|
3086
|
+
if (!moduleABI.exposed_functions) {
|
|
3087
|
+
throw new Error("Invalid module ABI response");
|
|
3088
|
+
}
|
|
3089
|
+
const functionDef = moduleABI.exposed_functions.find(
|
|
3090
|
+
(func) => func.name === functionName
|
|
3091
|
+
);
|
|
3092
|
+
if (!functionDef) {
|
|
3093
|
+
throw new Error(`Function ${functionName} not found in module ${moduleName}`);
|
|
3094
|
+
}
|
|
3095
|
+
return functionDef.params.filter((param) => {
|
|
3096
|
+
const trimmed = param.trim();
|
|
3097
|
+
return trimmed !== "signer" && trimmed !== "&signer";
|
|
3098
|
+
});
|
|
3099
|
+
},
|
|
3100
|
+
[fetchModuleABI]
|
|
3101
|
+
);
|
|
3102
|
+
const serializeTransactionArgs = useCallback4(
|
|
3103
|
+
async (args, moduleAddress, moduleName, functionName, rpcUrl) => {
|
|
3104
|
+
const paramTypes = await getFunctionParamTypes(
|
|
3105
|
+
moduleAddress,
|
|
3106
|
+
moduleName,
|
|
3107
|
+
functionName,
|
|
3108
|
+
rpcUrl
|
|
3109
|
+
);
|
|
3110
|
+
return serializeArgsFromTypes(args, paramTypes);
|
|
3111
|
+
},
|
|
3112
|
+
[getFunctionParamTypes, serializeArgsFromTypes]
|
|
3113
|
+
);
|
|
3114
|
+
return {
|
|
3115
|
+
stringToUint8Array,
|
|
3116
|
+
addressToUint8Array,
|
|
3117
|
+
serializeString,
|
|
3118
|
+
serializeUint8,
|
|
3119
|
+
serializeUint16,
|
|
3120
|
+
serializeUint32,
|
|
3121
|
+
serializeUint64,
|
|
3122
|
+
serializeUint128,
|
|
3123
|
+
serializeU256,
|
|
3124
|
+
serializeBool,
|
|
3125
|
+
serializeVector,
|
|
3126
|
+
deserializeString,
|
|
3127
|
+
deserializeVector,
|
|
3128
|
+
hexToString,
|
|
3129
|
+
stringToHex,
|
|
3130
|
+
// ABI-based serialization
|
|
3131
|
+
serializeValueByType,
|
|
3132
|
+
serializeArgsFromTypes,
|
|
3133
|
+
fetchModuleABI,
|
|
3134
|
+
getFunctionParamTypes,
|
|
3135
|
+
serializeTransactionArgs
|
|
3136
|
+
// Main function to use
|
|
3137
|
+
};
|
|
3138
|
+
};
|
|
3139
|
+
var useConversionUtils_default = useConversionUtils;
|
|
3140
|
+
|
|
3141
|
+
// src/components/ui/button.tsx
|
|
3142
|
+
import * as React3 from "react";
|
|
3143
|
+
import { Slot as Slot2 } from "@radix-ui/react-slot";
|
|
3144
|
+
import { cva as cva2 } from "class-variance-authority";
|
|
3145
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
3146
|
+
var buttonVariants2 = cva2(
|
|
3147
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
3148
|
+
{
|
|
3149
|
+
variants: {
|
|
3150
|
+
variant: {
|
|
3151
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
3152
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
3153
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
3154
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
3155
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
3156
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
3157
|
+
},
|
|
3158
|
+
size: {
|
|
3159
|
+
default: "h-10 px-4 py-2",
|
|
3160
|
+
sm: "h-9 rounded-md px-3",
|
|
3161
|
+
lg: "h-11 rounded-md px-8",
|
|
3162
|
+
icon: "h-10 w-10"
|
|
3163
|
+
}
|
|
3164
|
+
},
|
|
3165
|
+
defaultVariants: {
|
|
3166
|
+
variant: "default",
|
|
3167
|
+
size: "default"
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
);
|
|
3171
|
+
var Button2 = React3.forwardRef(
|
|
3172
|
+
(_a, ref) => {
|
|
3173
|
+
var _b = _a, { className, variant, size, asChild = false } = _b, props = __objRest(_b, ["className", "variant", "size", "asChild"]);
|
|
3174
|
+
const Comp = asChild ? Slot2 : "button";
|
|
3175
|
+
return /* @__PURE__ */ jsx4(
|
|
3176
|
+
Comp,
|
|
3177
|
+
__spreadValues({
|
|
3178
|
+
className: cn2(buttonVariants2({ variant, size, className })),
|
|
3179
|
+
ref
|
|
3180
|
+
}, props)
|
|
3181
|
+
);
|
|
3182
|
+
}
|
|
3183
|
+
);
|
|
3184
|
+
Button2.displayName = "Button";
|
|
3185
|
+
|
|
3186
|
+
// src/components/ui/dialog.tsx
|
|
3187
|
+
import * as React4 from "react";
|
|
3188
|
+
import * as DialogPrimitive2 from "@radix-ui/react-dialog";
|
|
3189
|
+
import { X as X3 } from "lucide-react";
|
|
3190
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
3191
|
+
var Dialog2 = DialogPrimitive2.Root;
|
|
3192
|
+
var DialogTrigger = DialogPrimitive2.Trigger;
|
|
3193
|
+
var DialogPortal2 = DialogPrimitive2.Portal;
|
|
3194
|
+
var DialogClose = DialogPrimitive2.Close;
|
|
3195
|
+
var DialogOverlay2 = React4.forwardRef((_a, ref) => {
|
|
3196
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
3197
|
+
return /* @__PURE__ */ jsx5(DialogPortal2, { children: /* @__PURE__ */ jsx5(
|
|
3198
|
+
DialogPrimitive2.Overlay,
|
|
3199
|
+
__spreadValues({
|
|
3200
|
+
ref,
|
|
3201
|
+
className: cn2(
|
|
3202
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
3203
|
+
className
|
|
3204
|
+
)
|
|
3205
|
+
}, props)
|
|
3206
|
+
) });
|
|
3207
|
+
});
|
|
3208
|
+
DialogOverlay2.displayName = DialogPrimitive2.Overlay.displayName;
|
|
3209
|
+
var DialogContent2 = React4.forwardRef((_a, ref) => {
|
|
3210
|
+
var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
|
|
3211
|
+
return /* @__PURE__ */ jsxs3(DialogPortal2, { children: [
|
|
3212
|
+
/* @__PURE__ */ jsx5(DialogOverlay2, {}),
|
|
3213
|
+
/* @__PURE__ */ jsxs3(
|
|
3214
|
+
DialogPrimitive2.Content,
|
|
3215
|
+
__spreadProps(__spreadValues({
|
|
3216
|
+
ref,
|
|
3217
|
+
className: cn2(
|
|
3218
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
|
3219
|
+
className
|
|
3220
|
+
)
|
|
3221
|
+
}, props), {
|
|
3222
|
+
children: [
|
|
3223
|
+
children,
|
|
3224
|
+
/* @__PURE__ */ jsxs3(DialogPrimitive2.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
|
|
3225
|
+
/* @__PURE__ */ jsx5(X3, { className: "h-4 w-4" }),
|
|
3226
|
+
/* @__PURE__ */ jsx5("span", { className: "sr-only", children: "Close" })
|
|
3227
|
+
] })
|
|
3228
|
+
]
|
|
3229
|
+
})
|
|
3230
|
+
)
|
|
3231
|
+
] });
|
|
3232
|
+
});
|
|
3233
|
+
DialogContent2.displayName = DialogPrimitive2.Content.displayName;
|
|
3234
|
+
var DialogHeader2 = (_a) => {
|
|
3235
|
+
var _b = _a, {
|
|
3236
|
+
className
|
|
3237
|
+
} = _b, props = __objRest(_b, [
|
|
3238
|
+
"className"
|
|
3239
|
+
]);
|
|
3240
|
+
return /* @__PURE__ */ jsx5(
|
|
3241
|
+
"div",
|
|
3242
|
+
__spreadValues({
|
|
3243
|
+
className: cn2(
|
|
3244
|
+
"flex flex-col space-y-1.5 text-center sm:text-left",
|
|
3245
|
+
className
|
|
3246
|
+
)
|
|
3247
|
+
}, props)
|
|
3248
|
+
);
|
|
3249
|
+
};
|
|
3250
|
+
DialogHeader2.displayName = "DialogHeader";
|
|
3251
|
+
var DialogFooter2 = (_a) => {
|
|
3252
|
+
var _b = _a, {
|
|
3253
|
+
className
|
|
3254
|
+
} = _b, props = __objRest(_b, [
|
|
3255
|
+
"className"
|
|
3256
|
+
]);
|
|
3257
|
+
return /* @__PURE__ */ jsx5(
|
|
3258
|
+
"div",
|
|
3259
|
+
__spreadValues({
|
|
3260
|
+
className: cn2(
|
|
3261
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
3262
|
+
className
|
|
3263
|
+
)
|
|
3264
|
+
}, props)
|
|
3265
|
+
);
|
|
3266
|
+
};
|
|
3267
|
+
DialogFooter2.displayName = "DialogFooter";
|
|
3268
|
+
var DialogTitle2 = React4.forwardRef((_a, ref) => {
|
|
3269
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
3270
|
+
return /* @__PURE__ */ jsx5(
|
|
3271
|
+
DialogPrimitive2.Title,
|
|
3272
|
+
__spreadValues({
|
|
3273
|
+
ref,
|
|
3274
|
+
className: cn2(
|
|
3275
|
+
"text-lg font-semibold leading-none tracking-tight",
|
|
3276
|
+
className
|
|
3277
|
+
)
|
|
3278
|
+
}, props)
|
|
3279
|
+
);
|
|
3280
|
+
});
|
|
3281
|
+
DialogTitle2.displayName = DialogPrimitive2.Title.displayName;
|
|
3282
|
+
var DialogDescription2 = React4.forwardRef((_a, ref) => {
|
|
3283
|
+
var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
|
|
3284
|
+
return /* @__PURE__ */ jsx5(
|
|
3285
|
+
DialogPrimitive2.Description,
|
|
3286
|
+
__spreadValues({
|
|
3287
|
+
ref,
|
|
3288
|
+
className: cn2("text-sm text-muted-foreground", className)
|
|
3289
|
+
}, props)
|
|
3290
|
+
);
|
|
3291
|
+
});
|
|
3292
|
+
DialogDescription2.displayName = DialogPrimitive2.Description.displayName;
|
|
3293
|
+
|
|
3294
|
+
// src/components/ui/sonner.tsx
|
|
3295
|
+
import { Toaster as Sonner } from "sonner";
|
|
3296
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
3297
|
+
var Toaster = (_a) => {
|
|
3298
|
+
var _b = _a, { theme = "system" } = _b, props = __objRest(_b, ["theme"]);
|
|
3299
|
+
return /* @__PURE__ */ jsx6(
|
|
3300
|
+
Sonner,
|
|
3301
|
+
__spreadValues({
|
|
3302
|
+
theme,
|
|
3303
|
+
className: "toaster group",
|
|
3304
|
+
toastOptions: {
|
|
3305
|
+
classNames: {
|
|
3306
|
+
toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
|
|
3307
|
+
description: "group-[.toast]:text-muted-foreground",
|
|
3308
|
+
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
|
3309
|
+
cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground"
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
}, props)
|
|
3313
|
+
);
|
|
3314
|
+
};
|
|
3315
|
+
|
|
3316
|
+
// src/assets/walletIcons/index.ts
|
|
3317
|
+
var WALLET_ICONS = {
|
|
3318
|
+
starkey: Starkey_default,
|
|
3319
|
+
ribbit: Ribbit_default
|
|
3320
|
+
};
|
|
3321
|
+
export {
|
|
3322
|
+
Button2 as Button,
|
|
3323
|
+
ConnectWalletHandler,
|
|
3324
|
+
Dialog2 as Dialog,
|
|
3325
|
+
DialogClose,
|
|
3326
|
+
DialogContent2 as DialogContent,
|
|
3327
|
+
DialogDescription2 as DialogDescription,
|
|
3328
|
+
DialogFooter2 as DialogFooter,
|
|
3329
|
+
DialogHeader2 as DialogHeader,
|
|
3330
|
+
DialogOverlay2 as DialogOverlay,
|
|
3331
|
+
DialogPortal2 as DialogPortal,
|
|
3332
|
+
DialogTitle2 as DialogTitle,
|
|
3333
|
+
DialogTrigger,
|
|
3334
|
+
Toaster,
|
|
3335
|
+
WALLET_EVENTS2 as WALLET_EVENTS,
|
|
3336
|
+
WALLET_ICONS,
|
|
3337
|
+
buttonVariants2 as buttonVariants,
|
|
3338
|
+
cn2 as cn,
|
|
3339
|
+
getStoredABI,
|
|
3340
|
+
Ribbit_default as ribbitIcon,
|
|
3341
|
+
standardizeAddress,
|
|
3342
|
+
Starkey_default as starkeyIcon,
|
|
3343
|
+
useConversionUtils_default as useConversionUtils,
|
|
3344
|
+
useSupraMultiWallet_default2 as useSupraMultiWallet
|
|
3345
|
+
};
|
|
3346
|
+
//# sourceMappingURL=index.mjs.map
|