github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/distribution/keeper/keeper.go (about) 1 package keeper 2 3 import ( 4 "fmt" 5 6 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 7 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 8 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 9 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/distribution/types" 10 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/params" 11 12 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 13 ) 14 15 // Keeper of the distribution store 16 type Keeper struct { 17 storeKey sdk.StoreKey 18 cdc *codec.Codec 19 paramSpace params.Subspace 20 stakingKeeper types.StakingKeeper 21 supplyKeeper types.SupplyKeeper 22 23 blacklistedAddrs map[string]bool 24 25 feeCollectorName string // name of the FeeCollector ModuleAccount 26 } 27 28 // NewKeeper creates a new distribution Keeper instance 29 func NewKeeper( 30 cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, 31 sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, 32 blacklistedAddrs map[string]bool, 33 ) Keeper { 34 35 // ensure distribution module account is set 36 if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil { 37 panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) 38 } 39 40 // set KeyTable if it has not already been set 41 if !paramSpace.HasKeyTable() { 42 paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) 43 } 44 45 return Keeper{ 46 storeKey: key, 47 cdc: cdc, 48 paramSpace: paramSpace, 49 stakingKeeper: sk, 50 supplyKeeper: supplyKeeper, 51 feeCollectorName: feeCollectorName, 52 blacklistedAddrs: blacklistedAddrs, 53 } 54 } 55 56 // Logger returns a module-specific logger. 57 func (k Keeper) Logger(ctx sdk.Context) log.Logger { 58 return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) 59 } 60 61 // SetWithdrawAddr sets a new address that will receive the rewards upon withdrawal 62 func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error { 63 if k.blacklistedAddrs[withdrawAddr.String()] { 64 return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is blacklisted from receiving external funds", withdrawAddr) 65 } 66 67 if !k.GetWithdrawAddrEnabled(ctx) { 68 return types.ErrSetWithdrawAddrDisabled 69 } 70 71 ctx.EventManager().EmitEvent( 72 sdk.NewEvent( 73 types.EventTypeSetWithdrawAddress, 74 sdk.NewAttribute(types.AttributeKeyWithdrawAddress, withdrawAddr.String()), 75 ), 76 ) 77 78 k.SetDelegatorWithdrawAddr(ctx, delegatorAddr, withdrawAddr) 79 return nil 80 } 81 82 // withdraw rewards from a delegation 83 func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) { 84 val := k.stakingKeeper.Validator(ctx, valAddr) 85 if val == nil { 86 return nil, types.ErrNoValidatorDistInfo 87 } 88 89 del := k.stakingKeeper.Delegation(ctx, delAddr, valAddr) 90 if del == nil { 91 return nil, types.ErrEmptyDelegationDistInfo 92 } 93 94 // withdraw rewards 95 rewards, err := k.withdrawDelegationRewards(ctx, val, del) 96 if err != nil { 97 return nil, err 98 } 99 100 ctx.EventManager().EmitEvent( 101 sdk.NewEvent( 102 types.EventTypeWithdrawRewards, 103 sdk.NewAttribute(sdk.AttributeKeyAmount, rewards.String()), 104 sdk.NewAttribute(types.AttributeKeyValidator, valAddr.String()), 105 ), 106 ) 107 108 // reinitialize the delegation 109 k.initializeDelegation(ctx, valAddr, delAddr) 110 return rewards, nil 111 } 112 113 // withdraw validator commission 114 func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddress) (sdk.Coins, error) { 115 // fetch validator accumulated commission 116 accumCommission := k.GetValidatorAccumulatedCommission(ctx, valAddr) 117 if accumCommission.IsZero() { 118 return nil, types.ErrNoValidatorCommission 119 } 120 121 commission, remainder := accumCommission.TruncateDecimal() 122 k.SetValidatorAccumulatedCommission(ctx, valAddr, remainder) // leave remainder to withdraw later 123 124 if !commission.IsZero() { 125 accAddr := sdk.AccAddress(valAddr) 126 withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, accAddr) 127 err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, withdrawAddr, commission) 128 if err != nil { 129 return nil, err 130 } 131 } 132 133 ctx.EventManager().EmitEvent( 134 sdk.NewEvent( 135 types.EventTypeWithdrawCommission, 136 sdk.NewAttribute(sdk.AttributeKeyAmount, commission.String()), 137 ), 138 ) 139 140 return commission, nil 141 } 142 143 // GetTotalRewards returns the total amount of fee distribution rewards held in the store 144 func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) { 145 k.IterateValidatorOutstandingRewards(ctx, 146 func(_ sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) { 147 totalRewards = totalRewards.Add(rewards...) 148 return false 149 }, 150 ) 151 152 return totalRewards 153 } 154 155 // FundCommunityPool allows an account to directly fund the community fund pool. 156 // The amount is first added to the distribution module account and then directly 157 // added to the pool. An error is returned if the amount cannot be sent to the 158 // module account. 159 func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error { 160 if err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil { 161 return err 162 } 163 164 feePool := k.GetFeePool(ctx) 165 feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...) 166 k.SetFeePool(ctx, feePool) 167 168 return nil 169 }