- 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
198 lines
8.1 KiB
TypeScript
198 lines
8.1 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { useMemo, useState } from "react";
|
|
import ThemedLayout from "@/components/layouts/ThemedLayout";
|
|
import { useAccount } from "@/contexts/AccountContext";
|
|
import { useWallet } from "@/contexts/WalletContext";
|
|
|
|
type MixLog = { id: string; text: string };
|
|
|
|
function rid() {
|
|
return Math.random().toString(16).slice(2, 10).toUpperCase();
|
|
}
|
|
|
|
export default function MixerPage() {
|
|
const { user, hydrated } = useAccount();
|
|
const { luxCredits, spendLuxCredits, setVaultFlag, addVaultReceipt } = useWallet();
|
|
const [amount, setAmount] = useState(500);
|
|
const [hops, setHops] = useState(3);
|
|
const [noise, setNoise] = useState(65);
|
|
const [log, setLog] = useState<MixLog[]>([]);
|
|
|
|
const relayReady = Boolean(hydrated && user);
|
|
|
|
const fee = useMemo(() => {
|
|
const base = Math.floor(amount * 0.04);
|
|
const hopFee = hops * 25;
|
|
const noiseFee = Math.floor(noise * 2);
|
|
return base + hopFee + noiseFee;
|
|
}, [amount, hops, noise]);
|
|
|
|
const total = amount + fee;
|
|
|
|
const push = (text: string) => setLog((l) => [{ id: rid(), text }, ...l].slice(0, 10));
|
|
|
|
return (
|
|
<ThemedLayout theme="terminal" siteTitle="COIN BLENDER" siteSubtitle="Onion-routed blend pipeline">
|
|
<section className="container mx-auto max-w-6xl px-4 py-12">
|
|
<div className="text-center">
|
|
<h1 className="text-4xl font-bold md:text-5xl">
|
|
COIN <span className="theme-accent">BLENDER</span>
|
|
</h1>
|
|
<p className="mx-auto mt-6 max-w-3xl text-xl opacity-90">
|
|
Terminal theatre: dramatic hops, noise, and logs — while LUX debits for real on your handle.
|
|
</p>
|
|
<p className="mx-auto mt-3 max-w-3xl text-sm opacity-70">
|
|
No outbound chain traffic from this page. Spending Bitcoin-backed USD happens at{" "}
|
|
<Link href="/account/add-funds" className="theme-accent underline">
|
|
Add funds
|
|
</Link>{" "}
|
|
and{" "}
|
|
<Link href="/checkout" className="theme-accent underline">
|
|
Checkout
|
|
</Link>
|
|
.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="mt-12 grid grid-cols-1 gap-8 lg:grid-cols-3">
|
|
<div className="theme-card rounded-3xl border border-white/10 p-8 lg:col-span-2">
|
|
<div className="mb-6 flex items-end justify-between gap-4">
|
|
<div>
|
|
<div className="text-xs text-foreground/40">available</div>
|
|
<div className="font-orbitron text-4xl font-bold text-neon-green">
|
|
{luxCredits.toLocaleString()} LUX
|
|
</div>
|
|
</div>
|
|
<div className="text-right text-sm text-foreground/60">
|
|
{relayReady ? (
|
|
<span className="text-neon-green">Relay: @{user!.username}</span>
|
|
) : (
|
|
<span>
|
|
<Link href="/sign-in" className="theme-accent underline">
|
|
Sign in
|
|
</Link>{" "}
|
|
to burn LUX
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
<div className="theme-card rounded-2xl border border-white/10 p-6">
|
|
<div className="mb-2 font-bold">Amount (LUX)</div>
|
|
<input
|
|
type="range"
|
|
min={50}
|
|
max={2500}
|
|
value={amount}
|
|
onChange={(e) => setAmount(parseInt(e.target.value, 10))}
|
|
className="w-full"
|
|
disabled={!relayReady}
|
|
/>
|
|
<div className="mt-2 text-foreground/70">{amount.toLocaleString()} LUX</div>
|
|
|
|
<div className="mt-6 mb-2 font-bold">Route hops</div>
|
|
<div className="grid grid-cols-5 gap-2">
|
|
{[1, 2, 3, 4, 5].map((n) => (
|
|
<button
|
|
key={n}
|
|
type="button"
|
|
disabled={!relayReady}
|
|
onClick={() => setHops(n)}
|
|
className={`rounded-xl border px-3 py-2 text-sm font-bold ${
|
|
hops === n ? "border-neon-cyan bg-neon-cyan/10" : "border-white/10 bg-white/5"
|
|
}`}
|
|
>
|
|
{n}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<div className="mt-6 mb-2 font-bold">Plausible deniability noise</div>
|
|
<input
|
|
type="range"
|
|
min={0}
|
|
max={100}
|
|
value={noise}
|
|
onChange={(e) => setNoise(parseInt(e.target.value, 10))}
|
|
className="w-full"
|
|
disabled={!relayReady}
|
|
/>
|
|
<div className="mt-2 text-foreground/70">{noise}% nonsense</div>
|
|
</div>
|
|
|
|
<div className="theme-card rounded-2xl border border-white/10 p-6">
|
|
<div className="mb-4 font-orbitron text-2xl font-bold">Receipt</div>
|
|
<div className="space-y-3 text-sm text-foreground/70">
|
|
<div className="flex justify-between">
|
|
<span>Blend amount</span>
|
|
<span className="font-bold">{amount.toLocaleString()} LUX</span>
|
|
</div>
|
|
<div className="flex justify-between">
|
|
<span>Obfuscation fee</span>
|
|
<span className="font-bold text-neon-pink">{fee.toLocaleString()} LUX</span>
|
|
</div>
|
|
<div className="flex justify-between border-t border-white/10 pt-3">
|
|
<span>Total burn</span>
|
|
<span className="font-orbitron font-bold text-neon-pink">{total.toLocaleString()} LUX</span>
|
|
</div>
|
|
<div className="mt-4 rounded-xl bg-white/5 p-4 text-xs text-foreground/60">
|
|
LUX is loyalty currency tied to your account (earn some on completed checkouts). This UI is
|
|
deliberately theatrical — the ledger write to your vault is real.
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
disabled={!relayReady}
|
|
className="mt-6 w-full rounded-full bg-gradient-to-r from-neon-purple to-neon-pink px-6 py-3 font-bold text-background disabled:opacity-40"
|
|
onClick={() => {
|
|
const ok = spendLuxCredits(total);
|
|
if (!ok) {
|
|
push("Blend failed: insufficient LUX.");
|
|
return;
|
|
}
|
|
setVaultFlag("blendedOnce", true);
|
|
addVaultReceipt({
|
|
id: `MX-${rid()}`,
|
|
title: "Blender session",
|
|
desc: `${amount.toLocaleString()} LUX fee burn (${hops} hops, ${noise}% noise).`,
|
|
date: new Date().toISOString().slice(0, 10),
|
|
severity: "normal",
|
|
});
|
|
push(`Session ${rid()}: accepted. Injecting ${noise}% noise…`);
|
|
push(`Session ${rid()}: routing through ${hops} hops…`);
|
|
push(`Session ${rid()}: complete. LUX debited; vault receipt stored.`);
|
|
}}
|
|
>
|
|
BLEND NOW 🌀
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="theme-card rounded-3xl border border-white/10 p-8">
|
|
<div className="font-orbitron text-2xl font-bold">Console</div>
|
|
<div className="mt-6 space-y-3">
|
|
{log.length === 0 ? (
|
|
<div className="text-foreground/60">No sessions yet.</div>
|
|
) : (
|
|
log.map((e) => (
|
|
<div
|
|
key={e.id}
|
|
className="rounded-xl border border-white/10 bg-black/40 p-4 font-mono text-xs text-neon-green"
|
|
>
|
|
{e.text}
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</ThemedLayout>
|
|
);
|
|
}
|