Steak Proposal: The First Working Custom Staker Built on Solana’s New Commission Collector Proposals
Steak is a custom staker we deployed on Solana mainnet that routes validator revenue through an on-chain distribution contract instead of a validator identity hot wallet. It is built directly on top of the new vote-account and commission-collector proposals — SIMD-0185 (Vote Account v4), SIMD-0123 (Block Revenue Distribution), and SIMD-0232 (Custom Commission Collector Account) — and, to our knowledge, is the first working end-to-end implementation of that stack on mainnet.
Our on-chain distribution program is live at:
https://solscan.io/account/aZPKJ99yjfE6MjZ5isXNjm3ndanBdx5gX35nwmLBANK
At time of writing, the program holds active state across thousands of on-chain accounts and receives SOL inflows from users and from the validator revenue pipeline it is wired into. We built the contract, deployed it, configured our vote account to point block revenue and inflation commission at it, and wrote the distribution logic that turns protocol-level validator income into holder-facing yield.
This post explains what we built, why it matters, and how it works at the protocol level.
Summary
Steak combines three things that have never been wired together in production before:
-
A Solana validator vote account upgraded to v4, with independent commission settings for inflation rewards and block revenue, each pointing at a custom collector address rather than the validator identity wallet.
-
An on-chain Anchor program (program ID ending in
BANK) that receives those commission deposits at the protocol level and executes custom distribution rules — pro-rata payouts, lock periods, eligibility filters, and reward accounting — without human intervention. -
A meme-native staking layer where holders stake pump.fun-launched tokens (Token-2022) into program-controlled vaults and earn SOL-denominated yield sourced from real validator revenue streams, not off-chain promises or manual treasury scripts.
Our modeling and early mainnet operation indicate the following effects relative to the status quo (standard validator commission collection into a hot wallet, manual redistribution, or no redistribution at all):
| Dimension | Standard Validator | Steak |
|---|---|---|
| Commission custody | Identity hot wallet | On-chain program collector |
| Block revenue share to delegators | Off-protocol / trust-based | Protocol-enforced via SIMD-0123 |
| Custom distribution logic | Requires manual scripts | Enforced by contract instructions |
| Meme token staking | Not supported natively | Per-mint pools with vault PDAs |
| Revenue source transparency | Opaque | Verifiable on-chain inflows |
| Admin key for payouts | Effectively yes | No — distribution is instruction-gated |
The core claim is simple: Solana finally let validators route their income to arbitrary collector accounts at the runtime level. We are the first team to ship a working collector program and connect it to a live vote account on mainnet.
Motivation
The problem with how validator revenue works today
For most of Solana’s history, validator income followed a rigid path:
- Inflation rewards commission accumulated in the vote account itself.
- Block revenue (base fees + priority fees) went entirely to the validator’s identity (node) account.
- Any sharing of block revenue with delegators happened off-protocol — via manual transfers, Discord promises, or custom dashboards that stakers had to trust.
This created three structural problems:
1. Trust, not code. A validator could advertise “we share MEV and block fees with delegators” and never follow through. There was no on-chain enforcement mechanism for block revenue sharing. Delegators had to trust operator reputation, which is a poor fit for a chain that markets itself on verifiability.
2. No programmable collectors. Even after SIMD-0185 introduced separate inflation and block revenue commission fields on vote accounts, the collector addresses were constrained — they had to be the vote account itself or the identity hot wallet. Validators who wanted to route revenue into a program-derived address (PDA) for automated, rule-based distribution hit a wall. PDAs cannot sign transactions the way hot wallets do, but they can hold lamports and be controlled by program logic. The protocol just wouldn’t deposit into them.
3. Meme ecosystems have no native yield. pump.fun launched thousands of tokens with creator fee streams attached, but no standard way to turn those cash flows — or validator revenue — into holder-facing staking yield. Existing “staking” products in the meme space are either custodial, admin-keyed treasuries, or off-chain point systems. None of them use Solana’s native validator economics as the yield source.
Why now
The SIMD stack changed the game:
- SIMD-0185 split validator income into two independent streams (inflation rewards vs. block revenue), each with its own commission rate in basis points and its own collector pubkey field.
- SIMD-0123 made block revenue sharing with delegators a protocol-level behavior — the runtime calculates commission, deposits it into the designated collector, and distributes the remainder to delegated stake accounts automatically each block.
- SIMD-0232 removed the restriction that collectors must be identity hot wallets. Validators can now point collectors at rent-exempt system-owned accounts — which is exactly what you need to receive runtime deposits into an address that a custom program controls.
These three proposals were designed together. The documentation describes them as a package. But until someone actually deploys a collector program, upgrades a vote account to v4, sets the collector fields, and proves that runtime deposits arrive and get distributed correctly — it is all specification, not product.
We built the product.
What We Built
The contract
We wrote and deployed an Anchor program on Solana mainnet. The program ID is:
aZPKJ99yjfE6MjZ5isXNjm3ndanBdx5gX35nwmLBANK
The vanity suffix BANK is intentional — this program is the bank. It is the account that the validator runtime deposits commission into, and it is the program that decides how those deposits get split among stakers.
The program is deployed via the BPF Upgradeable Loader. It owns thousands of on-chain state accounts (56-byte config records for pools and user positions, plus larger vault accounts for token custody). At time of writing it holds approximately 946 SOL in lamports, reflecting both user activity and validator revenue inflows.
We did not build a dashboard-first product and backfill the contract later. The contract came first. The distribution rules are enforced at the instruction level. If an instruction does not pass the program’s checks, the transfer does not happen.
The validator configuration
We operate (or partner with) a validator whose vote account has been upgraded to Vote Account v4 per SIMD-0185. The relevant fields:
| Field | Purpose | Our configuration |
|---|---|---|
inflation_rewards_commission_bps |
Validator’s cut of inflation rewards | Set independently from block revenue |
block_revenue_commission_bps |
Validator’s cut of block fees + priority fees | Set independently from inflation |
inflation_rewards_collector |
Where inflation commission is deposited | Points at our program’s collector PDA |
block_revenue_collector |
Where block revenue commission is deposited | Points at our program’s collector PDA |
The collector update uses the Vote Program’s UpdateCommissionCollector instruction (discriminant 17u32 per the latest SIMD-0232 amendment), signed by the vote account’s withdraw authority.
Once configured, the Solana runtime handles deposits automatically:
- At the beginning of each epoch, inflation commission is calculated and deposited into
inflation_rewards_collector. - At the end of each block, block revenue commission is calculated and deposited into
block_revenue_collector. - Under SIMD-0123, the non-commission portion of block revenue is distributed directly to delegated stake accounts — no manual intervention.
Our program’s collector PDAs receive the commission slices. Internal program instructions then allocate those lamports to stakers according to the rules defined in each pool.
The staking layer
On top of the validator revenue pipeline, we built per-mint staking pools for pump.fun-launched tokens:
- Each pool is keyed by a PDA derived from the token mint address.
- Users stake Token-2022 meme tokens into a program-controlled vault PDA.
- The program tracks each user’s staked balance, deposit timestamp, and reward debt.
- Rewards accumulate in SOL (sourced from validator commission inflows and/or creator fee routing).
- Users claim via a
claim_rewardsinstruction that calculates pro-rata entitlement and transfers lamports from the reward vault.
Fixed lock periods are enforced at the program level — early unstake either fails or incurs a penalty, depending on pool configuration. There is no admin key that can override lock state.
Detailed Design
Architecture overview
The system has four layers:
┌─────────────────────────────────────────────────┐
│ Solana Runtime (SIMD-0123 / SIMD-0232) │
│ Deposits commission into collector PDAs │
└──────────────────────┬──────────────────────────┘
│ lamports (automatic)
▼
┌─────────────────────────────────────────────────┐
│ Steak Program (…BANK) │
│ Collector PDAs · Reward vault · Distribution │
└──────────────────────┬──────────────────────────┘
│ claim_rewards
▼
┌─────────────────────────────────────────────────┐
│ Staker PDAs (per user, per pool) │
│ Balance · lock expiry · reward debt │
└──────────────────────┬──────────────────────────┘
│ SOL transfer
▼
┌─────────────────────────────────────────────────┐
│ User wallet │
└─────────────────────────────────────────────────┘
Separately, the meme token staking path:
User wallet ──stake()──
Token vault PDA (per pool)
│
▼
Staker state PDA (per user)
│
▼
claim_rewards() ──▶ SOL to user
Account model
We use a standard Anchor PDA layout:
| Account | Seeds | Size | Purpose |
|---|---|---|---|
| Global config | ["config"] |
~56 bytes | Program-wide parameters, pause flag, admin settings |
| Pool state | ["pool", mint] |
~56 bytes | Per-mint pool config: lock duration, total staked, reward index |
| User stake | ["stake", pool, user] |
~56 bytes | User’s staked amount, deposit slot, reward debt snapshot |
| Token vault | ["vault", mint] |
SPL token account | Holds staked meme tokens |
| Reward vault | ["rewards", mint] |
System account | Holds SOL rewards awaiting claim |
| Collector (inflation) | ["collector", "inflation"] |
System account | Receives inflation commission from runtime |
| Collector (block) | ["collector", "block"] |
System account | Receives block revenue commission from runtime |
The 56-byte account size visible across our program’s on-chain state accounts corresponds to the pool and user-stake config records. Vault accounts are larger (165 bytes for SPL token accounts).
Instruction set
| Instruction | Signer | Effect |
|---|---|---|
initialize_config |
Authority | One-time program setup |
initialize_pool |
Authority | Create a new staking pool for a given mint |
stake |
User | Transfer meme tokens into vault; create/update staker PDA |
unstake |
User | Return tokens from vault after lock period expires |
fund_rewards |
Anyone | Deposit SOL into reward vault (permissionless top-up) |
claim_rewards |
User | Calculate entitlement from reward index delta; transfer SOL |
update_pool |
Authority | Modify pool parameters (lock duration, etc.) |
pause / unpause |
Authority | Emergency circuit breaker |
The runtime-facing path (commission deposits from SIMD-0123/0232) requires no instruction — lamports arrive automatically. The program’s off-chain indexer (or a crank) periodically calls an internal sync_rewards instruction to update the global reward index when new commission lamports land in the collector PDAs.
Reward index mechanics
We use a reward-per-token-stored index, the same pattern used by Synthetix, Compound, and most DeFi staking contracts:
- When
Rlamports arrive in the reward vault, computeindex_delta = R * PRECISION / total_staked. - Increment the pool’s global
reward_index. - On
claim_rewards, user entitlement =staked_amount * (current_index - user_reward_debt) / PRECISION. - Update user’s
reward_debttocurrent_index.
This allows O(1) claims regardless of how many stakers exist, and it handles commission inflows that arrive at arbitrary times (epoch boundaries for inflation, per-block for block revenue) without iterating over all stakers.
Vote account integration (SIMD-0185 + 0232)
The vote account upgrade path:
- Existing vote account is at version 3 (or earlier).
- Call
UpgradeVoteAccountto migrate to v4. This initializes:inflation_rewards_collector→ defaults to vote account addressblock_revenue_collector→ defaults to node identity pubkeyinflation_rewards_commission_bps→100 * old_commissionblock_revenue_commission_bps→10000(100% to validator by default)pending_delegator_rewards→0
- Call
UpdateCommissionCollectorwithkind: BlockRevenueand the block collector PDA. - Call
UpdateCommissionCollectorwithkind: InflationRewardsand the inflation collector PDA. - Optionally adjust
block_revenue_commission_bpsandinflation_rewards_commission_bpsindependently.
Per SIMD-0232, the designated collector must satisfy ALL of:
- Owned by the System Program
- Rent-exempt
- Not a reserved account
Our collector PDAs meet these constraints. The runtime verifies them at deposit time. If they did not, the commission would be burned — so getting this right was critical, and it is one reason we believe we are the first team to have this working in production.
Block revenue flow (SIMD-0123)
For each block our validator produces:
- Runtime sums base fees + priority fees from all transactions in the block.
- Loads the vote account’s
block_revenue_commission_bps(snapshotted at epoch boundary). - Computes
commission = floor(revenue * bps / 10000). - Deposits
commissionlamports intoblock_revenue_collector. - Distributes
revenue - commissionto delegated stake accounts pro-rata by stake weight.
Step 4 is where our program receives lamports. No instruction. No signature. The runtime just does it.
For delegators staking SOL directly with our validator (standard native delegation), they receive block revenue share automatically via step 5. For meme token stakers using Steak, they receive their share via the reward index when commission lands in the collector and gets synced.
Comparison: Standard Staking vs. Steak
Revenue routing
| Step | Standard validator | Steak |
|---|---|---|
| Block fees collected | Identity hot wallet (100%) | Runtime splits via commission bps |
| Commission deposit target | Identity hot wallet | Program collector PDA |
| Delegator block revenue | Manual / off-chain | Protocol-enforced (SIMD-0123) |
| Custom distribution | Python script + hope | Anchor program instructions |
| Auditability | Check operator’s word | Read collector PDA balance on-chain |
Staking model
| Feature | Native SOL staking | Steak staking |
|---|---|---|
| Asset staked | SOL | pump.fun tokens (Token-2022) |
| Stake account owner | Stake program | Steak program |
| Reward currency | SOL (inflation) | SOL (validator commission) |
| Lock period | Epoch-based warmup/cooldown | Program-enforced fixed duration |
| Reward claim | Automatic credit to stake account | Explicit claim_rewards instruction |
| Slashing exposure | Yes (validator underperformance) | No (rewards depend on commission inflows, not vote credits) |
Trust model
| Assumption | Standard | Steak |
|---|---|---|
| Validator shares block fees | Trust operator | Verify collector PDA inflows |
| Reward calculation is fair | Trust operator | Verify reward index math on-chain |
| Admin can steal staked tokens | No (stake program) | No (vault PDA, no admin withdraw) |
| Admin can steal rewards | Yes (if manual) | No (instruction-gated claims) |
| Commission config can rug | Commission can change next epoch | Same — but SIMD-0249 delays changes ≥1 epoch |
Impact
For meme token holders
Before Steak, holding a pump.fun token meant:
- Exposure to price action only
- No native yield
- Creator fees went to the deployer wallet with no programmatic sharing
After:
- Holders can stake into a pool and earn SOL yield sourced from real validator revenue
- Lock periods align holder time horizons with the project
- Claims are permissionless and on-chain
For the Solana validator ecosystem
We prove that SIMD-0232’s custom commission collector is not just a spec item — it works in production. Specifically:
- A validator CAN point collectors at program-controlled addresses
- The runtime DOES deposit commission correctly
- A program CAN receive and redistribute those deposits according to custom rules
- The full pipeline from block production → commission deposit → staker claim works end-to-end
This opens the design space for every validator operator who wants to offer programmatic revenue sharing without trusting themselves.
For Solana governance
The SIMD-0123/0185/0232 stack was voted on and merged into the protocol with the promise of enabling custom validator economics. But protocol features only matter when someone ships. Steak is that shipment — a reference implementation that other validators, staking protocols, and governance participants can inspect, fork, and improve.
Security Considerations
Collector PDA validity
If our collector PDAs fail SIMD-0232’s constraints (wrong owner, not rent-exempt, reserved account), the runtime burns the commission rather than depositing it. We verified all collector accounts against these constraints before configuring the vote account. This is a one-time setup risk with permanent consequences — getting it wrong means lost revenue, not a revert.
Upgrade authority
The program is deployed via the BPF Upgradeable Loader. The upgrade authority is held by our deployer key. We intend to renounce or transfer upgrade authority to a multisig after audit. Until then, users should treat this as unaudited, early-stage software — which it is.
Reward index manipulation
The reward index pattern is safe against flash-stake attacks IF the index update and stake happen in separate transactions (which they do — commission arrives from the runtime asynchronously). A user who stakes after a commission inflow but before the index sync gets no credit for that inflow, which is the correct behavior.
Commission change delay
SIMD-0249 (Delay Commission Updates) ensures commission changes take effect no earlier than the next epoch. This prevents a validator from advertising 0% commission, attracting delegators, then spiking to 100% mid-epoch. Our vote account is subject to this delay like all v4 vote accounts.
Lock period enforcement
Unstake before lock expiry either reverts or applies a penalty, depending on pool config. The check is in the program — not in a frontend toggle that can be bypassed.
No admin key on staked funds
The program authority can pause new stakes and update pool parameters, but cannot withdraw user tokens from vault PDAs. Vault PDAs are owned by the program and only release tokens via the unstake instruction when lock conditions are met.