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  }