cosmos-sdk/x/distribution/keeper/keeper.go
Marko 4674c88bb3
refactor: reuse bank blocked addrs list (#10816)
## Description

Reuse bank blocked address instead of passing it to distribution. Right now we are passing the same value to bank and distribution, it doesn't seem like it has any extra benefit?

---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
2021-12-23 10:17:50 +00:00

182 lines
5.6 KiB
Go

package keeper
import (
"fmt"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
)
// Keeper of the distribution store
type Keeper struct {
storeKey storetypes.StoreKey
cdc codec.BinaryCodec
paramSpace paramtypes.Subspace
authKeeper types.AccountKeeper
bankKeeper types.BankKeeper
stakingKeeper types.StakingKeeper
feeCollectorName string // name of the FeeCollector ModuleAccount
}
// NewKeeper creates a new distribution Keeper instance
func NewKeeper(
cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace,
ak types.AccountKeeper, bk types.BankKeeper, sk types.StakingKeeper,
feeCollectorName string,
) Keeper {
// ensure distribution module account is set
if addr := ak.GetModuleAddress(types.ModuleName); addr == nil {
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
}
// set KeyTable if it has not already been set
if !paramSpace.HasKeyTable() {
paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
}
return Keeper{
storeKey: key,
cdc: cdc,
paramSpace: paramSpace,
authKeeper: ak,
bankKeeper: bk,
stakingKeeper: sk,
feeCollectorName: feeCollectorName,
}
}
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", "x/"+types.ModuleName)
}
// SetWithdrawAddr sets a new address that will receive the rewards upon withdrawal
func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error {
if k.bankKeeper.BlockedAddr(withdrawAddr) {
return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive external funds", withdrawAddr)
}
if !k.GetWithdrawAddrEnabled(ctx) {
return types.ErrSetWithdrawAddrDisabled
}
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeSetWithdrawAddress,
sdk.NewAttribute(types.AttributeKeyWithdrawAddress, withdrawAddr.String()),
),
)
k.SetDelegatorWithdrawAddr(ctx, delegatorAddr, withdrawAddr)
return nil
}
// withdraw rewards from a delegation
func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) {
val := k.stakingKeeper.Validator(ctx, valAddr)
if val == nil {
return nil, types.ErrNoValidatorDistInfo
}
del := k.stakingKeeper.Delegation(ctx, delAddr, valAddr)
if del == nil {
return nil, types.ErrEmptyDelegationDistInfo
}
// withdraw rewards
rewards, err := k.withdrawDelegationRewards(ctx, val, del)
if err != nil {
return nil, err
}
if rewards.IsZero() {
baseDenom, _ := sdk.GetBaseDenom()
rewards = sdk.Coins{sdk.Coin{
Denom: baseDenom,
Amount: sdk.ZeroInt(),
}}
}
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeWithdrawRewards,
sdk.NewAttribute(sdk.AttributeKeyAmount, rewards.String()),
sdk.NewAttribute(types.AttributeKeyValidator, valAddr.String()),
),
)
// reinitialize the delegation
k.initializeDelegation(ctx, valAddr, delAddr)
return rewards, nil
}
// withdraw validator commission
func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddress) (sdk.Coins, error) {
// fetch validator accumulated commission
accumCommission := k.GetValidatorAccumulatedCommission(ctx, valAddr)
if accumCommission.Commission.IsZero() {
return nil, types.ErrNoValidatorCommission
}
commission, remainder := accumCommission.Commission.TruncateDecimal()
k.SetValidatorAccumulatedCommission(ctx, valAddr, types.ValidatorAccumulatedCommission{Commission: remainder}) // leave remainder to withdraw later
// update outstanding
outstanding := k.GetValidatorOutstandingRewards(ctx, valAddr).Rewards
k.SetValidatorOutstandingRewards(ctx, valAddr, types.ValidatorOutstandingRewards{Rewards: outstanding.Sub(sdk.NewDecCoinsFromCoins(commission...))})
if !commission.IsZero() {
accAddr := sdk.AccAddress(valAddr)
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, accAddr)
err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, withdrawAddr, commission)
if err != nil {
return nil, err
}
}
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeWithdrawCommission,
sdk.NewAttribute(sdk.AttributeKeyAmount, commission.String()),
),
)
return commission, nil
}
// GetTotalRewards returns the total amount of fee distribution rewards held in the store
func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) {
k.IterateValidatorOutstandingRewards(ctx,
func(_ sdk.ValAddress, rewards types.ValidatorOutstandingRewards) (stop bool) {
totalRewards = totalRewards.Add(rewards.Rewards...)
return false
},
)
return totalRewards
}
// FundCommunityPool allows an account to directly fund the community fund pool.
// The amount is first added to the distribution module account and then directly
// added to the pool. An error is returned if the amount cannot be sent to the
// module account.
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
}