github.com/cosmos/cosmos-sdk@v0.50.10/x/distribution/keeper/allocation.go (about) 1 package keeper 2 3 import ( 4 "context" 5 6 abci "github.com/cometbft/cometbft/abci/types" 7 8 "cosmossdk.io/math" 9 10 sdk "github.com/cosmos/cosmos-sdk/types" 11 "github.com/cosmos/cosmos-sdk/x/distribution/types" 12 stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" 13 ) 14 15 // AllocateTokens performs reward and fee distribution to all validators based 16 // on the F1 fee distribution specification. 17 func (k Keeper) AllocateTokens(ctx context.Context, totalPreviousPower int64, bondedVotes []abci.VoteInfo) error { 18 // fetch and clear the collected fees for distribution, since this is 19 // called in BeginBlock, collected fees will be from the previous block 20 // (and distributed to the previous proposer) 21 feeCollector := k.authKeeper.GetModuleAccount(ctx, k.feeCollectorName) 22 feesCollectedInt := k.bankKeeper.GetAllBalances(ctx, feeCollector.GetAddress()) 23 feesCollected := sdk.NewDecCoinsFromCoins(feesCollectedInt...) 24 25 // transfer collected fees to the distribution module account 26 err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, k.feeCollectorName, types.ModuleName, feesCollectedInt) 27 if err != nil { 28 return err 29 } 30 31 // temporary workaround to keep CanWithdrawInvariant happy 32 // general discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634 33 feePool, err := k.FeePool.Get(ctx) 34 if err != nil { 35 return err 36 } 37 38 if totalPreviousPower == 0 { 39 feePool.CommunityPool = feePool.CommunityPool.Add(feesCollected...) 40 return k.FeePool.Set(ctx, feePool) 41 } 42 43 // calculate fraction allocated to validators 44 remaining := feesCollected 45 communityTax, err := k.GetCommunityTax(ctx) 46 if err != nil { 47 return err 48 } 49 50 voteMultiplier := math.LegacyOneDec().Sub(communityTax) 51 feeMultiplier := feesCollected.MulDecTruncate(voteMultiplier) 52 53 // allocate tokens proportionally to voting power 54 // 55 // TODO: Consider parallelizing later 56 // 57 // Ref: https://github.com/cosmos/cosmos-sdk/pull/3099#discussion_r246276376 58 for _, vote := range bondedVotes { 59 validator, err := k.stakingKeeper.ValidatorByConsAddr(ctx, vote.Validator.Address) 60 if err != nil { 61 return err 62 } 63 64 // TODO: Consider micro-slashing for missing votes. 65 // 66 // Ref: https://github.com/cosmos/cosmos-sdk/issues/2525#issuecomment-430838701 67 powerFraction := math.LegacyNewDec(vote.Validator.Power).QuoTruncate(math.LegacyNewDec(totalPreviousPower)) 68 reward := feeMultiplier.MulDecTruncate(powerFraction) 69 70 err = k.AllocateTokensToValidator(ctx, validator, reward) 71 if err != nil { 72 return err 73 } 74 75 remaining = remaining.Sub(reward) 76 } 77 78 // allocate community funding 79 feePool.CommunityPool = feePool.CommunityPool.Add(remaining...) 80 return k.FeePool.Set(ctx, feePool) 81 } 82 83 // AllocateTokensToValidator allocate tokens to a particular validator, 84 // splitting according to commission. 85 func (k Keeper) AllocateTokensToValidator(ctx context.Context, val stakingtypes.ValidatorI, tokens sdk.DecCoins) error { 86 // split tokens between validator and delegators according to commission 87 commission := tokens.MulDec(val.GetCommission()) 88 shared := tokens.Sub(commission) 89 90 valBz, err := k.stakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator()) 91 if err != nil { 92 return err 93 } 94 95 // update current commission 96 sdkCtx := sdk.UnwrapSDKContext(ctx) 97 sdkCtx.EventManager().EmitEvent( 98 sdk.NewEvent( 99 types.EventTypeCommission, 100 sdk.NewAttribute(sdk.AttributeKeyAmount, commission.String()), 101 sdk.NewAttribute(types.AttributeKeyValidator, val.GetOperator()), 102 ), 103 ) 104 currentCommission, err := k.GetValidatorAccumulatedCommission(ctx, valBz) 105 if err != nil { 106 return err 107 } 108 109 currentCommission.Commission = currentCommission.Commission.Add(commission...) 110 err = k.SetValidatorAccumulatedCommission(ctx, valBz, currentCommission) 111 if err != nil { 112 return err 113 } 114 115 // update current rewards 116 currentRewards, err := k.GetValidatorCurrentRewards(ctx, valBz) 117 if err != nil { 118 return err 119 } 120 121 currentRewards.Rewards = currentRewards.Rewards.Add(shared...) 122 err = k.SetValidatorCurrentRewards(ctx, valBz, currentRewards) 123 if err != nil { 124 return err 125 } 126 127 // update outstanding rewards 128 sdkCtx.EventManager().EmitEvent( 129 sdk.NewEvent( 130 types.EventTypeRewards, 131 sdk.NewAttribute(sdk.AttributeKeyAmount, tokens.String()), 132 sdk.NewAttribute(types.AttributeKeyValidator, val.GetOperator()), 133 ), 134 ) 135 136 outstanding, err := k.GetValidatorOutstandingRewards(ctx, valBz) 137 if err != nil { 138 return err 139 } 140 141 outstanding.Rewards = outstanding.Rewards.Add(tokens...) 142 return k.SetValidatorOutstandingRewards(ctx, valBz, outstanding) 143 }