diff --git a/proposals/0232-custom-commission-collector.md b/proposals/0232-custom-commission-collector.md new file mode 100644 index 000000000..cfde51187 --- /dev/null +++ b/proposals/0232-custom-commission-collector.md @@ -0,0 +1,190 @@ +--- +simd: '0232' +title: Custom Commission Collector Account +authors: Justin Starry (Anza) +category: Standard +type: Core +status: Review +created: 2025-01-24 +feature: (fill in with feature tracking issues once accepted) +--- + +## Summary + +Allow validators to specify custom commission collector accounts where block +revenue and inflation rewards commissions will be deposited. + +## Motivation + +Validator commission collector accounts must currently be the same as their +identity hot wallet account. This means that program derived addresses are +unable to be used for block revenue collection adding friction to validators +wishing to distribute their revenue in custom ways. By allowing validators to +specify a separate custom commission collector account, they can use onchain +programs to customize how their block revenue is distributed. + +## Dependencies + +This proposal depends on the following previously accepted proposals: + +- **[SIMD-0180]: Use Vote Account Address To Key Leader Schedule** + + Necessary for designating a specific vote account for a given leader slot + +- **[SIMD-0185]: Vote Account v4** + + Adds necessary block revenue and inflation rewards commission collector + address fields to the vote account state + +[SIMD-0180]: https://github.com/solana-foundation/solana-improvement-documents/pull/180 +[SIMD-0185]: https://github.com/solana-foundation/solana-improvement-documents/pull/185 + +## Alternatives Considered + +NA + +## New Terminology + +- Block Revenue Commission Collector: The account used to collect commissioned +block revenue for validators. Previously collected by default into the validator +identity account. + +- Inflation Rewards Commission Collector: The account used to collect +commissioned inflation rewards for validators. Previously collected by default +into the vote account. + +## Detailed Design + +### Runtime + +#### Block Revenue Commission Collection + +When collecting block fee revenue after processing all transactions in a block, +the runtime must look up the validator's specified block revenue collector +address. After adoption of [SIMD-0180] and [SIMD-0185], a given block's fee +commission collector address can be looked up via the designated vote account +for the leader schedule slot that the block was produced in. Note that by +default, the commission rate for block fee revenue is 100% and support for other +rates will be added in [SIMD-0123]. + +In order to eliminate the overhead of tracking the latest commission collector +address of each vote account, the commission collector address should be fetched +from the state of the vote account at the beginning of the previous epoch. This +is the same vote account state used to build the leader schedule for the current +epoch. + +The designated commission collector must either be equal to the vote account's +address OR satisfy ALL of the following constraints: + +1. Must be a system program owned account +2. Must be rent-exempt after depositing block revenue commission +3. Must not be a reserved account (note that currently the only system program +owned reserved accounts are the native loader and the sysvar owner id). + +If any of these constraints are violated, the fees collected for that block will +be burned. + +Note that it's technically allowed to set the collector account to the +incinerator address. Incinerator funds are burned after block revenue collection +at the end of the block. + +[SIMD-0123]: https://github.com/solana-foundation/solana-improvement-documents/pull/123 + +#### Inflation Rewards Commission Collection + +For a given epoch `E`, the earned inflation rewards for each vote account are +calculated at the beginning of the next epoch `E + 1`. This proposal doesn't +change the commission calculation but it does define new rules for how the +calculated commission rewards are collected into an account. Rather than +collecting the inflation rewards commission into the vote accounts by default, +the protocol must fetch the inflation rewards commission collector address from +the vote account state at the beginning of epoch `E + 1`. This is the same +vote account state used to get the commission rate and latest vote credits +for inflation rewards calculation. + +The designated commission collector must either be equal to the vote account's +address OR satisfy ALL of the following constraints: + +1. Must be a system program owned account +2. Must be rent-exempt after depositing inflation rewards commission +3. Must not be a reserved account (note that currently the only system program +owned reserved accounts are the native loader and the sysvar owner id). + +If any of these constraints are violated, the inflation rewards commission +collected for that epoch will be burned. + +Note that it's technically allowed to set the collector account to the +incinerator address. Incinerator funds are burned at the end of the rewards +distribution block. + +### Vote Program + +```rust +pub enum VoteInstruction { + /// # Account references + /// 0. `[WRITE]` Vote account to be updated with the new collector public key + /// 1. `[WRITE]` New collector account + /// 2. `[SIGNER]` Withdraw authority + UpdateCommissionCollector { // 16u32 + kind: CommissionKind, + }, +} + +#[repr(u8)] +pub enum CommissionKind { + InflationRewards = 0, + BlockRevenue = 1, +} +``` + +#### `UpdateCommissionCollector` + +A new instruction for setting collector accounts will be added to the vote +program with the enum discriminant value of `16u32` little endian encoded in the +first 4 bytes. + +Perform the following checks: + +- If the number of account inputs is less than 2, return +`InstructionError::NotEnoughAccountKeys` +- If the vote account (index `0`) fails to deserialize, return +`InstructionError::InvalidAccountData` +- If the vote account's authorized withdrawer is not an account input for the +instruction or is not a signer, return +`InstructionError::MissingRequiredSignature` +- If the new collector account (index `1`) is not the same as the vote account +and not system program owned, return `InstructionError::InvalidAccountOwner` +- If the new collector account is not rent-exempt, return +`InstructionError::InsufficientFunds` +- If the new collector account is not writable, return +`InstructionError::InvalidArgument`. Note that this check is performed to ensure +that the new collector account is not a reserved account. + +Update the corresponding field for the specified commission kind: + +- `CommissionKind::InflationRewards`: update the `inflation_rewards_collector` field +- `CommissionKind::BlockRevenue`: update the `block_revenue_collector` field + +## Impact + +Validator identity and fee collector accounts no longer need to be the same +account. This opens up the ability to use PDA accounts for block revenue +collection. + +Inflation reward commissions no longer need to be collected into a validator's +vote account. This validators more flexibility over managing inflation reward +income. + +## Security Considerations + +NA + +## Drawbacks *(Optional)* + +NA + +## Backwards Compatibility *(Optional)* + +This change will require the use of a new feature gate which will enable +collecting block fees and inflation rewards into custom commission collector +addresses if specified by a validator.