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
Controller
variant if we are to fully deprecate controller accounts.Controller
is 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
Controller
variant is removed then we realise that theStash
andAccount
variants are essentially the same thing. - If we simply add the
Split
variant to the existing enum, we still have theController
variant 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 #14438 · paritytech/substrate · GitHub
-
Part 1 of the lazy migration, introducing the
PayeeDestination
enum and means to do the migration via anupdate_payee
call: Introduce `Payees` and `PayeeDestination` 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.