Skip to content

Commit

Permalink
Merge PR cosmos#5384: Fund Community Pool -- Part II
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored and xiangjianmeng committed Dec 18, 2019
1 parent 5b30343 commit e3f1331
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 26 deletions.
1 change: 1 addition & 0 deletions simapp/params/weights.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const (
DefaultWeightMsgSetWithdrawAddress int = 50
DefaultWeightMsgWithdrawDelegationReward int = 50
DefaultWeightMsgWithdrawValidatorCommission int = 50
DefaultWeightMsgFundCommunityPool int = 50
DefaultWeightMsgDeposit int = 100
DefaultWeightMsgVote int = 67
DefaultWeightMsgUnjail int = 100
Expand Down
2 changes: 2 additions & 0 deletions x/distribution/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (
ParamBaseProposerReward = types.ParamBaseProposerReward
ParamBonusProposerReward = types.ParamBonusProposerReward
ParamWithdrawAddrEnabled = types.ParamWithdrawAddrEnabled
TypeMsgFundCommunityPool = types.TypeMsgFundCommunityPool
)

var (
Expand Down Expand Up @@ -90,6 +91,7 @@ var (
NewMsgSetWithdrawAddress = types.NewMsgSetWithdrawAddress
NewMsgWithdrawDelegatorReward = types.NewMsgWithdrawDelegatorReward
NewMsgWithdrawValidatorCommission = types.NewMsgWithdrawValidatorCommission
MsgFundCommunityPool = types.NewMsgFundCommunityPool
NewCommunityPoolSpendProposal = types.NewCommunityPoolSpendProposal
NewQueryValidatorOutstandingRewardsParams = types.NewQueryValidatorOutstandingRewardsParams
NewQueryValidatorCommissionParams = types.NewQueryValidatorCommissionParams
Expand Down
11 changes: 8 additions & 3 deletions x/distribution/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,12 +261,13 @@ Where proposal.json contains:
return cmd
}

// command to fund the community pool
// GetCmdFundCommunityPool returns a command implementation that supports directly
// funding the community pool.
func GetCmdFundCommunityPool(cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "fund-community-pool [amount]",
Args: cobra.ExactArgs(1),
Short: "funds the community pool with the specified amount",
Short: "Funds the community pool with the specified amount",
Long: strings.TrimSpace(
fmt.Sprintf(`Funds the community pool with the specified amount
Expand All @@ -287,7 +288,11 @@ $ %s tx fund-community-pool 100uatom --from mykey
return err
}

msg := types.NewMsgDepositIntoCommunityPool(amount, depositorAddr)
msg := types.NewMsgFundCommunityPool(amount, depositorAddr)
if err := msg.ValidateBasic(); err != nil {
return err
}

return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
Expand Down
8 changes: 6 additions & 2 deletions x/distribution/client/rest/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ func withdrawValidatorRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFu
}
}

// Fund the community pool
func fundCommunityPoolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req fundCommunityPoolReq
Expand All @@ -207,7 +206,12 @@ func fundCommunityPoolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}

msg := types.NewMsgDepositIntoCommunityPool(req.Amount, fromAddr)
msg := types.NewMsgFundCommunityPool(req.Amount, fromAddr)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}

utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}
Expand Down
8 changes: 4 additions & 4 deletions x/distribution/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
case types.MsgWithdrawValidatorCommission:
return handleMsgWithdrawValidatorCommission(ctx, msg, k)

case types.MsgDepositIntoCommunityPool:
return handleMsgDepositIntoCommunityPool(ctx, msg, k)
case types.MsgFundCommunityPool:
return handleMsgFundCommunityPool(ctx, msg, k)

default:
errMsg := fmt.Sprintf("unrecognized distribution message type: %T", msg)
Expand Down Expand Up @@ -86,8 +86,8 @@ func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdraw
return sdk.Result{Events: ctx.EventManager().Events()}
}

func handleMsgDepositIntoCommunityPool(ctx sdk.Context, msg types.MsgDepositIntoCommunityPool, k keeper.Keeper) sdk.Result {
if err := k.DepositCommunityPoolFunds(ctx, msg.Amount, msg.Depositor); err != nil {
func handleMsgFundCommunityPool(ctx sdk.Context, msg types.MsgFundCommunityPool, k keeper.Keeper) sdk.Result {
if err := k.FundCommunityPool(ctx, msg.Amount, msg.Depositor); err != nil {
return sdk.ResultFromError(err)
}

Expand Down
7 changes: 5 additions & 2 deletions x/distribution/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,11 @@ func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) {
return totalRewards
}

// DepositCommunityPoolFunds allows to transfer the specified amount from the sender into the community pool
func (k Keeper) DepositCommunityPoolFunds(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error {
// 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.supplyKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions x/distribution/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func TestGetTotalRewards(t *testing.T) {
require.Equal(t, expectedRewards, totalRewards)
}

func TestDepositCommunityPoolFunds(t *testing.T) {
func TestFundCommunityPool(t *testing.T) {
// nolint dogsled
ctx, _, bk, keeper, _, _, _ := CreateTestInputAdvanced(t, false, 1000, sdk.NewDecWithPrec(2, 2))

Expand All @@ -102,7 +102,7 @@ func TestDepositCommunityPoolFunds(t *testing.T) {
initPool := keeper.GetFeePool(ctx)
assert.Empty(t, initPool.CommunityPool)

err := keeper.DepositCommunityPoolFunds(ctx, amount, delAddr1)
err := keeper.FundCommunityPool(ctx, amount, delAddr1)
assert.Nil(t, err)

assert.Equal(t, initPool.CommunityPool.Add(sdk.NewDecCoins(amount)), keeper.GetFeePool(ctx).CommunityPool)
Expand Down
61 changes: 61 additions & 0 deletions x/distribution/simulation/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address"
OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward"
OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission"
OpWeightMsgFundCommunityPool = "op_weight_msg_fund_community_pool"
)

// WeightedOperations returns all the operations from the module with their respective weights
Expand Down Expand Up @@ -50,6 +51,13 @@ func WeightedOperations(
},
)

var weightMsgFundCommunityPool int
appParams.GetOrGenerate(cdc, OpWeightMsgFundCommunityPool, &weightMsgFundCommunityPool, nil,
func(_ *rand.Rand) {
weightMsgFundCommunityPool = simappparams.DefaultWeightMsgFundCommunityPool
},
)

return simulation.WeightedOperations{
simulation.NewWeightedOperation(
weightMsgSetWithdrawAddress,
Expand All @@ -63,6 +71,10 @@ func WeightedOperations(
weightMsgWithdrawValidatorCommission,
SimulateMsgWithdrawValidatorCommission(ak, k, sk),
),
simulation.NewWeightedOperation(
weightMsgFundCommunityPool,
SimulateMsgFundCommunityPool(ak, k, sk),
),
}
}

Expand Down Expand Up @@ -197,3 +209,52 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee
return simulation.NewOperationMsg(msg, true, ""), nil, nil
}
}

// SimulateMsgFundCommunityPool simulates MsgFundCommunityPool execution where
// a random account sends a random amount of its funds to the community pool.
func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string,
) (simulation.OperationMsg, []simulation.FutureOperation, error) {

funder, _ := simulation.RandomAcc(r, accs)

account := ak.GetAccount(ctx, funder.Address)
coins := account.SpendableCoins(ctx.BlockTime())

fundAmount := simulation.RandSubsetCoins(r, coins)
if fundAmount.Empty() {
return simulation.NoOpMsg(types.ModuleName), nil, nil
}

var (
fees sdk.Coins
err error
)

coins, hasNeg := coins.SafeSub(fundAmount)
if !hasNeg {
fees, err = simulation.RandomFees(r, ctx, coins)
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
}

msg := types.NewMsgFundCommunityPool(fundAmount, funder.Address)
tx := helpers.GenTx(
[]sdk.Msg{msg},
fees,
chainID,
[]uint64{account.GetAccountNumber()},
[]uint64{account.GetSequence()},
funder.PrivKey,
)

res := app.Deliver(tx)
if !res.IsOK() {
return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log)
}

return simulation.NewOperationMsg(msg, true, ""), nil, nil
}
}
35 changes: 23 additions & 12 deletions x/distribution/types/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,40 +117,51 @@ func (msg MsgWithdrawValidatorCommission) ValidateBasic() sdk.Error {
return nil
}

// msg struct for delegation withdraw from a single validator
type MsgDepositIntoCommunityPool struct {
const TypeMsgFundCommunityPool = "fund_community_pool"

// MsgFundCommunityPool defines a Msg type that allows an account to directly
// fund the community pool.
type MsgFundCommunityPool struct {
Amount sdk.Coins `json:"amount" yaml:"amount"`
Depositor sdk.AccAddress `json:"depositor" yaml:"depositor"`
}

func NewMsgDepositIntoCommunityPool(amount sdk.Coins, depositor sdk.AccAddress) MsgDepositIntoCommunityPool {
return MsgDepositIntoCommunityPool{
// NewMsgFundCommunityPool returns a new MsgFundCommunityPool with a sender and
// a funding amount.
func NewMsgFundCommunityPool(amount sdk.Coins, depositor sdk.AccAddress) MsgFundCommunityPool {
return MsgFundCommunityPool{
Amount: amount,
Depositor: depositor,
}
}

func (msg MsgDepositIntoCommunityPool) Route() string { return ModuleName }
func (msg MsgDepositIntoCommunityPool) Type() string { return "deposit_into_community_pool" }
// Route returns the MsgFundCommunityPool message route.
func (msg MsgFundCommunityPool) Route() string { return ModuleName }

// Return address that must sign over msg.GetSignBytes()
func (msg MsgDepositIntoCommunityPool) GetSigners() []sdk.AccAddress {
// Type returns the MsgFundCommunityPool message type.
func (msg MsgFundCommunityPool) Type() string { return TypeMsgFundCommunityPool }

// GetSigners returns the signer addresses that are expected to sign the result
// of GetSignBytes.
func (msg MsgFundCommunityPool) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{msg.Depositor}
}

// get the bytes for the message signer to sign on
func (msg MsgDepositIntoCommunityPool) GetSignBytes() []byte {
// GetSignBytes returns the raw bytes for a MsgFundCommunityPool message that
// the expected signer needs to sign.
func (msg MsgFundCommunityPool) GetSignBytes() []byte {
bz := ModuleCdc.MustMarshalJSON(msg)
return sdk.MustSortJSON(bz)
}

// quick validity check
func (msg MsgDepositIntoCommunityPool) ValidateBasic() sdk.Error {
// ValidateBasic performs basic MsgFundCommunityPool message validation.
func (msg MsgFundCommunityPool) ValidateBasic() sdk.Error {
if !msg.Amount.IsValid() {
return sdk.ErrInvalidCoins(msg.Amount.String())
}
if msg.Depositor.Empty() {
return sdk.ErrInvalidAddress(msg.Depositor.String())
}

return nil
}
2 changes: 1 addition & 1 deletion x/distribution/types/msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func TestMsgDepositIntoCommunityPool(t *testing.T) {
{sdk.NewCoins(sdk.NewInt64Coin("uatom", 1000)), delAddr1, true},
}
for i, tc := range tests {
msg := NewMsgDepositIntoCommunityPool(tc.amount, tc.depositor)
msg := NewMsgFundCommunityPool(tc.amount, tc.depositor)
if tc.expectPass {
require.Nil(t, msg.ValidateBasic(), "test index: %v", i)
} else {
Expand Down

0 comments on commit e3f1331

Please sign in to comment.