How it works

Three actors, one contract, two secrets. This page walks through the full lifecycle of a campaign and spells out exactly what is visible to whom.

Actors

ActorHoldsVisible on-chain
Creator walletSigns the create / close / rotate transactionsYes — it is the campaign's creator
Claim keyAn off-chain secp256k1 private key held only by the creatorOnly its public address; it never sends a transaction
Donor walletSends BNB to donate()Yes — amount and sender are in the transaction
Collector walletSubmits a claim() carrying a signature from the claim keyYes as a transaction sender, but nothing ties it to the creator

Lifecycle

1. Create

The creator's browser generates a fresh random private key — the claim key. Its address is passed to createCampaign(title, description, goal, claimKey) together with the campaign metadata. The contract stores the campaign, assigns it the next sequential id, and emits CampaignCreated. The private key is encoded into a claim code and shown to the creator exactly once.

2. Donate

Anyone calls donate(campaignId) with BNB attached. The contract increments the campaign's raised and balance and emits Donated(campaignId, amount). The BNB is held by the contract itself; there is no per-campaign vault, so the contract balance is simply the sum of all unclaimed balances.

3. Claim

To collect, the creator opens the claim page from any wallet — ideally a brand-new one. The page reads the campaign's current nonce, builds an EIP-712 message Claim(campaignId, recipient, amount, nonce), signs it locally with the claim key, and the connected wallet submits claim(campaignId, recipient, amount, signature). The contract recovers the signer, checks it equals the stored claim key, bumps the nonce, decrements the balance and transfers the BNB. It emits Claimed(campaignId, amount) — deliberately without the recipient.

4. Manage

The creator wallet can setActive(id, false) to stop accepting donations (and reopen later), and rotateClaimKey(id, newKey) if the code was lost or leaked. Rotation bumps the nonce so signatures from the old key are rejected immediately.

What stays private

  • The recipient of every claim. It appears only as the destination of an internal BNB transfer inside the claim transaction, which is sent by an unrelated wallet.
  • The claim key itself. It signs messages off-chain and is never used as a transaction sender, so it has no on-chain history to analyse.
  • Which campaign funded which withdrawal. All balances are pooled in one treasury; a claim transfers BNB out of the shared pool.

What does not stay private

  • The creator wallet. It is stored in the campaign and visible to anyone. Create campaigns from a wallet you are comfortable associating with the cause.
  • Donations. Amount and sender are ordinary transactions. See donor privacy.
  • Amount correlation. Claimed events include the amount and campaign id. If a campaign holds a unique balance and a claim for exactly that amount lands in a fresh wallet, an observer can guess the link. Claim in partial, round amounts and avoid draining a campaign in one transaction if this matters to you.
  • Gas. The collector wallet needs BNB for gas. If you fund it from the creator wallet you re-create the link you were trying to avoid.