github.com/Finschia/finschia-sdk@v0.48.1/x/distribution/spec/04_messages.md (about)

     1  <!--
     2  order: 4
     3  -->
     4  
     5  # Messages
     6  
     7  ## MsgSetWithdrawAddress
     8  
     9  By default, the withdraw address is the delegator address. To change its withdraw address, a delegator must send a `MsgSetWithdrawAddress` message.
    10  Changing the withdraw address is possible only if the parameter `WithdrawAddrEnabled` is set to `true`.
    11  
    12  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.
    13  
    14  Response:
    15  
    16  +++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37
    17  
    18  ```go
    19  func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error
    20  	if k.blockedAddrs[withdrawAddr.String()] {
    21  		fail with "`{withdrawAddr}` is not allowed to receive external funds"
    22  	}
    23  
    24  	if !k.GetWithdrawAddrEnabled(ctx) {
    25  		fail with `ErrSetWithdrawAddrDisabled`
    26  	}
    27  
    28  	k.SetDelegatorWithdrawAddr(ctx, delegatorAddr, withdrawAddr)
    29  ```
    30  
    31  ## MsgWithdrawDelegatorReward
    32  
    33  A delegator can withdraw its rewards.
    34  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.
    35  The rewards are sent immediately from the distribution `ModuleAccount` to the withdraw address.
    36  Any remainder (truncated decimals) are sent to the community pool.
    37  The starting height of the delegation is set to the current validator period, and the reference count for the previous period is decremented.
    38  The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator.
    39  
    40  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.
    41  In basic F1, the total rewards that all the delegators are entitled to between to periods is calculated the following way.
    42  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`.
    43  Then the rewards for all the delegators for staking between periods `A` and `B` are `(R(B) - R(A)) * total stake`.
    44  However, these calculated rewards don't account for slashing.
    45  
    46  Taking the slashes into account requires iteration.
    47  Let `F(X)` be the fraction a validator is to be slashed for a slashing event that happened at period `X`.
    48  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:
    49  
    50  ```
    51  stake := initial stake
    52  rewards := 0
    53  previous := A
    54  for P in P1, ..., PN`:
    55      rewards = (R(P) - previous) * stake
    56      stake = stake * F(P)
    57      previous = P
    58  rewards = rewards + (R(B) - R(PN)) * stake
    59  ```
    60  
    61  The historical rewards are calculated retroactively by playing back all the slashes and then attenuating the delegator's stake at each step.
    62  The final calculated stake is equivalent to the actual staked coins in the delegation with a margin of error due to rounding errors.
    63  
    64  Response:
    65  
    66  +++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50
    67  
    68  ## WithdrawValidatorCommission
    69  
    70  The validator can send the WithdrawValidatorCommission message to withdraw their accumulated commission.
    71  The commission is calculated in every block during `BeginBlock`, so no iteration is required to withdraw.
    72  The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator.
    73  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.
    74  
    75  ## FundCommunityPool
    76  
    77  This message sends coins directly from the sender to the community pool.
    78  
    79  The transaction fails if the amount cannot be transferred from the sender to the distribution module account.
    80  
    81  ```go
    82  func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error {
    83      if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil {
    84          return err
    85      }
    86  
    87  	feePool := k.GetFeePool(ctx)
    88  	feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...)
    89  	k.SetFeePool(ctx, feePool)
    90  
    91  	return nil
    92  }
    93  ```
    94  
    95  ## Common distribution operations
    96  
    97  These operations take place during many different messages.
    98  
    99  ### Initialize delegation
   100  
   101  Each time a delegation is changed, the rewards are withdrawn and the delegation is reinitialized.
   102  Initializing a delegation increments the validator period and keeps track of the starting period of the delegation.
   103  
   104  ```go
   105  // initialize starting info for a new delegation
   106  func (k Keeper) initializeDelegation(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) {
   107      // period has already been incremented - we want to store the period ended by this delegation action
   108      previousPeriod := k.GetValidatorCurrentRewards(ctx, val).Period - 1
   109  
   110  	// increment reference count for the period we're going to track
   111  	k.incrementReferenceCount(ctx, val, previousPeriod)
   112  
   113  	validator := k.stakingKeeper.Validator(ctx, val)
   114  	delegation := k.stakingKeeper.Delegation(ctx, del, val)
   115  
   116  	// calculate delegation stake in tokens
   117  	// we don't store directly, so multiply delegation shares * (tokens per share)
   118  	// note: necessary to truncate so we don't allow withdrawing more rewards than owed
   119  	stake := validator.TokensFromSharesTruncated(delegation.GetShares())
   120  	k.SetDelegatorStartingInfo(ctx, val, del, types.NewDelegatorStartingInfo(previousPeriod, stake, uint64(ctx.BlockHeight())))
   121  }
   122  ```