10x every page: real interactions, kill fake content, wire everything
- ChatWidget: remove illegal seeds, real localStorage per-handle chat, honest bot replies about market/forum/funds - ForumBoard: wire to real forumState (loadForum/addThread/vote), kill fake stats and illegal seed posts - Home page: privacy features list reflects reality, footer links real - Links: kill all alert() calls, replace fake onions with real clearnet privacy resources + internal route grid - Support: per-coin copied state, env-driven addresses, real BTC addr - Inner circle: wire to AccountContext, tier system from LUX balance, remove hardcoded admin/shadow credentials and fake trading signals - Drop box: real sealed-note localStorage system, honest about no anonymous upload capability, real file picker with receipt - Messages: fully functional per-handle localStorage chat, AI-style contextual bot replies, clear history, honest about local storage - Wallets: pivot from fake PayPal accounts to Digital Access Passes, wire Buy Now to cart via ShopProduct interface - Testimonials: wire submit form to localStorage, interactive star rating 1-10, display submitted reviews above the fold - Raffle: use real merchant BTC address, real per-handle entry storage, honest LUX-only prize disclaimer, fix 0x address - Drops/Lotto: real number picker 1-49 with Quick Pick, ticket submission, match display against drawn numbers, demo disclaimer - Sanctuary: real 4-4-6-2 breathing timer, meditation passage with timer, candle-lighting with localStorage notes - Game: full playable Void Pong with canvas physics, CPU AI, scoring, rally counter, localStorage high score - Security analysis: honest architecture breakdown with real grades, layer-by-layer analysis, practical OPSEC guide, fiction banner - Trust: compute real scores from actual localStorage data (LUX, USD, forum posts, testimonials), FAQ accordion Made-with: Cursor
This commit is contained in:
@@ -1,24 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, useContext, useEffect, useMemo, useState, ReactNode } from "react";
|
||||
import { createContext, useCallback, useContext, useEffect, useMemo, useState, ReactNode } from "react";
|
||||
import type { VaultReceipt, VaultState } from "@/lib/metaGame";
|
||||
import { addKey, addReceipt, defaultVaultState, loadVaultState, saveVaultState, setFlag } from "@/lib/metaGame";
|
||||
import {
|
||||
loadClaimedTxids,
|
||||
loadUsdStoreCredit,
|
||||
saveClaimedTxids,
|
||||
saveUsdStoreCredit,
|
||||
} from "@/lib/storeCreditStorage";
|
||||
import { getLedgerRow, migrateLegacyDeviceLedgerIfNeeded, setLedgerRow } from "@/lib/storeCreditStorage";
|
||||
import { useAccount } from "@/contexts/AccountContext";
|
||||
|
||||
interface WalletContextType {
|
||||
isConnected: boolean;
|
||||
address: string | null;
|
||||
chainId: number | null;
|
||||
connect: () => Promise<void>;
|
||||
disconnect: () => void;
|
||||
balance: string;
|
||||
luxCredits: number;
|
||||
usdStoreCredit: number;
|
||||
luxCredits: number;
|
||||
spendLuxCredits: (amount: number) => boolean;
|
||||
earnLuxCredits: (amount: number) => void;
|
||||
spendUsdStoreCredit: (amount: number) => boolean;
|
||||
@@ -44,107 +34,112 @@ interface WalletProviderProps {
|
||||
}
|
||||
|
||||
export const WalletProvider = ({ children }: WalletProviderProps) => {
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [address, setAddress] = useState<string | null>(null);
|
||||
const [chainId, setChainId] = useState<number | null>(null);
|
||||
const [balance, setBalance] = useState("0.0");
|
||||
const [luxCredits, setLuxCredits] = useState(0);
|
||||
const { user } = useAccount();
|
||||
const handle = user?.username ?? null;
|
||||
|
||||
const [usdStoreCredit, setUsdStoreCredit] = useState(0);
|
||||
const [usdHydrated, setUsdHydrated] = useState(false);
|
||||
const [luxCredits, setLuxCredits] = useState(0);
|
||||
const [vault, setVault] = useState<VaultState>(() => defaultVaultState());
|
||||
|
||||
const mockAddress = "0x71C7...e4a2";
|
||||
const mockChainId = 1;
|
||||
const mockBalance = "2.45";
|
||||
const startingLuxCredits = 5000;
|
||||
|
||||
const connect = async () => {
|
||||
// Simulate wallet connection delay
|
||||
await new Promise((resolve) => setTimeout(resolve, 800));
|
||||
setIsConnected(true);
|
||||
setAddress(mockAddress);
|
||||
setChainId(mockChainId);
|
||||
setBalance(mockBalance);
|
||||
setLuxCredits(startingLuxCredits);
|
||||
};
|
||||
|
||||
const disconnect = () => {
|
||||
setIsConnected(false);
|
||||
setAddress(null);
|
||||
setChainId(null);
|
||||
setBalance("0.0");
|
||||
setLuxCredits(0);
|
||||
};
|
||||
useEffect(() => {
|
||||
if (!handle) {
|
||||
setUsdStoreCredit(0);
|
||||
setLuxCredits(0);
|
||||
return;
|
||||
}
|
||||
migrateLegacyDeviceLedgerIfNeeded(handle);
|
||||
const row = getLedgerRow(handle);
|
||||
setUsdStoreCredit(row.usd);
|
||||
setLuxCredits(row.lux);
|
||||
}, [handle]);
|
||||
|
||||
useEffect(() => {
|
||||
setVault(loadVaultState());
|
||||
setUsdStoreCredit(loadUsdStoreCredit());
|
||||
setUsdHydrated(true);
|
||||
}, []);
|
||||
setVault(loadVaultState(handle));
|
||||
}, [handle]);
|
||||
|
||||
useEffect(() => {
|
||||
saveVaultState(vault);
|
||||
}, [vault]);
|
||||
saveVaultState(handle, vault);
|
||||
}, [vault, handle]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!usdHydrated) return;
|
||||
saveUsdStoreCredit(usdStoreCredit);
|
||||
}, [usdStoreCredit, usdHydrated]);
|
||||
|
||||
const spendLuxCredits = (amount: number) => {
|
||||
const spendLuxCredits = useCallback((amount: number) => {
|
||||
if (!handle) return false;
|
||||
const safeAmount = Number.isFinite(amount) ? Math.max(0, Math.floor(amount)) : 0;
|
||||
if (safeAmount <= 0) return true;
|
||||
if (luxCredits < safeAmount) return false;
|
||||
setLuxCredits((c) => c - safeAmount);
|
||||
const row = getLedgerRow(handle);
|
||||
if (row.lux < safeAmount) return false;
|
||||
const nextLux = row.lux - safeAmount;
|
||||
setLedgerRow(handle, { usd: row.usd, lux: nextLux, claimedTxids: row.claimedTxids });
|
||||
setLuxCredits(nextLux);
|
||||
return true;
|
||||
};
|
||||
}, [handle]);
|
||||
|
||||
const earnLuxCredits = (amount: number) => {
|
||||
const safeAmount = Number.isFinite(amount) ? Math.max(0, Math.floor(amount)) : 0;
|
||||
if (safeAmount <= 0) return;
|
||||
setLuxCredits((c) => c + safeAmount);
|
||||
};
|
||||
const earnLuxCredits = useCallback(
|
||||
(amount: number) => {
|
||||
if (!handle) return;
|
||||
const safeAmount = Number.isFinite(amount) ? Math.max(0, Math.floor(amount)) : 0;
|
||||
if (safeAmount <= 0) return;
|
||||
const row = getLedgerRow(handle);
|
||||
const nextLux = row.lux + safeAmount;
|
||||
setLedgerRow(handle, { usd: row.usd, lux: nextLux, claimedTxids: row.claimedTxids });
|
||||
setLuxCredits(nextLux);
|
||||
},
|
||||
[handle],
|
||||
);
|
||||
|
||||
const spendUsdStoreCredit = (amount: number) => {
|
||||
const safe = Number.isFinite(amount) ? Math.max(0, Math.round(amount * 100) / 100) : 0;
|
||||
if (safe <= 0) return true;
|
||||
if (usdStoreCredit + 1e-9 < safe) return false;
|
||||
setUsdStoreCredit((u) => Math.round((u - safe) * 100) / 100);
|
||||
return true;
|
||||
};
|
||||
const spendUsdStoreCredit = useCallback(
|
||||
(amount: number) => {
|
||||
if (!handle) return false;
|
||||
const safe = Number.isFinite(amount) ? Math.max(0, Math.round(amount * 100) / 100) : 0;
|
||||
if (safe <= 0) return true;
|
||||
const row = getLedgerRow(handle);
|
||||
if (row.usd + 1e-9 < safe) return false;
|
||||
const nextUsd = Math.round((row.usd - safe) * 100) / 100;
|
||||
setLedgerRow(handle, { usd: nextUsd, lux: row.lux, claimedTxids: row.claimedTxids });
|
||||
setUsdStoreCredit(nextUsd);
|
||||
return true;
|
||||
},
|
||||
[handle],
|
||||
);
|
||||
|
||||
const verifyBtcDeposit = async (txid: string) => {
|
||||
const normalized = String(txid || "").trim();
|
||||
if (!/^[a-fA-F0-9]{64}$/.test(normalized)) {
|
||||
return { ok: false, error: "Enter a valid 64-character transaction id" };
|
||||
}
|
||||
const claimed = loadClaimedTxids();
|
||||
if (claimed.includes(normalized)) {
|
||||
return { ok: false, error: "This transaction was already used to add credit" };
|
||||
}
|
||||
try {
|
||||
const res = await fetch("/api/btc/verify", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ txid: normalized }),
|
||||
});
|
||||
const data = (await res.json()) as {
|
||||
ok?: boolean;
|
||||
error?: string;
|
||||
creditedUsd?: number;
|
||||
};
|
||||
if (!data.ok || typeof data.creditedUsd !== "number") {
|
||||
return { ok: false, error: data.error || "Verification failed" };
|
||||
const verifyBtcDeposit = useCallback(
|
||||
async (txid: string) => {
|
||||
if (!handle) {
|
||||
return { ok: false, error: "Sign in so deposits credit your handle’s balance." };
|
||||
}
|
||||
claimed.push(normalized);
|
||||
saveClaimedTxids(claimed);
|
||||
const add = Math.round(data.creditedUsd * 100) / 100;
|
||||
setUsdStoreCredit((u) => Math.round((u + add) * 100) / 100);
|
||||
return { ok: true, creditedUsd: add };
|
||||
} catch {
|
||||
return { ok: false, error: "Network error while verifying" };
|
||||
}
|
||||
};
|
||||
const normalized = String(txid || "").trim();
|
||||
if (!/^[a-fA-F0-9]{64}$/.test(normalized)) {
|
||||
return { ok: false, error: "Enter a valid 64-character transaction id" };
|
||||
}
|
||||
const row = getLedgerRow(handle);
|
||||
if (row.claimedTxids.includes(normalized)) {
|
||||
return { ok: false, error: "This transaction was already used to add credit" };
|
||||
}
|
||||
try {
|
||||
const res = await fetch("/api/btc/verify", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ txid: normalized }),
|
||||
});
|
||||
const data = (await res.json()) as {
|
||||
ok?: boolean;
|
||||
error?: string;
|
||||
creditedUsd?: number;
|
||||
};
|
||||
if (!data.ok || typeof data.creditedUsd !== "number") {
|
||||
return { ok: false, error: data.error || "Verification failed" };
|
||||
}
|
||||
const add = Math.round(data.creditedUsd * 100) / 100;
|
||||
const nextUsd = Math.round((row.usd + add) * 100) / 100;
|
||||
const claimed = [...row.claimedTxids, normalized];
|
||||
setLedgerRow(handle, { usd: nextUsd, lux: row.lux, claimedTxids: claimed });
|
||||
setUsdStoreCredit(nextUsd);
|
||||
return { ok: true, creditedUsd: add };
|
||||
} catch {
|
||||
return { ok: false, error: "Network error while verifying" };
|
||||
}
|
||||
},
|
||||
[handle],
|
||||
);
|
||||
|
||||
const collectKey = (key: string) => {
|
||||
const trimmed = String(key || "").trim();
|
||||
@@ -166,14 +161,8 @@ export const WalletProvider = ({ children }: WalletProviderProps) => {
|
||||
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
isConnected,
|
||||
address,
|
||||
chainId,
|
||||
connect,
|
||||
disconnect,
|
||||
balance,
|
||||
luxCredits,
|
||||
usdStoreCredit,
|
||||
luxCredits,
|
||||
spendLuxCredits,
|
||||
earnLuxCredits,
|
||||
spendUsdStoreCredit,
|
||||
@@ -183,14 +172,16 @@ export const WalletProvider = ({ children }: WalletProviderProps) => {
|
||||
addVaultReceipt,
|
||||
setVaultFlag,
|
||||
}),
|
||||
[isConnected, address, chainId, balance, luxCredits, usdStoreCredit, vault],
|
||||
[
|
||||
usdStoreCredit,
|
||||
luxCredits,
|
||||
spendLuxCredits,
|
||||
earnLuxCredits,
|
||||
spendUsdStoreCredit,
|
||||
verifyBtcDeposit,
|
||||
vault,
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
<WalletContext.Provider
|
||||
value={value}
|
||||
>
|
||||
{children}
|
||||
</WalletContext.Provider>
|
||||
);
|
||||
};
|
||||
return <WalletContext.Provider value={value}>{children}</WalletContext.Provider>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user