Skip to content

BolaIge/fanX

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FanX — ZK Fan Advertising Protocol

Privacy-first sports fan advertising network, live on Aleo testnet.

A fan can prove they qualify for a sponsor's campaign — without revealing their spending, attendance, or loyalty data — and earn real USDCx. No fan data ever touches the blockchain.


The Problem

Sports clubs know their fans deeply: spend history, attendance, loyalty tier. Sponsors want precision targeting. Today's solution? The club hands their fan database to the sponsor — a GDPR liability and a privacy disaster.

FanX eliminates that entirely using ZK proofs.


How It Works

Club publishes Merkle root  →  1 tx per season. Nothing else on-chain.
                                       ↓
Sponsor locks USDCx budget  →  sets targeting thresholds (spend / attendance / loyalty)
                                       ↓
Fan generates ZK proof       →  "I qualify. I won't tell you why."
                                       ↓
Contract verifies             →  Merkle membership ✅  Thresholds met ✅  No double-claim ✅
                                       ↓
Fan receives RewardTicket    →  private record → redeemable for USDCx
Sponsor sees                 →  matched_count += 1  (nothing else)

The fan's spend, attendance, loyalty, and tier are private Leo inputs. The Aleo VM never exposes them — not in calldata, not in finalize, not anywhere.


Architecture

┌──────────────┐     ┌─────────────────────────┐     ┌──────────────┐
│    Club      │────▶│  fanx_contract_v3.aleo  │◀────│   Sponsor    │
│              │     │                         │     │              │
│  Merkle tree │     │  update_season_root()   │     │  create_     │
│  (off-chain) │     │  claim_reward()    [ZK] │     │  campaign()  │
│  Serves fan  │     │  redeem_ticket()        │────▶│  sees only:  │
│  paths (API) │     │                         │     │  count++     │
└──────────────┘     └─────────────────────────┘     └──────────────┘

Contract Functions

# Function Actor Description
1 update_season_root Club Publish BHP256 Merkle root — 1 tx/season per 1M fans
2 create_campaign Sponsor Lock USDCx + set targeting thresholds
3 claim_reward Fan ZK Merkle proof + threshold check → private RewardTicket
4 redeem_ticket Fan Convert RewardTicket to public USDCx balance
5 deactivate_campaign Sponsor Pause a campaign
6 sponsor_withdraw Sponsor Reclaim unspent budget
7 register_club Admin Authorize a sports club

Scalability

  • 1 club tx per season — not 1 per fan
  • Depth-20 Merkle tree → 1,048,576 fans per club per season
  • Fan gas cost ~0.007 credits per claim

Live On-Chain State ✅

Verified April 12, 2026 — all mappings queryable via Aleo Explorer

Contract Network Status
fanx_contract_v3.aleo Aleo testnet LIVE
test_usdcx_stablecoin.aleo Aleo testnet ✅ Dependency (pre-deployed)

Key addresses:

  • Admin: aleo1s3qmy92sh6q7hgwdeqnzslycag0tfzdgzwqyh7pejkv23daqgq9qns8n7h
  • Program (for USDCx escrow): aleo1z46smphzpz0tcw8vmu9ea8hq304a43tpm0lxc4drr4fy2uq8yyzs5ah24n

Live Campaign

Field Value
Campaign ID 2677790036399590415212541804383891666584254468809915654462441701520987625138field
Sport ⚽ Soccer (All Sports / ID 0)
Min spend score 8,000 / 10,000
Min attendance 8,000 / 10,000
Min loyalty 9,000 / 10,000
Min tier Gold (2)
Reward per claim 1,000,000 µUSDCx = 1 USDCx
Total budget 10,000,000 µUSDCx = 10 USDCx
Max claims 10 fans

Current Chain State (live)

# Verify yourself:
curl "https://api.explorer.provable.com/v1/testnet/program/fanx_contract_v3.aleo/mapping/c_budget/2677790036399590415212541804383891666584254468809915654462441701520987625138field"
# → "8000000u128"   (8 USDCx remaining after 2 claims)

curl "https://api.explorer.provable.com/v1/testnet/program/fanx_contract_v3.aleo/mapping/matched_count/2677790036399590415212541804383891666584254468809915654462441701520987625138field"
# → "2u64"          (2 fans have claimed so far)

curl "https://api.explorer.provable.com/v1/testnet/program/test_usdcx_stablecoin.aleo/mapping/balances/aleo17ha5h9c87d0lupnfg9yv3r2gwsjgzhrtne67thys96l9v26zgurslmj6x0"
# → "1000000u128"   (Judge 1 already redeemed — 1 USDCx in wallet)

Key Transaction IDs

Event TX ID
v3 Deploy at13zzduc3tmyvsz5g4ze64ehmqv82wp9rf52sucvkk3cvwtv2spcgqkmtrzt
update_season_root at1xl5zuh7r6ejwrqw9mnhjgk38f3cgd0f75ehxddwepgqfk7zsdqxs9lv8hu
create_campaign at13cl7gvulea92d20wq46nzlad5exufakue5lwwzxl45xgpvy57spshj5n9k
Judge 1 claim_reward ✅ at1e69mwhs06ld3uray6ly2tsr4lq75e2p794jzwsvnrw2jeny57grqsqyj2x
Judge 1 redeem_ticket ✅ at1mj4y9wjplnpcp6w3w2audlj367vqfu07f2rv99jr6he5wh9pwgzqfe38p0

Judge Demo — Try It Yourself

Each judge has a pre-registered fan wallet in their own private Merkle tree. All 3 can claim simultaneously — the fan_claimed key is unique per address, preventing any collision.

Your Wallets

🎫 Judge 1 — aleo17ha5h... (already claimed + redeemed as proof-of-concept)

Address aleo17ha5h9c87d0lupnfg9yv3r2gwsjgzhrtne67thys96l9v26zgurslmj6x0
Private Key APrivateKey1zkp7Wt7BU1qVgApXKaNG3sWrSgeZqSVfokVekeGoZaXnHQF
Club ID 10000field
USDCx balance 1,000,000 µUSDCx (already redeemed ✅)

🎫 Judge 2 — aleo15w2ml...

Address aleo15w2ml049524ly7pss9rlzpu8g6mufqwvt4yhce8xrvzs8dpazspshxeh8d
Private Key APrivateKey1zkpDKjwNJtQwjedTXPezSty36S2nXdYLyLSkTgKkjWCz1i9
Club ID 20000field
USDCx balance 0 — claim yours!

🎫 Judge 3 — aleo1qtt9n...

Address aleo1qtt9na7t2g6vgrlxj7sxmw9szrhsva2yqc8e62r5dme60pyqjcgqnct5f5
Private Key APrivateKey1zkp6zaFFYV4m8Zoegee2oaJwgdoci2nb8X81NkGrXoTB8Tq
Club ID 30000field
USDCx balance 0 — claim yours!

Fan profile (same for all): Platinum Tier · Spend 9,500 · Attendance 9,500 · Loyalty 9,500 ✅


Step-by-Step Demo

Step 1 — Set Up Shield Wallet

  1. Install Shield Wallet (Chrome extension)
  2. Click Import Wallet → paste your Private Key from above
  3. Set any password

Step 2 — Open FanX

  1. Open the FanX frontend (running locally or deployed URL)
  2. Click Connect Wallet → select Shield
  3. Your address appears top-right

Step 3 — Claim Your ZK Reward

  1. Go to Campaigns tab
  2. Click "⚡ Live: Premier Soccer Fan Rewards" (the active campaign)
  3. Click "Claim with ZK Proof"
  4. The modal loads your fan profile automatically from fanx_proof.json
  5. Approve in Shield Wallet → wait ~10s

What just happened:

  • Your spend/attendance/loyalty/tier stayed private in your browser
  • A BHP256 Merkle proof ran in the ZK circuit
  • The contract verified you're a registered fan AND meet the thresholds
  • c_budget dropped by 1 USDCx on-chain
  • matched_count incremented

Step 4 — Redeem Your Ticket

  1. Go to My Rewards tab
  2. Click "Redeem → USDCx" on your RewardTicket
  3. Approve in Shield Wallet → ~10s
  4. Your USDCx balance → 1.000000 USDCx

Step 5 — Verify on Explorer

Open the claim TX in Aleo Explorer. Notice:

  • Inputs #1–7: all encrypted — spend, attendance, loyalty, tier, Merkle path are private
  • Inputs #8–16: public campaign parameters (campaign ID, thresholds, season)
  • The fan's actual metrics appear nowhere on-chain

Why This Is Real ZK (Not a Mock)

Claim Proof
Fan data never on-chain spend, attend, loyalty, tier are private in Leo — the Aleo VM physically prevents them appearing in finalize arguments
Merkle membership is cryptographic Leaf + 20-level BHP256 path runs inside the ZK circuit — one wrong byte fails the proof at the network level
Budget is real USDCx c_budget decrements on-chain with every valid claim — verify live
No double-claiming fan_claimed[BHP256(signer + campaign_id)] set permanently on-chain — replay is cryptographically impossible
Stablecoin payout is real redeem_ticket calls test_usdcx_stablecoin.aleo/transfer_public — Judge 1's 1 USDCx balance verifiable on-chain

Comparison

Feature Traditional Ad Tech FanX ZK
Fan data shared ✅ Full profiles to sponsor ❌ Zero — never leaves device
Sponsor sees Name, email, spend history Only matched_count
Eligibility check Off-chain (trust required) On-chain ZK (trustless)
Fake claim prevention Platform-enforced (centralised) Cryptographically impossible
GDPR compliance Requires data agreements Inherent — no data collected

Fan Metrics

Metric Scale Description
spend_score 0–10,000 Lifetime fan spend (10,000 = top spender)
attendance 0–10,000 Events attended this season
loyalty_score 0–10,000 Platform tenure + engagement
tier 0–3 0=Bronze · 1=Silver · 2=Gold · 3=Platinum

Supported Sports

ID Sport ID Sport
0 ⚽ Soccer 9 🥊 MMA / UFC
1 🏀 Basketball 10 🏎 Formula 1
2 🏈 American Football 11 🚴 Cycling
3 ⚾ Baseball 12 🏃 Athletics
4 🏏 Cricket 13 🥊 Boxing
5 🏉 Rugby 14 🏐 Volleyball
6 🎾 Tennis 15 🎮 Esports
7 ⛳ Golf 255 🏆 All Sports
8 🏒 Ice Hockey

Project Structure

fanx/
  contract/
    program.json            fanx_contract_v3.aleo manifest
    src/main.leo            Leo smart contract (ZK circuit)
  tests/
    helpers.mjs             BHP256 Merkle tree + test utilities
    0_setup.mjs             Environment check
    1_register_club.mjs     Register virtual clubs
    2_publish_root.mjs      Build Merkle tree + publish on-chain root
    3_create_campaign.mjs   Create sponsor campaigns
    4_claim_reward.mjs      Fan claim with ZK proof
    5_redeem_ticket.mjs     Redeem RewardTicket for USDCx
    6_sponsor_withdraw.mjs  Reclaim budget
    7_lifecycle.mjs         End-to-end validation
  frontend/
    public/fanx_proof.json  Pre-registered fan Merkle proofs (4 wallets)
    src/
      lib/
        constants.ts        Sports registry, tier definitions, config
        merkle.ts           Browser-side BHP256 Merkle tree
        fanx-client.ts      On-chain mapping fetchers + input builders
        store.ts            Zustand global state
      pages/
        Dashboard.tsx       Campaign browser (fetches live chain data)
        CampaignDetail.tsx  Campaign detail + ZK claim flow
        MyRewards.tsx       Fan's pending RewardTickets + redeem
        SponsorDashboard.tsx Create/manage campaigns

Local Development

# Frontend
cd fanx/frontend
npm install
npm run dev
# → http://localhost:3000

# Tests (requires .env with PRIVATE_KEY)
cd fanx/tests
cp .env.example .env
npm install
node 7_lifecycle.mjs   # full end-to-end validation

Tech Stack

  • ZK Proofs: Aleo / Leo (Marlin zk-SNARK, AleoBFT consensus)
  • Hash Function: BHP256 (collision-resistant, native in Leo circuit)
  • Stablecoin: test_usdcx_stablecoin.aleo (pre-deployed on testnet)
  • Frontend: React 18, TypeScript, Vite, Framer Motion
  • State: Zustand (localStorage-persisted tickets)
  • Wallet: Shield Wallet via @provablehq/aleo-wallet-adaptor-react

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors