I’m posting this to flag to the community that I am exploring how to improve the RewardDestination struct of staking, which determines how your staking reward is received. I’ll review what we have currently, the problems we face & a proposed iteration to solve those problems.
Current Enum
The current structure of RewardDestination is as follows:
Staked: compound your rewards (auto bond them)Stash: send rewards to your stash account as free balance.Controller: send rewards to your controller account as free balance.Account(AccountId): send rewards to an ad-hoc account as free balance.None: do not receive staking rewards.
Problems
The problems we are facing here are as follows:
- We need to remove the
Controllervariant if we are to fully deprecate controller accounts.Controlleris index 3 of the enum, so at the least, a migration will be needed for index 3, 4, and 5. There are > 68k Payee records on Polkadot, so this would entail a lazy migration. - There is no splitting mechanism whereby we can compound a % of rewards, and have the rest as free balance. Such a feature has been discussed over the years.
- If the
Controllervariant is removed then we realise that theStashandAccountvariants are essentially the same thing. - If we simply add the
Splitvariant to the existing enum, we still have theControllervariant that would eventually need to be removed, and result in an even larger migration.
Propossed New Enum
What I propose is to simplify the enum variants based on whether the rewards be compounded or be free balance. This new enum, PayeeDestination, will remove Controller and introduce Split((Perbill, AccountId)) whereby the Perbill amount of rewards will be sent to the AccountId, and the rest compounded. Over 2 runtime upgrades we can lazily migrate storage to this new enum, with the latter enabling the new Split variant.
The entire proposed enum is as follows:
pub enum PayeeDestination<AccountId> {
/// Pay into the staking account and compound to bond.
Compound,
/// Pay a part back into the stash and compound to bond, and send another part to a specified account as free balance.
Split((Perbill, AccountId)),
/// Pay into a specified account as free balance.
Free(AccountId),
/// Receive no reward.
None,
}
We no longer have stash and controller terminology, and the terminology is simplified to account for compounding (Compound), free balance (Free) or both (Split). None remains.
Further Splitting and Exotic Routing
This proposed change assumes that the staking pallet maintains a simple mechanism for splitting rewards - it should not be responsible for housing complex logic for more exotic splitting of rewards. Instead it only cares about the ability to re-stake or not. For more capable mechanisms smart contracts or dedicated pallets can take on the role of providing better splitting support.
So given the Split option is available, users will be able to compound a chunk of their rewards back into staking, and send the other chunk as free balance to an address, perhaps a smart contract, that could futher split the reward, exchange it into other tokens, & route to other accounts / platforms / DeFi products, and so-forth. This scenario is of course not a part of this current migration, but is an eventual outcome that we can work towards.
Current Progress
-
Tracking issue on the lazy migration and proposed enum: Refactor `Payee` and `RewardDestination` for split and controller removal · Issue #410 · paritytech/polkadot-sdk · GitHub
-
Part 1 of the lazy migration, introducing the
PayeeDestinationenum and means to do the migration via anupdate_payeecall: Introduce `Payees` and `PayoutDestination` with `Split` variant by rossbulat · Pull Request #14451 · paritytech/substrate · GitHub
If part 1 is supported and merged, this paves the way to fully transition to PayeeDestination and introduce splitting logic to set_payee and payout_stakers in a second PR.