How it works

A campaign moves through four steps: open, pledge, settle, claim. Every step is an instruction of the program and every money movement is between the campaign's own vault and a participant's own token account.

sequenceDiagram
  participant C as Creator
  participant V as Campaign vault
  participant B as Backer
  participant A as Anyone
  C->>V: create_campaign (bonus deposit moves in)
  B->>V: pledge (escrowed until the deadline)
  A->>V: settle (after the deadline)
  A->>B: claim_backer (failure: refund + bonus)
  A->>C: claim_creator (success: raised - fee + deposit)

1. Open

The creator calls create_campaign(id, goal, deadline, bonus_bps, bonus_deposit, uri). In the same transaction the whole bonus_deposit moves from the creator's token account into the campaign vault. No deposit, no campaign.

The program then fixes three numbers that nobody can change later:

Example: a 1,000 USDC deposit at 20% gives an early cap of 5,000 USDC.

2. Pledge

A backer calls pledge(amount, min_eligible). The amount moves into the vault and stays there until the deadline. There is no withdraw instruction.

The part of the pledge that earns the bonus is:

pub fn eligible_part(now: i64, early_end: i64, amount: u64, early_cap: u64, early_pledged: u64) -> u64 {
    if now >= early_end {
        return 0;
    }
    amount.min(early_cap.saturating_sub(early_pledged))
}

So a pledge made at or after the halfway point earns nothing extra, and a pledge made early earns the bonus on whatever room is left under the cap. min_eligible lets the backer refuse to pledge if less than that would still earn the bonus when the transaction lands.

The backer's bonus is fixed at that moment: floor(eligible x bonus_bps / 10,000). Repeat pledges add to the same record.

3. Settle

Once now >= deadline, anyone may call settle. If total_pledged >= goal the campaign succeeded, otherwise it failed. On success the 2% fee moves to the fee vault for that mint, unless the creator locked the fee waiver.

4. Claim

Anyone may run the claims; the money only ever goes to the owner's own token account.

Outcomeclaim_backer pays the backerclaim_creator pays the creator
Successnothing (the record closes, rent back to the backer)everything raised, minus the fee, plus the whole bonus deposit
Failurethe full pledge plus the bonus earnedthe deposit minus every bonus earned

When every backer, the creator and any waiver are paid, close_campaign closes the vault and the campaign and returns the rent to the creator.

Worked example

Goal 10,000 USDC, 30 days, 20% bonus, 1,000 USDC deposit. You pledge 100 USDC on day 3.