Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion x/distribution/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func NewCommunityPoolSpendProposalHandler(k Keeper) govtypes.Handler {
return keeper.HandleCommunityPoolSpendProposal(ctx, k, c)

default:
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized distr proposal content type: %T", c)
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s proposal content type: %T", types.ModuleName, c)
}
}
}
36 changes: 30 additions & 6 deletions x/distribution/keeper/allocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,24 +77,48 @@ func (k Keeper) AllocateTokens(
previousProposer.String()))
}

// calculate fraction allocated to validators
communityTax := k.GetCommunityTax(ctx)
voteMultiplier := sdk.OneDec().Sub(proposerMultiplier).Sub(communityTax)

// allocate tokens proportionally to voting power
// TODO consider parallelizing later, ref https://github.com/enigmampc/cosmos-sdk/pull/3099#discussion_r246276376
foundationTax := k.GetSecretFoundationTax(ctx)
foundationTaxAddr := k.GetSecretFoundationAddr(ctx)

// only apply the secret foundation tax when the tax and address is non-zero
var foundationTaxSum sdk.DecCoins
if !foundationTax.IsZero() && !foundationTaxAddr.Empty() {
voteMultiplier = voteMultiplier.Sub(foundationTax)

foundationTaxSum = feesCollected.MulDecTruncate(foundationTax)
remaining = remaining.Sub(foundationTaxSum)
}

// allocate tokens proportionally to voting power minus any taxes
for _, vote := range previousVotes {
validator := k.stakingKeeper.ValidatorByConsAddr(ctx, vote.Validator.Address)

// TODO consider microslashing for missing votes.
// ref https://github.com/enigmampc/cosmos-sdk/issues/2525#issuecomment-430838701
powerFraction := sdk.NewDec(vote.Validator.Power).QuoTruncate(sdk.NewDec(totalPreviousPower))
reward := feesCollected.MulDecTruncate(voteMultiplier).MulDecTruncate(powerFraction)

// allocate tokens to the validator
k.AllocateTokensToValidator(ctx, validator, reward)

// update the remaining allocation for the community pool
remaining = remaining.Sub(reward)
}

// allocate community funding
// Send the foundation tax sum to the foundation tax address. Note, the taxes
// collected are decimals and when coverted to integer coins, we must truncate.
// The remainder is given back to the community pool.
if !foundationTaxSum.IsZero() {
foundationTaxSumTrunc, rem := foundationTaxSum.TruncateDecimal()
remaining = remaining.Add(rem...)

if err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, foundationTaxAddr, foundationTaxSumTrunc); err != nil {
panic(err)
}
}

// allocate community funding minus the foundation tax
feePool.CommunityPool = feePool.CommunityPool.Add(remaining...)
k.SetFeePool(ctx, feePool)
}
Expand Down
12 changes: 12 additions & 0 deletions x/distribution/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,15 @@ func (k Keeper) GetWithdrawAddrEnabled(ctx sdk.Context) (enabled bool) {
k.paramSpace.Get(ctx, types.ParamStoreKeyWithdrawAddrEnabled, &enabled)
return enabled
}

// GetSecretFoundationTax returns the current secret foundation tax.
func (k Keeper) GetSecretFoundationTax(ctx sdk.Context) (tax sdk.Dec) {
k.paramSpace.Get(ctx, types.ParamSecretFoundationTax, &tax)
return tax
}

// GetSecretFoundationAddr returns the current secret foundation address.
func (k Keeper) GetSecretFoundationAddr(ctx sdk.Context) (addr sdk.AccAddress) {
k.paramSpace.Get(ctx, types.ParamSecretFoundationAddress, &addr)
return addr
}
25 changes: 21 additions & 4 deletions x/distribution/simulation/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
sdk "github.com/enigmampc/cosmos-sdk/types"
"github.com/enigmampc/cosmos-sdk/types/module"
"github.com/enigmampc/cosmos-sdk/x/distribution/types"
"github.com/enigmampc/cosmos-sdk/x/simulation"
)

// Simulation parameter constants
Expand All @@ -19,6 +20,7 @@ const (
BaseProposerReward = "base_proposer_reward"
BonusProposerReward = "bonus_proposer_reward"
WithdrawEnabled = "withdraw_enabled"
FoundationTax = "foundation_tax"
)

// GenCommunityTax randomized CommunityTax
Expand All @@ -41,6 +43,11 @@ func GenWithdrawEnabled(r *rand.Rand) bool {
return r.Int63n(101) <= 95 // 95% chance of withdraws being enabled
}

// GenSecretFoundationTax returns a randomized secret foundation tax parameter.
func GenSecretFoundationTax(r *rand.Rand) sdk.Dec {
return sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(int64(r.Intn(30)), 2))
}

// RandomizedGenState generates a random GenesisState for distribution
func RandomizedGenState(simState *module.SimulationState) {
var communityTax sdk.Dec
Expand All @@ -67,13 +74,23 @@ func RandomizedGenState(simState *module.SimulationState) {
func(r *rand.Rand) { withdrawEnabled = GenWithdrawEnabled(r) },
)

var foundationTax sdk.Dec
simState.AppParams.GetOrGenerate(
simState.Cdc, FoundationTax, &foundationTax, simState.Rand,
func(r *rand.Rand) { foundationTax = GenSecretFoundationTax(r) },
)

foundationTaxAcc, _ := simulation.RandomAcc(simState.Rand, simState.Accounts)

distrGenesis := types.GenesisState{
FeePool: types.InitialFeePool(),
Params: types.Params{
CommunityTax: communityTax,
BaseProposerReward: baseProposerReward,
BonusProposerReward: bonusProposerReward,
WithdrawAddrEnabled: withdrawEnabled,
CommunityTax: communityTax,
SecretFoundationTax: foundationTax,
SecretFoundationAddress: foundationTaxAcc.Address,
BaseProposerReward: baseProposerReward,
BonusProposerReward: bonusProposerReward,
WithdrawAddrEnabled: withdrawEnabled,
},
}

Expand Down
10 changes: 8 additions & 2 deletions x/distribution/simulation/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,23 @@ const (
keyCommunityTax = "communitytax"
keyBaseProposerReward = "baseproposerreward"
keyBonusProposerReward = "bonusproposerreward"
keySecretFoundationTax = "secretfoundationtax"
)

// ParamChanges defines the parameters that can be modified by param change proposals
// on the simulation
// ParamChanges defines the parameters that can be modified by param change
// proposals in simulations.
func ParamChanges(r *rand.Rand) []simulation.ParamChange {
return []simulation.ParamChange{
simulation.NewSimParamChange(types.ModuleName, keyCommunityTax,
func(r *rand.Rand) string {
return fmt.Sprintf("\"%s\"", GenCommunityTax(r))
},
),
simulation.NewSimParamChange(types.ModuleName, keySecretFoundationTax,
func(r *rand.Rand) string {
return fmt.Sprintf("\"%s\"", GenSecretFoundationTax(r))
},
),
simulation.NewSimParamChange(types.ModuleName, keyBaseProposerReward,
func(r *rand.Rand) string {
return fmt.Sprintf("\"%s\"", GenBaseProposerReward(r))
Expand Down
13 changes: 10 additions & 3 deletions x/distribution/types/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,16 @@ type GenesisState struct {
}

func NewGenesisState(
params Params, fp FeePool, dwis []DelegatorWithdrawInfo, pp sdk.ConsAddress, r []ValidatorOutstandingRewardsRecord,
acc []ValidatorAccumulatedCommissionRecord, historical []ValidatorHistoricalRewardsRecord,
cur []ValidatorCurrentRewardsRecord, dels []DelegatorStartingInfoRecord, slashes []ValidatorSlashEventRecord,
params Params,
fp FeePool,
dwis []DelegatorWithdrawInfo,
pp sdk.ConsAddress,
r []ValidatorOutstandingRewardsRecord,
acc []ValidatorAccumulatedCommissionRecord,
historical []ValidatorHistoricalRewardsRecord,
cur []ValidatorCurrentRewardsRecord,
dels []DelegatorStartingInfoRecord,
slashes []ValidatorSlashEventRecord,
) GenesisState {

return GenesisState{
Expand Down
61 changes: 53 additions & 8 deletions x/distribution/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ var (
ParamStoreKeyBaseProposerReward = []byte("baseproposerreward")
ParamStoreKeyBonusProposerReward = []byte("bonusproposerreward")
ParamStoreKeyWithdrawAddrEnabled = []byte("withdrawaddrenabled")
ParamSecretFoundationTax = []byte("secretfoundationtax")
ParamSecretFoundationAddress = []byte("secretfoundationaddress")
)

// Params defines the set of distribution parameters.
type Params struct {
CommunityTax sdk.Dec `json:"community_tax" yaml:"community_tax"`
BaseProposerReward sdk.Dec `json:"base_proposer_reward" yaml:"base_proposer_reward"`
BonusProposerReward sdk.Dec `json:"bonus_proposer_reward" yaml:"bonus_proposer_reward"`
WithdrawAddrEnabled bool `json:"withdraw_addr_enabled" yaml:"withdraw_addr_enabled"`
CommunityTax sdk.Dec `json:"community_tax" yaml:"community_tax"`
BaseProposerReward sdk.Dec `json:"base_proposer_reward" yaml:"base_proposer_reward"`
BonusProposerReward sdk.Dec `json:"bonus_proposer_reward" yaml:"bonus_proposer_reward"`
WithdrawAddrEnabled bool `json:"withdraw_addr_enabled" yaml:"withdraw_addr_enabled"`
SecretFoundationTax sdk.Dec `json:"secret_foundation_tax" yaml:"secret_foundation_tax"`
SecretFoundationAddress sdk.AccAddress `json:"secret_foundation_address" yaml:"secret_foundation_address"`
}

// ParamKeyTable returns the parameter key table.
Expand All @@ -38,10 +42,12 @@ func ParamKeyTable() params.KeyTable {
// DefaultParams returns default distribution parameters
func DefaultParams() Params {
return Params{
CommunityTax: sdk.NewDecWithPrec(2, 2), // 2%
BaseProposerReward: sdk.NewDecWithPrec(1, 2), // 1%
BonusProposerReward: sdk.NewDecWithPrec(4, 2), // 4%
WithdrawAddrEnabled: true,
CommunityTax: sdk.NewDecWithPrec(2, 2), // 2%
SecretFoundationTax: sdk.ZeroDec(), // 0%
SecretFoundationAddress: sdk.AccAddress{},
BaseProposerReward: sdk.NewDecWithPrec(1, 2), // 1%
BonusProposerReward: sdk.NewDecWithPrec(4, 2), // 4%
WithdrawAddrEnabled: true,
}
}

Expand All @@ -57,6 +63,8 @@ func (p *Params) ParamSetPairs() params.ParamSetPairs {
params.NewParamSetPair(ParamStoreKeyBaseProposerReward, &p.BaseProposerReward, validateBaseProposerReward),
params.NewParamSetPair(ParamStoreKeyBonusProposerReward, &p.BonusProposerReward, validateBonusProposerReward),
params.NewParamSetPair(ParamStoreKeyWithdrawAddrEnabled, &p.WithdrawAddrEnabled, validateWithdrawAddrEnabled),
params.NewParamSetPair(ParamSecretFoundationTax, &p.SecretFoundationTax, validateSecretFoundationTax),
params.NewParamSetPair(ParamSecretFoundationAddress, &p.SecretFoundationAddress, validateSecretFoundationAddress),
}
}

Expand All @@ -67,6 +75,11 @@ func (p Params) ValidateBasic() error {
"community tax should non-negative and less than one: %s", p.CommunityTax,
)
}
if p.SecretFoundationTax.IsNegative() || p.SecretFoundationTax.GT(sdk.OneDec()) {
return fmt.Errorf(
"secret foundation tax should non-negative and less than one: %s", p.SecretFoundationTax,
)
}
if p.BaseProposerReward.IsNegative() {
return fmt.Errorf(
"base proposer reward should be positive: %s", p.BaseProposerReward,
Expand Down Expand Up @@ -105,6 +118,38 @@ func validateCommunityTax(i interface{}) error {
return nil
}

func validateSecretFoundationTax(i interface{}) error {
v, ok := i.(sdk.Dec)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}

if v.IsNil() {
return fmt.Errorf("secret foundation tax must be not nil")
}
if v.IsNegative() {
return fmt.Errorf("secret foundation tax must be positive: %s", v)
}
if v.GT(sdk.OneDec()) {
return fmt.Errorf("secret foundation tax too large: %s", v)
}

return nil
}

func validateSecretFoundationAddress(i interface{}) error {
v, ok := i.(sdk.AccAddress)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}

if !v.Empty() {
return sdk.VerifyAddressFormat(v)
}

return nil
}

func validateBaseProposerReward(i interface{}) error {
v, ok := i.(sdk.Dec)
if !ok {
Expand Down