KAGURA 神楽

KAGURA is a continuous-time DeFi primitive on Solana. Two on-chain Anchor programs: a tick-attestation registry, and a USDC funding vault that compounds yield every block instead of every hour.

contact: hello@kagura.network
神楽KAGURA/ docs
v0.1.0 · pre-deployment← back to sitegithub →
security·threat model

threat model

explicit catalog of what kagura defends against, what it doesn't, and what residual risks operators must accept.

defended against

T1: share inflation

Integer math rounds toward zero on both deposit and withdraw. A depositor cannot mint “extra” shares by structuring deposits; the rounding always favors existing shareholders.

T2: clock regression

kagura-core rejects ticks where now < last_tick_unix_ms. If solana's clock somehow goes backward, the tick errors with ClockRegression rather than producing a negative dt.

T3: tick-frequency manipulation

Per-tick accrual is a function of wall-clock dt, not of tick count. Callingrecord_tick twice quickly produces two ticks with very small elapsed_ms each, summing to the same accrual as one tick with the larger dt. Attackers cannot inflate yield by ticking more.

T4: arithmetic overflow

All multiplications use checked_mul in u128. Final results are checked against u64::MAX before truncation. Overflow returns MathOverflow rather than wrapping.

T5: wrong mint

Deposit/withdraw constraints check user_token_account.mint == vault.usdc_mint and user_share_account.mint == vault.share_mint. A malicious user cannot deposit a different spl token and receive shares.

not defended against

R1: authority key compromise

Vault.authority can change funding rate, pause, set new policy. If that key is stolen, the attacker can:

  • set rate to 0 (halts yield)
  • set rate to 30000 bps (drains treasury fast)
  • pause the vault (halts deposits/withdraws/ticks)

The authority cannot drain principal. User funds are held by the principal pda whose token authority is [b"principal-auth", vault.key()]— controllable only by kagura-vault's own withdraw instruction, which requires the user to burn their shares.

R2: treasury exhaustion

If the treasury runs dry, ticks succeed but accrue zero. The advertised apr becomes false. This is an operational risk, not a smart-contract bug.

R3: rpc censorship

Ticker bot depends on rpc. A faulty/censored rpc that drops tick_funding transactions stops accrual. Solana validators cannot censor by program id under normal conditions; rpc providers in principle could. Mitigation: run multiple rpcs, tip via jito, fall back to direct submit.

R4: clock resolution on solana

Solana's Clock sysvar has 1-second resolution. Multiple sub-second ticks within the same second produce elapsed_ms = 0 and accrue zero. This is by design — the math is correct over wall-clock time regardless of tick frequency, and 1-second granularity is still 3,600× finer than the 1-hour cron used by legacy defi.

invariants checked at all times

  • shares × vault_balance / total_shares is the exact redemption price; rounding is always toward the vault.
  • treasury + principal never exceeds the total usdc that has ever been transferred in.
  • vault.last_tick_unix_ms is monotonic.
  • token accounts are owned by the program-derived authority pdas, not by the vault authority key.