Coinviction · P7 reference

Pandora Referral —
every UI state & the binding flow

A faithful reconstruction of Pandora's referral program, reverse-engineered live from the running app and its JS bundle. Every screen, string, and status below is what the real product shows — rebuilt here so each case is visible side by side. Reference for building Coinviction's own P7.

source · thisispandora.ai + index bundle captured · 2026-07-15 contracts · ReferralFactory + ReferralCampaign theme · dark (as shipped)
00

Two roles, one state machine

The confusion to avoid: creating your own code (referrer) and being bound to someone's code (referee) are independent. Different screens, different triggers, different signatures.

Referrer — invites

Generates a code on the /referral page, shares the link, watches stats, claims rewards.

acts on: /referral page · signs to register code · pays gas to claim

Referee — gets invited

Arrives via a ?ref= link, sees a global banner, signs once (gasless) to bind.

acts on: global app-shell banner · one signature · no page to visit
not_foundWallet has no referrer yet. Eligible to be bound.
referee signs · POST /register
pending_referrerReferee signed (backend). Awaiting on-chain lock.
operator / referrer submits on-chain
confirmedregisterReferral() mined. Bound forever.
01

Referee flow — applying a code

There is no “enter a code” field anywhere. A code enters the system only through a share link, and the whole binding is these five moments.

thisispandora.ai/?ref=7N53XEGV → thisispandora.ai/
● PERMISSIONLESS
Open Pandora's Box.
Bet on Anything.
localStorage[pandora_referral_attribution] =
  { "code":"7N53XEGV", "timestamp":1784106929667 }
STEP 01

Capture — silent, pre-connect

Landing on any URL with ?ref=CODE writes the code to localStorage and immediately strips ?ref from the address bar. No wallet, no profile, no prompt.

// on mount
captureFromURL()
history.replaceState() // removes ?ref
The code is now “attributed” to this browser. It waits here until the user connects.
STEP 02

The banner — global, in the app shell

Once the wallet connects, a full-width banner appears under the header on every in-app page — not on /referral, not in a menu. This is the piece that was invisible to you: your wallet never had an attributed code, so it never rendered.

Render gate — all three must hold:
authenticated && attribution.code && !hasReferrer
app · any page · connected
modal · vde “Register Referral”
STEP 03

Confirm modal → the one signature

Sign on the banner opens this modal. Confirm triggers an EIP-712 RegisterReferral(user, referralCodeHash) signature. Gasless — no token approval, no fee.

signTypedData({
  domain:{ name:"ReferralFactory" },
  message:{ user, referralCodeHash }})
→ POST /api/referral/register
Real quirk: the modal body reuses leftover pari-mutuel copy (“You are the Taker…”). A copy-paste bug in Pandora — evidence the feature shipped but is unpolished. Coinviction should write proper copy here.
STEP 04 → 05

Pending, then confirmed

After signing, the backend records status pending_referrer and the banner disappears immediately (it treats pending as “already referred”). Later, the operator or referrer submits the on-chain registerReferral() — status flips to confirmed and the bond is permanent.

GET /register/status →
not_foundpending_referrerconfirmed
status · what the referee sees after signing
pending_referrer Signed · banner dismissed · awaiting on-chain lock
confirmed registerReferral() mined · bound to referrer forever
referrals[referee] = referrer  // immutable, no re-bind
02

Referrer page — /referral

The page the referrer owns. It has two states: before a code exists, and after. This is where “register a referral code” actually happens — a one-time on-chain signature.

STATE ANo code yet — the onboarding card
/referral · no code
Refer friends and earn rewards

Create your referral code and share it. Rewards are defined by the currently active campaign and change as campaigns rotate.

  • Tied to your wallet forever: Your referral signature is bound to your wallet on-chain and can't be lost or transferred.
  • They sign, you approve: When someone uses your link, they sign a message to register as your referral. You then approve them from your dashboard to lock in the attribution.
  • Periodic reward drops: Allocations happen on no fixed schedule. When a drop lands, claim it from your dashboard.
A one-time signature is required to register your code on-chain. No token approvals or fund access involved, just the gas to broadcast the transaction.
Generate Ref Code

Active Campaign

Earn 0.5% on every claim and withdrawal your referrals make. Whenever they cash out winnings or sold positions — your share is allocated automatically.

STATE BCode generated — the live dashboard (empty)
/referral · code = 7N53XEGV
Your Code
7N53XEGV
Share Link
Referral↕ Earned ⓘ↕ Joined ⓘ
No referrals found
You haven't referred any users yet.
Pending Rewards
0
Claim

Active Campaign

Earn 0.5% on every claim and withdrawal your referrals make. Whenever they cash out winnings or sold positions — your share is allocated automatically.

Referrals
0
Earned
$0
STATE CWith referrals & a claimable drop (illustrative)
/referral · active
Referral↕ Earned ⓘ↕ Joined ⓘ
0x4A1c…9F02$182.40Jul 02
0xBE77…13aa$54.11Jul 09
0x9012…7c5e$0.00Jul 14
Pending Rewards
236.51
Claim
Referrals
3
Earned
$236
03

Claim — the referrer takes the reward

The referrer signs nothing. The backend computes the amount and the operator signs the voucher; the referrer just broadcasts it on-chain and pays gas.

Click “Claim”on /referral or the portfolio header
GET /claim-signaturebackend returns { amount, operator-signature }
ReferralCampaign.claim(amount, sig)referrer sends tx · pays gas · USDC arrives