Last updated

Rakurai Reward Distribution Program

This is the accounting layer behind every Rakurai revenue stream. It is how four kinds of money on a Rakurai validator get split and paid out: block rewards owed to stakers, plus the three TIN streams — tips, post-pack subscriptions, and backrun share.

Each stream gets its own account per validator, and for TIN partners per service, so what is owed and what has been paid is on-chain and checkable by both sides.

You do not need to know how the chain works to follow this. Each kind of money has its own account (a labeled wallet the program controls) and its own flow. They do not mix.

RCATCAPSAMCA
Full nameReward Collection AccountTips Collection AccountP2C Subscription AccountMevShare Collection Account
What money is this?The validator’s block rewardsTips traders and landing services pay to land transactionsA subscription fee to use post-pack, priced from SOL stakeBackrun profit from post-pack
Who pays?The network (block rewards)Traders / landing servicesAnyone who wants post-pack accessThe post-pack user who backran
Why it existsStakers should get their share of block rewardsTips must be split: Rakurai cut, then the validatorPost-pack is not free; pay a prepaid fee so the stream stays onBackrun profit must be shared: Rakurai cut, then the validator
During the epochEach time this validator leads, the last block’s reward is split; the staker share is parked in the RCATips land in Rakurai tip accounts; Rakurai’s cut is taken; the rest is parked in the TCAYou top up the PSA so there is prepaid SOL sitting thereNothing is collected automatically — profit sits with the user
After the epochA payout list is published; stakers collectRemainder → validator (high-priority block reward, default)Fee from prepaid: Rakurai’s cut, rest → validator (high-priority block reward, default)User reports and sends shared profit; rest → validator (high-priority block reward, default)
If it is not paidUnclaimed staker funds eventually return to the validatorCustom-tip partners who do not settle lose tip priority after a short graceStream is stopped until the balance is topped upUsers who do not share lose post-pack priority after a short grace

Where to click: P2C subscription (PSA) · Partner settlement (TCA / MCA) · Account layouts · View on Solscan.

➤ On-chain interface file: reward_distribution.json.

Post-pack users read this order

Fund the PSA first — it buys access to the stream. Only then does the MCA matter, because it shares the profit you made from that stream. You cannot skip the PSA and go straight to the MCA.


1. Deployed program ID


2. Block reward conversion for TCA / MCA / PSA revenue

TCA, PSA, and MCA validator shares, after Rakurai’s commission, are first claimed and credited to the validator identity account.

With block-reward conversion enabled by default, that claimed amount is then converted into a high-priority block-reward transaction during the validator’s next leader turn. The effect is that revenue which arrived as a tip, a subscription fee, or a MevShare payment reaches stakers through the same block-reward path as ordinary block rewards.

The flag lives on each account individually (block_reward_conversion_enabled on the TCA, PSA, and MCA), so it can be on for one revenue stream and off for another on the same validator.

The conversion transaction is not retried

The conversion must land within that same leader turn. If it does not, it is dropped and not forwarded to the next leader — the funds simply stay in the validator identity account instead of being converted.

Do not count the same SOL twice

An indexer that watches both transfers into Rakurai tip accounts and validator block rewards will see the same lamports twice: once as the tip or claim, and again as the converted block reward. Count it once. Full explanation: TIN — indexing note.


3. RCA — block rewards for stakers

3.1. Why it exists

When a validator produces blocks, Solana pays block rewards. Those rewards belong in part to people who staked with that validator, not only to the operator.

Solana has no native mechanism to pay block rewards out to stakers, so by default they stay in the validator identity account. The RCA is the holding account that fixes this: it collects the stakers’ share for one validator, for one epoch (~2 days), so it can be distributed after the epoch closes.

Operator-facing walkthrough: Block Reward Distribution.

3.2. Epoch flow

3.2.1. RewardCollectionAccount initialization

On the first leader turn of each epoch, the RewardCollectionAccount is automatically initialized by the Rakurai Solana client. This initialization includes:

  • Commission details, read from the validator-specific RakuraiActivationAccount.
  • The authority allowed to update the reward Merkle root. Only this authority can upload the Merkle root to the RewardCollectionAccount.
Initialization is client-side

Account initialization logic lives in the Rakurai Solana client, not in a command you run. If the validator never leads during an epoch, no RCA is created for that epoch.

3.2.2. Per-turn transfers

During every leader turn, the previous turn’s block reward is processed:

  • Client commission → transferred to the client (Rakurai) account.
  • Validator commission → remains in the validator’s identity account.
  • Staker share → accumulated into the RewardCollectionAccount.
Rewards lag one turn behind

Because the reward for the current turn is transferred during the next one, the first turn of an epoch settles the last reward of the previous epoch.

3.2.3. Post-epoch staker distribution

At the final slot of each epoch:

  1. A snapshot of Solana accounts is captured.
  2. Each validator’s staker details and stake weights are extracted.
  3. An off-chain Merkle tree is generated containing reward share data. At this stage specific stakers can be blacklisted and individual stake weights adjusted before the tree is finalized — see custom distribution config.
  4. The Merkle root is uploaded to the RewardCollectionAccount by the reward_merkle_root_authority.
  5. Stakers receive rewards via Merkle claims. When reward_merkle_root_authority is Rakurai, Rakurai runs the claim process on behalf of stakers.

3.3. Reward distribution — free and automated by Rakurai

  • Set the Merkle root authority to Rakurai for fully automated reward distribution.
  • Keep it yourself if you want to run distribution manually.

When set to Rakurai, Rakurai will automatically:

  1. Create a snapshot
  2. Calculate the Merkle root
  3. Upload it on-chain
  4. Run the claim process for stakers
0% distribution fees charged by Rakurai

Delegating Merkle root authority to Rakurai costs nothing beyond standard Solana transaction fees.

3.4. Client commission on MEV rewards

The client charges commission on MEV rewards only if both of the following are true:

  • The validator is actively running Rakurai during that epoch.
  • The validator has set a non-zero MEV commission in their Tip Distribution Account.
Zero MEV commission means zero Rakurai commission

If the validator’s MEV commission is 0%, Rakurai does not charge any commission on MEV tips.

3.4.1. Deduction flow

  1. The validator’s share of MEV tips is credited to their vote account by the Tip Distribution Program in the following epoch.
  2. A ClaimStatus account is created to track that the validator has received MEV rewards.
  3. The Rakurai client monitors the ClaimStatus account; once it exists, commission becomes eligible for deduction.
  4. Rakurai cannot deduct directly from the vote account, so the same commission amount is deducted from the validator’s identity account instead.
  5. The deduction is performed by invoking the transfer_client_commission_on_mev_commission instruction in the Reward Distribution program.
  6. The commission rate is defined in the Reward Distribution Config account.

4. TCA — tips for landing transactions

4.1. Why it exists

Traders and transaction-landing services pay a tip so the Rakurai scheduler will prioritize their transactions. Those tips must be split: Rakurai gets a commission, the validator gets the rest.

The TCA is where the validator’s tip remainder is collected for the epoch, then paid to the validator after the epoch ends (typically claimed in the next epoch).

There is one TCA per service per validator, so a validator that receives tips from several landing services has one TCA per service. Searcher-facing guide: Tips.

4.2. Working model — Rakurai tip accounts (usual case)

By default, services tip Rakurai’s eight tip accounts, and rakurai_tip_manager drains them automatically.

  1. A trader tips any of the eight accounts
  2. Each time this validator is leader, those tip accounts are emptied
  3. Rakurai’s commission is taken immediately
  4. The remainder is moved into this validator’s TCA
  5. After the epoch, that remainder is paid to the validator’s identity, then converted to a high-priority block reward (on by default)

Rakurai is not paid a second time at step 5 — the commission already happened at step 3.

4.3. Working model — custom tip account (partner)

Some landing services want tips in their own account. Rakurai cannot empty that account, so the money moves in the opposite direction: the partner pays in, rather than Rakurai draining.

  1. You register the account and an agreed share with Rakurai (for example 30%)
  2. During the epoch, the validator writes down what is owed (no SOL moves yet)
  3. After the epoch, you send the owed SOL into the TCA
  4. Then Rakurai’s commission is taken from what you sent, and the rest goes to the validator identity (same block-reward conversion as above)
Unsettled custom tip accounts lose priority

If you do not settle within about two epochs, that custom tip account stops being used for prioritization from the next epoch onward. Settle with rakurai-revshare transfer --revenue-kind Tip.

Partner steps: rakurai-revshare (Tip). On-chain layout: TCA / MCA struct.


5. PSA — prepaid fee to use post-pack

5.1. Why it exists

Anyone who wants P2C / post-pack must pay a subscription to receive the stream. This is not a tip and not a share of backrun profit — it is the price of access, based on SOL stake (a public number you can check on explorers).

From each epoch’s fee: commission to Rakurai, remainder to the validator.

There is one PSA per service per validator: you pay for each validator whose updates you receive. Which servers receive the stream is configured separately in Client Config (always submit the full current list plus any new endpoint). The PSA only holds the prepaid SOL.

Full product guide: Post-pack confirmations.

5.2. Working model

  1. A PSA exists for your service + validator (created by Rakurai / ops; defaults from on-chain P2CConfigAccount)
  2. You top up SOL into that account (fund / fund-all, or any wallet transfer)
  3. For MevShare settlement, an MCA is also created by Rakurai / ops — then start post-pack
  4. Epoch ends. Rakurai writes the stake snapshot and the fee due
  5. The fee is taken from prepaid: Rakurai’s cut, rest to the validator identity (block-reward conversion on by default)
  6. If the balance is too low, top up and try again — or the shortfall is booked as deficit
  7. After a short grace, status becomes Suspended and post-pack is stopped until the shortfall is cleared
  8. When you leave, after every epoch is paid, leftover prepaid is returned
PSA exists (ops) → fund
    → MCA exists if sharing MevShare (ops) → start post-pack
    → epoch ends → fee calculated from stake
    → fee taken from prepaid (Rakurai + validator identity → high-priority block reward)if empty: grace, then stream stopped until you top up
    → close → leftover returned
An empty PSA stops the stream

The unpaid streak is tracked in unpaid_streak and compared against grace_epochs (default 2). Once it is exceeded the status becomes Suspended and post-pack delivery stops until the deficit is cleared. Check with rakurai-p2c get-account.

User / consumer steps: rakurai-p2c. On-chain layout: PSA struct.


6. MCA — sharing post-pack backrun profit

6.1. Why it exists

After you fund the PSA, post-pack sends you transactions at the point of no return (too late for anyone to front-run). You can backrun (trade after them). That extra profit sits in your wallet.

The deal is: you share that profit with the validator. The MCA is the account that receives the shared amount so Rakurai can take commission and pay the validator.

6.2. Working model

  1. After the PSA exists and is funded, an MCA is created by Rakurai / ops (TCA create is not a partner CLI path)
  2. You keep the key that is allowed to report the amount (record_authority on the MCA)
  3. During the epoch, nothing is taken automatically — you trade as usual
  4. After the epoch you report the shared profit once, then send that SOL into the MCA
  5. Rakurai’s commission is taken; the remainder is paid to the validator identity (block-reward conversion on by default)
Reporting requires the record authority

Step 4 is signed by the MCA record_authority keypair. Without that key you cannot record what you owe, and therefore cannot settle. Confirm which key it is with rakurai-revshare get-account --detail.

Settle within about two epochs

If you do not report and send within roughly two epochs, post-pack priority for your service stops.

Partner steps: rakurai-revshare (Mev-share). On-chain layout: TCA / MCA struct.


7. Account layouts

Production TCA / MCA are RevenueShareAccountV1 (aliases TipsCollectionAccountV1 / MevShareCollectionAccountV1). PSA is P2CSubscriptionAccount. Full IDL: reward_distribution.json.

7.1. TCA / MCA — RevenueShareAccountV1

Same struct for both. share_kind is Tip (TCA) or MevShare (MCA).

PDA: [REVENUE_SHARE_V1, TIP|MEV_SHARE, name[32], vote]

pub struct RevenueShareAccountV1 {
    pub share_kind: RevenueKind,           // Tip or MevShare
    pub name: [u8; 32],                    // service id (PDA seed)
    pub validator_vote: Pubkey,
    pub initializer: Pubkey,               // paid rent; gets it back on close
    pub manager_authority: Pubkey,         // claim / config / close
    pub record_authority: Pubkey,          // TCA: validator each leader turn; MCA: partner once post-epoch
    pub max_epoch_entries: u8,
    pub commission_bps: u16,               // Rakurai cut on claim (0 for Rakurai tip TCA)
    pub commission_account: Pubkey,
    pub block_reward_conversion_enabled: bool, // default on
    pub ledger: RevenueLedgerV1,           // Vec<EpochAmountEntryV1>
    pub deficit: u64,                      // unpaid shortfall
    pub bump: u8,
}

pub struct EpochAmountEntryV1 {
    pub epoch: u64,
    pub amount: u64,                       // recorded / attributed
    pub transferred_amount: u64,           // SOL actually settled into the PDA
    pub claimed: bool,
    pub block_reward_converted: bool,
}

pending = amount - transferred_amount. Inspect: rakurai-revshare get-account.

7.2. PSA — P2CSubscriptionAccount

Config PDA: [P2C_CONFIG]P2CConfigAccount (authority + manager / record / max_epoch / commission / grace defaults).

PSA PDA: [P2C_SUBSCRIPTION, name[32], vote] — anyone may init; fields above are copied from P2CConfigAccount.

pub struct P2CConfigAccount {
    pub authority: Pubkey,                 // update / close this config
    pub manager_authority: Pubkey,         // copied onto each PSA at init
    pub record_authority: Pubkey,          // copied onto each PSA at init
    pub max_epoch_entries: u8,
    pub commission_bps: u16,
    pub commission_account: Pubkey,
    pub grace_epochs: u8,
    pub bump: u8,
}

pub struct P2CSubscriptionAccount {
    pub name: [u8; 32],
    pub validator_vote: Pubkey,
    pub initializer: Pubkey,               // paid rent; residual on close
    pub manager_authority: Pubkey,         // record / claim / config / close
    pub record_authority: Pubkey,          // convert-to-block only (not epoch record)
    pub max_epoch_entries: u8,
    pub commission_bps: u16,
    pub commission_account: Pubkey,
    pub grace_epochs: u8,                  // unpaid epochs before Suspended (default 2)
    pub block_reward_conversion_enabled: bool, // default on
    pub unpaid_streak: u8,
    pub status: P2CSubscriptionStatus,     // Active / InGrace / Suspended
    pub deficit: u64,
    pub ledger: P2CSubscriptionLedger,     // Vec<P2CEpochEntry>
    pub bump: u8,
}

pub struct P2CEpochEntry {
    pub epoch: u64,
    pub stake: u64,                        // snapshot used to price the fee
    pub amount_due: u64,
    pub amount_deducted: u64,              // paid from prepaid on claim
    pub claimed: bool,
    pub block_reward_converted: bool,
}

Inspect: rakurai-p2c get-account.

7.3. How to view on-chain

You can read the same accounts in an explorer or via CLI.

CLI (decoded fields)

# TCA or MCA
rakurai-revshare -u m -p <RD_PROGRAM_ID> get-account \
  --revenue-kind Tip \
  --revenue-name <REVENUE_NAME> \
  --vote-pubkey <VOTE>

# PSA
rakurai-p2c -u m -p <RD_PROGRAM_ID> get-account \
  --name <SERVICE_NAME> -v <VOTE>

Use -u t and the testnet program ID on testnet. get-account prints the derived PDA — open that address on Solscan.

Solscan PDA tool

  1. Open Solscan PDA Create.
  2. Program ID: Reward Distribution (mainnet / testnet).
  3. Seeds:
AccountSeed 1 (string)Seed 2 (string)Seed 3Seed 4
TCAREVENUE_SHARE_V1TIPname padded to 32 bytesvote pubkey
MCAREVENUE_SHARE_V1MEV_SHAREname padded to 32 bytesvote pubkey
PSAP2C_SUBSCRIPTIONname padded to 32 bytesvote pubkey
  1. Open the derived address on Solscan (add ?cluster=testnet on testnet) to view lamports and raw data.

8. How long accounts live

  • RCA — one per validator per epoch. After about two epochs, leftovers return to the validator and it is closed.
  • TCA / PSA / MCA — one per service per validator, reused across epochs, until Rakurai closes it. PSA close only after every billed epoch is paid; leftover prepaid is returned.