From d3b30e946d0d8cc69bf74d62b9f7262c715b3470 Mon Sep 17 00:00:00 2001 From: testinginprod <98415576+testinginprod@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:41:59 +0100 Subject: [PATCH] feat(accounts): implement account abstraction execution (#18499) Co-authored-by: unknown unknown Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- CHANGELOG.md | 1 + .../v1/interface.pulsar.go | 536 +++++++++++------- .../accounts/v1/account_abstraction.pulsar.go | 342 +++++------ baseapp/internal/protocompat/protocompat.go | 16 + baseapp/msg_service_router.go | 17 +- .../account_abstraction/v1/interface.proto | 22 +- .../accounts/v1/account_abstraction.proto | 20 +- simapp/app.go | 4 + .../e2e/accounts/account_abstraction_test.go | 349 ++++++++++++ tests/e2e/accounts/setup_test.go | 13 + x/accounts/accountstd/exports.go | 52 ++ x/accounts/genesis_test.go | 7 +- .../internal/implementation/api_builder.go | 9 + x/accounts/internal/implementation/context.go | 52 +- .../internal/implementation/context_test.go | 31 +- .../internal/implementation/proto_util.go | 31 + x/accounts/keeper.go | 198 +++++-- x/accounts/keeper_account_abstraction.go | 236 ++++++++ x/accounts/keeper_test.go | 58 +- x/accounts/module.go | 4 + x/accounts/msg_server.go | 2 +- x/accounts/msg_server_test.go | 7 +- x/accounts/query_server_test.go | 5 +- .../testing/account_abstraction/full.go | 77 +++ .../testing/account_abstraction/minimal.go | 70 +++ .../account_abstraction/partial_account.go | 68 --- x/accounts/utils_test.go | 80 +++ x/accounts/v1/account_abstraction.pb.go | 178 +++--- 28 files changed, 1781 insertions(+), 704 deletions(-) create mode 100644 tests/e2e/accounts/account_abstraction_test.go create mode 100644 tests/e2e/accounts/setup_test.go create mode 100644 x/accounts/internal/implementation/proto_util.go create mode 100644 x/accounts/keeper_account_abstraction.go create mode 100644 x/accounts/testing/account_abstraction/full.go create mode 100644 x/accounts/testing/account_abstraction/minimal.go delete mode 100644 x/accounts/testing/account_abstraction/partial_account.go create mode 100644 x/accounts/utils_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a524c978dc3..5bcebf869eee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/auth/vesting) [#17810](https://github.com/cosmos/cosmos-sdk/pull/17810) Add the ability to specify a start time for continuous vesting accounts. * (runtime) [#18475](https://github.com/cosmos/cosmos-sdk/pull/18475) Adds an implementation for core.branch.Service. * (server) [#18478](https://github.com/cosmos/cosmos-sdk/pull/18478) CMD flag to disable colored logs. +* (baseapp) [#18499](https://github.com/cosmos/cosmos-sdk/pull/18499) Add `MsgRouter` response type from message name function. ### Improvements diff --git a/api/cosmos/accounts/interfaces/account_abstraction/v1/interface.pulsar.go b/api/cosmos/accounts/interfaces/account_abstraction/v1/interface.pulsar.go index 9b3c46e0a297..3708e80079b8 100644 --- a/api/cosmos/accounts/interfaces/account_abstraction/v1/interface.pulsar.go +++ b/api/cosmos/accounts/interfaces/account_abstraction/v1/interface.pulsar.go @@ -16,17 +16,15 @@ import ( var ( md_MsgAuthenticate protoreflect.MessageDescriptor + fd_MsgAuthenticate_bundler protoreflect.FieldDescriptor fd_MsgAuthenticate_user_operation protoreflect.FieldDescriptor - fd_MsgAuthenticate_chain_id protoreflect.FieldDescriptor - fd_MsgAuthenticate_account_number protoreflect.FieldDescriptor ) func init() { file_cosmos_accounts_interfaces_account_abstraction_v1_interface_proto_init() md_MsgAuthenticate = File_cosmos_accounts_interfaces_account_abstraction_v1_interface_proto.Messages().ByName("MsgAuthenticate") + fd_MsgAuthenticate_bundler = md_MsgAuthenticate.Fields().ByName("bundler") fd_MsgAuthenticate_user_operation = md_MsgAuthenticate.Fields().ByName("user_operation") - fd_MsgAuthenticate_chain_id = md_MsgAuthenticate.Fields().ByName("chain_id") - fd_MsgAuthenticate_account_number = md_MsgAuthenticate.Fields().ByName("account_number") } var _ protoreflect.Message = (*fastReflection_MsgAuthenticate)(nil) @@ -94,21 +92,15 @@ func (x *fastReflection_MsgAuthenticate) Interface() protoreflect.ProtoMessage { // While iterating, mutating operations may only be performed // on the current field descriptor. func (x *fastReflection_MsgAuthenticate) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { - if x.UserOperation != nil { - value := protoreflect.ValueOfMessage(x.UserOperation.ProtoReflect()) - if !f(fd_MsgAuthenticate_user_operation, value) { - return - } - } - if x.ChainId != "" { - value := protoreflect.ValueOfString(x.ChainId) - if !f(fd_MsgAuthenticate_chain_id, value) { + if x.Bundler != "" { + value := protoreflect.ValueOfString(x.Bundler) + if !f(fd_MsgAuthenticate_bundler, value) { return } } - if x.AccountNumber != uint64(0) { - value := protoreflect.ValueOfUint64(x.AccountNumber) - if !f(fd_MsgAuthenticate_account_number, value) { + if x.UserOperation != nil { + value := protoreflect.ValueOfMessage(x.UserOperation.ProtoReflect()) + if !f(fd_MsgAuthenticate_user_operation, value) { return } } @@ -127,12 +119,10 @@ func (x *fastReflection_MsgAuthenticate) Range(f func(protoreflect.FieldDescript // a repeated field is populated if it is non-empty. func (x *fastReflection_MsgAuthenticate) Has(fd protoreflect.FieldDescriptor) bool { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.bundler": + return x.Bundler != "" case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.user_operation": return x.UserOperation != nil - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.chain_id": - return x.ChainId != "" - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.account_number": - return x.AccountNumber != uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate")) @@ -149,12 +139,10 @@ func (x *fastReflection_MsgAuthenticate) Has(fd protoreflect.FieldDescriptor) bo // Clear is a mutating operation and unsafe for concurrent use. func (x *fastReflection_MsgAuthenticate) Clear(fd protoreflect.FieldDescriptor) { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.bundler": + x.Bundler = "" case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.user_operation": x.UserOperation = nil - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.chain_id": - x.ChainId = "" - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.account_number": - x.AccountNumber = uint64(0) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate")) @@ -171,15 +159,12 @@ func (x *fastReflection_MsgAuthenticate) Clear(fd protoreflect.FieldDescriptor) // of the value; to obtain a mutable reference, use Mutable. func (x *fastReflection_MsgAuthenticate) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { switch descriptor.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.bundler": + value := x.Bundler + return protoreflect.ValueOfString(value) case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.user_operation": value := x.UserOperation return protoreflect.ValueOfMessage(value.ProtoReflect()) - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.chain_id": - value := x.ChainId - return protoreflect.ValueOfString(value) - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.account_number": - value := x.AccountNumber - return protoreflect.ValueOfUint64(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate")) @@ -200,12 +185,10 @@ func (x *fastReflection_MsgAuthenticate) Get(descriptor protoreflect.FieldDescri // Set is a mutating operation and unsafe for concurrent use. func (x *fastReflection_MsgAuthenticate) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.bundler": + x.Bundler = value.Interface().(string) case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.user_operation": x.UserOperation = value.Message().Interface().(*v1.UserOperation) - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.chain_id": - x.ChainId = value.Interface().(string) - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.account_number": - x.AccountNumber = value.Uint() default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate")) @@ -231,10 +214,8 @@ func (x *fastReflection_MsgAuthenticate) Mutable(fd protoreflect.FieldDescriptor x.UserOperation = new(v1.UserOperation) } return protoreflect.ValueOfMessage(x.UserOperation.ProtoReflect()) - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.chain_id": - panic(fmt.Errorf("field chain_id of message cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate is not mutable")) - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.account_number": - panic(fmt.Errorf("field account_number of message cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate is not mutable")) + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.bundler": + panic(fmt.Errorf("field bundler of message cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate")) @@ -248,13 +229,11 @@ func (x *fastReflection_MsgAuthenticate) Mutable(fd protoreflect.FieldDescriptor // For lists, maps, and messages, this returns a new, empty, mutable value. func (x *fastReflection_MsgAuthenticate) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.bundler": + return protoreflect.ValueOfString("") case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.user_operation": m := new(v1.UserOperation) return protoreflect.ValueOfMessage(m.ProtoReflect()) - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.chain_id": - return protoreflect.ValueOfString("") - case "cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate.account_number": - return protoreflect.ValueOfUint64(uint64(0)) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.interfaces.account_abstraction.v1.MsgAuthenticate")) @@ -324,16 +303,13 @@ func (x *fastReflection_MsgAuthenticate) ProtoMethods() *protoiface.Methods { var n int var l int _ = l - if x.UserOperation != nil { - l = options.Size(x.UserOperation) - n += 1 + l + runtime.Sov(uint64(l)) - } - l = len(x.ChainId) + l = len(x.Bundler) if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) } - if x.AccountNumber != 0 { - n += 1 + runtime.Sov(uint64(x.AccountNumber)) + if x.UserOperation != nil { + l = options.Size(x.UserOperation) + n += 1 + l + runtime.Sov(uint64(l)) } if x.unknownFields != nil { n += len(x.unknownFields) @@ -364,18 +340,6 @@ func (x *fastReflection_MsgAuthenticate) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } - if x.AccountNumber != 0 { - i = runtime.EncodeVarint(dAtA, i, uint64(x.AccountNumber)) - i-- - dAtA[i] = 0x18 - } - if len(x.ChainId) > 0 { - i -= len(x.ChainId) - copy(dAtA[i:], x.ChainId) - i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ChainId))) - i-- - dAtA[i] = 0x12 - } if x.UserOperation != nil { encoded, err := options.Marshal(x.UserOperation) if err != nil { @@ -388,6 +352,13 @@ func (x *fastReflection_MsgAuthenticate) ProtoMethods() *protoiface.Methods { copy(dAtA[i:], encoded) i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) i-- + dAtA[i] = 0x12 + } + if len(x.Bundler) > 0 { + i -= len(x.Bundler) + copy(dAtA[i:], x.Bundler) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Bundler))) + i-- dAtA[i] = 0xa } if input.Buf != nil { @@ -441,9 +412,9 @@ func (x *fastReflection_MsgAuthenticate) ProtoMethods() *protoiface.Methods { switch fieldNum { case 1: if wireType != 2 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field UserOperation", wireType) + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Bundler", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow @@ -453,33 +424,29 @@ func (x *fastReflection_MsgAuthenticate) ProtoMethods() *protoiface.Methods { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength } - postIndex := iNdEx + msglen + 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 } - if x.UserOperation == nil { - x.UserOperation = &v1.UserOperation{} - } - if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.UserOperation); err != nil { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err - } + x.Bundler = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field UserOperation", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow @@ -489,43 +456,28 @@ func (x *fastReflection_MsgAuthenticate) ProtoMethods() *protoiface.Methods { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen 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.ChainId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field AccountNumber", wireType) + if x.UserOperation == nil { + x.UserOperation = &v1.UserOperation{} } - x.AccountNumber = 0 - 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++ - x.AccountNumber |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.UserOperation); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -917,65 +869,67 @@ func (x *fastReflection_MsgAuthenticateResponse) ProtoMethods() *protoiface.Meth } } -var _ protoreflect.List = (*_MsgPayBundler_1_list)(nil) +var _ protoreflect.List = (*_MsgPayBundler_2_list)(nil) -type _MsgPayBundler_1_list struct { +type _MsgPayBundler_2_list struct { list *[]*anypb.Any } -func (x *_MsgPayBundler_1_list) Len() int { +func (x *_MsgPayBundler_2_list) Len() int { if x.list == nil { return 0 } return len(*x.list) } -func (x *_MsgPayBundler_1_list) Get(i int) protoreflect.Value { +func (x *_MsgPayBundler_2_list) Get(i int) protoreflect.Value { return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) } -func (x *_MsgPayBundler_1_list) Set(i int, value protoreflect.Value) { +func (x *_MsgPayBundler_2_list) Set(i int, value protoreflect.Value) { valueUnwrapped := value.Message() concreteValue := valueUnwrapped.Interface().(*anypb.Any) (*x.list)[i] = concreteValue } -func (x *_MsgPayBundler_1_list) Append(value protoreflect.Value) { +func (x *_MsgPayBundler_2_list) Append(value protoreflect.Value) { valueUnwrapped := value.Message() concreteValue := valueUnwrapped.Interface().(*anypb.Any) *x.list = append(*x.list, concreteValue) } -func (x *_MsgPayBundler_1_list) AppendMutable() protoreflect.Value { +func (x *_MsgPayBundler_2_list) AppendMutable() protoreflect.Value { v := new(anypb.Any) *x.list = append(*x.list, v) return protoreflect.ValueOfMessage(v.ProtoReflect()) } -func (x *_MsgPayBundler_1_list) Truncate(n int) { +func (x *_MsgPayBundler_2_list) Truncate(n int) { for i := n; i < len(*x.list); i++ { (*x.list)[i] = nil } *x.list = (*x.list)[:n] } -func (x *_MsgPayBundler_1_list) NewElement() protoreflect.Value { +func (x *_MsgPayBundler_2_list) NewElement() protoreflect.Value { v := new(anypb.Any) return protoreflect.ValueOfMessage(v.ProtoReflect()) } -func (x *_MsgPayBundler_1_list) IsValid() bool { +func (x *_MsgPayBundler_2_list) IsValid() bool { return x.list != nil } var ( md_MsgPayBundler protoreflect.MessageDescriptor + fd_MsgPayBundler_bundler protoreflect.FieldDescriptor fd_MsgPayBundler_bundler_payment_messages protoreflect.FieldDescriptor ) func init() { file_cosmos_accounts_interfaces_account_abstraction_v1_interface_proto_init() md_MsgPayBundler = File_cosmos_accounts_interfaces_account_abstraction_v1_interface_proto.Messages().ByName("MsgPayBundler") + fd_MsgPayBundler_bundler = md_MsgPayBundler.Fields().ByName("bundler") fd_MsgPayBundler_bundler_payment_messages = md_MsgPayBundler.Fields().ByName("bundler_payment_messages") } @@ -1044,8 +998,14 @@ func (x *fastReflection_MsgPayBundler) Interface() protoreflect.ProtoMessage { // While iterating, mutating operations may only be performed // on the current field descriptor. func (x *fastReflection_MsgPayBundler) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Bundler != "" { + value := protoreflect.ValueOfString(x.Bundler) + if !f(fd_MsgPayBundler_bundler, value) { + return + } + } if len(x.BundlerPaymentMessages) != 0 { - value := protoreflect.ValueOfList(&_MsgPayBundler_1_list{list: &x.BundlerPaymentMessages}) + value := protoreflect.ValueOfList(&_MsgPayBundler_2_list{list: &x.BundlerPaymentMessages}) if !f(fd_MsgPayBundler_bundler_payment_messages, value) { return } @@ -1065,6 +1025,8 @@ func (x *fastReflection_MsgPayBundler) Range(f func(protoreflect.FieldDescriptor // a repeated field is populated if it is non-empty. func (x *fastReflection_MsgPayBundler) Has(fd protoreflect.FieldDescriptor) bool { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler": + return x.Bundler != "" case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler_payment_messages": return len(x.BundlerPaymentMessages) != 0 default: @@ -1083,6 +1045,8 @@ func (x *fastReflection_MsgPayBundler) Has(fd protoreflect.FieldDescriptor) bool // Clear is a mutating operation and unsafe for concurrent use. func (x *fastReflection_MsgPayBundler) Clear(fd protoreflect.FieldDescriptor) { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler": + x.Bundler = "" case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler_payment_messages": x.BundlerPaymentMessages = nil default: @@ -1101,11 +1065,14 @@ func (x *fastReflection_MsgPayBundler) Clear(fd protoreflect.FieldDescriptor) { // of the value; to obtain a mutable reference, use Mutable. func (x *fastReflection_MsgPayBundler) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { switch descriptor.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler": + value := x.Bundler + return protoreflect.ValueOfString(value) case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler_payment_messages": if len(x.BundlerPaymentMessages) == 0 { - return protoreflect.ValueOfList(&_MsgPayBundler_1_list{}) + return protoreflect.ValueOfList(&_MsgPayBundler_2_list{}) } - listValue := &_MsgPayBundler_1_list{list: &x.BundlerPaymentMessages} + listValue := &_MsgPayBundler_2_list{list: &x.BundlerPaymentMessages} return protoreflect.ValueOfList(listValue) default: if descriptor.IsExtension() { @@ -1127,9 +1094,11 @@ func (x *fastReflection_MsgPayBundler) Get(descriptor protoreflect.FieldDescript // Set is a mutating operation and unsafe for concurrent use. func (x *fastReflection_MsgPayBundler) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler": + x.Bundler = value.Interface().(string) case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler_payment_messages": lv := value.List() - clv := lv.(*_MsgPayBundler_1_list) + clv := lv.(*_MsgPayBundler_2_list) x.BundlerPaymentMessages = *clv.list default: if fd.IsExtension() { @@ -1155,8 +1124,10 @@ func (x *fastReflection_MsgPayBundler) Mutable(fd protoreflect.FieldDescriptor) if x.BundlerPaymentMessages == nil { x.BundlerPaymentMessages = []*anypb.Any{} } - value := &_MsgPayBundler_1_list{list: &x.BundlerPaymentMessages} + value := &_MsgPayBundler_2_list{list: &x.BundlerPaymentMessages} return protoreflect.ValueOfList(value) + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler": + panic(fmt.Errorf("field bundler of message cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler")) @@ -1170,9 +1141,11 @@ func (x *fastReflection_MsgPayBundler) Mutable(fd protoreflect.FieldDescriptor) // For lists, maps, and messages, this returns a new, empty, mutable value. func (x *fastReflection_MsgPayBundler) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler": + return protoreflect.ValueOfString("") case "cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler.bundler_payment_messages": list := []*anypb.Any{} - return protoreflect.ValueOfList(&_MsgPayBundler_1_list{list: &list}) + return protoreflect.ValueOfList(&_MsgPayBundler_2_list{list: &list}) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.interfaces.account_abstraction.v1.MsgPayBundler")) @@ -1242,6 +1215,10 @@ func (x *fastReflection_MsgPayBundler) ProtoMethods() *protoiface.Methods { var n int var l int _ = l + l = len(x.Bundler) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } if len(x.BundlerPaymentMessages) > 0 { for _, e := range x.BundlerPaymentMessages { l = options.Size(e) @@ -1290,9 +1267,16 @@ func (x *fastReflection_MsgPayBundler) ProtoMethods() *protoiface.Methods { copy(dAtA[i:], encoded) i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) i-- - dAtA[i] = 0xa + dAtA[i] = 0x12 } } + if len(x.Bundler) > 0 { + i -= len(x.Bundler) + copy(dAtA[i:], x.Bundler) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Bundler))) + i-- + dAtA[i] = 0xa + } if input.Buf != nil { input.Buf = append(input.Buf, dAtA...) } else { @@ -1343,6 +1327,38 @@ func (x *fastReflection_MsgPayBundler) ProtoMethods() *protoiface.Methods { } switch fieldNum { case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Bundler", 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.Bundler = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field BundlerPaymentMessages", wireType) } @@ -1905,65 +1921,67 @@ func (x *fastReflection_MsgPayBundlerResponse) ProtoMethods() *protoiface.Method } } -var _ protoreflect.List = (*_MsgExecute_1_list)(nil) +var _ protoreflect.List = (*_MsgExecute_2_list)(nil) -type _MsgExecute_1_list struct { +type _MsgExecute_2_list struct { list *[]*anypb.Any } -func (x *_MsgExecute_1_list) Len() int { +func (x *_MsgExecute_2_list) Len() int { if x.list == nil { return 0 } return len(*x.list) } -func (x *_MsgExecute_1_list) Get(i int) protoreflect.Value { +func (x *_MsgExecute_2_list) Get(i int) protoreflect.Value { return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) } -func (x *_MsgExecute_1_list) Set(i int, value protoreflect.Value) { +func (x *_MsgExecute_2_list) Set(i int, value protoreflect.Value) { valueUnwrapped := value.Message() concreteValue := valueUnwrapped.Interface().(*anypb.Any) (*x.list)[i] = concreteValue } -func (x *_MsgExecute_1_list) Append(value protoreflect.Value) { +func (x *_MsgExecute_2_list) Append(value protoreflect.Value) { valueUnwrapped := value.Message() concreteValue := valueUnwrapped.Interface().(*anypb.Any) *x.list = append(*x.list, concreteValue) } -func (x *_MsgExecute_1_list) AppendMutable() protoreflect.Value { +func (x *_MsgExecute_2_list) AppendMutable() protoreflect.Value { v := new(anypb.Any) *x.list = append(*x.list, v) return protoreflect.ValueOfMessage(v.ProtoReflect()) } -func (x *_MsgExecute_1_list) Truncate(n int) { +func (x *_MsgExecute_2_list) Truncate(n int) { for i := n; i < len(*x.list); i++ { (*x.list)[i] = nil } *x.list = (*x.list)[:n] } -func (x *_MsgExecute_1_list) NewElement() protoreflect.Value { +func (x *_MsgExecute_2_list) NewElement() protoreflect.Value { v := new(anypb.Any) return protoreflect.ValueOfMessage(v.ProtoReflect()) } -func (x *_MsgExecute_1_list) IsValid() bool { +func (x *_MsgExecute_2_list) IsValid() bool { return x.list != nil } var ( md_MsgExecute protoreflect.MessageDescriptor + fd_MsgExecute_bundler protoreflect.FieldDescriptor fd_MsgExecute_execution_messages protoreflect.FieldDescriptor ) func init() { file_cosmos_accounts_interfaces_account_abstraction_v1_interface_proto_init() md_MsgExecute = File_cosmos_accounts_interfaces_account_abstraction_v1_interface_proto.Messages().ByName("MsgExecute") + fd_MsgExecute_bundler = md_MsgExecute.Fields().ByName("bundler") fd_MsgExecute_execution_messages = md_MsgExecute.Fields().ByName("execution_messages") } @@ -2032,8 +2050,14 @@ func (x *fastReflection_MsgExecute) Interface() protoreflect.ProtoMessage { // While iterating, mutating operations may only be performed // on the current field descriptor. func (x *fastReflection_MsgExecute) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Bundler != "" { + value := protoreflect.ValueOfString(x.Bundler) + if !f(fd_MsgExecute_bundler, value) { + return + } + } if len(x.ExecutionMessages) != 0 { - value := protoreflect.ValueOfList(&_MsgExecute_1_list{list: &x.ExecutionMessages}) + value := protoreflect.ValueOfList(&_MsgExecute_2_list{list: &x.ExecutionMessages}) if !f(fd_MsgExecute_execution_messages, value) { return } @@ -2053,6 +2077,8 @@ func (x *fastReflection_MsgExecute) Range(f func(protoreflect.FieldDescriptor, p // a repeated field is populated if it is non-empty. func (x *fastReflection_MsgExecute) Has(fd protoreflect.FieldDescriptor) bool { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.bundler": + return x.Bundler != "" case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.execution_messages": return len(x.ExecutionMessages) != 0 default: @@ -2071,6 +2097,8 @@ func (x *fastReflection_MsgExecute) Has(fd protoreflect.FieldDescriptor) bool { // Clear is a mutating operation and unsafe for concurrent use. func (x *fastReflection_MsgExecute) Clear(fd protoreflect.FieldDescriptor) { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.bundler": + x.Bundler = "" case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.execution_messages": x.ExecutionMessages = nil default: @@ -2089,11 +2117,14 @@ func (x *fastReflection_MsgExecute) Clear(fd protoreflect.FieldDescriptor) { // of the value; to obtain a mutable reference, use Mutable. func (x *fastReflection_MsgExecute) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { switch descriptor.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.bundler": + value := x.Bundler + return protoreflect.ValueOfString(value) case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.execution_messages": if len(x.ExecutionMessages) == 0 { - return protoreflect.ValueOfList(&_MsgExecute_1_list{}) + return protoreflect.ValueOfList(&_MsgExecute_2_list{}) } - listValue := &_MsgExecute_1_list{list: &x.ExecutionMessages} + listValue := &_MsgExecute_2_list{list: &x.ExecutionMessages} return protoreflect.ValueOfList(listValue) default: if descriptor.IsExtension() { @@ -2115,9 +2146,11 @@ func (x *fastReflection_MsgExecute) Get(descriptor protoreflect.FieldDescriptor) // Set is a mutating operation and unsafe for concurrent use. func (x *fastReflection_MsgExecute) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.bundler": + x.Bundler = value.Interface().(string) case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.execution_messages": lv := value.List() - clv := lv.(*_MsgExecute_1_list) + clv := lv.(*_MsgExecute_2_list) x.ExecutionMessages = *clv.list default: if fd.IsExtension() { @@ -2143,8 +2176,10 @@ func (x *fastReflection_MsgExecute) Mutable(fd protoreflect.FieldDescriptor) pro if x.ExecutionMessages == nil { x.ExecutionMessages = []*anypb.Any{} } - value := &_MsgExecute_1_list{list: &x.ExecutionMessages} + value := &_MsgExecute_2_list{list: &x.ExecutionMessages} return protoreflect.ValueOfList(value) + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.bundler": + panic(fmt.Errorf("field bundler of message cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute")) @@ -2158,9 +2193,11 @@ func (x *fastReflection_MsgExecute) Mutable(fd protoreflect.FieldDescriptor) pro // For lists, maps, and messages, this returns a new, empty, mutable value. func (x *fastReflection_MsgExecute) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { switch fd.FullName() { + case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.bundler": + return protoreflect.ValueOfString("") case "cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute.execution_messages": list := []*anypb.Any{} - return protoreflect.ValueOfList(&_MsgExecute_1_list{list: &list}) + return protoreflect.ValueOfList(&_MsgExecute_2_list{list: &list}) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.interfaces.account_abstraction.v1.MsgExecute")) @@ -2230,6 +2267,10 @@ func (x *fastReflection_MsgExecute) ProtoMethods() *protoiface.Methods { var n int var l int _ = l + l = len(x.Bundler) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } if len(x.ExecutionMessages) > 0 { for _, e := range x.ExecutionMessages { l = options.Size(e) @@ -2278,9 +2319,16 @@ func (x *fastReflection_MsgExecute) ProtoMethods() *protoiface.Methods { copy(dAtA[i:], encoded) i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) i-- - dAtA[i] = 0xa + dAtA[i] = 0x12 } } + if len(x.Bundler) > 0 { + i -= len(x.Bundler) + copy(dAtA[i:], x.Bundler) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Bundler))) + i-- + dAtA[i] = 0xa + } if input.Buf != nil { input.Buf = append(input.Buf, dAtA...) } else { @@ -2331,6 +2379,38 @@ func (x *fastReflection_MsgExecute) ProtoMethods() *protoiface.Methods { } switch fieldNum { case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Bundler", 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.Bundler = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ExecutionMessages", wireType) } @@ -3749,13 +3829,13 @@ type MsgAuthenticate struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // bundler defines the address of the bundler that sent the operation. + // NOTE: in case the operation was sent directly by the user, this field will reflect + // the user address. + Bundler string `protobuf:"bytes,1,opt,name=bundler,proto3" json:"bundler,omitempty"` // user_operation is the operation that the user is trying to perform. // it also contains authentication information. - UserOperation *v1.UserOperation `protobuf:"bytes,1,opt,name=user_operation,json=userOperation,proto3" json:"user_operation,omitempty"` - // chain_id defines the network identifier. - ChainId string `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - // account_number is the account number of the user_operation. - AccountNumber uint64 `protobuf:"varint,3,opt,name=account_number,json=accountNumber,proto3" json:"account_number,omitempty"` + UserOperation *v1.UserOperation `protobuf:"bytes,2,opt,name=user_operation,json=userOperation,proto3" json:"user_operation,omitempty"` } func (x *MsgAuthenticate) Reset() { @@ -3778,25 +3858,18 @@ func (*MsgAuthenticate) Descriptor() ([]byte, []int) { return file_cosmos_accounts_interfaces_account_abstraction_v1_interface_proto_rawDescGZIP(), []int{0} } -func (x *MsgAuthenticate) GetUserOperation() *v1.UserOperation { +func (x *MsgAuthenticate) GetBundler() string { if x != nil { - return x.UserOperation - } - return nil -} - -func (x *MsgAuthenticate) GetChainId() string { - if x != nil { - return x.ChainId + return x.Bundler } return "" } -func (x *MsgAuthenticate) GetAccountNumber() uint64 { +func (x *MsgAuthenticate) GetUserOperation() *v1.UserOperation { if x != nil { - return x.AccountNumber + return x.UserOperation } - return 0 + return nil } // MsgAuthenticateResponse is the response to MsgAuthenticate. @@ -3837,9 +3910,13 @@ type MsgPayBundler struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // bundler is the address of the bundler. + // NOTE: in case the operation was sent directly by the user, this field will + // reflect the user address. + Bundler string `protobuf:"bytes,1,opt,name=bundler,proto3" json:"bundler,omitempty"` // bundler_payment_messages are the messages that the operation sender will execute. // The account can modify the messages as it sees fit. - BundlerPaymentMessages []*anypb.Any `protobuf:"bytes,1,rep,name=bundler_payment_messages,json=bundlerPaymentMessages,proto3" json:"bundler_payment_messages,omitempty"` + BundlerPaymentMessages []*anypb.Any `protobuf:"bytes,2,rep,name=bundler_payment_messages,json=bundlerPaymentMessages,proto3" json:"bundler_payment_messages,omitempty"` } func (x *MsgPayBundler) Reset() { @@ -3862,6 +3939,13 @@ func (*MsgPayBundler) Descriptor() ([]byte, []int) { return file_cosmos_accounts_interfaces_account_abstraction_v1_interface_proto_rawDescGZIP(), []int{2} } +func (x *MsgPayBundler) GetBundler() string { + if x != nil { + return x.Bundler + } + return "" +} + func (x *MsgPayBundler) GetBundlerPaymentMessages() []*anypb.Any { if x != nil { return x.BundlerPaymentMessages @@ -3916,9 +4000,13 @@ type MsgExecute struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // bundler is the address of the bundler. + // NOTE: in case the operation was sent directly by the user, this field will + // reflect the user address. + Bundler string `protobuf:"bytes,1,opt,name=bundler,proto3" json:"bundler,omitempty"` // execution_messages are the messages that the operation sender will execute. // The account can modify the messages as it sees fit. - ExecutionMessages []*anypb.Any `protobuf:"bytes,1,rep,name=execution_messages,json=executionMessages,proto3" json:"execution_messages,omitempty"` + ExecutionMessages []*anypb.Any `protobuf:"bytes,2,rep,name=execution_messages,json=executionMessages,proto3" json:"execution_messages,omitempty"` } func (x *MsgExecute) Reset() { @@ -3941,6 +4029,13 @@ func (*MsgExecute) Descriptor() ([]byte, []int) { return file_cosmos_accounts_interfaces_account_abstraction_v1_interface_proto_rawDescGZIP(), []int{4} } +func (x *MsgExecute) GetBundler() string { + if x != nil { + return x.Bundler + } + return "" +} + func (x *MsgExecute) GetExecutionMessages() []*anypb.Any { if x != nil { return x.ExecutionMessages @@ -4065,76 +4160,77 @@ var file_cosmos_accounts_interfaces_account_abstraction_v1_interface_proto_rawDe 0x6f, 0x1a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, - 0x9d, 0x01, 0x0a, 0x0f, 0x4d, 0x73, 0x67, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x12, 0x48, 0x0a, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, - 0x75, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, - 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, - 0x19, 0x0a, 0x17, 0x4d, 0x73, 0x67, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x0a, 0x0d, 0x4d, 0x73, - 0x67, 0x50, 0x61, 0x79, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x18, 0x62, - 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x41, 0x6e, 0x79, 0x52, 0x16, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, - 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x78, 0x0a, 0x15, 0x4d, - 0x73, 0x67, 0x50, 0x61, 0x79, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x21, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x5f, - 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, - 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x1e, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x0a, 0x0a, 0x4d, 0x73, 0x67, 0x45, 0x78, 0x65, 0x63, - 0x75, 0x74, 0x65, 0x12, 0x43, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x6a, 0x0a, 0x12, 0x4d, 0x73, 0x67, 0x45, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, - 0x0a, 0x1b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x19, 0x65, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x75, 0x74, - 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x73, 0x22, 0x5b, 0x0a, 0x22, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x16, 0x61, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x15, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, - 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x42, - 0x86, 0x03, 0x0a, 0x35, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, - 0x65, 0x73, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x49, 0x6e, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x58, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, - 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x76, 0x31, 0xa2, 0x02, 0x04, 0x43, 0x41, 0x49, 0x41, 0xaa, 0x02, 0x30, 0x43, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x31, 0xca, - 0x02, 0x30, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x73, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x5c, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5c, - 0x56, 0x31, 0xe2, 0x02, 0x3c, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x73, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x5c, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x34, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x63, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x73, 0x3a, 0x3a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, - 0x3a, 0x3a, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x75, 0x0a, 0x0f, 0x4d, 0x73, 0x67, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x0e, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x19, 0x0a, 0x17, 0x4d, 0x73, 0x67, 0x41, 0x75, 0x74, + 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x79, 0x0a, 0x0d, 0x4d, 0x73, 0x67, 0x50, 0x61, 0x79, 0x42, 0x75, 0x6e, 0x64, 0x6c, + 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x12, 0x4e, 0x0a, 0x18, + 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x16, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x78, 0x0a, 0x15, + 0x4d, 0x73, 0x67, 0x50, 0x61, 0x79, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x21, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, + 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x73, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x1e, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6b, 0x0a, 0x0a, 0x4d, 0x73, 0x67, 0x45, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x12, 0x43, + 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, + 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x22, 0x6a, 0x0a, 0x12, 0x4d, 0x73, 0x67, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x1b, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x5f, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x19, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x1c, 0x0a, 0x1a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0x5b, 0x0a, + 0x22, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x16, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x15, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x42, 0x86, 0x03, 0x0a, 0x35, 0x63, + 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x58, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, + 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x62, 0x73, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x5f, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x76, 0x31, + 0xa2, 0x02, 0x04, 0x43, 0x41, 0x49, 0x41, 0xaa, 0x02, 0x30, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, + 0x61, 0x63, 0x65, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x62, 0x73, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x30, 0x43, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5c, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x5c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, + 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x3c, + 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5c, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x5c, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, + 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x34, 0x43, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x3a, + 0x3a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x3a, 0x3a, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, + 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/cosmos/accounts/v1/account_abstraction.pulsar.go b/api/cosmos/accounts/v1/account_abstraction.pulsar.go index f805e13d32bf..838500494cb6 100644 --- a/api/cosmos/accounts/v1/account_abstraction.pulsar.go +++ b/api/cosmos/accounts/v1/account_abstraction.pulsar.go @@ -13,105 +13,105 @@ import ( sync "sync" ) -var _ protoreflect.List = (*_UserOperation_6_list)(nil) +var _ protoreflect.List = (*_UserOperation_5_list)(nil) -type _UserOperation_6_list struct { +type _UserOperation_5_list struct { list *[]*anypb.Any } -func (x *_UserOperation_6_list) Len() int { +func (x *_UserOperation_5_list) Len() int { if x.list == nil { return 0 } return len(*x.list) } -func (x *_UserOperation_6_list) Get(i int) protoreflect.Value { +func (x *_UserOperation_5_list) Get(i int) protoreflect.Value { return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) } -func (x *_UserOperation_6_list) Set(i int, value protoreflect.Value) { +func (x *_UserOperation_5_list) Set(i int, value protoreflect.Value) { valueUnwrapped := value.Message() concreteValue := valueUnwrapped.Interface().(*anypb.Any) (*x.list)[i] = concreteValue } -func (x *_UserOperation_6_list) Append(value protoreflect.Value) { +func (x *_UserOperation_5_list) Append(value protoreflect.Value) { valueUnwrapped := value.Message() concreteValue := valueUnwrapped.Interface().(*anypb.Any) *x.list = append(*x.list, concreteValue) } -func (x *_UserOperation_6_list) AppendMutable() protoreflect.Value { +func (x *_UserOperation_5_list) AppendMutable() protoreflect.Value { v := new(anypb.Any) *x.list = append(*x.list, v) return protoreflect.ValueOfMessage(v.ProtoReflect()) } -func (x *_UserOperation_6_list) Truncate(n int) { +func (x *_UserOperation_5_list) Truncate(n int) { for i := n; i < len(*x.list); i++ { (*x.list)[i] = nil } *x.list = (*x.list)[:n] } -func (x *_UserOperation_6_list) NewElement() protoreflect.Value { +func (x *_UserOperation_5_list) NewElement() protoreflect.Value { v := new(anypb.Any) return protoreflect.ValueOfMessage(v.ProtoReflect()) } -func (x *_UserOperation_6_list) IsValid() bool { +func (x *_UserOperation_5_list) IsValid() bool { return x.list != nil } -var _ protoreflect.List = (*_UserOperation_8_list)(nil) +var _ protoreflect.List = (*_UserOperation_7_list)(nil) -type _UserOperation_8_list struct { +type _UserOperation_7_list struct { list *[]*anypb.Any } -func (x *_UserOperation_8_list) Len() int { +func (x *_UserOperation_7_list) Len() int { if x.list == nil { return 0 } return len(*x.list) } -func (x *_UserOperation_8_list) Get(i int) protoreflect.Value { +func (x *_UserOperation_7_list) Get(i int) protoreflect.Value { return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) } -func (x *_UserOperation_8_list) Set(i int, value protoreflect.Value) { +func (x *_UserOperation_7_list) Set(i int, value protoreflect.Value) { valueUnwrapped := value.Message() concreteValue := valueUnwrapped.Interface().(*anypb.Any) (*x.list)[i] = concreteValue } -func (x *_UserOperation_8_list) Append(value protoreflect.Value) { +func (x *_UserOperation_7_list) Append(value protoreflect.Value) { valueUnwrapped := value.Message() concreteValue := valueUnwrapped.Interface().(*anypb.Any) *x.list = append(*x.list, concreteValue) } -func (x *_UserOperation_8_list) AppendMutable() protoreflect.Value { +func (x *_UserOperation_7_list) AppendMutable() protoreflect.Value { v := new(anypb.Any) *x.list = append(*x.list, v) return protoreflect.ValueOfMessage(v.ProtoReflect()) } -func (x *_UserOperation_8_list) Truncate(n int) { +func (x *_UserOperation_7_list) Truncate(n int) { for i := n; i < len(*x.list); i++ { (*x.list)[i] = nil } *x.list = (*x.list)[:n] } -func (x *_UserOperation_8_list) NewElement() protoreflect.Value { +func (x *_UserOperation_7_list) NewElement() protoreflect.Value { v := new(anypb.Any) return protoreflect.ValueOfMessage(v.ProtoReflect()) } -func (x *_UserOperation_8_list) IsValid() bool { +func (x *_UserOperation_7_list) IsValid() bool { return x.list != nil } @@ -120,7 +120,6 @@ var ( fd_UserOperation_sender protoreflect.FieldDescriptor fd_UserOperation_authentication_method protoreflect.FieldDescriptor fd_UserOperation_authentication_data protoreflect.FieldDescriptor - fd_UserOperation_sequence protoreflect.FieldDescriptor fd_UserOperation_authentication_gas_limit protoreflect.FieldDescriptor fd_UserOperation_bundler_payment_messages protoreflect.FieldDescriptor fd_UserOperation_bundler_payment_gas_limit protoreflect.FieldDescriptor @@ -134,7 +133,6 @@ func init() { fd_UserOperation_sender = md_UserOperation.Fields().ByName("sender") fd_UserOperation_authentication_method = md_UserOperation.Fields().ByName("authentication_method") fd_UserOperation_authentication_data = md_UserOperation.Fields().ByName("authentication_data") - fd_UserOperation_sequence = md_UserOperation.Fields().ByName("sequence") fd_UserOperation_authentication_gas_limit = md_UserOperation.Fields().ByName("authentication_gas_limit") fd_UserOperation_bundler_payment_messages = md_UserOperation.Fields().ByName("bundler_payment_messages") fd_UserOperation_bundler_payment_gas_limit = md_UserOperation.Fields().ByName("bundler_payment_gas_limit") @@ -225,12 +223,6 @@ func (x *fastReflection_UserOperation) Range(f func(protoreflect.FieldDescriptor return } } - if x.Sequence != uint64(0) { - value := protoreflect.ValueOfUint64(x.Sequence) - if !f(fd_UserOperation_sequence, value) { - return - } - } if x.AuthenticationGasLimit != uint64(0) { value := protoreflect.ValueOfUint64(x.AuthenticationGasLimit) if !f(fd_UserOperation_authentication_gas_limit, value) { @@ -238,7 +230,7 @@ func (x *fastReflection_UserOperation) Range(f func(protoreflect.FieldDescriptor } } if len(x.BundlerPaymentMessages) != 0 { - value := protoreflect.ValueOfList(&_UserOperation_6_list{list: &x.BundlerPaymentMessages}) + value := protoreflect.ValueOfList(&_UserOperation_5_list{list: &x.BundlerPaymentMessages}) if !f(fd_UserOperation_bundler_payment_messages, value) { return } @@ -250,7 +242,7 @@ func (x *fastReflection_UserOperation) Range(f func(protoreflect.FieldDescriptor } } if len(x.ExecutionMessages) != 0 { - value := protoreflect.ValueOfList(&_UserOperation_8_list{list: &x.ExecutionMessages}) + value := protoreflect.ValueOfList(&_UserOperation_7_list{list: &x.ExecutionMessages}) if !f(fd_UserOperation_execution_messages, value) { return } @@ -282,8 +274,6 @@ func (x *fastReflection_UserOperation) Has(fd protoreflect.FieldDescriptor) bool return x.AuthenticationMethod != "" case "cosmos.accounts.v1.UserOperation.authentication_data": return len(x.AuthenticationData) != 0 - case "cosmos.accounts.v1.UserOperation.sequence": - return x.Sequence != uint64(0) case "cosmos.accounts.v1.UserOperation.authentication_gas_limit": return x.AuthenticationGasLimit != uint64(0) case "cosmos.accounts.v1.UserOperation.bundler_payment_messages": @@ -316,8 +306,6 @@ func (x *fastReflection_UserOperation) Clear(fd protoreflect.FieldDescriptor) { x.AuthenticationMethod = "" case "cosmos.accounts.v1.UserOperation.authentication_data": x.AuthenticationData = nil - case "cosmos.accounts.v1.UserOperation.sequence": - x.Sequence = uint64(0) case "cosmos.accounts.v1.UserOperation.authentication_gas_limit": x.AuthenticationGasLimit = uint64(0) case "cosmos.accounts.v1.UserOperation.bundler_payment_messages": @@ -353,26 +341,23 @@ func (x *fastReflection_UserOperation) Get(descriptor protoreflect.FieldDescript case "cosmos.accounts.v1.UserOperation.authentication_data": value := x.AuthenticationData return protoreflect.ValueOfBytes(value) - case "cosmos.accounts.v1.UserOperation.sequence": - value := x.Sequence - return protoreflect.ValueOfUint64(value) case "cosmos.accounts.v1.UserOperation.authentication_gas_limit": value := x.AuthenticationGasLimit return protoreflect.ValueOfUint64(value) case "cosmos.accounts.v1.UserOperation.bundler_payment_messages": if len(x.BundlerPaymentMessages) == 0 { - return protoreflect.ValueOfList(&_UserOperation_6_list{}) + return protoreflect.ValueOfList(&_UserOperation_5_list{}) } - listValue := &_UserOperation_6_list{list: &x.BundlerPaymentMessages} + listValue := &_UserOperation_5_list{list: &x.BundlerPaymentMessages} return protoreflect.ValueOfList(listValue) case "cosmos.accounts.v1.UserOperation.bundler_payment_gas_limit": value := x.BundlerPaymentGasLimit return protoreflect.ValueOfUint64(value) case "cosmos.accounts.v1.UserOperation.execution_messages": if len(x.ExecutionMessages) == 0 { - return protoreflect.ValueOfList(&_UserOperation_8_list{}) + return protoreflect.ValueOfList(&_UserOperation_7_list{}) } - listValue := &_UserOperation_8_list{list: &x.ExecutionMessages} + listValue := &_UserOperation_7_list{list: &x.ExecutionMessages} return protoreflect.ValueOfList(listValue) case "cosmos.accounts.v1.UserOperation.execution_gas_limit": value := x.ExecutionGasLimit @@ -403,19 +388,17 @@ func (x *fastReflection_UserOperation) Set(fd protoreflect.FieldDescriptor, valu x.AuthenticationMethod = value.Interface().(string) case "cosmos.accounts.v1.UserOperation.authentication_data": x.AuthenticationData = value.Bytes() - case "cosmos.accounts.v1.UserOperation.sequence": - x.Sequence = value.Uint() case "cosmos.accounts.v1.UserOperation.authentication_gas_limit": x.AuthenticationGasLimit = value.Uint() case "cosmos.accounts.v1.UserOperation.bundler_payment_messages": lv := value.List() - clv := lv.(*_UserOperation_6_list) + clv := lv.(*_UserOperation_5_list) x.BundlerPaymentMessages = *clv.list case "cosmos.accounts.v1.UserOperation.bundler_payment_gas_limit": x.BundlerPaymentGasLimit = value.Uint() case "cosmos.accounts.v1.UserOperation.execution_messages": lv := value.List() - clv := lv.(*_UserOperation_8_list) + clv := lv.(*_UserOperation_7_list) x.ExecutionMessages = *clv.list case "cosmos.accounts.v1.UserOperation.execution_gas_limit": x.ExecutionGasLimit = value.Uint() @@ -443,13 +426,13 @@ func (x *fastReflection_UserOperation) Mutable(fd protoreflect.FieldDescriptor) if x.BundlerPaymentMessages == nil { x.BundlerPaymentMessages = []*anypb.Any{} } - value := &_UserOperation_6_list{list: &x.BundlerPaymentMessages} + value := &_UserOperation_5_list{list: &x.BundlerPaymentMessages} return protoreflect.ValueOfList(value) case "cosmos.accounts.v1.UserOperation.execution_messages": if x.ExecutionMessages == nil { x.ExecutionMessages = []*anypb.Any{} } - value := &_UserOperation_8_list{list: &x.ExecutionMessages} + value := &_UserOperation_7_list{list: &x.ExecutionMessages} return protoreflect.ValueOfList(value) case "cosmos.accounts.v1.UserOperation.sender": panic(fmt.Errorf("field sender of message cosmos.accounts.v1.UserOperation is not mutable")) @@ -457,8 +440,6 @@ func (x *fastReflection_UserOperation) Mutable(fd protoreflect.FieldDescriptor) panic(fmt.Errorf("field authentication_method of message cosmos.accounts.v1.UserOperation is not mutable")) case "cosmos.accounts.v1.UserOperation.authentication_data": panic(fmt.Errorf("field authentication_data of message cosmos.accounts.v1.UserOperation is not mutable")) - case "cosmos.accounts.v1.UserOperation.sequence": - panic(fmt.Errorf("field sequence of message cosmos.accounts.v1.UserOperation is not mutable")) case "cosmos.accounts.v1.UserOperation.authentication_gas_limit": panic(fmt.Errorf("field authentication_gas_limit of message cosmos.accounts.v1.UserOperation is not mutable")) case "cosmos.accounts.v1.UserOperation.bundler_payment_gas_limit": @@ -484,18 +465,16 @@ func (x *fastReflection_UserOperation) NewField(fd protoreflect.FieldDescriptor) return protoreflect.ValueOfString("") case "cosmos.accounts.v1.UserOperation.authentication_data": return protoreflect.ValueOfBytes(nil) - case "cosmos.accounts.v1.UserOperation.sequence": - return protoreflect.ValueOfUint64(uint64(0)) case "cosmos.accounts.v1.UserOperation.authentication_gas_limit": return protoreflect.ValueOfUint64(uint64(0)) case "cosmos.accounts.v1.UserOperation.bundler_payment_messages": list := []*anypb.Any{} - return protoreflect.ValueOfList(&_UserOperation_6_list{list: &list}) + return protoreflect.ValueOfList(&_UserOperation_5_list{list: &list}) case "cosmos.accounts.v1.UserOperation.bundler_payment_gas_limit": return protoreflect.ValueOfUint64(uint64(0)) case "cosmos.accounts.v1.UserOperation.execution_messages": list := []*anypb.Any{} - return protoreflect.ValueOfList(&_UserOperation_8_list{list: &list}) + return protoreflect.ValueOfList(&_UserOperation_7_list{list: &list}) case "cosmos.accounts.v1.UserOperation.execution_gas_limit": return protoreflect.ValueOfUint64(uint64(0)) default: @@ -579,9 +558,6 @@ func (x *fastReflection_UserOperation) ProtoMethods() *protoiface.Methods { if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) } - if x.Sequence != 0 { - n += 1 + runtime.Sov(uint64(x.Sequence)) - } if x.AuthenticationGasLimit != 0 { n += 1 + runtime.Sov(uint64(x.AuthenticationGasLimit)) } @@ -635,7 +611,7 @@ func (x *fastReflection_UserOperation) ProtoMethods() *protoiface.Methods { if x.ExecutionGasLimit != 0 { i = runtime.EncodeVarint(dAtA, i, uint64(x.ExecutionGasLimit)) i-- - dAtA[i] = 0x48 + dAtA[i] = 0x40 } if len(x.ExecutionMessages) > 0 { for iNdEx := len(x.ExecutionMessages) - 1; iNdEx >= 0; iNdEx-- { @@ -650,13 +626,13 @@ func (x *fastReflection_UserOperation) ProtoMethods() *protoiface.Methods { copy(dAtA[i:], encoded) i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) i-- - dAtA[i] = 0x42 + dAtA[i] = 0x3a } } if x.BundlerPaymentGasLimit != 0 { i = runtime.EncodeVarint(dAtA, i, uint64(x.BundlerPaymentGasLimit)) i-- - dAtA[i] = 0x38 + dAtA[i] = 0x30 } if len(x.BundlerPaymentMessages) > 0 { for iNdEx := len(x.BundlerPaymentMessages) - 1; iNdEx >= 0; iNdEx-- { @@ -671,17 +647,12 @@ func (x *fastReflection_UserOperation) ProtoMethods() *protoiface.Methods { copy(dAtA[i:], encoded) i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) i-- - dAtA[i] = 0x32 + dAtA[i] = 0x2a } } if x.AuthenticationGasLimit != 0 { i = runtime.EncodeVarint(dAtA, i, uint64(x.AuthenticationGasLimit)) i-- - dAtA[i] = 0x28 - } - if x.Sequence != 0 { - i = runtime.EncodeVarint(dAtA, i, uint64(x.Sequence)) - i-- dAtA[i] = 0x20 } if len(x.AuthenticationData) > 0 { @@ -853,25 +824,6 @@ func (x *fastReflection_UserOperation) ProtoMethods() *protoiface.Methods { } iNdEx = postIndex case 4: - if wireType != 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) - } - x.Sequence = 0 - 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++ - x.Sequence |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: if wireType != 0 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field AuthenticationGasLimit", wireType) } @@ -890,7 +842,7 @@ func (x *fastReflection_UserOperation) ProtoMethods() *protoiface.Methods { break } } - case 6: + case 5: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field BundlerPaymentMessages", wireType) } @@ -924,7 +876,7 @@ func (x *fastReflection_UserOperation) ProtoMethods() *protoiface.Methods { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } iNdEx = postIndex - case 7: + case 6: if wireType != 0 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field BundlerPaymentGasLimit", wireType) } @@ -943,7 +895,7 @@ func (x *fastReflection_UserOperation) ProtoMethods() *protoiface.Methods { break } } - case 8: + case 7: if wireType != 2 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ExecutionMessages", wireType) } @@ -977,7 +929,7 @@ func (x *fastReflection_UserOperation) ProtoMethods() *protoiface.Methods { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } iNdEx = postIndex - case 9: + case 8: if wireType != 0 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ExecutionGasLimit", wireType) } @@ -1140,6 +1092,7 @@ var ( fd_UserOperationResponse_bundler_payment_responses protoreflect.FieldDescriptor fd_UserOperationResponse_execution_gas_used protoreflect.FieldDescriptor fd_UserOperationResponse_execution_responses protoreflect.FieldDescriptor + fd_UserOperationResponse_error protoreflect.FieldDescriptor ) func init() { @@ -1150,6 +1103,7 @@ func init() { fd_UserOperationResponse_bundler_payment_responses = md_UserOperationResponse.Fields().ByName("bundler_payment_responses") fd_UserOperationResponse_execution_gas_used = md_UserOperationResponse.Fields().ByName("execution_gas_used") fd_UserOperationResponse_execution_responses = md_UserOperationResponse.Fields().ByName("execution_responses") + fd_UserOperationResponse_error = md_UserOperationResponse.Fields().ByName("error") } var _ protoreflect.Message = (*fastReflection_UserOperationResponse)(nil) @@ -1247,6 +1201,12 @@ func (x *fastReflection_UserOperationResponse) Range(f func(protoreflect.FieldDe return } } + if x.Error != "" { + value := protoreflect.ValueOfString(x.Error) + if !f(fd_UserOperationResponse_error, value) { + return + } + } } // Has reports whether a field is populated. @@ -1272,6 +1232,8 @@ func (x *fastReflection_UserOperationResponse) Has(fd protoreflect.FieldDescript return x.ExecutionGasUsed != uint64(0) case "cosmos.accounts.v1.UserOperationResponse.execution_responses": return len(x.ExecutionResponses) != 0 + case "cosmos.accounts.v1.UserOperationResponse.error": + return x.Error != "" default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.v1.UserOperationResponse")) @@ -1298,6 +1260,8 @@ func (x *fastReflection_UserOperationResponse) Clear(fd protoreflect.FieldDescri x.ExecutionGasUsed = uint64(0) case "cosmos.accounts.v1.UserOperationResponse.execution_responses": x.ExecutionResponses = nil + case "cosmos.accounts.v1.UserOperationResponse.error": + x.Error = "" default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.v1.UserOperationResponse")) @@ -1335,6 +1299,9 @@ func (x *fastReflection_UserOperationResponse) Get(descriptor protoreflect.Field } listValue := &_UserOperationResponse_5_list{list: &x.ExecutionResponses} return protoreflect.ValueOfList(listValue) + case "cosmos.accounts.v1.UserOperationResponse.error": + value := x.Error + return protoreflect.ValueOfString(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.v1.UserOperationResponse")) @@ -1369,6 +1336,8 @@ func (x *fastReflection_UserOperationResponse) Set(fd protoreflect.FieldDescript lv := value.List() clv := lv.(*_UserOperationResponse_5_list) x.ExecutionResponses = *clv.list + case "cosmos.accounts.v1.UserOperationResponse.error": + x.Error = value.Interface().(string) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.v1.UserOperationResponse")) @@ -1407,6 +1376,8 @@ func (x *fastReflection_UserOperationResponse) Mutable(fd protoreflect.FieldDesc panic(fmt.Errorf("field bundler_payment_gas_used of message cosmos.accounts.v1.UserOperationResponse is not mutable")) case "cosmos.accounts.v1.UserOperationResponse.execution_gas_used": panic(fmt.Errorf("field execution_gas_used of message cosmos.accounts.v1.UserOperationResponse is not mutable")) + case "cosmos.accounts.v1.UserOperationResponse.error": + panic(fmt.Errorf("field error of message cosmos.accounts.v1.UserOperationResponse is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.v1.UserOperationResponse")) @@ -1432,6 +1403,8 @@ func (x *fastReflection_UserOperationResponse) NewField(fd protoreflect.FieldDes case "cosmos.accounts.v1.UserOperationResponse.execution_responses": list := []*anypb.Any{} return protoreflect.ValueOfList(&_UserOperationResponse_5_list{list: &list}) + case "cosmos.accounts.v1.UserOperationResponse.error": + return protoreflect.ValueOfString("") default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.accounts.v1.UserOperationResponse")) @@ -1522,6 +1495,10 @@ func (x *fastReflection_UserOperationResponse) ProtoMethods() *protoiface.Method n += 1 + l + runtime.Sov(uint64(l)) } } + l = len(x.Error) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -1551,6 +1528,13 @@ func (x *fastReflection_UserOperationResponse) ProtoMethods() *protoiface.Method i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if len(x.Error) > 0 { + i -= len(x.Error) + copy(dAtA[i:], x.Error) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Error))) + i-- + dAtA[i] = 0x32 + } if len(x.ExecutionResponses) > 0 { for iNdEx := len(x.ExecutionResponses) - 1; iNdEx >= 0; iNdEx-- { encoded, err := options.Marshal(x.ExecutionResponses[iNdEx]) @@ -1772,6 +1756,38 @@ func (x *fastReflection_UserOperationResponse) ProtoMethods() *protoiface.Method return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } iNdEx = postIndex + case 6: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Error", 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.Error = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -1836,12 +1852,9 @@ type UserOperation struct { // authentication_data defines the authentication data associated with the authentication method. // It is the account implementer duty to assess that the UserOperation is properly signed. AuthenticationData []byte `protobuf:"bytes,3,opt,name=authentication_data,json=authenticationData,proto3" json:"authentication_data,omitempty"` - // sequence defines the sequence number of the account, the authentication method might require this - // to ensure non-replayability. - Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` // authentication_gas_limit expresses the gas limit to be used for the authentication part of the // UserOperation. - AuthenticationGasLimit uint64 `protobuf:"varint,5,opt,name=authentication_gas_limit,json=authenticationGasLimit,proto3" json:"authentication_gas_limit,omitempty"` + AuthenticationGasLimit uint64 `protobuf:"varint,4,opt,name=authentication_gas_limit,json=authenticationGasLimit,proto3" json:"authentication_gas_limit,omitempty"` // bundler_payment_messages expresses a list of messages that the account // executes to pay the bundler for submitting the UserOperation. // It can be empty if the bundler does not need any form of payment, @@ -1851,18 +1864,18 @@ type UserOperation struct { // - NFT payment // - IBC Token payment. // - Payment through delegations. - BundlerPaymentMessages []*anypb.Any `protobuf:"bytes,6,rep,name=bundler_payment_messages,json=bundlerPaymentMessages,proto3" json:"bundler_payment_messages,omitempty"` + BundlerPaymentMessages []*anypb.Any `protobuf:"bytes,5,rep,name=bundler_payment_messages,json=bundlerPaymentMessages,proto3" json:"bundler_payment_messages,omitempty"` // bundler_payment_gas_limit defines the gas limit to be used for the bundler payment. // This ensures that, since the bundler executes a list of UserOperations and there needs to // be minimal trust between bundler and UserOperation sender, the sender cannot consume // the whole bundle gas. - BundlerPaymentGasLimit uint64 `protobuf:"varint,7,opt,name=bundler_payment_gas_limit,json=bundlerPaymentGasLimit,proto3" json:"bundler_payment_gas_limit,omitempty"` + BundlerPaymentGasLimit uint64 `protobuf:"varint,6,opt,name=bundler_payment_gas_limit,json=bundlerPaymentGasLimit,proto3" json:"bundler_payment_gas_limit,omitempty"` // execution_messages expresses a list of messages that the account wants to execute. // This concretely is the intent of the transaction expressed as a UserOperation. - ExecutionMessages []*anypb.Any `protobuf:"bytes,8,rep,name=execution_messages,json=executionMessages,proto3" json:"execution_messages,omitempty"` + ExecutionMessages []*anypb.Any `protobuf:"bytes,7,rep,name=execution_messages,json=executionMessages,proto3" json:"execution_messages,omitempty"` // execution_gas_limit defines the gas limit to be used for the execution of the UserOperation's // execution messages. - ExecutionGasLimit uint64 `protobuf:"varint,9,opt,name=execution_gas_limit,json=executionGasLimit,proto3" json:"execution_gas_limit,omitempty"` + ExecutionGasLimit uint64 `protobuf:"varint,8,opt,name=execution_gas_limit,json=executionGasLimit,proto3" json:"execution_gas_limit,omitempty"` } func (x *UserOperation) Reset() { @@ -1906,13 +1919,6 @@ func (x *UserOperation) GetAuthenticationData() []byte { return nil } -func (x *UserOperation) GetSequence() uint64 { - if x != nil { - return x.Sequence - } - return 0 -} - func (x *UserOperation) GetAuthenticationGasLimit() uint64 { if x != nil { return x.AuthenticationGasLimit @@ -1949,6 +1955,7 @@ func (x *UserOperation) GetExecutionGasLimit() uint64 { } // UserOperationResponse defines the response of a UserOperation. +// If the operation fails the error field will be populated. type UserOperationResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1965,6 +1972,12 @@ type UserOperationResponse struct { ExecutionGasUsed uint64 `protobuf:"varint,4,opt,name=execution_gas_used,json=executionGasUsed,proto3" json:"execution_gas_used,omitempty"` // execution_responses defines the responses of the execution messages. ExecutionResponses []*anypb.Any `protobuf:"bytes,5,rep,name=execution_responses,json=executionResponses,proto3" json:"execution_responses,omitempty"` + // error defines the error that occurred during the execution of the UserOperation. + // If the error is not empty, the UserOperation failed. + // Other fields might be populated even if the error is not empty, for example + // if the operation fails after the authentication step, the authentication_gas_used + // field will be populated. + Error string `protobuf:"bytes,6,opt,name=error,proto3" json:"error,omitempty"` } func (x *UserOperationResponse) Reset() { @@ -2022,6 +2035,13 @@ func (x *UserOperationResponse) GetExecutionResponses() []*anypb.Any { return nil } +func (x *UserOperationResponse) GetError() string { + if x != nil { + return x.Error + } + return "" +} + var File_cosmos_accounts_v1_account_abstraction_proto protoreflect.FileDescriptor var file_cosmos_accounts_v1_account_abstraction_proto_rawDesc = []byte{ @@ -2030,7 +2050,7 @@ var file_cosmos_accounts_v1_account_abstraction_proto_rawDesc = []byte{ 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe3, 0x03, + 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x03, 0x0a, 0x0d, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x15, 0x61, 0x75, 0x74, 0x68, 0x65, @@ -2039,63 +2059,63 @@ var file_cosmos_accounts_v1_account_abstraction_proto_rawDesc = []byte{ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x2f, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, - 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x38, 0x0a, 0x18, 0x61, 0x75, 0x74, - 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x61, 0x73, 0x5f, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x61, 0x75, 0x74, - 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x61, 0x73, 0x4c, 0x69, - 0x6d, 0x69, 0x74, 0x12, 0x4e, 0x0a, 0x18, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x5f, 0x70, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x16, 0x62, 0x75, 0x6e, - 0x64, 0x6c, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x5f, 0x70, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x50, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x43, - 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, - 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x61, 0x73, 0x4c, 0x69, - 0x6d, 0x69, 0x74, 0x22, 0xcf, 0x02, 0x0a, 0x15, 0x55, 0x73, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, - 0x17, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, - 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x61, - 0x73, 0x55, 0x73, 0x65, 0x64, 0x12, 0x37, 0x0a, 0x18, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, - 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, - 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x12, 0x50, - 0x0a, 0x19, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x17, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, - 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, - 0x12, 0x2c, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x61, - 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x12, 0x45, - 0x0a, 0x13, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, - 0x79, 0x52, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x42, 0xcb, 0x01, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, - 0x42, 0x17, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x76, 0x31, - 0x3b, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x41, - 0x58, 0xaa, 0x02, 0x12, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x73, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x12, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, - 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1e, 0x43, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5c, 0x56, 0x31, - 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x43, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x3a, - 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x38, 0x0a, + 0x18, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x16, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x47, + 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x4e, 0x0a, 0x18, 0x62, 0x75, 0x6e, 0x64, 0x6c, + 0x65, 0x72, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, + 0x16, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x62, 0x75, 0x6e, 0x64, 0x6c, + 0x65, 0x72, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x75, 0x6e, 0x64, + 0x6c, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x61, 0x73, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x12, 0x43, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x47, + 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0xe5, 0x02, 0x0a, 0x15, 0x55, 0x73, 0x65, 0x72, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x36, 0x0a, 0x17, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x15, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x47, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64, 0x12, 0x37, 0x0a, 0x18, 0x62, 0x75, 0x6e, + 0x64, 0x6c, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x67, 0x61, 0x73, + 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x62, 0x75, 0x6e, + 0x64, 0x6c, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x47, 0x61, 0x73, 0x55, 0x73, + 0x65, 0x64, 0x12, 0x50, 0x0a, 0x19, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x5f, 0x70, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x17, 0x62, 0x75, 0x6e, + 0x64, 0x6c, 0x65, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x61, 0x73, 0x55, 0x73, + 0x65, 0x64, 0x12, 0x45, 0x0a, 0x13, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, + 0xcb, 0x01, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x17, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, + 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x73, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x41, 0x58, 0xaa, 0x02, 0x12, 0x43, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x56, 0x31, + 0xca, 0x02, 0x12, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x73, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1e, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, + 0x3a, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/baseapp/internal/protocompat/protocompat.go b/baseapp/internal/protocompat/protocompat.go index 18de9ac7a608..8e85ea6cede0 100644 --- a/baseapp/internal/protocompat/protocompat.go +++ b/baseapp/internal/protocompat/protocompat.go @@ -23,6 +23,8 @@ var ( type Handler = func(ctx context.Context, request, response protoiface.MessageV1) error +// MakeHybridHandler returns a handler that can handle both gogo and protov2 messages, no matter +// if the handler is a gogo or protov2 handler. func MakeHybridHandler(cdc codec.BinaryCodec, sd *grpc.ServiceDesc, method grpc.MethodDesc, handler interface{}) (Handler, error) { methodFullName := protoreflect.FullName(fmt.Sprintf("%s.%s", sd.ServiceName, method.MethodName)) desc, err := gogoproto.HybridResolver.FindDescriptorByName(methodFullName) @@ -221,3 +223,17 @@ func RequestFullNameFromMethodDesc(sd *grpc.ServiceDesc, method grpc.MethodDesc) } return methodDesc.Input().FullName(), nil } + +// ResponseFullNameFromMethodDesc returns the fully-qualified name of the response message of the provided service's method. +func ResponseFullNameFromMethodDesc(sd *grpc.ServiceDesc, method grpc.MethodDesc) (protoreflect.FullName, error) { + methodFullName := protoreflect.FullName(fmt.Sprintf("%s.%s", sd.ServiceName, method.MethodName)) + desc, err := gogoproto.HybridResolver.FindDescriptorByName(methodFullName) + if err != nil { + return "", fmt.Errorf("cannot find method descriptor %s", methodFullName) + } + methodDesc, ok := desc.(protoreflect.MethodDescriptor) + if !ok { + return "", fmt.Errorf("invalid method descriptor %s", methodFullName) + } + return methodDesc.Output().FullName(), nil +} diff --git a/baseapp/msg_service_router.go b/baseapp/msg_service_router.go index 506112490220..f2857affcead 100644 --- a/baseapp/msg_service_router.go +++ b/baseapp/msg_service_router.go @@ -31,6 +31,7 @@ type MsgServiceRouter struct { interfaceRegistry codectypes.InterfaceRegistry routes map[string]MsgServiceHandler hybridHandlers map[string]func(ctx context.Context, req, resp protoiface.MessageV1) error + responseByRequest map[string]string circuitBreaker CircuitBreaker } @@ -39,8 +40,10 @@ var _ gogogrpc.Server = &MsgServiceRouter{} // NewMsgServiceRouter creates a new MsgServiceRouter. func NewMsgServiceRouter() *MsgServiceRouter { return &MsgServiceRouter{ - routes: map[string]MsgServiceHandler{}, - hybridHandlers: map[string]func(ctx context.Context, req, resp protoiface.MessageV1) error{}, + routes: map[string]MsgServiceHandler{}, + hybridHandlers: map[string]func(ctx context.Context, req, resp protoiface.MessageV1) error{}, + responseByRequest: map[string]string{}, + circuitBreaker: nil, } } @@ -87,16 +90,26 @@ func (msr *MsgServiceRouter) HybridHandlerByMsgName(msgName string) func(ctx con return msr.hybridHandlers[msgName] } +func (msr *MsgServiceRouter) ResponseNameByRequestName(msgName string) string { + return msr.responseByRequest[msgName] +} + func (msr *MsgServiceRouter) registerHybridHandler(sd *grpc.ServiceDesc, method grpc.MethodDesc, handler interface{}) error { inputName, err := protocompat.RequestFullNameFromMethodDesc(sd, method) if err != nil { return err } + outputName, err := protocompat.ResponseFullNameFromMethodDesc(sd, method) + if err != nil { + return err + } cdc := codec.NewProtoCodec(msr.interfaceRegistry) hybridHandler, err := protocompat.MakeHybridHandler(cdc, sd, method, handler) if err != nil { return err } + // map input name to output name + msr.responseByRequest[string(inputName)] = string(outputName) // if circuit breaker is not nil, then we decorate the hybrid handler with the circuit breaker if msr.circuitBreaker == nil { msr.hybridHandlers[string(inputName)] = hybridHandler diff --git a/proto/cosmos/accounts/interfaces/account_abstraction/v1/interface.proto b/proto/cosmos/accounts/interfaces/account_abstraction/v1/interface.proto index 0f09e60c688b..098448d61809 100644 --- a/proto/cosmos/accounts/interfaces/account_abstraction/v1/interface.proto +++ b/proto/cosmos/accounts/interfaces/account_abstraction/v1/interface.proto @@ -8,13 +8,13 @@ import "cosmos/accounts/v1/account_abstraction.proto"; // MsgAuthenticate is a message that an x/account account abstraction implementer // must handle to authenticate a state transition. message MsgAuthenticate { + // bundler defines the address of the bundler that sent the operation. + // NOTE: in case the operation was sent directly by the user, this field will reflect + // the user address. + string bundler = 1; // user_operation is the operation that the user is trying to perform. // it also contains authentication information. - cosmos.accounts.v1.UserOperation user_operation = 1; - // chain_id defines the network identifier. - string chain_id = 2; - // account_number is the account number of the user_operation. - uint64 account_number = 3; + cosmos.accounts.v1.UserOperation user_operation = 2; } // MsgAuthenticateResponse is the response to MsgAuthenticate. @@ -27,9 +27,13 @@ message MsgAuthenticateResponse {} // the bundler payment messages. // The account must ensure the caller of this message is the x/accounts module itself. message MsgPayBundler { + // bundler is the address of the bundler. + // NOTE: in case the operation was sent directly by the user, this field will + // reflect the user address. + string bundler = 1; // bundler_payment_messages are the messages that the operation sender will execute. // The account can modify the messages as it sees fit. - repeated google.protobuf.Any bundler_payment_messages = 1; + repeated google.protobuf.Any bundler_payment_messages = 2; } // MsgPayBundlerResponse is the response to MsgPayBundler. @@ -44,9 +48,13 @@ message MsgPayBundlerResponse { // block certain messages, or modify them. // The account must ensure the caller of this message is the x/accounts module itself. message MsgExecute { + // bundler is the address of the bundler. + // NOTE: in case the operation was sent directly by the user, this field will + // reflect the user address. + string bundler = 1; // execution_messages are the messages that the operation sender will execute. // The account can modify the messages as it sees fit. - repeated google.protobuf.Any execution_messages = 1; + repeated google.protobuf.Any execution_messages = 2; } // MsgExecuteResponse is the response to MsgExecute. diff --git a/proto/cosmos/accounts/v1/account_abstraction.proto b/proto/cosmos/accounts/v1/account_abstraction.proto index a77eda5cea97..01fb36436fbc 100644 --- a/proto/cosmos/accounts/v1/account_abstraction.proto +++ b/proto/cosmos/accounts/v1/account_abstraction.proto @@ -18,12 +18,9 @@ message UserOperation { // authentication_data defines the authentication data associated with the authentication method. // It is the account implementer duty to assess that the UserOperation is properly signed. bytes authentication_data = 3; - // sequence defines the sequence number of the account, the authentication method might require this - // to ensure non-replayability. - uint64 sequence = 4; // authentication_gas_limit expresses the gas limit to be used for the authentication part of the // UserOperation. - uint64 authentication_gas_limit = 5; + uint64 authentication_gas_limit = 4; // bundler_payment_messages expresses a list of messages that the account // executes to pay the bundler for submitting the UserOperation. // It can be empty if the bundler does not need any form of payment, @@ -33,21 +30,22 @@ message UserOperation { // - NFT payment // - IBC Token payment. // - Payment through delegations. - repeated google.protobuf.Any bundler_payment_messages = 6; + repeated google.protobuf.Any bundler_payment_messages = 5; // bundler_payment_gas_limit defines the gas limit to be used for the bundler payment. // This ensures that, since the bundler executes a list of UserOperations and there needs to // be minimal trust between bundler and UserOperation sender, the sender cannot consume // the whole bundle gas. - uint64 bundler_payment_gas_limit = 7; + uint64 bundler_payment_gas_limit = 6; // execution_messages expresses a list of messages that the account wants to execute. // This concretely is the intent of the transaction expressed as a UserOperation. - repeated google.protobuf.Any execution_messages = 8; + repeated google.protobuf.Any execution_messages = 7; // execution_gas_limit defines the gas limit to be used for the execution of the UserOperation's // execution messages. - uint64 execution_gas_limit = 9; + uint64 execution_gas_limit = 8; } // UserOperationResponse defines the response of a UserOperation. +// If the operation fails the error field will be populated. message UserOperationResponse { // authentication_gas_used defines the gas used for the authentication part of the UserOperation. uint64 authentication_gas_used = 1; @@ -60,4 +58,10 @@ message UserOperationResponse { uint64 execution_gas_used = 4; // execution_responses defines the responses of the execution messages. repeated google.protobuf.Any execution_responses = 5; + // error defines the error that occurred during the execution of the UserOperation. + // If the error is not empty, the UserOperation failed. + // Other fields might be populated even if the error is not empty, for example + // if the operation fails after the authentication step, the authentication_gas_used + // field will be populated. + string error = 6; } \ No newline at end of file diff --git a/simapp/app.go b/simapp/app.go index 7c56ee644114..5ab2391eb763 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -22,6 +22,7 @@ import ( storetypes "cosmossdk.io/store/types" "cosmossdk.io/x/accounts" "cosmossdk.io/x/accounts/accountstd" + "cosmossdk.io/x/accounts/testing/account_abstraction" "cosmossdk.io/x/accounts/testing/counter" "cosmossdk.io/x/auth" "cosmossdk.io/x/auth/ante" @@ -284,11 +285,14 @@ func NewSimApp( accountsKeeper, err := accounts.NewKeeper( runtime.NewKVStoreService(keys[accounts.StoreKey]), runtime.EventService{}, + runtime.BranchService{}, app.AuthKeeper.AddressCodec(), appCodec.InterfaceRegistry().SigningContext(), app.MsgServiceRouter(), app.GRPCQueryRouter(), accountstd.AddAccount("counter", counter.NewAccount), + accountstd.AddAccount("aa_minimal", account_abstraction.NewMinimalAbstractedAccount), + accountstd.AddAccount("aa_full", account_abstraction.NewFullAbstractedAccount), ) if err != nil { panic(err) diff --git a/tests/e2e/accounts/account_abstraction_test.go b/tests/e2e/accounts/account_abstraction_test.go new file mode 100644 index 000000000000..0b0802ffb551 --- /dev/null +++ b/tests/e2e/accounts/account_abstraction_test.go @@ -0,0 +1,349 @@ +//go:build app_v1 + +package accounts + +import ( + "context" + "testing" + + rotationv1 "cosmossdk.io/api/cosmos/accounts/testing/rotation/v1" + accountsv1 "cosmossdk.io/api/cosmos/accounts/v1" + bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" + v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + nftv1beta1 "cosmossdk.io/api/cosmos/nft/v1beta1" + stakingv1beta1 "cosmossdk.io/api/cosmos/staking/v1beta1" + "cosmossdk.io/simapp" + "cosmossdk.io/x/accounts" + "cosmossdk.io/x/bank/testutil" + "cosmossdk.io/x/nft" + "github.com/cosmos/cosmos-proto/anyutil" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" +) + +var ( + privKey = secp256k1.GenPrivKey() + accCreator = []byte("creator") + bundlerAddr = secp256k1.GenPrivKey().PubKey().Address() + aliceAddr = secp256k1.GenPrivKey().PubKey().Address() +) + +func TestAccountAbstraction(t *testing.T) { + app := setupApp(t) + ak := app.AccountsKeeper + ctx := sdk.NewContext(app.CommitMultiStore(), false, app.Logger()) + + _, aaAddr, err := ak.Init(ctx, "aa_minimal", accCreator, &rotationv1.MsgInit{ + PubKeyBytes: privKey.PubKey().Bytes(), + }) + require.NoError(t, err) + + _, aaFullAddr, err := ak.Init(ctx, "aa_full", accCreator, &rotationv1.MsgInit{ + PubKeyBytes: privKey.PubKey().Bytes(), + }) + require.NoError(t, err) + + aaAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(aaAddr) + require.NoError(t, err) + + aaFullAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(aaFullAddr) + require.NoError(t, err) + + // let's give aa some coins. + require.NoError(t, testutil.FundAccount(ctx, app.BankKeeper, aaAddr, sdk.NewCoins(sdk.NewInt64Coin("stake", 100000000000)))) + require.NoError(t, testutil.FundAccount(ctx, app.BankKeeper, aaFullAddr, sdk.NewCoins(sdk.NewInt64Coin("stake", 100000000000)))) + + bundlerAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(bundlerAddr) + require.NoError(t, err) + + aliceAddrStr, err := app.AuthKeeper.AddressCodec().BytesToString(aliceAddr) + require.NoError(t, err) + + t.Run("ok - pay bundler and exec not implemented", func(t *testing.T) { + // we simulate executing an user operation in an abstracted account + // which only implements the authentication. + resp := ak.ExecuteUserOperation(ctx, bundlerAddrStr, &accountsv1.UserOperation{ + Sender: aaAddrStr, + AuthenticationMethod: "secp256k1", + AuthenticationData: []byte("signature"), + AuthenticationGasLimit: 10000, + BundlerPaymentMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaAddrStr, + ToAddress: bundlerAddrStr, + Amount: coins(t, "1stake"), // the sender is the AA, so it has the coins and wants to pay the bundler for the gas + }), + BundlerPaymentGasLimit: 50000, + ExecutionMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaAddrStr, + ToAddress: aliceAddrStr, + Amount: coins(t, "2000stake"), // as the real action the sender wants to send coins to alice + }), + ExecutionGasLimit: 36000, + }) + require.Empty(t, resp.Error) // no error + require.Len(t, resp.BundlerPaymentResponses, 1) + require.Len(t, resp.ExecutionResponses, 1) + require.NotZero(t, resp.ExecutionGasUsed) + require.NotZero(t, resp.BundlerPaymentGasUsed) + require.NotZero(t, resp.AuthenticationGasUsed) + // assert there were state changes + balanceIs(t, ctx, app, bundlerAddr.Bytes(), "1stake") // pay bundler state change + balanceIs(t, ctx, app, aliceAddr.Bytes(), "2000stake") // execute messages state change. + + }) + t.Run("pay bundle impersonation", func(t *testing.T) { + // we simulate the execution of an abstracted account + // which only implements authentication and tries in the pay + // bundler messages the account tries to impersonate another one. + resp := ak.ExecuteUserOperation(ctx, bundlerAddrStr, &accountsv1.UserOperation{ + Sender: aaAddrStr, + AuthenticationMethod: "secp256k1", + AuthenticationData: []byte("signature"), + AuthenticationGasLimit: 10000, + BundlerPaymentMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: bundlerAddrStr, // abstracted account tries to send money from bundler to itself. + ToAddress: aaAddrStr, + Amount: coins(t, "1stake"), + }), + BundlerPaymentGasLimit: 50000, + ExecutionMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaAddrStr, + ToAddress: aliceAddrStr, + Amount: coins(t, "2000stake"), // as the real action the sender wants to send coins to alice + }), + ExecutionGasLimit: 36000, + }) + require.Contains(t, resp.Error, accounts.ErrUnauthorized.Error()) // error is unauthorized + require.Empty(t, resp.BundlerPaymentResponses) // no bundler payment responses, since the atomic exec failed + require.Empty(t, resp.ExecutionResponses) // no execution responses, since the atomic exec failed + require.Zero(t, resp.ExecutionGasUsed) // no execution gas used, since the atomic exec failed + require.NotZero(t, resp.BundlerPaymentGasUsed) // bundler payment gas used, even if the atomic exec failed + }) + t.Run("exec message impersonation", func(t *testing.T) { + // we simulate a case in which the abstracted account tries to impersonate + // someone else in the execution of messages. + resp := ak.ExecuteUserOperation(ctx, bundlerAddrStr, &accountsv1.UserOperation{ + Sender: aaAddrStr, + AuthenticationMethod: "secp256k1", + AuthenticationData: []byte("signature"), + AuthenticationGasLimit: 10000, + BundlerPaymentMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaAddrStr, + ToAddress: bundlerAddrStr, + Amount: coins(t, "1stake"), + }), + BundlerPaymentGasLimit: 50000, + ExecutionMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aliceAddrStr, // abstracted account attempts to send money from alice to itself + ToAddress: aaAddrStr, + Amount: coins(t, "2000stake"), + }), + ExecutionGasLimit: 36000, + }) + require.Contains(t, resp.Error, accounts.ErrUnauthorized.Error()) // error is unauthorized + require.NotEmpty(t, resp.BundlerPaymentResponses) // bundler payment responses, since the bundler payment succeeded + require.Empty(t, resp.ExecutionResponses) // no execution responses, since the atomic exec failed + require.NotZero(t, resp.ExecutionGasUsed) // execution gas used, even if the atomic exec failed + require.NotZero(t, resp.BundlerPaymentGasUsed) // bundler payment gas used, even if the atomic exec failed + }) + t.Run("auth failure", func(t *testing.T) { + // if auth fails nothing more should be attempted, the authentication + // should have spent gas and the error should be returned. + // we simulate a case in which the abstracted account tries to impersonate + // someone else in the execution of messages. + resp := ak.ExecuteUserOperation(ctx, bundlerAddrStr, &accountsv1.UserOperation{ + Sender: aaAddrStr, + AuthenticationMethod: "invalid", + AuthenticationData: []byte("signature"), + AuthenticationGasLimit: 10000, + BundlerPaymentMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaAddrStr, + ToAddress: bundlerAddrStr, + Amount: coins(t, "1stake"), + }), + BundlerPaymentGasLimit: 50000, + ExecutionMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aliceAddrStr, // abstracted account attempts to send money from alice to itself + ToAddress: aaAddrStr, + Amount: coins(t, "2000stake"), + }), + ExecutionGasLimit: 36000, + }) + require.Contains(t, resp.Error, accounts.ErrAuthentication.Error()) // error is authentication + require.Empty(t, resp.BundlerPaymentResponses) // no bundler payment responses, since the atomic exec failed + require.Empty(t, resp.ExecutionResponses) // no execution responses, since the atomic exec failed + require.Zero(t, resp.ExecutionGasUsed) // no execution gas used, since the atomic exec failed + require.Zero(t, resp.BundlerPaymentGasUsed) // no bundler payment gas used, since the atomic exec failed + require.NotZero(t, resp.AuthenticationGasUsed) // authentication gas used, even if the atomic exec failed + }) + t.Run("pay bundle failure", func(t *testing.T) { + // pay bundler fails, nothing more should be attempted, the authentication + // succeeded. We expect gas used in auth and pay bundler step. + // we simulate a case in which the abstracted account tries to impersonate + // someone else in the execution of messages. + resp := ak.ExecuteUserOperation(ctx, bundlerAddrStr, &accountsv1.UserOperation{ + Sender: aaAddrStr, + AuthenticationMethod: "secp256k1", + AuthenticationData: []byte("signature"), + AuthenticationGasLimit: 10000, + BundlerPaymentMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaAddrStr, + ToAddress: bundlerAddrStr, + Amount: coins(t, "1atom"), // abstracted account does not have enough money to pay the bundler, since it does not hold atom + }), + BundlerPaymentGasLimit: 50000, + ExecutionMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aliceAddrStr, // abstracted account attempts to send money from alice to itself + ToAddress: aaAddrStr, + Amount: coins(t, "2000stake"), + }), + ExecutionGasLimit: 36000, + }) + require.Contains(t, resp.Error, accounts.ErrBundlerPayment.Error()) // error is bundler payment + require.Empty(t, resp.BundlerPaymentResponses) // no bundler payment responses, since the atomic exec failed + require.Empty(t, resp.ExecutionResponses) // no execution responses, since the atomic exec failed + require.Zero(t, resp.ExecutionGasUsed) // no execution gas used, since the atomic exec failed + require.NotZero(t, resp.BundlerPaymentGasUsed) // bundler payment gas used, even if the atomic exec failed + require.NotZero(t, resp.AuthenticationGasUsed) // authentication gas used, even if the atomic exec failed + }) + t.Run("exec message failure", func(t *testing.T) { + // execution message fails, nothing more should be attempted, the authentication + // and pay bundler succeeded. We expect gas used in auth, pay bundler and + // execution step. + resp := ak.ExecuteUserOperation(ctx, bundlerAddrStr, &accountsv1.UserOperation{ + Sender: aaAddrStr, + AuthenticationMethod: "secp256k1", + AuthenticationData: []byte("signature"), + AuthenticationGasLimit: 10000, + BundlerPaymentMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaAddrStr, + ToAddress: bundlerAddrStr, + Amount: coins(t, "1stake"), + }), + BundlerPaymentGasLimit: 50000, + ExecutionMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaAddrStr, + ToAddress: aliceAddrStr, + Amount: coins(t, "2000atom"), // abstracted account does not have enough money to pay alice, since it does not hold atom + }), + ExecutionGasLimit: 36000, + }) + require.Contains(t, resp.Error, accounts.ErrExecution.Error()) // error is execution + require.Len(t, resp.BundlerPaymentResponses, 1) // bundler payment response, since the pay bundler succeeded + require.Empty(t, resp.ExecutionResponses) // no execution responses, since the atomic exec failed + require.NotZero(t, resp.ExecutionGasUsed) // execution gas used, even if the atomic exec failed + require.NotZero(t, resp.BundlerPaymentGasUsed) // bundler payment gas used, even if the atomic exec failed + require.NotZero(t, resp.AuthenticationGasUsed) // authentication gas used, even if the atomic exec failed + }) + + t.Run("implements bundler payment - fail ", func(t *testing.T) { + // we assert that if an aa implements the bundler payment interface, then + // that is called. + resp := ak.ExecuteUserOperation(ctx, bundlerAddrStr, &accountsv1.UserOperation{ + Sender: aaFullAddrStr, + AuthenticationMethod: "secp256k1", + AuthenticationData: []byte("signature"), + AuthenticationGasLimit: 10000, + BundlerPaymentMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaFullAddrStr, + ToAddress: bundlerAddrStr, + Amount: coins(t, "1stake"), // we expect this to fail since the account is implement in such a way not to allow bank sends. + }), + BundlerPaymentGasLimit: 50000, + ExecutionMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaFullAddrStr, + ToAddress: aliceAddrStr, + Amount: coins(t, "2000stake"), + }), + ExecutionGasLimit: 36000, + }) + // in order to assert the call we expect an error to be returned. + require.Contains(t, resp.Error, accounts.ErrBundlerPayment.Error()) // error is bundler payment + require.Contains(t, resp.Error, "this account does not allow bank send messages") // error is bundler payment + }) + + t.Run("implements execution - fail", func(t *testing.T) { + resp := ak.ExecuteUserOperation(ctx, bundlerAddrStr, &accountsv1.UserOperation{ + Sender: aaFullAddrStr, + AuthenticationMethod: "secp256k1", + AuthenticationData: []byte("signature"), + AuthenticationGasLimit: 10000, + BundlerPaymentMessages: nil, + BundlerPaymentGasLimit: 50000, + ExecutionMessages: intoAny(t, &stakingv1beta1.MsgDelegate{ + DelegatorAddress: aaFullAddrStr, + ValidatorAddress: "some-validator", + Amount: coins(t, "2000stake")[0], + }), + ExecutionGasLimit: 36000, + }) + // in order to assert the call we expect an error to be returned. + require.Contains(t, resp.Error, accounts.ErrExecution.Error()) // error is in execution + require.Contains(t, resp.Error, "this account does not allow delegation messages") + }) + + t.Run("implements bundler payment and execution - success", func(t *testing.T) { + // we simulate the abstracted account pays the bundler using an NFT. + require.NoError(t, app.NFTKeeper.SaveClass(ctx, nft.Class{ + Id: "omega-rare", + })) + require.NoError(t, app.NFTKeeper.Mint(ctx, nft.NFT{ + ClassId: "omega-rare", + Id: "the-most-rare", + }, aaFullAddr)) + + resp := ak.ExecuteUserOperation(ctx, bundlerAddrStr, &accountsv1.UserOperation{ + Sender: aaFullAddrStr, + AuthenticationMethod: "secp256k1", + AuthenticationData: []byte("signature"), + AuthenticationGasLimit: 10000, + BundlerPaymentMessages: intoAny(t, &nftv1beta1.MsgSend{ + ClassId: "omega-rare", + Id: "the-most-rare", + Sender: aaFullAddrStr, + Receiver: bundlerAddrStr, + }), + BundlerPaymentGasLimit: 50000, + ExecutionMessages: intoAny(t, &bankv1beta1.MsgSend{ + FromAddress: aaFullAddrStr, + ToAddress: aliceAddrStr, + Amount: coins(t, "2000stake"), + }), + ExecutionGasLimit: 36000, + }) + require.Empty(t, resp.Error) // no error + }) +} + +func intoAny(t *testing.T, msgs ...proto.Message) (anys []*anypb.Any) { + t.Helper() + for _, msg := range msgs { + any, err := anyutil.New(msg) + require.NoError(t, err) + anys = append(anys, any) + } + return +} + +func coins(t *testing.T, s string) []*v1beta1.Coin { + t.Helper() + coins, err := sdk.ParseCoinsNormalized(s) + require.NoError(t, err) + coinsv2 := make([]*v1beta1.Coin, len(coins)) + for i, coin := range coins { + coinsv2[i] = &v1beta1.Coin{ + Denom: coin.Denom, + Amount: coin.Amount.String(), + } + } + return coinsv2 +} + +func balanceIs(t *testing.T, ctx context.Context, app *simapp.SimApp, addr sdk.AccAddress, s string) { + t.Helper() + balance := app.BankKeeper.GetAllBalances(ctx, addr) + require.Equal(t, s, balance.String()) +} diff --git a/tests/e2e/accounts/setup_test.go b/tests/e2e/accounts/setup_test.go new file mode 100644 index 000000000000..d0588f6825b1 --- /dev/null +++ b/tests/e2e/accounts/setup_test.go @@ -0,0 +1,13 @@ +package accounts + +import ( + "testing" + + "cosmossdk.io/simapp" +) + +func setupApp(t *testing.T) *simapp.SimApp { + t.Helper() + app := simapp.Setup(t, false) + return app +} diff --git a/x/accounts/accountstd/exports.go b/x/accounts/accountstd/exports.go index e2332b19ad28..f05191bf8ed5 100644 --- a/x/accounts/accountstd/exports.go +++ b/x/accounts/accountstd/exports.go @@ -2,11 +2,20 @@ package accountstd import ( + "bytes" "context" + "fmt" + + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" "cosmossdk.io/x/accounts/internal/implementation" + + "github.com/cosmos/cosmos-sdk/types/address" ) +var accountsModuleAddress = address.Module("accounts") + // Interface is the exported interface of an Account. type Interface = implementation.Account @@ -63,12 +72,55 @@ func Sender(ctx context.Context) []byte { return implementation.Sender(ctx) } +// SenderIsAccountsModule returns true if the sender of the execution request is the accounts module. +func SenderIsAccountsModule(ctx context.Context) bool { + return bytes.Equal(Sender(ctx), accountsModuleAddress) +} + // ExecModule can be used to execute a message towards a module. func ExecModule[Resp any, RespProto implementation.ProtoMsg[Resp], Req any, ReqProto implementation.ProtoMsg[Req]](ctx context.Context, msg ReqProto) (RespProto, error) { return implementation.ExecModule[Resp, RespProto, Req, ReqProto](ctx, msg) } +func ExecModuleUntyped(ctx context.Context, msg proto.Message) (proto.Message, error) { + return implementation.ExecModuleUntyped(ctx, msg) +} + // QueryModule can be used by an account to execute a module query. func QueryModule[Resp any, RespProto implementation.ProtoMsg[Resp], Req any, ReqProto implementation.ProtoMsg[Req]](ctx context.Context, req ReqProto) (RespProto, error) { return implementation.QueryModule[Resp, RespProto, Req, ReqProto](ctx, req) } + +// UnpackAny unpacks a protobuf Any message generically. +func UnpackAny[Msg any, ProtoMsg implementation.ProtoMsg[Msg]](any *anypb.Any) (*Msg, error) { + return implementation.UnpackAny[Msg, ProtoMsg](any) +} + +// PackAny packs a protobuf Any message generically. +func PackAny(msg proto.Message) (*anypb.Any, error) { + return implementation.PackAny(msg) +} + +// ExecModuleAnys can be used to execute a list of messages towards a module +// when those messages are packed in Any messages. The function returns a list +// of responses packed in Any messages. +func ExecModuleAnys(ctx context.Context, msgs []*anypb.Any) ([]*anypb.Any, error) { + responses := make([]*anypb.Any, len(msgs)) + for i, msg := range msgs { + concreteMessage, err := implementation.UnpackAnyRaw(msg) + if err != nil { + return nil, fmt.Errorf("error unpacking message %d: %w", i, err) + } + resp, err := ExecModuleUntyped(ctx, concreteMessage) + if err != nil { + return nil, fmt.Errorf("error executing message %d: %w", i, err) + } + // pack again + respAnyPB, err := implementation.PackAny(resp) + if err != nil { + return nil, fmt.Errorf("error packing response %d: %w", i, err) + } + responses[i] = respAnyPB + } + return responses, nil +} diff --git a/x/accounts/genesis_test.go b/x/accounts/genesis_test.go index 7e9d0aac46ce..1edafbf5a833 100644 --- a/x/accounts/genesis_test.go +++ b/x/accounts/genesis_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/stretchr/testify/require" - "google.golang.org/protobuf/runtime/protoiface" + "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/wrapperspb" @@ -15,10 +15,7 @@ import ( func TestGenesis(t *testing.T) { k, ctx := newKeeper(t, implementation.AddAccount("test", NewTestAccount)) - k.queryModuleFunc = func(ctx context.Context, req, resp protoiface.MessageV1) error { - return nil - } - + k.queryRouter = mockQuery(func(ctx context.Context, req, resp proto.Message) error { return nil }) // we init two accounts of the same type // we set counter to 10 diff --git a/x/accounts/internal/implementation/api_builder.go b/x/accounts/internal/implementation/api_builder.go index 10fb653bb395..ee8344b86c1a 100644 --- a/x/accounts/internal/implementation/api_builder.go +++ b/x/accounts/internal/implementation/api_builder.go @@ -152,3 +152,12 @@ type QueryBuilder struct { func (r *QueryBuilder) makeHandler() (func(ctx context.Context, queryRequest any) (queryResponse any, err error), error) { return r.er.makeHandler() } + +// IsRoutingError returns true if the error is a routing error, +// which typically occurs when a message cannot be matched to a handler. +func IsRoutingError(err error) bool { + if err == nil { + return false + } + return errors.Is(err, errInvalidMessage) +} diff --git a/x/accounts/internal/implementation/context.go b/x/accounts/internal/implementation/context.go index 5054f210691e..7f14a73d04ce 100644 --- a/x/accounts/internal/implementation/context.go +++ b/x/accounts/internal/implementation/context.go @@ -1,38 +1,33 @@ package implementation import ( - "bytes" "context" - "errors" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/runtime/protoiface" "cosmossdk.io/collections" "cosmossdk.io/core/store" "cosmossdk.io/x/accounts/internal/prefixstore" ) -var ( - errUnauthorized = errors.New("unauthorized") - AccountStatePrefix = collections.NewPrefix(255) -) +var AccountStatePrefix = collections.NewPrefix(255) type ( - ModuleExecFunc = func(ctx context.Context, msg, msgResp protoiface.MessageV1) error - ModuleQueryFunc = ModuleExecFunc + ModuleExecUntypedFunc = func(ctx context.Context, sender []byte, msg proto.Message) (proto.Message, error) + ModuleExecFunc = func(ctx context.Context, sender []byte, msg, msgResp proto.Message) error + ModuleQueryFunc = func(ctx context.Context, queryReq, queryResp proto.Message) error ) type contextKey struct{} type contextValue struct { - store store.KVStore // store is the prefixed store for the account. - sender []byte // sender is the address of the entity invoking the account action. - whoami []byte // whoami is the address of the account being invoked. - originalContext context.Context // originalContext that was used to build the account context. - getExpectedSender func(msg proto.Message) ([]byte, error) // getExpectedSender is a function that returns the expected sender for a given message. - moduleExec ModuleExecFunc // moduleExec is a function that executes a module message. - moduleQuery ModuleQueryFunc // moduleQuery is a function that queries a module. + store store.KVStore // store is the prefixed store for the account. + sender []byte // sender is the address of the entity invoking the account action. + whoami []byte // whoami is the address of the account being invoked. + originalContext context.Context // originalContext that was used to build the account context. + moduleExec ModuleExecFunc // moduleExec is a function that executes a module message, when the resp type is known. + moduleExecUntyped ModuleExecUntypedFunc // moduleExecUntyped is a function that executes a module message, when the resp type is unknown. + moduleQuery ModuleQueryFunc // moduleQuery is a function that queries a module. } // MakeAccountContext creates a new account execution context given: @@ -47,8 +42,8 @@ func MakeAccountContext( storeSvc store.KVStoreService, accountAddr, sender []byte, - getSenderFunc func(msg proto.Message) ([]byte, error), moduleExec ModuleExecFunc, + moduleExecUntyped ModuleExecUntypedFunc, moduleQuery ModuleQueryFunc, ) context.Context { return context.WithValue(ctx, contextKey{}, contextValue{ @@ -56,28 +51,33 @@ func MakeAccountContext( sender: sender, whoami: accountAddr, originalContext: ctx, - getExpectedSender: getSenderFunc, + moduleExecUntyped: moduleExecUntyped, moduleExec: moduleExec, moduleQuery: moduleQuery, }) } -// ExecModule can be used to execute a message towards a module. -func ExecModule[Resp any, RespProto ProtoMsg[Resp], Req any, ReqProto ProtoMsg[Req]](ctx context.Context, msg ReqProto) (RespProto, error) { +// ExecModuleUntyped can be used to execute a message towards a module, when the response type is unknown. +func ExecModuleUntyped(ctx context.Context, msg proto.Message) (proto.Message, error) { // get sender v := ctx.Value(contextKey{}).(contextValue) - // check sender - expectedSender, err := v.getExpectedSender(msg) + + resp, err := v.moduleExecUntyped(v.originalContext, v.whoami, msg) if err != nil { return nil, err } - if !bytes.Equal(expectedSender, v.whoami) { - return nil, errUnauthorized - } + + return resp, nil +} + +// ExecModule can be used to execute a message towards a module. +func ExecModule[Resp any, RespProto ProtoMsg[Resp], Req any, ReqProto ProtoMsg[Req]](ctx context.Context, msg ReqProto) (RespProto, error) { + // get sender + v := ctx.Value(contextKey{}).(contextValue) // execute module, unwrapping the original context. resp := RespProto(new(Resp)) - err = v.moduleExec(v.originalContext, msg, resp) + err := v.moduleExec(v.originalContext, v.whoami, msg, resp) if err != nil { return nil, err } diff --git a/x/accounts/internal/implementation/context_test.go b/x/accounts/internal/implementation/context_test.go index 563b1f3cf4f2..327445fb7623 100644 --- a/x/accounts/internal/implementation/context_test.go +++ b/x/accounts/internal/implementation/context_test.go @@ -6,7 +6,6 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/runtime/protoiface" "google.golang.org/protobuf/types/known/wrapperspb" "cosmossdk.io/collections" @@ -44,33 +43,33 @@ func TestMakeAccountContext(t *testing.T) { require.NoError(t, err) require.Equal(t, []byte{0, 0, 0, 0, 0, 0, 3, 232}, value) - // ensure getSenderAccount blocks impersonation - accountCtx = MakeAccountContext(originalContext, storeService, []byte("impersonator"), []byte("account-invoker"), func(_ proto.Message) ([]byte, error) { - return []byte("legit-exec-module"), nil - }, nil, nil) - - _, err = ExecModule[wrapperspb.StringValue](accountCtx, &wrapperspb.UInt64Value{Value: 1000}) - require.ErrorIs(t, err, errUnauthorized) - // ensure calling ExecModule works - accountCtx = MakeAccountContext(originalContext, storeService, []byte("legit-exec-module"), []byte("invoker"), func(_ proto.Message) ([]byte, error) { - return []byte("legit-exec-module"), nil - }, func(ctx context.Context, msg, msgResp protoiface.MessageV1) error { + accountCtx = MakeAccountContext(originalContext, storeService, []byte("legit-exec-module"), []byte("invoker"), func(ctx context.Context, sender []byte, msg, msgResp proto.Message) error { // ensure we unwrapped the context when invoking a module call require.Equal(t, originalContext, ctx) - proto.Merge(msgResp.(proto.Message), &wrapperspb.StringValue{Value: "module exec was called"}) + proto.Merge(msgResp, &wrapperspb.StringValue{Value: "module exec was called"}) return nil - }, nil) + }, nil, nil) resp, err := ExecModule[wrapperspb.StringValue](accountCtx, &wrapperspb.UInt64Value{Value: 1000}) require.NoError(t, err) require.True(t, proto.Equal(wrapperspb.String("module exec was called"), resp)) + // ensure calling ExecModuleUntyped works + accountCtx = MakeAccountContext(originalContext, storeService, []byte("legit-exec-module-untyped"), []byte("invoker"), nil, func(ctx context.Context, sender []byte, msg proto.Message) (proto.Message, error) { + require.Equal(t, originalContext, ctx) + return &wrapperspb.StringValue{Value: "module exec untyped was called"}, nil + }, nil) + + respUntyped, err := ExecModuleUntyped(accountCtx, &wrapperspb.UInt64Value{Value: 1000}) + require.NoError(t, err) + require.True(t, proto.Equal(wrapperspb.String("module exec untyped was called"), respUntyped)) + // ensure calling QueryModule works, also by setting everything else communication related to nil // we can guarantee that exec paths do not impact query paths. - accountCtx = MakeAccountContext(originalContext, storeService, nil, nil, nil, nil, func(ctx context.Context, req, resp protoiface.MessageV1) error { + accountCtx = MakeAccountContext(originalContext, storeService, nil, nil, nil, nil, func(ctx context.Context, req, resp proto.Message) error { require.Equal(t, originalContext, ctx) - proto.Merge(resp.(proto.Message), wrapperspb.String("module query was called")) + proto.Merge(resp, wrapperspb.String("module query was called")) return nil }) diff --git a/x/accounts/internal/implementation/proto_util.go b/x/accounts/internal/implementation/proto_util.go new file mode 100644 index 000000000000..caf89a4af2dc --- /dev/null +++ b/x/accounts/internal/implementation/proto_util.go @@ -0,0 +1,31 @@ +package implementation + +import ( + "github.com/cosmos/cosmos-proto/anyutil" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" +) + +// PackAny packs a proto message into an anypb.Any. +func PackAny(msg proto.Message) (*anypb.Any, error) { + anyPB := new(anypb.Any) + return anyPB, anyutil.MarshalFrom(anyPB, msg, proto.MarshalOptions{Deterministic: true}) +} + +// UnpackAny unpacks an anypb.Any into a proto message. +func UnpackAny[T any, PT ProtoMsg[T]](anyPB *anypb.Any) (PT, error) { + to := new(T) + return to, UnpackAnyTo(anyPB, PT(to)) +} + +func UnpackAnyTo(anyPB *anypb.Any, to proto.Message) error { + return anypb.UnmarshalTo(anyPB, to, proto.UnmarshalOptions{ + DiscardUnknown: true, + }) +} + +func UnpackAnyRaw(anyPB *anypb.Any) (proto.Message, error) { + return anypb.UnmarshalNew(anyPB, proto.UnmarshalOptions{ + DiscardUnknown: true, + }) +} diff --git a/x/accounts/keeper.go b/x/accounts/keeper.go index 0b4c61d8f1e6..913f4d5fd549 100644 --- a/x/accounts/keeper.go +++ b/x/accounts/keeper.go @@ -1,6 +1,7 @@ package accounts import ( + "bytes" "context" "crypto/sha256" "encoding/binary" @@ -8,10 +9,14 @@ import ( "fmt" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" "google.golang.org/protobuf/runtime/protoiface" + "google.golang.org/protobuf/types/known/anypb" "cosmossdk.io/collections" "cosmossdk.io/core/address" + "cosmossdk.io/core/branch" "cosmossdk.io/core/event" "cosmossdk.io/core/store" "cosmossdk.io/x/accounts/accountstd" @@ -20,13 +25,19 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" ) -var errAccountTypeNotFound = errors.New("account type not found") +var ( + errAccountTypeNotFound = errors.New("account type not found") + // ErrUnauthorized is returned when a message sender is not allowed to perform the operation. + ErrUnauthorized = errors.New("unauthorized") +) var ( // AccountTypeKeyPrefix is the prefix for the account type key. AccountTypeKeyPrefix = collections.NewPrefix(0) // AccountNumberKey is the key for the account number. AccountNumberKey = collections.NewPrefix(1) + // AccountByNumber is the key for the accounts by number. + AccountByNumber = collections.NewPrefix(2) ) // QueryRouter represents a router which can be used to route queries to the correct module. @@ -39,6 +50,7 @@ type QueryRouter interface { // MsgRouter represents a router which can be used to route messages to the correct module. type MsgRouter interface { HybridHandlerByMsgName(msgName string) func(ctx context.Context, req, resp protoiface.MessageV1) error + ResponseNameByRequestName(name string) string } // SignerProvider defines an interface used to get the expected sender from a message. @@ -47,9 +59,13 @@ type SignerProvider interface { GetSigners(msg proto.Message) ([][]byte, error) } +// BranchExecutor defines an interface used to execute ops in a branch. +type BranchExecutor = branch.Service + func NewKeeper( ss store.KVStoreService, es event.Service, + bs BranchExecutor, addressCodec address.Codec, signerProvider SignerProvider, execRouter MsgRouter, @@ -58,41 +74,18 @@ func NewKeeper( ) (Keeper, error) { sb := collections.NewSchemaBuilder(ss) keeper := Keeper{ - storeService: ss, - eventService: es, - addressCodec: addressCodec, - getSenderFunc: func(msg proto.Message) ([]byte, error) { - signers, err := signerProvider.GetSigners(msg) - if err != nil { - return nil, err - } - if len(signers) != 1 { - return nil, fmt.Errorf("expected 1 signer, got %d", len(signers)) - } - return signers[0], nil - }, - execModuleFunc: func(ctx context.Context, msg, msgResp protoiface.MessageV1) error { - name := getMessageName(msg) - handler := execRouter.HybridHandlerByMsgName(name) - if handler == nil { - return fmt.Errorf("no handler found for message %s", name) - } - return handler(ctx, msg, msgResp) - }, - queryModuleFunc: func(ctx context.Context, req, resp protoiface.MessageV1) error { - name := getMessageName(req) - handlers := queryRouter.HybridHandlerByRequestName(name) - if len(handlers) == 0 { - return fmt.Errorf("no handler found for query request %s", name) - } - if len(handlers) > 1 { - return fmt.Errorf("multiple handlers found for query request %s", name) - } - return handlers[0](ctx, req, resp) - }, - AccountNumber: collections.NewSequence(sb, AccountNumberKey, "account_number"), - AccountsByType: collections.NewMap(sb, AccountTypeKeyPrefix, "accounts_by_type", collections.BytesKey, collections.StringValue), - AccountsState: collections.NewMap(sb, implementation.AccountStatePrefix, "accounts_state", collections.BytesKey, collections.BytesValue), + storeService: ss, + eventService: es, + branchExecutor: bs, + addressCodec: addressCodec, + signerProvider: signerProvider, + msgRouter: execRouter, + queryRouter: queryRouter, + Schema: collections.Schema{}, + AccountNumber: collections.NewSequence(sb, AccountNumberKey, "account_number"), + AccountsByType: collections.NewMap(sb, AccountTypeKeyPrefix, "accounts_by_type", collections.BytesKey, collections.StringValue), + AccountByNumber: collections.NewMap(sb, AccountByNumber, "account_by_number", collections.BytesKey, collections.Uint64Value), + AccountsState: collections.NewMap(sb, implementation.AccountStatePrefix, "accounts_state", collections.BytesKey, collections.BytesValue), } schema, err := sb.Build() @@ -109,12 +102,13 @@ func NewKeeper( type Keeper struct { // deps coming from the runtime - storeService store.KVStoreService - eventService event.Service - addressCodec address.Codec - getSenderFunc func(msg proto.Message) ([]byte, error) - execModuleFunc implementation.ModuleExecFunc - queryModuleFunc implementation.ModuleQueryFunc + storeService store.KVStoreService + eventService event.Service + addressCodec address.Codec + branchExecutor BranchExecutor + msgRouter MsgRouter + signerProvider SignerProvider + queryRouter QueryRouter accounts map[string]implementation.Implementation @@ -124,6 +118,8 @@ type Keeper struct { AccountNumber collections.Sequence // AccountsByType maps account address to their implementation. AccountsByType collections.Map[[]byte, string] + // AccountByNumber maps account number to their address. + AccountByNumber collections.Map[[]byte, uint64] // AccountsState keeps track of the state of each account. // NOTE: this is only used for genesis import and export. @@ -144,8 +140,14 @@ func (k Keeper) Init( return nil, nil, err } + // get the next account number + num, err := k.AccountNumber.Next(ctx) + if err != nil { + return nil, nil, err + } + // make a new account address - accountAddr, err := k.makeAddress(ctx) + accountAddr, err := k.makeAddress(num) if err != nil { return nil, nil, err } @@ -161,6 +163,10 @@ func (k Keeper) Init( if err := k.AccountsByType.Set(ctx, accountAddr, accountType); err != nil { return nil, nil, err } + // map account number to account address + if err := k.AccountByNumber.Set(ctx, accountAddr, num); err != nil { + return nil, nil, err + } return resp, accountAddr, nil } @@ -225,14 +231,9 @@ func (k Keeper) getImplementation(accountType string) (implementation.Implementa return impl, nil } -func (k Keeper) makeAddress(ctx context.Context) ([]byte, error) { - num, err := k.AccountNumber.Next(ctx) - if err != nil { - return nil, err - } - +func (k Keeper) makeAddress(accNum uint64) ([]byte, error) { // TODO: better address scheme, ref: https://github.com/cosmos/cosmos-sdk/issues/17516 - addr := sha256.Sum256(append([]byte("x/accounts"), binary.BigEndian.AppendUint64(nil, num)...)) + addr := sha256.Sum256(append([]byte("x/accounts"), binary.BigEndian.AppendUint64(nil, accNum)...)) return addr[:], nil } @@ -245,9 +246,9 @@ func (k Keeper) makeAccountContext(ctx context.Context, accountAddr, sender []by k.storeService, accountAddr, sender, - k.getSenderFunc, - k.execModuleFunc, - k.queryModuleFunc, + k.sendModuleMessage, + k.sendModuleMessageUntyped, + k.queryModule, ) } @@ -258,16 +259,97 @@ func (k Keeper) makeAccountContext(ctx context.Context, accountAddr, sender []by k.storeService, accountAddr, nil, - func(_ proto.Message) ([]byte, error) { - return nil, fmt.Errorf("cannot get sender from query") + func(ctx context.Context, sender []byte, msg, msgResp proto.Message) error { + return fmt.Errorf("cannot execute in query context") }, - func(ctx context.Context, msg, msgResp protoiface.MessageV1) error { - return fmt.Errorf("cannot execute module from a query execution context") + func(ctx context.Context, sender []byte, msg proto.Message) (proto.Message, error) { + return nil, fmt.Errorf("cannot execute in query context") }, - k.queryModuleFunc, + k.queryModule, ) } +// sendAnyMessages it a helper function that executes untyped anypb.Any messages +// The messages must all belong to a module. +func (k Keeper) sendAnyMessages(ctx context.Context, sender []byte, anyMessages []*anypb.Any) ([]*anypb.Any, error) { + anyResponses := make([]*anypb.Any, len(anyMessages)) + for i := range anyMessages { + msg, err := anyMessages[i].UnmarshalNew() + if err != nil { + return nil, err + } + resp, err := k.sendModuleMessageUntyped(ctx, sender, msg) + if err != nil { + return nil, fmt.Errorf("failed to execute message %d: %s", i, err.Error()) + } + anyResp, err := implementation.PackAny(resp) + if err != nil { + return nil, err + } + anyResponses[i] = anyResp + } + return anyResponses, nil +} + +// sendModuleMessageUntyped can be used to send a message towards a module. +// It should be used when the response type is not known by the caller. +func (k Keeper) sendModuleMessageUntyped(ctx context.Context, sender []byte, msg proto.Message) (proto.Message, error) { + // we need to fetch the response type from the request message type. + // this is because the response type is not known. + respName := k.msgRouter.ResponseNameByRequestName(string(msg.ProtoReflect().Descriptor().FullName())) + if respName == "" { + return nil, fmt.Errorf("could not find response type for message %T", msg) + } + // get response type + respType, err := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(respName)) + if err != nil { + return nil, err + } + resp := respType.New().Interface() + // send the message + return resp, k.sendModuleMessage(ctx, sender, msg, resp) +} + +// sendModuleMessage can be used to send a message towards a module. It expects the +// response type to be known by the caller. It will also assert the sender has the right +// is not trying to impersonate another account. +func (k Keeper) sendModuleMessage(ctx context.Context, sender []byte, msg, msgResp proto.Message) error { + // do sender assertions. + wantSenders, err := k.signerProvider.GetSigners(msg) + if err != nil { + return fmt.Errorf("cannot get signers: %w", err) + } + if len(wantSenders) != 1 { + return fmt.Errorf("expected only one signer, got %d", len(wantSenders)) + } + if !bytes.Equal(sender, wantSenders[0]) { + return fmt.Errorf("%w: sender does not match expected sender", ErrUnauthorized) + } + msgV1, msgRespV1 := msg.(protoiface.MessageV1), msgResp.(protoiface.MessageV1) + messageName := getMessageName(msgV1) + handler := k.msgRouter.HybridHandlerByMsgName(messageName) + if handler == nil { + return fmt.Errorf("unknown message: %s", messageName) + } + return handler(ctx, msgV1, msgRespV1) +} + +// queryModule is the entrypoint for an account to query a module. +// It will try to find the query handler for the given query and execute it. +// If multiple query handlers are found, it will return an error. +func (k Keeper) queryModule(ctx context.Context, queryReq, queryResp proto.Message) error { + queryReqV1, queryRespV1 := queryReq.(protoiface.MessageV1), queryResp.(protoiface.MessageV1) + queryName := getMessageName(queryReqV1) + handlers := k.queryRouter.HybridHandlerByRequestName(queryName) + if len(handlers) == 0 { + return fmt.Errorf("unknown query: %s", queryName) + } + if len(handlers) > 1 { + return fmt.Errorf("multiple handlers for query: %s", queryName) + } + return handlers[0](ctx, queryReqV1, queryRespV1) +} + func getMessageName(msg protoiface.MessageV1) string { return codectypes.MsgTypeURL(msg)[1:] } diff --git a/x/accounts/keeper_account_abstraction.go b/x/accounts/keeper_account_abstraction.go new file mode 100644 index 000000000000..5971a24fc5a2 --- /dev/null +++ b/x/accounts/keeper_account_abstraction.go @@ -0,0 +1,236 @@ +package accounts + +import ( + "context" + "errors" + "fmt" + + "google.golang.org/protobuf/types/known/anypb" + + account_abstractionv1 "cosmossdk.io/api/cosmos/accounts/interfaces/account_abstraction/v1" + accountsv1 "cosmossdk.io/api/cosmos/accounts/v1" + "cosmossdk.io/x/accounts/internal/implementation" +) + +var ( + // ErrAuthentication is returned when the authentication fails. + ErrAuthentication = errors.New("authentication failed") + // ErrBundlerPayment is returned when the bundler payment fails. + ErrBundlerPayment = errors.New("bundler payment failed") + // ErrExecution is returned when the execution fails. + ErrExecution = errors.New("execution failed") +) + +// ExecuteUserOperation handles the execution of an abstracted account UserOperation. +func (k Keeper) ExecuteUserOperation( + ctx context.Context, + bundler string, + op *accountsv1.UserOperation, +) *accountsv1.UserOperationResponse { + resp := &accountsv1.UserOperationResponse{} + + // authenticate + authGas, err := k.Authenticate(ctx, bundler, op) + resp.AuthenticationGasUsed = authGas + if err != nil { + resp.Error = err.Error() + return resp + } + resp.AuthenticationGasUsed = authGas + + // pay bundler + bundlerPayGas, bundlerPayResp, err := k.PayBundler(ctx, bundler, op) + resp.BundlerPaymentGasUsed = bundlerPayGas + if err != nil { + resp.Error = err.Error() + return resp + } + resp.BundlerPaymentResponses = bundlerPayResp + + // execute messages, the real operation intent + executeGas, executeResp, err := k.OpExecuteMessages(ctx, bundler, op) + resp.ExecutionGasUsed = executeGas + if err != nil { + resp.Error = err.Error() + return resp + } + resp.ExecutionResponses = executeResp + + // done! + return resp +} + +// Authenticate handles the authentication flow of an abstracted account. +// Authentication happens in an isolated context with the authentication gas limit. +// If the authentication is successful, then the state is committed. +func (k Keeper) Authenticate( + ctx context.Context, + bundler string, + op *accountsv1.UserOperation, +) (gasUsed uint64, err error) { + // authenticate + gasUsed, err = k.branchExecutor.ExecuteWithGasLimit(ctx, op.AuthenticationGasLimit, func(ctx context.Context) error { + return k.authenticate(ctx, bundler, op) + }) + if err != nil { + return gasUsed, fmt.Errorf("%v: %w", ErrAuthentication, err) + } + return gasUsed, nil +} + +// authenticate handles the authentication flow of an abstracted account. +func (k Keeper) authenticate( + ctx context.Context, + bundler string, + op *accountsv1.UserOperation, +) error { + senderAddr, err := k.addressCodec.StringToBytes(op.Sender) + if err != nil { + return err + } + // create an isolated context in which we execute authentication + // without affecting the parent context and with the authentication gas limit. + _, err = k.Execute(ctx, senderAddr, ModuleAccountAddress, &account_abstractionv1.MsgAuthenticate{ + Bundler: bundler, + UserOperation: op, + }) + return err +} + +// OpExecuteMessages handles the execution of the messages in a given v1.UserOperation. +// It executes in an isolated branch, in an atomic way, if all the messages pass then +// the execution is deemed successful and the state is committed. +// An account abstraction implementer can choose to handle execution messages or not, +// if it does not expose the execution messages method, then this method will simply +// execute the provided messages on behalf of the sender and return. +func (k Keeper) OpExecuteMessages( + ctx context.Context, + bundler string, + op *accountsv1.UserOperation, +) (gasUsed uint64, responses []*anypb.Any, err error) { + // execute messages, the real operation intent + gasUsed, err = k.branchExecutor.ExecuteWithGasLimit(ctx, op.ExecutionGasLimit, func(ctx context.Context) error { + responses, err = k.opExecuteMessages(ctx, bundler, op) + return err + }) + if err != nil { + return gasUsed, nil, fmt.Errorf("%v: %w", ErrExecution, err) + } + return gasUsed, responses, nil +} + +func (k Keeper) opExecuteMessages( + ctx context.Context, + bundler string, + op *accountsv1.UserOperation, +) (messagesResponse []*anypb.Any, err error) { + senderAddr, err := k.addressCodec.StringToBytes(op.Sender) + if err != nil { + return nil, err + } + resp, err := k.Execute(ctx, senderAddr, ModuleAccountAddress, &account_abstractionv1.MsgExecute{ + Bundler: bundler, + ExecutionMessages: op.ExecutionMessages, + }) + // here is where we check if the account handles execution messages + // if it does not, then we simply execute the provided messages on behalf of the sender + switch { + case err == nil: + // all is ok, so parse responses. + executeResp, err := parseExecuteResponse(resp) + return executeResp, err + case implementation.IsRoutingError(err): + // if it is a routing error, it means the account does not handle execution messages, + // in this case we attempt to execute the provided messages on behalf of the op sender. + return k.sendAnyMessages(ctx, senderAddr, op.ExecutionMessages) + default: + // some other error + return nil, err + } +} + +// PayBundler handles the payment of the bundler in a given v1.UserOperation. +// Must be called after Authenticate. +// It gets executed in an isolated context with the bundler payment gas limit. +// If the payment is successful, then the state is committed. +// Since for an abstracted account the bundler payment method is optional, +// if the account does not handle bundler payment messages, then this method +// will simply execute the provided messages on behalf of the sender and return. +func (k Keeper) PayBundler( + ctx context.Context, + bundler string, + op *accountsv1.UserOperation, +) (gasUsed uint64, responses []*anypb.Any, err error) { + // pay bundler + gasUsed, err = k.branchExecutor.ExecuteWithGasLimit(ctx, op.BundlerPaymentGasLimit, func(ctx context.Context) error { + responses, err = k.payBundler(ctx, bundler, op) + return err + }) + if err != nil { + return gasUsed, nil, fmt.Errorf("%v: %w", ErrBundlerPayment, err) + } + return gasUsed, responses, nil +} + +func (k Keeper) payBundler( + ctx context.Context, + bundler string, + op *accountsv1.UserOperation, +) (paymentResponses []*anypb.Any, err error) { + // if messages are empty, then there is nothing to do + if len(op.BundlerPaymentMessages) == 0 { + return nil, nil + } + // pay bundler + senderAddr, err := k.addressCodec.StringToBytes(op.Sender) + if err != nil { + return nil, err + } + resp, err := k.Execute(ctx, senderAddr, ModuleAccountAddress, &account_abstractionv1.MsgPayBundler{ + Bundler: bundler, + BundlerPaymentMessages: op.BundlerPaymentMessages, + }) + // here is where we check if the account handles bundler payment messages + // if it does not, then we simply execute the provided messages on behalf of the sender + switch { + case err == nil: + // if no error, execution went fine, so parse responses. + payBundlerResp, err := parsePayBundlerResponse(resp) + return payBundlerResp, err + case implementation.IsRoutingError(err): + // if we get a routing message error it means the account does not handle bundler payment messages, + // in this case we attempt to execute the provided messages on behalf of the op sender. + return k.sendAnyMessages(ctx, senderAddr, op.BundlerPaymentMessages) + default: + // some other execution error. + return nil, err + } +} + +// parsePayBundlerResponse parses the bundler response as any into a slice of +// responses on payment messages. +func parsePayBundlerResponse(resp any) ([]*anypb.Any, error) { + payBundlerResp, ok := resp.(*account_abstractionv1.MsgPayBundlerResponse) + // this means the account does not properly implement account abstraction. + if payBundlerResp == nil { + return nil, fmt.Errorf("account does not implement account abstraction correctly: wanted %T, got nil", &account_abstractionv1.MsgPayBundlerResponse{}) + } + if !ok { + return nil, fmt.Errorf("account does not implement account abstraction correctly: wanted %T, got %T", &account_abstractionv1.MsgPayBundlerResponse{}, resp) + } + return payBundlerResp.BundlerPaymentMessagesResponse, nil +} + +// parseExecuteResponse parses the execute response as any into a slice of +// responses on execution messages. +func parseExecuteResponse(resp any) ([]*anypb.Any, error) { + executeResp, ok := resp.(*account_abstractionv1.MsgExecuteResponse) + // this means the account does not properly implement account abstraction. + if executeResp == nil { + return nil, fmt.Errorf("account does not implement account abstraction correctly: wanted %T, got nil", &account_abstractionv1.MsgExecuteResponse{}) + } + if !ok { + return nil, fmt.Errorf("account does not implement account abstraction correctly: wanted %T, got %T", &account_abstractionv1.MsgExecuteResponse{}, resp) + } + return executeResp.ExecutionMessagesResponse, nil +} diff --git a/x/accounts/keeper_test.go b/x/accounts/keeper_test.go index 11530a4c72b5..6535d99a9783 100644 --- a/x/accounts/keeper_test.go +++ b/x/accounts/keeper_test.go @@ -6,58 +6,24 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/runtime/protoiface" "google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/wrapperspb" bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" "cosmossdk.io/collections" - "cosmossdk.io/collections/colltest" - "cosmossdk.io/core/address" - "cosmossdk.io/core/event" "cosmossdk.io/x/accounts/accountstd" - "cosmossdk.io/x/accounts/internal/implementation" ) -var _ address.Codec = (*addressCodec)(nil) - -type addressCodec struct{} - -func (a addressCodec) StringToBytes(text string) ([]byte, error) { return []byte(text), nil } -func (a addressCodec) BytesToString(bz []byte) (string, error) { return string(bz), nil } - -type eventService struct{} - -func (e eventService) Emit(ctx context.Context, event protoiface.MessageV1) error { return nil } - -func (e eventService) EmitKV(ctx context.Context, eventType string, attrs ...event.Attribute) error { - return nil -} - -func (e eventService) EmitNonConsensus(ctx context.Context, event protoiface.MessageV1) error { - return nil -} - -func (e eventService) EventManager(ctx context.Context) event.Manager { return e } - -func newKeeper(t *testing.T, accounts ...implementation.AccountCreatorFunc) (Keeper, context.Context) { - t.Helper() - ss, ctx := colltest.MockStore() - m, err := NewKeeper(ss, eventService{}, addressCodec{}, nil, nil, nil, accounts...) - require.NoError(t, err) - return m, ctx -} - func TestKeeper_Init(t *testing.T) { m, ctx := newKeeper(t, accountstd.AddAccount("test", NewTestAccount)) - m.queryModuleFunc = func(ctx context.Context, req, resp protoiface.MessageV1) error { + m.queryRouter = mockQuery(func(ctx context.Context, req, resp proto.Message) error { _, ok := req.(*bankv1beta1.QueryBalanceRequest) require.True(t, ok) _, ok = resp.(*bankv1beta1.QueryBalanceResponse) require.True(t, ok) return nil - } + }) t.Run("ok", func(t *testing.T) { sender := []byte("sender") @@ -86,7 +52,7 @@ func TestKeeper_Init(t *testing.T) { func TestKeeper_Execute(t *testing.T) { m, ctx := newKeeper(t, accountstd.AddAccount("test", NewTestAccount)) - m.queryModuleFunc = func(ctx context.Context, req, resp protoiface.MessageV1) error { return nil } + m.queryRouter = mockQuery(func(ctx context.Context, req, resp proto.Message) error { return nil }) // create account sender := []byte("sender") @@ -105,19 +71,19 @@ func TestKeeper_Execute(t *testing.T) { }) t.Run("exec module", func(t *testing.T) { - m.execModuleFunc = func(ctx context.Context, msg, msgResp protoiface.MessageV1) error { + m.msgRouter = mockExec(func(ctx context.Context, msg, msgResp proto.Message) error { concrete, ok := msg.(*bankv1beta1.MsgSend) require.True(t, ok) require.Equal(t, concrete.ToAddress, "recipient") _, ok = msgResp.(*bankv1beta1.MsgSendResponse) require.True(t, ok) return nil - } + }) - m.getSenderFunc = func(msg proto.Message) ([]byte, error) { + m.signerProvider = mockSigner(func(msg proto.Message) ([]byte, error) { require.Equal(t, msg.(*bankv1beta1.MsgSend).FromAddress, string(accAddr)) return accAddr, nil - } + }) resp, err := m.Execute(ctx, accAddr, sender, &wrapperspb.Int64Value{Value: 1000}) require.NoError(t, err) @@ -127,9 +93,9 @@ func TestKeeper_Execute(t *testing.T) { func TestKeeper_Query(t *testing.T) { m, ctx := newKeeper(t, accountstd.AddAccount("test", NewTestAccount)) - m.queryModuleFunc = func(ctx context.Context, req, resp protoiface.MessageV1) error { + m.queryRouter = mockQuery(func(ctx context.Context, req, resp proto.Message) error { return nil - } + }) // create account sender := []byte("sender") @@ -150,7 +116,7 @@ func TestKeeper_Query(t *testing.T) { t.Run("query module", func(t *testing.T) { // we inject the module query function, which accepts only a specific type of message // we force the response - m.queryModuleFunc = func(ctx context.Context, req, resp protoiface.MessageV1) error { + m.queryRouter = mockQuery(func(ctx context.Context, req, resp proto.Message) error { concrete, ok := req.(*bankv1beta1.QueryBalanceRequest) require.True(t, ok) require.Equal(t, string(accAddr), concrete.Address) @@ -159,9 +125,9 @@ func TestKeeper_Query(t *testing.T) { Denom: "atom", Amount: "1000", }} - proto.Merge(resp.(proto.Message), copyResp) + proto.Merge(resp, copyResp) return nil - } + }) resp, err := m.Query(ctx, accAddr, wrapperspb.String("atom")) require.NoError(t, err) diff --git a/x/accounts/module.go b/x/accounts/module.go index 22b049623e03..4d00f15ed345 100644 --- a/x/accounts/module.go +++ b/x/accounts/module.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/msgservice" ) @@ -23,6 +24,9 @@ const ( StoreKey = "_" + ModuleName // unfortunately accounts collides with auth store key ) +// ModuleAccountAddress defines the x/accounts module address. +var ModuleAccountAddress = address.Module(ModuleName) + const ( ConsensusVersion = 1 ) diff --git a/x/accounts/msg_server.go b/x/accounts/msg_server.go index 5b5408790406..04cf4963c42e 100644 --- a/x/accounts/msg_server.go +++ b/x/accounts/msg_server.go @@ -121,5 +121,5 @@ func (m msgServer) Execute(ctx context.Context, execute *v1.MsgExecute) (*v1.Msg } func (m msgServer) ExecuteBundle(ctx context.Context, req *v1.MsgExecuteBundle) (*v1.MsgExecuteBundleResponse, error) { - return nil, status.New(codes.Unimplemented, "not implemented").Err() + return nil, status.Error(codes.Unimplemented, "not implemented") } diff --git a/x/accounts/msg_server_test.go b/x/accounts/msg_server_test.go index 925670ccfa45..a55536b900a4 100644 --- a/x/accounts/msg_server_test.go +++ b/x/accounts/msg_server_test.go @@ -6,7 +6,6 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/runtime/protoiface" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/wrapperspb" @@ -18,12 +17,12 @@ import ( func TestMsgServer(t *testing.T) { k, ctx := newKeeper(t, accountstd.AddAccount("test", NewTestAccount)) - k.queryModuleFunc = func(ctx context.Context, req, resp protoiface.MessageV1) error { + k.queryRouter = mockQuery(func(ctx context.Context, req, resp proto.Message) error { _, ok := req.(*bankv1beta1.QueryBalanceRequest) require.True(t, ok) - proto.Merge(resp.(proto.Message), &bankv1beta1.QueryBalanceResponse{}) + proto.Merge(resp, &bankv1beta1.QueryBalanceResponse{}) return nil - } + }) s := NewMsgServer(k) diff --git a/x/accounts/query_server_test.go b/x/accounts/query_server_test.go index 6aff2def1c11..6b091918cede 100644 --- a/x/accounts/query_server_test.go +++ b/x/accounts/query_server_test.go @@ -6,7 +6,6 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/runtime/protoiface" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/wrapperspb" @@ -17,9 +16,9 @@ import ( func TestQueryServer(t *testing.T) { k, ctx := newKeeper(t, accountstd.AddAccount("test", NewTestAccount)) - k.queryModuleFunc = func(ctx context.Context, req, resp protoiface.MessageV1) error { + k.queryRouter = mockQuery(func(ctx context.Context, req, resp proto.Message) error { return nil - } + }) ms := NewMsgServer(k) qs := NewQueryServer(k) diff --git a/x/accounts/testing/account_abstraction/full.go b/x/accounts/testing/account_abstraction/full.go new file mode 100644 index 000000000000..64d61874770f --- /dev/null +++ b/x/accounts/testing/account_abstraction/full.go @@ -0,0 +1,77 @@ +package account_abstraction + +import ( + "context" + "fmt" + + account_abstractionv1 "cosmossdk.io/api/cosmos/accounts/interfaces/account_abstraction/v1" + "cosmossdk.io/x/accounts/accountstd" +) + +// FullAbstractedAccount is an account abstraction that implements +// the account abstraction interface fully. It is used for testing. +type FullAbstractedAccount struct { + m *MinimalAbstractedAccount +} + +func NewFullAbstractedAccount(d accountstd.Dependencies) (FullAbstractedAccount, error) { + m, err := NewMinimalAbstractedAccount(d) + if err != nil { + return FullAbstractedAccount{}, err + } + return FullAbstractedAccount{m: &m}, nil +} + +func (a FullAbstractedAccount) ExecuteMessages(ctx context.Context, msg *account_abstractionv1.MsgExecute) (*account_abstractionv1.MsgExecuteResponse, error) { + // we always want to ensure that this is called by the x/accounts module, it's the only trusted entrypoint. + // if we do not do this check then someone could call this method directly and bypass the authentication. + if !accountstd.SenderIsAccountsModule(ctx) { + return nil, fmt.Errorf("sender is not the x/accounts module") + } + // we simulate this account does not allow delegation messages to be executed. + for _, m := range msg.ExecutionMessages { + if m.TypeUrl == "/cosmos.staking.v1beta1.MsgDelegate" { // NOTE: this is not a safe way to check the typeUrl, it's just for testing. + return nil, fmt.Errorf("this account does not allow delegation messages") + } + } + // execute messages + responses, err := accountstd.ExecModuleAnys(ctx, msg.ExecutionMessages) + if err != nil { + return nil, err + } + return &account_abstractionv1.MsgExecuteResponse{ExecutionMessagesResponse: responses}, nil +} + +func (a FullAbstractedAccount) PayBundler(ctx context.Context, msg *account_abstractionv1.MsgPayBundler) (*account_abstractionv1.MsgPayBundlerResponse, error) { + // we always want to ensure that this is called by the x/accounts module, it's the only trusted entrypoint. + // if we do not do this check then someone could call this method directly and bypass the authentication. + if !accountstd.SenderIsAccountsModule(ctx) { + return nil, fmt.Errorf("sender is not the x/accounts module") + } + // we check if it's a bank send, if it is we reject it. + for _, m := range msg.BundlerPaymentMessages { + if m.TypeUrl == "/cosmos.bank.v1beta1.MsgSend" { // NOTE: this is not a safe way to check the typeUrl, it's just for testing. + return nil, fmt.Errorf("this account does not allow bank send messages") + } + } + // execute messages + responses, err := accountstd.ExecModuleAnys(ctx, msg.BundlerPaymentMessages) + if err != nil { + return nil, err + } + return &account_abstractionv1.MsgPayBundlerResponse{BundlerPaymentMessagesResponse: responses}, nil +} + +func (a FullAbstractedAccount) RegisterInitHandler(builder *accountstd.InitBuilder) { + a.m.RegisterInitHandler(builder) // registers same init message as MinimalAbstractedAccount +} + +func (a FullAbstractedAccount) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder) { + accountstd.RegisterExecuteHandler(builder, a.ExecuteMessages) // implements accounts_abstraction + accountstd.RegisterExecuteHandler(builder, a.PayBundler) // implements account_abstraction + a.m.RegisterExecuteHandlers(builder) // note: MinimalAbstractedAccount implements account_abstraction, and we're calling its RegisterExecuteHandlers +} + +func (a FullAbstractedAccount) RegisterQueryHandlers(builder *accountstd.QueryBuilder) { + a.m.RegisterQueryHandlers(builder) +} diff --git a/x/accounts/testing/account_abstraction/minimal.go b/x/accounts/testing/account_abstraction/minimal.go new file mode 100644 index 000000000000..7be41619f6be --- /dev/null +++ b/x/accounts/testing/account_abstraction/minimal.go @@ -0,0 +1,70 @@ +package account_abstraction + +import ( + "context" + "fmt" + + account_abstractionv1 "cosmossdk.io/api/cosmos/accounts/interfaces/account_abstraction/v1" + rotationv1 "cosmossdk.io/api/cosmos/accounts/testing/rotation/v1" + "cosmossdk.io/api/cosmos/crypto/secp256k1" + "cosmossdk.io/collections" + "cosmossdk.io/x/accounts/accountstd" + + "github.com/cosmos/cosmos-sdk/codec" +) + +var ( + PubKeyPrefix = collections.NewPrefix(0) + SequencePrefix = collections.NewPrefix(1) +) + +var _ accountstd.Interface = (*MinimalAbstractedAccount)(nil) + +func NewMinimalAbstractedAccount(d accountstd.Dependencies) (MinimalAbstractedAccount, error) { + return MinimalAbstractedAccount{ + PubKey: collections.NewItem(d.SchemaBuilder, PubKeyPrefix, "pubkey", codec.CollValueV2[secp256k1.PubKey]()), + Sequence: collections.NewSequence(d.SchemaBuilder, SequencePrefix, "sequence"), + }, nil +} + +// MinimalAbstractedAccount implements the Account interface. +// It implements the minimum required methods. +type MinimalAbstractedAccount struct { + PubKey collections.Item[*secp256k1.PubKey] + Sequence collections.Sequence +} + +func (a MinimalAbstractedAccount) Init(ctx context.Context, msg *rotationv1.MsgInit) (*rotationv1.MsgInitResponse, error) { + return nil, a.PubKey.Set(ctx, &secp256k1.PubKey{Key: msg.PubKeyBytes}) +} + +func (a MinimalAbstractedAccount) RotatePubKey(ctx context.Context, msg *rotationv1.MsgRotatePubKey) (*rotationv1.MsgRotatePubKeyResponse, error) { + return nil, fmt.Errorf("not implemented") +} + +// Authenticate authenticates the account, auth always passess. +func (a MinimalAbstractedAccount) Authenticate(ctx context.Context, msg *account_abstractionv1.MsgAuthenticate) (*account_abstractionv1.MsgAuthenticateResponse, error) { + if msg.UserOperation.AuthenticationMethod != "secp256k1" { + return nil, fmt.Errorf("authentication method not supported") + } + _, err := a.Sequence.Next(ctx) + return &account_abstractionv1.MsgAuthenticateResponse{}, err +} + +// QueryAuthenticateMethods queries the authentication methods of the account. +func (a MinimalAbstractedAccount) QueryAuthenticateMethods(ctx context.Context, req *account_abstractionv1.QueryAuthenticationMethods) (*account_abstractionv1.QueryAuthenticationMethodsResponse, error) { + return nil, fmt.Errorf("not implemented") +} + +func (a MinimalAbstractedAccount) RegisterInitHandler(builder *accountstd.InitBuilder) { + accountstd.RegisterInitHandler(builder, a.Init) +} + +func (a MinimalAbstractedAccount) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder) { + accountstd.RegisterExecuteHandler(builder, a.RotatePubKey) + accountstd.RegisterExecuteHandler(builder, a.Authenticate) // implements account_abstraction +} + +func (a MinimalAbstractedAccount) RegisterQueryHandlers(builder *accountstd.QueryBuilder) { + accountstd.RegisterQueryHandler(builder, a.QueryAuthenticateMethods) // implements account_abstraction +} diff --git a/x/accounts/testing/account_abstraction/partial_account.go b/x/accounts/testing/account_abstraction/partial_account.go deleted file mode 100644 index 43acef23e053..000000000000 --- a/x/accounts/testing/account_abstraction/partial_account.go +++ /dev/null @@ -1,68 +0,0 @@ -package account_abstraction - -import ( - "context" - "fmt" - - account_abstractionv1 "cosmossdk.io/api/cosmos/accounts/interfaces/account_abstraction/v1" - rotationv1 "cosmossdk.io/api/cosmos/accounts/testing/rotation/v1" - "cosmossdk.io/api/cosmos/crypto/secp256k1" - "cosmossdk.io/collections" - "cosmossdk.io/x/accounts/accountstd" - - "github.com/cosmos/cosmos-sdk/codec" -) - -var ( - PubKeyPrefix = collections.NewPrefix(0) - SequencePrefix = collections.NewPrefix(1) -) - -var _ accountstd.Interface = (*PartialAccount)(nil) - -func NewPartialAccount(d accountstd.Dependencies) (PartialAccount, error) { - return PartialAccount{ - PubKey: collections.NewItem(d.SchemaBuilder, PubKeyPrefix, "pubkey", codec.CollValueV2[secp256k1.PubKey]()), - Sequence: collections.NewItem(d.SchemaBuilder, SequencePrefix, "sequence", collections.Uint64Value), - }, nil -} - -// PartialAccount implements the Account interface. It also -// implements the account_abstraction interface, it only implements -// the minimum methods required to be a valid account_abstraction -// implementer. -type PartialAccount struct { - PubKey collections.Item[*secp256k1.PubKey] - Sequence collections.Item[uint64] -} - -func (a PartialAccount) Init(ctx context.Context, msg *rotationv1.MsgInit) (*rotationv1.MsgInitResponse, error) { - return nil, fmt.Errorf("not implemented") -} - -func (a PartialAccount) RotatePubKey(ctx context.Context, msg *rotationv1.MsgRotatePubKey) (*rotationv1.MsgRotatePubKeyResponse, error) { - return nil, fmt.Errorf("not implemented") -} - -// Authenticate authenticates the account. -func (a PartialAccount) Authenticate(ctx context.Context, msg *account_abstractionv1.MsgAuthenticate) (*account_abstractionv1.MsgAuthenticateResponse, error) { - return nil, fmt.Errorf("not implemented") -} - -// QueryAuthenticateMethods queries the authentication methods of the account. -func (a PartialAccount) QueryAuthenticateMethods(ctx context.Context, req *account_abstractionv1.QueryAuthenticationMethods) (*account_abstractionv1.QueryAuthenticationMethodsResponse, error) { - return nil, fmt.Errorf("not implemented") -} - -func (a PartialAccount) RegisterInitHandler(builder *accountstd.InitBuilder) { - accountstd.RegisterInitHandler(builder, a.Init) -} - -func (a PartialAccount) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder) { - accountstd.RegisterExecuteHandler(builder, a.RotatePubKey) - accountstd.RegisterExecuteHandler(builder, a.Authenticate) // implements account_abstraction -} - -func (a PartialAccount) RegisterQueryHandlers(builder *accountstd.QueryBuilder) { - accountstd.RegisterQueryHandler(builder, a.QueryAuthenticateMethods) // implements account_abstraction -} diff --git a/x/accounts/utils_test.go b/x/accounts/utils_test.go new file mode 100644 index 000000000000..fa8655431ec4 --- /dev/null +++ b/x/accounts/utils_test.go @@ -0,0 +1,80 @@ +package accounts + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/runtime/protoiface" + + "cosmossdk.io/collections/colltest" + "cosmossdk.io/core/address" + "cosmossdk.io/core/event" + "cosmossdk.io/x/accounts/internal/implementation" +) + +var _ address.Codec = (*addressCodec)(nil) + +type addressCodec struct{} + +func (a addressCodec) StringToBytes(text string) ([]byte, error) { return []byte(text), nil } +func (a addressCodec) BytesToString(bz []byte) (string, error) { return string(bz), nil } + +type eventService struct{} + +func (e eventService) Emit(ctx context.Context, event protoiface.MessageV1) error { return nil } + +func (e eventService) EmitKV(ctx context.Context, eventType string, attrs ...event.Attribute) error { + return nil +} + +func (e eventService) EmitNonConsensus(ctx context.Context, event protoiface.MessageV1) error { + return nil +} + +func (e eventService) EventManager(ctx context.Context) event.Manager { return e } + +func newKeeper(t *testing.T, accounts ...implementation.AccountCreatorFunc) (Keeper, context.Context) { + t.Helper() + ss, ctx := colltest.MockStore() + m, err := NewKeeper(ss, eventService{}, nil, addressCodec{}, nil, nil, nil, accounts...) + require.NoError(t, err) + return m, ctx +} + +var _ QueryRouter = (*mockQuery)(nil) + +type mockQuery func(ctx context.Context, req, resp proto.Message) error + +func (m mockQuery) HybridHandlerByRequestName(_ string) []func(ctx context.Context, req, resp protoiface.MessageV1) error { + return []func(ctx context.Context, req, resp protoiface.MessageV1) error{func(ctx context.Context, req, resp protoiface.MessageV1) error { + return m(ctx, req.(proto.Message), resp.(proto.Message)) + }} +} + +var _ SignerProvider = (*mockSigner)(nil) + +type mockSigner func(msg proto.Message) ([]byte, error) + +func (m mockSigner) GetSigners(msg proto.Message) ([][]byte, error) { + s, err := m(msg) + if err != nil { + return nil, err + } + return [][]byte{s}, nil +} + +var _ MsgRouter = (*mockExec)(nil) + +type mockExec func(ctx context.Context, msg, msgResp proto.Message) error + +func (m mockExec) HybridHandlerByMsgName(_ string) func(ctx context.Context, req, resp protoiface.MessageV1) error { + return func(ctx context.Context, req, resp protoiface.MessageV1) error { + return m(ctx, req.(proto.Message), resp.(proto.Message)) + } +} + +func (m mockExec) ResponseNameByRequestName(name string) string { + return name + "Response" +} diff --git a/x/accounts/v1/account_abstraction.pb.go b/x/accounts/v1/account_abstraction.pb.go index 76a7ccd2e140..95ebb759fca7 100644 --- a/x/accounts/v1/account_abstraction.pb.go +++ b/x/accounts/v1/account_abstraction.pb.go @@ -35,12 +35,9 @@ type UserOperation struct { // authentication_data defines the authentication data associated with the authentication method. // It is the account implementer duty to assess that the UserOperation is properly signed. AuthenticationData []byte `protobuf:"bytes,3,opt,name=authentication_data,json=authenticationData,proto3" json:"authentication_data,omitempty"` - // sequence defines the sequence number of the account, the authentication method might require this - // to ensure non-replayability. - Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` // authentication_gas_limit expresses the gas limit to be used for the authentication part of the // UserOperation. - AuthenticationGasLimit uint64 `protobuf:"varint,5,opt,name=authentication_gas_limit,json=authenticationGasLimit,proto3" json:"authentication_gas_limit,omitempty"` + AuthenticationGasLimit uint64 `protobuf:"varint,4,opt,name=authentication_gas_limit,json=authenticationGasLimit,proto3" json:"authentication_gas_limit,omitempty"` // bundler_payment_messages expresses a list of messages that the account // executes to pay the bundler for submitting the UserOperation. // It can be empty if the bundler does not need any form of payment, @@ -50,18 +47,18 @@ type UserOperation struct { // - NFT payment // - IBC Token payment. // - Payment through delegations. - BundlerPaymentMessages []*types.Any `protobuf:"bytes,6,rep,name=bundler_payment_messages,json=bundlerPaymentMessages,proto3" json:"bundler_payment_messages,omitempty"` + BundlerPaymentMessages []*types.Any `protobuf:"bytes,5,rep,name=bundler_payment_messages,json=bundlerPaymentMessages,proto3" json:"bundler_payment_messages,omitempty"` // bundler_payment_gas_limit defines the gas limit to be used for the bundler payment. // This ensures that, since the bundler executes a list of UserOperations and there needs to // be minimal trust between bundler and UserOperation sender, the sender cannot consume // the whole bundle gas. - BundlerPaymentGasLimit uint64 `protobuf:"varint,7,opt,name=bundler_payment_gas_limit,json=bundlerPaymentGasLimit,proto3" json:"bundler_payment_gas_limit,omitempty"` + BundlerPaymentGasLimit uint64 `protobuf:"varint,6,opt,name=bundler_payment_gas_limit,json=bundlerPaymentGasLimit,proto3" json:"bundler_payment_gas_limit,omitempty"` // execution_messages expresses a list of messages that the account wants to execute. // This concretely is the intent of the transaction expressed as a UserOperation. - ExecutionMessages []*types.Any `protobuf:"bytes,8,rep,name=execution_messages,json=executionMessages,proto3" json:"execution_messages,omitempty"` + ExecutionMessages []*types.Any `protobuf:"bytes,7,rep,name=execution_messages,json=executionMessages,proto3" json:"execution_messages,omitempty"` // execution_gas_limit defines the gas limit to be used for the execution of the UserOperation's // execution messages. - ExecutionGasLimit uint64 `protobuf:"varint,9,opt,name=execution_gas_limit,json=executionGasLimit,proto3" json:"execution_gas_limit,omitempty"` + ExecutionGasLimit uint64 `protobuf:"varint,8,opt,name=execution_gas_limit,json=executionGasLimit,proto3" json:"execution_gas_limit,omitempty"` } func (m *UserOperation) Reset() { *m = UserOperation{} } @@ -118,13 +115,6 @@ func (m *UserOperation) GetAuthenticationData() []byte { return nil } -func (m *UserOperation) GetSequence() uint64 { - if m != nil { - return m.Sequence - } - return 0 -} - func (m *UserOperation) GetAuthenticationGasLimit() uint64 { if m != nil { return m.AuthenticationGasLimit @@ -161,6 +151,7 @@ func (m *UserOperation) GetExecutionGasLimit() uint64 { } // UserOperationResponse defines the response of a UserOperation. +// If the operation fails the error field will be populated. type UserOperationResponse struct { // authentication_gas_used defines the gas used for the authentication part of the UserOperation. AuthenticationGasUsed uint64 `protobuf:"varint,1,opt,name=authentication_gas_used,json=authenticationGasUsed,proto3" json:"authentication_gas_used,omitempty"` @@ -173,6 +164,12 @@ type UserOperationResponse struct { ExecutionGasUsed uint64 `protobuf:"varint,4,opt,name=execution_gas_used,json=executionGasUsed,proto3" json:"execution_gas_used,omitempty"` // execution_responses defines the responses of the execution messages. ExecutionResponses []*types.Any `protobuf:"bytes,5,rep,name=execution_responses,json=executionResponses,proto3" json:"execution_responses,omitempty"` + // error defines the error that occurred during the execution of the UserOperation. + // If the error is not empty, the UserOperation failed. + // Other fields might be populated even if the error is not empty, for example + // if the operation fails after the authentication step, the authentication_gas_used + // field will be populated. + Error string `protobuf:"bytes,6,opt,name=error,proto3" json:"error,omitempty"` } func (m *UserOperationResponse) Reset() { *m = UserOperationResponse{} } @@ -243,6 +240,13 @@ func (m *UserOperationResponse) GetExecutionResponses() []*types.Any { return nil } +func (m *UserOperationResponse) GetError() string { + if m != nil { + return m.Error + } + return "" +} + func init() { proto.RegisterType((*UserOperation)(nil), "cosmos.accounts.v1.UserOperation") proto.RegisterType((*UserOperationResponse)(nil), "cosmos.accounts.v1.UserOperationResponse") @@ -253,36 +257,36 @@ func init() { } var fileDescriptor_9f9bcc910ad46d4b = []byte{ - // 463 bytes of a gzipped FileDescriptorProto + // 461 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0xcd, 0x6e, 0xd3, 0x40, - 0x14, 0x85, 0xe3, 0x24, 0x0d, 0xed, 0x00, 0x12, 0x4c, 0x9b, 0x74, 0x9a, 0x85, 0x15, 0x75, 0x95, - 0x45, 0x35, 0x56, 0x29, 0xe2, 0x67, 0xc9, 0x9f, 0xd8, 0x50, 0xa8, 0x2c, 0x75, 0xc3, 0xc6, 0x9a, - 0xd8, 0x97, 0xd4, 0x22, 0x9e, 0x09, 0xbe, 0xe3, 0xaa, 0x79, 0x0b, 0x1e, 0x8b, 0x1d, 0x5d, 0xb2, - 0x44, 0xc9, 0x8b, 0xa0, 0xcc, 0xf8, 0x27, 0x8e, 0x51, 0x76, 0x19, 0xdd, 0x73, 0xee, 0x39, 0xf9, - 0xc6, 0x43, 0xce, 0x42, 0x85, 0x89, 0x42, 0x4f, 0x84, 0xa1, 0xca, 0xa4, 0x46, 0xef, 0xf6, 0xbc, - 0xf8, 0x1d, 0x88, 0x09, 0xea, 0x54, 0x84, 0x3a, 0x56, 0x92, 0xcf, 0x53, 0xa5, 0x15, 0xa5, 0x56, - 0xcd, 0x0b, 0x35, 0xbf, 0x3d, 0x1f, 0x9e, 0x4c, 0x95, 0x9a, 0xce, 0xc0, 0x33, 0x8a, 0x49, 0xf6, - 0xcd, 0x13, 0x72, 0x61, 0xe5, 0xa7, 0xab, 0x0e, 0x79, 0x7c, 0x8d, 0x90, 0x7e, 0x99, 0x43, 0x2a, - 0xd6, 0x6b, 0xe8, 0x80, 0xf4, 0x10, 0x64, 0x04, 0x29, 0x73, 0x46, 0xce, 0xf8, 0xc0, 0xcf, 0x4f, - 0xf4, 0x82, 0xf4, 0x45, 0xa6, 0x6f, 0x40, 0xea, 0x38, 0x34, 0xca, 0x20, 0x01, 0x7d, 0xa3, 0x22, - 0xd6, 0x36, 0xb2, 0xa3, 0xfa, 0xf0, 0xd2, 0xcc, 0xa8, 0x47, 0x0e, 0xb7, 0x4c, 0x91, 0xd0, 0x82, - 0x75, 0x46, 0xce, 0xf8, 0x91, 0x4f, 0xeb, 0xa3, 0xf7, 0x42, 0x0b, 0x3a, 0x24, 0xfb, 0x08, 0x3f, - 0x32, 0x90, 0x21, 0xb0, 0xee, 0xc8, 0x19, 0x77, 0xfd, 0xf2, 0x4c, 0x5f, 0x11, 0xb6, 0xb5, 0x6c, - 0x2a, 0x30, 0x98, 0xc5, 0x49, 0xac, 0xd9, 0x9e, 0xd1, 0x0e, 0xea, 0xf3, 0x8f, 0x02, 0x3f, 0xad, - 0xa7, 0xf4, 0x33, 0x61, 0x93, 0x4c, 0x46, 0x33, 0x48, 0x83, 0xb9, 0x58, 0x24, 0x20, 0x75, 0x90, - 0x00, 0xa2, 0x98, 0x02, 0xb2, 0xde, 0xa8, 0x33, 0x7e, 0xf8, 0xec, 0x88, 0x5b, 0x46, 0xbc, 0x60, - 0xc4, 0xdf, 0xc8, 0x85, 0x3f, 0xc8, 0x5d, 0x57, 0xd6, 0x74, 0x99, 0x7b, 0xe8, 0x6b, 0x72, 0xb2, - 0xbd, 0xaf, 0xaa, 0xf2, 0xc0, 0x56, 0xa9, 0x5b, 0xcb, 0x2a, 0xef, 0x08, 0x85, 0x3b, 0x08, 0xb3, - 0x9c, 0x60, 0x5e, 0x62, 0x7f, 0x47, 0x89, 0xa7, 0xa5, 0xbe, 0xcc, 0xe7, 0xe4, 0xb0, 0x5a, 0x52, - 0x25, 0x1f, 0x98, 0xe4, 0x4a, 0x5f, 0x84, 0x9e, 0xfe, 0x6e, 0x93, 0x7e, 0xed, 0x96, 0x7d, 0xc0, - 0xb9, 0x92, 0x08, 0xf4, 0x05, 0x39, 0xfe, 0x0f, 0xd3, 0x0c, 0x21, 0x32, 0xd7, 0xdf, 0xf5, 0xfb, - 0x0d, 0xa4, 0xd7, 0x08, 0x11, 0x7d, 0xd9, 0x24, 0x5a, 0x1a, 0xdb, 0xd6, 0xd8, 0x00, 0x60, 0x8c, - 0x57, 0x4d, 0x74, 0x69, 0x5e, 0x06, 0x59, 0x67, 0x07, 0x86, 0xe3, 0xfa, 0xbe, 0xe2, 0x1f, 0x20, - 0x3d, 0xdb, 0x24, 0x5a, 0x96, 0xb0, 0x1f, 0xcf, 0x93, 0x4d, 0x16, 0x26, 0xff, 0xc3, 0x26, 0xba, - 0x2a, 0x79, 0x6f, 0x47, 0x72, 0xb5, 0xbe, 0x0c, 0x7d, 0xfb, 0xfc, 0xd7, 0xd2, 0x75, 0xee, 0x97, - 0xae, 0xf3, 0x77, 0xe9, 0x3a, 0x3f, 0x57, 0x6e, 0xeb, 0x7e, 0xe5, 0xb6, 0xfe, 0xac, 0xdc, 0xd6, - 0xd7, 0xa1, 0x7d, 0x80, 0x18, 0x7d, 0xe7, 0xb1, 0xf2, 0xee, 0x36, 0x9f, 0xed, 0xa4, 0x67, 0xf6, - 0x5e, 0xfc, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xea, 0xb4, 0x8f, 0x4f, 0xd3, 0x03, 0x00, 0x00, + 0x14, 0x85, 0xe3, 0x24, 0x0d, 0x74, 0x00, 0x09, 0xa6, 0x49, 0xea, 0x76, 0x61, 0x45, 0x5d, 0x65, + 0x51, 0x8d, 0x55, 0x8a, 0xf8, 0x59, 0xf2, 0x27, 0x36, 0x14, 0x2a, 0x4b, 0xdd, 0xb0, 0xb1, 0x26, + 0xf6, 0x25, 0xb5, 0x88, 0x67, 0xa2, 0xb9, 0xe3, 0xaa, 0x79, 0x0b, 0xde, 0x0a, 0x96, 0x5d, 0xb2, + 0x44, 0x89, 0x78, 0x0f, 0x94, 0x19, 0xff, 0xc4, 0x71, 0x95, 0x5d, 0xac, 0x7b, 0xce, 0x3d, 0x27, + 0xdf, 0xcc, 0x90, 0xd3, 0x48, 0x62, 0x2a, 0xd1, 0xe7, 0x51, 0x24, 0x33, 0xa1, 0xd1, 0xbf, 0x39, + 0x2b, 0x7e, 0x87, 0x7c, 0x82, 0x5a, 0xf1, 0x48, 0x27, 0x52, 0xb0, 0xb9, 0x92, 0x5a, 0x52, 0x6a, + 0xd5, 0xac, 0x50, 0xb3, 0x9b, 0xb3, 0xe3, 0xa3, 0xa9, 0x94, 0xd3, 0x19, 0xf8, 0x46, 0x31, 0xc9, + 0xbe, 0xfb, 0x5c, 0x2c, 0xac, 0xfc, 0xe4, 0x57, 0x87, 0x3c, 0xb9, 0x42, 0x50, 0x5f, 0xe7, 0xa0, + 0xf8, 0x7a, 0x0d, 0x1d, 0x92, 0x1e, 0x82, 0x88, 0x41, 0xb9, 0xce, 0xc8, 0x19, 0xef, 0x07, 0xf9, + 0x17, 0x3d, 0x27, 0x03, 0x9e, 0xe9, 0x6b, 0x10, 0x3a, 0x89, 0x8c, 0x32, 0x4c, 0x41, 0x5f, 0xcb, + 0xd8, 0x6d, 0x1b, 0x59, 0xbf, 0x3e, 0xbc, 0x30, 0x33, 0xea, 0x93, 0x83, 0x2d, 0x53, 0xcc, 0x35, + 0x77, 0x3b, 0x23, 0x67, 0xfc, 0x38, 0xa0, 0xf5, 0xd1, 0x07, 0xae, 0x39, 0x7d, 0x4d, 0xdc, 0x2d, + 0xc3, 0x94, 0x63, 0x38, 0x4b, 0xd2, 0x44, 0xbb, 0xdd, 0x91, 0x33, 0xee, 0x06, 0xc3, 0xfa, 0xfc, + 0x13, 0xc7, 0xcf, 0xeb, 0x29, 0xfd, 0x42, 0xdc, 0x49, 0x26, 0xe2, 0x19, 0xa8, 0x70, 0xce, 0x17, + 0x29, 0x08, 0x1d, 0xa6, 0x80, 0xc8, 0xa7, 0x80, 0xee, 0xde, 0xa8, 0x33, 0x7e, 0xf4, 0xbc, 0xcf, + 0x2c, 0x07, 0x56, 0x70, 0x60, 0x6f, 0xc5, 0x22, 0x18, 0xe6, 0xae, 0x4b, 0x6b, 0xba, 0xc8, 0x3d, + 0xf4, 0x0d, 0x39, 0xda, 0xde, 0x57, 0x55, 0xe9, 0xd9, 0x2a, 0x75, 0x6b, 0x59, 0xe5, 0x3d, 0xa1, + 0x70, 0x0b, 0x51, 0x96, 0x53, 0xca, 0x4b, 0x3c, 0xd8, 0x51, 0xe2, 0x59, 0xa9, 0x2f, 0xf3, 0x19, + 0x39, 0xa8, 0x96, 0x54, 0xc9, 0x0f, 0x4d, 0x72, 0xa5, 0x2f, 0x42, 0x4f, 0xfe, 0xb5, 0xc9, 0xa0, + 0x76, 0x92, 0x01, 0xe0, 0x5c, 0x0a, 0x04, 0xfa, 0x92, 0x1c, 0xde, 0xc3, 0x34, 0x43, 0x88, 0xcd, + 0x11, 0x77, 0x83, 0x41, 0x03, 0xe9, 0x15, 0x42, 0x4c, 0x5f, 0x35, 0x89, 0x96, 0xc6, 0xb6, 0x35, + 0x36, 0x00, 0x18, 0xe3, 0x65, 0x13, 0x9d, 0xca, 0xcb, 0xa0, 0xdb, 0xd9, 0x81, 0xe1, 0xb0, 0xbe, + 0xaf, 0xf8, 0x07, 0x48, 0x4f, 0x37, 0x89, 0x96, 0x25, 0xec, 0x85, 0x78, 0xba, 0xc9, 0xc2, 0xe4, + 0x7f, 0xdc, 0x44, 0x57, 0x25, 0xef, 0xba, 0x05, 0xd5, 0xfa, 0x2a, 0xb4, 0x4f, 0xf6, 0x40, 0x29, + 0xa9, 0xcc, 0x69, 0xef, 0x07, 0xf6, 0xe3, 0xdd, 0x8b, 0xdf, 0x4b, 0xcf, 0xb9, 0x5b, 0x7a, 0xce, + 0xdf, 0xa5, 0xe7, 0xfc, 0x5c, 0x79, 0xad, 0xbb, 0x95, 0xd7, 0xfa, 0xb3, 0xf2, 0x5a, 0xdf, 0x8e, + 0xed, 0xd3, 0xc3, 0xf8, 0x07, 0x4b, 0xa4, 0x7f, 0xbb, 0xf9, 0x60, 0x27, 0x3d, 0x93, 0x76, 0xfe, + 0x3f, 0x00, 0x00, 0xff, 0xff, 0xf6, 0xb6, 0x1b, 0x5c, 0xcd, 0x03, 0x00, 0x00, } func (m *UserOperation) Marshal() (dAtA []byte, err error) { @@ -308,7 +312,7 @@ func (m *UserOperation) MarshalToSizedBuffer(dAtA []byte) (int, error) { if m.ExecutionGasLimit != 0 { i = encodeVarintAccountAbstraction(dAtA, i, uint64(m.ExecutionGasLimit)) i-- - dAtA[i] = 0x48 + dAtA[i] = 0x40 } if len(m.ExecutionMessages) > 0 { for iNdEx := len(m.ExecutionMessages) - 1; iNdEx >= 0; iNdEx-- { @@ -321,13 +325,13 @@ func (m *UserOperation) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintAccountAbstraction(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x42 + dAtA[i] = 0x3a } } if m.BundlerPaymentGasLimit != 0 { i = encodeVarintAccountAbstraction(dAtA, i, uint64(m.BundlerPaymentGasLimit)) i-- - dAtA[i] = 0x38 + dAtA[i] = 0x30 } if len(m.BundlerPaymentMessages) > 0 { for iNdEx := len(m.BundlerPaymentMessages) - 1; iNdEx >= 0; iNdEx-- { @@ -340,17 +344,12 @@ func (m *UserOperation) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintAccountAbstraction(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x32 + dAtA[i] = 0x2a } } if m.AuthenticationGasLimit != 0 { i = encodeVarintAccountAbstraction(dAtA, i, uint64(m.AuthenticationGasLimit)) i-- - dAtA[i] = 0x28 - } - if m.Sequence != 0 { - i = encodeVarintAccountAbstraction(dAtA, i, uint64(m.Sequence)) - i-- dAtA[i] = 0x20 } if len(m.AuthenticationData) > 0 { @@ -397,6 +396,13 @@ func (m *UserOperationResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Error) > 0 { + i -= len(m.Error) + copy(dAtA[i:], m.Error) + i = encodeVarintAccountAbstraction(dAtA, i, uint64(len(m.Error))) + i-- + dAtA[i] = 0x32 + } if len(m.ExecutionResponses) > 0 { for iNdEx := len(m.ExecutionResponses) - 1; iNdEx >= 0; iNdEx-- { { @@ -472,9 +478,6 @@ func (m *UserOperation) Size() (n int) { if l > 0 { n += 1 + l + sovAccountAbstraction(uint64(l)) } - if m.Sequence != 0 { - n += 1 + sovAccountAbstraction(uint64(m.Sequence)) - } if m.AuthenticationGasLimit != 0 { n += 1 + sovAccountAbstraction(uint64(m.AuthenticationGasLimit)) } @@ -526,6 +529,10 @@ func (m *UserOperationResponse) Size() (n int) { n += 1 + l + sovAccountAbstraction(uint64(l)) } } + l = len(m.Error) + if l > 0 { + n += 1 + l + sovAccountAbstraction(uint64(l)) + } return n } @@ -663,25 +670,6 @@ func (m *UserOperation) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) - } - m.Sequence = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAccountAbstraction - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Sequence |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field AuthenticationGasLimit", wireType) } @@ -700,7 +688,7 @@ func (m *UserOperation) Unmarshal(dAtA []byte) error { break } } - case 6: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field BundlerPaymentMessages", wireType) } @@ -734,7 +722,7 @@ func (m *UserOperation) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 7: + case 6: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field BundlerPaymentGasLimit", wireType) } @@ -753,7 +741,7 @@ func (m *UserOperation) Unmarshal(dAtA []byte) error { break } } - case 8: + case 7: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ExecutionMessages", wireType) } @@ -787,7 +775,7 @@ func (m *UserOperation) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 9: + case 8: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field ExecutionGasLimit", wireType) } @@ -981,6 +969,38 @@ func (m *UserOperationResponse) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAccountAbstraction + } + 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 ErrInvalidLengthAccountAbstraction + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAccountAbstraction + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Error = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAccountAbstraction(dAtA[iNdEx:])