Skip to content

Commit

Permalink
add MsgGovSendFromFeePool
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronc committed Feb 29, 2024
1 parent bd95846 commit caa606c
Show file tree
Hide file tree
Showing 14 changed files with 2,411 additions and 348 deletions.
1,647 changes: 1,378 additions & 269 deletions api/regen/ecocredit/marketplace/v1/tx.pulsar.go

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions api/regen/ecocredit/marketplace/v1/tx_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions proto/regen/ecocredit/marketplace/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ service Msg {
// Since Revision 3
rpc GovSetFeeParams(MsgGovSetFeeParams)
returns (MsgGovSetFeeParamsResponse);

// GovSendFromFeePool is a governance method that allows the sending of the
// marketplace fees.
//
// Since Revision 3
rpc GovSendFromFeePool(MsgGovSendFromFeePool)
returns (MsgGovSendFromFeePoolResponse);

}

// MsgSell is the Msg/Sell request type.
Expand Down Expand Up @@ -251,3 +259,20 @@ message MsgGovSetFeeParams {

// MsgSetFeeParamsResponse is the Msg/SetFeeParams response type.
message MsgGovSetFeeParamsResponse {}

// MsgSendFromFeePool is the Msg/SendFromFeePool request type.
message MsgGovSendFromFeePool {
option (cosmos.msg.v1.signer) = "authority";

// authority is the address of the governance account.
string authority = 1;

// recipient is the address of the account that will receive the funds.
string recipient = 2;

// amount is the amount of coins to send from the fee pool.
repeated cosmos.base.v1beta1.Coin amount = 3;
}

// MsgSendFromFeePoolResponse is the Msg/SendFromFeePool response type.
message MsgGovSendFromFeePoolResponse {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Feature: Msg/SendFromFeePool

Background:
Given recipient "regen1nzh226hxrsvf4k69sa8v0nfuzx5vgwkczk8j68"

Rule: gov authority must be authorized
Scenario: gov authority is not authorized
Given authority is set to "regen1elq7ys34gpkj3jyvqee0h6yk4h9wsfxmgqelsw"
When funds are sent
Then expect error contains "unauthorized"

Scenario: gov authority is authorized
Given authority is set to the keeper authority
When funds are sent
Then expect no error

Rule: the fee pool must have enough funds to cover the fee
Background:
Given authority is set to the keeper authority

Scenario: fee pool is underfunded
Given fee pool balance "100foo"
And send amount "200foo"
When funds are sent
Then expect error contains "insufficient funds"

Scenario: fee pool is well funded
Given fee pool balance "1000foo"
And send amount "200foo"
When funds are sent
Then expect no error

Rule: funds are transferred from the fee pool to the recipient
Scenario: funds are transferred
Given authority is set to the keeper authority
Given fee pool balance "1000foo"
And send amount "200foo"
When funds are sent
Then expect no error
And fee pool balance "800foo"
And recipient balance "200foo"
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
Feature: Msg/SetFeeParams

Rule: gov authority must be authorized
Background:
Given fee params
"""
{}
"""

Scenario: gov authority is not authorized
Given authority is set to "regen1elq7ys34gpkj3jyvqee0h6yk4h9wsfxmgqelsw"
When fee params are set
Then expect error contains "unauthorized"

Scenario: gov authority is authorized
Given authority is set to the keeper authority
When fee params are set
Then expect no error

Rule: fee params get saved
Scenario: non-empty fee params
Given authority is set to the keeper authority
And fee params
"""
{
"buyer_percentage_fee": "0.01",
"seller_percentage_fee": "0.01"
}
"""
When fee params are set
Then expect no error
And expect fee params
"""
{
"buyer_percentage_fee": "0.01",
"seller_percentage_fee": "0.01"
}
"""

Scenario: empty fee params
Given authority is set to the keeper authority
And fee params
"""
{}
"""
When fee params are set
Then expect no error
And expect fee params
"""
{}
"""
35 changes: 35 additions & 0 deletions x/ecocredit/marketplace/keeper/msg_gov_send_from_fee_pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package keeper

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

types "github.com/regen-network/regen-ledger/x/ecocredit/v3/marketplace/types/v1"
)

func (k Keeper) GovSendFromFeePool(ctx context.Context, msg *types.MsgGovSendFromFeePool) (*types.MsgGovSendFromFeePoolResponse, error) {
authority, err := sdk.AccAddressFromBech32(msg.Authority)
if err != nil {
return nil, err
}

Check warning on line 16 in x/ecocredit/marketplace/keeper/msg_gov_send_from_fee_pool.go

View check run for this annotation

Codecov / codecov/patch

x/ecocredit/marketplace/keeper/msg_gov_send_from_fee_pool.go#L15-L16

Added lines #L15 - L16 were not covered by tests

if !authority.Equals(k.authority) {
return nil, sdkerrors.ErrUnauthorized
}

recipient, err := sdk.AccAddressFromBech32(msg.Recipient)
if err != nil {
return nil, err
}

Check warning on line 25 in x/ecocredit/marketplace/keeper/msg_gov_send_from_fee_pool.go

View check run for this annotation

Codecov / codecov/patch

x/ecocredit/marketplace/keeper/msg_gov_send_from_fee_pool.go#L24-L25

Added lines #L24 - L25 were not covered by tests

amount := types.ToSDKCoins(msg.Amount)

err = k.bankKeeper.SendCoinsFromModuleToAccount(sdk.UnwrapSDKContext(ctx), k.feePoolName, recipient, amount)
if err != nil {
return nil, err
}

return &types.MsgGovSendFromFeePoolResponse{}, nil
}
107 changes: 107 additions & 0 deletions x/ecocredit/marketplace/keeper/msg_gov_send_from_fee_pool_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package keeper

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/golang/mock/gomock"
"github.com/regen-network/gocuke"
"github.com/stretchr/testify/require"

types "github.com/regen-network/regen-ledger/x/ecocredit/v3/marketplace/types/v1"
)

type govSendFromFeePool struct {
*baseSuite
err error
msg *types.MsgGovSendFromFeePool
moduleBalances map[string]sdk.Coins
accountBalances map[string]sdk.Coins
}

func TestGovSendFromFeePool(t *testing.T) {
gocuke.NewRunner(t, &govSendFromFeePool{}).Path("./features/msg_gov_send_from_fee_pool.feature").Run()
}

func (s *govSendFromFeePool) Before(t gocuke.TestingT) {
s.baseSuite = setupBase(t, 2)
s.msg = &types.MsgGovSendFromFeePool{}
s.moduleBalances = make(map[string]sdk.Coins)
s.accountBalances = make(map[string]sdk.Coins)
s.bankKeeper.EXPECT().
SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
AnyTimes().
DoAndReturn(func(_ sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amount sdk.Coins) error {
newModBalance, neg := s.moduleBalances[senderModule].SafeSub(amount...)
if neg {
return sdkerrors.ErrInsufficientFunds
}

s.moduleBalances[senderModule] = newModBalance
s.accountBalances[recipientAddr.String()] = s.accountBalances[recipientAddr.String()].Add(amount...)
return nil
})
}

func (s *govSendFromFeePool) AuthorityIsSetToTheKeeperAuthority() {
s.msg.Authority = s.k.authority.String()
}

func (s *govSendFromFeePool) AuthorityIsSetTo(a string) {
s.msg.Authority = a
}

func (s *govSendFromFeePool) Recipient(a string) {
s.msg.Recipient = a
}

func (s *govSendFromFeePool) SendAmount(a string) {
coins, err := sdk.ParseCoinsNormalized(a)
require.NoError(s.t, err)
var ptrCoins []*sdk.Coin

Check failure on line 62 in x/ecocredit/marketplace/keeper/msg_gov_send_from_fee_pool_test.go

View workflow job for this annotation

GitHub Actions / golangci (x/ecocredit)

Consider pre-allocating `ptrCoins` (prealloc)
for _, coin := range coins {
ptrCoins = append(ptrCoins, &coin)

Check failure on line 64 in x/ecocredit/marketplace/keeper/msg_gov_send_from_fee_pool_test.go

View workflow job for this annotation

GitHub Actions / golangci (x/ecocredit)

G601: Implicit memory aliasing in for loop. (gosec)
}
s.msg.Amount = ptrCoins
}

func (s *govSendFromFeePool) FeePoolBalance(a string) {
coins, err := sdk.ParseCoinsNormalized(a)
require.NoError(s.t, err)
s.moduleBalances[s.k.feePoolName] = coins
}

func (s *govSendFromFeePool) RecipientBalance(a string) {
coins, err := sdk.ParseCoinsNormalized(a)
require.NoError(s.t, err)
s.accountBalances[s.msg.Recipient] = coins
}

func (s *govSendFromFeePool) FundsAreSent() {
_, s.err = s.k.GovSendFromFeePool(s.ctx, s.msg)
}

func (s *govSendFromFeePool) ExpectErrorContains(a string) {
if s.err != nil {
require.ErrorContains(s.t, s.err, a)
} else {
require.NoError(s.t, s.err)
}
}

func (s *govSendFromFeePool) ExpectNoError() {
require.NoError(s.t, s.err)
}

func (s *govSendFromFeePool) ExpectFeePoolBalance(a string) {
coins, err := sdk.ParseCoinsNormalized(a)
require.NoError(s.t, err)
require.True(s.t, coins.IsEqual(s.moduleBalances[s.k.feePoolName]))
}

func (s *govSendFromFeePool) ExpectRecipientBalance(a string) {
coins, err := sdk.ParseCoinsNormalized(a)
require.NoError(s.t, err)
require.True(s.t, coins.IsEqual(s.accountBalances[s.msg.Recipient]))
}
Loading

0 comments on commit caa606c

Please sign in to comment.