123 lines
5.6 KiB
Markdown
123 lines
5.6 KiB
Markdown
<!--
|
|
order: 4
|
|
-->
|
|
|
|
# Messages
|
|
|
|
## MsgSetWithdrawAddress
|
|
|
|
By default, the withdraw address is the delegator address. To change its withdraw address, a delegator must send a `MsgSetWithdrawAddress` message.
|
|
Changing the withdraw address is possible only if the parameter `WithdrawAddrEnabled` is set to `true`.
|
|
|
|
The withdraw address cannot be any of the module accounts. These accounts are blocked from being withdraw addresses by being added to the distribution keeper's `blockedAddrs` array at initialization.
|
|
|
|
Response:
|
|
|
|
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37
|
|
|
|
```go
|
|
func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error
|
|
if k.blockedAddrs[withdrawAddr.String()] {
|
|
fail with "`{withdrawAddr}` is not allowed to receive external funds"
|
|
}
|
|
|
|
if !k.GetWithdrawAddrEnabled(ctx) {
|
|
fail with `ErrSetWithdrawAddrDisabled`
|
|
}
|
|
|
|
k.SetDelegatorWithdrawAddr(ctx, delegatorAddr, withdrawAddr)
|
|
```
|
|
|
|
## MsgWithdrawDelegatorReward
|
|
|
|
A delegator can withdraw its rewards.
|
|
Internally in the distribution module, this transaction simultaneously removes the previous delegation with associated rewards, the same as if the delegator simply started a new delegation of the same value.
|
|
The rewards are sent immediately from the distribution `ModuleAccount` to the withdraw address.
|
|
Any remainder (truncated decimals) are sent to the community pool.
|
|
The starting height of the delegation is set to the current validator period, and the reference count for the previous period is decremented.
|
|
The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator.
|
|
|
|
In the F1 distribution, the total rewards are calculated per validator period, and a delegator receives a piece of those rewards in proportion to their stake in the validator.
|
|
In basic F1, the total rewards that all the delegators are entitled to between to periods is calculated the following way.
|
|
Let `R(X)` be the total accumulated rewards up to period `X` divided by the tokens staked at that time. The delegator allocation is `R(X) * delegator_stake`.
|
|
Then the rewards for all the delegators for staking between periods `A` and `B` are `(R(B) - R(A)) * total stake`.
|
|
However, these calculated rewards don't account for slashing.
|
|
|
|
Taking the slashes into account requires iteration.
|
|
Let `F(X)` be the fraction a validator is to be slashed for a slashing event that happened at period `X`.
|
|
If the validator was slashed at periods `P1, ..., PN`, where `A < P1`, `PN < B`, the distribution module calculates the individual delegator's rewards, `T(A, B)`, as follows:
|
|
|
|
```go
|
|
stake := initial stake
|
|
rewards := 0
|
|
previous := A
|
|
for P in P1, ..., PN`:
|
|
rewards = (R(P) - previous) * stake
|
|
stake = stake * F(P)
|
|
previous = P
|
|
rewards = rewards + (R(B) - R(PN)) * stake
|
|
```
|
|
|
|
The historical rewards are calculated retroactively by playing back all the slashes and then attenuating the delegator's stake at each step.
|
|
The final calculated stake is equivalent to the actual staked coins in the delegation with a margin of error due to rounding errors.
|
|
|
|
Response:
|
|
|
|
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50
|
|
|
|
## WithdrawValidatorCommission
|
|
|
|
The validator can send the WithdrawValidatorCommission message to withdraw their accumulated commission.
|
|
The commission is calculated in every block during `BeginBlock`, so no iteration is required to withdraw.
|
|
The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator.
|
|
Only integer amounts can be sent. If the accumulated awards have decimals, the amount is truncated before the withdrawal is sent, and the remainder is left to be withdrawn later.
|
|
|
|
## FundCommunityPool
|
|
|
|
This message sends coins directly from the sender to the community pool.
|
|
|
|
The transaction fails if the amount cannot be transferred from the sender to the distribution module account.
|
|
|
|
```go
|
|
func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error {
|
|
if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil {
|
|
return err
|
|
}
|
|
|
|
feePool := k.GetFeePool(ctx)
|
|
feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...)
|
|
k.SetFeePool(ctx, feePool)
|
|
|
|
return nil
|
|
}
|
|
```
|
|
|
|
## Common distribution operations
|
|
|
|
These operations take place during many different messages.
|
|
|
|
### Initialize delegation
|
|
|
|
Each time a delegation is changed, the rewards are withdrawn and the delegation is reinitialized.
|
|
Initializing a delegation increments the validator period and keeps track of the starting period of the delegation.
|
|
|
|
```go
|
|
// initialize starting info for a new delegation
|
|
func (k Keeper) initializeDelegation(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) {
|
|
// period has already been incremented - we want to store the period ended by this delegation action
|
|
previousPeriod := k.GetValidatorCurrentRewards(ctx, val).Period - 1
|
|
|
|
// increment reference count for the period we're going to track
|
|
k.incrementReferenceCount(ctx, val, previousPeriod)
|
|
|
|
validator := k.stakingKeeper.Validator(ctx, val)
|
|
delegation := k.stakingKeeper.Delegation(ctx, del, val)
|
|
|
|
// calculate delegation stake in tokens
|
|
// we don't store directly, so multiply delegation shares * (tokens per share)
|
|
// note: necessary to truncate so we don't allow withdrawing more rewards than owed
|
|
stake := validator.TokensFromSharesTruncated(delegation.GetShares())
|
|
k.SetDelegatorStartingInfo(ctx, val, del, types.NewDelegatorStartingInfo(previousPeriod, stake, uint64(ctx.BlockHeight())))
|
|
}
|
|
```
|