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