CAsoon

Launches

Holder rewards

A share of each trade, paid to holders in SOL, claimable any time. The kit does it with the 64 bytes and one number per token.

The accounting#

The launch pool’s hook pays the holder fee, in bridged SOL, into the reward vault. KitConfig keeps acc_per_share, the lamports earned so far per eligible base unit (scaled by 1012); each holder’s 64 bytes keep a snapshot of it and what it is owed. Every callback syncs first, then settles each holder it touches at its balance before the operation.

rust
pub fn sync(&mut self, vault_amount: u64, now: i64) -> Result<()> {
    let released = self.release(now)?;          // the share stream; paused while nobody is eligible
    let total = vault_amount + self.total_claimed;
    let fresh = total - self.seen + released;    // what arrived since the last sync
    self.seen = total;
    if self.divides() {                         // eligible > 0 and eligible >= min_eligible
        let pot = fresh + self.held;
        self.held = 0;
        if pot > 0 {
            let scaled = u128::from(pot) * SCALE + self.rem;     // SCALE = 10^12
            let inc = scaled / u128::from(self.eligible);
            self.rem = scaled - inc * u128::from(self.eligible);  // the exact remainder, kept
            self.acc_per_share += inc;
            self.total_distributed += pot;
        }
    } else {
        self.held += fresh;                     // waits until holders hold enough
    }
    Ok(())
}
programs/kit/src/math.rs · checked arithmetic abridged

Below min_eligible (a thousandth of the supply held) nothing is divided: what arrives waits in held, and the pool hook takes no holder fee. The division keeps its remainder, so nothing is paid twice and nothing is lost.

Claims#

claim syncs, settles the holder and pays min(owed, reward vault) to its bridged-SOL holding. It writes bytes 0 to 23 through write_hook_data and keeps 24 to 63 as read, so a claim never unlocks an early buyer. A wallet that sold everything keeps what it earned until it claims. The site claims up to about four tokens in one transaction and unwraps the SOL.

Share with holders#

share(amount) lets anyone send bridged SOL to every holder, pro rata. It streams over 3,600 seconds, so buying just before a share and selling after it gains nothing. While nobody is eligible the stream pauses, and resumes with the same time left.

Why the vault always covers it#

After every instruction the reward vault holds at least what every holder could claim, plus what is held, plus what is still streaming, because:

  1. eligible is the sum of the balances that will be settled: every balance change passes through a kit callback, minting is impossible, and excluded owners never claim;
  2. every balance change of a holder is settled first, at the balance before it;
  3. every rounding favours the vault: the division, owed and stream releases all floor;
  4. shared lamports count as seen when they arrive and reach holders only as they are released.

The off-chain mirror#

What the site shows as claimable is a pure function of three accounts (KitConfig, the reward vault, the holding), read in one call:

layoutdocs/hooks-v2.md §4.13 · what a holder can claim now
released  = what the stream releases by now        // 0 while nobody is eligible
pending   = vault.amount + total_claimed - seen + released
acc       = acc_per_share
if eligible > 0 and eligible >= min_eligible and pending + held > 0:
    acc   = acc_per_share + ((pending + held) * SCALE + rem) / eligible
claimable = 0 for the pool and the launch,
            else owed + balance * (acc - snapshot) / SCALE          // floors
a claim pays min(claimable, vault.amount)