PolHunter v0.2: the hunt engine
Hand-off sign-in from InstantAdPay (lib/sso.js: HMAC token, five minutes, single use; no sign-up, no mailer), missions with per-member per-visit proof codes (lib/missions.js: the embed is answered only from the mission's own origin, only after the dwell; hiding place rotates by day and member), weighted-low rewards with a daily cap that queues rather than refuses (lib/rewards.js), the faucet sender on ethers with a low-balance alert (lib/faucet.js), the one-line embed for the sites (public/embed.js), the hunter board, the public ledger, an admin page, and the site's own look. Telegram is behind the OUTBOUND gate like everything else. 13-check end-to-end test in test/run.js. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+60
-18
@@ -4,27 +4,69 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>PolHunter</title>
|
||||
<style>
|
||||
:root{--bg:#0b0a14;--ink:#f1eefb;--muted:#a79fc4;--pol:#8247e5;--pol-hi:#a97cf5;--gold:#f3be43}
|
||||
*{margin:0;padding:0;box-sizing:border-box}
|
||||
body{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:32px 20px;background:radial-gradient(circle at 20% 10%,rgba(130,71,229,.28),transparent 45%),radial-gradient(circle at 85% 90%,rgba(243,190,67,.16),transparent 40%),var(--bg);color:var(--ink);font:16px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif}
|
||||
.wrap{max-width:640px;text-align:center}
|
||||
.mark{display:inline-flex;align-items:center;gap:12px;font-weight:800;font-size:22px;letter-spacing:-.3px;margin-bottom:28px}
|
||||
.mark i{width:34px;height:34px;border-radius:50%;background:var(--pol);box-shadow:0 0 34px rgba(130,71,229,.7)}
|
||||
h1{font-size:clamp(32px,7vw,54px);line-height:1.05;font-weight:800;letter-spacing:-1px;margin-bottom:16px}
|
||||
h1 b{color:var(--gold)}
|
||||
p{color:var(--muted);font-size:18px;max-width:520px;margin:0 auto 22px}
|
||||
.pill{display:inline-block;padding:8px 16px;border:1px solid rgba(167,159,196,.35);border-radius:999px;color:var(--muted);font-size:13px;letter-spacing:.08em;text-transform:uppercase}
|
||||
.fine{margin-top:40px;font-size:12px;color:#6e678a}
|
||||
</style>
|
||||
<meta name="description" content="Missions across the network. Visit a site, find the thing, get a drip of POL to your wallet.">
|
||||
<link rel="stylesheet" href="/style.css?v=1">
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<div class="mark"><i></i>PolHunter</div>
|
||||
<h1>Visit. Find it. <b>Get paid in POL.</b></h1>
|
||||
<p>Missions across the network. Each one takes a few minutes on a site, a thing to find, and a drip of POL to your wallet when you find it.</p>
|
||||
<span class="pill">Building — opens soon</span>
|
||||
<div class="fine">Rewards are for completed missions, not income. Cryptocurrency involves risk of loss.</div>
|
||||
<header class="top">
|
||||
<a class="mark" href="/"><span class="coin"></span>PolHunter</a>
|
||||
<nav class="nav">
|
||||
<a class="btn ghost sm" href="#how">How it works</a>
|
||||
<a class="btn ghost sm" href="#ledger">Paid so far</a>
|
||||
<a class="btn sm" id="signin" href="https://instantadpay.com/my#polhunter">Open my board</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section class="hero">
|
||||
<div>
|
||||
<span class="pill"><i></i> Paying in POL on Polygon</span>
|
||||
<h1>Visit. Find it.<br><b>Get paid in POL.</b></h1>
|
||||
<p>Every mission is a few minutes on one of our sites, one thing to find, and a drip of POL straight to your wallet when you find it. Your code is yours alone, and the hiding place moves.</p>
|
||||
<a class="btn" href="https://instantadpay.com/my#polhunter">Start hunting</a>
|
||||
<a class="btn ghost" href="#how" style="margin-left:8px">See how</a>
|
||||
<p id="signinNote" style="font-size:13px;color:var(--dim);margin-top:14px;display:none">Open PolHunter from your InstantAdPay dashboard to sign in. No password, no new account.</p>
|
||||
</div>
|
||||
<div class="stack" aria-hidden="true"><div class="c c1"></div><div class="c c2"></div><div class="c c3"></div><div class="g"></div></div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="how">
|
||||
<h2>How a hunt works</h2>
|
||||
<div class="sub">Three steps, one code, real POL.</div>
|
||||
<div class="steps">
|
||||
<div class="step"><b>Pick a mission</b> on your board. Each one names a site and what to find there.</div>
|
||||
<div class="step"><b>Go find it.</b> Spend the time on the site. Your personal code appears when you have, somewhere on the page.</div>
|
||||
<div class="step"><b>Type the code.</b> If it is yours, a random drip between the day's range lands in your wallet, on-chain, with a link to prove it.</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="ledger">
|
||||
<h2>Paid so far</h2>
|
||||
<div class="sub">Every drip is a Polygon transaction you can open.</div>
|
||||
<div class="stats" id="stats"></div>
|
||||
<div class="ledger" id="recent"><div class="row"><span class="site">Loading…</span></div></div>
|
||||
</section>
|
||||
|
||||
<div class="adslot" data-ad="home-footer"></div>
|
||||
|
||||
<footer class="foot">
|
||||
PolHunter rewards completed missions. Rewards are not income and are not guaranteed; the daily pool is limited and drips are random within the posted range. Cryptocurrency involves risk of loss. Hunters sign in with an InstantAdPay account; no account is created here.
|
||||
<br><a href="https://instantadpay.com">InstantAdPay</a> · <a href="/admin" rel="nofollow" style="color:var(--dim)">·</a>
|
||||
</footer>
|
||||
</div>
|
||||
<script>
|
||||
(async () => {
|
||||
if (new URLSearchParams(location.search).get('signin')) document.getElementById('signinNote').style.display = 'block';
|
||||
try {
|
||||
const r = await (await fetch('/api/ledger')).json();
|
||||
const t = r.totals || {};
|
||||
document.getElementById('stats').innerHTML = [['POL paid', (t.pol || 0).toLocaleString('en-US', { maximumFractionDigits: 2 })], ['drips', t.paid || 0], ['hunters', t.hunters || 0], ['today', (t.today || 0).toLocaleString('en-US', { maximumFractionDigits: 2 }) + ' POL']]
|
||||
.map(([l, v]) => '<div class="stat"><div class="v num">' + v + '</div><div class="l">' + l + '</div></div>').join('');
|
||||
const cfg = await (await fetch('/api/config')).json();
|
||||
document.getElementById('recent').innerHTML = (r.recent || []).length ? r.recent.map(x => '<div class="row"><span>' + x.who + '</span><span class="site">' + x.site + '</span><span class="pol">+' + x.pol + ' POL</span><a class="when" href="' + cfg.explorer + '/tx/' + x.tx + '" target="_blank" rel="noopener">verify ↗</a></div>').join('')
|
||||
: '<div class="row"><span class="site">No drips yet. The first hunter gets the first line.</span></div>';
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user