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:
early_end = start + (deadline - start) / 2: the bonus window is the first half.early_cap = bonus_deposit x 10,000 / bonus_bps, rounded down: the most early pledging the deposit can pay the bonus rate on.early_cap <= goal, or the call fails withBonusAboveGoal. A failed campaign raised less than its goal, so bonus capacity above the goal could never be earned.
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.
| Outcome | claim_backer pays the backer | claim_creator pays the creator |
|---|---|---|
| Success | nothing (the record closes, rent back to the backer) | everything raised, minus the fee, plus the whole bonus deposit |
| Failure | the full pledge plus the bonus earned | the 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.
- Goal met at 10,000 USDC: the creator receives 9,800 USDC plus the 1,000 USDC deposit back; 200 USDC of fee goes to the burn. You receive nothing back: your 100 USDC paid for the work.
- Goal missed: you receive 120 USDC (100 refund + 20 bonus).
- Had you pledged on day 16 instead, a miss would return exactly 100 USDC.