Limits that belong to the program, not the admin.
Bulkhead holds a Solana protocol's vaults. Your own deposit always comes back at once. Everything else leaves at most 2% an hour and 5% a day, even with the admin keys stolen.
Quickstart#
Pick the tier that fits where your program is today. Both run on devnet now.
| Tier | For | What it holds |
|---|---|---|
| Tier 1 · Vault | New launches | The protocol's token accounts. Every payout goes through it. |
| Tier 0 · Floor | Any program | The program's upgrade key. No code changes. |
Check any upgradeable program from the command line:
$ floor check Hrb9…x2Qe loader v3 upgradeable authority Floor PDA delay 72h · vetoable abort binary ready
Rerun every number on the landing page with one command:
$ ./scripts/check.sh 6.9M cases where Rust and Python agree exactly.
Backed and unbacked#
The protocol decides who gets paid. Bulkhead decides how fast. Every payout is sorted into one of two lanes before it leaves the vault.
| Payout | Lane | Speed |
|---|---|---|
| Own deposit back | Backed | Instant, always |
| Borrow against listed collateral | Backed | Instant |
| Repay, then withdraw | Backed | Instant |
| Admin withdrawal | Unbacked | Rate-limited |
| Bonus payout | Unbacked | Rate-limited |
| Borrow against unlisted collateral | Unbacked | Rate-limited |
Normal users never touch the limiter. Only money that isn't provably theirs waits.
Rate limits#
The unbacked lane releases at most 2% of the vault an hour and 5% a day. These limits live in the program, so stealing the admin keys doesn't raise them.
Modelled loss if a guardian freezes the vault after the first unbacked payout:
| Freeze within | Most that can leave |
|---|---|
| 2 minutes | ~2% |
| 1 hour | 4% |
| 24 hours | 10% |
Tightening a limit is instant. Loosening one is a proposal that waits 72 hours and any guardian can veto it.
Tickets and the queue#
When an unbacked payout exceeds what the hour allows, the rest becomes a public ticket. Tickets are paid in order as capacity returns. Anyone can see them, and guardians can cancel them while they wait.
Guardians#
People or bots you choose. They can freeze, cancel, extend, veto and abort.
- They can stop money. They can never move it or choose who receives it.
- A freeze lasts up to 24 hours per call and only delays unbacked payouts.
- Only live guardians count. Unfreezing needs a live quorum.
- No guardian can block anyone's own deposit.
Floor: upgrade delay#
Floor holds the program's upgrade key. Every upgrade waits 72 hours in public and can be vetoed. One guardian can stop the program in one transaction by swapping in an abort binary: every instruction fails and funds stay untouched until quorum restores it.
Propose
The upgrade buffer is frozen and published with its proposal time.
Wait 72 hours
The delay is a constant in the code. Any guardian can veto during the window.
Execute or abort
If no one vetoes, the upgrade lands. In an emergency, one guardian swaps in the abort binary.
Integration#
About 40 lines. Three moves: hand over custody, route every move, seal.
Hand over custody
Move the protocol's token accounts under the Bulkhead vault.
Route every move
Replace direct transfers with a release call. Your program still picks the recipient.
Seal
Hand the upgrade key to Floor so the routing itself can't be removed quietly.
// the protocol picks who; Bulkhead decides how fast bulkhead::cpi::release( CpiContext::new_with_signer( ctx.accounts.bulkhead.to_account_info(), Release { vault, ledger, owner, to, .. }, signer, ), amount, )?; // backed: paid now · unbacked: limited
See the full example in the repository docs.
Constants#
| Name | Value | Meaning |
|---|---|---|
| G1 hourly | 2% | Unbacked outflow per hour |
| G1 daily | 5% | Unbacked outflow per day |
| G4 delay | 72h | Wait before loosening or upgrading |
| Freeze | ≤ 24h | Longest a single guardian freeze lasts |
Security model#
Bulkhead buys time. People still have to use that time.
- It doesn't detect attacks, protect user wallets, protect AMM pools or run an oracle.
- Biggest risk: a bug in Bulkhead itself. Every rule is stated three ways and checked on millions of cases.
- Before mainnet: audits, TVL caps, then burning Bulkhead's own upgrade key.
Not audited yet. Runs on devnet, open source under Apache-2.0. SECURITY.md lists what is unaudited.
FAQ#
Isn't this just a rate limiter?
Drift had a rate limiter; the admin controlled it. Bulkhead's limit sits outside the admin's reach, and it tells your own deposit apart from someone else's money.
Does it slow normal users down?
No. Deposits, withdrawals of your own funds and ordinary borrows never touch the limiter.
What if a guardian is malicious?
It can delay unbacked payouts for up to 24 hours per freeze. It can't move funds, choose a recipient or block anyone's own deposit.