## 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)
182 lines
5.6 KiB
Go
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
|
|
}
|