Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for sending funds to the community pool #5249

Merged
merged 27 commits into from
Dec 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d2569c7
Support for sending funds to the community pool
RiccardoM Oct 25, 2019
6929767
Added the REST and CLI txs
RiccardoM Oct 25, 2019
b6bfcab
Reverted back all the changes and edited the blacklisted address as s…
RiccardoM Oct 28, 2019
f4d74b2
Merge branch 'master' of github.com:cosmos/cosmos-sdk into community-…
RiccardoM Nov 13, 2019
f1da9ff
Improved how allowed receiving accounts are specified inside the app
RiccardoM Nov 13, 2019
8b0870c
Merge branch 'master' into community-pool-funding
RiccardoM Nov 13, 2019
8d54b1e
Merge branch 'master' into community-pool-funding
alexanderbez Nov 29, 2019
8cb3615
Merge remote-tracking branch 'origin/community-pool-funding' into com…
RiccardoM Nov 29, 2019
3ea2eef
Added the changelod entry
RiccardoM Nov 29, 2019
31a38a3
Removed custom msg and handler (leftover from first implementation)
RiccardoM Nov 29, 2019
72d3776
Removed custom msg and handler (leftover from first implementation)
RiccardoM Nov 29, 2019
161e861
Removed bank usage from the dist module
RiccardoM Nov 29, 2019
8a6fcf5
Removed state machine changelog entry
RiccardoM Nov 30, 2019
5e13360
Merge branch 'master' into community-pool-funding
alexanderbez Nov 30, 2019
3b095e3
Merge branch 'master' into community-pool-funding
alexanderbez Dec 2, 2019
f4d8e61
Merge branch 'master' of github.com:cosmos/cosmos-sdk into community-…
RiccardoM Dec 9, 2019
a0217ab
Support for sending funds to the community pool
RiccardoM Oct 25, 2019
1c59821
Added the REST and CLI txs
RiccardoM Oct 25, 2019
6aabb39
Reverted to the usage of a custom message to send funds
RiccardoM Dec 9, 2019
a34b963
Update x/distribution/client/cli/tx.go
RiccardoM Dec 9, 2019
4bdfff9
Update x/distribution/keeper/keeper.go
RiccardoM Dec 9, 2019
3f8ce2c
Update x/distribution/client/cli/tx.go
RiccardoM Dec 9, 2019
ea765d2
Update x/distribution/client/cli/tx.go
RiccardoM Dec 9, 2019
53316f7
Update x/distribution/client/cli/tx.go
RiccardoM Dec 9, 2019
5977e15
Fixed some errors
RiccardoM Dec 10, 2019
95b64f1
Fixed some lint errors
RiccardoM Dec 10, 2019
837b5f3
Merge branch 'master' into community-pool-funding
alexanderbez Dec 10, 2019
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ that allows for arbitrary vesting periods.
* `ValidateSigCountDecorator`: Validate the number of signatures in tx based on app-parameters.
* `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks.
* (cli) [\#5223](https://github.com/cosmos/cosmos-sdk/issues/5223) Cosmos Ledger App v2.0.0 is now supported. The changes are backwards compatible and App v1.5.x is still supported.
* (modules) [\#5249](https://github.com/cosmos/cosmos-sdk/pull/5249) Funds are now allowed to be directly sent to the community pool (via the distribution module account).

### Improvements

Expand Down
17 changes: 16 additions & 1 deletion simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ var (
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
gov.ModuleName: {supply.Burner},
}

// module accounts that are allowed to receive tokens
allowedReceivingModAcc = map[string]bool{
distr.ModuleName: true,
}
)

// MakeCodec - custom tx codec
Expand Down Expand Up @@ -167,7 +172,7 @@ func NewSimApp(
)
app.BankKeeper = bank.NewBaseKeeper(
app.AccountKeeper, app.subspaces[bank.ModuleName], bank.DefaultCodespace,
app.ModuleAccountAddrs(),
app.BlacklistedAccAddrs(),
)
app.SupplyKeeper = supply.NewKeeper(
app.cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms,
Expand Down Expand Up @@ -322,6 +327,16 @@ func (app *SimApp) ModuleAccountAddrs() map[string]bool {
return modAccAddrs
}

// BlacklistedAccAddrs returns all the app's module account addresses black listed for receiving tokens.
func (app *SimApp) BlacklistedAccAddrs() map[string]bool {
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
blacklistedAddrs := make(map[string]bool)
for acc := range maccPerms {
blacklistedAddrs[supply.NewModuleAddress(acc).String()] = !allowedReceivingModAcc[acc]
}

return blacklistedAddrs
}

// Codec returns SimApp's codec.
//
// NOTE: This is solely to be used for testing purposes as it may be desirable
Expand Down
2 changes: 1 addition & 1 deletion simapp/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestBlackListedAddrs(t *testing.T) {
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0)

for acc := range maccPerms {
require.True(t, app.BankKeeper.BlacklistedAddr(app.SupplyKeeper.GetModuleAddress(acc)))
require.Equal(t, !allowedReceivingModAcc[acc], app.BankKeeper.BlacklistedAddr(app.SupplyKeeper.GetModuleAddress(acc)))
}
}

Expand Down
2 changes: 1 addition & 1 deletion simapp/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, exp sdk.Coins)
ctxCheck := app.BaseApp.NewContext(true, abci.Header{})
res := app.AccountKeeper.GetAccount(ctxCheck, addr)

require.Equal(t, exp, res.GetCoins())
require.True(t, exp.IsEqual(res.GetCoins()))
}

// SignCheckDeliver checks a generated signed transaction and simulates a
Expand Down
76 changes: 56 additions & 20 deletions x/bank/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package bank_test
import (
"testing"

"github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/supply"
"github.com/stretchr/testify/require"

abci "github.com/tendermint/tendermint/abci/types"
Expand Down Expand Up @@ -118,36 +120,70 @@ func TestSendNotEnoughBalance(t *testing.T) {
require.Equal(t, res2.GetSequence(), origSeq+1)
}

// A module account cannot be the recipient of bank sends
// A module account cannot be the recipient of bank sends unless it has been marked as such
func TestSendToModuleAcc(t *testing.T) {
acc := &auth.BaseAccount{
Address: addr1,
Coins: coins,
tests := []struct {
name string
fromBalance sdk.Coins
msg types.MsgSend
expSimPass bool
expPass bool
expFromBalance sdk.Coins
expToBalance sdk.Coins
}{
{
name: "Normal module account cannot be the recipient of bank sends",
fromBalance: coins,
msg: types.NewMsgSend(addr1, moduleAccAddr, coins),
expSimPass: false,
expPass: false,
expFromBalance: coins,
expToBalance: sdk.NewCoins(),
},
{
name: "Allowed module account can be the recipient of bank sends",
fromBalance: coins,
msg: types.NewMsgSend(addr1, supply.NewModuleAddress(distribution.ModuleName), coins),
expPass: true,
expSimPass: true,
expFromBalance: sdk.NewCoins(),
expToBalance: coins,
},
}

genAccs := []authexported.GenesisAccount{acc}
app := simapp.SetupWithGenesisAccounts(genAccs)
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
acc := &auth.BaseAccount{
Address: test.msg.FromAddress,
Coins: test.fromBalance,
}

ctxCheck := app.BaseApp.NewContext(true, abci.Header{})
genAccs := []authexported.GenesisAccount{acc}
app := simapp.SetupWithGenesisAccounts(genAccs)

res1 := app.AccountKeeper.GetAccount(ctxCheck, addr1)
require.NotNil(t, res1)
require.Equal(t, acc, res1.(*auth.BaseAccount))
ctxCheck := app.BaseApp.NewContext(true, abci.Header{})

origAccNum := res1.GetAccountNumber()
origSeq := res1.GetSequence()
res1 := app.AccountKeeper.GetAccount(ctxCheck, test.msg.FromAddress)
require.NotNil(t, res1)
require.Equal(t, acc, res1.(*auth.BaseAccount))

header := abci.Header{Height: app.LastBlockHeight() + 1}
simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{sendMsg2}, []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1)
origAccNum := res1.GetAccountNumber()
origSeq := res1.GetSequence()

simapp.CheckBalance(t, app, addr1, coins)
simapp.CheckBalance(t, app, moduleAccAddr, sdk.Coins(nil))
header := abci.Header{Height: app.LastBlockHeight() + 1}
simapp.SignCheckDeliver(t, app.Codec(), app.BaseApp, header, []sdk.Msg{test.msg}, []uint64{origAccNum}, []uint64{origSeq}, test.expSimPass, test.expPass, priv1)

res2 := app.AccountKeeper.GetAccount(app.NewContext(true, abci.Header{}), addr1)
require.NotNil(t, res2)
simapp.CheckBalance(t, app, test.msg.FromAddress, test.expFromBalance)
simapp.CheckBalance(t, app, test.msg.ToAddress, test.expToBalance)

require.Equal(t, res2.GetAccountNumber(), origAccNum)
require.Equal(t, res2.GetSequence(), origSeq+1)
res2 := app.AccountKeeper.GetAccount(app.NewContext(true, abci.Header{}), addr1)
require.NotNil(t, res2)

require.Equal(t, res2.GetAccountNumber(), origAccNum)
require.Equal(t, res2.GetSequence(), origSeq+1)
})
}
}

func TestMsgMultiSendWithAccounts(t *testing.T) {
Expand Down
4 changes: 3 additions & 1 deletion x/bank/internal/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"
"time"

"github.com/cosmos/cosmos-sdk/x/supply"
"github.com/tendermint/tendermint/libs/common"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -97,7 +98,8 @@ func TestKeeper(t *testing.T) {

// Test retrieving black listed accounts
for acc := range simapp.GetMaccPerms() {
require.True(t, app.BankKeeper.BlacklistedAddr(app.SupplyKeeper.GetModuleAddress(acc)))
addr := supply.NewModuleAddress(acc)
require.Equal(t, app.BlacklistedAccAddrs()[addr.String()], app.BankKeeper.BlacklistedAddr(addr))
}
}

Expand Down
33 changes: 33 additions & 0 deletions x/distribution/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
GetCmdWithdrawRewards(cdc),
GetCmdSetWithdrawAddr(cdc),
GetCmdWithdrawAllRewards(cdc, storeKey),
GetCmdFundCommunityPool(cdc),
)...)

return distTxCmd
Expand Down Expand Up @@ -259,3 +260,35 @@ Where proposal.json contains:

return cmd
}

// command to fund the community pool
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
func GetCmdFundCommunityPool(cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "fund-community-pool [amount]",
RiccardoM marked this conversation as resolved.
Show resolved Hide resolved
Args: cobra.ExactArgs(1),
Short: "funds the community pool with the specified amount",
Long: strings.TrimSpace(
fmt.Sprintf(`Funds the community pool with the specified amount

Example:
$ %s tx fund-community-pool 100uatom --from mykey
`,
version.ClientName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)

depositorAddr := cliCtx.GetFromAddress()
amount, err := sdk.ParseCoins(args[0])
if err != nil {
return err
}

msg := types.NewMsgDepositIntoCommunityPool(amount, depositorAddr)
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
}
35 changes: 35 additions & 0 deletions x/distribution/client/rest/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute strin
withdrawValidatorRewardsHandlerFn(cliCtx),
).Methods("POST")

// Fund the community pool
r.HandleFunc(
"/distribution/community_pool",
fundCommunityPoolHandlerFn(cliCtx),
).Methods("POST")

}

type (
Expand All @@ -50,6 +56,11 @@ type (
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
WithdrawAddress sdk.AccAddress `json:"withdraw_address" yaml:"withdraw_address"`
}

fundCommunityPoolReq struct {
RiccardoM marked this conversation as resolved.
Show resolved Hide resolved
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
Amount sdk.Coins `json:"amount" yaml:"amount"`
}
)

// Withdraw delegator rewards
Expand Down Expand Up @@ -177,6 +188,30 @@ func withdrawValidatorRewardsHandlerFn(cliCtx context.CLIContext) http.HandlerFu
}
}

// Fund the community pool
func fundCommunityPoolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
RiccardoM marked this conversation as resolved.
Show resolved Hide resolved
return func(w http.ResponseWriter, r *http.Request) {
var req fundCommunityPoolReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}

req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}

fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}

msg := types.NewMsgDepositIntoCommunityPool(req.Amount, fromAddr)
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
utils.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}

// Auxiliary

func checkDelegatorAddressVar(w http.ResponseWriter, r *http.Request) (sdk.AccAddress, bool) {
Expand Down
19 changes: 19 additions & 0 deletions x/distribution/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
case types.MsgWithdrawValidatorCommission:
return handleMsgWithdrawValidatorCommission(ctx, msg, k)

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

default:
errMsg := fmt.Sprintf("unrecognized distribution message type: %T", msg)
return sdk.ErrUnknownRequest(errMsg).Result()
Expand Down Expand Up @@ -83,6 +86,22 @@ 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 {
return sdk.ResultFromError(err)
}

ctx.EventManager().EmitEvent(
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Depositor.String()),
),
)

return sdk.Result{Events: ctx.EventManager().Events()}
}

func NewCommunityPoolSpendProposalHandler(k Keeper) govtypes.Handler {
return func(ctx sdk.Context, content govtypes.Content) sdk.Error {
switch c := content.(type) {
Expand Down
13 changes: 13 additions & 0 deletions x/distribution/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,16 @@ 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 {
if err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil {
return err
}

feePool := k.GetFeePool(ctx)
feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoins(amount))
k.SetFeePool(ctx, feePool)

return nil
}
19 changes: 19 additions & 0 deletions x/distribution/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package keeper
import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/stretchr/testify/require"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -89,3 +91,20 @@ func TestGetTotalRewards(t *testing.T) {

require.Equal(t, expectedRewards, totalRewards)
}

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

amount := sdk.NewCoins(sdk.NewInt64Coin("stake", 100))
_ = bk.SetCoins(ctx, delAddr1, amount)

initPool := keeper.GetFeePool(ctx)
assert.Empty(t, initPool.CommunityPool)

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

assert.Equal(t, initPool.CommunityPool.Add(sdk.NewDecCoins(amount)), keeper.GetFeePool(ctx).CommunityPool)
assert.Empty(t, bk.GetCoins(ctx, delAddr1))
}
Loading