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

feat(distr): add distribution authorization #35

Merged
merged 7 commits into from
Jun 8, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
18 changes: 18 additions & 0 deletions proto/cosmos/distribution/v1beta1/authz.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
syntax = "proto3";
package cosmos.distribution.v1beta1;

import "cosmos_proto/cosmos.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/distribution/types";

// DistributionAuthorization defines a grant that can be given to an address to allow them to
// execute distribution messages on behalf of the granter.
message DistributionAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";

// message_type represents the type of the message that is authorized by this DistributionAuthorization.
string message_type = 1;
// allowed_list specifies list of addresses that are allowed to execute the distribution messages.
repeated string allowed_list = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

7 changes: 5 additions & 2 deletions x/distribution/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper_test
import (
gocontext "context"
"fmt"
"github.com/cosmos/cosmos-sdk/x/distribution/keeper"
Vvaradinov marked this conversation as resolved.
Show resolved Hide resolved
"testing"

"github.com/stretchr/testify/suite"
Expand Down Expand Up @@ -34,7 +35,8 @@ func (suite *KeeperTestSuite) SetupTest() {
ctx := app.BaseApp.NewContext(false, tmproto.Header{})

queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, app.DistrKeeper)
querySrv := keeper.NewQuerier(app.DistrKeeper)
types.RegisterQueryServer(queryHelper, querySrv)
queryClient := types.NewQueryClient(queryHelper)

suite.app = app
Expand Down Expand Up @@ -350,7 +352,8 @@ func (suite *KeeperTestSuite) TestGRPCDelegationRewards() {
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)

queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, app.DistrKeeper)
querySrv := keeper.NewQuerier(app.DistrKeeper)
types.RegisterQueryServer(queryHelper, querySrv)
queryClient := types.NewQueryClient(queryHelper)

val := app.StakingKeeper.Validator(ctx, valAddrs[0])
Expand Down
65 changes: 65 additions & 0 deletions x/distribution/types/authz.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package types

import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/authz"
"golang.org/x/exp/slices"
)

var _ authz.Authorization = &DistributionAuthorization{}

// NewDistributionAuthorization creates a new DistributionAuthorization.
func NewDistributionAuthorization(msgType string, allowed []string) *DistributionAuthorization {
Vvaradinov marked this conversation as resolved.
Show resolved Hide resolved
return &DistributionAuthorization{
MessageType: msgType,
AllowedList: allowed,
}
}

// MsgTypeURL implements Authorization.MsgTypeURL.
func (m *DistributionAuthorization) MsgTypeURL() string {
Vvaradinov marked this conversation as resolved.
Show resolved Hide resolved
return m.MessageType
}

// Accept implements Authorization.Accept. It checks, that the
// withdrawer for MsgSetWithdrawAddress,
// validator for MsgWithdrawValidatorCommission,
// the delegator address for MsgWithdrawDelegatorReward
// is in the allowed list. If these conditions are met, the AcceptResponse is returned.
func (m *DistributionAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authz.AcceptResponse, error) {
Vvaradinov marked this conversation as resolved.
Show resolved Hide resolved
switch msg := msg.(type) {
case *MsgSetWithdrawAddress:
if !slices.Contains(m.AllowedList, msg.WithdrawAddress) {
return authz.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrap("address is not in the allowed list")
}
case *MsgWithdrawValidatorCommission:
if !slices.Contains(m.AllowedList, msg.ValidatorAddress) {
return authz.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrap("address is not in the allowed list")
}
case *MsgWithdrawDelegatorReward:
if !slices.Contains(m.AllowedList, msg.DelegatorAddress) {
return authz.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrap("address is not in the allowed list")
}
default:
return authz.AcceptResponse{}, sdkerrors.ErrInvalidRequest.Wrap("unknown msg type")
}

return authz.AcceptResponse{
Accept: true,
Delete: false,
Updated: &DistributionAuthorization{
AllowedList: m.AllowedList,
MessageType: m.MessageType,
},
Vvaradinov marked this conversation as resolved.
Show resolved Hide resolved
}, nil
}

// ValidateBasic performs a stateless validation of the fields.
func (m *DistributionAuthorization) ValidateBasic() error {
if len(m.AllowedList) == 0 {
return sdkerrors.ErrInvalidRequest.Wrap("allowed list cannot be empty")
}
Vvaradinov marked this conversation as resolved.
Show resolved Hide resolved

return nil
}
Loading