@cookill/wallet-adapter 3.1.7 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +14 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1092 -886
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +17 -1
- package/dist/react.d.ts +17 -1
- package/dist/react.js +1208 -1003
- package/dist/react.js.map +1 -1
- package/dist/standard.cjs.map +1 -1
- package/dist/standard.js.map +1 -1
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import React2, { createContext, useState, useRef, useEffect, useCallback, useReducer, useMemo, useContext, Component } from 'react';
|
|
2
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/core/types.ts
|
|
5
5
|
var NETWORKS = {
|
|
@@ -51,6 +51,14 @@ var NETWORKS = {
|
|
|
51
51
|
|
|
52
52
|
// src/core/provider.ts
|
|
53
53
|
function isInstalled() {
|
|
54
|
+
if (typeof window === "undefined") return false;
|
|
55
|
+
try {
|
|
56
|
+
return !!window.rialo?.isRialo && !window.rialo?.isWebWallet;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function hasProvider() {
|
|
54
62
|
if (typeof window === "undefined") return false;
|
|
55
63
|
try {
|
|
56
64
|
return !!window.rialo?.isRialo;
|
|
@@ -158,9 +166,14 @@ var SheepWallet = class {
|
|
|
158
166
|
// =========================================================================
|
|
159
167
|
// Getters (all synchronous, never block)
|
|
160
168
|
// =========================================================================
|
|
169
|
+
/** True only if the browser extension is installed (not web wallet) */
|
|
161
170
|
get isInstalled() {
|
|
162
171
|
return isInstalled();
|
|
163
172
|
}
|
|
173
|
+
/** True if any provider (extension or web wallet) is available */
|
|
174
|
+
get hasProvider() {
|
|
175
|
+
return hasProvider();
|
|
176
|
+
}
|
|
164
177
|
get connected() {
|
|
165
178
|
return this._connected;
|
|
166
179
|
}
|
|
@@ -185,7 +198,7 @@ var SheepWallet = class {
|
|
|
185
198
|
async connect() {
|
|
186
199
|
this._provider = getProvider();
|
|
187
200
|
if (!this._provider) {
|
|
188
|
-
throw new Error("Sheep Wallet
|
|
201
|
+
throw new Error("No wallet provider found. Install Sheep Wallet extension or set up a web wallet.");
|
|
189
202
|
}
|
|
190
203
|
try {
|
|
191
204
|
const rawAccounts = await withTimeout(
|
|
@@ -556,586 +569,690 @@ var SheepWallet = class {
|
|
|
556
569
|
);
|
|
557
570
|
}
|
|
558
571
|
};
|
|
559
|
-
var
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
572
|
+
var IconClose = () => /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
573
|
+
/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
|
|
574
|
+
/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
|
|
575
|
+
] });
|
|
576
|
+
var IconExtension = () => /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
577
|
+
/* @__PURE__ */ jsx("path", { d: "M16 3h5v5" }),
|
|
578
|
+
/* @__PURE__ */ jsx("path", { d: "M8 3H3v5" }),
|
|
579
|
+
/* @__PURE__ */ jsx("path", { d: "M12 22v-8.3a4 4 0 0 0-1.172-2.872L3 3" }),
|
|
580
|
+
/* @__PURE__ */ jsx("path", { d: "m15 9 6-6" })
|
|
581
|
+
] });
|
|
582
|
+
var IconQR = () => /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
583
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "7", height: "7" }),
|
|
584
|
+
/* @__PURE__ */ jsx("rect", { x: "14", y: "3", width: "7", height: "7" }),
|
|
585
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "14", width: "7", height: "7" }),
|
|
586
|
+
/* @__PURE__ */ jsx("path", { d: "M14 14h7v7h-7z" })
|
|
587
|
+
] });
|
|
588
|
+
var IconWeb = () => /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
589
|
+
/* @__PURE__ */ jsx("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
|
|
590
|
+
/* @__PURE__ */ jsx("path", { d: "M2 10h20" }),
|
|
591
|
+
/* @__PURE__ */ jsx("path", { d: "M12 17v4" }),
|
|
592
|
+
/* @__PURE__ */ jsx("path", { d: "M8 21h8" })
|
|
593
|
+
] });
|
|
594
|
+
var IconCheck = () => /* @__PURE__ */ jsx("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "#6EB9A8", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) });
|
|
595
|
+
var IconCamera = () => /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
596
|
+
/* @__PURE__ */ jsx("path", { d: "M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z" }),
|
|
597
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "13", r: "3" })
|
|
598
|
+
] });
|
|
599
|
+
var IconRefresh = () => /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
600
|
+
/* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" }),
|
|
601
|
+
/* @__PURE__ */ jsx("path", { d: "M21 3v5h-5" })
|
|
602
|
+
] });
|
|
603
|
+
var S = {
|
|
604
|
+
backdrop: {
|
|
605
|
+
position: "absolute",
|
|
606
|
+
inset: 0,
|
|
607
|
+
backgroundColor: "rgba(0,0,0,0.6)",
|
|
608
|
+
backdropFilter: "blur(8px)",
|
|
609
|
+
WebkitBackdropFilter: "blur(8px)"
|
|
610
|
+
},
|
|
611
|
+
dialog: {
|
|
612
|
+
pointerEvents: "auto",
|
|
613
|
+
backgroundColor: "#011B29",
|
|
614
|
+
borderRadius: "20px",
|
|
615
|
+
padding: "24px",
|
|
616
|
+
width: "100%",
|
|
617
|
+
maxWidth: "400px",
|
|
618
|
+
margin: "16px",
|
|
619
|
+
boxShadow: "0 25px 60px -12px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.05)",
|
|
620
|
+
maxHeight: "90vh",
|
|
621
|
+
overflow: "auto",
|
|
622
|
+
animation: "swModalFadeIn 0.25s cubic-bezier(0.4,0,0.2,1)"
|
|
623
|
+
},
|
|
624
|
+
header: {
|
|
625
|
+
display: "flex",
|
|
626
|
+
justifyContent: "space-between",
|
|
627
|
+
alignItems: "center",
|
|
628
|
+
marginBottom: "20px"
|
|
629
|
+
},
|
|
630
|
+
title: { color: "#fff", fontSize: "18px", fontWeight: 600, margin: 0, letterSpacing: "-0.01em" },
|
|
631
|
+
closeBtn: {
|
|
632
|
+
background: "none",
|
|
633
|
+
border: "none",
|
|
634
|
+
color: "rgba(255,255,255,0.3)",
|
|
635
|
+
cursor: "pointer",
|
|
636
|
+
padding: "6px",
|
|
637
|
+
borderRadius: "8px",
|
|
638
|
+
display: "flex",
|
|
639
|
+
alignItems: "center",
|
|
640
|
+
justifyContent: "center",
|
|
641
|
+
transition: "all 0.15s"
|
|
642
|
+
},
|
|
643
|
+
tabBar: {
|
|
644
|
+
display: "flex",
|
|
645
|
+
gap: "4px",
|
|
646
|
+
padding: "4px",
|
|
647
|
+
backgroundColor: "rgba(255,255,255,0.04)",
|
|
648
|
+
borderRadius: "14px",
|
|
649
|
+
marginBottom: "20px"
|
|
650
|
+
},
|
|
651
|
+
walletBtn: (isConnecting) => ({
|
|
652
|
+
width: "100%",
|
|
653
|
+
display: "flex",
|
|
654
|
+
alignItems: "center",
|
|
655
|
+
gap: "14px",
|
|
656
|
+
padding: "16px",
|
|
657
|
+
backgroundColor: "rgba(255,255,255,0.04)",
|
|
658
|
+
border: "1px solid rgba(255,255,255,0.08)",
|
|
659
|
+
borderRadius: "14px",
|
|
660
|
+
cursor: isConnecting ? "wait" : "pointer",
|
|
661
|
+
transition: "all 0.15s",
|
|
662
|
+
color: "inherit"
|
|
663
|
+
}),
|
|
664
|
+
walletIcon: {
|
|
665
|
+
width: "44px",
|
|
666
|
+
height: "44px",
|
|
667
|
+
borderRadius: "12px",
|
|
668
|
+
background: "linear-gradient(135deg, #6EB9A8, #4a9a8a)",
|
|
669
|
+
display: "flex",
|
|
670
|
+
alignItems: "center",
|
|
671
|
+
justifyContent: "center",
|
|
672
|
+
color: "#fff",
|
|
673
|
+
fontWeight: 700,
|
|
674
|
+
fontSize: "18px",
|
|
675
|
+
flexShrink: 0
|
|
676
|
+
},
|
|
677
|
+
badge: (color) => ({
|
|
678
|
+
padding: "5px 10px",
|
|
679
|
+
backgroundColor: `${color}10`,
|
|
680
|
+
borderRadius: "8px",
|
|
681
|
+
border: `1px solid ${color}18`,
|
|
682
|
+
display: "flex",
|
|
683
|
+
alignItems: "center",
|
|
684
|
+
gap: "6px"
|
|
685
|
+
}),
|
|
686
|
+
input: {
|
|
687
|
+
width: "100%",
|
|
688
|
+
padding: "12px 14px",
|
|
689
|
+
backgroundColor: "rgba(255,255,255,0.04)",
|
|
690
|
+
border: "1px solid rgba(255,255,255,0.1)",
|
|
691
|
+
borderRadius: "12px",
|
|
692
|
+
color: "#fff",
|
|
693
|
+
fontSize: "14px",
|
|
694
|
+
marginBottom: "12px",
|
|
695
|
+
outline: "none",
|
|
696
|
+
boxSizing: "border-box"
|
|
697
|
+
},
|
|
698
|
+
primaryBtn: (loading) => ({
|
|
699
|
+
width: "100%",
|
|
700
|
+
padding: "12px",
|
|
701
|
+
backgroundColor: "#6EB9A8",
|
|
702
|
+
border: "none",
|
|
703
|
+
borderRadius: "12px",
|
|
704
|
+
color: "#011B29",
|
|
705
|
+
fontSize: "14px",
|
|
706
|
+
fontWeight: 600,
|
|
707
|
+
cursor: loading ? "wait" : "pointer",
|
|
708
|
+
opacity: loading ? 0.6 : 1
|
|
709
|
+
}),
|
|
710
|
+
error: {
|
|
711
|
+
marginTop: "16px",
|
|
712
|
+
padding: "12px 14px",
|
|
713
|
+
backgroundColor: "rgba(239,68,68,0.08)",
|
|
714
|
+
border: "1px solid rgba(239,68,68,0.15)",
|
|
715
|
+
borderRadius: "12px",
|
|
716
|
+
color: "#f87171",
|
|
717
|
+
fontSize: "13px",
|
|
718
|
+
lineHeight: 1.4
|
|
602
719
|
}
|
|
720
|
+
};
|
|
721
|
+
function tabStyle(active) {
|
|
722
|
+
return {
|
|
723
|
+
flex: 1,
|
|
724
|
+
padding: "10px 0",
|
|
725
|
+
border: "none",
|
|
726
|
+
borderRadius: "10px",
|
|
727
|
+
fontSize: "13px",
|
|
728
|
+
cursor: "pointer",
|
|
729
|
+
transition: "all 0.2s",
|
|
730
|
+
display: "flex",
|
|
731
|
+
alignItems: "center",
|
|
732
|
+
justifyContent: "center",
|
|
733
|
+
gap: "6px",
|
|
734
|
+
backgroundColor: active ? "rgba(255,255,255,0.08)" : "transparent",
|
|
735
|
+
color: active ? "#6EB9A8" : "rgba(255,255,255,0.4)",
|
|
736
|
+
fontWeight: active ? 600 : 400
|
|
737
|
+
};
|
|
603
738
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
function WalletProvider({
|
|
617
|
-
children,
|
|
618
|
-
network: initialNetwork = "devnet",
|
|
619
|
-
autoConnect = true,
|
|
620
|
-
wallets: customWallets = [],
|
|
621
|
-
scanConnectRelay = "wss://relay.rialo.io",
|
|
622
|
-
onConnect,
|
|
623
|
-
onDisconnect,
|
|
624
|
-
onError,
|
|
625
|
-
onNetworkChange
|
|
626
|
-
}) {
|
|
627
|
-
const [state, dispatch] = useReducer(walletReducer, {
|
|
628
|
-
...initialState,
|
|
629
|
-
network: initialNetwork
|
|
630
|
-
});
|
|
631
|
-
const walletRef = useRef(null);
|
|
632
|
-
const providerRef = useRef(void 0);
|
|
633
|
-
const connectingRef = useRef(false);
|
|
634
|
-
const mountedRef = useRef(true);
|
|
635
|
-
useEffect(() => {
|
|
636
|
-
mountedRef.current = true;
|
|
637
|
-
walletRef.current = new SheepWallet();
|
|
638
|
-
waitForProvider(3e3).then((provider) => {
|
|
639
|
-
if (mountedRef.current) {
|
|
640
|
-
providerRef.current = provider;
|
|
641
|
-
}
|
|
642
|
-
});
|
|
643
|
-
return () => {
|
|
644
|
-
mountedRef.current = false;
|
|
645
|
-
walletRef.current?.destroy();
|
|
646
|
-
};
|
|
647
|
-
}, []);
|
|
648
|
-
useEffect(() => {
|
|
649
|
-
const setupEvents = async () => {
|
|
650
|
-
const provider = await waitForProvider(3e3);
|
|
651
|
-
if (!provider || !mountedRef.current) return;
|
|
652
|
-
providerRef.current = provider;
|
|
653
|
-
const cleanups = [];
|
|
654
|
-
cleanups.push(
|
|
655
|
-
provider.on("disconnect", () => {
|
|
656
|
-
if (!mountedRef.current) return;
|
|
657
|
-
dispatch({ type: "DISCONNECTED" });
|
|
658
|
-
onDisconnect?.();
|
|
659
|
-
})
|
|
660
|
-
);
|
|
661
|
-
cleanups.push(
|
|
662
|
-
provider.on("accountsChanged", (data) => {
|
|
663
|
-
if (!mountedRef.current) return;
|
|
664
|
-
const accounts = normalizeAccounts(data);
|
|
665
|
-
dispatch({ type: "SET_ACCOUNTS", accounts });
|
|
666
|
-
})
|
|
667
|
-
);
|
|
668
|
-
cleanups.push(
|
|
669
|
-
provider.on("networkChanged", (data) => {
|
|
670
|
-
if (!mountedRef.current) return;
|
|
671
|
-
const { network } = data;
|
|
672
|
-
if (network) {
|
|
673
|
-
dispatch({ type: "SET_NETWORK", network });
|
|
674
|
-
onNetworkChange?.(network);
|
|
675
|
-
}
|
|
676
|
-
})
|
|
677
|
-
);
|
|
678
|
-
return () => {
|
|
679
|
-
cleanups.forEach((fn) => {
|
|
680
|
-
try {
|
|
681
|
-
fn();
|
|
682
|
-
} catch {
|
|
739
|
+
function ExtensionTab({ onConnect, extensionDetected, connecting, error }) {
|
|
740
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
741
|
+
/* @__PURE__ */ jsxs(
|
|
742
|
+
"button",
|
|
743
|
+
{
|
|
744
|
+
type: "button",
|
|
745
|
+
onClick: (e) => {
|
|
746
|
+
e.stopPropagation();
|
|
747
|
+
if (extensionDetected) {
|
|
748
|
+
onConnect();
|
|
749
|
+
} else {
|
|
750
|
+
window.open("https://rialo.io/wallet", "_blank");
|
|
683
751
|
}
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
752
|
+
},
|
|
753
|
+
disabled: connecting,
|
|
754
|
+
style: S.walletBtn(connecting),
|
|
755
|
+
onMouseEnter: (e) => {
|
|
756
|
+
e.currentTarget.style.backgroundColor = "rgba(255,255,255,0.07)";
|
|
757
|
+
},
|
|
758
|
+
onMouseLeave: (e) => {
|
|
759
|
+
e.currentTarget.style.backgroundColor = "rgba(255,255,255,0.04)";
|
|
760
|
+
},
|
|
761
|
+
children: [
|
|
762
|
+
/* @__PURE__ */ jsx("div", { style: S.walletIcon, children: "S" }),
|
|
763
|
+
/* @__PURE__ */ jsxs("div", { style: { flex: 1, textAlign: "left" }, children: [
|
|
764
|
+
/* @__PURE__ */ jsx("div", { style: { color: "#fff", fontWeight: 500, fontSize: "15px", marginBottom: "2px" }, children: "Sheep Wallet" }),
|
|
765
|
+
/* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: extensionDetected ? "#6EB9A8" : "rgba(255,255,255,0.4)", display: "flex", alignItems: "center", gap: "5px" }, children: connecting ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
766
|
+
/* @__PURE__ */ jsx("span", { style: { display: "inline-block", width: "6px", height: "6px", borderRadius: "50%", backgroundColor: "#F59E0B", animation: "swModalPulse 1.2s infinite" } }),
|
|
767
|
+
"Connecting..."
|
|
768
|
+
] }) : extensionDetected ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
769
|
+
/* @__PURE__ */ jsx("span", { style: { display: "inline-block", width: "6px", height: "6px", borderRadius: "50%", backgroundColor: "#6EB9A8" } }),
|
|
770
|
+
"Detected \u2014 Click to connect"
|
|
771
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
772
|
+
/* @__PURE__ */ jsx("span", { style: { display: "inline-block", width: "6px", height: "6px", borderRadius: "50%", backgroundColor: "rgba(255,255,255,0.2)" } }),
|
|
773
|
+
"Not installed"
|
|
774
|
+
] }) })
|
|
775
|
+
] }),
|
|
776
|
+
!extensionDetected && /* @__PURE__ */ jsx("span", { style: { color: "#6EB9A8", fontSize: "12px", fontWeight: 500, padding: "4px 10px", borderRadius: "8px", backgroundColor: "rgba(110,185,168,0.1)" }, children: "Install" })
|
|
777
|
+
]
|
|
705
778
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
779
|
+
),
|
|
780
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "8px", marginTop: "16px", flexWrap: "wrap" }, children: [
|
|
781
|
+
{ label: "REX", desc: "Confidential TX", color: "#8B5CF6" },
|
|
782
|
+
{ label: "SfS", desc: "Gasless TX", color: "#F59E0B" },
|
|
783
|
+
{ label: "QR", desc: "Scan Connect", color: "#6EB9A8" }
|
|
784
|
+
].map((b) => /* @__PURE__ */ jsxs("div", { style: S.badge(b.color), children: [
|
|
785
|
+
/* @__PURE__ */ jsx("span", { style: { color: b.color, fontSize: "11px", fontWeight: 600 }, children: b.label }),
|
|
786
|
+
/* @__PURE__ */ jsx("span", { style: { color: "rgba(255,255,255,0.35)", fontSize: "10px" }, children: b.desc })
|
|
787
|
+
] }, b.label)) }),
|
|
788
|
+
error && /* @__PURE__ */ jsx("div", { style: S.error, children: error.message })
|
|
789
|
+
] });
|
|
790
|
+
}
|
|
791
|
+
function ScanTab({ scanConnectRelay }) {
|
|
792
|
+
const [scanMode, setScanMode] = useState("show-qr");
|
|
793
|
+
const [generatedURI, setGeneratedURI] = useState(null);
|
|
794
|
+
const canvasRef = useRef(null);
|
|
795
|
+
const generateSession = useCallback(() => {
|
|
796
|
+
const sessionId = crypto.randomUUID();
|
|
797
|
+
const topic = btoa(sessionId).slice(0, 32);
|
|
798
|
+
const uri = `rialo-wc://${sessionId}?relay=${encodeURIComponent(scanConnectRelay)}&topic=${topic}&networks=devnet`;
|
|
799
|
+
setGeneratedURI(uri);
|
|
800
|
+
}, [scanConnectRelay]);
|
|
710
801
|
useEffect(() => {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
802
|
+
generateSession();
|
|
803
|
+
}, [generateSession]);
|
|
804
|
+
useEffect(() => {
|
|
805
|
+
if (!generatedURI || !canvasRef.current) return;
|
|
806
|
+
const canvas = canvasRef.current;
|
|
807
|
+
const ctx = canvas.getContext("2d");
|
|
808
|
+
if (!ctx) return;
|
|
809
|
+
const size = 200;
|
|
810
|
+
canvas.width = size;
|
|
811
|
+
canvas.height = size;
|
|
812
|
+
ctx.fillStyle = "#FFFFFF";
|
|
813
|
+
ctx.fillRect(0, 0, size, size);
|
|
814
|
+
ctx.fillStyle = "#011B29";
|
|
815
|
+
const gridSize = 25;
|
|
816
|
+
const cellSize = size / gridSize;
|
|
817
|
+
for (let y = 0; y < gridSize; y++) {
|
|
818
|
+
for (let x = 0; x < gridSize; x++) {
|
|
819
|
+
const isFinderArea = x < 7 && y < 7 || x >= gridSize - 7 && y < 7 || x < 7 && y >= gridSize - 7;
|
|
820
|
+
if (isFinderArea) {
|
|
821
|
+
const isOuter = x === 0 || y === 0 || x === 6 || y === 6 || x === gridSize - 7 || x === gridSize - 1 || y === gridSize - 7 || y === gridSize - 1;
|
|
822
|
+
const isInner = x >= 2 && x <= 4 && y >= 2 && y <= 4 || x >= gridSize - 5 && x <= gridSize - 3 && y >= 2 && y <= 4 || x >= 2 && x <= 4 && y >= gridSize - 5 && y <= gridSize - 3;
|
|
823
|
+
if (isOuter || isInner) ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
|
|
824
|
+
continue;
|
|
719
825
|
}
|
|
720
|
-
|
|
826
|
+
const charIndex = (y * gridSize + x) % generatedURI.length;
|
|
827
|
+
const charCode = generatedURI.charCodeAt(charIndex);
|
|
828
|
+
if (charCode % 3 !== 0) ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
|
|
721
829
|
}
|
|
722
|
-
};
|
|
723
|
-
refresh();
|
|
724
|
-
const interval = setInterval(refresh, 3e4);
|
|
725
|
-
return () => clearInterval(interval);
|
|
726
|
-
}, [state.status, state.accounts]);
|
|
727
|
-
const connect = useCallback(async () => {
|
|
728
|
-
if (connectingRef.current) {
|
|
729
|
-
throw new Error("Connection already in progress");
|
|
730
830
|
}
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
831
|
+
const logoSize = 40;
|
|
832
|
+
const logoX = (size - logoSize) / 2;
|
|
833
|
+
const logoY = (size - logoSize) / 2;
|
|
834
|
+
ctx.beginPath();
|
|
835
|
+
ctx.arc(size / 2, size / 2, logoSize / 2 + 4, 0, Math.PI * 2);
|
|
836
|
+
ctx.fillStyle = "#FFFFFF";
|
|
837
|
+
ctx.fill();
|
|
838
|
+
ctx.beginPath();
|
|
839
|
+
const r = 6;
|
|
840
|
+
ctx.moveTo(logoX + r, logoY);
|
|
841
|
+
ctx.lineTo(logoX + logoSize - r, logoY);
|
|
842
|
+
ctx.quadraticCurveTo(logoX + logoSize, logoY, logoX + logoSize, logoY + r);
|
|
843
|
+
ctx.lineTo(logoX + logoSize, logoY + logoSize - r);
|
|
844
|
+
ctx.quadraticCurveTo(logoX + logoSize, logoY + logoSize, logoX + logoSize - r, logoY + logoSize);
|
|
845
|
+
ctx.lineTo(logoX + r, logoY + logoSize);
|
|
846
|
+
ctx.quadraticCurveTo(logoX, logoY + logoSize, logoX, logoY + logoSize - r);
|
|
847
|
+
ctx.lineTo(logoX, logoY + r);
|
|
848
|
+
ctx.quadraticCurveTo(logoX, logoY, logoX + r, logoY);
|
|
849
|
+
ctx.fillStyle = "#6EB9A8";
|
|
850
|
+
ctx.fill();
|
|
851
|
+
ctx.fillStyle = "#FFFFFF";
|
|
852
|
+
ctx.font = "bold 22px sans-serif";
|
|
853
|
+
ctx.textAlign = "center";
|
|
854
|
+
ctx.textBaseline = "middle";
|
|
855
|
+
ctx.fillText("S", size / 2, size / 2 + 1);
|
|
856
|
+
}, [generatedURI]);
|
|
857
|
+
const stop = (e) => e.stopPropagation();
|
|
858
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
859
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "8px", marginBottom: "16px" }, children: ["show-qr", "scan-qr"].map((mode) => /* @__PURE__ */ jsx(
|
|
860
|
+
"button",
|
|
861
|
+
{
|
|
862
|
+
type: "button",
|
|
863
|
+
onClick: (e) => {
|
|
864
|
+
stop(e);
|
|
865
|
+
setScanMode(mode);
|
|
866
|
+
},
|
|
867
|
+
style: {
|
|
868
|
+
flex: 1,
|
|
869
|
+
padding: "8px",
|
|
870
|
+
display: "flex",
|
|
871
|
+
alignItems: "center",
|
|
872
|
+
justifyContent: "center",
|
|
873
|
+
gap: "6px",
|
|
874
|
+
backgroundColor: scanMode === mode ? "rgba(110,185,168,0.1)" : "transparent",
|
|
875
|
+
border: `1px solid ${scanMode === mode ? "rgba(110,185,168,0.25)" : "rgba(255,255,255,0.08)"}`,
|
|
876
|
+
borderRadius: "10px",
|
|
877
|
+
color: scanMode === mode ? "#6EB9A8" : "rgba(255,255,255,0.4)",
|
|
878
|
+
fontSize: "12px",
|
|
879
|
+
fontWeight: scanMode === mode ? 500 : 400,
|
|
880
|
+
cursor: "pointer",
|
|
881
|
+
transition: "all 0.15s"
|
|
882
|
+
},
|
|
883
|
+
children: mode === "show-qr" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
884
|
+
/* @__PURE__ */ jsx(IconQR, {}),
|
|
885
|
+
" Show QR"
|
|
886
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
887
|
+
/* @__PURE__ */ jsx(IconCamera, {}),
|
|
888
|
+
" Scan QR"
|
|
889
|
+
] })
|
|
890
|
+
},
|
|
891
|
+
mode
|
|
892
|
+
)) }),
|
|
893
|
+
scanMode === "show-qr" && /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
|
|
894
|
+
/* @__PURE__ */ jsx("p", { style: { color: "rgba(255,255,255,0.45)", fontSize: "13px", marginBottom: "16px", lineHeight: 1.5 }, children: "Scan this QR code with Sheep Wallet on your mobile device" }),
|
|
895
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "inline-block", padding: "16px", backgroundColor: "#FFFFFF", borderRadius: "16px", position: "relative" }, children: [
|
|
896
|
+
[
|
|
897
|
+
{ top: -2, left: -2, borderTop: "3px solid #6EB9A8", borderLeft: "3px solid #6EB9A8", borderTopLeftRadius: "12px" },
|
|
898
|
+
{ top: -2, right: -2, borderTop: "3px solid #6EB9A8", borderRight: "3px solid #6EB9A8", borderTopRightRadius: "12px" },
|
|
899
|
+
{ bottom: -2, left: -2, borderBottom: "3px solid #6EB9A8", borderLeft: "3px solid #6EB9A8", borderBottomLeftRadius: "12px" },
|
|
900
|
+
{ bottom: -2, right: -2, borderBottom: "3px solid #6EB9A8", borderRight: "3px solid #6EB9A8", borderBottomRightRadius: "12px" }
|
|
901
|
+
].map((s, i) => /* @__PURE__ */ jsx("div", { style: { position: "absolute", width: "24px", height: "24px", ...s } }, i)),
|
|
902
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, style: { width: "200px", height: "200px", display: "block" } })
|
|
903
|
+
] }),
|
|
904
|
+
/* @__PURE__ */ jsxs("div", { style: { marginTop: "16px", display: "flex", alignItems: "center", justifyContent: "center", gap: "8px" }, children: [
|
|
905
|
+
/* @__PURE__ */ jsx("div", { style: { width: "7px", height: "7px", borderRadius: "50%", backgroundColor: "#6EB9A8", animation: "swModalPulse 2s infinite" } }),
|
|
906
|
+
/* @__PURE__ */ jsx("span", { style: { color: "rgba(255,255,255,0.4)", fontSize: "12px" }, children: "Waiting for wallet to scan..." })
|
|
907
|
+
] }),
|
|
908
|
+
/* @__PURE__ */ jsxs(
|
|
909
|
+
"button",
|
|
910
|
+
{
|
|
911
|
+
type: "button",
|
|
912
|
+
onClick: (e) => {
|
|
913
|
+
stop(e);
|
|
914
|
+
generateSession();
|
|
915
|
+
},
|
|
916
|
+
style: { marginTop: "12px", padding: "8px 16px", backgroundColor: "transparent", border: "1px solid rgba(255,255,255,0.08)", borderRadius: "10px", color: "#6EB9A8", fontSize: "12px", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: "6px" },
|
|
917
|
+
children: [
|
|
918
|
+
/* @__PURE__ */ jsx(IconRefresh, {}),
|
|
919
|
+
" Refresh QR"
|
|
920
|
+
]
|
|
921
|
+
}
|
|
922
|
+
)
|
|
923
|
+
] }),
|
|
924
|
+
scanMode === "scan-qr" && /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
|
|
925
|
+
/* @__PURE__ */ jsx("p", { style: { color: "rgba(255,255,255,0.45)", fontSize: "13px", marginBottom: "16px", lineHeight: 1.5 }, children: "Open Sheep Wallet on another device, go to Settings \u2192 Show Connect QR, then scan it here" }),
|
|
926
|
+
/* @__PURE__ */ jsxs("div", { style: {
|
|
927
|
+
width: "100%",
|
|
928
|
+
height: "200px",
|
|
929
|
+
backgroundColor: "rgba(255,255,255,0.02)",
|
|
930
|
+
borderRadius: "14px",
|
|
931
|
+
border: "1px dashed rgba(255,255,255,0.1)",
|
|
932
|
+
display: "flex",
|
|
933
|
+
flexDirection: "column",
|
|
934
|
+
alignItems: "center",
|
|
935
|
+
justifyContent: "center",
|
|
936
|
+
gap: "12px"
|
|
937
|
+
}, children: [
|
|
938
|
+
/* @__PURE__ */ jsx("div", { style: { color: "rgba(255,255,255,0.2)" }, children: /* @__PURE__ */ jsx(IconCamera, {}) }),
|
|
939
|
+
/* @__PURE__ */ jsx("span", { style: { color: "rgba(255,255,255,0.3)", fontSize: "13px" }, children: "Camera access required" }),
|
|
940
|
+
/* @__PURE__ */ jsx(
|
|
941
|
+
"button",
|
|
942
|
+
{
|
|
943
|
+
type: "button",
|
|
944
|
+
onClick: (e) => {
|
|
945
|
+
stop(e);
|
|
946
|
+
alert("Camera scanning requires HTTPS. This feature works in the installed extension.");
|
|
947
|
+
},
|
|
948
|
+
style: { padding: "8px 20px", backgroundColor: "#6EB9A8", border: "none", borderRadius: "10px", color: "#011B29", fontSize: "13px", fontWeight: 500, cursor: "pointer" },
|
|
949
|
+
children: "Open Camera"
|
|
950
|
+
}
|
|
951
|
+
)
|
|
952
|
+
] })
|
|
953
|
+
] })
|
|
954
|
+
] });
|
|
955
|
+
}
|
|
956
|
+
function WebWalletTab({ onConnected }) {
|
|
957
|
+
const { connect } = useWallet();
|
|
958
|
+
const [mode, setMode] = useState("menu");
|
|
959
|
+
const [password, setPassword] = useState("");
|
|
960
|
+
const [mnemonic, setMnemonic] = useState("");
|
|
961
|
+
const [generatedMnemonic, setGeneratedMnemonic] = useState("");
|
|
962
|
+
const [error, setError] = useState("");
|
|
963
|
+
const [loading, setLoading] = useState(false);
|
|
964
|
+
const stop = (e) => e.stopPropagation();
|
|
965
|
+
const webProvider = typeof window !== "undefined" ? window.rialo : null;
|
|
966
|
+
const isWebProvider = webProvider?.isWebWallet;
|
|
967
|
+
const hasWallet = isWebProvider && webProvider?.hasWallet?.();
|
|
968
|
+
const isUnlocked = isWebProvider && webProvider?.isUnlocked?.();
|
|
969
|
+
const handleAction = async (action) => {
|
|
970
|
+
setError("");
|
|
971
|
+
setLoading(true);
|
|
746
972
|
try {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
dispatch({ type: "CONNECTED", accounts, network: wallet.network });
|
|
750
|
-
onConnect?.(accounts);
|
|
973
|
+
if (!webProvider?.isWebWallet) {
|
|
974
|
+
throw new Error("Web wallet provider not available. Make sure registerWebWallet() is called at app startup.");
|
|
751
975
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
976
|
+
if (action === "create") {
|
|
977
|
+
if (!password || password.length < 6) throw new Error("Password must be at least 6 characters");
|
|
978
|
+
const result = await webProvider.createWallet(password);
|
|
979
|
+
setGeneratedMnemonic(result.mnemonic);
|
|
980
|
+
try {
|
|
981
|
+
await connect();
|
|
982
|
+
onConnected();
|
|
983
|
+
} catch {
|
|
984
|
+
}
|
|
985
|
+
} else if (action === "import") {
|
|
986
|
+
if (!mnemonic.trim()) throw new Error("Please enter your recovery phrase");
|
|
987
|
+
if (!password || password.length < 6) throw new Error("Password must be at least 6 characters");
|
|
988
|
+
await webProvider.importWallet(mnemonic.trim(), password);
|
|
989
|
+
try {
|
|
990
|
+
await connect();
|
|
991
|
+
onConnected();
|
|
992
|
+
} catch {
|
|
993
|
+
}
|
|
994
|
+
} else if (action === "unlock") {
|
|
995
|
+
if (!password) throw new Error("Please enter your password");
|
|
996
|
+
const unlocked = await webProvider.unlock(password);
|
|
997
|
+
if (!unlocked) throw new Error("Incorrect password");
|
|
998
|
+
try {
|
|
999
|
+
await connect();
|
|
1000
|
+
onConnected();
|
|
1001
|
+
} catch {
|
|
1002
|
+
}
|
|
758
1003
|
}
|
|
759
|
-
|
|
1004
|
+
} catch (err) {
|
|
1005
|
+
setError(err?.message || "Operation failed");
|
|
760
1006
|
} finally {
|
|
761
|
-
|
|
762
|
-
}
|
|
763
|
-
}, [onConnect, onError]);
|
|
764
|
-
const disconnect = useCallback(async () => {
|
|
765
|
-
const wallet = walletRef.current;
|
|
766
|
-
if (!wallet) return;
|
|
767
|
-
try {
|
|
768
|
-
await wallet.disconnect();
|
|
769
|
-
} catch {
|
|
770
|
-
}
|
|
771
|
-
if (mountedRef.current) {
|
|
772
|
-
dispatch({ type: "DISCONNECTED" });
|
|
773
|
-
onDisconnect?.();
|
|
774
|
-
}
|
|
775
|
-
}, [onDisconnect]);
|
|
776
|
-
const refreshBalance = useCallback(async () => {
|
|
777
|
-
const wallet = walletRef.current;
|
|
778
|
-
if (!wallet || state.status !== "connected") return;
|
|
779
|
-
try {
|
|
780
|
-
const balance = await wallet.getBalance();
|
|
781
|
-
if (mountedRef.current) {
|
|
782
|
-
dispatch({ type: "SET_BALANCE", balance });
|
|
783
|
-
}
|
|
784
|
-
} catch {
|
|
785
|
-
}
|
|
786
|
-
}, [state.status]);
|
|
787
|
-
const switchNetwork = useCallback(async (network) => {
|
|
788
|
-
const wallet = walletRef.current;
|
|
789
|
-
if (!wallet) return;
|
|
790
|
-
await wallet.switchNetwork(network);
|
|
791
|
-
if (mountedRef.current) {
|
|
792
|
-
dispatch({ type: "SET_NETWORK", network });
|
|
793
|
-
onNetworkChange?.(network);
|
|
794
|
-
}
|
|
795
|
-
}, [onNetworkChange]);
|
|
796
|
-
const signMessage = useCallback(async (message) => {
|
|
797
|
-
const wallet = walletRef.current;
|
|
798
|
-
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
799
|
-
return wallet.signMessage(message);
|
|
800
|
-
}, [state.status]);
|
|
801
|
-
const signTransaction = useCallback(async (tx) => {
|
|
802
|
-
const wallet = walletRef.current;
|
|
803
|
-
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
804
|
-
return wallet.signTransaction(tx);
|
|
805
|
-
}, [state.status]);
|
|
806
|
-
const sendTransaction = useCallback(async (tx) => {
|
|
807
|
-
const wallet = walletRef.current;
|
|
808
|
-
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
809
|
-
return wallet.sendTransaction(tx);
|
|
810
|
-
}, [state.status]);
|
|
811
|
-
const signAndSendTransaction = useCallback(async (tx) => {
|
|
812
|
-
const wallet = walletRef.current;
|
|
813
|
-
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
814
|
-
return wallet.signAndSendTransaction(tx);
|
|
815
|
-
}, [state.status]);
|
|
816
|
-
const getREXCapabilities = useCallback(async () => {
|
|
817
|
-
const wallet = walletRef.current;
|
|
818
|
-
if (!wallet) return { supported: false, privacyModes: [], maxInputSize: 0, programs: [] };
|
|
819
|
-
return wallet.getREXCapabilities();
|
|
820
|
-
}, []);
|
|
821
|
-
const submitREXTransaction = useCallback(async (tx) => {
|
|
822
|
-
const wallet = walletRef.current;
|
|
823
|
-
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
824
|
-
return wallet.submitREXTransaction(tx);
|
|
825
|
-
}, [state.status]);
|
|
826
|
-
const sendGaslessTransaction = useCallback(async (tx) => {
|
|
827
|
-
const wallet = walletRef.current;
|
|
828
|
-
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
829
|
-
return wallet.sendGaslessTransaction(tx);
|
|
830
|
-
}, [state.status]);
|
|
831
|
-
const getSfSPositions = useCallback(async () => {
|
|
832
|
-
const wallet = walletRef.current;
|
|
833
|
-
if (!wallet || state.status !== "connected") return [];
|
|
834
|
-
return wallet.getSfSPositions();
|
|
835
|
-
}, [state.status]);
|
|
836
|
-
const createSfSPosition = useCallback(async (params) => {
|
|
837
|
-
const wallet = walletRef.current;
|
|
838
|
-
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
839
|
-
return wallet.createSfSPosition(params);
|
|
840
|
-
}, [state.status]);
|
|
841
|
-
const getSfSCredits = useCallback(async () => {
|
|
842
|
-
const wallet = walletRef.current;
|
|
843
|
-
if (!wallet || state.status !== "connected") {
|
|
844
|
-
return { available: "0", usedThisEpoch: "0", totalEarned: "0", estimatedPerEpoch: "0" };
|
|
1007
|
+
setLoading(false);
|
|
845
1008
|
}
|
|
846
|
-
return wallet.getSfSCredits();
|
|
847
|
-
}, [state.status]);
|
|
848
|
-
const openModal = useCallback(() => dispatch({ type: "OPEN_MODAL" }), []);
|
|
849
|
-
const closeModal = useCallback(() => dispatch({ type: "CLOSE_MODAL" }), []);
|
|
850
|
-
const wallets = useMemo(() => {
|
|
851
|
-
const installed = isInstalled();
|
|
852
|
-
return [...DEFAULT_WALLETS, ...customWallets].map((w) => ({
|
|
853
|
-
...w,
|
|
854
|
-
installed: w.id === "sheep-wallet" ? installed : false
|
|
855
|
-
}));
|
|
856
|
-
}, [customWallets]);
|
|
857
|
-
const value = useMemo(() => ({
|
|
858
|
-
state,
|
|
859
|
-
connected: state.status === "connected",
|
|
860
|
-
connecting: state.status === "connecting",
|
|
861
|
-
activeAccount: state.accounts[0] || null,
|
|
862
|
-
chainId: `rialo:${state.network}`,
|
|
863
|
-
isInstalled: isInstalled(),
|
|
864
|
-
wallets,
|
|
865
|
-
connect,
|
|
866
|
-
disconnect,
|
|
867
|
-
refreshBalance,
|
|
868
|
-
switchNetwork,
|
|
869
|
-
signMessage,
|
|
870
|
-
signTransaction,
|
|
871
|
-
sendTransaction,
|
|
872
|
-
signAndSendTransaction,
|
|
873
|
-
getREXCapabilities,
|
|
874
|
-
submitREXTransaction,
|
|
875
|
-
sendGaslessTransaction,
|
|
876
|
-
getSfSPositions,
|
|
877
|
-
createSfSPosition,
|
|
878
|
-
getSfSCredits,
|
|
879
|
-
openModal,
|
|
880
|
-
closeModal,
|
|
881
|
-
wallet: walletRef.current
|
|
882
|
-
}), [
|
|
883
|
-
state,
|
|
884
|
-
wallets,
|
|
885
|
-
connect,
|
|
886
|
-
disconnect,
|
|
887
|
-
refreshBalance,
|
|
888
|
-
switchNetwork,
|
|
889
|
-
signMessage,
|
|
890
|
-
signTransaction,
|
|
891
|
-
sendTransaction,
|
|
892
|
-
signAndSendTransaction,
|
|
893
|
-
getREXCapabilities,
|
|
894
|
-
submitREXTransaction,
|
|
895
|
-
sendGaslessTransaction,
|
|
896
|
-
getSfSPositions,
|
|
897
|
-
createSfSPosition,
|
|
898
|
-
getSfSCredits,
|
|
899
|
-
openModal,
|
|
900
|
-
closeModal
|
|
901
|
-
]);
|
|
902
|
-
return /* @__PURE__ */ jsxs(WalletContext.Provider, { value, children: [
|
|
903
|
-
children,
|
|
904
|
-
/* @__PURE__ */ jsx(
|
|
905
|
-
WalletModal,
|
|
906
|
-
{
|
|
907
|
-
scanConnectRelay,
|
|
908
|
-
dispatch
|
|
909
|
-
}
|
|
910
|
-
)
|
|
911
|
-
] });
|
|
912
|
-
}
|
|
913
|
-
function useWallet() {
|
|
914
|
-
const context = useContext(WalletContext);
|
|
915
|
-
if (!context) {
|
|
916
|
-
throw new Error("useWallet must be used within WalletProvider");
|
|
917
|
-
}
|
|
918
|
-
return context;
|
|
919
|
-
}
|
|
920
|
-
function useIsConnected() {
|
|
921
|
-
return useWallet().connected;
|
|
922
|
-
}
|
|
923
|
-
function useActiveAccount() {
|
|
924
|
-
return useWallet().activeAccount;
|
|
925
|
-
}
|
|
926
|
-
function useAccounts() {
|
|
927
|
-
return useWallet().state.accounts;
|
|
928
|
-
}
|
|
929
|
-
function useBalance() {
|
|
930
|
-
const { state, refreshBalance } = useWallet();
|
|
931
|
-
return { balance: state.balance, refresh: refreshBalance };
|
|
932
|
-
}
|
|
933
|
-
function useNetwork() {
|
|
934
|
-
const { state, chainId } = useWallet();
|
|
935
|
-
return { network: state.network, chainId };
|
|
936
|
-
}
|
|
937
|
-
function useSwitchNetwork() {
|
|
938
|
-
const { switchNetwork, state } = useWallet();
|
|
939
|
-
return { switchNetwork, network: state.network };
|
|
940
|
-
}
|
|
941
|
-
function useConnectWallet() {
|
|
942
|
-
const { connect, openModal, connecting, connected, isInstalled: isInstalled2, state } = useWallet();
|
|
943
|
-
return { connect, openModal, connecting, connected, isInstalled: isInstalled2, error: state.error };
|
|
944
|
-
}
|
|
945
|
-
function useDisconnectWallet() {
|
|
946
|
-
const { disconnect, connected } = useWallet();
|
|
947
|
-
return { disconnect, connected };
|
|
948
|
-
}
|
|
949
|
-
function useSignMessage() {
|
|
950
|
-
const { signMessage, connected } = useWallet();
|
|
951
|
-
return { signMessage, connected };
|
|
952
|
-
}
|
|
953
|
-
function useSendTransaction() {
|
|
954
|
-
const { sendTransaction, signAndSendTransaction, sendGaslessTransaction, connected } = useWallet();
|
|
955
|
-
return { sendTransaction, signAndSendTransaction, sendGaslessTransaction, connected };
|
|
956
|
-
}
|
|
957
|
-
function useREX() {
|
|
958
|
-
const { getREXCapabilities, submitREXTransaction, connected } = useWallet();
|
|
959
|
-
const [capabilities, setCapabilities] = useState(null);
|
|
960
|
-
useEffect(() => {
|
|
961
|
-
if (connected) {
|
|
962
|
-
getREXCapabilities().then(setCapabilities).catch(() => {
|
|
963
|
-
});
|
|
964
|
-
}
|
|
965
|
-
}, [connected, getREXCapabilities]);
|
|
966
|
-
return {
|
|
967
|
-
capabilities,
|
|
968
|
-
supported: capabilities?.supported ?? false,
|
|
969
|
-
submitREXTransaction,
|
|
970
|
-
connected
|
|
971
|
-
};
|
|
972
|
-
}
|
|
973
|
-
function useSfS() {
|
|
974
|
-
const { getSfSPositions, createSfSPosition, getSfSCredits, sendGaslessTransaction, connected } = useWallet();
|
|
975
|
-
const [positions, setPositions] = useState([]);
|
|
976
|
-
const [credits, setCredits] = useState(null);
|
|
977
|
-
const refresh = useCallback(async () => {
|
|
978
|
-
if (!connected) return;
|
|
979
|
-
const [pos, cred] = await Promise.all([
|
|
980
|
-
getSfSPositions().catch(() => []),
|
|
981
|
-
getSfSCredits().catch(() => null)
|
|
982
|
-
]);
|
|
983
|
-
setPositions(pos);
|
|
984
|
-
if (cred) setCredits(cred);
|
|
985
|
-
}, [connected, getSfSPositions, getSfSCredits]);
|
|
986
|
-
useEffect(() => {
|
|
987
|
-
refresh();
|
|
988
|
-
}, [refresh]);
|
|
989
|
-
return {
|
|
990
|
-
positions,
|
|
991
|
-
credits,
|
|
992
|
-
hasCredits: BigInt(credits?.available ?? "0") > 0n,
|
|
993
|
-
createPosition: createSfSPosition,
|
|
994
|
-
sendGasless: sendGaslessTransaction,
|
|
995
|
-
refresh,
|
|
996
|
-
connected
|
|
997
1009
|
};
|
|
1010
|
+
if (generatedMnemonic) {
|
|
1011
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
1012
|
+
/* @__PURE__ */ jsxs("div", { style: { padding: "14px", backgroundColor: "rgba(110,185,168,0.08)", border: "1px solid rgba(110,185,168,0.2)", borderRadius: "12px", marginBottom: "16px" }, children: [
|
|
1013
|
+
/* @__PURE__ */ jsx("div", { style: { color: "#6EB9A8", fontSize: "12px", fontWeight: 600, marginBottom: "8px" }, children: "Wallet Created & Connected!" }),
|
|
1014
|
+
/* @__PURE__ */ jsx("div", { style: { color: "rgba(255,255,255,0.6)", fontSize: "11px", marginBottom: "8px" }, children: "Save your recovery phrase securely:" }),
|
|
1015
|
+
/* @__PURE__ */ jsx("div", { style: { padding: "10px", backgroundColor: "rgba(0,0,0,0.3)", borderRadius: "8px", color: "#fff", fontSize: "12px", fontFamily: "monospace", wordBreak: "break-word", lineHeight: 1.6 }, children: generatedMnemonic })
|
|
1016
|
+
] }),
|
|
1017
|
+
/* @__PURE__ */ jsx(
|
|
1018
|
+
"button",
|
|
1019
|
+
{
|
|
1020
|
+
type: "button",
|
|
1021
|
+
onClick: (e) => {
|
|
1022
|
+
stop(e);
|
|
1023
|
+
setGeneratedMnemonic("");
|
|
1024
|
+
onConnected();
|
|
1025
|
+
},
|
|
1026
|
+
style: S.primaryBtn(false),
|
|
1027
|
+
children: "I've Saved It \u2014 Continue"
|
|
1028
|
+
}
|
|
1029
|
+
)
|
|
1030
|
+
] });
|
|
1031
|
+
}
|
|
1032
|
+
if (hasWallet && !isUnlocked) {
|
|
1033
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
1034
|
+
/* @__PURE__ */ jsx("p", { style: { color: "rgba(255,255,255,0.5)", fontSize: "13px", marginBottom: "16px" }, children: "Web wallet locked. Enter password to connect." }),
|
|
1035
|
+
/* @__PURE__ */ jsx(
|
|
1036
|
+
"input",
|
|
1037
|
+
{
|
|
1038
|
+
type: "password",
|
|
1039
|
+
placeholder: "Password",
|
|
1040
|
+
value: password,
|
|
1041
|
+
onChange: (e) => setPassword(e.target.value),
|
|
1042
|
+
onClick: stop,
|
|
1043
|
+
onKeyDown: (e) => {
|
|
1044
|
+
if (e.key === "Enter") handleAction("unlock");
|
|
1045
|
+
},
|
|
1046
|
+
style: S.input
|
|
1047
|
+
}
|
|
1048
|
+
),
|
|
1049
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: (e) => {
|
|
1050
|
+
stop(e);
|
|
1051
|
+
handleAction("unlock");
|
|
1052
|
+
}, disabled: loading, style: S.primaryBtn(loading), children: loading ? "Unlocking..." : "Unlock & Connect" }),
|
|
1053
|
+
error && /* @__PURE__ */ jsx("div", { style: S.error, children: error })
|
|
1054
|
+
] });
|
|
1055
|
+
}
|
|
1056
|
+
if (hasWallet && isUnlocked) {
|
|
1057
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
1058
|
+
/* @__PURE__ */ jsxs("button", { type: "button", onClick: async (e) => {
|
|
1059
|
+
stop(e);
|
|
1060
|
+
setLoading(true);
|
|
1061
|
+
try {
|
|
1062
|
+
await connect();
|
|
1063
|
+
onConnected();
|
|
1064
|
+
} catch (err) {
|
|
1065
|
+
setError(err?.message || "Failed");
|
|
1066
|
+
} finally {
|
|
1067
|
+
setLoading(false);
|
|
1068
|
+
}
|
|
1069
|
+
}, disabled: loading, style: S.walletBtn(loading), children: [
|
|
1070
|
+
/* @__PURE__ */ jsx("div", { style: { width: "44px", height: "44px", borderRadius: "12px", background: "linear-gradient(135deg, #3B82F6, #6366F1)", display: "flex", alignItems: "center", justifyContent: "center", color: "#fff", flexShrink: 0 }, children: /* @__PURE__ */ jsx(IconWeb, {}) }),
|
|
1071
|
+
/* @__PURE__ */ jsxs("div", { style: { flex: 1, textAlign: "left" }, children: [
|
|
1072
|
+
/* @__PURE__ */ jsx("div", { style: { color: "#fff", fontWeight: 500, fontSize: "15px" }, children: "Web Wallet" }),
|
|
1073
|
+
/* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: "#6EB9A8" }, children: loading ? "Connecting..." : "Ready \u2014 Click to connect" })
|
|
1074
|
+
] })
|
|
1075
|
+
] }),
|
|
1076
|
+
error && /* @__PURE__ */ jsx("div", { style: S.error, children: error })
|
|
1077
|
+
] });
|
|
1078
|
+
}
|
|
1079
|
+
if (mode === "create") {
|
|
1080
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
1081
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: (e) => {
|
|
1082
|
+
stop(e);
|
|
1083
|
+
setMode("menu");
|
|
1084
|
+
}, style: { background: "none", border: "none", color: "rgba(255,255,255,0.4)", cursor: "pointer", fontSize: "12px", marginBottom: "12px", padding: 0 }, children: "\u2190 Back" }),
|
|
1085
|
+
/* @__PURE__ */ jsx("p", { style: { color: "rgba(255,255,255,0.5)", fontSize: "13px", marginBottom: "16px" }, children: "Create a new web wallet with a generated recovery phrase." }),
|
|
1086
|
+
/* @__PURE__ */ jsx(
|
|
1087
|
+
"input",
|
|
1088
|
+
{
|
|
1089
|
+
type: "password",
|
|
1090
|
+
placeholder: "Set password (min 6 chars)",
|
|
1091
|
+
value: password,
|
|
1092
|
+
onChange: (e) => setPassword(e.target.value),
|
|
1093
|
+
onClick: stop,
|
|
1094
|
+
style: S.input
|
|
1095
|
+
}
|
|
1096
|
+
),
|
|
1097
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: (e) => {
|
|
1098
|
+
stop(e);
|
|
1099
|
+
handleAction("create");
|
|
1100
|
+
}, disabled: loading, style: S.primaryBtn(loading), children: loading ? "Creating..." : "Create Wallet" }),
|
|
1101
|
+
error && /* @__PURE__ */ jsx("div", { style: S.error, children: error })
|
|
1102
|
+
] });
|
|
1103
|
+
}
|
|
1104
|
+
if (mode === "import") {
|
|
1105
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
1106
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: (e) => {
|
|
1107
|
+
stop(e);
|
|
1108
|
+
setMode("menu");
|
|
1109
|
+
}, style: { background: "none", border: "none", color: "rgba(255,255,255,0.4)", cursor: "pointer", fontSize: "12px", marginBottom: "12px", padding: 0 }, children: "\u2190 Back" }),
|
|
1110
|
+
/* @__PURE__ */ jsx("p", { style: { color: "rgba(255,255,255,0.5)", fontSize: "13px", marginBottom: "16px" }, children: "Import wallet from recovery phrase." }),
|
|
1111
|
+
/* @__PURE__ */ jsx(
|
|
1112
|
+
"textarea",
|
|
1113
|
+
{
|
|
1114
|
+
placeholder: "Enter 12 or 24 word recovery phrase",
|
|
1115
|
+
value: mnemonic,
|
|
1116
|
+
onChange: (e) => setMnemonic(e.target.value),
|
|
1117
|
+
onClick: stop,
|
|
1118
|
+
style: { ...S.input, minHeight: "80px", resize: "vertical", fontFamily: "monospace", fontSize: "13px" }
|
|
1119
|
+
}
|
|
1120
|
+
),
|
|
1121
|
+
/* @__PURE__ */ jsx(
|
|
1122
|
+
"input",
|
|
1123
|
+
{
|
|
1124
|
+
type: "password",
|
|
1125
|
+
placeholder: "Set password (min 6 chars)",
|
|
1126
|
+
value: password,
|
|
1127
|
+
onChange: (e) => setPassword(e.target.value),
|
|
1128
|
+
onClick: stop,
|
|
1129
|
+
style: S.input
|
|
1130
|
+
}
|
|
1131
|
+
),
|
|
1132
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: (e) => {
|
|
1133
|
+
stop(e);
|
|
1134
|
+
handleAction("import");
|
|
1135
|
+
}, disabled: loading, style: S.primaryBtn(loading), children: loading ? "Importing..." : "Import & Connect" }),
|
|
1136
|
+
error && /* @__PURE__ */ jsx("div", { style: S.error, children: error })
|
|
1137
|
+
] });
|
|
1138
|
+
}
|
|
1139
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
1140
|
+
/* @__PURE__ */ jsx("p", { style: { color: "rgba(255,255,255,0.5)", fontSize: "13px", marginBottom: "16px", lineHeight: 1.5 }, children: isWebProvider ? "Create or import a web wallet \u2014 no extension needed." : "Web wallet not available. Call registerWebWallet() at app startup." }),
|
|
1141
|
+
isWebProvider && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "10px" }, children: [
|
|
1142
|
+
/* @__PURE__ */ jsxs(
|
|
1143
|
+
"button",
|
|
1144
|
+
{
|
|
1145
|
+
type: "button",
|
|
1146
|
+
onClick: (e) => {
|
|
1147
|
+
stop(e);
|
|
1148
|
+
setMode("create");
|
|
1149
|
+
setError("");
|
|
1150
|
+
},
|
|
1151
|
+
style: S.walletBtn(false),
|
|
1152
|
+
children: [
|
|
1153
|
+
/* @__PURE__ */ jsx("div", { style: { width: "40px", height: "40px", borderRadius: "10px", background: "linear-gradient(135deg, #3B82F6, #6366F1)", display: "flex", alignItems: "center", justifyContent: "center", color: "#fff", fontSize: "18px", flexShrink: 0 }, children: "+" }),
|
|
1154
|
+
/* @__PURE__ */ jsxs("div", { style: { textAlign: "left" }, children: [
|
|
1155
|
+
/* @__PURE__ */ jsx("div", { style: { color: "#fff", fontWeight: 500, fontSize: "14px" }, children: "Create New Wallet" }),
|
|
1156
|
+
/* @__PURE__ */ jsx("div", { style: { color: "rgba(255,255,255,0.4)", fontSize: "11px" }, children: "Generate a new recovery phrase" })
|
|
1157
|
+
] })
|
|
1158
|
+
]
|
|
1159
|
+
}
|
|
1160
|
+
),
|
|
1161
|
+
/* @__PURE__ */ jsxs(
|
|
1162
|
+
"button",
|
|
1163
|
+
{
|
|
1164
|
+
type: "button",
|
|
1165
|
+
onClick: (e) => {
|
|
1166
|
+
stop(e);
|
|
1167
|
+
setMode("import");
|
|
1168
|
+
setError("");
|
|
1169
|
+
},
|
|
1170
|
+
style: S.walletBtn(false),
|
|
1171
|
+
children: [
|
|
1172
|
+
/* @__PURE__ */ jsx("div", { style: { width: "40px", height: "40px", borderRadius: "10px", background: "linear-gradient(135deg, #F59E0B, #EF4444)", display: "flex", alignItems: "center", justifyContent: "center", color: "#fff", flexShrink: 0 }, children: /* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1173
|
+
/* @__PURE__ */ jsx("path", { d: "M12 3v12" }),
|
|
1174
|
+
/* @__PURE__ */ jsx("path", { d: "m8 11 4 4 4-4" }),
|
|
1175
|
+
/* @__PURE__ */ jsx("path", { d: "M8 5H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-4" })
|
|
1176
|
+
] }) }),
|
|
1177
|
+
/* @__PURE__ */ jsxs("div", { style: { textAlign: "left" }, children: [
|
|
1178
|
+
/* @__PURE__ */ jsx("div", { style: { color: "#fff", fontWeight: 500, fontSize: "14px" }, children: "Import Wallet" }),
|
|
1179
|
+
/* @__PURE__ */ jsx("div", { style: { color: "rgba(255,255,255,0.4)", fontSize: "11px" }, children: "Use existing recovery phrase" })
|
|
1180
|
+
] })
|
|
1181
|
+
]
|
|
1182
|
+
}
|
|
1183
|
+
)
|
|
1184
|
+
] }),
|
|
1185
|
+
error && /* @__PURE__ */ jsx("div", { style: S.error, children: error })
|
|
1186
|
+
] });
|
|
998
1187
|
}
|
|
999
|
-
function
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
if (!wallet) return [];
|
|
1016
|
-
setStatus("approving");
|
|
1017
|
-
try {
|
|
1018
|
-
const accounts = await wallet.approveScanSession(sessionId);
|
|
1019
|
-
setStatus("connected");
|
|
1020
|
-
return accounts;
|
|
1021
|
-
} catch {
|
|
1022
|
-
setStatus("error");
|
|
1023
|
-
return [];
|
|
1024
|
-
}
|
|
1025
|
-
}, [wallet]);
|
|
1026
|
-
const rejectSession = useCallback(async (sessionId) => {
|
|
1027
|
-
if (!wallet) return;
|
|
1028
|
-
await wallet.rejectScanSession(sessionId);
|
|
1029
|
-
setStatus("rejected");
|
|
1030
|
-
}, [wallet]);
|
|
1031
|
-
return {
|
|
1032
|
-
scanURI,
|
|
1033
|
-
status,
|
|
1034
|
-
generateQR,
|
|
1035
|
-
approveSession,
|
|
1036
|
-
rejectSession
|
|
1037
|
-
};
|
|
1188
|
+
function SuccessView({ address }) {
|
|
1189
|
+
return /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "24px 0" }, children: [
|
|
1190
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
1191
|
+
width: "56px",
|
|
1192
|
+
height: "56px",
|
|
1193
|
+
borderRadius: "50%",
|
|
1194
|
+
backgroundColor: "rgba(110,185,168,0.12)",
|
|
1195
|
+
border: "2px solid rgba(110,185,168,0.3)",
|
|
1196
|
+
display: "flex",
|
|
1197
|
+
alignItems: "center",
|
|
1198
|
+
justifyContent: "center",
|
|
1199
|
+
margin: "0 auto 16px"
|
|
1200
|
+
}, children: /* @__PURE__ */ jsx(IconCheck, {}) }),
|
|
1201
|
+
/* @__PURE__ */ jsx("div", { style: { color: "#fff", fontSize: "16px", fontWeight: 600, marginBottom: "6px" }, children: "Connected!" }),
|
|
1202
|
+
/* @__PURE__ */ jsx("div", { style: { color: "rgba(255,255,255,0.4)", fontSize: "13px", fontFamily: "monospace" }, children: formatAddress(address) })
|
|
1203
|
+
] });
|
|
1038
1204
|
}
|
|
1039
|
-
function WalletModal({ scanConnectRelay
|
|
1040
|
-
const { state,
|
|
1205
|
+
function WalletModal({ scanConnectRelay }) {
|
|
1206
|
+
const { state, connect, closeModal } = useWallet();
|
|
1041
1207
|
const [activeTab, setActiveTab] = useState("extension");
|
|
1042
|
-
const [scanMode, setScanMode] = useState("show-qr");
|
|
1043
|
-
const [generatedURI, setGeneratedURI] = useState(null);
|
|
1044
|
-
const [qrReady, setQRReady] = useState(false);
|
|
1045
|
-
const canvasRef = useRef(null);
|
|
1046
1208
|
const [isMobile, setIsMobile] = useState(false);
|
|
1209
|
+
const [showSuccess, setShowSuccess] = useState(false);
|
|
1210
|
+
const statusOnOpenRef = useRef(null);
|
|
1211
|
+
const successTimerRef = useRef(null);
|
|
1047
1212
|
const [dragY, setDragY] = useState(0);
|
|
1048
1213
|
const [isDragging, setIsDragging] = useState(false);
|
|
1049
1214
|
const dragStartRef = useRef(0);
|
|
1050
|
-
const
|
|
1215
|
+
const extensionDetected = isInstalled();
|
|
1051
1216
|
useEffect(() => {
|
|
1052
1217
|
const check = () => setIsMobile(window.innerWidth < 640);
|
|
1053
1218
|
check();
|
|
1054
1219
|
window.addEventListener("resize", check);
|
|
1055
1220
|
return () => window.removeEventListener("resize", check);
|
|
1056
1221
|
}, []);
|
|
1222
|
+
useEffect(() => {
|
|
1223
|
+
if (state.isModalOpen) {
|
|
1224
|
+
statusOnOpenRef.current = state.status;
|
|
1225
|
+
setActiveTab("extension");
|
|
1226
|
+
setShowSuccess(false);
|
|
1227
|
+
} else {
|
|
1228
|
+
statusOnOpenRef.current = null;
|
|
1229
|
+
}
|
|
1230
|
+
}, [state.isModalOpen]);
|
|
1231
|
+
useEffect(() => {
|
|
1232
|
+
if (state.isModalOpen && state.status === "connected" && state.accounts.length > 0 && !showSuccess && statusOnOpenRef.current !== "connected") {
|
|
1233
|
+
setShowSuccess(true);
|
|
1234
|
+
successTimerRef.current = setTimeout(() => {
|
|
1235
|
+
closeModal();
|
|
1236
|
+
setShowSuccess(false);
|
|
1237
|
+
}, 1500);
|
|
1238
|
+
}
|
|
1239
|
+
return () => {
|
|
1240
|
+
if (successTimerRef.current) clearTimeout(successTimerRef.current);
|
|
1241
|
+
};
|
|
1242
|
+
}, [state.isModalOpen, state.status, state.accounts.length, showSuccess, closeModal]);
|
|
1057
1243
|
useEffect(() => {
|
|
1058
1244
|
if (!state.isModalOpen) {
|
|
1245
|
+
setShowSuccess(false);
|
|
1059
1246
|
setDragY(0);
|
|
1060
1247
|
setIsDragging(false);
|
|
1061
1248
|
}
|
|
1062
1249
|
}, [state.isModalOpen]);
|
|
1063
|
-
const
|
|
1064
|
-
const handleConnect = async (e) => {
|
|
1065
|
-
e.stopPropagation();
|
|
1066
|
-
e.preventDefault();
|
|
1250
|
+
const handleExtensionConnect = useCallback(async () => {
|
|
1067
1251
|
try {
|
|
1068
1252
|
await connect();
|
|
1069
1253
|
} catch {
|
|
1070
1254
|
}
|
|
1071
|
-
};
|
|
1072
|
-
const generateScanSession = async () => {
|
|
1073
|
-
dispatch({ type: "SET_SCAN_STATUS", status: "generating" });
|
|
1074
|
-
const sessionId = crypto.randomUUID();
|
|
1075
|
-
const topic = btoa(sessionId).slice(0, 32);
|
|
1076
|
-
const uri = `rialo-wc://${sessionId}?relay=${encodeURIComponent(scanConnectRelay)}&topic=${topic}&networks=devnet`;
|
|
1077
|
-
setGeneratedURI(uri);
|
|
1078
|
-
dispatch({ type: "SET_SCAN_STATUS", status: "waiting" });
|
|
1079
|
-
setQRReady(true);
|
|
1080
|
-
};
|
|
1081
|
-
useEffect(() => {
|
|
1082
|
-
if (!qrReady || !generatedURI || !canvasRef.current) return;
|
|
1083
|
-
const canvas = canvasRef.current;
|
|
1084
|
-
const ctx = canvas.getContext("2d");
|
|
1085
|
-
if (!ctx) return;
|
|
1086
|
-
const size = 200;
|
|
1087
|
-
canvas.width = size;
|
|
1088
|
-
canvas.height = size;
|
|
1089
|
-
ctx.fillStyle = "#FFFFFF";
|
|
1090
|
-
ctx.fillRect(0, 0, size, size);
|
|
1091
|
-
ctx.fillStyle = "#011B29";
|
|
1092
|
-
const gridSize = 25;
|
|
1093
|
-
const cellSize = size / gridSize;
|
|
1094
|
-
for (let y = 0; y < gridSize; y++) {
|
|
1095
|
-
for (let x = 0; x < gridSize; x++) {
|
|
1096
|
-
const isFinderArea = x < 7 && y < 7 || x >= gridSize - 7 && y < 7 || x < 7 && y >= gridSize - 7;
|
|
1097
|
-
if (isFinderArea) {
|
|
1098
|
-
const isOuter = x === 0 || y === 0 || x === 6 || y === 6 || x === gridSize - 7 || x === gridSize - 1 || y === gridSize - 7 || y === gridSize - 1;
|
|
1099
|
-
const isInner = x >= 2 && x <= 4 && y >= 2 && y <= 4 || x >= gridSize - 5 && x <= gridSize - 3 && y >= 2 && y <= 4 || x >= 2 && x <= 4 && y >= gridSize - 5 && y <= gridSize - 3;
|
|
1100
|
-
if (isOuter || isInner) ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
|
|
1101
|
-
continue;
|
|
1102
|
-
}
|
|
1103
|
-
const charIndex = (y * gridSize + x) % generatedURI.length;
|
|
1104
|
-
const charCode = generatedURI.charCodeAt(charIndex);
|
|
1105
|
-
if (charCode % 3 !== 0) ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
const logoSize = 40;
|
|
1109
|
-
const logoX = (size - logoSize) / 2;
|
|
1110
|
-
const logoY = (size - logoSize) / 2;
|
|
1111
|
-
ctx.beginPath();
|
|
1112
|
-
ctx.arc(size / 2, size / 2, logoSize / 2 + 4, 0, Math.PI * 2);
|
|
1113
|
-
ctx.fillStyle = "#FFFFFF";
|
|
1114
|
-
ctx.fill();
|
|
1115
|
-
ctx.beginPath();
|
|
1116
|
-
const r = 6;
|
|
1117
|
-
ctx.moveTo(logoX + r, logoY);
|
|
1118
|
-
ctx.lineTo(logoX + logoSize - r, logoY);
|
|
1119
|
-
ctx.quadraticCurveTo(logoX + logoSize, logoY, logoX + logoSize, logoY + r);
|
|
1120
|
-
ctx.lineTo(logoX + logoSize, logoY + logoSize - r);
|
|
1121
|
-
ctx.quadraticCurveTo(logoX + logoSize, logoY + logoSize, logoX + logoSize - r, logoY + logoSize);
|
|
1122
|
-
ctx.lineTo(logoX + r, logoY + logoSize);
|
|
1123
|
-
ctx.quadraticCurveTo(logoX, logoY + logoSize, logoX, logoY + logoSize - r);
|
|
1124
|
-
ctx.lineTo(logoX, logoY + r);
|
|
1125
|
-
ctx.quadraticCurveTo(logoX, logoY, logoX + r, logoY);
|
|
1126
|
-
ctx.fillStyle = "#6EB9A8";
|
|
1127
|
-
ctx.fill();
|
|
1128
|
-
ctx.fillStyle = "#FFFFFF";
|
|
1129
|
-
ctx.font = "bold 22px sans-serif";
|
|
1130
|
-
ctx.textAlign = "center";
|
|
1131
|
-
ctx.textBaseline = "middle";
|
|
1132
|
-
ctx.fillText("S", size / 2, size / 2 + 1);
|
|
1133
|
-
}, [qrReady, generatedURI]);
|
|
1134
|
-
useEffect(() => {
|
|
1135
|
-
if (activeTab === "scan" && scanMode === "show-qr" && !generatedURI) {
|
|
1136
|
-
generateScanSession();
|
|
1137
|
-
}
|
|
1138
|
-
}, [activeTab, scanMode]);
|
|
1255
|
+
}, [connect]);
|
|
1139
1256
|
const handleTouchStart = (e) => {
|
|
1140
1257
|
if (!isMobile) return;
|
|
1141
1258
|
dragStartRef.current = e.touches[0].clientY;
|
|
@@ -1153,389 +1270,69 @@ function WalletModal({ scanConnectRelay, dispatch }) {
|
|
|
1153
1270
|
setDragY(0);
|
|
1154
1271
|
};
|
|
1155
1272
|
if (!state.isModalOpen) return null;
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
/* @__PURE__ */
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
/* @__PURE__ */ jsx("rect", { x: "3", y: "14", width: "7", height: "7" }),
|
|
1166
|
-
/* @__PURE__ */ jsx("path", { d: "M14 14h7v7h-7z" })
|
|
1167
|
-
] });
|
|
1168
|
-
const CameraIcon = () => /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1169
|
-
/* @__PURE__ */ jsx("path", { d: "M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z" }),
|
|
1170
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "13", r: "3" })
|
|
1171
|
-
] });
|
|
1172
|
-
const RefreshIcon = () => /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1173
|
-
/* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" }),
|
|
1174
|
-
/* @__PURE__ */ jsx("path", { d: "M21 3v5h-5" })
|
|
1175
|
-
] });
|
|
1176
|
-
const tabBaseStyle = {
|
|
1177
|
-
flex: 1,
|
|
1178
|
-
padding: "10px 0",
|
|
1179
|
-
border: "none",
|
|
1180
|
-
borderRadius: "10px",
|
|
1181
|
-
fontSize: "13px",
|
|
1182
|
-
cursor: "pointer",
|
|
1183
|
-
transition: "all 0.2s",
|
|
1184
|
-
display: "flex",
|
|
1185
|
-
alignItems: "center",
|
|
1186
|
-
justifyContent: "center",
|
|
1187
|
-
gap: "6px"
|
|
1188
|
-
};
|
|
1189
|
-
const renderContent = () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1190
|
-
/* @__PURE__ */ jsxs("div", { style: {
|
|
1191
|
-
display: "flex",
|
|
1192
|
-
gap: "4px",
|
|
1193
|
-
padding: "4px",
|
|
1194
|
-
backgroundColor: "rgba(255,255,255,0.04)",
|
|
1195
|
-
borderRadius: "14px",
|
|
1196
|
-
marginBottom: "20px"
|
|
1197
|
-
}, children: [
|
|
1198
|
-
/* @__PURE__ */ jsxs(
|
|
1199
|
-
"button",
|
|
1200
|
-
{
|
|
1201
|
-
type: "button",
|
|
1202
|
-
onClick: (e) => {
|
|
1203
|
-
stop(e);
|
|
1204
|
-
setActiveTab("extension");
|
|
1205
|
-
},
|
|
1206
|
-
style: {
|
|
1207
|
-
...tabBaseStyle,
|
|
1208
|
-
backgroundColor: activeTab === "extension" ? "rgba(255,255,255,0.08)" : "transparent",
|
|
1209
|
-
color: activeTab === "extension" ? "#6EB9A8" : "rgba(255,255,255,0.4)",
|
|
1210
|
-
fontWeight: activeTab === "extension" ? 600 : 400
|
|
1211
|
-
},
|
|
1212
|
-
children: [
|
|
1213
|
-
/* @__PURE__ */ jsx(ExtensionIcon, {}),
|
|
1214
|
-
" Extension"
|
|
1215
|
-
]
|
|
1216
|
-
}
|
|
1217
|
-
),
|
|
1218
|
-
/* @__PURE__ */ jsxs(
|
|
1219
|
-
"button",
|
|
1220
|
-
{
|
|
1221
|
-
type: "button",
|
|
1222
|
-
onClick: (e) => {
|
|
1223
|
-
stop(e);
|
|
1224
|
-
setActiveTab("scan");
|
|
1225
|
-
},
|
|
1226
|
-
style: {
|
|
1227
|
-
...tabBaseStyle,
|
|
1228
|
-
backgroundColor: activeTab === "scan" ? "rgba(255,255,255,0.08)" : "transparent",
|
|
1229
|
-
color: activeTab === "scan" ? "#6EB9A8" : "rgba(255,255,255,0.4)",
|
|
1230
|
-
fontWeight: activeTab === "scan" ? 600 : 400
|
|
1231
|
-
},
|
|
1232
|
-
children: [
|
|
1233
|
-
/* @__PURE__ */ jsx(QrIcon, {}),
|
|
1234
|
-
" Scan to Connect"
|
|
1235
|
-
]
|
|
1236
|
-
}
|
|
1237
|
-
)
|
|
1238
|
-
] }),
|
|
1239
|
-
activeTab === "extension" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1240
|
-
sheepWallet && /* @__PURE__ */ jsxs(
|
|
1241
|
-
"button",
|
|
1242
|
-
{
|
|
1243
|
-
type: "button",
|
|
1244
|
-
onClick: installed ? handleConnect : (e) => {
|
|
1245
|
-
stop(e);
|
|
1246
|
-
window.open(sheepWallet.downloadUrl, "_blank");
|
|
1247
|
-
},
|
|
1248
|
-
disabled: state.status === "connecting",
|
|
1249
|
-
style: {
|
|
1250
|
-
width: "100%",
|
|
1251
|
-
display: "flex",
|
|
1252
|
-
alignItems: "center",
|
|
1253
|
-
gap: "14px",
|
|
1254
|
-
padding: "16px",
|
|
1255
|
-
backgroundColor: "rgba(255,255,255,0.04)",
|
|
1256
|
-
border: "1px solid rgba(255,255,255,0.08)",
|
|
1257
|
-
borderRadius: "14px",
|
|
1258
|
-
cursor: state.status === "connecting" ? "wait" : "pointer",
|
|
1259
|
-
transition: "all 0.15s"
|
|
1260
|
-
},
|
|
1261
|
-
onMouseEnter: (e) => {
|
|
1262
|
-
e.currentTarget.style.backgroundColor = "rgba(255,255,255,0.07)";
|
|
1263
|
-
},
|
|
1264
|
-
onMouseLeave: (e) => {
|
|
1265
|
-
e.currentTarget.style.backgroundColor = "rgba(255,255,255,0.04)";
|
|
1266
|
-
},
|
|
1267
|
-
children: [
|
|
1268
|
-
/* @__PURE__ */ jsx("div", { style: {
|
|
1269
|
-
width: "44px",
|
|
1270
|
-
height: "44px",
|
|
1271
|
-
borderRadius: "12px",
|
|
1272
|
-
background: "linear-gradient(135deg, #6EB9A8, #4a9a8a)",
|
|
1273
|
-
display: "flex",
|
|
1274
|
-
alignItems: "center",
|
|
1275
|
-
justifyContent: "center",
|
|
1276
|
-
color: "#fff",
|
|
1277
|
-
fontWeight: 700,
|
|
1278
|
-
fontSize: "18px"
|
|
1279
|
-
}, children: "S" }),
|
|
1280
|
-
/* @__PURE__ */ jsxs("div", { style: { flex: 1, textAlign: "left" }, children: [
|
|
1281
|
-
/* @__PURE__ */ jsx("div", { style: { color: "#fff", fontWeight: 500, fontSize: "15px", marginBottom: "2px" }, children: sheepWallet.name }),
|
|
1282
|
-
/* @__PURE__ */ jsx("div", { style: {
|
|
1283
|
-
fontSize: "12px",
|
|
1284
|
-
color: installed ? "#6EB9A8" : "rgba(255,255,255,0.4)",
|
|
1285
|
-
display: "flex",
|
|
1286
|
-
alignItems: "center",
|
|
1287
|
-
gap: "5px"
|
|
1288
|
-
}, children: state.status === "connecting" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1289
|
-
/* @__PURE__ */ jsx("span", { style: {
|
|
1290
|
-
display: "inline-block",
|
|
1291
|
-
width: "6px",
|
|
1292
|
-
height: "6px",
|
|
1293
|
-
borderRadius: "50%",
|
|
1294
|
-
backgroundColor: "#F59E0B",
|
|
1295
|
-
animation: "walletModalPulse 1.2s infinite"
|
|
1296
|
-
} }),
|
|
1297
|
-
"Connecting..."
|
|
1298
|
-
] }) : installed ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1299
|
-
/* @__PURE__ */ jsx("span", { style: {
|
|
1300
|
-
display: "inline-block",
|
|
1301
|
-
width: "6px",
|
|
1302
|
-
height: "6px",
|
|
1303
|
-
borderRadius: "50%",
|
|
1304
|
-
backgroundColor: "#6EB9A8"
|
|
1305
|
-
} }),
|
|
1306
|
-
"Detected \u2014 Click to connect"
|
|
1307
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1308
|
-
/* @__PURE__ */ jsx("span", { style: {
|
|
1309
|
-
display: "inline-block",
|
|
1310
|
-
width: "6px",
|
|
1311
|
-
height: "6px",
|
|
1312
|
-
borderRadius: "50%",
|
|
1313
|
-
backgroundColor: "rgba(255,255,255,0.2)"
|
|
1314
|
-
} }),
|
|
1315
|
-
"Not installed"
|
|
1316
|
-
] }) })
|
|
1317
|
-
] }),
|
|
1318
|
-
!installed && /* @__PURE__ */ jsx("span", { style: {
|
|
1319
|
-
color: "#6EB9A8",
|
|
1320
|
-
fontSize: "12px",
|
|
1321
|
-
fontWeight: 500,
|
|
1322
|
-
padding: "4px 10px",
|
|
1323
|
-
borderRadius: "8px",
|
|
1324
|
-
backgroundColor: "rgba(110,185,168,0.1)"
|
|
1325
|
-
}, children: "Install" })
|
|
1326
|
-
]
|
|
1327
|
-
}
|
|
1328
|
-
),
|
|
1329
|
-
/* @__PURE__ */ jsx("div", { style: {
|
|
1330
|
-
display: "flex",
|
|
1331
|
-
gap: "8px",
|
|
1332
|
-
marginTop: "16px",
|
|
1333
|
-
flexWrap: "wrap"
|
|
1334
|
-
}, children: [
|
|
1335
|
-
{ label: "REX", desc: "Confidential TX", color: "#8B5CF6" },
|
|
1336
|
-
{ label: "SfS", desc: "Gasless TX", color: "#F59E0B" },
|
|
1337
|
-
{ label: "QR", desc: "Scan Connect", color: "#6EB9A8" }
|
|
1338
|
-
].map((badge) => /* @__PURE__ */ jsxs("div", { style: {
|
|
1339
|
-
padding: "5px 10px",
|
|
1340
|
-
backgroundColor: `${badge.color}10`,
|
|
1341
|
-
borderRadius: "8px",
|
|
1342
|
-
border: `1px solid ${badge.color}18`,
|
|
1343
|
-
display: "flex",
|
|
1344
|
-
alignItems: "center",
|
|
1345
|
-
gap: "6px"
|
|
1346
|
-
}, children: [
|
|
1347
|
-
/* @__PURE__ */ jsx("span", { style: { color: badge.color, fontSize: "11px", fontWeight: 600 }, children: badge.label }),
|
|
1348
|
-
/* @__PURE__ */ jsx("span", { style: { color: "rgba(255,255,255,0.35)", fontSize: "10px" }, children: badge.desc })
|
|
1349
|
-
] }, badge.label)) })
|
|
1350
|
-
] }),
|
|
1351
|
-
activeTab === "scan" && /* @__PURE__ */ jsxs("div", { children: [
|
|
1352
|
-
/* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "8px", marginBottom: "16px" }, children: ["show-qr", "scan-qr"].map((mode) => /* @__PURE__ */ jsx(
|
|
1353
|
-
"button",
|
|
1354
|
-
{
|
|
1355
|
-
type: "button",
|
|
1356
|
-
onClick: (e) => {
|
|
1357
|
-
stop(e);
|
|
1358
|
-
setScanMode(mode);
|
|
1359
|
-
},
|
|
1360
|
-
style: {
|
|
1361
|
-
flex: 1,
|
|
1362
|
-
padding: "8px",
|
|
1363
|
-
display: "flex",
|
|
1364
|
-
alignItems: "center",
|
|
1365
|
-
justifyContent: "center",
|
|
1366
|
-
gap: "6px",
|
|
1367
|
-
backgroundColor: scanMode === mode ? "rgba(110,185,168,0.1)" : "transparent",
|
|
1368
|
-
border: `1px solid ${scanMode === mode ? "rgba(110,185,168,0.25)" : "rgba(255,255,255,0.08)"}`,
|
|
1369
|
-
borderRadius: "10px",
|
|
1370
|
-
color: scanMode === mode ? "#6EB9A8" : "rgba(255,255,255,0.4)",
|
|
1371
|
-
fontSize: "12px",
|
|
1372
|
-
fontWeight: scanMode === mode ? 500 : 400,
|
|
1373
|
-
cursor: "pointer",
|
|
1374
|
-
transition: "all 0.15s"
|
|
1375
|
-
},
|
|
1376
|
-
children: mode === "show-qr" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1377
|
-
/* @__PURE__ */ jsx(QrIcon, {}),
|
|
1378
|
-
" Show QR"
|
|
1379
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1380
|
-
/* @__PURE__ */ jsx(CameraIcon, {}),
|
|
1381
|
-
" Scan QR"
|
|
1382
|
-
] })
|
|
1383
|
-
},
|
|
1384
|
-
mode
|
|
1385
|
-
)) }),
|
|
1386
|
-
scanMode === "show-qr" && /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
|
|
1387
|
-
/* @__PURE__ */ jsx("p", { style: { color: "rgba(255,255,255,0.45)", fontSize: "13px", marginBottom: "16px", lineHeight: 1.5 }, children: "Scan this QR code with Sheep Wallet on your mobile device to connect" }),
|
|
1388
|
-
/* @__PURE__ */ jsxs("div", { style: {
|
|
1389
|
-
display: "inline-block",
|
|
1390
|
-
padding: "16px",
|
|
1391
|
-
backgroundColor: "#FFFFFF",
|
|
1392
|
-
borderRadius: "16px",
|
|
1393
|
-
position: "relative"
|
|
1394
|
-
}, children: [
|
|
1395
|
-
[
|
|
1396
|
-
{ top: -2, left: -2, borderTop: "3px solid #6EB9A8", borderLeft: "3px solid #6EB9A8", borderTopLeftRadius: "12px" },
|
|
1397
|
-
{ top: -2, right: -2, borderTop: "3px solid #6EB9A8", borderRight: "3px solid #6EB9A8", borderTopRightRadius: "12px" },
|
|
1398
|
-
{ bottom: -2, left: -2, borderBottom: "3px solid #6EB9A8", borderLeft: "3px solid #6EB9A8", borderBottomLeftRadius: "12px" },
|
|
1399
|
-
{ bottom: -2, right: -2, borderBottom: "3px solid #6EB9A8", borderRight: "3px solid #6EB9A8", borderBottomRightRadius: "12px" }
|
|
1400
|
-
].map((s, i) => /* @__PURE__ */ jsx("div", { style: { position: "absolute", width: "24px", height: "24px", ...s } }, i)),
|
|
1401
|
-
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, style: { width: "200px", height: "200px", display: "block" } })
|
|
1402
|
-
] }),
|
|
1403
|
-
/* @__PURE__ */ jsxs("div", { style: { marginTop: "16px", display: "flex", alignItems: "center", justifyContent: "center", gap: "8px" }, children: [
|
|
1404
|
-
/* @__PURE__ */ jsx("div", { style: {
|
|
1405
|
-
width: "7px",
|
|
1406
|
-
height: "7px",
|
|
1407
|
-
borderRadius: "50%",
|
|
1408
|
-
backgroundColor: state.scanConnectStatus === "waiting" ? "#6EB9A8" : "#F59E0B",
|
|
1409
|
-
animation: "walletModalPulse 2s infinite"
|
|
1410
|
-
} }),
|
|
1411
|
-
/* @__PURE__ */ jsxs("span", { style: { color: "rgba(255,255,255,0.4)", fontSize: "12px" }, children: [
|
|
1412
|
-
state.scanConnectStatus === "generating" && "Generating session...",
|
|
1413
|
-
state.scanConnectStatus === "waiting" && "Waiting for wallet to scan...",
|
|
1414
|
-
state.scanConnectStatus === "scanned" && "Scanned! Waiting for approval...",
|
|
1415
|
-
state.scanConnectStatus === "connected" && "Connected!",
|
|
1416
|
-
state.scanConnectStatus === "error" && "Connection failed. Try again.",
|
|
1417
|
-
state.scanConnectStatus === "idle" && "Initializing..."
|
|
1418
|
-
] })
|
|
1419
|
-
] }),
|
|
1420
|
-
/* @__PURE__ */ jsxs(
|
|
1421
|
-
"button",
|
|
1422
|
-
{
|
|
1423
|
-
type: "button",
|
|
1424
|
-
onClick: (e) => {
|
|
1425
|
-
stop(e);
|
|
1426
|
-
generateScanSession();
|
|
1427
|
-
},
|
|
1428
|
-
style: {
|
|
1429
|
-
marginTop: "12px",
|
|
1430
|
-
padding: "8px 16px",
|
|
1431
|
-
backgroundColor: "transparent",
|
|
1432
|
-
border: "1px solid rgba(255,255,255,0.08)",
|
|
1433
|
-
borderRadius: "10px",
|
|
1434
|
-
color: "#6EB9A8",
|
|
1435
|
-
fontSize: "12px",
|
|
1436
|
-
cursor: "pointer",
|
|
1437
|
-
display: "inline-flex",
|
|
1438
|
-
alignItems: "center",
|
|
1439
|
-
gap: "6px",
|
|
1440
|
-
transition: "all 0.15s"
|
|
1441
|
-
},
|
|
1442
|
-
children: [
|
|
1443
|
-
/* @__PURE__ */ jsx(RefreshIcon, {}),
|
|
1444
|
-
" Refresh QR"
|
|
1445
|
-
]
|
|
1446
|
-
}
|
|
1447
|
-
)
|
|
1273
|
+
const stop = (e) => e.stopPropagation();
|
|
1274
|
+
const content = /* @__PURE__ */ jsx(Fragment, { children: showSuccess && state.status === "connected" && state.accounts.length > 0 ? /* @__PURE__ */ jsx(SuccessView, { address: state.accounts[0]?.address || "" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1275
|
+
/* @__PURE__ */ jsxs("div", { style: S.tabBar, children: [
|
|
1276
|
+
/* @__PURE__ */ jsxs("button", { type: "button", onClick: (e) => {
|
|
1277
|
+
stop(e);
|
|
1278
|
+
setActiveTab("extension");
|
|
1279
|
+
}, style: tabStyle(activeTab === "extension"), children: [
|
|
1280
|
+
/* @__PURE__ */ jsx(IconExtension, {}),
|
|
1281
|
+
" Extension"
|
|
1448
1282
|
] }),
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
}, children: [
|
|
1463
|
-
/* @__PURE__ */ jsx("div", { style: { color: "rgba(255,255,255,0.2)" }, children: /* @__PURE__ */ jsx(CameraIcon, {}) }),
|
|
1464
|
-
/* @__PURE__ */ jsx("span", { style: { color: "rgba(255,255,255,0.3)", fontSize: "13px" }, children: "Camera access required" }),
|
|
1465
|
-
/* @__PURE__ */ jsx(
|
|
1466
|
-
"button",
|
|
1467
|
-
{
|
|
1468
|
-
type: "button",
|
|
1469
|
-
onClick: (e) => {
|
|
1470
|
-
stop(e);
|
|
1471
|
-
alert("Camera scanning requires HTTPS and camera permissions. This feature works in the installed extension.");
|
|
1472
|
-
},
|
|
1473
|
-
style: {
|
|
1474
|
-
padding: "8px 20px",
|
|
1475
|
-
backgroundColor: "#6EB9A8",
|
|
1476
|
-
border: "none",
|
|
1477
|
-
borderRadius: "10px",
|
|
1478
|
-
color: "#011B29",
|
|
1479
|
-
fontSize: "13px",
|
|
1480
|
-
fontWeight: 500,
|
|
1481
|
-
cursor: "pointer"
|
|
1482
|
-
},
|
|
1483
|
-
children: "Open Camera"
|
|
1484
|
-
}
|
|
1485
|
-
)
|
|
1486
|
-
] })
|
|
1283
|
+
/* @__PURE__ */ jsxs("button", { type: "button", onClick: (e) => {
|
|
1284
|
+
stop(e);
|
|
1285
|
+
setActiveTab("scan");
|
|
1286
|
+
}, style: tabStyle(activeTab === "scan"), children: [
|
|
1287
|
+
/* @__PURE__ */ jsx(IconQR, {}),
|
|
1288
|
+
" Scan"
|
|
1289
|
+
] }),
|
|
1290
|
+
/* @__PURE__ */ jsxs("button", { type: "button", onClick: (e) => {
|
|
1291
|
+
stop(e);
|
|
1292
|
+
setActiveTab("webwallet");
|
|
1293
|
+
}, style: tabStyle(activeTab === "webwallet"), children: [
|
|
1294
|
+
/* @__PURE__ */ jsx(IconWeb, {}),
|
|
1295
|
+
" Web Wallet"
|
|
1487
1296
|
] })
|
|
1488
|
-
] }),
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
/* @__PURE__ */ jsx(
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1297
|
+
] }),
|
|
1298
|
+
activeTab === "extension" && /* @__PURE__ */ jsx(
|
|
1299
|
+
ExtensionTab,
|
|
1300
|
+
{
|
|
1301
|
+
onConnect: handleExtensionConnect,
|
|
1302
|
+
extensionDetected,
|
|
1303
|
+
connecting: state.status === "connecting",
|
|
1304
|
+
error: state.error
|
|
1305
|
+
}
|
|
1306
|
+
),
|
|
1307
|
+
activeTab === "scan" && /* @__PURE__ */ jsx(ScanTab, { scanConnectRelay }),
|
|
1308
|
+
activeTab === "webwallet" && /* @__PURE__ */ jsx(WebWalletTab, { onConnected: () => {
|
|
1309
|
+
} }),
|
|
1310
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
1311
|
+
marginTop: "24px",
|
|
1312
|
+
textAlign: "center",
|
|
1313
|
+
color: "rgba(255,255,255,0.2)",
|
|
1314
|
+
fontSize: "11px",
|
|
1315
|
+
paddingTop: "16px",
|
|
1316
|
+
borderTop: "1px solid rgba(255,255,255,0.04)"
|
|
1317
|
+
}, children: "Powered by Rialo Network" })
|
|
1318
|
+
] }) });
|
|
1319
|
+
const keyframes = `
|
|
1320
|
+
@keyframes swModalFadeIn {
|
|
1321
|
+
from { opacity: 0; transform: scale(0.97) translateY(8px); }
|
|
1322
|
+
to { opacity: 1; transform: scale(1) translateY(0); }
|
|
1323
|
+
}
|
|
1324
|
+
@keyframes swModalSlideUp {
|
|
1325
|
+
from { transform: translateY(100%); }
|
|
1326
|
+
to { transform: translateY(0); }
|
|
1327
|
+
}
|
|
1328
|
+
@keyframes swModalPulse {
|
|
1329
|
+
0%, 100% { opacity: 1; }
|
|
1330
|
+
50% { opacity: 0.3; }
|
|
1331
|
+
}
|
|
1332
|
+
`;
|
|
1524
1333
|
if (isMobile) {
|
|
1525
1334
|
return /* @__PURE__ */ jsxs("div", { style: { position: "fixed", inset: 0, zIndex: 9999 }, children: [
|
|
1526
|
-
/* @__PURE__ */ jsx(
|
|
1527
|
-
"div",
|
|
1528
|
-
{
|
|
1529
|
-
style: {
|
|
1530
|
-
position: "absolute",
|
|
1531
|
-
inset: 0,
|
|
1532
|
-
backgroundColor: "rgba(0,0,0,0.6)",
|
|
1533
|
-
backdropFilter: "blur(8px)",
|
|
1534
|
-
WebkitBackdropFilter: "blur(8px)"
|
|
1535
|
-
},
|
|
1536
|
-
onClick: closeModal
|
|
1537
|
-
}
|
|
1538
|
-
),
|
|
1335
|
+
/* @__PURE__ */ jsx("div", { style: S.backdrop, onClick: closeModal }),
|
|
1539
1336
|
/* @__PURE__ */ jsxs(
|
|
1540
1337
|
"div",
|
|
1541
1338
|
{
|
|
@@ -1556,88 +1353,503 @@ function WalletModal({ scanConnectRelay, dispatch }) {
|
|
|
1556
1353
|
boxShadow: "0 -8px 40px rgba(0,0,0,0.5)",
|
|
1557
1354
|
transform: `translateY(${dragY}px)`,
|
|
1558
1355
|
transition: isDragging ? "none" : "transform 0.3s cubic-bezier(0.4,0,0.2,1)",
|
|
1559
|
-
animation: isDragging ? "none" : "
|
|
1356
|
+
animation: isDragging ? "none" : "swModalSlideUp 0.35s cubic-bezier(0.4,0,0.2,1)"
|
|
1560
1357
|
},
|
|
1561
1358
|
children: [
|
|
1562
1359
|
/* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center", padding: "12px 0 16px", cursor: "grab", touchAction: "none" }, children: /* @__PURE__ */ jsx("div", { style: { width: "36px", height: "4px", borderRadius: "2px", backgroundColor: "rgba(255,255,255,0.12)" } }) }),
|
|
1563
|
-
/* @__PURE__ */ jsxs("div", { style:
|
|
1564
|
-
/* @__PURE__ */ jsx("h2", { style:
|
|
1565
|
-
/* @__PURE__ */ jsx("button", { type: "button", onClick: closeModal, style: closeBtn, children: /* @__PURE__ */ jsx(
|
|
1360
|
+
/* @__PURE__ */ jsxs("div", { style: S.header, children: [
|
|
1361
|
+
/* @__PURE__ */ jsx("h2", { style: S.title, children: "Connect Wallet" }),
|
|
1362
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: closeModal, style: S.closeBtn, children: /* @__PURE__ */ jsx(IconClose, {}) })
|
|
1566
1363
|
] }),
|
|
1567
|
-
|
|
1364
|
+
content
|
|
1568
1365
|
]
|
|
1569
1366
|
}
|
|
1570
1367
|
),
|
|
1571
|
-
/* @__PURE__ */ jsx("style", { children:
|
|
1572
|
-
@keyframes walletModalSlideUp {
|
|
1573
|
-
from { transform: translateY(100%); }
|
|
1574
|
-
to { transform: translateY(0); }
|
|
1575
|
-
}
|
|
1576
|
-
@keyframes walletModalPulse {
|
|
1577
|
-
0%, 100% { opacity: 1; }
|
|
1578
|
-
50% { opacity: 0.3; }
|
|
1579
|
-
}
|
|
1580
|
-
` })
|
|
1368
|
+
/* @__PURE__ */ jsx("style", { children: keyframes })
|
|
1581
1369
|
] });
|
|
1582
1370
|
}
|
|
1583
1371
|
return /* @__PURE__ */ jsxs("div", { style: { position: "fixed", inset: 0, zIndex: 9999 }, children: [
|
|
1584
|
-
/* @__PURE__ */ jsx(
|
|
1585
|
-
|
|
1586
|
-
{
|
|
1587
|
-
style:
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1372
|
+
/* @__PURE__ */ jsx("div", { style: S.backdrop, onClick: closeModal }),
|
|
1373
|
+
/* @__PURE__ */ jsx("div", { style: { position: "fixed", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", pointerEvents: "none" }, children: /* @__PURE__ */ jsxs("div", { style: S.dialog, children: [
|
|
1374
|
+
/* @__PURE__ */ jsxs("div", { style: S.header, children: [
|
|
1375
|
+
/* @__PURE__ */ jsx("h2", { style: S.title, children: "Connect Wallet" }),
|
|
1376
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: closeModal, style: S.closeBtn, children: /* @__PURE__ */ jsx(IconClose, {}) })
|
|
1377
|
+
] }),
|
|
1378
|
+
content
|
|
1379
|
+
] }) }),
|
|
1380
|
+
/* @__PURE__ */ jsx("style", { children: keyframes })
|
|
1381
|
+
] });
|
|
1382
|
+
}
|
|
1383
|
+
var initialState = {
|
|
1384
|
+
status: "disconnected",
|
|
1385
|
+
accounts: [],
|
|
1386
|
+
network: "devnet",
|
|
1387
|
+
balance: null,
|
|
1388
|
+
error: null,
|
|
1389
|
+
isModalOpen: false,
|
|
1390
|
+
scanConnectStatus: "idle"
|
|
1391
|
+
};
|
|
1392
|
+
function walletReducer(state, action) {
|
|
1393
|
+
switch (action.type) {
|
|
1394
|
+
case "CONNECTING":
|
|
1395
|
+
return { ...state, status: "connecting", error: null };
|
|
1396
|
+
case "CONNECTED":
|
|
1397
|
+
return {
|
|
1398
|
+
...state,
|
|
1399
|
+
status: "connected",
|
|
1400
|
+
accounts: action.accounts,
|
|
1401
|
+
network: action.network,
|
|
1402
|
+
error: null
|
|
1403
|
+
// Do NOT close modal here — let the modal show success state first
|
|
1404
|
+
};
|
|
1405
|
+
case "DISCONNECTED":
|
|
1406
|
+
return { ...state, status: "disconnected", accounts: [], balance: null, error: null };
|
|
1407
|
+
case "ERROR":
|
|
1408
|
+
return { ...state, status: "error", error: action.error };
|
|
1409
|
+
case "SET_BALANCE":
|
|
1410
|
+
return { ...state, balance: action.balance };
|
|
1411
|
+
case "SET_NETWORK":
|
|
1412
|
+
return { ...state, network: action.network };
|
|
1413
|
+
case "SET_ACCOUNTS":
|
|
1414
|
+
return { ...state, accounts: action.accounts };
|
|
1415
|
+
case "OPEN_MODAL":
|
|
1416
|
+
return { ...state, isModalOpen: true };
|
|
1417
|
+
case "CLOSE_MODAL":
|
|
1418
|
+
return { ...state, isModalOpen: false, scanConnectStatus: "idle" };
|
|
1419
|
+
case "RESET_ERROR":
|
|
1420
|
+
return { ...state, error: null, status: state.accounts.length > 0 ? "connected" : "disconnected" };
|
|
1421
|
+
case "SET_SCAN_STATUS":
|
|
1422
|
+
return { ...state, scanConnectStatus: action.status };
|
|
1423
|
+
default:
|
|
1424
|
+
return state;
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
var WalletContext = createContext(null);
|
|
1428
|
+
var DEFAULT_WALLETS = [
|
|
1429
|
+
{
|
|
1430
|
+
id: "sheep-wallet",
|
|
1431
|
+
name: "Sheep Wallet",
|
|
1432
|
+
icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHJ4PSI4IiBmaWxsPSIjMDExQjI5Ii8+PHRleHQgeD0iNTAlIiB5PSI1NSUiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXdlaWdodD0iYm9sZCIgZm9udC1zaXplPSIxNiIgZmlsbD0iIzZFQjlBOCI+Uzwvc2VsZj48L3N2Zz4=",
|
|
1433
|
+
downloadUrl: "https://rialo.io/wallet",
|
|
1434
|
+
supportsREX: true,
|
|
1435
|
+
supportsSfS: true,
|
|
1436
|
+
supportsScanConnect: true
|
|
1437
|
+
}
|
|
1438
|
+
];
|
|
1439
|
+
function WalletProvider({
|
|
1440
|
+
children,
|
|
1441
|
+
network: initialNetwork = "devnet",
|
|
1442
|
+
autoConnect = true,
|
|
1443
|
+
wallets: customWallets = [],
|
|
1444
|
+
scanConnectRelay = "wss://relay.rialo.io",
|
|
1445
|
+
onConnect,
|
|
1446
|
+
onDisconnect,
|
|
1447
|
+
onError,
|
|
1448
|
+
onNetworkChange
|
|
1449
|
+
}) {
|
|
1450
|
+
const [state, dispatch] = useReducer(walletReducer, {
|
|
1451
|
+
...initialState,
|
|
1452
|
+
network: initialNetwork
|
|
1453
|
+
});
|
|
1454
|
+
const walletRef = useRef(null);
|
|
1455
|
+
const providerRef = useRef(void 0);
|
|
1456
|
+
const connectingRef = useRef(false);
|
|
1457
|
+
const mountedRef = useRef(true);
|
|
1458
|
+
useEffect(() => {
|
|
1459
|
+
mountedRef.current = true;
|
|
1460
|
+
walletRef.current = new SheepWallet();
|
|
1461
|
+
waitForProvider(3e3).then((provider) => {
|
|
1462
|
+
if (mountedRef.current) {
|
|
1463
|
+
providerRef.current = provider;
|
|
1595
1464
|
}
|
|
1596
|
-
)
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1465
|
+
});
|
|
1466
|
+
return () => {
|
|
1467
|
+
mountedRef.current = false;
|
|
1468
|
+
walletRef.current?.destroy();
|
|
1469
|
+
};
|
|
1470
|
+
}, []);
|
|
1471
|
+
useEffect(() => {
|
|
1472
|
+
const setupEvents = async () => {
|
|
1473
|
+
const provider = await waitForProvider(3e3);
|
|
1474
|
+
if (!provider || !mountedRef.current) return;
|
|
1475
|
+
providerRef.current = provider;
|
|
1476
|
+
const cleanups = [];
|
|
1477
|
+
cleanups.push(
|
|
1478
|
+
provider.on("disconnect", () => {
|
|
1479
|
+
if (!mountedRef.current) return;
|
|
1480
|
+
dispatch({ type: "DISCONNECTED" });
|
|
1481
|
+
onDisconnect?.();
|
|
1482
|
+
})
|
|
1483
|
+
);
|
|
1484
|
+
cleanups.push(
|
|
1485
|
+
provider.on("accountsChanged", (data) => {
|
|
1486
|
+
if (!mountedRef.current) return;
|
|
1487
|
+
const accounts = normalizeAccounts(data);
|
|
1488
|
+
dispatch({ type: "SET_ACCOUNTS", accounts });
|
|
1489
|
+
})
|
|
1490
|
+
);
|
|
1491
|
+
cleanups.push(
|
|
1492
|
+
provider.on("networkChanged", (data) => {
|
|
1493
|
+
if (!mountedRef.current) return;
|
|
1494
|
+
const { network } = data;
|
|
1495
|
+
if (network) {
|
|
1496
|
+
dispatch({ type: "SET_NETWORK", network });
|
|
1497
|
+
onNetworkChange?.(network);
|
|
1498
|
+
}
|
|
1499
|
+
})
|
|
1500
|
+
);
|
|
1501
|
+
return () => {
|
|
1502
|
+
cleanups.forEach((fn) => {
|
|
1503
|
+
try {
|
|
1504
|
+
fn();
|
|
1505
|
+
} catch {
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
|
+
};
|
|
1509
|
+
};
|
|
1510
|
+
const cleanup = setupEvents();
|
|
1511
|
+
return () => {
|
|
1512
|
+
cleanup.then((fn) => fn?.());
|
|
1513
|
+
};
|
|
1514
|
+
}, [onDisconnect, onNetworkChange]);
|
|
1515
|
+
useEffect(() => {
|
|
1516
|
+
if (!autoConnect) return;
|
|
1517
|
+
if (state.status === "connected" || state.status === "connecting") return;
|
|
1518
|
+
const tryAutoConnect = async () => {
|
|
1519
|
+
const wallet = walletRef.current;
|
|
1520
|
+
if (!wallet || !hasProvider()) return;
|
|
1521
|
+
try {
|
|
1522
|
+
const accounts = await wallet.checkSession();
|
|
1523
|
+
if (accounts && accounts.length > 0 && mountedRef.current) {
|
|
1524
|
+
dispatch({ type: "CONNECTED", accounts, network: wallet.network });
|
|
1525
|
+
onConnect?.(accounts);
|
|
1526
|
+
}
|
|
1527
|
+
} catch {
|
|
1528
|
+
}
|
|
1529
|
+
};
|
|
1530
|
+
const timer = setTimeout(tryAutoConnect, 500);
|
|
1531
|
+
return () => clearTimeout(timer);
|
|
1532
|
+
}, [autoConnect, onConnect]);
|
|
1533
|
+
useEffect(() => {
|
|
1534
|
+
if (state.status !== "connected" || state.accounts.length === 0) return;
|
|
1535
|
+
const refresh = async () => {
|
|
1536
|
+
const wallet = walletRef.current;
|
|
1537
|
+
if (!wallet || !mountedRef.current) return;
|
|
1538
|
+
try {
|
|
1539
|
+
const balance = await wallet.getBalance();
|
|
1540
|
+
if (mountedRef.current) {
|
|
1541
|
+
dispatch({ type: "SET_BALANCE", balance });
|
|
1542
|
+
}
|
|
1543
|
+
} catch {
|
|
1544
|
+
}
|
|
1545
|
+
};
|
|
1546
|
+
refresh();
|
|
1547
|
+
const interval = setInterval(refresh, 3e4);
|
|
1548
|
+
return () => clearInterval(interval);
|
|
1549
|
+
}, [state.status, state.accounts]);
|
|
1550
|
+
const connect = useCallback(async () => {
|
|
1551
|
+
if (connectingRef.current) {
|
|
1552
|
+
throw new Error("Connection already in progress");
|
|
1553
|
+
}
|
|
1554
|
+
const wallet = walletRef.current;
|
|
1555
|
+
if (!wallet) {
|
|
1556
|
+
const err = new Error("Wallet not initialized");
|
|
1557
|
+
dispatch({ type: "ERROR", error: err });
|
|
1558
|
+
throw err;
|
|
1559
|
+
}
|
|
1560
|
+
if (!hasProvider()) {
|
|
1561
|
+
dispatch({ type: "OPEN_MODAL" });
|
|
1562
|
+
return [];
|
|
1563
|
+
}
|
|
1564
|
+
connectingRef.current = true;
|
|
1565
|
+
dispatch({ type: "CONNECTING" });
|
|
1566
|
+
try {
|
|
1567
|
+
const accounts = await wallet.connect();
|
|
1568
|
+
if (mountedRef.current) {
|
|
1569
|
+
dispatch({ type: "CONNECTED", accounts, network: wallet.network });
|
|
1570
|
+
onConnect?.(accounts);
|
|
1571
|
+
}
|
|
1572
|
+
return accounts;
|
|
1573
|
+
} catch (error) {
|
|
1574
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1575
|
+
if (mountedRef.current) {
|
|
1576
|
+
dispatch({ type: "ERROR", error: err });
|
|
1577
|
+
onError?.(err);
|
|
1578
|
+
}
|
|
1579
|
+
throw err;
|
|
1580
|
+
} finally {
|
|
1581
|
+
connectingRef.current = false;
|
|
1582
|
+
}
|
|
1583
|
+
}, [onConnect, onError]);
|
|
1584
|
+
const disconnect = useCallback(async () => {
|
|
1585
|
+
const wallet = walletRef.current;
|
|
1586
|
+
if (!wallet) return;
|
|
1587
|
+
try {
|
|
1588
|
+
await wallet.disconnect();
|
|
1589
|
+
} catch {
|
|
1590
|
+
}
|
|
1591
|
+
if (mountedRef.current) {
|
|
1592
|
+
dispatch({ type: "DISCONNECTED" });
|
|
1593
|
+
onDisconnect?.();
|
|
1594
|
+
}
|
|
1595
|
+
}, [onDisconnect]);
|
|
1596
|
+
const refreshBalance = useCallback(async () => {
|
|
1597
|
+
const wallet = walletRef.current;
|
|
1598
|
+
if (!wallet || state.status !== "connected") return;
|
|
1599
|
+
try {
|
|
1600
|
+
const balance = await wallet.getBalance();
|
|
1601
|
+
if (mountedRef.current) {
|
|
1602
|
+
dispatch({ type: "SET_BALANCE", balance });
|
|
1627
1603
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1604
|
+
} catch {
|
|
1605
|
+
}
|
|
1606
|
+
}, [state.status]);
|
|
1607
|
+
const switchNetwork = useCallback(async (network) => {
|
|
1608
|
+
const wallet = walletRef.current;
|
|
1609
|
+
if (!wallet) return;
|
|
1610
|
+
await wallet.switchNetwork(network);
|
|
1611
|
+
if (mountedRef.current) {
|
|
1612
|
+
dispatch({ type: "SET_NETWORK", network });
|
|
1613
|
+
onNetworkChange?.(network);
|
|
1614
|
+
}
|
|
1615
|
+
}, [onNetworkChange]);
|
|
1616
|
+
const signMessage = useCallback(async (message) => {
|
|
1617
|
+
const wallet = walletRef.current;
|
|
1618
|
+
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
1619
|
+
return wallet.signMessage(message);
|
|
1620
|
+
}, [state.status]);
|
|
1621
|
+
const signTransaction = useCallback(async (tx) => {
|
|
1622
|
+
const wallet = walletRef.current;
|
|
1623
|
+
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
1624
|
+
return wallet.signTransaction(tx);
|
|
1625
|
+
}, [state.status]);
|
|
1626
|
+
const sendTransaction = useCallback(async (tx) => {
|
|
1627
|
+
const wallet = walletRef.current;
|
|
1628
|
+
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
1629
|
+
return wallet.sendTransaction(tx);
|
|
1630
|
+
}, [state.status]);
|
|
1631
|
+
const signAndSendTransaction = useCallback(async (tx) => {
|
|
1632
|
+
const wallet = walletRef.current;
|
|
1633
|
+
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
1634
|
+
return wallet.signAndSendTransaction(tx);
|
|
1635
|
+
}, [state.status]);
|
|
1636
|
+
const getREXCapabilities = useCallback(async () => {
|
|
1637
|
+
const wallet = walletRef.current;
|
|
1638
|
+
if (!wallet) return { supported: false, privacyModes: [], maxInputSize: 0, programs: [] };
|
|
1639
|
+
return wallet.getREXCapabilities();
|
|
1640
|
+
}, []);
|
|
1641
|
+
const submitREXTransaction = useCallback(async (tx) => {
|
|
1642
|
+
const wallet = walletRef.current;
|
|
1643
|
+
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
1644
|
+
return wallet.submitREXTransaction(tx);
|
|
1645
|
+
}, [state.status]);
|
|
1646
|
+
const sendGaslessTransaction = useCallback(async (tx) => {
|
|
1647
|
+
const wallet = walletRef.current;
|
|
1648
|
+
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
1649
|
+
return wallet.sendGaslessTransaction(tx);
|
|
1650
|
+
}, [state.status]);
|
|
1651
|
+
const getSfSPositions = useCallback(async () => {
|
|
1652
|
+
const wallet = walletRef.current;
|
|
1653
|
+
if (!wallet || state.status !== "connected") return [];
|
|
1654
|
+
return wallet.getSfSPositions();
|
|
1655
|
+
}, [state.status]);
|
|
1656
|
+
const createSfSPosition = useCallback(async (params) => {
|
|
1657
|
+
const wallet = walletRef.current;
|
|
1658
|
+
if (!wallet || state.status !== "connected") throw new Error("Wallet not connected");
|
|
1659
|
+
return wallet.createSfSPosition(params);
|
|
1660
|
+
}, [state.status]);
|
|
1661
|
+
const getSfSCredits = useCallback(async () => {
|
|
1662
|
+
const wallet = walletRef.current;
|
|
1663
|
+
if (!wallet || state.status !== "connected") {
|
|
1664
|
+
return { available: "0", usedThisEpoch: "0", totalEarned: "0", estimatedPerEpoch: "0" };
|
|
1665
|
+
}
|
|
1666
|
+
return wallet.getSfSCredits();
|
|
1667
|
+
}, [state.status]);
|
|
1668
|
+
const openModal = useCallback(() => dispatch({ type: "OPEN_MODAL" }), []);
|
|
1669
|
+
const closeModal = useCallback(() => dispatch({ type: "CLOSE_MODAL" }), []);
|
|
1670
|
+
const wallets = useMemo(() => {
|
|
1671
|
+
const extensionInstalled = isInstalled();
|
|
1672
|
+
return [...DEFAULT_WALLETS, ...customWallets].map((w) => ({
|
|
1673
|
+
...w,
|
|
1674
|
+
installed: w.id === "sheep-wallet" ? extensionInstalled : false
|
|
1675
|
+
}));
|
|
1676
|
+
}, [customWallets]);
|
|
1677
|
+
const value = useMemo(() => ({
|
|
1678
|
+
state,
|
|
1679
|
+
connected: state.status === "connected",
|
|
1680
|
+
connecting: state.status === "connecting",
|
|
1681
|
+
activeAccount: state.accounts[0] || null,
|
|
1682
|
+
chainId: `rialo:${state.network}`,
|
|
1683
|
+
isInstalled: isInstalled(),
|
|
1684
|
+
wallets,
|
|
1685
|
+
connect,
|
|
1686
|
+
disconnect,
|
|
1687
|
+
refreshBalance,
|
|
1688
|
+
switchNetwork,
|
|
1689
|
+
signMessage,
|
|
1690
|
+
signTransaction,
|
|
1691
|
+
sendTransaction,
|
|
1692
|
+
signAndSendTransaction,
|
|
1693
|
+
getREXCapabilities,
|
|
1694
|
+
submitREXTransaction,
|
|
1695
|
+
sendGaslessTransaction,
|
|
1696
|
+
getSfSPositions,
|
|
1697
|
+
createSfSPosition,
|
|
1698
|
+
getSfSCredits,
|
|
1699
|
+
openModal,
|
|
1700
|
+
closeModal,
|
|
1701
|
+
wallet: walletRef.current
|
|
1702
|
+
}), [
|
|
1703
|
+
state,
|
|
1704
|
+
wallets,
|
|
1705
|
+
connect,
|
|
1706
|
+
disconnect,
|
|
1707
|
+
refreshBalance,
|
|
1708
|
+
switchNetwork,
|
|
1709
|
+
signMessage,
|
|
1710
|
+
signTransaction,
|
|
1711
|
+
sendTransaction,
|
|
1712
|
+
signAndSendTransaction,
|
|
1713
|
+
getREXCapabilities,
|
|
1714
|
+
submitREXTransaction,
|
|
1715
|
+
sendGaslessTransaction,
|
|
1716
|
+
getSfSPositions,
|
|
1717
|
+
createSfSPosition,
|
|
1718
|
+
getSfSCredits,
|
|
1719
|
+
openModal,
|
|
1720
|
+
closeModal
|
|
1721
|
+
]);
|
|
1722
|
+
return /* @__PURE__ */ jsxs(WalletContext.Provider, { value, children: [
|
|
1723
|
+
children,
|
|
1724
|
+
/* @__PURE__ */ jsx(WalletModal, { scanConnectRelay })
|
|
1639
1725
|
] });
|
|
1640
1726
|
}
|
|
1727
|
+
function useWallet() {
|
|
1728
|
+
const context = useContext(WalletContext);
|
|
1729
|
+
if (!context) {
|
|
1730
|
+
throw new Error("useWallet must be used within WalletProvider");
|
|
1731
|
+
}
|
|
1732
|
+
return context;
|
|
1733
|
+
}
|
|
1734
|
+
function useIsConnected() {
|
|
1735
|
+
return useWallet().connected;
|
|
1736
|
+
}
|
|
1737
|
+
function useActiveAccount() {
|
|
1738
|
+
return useWallet().activeAccount;
|
|
1739
|
+
}
|
|
1740
|
+
function useAccounts() {
|
|
1741
|
+
return useWallet().state.accounts;
|
|
1742
|
+
}
|
|
1743
|
+
function useBalance() {
|
|
1744
|
+
const { state, refreshBalance } = useWallet();
|
|
1745
|
+
return { balance: state.balance, refresh: refreshBalance };
|
|
1746
|
+
}
|
|
1747
|
+
function useNetwork() {
|
|
1748
|
+
const { state, chainId } = useWallet();
|
|
1749
|
+
return { network: state.network, chainId };
|
|
1750
|
+
}
|
|
1751
|
+
function useSwitchNetwork() {
|
|
1752
|
+
const { switchNetwork, state } = useWallet();
|
|
1753
|
+
return { switchNetwork, network: state.network };
|
|
1754
|
+
}
|
|
1755
|
+
function useConnectWallet() {
|
|
1756
|
+
const { connect, openModal, connecting, connected, isInstalled: isInstalled2, state } = useWallet();
|
|
1757
|
+
return { connect, openModal, connecting, connected, isInstalled: isInstalled2, error: state.error };
|
|
1758
|
+
}
|
|
1759
|
+
function useDisconnectWallet() {
|
|
1760
|
+
const { disconnect, connected } = useWallet();
|
|
1761
|
+
return { disconnect, connected };
|
|
1762
|
+
}
|
|
1763
|
+
function useSignMessage() {
|
|
1764
|
+
const { signMessage, connected } = useWallet();
|
|
1765
|
+
return { signMessage, connected };
|
|
1766
|
+
}
|
|
1767
|
+
function useSendTransaction() {
|
|
1768
|
+
const { sendTransaction, signAndSendTransaction, sendGaslessTransaction, connected } = useWallet();
|
|
1769
|
+
return { sendTransaction, signAndSendTransaction, sendGaslessTransaction, connected };
|
|
1770
|
+
}
|
|
1771
|
+
function useREX() {
|
|
1772
|
+
const { getREXCapabilities, submitREXTransaction, connected } = useWallet();
|
|
1773
|
+
const [capabilities, setCapabilities] = useState(null);
|
|
1774
|
+
useEffect(() => {
|
|
1775
|
+
if (connected) {
|
|
1776
|
+
getREXCapabilities().then(setCapabilities).catch(() => {
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
}, [connected, getREXCapabilities]);
|
|
1780
|
+
return {
|
|
1781
|
+
capabilities,
|
|
1782
|
+
supported: capabilities?.supported ?? false,
|
|
1783
|
+
submitREXTransaction,
|
|
1784
|
+
connected
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
function useSfS() {
|
|
1788
|
+
const { getSfSPositions, createSfSPosition, getSfSCredits, sendGaslessTransaction, connected } = useWallet();
|
|
1789
|
+
const [positions, setPositions] = useState([]);
|
|
1790
|
+
const [credits, setCredits] = useState(null);
|
|
1791
|
+
const refresh = useCallback(async () => {
|
|
1792
|
+
if (!connected) return;
|
|
1793
|
+
const [pos, cred] = await Promise.all([
|
|
1794
|
+
getSfSPositions().catch(() => []),
|
|
1795
|
+
getSfSCredits().catch(() => null)
|
|
1796
|
+
]);
|
|
1797
|
+
setPositions(pos);
|
|
1798
|
+
if (cred) setCredits(cred);
|
|
1799
|
+
}, [connected, getSfSPositions, getSfSCredits]);
|
|
1800
|
+
useEffect(() => {
|
|
1801
|
+
refresh();
|
|
1802
|
+
}, [refresh]);
|
|
1803
|
+
return {
|
|
1804
|
+
positions,
|
|
1805
|
+
credits,
|
|
1806
|
+
hasCredits: BigInt(credits?.available ?? "0") > 0n,
|
|
1807
|
+
createPosition: createSfSPosition,
|
|
1808
|
+
sendGasless: sendGaslessTransaction,
|
|
1809
|
+
refresh,
|
|
1810
|
+
connected
|
|
1811
|
+
};
|
|
1812
|
+
}
|
|
1813
|
+
function useScanConnect() {
|
|
1814
|
+
const { wallet, state } = useWallet();
|
|
1815
|
+
const [scanURI, setScanURI] = useState(null);
|
|
1816
|
+
const [status, setStatus] = useState("idle");
|
|
1817
|
+
const generateQR = useCallback(async () => {
|
|
1818
|
+
if (!wallet) return;
|
|
1819
|
+
setStatus("generating");
|
|
1820
|
+
try {
|
|
1821
|
+
const uri = await wallet.createScanSession();
|
|
1822
|
+
setScanURI(uri);
|
|
1823
|
+
setStatus("waiting");
|
|
1824
|
+
} catch (error) {
|
|
1825
|
+
setStatus("error");
|
|
1826
|
+
}
|
|
1827
|
+
}, [wallet]);
|
|
1828
|
+
const approveSession = useCallback(async (sessionId) => {
|
|
1829
|
+
if (!wallet) return [];
|
|
1830
|
+
setStatus("approving");
|
|
1831
|
+
try {
|
|
1832
|
+
const accounts = await wallet.approveScanSession(sessionId);
|
|
1833
|
+
setStatus("connected");
|
|
1834
|
+
return accounts;
|
|
1835
|
+
} catch {
|
|
1836
|
+
setStatus("error");
|
|
1837
|
+
return [];
|
|
1838
|
+
}
|
|
1839
|
+
}, [wallet]);
|
|
1840
|
+
const rejectSession = useCallback(async (sessionId) => {
|
|
1841
|
+
if (!wallet) return;
|
|
1842
|
+
await wallet.rejectScanSession(sessionId);
|
|
1843
|
+
setStatus("rejected");
|
|
1844
|
+
}, [wallet]);
|
|
1845
|
+
return {
|
|
1846
|
+
scanURI,
|
|
1847
|
+
status,
|
|
1848
|
+
generateQR,
|
|
1849
|
+
approveSession,
|
|
1850
|
+
rejectSession
|
|
1851
|
+
};
|
|
1852
|
+
}
|
|
1641
1853
|
function ConnectButton({
|
|
1642
1854
|
connectLabel = "Connect Wallet",
|
|
1643
1855
|
disconnectLabel = "Disconnect",
|
|
@@ -1648,19 +1860,12 @@ function ConnectButton({
|
|
|
1648
1860
|
style
|
|
1649
1861
|
}) {
|
|
1650
1862
|
const { connected, connecting, connect, disconnect, activeAccount, state, openModal, isInstalled: installed } = useWallet();
|
|
1651
|
-
const [showMenu, setShowMenu] =
|
|
1863
|
+
const [showMenu, setShowMenu] = React2.useState(false);
|
|
1652
1864
|
const handleClick = async () => {
|
|
1653
1865
|
if (connected) {
|
|
1654
1866
|
setShowMenu(!showMenu);
|
|
1655
1867
|
} else {
|
|
1656
|
-
|
|
1657
|
-
try {
|
|
1658
|
-
await connect();
|
|
1659
|
-
} catch {
|
|
1660
|
-
}
|
|
1661
|
-
} else {
|
|
1662
|
-
openModal();
|
|
1663
|
-
}
|
|
1868
|
+
openModal();
|
|
1664
1869
|
}
|
|
1665
1870
|
};
|
|
1666
1871
|
const displayText = connected && activeAccount && showAddress ? `${activeAccount.address.slice(0, 6)}...${activeAccount.address.slice(-4)}` : connecting ? "Connecting..." : connectLabel;
|
|
@@ -1964,6 +2169,6 @@ function ApprovalPending({
|
|
|
1964
2169
|
] });
|
|
1965
2170
|
}
|
|
1966
2171
|
|
|
1967
|
-
export { ApprovalPending, ConnectButton, ConnectionStatus, LoadingSpinner, NETWORKS, SheepWallet, WalletErrorBoundary, WalletProvider, formatAddress, formatBalance, isInstalled, isValidAddress, parseBalance, useAccounts, useActiveAccount, useBalance, useConnectWallet, useDisconnectWallet, useIsConnected, useNetwork, useREX, useScanConnect, useSendTransaction, useSfS, useSignMessage, useSwitchNetwork, useWallet, withWalletErrorBoundary };
|
|
2172
|
+
export { ApprovalPending, ConnectButton, ConnectionStatus, LoadingSpinner, NETWORKS, SheepWallet, WalletErrorBoundary, WalletModal, WalletProvider, formatAddress, formatBalance, isInstalled, isValidAddress, parseBalance, useAccounts, useActiveAccount, useBalance, useConnectWallet, useDisconnectWallet, useIsConnected, useNetwork, useREX, useScanConnect, useSendTransaction, useSfS, useSignMessage, useSwitchNetwork, useWallet, withWalletErrorBoundary };
|
|
1968
2173
|
//# sourceMappingURL=react.js.map
|
|
1969
2174
|
//# sourceMappingURL=react.js.map
|