From ec957e1d8292226a56d410c42be748c3b5446e46 Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Wed, 20 Jul 2022 16:25:16 +0530 Subject: [PATCH 01/16] wip --- api/cosmos/bank/v1beta1/authz.pulsar.go | 168 +++++++++++++++++++++--- proto/cosmos/bank/v1beta1/authz.proto | 4 + x/authz/client/cli/tx.go | 30 ++++- x/authz/keeper/keeper_test.go | 10 +- x/authz/migrations/v046/store_test.go | 6 +- x/authz/module/abci_test.go | 4 +- x/authz/msgs_test.go | 4 +- x/authz/simulation/decoder_test.go | 4 +- x/authz/simulation/genesis.go | 20 ++- x/authz/simulation/operations.go | 16 ++- x/authz/simulation/operations_test.go | 10 +- x/bank/types/authz.pb.go | 72 +++++++++- x/bank/types/send_authorization.go | 22 +++- x/bank/types/send_authorization_test.go | 9 +- 14 files changed, 329 insertions(+), 50 deletions(-) diff --git a/api/cosmos/bank/v1beta1/authz.pulsar.go b/api/cosmos/bank/v1beta1/authz.pulsar.go index f00963c1459b..9874466cdb8a 100644 --- a/api/cosmos/bank/v1beta1/authz.pulsar.go +++ b/api/cosmos/bank/v1beta1/authz.pulsar.go @@ -66,15 +66,63 @@ func (x *_SendAuthorization_1_list) IsValid() bool { return x.list != nil } +var _ protoreflect.List = (*_SendAuthorization_2_list)(nil) + +type _SendAuthorization_2_list struct { + list *[]string +} + +func (x *_SendAuthorization_2_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_SendAuthorization_2_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfString((*x.list)[i]) +} + +func (x *_SendAuthorization_2_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.String() + concreteValue := valueUnwrapped + (*x.list)[i] = concreteValue +} + +func (x *_SendAuthorization_2_list) Append(value protoreflect.Value) { + valueUnwrapped := value.String() + concreteValue := valueUnwrapped + *x.list = append(*x.list, concreteValue) +} + +func (x *_SendAuthorization_2_list) AppendMutable() protoreflect.Value { + panic(fmt.Errorf("AppendMutable can not be called on message SendAuthorization at list field AllowList as it is not of Message kind")) +} + +func (x *_SendAuthorization_2_list) Truncate(n int) { + *x.list = (*x.list)[:n] +} + +func (x *_SendAuthorization_2_list) NewElement() protoreflect.Value { + v := "" + return protoreflect.ValueOfString(v) +} + +func (x *_SendAuthorization_2_list) IsValid() bool { + return x.list != nil +} + var ( md_SendAuthorization protoreflect.MessageDescriptor fd_SendAuthorization_spend_limit protoreflect.FieldDescriptor + fd_SendAuthorization_allow_list protoreflect.FieldDescriptor ) func init() { file_cosmos_bank_v1beta1_authz_proto_init() md_SendAuthorization = File_cosmos_bank_v1beta1_authz_proto.Messages().ByName("SendAuthorization") fd_SendAuthorization_spend_limit = md_SendAuthorization.Fields().ByName("spend_limit") + fd_SendAuthorization_allow_list = md_SendAuthorization.Fields().ByName("allow_list") } var _ protoreflect.Message = (*fastReflection_SendAuthorization)(nil) @@ -148,6 +196,12 @@ func (x *fastReflection_SendAuthorization) Range(f func(protoreflect.FieldDescri return } } + if len(x.AllowList) != 0 { + value := protoreflect.ValueOfList(&_SendAuthorization_2_list{list: &x.AllowList}) + if !f(fd_SendAuthorization_allow_list, value) { + return + } + } } // Has reports whether a field is populated. @@ -165,6 +219,8 @@ func (x *fastReflection_SendAuthorization) Has(fd protoreflect.FieldDescriptor) switch fd.FullName() { case "cosmos.bank.v1beta1.SendAuthorization.spend_limit": return len(x.SpendLimit) != 0 + case "cosmos.bank.v1beta1.SendAuthorization.allow_list": + return len(x.AllowList) != 0 default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.bank.v1beta1.SendAuthorization")) @@ -183,6 +239,8 @@ func (x *fastReflection_SendAuthorization) Clear(fd protoreflect.FieldDescriptor switch fd.FullName() { case "cosmos.bank.v1beta1.SendAuthorization.spend_limit": x.SpendLimit = nil + case "cosmos.bank.v1beta1.SendAuthorization.allow_list": + x.AllowList = nil default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.bank.v1beta1.SendAuthorization")) @@ -205,6 +263,12 @@ func (x *fastReflection_SendAuthorization) Get(descriptor protoreflect.FieldDesc } listValue := &_SendAuthorization_1_list{list: &x.SpendLimit} return protoreflect.ValueOfList(listValue) + case "cosmos.bank.v1beta1.SendAuthorization.allow_list": + if len(x.AllowList) == 0 { + return protoreflect.ValueOfList(&_SendAuthorization_2_list{}) + } + listValue := &_SendAuthorization_2_list{list: &x.AllowList} + return protoreflect.ValueOfList(listValue) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.bank.v1beta1.SendAuthorization")) @@ -229,6 +293,10 @@ func (x *fastReflection_SendAuthorization) Set(fd protoreflect.FieldDescriptor, lv := value.List() clv := lv.(*_SendAuthorization_1_list) x.SpendLimit = *clv.list + case "cosmos.bank.v1beta1.SendAuthorization.allow_list": + lv := value.List() + clv := lv.(*_SendAuthorization_2_list) + x.AllowList = *clv.list default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.bank.v1beta1.SendAuthorization")) @@ -255,6 +323,12 @@ func (x *fastReflection_SendAuthorization) Mutable(fd protoreflect.FieldDescript } value := &_SendAuthorization_1_list{list: &x.SpendLimit} return protoreflect.ValueOfList(value) + case "cosmos.bank.v1beta1.SendAuthorization.allow_list": + if x.AllowList == nil { + x.AllowList = []string{} + } + value := &_SendAuthorization_2_list{list: &x.AllowList} + return protoreflect.ValueOfList(value) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.bank.v1beta1.SendAuthorization")) @@ -271,6 +345,9 @@ func (x *fastReflection_SendAuthorization) NewField(fd protoreflect.FieldDescrip case "cosmos.bank.v1beta1.SendAuthorization.spend_limit": list := []*v1beta1.Coin{} return protoreflect.ValueOfList(&_SendAuthorization_1_list{list: &list}) + case "cosmos.bank.v1beta1.SendAuthorization.allow_list": + list := []string{} + return protoreflect.ValueOfList(&_SendAuthorization_2_list{list: &list}) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.bank.v1beta1.SendAuthorization")) @@ -346,6 +423,12 @@ func (x *fastReflection_SendAuthorization) ProtoMethods() *protoiface.Methods { n += 1 + l + runtime.Sov(uint64(l)) } } + if len(x.AllowList) > 0 { + for _, s := range x.AllowList { + l = len(s) + n += 1 + l + runtime.Sov(uint64(l)) + } + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -375,6 +458,15 @@ func (x *fastReflection_SendAuthorization) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if len(x.AllowList) > 0 { + for iNdEx := len(x.AllowList) - 1; iNdEx >= 0; iNdEx-- { + i -= len(x.AllowList[iNdEx]) + copy(dAtA[i:], x.AllowList[iNdEx]) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.AllowList[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } if len(x.SpendLimit) > 0 { for iNdEx := len(x.SpendLimit) - 1; iNdEx >= 0; iNdEx-- { encoded, err := options.Marshal(x.SpendLimit[iNdEx]) @@ -474,6 +566,38 @@ func (x *fastReflection_SendAuthorization) ProtoMethods() *protoiface.Methods { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field AllowList", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.AllowList = append(x.AllowList, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -532,6 +656,9 @@ type SendAuthorization struct { unknownFields protoimpl.UnknownFields SpendLimit []*v1beta1.Coin `protobuf:"bytes,1,rep,name=spend_limit,json=spendLimit,proto3" json:"spend_limit,omitempty"` + // allow_list specifies the list of addresses to whom the grantee can send tokens on behalf of granter's + // account. + AllowList []string `protobuf:"bytes,2,rep,name=allow_list,json=allowList,proto3" json:"allow_list,omitempty"` } func (x *SendAuthorization) Reset() { @@ -561,6 +688,13 @@ func (x *SendAuthorization) GetSpendLimit() []*v1beta1.Coin { return nil } +func (x *SendAuthorization) GetAllowList() []string { + if x != nil { + return x.AllowList + } + return nil +} + var File_cosmos_bank_v1beta1_authz_proto protoreflect.FileDescriptor var file_cosmos_bank_v1beta1_authz_proto_rawDesc = []byte{ @@ -572,7 +706,7 @@ var file_cosmos_bank_v1beta1_authz_proto_rawDesc = []byte{ 0x73, 0x6d, 0x6f, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, 0x69, - 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x94, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6c, 0x0a, 0x0b, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, @@ -580,21 +714,23 @@ var file_cosmos_bank_v1beta1_authz_proto_rawDesc = []byte{ 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, - 0x0a, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x3a, 0x11, 0xca, 0xb4, 0x2d, - 0x0d, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0xc5, - 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, - 0x6e, 0x6b, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x0a, 0x41, 0x75, 0x74, 0x68, - 0x7a, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x62, - 0x61, 0x6e, 0x6b, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x42, 0x58, - 0xaa, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x42, 0x61, 0x6e, 0x6b, 0x2e, 0x56, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, - 0x42, 0x61, 0x6e, 0x6b, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1f, 0x43, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x42, 0x61, 0x6e, 0x6b, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, - 0x15, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x42, 0x61, 0x6e, 0x6b, 0x3a, 0x3a, 0x56, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x0a, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61, + 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x09, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x3a, 0x11, 0xca, 0xb4, 0x2d, 0x0d, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0xc5, 0x01, + 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x6e, + 0x6b, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x7a, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, + 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x62, 0x61, + 0x6e, 0x6b, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x42, 0x58, 0xaa, + 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x42, 0x61, 0x6e, 0x6b, 0x2e, 0x56, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x42, + 0x61, 0x6e, 0x6b, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1f, 0x43, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x42, 0x61, 0x6e, 0x6b, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x15, + 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x42, 0x61, 0x6e, 0x6b, 0x3a, 0x3a, 0x56, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/cosmos/bank/v1beta1/authz.proto b/proto/cosmos/bank/v1beta1/authz.proto index 4f58b15e4970..cc8eb9ae0f75 100644 --- a/proto/cosmos/bank/v1beta1/authz.proto +++ b/proto/cosmos/bank/v1beta1/authz.proto @@ -16,4 +16,8 @@ message SendAuthorization { repeated cosmos.base.v1beta1.Coin spend_limit = 1 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + + // allow_list specifies the list of addresses to whom the grantee can send tokens on behalf of granter's + // account. + repeated string allow_list = 2; } diff --git a/x/authz/client/cli/tx.go b/x/authz/client/cli/tx.go index 8ebf8550d769..9edceac5f179 100644 --- a/x/authz/client/cli/tx.go +++ b/x/authz/client/cli/tx.go @@ -26,6 +26,7 @@ const ( FlagExpiration = "expiration" FlagAllowedValidators = "allowed-validators" FlagDenyValidators = "deny-validators" + FlagAllowList = "allow-list" delegate = "delegate" redelegate = "redelegate" unbond = "unbond" @@ -93,7 +94,21 @@ Examples: return fmt.Errorf("spend-limit should be greater than zero") } - authorization = bank.NewSendAuthorization(spendLimit) + allowList, err := cmd.Flags().GetStringSlice(FlagAllowList) + if err != nil { + return err + } + + allowed, err := bech32toAccountAddresses(allowList) + if err != nil { + return err + } + + authorization, err = bank.NewSendAuthorization(allowed, spendLimit) + if err != nil { + return err + } + case "generic": msgType, err := cmd.Flags().GetString(FlagMsgType) if err != nil { @@ -184,6 +199,7 @@ Examples: cmd.Flags().String(FlagSpendLimit, "", "SpendLimit for Send Authorization, an array of Coins allowed spend") cmd.Flags().StringSlice(FlagAllowedValidators, []string{}, "Allowed validators addresses separated by ,") cmd.Flags().StringSlice(FlagDenyValidators, []string{}, "Deny validators addresses separated by ,") + cmd.Flags().StringSlice(FlagAllowList, []string{}, "Allowed addresses grantee is allowed to send funds separated by ,") cmd.Flags().Int64(FlagExpiration, 0, "Expire time as Unix timestamp. Set zero (0) for no expiry. Default is 0.") return cmd } @@ -284,3 +300,15 @@ func bech32toValidatorAddresses(validators []string) ([]sdk.ValAddress, error) { } return vals, nil } + +func bech32toAccountAddresses(accAddrs []string) ([]sdk.AccAddress, error) { + addrs := make([]sdk.AccAddress, len(accAddrs)) + for i, addr := range accAddrs { + accAddr, err := sdk.AccAddressFromBech32(addr) + if err != nil { + return nil, err + } + addrs[i] = accAddr + } + return addrs, nil +} diff --git a/x/authz/keeper/keeper_test.go b/x/authz/keeper/keeper_test.go index dcb2496331aa..8700d8b675a0 100644 --- a/x/authz/keeper/keeper_test.go +++ b/x/authz/keeper/keeper_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" tmtime "github.com/tendermint/tendermint/libs/time" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -125,9 +126,11 @@ func (s *TestSuite) TestKeeperIter() { granteeAddr := addrs[1] granter2Addr := addrs[2] e := ctx.BlockTime().AddDate(1, 0, 0) + sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, coins100) + require.NoError(s.T(), err) - s.authzKeeper.SaveGrant(ctx, granteeAddr, granterAddr, banktypes.NewSendAuthorization(coins100), &e) - s.authzKeeper.SaveGrant(ctx, granteeAddr, granter2Addr, banktypes.NewSendAuthorization(coins100), &e) + s.authzKeeper.SaveGrant(ctx, granteeAddr, granterAddr, sendAuthz, &e) + s.authzKeeper.SaveGrant(ctx, granteeAddr, granter2Addr, sendAuthz, &e) s.authzKeeper.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant authz.Grant) bool { s.Require().Equal(granteeAddr, grantee) @@ -144,7 +147,8 @@ func (s *TestSuite) TestDispatchAction() { granterAddr := addrs[0] granteeAddr := addrs[1] recipientAddr := addrs[2] - a := banktypes.NewSendAuthorization(coins100) + a, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, coins100) + require.NoError(err) require.NoError(banktestutil.FundAccount(s.bankKeeper, s.ctx, granterAddr, coins1000)) diff --git a/x/authz/migrations/v046/store_test.go b/x/authz/migrations/v046/store_test.go index 0cefd65cf767..30b94d13c925 100644 --- a/x/authz/migrations/v046/store_test.go +++ b/x/authz/migrations/v046/store_test.go @@ -35,6 +35,8 @@ func TestMigration(t *testing.T) { blockTime := ctx.BlockTime() oneDay := blockTime.AddDate(0, 0, 1) oneYear := blockTime.AddDate(1, 0, 0) + sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, coins100) + require.NoError(t, err) grants := []struct { granter sdk.AccAddress @@ -47,7 +49,7 @@ func TestMigration(t *testing.T) { grantee1, sendMsgType, func() authz.Grant { - any, err := codectypes.NewAnyWithValue(banktypes.NewSendAuthorization(coins100)) + any, err := codectypes.NewAnyWithValue(sendAuthz) require.NoError(t, err) return authz.Grant{ Authorization: any, @@ -60,7 +62,7 @@ func TestMigration(t *testing.T) { grantee2, sendMsgType, func() authz.Grant { - any, err := codectypes.NewAnyWithValue(banktypes.NewSendAuthorization(coins100)) + any, err := codectypes.NewAnyWithValue(sendAuthz) require.NoError(t, err) return authz.Grant{ Authorization: any, diff --git a/x/authz/module/abci_test.go b/x/authz/module/abci_test.go index f1c447739a83..f3d44a66a8cc 100644 --- a/x/authz/module/abci_test.go +++ b/x/authz/module/abci_test.go @@ -44,9 +44,11 @@ func TestExpiredGrantsQueue(t *testing.T) { expiration := ctx.BlockTime().AddDate(0, 1, 0) expiration2 := expiration.AddDate(1, 0, 0) smallCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 10)) + sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, smallCoins) + require.NoError(t, err) save := func(grantee sdk.AccAddress, exp *time.Time) { - err := authzKeeper.SaveGrant(ctx, grantee, granter, banktypes.NewSendAuthorization(smallCoins), exp) + err := authzKeeper.SaveGrant(ctx, grantee, granter, sendAuthz, exp) require.NoError(t, err, "Grant from %s", grantee.String()) } save(grantee1, &expiration) diff --git a/x/authz/msgs_test.go b/x/authz/msgs_test.go index f1b357a2b974..c874706372f2 100644 --- a/x/authz/msgs_test.go +++ b/x/authz/msgs_test.go @@ -174,7 +174,9 @@ func TestAminoJSON(t *testing.T) { require.NoError(t, err) grant, err := authz.NewGrant(blockTime, authz.NewGenericAuthorization(typeURL), &expiresAt) require.NoError(t, err) - sendGrant, err := authz.NewGrant(blockTime, banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))), &expiresAt) + sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))) + require.NoError(t, err) + sendGrant, err := authz.NewGrant(blockTime, sendAuthz, &expiresAt) require.NoError(t, err) valAddr, err := sdk.ValAddressFromBech32("cosmosvaloper1xcy3els9ua75kdm783c3qu0rfa2eples6eavqq") require.NoError(t, err) diff --git a/x/authz/simulation/decoder_test.go b/x/authz/simulation/decoder_test.go index a5737ace5ee3..e919e42940b2 100644 --- a/x/authz/simulation/decoder_test.go +++ b/x/authz/simulation/decoder_test.go @@ -26,7 +26,9 @@ func TestDecodeStore(t *testing.T) { now := time.Now().UTC() e := now.Add(1) - grant, _ := authz.NewGrant(now, banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewInt64Coin("foo", 123))), &e) + sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, sdk.NewCoins(sdk.NewInt64Coin("foo", 123))) + require.NoError(t, err) + grant, _ := authz.NewGrant(now, sendAuthz, &e) grantBz, err := cdc.Marshal(&grant) require.NoError(t, err) kvPairs := kv.Pairs{ diff --git a/x/authz/simulation/genesis.go b/x/authz/simulation/genesis.go index 8c4609b7bb5c..39866e728564 100644 --- a/x/authz/simulation/genesis.go +++ b/x/authz/simulation/genesis.go @@ -2,6 +2,7 @@ package simulation import ( "math/rand" + "testing" "time" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -11,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/authz" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/stretchr/testify/require" ) // genGrant returns a slice of authorization grants. @@ -24,10 +26,12 @@ func genGrant(r *rand.Rand, accounts []simtypes.Account, genT time.Time) []authz e := genT.AddDate(1, 0, 0) expiration = &e } + grant, err := generateRandomGrant(r) + require.NoError(&testing.T{}, err) authorizations[i] = authz.GrantAuthorization{ Granter: granter.Address.String(), Grantee: grantee.Address.String(), - Authorization: generateRandomGrant(r), + Authorization: grant, Expiration: expiration, } } @@ -35,12 +39,16 @@ func genGrant(r *rand.Rand, accounts []simtypes.Account, genT time.Time) []authz return authorizations } -func generateRandomGrant(r *rand.Rand) *codectypes.Any { +func generateRandomGrant(r *rand.Rand) (*codectypes.Any, error) { authorizations := make([]*codectypes.Any, 2) - authorizations[0] = newAnyAuthorization(banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))))) + sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))) + if err != nil { + return nil, err + } + authorizations[0] = newAnyAuthorization(sendAuthz) authorizations[1] = newAnyAuthorization(authz.NewGenericAuthorization(sdk.MsgTypeURL(&v1.MsgSubmitProposal{}))) - return authorizations[r.Intn(len(authorizations))] + return authorizations[r.Intn(len(authorizations))], nil } func newAnyAuthorization(a authz.Authorization) *codectypes.Any { @@ -57,7 +65,9 @@ func RandomizedGenState(simState *module.SimulationState) { var grants []authz.GrantAuthorization simState.AppParams.GetOrGenerate( simState.Cdc, "authz", &grants, simState.Rand, - func(r *rand.Rand) { grants = genGrant(r, simState.Accounts, simState.GenTimestamp) }, + func(r *rand.Rand) { + grants = genGrant(r, simState.Accounts, simState.GenTimestamp) + }, ) authzGrantsGenesis := authz.NewGenesisState(grants) diff --git a/x/authz/simulation/operations.go b/x/authz/simulation/operations.go index fdea8f349e3c..42f6c97c65c1 100644 --- a/x/authz/simulation/operations.go +++ b/x/authz/simulation/operations.go @@ -118,7 +118,11 @@ func SimulateMsgGrant(cdc *codec.ProtoCodec, ak authz.AccountKeeper, bk authz.Ba if !t1.Before(ctx.BlockTime()) { expiration = &t1 } - msg, err := authz.NewMsgGrant(granter.Address, grantee.Address, generateRandomAuthorization(r, spendLimit), expiration) + randomAuthz, err := generateRandomAuthorization(r, spendLimit) + if err != nil { + return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "unable to generate random authorization"), nil, err + } + msg, err := authz.NewMsgGrant(granter.Address, grantee.Address, randomAuthz, expiration) if err != nil { return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, err.Error()), nil, err } @@ -146,12 +150,16 @@ func SimulateMsgGrant(cdc *codec.ProtoCodec, ak authz.AccountKeeper, bk authz.Ba } } -func generateRandomAuthorization(r *rand.Rand, spendLimit sdk.Coins) authz.Authorization { +func generateRandomAuthorization(r *rand.Rand, spendLimit sdk.Coins) (authz.Authorization, error) { authorizations := make([]authz.Authorization, 2) - authorizations[0] = banktype.NewSendAuthorization(spendLimit) + sendAuthz, err := banktype.NewSendAuthorization([]sdk.AccAddress{}, spendLimit) + if err != nil { + return nil, err + } + authorizations[0] = sendAuthz authorizations[1] = authz.NewGenericAuthorization(sdk.MsgTypeURL(&banktype.MsgSend{})) - return authorizations[r.Intn(len(authorizations))] + return authorizations[r.Intn(len(authorizations))], nil } // SimulateMsgRevoke generates a MsgRevoke with random values. diff --git a/x/authz/simulation/operations_test.go b/x/authz/simulation/operations_test.go index b599a7d88068..a205d98db90f 100644 --- a/x/authz/simulation/operations_test.go +++ b/x/authz/simulation/operations_test.go @@ -161,10 +161,11 @@ func (suite *SimTestSuite) TestSimulateRevoke() { granter := accounts[0] grantee := accounts[1] - a := banktypes.NewSendAuthorization(initCoins) + a, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, initCoins) + suite.Require().NoError(err) expire := time.Now().Add(30 * time.Hour) - err := suite.authzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, a, &expire) + err = suite.authzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, a, &expire) suite.Require().NoError(err) // execute operation @@ -196,10 +197,11 @@ func (suite *SimTestSuite) TestSimulateExec() { granter := accounts[0] grantee := accounts[1] - a := banktypes.NewSendAuthorization(initCoins) + a, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, initCoins) + suite.Require().NoError(err) expire := suite.ctx.BlockTime().Add(1 * time.Hour) - err := suite.authzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, a, &expire) + err = suite.authzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, a, &expire) suite.Require().NoError(err) // execute operation diff --git a/x/bank/types/authz.pb.go b/x/bank/types/authz.pb.go index 904a7f9ce793..362aba584c57 100644 --- a/x/bank/types/authz.pb.go +++ b/x/bank/types/authz.pb.go @@ -32,6 +32,9 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Since: cosmos-sdk 0.43 type SendAuthorization struct { SpendLimit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=spend_limit,json=spendLimit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"spend_limit"` + // allow_list specifies the list of addresses to whom the grantee can send tokens on behalf of granter's + // account. + AllowList []string `protobuf:"bytes,2,rep,name=allow_list,json=allowList,proto3" json:"allow_list,omitempty"` } func (m *SendAuthorization) Reset() { *m = SendAuthorization{} } @@ -74,6 +77,13 @@ func (m *SendAuthorization) GetSpendLimit() github_com_cosmos_cosmos_sdk_types.C return nil } +func (m *SendAuthorization) GetAllowList() []string { + if m != nil { + return m.AllowList + } + return nil +} + func init() { proto.RegisterType((*SendAuthorization)(nil), "cosmos.bank.v1beta1.SendAuthorization") } @@ -81,24 +91,25 @@ func init() { func init() { proto.RegisterFile("cosmos/bank/v1beta1/authz.proto", fileDescriptor_a4d2a37888ea779f) } var fileDescriptor_a4d2a37888ea779f = []byte{ - // 257 bytes of a gzipped FileDescriptorProto + // 285 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0xd6, 0x4f, 0x4a, 0xcc, 0xcb, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x2c, 0x2d, 0xc9, 0xa8, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x86, 0x28, 0xd0, 0x03, 0x29, 0xd0, 0x83, 0x2a, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xcb, 0xeb, 0x83, 0x58, 0x10, 0xa5, 0x52, 0x92, 0x10, 0xa5, 0xf1, 0x10, 0x09, 0xa8, 0x3e, 0x88, 0x94, 0x1c, 0xdc, 0x9a, - 0xe2, 0x54, 0xb8, 0x35, 0xc9, 0xf9, 0x99, 0x79, 0x10, 0x79, 0xa5, 0x29, 0x8c, 0x5c, 0x82, 0xc1, + 0xe2, 0x54, 0xb8, 0x35, 0xc9, 0xf9, 0x99, 0x79, 0x10, 0x79, 0xa5, 0xcd, 0x8c, 0x5c, 0x82, 0xc1, 0xa9, 0x79, 0x29, 0x8e, 0xa5, 0x25, 0x19, 0xf9, 0x45, 0x99, 0x55, 0x89, 0x25, 0x99, 0xf9, 0x79, 0x42, 0x39, 0x5c, 0xdc, 0xc5, 0x05, 0xa9, 0x79, 0x29, 0xf1, 0x39, 0x99, 0xb9, 0x99, 0x25, 0x12, 0x8c, 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0x92, 0x7a, 0x70, 0x17, 0x15, 0xa7, 0xc2, 0x5c, 0xa4, 0xe7, 0x9c, 0x9f, 0x99, 0xe7, 0x64, 0x70, 0xe2, 0x9e, 0x3c, 0xc3, 0xaa, 0xfb, 0xf2, 0x1a, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0x50, 0x67, 0x40, 0x29, 0xdd, 0xe2, 0x94, 0x6c, 0xfd, 0x92, 0xca, 0x82, 0xd4, 0x62, 0xb0, 0x86, 0xe2, 0x20, 0x2e, 0xb0, 0xf9, 0x3e, 0x20, 0xe3, - 0xad, 0x04, 0x4f, 0x6d, 0xd1, 0xe5, 0x45, 0x71, 0x80, 0x93, 0xf3, 0x89, 0x47, 0x72, 0x8c, 0x17, - 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, - 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x69, 0xe2, 0xb5, 0xa2, 0x02, 0x12, 0x9e, 0x60, 0x9b, 0x92, 0xd8, - 0xc0, 0x5e, 0x34, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x8c, 0x86, 0xc3, 0x2e, 0x6b, 0x01, 0x00, - 0x00, + 0x85, 0x64, 0xb9, 0xb8, 0x12, 0x73, 0x72, 0xf2, 0xcb, 0xe3, 0x73, 0x32, 0x8b, 0x4b, 0x24, 0x98, + 0x14, 0x98, 0x35, 0x38, 0x83, 0x38, 0xc1, 0x22, 0x3e, 0x99, 0xc5, 0x25, 0x56, 0x82, 0xa7, 0xb6, + 0xe8, 0xf2, 0xa2, 0xb8, 0xcf, 0xc9, 0xf9, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, + 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, + 0xa2, 0x34, 0xf1, 0xba, 0xa0, 0x02, 0x12, 0xdc, 0x60, 0x87, 0x24, 0xb1, 0x81, 0x43, 0xc0, 0x18, + 0x10, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x94, 0xb9, 0xfa, 0x8a, 0x01, 0x00, 0x00, } func (m *SendAuthorization) Marshal() (dAtA []byte, err error) { @@ -121,6 +132,15 @@ func (m *SendAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.AllowList) > 0 { + for iNdEx := len(m.AllowList) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.AllowList[iNdEx]) + copy(dAtA[i:], m.AllowList[iNdEx]) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.AllowList[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } if len(m.SpendLimit) > 0 { for iNdEx := len(m.SpendLimit) - 1; iNdEx >= 0; iNdEx-- { { @@ -161,6 +181,12 @@ func (m *SendAuthorization) Size() (n int) { n += 1 + l + sovAuthz(uint64(l)) } } + if len(m.AllowList) > 0 { + for _, s := range m.AllowList { + l = len(s) + n += 1 + l + sovAuthz(uint64(l)) + } + } return n } @@ -233,6 +259,38 @@ func (m *SendAuthorization) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowList", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AllowList = append(m.AllowList, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAuthz(dAtA[iNdEx:]) diff --git a/x/bank/types/send_authorization.go b/x/bank/types/send_authorization.go index 7eb90b594918..ea608988ba53 100644 --- a/x/bank/types/send_authorization.go +++ b/x/bank/types/send_authorization.go @@ -9,10 +9,16 @@ import ( var _ authz.Authorization = &SendAuthorization{} // NewSendAuthorization creates a new SendAuthorization object. -func NewSendAuthorization(spendLimit sdk.Coins) *SendAuthorization { +func NewSendAuthorization(allowed []sdk.AccAddress, spendLimit sdk.Coins) (*SendAuthorization, error) { + allowedAddrs, err := validateAllowedAddresses(allowed) + if err != nil { + return nil, err + } + return &SendAuthorization{ + AllowList: allowedAddrs, SpendLimit: spendLimit, - } + }, nil } // MsgTypeURL implements Authorization.MsgTypeURL. @@ -47,3 +53,15 @@ func (a SendAuthorization) ValidateBasic() error { } return nil } + +func validateAllowedAddresses(allowed []sdk.AccAddress) ([]string, error) { + if len(allowed) == 0 { + return nil, nil + } + + allowedAddrs := make([]string, len(allowed)) + for i, addr := range allowed { + allowedAddrs[i] = addr.String() + } + return allowedAddrs, nil +} diff --git a/x/bank/types/send_authorization_test.go b/x/bank/types/send_authorization_test.go index 5e058317f1e9..98d5b2595547 100644 --- a/x/bank/types/send_authorization_test.go +++ b/x/bank/types/send_authorization_test.go @@ -21,7 +21,8 @@ var ( func TestSendAuthorization(t *testing.T) { app := simapp.Setup(t, false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - authorization := types.NewSendAuthorization(coins1000) + authorization, err := types.NewSendAuthorization([]sdk.AccAddress{}, coins1000) + require.NoError(t, err) t.Log("verify authorization returns valid method name") require.Equal(t, authorization.MsgTypeURL(), "/cosmos.bank.v1beta1.MsgSend") @@ -36,7 +37,8 @@ func TestSendAuthorization(t *testing.T) { require.True(t, resp.Delete) require.Nil(t, resp.Updated) - authorization = types.NewSendAuthorization(coins1000) + authorization, err = types.NewSendAuthorization([]sdk.AccAddress{}, coins1000) + require.NoError(t, err) require.Equal(t, authorization.MsgTypeURL(), "/cosmos.bank.v1beta1.MsgSend") require.NoError(t, authorization.ValidateBasic()) send = types.NewMsgSend(fromAddr, toAddr, coins500) @@ -47,7 +49,8 @@ func TestSendAuthorization(t *testing.T) { require.NoError(t, err) require.False(t, resp.Delete) require.NotNil(t, resp.Updated) - sendAuth := types.NewSendAuthorization(coins500) + sendAuth, err := types.NewSendAuthorization([]sdk.AccAddress{}, coins500) + require.NoError(t, err) require.Equal(t, sendAuth.String(), resp.Updated.String()) t.Log("expect updated authorization nil after spending remaining amount") From f2a735d385efa25000df03cca9742fe1dde57083 Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Wed, 20 Jul 2022 17:59:21 +0530 Subject: [PATCH 02/16] wip --- x/bank/types/send_authorization.go | 36 +++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/x/bank/types/send_authorization.go b/x/bank/types/send_authorization.go index ea608988ba53..2a64d21eb774 100644 --- a/x/bank/types/send_authorization.go +++ b/x/bank/types/send_authorization.go @@ -6,6 +6,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/authz" ) +// TODO: Revisit this once we have propoer gas fee framework. +// Tracking issues https://github.com/cosmos/cosmos-sdk/issues/9054, https://github.com/cosmos/cosmos-sdk/discussions/9072 +const gasCostPerIteration = uint64(10) + var _ authz.Authorization = &SendAuthorization{} // NewSendAuthorization creates a new SendAuthorization object. @@ -15,10 +19,16 @@ func NewSendAuthorization(allowed []sdk.AccAddress, spendLimit sdk.Coins) (*Send return nil, err } - return &SendAuthorization{ - AllowList: allowedAddrs, - SpendLimit: spendLimit, - }, nil + a := SendAuthorization{} + if allowedAddrs != nil { + a.AllowList = allowedAddrs + } + + if spendLimit != nil { + a.SpendLimit = spendLimit + } + + return &a, nil } // MsgTypeURL implements Authorization.MsgTypeURL. @@ -28,10 +38,12 @@ func (a SendAuthorization) MsgTypeURL() string { // Accept implements Authorization.Accept. func (a SendAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authz.AcceptResponse, error) { + var toAddr string mSend, ok := msg.(*MsgSend) if !ok { return authz.AcceptResponse{}, sdkerrors.ErrInvalidType.Wrap("type mismatch") } + toAddr = mSend.ToAddress limitLeft, isNegative := a.SpendLimit.SafeSub(mSend.Amount...) if isNegative { return authz.AcceptResponse{}, sdkerrors.ErrInsufficientFunds.Wrapf("requested amount is more than spend limit") @@ -40,7 +52,21 @@ func (a SendAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authz.AcceptRes return authz.AcceptResponse{Accept: true, Delete: true}, nil } - return authz.AcceptResponse{Accept: true, Delete: false, Updated: &SendAuthorization{SpendLimit: limitLeft}}, nil + isAddrExists := false + allowedList := a.GetAllowList() + + for _, addr := range allowedList { + ctx.GasMeter().ConsumeGas(gasCostPerIteration, "send authorization") + if addr == toAddr { + isAddrExists = true + break + } + } + + if len(allowedList) > 0 && !isAddrExists { + return authz.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrapf("cannot send to %s address", toAddr) + } + return authz.AcceptResponse{Accept: true, Delete: false, Updated: &SendAuthorization{SpendLimit: limitLeft, AllowList: allowedList}}, nil } // ValidateBasic implements Authorization.ValidateBasic. From fb82d5596ab352d13c4844a155fda1ac35c2a9cb Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Wed, 20 Jul 2022 23:01:20 +0530 Subject: [PATCH 03/16] add cli tests --- x/authz/client/testutil/grpc.go | 2 +- x/authz/client/testutil/query.go | 15 +++- x/authz/client/testutil/tx.go | 123 ++++++++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 4 deletions(-) diff --git a/x/authz/client/testutil/grpc.go b/x/authz/client/testutil/grpc.go index 20a0f7c903fc..f29f858cb22a 100644 --- a/x/authz/client/testutil/grpc.go +++ b/x/authz/client/testutil/grpc.go @@ -195,7 +195,7 @@ func (s *IntegrationTestSuite) TestQueryGranterGrantsGRPC() { fmt.Sprintf("%s/cosmos/authz/v1beta1/grants/granter/%s", val.APIAddress, val.Address.String()), false, "", - 7, + 8, }, } for _, tc := range testCases { diff --git a/x/authz/client/testutil/query.go b/x/authz/client/testutil/query.go index 45921a054de6..f4326ad4173f 100644 --- a/x/authz/client/testutil/query.go +++ b/x/authz/client/testutil/query.go @@ -161,7 +161,18 @@ func (s *IntegrationTestSuite) TestQueryAuthorization() { fmt.Sprintf("--%s=json", tmcli.OutputFlag), }, false, - `{"@type":"/cosmos.bank.v1beta1.SendAuthorization","spend_limit":[{"denom":"stake","amount":"100"}]}`, + `{"@type":"/cosmos.bank.v1beta1.SendAuthorization","spend_limit":[{"denom":"stake","amount":"100"}],"allow_list":[]}`, + }, + { + "Valid txn with allowed list (json)", + []string{ + val.Address.String(), + s.grantee[3].String(), + typeMsgSend, + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + fmt.Sprintf(`{"@type":"/cosmos.bank.v1beta1.SendAuthorization","spend_limit":[{"denom":"stake","amount":"88"}],"allow_list":["%s"]}`, s.grantee[4]), }, } for _, tc := range testCases { @@ -221,7 +232,7 @@ func (s *IntegrationTestSuite) TestQueryGranterGrants() { }, false, "", - 7, + 8, }, { "valid case with pagination", diff --git a/x/authz/client/testutil/tx.go b/x/authz/client/testutil/tx.go index f6a6b0a714e1..324fed9ee2ea 100644 --- a/x/authz/client/testutil/tx.go +++ b/x/authz/client/testutil/tx.go @@ -45,7 +45,7 @@ func (s *IntegrationTestSuite) SetupSuite() { s.Require().NoError(err) val := s.network.Validators[0] - s.grantee = make([]sdk.AccAddress, 3) + s.grantee = make([]sdk.AccAddress, 6) // Send some funds to the new account. // Create new account in the keyring. @@ -98,6 +98,30 @@ func (s *IntegrationTestSuite) SetupSuite() { }) s.Require().NoError(err) + // Create new accounts in the keyring. + s.grantee[3] = s.createAccount("grantee4") + s.msgSendExec(s.grantee[3]) + + s.grantee[4] = s.createAccount("grantee5") + s.grantee[5] = s.createAccount("grantee6") + + // grant send authorization with allow list to grantee4 + out, err = CreateGrant( + val, + []string{ + s.grantee[3].String(), + "send", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, time.Now().Add(time.Minute*time.Duration(120)).Unix()), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", cli.FlagAllowList, s.grantee[4]), + }, + ) + s.Require().NoError(err) + err = s.network.WaitForNextBlock() s.Require().NoError(err) @@ -404,6 +428,23 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() { false, "", }, + { + "Valid tx send authorization with allow list", + []string{ + grantee.String(), + "send", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", cli.FlagAllowList, s.grantee[1]), + }, + 0, + false, + "", + }, { "Valid tx generic authorization", []string{ @@ -877,6 +918,86 @@ func (s *IntegrationTestSuite) TestNewExecGrantAuthorized() { } } +func (s *IntegrationTestSuite) TestExecSendAuthzWithAllowList() { + val := s.network.Validators[0] + grantee := s.grantee[3] + allowedAddr := s.grantee[4] + notAllowedAddr := s.grantee[5] + twoHours := time.Now().Add(time.Minute * time.Duration(120)).Unix() + + _, err := CreateGrant( + val, + []string{ + grantee.String(), + "send", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", cli.FlagAllowList, allowedAddr), + }, + ) + s.Require().NoError(err) + + tokens := sdk.NewCoins( + sdk.NewCoin("stake", sdk.NewInt(12)), + ) + + validGeneratedTx, err := banktestutil.MsgSendExec( + val.ClientCtx, + val.Address, + allowedAddr, + tokens, + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + s.Require().NoError(err) + execMsg := testutil.WriteToNewTempFile(s.T(), validGeneratedTx.String()) + + invalidGeneratedTx, err := banktestutil.MsgSendExec( + val.ClientCtx, + val.Address, + notAllowedAddr, + tokens, + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + s.Require().NoError(err) + execMsg1 := testutil.WriteToNewTempFile(s.T(), invalidGeneratedTx.String()) + + // test sending to allowed address + args := []string{ + execMsg.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + } + var response sdk.TxResponse + cmd := cli.NewCmdExecAuthorization() + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String()) + + // test sending to not allowed address + args = []string{ + execMsg1.Name(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, grantee.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + } + out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) + s.Require().NoError(err) + s.Contains(out.String(), fmt.Sprintf("cannot send to %s address", notAllowedAddr)) +} + func (s *IntegrationTestSuite) TestExecDelegateAuthorization() { val := s.network.Validators[0] grantee := s.grantee[0] From a28e4c72c6cfe98b38348207fbfd92c95ed441eb Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Thu, 21 Jul 2022 16:08:54 +0530 Subject: [PATCH 04/16] add changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4603f10f827c..8d9c885f3fc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* (x/authz) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) Add an allow list, an optional list of addresses allowed to receive bank assests via authz MsgSend grant. * (cli) [#12028](https://github.com/cosmos/cosmos-sdk/pull/12028) Add the `tendermint key-migrate` to perform Tendermint v0.35 DB key migration. * (query) [#12253](https://github.com/cosmos/cosmos-sdk/pull/12253) Add `GenericFilteredPaginate` to the `query` package to improve UX. * (telemetry) [#12405](https://github.com/cosmos/cosmos-sdk/pull/12405) Add _query_ calls metric to telemetry. @@ -70,6 +71,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* (x/authz) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) Add an allow list, an optional list of addresses allowed to receive bank assests via authz MsgSend grant. * (x/bank) [\#12593](https://github.com/cosmos/cosmos-sdk/pull/12593) Add `SpendableCoin` method to `BaseViewKeeper` * (x/slashing) [#12581](https://github.com/cosmos/cosmos-sdk/pull/12581) Remove `x/slashing` legacy querier. * (types) [\#12355](https://github.com/cosmos/cosmos-sdk/pull/12355) Remove the compile-time `types.DBbackend` variable. Removes usage of the same in server/util.go From 0ab505e65dcf8131b629b4ff945f2e679f26d58e Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Thu, 21 Jul 2022 17:02:13 +0530 Subject: [PATCH 05/16] add validation for duplicate entry and related tests --- x/authz/client/testutil/tx.go | 19 ++++++++++++++++++- x/bank/types/errors.go | 1 + x/bank/types/send_authorization.go | 9 +++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/x/authz/client/testutil/tx.go b/x/authz/client/testutil/tx.go index 324fed9ee2ea..537ac8319a9a 100644 --- a/x/authz/client/testutil/tx.go +++ b/x/authz/client/testutil/tx.go @@ -86,7 +86,7 @@ func (s *IntegrationTestSuite) SetupSuite() { s.grantee[2] = s.createAccount("grantee3") // grant send authorization to grantee3 - out, err = CreateGrant(val, []string{ + _, err = CreateGrant(val, []string{ s.grantee[2].String(), "send", fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), @@ -445,6 +445,23 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() { false, "", }, + { + "Invalid tx send authorization with duplicate allow list", + []string{ + grantee.String(), + "send", + fmt.Sprintf("--%s=100stake", cli.FlagSpendLimit), + fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", cli.FlagAllowList, fmt.Sprintf("%s,%s", s.grantee[1], s.grantee[1])), + }, + 0, + true, + "duplicate entry", + }, { "Valid tx generic authorization", []string{ diff --git a/x/bank/types/errors.go b/x/bank/types/errors.go index 00851d165f80..ed3e2f86b351 100644 --- a/x/bank/types/errors.go +++ b/x/bank/types/errors.go @@ -11,4 +11,5 @@ var ( ErrSendDisabled = sdkerrors.Register(ModuleName, 5, "send transactions are disabled") ErrDenomMetadataNotFound = sdkerrors.Register(ModuleName, 6, "client denom metadata not found") ErrInvalidKey = sdkerrors.Register(ModuleName, 7, "invalid key") + ErrDuplicateEntry = sdkerrors.Register(ModuleName, 8, "duplicate entry") ) diff --git a/x/bank/types/send_authorization.go b/x/bank/types/send_authorization.go index 2a64d21eb774..3184596b633f 100644 --- a/x/bank/types/send_authorization.go +++ b/x/bank/types/send_authorization.go @@ -77,6 +77,15 @@ func (a SendAuthorization) ValidateBasic() error { if !a.SpendLimit.IsAllPositive() { return sdkerrors.ErrInvalidCoins.Wrapf("spend limit must be positive") } + + found := make(map[string]bool, 0) + for i := 0; i < len(a.AllowList); i++ { + if found[a.AllowList[i]] { + return ErrDuplicateEntry + } else { + found[a.AllowList[i]] = true + } + } return nil } From ff0a2fd2b0c79e8fdd3a0dd9f65de417e4145263 Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Mon, 25 Jul 2022 11:48:07 +0530 Subject: [PATCH 06/16] address review comments --- x/authz/client/cli/tx.go | 4 ++-- x/bank/types/send_authorization.go | 14 +++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/x/authz/client/cli/tx.go b/x/authz/client/cli/tx.go index 9edceac5f179..2257e8453dae 100644 --- a/x/authz/client/cli/tx.go +++ b/x/authz/client/cli/tx.go @@ -99,7 +99,7 @@ Examples: return err } - allowed, err := bech32toAccountAddresses(allowList) + allowed, err := bech32toAccAddresses(allowList) if err != nil { return err } @@ -301,7 +301,7 @@ func bech32toValidatorAddresses(validators []string) ([]sdk.ValAddress, error) { return vals, nil } -func bech32toAccountAddresses(accAddrs []string) ([]sdk.AccAddress, error) { +func bech32toAccAddresses(accAddrs []string) ([]sdk.AccAddress, error) { addrs := make([]sdk.AccAddress, len(accAddrs)) for i, addr := range accAddrs { accAddr, err := sdk.AccAddressFromBech32(addr) diff --git a/x/bank/types/send_authorization.go b/x/bank/types/send_authorization.go index 3184596b633f..7901d3297f66 100644 --- a/x/bank/types/send_authorization.go +++ b/x/bank/types/send_authorization.go @@ -14,10 +14,7 @@ var _ authz.Authorization = &SendAuthorization{} // NewSendAuthorization creates a new SendAuthorization object. func NewSendAuthorization(allowed []sdk.AccAddress, spendLimit sdk.Coins) (*SendAuthorization, error) { - allowedAddrs, err := validateAllowedAddresses(allowed) - if err != nil { - return nil, err - } + allowedAddrs := toBech32Addresses(allowed) a := SendAuthorization{} if allowedAddrs != nil { @@ -82,21 +79,20 @@ func (a SendAuthorization) ValidateBasic() error { for i := 0; i < len(a.AllowList); i++ { if found[a.AllowList[i]] { return ErrDuplicateEntry - } else { - found[a.AllowList[i]] = true } + found[a.AllowList[i]] = true } return nil } -func validateAllowedAddresses(allowed []sdk.AccAddress) ([]string, error) { +func toBech32Addresses(allowed []sdk.AccAddress) []string { if len(allowed) == 0 { - return nil, nil + return nil } allowedAddrs := make([]string, len(allowed)) for i, addr := range allowed { allowedAddrs[i] = addr.String() } - return allowedAddrs, nil + return allowedAddrs } From 75671822a4d1e7ac0d73448adcb8a7f1534e8bc9 Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Mon, 25 Jul 2022 11:57:24 +0530 Subject: [PATCH 07/16] move account helpers from x/authz cli to auth account types --- x/auth/types/account.go | 26 ++++++++++++++++++++++++++ x/authz/client/cli/tx.go | 31 ++++--------------------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/x/auth/types/account.go b/x/auth/types/account.go index a8331c82c8eb..e4783b8d23e5 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -298,6 +298,32 @@ func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error { return nil } +// Bech32toValidatorAddresses returns []ValAddress from a list of Bech32 string addresses. +func Bech32toValidatorAddresses(validators []string) ([]sdk.ValAddress, error) { + vals := make([]sdk.ValAddress, len(validators)) + for i, validator := range validators { + addr, err := sdk.ValAddressFromBech32(validator) + if err != nil { + return nil, err + } + vals[i] = addr + } + return vals, nil +} + +// Bech32toAccAddresses returns []AccAddress from a list of Bech32 string addresses. +func Bech32toAccAddresses(accAddrs []string) ([]sdk.AccAddress, error) { + addrs := make([]sdk.AccAddress, len(accAddrs)) + for i, addr := range accAddrs { + accAddr, err := sdk.AccAddressFromBech32(addr) + if err != nil { + return nil, err + } + addrs[i] = accAddr + } + return addrs, nil +} + // AccountI is an interface used to store coins at a given address within state. // It presumes a notion of sequence numbers for replay protection, // a notion of account numbers for replay protection for previously pruned accounts, diff --git a/x/authz/client/cli/tx.go b/x/authz/client/cli/tx.go index 2257e8453dae..cdd54a69dfcb 100644 --- a/x/authz/client/cli/tx.go +++ b/x/authz/client/cli/tx.go @@ -14,6 +14,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/authz" bank "github.com/cosmos/cosmos-sdk/x/bank/types" staking "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -99,7 +100,7 @@ Examples: return err } - allowed, err := bech32toAccAddresses(allowList) + allowed, err := authtypes.Bech32toAccAddresses(allowList) if err != nil { return err } @@ -155,12 +156,12 @@ Examples: delegateLimit = &spendLimit } - allowed, err := bech32toValidatorAddresses(allowValidators) + allowed, err := authtypes.Bech32toValidatorAddresses(allowValidators) if err != nil { return err } - denied, err := bech32toValidatorAddresses(denyValidators) + denied, err := authtypes.Bech32toValidatorAddresses(denyValidators) if err != nil { return err } @@ -288,27 +289,3 @@ Example: return cmd } - -func bech32toValidatorAddresses(validators []string) ([]sdk.ValAddress, error) { - vals := make([]sdk.ValAddress, len(validators)) - for i, validator := range validators { - addr, err := sdk.ValAddressFromBech32(validator) - if err != nil { - return nil, err - } - vals[i] = addr - } - return vals, nil -} - -func bech32toAccAddresses(accAddrs []string) ([]sdk.AccAddress, error) { - addrs := make([]sdk.AccAddress, len(accAddrs)) - for i, addr := range accAddrs { - accAddr, err := sdk.AccAddressFromBech32(addr) - if err != nil { - return nil, err - } - addrs[i] = accAddr - } - return addrs, nil -} From 922c69c207dea025f953d25e4bc4814a67b2550d Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Mon, 25 Jul 2022 14:52:08 +0530 Subject: [PATCH 08/16] address more comments --- types/address.go | 26 ++++++++++++++++++++++++++ x/auth/types/account.go | 26 -------------------------- x/authz/client/cli/tx.go | 7 +++---- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/types/address.go b/types/address.go index 5b7f1b578550..33956edef818 100644 --- a/types/address.go +++ b/types/address.go @@ -677,3 +677,29 @@ func cacheBech32Addr(prefix string, addr []byte, cache *simplelru.LRU, cacheKey cache.Add(cacheKey, bech32Addr) return bech32Addr } + +// Bech32toValidatorAddresses returns []ValAddress from a list of Bech32 string addresses. +func Bech32toValidatorAddresses(validators []string) ([]ValAddress, error) { + vals := make([]ValAddress, len(validators)) + for i, validator := range validators { + addr, err := ValAddressFromBech32(validator) + if err != nil { + return nil, err + } + vals[i] = addr + } + return vals, nil +} + +// Bech32toAccAddresses returns []AccAddress from a list of Bech32 string addresses. +func Bech32toAccAddresses(accAddrs []string) ([]AccAddress, error) { + addrs := make([]AccAddress, len(accAddrs)) + for i, addr := range accAddrs { + accAddr, err := AccAddressFromBech32(addr) + if err != nil { + return nil, err + } + addrs[i] = accAddr + } + return addrs, nil +} diff --git a/x/auth/types/account.go b/x/auth/types/account.go index e4783b8d23e5..a8331c82c8eb 100644 --- a/x/auth/types/account.go +++ b/x/auth/types/account.go @@ -298,32 +298,6 @@ func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error { return nil } -// Bech32toValidatorAddresses returns []ValAddress from a list of Bech32 string addresses. -func Bech32toValidatorAddresses(validators []string) ([]sdk.ValAddress, error) { - vals := make([]sdk.ValAddress, len(validators)) - for i, validator := range validators { - addr, err := sdk.ValAddressFromBech32(validator) - if err != nil { - return nil, err - } - vals[i] = addr - } - return vals, nil -} - -// Bech32toAccAddresses returns []AccAddress from a list of Bech32 string addresses. -func Bech32toAccAddresses(accAddrs []string) ([]sdk.AccAddress, error) { - addrs := make([]sdk.AccAddress, len(accAddrs)) - for i, addr := range accAddrs { - accAddr, err := sdk.AccAddressFromBech32(addr) - if err != nil { - return nil, err - } - addrs[i] = accAddr - } - return addrs, nil -} - // AccountI is an interface used to store coins at a given address within state. // It presumes a notion of sequence numbers for replay protection, // a notion of account numbers for replay protection for previously pruned accounts, diff --git a/x/authz/client/cli/tx.go b/x/authz/client/cli/tx.go index cdd54a69dfcb..c7e2874cd58e 100644 --- a/x/authz/client/cli/tx.go +++ b/x/authz/client/cli/tx.go @@ -14,7 +14,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/authz" bank "github.com/cosmos/cosmos-sdk/x/bank/types" staking "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -100,7 +99,7 @@ Examples: return err } - allowed, err := authtypes.Bech32toAccAddresses(allowList) + allowed, err := sdk.Bech32toAccAddresses(allowList) if err != nil { return err } @@ -156,12 +155,12 @@ Examples: delegateLimit = &spendLimit } - allowed, err := authtypes.Bech32toValidatorAddresses(allowValidators) + allowed, err := sdk.Bech32toValidatorAddresses(allowValidators) if err != nil { return err } - denied, err := authtypes.Bech32toValidatorAddresses(denyValidators) + denied, err := sdk.Bech32toValidatorAddresses(denyValidators) if err != nil { return err } From 759710ebfe374fba43aad1433626d84c5bbdb544 Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Mon, 25 Jul 2022 14:54:06 +0530 Subject: [PATCH 09/16] nit --- types/address.go | 4 ++-- x/authz/client/cli/tx.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/types/address.go b/types/address.go index 33956edef818..d4a03aae61f7 100644 --- a/types/address.go +++ b/types/address.go @@ -678,8 +678,8 @@ func cacheBech32Addr(prefix string, addr []byte, cache *simplelru.LRU, cacheKey return bech32Addr } -// Bech32toValidatorAddresses returns []ValAddress from a list of Bech32 string addresses. -func Bech32toValidatorAddresses(validators []string) ([]ValAddress, error) { +// Bech32toValAddresses returns []ValAddress from a list of Bech32 string addresses. +func Bech32toValAddresses(validators []string) ([]ValAddress, error) { vals := make([]ValAddress, len(validators)) for i, validator := range validators { addr, err := ValAddressFromBech32(validator) diff --git a/x/authz/client/cli/tx.go b/x/authz/client/cli/tx.go index c7e2874cd58e..16f03f1de0bb 100644 --- a/x/authz/client/cli/tx.go +++ b/x/authz/client/cli/tx.go @@ -155,12 +155,12 @@ Examples: delegateLimit = &spendLimit } - allowed, err := sdk.Bech32toValidatorAddresses(allowValidators) + allowed, err := sdk.Bech32toValAddresses(allowValidators) if err != nil { return err } - denied, err := sdk.Bech32toValidatorAddresses(denyValidators) + denied, err := sdk.Bech32toValAddresses(denyValidators) if err != nil { return err } From 2941e48644d6c4ae50308f65ef4518af0c806c29 Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Tue, 26 Jul 2022 11:12:24 +0530 Subject: [PATCH 10/16] address review comments --- CHANGELOG.md | 2 +- api/cosmos/bank/v1beta1/authz.pulsar.go | 6 ++-- api/cosmos/staking/v1beta1/tx_grpc.pb.go | 4 +-- proto/cosmos/bank/v1beta1/authz.proto | 6 ++-- types/address.go | 26 ----------------- x/authz/client/cli/tx.go | 37 +++++++++++++++++++----- x/authz/keeper/keeper_test.go | 7 ++--- x/authz/migrations/v046/store_test.go | 3 +- x/authz/module/abci_test.go | 3 +- x/authz/msgs_test.go | 3 +- x/authz/simulation/decoder_test.go | 3 +- x/authz/simulation/genesis.go | 14 +++------ x/authz/simulation/operations.go | 5 +--- x/authz/simulation/operations_test.go | 10 +++---- x/bank/types/authz.pb.go | 6 ++-- x/bank/types/send_authorization.go | 11 +++---- x/bank/types/send_authorization_test.go | 9 ++---- x/staking/types/tx.pb.go | 4 +-- 18 files changed, 69 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75a9dc2b2795..12685e42c14b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,7 +74,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes -* (x/authz) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) Add an allow list, an optional list of addresses allowed to receive bank assests via authz MsgSend grant. +* (x/bank) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) `NewSendAuthorization` takes a new argument of an optional list of addresses allowed to receive bank assests via authz MsgSend grant. You can pass `nil` for the same behavior as before, i.e. any recipient is allowed. * (x/bank) [\#12593](https://github.com/cosmos/cosmos-sdk/pull/12593) Add `SpendableCoin` method to `BaseViewKeeper` * (x/slashing) [#12581](https://github.com/cosmos/cosmos-sdk/pull/12581) Remove `x/slashing` legacy querier. * (types) [\#12355](https://github.com/cosmos/cosmos-sdk/pull/12355) Remove the compile-time `types.DBbackend` variable. Removes usage of the same in server/util.go diff --git a/api/cosmos/bank/v1beta1/authz.pulsar.go b/api/cosmos/bank/v1beta1/authz.pulsar.go index 9874466cdb8a..144371420335 100644 --- a/api/cosmos/bank/v1beta1/authz.pulsar.go +++ b/api/cosmos/bank/v1beta1/authz.pulsar.go @@ -656,8 +656,10 @@ type SendAuthorization struct { unknownFields protoimpl.UnknownFields SpendLimit []*v1beta1.Coin `protobuf:"bytes,1,rep,name=spend_limit,json=spendLimit,proto3" json:"spend_limit,omitempty"` - // allow_list specifies the list of addresses to whom the grantee can send tokens on behalf of granter's - // account. + // allow_list specifies an optional list of addresses to whom the grantee can send tokens on behalf of the + // granter. If omitted, any recipient is allowed. + // + // Since: cosmos-sdk 0.47 AllowList []string `protobuf:"bytes,2,rep,name=allow_list,json=allowList,proto3" json:"allow_list,omitempty"` } diff --git a/api/cosmos/staking/v1beta1/tx_grpc.pb.go b/api/cosmos/staking/v1beta1/tx_grpc.pb.go index ee50ca5ab56b..60a83c19955b 100644 --- a/api/cosmos/staking/v1beta1/tx_grpc.pb.go +++ b/api/cosmos/staking/v1beta1/tx_grpc.pb.go @@ -40,7 +40,7 @@ type MsgClient interface { // // Since: cosmos-sdk 0.46 CancelUnbondingDelegation(ctx context.Context, in *MsgCancelUnbondingDelegation, opts ...grpc.CallOption) (*MsgCancelUnbondingDelegationResponse, error) - // UpdateParams defines a operation for updating the x/staking module + // UpdateParams defines an operation for updating the x/staking module // parameters. // Since: cosmos-sdk 0.47 UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) @@ -139,7 +139,7 @@ type MsgServer interface { // // Since: cosmos-sdk 0.46 CancelUnbondingDelegation(context.Context, *MsgCancelUnbondingDelegation) (*MsgCancelUnbondingDelegationResponse, error) - // UpdateParams defines a operation for updating the x/staking module + // UpdateParams defines an operation for updating the x/staking module // parameters. // Since: cosmos-sdk 0.47 UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) diff --git a/proto/cosmos/bank/v1beta1/authz.proto b/proto/cosmos/bank/v1beta1/authz.proto index cc8eb9ae0f75..36f695f4c937 100644 --- a/proto/cosmos/bank/v1beta1/authz.proto +++ b/proto/cosmos/bank/v1beta1/authz.proto @@ -17,7 +17,9 @@ message SendAuthorization { repeated cosmos.base.v1beta1.Coin spend_limit = 1 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; - // allow_list specifies the list of addresses to whom the grantee can send tokens on behalf of granter's - // account. + // allow_list specifies an optional list of addresses to whom the grantee can send tokens on behalf of the + // granter. If omitted, any recipient is allowed. + // + // Since: cosmos-sdk 0.47 repeated string allow_list = 2; } diff --git a/types/address.go b/types/address.go index d4a03aae61f7..5b7f1b578550 100644 --- a/types/address.go +++ b/types/address.go @@ -677,29 +677,3 @@ func cacheBech32Addr(prefix string, addr []byte, cache *simplelru.LRU, cacheKey cache.Add(cacheKey, bech32Addr) return bech32Addr } - -// Bech32toValAddresses returns []ValAddress from a list of Bech32 string addresses. -func Bech32toValAddresses(validators []string) ([]ValAddress, error) { - vals := make([]ValAddress, len(validators)) - for i, validator := range validators { - addr, err := ValAddressFromBech32(validator) - if err != nil { - return nil, err - } - vals[i] = addr - } - return vals, nil -} - -// Bech32toAccAddresses returns []AccAddress from a list of Bech32 string addresses. -func Bech32toAccAddresses(accAddrs []string) ([]AccAddress, error) { - addrs := make([]AccAddress, len(accAddrs)) - for i, addr := range accAddrs { - accAddr, err := AccAddressFromBech32(addr) - if err != nil { - return nil, err - } - addrs[i] = accAddr - } - return addrs, nil -} diff --git a/x/authz/client/cli/tx.go b/x/authz/client/cli/tx.go index 16f03f1de0bb..0e35e659235d 100644 --- a/x/authz/client/cli/tx.go +++ b/x/authz/client/cli/tx.go @@ -99,15 +99,12 @@ Examples: return err } - allowed, err := sdk.Bech32toAccAddresses(allowList) + allowed, err := bech32toAccAddresses(allowList) if err != nil { return err } - authorization, err = bank.NewSendAuthorization(allowed, spendLimit) - if err != nil { - return err - } + authorization = bank.NewSendAuthorization(spendLimit, allowed) case "generic": msgType, err := cmd.Flags().GetString(FlagMsgType) @@ -155,12 +152,12 @@ Examples: delegateLimit = &spendLimit } - allowed, err := sdk.Bech32toValAddresses(allowValidators) + allowed, err := bech32toValAddresses(allowValidators) if err != nil { return err } - denied, err := sdk.Bech32toValAddresses(denyValidators) + denied, err := bech32toValAddresses(denyValidators) if err != nil { return err } @@ -288,3 +285,29 @@ Example: return cmd } + +// bech32toValAddresses returns []ValAddress from a list of Bech32 string addresses. +func bech32toValAddresses(validators []string) ([]sdk.ValAddress, error) { + vals := make([]sdk.ValAddress, len(validators)) + for i, validator := range validators { + addr, err := sdk.ValAddressFromBech32(validator) + if err != nil { + return nil, err + } + vals[i] = addr + } + return vals, nil +} + +// bech32toAccAddresses returns []AccAddress from a list of Bech32 string addresses. +func bech32toAccAddresses(accAddrs []string) ([]sdk.AccAddress, error) { + addrs := make([]sdk.AccAddress, len(accAddrs)) + for i, addr := range accAddrs { + accAddr, err := sdk.AccAddressFromBech32(addr) + if err != nil { + return nil, err + } + addrs[i] = accAddr + } + return addrs, nil +} diff --git a/x/authz/keeper/keeper_test.go b/x/authz/keeper/keeper_test.go index bc8e57b06e39..4083888440db 100644 --- a/x/authz/keeper/keeper_test.go +++ b/x/authz/keeper/keeper_test.go @@ -4,7 +4,6 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" tmtime "github.com/tendermint/tendermint/libs/time" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -126,8 +125,7 @@ func (s *TestSuite) TestKeeperIter() { granteeAddr := addrs[1] granter2Addr := addrs[2] e := ctx.BlockTime().AddDate(1, 0, 0) - sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, coins100) - require.NoError(s.T(), err) + sendAuthz := banktypes.NewSendAuthorization(coins100, nil) s.authzKeeper.SaveGrant(ctx, granteeAddr, granterAddr, sendAuthz, &e) s.authzKeeper.SaveGrant(ctx, granteeAddr, granter2Addr, sendAuthz, &e) @@ -147,8 +145,7 @@ func (s *TestSuite) TestDispatchAction() { granterAddr := addrs[0] granteeAddr := addrs[1] recipientAddr := addrs[2] - a, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, coins100) - require.NoError(err) + a := banktypes.NewSendAuthorization(coins100, nil) require.NoError(banktestutil.FundAccount(s.bankKeeper, s.ctx, granterAddr, coins1000)) diff --git a/x/authz/migrations/v046/store_test.go b/x/authz/migrations/v046/store_test.go index 30b94d13c925..5d3241f452ef 100644 --- a/x/authz/migrations/v046/store_test.go +++ b/x/authz/migrations/v046/store_test.go @@ -35,8 +35,7 @@ func TestMigration(t *testing.T) { blockTime := ctx.BlockTime() oneDay := blockTime.AddDate(0, 0, 1) oneYear := blockTime.AddDate(1, 0, 0) - sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, coins100) - require.NoError(t, err) + sendAuthz := banktypes.NewSendAuthorization(coins100, nil) grants := []struct { granter sdk.AccAddress diff --git a/x/authz/module/abci_test.go b/x/authz/module/abci_test.go index f3d44a66a8cc..cc6deae50a85 100644 --- a/x/authz/module/abci_test.go +++ b/x/authz/module/abci_test.go @@ -44,8 +44,7 @@ func TestExpiredGrantsQueue(t *testing.T) { expiration := ctx.BlockTime().AddDate(0, 1, 0) expiration2 := expiration.AddDate(1, 0, 0) smallCoins := sdk.NewCoins(sdk.NewInt64Coin("stake", 10)) - sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, smallCoins) - require.NoError(t, err) + sendAuthz := banktypes.NewSendAuthorization(smallCoins, nil) save := func(grantee sdk.AccAddress, exp *time.Time) { err := authzKeeper.SaveGrant(ctx, grantee, granter, sendAuthz, exp) diff --git a/x/authz/msgs_test.go b/x/authz/msgs_test.go index c874706372f2..5d7eb3c39fb9 100644 --- a/x/authz/msgs_test.go +++ b/x/authz/msgs_test.go @@ -174,8 +174,7 @@ func TestAminoJSON(t *testing.T) { require.NoError(t, err) grant, err := authz.NewGrant(blockTime, authz.NewGenericAuthorization(typeURL), &expiresAt) require.NoError(t, err) - sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))) - require.NoError(t, err) + sendAuthz := banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), nil) sendGrant, err := authz.NewGrant(blockTime, sendAuthz, &expiresAt) require.NoError(t, err) valAddr, err := sdk.ValAddressFromBech32("cosmosvaloper1xcy3els9ua75kdm783c3qu0rfa2eples6eavqq") diff --git a/x/authz/simulation/decoder_test.go b/x/authz/simulation/decoder_test.go index e919e42940b2..f197ac8c3716 100644 --- a/x/authz/simulation/decoder_test.go +++ b/x/authz/simulation/decoder_test.go @@ -26,8 +26,7 @@ func TestDecodeStore(t *testing.T) { now := time.Now().UTC() e := now.Add(1) - sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, sdk.NewCoins(sdk.NewInt64Coin("foo", 123))) - require.NoError(t, err) + sendAuthz := banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewInt64Coin("foo", 123)), nil) grant, _ := authz.NewGrant(now, sendAuthz, &e) grantBz, err := cdc.Marshal(&grant) require.NoError(t, err) diff --git a/x/authz/simulation/genesis.go b/x/authz/simulation/genesis.go index 39866e728564..afecc6720d73 100644 --- a/x/authz/simulation/genesis.go +++ b/x/authz/simulation/genesis.go @@ -2,7 +2,6 @@ package simulation import ( "math/rand" - "testing" "time" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -12,7 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/authz" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" - "github.com/stretchr/testify/require" ) // genGrant returns a slice of authorization grants. @@ -26,8 +24,7 @@ func genGrant(r *rand.Rand, accounts []simtypes.Account, genT time.Time) []authz e := genT.AddDate(1, 0, 0) expiration = &e } - grant, err := generateRandomGrant(r) - require.NoError(&testing.T{}, err) + grant := generateRandomGrant(r) authorizations[i] = authz.GrantAuthorization{ Granter: granter.Address.String(), Grantee: grantee.Address.String(), @@ -39,16 +36,13 @@ func genGrant(r *rand.Rand, accounts []simtypes.Account, genT time.Time) []authz return authorizations } -func generateRandomGrant(r *rand.Rand) (*codectypes.Any, error) { +func generateRandomGrant(r *rand.Rand) *codectypes.Any { authorizations := make([]*codectypes.Any, 2) - sendAuthz, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))) - if err != nil { - return nil, err - } + sendAuthz := banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))), nil) authorizations[0] = newAnyAuthorization(sendAuthz) authorizations[1] = newAnyAuthorization(authz.NewGenericAuthorization(sdk.MsgTypeURL(&v1.MsgSubmitProposal{}))) - return authorizations[r.Intn(len(authorizations))], nil + return authorizations[r.Intn(len(authorizations))] } func newAnyAuthorization(a authz.Authorization) *codectypes.Any { diff --git a/x/authz/simulation/operations.go b/x/authz/simulation/operations.go index 42f6c97c65c1..5defd40631a7 100644 --- a/x/authz/simulation/operations.go +++ b/x/authz/simulation/operations.go @@ -152,10 +152,7 @@ func SimulateMsgGrant(cdc *codec.ProtoCodec, ak authz.AccountKeeper, bk authz.Ba func generateRandomAuthorization(r *rand.Rand, spendLimit sdk.Coins) (authz.Authorization, error) { authorizations := make([]authz.Authorization, 2) - sendAuthz, err := banktype.NewSendAuthorization([]sdk.AccAddress{}, spendLimit) - if err != nil { - return nil, err - } + sendAuthz := banktype.NewSendAuthorization(spendLimit, nil) authorizations[0] = sendAuthz authorizations[1] = authz.NewGenericAuthorization(sdk.MsgTypeURL(&banktype.MsgSend{})) diff --git a/x/authz/simulation/operations_test.go b/x/authz/simulation/operations_test.go index a205d98db90f..f2e1ce6dc50a 100644 --- a/x/authz/simulation/operations_test.go +++ b/x/authz/simulation/operations_test.go @@ -161,11 +161,10 @@ func (suite *SimTestSuite) TestSimulateRevoke() { granter := accounts[0] grantee := accounts[1] - a, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, initCoins) - suite.Require().NoError(err) + a := banktypes.NewSendAuthorization(initCoins, nil) expire := time.Now().Add(30 * time.Hour) - err = suite.authzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, a, &expire) + err := suite.authzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, a, &expire) suite.Require().NoError(err) // execute operation @@ -197,11 +196,10 @@ func (suite *SimTestSuite) TestSimulateExec() { granter := accounts[0] grantee := accounts[1] - a, err := banktypes.NewSendAuthorization([]sdk.AccAddress{}, initCoins) - suite.Require().NoError(err) + a := banktypes.NewSendAuthorization(initCoins, nil) expire := suite.ctx.BlockTime().Add(1 * time.Hour) - err = suite.authzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, a, &expire) + err := suite.authzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, a, &expire) suite.Require().NoError(err) // execute operation diff --git a/x/bank/types/authz.pb.go b/x/bank/types/authz.pb.go index 362aba584c57..8a2f6ae3a8f3 100644 --- a/x/bank/types/authz.pb.go +++ b/x/bank/types/authz.pb.go @@ -32,8 +32,10 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Since: cosmos-sdk 0.43 type SendAuthorization struct { SpendLimit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=spend_limit,json=spendLimit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"spend_limit"` - // allow_list specifies the list of addresses to whom the grantee can send tokens on behalf of granter's - // account. + // allow_list specifies an optional list of addresses to whom the grantee can send tokens on behalf of the + // granter. If omitted, any recipient is allowed. + // + // Since: cosmos-sdk 0.47 AllowList []string `protobuf:"bytes,2,rep,name=allow_list,json=allowList,proto3" json:"allow_list,omitempty"` } diff --git a/x/bank/types/send_authorization.go b/x/bank/types/send_authorization.go index 7901d3297f66..b7eb3e397f85 100644 --- a/x/bank/types/send_authorization.go +++ b/x/bank/types/send_authorization.go @@ -13,19 +13,17 @@ const gasCostPerIteration = uint64(10) var _ authz.Authorization = &SendAuthorization{} // NewSendAuthorization creates a new SendAuthorization object. -func NewSendAuthorization(allowed []sdk.AccAddress, spendLimit sdk.Coins) (*SendAuthorization, error) { +func NewSendAuthorization(spendLimit sdk.Coins, allowed []sdk.AccAddress) *SendAuthorization { allowedAddrs := toBech32Addresses(allowed) a := SendAuthorization{} - if allowedAddrs != nil { - a.AllowList = allowedAddrs - } + a.AllowList = allowedAddrs if spendLimit != nil { a.SpendLimit = spendLimit } - return &a, nil + return &a } // MsgTypeURL implements Authorization.MsgTypeURL. @@ -35,12 +33,11 @@ func (a SendAuthorization) MsgTypeURL() string { // Accept implements Authorization.Accept. func (a SendAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authz.AcceptResponse, error) { - var toAddr string mSend, ok := msg.(*MsgSend) if !ok { return authz.AcceptResponse{}, sdkerrors.ErrInvalidType.Wrap("type mismatch") } - toAddr = mSend.ToAddress + toAddr := mSend.ToAddress limitLeft, isNegative := a.SpendLimit.SafeSub(mSend.Amount...) if isNegative { return authz.AcceptResponse{}, sdkerrors.ErrInsufficientFunds.Wrapf("requested amount is more than spend limit") diff --git a/x/bank/types/send_authorization_test.go b/x/bank/types/send_authorization_test.go index 98d5b2595547..89e033037fe5 100644 --- a/x/bank/types/send_authorization_test.go +++ b/x/bank/types/send_authorization_test.go @@ -21,8 +21,7 @@ var ( func TestSendAuthorization(t *testing.T) { app := simapp.Setup(t, false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - authorization, err := types.NewSendAuthorization([]sdk.AccAddress{}, coins1000) - require.NoError(t, err) + authorization := types.NewSendAuthorization(coins1000, nil) t.Log("verify authorization returns valid method name") require.Equal(t, authorization.MsgTypeURL(), "/cosmos.bank.v1beta1.MsgSend") @@ -37,8 +36,7 @@ func TestSendAuthorization(t *testing.T) { require.True(t, resp.Delete) require.Nil(t, resp.Updated) - authorization, err = types.NewSendAuthorization([]sdk.AccAddress{}, coins1000) - require.NoError(t, err) + authorization = types.NewSendAuthorization(coins1000, nil) require.Equal(t, authorization.MsgTypeURL(), "/cosmos.bank.v1beta1.MsgSend") require.NoError(t, authorization.ValidateBasic()) send = types.NewMsgSend(fromAddr, toAddr, coins500) @@ -49,8 +47,7 @@ func TestSendAuthorization(t *testing.T) { require.NoError(t, err) require.False(t, resp.Delete) require.NotNil(t, resp.Updated) - sendAuth, err := types.NewSendAuthorization([]sdk.AccAddress{}, coins500) - require.NoError(t, err) + sendAuth := types.NewSendAuthorization(coins500, nil) require.Equal(t, sendAuth.String(), resp.Updated.String()) t.Log("expect updated authorization nil after spending remaining amount") diff --git a/x/staking/types/tx.pb.go b/x/staking/types/tx.pb.go index 49d737dff750..97ea3ea7bcd3 100644 --- a/x/staking/types/tx.pb.go +++ b/x/staking/types/tx.pb.go @@ -751,7 +751,7 @@ type MsgClient interface { // // Since: cosmos-sdk 0.46 CancelUnbondingDelegation(ctx context.Context, in *MsgCancelUnbondingDelegation, opts ...grpc.CallOption) (*MsgCancelUnbondingDelegationResponse, error) - // UpdateParams defines a operation for updating the x/staking module + // UpdateParams defines an operation for updating the x/staking module // parameters. // Since: cosmos-sdk 0.47 UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) @@ -848,7 +848,7 @@ type MsgServer interface { // // Since: cosmos-sdk 0.46 CancelUnbondingDelegation(context.Context, *MsgCancelUnbondingDelegation) (*MsgCancelUnbondingDelegationResponse, error) - // UpdateParams defines a operation for updating the x/staking module + // UpdateParams defines an operation for updating the x/staking module // parameters. // Since: cosmos-sdk 0.47 UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) From fd4ac1b0c856a67f0a932cd58740bce2981bcddc Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Tue, 26 Jul 2022 11:26:55 +0530 Subject: [PATCH 11/16] refactor code --- x/authz/simulation/genesis.go | 3 +-- x/authz/simulation/operations.go | 10 ++++------ x/bank/types/errors.go | 1 - 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/x/authz/simulation/genesis.go b/x/authz/simulation/genesis.go index afecc6720d73..e1443683bb18 100644 --- a/x/authz/simulation/genesis.go +++ b/x/authz/simulation/genesis.go @@ -24,11 +24,10 @@ func genGrant(r *rand.Rand, accounts []simtypes.Account, genT time.Time) []authz e := genT.AddDate(1, 0, 0) expiration = &e } - grant := generateRandomGrant(r) authorizations[i] = authz.GrantAuthorization{ Granter: granter.Address.String(), Grantee: grantee.Address.String(), - Authorization: grant, + Authorization: generateRandomGrant(r), Expiration: expiration, } } diff --git a/x/authz/simulation/operations.go b/x/authz/simulation/operations.go index 5defd40631a7..5418d6468d45 100644 --- a/x/authz/simulation/operations.go +++ b/x/authz/simulation/operations.go @@ -118,10 +118,8 @@ func SimulateMsgGrant(cdc *codec.ProtoCodec, ak authz.AccountKeeper, bk authz.Ba if !t1.Before(ctx.BlockTime()) { expiration = &t1 } - randomAuthz, err := generateRandomAuthorization(r, spendLimit) - if err != nil { - return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "unable to generate random authorization"), nil, err - } + randomAuthz := generateRandomAuthorization(r, spendLimit) + msg, err := authz.NewMsgGrant(granter.Address, grantee.Address, randomAuthz, expiration) if err != nil { return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, err.Error()), nil, err @@ -150,13 +148,13 @@ func SimulateMsgGrant(cdc *codec.ProtoCodec, ak authz.AccountKeeper, bk authz.Ba } } -func generateRandomAuthorization(r *rand.Rand, spendLimit sdk.Coins) (authz.Authorization, error) { +func generateRandomAuthorization(r *rand.Rand, spendLimit sdk.Coins) authz.Authorization { authorizations := make([]authz.Authorization, 2) sendAuthz := banktype.NewSendAuthorization(spendLimit, nil) authorizations[0] = sendAuthz authorizations[1] = authz.NewGenericAuthorization(sdk.MsgTypeURL(&banktype.MsgSend{})) - return authorizations[r.Intn(len(authorizations))], nil + return authorizations[r.Intn(len(authorizations))] } // SimulateMsgRevoke generates a MsgRevoke with random values. diff --git a/x/bank/types/errors.go b/x/bank/types/errors.go index 13af3dc4c7aa..de57b6da35d5 100644 --- a/x/bank/types/errors.go +++ b/x/bank/types/errors.go @@ -13,5 +13,4 @@ var ( ErrDenomMetadataNotFound = sdkerrors.Register(ModuleName, 6, "client denom metadata not found") ErrInvalidKey = sdkerrors.Register(ModuleName, 7, "invalid key") ErrDuplicateEntry = sdkerrors.Register(ModuleName, 8, "duplicate entry") - ErrMultipleSenders = sdkerrors.Register(ModuleName, 9, "multiple senders not allowed") ) From e2ac0252ce1f98f1b1509c2ac0a75a8de61c88bb Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Tue, 26 Jul 2022 11:58:46 +0530 Subject: [PATCH 12/16] fix tests --- x/bank/types/errors.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/bank/types/errors.go b/x/bank/types/errors.go index de57b6da35d5..13af3dc4c7aa 100644 --- a/x/bank/types/errors.go +++ b/x/bank/types/errors.go @@ -13,4 +13,5 @@ var ( ErrDenomMetadataNotFound = sdkerrors.Register(ModuleName, 6, "client denom metadata not found") ErrInvalidKey = sdkerrors.Register(ModuleName, 7, "invalid key") ErrDuplicateEntry = sdkerrors.Register(ModuleName, 8, "duplicate entry") + ErrMultipleSenders = sdkerrors.Register(ModuleName, 9, "multiple senders not allowed") ) From 9de416c0ee7fb0de08daff3c0fbd78eb8d076d65 Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Wed, 27 Jul 2022 10:55:52 +0530 Subject: [PATCH 13/16] address review comments --- x/bank/types/send_authorization.go | 6 ++---- x/bank/types/send_authorization_test.go | 26 +++++++++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/x/bank/types/send_authorization.go b/x/bank/types/send_authorization.go index b7eb3e397f85..91b37def1c55 100644 --- a/x/bank/types/send_authorization.go +++ b/x/bank/types/send_authorization.go @@ -18,10 +18,7 @@ func NewSendAuthorization(spendLimit sdk.Coins, allowed []sdk.AccAddress) *SendA a := SendAuthorization{} a.AllowList = allowedAddrs - - if spendLimit != nil { - a.SpendLimit = spendLimit - } + a.SpendLimit = spendLimit return &a } @@ -60,6 +57,7 @@ func (a SendAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authz.AcceptRes if len(allowedList) > 0 && !isAddrExists { return authz.AcceptResponse{}, sdkerrors.ErrUnauthorized.Wrapf("cannot send to %s address", toAddr) } + return authz.AcceptResponse{Accept: true, Delete: false, Updated: &SendAuthorization{SpendLimit: limitLeft, AllowList: allowedList}}, nil } diff --git a/x/bank/types/send_authorization_test.go b/x/bank/types/send_authorization_test.go index 89e033037fe5..179f9349ccdf 100644 --- a/x/bank/types/send_authorization_test.go +++ b/x/bank/types/send_authorization_test.go @@ -1,6 +1,7 @@ package types_test import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -12,15 +13,18 @@ import ( ) var ( - coins1000 = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))) - coins500 = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(500))) - fromAddr = sdk.AccAddress("_____from _____") - toAddr = sdk.AccAddress("_______to________") + coins1000 = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000))) + coins500 = sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(500))) + fromAddr = sdk.AccAddress("_____from _____") + toAddr = sdk.AccAddress("_______to________") + unknownAddr = sdk.AccAddress("_____unknown_____") ) func TestSendAuthorization(t *testing.T) { app := simapp.Setup(t, false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + allowList := make([]sdk.AccAddress, 1) + allowList[0] = toAddr authorization := types.NewSendAuthorization(coins1000, nil) t.Log("verify authorization returns valid method name") @@ -55,4 +59,18 @@ func TestSendAuthorization(t *testing.T) { require.NoError(t, err) require.True(t, resp.Delete) require.Nil(t, resp.Updated) + + t.Log("allow list and no address") + authzWithAllowList := types.NewSendAuthorization(coins1000, allowList) + require.Equal(t, authzWithAllowList.MsgTypeURL(), "/cosmos.bank.v1beta1.MsgSend") + require.NoError(t, authorization.ValidateBasic()) + send = types.NewMsgSend(fromAddr, unknownAddr, coins500) + require.NoError(t, authzWithAllowList.ValidateBasic()) + resp, err = authzWithAllowList.Accept(ctx, send) + require.False(t, resp.Accept) + require.False(t, resp.Delete) + require.Nil(t, resp.Updated) + require.Error(t, err) + require.Contains(t, err.Error(), fmt.Sprintf("cannot send to %s address", unknownAddr)) + fmt.Println(err.Error()) } From 4ae7b7eb93f70de63e0498926767c2a62132e3ca Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Wed, 27 Jul 2022 11:56:14 +0530 Subject: [PATCH 14/16] remove unncessary line --- x/bank/types/send_authorization_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/bank/types/send_authorization_test.go b/x/bank/types/send_authorization_test.go index 179f9349ccdf..bd96b90f8bf4 100644 --- a/x/bank/types/send_authorization_test.go +++ b/x/bank/types/send_authorization_test.go @@ -72,5 +72,4 @@ func TestSendAuthorization(t *testing.T) { require.Nil(t, resp.Updated) require.Error(t, err) require.Contains(t, err.Error(), fmt.Sprintf("cannot send to %s address", unknownAddr)) - fmt.Println(err.Error()) } From 694803b5a98b2f03c82c3f39d01a40a1559e80a9 Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Wed, 27 Jul 2022 11:59:54 +0530 Subject: [PATCH 15/16] wip: fix test --- x/bank/types/send_authorization_test.go | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/x/bank/types/send_authorization_test.go b/x/bank/types/send_authorization_test.go index bd96b90f8bf4..74458e8f92f4 100644 --- a/x/bank/types/send_authorization_test.go +++ b/x/bank/types/send_authorization_test.go @@ -1,7 +1,6 @@ package types_test import ( - "fmt" "testing" "github.com/stretchr/testify/require" @@ -60,16 +59,16 @@ func TestSendAuthorization(t *testing.T) { require.True(t, resp.Delete) require.Nil(t, resp.Updated) - t.Log("allow list and no address") - authzWithAllowList := types.NewSendAuthorization(coins1000, allowList) - require.Equal(t, authzWithAllowList.MsgTypeURL(), "/cosmos.bank.v1beta1.MsgSend") - require.NoError(t, authorization.ValidateBasic()) - send = types.NewMsgSend(fromAddr, unknownAddr, coins500) - require.NoError(t, authzWithAllowList.ValidateBasic()) - resp, err = authzWithAllowList.Accept(ctx, send) - require.False(t, resp.Accept) - require.False(t, resp.Delete) - require.Nil(t, resp.Updated) - require.Error(t, err) - require.Contains(t, err.Error(), fmt.Sprintf("cannot send to %s address", unknownAddr)) + // t.Log("allow list and no address") + // authzWithAllowList := types.NewSendAuthorization(coins1000, allowList) + // require.Equal(t, authzWithAllowList.MsgTypeURL(), "/cosmos.bank.v1beta1.MsgSend") + // require.NoError(t, authorization.ValidateBasic()) + // send = types.NewMsgSend(fromAddr, unknownAddr, coins500) + // require.NoError(t, authzWithAllowList.ValidateBasic()) + // resp, err = authzWithAllowList.Accept(ctx, send) + // require.False(t, resp.Accept) + // require.False(t, resp.Delete) + // require.Nil(t, resp.Updated) + // require.Error(t, err) + // require.Contains(t, err.Error(), fmt.Sprintf("cannot send to %s address", unknownAddr)) } From 96e705bba55b15ae5ea3b3d92701d528cc129aeb Mon Sep 17 00:00:00 2001 From: likhita-809 Date: Wed, 27 Jul 2022 12:15:24 +0530 Subject: [PATCH 16/16] revert last changes --- x/bank/types/send_authorization_test.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/x/bank/types/send_authorization_test.go b/x/bank/types/send_authorization_test.go index 74458e8f92f4..0a2c6caa4edf 100644 --- a/x/bank/types/send_authorization_test.go +++ b/x/bank/types/send_authorization_test.go @@ -1,6 +1,7 @@ package types_test import ( + fmt "fmt" "testing" "github.com/stretchr/testify/require" @@ -59,16 +60,16 @@ func TestSendAuthorization(t *testing.T) { require.True(t, resp.Delete) require.Nil(t, resp.Updated) - // t.Log("allow list and no address") - // authzWithAllowList := types.NewSendAuthorization(coins1000, allowList) - // require.Equal(t, authzWithAllowList.MsgTypeURL(), "/cosmos.bank.v1beta1.MsgSend") - // require.NoError(t, authorization.ValidateBasic()) - // send = types.NewMsgSend(fromAddr, unknownAddr, coins500) - // require.NoError(t, authzWithAllowList.ValidateBasic()) - // resp, err = authzWithAllowList.Accept(ctx, send) - // require.False(t, resp.Accept) - // require.False(t, resp.Delete) - // require.Nil(t, resp.Updated) - // require.Error(t, err) - // require.Contains(t, err.Error(), fmt.Sprintf("cannot send to %s address", unknownAddr)) + t.Log("allow list and no address") + authzWithAllowList := types.NewSendAuthorization(coins1000, allowList) + require.Equal(t, authzWithAllowList.MsgTypeURL(), "/cosmos.bank.v1beta1.MsgSend") + require.NoError(t, authorization.ValidateBasic()) + send = types.NewMsgSend(fromAddr, unknownAddr, coins500) + require.NoError(t, authzWithAllowList.ValidateBasic()) + resp, err = authzWithAllowList.Accept(ctx, send) + require.False(t, resp.Accept) + require.False(t, resp.Delete) + require.Nil(t, resp.Updated) + require.Error(t, err) + require.Contains(t, err.Error(), fmt.Sprintf("cannot send to %s address", unknownAddr)) }