feat: Add x/authz SendAuthorization AllowList (#12648)
## Description Closes: #12609 --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable)
This commit is contained in:
parent
df4339cd16
commit
9f5ee97889
@ -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.
|
||||
* (sdk.Coins) [#12627](https://github.com/cosmos/cosmos-sdk/pull/12627) Make a Denoms method on sdk.Coins.
|
||||
|
||||
@ -63,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
### API Breaking Changes
|
||||
|
||||
* (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
|
||||
|
||||
@ -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,11 @@ 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 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"`
|
||||
}
|
||||
|
||||
func (x *SendAuthorization) Reset() {
|
||||
@ -561,6 +690,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 +708,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 +716,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 (
|
||||
|
||||
@ -16,4 +16,10 @@ 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 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;
|
||||
}
|
||||
|
||||
@ -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,18 @@ 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 := bech32toAccAddresses(allowList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authorization = bank.NewSendAuthorization(spendLimit, allowed)
|
||||
|
||||
case "generic":
|
||||
msgType, err := cmd.Flags().GetString(FlagMsgType)
|
||||
if err != nil {
|
||||
@ -140,12 +152,12 @@ Examples:
|
||||
delegateLimit = &spendLimit
|
||||
}
|
||||
|
||||
allowed, err := bech32toValidatorAddresses(allowValidators)
|
||||
allowed, err := bech32toValAddresses(allowValidators)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
denied, err := bech32toValidatorAddresses(denyValidators)
|
||||
denied, err := bech32toValAddresses(denyValidators)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -184,6 +196,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
|
||||
}
|
||||
@ -273,7 +286,8 @@ Example:
|
||||
return cmd
|
||||
}
|
||||
|
||||
func bech32toValidatorAddresses(validators []string) ([]sdk.ValAddress, error) {
|
||||
// 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)
|
||||
@ -284,3 +298,16 @@ func bech32toValidatorAddresses(validators []string) ([]sdk.ValAddress, error) {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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.
|
||||
@ -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),
|
||||
@ -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,40 @@ 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,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"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{
|
||||
@ -877,6 +935,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]
|
||||
|
||||
@ -125,9 +125,10 @@ func (s *TestSuite) TestKeeperIter() {
|
||||
granteeAddr := addrs[1]
|
||||
granter2Addr := addrs[2]
|
||||
e := ctx.BlockTime().AddDate(1, 0, 0)
|
||||
sendAuthz := banktypes.NewSendAuthorization(coins100, nil)
|
||||
|
||||
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 +145,7 @@ func (s *TestSuite) TestDispatchAction() {
|
||||
granterAddr := addrs[0]
|
||||
granteeAddr := addrs[1]
|
||||
recipientAddr := addrs[2]
|
||||
a := banktypes.NewSendAuthorization(coins100)
|
||||
a := banktypes.NewSendAuthorization(coins100, nil)
|
||||
|
||||
require.NoError(banktestutil.FundAccount(s.bankKeeper, s.ctx, granterAddr, coins1000))
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@ func TestMigration(t *testing.T) {
|
||||
blockTime := ctx.BlockTime()
|
||||
oneDay := blockTime.AddDate(0, 0, 1)
|
||||
oneYear := blockTime.AddDate(1, 0, 0)
|
||||
sendAuthz := banktypes.NewSendAuthorization(coins100, nil)
|
||||
|
||||
grants := []struct {
|
||||
granter sdk.AccAddress
|
||||
@ -47,7 +48,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 +61,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,
|
||||
|
||||
@ -44,9 +44,10 @@ 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 := banktypes.NewSendAuthorization(smallCoins, nil)
|
||||
|
||||
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)
|
||||
|
||||
@ -174,7 +174,8 @@ 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 := 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")
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -26,7 +26,8 @@ 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 := banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewInt64Coin("foo", 123)), nil)
|
||||
grant, _ := authz.NewGrant(now, sendAuthz, &e)
|
||||
grantBz, err := cdc.Marshal(&grant)
|
||||
require.NoError(t, err)
|
||||
kvPairs := kv.Pairs{
|
||||
|
||||
@ -37,7 +37,8 @@ func genGrant(r *rand.Rand, accounts []simtypes.Account, genT time.Time) []authz
|
||||
|
||||
func generateRandomGrant(r *rand.Rand) *codectypes.Any {
|
||||
authorizations := make([]*codectypes.Any, 2)
|
||||
authorizations[0] = newAnyAuthorization(banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))))
|
||||
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))]
|
||||
@ -57,7 +58,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)
|
||||
|
||||
@ -118,7 +118,9 @@ 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 := 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
|
||||
}
|
||||
@ -148,7 +150,8 @@ func SimulateMsgGrant(cdc *codec.ProtoCodec, ak authz.AccountKeeper, bk authz.Ba
|
||||
|
||||
func generateRandomAuthorization(r *rand.Rand, spendLimit sdk.Coins) authz.Authorization {
|
||||
authorizations := make([]authz.Authorization, 2)
|
||||
authorizations[0] = banktype.NewSendAuthorization(spendLimit)
|
||||
sendAuthz := banktype.NewSendAuthorization(spendLimit, nil)
|
||||
authorizations[0] = sendAuthz
|
||||
authorizations[1] = authz.NewGenericAuthorization(sdk.MsgTypeURL(&banktype.MsgSend{}))
|
||||
|
||||
return authorizations[r.Intn(len(authorizations))]
|
||||
|
||||
@ -161,7 +161,7 @@ func (suite *SimTestSuite) TestSimulateRevoke() {
|
||||
|
||||
granter := accounts[0]
|
||||
grantee := accounts[1]
|
||||
a := banktypes.NewSendAuthorization(initCoins)
|
||||
a := banktypes.NewSendAuthorization(initCoins, nil)
|
||||
expire := time.Now().Add(30 * time.Hour)
|
||||
|
||||
err := suite.authzKeeper.SaveGrant(suite.ctx, grantee.Address, granter.Address, a, &expire)
|
||||
@ -196,7 +196,7 @@ func (suite *SimTestSuite) TestSimulateExec() {
|
||||
|
||||
granter := accounts[0]
|
||||
grantee := accounts[1]
|
||||
a := banktypes.NewSendAuthorization(initCoins)
|
||||
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)
|
||||
|
||||
@ -32,6 +32,11 @@ 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 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"`
|
||||
}
|
||||
|
||||
func (m *SendAuthorization) Reset() { *m = SendAuthorization{} }
|
||||
@ -74,6 +79,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 +93,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 +134,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 +183,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 +261,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:])
|
||||
|
||||
@ -12,5 +12,6 @@ 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")
|
||||
ErrMultipleSenders = sdkerrors.Register(ModuleName, 8, "multiple senders not allowed")
|
||||
ErrDuplicateEntry = sdkerrors.Register(ModuleName, 8, "duplicate entry")
|
||||
ErrMultipleSenders = sdkerrors.Register(ModuleName, 9, "multiple senders not allowed")
|
||||
)
|
||||
|
||||
@ -6,13 +6,21 @@ 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.
|
||||
func NewSendAuthorization(spendLimit sdk.Coins) *SendAuthorization {
|
||||
return &SendAuthorization{
|
||||
SpendLimit: spendLimit,
|
||||
}
|
||||
func NewSendAuthorization(spendLimit sdk.Coins, allowed []sdk.AccAddress) *SendAuthorization {
|
||||
allowedAddrs := toBech32Addresses(allowed)
|
||||
|
||||
a := SendAuthorization{}
|
||||
a.AllowList = allowedAddrs
|
||||
a.SpendLimit = spendLimit
|
||||
|
||||
return &a
|
||||
}
|
||||
|
||||
// MsgTypeURL implements Authorization.MsgTypeURL.
|
||||
@ -26,6 +34,7 @@ func (a SendAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authz.AcceptRes
|
||||
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")
|
||||
@ -34,7 +43,22 @@ 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.
|
||||
@ -45,5 +69,25 @@ 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
|
||||
}
|
||||
found[a.AllowList[i]] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toBech32Addresses(allowed []sdk.AccAddress) []string {
|
||||
if len(allowed) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
allowedAddrs := make([]string, len(allowed))
|
||||
for i, addr := range allowed {
|
||||
allowedAddrs[i] = addr.String()
|
||||
}
|
||||
return allowedAddrs
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -12,16 +13,19 @@ 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{})
|
||||
authorization := types.NewSendAuthorization(coins1000)
|
||||
allowList := make([]sdk.AccAddress, 1)
|
||||
allowList[0] = toAddr
|
||||
authorization := types.NewSendAuthorization(coins1000, nil)
|
||||
|
||||
t.Log("verify authorization returns valid method name")
|
||||
require.Equal(t, authorization.MsgTypeURL(), "/cosmos.bank.v1beta1.MsgSend")
|
||||
@ -36,7 +40,7 @@ func TestSendAuthorization(t *testing.T) {
|
||||
require.True(t, resp.Delete)
|
||||
require.Nil(t, resp.Updated)
|
||||
|
||||
authorization = types.NewSendAuthorization(coins1000)
|
||||
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)
|
||||
@ -47,7 +51,7 @@ func TestSendAuthorization(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.False(t, resp.Delete)
|
||||
require.NotNil(t, resp.Updated)
|
||||
sendAuth := types.NewSendAuthorization(coins500)
|
||||
sendAuth := types.NewSendAuthorization(coins500, nil)
|
||||
require.Equal(t, sendAuth.String(), resp.Updated.String())
|
||||
|
||||
t.Log("expect updated authorization nil after spending remaining amount")
|
||||
@ -55,4 +59,17 @@ 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))
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user