2018-09-03 17:46:33 -07:00
|
|
|
package keeper
|
2018-09-04 13:19:37 -07:00
|
|
|
|
|
|
|
import (
|
2019-06-26 09:41:14 -07:00
|
|
|
"fmt"
|
|
|
|
|
2018-09-19 16:00:21 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
2018-09-04 13:19:37 -07:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
"github.com/cosmos/cosmos-sdk/x/distribution/types"
|
2018-09-18 21:42:05 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/params"
|
2019-04-15 20:58:06 -07:00
|
|
|
|
|
|
|
"github.com/tendermint/tendermint/libs/log"
|
2018-09-18 21:42:05 -07:00
|
|
|
)
|
|
|
|
|
2019-06-28 13:11:27 -07:00
|
|
|
// Keeper of the distribution store
|
2018-09-04 13:19:37 -07:00
|
|
|
type Keeper struct {
|
2019-06-28 13:11:27 -07:00
|
|
|
storeKey sdk.StoreKey
|
|
|
|
cdc *codec.Codec
|
|
|
|
paramSpace params.Subspace
|
|
|
|
stakingKeeper types.StakingKeeper
|
|
|
|
supplyKeeper types.SupplyKeeper
|
2018-09-04 13:19:37 -07:00
|
|
|
|
|
|
|
// codespace
|
|
|
|
codespace sdk.CodespaceType
|
2019-06-28 13:11:27 -07:00
|
|
|
|
|
|
|
feeCollectorName string // name of the FeeCollector ModuleAccount
|
2018-09-04 13:19:37 -07:00
|
|
|
}
|
|
|
|
|
2019-06-28 13:11:27 -07:00
|
|
|
// NewKeeper creates a new distribution Keeper instance
|
|
|
|
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace,
|
|
|
|
sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, codespace sdk.CodespaceType,
|
|
|
|
feeCollectorName string) Keeper {
|
|
|
|
|
|
|
|
// ensure distribution module account is set
|
|
|
|
if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil {
|
|
|
|
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
|
|
|
|
}
|
|
|
|
|
|
|
|
return Keeper{
|
|
|
|
storeKey: key,
|
|
|
|
cdc: cdc,
|
|
|
|
paramSpace: paramSpace.WithKeyTable(ParamKeyTable()),
|
|
|
|
stakingKeeper: sk,
|
|
|
|
supplyKeeper: supplyKeeper,
|
|
|
|
codespace: codespace,
|
|
|
|
feeCollectorName: feeCollectorName,
|
2018-09-04 13:19:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-15 20:58:06 -07:00
|
|
|
// Logger returns a module-specific logger.
|
2019-06-26 09:41:14 -07:00
|
|
|
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
|
|
|
|
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
|
|
|
|
}
|
2019-04-15 20:58:06 -07:00
|
|
|
|
2019-01-16 14:17:56 -08:00
|
|
|
// set withdraw address
|
|
|
|
func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) sdk.Error {
|
|
|
|
if !k.GetWithdrawAddrEnabled(ctx) {
|
|
|
|
return types.ErrSetWithdrawAddrDisabled(k.codespace)
|
|
|
|
}
|
|
|
|
|
2019-06-26 09:03:25 -07:00
|
|
|
ctx.EventManager().EmitEvent(
|
|
|
|
sdk.NewEvent(
|
|
|
|
types.EventTypeSetWithdrawAddress,
|
|
|
|
sdk.NewAttribute(types.AttributeKeyWithdrawAddress, withdrawAddr.String()),
|
|
|
|
),
|
|
|
|
)
|
2019-01-16 14:17:56 -08:00
|
|
|
|
2019-06-26 09:03:25 -07:00
|
|
|
k.SetDelegatorWithdrawAddr(ctx, delegatorAddr, withdrawAddr)
|
2019-01-16 14:17:56 -08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// withdraw rewards from a delegation
|
2019-04-26 16:11:45 -07:00
|
|
|
func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, sdk.Error) {
|
2019-01-16 13:38:05 -08:00
|
|
|
val := k.stakingKeeper.Validator(ctx, valAddr)
|
|
|
|
if val == nil {
|
2019-04-26 16:11:45 -07:00
|
|
|
return nil, types.ErrNoValidatorDistInfo(k.codespace)
|
2018-09-04 13:19:37 -07:00
|
|
|
}
|
2018-10-26 04:42:53 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
del := k.stakingKeeper.Delegation(ctx, delAddr, valAddr)
|
|
|
|
if del == nil {
|
2019-04-26 16:11:45 -07:00
|
|
|
return nil, types.ErrNoDelegationDistInfo(k.codespace)
|
2018-09-13 23:35:02 -07:00
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// withdraw rewards
|
2019-04-26 16:11:45 -07:00
|
|
|
rewards, err := k.withdrawDelegationRewards(ctx, val, del)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2019-01-16 13:38:05 -08:00
|
|
|
}
|
2018-10-26 04:42:53 -07:00
|
|
|
|
2019-06-26 09:03:25 -07:00
|
|
|
ctx.EventManager().EmitEvent(
|
|
|
|
sdk.NewEvent(
|
|
|
|
types.EventTypeWithdrawRewards,
|
2019-07-24 15:50:34 -07:00
|
|
|
sdk.NewAttribute(sdk.AttributeKeyAmount, rewards.String()),
|
2019-06-26 09:03:25 -07:00
|
|
|
sdk.NewAttribute(types.AttributeKeyValidator, valAddr.String()),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// reinitialize the delegation
|
|
|
|
k.initializeDelegation(ctx, valAddr, delAddr)
|
2019-04-26 16:11:45 -07:00
|
|
|
return rewards, nil
|
2018-10-26 04:42:53 -07:00
|
|
|
}
|
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// withdraw validator commission
|
2019-04-26 16:11:45 -07:00
|
|
|
func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddress) (sdk.Coins, sdk.Error) {
|
2019-01-16 13:38:05 -08:00
|
|
|
// fetch validator accumulated commission
|
2019-06-26 09:03:25 -07:00
|
|
|
accumCommission := k.GetValidatorAccumulatedCommission(ctx, valAddr)
|
|
|
|
if accumCommission.IsZero() {
|
2019-04-26 16:11:45 -07:00
|
|
|
return nil, types.ErrNoValidatorCommission(k.codespace)
|
2019-01-16 13:38:05 -08:00
|
|
|
}
|
2018-10-15 12:51:51 -07:00
|
|
|
|
2019-06-26 09:03:25 -07:00
|
|
|
commission, remainder := accumCommission.TruncateDecimal()
|
2019-03-12 08:10:20 -07:00
|
|
|
k.SetValidatorAccumulatedCommission(ctx, valAddr, remainder) // leave remainder to withdraw later
|
2018-10-15 13:12:42 -07:00
|
|
|
|
2019-01-16 13:38:05 -08:00
|
|
|
// update outstanding
|
2019-03-06 10:54:12 -08:00
|
|
|
outstanding := k.GetValidatorOutstandingRewards(ctx, valAddr)
|
2019-06-26 09:03:25 -07:00
|
|
|
k.SetValidatorOutstandingRewards(ctx, valAddr, outstanding.Sub(sdk.NewDecCoins(commission)))
|
2018-10-15 13:12:42 -07:00
|
|
|
|
2019-06-26 09:03:25 -07:00
|
|
|
if !commission.IsZero() {
|
2019-02-27 13:09:26 -08:00
|
|
|
accAddr := sdk.AccAddress(valAddr)
|
|
|
|
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, accAddr)
|
2019-06-28 13:11:27 -07:00
|
|
|
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, withdrawAddr, commission)
|
|
|
|
if err != nil {
|
2019-04-26 16:11:45 -07:00
|
|
|
return nil, err
|
2019-02-27 13:09:26 -08:00
|
|
|
}
|
2019-01-16 13:38:05 -08:00
|
|
|
}
|
2018-10-15 13:12:42 -07:00
|
|
|
|
2019-06-26 09:03:25 -07:00
|
|
|
ctx.EventManager().EmitEvent(
|
|
|
|
sdk.NewEvent(
|
|
|
|
types.EventTypeWithdrawCommission,
|
2019-07-24 15:50:34 -07:00
|
|
|
sdk.NewAttribute(sdk.AttributeKeyAmount, commission.String()),
|
2019-06-26 09:03:25 -07:00
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
return commission, nil
|
2018-09-18 21:42:05 -07:00
|
|
|
}
|
2019-06-28 13:11:27 -07:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
return false
|
|
|
|
},
|
|
|
|
)
|
|
|
|
return totalRewards
|
|
|
|
}
|