From 0a0e6301598d6e6c36237e26b91a17a80bdb4b7e Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 16:00:11 +0200 Subject: [PATCH 01/18] add MsgFundConsumerFeePool, MsgWithdrawConsumerFeePool, MsgSweepConsumerFeePool with ValidateBasic --- proto/vaas/provider/v1/genesis.proto | 19 + proto/vaas/provider/v1/query.proto | 41 + proto/vaas/provider/v1/tx.proto | 69 ++ x/vaas/provider/keeper/grpc_query.go | 8 + x/vaas/provider/keeper/msg_server.go | 13 + x/vaas/provider/types/codec.go | 3 + x/vaas/provider/types/errors.go | 4 + x/vaas/provider/types/events.go | 9 + x/vaas/provider/types/genesis.pb.go | 500 +++++++- x/vaas/provider/types/keys.go | 7 + x/vaas/provider/types/msg.go | 60 + x/vaas/provider/types/msg_test.go | 140 +++ x/vaas/provider/types/query.pb.go | 1563 +++++++++++++++++++++++--- x/vaas/provider/types/query.pb.gw.go | 242 ++++ x/vaas/provider/types/tx.pb.go | 1530 +++++++++++++++++++++++-- 15 files changed, 3875 insertions(+), 333 deletions(-) diff --git a/proto/vaas/provider/v1/genesis.proto b/proto/vaas/provider/v1/genesis.proto index 366faa0..44e13e2 100644 --- a/proto/vaas/provider/v1/genesis.proto +++ b/proto/vaas/provider/v1/genesis.proto @@ -6,6 +6,8 @@ option go_package = "github.com/allinbits/vaas/x/vaas/provider/types"; import "gogoproto/gogo.proto"; import "google/protobuf/timestamp.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; import "vaas/v1/shared_consumer.proto"; import "vaas/v1/wire.proto"; import "vaas/provider/v1/provider.proto"; @@ -33,6 +35,9 @@ message GenesisState { // empty for a new chain repeated ConsumerAddrsToPrune consumer_addrs_to_prune = 7 [ (gogoproto.nullable) = false ]; + // empty for a new chain + repeated ConsumerFeePoolShare consumer_fee_pool_shares = 8 + [ (gogoproto.nullable) = false ]; } // The provider VAAS module's knowledge of consumer state. @@ -84,3 +89,17 @@ message ValsetUpdateIdToHeight { uint64 valset_update_id = 1; uint64 height = 2; } + +// ConsumerFeePoolShare is a single depositor's share holding in a consumer +// fee pool, scoped to one denom. The triple (consumer_id, depositor, denom) +// is unique. +message ConsumerFeePoolShare { + string consumer_id = 1; + string depositor = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string denom = 3; + string shares = 4 [ + (cosmos_proto.scalar) = "cosmos.Int", + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false + ]; +} diff --git a/proto/vaas/provider/v1/query.proto b/proto/vaas/provider/v1/query.proto index ab3c7be..38052a6 100644 --- a/proto/vaas/provider/v1/query.proto +++ b/proto/vaas/provider/v1/query.proto @@ -13,6 +13,7 @@ import "tendermint/crypto/keys.proto"; import "cosmos_proto/cosmos.proto"; import "cosmos/staking/v1beta1/staking.proto"; import "cosmos/base/query/v1beta1/pagination.proto"; +import "cosmos/base/v1beta1/coin.proto"; service Query { // ConsumerGenesis queries the genesis state needed to start a consumer chain @@ -106,6 +107,13 @@ service Query { option (google.api.http).get = "/vaas/provider/consumer_genesis_time/{consumer_id}"; } + + rpc ConsumerFeePoolClaim(QueryConsumerFeePoolClaimRequest) returns (QueryConsumerFeePoolClaimResponse) { + option (google.api.http).get = "/vaas/provider/v1/consumer_fee_pool_claim/{consumer_id}/{depositor}"; + } + rpc ConsumerFeePoolClaims(QueryConsumerFeePoolClaimsRequest) returns (QueryConsumerFeePoolClaimsResponse) { + option (google.api.http).get = "/vaas/provider/v1/consumer_fee_pool_claims/{consumer_id}"; + } } message QueryConsumerGenesisRequest { @@ -277,3 +285,36 @@ message QueryConsumerGenesisTimeResponse { google.protobuf.Timestamp genesis_time = 1 [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; } + +message QueryConsumerFeePoolClaimRequest { + string consumer_id = 1; + // bech32 address; if equal to the gov module authority, aliases to the + // distribution module account address + string depositor = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +message QueryConsumerFeePoolClaimResponse { + // claimable balance across all denoms; excludes zero-claim denoms + repeated cosmos.base.v1beta1.Coin claim = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +message DepositorClaim { + string depositor = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + repeated cosmos.base.v1beta1.Coin claim = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +message QueryConsumerFeePoolClaimsRequest { + string consumer_id = 1; + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +message QueryConsumerFeePoolClaimsResponse { + repeated DepositorClaim claims = 1 [(gogoproto.nullable) = false]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} diff --git a/proto/vaas/provider/v1/tx.proto b/proto/vaas/provider/v1/tx.proto index 3ac3677..bd4bb5b 100644 --- a/proto/vaas/provider/v1/tx.proto +++ b/proto/vaas/provider/v1/tx.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package vaas.provider.v1; import "amino/amino.proto"; +import "cosmos/base/v1beta1/coin.proto"; import "cosmos/msg/v1/msg.proto"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; @@ -27,6 +28,9 @@ service Msg { rpc UpdateConsumer(MsgUpdateConsumer) returns (MsgUpdateConsumerResponse); rpc RemoveConsumer(MsgRemoveConsumer) returns (MsgRemoveConsumerResponse); rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); + rpc FundConsumerFeePool(MsgFundConsumerFeePool) returns (MsgFundConsumerFeePoolResponse); + rpc WithdrawConsumerFeePool(MsgWithdrawConsumerFeePool) returns (MsgWithdrawConsumerFeePoolResponse); + rpc SweepConsumerFeePool(MsgSweepConsumerFeePool) returns (MsgSweepConsumerFeePoolResponse); } message MsgAssignConsumerKey { @@ -165,3 +169,68 @@ message MsgUpdateConsumer { // MsgUpdateConsumerResponse defines response type for MsgUpdateConsumer messages message MsgUpdateConsumerResponse {} + +// MsgFundConsumerFeePool deposits a single-denom amount into a consumer's +// fee pool and credits the signer with shares. If the signer is the gov +// module authority, funds are pulled from the community pool and the +// distribution module account is credited as the depositor. +message MsgFundConsumerFeePool { + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string consumer_id = 2; + cosmos.base.v1beta1.Coin amount = 3 [ + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true + ]; +} + +message MsgFundConsumerFeePoolResponse {} + +// MsgWithdrawConsumerFeePool withdraws tokens from the signer's share in a +// consumer fee pool across one or more denoms. The transaction is atomic: +// if any denom in `amount` fails its share check, the whole tx aborts. +// If the signer is the gov module authority, the withdrawal targets the +// distribution module account's shares and tokens are routed back to the +// community pool. +message MsgWithdrawConsumerFeePool { + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string consumer_id = 2; + repeated cosmos.base.v1beta1.Coin amount = 3 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (amino.dont_omitempty) = true + ]; +} + +message MsgWithdrawConsumerFeePoolResponse { + // total tokens actually delivered (may be less than requested due to + // truncation in the partial-withdraw branch) + repeated cosmos.base.v1beta1.Coin amount = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// MsgSweepConsumerFeePool distributes a consumer fee pool's balance pro-rata +// to all share-holders across the specified denoms (or all denoms if `denoms` +// is empty). Truncation residue per denom is forwarded to the community pool. +// Only the consumer owner may sign. +message MsgSweepConsumerFeePool { + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string consumer_id = 2; + // empty = all denoms with shares or balance for this consumer + repeated string denoms = 3; +} + +message MsgSweepConsumerFeePoolResponse {} diff --git a/x/vaas/provider/keeper/grpc_query.go b/x/vaas/provider/keeper/grpc_query.go index 98a55d9..c144951 100644 --- a/x/vaas/provider/keeper/grpc_query.go +++ b/x/vaas/provider/keeper/grpc_query.go @@ -321,6 +321,14 @@ func (k Keeper) QueryConsumerChain(goCtx context.Context, req *types.QueryConsum }, nil } +func (k Keeper) ConsumerFeePoolClaim(_ context.Context, _ *types.QueryConsumerFeePoolClaimRequest) (*types.QueryConsumerFeePoolClaimResponse, error) { + panic("not implemented") +} + +func (k Keeper) ConsumerFeePoolClaims(_ context.Context, _ *types.QueryConsumerFeePoolClaimsRequest) (*types.QueryConsumerFeePoolClaimsResponse, error) { + panic("not implemented") +} + func (k Keeper) QueryConsumerGenesisTime(goCtx context.Context, req *types.QueryConsumerGenesisTimeRequest) (*types.QueryConsumerGenesisTimeResponse, error) { if req == nil { return nil, status.Errorf(codes.InvalidArgument, "empty request") diff --git a/x/vaas/provider/keeper/msg_server.go b/x/vaas/provider/keeper/msg_server.go index e844ad8..fb17411 100644 --- a/x/vaas/provider/keeper/msg_server.go +++ b/x/vaas/provider/keeper/msg_server.go @@ -466,3 +466,16 @@ func (k msgServer) RemoveConsumer(goCtx context.Context, msg *types.MsgRemoveCon return &resp, err } + +// FundConsumerFeePool deposits funds into a consumer's fee pool. +func (k msgServer) FundConsumerFeePool(_ context.Context, _ *types.MsgFundConsumerFeePool) (*types.MsgFundConsumerFeePoolResponse, error) { + panic("not implemented") +} + +func (k msgServer) WithdrawConsumerFeePool(_ context.Context, _ *types.MsgWithdrawConsumerFeePool) (*types.MsgWithdrawConsumerFeePoolResponse, error) { + panic("not implemented") +} + +func (k msgServer) SweepConsumerFeePool(_ context.Context, _ *types.MsgSweepConsumerFeePool) (*types.MsgSweepConsumerFeePoolResponse, error) { + panic("not implemented") +} diff --git a/x/vaas/provider/types/codec.go b/x/vaas/provider/types/codec.go index 7021812..acb3b0a 100644 --- a/x/vaas/provider/types/codec.go +++ b/x/vaas/provider/types/codec.go @@ -24,6 +24,9 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { &MsgUpdateParams{}, &MsgSubmitConsumerMisbehaviour{}, &MsgSubmitConsumerDoubleVoting{}, + &MsgFundConsumerFeePool{}, + &MsgWithdrawConsumerFeePool{}, + &MsgSweepConsumerFeePool{}, ) registry.RegisterImplementations( (*exported.ClientMessage)(nil), diff --git a/x/vaas/provider/types/errors.go b/x/vaas/provider/types/errors.go index f97d3fd..6fc64de 100644 --- a/x/vaas/provider/types/errors.go +++ b/x/vaas/provider/types/errors.go @@ -28,4 +28,8 @@ var ( ErrInvalidMsgSubmitConsumerDoubleVoting = errorsmod.Register(ModuleName, 20, "invalid submit consumer double voting message") ErrInvalidConsumerInfractionParameters = errorsmod.Register(ModuleName, 21, "invalid consumer infraction parameters") ErrDuplicateChainId = errorsmod.Register(ModuleName, 22, "consumer chain-id is already in use") + ErrPoolEmpty = errorsmod.Register(ModuleName, 23, "consumer fee pool has zero balance for the requested denom") + ErrUnsolicitedFeePoolDeposit = errorsmod.Register(ModuleName, 24, "direct sends to consumer fee pool addresses are not permitted; use MsgFundConsumerFeePool") + ErrInvalidFundDenom = errorsmod.Register(ModuleName, 25, "deposit denom does not match the current fees_per_block denom") + ErrFeePoolSweepFailed = errorsmod.Register(ModuleName, 26, "consumer fee pool sweep failed") ) diff --git a/x/vaas/provider/types/events.go b/x/vaas/provider/types/events.go index 3d66360..6d76b2a 100644 --- a/x/vaas/provider/types/events.go +++ b/x/vaas/provider/types/events.go @@ -8,6 +8,9 @@ const ( EventTypeCreateConsumer = "create_consumer" EventTypeUpdateConsumer = "update_consumer" EventTypeRemoveConsumer = "remove_consumer" + EventTypeConsumerFeePoolFund = "consumer_fee_pool_fund" + EventTypeConsumerFeePoolWithdraw = "consumer_fee_pool_withdraw" + EventTypeConsumerFeePoolSweep = "consumer_fee_pool_sweep" AttributeInfractionHeight = "infraction_height" AttributeInitialHeight = "initial_height" @@ -23,4 +26,10 @@ const ( AttributeConsumerOwner = "consumer_owner" AttributeConsumerSpawnTime = "consumer_spawn_time" AttributeConsumerPhase = "consumer_phase" + AttributeDepositor = "depositor" + AttributeRecipient = "recipient" + AttributeAmount = "amount" + AttributeDenom = "denom" + AttributeTotalDistributed = "total_distributed" + AttributeDust = "dust" ) diff --git a/x/vaas/provider/types/genesis.pb.go b/x/vaas/provider/types/genesis.pb.go index c9341c3..d5d71fa 100644 --- a/x/vaas/provider/types/genesis.pb.go +++ b/x/vaas/provider/types/genesis.pb.go @@ -4,8 +4,11 @@ package types import ( + cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" types "github.com/allinbits/vaas/x/vaas/types" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" @@ -43,6 +46,8 @@ type GenesisState struct { ValidatorsByConsumerAddr []ValidatorByConsumerAddr `protobuf:"bytes,6,rep,name=validators_by_consumer_addr,json=validatorsByConsumerAddr,proto3" json:"validators_by_consumer_addr"` // empty for a new chain ConsumerAddrsToPrune []ConsumerAddrsToPrune `protobuf:"bytes,7,rep,name=consumer_addrs_to_prune,json=consumerAddrsToPrune,proto3" json:"consumer_addrs_to_prune"` + // empty for a new chain + ConsumerFeePoolShares []ConsumerFeePoolShare `protobuf:"bytes,8,rep,name=consumer_fee_pool_shares,json=consumerFeePoolShares,proto3" json:"consumer_fee_pool_shares"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -127,6 +132,13 @@ func (m *GenesisState) GetConsumerAddrsToPrune() []ConsumerAddrsToPrune { return nil } +func (m *GenesisState) GetConsumerFeePoolShares() []ConsumerFeePoolShare { + if m != nil { + return m.ConsumerFeePoolShares + } + return nil +} + // The provider VAAS module's knowledge of consumer state. // // Note this type is only used internally to the provider VAAS module. @@ -339,66 +351,141 @@ func (m *ValsetUpdateIdToHeight) GetHeight() uint64 { return 0 } +// ConsumerFeePoolShare is a single depositor's share holding in a consumer +// fee pool, scoped to one denom. The triple (consumer_id, depositor, denom) +// is unique. +type ConsumerFeePoolShare struct { + ConsumerId string `protobuf:"bytes,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + Depositor string `protobuf:"bytes,2,opt,name=depositor,proto3" json:"depositor,omitempty"` + Denom string `protobuf:"bytes,3,opt,name=denom,proto3" json:"denom,omitempty"` + Shares cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=shares,proto3,customtype=cosmossdk.io/math.Int" json:"shares"` +} + +func (m *ConsumerFeePoolShare) Reset() { *m = ConsumerFeePoolShare{} } +func (m *ConsumerFeePoolShare) String() string { return proto.CompactTextString(m) } +func (*ConsumerFeePoolShare) ProtoMessage() {} +func (*ConsumerFeePoolShare) Descriptor() ([]byte, []int) { + return fileDescriptor_c9071b84cde652f9, []int{3} +} +func (m *ConsumerFeePoolShare) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConsumerFeePoolShare) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConsumerFeePoolShare.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ConsumerFeePoolShare) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsumerFeePoolShare.Merge(m, src) +} +func (m *ConsumerFeePoolShare) XXX_Size() int { + return m.Size() +} +func (m *ConsumerFeePoolShare) XXX_DiscardUnknown() { + xxx_messageInfo_ConsumerFeePoolShare.DiscardUnknown(m) +} + +var xxx_messageInfo_ConsumerFeePoolShare proto.InternalMessageInfo + +func (m *ConsumerFeePoolShare) GetConsumerId() string { + if m != nil { + return m.ConsumerId + } + return "" +} + +func (m *ConsumerFeePoolShare) GetDepositor() string { + if m != nil { + return m.Depositor + } + return "" +} + +func (m *ConsumerFeePoolShare) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + func init() { proto.RegisterType((*GenesisState)(nil), "vaas.provider.v1.GenesisState") proto.RegisterType((*ConsumerState)(nil), "vaas.provider.v1.ConsumerState") proto.RegisterType((*ValsetUpdateIdToHeight)(nil), "vaas.provider.v1.ValsetUpdateIdToHeight") + proto.RegisterType((*ConsumerFeePoolShare)(nil), "vaas.provider.v1.ConsumerFeePoolShare") } func init() { proto.RegisterFile("vaas/provider/v1/genesis.proto", fileDescriptor_c9071b84cde652f9) } var fileDescriptor_c9071b84cde652f9 = []byte{ - // 795 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcd, 0x6e, 0xeb, 0x44, - 0x18, 0x8d, 0xdb, 0x24, 0x37, 0x99, 0xa4, 0x21, 0x1a, 0x5d, 0x05, 0x93, 0xab, 0xeb, 0x44, 0x41, - 0x17, 0x05, 0x09, 0xd9, 0x6a, 0x11, 0x2c, 0x58, 0x20, 0x35, 0xad, 0x04, 0x11, 0x02, 0x45, 0x6e, - 0x61, 0xd1, 0x8d, 0x35, 0xf1, 0x0c, 0xf6, 0x10, 0xdb, 0x63, 0x79, 0x26, 0x2e, 0xe1, 0x11, 0x58, - 0xf5, 0x29, 0x78, 0x96, 0x2e, 0xbb, 0x64, 0x55, 0x50, 0xfb, 0x06, 0x3c, 0x01, 0x9a, 0xf1, 0xd8, - 0x34, 0x4d, 0x0a, 0x62, 0x67, 0x7f, 0xe7, 0xcc, 0x39, 0xdf, 0xcc, 0xf7, 0x03, 0xac, 0x1c, 0x21, - 0xee, 0xa4, 0x19, 0xcb, 0x29, 0x26, 0x99, 0x93, 0x1f, 0x3b, 0x01, 0x49, 0x08, 0xa7, 0xdc, 0x4e, - 0x33, 0x26, 0x18, 0xec, 0x4b, 0xdc, 0x2e, 0x71, 0x3b, 0x3f, 0x1e, 0xbe, 0x0e, 0x58, 0xc0, 0x14, - 0xe8, 0xc8, 0xaf, 0x82, 0x37, 0x1c, 0x05, 0x8c, 0x05, 0x11, 0x71, 0xd4, 0xdf, 0x72, 0xfd, 0xa3, - 0x23, 0x68, 0x4c, 0xb8, 0x40, 0x71, 0xaa, 0x09, 0x6f, 0x95, 0x51, 0x7e, 0xec, 0xf0, 0x10, 0x65, - 0x04, 0x7b, 0x3e, 0x4b, 0xf8, 0x3a, 0x26, 0x99, 0x86, 0x61, 0x09, 0x5f, 0xd3, 0x8c, 0x94, 0x9a, - 0x3b, 0xb9, 0x55, 0x79, 0x28, 0xc2, 0xe4, 0xd7, 0x06, 0xe8, 0x7e, 0x55, 0xa4, 0x7b, 0x21, 0x90, - 0x20, 0x70, 0x0a, 0xfa, 0x39, 0x8a, 0x38, 0x11, 0xde, 0x3a, 0xc5, 0x48, 0x10, 0x8f, 0x62, 0xd3, - 0x18, 0x1b, 0xd3, 0xba, 0xdb, 0x2b, 0xe2, 0xdf, 0xab, 0xf0, 0x1c, 0xc3, 0x10, 0xbc, 0x57, 0x66, - 0xe0, 0x71, 0x79, 0x96, 0x9b, 0x07, 0xe3, 0xc3, 0x69, 0xe7, 0x64, 0x64, 0x3f, 0xbf, 0xb1, 0x7d, - 0xa6, 0x89, 0xca, 0x63, 0x66, 0xdd, 0xde, 0x8f, 0x6a, 0x7f, 0xdd, 0x8f, 0x06, 0x1b, 0x14, 0x47, - 0x5f, 0x4c, 0x9e, 0xa9, 0x4c, 0xdc, 0x9e, 0xff, 0x94, 0xce, 0xe1, 0x4f, 0x60, 0xf8, 0x3c, 0x27, - 0x4f, 0x30, 0x2f, 0x24, 0x34, 0x08, 0x85, 0x79, 0xa8, 0x4c, 0xa7, 0xbb, 0xa6, 0x3f, 0x6c, 0xe5, - 0x7b, 0xc9, 0xbe, 0x56, 0xfc, 0x59, 0x5d, 0xba, 0xbb, 0x83, 0x7c, 0x2f, 0x0a, 0x3f, 0x07, 0xcd, - 0x14, 0x65, 0x28, 0xe6, 0x66, 0x7d, 0x6c, 0x4c, 0x3b, 0x27, 0xe6, 0xae, 0xee, 0x42, 0xe1, 0x5a, - 0x47, 0xb3, 0x61, 0xac, 0x72, 0xa4, 0x18, 0x09, 0x96, 0x55, 0x95, 0xf1, 0xd2, 0xf5, 0x72, 0x45, - 0x36, 0xdc, 0x6c, 0xa8, 0x1c, 0x3f, 0xde, 0x9b, 0x63, 0x71, 0xa6, 0x7c, 0xa1, 0xc5, 0x7a, 0xf9, - 0x0d, 0xd9, 0x68, 0x71, 0x33, 0xdf, 0x03, 0x4b, 0x41, 0x98, 0x80, 0x37, 0x15, 0xc6, 0xbd, 0xe5, - 0xe6, 0x1f, 0x4b, 0x84, 0x71, 0x66, 0x36, 0xff, 0xd3, 0x6f, 0xb6, 0x29, 0x25, 0x4f, 0x31, 0xce, - 0x76, 0xfc, 0xf8, 0x36, 0x0e, 0x7d, 0xf0, 0xfe, 0x96, 0x03, 0x97, 0x05, 0x48, 0xb3, 0x75, 0x42, - 0xcc, 0x57, 0xca, 0xeb, 0xa3, 0x97, 0x8b, 0x2e, 0x05, 0xf8, 0x25, 0x5b, 0x48, 0xb6, 0x36, 0x7a, - 0xed, 0xef, 0xc1, 0x26, 0xbf, 0x35, 0xc0, 0xd1, 0x56, 0xa7, 0xc0, 0x11, 0xe8, 0x54, 0xb6, 0x55, - 0x23, 0x82, 0x32, 0x34, 0xc7, 0xf0, 0x03, 0xd0, 0xf2, 0x43, 0x44, 0x13, 0x89, 0x1e, 0x8c, 0x8d, - 0x69, 0xdb, 0x7d, 0xa5, 0xfe, 0xe7, 0x18, 0xbe, 0x01, 0x6d, 0x3f, 0xa2, 0x24, 0x11, 0x12, 0x3b, - 0x54, 0x58, 0xab, 0x08, 0xcc, 0x31, 0x7c, 0x07, 0x7a, 0x34, 0xa1, 0x82, 0xa2, 0xa8, 0x6c, 0xa3, - 0xba, 0xd2, 0x3e, 0xd2, 0x51, 0xdd, 0x0d, 0xdf, 0x81, 0x7e, 0xe5, 0xaf, 0xa7, 0xda, 0x6c, 0xa8, - 0xbe, 0x78, 0x5b, 0xdc, 0xf7, 0xc9, 0x35, 0x9f, 0x8e, 0x91, 0xbe, 0x66, 0x35, 0x20, 0x1a, 0x83, - 0x08, 0x0c, 0x52, 0x92, 0x60, 0x9a, 0x04, 0x9e, 0xee, 0x68, 0x3f, 0x44, 0x49, 0x40, 0xb8, 0xae, - 0xd8, 0xbb, 0x4a, 0xb5, 0x2a, 0xd4, 0x05, 0x11, 0x67, 0x8a, 0xb3, 0x40, 0xfe, 0x8a, 0x88, 0x73, - 0x24, 0x50, 0xf9, 0x88, 0x5a, 0xaa, 0xe8, 0xf3, 0x82, 0xc4, 0xe1, 0x27, 0x00, 0xf2, 0x08, 0xf1, - 0xd0, 0xc3, 0xec, 0x3a, 0x91, 0x2b, 0xc4, 0x43, 0xfe, 0x4a, 0x15, 0xa9, 0xed, 0xf6, 0x15, 0x72, - 0xae, 0x81, 0x53, 0x7f, 0x05, 0x3f, 0x03, 0x8d, 0x34, 0x44, 0x9c, 0x98, 0xad, 0xb1, 0x31, 0xed, - 0xfd, 0xdb, 0xe8, 0x2e, 0x24, 0xcd, 0x2d, 0xd8, 0xf0, 0x43, 0x70, 0xc4, 0xae, 0x13, 0xdd, 0x0b, - 0x84, 0x73, 0xb3, 0xad, 0xde, 0xb7, 0xab, 0x82, 0xa7, 0x45, 0x0c, 0x7e, 0x09, 0x5a, 0x31, 0x11, - 0x08, 0x23, 0x81, 0x4c, 0xa0, 0x1e, 0x6d, 0xf2, 0xb2, 0xfc, 0xb7, 0x9a, 0xe9, 0x56, 0x67, 0xe0, - 0x05, 0xe8, 0xc8, 0x6a, 0x78, 0x7a, 0x1e, 0x3b, 0x4a, 0xe2, 0xe4, 0x65, 0x89, 0x79, 0x51, 0x3a, - 0xfa, 0x0b, 0x12, 0x94, 0x25, 0x6a, 0x4a, 0x89, 0x20, 0x19, 0x77, 0x81, 0x94, 0x29, 0xa6, 0x16, - 0x9e, 0x81, 0x6e, 0x46, 0x62, 0x96, 0xa3, 0xc8, 0x93, 0x6f, 0x60, 0x76, 0x95, 0xea, 0xd0, 0x2e, - 0x96, 0xaf, 0x5d, 0x2e, 0x5f, 0xfb, 0xb2, 0x5c, 0xbe, 0xb3, 0xfa, 0xcd, 0x1f, 0x23, 0xc3, 0xed, - 0xe8, 0x53, 0x32, 0x3e, 0xb9, 0x02, 0x83, 0xfd, 0xcb, 0xe5, 0x7f, 0xac, 0xcf, 0x01, 0x68, 0xea, - 0xce, 0x3b, 0x50, 0xb8, 0xfe, 0x9b, 0xcd, 0x6f, 0x1f, 0x2c, 0xe3, 0xee, 0xc1, 0x32, 0xfe, 0x7c, - 0xb0, 0x8c, 0x9b, 0x47, 0xab, 0x76, 0xf7, 0x68, 0xd5, 0x7e, 0x7f, 0xb4, 0x6a, 0x57, 0x4e, 0x40, - 0x45, 0xb8, 0x5e, 0xda, 0x3e, 0x8b, 0x1d, 0x14, 0x45, 0x34, 0x59, 0x52, 0xc1, 0x1d, 0xb5, 0xe1, - 0x7f, 0x76, 0xb6, 0x17, 0xbd, 0xd8, 0xa4, 0x84, 0x2f, 0x9b, 0xea, 0x36, 0x9f, 0xfe, 0x1d, 0x00, - 0x00, 0xff, 0xff, 0x5e, 0xf7, 0x5c, 0x97, 0xa2, 0x06, 0x00, 0x00, + // 956 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xd1, 0x6e, 0xdb, 0x36, + 0x17, 0x8e, 0x12, 0x3b, 0xb5, 0xe9, 0x24, 0x7f, 0x40, 0xb8, 0xfe, 0xd5, 0x14, 0xb5, 0x0d, 0x0f, + 0x1d, 0x3c, 0x6c, 0x95, 0xe0, 0x0c, 0xeb, 0xc5, 0x2e, 0x06, 0xc4, 0x29, 0xb6, 0x19, 0xc3, 0x06, + 0x43, 0xce, 0x76, 0xd1, 0x1b, 0x81, 0x16, 0x59, 0x89, 0xb3, 0x44, 0x0a, 0x22, 0xad, 0xcc, 0x7b, + 0x8a, 0x3e, 0xc5, 0x9e, 0xa0, 0x0f, 0x51, 0xec, 0xaa, 0xe8, 0xd5, 0xb0, 0x8b, 0x6c, 0x48, 0x9e, + 0x60, 0x7b, 0x82, 0x41, 0x24, 0xa5, 0xc6, 0x89, 0xb3, 0x62, 0x77, 0xe2, 0xf9, 0x3e, 0x7e, 0xdf, + 0xa1, 0xce, 0x39, 0x24, 0xe8, 0xe6, 0x08, 0x09, 0x37, 0xcd, 0x78, 0x4e, 0x31, 0xc9, 0xdc, 0x7c, + 0xe4, 0x86, 0x84, 0x11, 0x41, 0x85, 0x93, 0x66, 0x5c, 0x72, 0x78, 0x58, 0xe0, 0x4e, 0x89, 0x3b, + 0xf9, 0xe8, 0xa8, 0x1d, 0xf2, 0x90, 0x2b, 0xd0, 0x2d, 0xbe, 0x34, 0xef, 0xa8, 0x17, 0x72, 0x1e, + 0xc6, 0xc4, 0x55, 0xab, 0xf9, 0xf2, 0x85, 0x2b, 0x69, 0x42, 0x84, 0x44, 0x49, 0x6a, 0x08, 0x0f, + 0x02, 0x2e, 0x12, 0x2e, 0x7c, 0xbd, 0x53, 0x2f, 0x0c, 0xd4, 0xd5, 0x2b, 0x77, 0x8e, 0x04, 0x71, + 0xf3, 0xd1, 0x9c, 0x48, 0x34, 0x72, 0x03, 0x4e, 0x99, 0xc1, 0x1f, 0xa9, 0x1c, 0xf3, 0x91, 0x2b, + 0x22, 0x94, 0x11, 0xec, 0x07, 0x9c, 0x89, 0x65, 0x42, 0x32, 0x03, 0xc3, 0x12, 0x3e, 0xa7, 0x19, + 0x29, 0xd3, 0xb9, 0x75, 0xac, 0xea, 0x08, 0x8a, 0x30, 0xf8, 0xab, 0x0e, 0xf6, 0xbe, 0xd2, 0x27, + 0x9d, 0x49, 0x24, 0x09, 0x1c, 0x82, 0xc3, 0x1c, 0xc5, 0x82, 0x48, 0x7f, 0x99, 0x62, 0x24, 0x89, + 0x4f, 0xb1, 0x6d, 0xf5, 0xad, 0x61, 0xcd, 0x3b, 0xd0, 0xf1, 0xef, 0x55, 0x78, 0x82, 0x61, 0x04, + 0xfe, 0x57, 0x66, 0xe0, 0x8b, 0x62, 0xaf, 0xb0, 0xb7, 0xfb, 0x3b, 0xc3, 0xd6, 0x71, 0xcf, 0xb9, + 0xf9, 0xb3, 0x9c, 0x53, 0x43, 0x54, 0x1e, 0xe3, 0xee, 0xeb, 0x8b, 0xde, 0xd6, 0xdf, 0x17, 0xbd, + 0xce, 0x0a, 0x25, 0xf1, 0xe7, 0x83, 0x1b, 0x2a, 0x03, 0xef, 0x20, 0xb8, 0x4e, 0x17, 0xf0, 0x47, + 0x70, 0x74, 0x33, 0x27, 0x5f, 0x72, 0x3f, 0x22, 0x34, 0x8c, 0xa4, 0xbd, 0xa3, 0x4c, 0x87, 0xb7, + 0x4d, 0x7f, 0x58, 0xcb, 0xf7, 0x8c, 0x7f, 0xad, 0xf8, 0xe3, 0x5a, 0xe1, 0xee, 0x75, 0xf2, 0x8d, + 0x28, 0x7c, 0x0a, 0x76, 0x53, 0x94, 0xa1, 0x44, 0xd8, 0xb5, 0xbe, 0x35, 0x6c, 0x1d, 0xdb, 0xb7, + 0x75, 0xa7, 0x0a, 0x37, 0x3a, 0x86, 0x0d, 0x13, 0x95, 0x23, 0xc5, 0x48, 0xf2, 0xac, 0xaa, 0x8c, + 0x9f, 0x2e, 0xe7, 0x0b, 0xb2, 0x12, 0x76, 0x5d, 0xe5, 0xf8, 0xd1, 0xc6, 0x1c, 0xf5, 0x9e, 0xf2, + 0x0f, 0x4d, 0x97, 0xf3, 0x6f, 0xc8, 0xca, 0x88, 0xdb, 0xf9, 0x06, 0xb8, 0x10, 0x84, 0x0c, 0x3c, + 0xac, 0x30, 0xe1, 0xcf, 0x57, 0xef, 0x2c, 0x11, 0xc6, 0x99, 0xbd, 0xfb, 0x5e, 0xbf, 0xf1, 0xaa, + 0x94, 0x3c, 0xc1, 0x38, 0xbb, 0xe5, 0x27, 0xd6, 0x71, 0x18, 0x80, 0xff, 0xaf, 0x39, 0x88, 0xa2, + 0x00, 0x69, 0xb6, 0x64, 0xc4, 0xbe, 0xa7, 0xbc, 0x3e, 0xbc, 0xbb, 0xe8, 0x85, 0x80, 0x38, 0xe3, + 0xd3, 0x82, 0x6d, 0x8c, 0xda, 0xc1, 0x06, 0x0c, 0x12, 0x60, 0x57, 0x26, 0x2f, 0x08, 0xf1, 0x53, + 0xce, 0x63, 0x5f, 0x35, 0xbb, 0xb0, 0x1b, 0xef, 0x73, 0xf9, 0x92, 0x90, 0x29, 0xe7, 0xf1, 0xac, + 0xa0, 0x1b, 0x97, 0xfb, 0xc1, 0x06, 0x4c, 0x0c, 0x7e, 0xa9, 0x83, 0xfd, 0xb5, 0x86, 0x84, 0x3d, + 0xd0, 0xaa, 0x8c, 0xab, 0x7e, 0x07, 0x65, 0x68, 0x82, 0xe1, 0x03, 0xd0, 0x08, 0x22, 0x44, 0x59, + 0x81, 0x6e, 0xf7, 0xad, 0x61, 0xd3, 0xbb, 0xa7, 0xd6, 0x13, 0x0c, 0x1f, 0x82, 0x66, 0x10, 0x53, + 0xc2, 0x64, 0x81, 0xed, 0x28, 0xac, 0xa1, 0x03, 0x13, 0x0c, 0x1f, 0x83, 0x03, 0xca, 0xa8, 0xa4, + 0x28, 0x2e, 0xbb, 0xb5, 0xa6, 0xb4, 0xf7, 0x4d, 0xd4, 0x34, 0xdd, 0x77, 0xe0, 0xb0, 0xf2, 0x37, + 0xf7, 0x8e, 0x5d, 0x57, 0xed, 0xf7, 0x48, 0x1f, 0xf8, 0xda, 0x39, 0xaf, 0x4f, 0xab, 0x39, 0x67, + 0x35, 0x87, 0x06, 0x83, 0x08, 0x74, 0x52, 0xc2, 0x30, 0x65, 0xa1, 0x6f, 0x06, 0x27, 0x88, 0x10, + 0x0b, 0x89, 0x30, 0x8d, 0xf1, 0xb8, 0x52, 0xad, 0xfa, 0x61, 0x46, 0xe4, 0xa9, 0xe2, 0x4c, 0x51, + 0xb0, 0x20, 0xf2, 0x19, 0x92, 0xa8, 0xac, 0x95, 0x91, 0xd2, 0xe3, 0xa4, 0x49, 0x02, 0x7e, 0x02, + 0xa0, 0x88, 0x91, 0x88, 0x7c, 0xcc, 0xcf, 0x59, 0x71, 0xc9, 0xf9, 0x28, 0x58, 0xa8, 0x5e, 0x68, + 0x7a, 0x87, 0x0a, 0x79, 0x66, 0x80, 0x93, 0x60, 0x01, 0x3f, 0x03, 0xf5, 0x34, 0x42, 0x82, 0xd8, + 0x8d, 0xbe, 0x35, 0x3c, 0xf8, 0xb7, 0x1b, 0x62, 0x5a, 0xd0, 0x3c, 0xcd, 0x86, 0x1f, 0x80, 0x7d, + 0x7e, 0xce, 0x4c, 0xcb, 0x11, 0x21, 0xec, 0xa6, 0xfa, 0xbf, 0x7b, 0x2a, 0x78, 0xa2, 0x63, 0xf0, + 0x0b, 0xd0, 0x48, 0x88, 0x44, 0x18, 0x49, 0x64, 0x03, 0xf5, 0xd3, 0x06, 0x77, 0xcb, 0x7f, 0x6b, + 0x98, 0x5e, 0xb5, 0x07, 0xce, 0x40, 0xab, 0xa8, 0x86, 0x6f, 0xc6, 0xbe, 0xa5, 0x24, 0x8e, 0xef, + 0x96, 0x98, 0xe8, 0xd2, 0xd1, 0x9f, 0x91, 0xa4, 0x9c, 0xa9, 0xcb, 0x80, 0x48, 0x92, 0x09, 0x0f, + 0x14, 0x32, 0xfa, 0x72, 0x80, 0xa7, 0x60, 0x2f, 0x23, 0x09, 0xcf, 0x51, 0xec, 0x17, 0xff, 0xc0, + 0xde, 0x53, 0xaa, 0x47, 0x8e, 0x7e, 0x1e, 0x9c, 0xf2, 0x79, 0x70, 0xce, 0xca, 0xe7, 0x61, 0x5c, + 0x7b, 0xf9, 0x47, 0xcf, 0xf2, 0x5a, 0x66, 0x57, 0x11, 0x1f, 0x3c, 0x07, 0x9d, 0xcd, 0x77, 0xd8, + 0x7f, 0xb8, 0xa5, 0x3b, 0x60, 0xd7, 0x74, 0xde, 0xb6, 0xc2, 0xcd, 0x6a, 0xf0, 0xab, 0x05, 0xda, + 0x9b, 0x46, 0x67, 0xd3, 0x2c, 0x34, 0xd7, 0x66, 0xe1, 0x29, 0x68, 0x62, 0x92, 0x72, 0x41, 0x25, + 0xcf, 0xf4, 0x30, 0x8c, 0xed, 0xb7, 0xaf, 0x9e, 0xb4, 0xcd, 0x5b, 0x66, 0xca, 0x32, 0x93, 0x19, + 0x65, 0xa1, 0xf7, 0x8e, 0x0a, 0xdb, 0xa0, 0x8e, 0x09, 0xe3, 0x89, 0x19, 0x12, 0xbd, 0x80, 0xa7, + 0x60, 0xd7, 0x4c, 0x78, 0x4d, 0x49, 0x7d, 0x5c, 0xf4, 0xdc, 0xef, 0x17, 0xbd, 0xfb, 0x5a, 0x4e, + 0xe0, 0x85, 0x43, 0xb9, 0x9b, 0x20, 0x19, 0x39, 0x13, 0x26, 0xdf, 0xbe, 0x7a, 0x02, 0x8c, 0xcf, + 0x84, 0x49, 0xcf, 0x6c, 0x1d, 0x4f, 0x5e, 0x5f, 0x76, 0xad, 0x37, 0x97, 0x5d, 0xeb, 0xcf, 0xcb, + 0xae, 0xf5, 0xf2, 0xaa, 0xbb, 0xf5, 0xe6, 0xaa, 0xbb, 0xf5, 0xdb, 0x55, 0x77, 0xeb, 0xb9, 0x1b, + 0x52, 0x19, 0x2d, 0xe7, 0x4e, 0xc0, 0x13, 0x17, 0xc5, 0x31, 0x65, 0x73, 0x2a, 0x85, 0xab, 0x5e, + 0xc5, 0x9f, 0xdc, 0xf5, 0xc7, 0x51, 0xae, 0x52, 0x22, 0xe6, 0xbb, 0xaa, 0x34, 0x9f, 0xfe, 0x13, + 0x00, 0x00, 0xff, 0xff, 0x51, 0x56, 0x9f, 0xcf, 0x11, 0x08, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -421,6 +508,20 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ConsumerFeePoolShares) > 0 { + for iNdEx := len(m.ConsumerFeePoolShares) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ConsumerFeePoolShares[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } if len(m.ConsumerAddrsToPrune) > 0 { for iNdEx := len(m.ConsumerAddrsToPrune) - 1; iNdEx >= 0; iNdEx-- { { @@ -668,6 +769,60 @@ func (m *ValsetUpdateIdToHeight) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *ConsumerFeePoolShare) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ConsumerFeePoolShare) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsumerFeePoolShare) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Shares.Size() + i -= size + if _, err := m.Shares.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x1a + } + if len(m.Depositor) > 0 { + i -= len(m.Depositor) + copy(dAtA[i:], m.Depositor) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Depositor))) + i-- + dAtA[i] = 0x12 + } + if len(m.ConsumerId) > 0 { + i -= len(m.ConsumerId) + copy(dAtA[i:], m.ConsumerId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ConsumerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { offset -= sovGenesis(v) base := offset @@ -720,6 +875,12 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.ConsumerFeePoolShares) > 0 { + for _, e := range m.ConsumerFeePoolShares { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -794,6 +955,29 @@ func (m *ValsetUpdateIdToHeight) Size() (n int) { return n } +func (m *ConsumerFeePoolShare) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ConsumerId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Depositor) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.Shares.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + func sovGenesis(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1051,6 +1235,40 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerFeePoolShares", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerFeePoolShares = append(m.ConsumerFeePoolShares, ConsumerFeePoolShare{}) + if err := m.ConsumerFeePoolShares[len(m.ConsumerFeePoolShares)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) @@ -1570,6 +1788,186 @@ func (m *ValsetUpdateIdToHeight) Unmarshal(dAtA []byte) error { } return nil } +func (m *ConsumerFeePoolShare) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ConsumerFeePoolShare: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConsumerFeePoolShare: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Depositor = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Shares", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Shares.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipGenesis(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/vaas/provider/types/keys.go b/x/vaas/provider/types/keys.go index 5fcda22..d3a7a37 100644 --- a/x/vaas/provider/types/keys.go +++ b/x/vaas/provider/types/keys.go @@ -80,6 +80,10 @@ const ( InfractionScheduledTimeToConsumerIdsKeyName = "InfractionScheduledTimeToConsumerIdsKeyName" ConsumerIdToDebtKeyName = "ConsumerIdToDebtKeyName" + + ConsumerFeePoolSharesKeyName = "ConsumerFeePoolSharesKey" + ConsumerFeePoolTotalSharesKeyName = "ConsumerFeePoolTotalSharesKey" + FeePoolAddressToConsumerIdKeyName = "FeePoolAddressToConsumerIdKey" ) // Collection key prefixes for use with cosmossdk.io/collections @@ -110,5 +114,8 @@ var ( ConsumerIdToQueuedInfractionPrefix = collections.NewPrefix(23) InfractionScheduledTimePrefix = collections.NewPrefix(24) ConsumerIdToDebtPrefix = collections.NewPrefix(25) + ConsumerFeePoolSharesKeyPrefix = collections.NewPrefix(26) + ConsumerFeePoolTotalSharesKeyPrefix = collections.NewPrefix(27) + FeePoolAddressToConsumerIdKeyPrefix = collections.NewPrefix(28) ParametersPrefix = collections.NewPrefix(0xFF) ) diff --git a/x/vaas/provider/types/msg.go b/x/vaas/provider/types/msg.go index 736b4c4..62c39fc 100644 --- a/x/vaas/provider/types/msg.go +++ b/x/vaas/provider/types/msg.go @@ -17,6 +17,7 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -39,6 +40,9 @@ var ( _ sdk.Msg = (*MsgCreateConsumer)(nil) _ sdk.Msg = (*MsgUpdateConsumer)(nil) _ sdk.Msg = (*MsgRemoveConsumer)(nil) + _ sdk.Msg = (*MsgFundConsumerFeePool)(nil) + _ sdk.Msg = (*MsgWithdrawConsumerFeePool)(nil) + _ sdk.Msg = (*MsgSweepConsumerFeePool)(nil) _ sdk.HasValidateBasic = (*MsgAssignConsumerKey)(nil) _ sdk.HasValidateBasic = (*MsgSubmitConsumerMisbehaviour)(nil) @@ -46,6 +50,9 @@ var ( _ sdk.HasValidateBasic = (*MsgCreateConsumer)(nil) _ sdk.HasValidateBasic = (*MsgUpdateConsumer)(nil) _ sdk.HasValidateBasic = (*MsgRemoveConsumer)(nil) + _ sdk.HasValidateBasic = (*MsgFundConsumerFeePool)(nil) + _ sdk.HasValidateBasic = (*MsgWithdrawConsumerFeePool)(nil) + _ sdk.HasValidateBasic = (*MsgSweepConsumerFeePool)(nil) ) // NewMsgAssignConsumerKey creates a new MsgAssignConsumerKey instance. @@ -418,3 +425,56 @@ func ValidateInitialHeight(initialHeight clienttypes.Height, chainID string) err } return nil } + +// ValidateBasic implements the sdk.HasValidateBasic interface. +func (msg MsgFundConsumerFeePool) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid signer: %s", err) + } + if strings.TrimSpace(msg.ConsumerId) == "" { + return errorsmod.Wrap(ErrNoConsumerId, "consumer_id must not be empty") + } + if err := msg.Amount.Validate(); err != nil { + return errorsmod.Wrapf(ErrInvalidFundDenom, "invalid amount: %s", err) + } + if !msg.Amount.IsPositive() { + return errorsmod.Wrap(ErrInvalidFundDenom, "amount must be positive") + } + return nil +} + +// ValidateBasic implements the sdk.HasValidateBasic interface. +func (msg MsgWithdrawConsumerFeePool) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid signer: %s", err) + } + if strings.TrimSpace(msg.ConsumerId) == "" { + return errorsmod.Wrap(ErrNoConsumerId, "consumer_id must not be empty") + } + if len(msg.Amount) == 0 { + return errorsmod.Wrap(ErrInvalidFundDenom, "amount must not be empty") + } + if err := msg.Amount.Validate(); err != nil { + return errorsmod.Wrapf(ErrInvalidFundDenom, "invalid amount: %s", err) + } + if !msg.Amount.IsAllPositive() { + return errorsmod.Wrap(ErrInvalidFundDenom, "amounts must be positive") + } + return nil +} + +// ValidateBasic implements the sdk.HasValidateBasic interface. +func (msg MsgSweepConsumerFeePool) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid signer: %s", err) + } + if strings.TrimSpace(msg.ConsumerId) == "" { + return errorsmod.Wrap(ErrNoConsumerId, "consumer_id must not be empty") + } + for _, d := range msg.Denoms { + if err := sdk.ValidateDenom(d); err != nil { + return errorsmod.Wrapf(ErrInvalidFundDenom, "invalid denom %q: %s", d, err) + } + } + return nil +} diff --git a/x/vaas/provider/types/msg_test.go b/x/vaas/provider/types/msg_test.go index a9ad1ab..d8bbc01 100644 --- a/x/vaas/provider/types/msg_test.go +++ b/x/vaas/provider/types/msg_test.go @@ -543,6 +543,146 @@ func TestValidateInitialHeight(t *testing.T) { } } +func TestMsgFundConsumerFeePool_ValidateBasic(t *testing.T) { + validSigner := sdk.AccAddress([]byte("alice___________")).String() + tests := []struct { + name string + msg types.MsgFundConsumerFeePool + wantErr bool + }{ + {"valid", types.MsgFundConsumerFeePool{ + Signer: validSigner, + ConsumerId: "0", + Amount: sdk.NewInt64Coin("uphoton", 100), + }, false}, + {"invalid signer", types.MsgFundConsumerFeePool{ + Signer: "not-bech32", + ConsumerId: "0", + Amount: sdk.NewInt64Coin("uphoton", 100), + }, true}, + {"empty consumer id", types.MsgFundConsumerFeePool{ + Signer: validSigner, + ConsumerId: "", + Amount: sdk.NewInt64Coin("uphoton", 100), + }, true}, + {"zero amount", types.MsgFundConsumerFeePool{ + Signer: validSigner, + ConsumerId: "0", + Amount: sdk.NewInt64Coin("uphoton", 0), + }, true}, + {"invalid denom", types.MsgFundConsumerFeePool{ + Signer: validSigner, + ConsumerId: "0", + Amount: sdk.Coin{Denom: "", Amount: math.NewInt(100)}, + }, true}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestMsgWithdrawConsumerFeePool_ValidateBasic(t *testing.T) { + validSigner := sdk.AccAddress([]byte("alice___________")).String() + tests := []struct { + name string + msg types.MsgWithdrawConsumerFeePool + wantErr bool + }{ + {"valid", types.MsgWithdrawConsumerFeePool{ + Signer: validSigner, + ConsumerId: "0", + Amount: sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), + }, false}, + {"invalid signer", types.MsgWithdrawConsumerFeePool{ + Signer: "not-bech32", + ConsumerId: "0", + Amount: sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), + }, true}, + {"empty consumer id", types.MsgWithdrawConsumerFeePool{ + Signer: validSigner, + ConsumerId: "", + Amount: sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), + }, true}, + {"empty coins", types.MsgWithdrawConsumerFeePool{ + Signer: validSigner, + ConsumerId: "0", + Amount: sdk.Coins{}, + }, true}, + {"coins with zero amount", types.MsgWithdrawConsumerFeePool{ + Signer: validSigner, + ConsumerId: "0", + Amount: sdk.Coins{sdk.NewInt64Coin("uphoton", 0)}, + }, true}, + {"coins with duplicate denom", types.MsgWithdrawConsumerFeePool{ + Signer: validSigner, + ConsumerId: "0", + Amount: sdk.Coins{sdk.NewInt64Coin("uphoton", 50), sdk.NewInt64Coin("uphoton", 50)}, + }, true}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestMsgSweepConsumerFeePool_ValidateBasic(t *testing.T) { + validSigner := sdk.AccAddress([]byte("alice___________")).String() + tests := []struct { + name string + msg types.MsgSweepConsumerFeePool + wantErr bool + }{ + {"valid with explicit denoms", types.MsgSweepConsumerFeePool{ + Signer: validSigner, + ConsumerId: "0", + Denoms: []string{"uphoton", "uatom"}, + }, false}, + {"valid with empty denoms", types.MsgSweepConsumerFeePool{ + Signer: validSigner, + ConsumerId: "0", + Denoms: []string{}, + }, false}, + {"invalid signer", types.MsgSweepConsumerFeePool{ + Signer: "not-bech32", + ConsumerId: "0", + Denoms: []string{"uphoton"}, + }, true}, + {"empty consumer id", types.MsgSweepConsumerFeePool{ + Signer: validSigner, + ConsumerId: "", + Denoms: []string{"uphoton"}, + }, true}, + {"invalid denom string", types.MsgSweepConsumerFeePool{ + Signer: validSigner, + ConsumerId: "0", + Denoms: []string{"INVALID DENOM WITH SPACES"}, + }, true}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + func TestValidateChainId(t *testing.T) { testCases := []struct { name string diff --git a/x/vaas/provider/types/query.pb.go b/x/vaas/provider/types/query.pb.go index 4447664..efcb9d8 100644 --- a/x/vaas/provider/types/query.pb.go +++ b/x/vaas/provider/types/query.pb.go @@ -10,6 +10,8 @@ import ( types "github.com/allinbits/vaas/x/vaas/types" crypto "github.com/cometbft/cometbft/proto/tendermint/crypto" _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types2 "github.com/cosmos/cosmos-sdk/types" query "github.com/cosmos/cosmos-sdk/types/query" types1 "github.com/cosmos/cosmos-sdk/x/staking/types" _ "github.com/cosmos/gogoproto/gogoproto" @@ -1361,6 +1363,261 @@ func (m *QueryConsumerGenesisTimeResponse) GetGenesisTime() time.Time { return time.Time{} } +type QueryConsumerFeePoolClaimRequest struct { + ConsumerId string `protobuf:"bytes,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + // bech32 address; if equal to the gov module authority, aliases to the + // distribution module account address + Depositor string `protobuf:"bytes,2,opt,name=depositor,proto3" json:"depositor,omitempty"` +} + +func (m *QueryConsumerFeePoolClaimRequest) Reset() { *m = QueryConsumerFeePoolClaimRequest{} } +func (m *QueryConsumerFeePoolClaimRequest) String() string { return proto.CompactTextString(m) } +func (*QueryConsumerFeePoolClaimRequest) ProtoMessage() {} +func (*QueryConsumerFeePoolClaimRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_71b3f55ed407aa51, []int{25} +} +func (m *QueryConsumerFeePoolClaimRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryConsumerFeePoolClaimRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryConsumerFeePoolClaimRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryConsumerFeePoolClaimRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryConsumerFeePoolClaimRequest.Merge(m, src) +} +func (m *QueryConsumerFeePoolClaimRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryConsumerFeePoolClaimRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryConsumerFeePoolClaimRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryConsumerFeePoolClaimRequest proto.InternalMessageInfo + +func (m *QueryConsumerFeePoolClaimRequest) GetConsumerId() string { + if m != nil { + return m.ConsumerId + } + return "" +} + +func (m *QueryConsumerFeePoolClaimRequest) GetDepositor() string { + if m != nil { + return m.Depositor + } + return "" +} + +type QueryConsumerFeePoolClaimResponse struct { + // claimable balance across all denoms; excludes zero-claim denoms + Claim github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=claim,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"claim"` +} + +func (m *QueryConsumerFeePoolClaimResponse) Reset() { *m = QueryConsumerFeePoolClaimResponse{} } +func (m *QueryConsumerFeePoolClaimResponse) String() string { return proto.CompactTextString(m) } +func (*QueryConsumerFeePoolClaimResponse) ProtoMessage() {} +func (*QueryConsumerFeePoolClaimResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_71b3f55ed407aa51, []int{26} +} +func (m *QueryConsumerFeePoolClaimResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryConsumerFeePoolClaimResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryConsumerFeePoolClaimResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryConsumerFeePoolClaimResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryConsumerFeePoolClaimResponse.Merge(m, src) +} +func (m *QueryConsumerFeePoolClaimResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryConsumerFeePoolClaimResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryConsumerFeePoolClaimResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryConsumerFeePoolClaimResponse proto.InternalMessageInfo + +func (m *QueryConsumerFeePoolClaimResponse) GetClaim() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Claim + } + return nil +} + +type DepositorClaim struct { + Depositor string `protobuf:"bytes,1,opt,name=depositor,proto3" json:"depositor,omitempty"` + Claim github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=claim,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"claim"` +} + +func (m *DepositorClaim) Reset() { *m = DepositorClaim{} } +func (m *DepositorClaim) String() string { return proto.CompactTextString(m) } +func (*DepositorClaim) ProtoMessage() {} +func (*DepositorClaim) Descriptor() ([]byte, []int) { + return fileDescriptor_71b3f55ed407aa51, []int{27} +} +func (m *DepositorClaim) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DepositorClaim) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DepositorClaim.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DepositorClaim) XXX_Merge(src proto.Message) { + xxx_messageInfo_DepositorClaim.Merge(m, src) +} +func (m *DepositorClaim) XXX_Size() int { + return m.Size() +} +func (m *DepositorClaim) XXX_DiscardUnknown() { + xxx_messageInfo_DepositorClaim.DiscardUnknown(m) +} + +var xxx_messageInfo_DepositorClaim proto.InternalMessageInfo + +func (m *DepositorClaim) GetDepositor() string { + if m != nil { + return m.Depositor + } + return "" +} + +func (m *DepositorClaim) GetClaim() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Claim + } + return nil +} + +type QueryConsumerFeePoolClaimsRequest struct { + ConsumerId string `protobuf:"bytes,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryConsumerFeePoolClaimsRequest) Reset() { *m = QueryConsumerFeePoolClaimsRequest{} } +func (m *QueryConsumerFeePoolClaimsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryConsumerFeePoolClaimsRequest) ProtoMessage() {} +func (*QueryConsumerFeePoolClaimsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_71b3f55ed407aa51, []int{28} +} +func (m *QueryConsumerFeePoolClaimsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryConsumerFeePoolClaimsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryConsumerFeePoolClaimsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryConsumerFeePoolClaimsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryConsumerFeePoolClaimsRequest.Merge(m, src) +} +func (m *QueryConsumerFeePoolClaimsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryConsumerFeePoolClaimsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryConsumerFeePoolClaimsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryConsumerFeePoolClaimsRequest proto.InternalMessageInfo + +func (m *QueryConsumerFeePoolClaimsRequest) GetConsumerId() string { + if m != nil { + return m.ConsumerId + } + return "" +} + +func (m *QueryConsumerFeePoolClaimsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +type QueryConsumerFeePoolClaimsResponse struct { + Claims []DepositorClaim `protobuf:"bytes,1,rep,name=claims,proto3" json:"claims"` + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryConsumerFeePoolClaimsResponse) Reset() { *m = QueryConsumerFeePoolClaimsResponse{} } +func (m *QueryConsumerFeePoolClaimsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryConsumerFeePoolClaimsResponse) ProtoMessage() {} +func (*QueryConsumerFeePoolClaimsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_71b3f55ed407aa51, []int{29} +} +func (m *QueryConsumerFeePoolClaimsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryConsumerFeePoolClaimsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryConsumerFeePoolClaimsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryConsumerFeePoolClaimsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryConsumerFeePoolClaimsResponse.Merge(m, src) +} +func (m *QueryConsumerFeePoolClaimsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryConsumerFeePoolClaimsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryConsumerFeePoolClaimsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryConsumerFeePoolClaimsResponse proto.InternalMessageInfo + +func (m *QueryConsumerFeePoolClaimsResponse) GetClaims() []DepositorClaim { + if m != nil { + return m.Claims + } + return nil +} + +func (m *QueryConsumerFeePoolClaimsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + func init() { proto.RegisterType((*QueryConsumerGenesisRequest)(nil), "vaas.provider.v1.QueryConsumerGenesisRequest") proto.RegisterType((*QueryConsumerGenesisResponse)(nil), "vaas.provider.v1.QueryConsumerGenesisResponse") @@ -1387,125 +1644,145 @@ func init() { proto.RegisterType((*QueryConsumerChainResponse)(nil), "vaas.provider.v1.QueryConsumerChainResponse") proto.RegisterType((*QueryConsumerGenesisTimeRequest)(nil), "vaas.provider.v1.QueryConsumerGenesisTimeRequest") proto.RegisterType((*QueryConsumerGenesisTimeResponse)(nil), "vaas.provider.v1.QueryConsumerGenesisTimeResponse") + proto.RegisterType((*QueryConsumerFeePoolClaimRequest)(nil), "vaas.provider.v1.QueryConsumerFeePoolClaimRequest") + proto.RegisterType((*QueryConsumerFeePoolClaimResponse)(nil), "vaas.provider.v1.QueryConsumerFeePoolClaimResponse") + proto.RegisterType((*DepositorClaim)(nil), "vaas.provider.v1.DepositorClaim") + proto.RegisterType((*QueryConsumerFeePoolClaimsRequest)(nil), "vaas.provider.v1.QueryConsumerFeePoolClaimsRequest") + proto.RegisterType((*QueryConsumerFeePoolClaimsResponse)(nil), "vaas.provider.v1.QueryConsumerFeePoolClaimsResponse") } func init() { proto.RegisterFile("vaas/provider/v1/query.proto", fileDescriptor_71b3f55ed407aa51) } var fileDescriptor_71b3f55ed407aa51 = []byte{ - // 1794 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x58, 0x4d, 0x6c, 0x1b, 0x41, - 0x15, 0xce, 0x3a, 0x3f, 0x75, 0xc6, 0x6d, 0x1a, 0x86, 0x84, 0x38, 0x6e, 0x12, 0xb7, 0xdb, 0x1f, - 0xd2, 0x9f, 0xec, 0xd6, 0x4e, 0x53, 0xa1, 0x50, 0x40, 0x71, 0x4a, 0x82, 0x55, 0x4a, 0xcd, 0x26, - 0xf4, 0x50, 0x04, 0xab, 0xb1, 0x77, 0xe2, 0x0c, 0x59, 0xef, 0x6e, 0x77, 0xd7, 0x6e, 0x4d, 0x94, - 0x0b, 0x27, 0x0e, 0x20, 0x55, 0xe2, 0xc0, 0x81, 0x4b, 0x85, 0x38, 0x72, 0xec, 0x01, 0x21, 0x71, - 0xe2, 0xd2, 0x63, 0xd5, 0x5e, 0x2a, 0x0e, 0x01, 0xb5, 0x1c, 0x38, 0x57, 0x1c, 0x38, 0x21, 0xb4, - 0xf3, 0xb3, 0xf1, 0x6e, 0x76, 0x63, 0xa7, 0xe5, 0xe6, 0x9d, 0x79, 0xf3, 0xde, 0xf7, 0xde, 0xbc, - 0x79, 0xef, 0x7b, 0x06, 0x73, 0x1d, 0x84, 0x3c, 0xd5, 0x71, 0xed, 0x0e, 0x31, 0xb0, 0xab, 0x76, - 0x4a, 0xea, 0xd3, 0x36, 0x76, 0xbb, 0x8a, 0xe3, 0xda, 0xbe, 0x0d, 0x27, 0x83, 0x5d, 0x45, 0xec, - 0x2a, 0x9d, 0x52, 0x61, 0xae, 0x69, 0xdb, 0x4d, 0x13, 0xab, 0xc8, 0x21, 0x2a, 0xb2, 0x2c, 0xdb, - 0x47, 0x3e, 0xb1, 0x2d, 0x8f, 0xc9, 0x17, 0xa6, 0x9a, 0x76, 0xd3, 0xa6, 0x3f, 0xd5, 0xe0, 0x17, - 0x5f, 0x2d, 0xf2, 0x33, 0xf4, 0xab, 0xde, 0xde, 0x51, 0x7d, 0xd2, 0xc2, 0x9e, 0x8f, 0x5a, 0x8e, - 0x10, 0x38, 0x06, 0x22, 0x34, 0xc9, 0x04, 0xe6, 0xa9, 0x40, 0xa7, 0xa4, 0x7a, 0xbb, 0xc8, 0xc5, - 0x86, 0xde, 0xb0, 0x2d, 0xaf, 0xdd, 0x0a, 0xb7, 0xa1, 0xd8, 0x7e, 0x46, 0x5c, 0xcc, 0xd7, 0xe6, - 0x7c, 0x6c, 0x19, 0xd8, 0x6d, 0x11, 0xcb, 0x57, 0x1b, 0x6e, 0xd7, 0xf1, 0x6d, 0x75, 0x0f, 0x77, - 0x05, 0xd0, 0xd9, 0x86, 0xed, 0xb5, 0x6c, 0x4f, 0x67, 0x58, 0xd9, 0x07, 0xdf, 0xba, 0xc2, 0xbe, - 0x54, 0xcf, 0x47, 0x7b, 0xc4, 0x6a, 0xaa, 0x9d, 0x52, 0x1d, 0xfb, 0xa8, 0x24, 0xbe, 0xb9, 0xd4, - 0x0d, 0x2e, 0x55, 0x47, 0x1e, 0x66, 0x21, 0x0b, 0x05, 0x1d, 0xd4, 0x24, 0x16, 0x0d, 0x0b, 0x93, - 0x95, 0xbf, 0x0d, 0x2e, 0xfc, 0x30, 0x90, 0x58, 0xe7, 0xa8, 0x37, 0xb1, 0x85, 0x3d, 0xe2, 0x69, - 0xf8, 0x69, 0x1b, 0x7b, 0x3e, 0x2c, 0x82, 0x9c, 0xf0, 0x47, 0x27, 0x46, 0x5e, 0xba, 0x28, 0x2d, - 0x8e, 0x68, 0x40, 0x2c, 0x55, 0x0d, 0x79, 0x17, 0xcc, 0x25, 0x9f, 0xf7, 0x1c, 0xdb, 0xf2, 0x30, - 0xfc, 0x1e, 0x38, 0xd7, 0x64, 0x4b, 0xba, 0xe7, 0x23, 0x1f, 0x53, 0x15, 0xb9, 0xf2, 0xbc, 0x42, - 0x6f, 0xaf, 0x53, 0x52, 0x62, 0x07, 0xb7, 0x02, 0xa1, 0xca, 0xc8, 0xeb, 0xc3, 0xe2, 0x90, 0x76, - 0xb6, 0xd9, 0xb3, 0x26, 0xff, 0x4e, 0x02, 0x85, 0x88, 0xa9, 0xf5, 0x5d, 0x44, 0xac, 0x10, 0xe9, - 0x0a, 0x18, 0x75, 0x76, 0x91, 0xc7, 0x0c, 0x4c, 0x94, 0x8b, 0x4a, 0x3c, 0x3d, 0x42, 0x4b, 0xb5, - 0x40, 0x4c, 0x63, 0xd2, 0x70, 0x03, 0x80, 0xa3, 0x98, 0xe4, 0x33, 0x14, 0xdc, 0x35, 0x85, 0x07, - 0x3d, 0x08, 0xa0, 0xc2, 0x72, 0x8e, 0x07, 0x50, 0xa9, 0xa1, 0x26, 0xe6, 0x26, 0xb5, 0x9e, 0x93, - 0xf2, 0x6f, 0xa5, 0x58, 0x20, 0x05, 0x3a, 0x1e, 0x07, 0x15, 0x8c, 0x35, 0xe8, 0x4a, 0x5e, 0xba, - 0x38, 0xbc, 0x98, 0x2b, 0xcf, 0x24, 0xe0, 0x0b, 0xf6, 0x35, 0x2e, 0x06, 0x37, 0x13, 0x80, 0x7d, - 0xbd, 0x2f, 0x30, 0x66, 0x2d, 0x82, 0xec, 0xaf, 0x19, 0x30, 0x4a, 0x55, 0xc3, 0x59, 0x90, 0xa5, - 0xca, 0xc5, 0x4d, 0x8e, 0x6b, 0x67, 0xe8, 0x77, 0xd5, 0x80, 0x17, 0xc0, 0x78, 0xc3, 0x24, 0xd8, - 0xf2, 0x83, 0xbd, 0x0c, 0xdd, 0xcb, 0xb2, 0x85, 0xaa, 0x01, 0xa7, 0x44, 0x68, 0x87, 0xe9, 0x06, - 0x8f, 0xdc, 0x7d, 0x90, 0x6d, 0x61, 0x1f, 0x19, 0xc8, 0x47, 0xf9, 0x11, 0x0a, 0x4f, 0x4e, 0x8f, - 0xf9, 0x43, 0x2e, 0xc9, 0x6f, 0x36, 0x3c, 0x19, 0x4f, 0xb0, 0xd1, 0x78, 0x82, 0xc1, 0x1f, 0x83, - 0x69, 0x62, 0xed, 0xb8, 0xa8, 0x11, 0x38, 0xa3, 0x3b, 0xc8, 0x45, 0x2d, 0xec, 0x63, 0xd7, 0xcb, - 0x8f, 0xf1, 0xbb, 0x3a, 0x66, 0xb3, 0x1a, 0x8a, 0xd7, 0x42, 0x69, 0x6d, 0x8a, 0x24, 0xac, 0xc2, - 0x45, 0x30, 0xb9, 0x83, 0xb1, 0xee, 0xd8, 0xb6, 0xa9, 0x23, 0xc3, 0x70, 0xb1, 0xe7, 0xe5, 0xcf, - 0x50, 0x27, 0x27, 0x76, 0x30, 0xae, 0xd9, 0xb6, 0xb9, 0xc6, 0x56, 0xe5, 0x5f, 0x4b, 0xe0, 0x12, - 0xbd, 0xdf, 0xc7, 0xc8, 0x24, 0x06, 0xf2, 0x6d, 0x57, 0xb8, 0x16, 0x48, 0x88, 0x24, 0xfc, 0x16, - 0x98, 0x14, 0x48, 0x42, 0x7d, 0x34, 0xd2, 0x15, 0xf8, 0xe9, 0xb0, 0x38, 0xd1, 0x45, 0x2d, 0x73, - 0x55, 0xe6, 0x1b, 0xb2, 0x76, 0x5e, 0xc8, 0x72, 0x23, 0xf1, 0x60, 0x64, 0xe2, 0xc1, 0x58, 0xcd, - 0xfe, 0xf2, 0x65, 0x71, 0xe8, 0x5f, 0x2f, 0x8b, 0x43, 0xf2, 0x23, 0x20, 0x9f, 0x04, 0x87, 0x67, - 0xdd, 0x75, 0x30, 0x19, 0x2a, 0x8c, 0xe0, 0xd1, 0xce, 0x37, 0x7a, 0xe4, 0x93, 0x1d, 0xac, 0xf5, - 0xa0, 0xeb, 0x71, 0x30, 0x59, 0x61, 0xb2, 0x83, 0x31, 0x23, 0x5f, 0xe4, 0x60, 0x14, 0xce, 0x91, - 0x83, 0xc9, 0x01, 0x3f, 0x16, 0x5c, 0xf9, 0xfb, 0xe0, 0x3a, 0x55, 0xb8, 0x66, 0x9a, 0x35, 0x44, - 0x5c, 0xef, 0x31, 0x32, 0x83, 0x98, 0x05, 0xdb, 0x95, 0xf0, 0xd5, 0x0e, 0x5c, 0xf7, 0x7e, 0x25, - 0x81, 0x1b, 0x83, 0xa8, 0xe3, 0x38, 0x7f, 0x0a, 0xbe, 0xe2, 0x20, 0xe2, 0xea, 0x1d, 0x64, 0x06, - 0x0d, 0x82, 0x62, 0xe5, 0x95, 0x60, 0xf9, 0x78, 0x06, 0x07, 0x0a, 0x99, 0xbe, 0x40, 0x5d, 0xe8, - 0xb8, 0x65, 0x84, 0x7a, 0x27, 0x9c, 0x88, 0x88, 0xfc, 0x6f, 0x09, 0x5c, 0xea, 0x7b, 0x0a, 0x6e, - 0xa4, 0xa6, 0xe7, 0x85, 0x4f, 0x87, 0xc5, 0x19, 0x76, 0x7b, 0x71, 0x89, 0x84, 0x3c, 0xdd, 0x48, - 0xc8, 0x82, 0x4c, 0x5c, 0x4f, 0x5c, 0x22, 0x21, 0x1d, 0xbe, 0x03, 0xce, 0x86, 0x52, 0x7b, 0xb8, - 0x4b, 0xeb, 0x4b, 0xae, 0x3c, 0xa7, 0x1c, 0xb5, 0x47, 0x85, 0xb5, 0x47, 0xa5, 0xd6, 0xae, 0x9b, - 0xa4, 0xf1, 0x00, 0x77, 0xb5, 0xf0, 0x5e, 0x1e, 0xe0, 0xae, 0x3c, 0x05, 0x20, 0xbd, 0x04, 0xfa, - 0xa4, 0x45, 0x2b, 0x90, 0x1f, 0x82, 0xaf, 0x46, 0x56, 0xf9, 0x1d, 0xdc, 0x05, 0x63, 0xb4, 0x7c, - 0x78, 0xbc, 0x07, 0xe5, 0x93, 0x02, 0x1f, 0xec, 0xf3, 0x22, 0xc5, 0xa5, 0xe5, 0x35, 0xb0, 0x10, - 0xa9, 0xec, 0x61, 0x46, 0x0e, 0xde, 0x25, 0xff, 0x3b, 0x02, 0x2e, 0xa6, 0xe8, 0x08, 0x7f, 0x7d, - 0x69, 0xf1, 0x88, 0x07, 0x33, 0x73, 0xca, 0x60, 0xc2, 0xab, 0x60, 0x22, 0x54, 0xe0, 0xd8, 0xcf, - 0xb0, 0x4b, 0xef, 0x63, 0x58, 0x3b, 0x27, 0x56, 0x6b, 0xc1, 0x22, 0x7c, 0x00, 0x72, 0x06, 0xf6, - 0x1a, 0x2e, 0x71, 0x68, 0x67, 0x62, 0xa5, 0xff, 0xb2, 0xe8, 0x4c, 0x82, 0x89, 0x88, 0xb6, 0x74, - 0xff, 0x48, 0x94, 0x87, 0xb5, 0xf7, 0x34, 0xfc, 0x09, 0x98, 0x0d, 0x7d, 0xb6, 0x1d, 0xec, 0x06, - 0x81, 0x08, 0x9d, 0x1f, 0xa5, 0xce, 0x5f, 0x7a, 0xfb, 0x6a, 0x69, 0x9e, 0x6b, 0x0f, 0x83, 0xc5, - 0x9d, 0xde, 0xf2, 0x5d, 0x62, 0x35, 0xb5, 0x19, 0xa1, 0xe3, 0x11, 0x57, 0x21, 0x62, 0xf2, 0x35, - 0x30, 0xf6, 0x33, 0x44, 0x4c, 0x6c, 0xd0, 0x6e, 0x91, 0xd5, 0xf8, 0x17, 0x5c, 0x05, 0x63, 0x01, - 0x1b, 0x69, 0xb3, 0x6a, 0x3f, 0x51, 0x96, 0xd3, 0xe0, 0x57, 0x6c, 0xcb, 0xd8, 0xa2, 0x92, 0x1a, - 0x3f, 0x01, 0xb7, 0x41, 0x18, 0x7a, 0xdd, 0xb7, 0xf7, 0xb0, 0xe5, 0xe5, 0xb3, 0x14, 0xe8, 0xcd, - 0xc0, 0xbd, 0xbf, 0x1d, 0x16, 0xa7, 0x99, 0x2e, 0xcf, 0xd8, 0x53, 0x88, 0xad, 0xb6, 0x90, 0xbf, - 0xab, 0x54, 0x2d, 0xff, 0xed, 0xab, 0x25, 0xc0, 0x8d, 0x54, 0x2d, 0x5f, 0x9b, 0x10, 0x3a, 0xb6, - 0xa9, 0x8a, 0x20, 0xf8, 0xa1, 0x56, 0x16, 0xfc, 0x71, 0x16, 0x7c, 0xb1, 0xca, 0x82, 0x7f, 0x17, - 0xcc, 0x74, 0x58, 0x0c, 0xb0, 0xa7, 0x37, 0xda, 0xae, 0x1b, 0xb4, 0x6c, 0xec, 0xd8, 0x8d, 0xdd, - 0x3c, 0xa0, 0x1e, 0x4e, 0x87, 0xdb, 0xeb, 0x6c, 0xf7, 0xbb, 0xc1, 0xa6, 0xdc, 0x06, 0xc5, 0xd4, - 0x1c, 0xe6, 0xcf, 0x43, 0x03, 0xa0, 0x13, 0xae, 0xf2, 0xda, 0x54, 0x3e, 0xfe, 0x44, 0xfa, 0xa5, - 0xb1, 0xd6, 0xa3, 0x45, 0x96, 0x79, 0xda, 0x57, 0x4c, 0xbb, 0xb1, 0xe7, 0xfd, 0xc8, 0xf2, 0x89, - 0xf9, 0x03, 0xfc, 0x9c, 0x61, 0x12, 0xaf, 0xf5, 0x09, 0xef, 0x3b, 0xc9, 0x32, 0x1c, 0xdc, 0x0a, - 0x98, 0xa9, 0xd3, 0x7d, 0xbd, 0x1d, 0x08, 0xe8, 0x16, 0x7e, 0x2e, 0xfc, 0x66, 0xaf, 0x6d, 0xaa, - 0x9e, 0x70, 0x5c, 0x5e, 0xe3, 0x4d, 0x64, 0x3d, 0x7c, 0x8a, 0x1b, 0xae, 0xdd, 0x5a, 0xe7, 0xc4, - 0x46, 0x3c, 0xdf, 0x08, 0xf9, 0x91, 0xa2, 0xe4, 0x47, 0xde, 0x00, 0x97, 0x4f, 0x54, 0xc1, 0x01, - 0xf6, 0x2d, 0x01, 0xf7, 0xc0, 0xec, 0x71, 0x7e, 0x38, 0x70, 0x01, 0x79, 0x3b, 0x9c, 0x44, 0x7e, - 0x07, 0xb6, 0x1e, 0xa1, 0x7e, 0x99, 0x28, 0xf5, 0xbb, 0x0c, 0xce, 0xd9, 0xcf, 0xac, 0x9e, 0x9a, - 0xc3, 0x58, 0xde, 0x59, 0xba, 0x28, 0x1e, 0x52, 0x48, 0x01, 0x47, 0xd2, 0x28, 0xe0, 0xe8, 0x67, - 0x53, 0xc0, 0x2d, 0x90, 0x23, 0x16, 0xf1, 0x75, 0x5e, 0x9c, 0x19, 0xaf, 0x2b, 0xa7, 0x2b, 0xaa, - 0x5a, 0xc4, 0x27, 0xc8, 0x24, 0x3f, 0x47, 0x31, 0x8e, 0x07, 0x02, 0x35, 0xac, 0x84, 0xa7, 0xd3, - 0xc6, 0x33, 0xff, 0x07, 0xda, 0x18, 0x49, 0x98, 0x6c, 0x8c, 0x2d, 0x27, 0x71, 0xca, 0xf1, 0x44, - 0x4e, 0x59, 0x89, 0x3d, 0x4a, 0x3e, 0x02, 0x6d, 0x93, 0x16, 0x1e, 0x38, 0x31, 0xf6, 0x62, 0x8d, - 0x25, 0xa2, 0x83, 0x67, 0xc7, 0x26, 0x10, 0x93, 0x94, 0x1e, 0x4c, 0xb7, 0xbc, 0xfd, 0x15, 0x14, - 0x36, 0xfa, 0x2a, 0x62, 0xf4, 0x55, 0xb6, 0xc5, 0xe8, 0x5b, 0xc9, 0x06, 0x57, 0xf4, 0xe2, 0xef, - 0x45, 0x49, 0xcb, 0x35, 0x8f, 0x14, 0x96, 0xff, 0x73, 0x1e, 0x8c, 0x52, 0x6b, 0xf0, 0x8f, 0x12, - 0x98, 0x4a, 0xb2, 0x0b, 0x97, 0xfa, 0x54, 0x8c, 0xe8, 0x7c, 0x59, 0x50, 0x06, 0x15, 0x67, 0xae, - 0xc8, 0x2b, 0xbf, 0x78, 0xf7, 0xcf, 0xdf, 0x64, 0x54, 0xb8, 0xa4, 0x46, 0xc7, 0xf2, 0x30, 0x48, - 0x1c, 0xae, 0xba, 0xdf, 0x13, 0xb6, 0x03, 0xf8, 0x7b, 0x89, 0x53, 0x82, 0xe8, 0x74, 0x06, 0x6f, - 0xf5, 0x31, 0x1f, 0x19, 0x31, 0x0b, 0x4b, 0x03, 0x4a, 0x73, 0xac, 0x0a, 0xc5, 0xba, 0x08, 0xaf, - 0xa5, 0x61, 0x65, 0x93, 0x9e, 0xba, 0x4f, 0x1f, 0xd3, 0x01, 0x7c, 0x2f, 0x06, 0xdc, 0x44, 0x4e, - 0x0f, 0x97, 0x53, 0xac, 0x9f, 0x34, 0x90, 0x14, 0xee, 0x9c, 0xee, 0x10, 0x47, 0xfe, 0x88, 0x22, - 0xaf, 0xc2, 0xcd, 0x18, 0xf2, 0xb0, 0xb2, 0xeb, 0x11, 0x72, 0x17, 0x0d, 0xb6, 0xba, 0x1f, 0x67, - 0x31, 0x49, 0xae, 0xf5, 0xb2, 0xf9, 0xfe, 0xae, 0x25, 0x8c, 0x22, 0xfd, 0x5d, 0x4b, 0x1a, 0x18, - 0x06, 0x70, 0x2d, 0x82, 0x3e, 0xee, 0x5a, 0x9c, 0xd4, 0x1e, 0xc0, 0x77, 0x12, 0xef, 0x31, 0x27, - 0x0e, 0x02, 0xf0, 0x9b, 0x29, 0x68, 0x07, 0x99, 0x46, 0x0a, 0xf7, 0x3e, 0xef, 0x30, 0x77, 0xb9, - 0x4c, 0x5d, 0xbe, 0x05, 0x6f, 0xc4, 0x5c, 0xe6, 0x2e, 0xe8, 0xc1, 0x28, 0x11, 0x7f, 0x30, 0x5d, - 0x90, 0xeb, 0xa1, 0xd0, 0xf0, 0x4a, 0x0a, 0x80, 0x08, 0xef, 0x2e, 0x5c, 0xed, 0x23, 0xc5, 0xf1, - 0xcc, 0x53, 0x3c, 0x33, 0x70, 0x3a, 0x86, 0x87, 0xd5, 0x7f, 0xf8, 0x27, 0x09, 0xcc, 0xa4, 0x90, - 0x0c, 0x78, 0x7b, 0x60, 0x3e, 0x22, 0x30, 0x95, 0x4e, 0x71, 0x82, 0xe3, 0xfb, 0x06, 0xc5, 0x57, - 0x86, 0xb7, 0xd3, 0xde, 0xed, 0x11, 0xc1, 0x89, 0x45, 0xed, 0x95, 0xc4, 0x9b, 0x7c, 0x12, 0x97, - 0x81, 0x69, 0x64, 0xea, 0x04, 0x72, 0x54, 0x58, 0x3e, 0xd5, 0x99, 0x3e, 0x85, 0x27, 0x85, 0x41, - 0xc1, 0x3f, 0xc7, 0xff, 0xbb, 0x8a, 0x72, 0x1c, 0x78, 0xa7, 0x4f, 0x0c, 0x13, 0x59, 0x55, 0x61, - 0xe5, 0x94, 0xa7, 0x06, 0xad, 0x9a, 0xc4, 0x50, 0xf7, 0xc3, 0xee, 0x7b, 0x00, 0xff, 0x20, 0xf1, - 0x19, 0x30, 0x52, 0x85, 0xe1, 0xcd, 0x41, 0x6a, 0xb5, 0x80, 0x7a, 0x6b, 0x30, 0x61, 0x8e, 0x70, - 0x99, 0x22, 0x5c, 0x82, 0x37, 0x4f, 0xac, 0xeb, 0xb1, 0xd4, 0xf8, 0x8b, 0x04, 0xf2, 0x69, 0x8d, - 0x1a, 0x96, 0x06, 0xeb, 0x82, 0x3d, 0xc4, 0xa0, 0x50, 0x3e, 0xcd, 0x11, 0x0e, 0x7c, 0x95, 0x02, - 0xbf, 0x03, 0xcb, 0x7d, 0x9a, 0x27, 0x65, 0x09, 0x51, 0xfc, 0x95, 0xea, 0xeb, 0x0f, 0x0b, 0xd2, - 0x9b, 0x0f, 0x0b, 0xd2, 0x3f, 0x3e, 0x2c, 0x48, 0x2f, 0x3e, 0x2e, 0x0c, 0xbd, 0xf9, 0xb8, 0x30, - 0xf4, 0xfe, 0xe3, 0xc2, 0xd0, 0x13, 0xb5, 0x49, 0xfc, 0xdd, 0x76, 0x5d, 0x69, 0xd8, 0x2d, 0x15, - 0x99, 0x26, 0xb1, 0xea, 0xc4, 0xf7, 0x98, 0x85, 0xe7, 0x31, 0x43, 0x7e, 0xd7, 0xc1, 0x5e, 0x7d, - 0x8c, 0x12, 0x8e, 0xe5, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x16, 0x20, 0x71, 0xbb, 0xdf, 0x17, - 0x00, 0x00, + // 2037 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0x4d, 0x70, 0x1c, 0x47, + 0x15, 0xd6, 0xac, 0x25, 0x59, 0x6a, 0xd9, 0x8a, 0xe9, 0x48, 0x68, 0xb5, 0x96, 0xb5, 0xf6, 0x38, + 0x09, 0x8a, 0x6d, 0xcd, 0x58, 0x2b, 0xdb, 0x95, 0x12, 0x21, 0xe0, 0x95, 0x23, 0xb3, 0x65, 0x82, + 0xc5, 0xd8, 0xe4, 0x10, 0x0a, 0xa6, 0x7a, 0x77, 0xda, 0xab, 0x46, 0xb3, 0x33, 0x93, 0x99, 0xd9, + 0xb5, 0x17, 0x95, 0x2e, 0x1c, 0x28, 0x0e, 0x81, 0x4a, 0x15, 0x07, 0x0e, 0x5c, 0x52, 0x14, 0x27, + 0x7e, 0x6e, 0x3e, 0x50, 0x54, 0x71, 0x82, 0x43, 0x0e, 0x1c, 0x52, 0xce, 0x25, 0xc5, 0x41, 0xa1, + 0x6c, 0x0e, 0x9c, 0x53, 0x9c, 0x29, 0x6a, 0xfa, 0x4f, 0x3b, 0xad, 0x99, 0xdd, 0x51, 0xe2, 0x9c, + 0xb4, 0xd3, 0xfd, 0xfa, 0xf5, 0xf7, 0x5e, 0xbf, 0x7e, 0xef, 0x7b, 0x2d, 0xb0, 0xd4, 0x43, 0x28, + 0x32, 0x83, 0xd0, 0xef, 0x11, 0x07, 0x87, 0x66, 0x6f, 0xcd, 0x7c, 0xb7, 0x8b, 0xc3, 0xbe, 0x11, + 0x84, 0x7e, 0xec, 0xc3, 0x33, 0xc9, 0xac, 0x21, 0x66, 0x8d, 0xde, 0x5a, 0x65, 0xa9, 0xed, 0xfb, + 0x6d, 0x17, 0x9b, 0x28, 0x20, 0x26, 0xf2, 0x3c, 0x3f, 0x46, 0x31, 0xf1, 0xbd, 0x88, 0xc9, 0x57, + 0xe6, 0xda, 0x7e, 0xdb, 0xa7, 0x3f, 0xcd, 0xe4, 0x17, 0x1f, 0xad, 0xf2, 0x35, 0xf4, 0xab, 0xd9, + 0x7d, 0x60, 0xc6, 0xa4, 0x83, 0xa3, 0x18, 0x75, 0x02, 0x21, 0x70, 0x04, 0x84, 0xdc, 0x92, 0x09, + 0x9c, 0xa3, 0x02, 0xbd, 0x35, 0x33, 0xda, 0x41, 0x21, 0x76, 0xec, 0x96, 0xef, 0x45, 0xdd, 0x8e, + 0x9c, 0x86, 0x62, 0xfa, 0x21, 0x09, 0x31, 0x1f, 0x5b, 0x8a, 0xb1, 0xe7, 0xe0, 0xb0, 0x43, 0xbc, + 0xd8, 0x6c, 0x85, 0xfd, 0x20, 0xf6, 0xcd, 0x5d, 0xdc, 0x17, 0x40, 0x17, 0x5b, 0x7e, 0xd4, 0xf1, + 0x23, 0x9b, 0x61, 0x65, 0x1f, 0x7c, 0xea, 0x25, 0xf6, 0x65, 0x46, 0x31, 0xda, 0x25, 0x5e, 0xdb, + 0xec, 0xad, 0x35, 0x71, 0x8c, 0xd6, 0xc4, 0x37, 0x97, 0xba, 0xc4, 0xa5, 0x9a, 0x28, 0xc2, 0xcc, + 0x65, 0x52, 0x30, 0x40, 0x6d, 0xe2, 0x51, 0xb7, 0x70, 0xd9, 0xe5, 0x41, 0x59, 0x21, 0xd5, 0xf2, + 0x09, 0x9f, 0xd7, 0xdf, 0x00, 0x67, 0xbf, 0x97, 0x68, 0xd8, 0xe4, 0x56, 0xdd, 0xc6, 0x1e, 0x8e, + 0x48, 0x64, 0xe1, 0x77, 0xbb, 0x38, 0x8a, 0x61, 0x15, 0xcc, 0x08, 0x7b, 0x6d, 0xe2, 0x94, 0xb5, + 0xf3, 0xda, 0xca, 0xb8, 0x05, 0xc4, 0x50, 0xc3, 0xd1, 0x77, 0xc0, 0x52, 0xf6, 0xfa, 0x28, 0xf0, + 0xbd, 0x08, 0xc3, 0x6f, 0x83, 0xd3, 0x6d, 0x36, 0x64, 0x47, 0x31, 0x8a, 0x31, 0x55, 0x31, 0x53, + 0x3b, 0x67, 0xd0, 0xd3, 0xed, 0xad, 0x19, 0xca, 0xc2, 0x7b, 0x89, 0x50, 0x7d, 0xfc, 0xc3, 0x83, + 0xea, 0x98, 0x75, 0xaa, 0x3d, 0x30, 0xa6, 0xff, 0x46, 0x03, 0x95, 0xd4, 0x56, 0x9b, 0x3b, 0x88, + 0x78, 0x12, 0xe9, 0x75, 0x30, 0x11, 0xec, 0xa0, 0x88, 0x6d, 0x30, 0x5b, 0xab, 0x1a, 0x6a, 0xf8, + 0xc8, 0x9d, 0xb6, 0x13, 0x31, 0x8b, 0x49, 0xc3, 0x2d, 0x00, 0x0e, 0x7d, 0x56, 0x2e, 0x51, 0x70, + 0xaf, 0x18, 0xfc, 0x50, 0x12, 0xa7, 0x19, 0x2c, 0x26, 0xb9, 0xeb, 0x8c, 0x6d, 0xd4, 0xc6, 0x7c, + 0x4b, 0x6b, 0x60, 0xa5, 0xfe, 0x6b, 0x4d, 0x71, 0xa4, 0x40, 0xc7, 0xfd, 0x60, 0x82, 0xc9, 0x16, + 0x1d, 0x29, 0x6b, 0xe7, 0x4f, 0xac, 0xcc, 0xd4, 0x16, 0x32, 0xf0, 0x25, 0xf3, 0x16, 0x17, 0x83, + 0xb7, 0x33, 0x80, 0x7d, 0x6d, 0x24, 0x30, 0xb6, 0x5b, 0x0a, 0xd9, 0xdf, 0x4a, 0x60, 0x82, 0xaa, + 0x86, 0x8b, 0x60, 0x8a, 0x2a, 0x17, 0x27, 0x39, 0x6d, 0x9d, 0xa4, 0xdf, 0x0d, 0x07, 0x9e, 0x05, + 0xd3, 0x2d, 0x97, 0x60, 0x2f, 0x4e, 0xe6, 0x4a, 0x74, 0x6e, 0x8a, 0x0d, 0x34, 0x1c, 0x38, 0x27, + 0x5c, 0x7b, 0x82, 0x4e, 0x70, 0xcf, 0xdd, 0x02, 0x53, 0x1d, 0x1c, 0x23, 0x07, 0xc5, 0xa8, 0x3c, + 0x4e, 0xe1, 0xe9, 0xf9, 0x3e, 0x7f, 0x8b, 0x4b, 0xf2, 0x93, 0x95, 0x2b, 0xd5, 0x00, 0x9b, 0x50, + 0x03, 0x0c, 0xfe, 0x00, 0xcc, 0x13, 0xef, 0x41, 0x88, 0x5a, 0x89, 0x31, 0x76, 0x80, 0x42, 0xd4, + 0xc1, 0x31, 0x0e, 0xa3, 0xf2, 0x24, 0x3f, 0xab, 0x23, 0x7b, 0x36, 0xa4, 0xf8, 0xb6, 0x94, 0xb6, + 0xe6, 0x48, 0xc6, 0x28, 0x5c, 0x01, 0x67, 0x1e, 0x60, 0x6c, 0x07, 0xbe, 0xef, 0xda, 0xc8, 0x71, + 0x42, 0x1c, 0x45, 0xe5, 0x93, 0xd4, 0xc8, 0xd9, 0x07, 0x18, 0x6f, 0xfb, 0xbe, 0x7b, 0x93, 0x8d, + 0xea, 0xbf, 0xd0, 0xc0, 0x05, 0x7a, 0xbe, 0x6f, 0x23, 0x97, 0x38, 0x28, 0xf6, 0x43, 0x61, 0x5a, + 0x22, 0x21, 0x82, 0xf0, 0x1b, 0xe0, 0x8c, 0x40, 0x22, 0xf5, 0x51, 0x4f, 0xd7, 0xe1, 0x67, 0x07, + 0xd5, 0xd9, 0x3e, 0xea, 0xb8, 0x1b, 0x3a, 0x9f, 0xd0, 0xad, 0x17, 0x84, 0x2c, 0xdf, 0x44, 0x75, + 0x46, 0x49, 0x75, 0xc6, 0xc6, 0xd4, 0xcf, 0x3f, 0xa8, 0x8e, 0xfd, 0xe7, 0x83, 0xea, 0x98, 0x7e, + 0x17, 0xe8, 0xc3, 0xe0, 0xf0, 0xa8, 0x7b, 0x15, 0x9c, 0x91, 0x0a, 0x53, 0x78, 0xac, 0x17, 0x5a, + 0x03, 0xf2, 0xd9, 0x06, 0x6e, 0x0f, 0xa0, 0x1b, 0x30, 0x30, 0x5b, 0x61, 0xb6, 0x81, 0xca, 0x26, + 0x5f, 0xc8, 0xc0, 0x34, 0x9c, 0x43, 0x03, 0xb3, 0x1d, 0x7e, 0xc4, 0xb9, 0xfa, 0x77, 0xc0, 0xab, + 0x54, 0xe1, 0x4d, 0xd7, 0xdd, 0x46, 0x24, 0x8c, 0xde, 0x46, 0x6e, 0xe2, 0xb3, 0x64, 0xba, 0x2e, + 0x6f, 0x6d, 0xe1, 0xbc, 0xf7, 0x9e, 0x06, 0x2e, 0x15, 0x51, 0xc7, 0x71, 0xfe, 0x08, 0x7c, 0x25, + 0x40, 0x24, 0xb4, 0x7b, 0xc8, 0x4d, 0x0a, 0x08, 0xc5, 0xca, 0x33, 0xc1, 0xfa, 0xd1, 0x08, 0x4e, + 0x14, 0x32, 0x7d, 0x89, 0x3a, 0x69, 0xb8, 0xe7, 0x48, 0xbd, 0xb3, 0x41, 0x4a, 0x44, 0xff, 0xaf, + 0x06, 0x2e, 0x8c, 0x5c, 0x05, 0xb7, 0x72, 0xc3, 0xf3, 0xec, 0x67, 0x07, 0xd5, 0x05, 0x76, 0x7a, + 0xaa, 0x44, 0x46, 0x9c, 0x6e, 0x65, 0x44, 0x41, 0x49, 0xd5, 0xa3, 0x4a, 0x64, 0x84, 0xc3, 0x37, + 0xc1, 0x29, 0x29, 0xb5, 0x8b, 0xfb, 0x34, 0xbf, 0xcc, 0xd4, 0x96, 0x8c, 0xc3, 0xf2, 0x69, 0xb0, + 0xf2, 0x69, 0x6c, 0x77, 0x9b, 0x2e, 0x69, 0xdd, 0xc1, 0x7d, 0x4b, 0x9e, 0xcb, 0x1d, 0xdc, 0xd7, + 0xe7, 0x00, 0xa4, 0x87, 0x40, 0xaf, 0xb4, 0x28, 0x05, 0xfa, 0x5b, 0xe0, 0xc5, 0xd4, 0x28, 0x3f, + 0x83, 0x1b, 0x60, 0x92, 0xa6, 0x8f, 0x88, 0xd7, 0xa0, 0x72, 0x96, 0xe3, 0x93, 0x79, 0x9e, 0xa4, + 0xb8, 0xb4, 0x7e, 0x13, 0x2c, 0xa7, 0x32, 0xbb, 0x8c, 0xc8, 0xe2, 0x55, 0xf2, 0x7f, 0xe3, 0xe0, + 0x7c, 0x8e, 0x0e, 0xf9, 0xeb, 0x8b, 0x26, 0x0f, 0xd5, 0x99, 0xa5, 0x63, 0x3a, 0x13, 0xbe, 0x0c, + 0x66, 0xa5, 0x82, 0xc0, 0x7f, 0x88, 0x43, 0x7a, 0x1e, 0x27, 0xac, 0xd3, 0x62, 0x74, 0x3b, 0x19, + 0x84, 0x77, 0xc0, 0x8c, 0x83, 0xa3, 0x56, 0x48, 0x02, 0x5a, 0x99, 0x58, 0xea, 0xbf, 0x28, 0x2a, + 0x93, 0x60, 0x2a, 0xa2, 0x2c, 0xdd, 0x3a, 0x14, 0xe5, 0x6e, 0x1d, 0x5c, 0x0d, 0x7f, 0x08, 0x16, + 0xa5, 0xcd, 0x7e, 0x80, 0xc3, 0xc4, 0x11, 0xd2, 0xf8, 0x09, 0x6a, 0xfc, 0x85, 0x27, 0x8f, 0x57, + 0xcf, 0x71, 0xed, 0xd2, 0x59, 0xdc, 0xe8, 0x7b, 0x71, 0x48, 0xbc, 0xb6, 0xb5, 0x20, 0x74, 0xdc, + 0xe5, 0x2a, 0x84, 0x4f, 0xbe, 0x0a, 0x26, 0x7f, 0x8c, 0x88, 0x8b, 0x1d, 0x5a, 0x2d, 0xa6, 0x2c, + 0xfe, 0x05, 0x37, 0xc0, 0x64, 0xc2, 0x46, 0xba, 0x2c, 0xdb, 0xcf, 0xd6, 0xf4, 0x3c, 0xf8, 0x75, + 0xdf, 0x73, 0xee, 0x51, 0x49, 0x8b, 0xaf, 0x80, 0xf7, 0x81, 0x74, 0xbd, 0x1d, 0xfb, 0xbb, 0xd8, + 0x8b, 0xca, 0x53, 0x14, 0xe8, 0xe5, 0xc4, 0xbc, 0x7f, 0x1e, 0x54, 0xe7, 0x99, 0xae, 0xc8, 0xd9, + 0x35, 0x88, 0x6f, 0x76, 0x50, 0xbc, 0x63, 0x34, 0xbc, 0xf8, 0xc9, 0xe3, 0x55, 0xc0, 0x37, 0x69, + 0x78, 0xb1, 0x35, 0x2b, 0x74, 0xdc, 0xa7, 0x2a, 0x12, 0xe7, 0x4b, 0xad, 0xcc, 0xf9, 0xd3, 0xcc, + 0xf9, 0x62, 0x94, 0x39, 0xff, 0x06, 0x58, 0xe8, 0x31, 0x1f, 0xe0, 0xc8, 0x6e, 0x75, 0xc3, 0x30, + 0x29, 0xd9, 0x38, 0xf0, 0x5b, 0x3b, 0x65, 0x40, 0x2d, 0x9c, 0x97, 0xd3, 0x9b, 0x6c, 0xf6, 0xcd, + 0x64, 0x52, 0xef, 0x82, 0x6a, 0x6e, 0x0c, 0xf3, 0xeb, 0x61, 0x01, 0xd0, 0x93, 0xa3, 0x3c, 0x37, + 0xd5, 0x8e, 0x5e, 0x91, 0x51, 0x61, 0x6c, 0x0d, 0x68, 0xd1, 0x75, 0x1e, 0xf6, 0x75, 0xd7, 0x6f, + 0xed, 0x46, 0xdf, 0xf7, 0x62, 0xe2, 0x7e, 0x17, 0x3f, 0x62, 0x98, 0xc4, 0x6d, 0x7d, 0x87, 0xd7, + 0x9d, 0x6c, 0x19, 0x0e, 0xee, 0x3a, 0x58, 0x68, 0xd2, 0x79, 0xbb, 0x9b, 0x08, 0xd8, 0x1e, 0x7e, + 0x24, 0xec, 0x66, 0xb7, 0x6d, 0xae, 0x99, 0xb1, 0x5c, 0xbf, 0xc9, 0x8b, 0xc8, 0xa6, 0xbc, 0x8a, + 0x5b, 0xa1, 0xdf, 0xd9, 0xe4, 0xc4, 0x46, 0x5c, 0xdf, 0x14, 0xf9, 0xd1, 0xd2, 0xe4, 0x47, 0xdf, + 0x02, 0x17, 0x87, 0xaa, 0xe0, 0x00, 0x47, 0xa6, 0x80, 0xd7, 0xc1, 0xe2, 0x51, 0x7e, 0x58, 0x38, + 0x81, 0x3c, 0x39, 0x91, 0x45, 0x7e, 0x0b, 0xef, 0x9e, 0xa2, 0x7e, 0xa5, 0x34, 0xf5, 0xbb, 0x08, + 0x4e, 0xfb, 0x0f, 0xbd, 0x81, 0x9c, 0xc3, 0x58, 0xde, 0x29, 0x3a, 0x28, 0x2e, 0x92, 0xa4, 0x80, + 0xe3, 0x79, 0x14, 0x70, 0xe2, 0x73, 0x53, 0xc0, 0x7b, 0x60, 0x86, 0x78, 0x24, 0xb6, 0x79, 0x72, + 0x66, 0xbc, 0xae, 0x96, 0xaf, 0xa8, 0xe1, 0x91, 0x98, 0x20, 0x97, 0xfc, 0x04, 0x29, 0x1c, 0x0f, + 0x24, 0x6a, 0x58, 0x0a, 0xcf, 0xa7, 0x8d, 0x27, 0x9f, 0x03, 0x6d, 0x4c, 0x05, 0xcc, 0x94, 0xc2, + 0x96, 0xb3, 0x38, 0xe5, 0x74, 0x26, 0xa7, 0xac, 0x2b, 0x97, 0x92, 0xb7, 0x40, 0xf7, 0x49, 0x07, + 0x17, 0x0e, 0x8c, 0x5d, 0xa5, 0xb0, 0xa4, 0x74, 0xf0, 0xe8, 0xb8, 0x0d, 0x44, 0x27, 0x65, 0x27, + 0xdd, 0x2f, 0x2f, 0x7f, 0x15, 0x83, 0xb5, 0xc6, 0x86, 0x68, 0x8d, 0x8d, 0xfb, 0xa2, 0x35, 0xae, + 0x4f, 0x25, 0x47, 0xf4, 0xfe, 0xa7, 0x55, 0xcd, 0x9a, 0x69, 0x1f, 0x2a, 0xd4, 0xf7, 0x94, 0xcd, + 0xb6, 0x98, 0x3d, 0x9b, 0x2e, 0x22, 0x9d, 0x21, 0x88, 0xa7, 0x53, 0xa1, 0x78, 0x03, 0x4c, 0x3b, + 0x38, 0xf0, 0x23, 0x12, 0xfb, 0x21, 0x67, 0x0d, 0xe5, 0x27, 0x8f, 0x57, 0xe7, 0x78, 0x72, 0x4c, + 0x67, 0xf6, 0x43, 0x51, 0xfd, 0x67, 0x82, 0xa0, 0x66, 0xef, 0xce, 0x6d, 0x45, 0x60, 0xa2, 0x95, + 0x0c, 0xf0, 0x04, 0xb6, 0x98, 0xea, 0x98, 0x44, 0x56, 0xdf, 0xf4, 0x89, 0x57, 0xbf, 0x9a, 0xd8, + 0xf8, 0xfb, 0x4f, 0xab, 0x2b, 0x6d, 0x12, 0xef, 0x74, 0x9b, 0x46, 0xcb, 0xef, 0xf0, 0x66, 0x9c, + 0xff, 0x59, 0x8d, 0x9c, 0x5d, 0x33, 0xee, 0x07, 0x38, 0xa2, 0x0b, 0x22, 0x8b, 0x69, 0xd6, 0xff, + 0xa0, 0x81, 0xd9, 0x5b, 0x02, 0x16, 0xdd, 0x3d, 0x6d, 0x93, 0x56, 0xd8, 0xa6, 0x43, 0xb4, 0xa5, + 0x2f, 0x0d, 0xed, 0x7b, 0xc3, 0xdc, 0x16, 0x15, 0x3e, 0xb5, 0xe7, 0xd5, 0x27, 0xff, 0x49, 0x53, + 0x52, 0xb2, 0x02, 0x87, 0x1f, 0xe3, 0x1b, 0x60, 0x92, 0xc2, 0x17, 0x85, 0xe8, 0xfc, 0xd1, 0xfb, + 0x9a, 0x3e, 0x02, 0xc1, 0xd9, 0xd8, 0xaa, 0xe7, 0xd6, 0x3d, 0xd7, 0x7e, 0xf9, 0x22, 0x98, 0xa0, + 0x78, 0xe1, 0x1f, 0x35, 0x30, 0x97, 0x75, 0xd5, 0xe0, 0xea, 0x88, 0x22, 0x99, 0x7e, 0x52, 0xa9, + 0x18, 0x45, 0xc5, 0x19, 0x1a, 0xfd, 0xfa, 0x4f, 0x3f, 0xfe, 0xf7, 0xaf, 0x4a, 0x26, 0x5c, 0x35, + 0xd3, 0x2f, 0x55, 0xf2, 0xbc, 0xf8, 0x0d, 0x35, 0xf7, 0x06, 0x4e, 0x70, 0x1f, 0xfe, 0x56, 0xe3, + 0x2c, 0x38, 0xfd, 0x20, 0x01, 0xaf, 0x8c, 0xd8, 0x3e, 0xf5, 0xaa, 0x52, 0x59, 0x2d, 0x28, 0xcd, + 0xb1, 0x1a, 0x14, 0xeb, 0x0a, 0x7c, 0x25, 0x0f, 0x2b, 0x7b, 0xdc, 0x30, 0xf7, 0x68, 0xfd, 0xd8, + 0x87, 0x9f, 0x88, 0x37, 0x9d, 0xcc, 0x36, 0x16, 0xae, 0xe7, 0xec, 0x3e, 0xac, 0x07, 0xaf, 0x5c, + 0x3b, 0xde, 0x22, 0x8e, 0xfc, 0x2e, 0x45, 0xde, 0x80, 0xb7, 0x15, 0xe4, 0x92, 0xcc, 0xd8, 0xa9, + 0x7e, 0x26, 0xed, 0x6c, 0x73, 0x4f, 0x25, 0xee, 0x59, 0xa6, 0x0d, 0x36, 0xb0, 0xa3, 0x4d, 0xcb, + 0xe8, 0xbe, 0x47, 0x9b, 0x96, 0xd5, 0x23, 0x17, 0x30, 0x2d, 0x85, 0x5e, 0x35, 0x4d, 0xed, 0xe3, + 0xf6, 0xe1, 0xc7, 0xe2, 0x0e, 0x0f, 0xed, 0x7d, 0xe1, 0xd7, 0x73, 0xd0, 0x16, 0x69, 0xc0, 0x2b, + 0xaf, 0x7f, 0xbe, 0xc5, 0xdc, 0xe4, 0x1a, 0x35, 0xf9, 0x0a, 0xbc, 0xa4, 0x98, 0xcc, 0x4d, 0xb0, + 0x93, 0xee, 0x59, 0xbd, 0x30, 0x7d, 0x30, 0x33, 0xd0, 0x35, 0xc2, 0x97, 0x72, 0x00, 0xa4, 0x5a, + 0xcd, 0xca, 0xcb, 0x23, 0xa4, 0x38, 0x9e, 0x73, 0x14, 0xcf, 0x02, 0x9c, 0x57, 0xf0, 0x30, 0xca, + 0x03, 0xff, 0xac, 0x81, 0x85, 0x1c, 0x5e, 0x0d, 0xaf, 0x16, 0xa6, 0xe0, 0x02, 0xd3, 0xda, 0x31, + 0x56, 0x70, 0x7c, 0xaf, 0x51, 0x7c, 0x35, 0x78, 0x35, 0xef, 0xde, 0x1e, 0x72, 0x7a, 0xc5, 0x6b, + 0x8f, 0x35, 0xce, 0x6b, 0xb3, 0xe8, 0x3b, 0xcc, 0xeb, 0x1f, 0x86, 0xf4, 0x03, 0x95, 0xf5, 0x63, + 0xad, 0x19, 0x91, 0x78, 0x72, 0x9a, 0x06, 0xf8, 0x17, 0xf5, 0xb9, 0x36, 0x4d, 0xeb, 0xe1, 0xb5, + 0x11, 0x3e, 0xcc, 0x6c, 0x24, 0x2a, 0xd7, 0x8f, 0xb9, 0xaa, 0x68, 0xd6, 0x24, 0x8e, 0xb9, 0x27, + 0x09, 0xe7, 0x3e, 0xfc, 0x9d, 0xc6, 0x9f, 0x3d, 0x52, 0x59, 0x18, 0x5e, 0x2e, 0x92, 0xab, 0x05, + 0xd4, 0x2b, 0xc5, 0x84, 0x39, 0xc2, 0x75, 0x8a, 0x70, 0x15, 0x5e, 0x1e, 0x9a, 0xd7, 0x95, 0xd0, + 0xf8, 0xab, 0x06, 0xca, 0x79, 0xdc, 0x14, 0xae, 0x15, 0xab, 0x82, 0x03, 0x5c, 0xb8, 0x52, 0x3b, + 0xce, 0x12, 0x0e, 0x7c, 0x83, 0x02, 0xbf, 0x06, 0x6b, 0x23, 0x8a, 0x27, 0x25, 0xc6, 0x0a, 0xfe, + 0x7f, 0x68, 0x60, 0x2e, 0x8b, 0xa5, 0xc0, 0x51, 0x40, 0x32, 0x68, 0x71, 0x6e, 0x54, 0x0f, 0x23, + 0xb3, 0xfa, 0x1d, 0x8a, 0xfe, 0x4d, 0xb8, 0x69, 0x1e, 0xf9, 0x27, 0x95, 0x44, 0x2a, 0x7b, 0x0d, + 0xca, 0x7c, 0xd4, 0xe4, 0x2d, 0xa9, 0xe6, 0x3e, 0xfc, 0xbb, 0x06, 0xe6, 0x33, 0x49, 0x17, 0x3c, + 0x0e, 0xb6, 0x68, 0x54, 0x2d, 0x1a, 0xca, 0xeb, 0xf4, 0x6f, 0x51, 0x8b, 0x36, 0xe0, 0x6b, 0x85, + 0x2d, 0x52, 0x12, 0x4e, 0xbd, 0xf1, 0xe1, 0xd3, 0x65, 0xed, 0xa3, 0xa7, 0xcb, 0xda, 0xbf, 0x9e, + 0x2e, 0x6b, 0xef, 0x3f, 0x5b, 0x1e, 0xfb, 0xe8, 0xd9, 0xf2, 0xd8, 0x27, 0xcf, 0x96, 0xc7, 0xde, + 0x31, 0x07, 0xa8, 0x31, 0x72, 0x5d, 0xe2, 0x35, 0x49, 0x1c, 0xb1, 0x7d, 0x1e, 0x29, 0xdb, 0x51, + 0x9e, 0xdc, 0x9c, 0xa4, 0x9d, 0xcf, 0xfa, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x28, 0x47, 0x02, + 0x10, 0x88, 0x1c, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1553,6 +1830,8 @@ type QueryClient interface { // QueryConsumerGenesisTime returns the genesis time // of the consumer chain associated with the provided consumer id QueryConsumerGenesisTime(ctx context.Context, in *QueryConsumerGenesisTimeRequest, opts ...grpc.CallOption) (*QueryConsumerGenesisTimeResponse, error) + ConsumerFeePoolClaim(ctx context.Context, in *QueryConsumerFeePoolClaimRequest, opts ...grpc.CallOption) (*QueryConsumerFeePoolClaimResponse, error) + ConsumerFeePoolClaims(ctx context.Context, in *QueryConsumerFeePoolClaimsRequest, opts ...grpc.CallOption) (*QueryConsumerFeePoolClaimsResponse, error) } type queryClient struct { @@ -1662,6 +1941,24 @@ func (c *queryClient) QueryConsumerGenesisTime(ctx context.Context, in *QueryCon return out, nil } +func (c *queryClient) ConsumerFeePoolClaim(ctx context.Context, in *QueryConsumerFeePoolClaimRequest, opts ...grpc.CallOption) (*QueryConsumerFeePoolClaimResponse, error) { + out := new(QueryConsumerFeePoolClaimResponse) + err := c.cc.Invoke(ctx, "/vaas.provider.v1.Query/ConsumerFeePoolClaim", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) ConsumerFeePoolClaims(ctx context.Context, in *QueryConsumerFeePoolClaimsRequest, opts ...grpc.CallOption) (*QueryConsumerFeePoolClaimsResponse, error) { + out := new(QueryConsumerFeePoolClaimsResponse) + err := c.cc.Invoke(ctx, "/vaas.provider.v1.Query/ConsumerFeePoolClaims", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // ConsumerGenesis queries the genesis state needed to start a consumer chain @@ -1697,6 +1994,8 @@ type QueryServer interface { // QueryConsumerGenesisTime returns the genesis time // of the consumer chain associated with the provided consumer id QueryConsumerGenesisTime(context.Context, *QueryConsumerGenesisTimeRequest) (*QueryConsumerGenesisTimeResponse, error) + ConsumerFeePoolClaim(context.Context, *QueryConsumerFeePoolClaimRequest) (*QueryConsumerFeePoolClaimResponse, error) + ConsumerFeePoolClaims(context.Context, *QueryConsumerFeePoolClaimsRequest) (*QueryConsumerFeePoolClaimsResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -1736,6 +2035,12 @@ func (*UnimplementedQueryServer) QueryConsumerChain(ctx context.Context, req *Qu func (*UnimplementedQueryServer) QueryConsumerGenesisTime(ctx context.Context, req *QueryConsumerGenesisTimeRequest) (*QueryConsumerGenesisTimeResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryConsumerGenesisTime not implemented") } +func (*UnimplementedQueryServer) ConsumerFeePoolClaim(ctx context.Context, req *QueryConsumerFeePoolClaimRequest) (*QueryConsumerFeePoolClaimResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConsumerFeePoolClaim not implemented") +} +func (*UnimplementedQueryServer) ConsumerFeePoolClaims(ctx context.Context, req *QueryConsumerFeePoolClaimsRequest) (*QueryConsumerFeePoolClaimsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConsumerFeePoolClaims not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -1939,6 +2244,42 @@ func _Query_QueryConsumerGenesisTime_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } +func _Query_ConsumerFeePoolClaim_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryConsumerFeePoolClaimRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ConsumerFeePoolClaim(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/vaas.provider.v1.Query/ConsumerFeePoolClaim", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ConsumerFeePoolClaim(ctx, req.(*QueryConsumerFeePoolClaimRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_ConsumerFeePoolClaims_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryConsumerFeePoolClaimsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ConsumerFeePoolClaims(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/vaas.provider.v1.Query/ConsumerFeePoolClaims", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ConsumerFeePoolClaims(ctx, req.(*QueryConsumerFeePoolClaimsRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "vaas.provider.v1.Query", HandlerType: (*QueryServer)(nil), @@ -1987,6 +2328,14 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "QueryConsumerGenesisTime", Handler: _Query_QueryConsumerGenesisTime_Handler, }, + { + MethodName: "ConsumerFeePoolClaim", + Handler: _Query_ConsumerFeePoolClaim_Handler, + }, + { + MethodName: "ConsumerFeePoolClaims", + Handler: _Query_ConsumerFeePoolClaims_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "vaas/provider/v1/query.proto", @@ -2982,58 +3331,267 @@ func (m *QueryConsumerGenesisTimeResponse) MarshalToSizedBuffer(dAtA []byte) (in return len(dAtA) - i, nil } -func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { - offset -= sovQuery(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *QueryConsumerGenesisRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ConsumerId != 0 { - n += 1 + sovQuery(uint64(m.ConsumerId)) +func (m *QueryConsumerFeePoolClaimRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - return n + return dAtA[:n], nil } -func (m *QueryConsumerGenesisResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.GenesisState.Size() - n += 1 + l + sovQuery(uint64(l)) - return n +func (m *QueryConsumerFeePoolClaimRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryConsumerChainsRequest) Size() (n int) { - if m == nil { - return 0 - } +func (m *QueryConsumerFeePoolClaimRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Phase != 0 { - n += 1 + sovQuery(uint64(m.Phase)) + if len(m.Depositor) > 0 { + i -= len(m.Depositor) + copy(dAtA[i:], m.Depositor) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Depositor))) + i-- + dAtA[i] = 0x12 } - if m.Pagination != nil { - l = m.Pagination.Size() - n += 1 + l + sovQuery(uint64(l)) + if len(m.ConsumerId) > 0 { + i -= len(m.ConsumerId) + copy(dAtA[i:], m.ConsumerId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ConsumerId))) + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *QueryConsumerChainsResponse) Size() (n int) { - if m == nil { +func (m *QueryConsumerFeePoolClaimResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryConsumerFeePoolClaimResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryConsumerFeePoolClaimResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Claim) > 0 { + for iNdEx := len(m.Claim) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Claim[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *DepositorClaim) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DepositorClaim) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DepositorClaim) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Claim) > 0 { + for iNdEx := len(m.Claim) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Claim[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Depositor) > 0 { + i -= len(m.Depositor) + copy(dAtA[i:], m.Depositor) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Depositor))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryConsumerFeePoolClaimsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryConsumerFeePoolClaimsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryConsumerFeePoolClaimsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.ConsumerId) > 0 { + i -= len(m.ConsumerId) + copy(dAtA[i:], m.ConsumerId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ConsumerId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryConsumerFeePoolClaimsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryConsumerFeePoolClaimsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryConsumerFeePoolClaimsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Claims) > 0 { + for iNdEx := len(m.Claims) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Claims[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryConsumerGenesisRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ConsumerId != 0 { + n += 1 + sovQuery(uint64(m.ConsumerId)) + } + return n +} + +func (m *QueryConsumerGenesisResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.GenesisState.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryConsumerChainsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Phase != 0 { + n += 1 + sovQuery(uint64(m.Phase)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryConsumerChainsResponse) Size() (n int) { + if m == nil { return 0 } var l int @@ -3401,36 +3959,123 @@ func (m *QueryConsumerGenesisTimeResponse) Size() (n int) { return n } -func sovQuery(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozQuery(x uint64) (n int) { - return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +func (m *QueryConsumerFeePoolClaimRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ConsumerId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Depositor) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n } -func (m *QueryConsumerGenesisRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } + +func (m *QueryConsumerFeePoolClaimResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Claim) > 0 { + for _, e := range m.Claim { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryConsumerGenesisRequest: wiretype end group for non-group") + } + return n +} + +func (m *DepositorClaim) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Depositor) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if len(m.Claim) > 0 { + for _, e := range m.Claim { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryConsumerFeePoolClaimsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ConsumerId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryConsumerFeePoolClaimsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Claims) > 0 { + for _, e := range m.Claims { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryConsumerGenesisRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsumerGenesisRequest: wiretype end group for non-group") } if fieldNum <= 0 { return fmt.Errorf("proto: QueryConsumerGenesisRequest: illegal tag %d (wire type %d)", fieldNum, wire) @@ -6144,6 +6789,558 @@ func (m *QueryConsumerGenesisTimeResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryConsumerFeePoolClaimRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsumerFeePoolClaimRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryConsumerFeePoolClaimRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Depositor = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryConsumerFeePoolClaimResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsumerFeePoolClaimResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryConsumerFeePoolClaimResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Claim", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Claim = append(m.Claim, types2.Coin{}) + if err := m.Claim[len(m.Claim)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DepositorClaim) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DepositorClaim: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DepositorClaim: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Depositor = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Claim", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Claim = append(m.Claim, types2.Coin{}) + if err := m.Claim[len(m.Claim)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryConsumerFeePoolClaimsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsumerFeePoolClaimsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryConsumerFeePoolClaimsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryConsumerFeePoolClaimsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsumerFeePoolClaimsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryConsumerFeePoolClaimsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Claims", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Claims = append(m.Claims, DepositorClaim{}) + if err := m.Claims[len(m.Claims)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/vaas/provider/types/query.pb.gw.go b/x/vaas/provider/types/query.pb.gw.go index d28b805..4fc9e91 100644 --- a/x/vaas/provider/types/query.pb.gw.go +++ b/x/vaas/provider/types/query.pb.gw.go @@ -623,6 +623,154 @@ func local_request_Query_QueryConsumerGenesisTime_0(ctx context.Context, marshal } +func request_Query_ConsumerFeePoolClaim_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryConsumerFeePoolClaimRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["consumer_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "consumer_id") + } + + protoReq.ConsumerId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "consumer_id", err) + } + + val, ok = pathParams["depositor"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "depositor") + } + + protoReq.Depositor, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "depositor", err) + } + + msg, err := client.ConsumerFeePoolClaim(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ConsumerFeePoolClaim_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryConsumerFeePoolClaimRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["consumer_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "consumer_id") + } + + protoReq.ConsumerId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "consumer_id", err) + } + + val, ok = pathParams["depositor"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "depositor") + } + + protoReq.Depositor, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "depositor", err) + } + + msg, err := server.ConsumerFeePoolClaim(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_ConsumerFeePoolClaims_0 = &utilities.DoubleArray{Encoding: map[string]int{"consumer_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_ConsumerFeePoolClaims_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryConsumerFeePoolClaimsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["consumer_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "consumer_id") + } + + protoReq.ConsumerId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "consumer_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ConsumerFeePoolClaims_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ConsumerFeePoolClaims(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ConsumerFeePoolClaims_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryConsumerFeePoolClaimsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["consumer_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "consumer_id") + } + + protoReq.ConsumerId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "consumer_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ConsumerFeePoolClaims_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ConsumerFeePoolClaims(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -882,6 +1030,52 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_ConsumerFeePoolClaim_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ConsumerFeePoolClaim_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ConsumerFeePoolClaim_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ConsumerFeePoolClaims_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ConsumerFeePoolClaims_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ConsumerFeePoolClaims_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1143,6 +1337,46 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_ConsumerFeePoolClaim_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_ConsumerFeePoolClaim_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ConsumerFeePoolClaim_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ConsumerFeePoolClaims_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_ConsumerFeePoolClaims_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ConsumerFeePoolClaims_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1168,6 +1402,10 @@ var ( pattern_Query_QueryConsumerChain_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"vaas", "provider", "consumer_chain", "consumer_id"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_QueryConsumerGenesisTime_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"vaas", "provider", "consumer_genesis_time", "consumer_id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ConsumerFeePoolClaim_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"vaas", "provider", "v1", "consumer_fee_pool_claim", "consumer_id", "depositor"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ConsumerFeePoolClaims_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"vaas", "provider", "v1", "consumer_fee_pool_claims", "consumer_id"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -1192,4 +1430,8 @@ var ( forward_Query_QueryConsumerChain_0 = runtime.ForwardResponseMessage forward_Query_QueryConsumerGenesisTime_0 = runtime.ForwardResponseMessage + + forward_Query_ConsumerFeePoolClaim_0 = runtime.ForwardResponseMessage + + forward_Query_ConsumerFeePoolClaims_0 = runtime.ForwardResponseMessage ) diff --git a/x/vaas/provider/types/tx.pb.go b/x/vaas/provider/types/tx.pb.go index 812b224..4f3a16b 100644 --- a/x/vaas/provider/types/tx.pb.go +++ b/x/vaas/provider/types/tx.pb.go @@ -9,6 +9,8 @@ import ( types "github.com/cometbft/cometbft/proto/tendermint/types" _ "github.com/cosmos/cosmos-proto" _ "github.com/cosmos/cosmos-sdk/codec/types" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/cosmos-sdk/types/msgservice" _ "github.com/cosmos/cosmos-sdk/types/tx/amino" _ "github.com/cosmos/gogoproto/gogoproto" @@ -730,6 +732,256 @@ func (m *MsgUpdateConsumerResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateConsumerResponse proto.InternalMessageInfo +// MsgFundConsumerFeePool deposits a single-denom amount into a consumer's +// fee pool and credits the signer with shares. If the signer is the gov +// module authority, funds are pulled from the community pool and the +// distribution module account is credited as the depositor. +type MsgFundConsumerFeePool struct { + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` + ConsumerId string `protobuf:"bytes,2,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + Amount types1.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgFundConsumerFeePool) Reset() { *m = MsgFundConsumerFeePool{} } +func (m *MsgFundConsumerFeePool) String() string { return proto.CompactTextString(m) } +func (*MsgFundConsumerFeePool) ProtoMessage() {} +func (*MsgFundConsumerFeePool) Descriptor() ([]byte, []int) { + return fileDescriptor_a07778b1d094765c, []int{14} +} +func (m *MsgFundConsumerFeePool) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgFundConsumerFeePool) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgFundConsumerFeePool.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgFundConsumerFeePool) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgFundConsumerFeePool.Merge(m, src) +} +func (m *MsgFundConsumerFeePool) XXX_Size() int { + return m.Size() +} +func (m *MsgFundConsumerFeePool) XXX_DiscardUnknown() { + xxx_messageInfo_MsgFundConsumerFeePool.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgFundConsumerFeePool proto.InternalMessageInfo + +type MsgFundConsumerFeePoolResponse struct { +} + +func (m *MsgFundConsumerFeePoolResponse) Reset() { *m = MsgFundConsumerFeePoolResponse{} } +func (m *MsgFundConsumerFeePoolResponse) String() string { return proto.CompactTextString(m) } +func (*MsgFundConsumerFeePoolResponse) ProtoMessage() {} +func (*MsgFundConsumerFeePoolResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a07778b1d094765c, []int{15} +} +func (m *MsgFundConsumerFeePoolResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgFundConsumerFeePoolResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgFundConsumerFeePoolResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgFundConsumerFeePoolResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgFundConsumerFeePoolResponse.Merge(m, src) +} +func (m *MsgFundConsumerFeePoolResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgFundConsumerFeePoolResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgFundConsumerFeePoolResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgFundConsumerFeePoolResponse proto.InternalMessageInfo + +// MsgWithdrawConsumerFeePool withdraws tokens from the signer's share in a +// consumer fee pool across one or more denoms. The transaction is atomic: +// if any denom in `amount` fails its share check, the whole tx aborts. +// If the signer is the gov module authority, the withdrawal targets the +// distribution module account's shares and tokens are routed back to the +// community pool. +type MsgWithdrawConsumerFeePool struct { + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` + ConsumerId string `protobuf:"bytes,2,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` +} + +func (m *MsgWithdrawConsumerFeePool) Reset() { *m = MsgWithdrawConsumerFeePool{} } +func (m *MsgWithdrawConsumerFeePool) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawConsumerFeePool) ProtoMessage() {} +func (*MsgWithdrawConsumerFeePool) Descriptor() ([]byte, []int) { + return fileDescriptor_a07778b1d094765c, []int{16} +} +func (m *MsgWithdrawConsumerFeePool) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawConsumerFeePool) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawConsumerFeePool.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgWithdrawConsumerFeePool) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawConsumerFeePool.Merge(m, src) +} +func (m *MsgWithdrawConsumerFeePool) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawConsumerFeePool) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawConsumerFeePool.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawConsumerFeePool proto.InternalMessageInfo + +type MsgWithdrawConsumerFeePoolResponse struct { + // total tokens actually delivered (may be less than requested due to + // truncation in the partial-withdraw branch) + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` +} + +func (m *MsgWithdrawConsumerFeePoolResponse) Reset() { *m = MsgWithdrawConsumerFeePoolResponse{} } +func (m *MsgWithdrawConsumerFeePoolResponse) String() string { return proto.CompactTextString(m) } +func (*MsgWithdrawConsumerFeePoolResponse) ProtoMessage() {} +func (*MsgWithdrawConsumerFeePoolResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a07778b1d094765c, []int{17} +} +func (m *MsgWithdrawConsumerFeePoolResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgWithdrawConsumerFeePoolResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgWithdrawConsumerFeePoolResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgWithdrawConsumerFeePoolResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgWithdrawConsumerFeePoolResponse.Merge(m, src) +} +func (m *MsgWithdrawConsumerFeePoolResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgWithdrawConsumerFeePoolResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgWithdrawConsumerFeePoolResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgWithdrawConsumerFeePoolResponse proto.InternalMessageInfo + +func (m *MsgWithdrawConsumerFeePoolResponse) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Amount + } + return nil +} + +// MsgSweepConsumerFeePool distributes a consumer fee pool's balance pro-rata +// to all share-holders across the specified denoms (or all denoms if `denoms` +// is empty). Truncation residue per denom is forwarded to the community pool. +// Only the consumer owner may sign. +type MsgSweepConsumerFeePool struct { + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` + ConsumerId string `protobuf:"bytes,2,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + // empty = all denoms with shares or balance for this consumer + Denoms []string `protobuf:"bytes,3,rep,name=denoms,proto3" json:"denoms,omitempty"` +} + +func (m *MsgSweepConsumerFeePool) Reset() { *m = MsgSweepConsumerFeePool{} } +func (m *MsgSweepConsumerFeePool) String() string { return proto.CompactTextString(m) } +func (*MsgSweepConsumerFeePool) ProtoMessage() {} +func (*MsgSweepConsumerFeePool) Descriptor() ([]byte, []int) { + return fileDescriptor_a07778b1d094765c, []int{18} +} +func (m *MsgSweepConsumerFeePool) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSweepConsumerFeePool) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSweepConsumerFeePool.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSweepConsumerFeePool) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSweepConsumerFeePool.Merge(m, src) +} +func (m *MsgSweepConsumerFeePool) XXX_Size() int { + return m.Size() +} +func (m *MsgSweepConsumerFeePool) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSweepConsumerFeePool.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSweepConsumerFeePool proto.InternalMessageInfo + +type MsgSweepConsumerFeePoolResponse struct { +} + +func (m *MsgSweepConsumerFeePoolResponse) Reset() { *m = MsgSweepConsumerFeePoolResponse{} } +func (m *MsgSweepConsumerFeePoolResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSweepConsumerFeePoolResponse) ProtoMessage() {} +func (*MsgSweepConsumerFeePoolResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a07778b1d094765c, []int{19} +} +func (m *MsgSweepConsumerFeePoolResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSweepConsumerFeePoolResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSweepConsumerFeePoolResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSweepConsumerFeePoolResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSweepConsumerFeePoolResponse.Merge(m, src) +} +func (m *MsgSweepConsumerFeePoolResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSweepConsumerFeePoolResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSweepConsumerFeePoolResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSweepConsumerFeePoolResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgAssignConsumerKey)(nil), "vaas.provider.v1.MsgAssignConsumerKey") proto.RegisterType((*MsgAssignConsumerKeyResponse)(nil), "vaas.provider.v1.MsgAssignConsumerKeyResponse") @@ -745,81 +997,103 @@ func init() { proto.RegisterType((*MsgCreateConsumerResponse)(nil), "vaas.provider.v1.MsgCreateConsumerResponse") proto.RegisterType((*MsgUpdateConsumer)(nil), "vaas.provider.v1.MsgUpdateConsumer") proto.RegisterType((*MsgUpdateConsumerResponse)(nil), "vaas.provider.v1.MsgUpdateConsumerResponse") + proto.RegisterType((*MsgFundConsumerFeePool)(nil), "vaas.provider.v1.MsgFundConsumerFeePool") + proto.RegisterType((*MsgFundConsumerFeePoolResponse)(nil), "vaas.provider.v1.MsgFundConsumerFeePoolResponse") + proto.RegisterType((*MsgWithdrawConsumerFeePool)(nil), "vaas.provider.v1.MsgWithdrawConsumerFeePool") + proto.RegisterType((*MsgWithdrawConsumerFeePoolResponse)(nil), "vaas.provider.v1.MsgWithdrawConsumerFeePoolResponse") + proto.RegisterType((*MsgSweepConsumerFeePool)(nil), "vaas.provider.v1.MsgSweepConsumerFeePool") + proto.RegisterType((*MsgSweepConsumerFeePoolResponse)(nil), "vaas.provider.v1.MsgSweepConsumerFeePoolResponse") } func init() { proto.RegisterFile("vaas/provider/v1/tx.proto", fileDescriptor_a07778b1d094765c) } var fileDescriptor_a07778b1d094765c = []byte{ - // 1104 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4d, 0x6f, 0xdc, 0x44, - 0x18, 0x5e, 0xe7, 0xab, 0xed, 0x24, 0xa4, 0xc4, 0xa4, 0x64, 0x77, 0x29, 0xbb, 0xa9, 0x11, 0xb4, - 0x14, 0xb0, 0x49, 0x90, 0x5a, 0x29, 0x42, 0x48, 0xf9, 0x40, 0x62, 0x85, 0x56, 0x44, 0xae, 0xe8, - 0x01, 0x10, 0xd6, 0xd8, 0x9e, 0x7a, 0x47, 0xb1, 0x67, 0x2c, 0xcf, 0xec, 0xa6, 0xcb, 0x09, 0x71, - 0x40, 0x88, 0x13, 0x1c, 0xb8, 0xf7, 0x27, 0xf4, 0xc0, 0x8f, 0xe8, 0xb1, 0x70, 0x42, 0x1c, 0x2a, - 0x94, 0x48, 0x94, 0x33, 0xbf, 0x00, 0x79, 0x3c, 0xf6, 0xda, 0x5e, 0xef, 0x07, 0x85, 0x5e, 0x56, - 0x9e, 0xf7, 0x7d, 0xde, 0x8f, 0x79, 0xde, 0x67, 0x3c, 0x5e, 0xd0, 0x18, 0x40, 0xc8, 0x8c, 0x30, - 0xa2, 0x03, 0xec, 0xa2, 0xc8, 0x18, 0xec, 0x18, 0xfc, 0xbe, 0x1e, 0x46, 0x94, 0x53, 0xf5, 0xc5, - 0xd8, 0xa5, 0xa7, 0x2e, 0x7d, 0xb0, 0xd3, 0xdc, 0x80, 0x01, 0x26, 0xd4, 0x10, 0xbf, 0x09, 0xa8, - 0xb9, 0xe5, 0x50, 0x16, 0x50, 0x66, 0x04, 0xcc, 0x8b, 0x83, 0x03, 0xe6, 0x49, 0x47, 0x23, 0x71, - 0x58, 0x62, 0x65, 0x24, 0x0b, 0xe9, 0xda, 0xf4, 0xa8, 0x47, 0x13, 0x7b, 0xfc, 0x24, 0xad, 0x57, - 0x3d, 0x4a, 0x3d, 0x1f, 0x19, 0x30, 0xc4, 0x06, 0x24, 0x84, 0x72, 0xc8, 0x31, 0x25, 0x69, 0x4c, - 0x43, 0x7a, 0xc5, 0xca, 0xee, 0xdf, 0x33, 0x20, 0x19, 0x4a, 0x57, 0xab, 0xec, 0x72, 0xfb, 0x91, - 0x88, 0x95, 0xfe, 0x76, 0xd9, 0xcf, 0x71, 0x80, 0x18, 0x87, 0x41, 0x98, 0x02, 0xb0, 0xed, 0x18, - 0x0e, 0x8d, 0x90, 0xe1, 0xf8, 0x18, 0x11, 0x1e, 0x6f, 0x24, 0x79, 0x92, 0x00, 0x23, 0x06, 0xf8, - 0xd8, 0xeb, 0xf1, 0xc4, 0xcc, 0x0c, 0x8e, 0x88, 0x8b, 0xa2, 0x00, 0x27, 0xe0, 0xd1, 0x2a, 0xcd, - 0x98, 0xf3, 0xf3, 0x61, 0x88, 0x98, 0x81, 0x62, 0x12, 0x89, 0x83, 0x52, 0xc0, 0x18, 0xed, 0x19, - 0xcf, 0x02, 0xa0, 0xfd, 0xae, 0x80, 0xcd, 0x2e, 0xf3, 0xf6, 0x19, 0xc3, 0x1e, 0x39, 0xa4, 0x84, - 0xf5, 0x03, 0x14, 0x7d, 0x8c, 0x86, 0x6a, 0x1b, 0xac, 0x3a, 0x72, 0x69, 0x61, 0xb7, 0xae, 0x6c, - 0x2b, 0x37, 0x96, 0x4c, 0x90, 0x9a, 0x3a, 0xae, 0x7a, 0x1b, 0xbc, 0x90, 0xe6, 0xb2, 0xa0, 0xeb, - 0x46, 0xf5, 0x85, 0x6d, 0xe5, 0xc6, 0xa5, 0x03, 0xf5, 0xef, 0x27, 0xed, 0xf5, 0x21, 0x0c, 0xfc, - 0x3d, 0x2d, 0xb6, 0x22, 0xc6, 0x34, 0x73, 0x2d, 0x05, 0xee, 0xbb, 0x6e, 0xa4, 0x5e, 0x03, 0x6b, - 0x59, 0xe6, 0x13, 0x34, 0xac, 0x2f, 0xc6, 0x71, 0x66, 0x56, 0x2d, 0x2e, 0xfe, 0x2e, 0x58, 0x89, - 0xfb, 0x41, 0x51, 0x7d, 0x49, 0x24, 0xad, 0xff, 0xfa, 0xf3, 0x3b, 0x9b, 0x72, 0xb6, 0xfb, 0x49, - 0xd6, 0x3b, 0x3c, 0xc2, 0xc4, 0x33, 0x25, 0x6e, 0xef, 0xa5, 0xef, 0x1e, 0xb4, 0x6b, 0x7f, 0x3d, - 0x68, 0xd7, 0xbe, 0x79, 0xfa, 0xf0, 0xa6, 0x34, 0x6a, 0x2d, 0x70, 0xb5, 0x6a, 0x6f, 0x26, 0x62, - 0x21, 0x25, 0x0c, 0x69, 0x67, 0x0a, 0x78, 0xb5, 0xcb, 0xbc, 0x3b, 0x7d, 0x3b, 0xc0, 0x3c, 0x05, - 0x74, 0x31, 0xb3, 0x51, 0x0f, 0x0e, 0x30, 0xed, 0x47, 0xea, 0x2d, 0x70, 0x89, 0x09, 0x2f, 0x47, - 0x91, 0xe0, 0x60, 0x5a, 0x2f, 0x23, 0xa8, 0x7a, 0x0c, 0xd6, 0x82, 0x5c, 0x1e, 0xc1, 0xcd, 0xea, - 0xee, 0xdb, 0x3a, 0xb6, 0x1d, 0x3d, 0x3f, 0x60, 0x3d, 0x37, 0xd2, 0xc1, 0x8e, 0x9e, 0xaf, 0x6d, - 0x16, 0x32, 0x94, 0xe7, 0xb1, 0x58, 0x9e, 0xc7, 0xde, 0xcb, 0x79, 0x06, 0x46, 0xad, 0x68, 0xd7, - 0xc1, 0xeb, 0x53, 0xf7, 0x98, 0xb1, 0xf1, 0xcb, 0x42, 0x05, 0x1b, 0x47, 0xb4, 0x6f, 0xfb, 0xe8, - 0x2e, 0xe5, 0x98, 0x78, 0xcf, 0xcc, 0x86, 0x05, 0xb6, 0xdc, 0x7e, 0xe8, 0x63, 0x07, 0x72, 0x64, - 0x0d, 0x28, 0x47, 0x56, 0x2a, 0x53, 0x49, 0xcc, 0xf5, 0x3c, 0x0f, 0x42, 0xc8, 0xfa, 0x51, 0x1a, - 0x70, 0x97, 0x72, 0xf4, 0xa1, 0x84, 0x9b, 0x57, 0xdc, 0x2a, 0xb3, 0xfa, 0x25, 0xd8, 0xc2, 0xe4, - 0x5e, 0x04, 0x9d, 0xf8, 0x38, 0x5a, 0xb6, 0x4f, 0x9d, 0x13, 0xab, 0x87, 0xa0, 0x8b, 0x22, 0x41, - 0xd4, 0xea, 0xee, 0x1b, 0xb3, 0x98, 0xff, 0x48, 0xa0, 0xcd, 0x2b, 0xa3, 0x34, 0x07, 0x71, 0x96, - 0xc4, 0x5c, 0x26, 0x7f, 0xe9, 0x3f, 0x91, 0x9f, 0xa7, 0x34, 0x23, 0xff, 0x47, 0x05, 0x5c, 0xee, - 0x32, 0xef, 0xd3, 0xd0, 0x85, 0x1c, 0x1d, 0xc3, 0x08, 0x06, 0x2c, 0xa6, 0x1b, 0xf6, 0x79, 0x8f, - 0x46, 0x98, 0x0f, 0x67, 0xd3, 0x9d, 0x41, 0xd5, 0x5b, 0x60, 0x25, 0x14, 0x19, 0x24, 0xbb, 0x75, - 0xbd, 0xfc, 0x86, 0xd5, 0x93, 0x0a, 0x07, 0x4b, 0x8f, 0x9e, 0xb4, 0x6b, 0xa6, 0x44, 0xef, 0xad, - 0x8b, 0xe6, 0xb3, 0x3c, 0x5a, 0x03, 0x6c, 0x95, 0x5a, 0xca, 0xda, 0x0d, 0xc1, 0x46, 0x97, 0x79, - 0x26, 0x0a, 0xe8, 0x00, 0xa5, 0xfb, 0x9a, 0xfd, 0xca, 0xd0, 0xc1, 0x32, 0x3d, 0x8d, 0x4f, 0xf5, - 0xc2, 0x8c, 0xcd, 0x24, 0xb0, 0x3d, 0x10, 0x37, 0x94, 0x3c, 0x6b, 0xaf, 0x80, 0xc6, 0x58, 0xc5, - 0xac, 0x9d, 0xef, 0x17, 0x45, 0x3f, 0x87, 0x11, 0x82, 0x7c, 0xd4, 0xcf, 0xb3, 0xca, 0xb5, 0x01, - 0x2e, 0x3a, 0x3d, 0x88, 0x49, 0xbc, 0x09, 0xd1, 0xa9, 0x79, 0x41, 0xac, 0x3b, 0xae, 0x7a, 0x04, - 0x2e, 0x06, 0x88, 0x43, 0x17, 0x72, 0x28, 0x95, 0xa5, 0x8d, 0x93, 0x9b, 0x9d, 0x32, 0x89, 0x94, - 0x34, 0x67, 0x91, 0x2a, 0x05, 0x0d, 0x4c, 0x30, 0xc7, 0xd0, 0xc7, 0x5f, 0x89, 0x1b, 0xc4, 0x12, - 0x13, 0x40, 0x1c, 0x45, 0x4c, 0x88, 0x6b, 0x75, 0x77, 0x77, 0x72, 0xda, 0x4e, 0x21, 0xf4, 0x38, - 0x8b, 0x34, 0xeb, 0x78, 0x82, 0x47, 0xfd, 0x1c, 0xe4, 0x84, 0x9d, 0x2f, 0xb6, 0x2c, 0x4f, 0xc7, - 0x58, 0xb1, 0x4e, 0x06, 0xcf, 0x15, 0xd8, 0xc4, 0x15, 0x56, 0x29, 0x9b, 0x91, 0xe6, 0xdf, 0x17, - 0x93, 0x2a, 0xce, 0x22, 0x9d, 0xd4, 0x4c, 0x8d, 0x68, 0x7f, 0x26, 0xa3, 0x4c, 0x54, 0x97, 0x8d, - 0x32, 0x53, 0x8e, 0x32, 0x97, 0x72, 0xca, 0x65, 0x16, 0xc6, 0xa4, 0x78, 0x04, 0x36, 0x08, 0x3a, - 0xb5, 0x04, 0xda, 0x92, 0x17, 0x55, 0x72, 0x13, 0x4d, 0x49, 0x7e, 0x99, 0xa0, 0xd3, 0x4f, 0xe2, - 0x08, 0x69, 0x56, 0x3f, 0xc8, 0xc9, 0x61, 0x69, 0x5e, 0x39, 0xcc, 0x2b, 0x84, 0xe5, 0xe7, 0x20, - 0x84, 0x6d, 0xb0, 0x16, 0x6f, 0x3b, 0x93, 0xf7, 0x8a, 0x90, 0x37, 0x20, 0xe8, 0xf4, 0x50, 0x2a, - 0x7c, 0xa2, 0x54, 0x2e, 0xfc, 0x0f, 0x52, 0x19, 0x3f, 0xd0, 0xc5, 0x39, 0xa7, 0x32, 0xd9, 0xfd, - 0x69, 0x05, 0x2c, 0x76, 0x99, 0xa7, 0x9e, 0x80, 0x8d, 0xf1, 0x4f, 0x93, 0x8a, 0x1e, 0xaa, 0xae, - 0xf9, 0xa6, 0x3e, 0x1f, 0x2e, 0xd3, 0xe6, 0xb7, 0x0a, 0x68, 0x4e, 0xf9, 0x16, 0x30, 0x2a, 0xd3, - 0x4d, 0x0e, 0x68, 0xde, 0xfe, 0x97, 0x01, 0x53, 0x1a, 0x29, 0x5c, 0xc3, 0xf3, 0x34, 0x92, 0x0f, - 0x98, 0xab, 0x91, 0xaa, 0x5b, 0x49, 0xb5, 0xc1, 0x7a, 0xe9, 0x9d, 0xfa, 0x5a, 0x65, 0xaa, 0x22, - 0xa8, 0xf9, 0xd6, 0x1c, 0xa0, 0x7c, 0x8d, 0xd2, 0x61, 0xaf, 0xae, 0x51, 0x04, 0x4d, 0xa8, 0x51, - 0x2d, 0xa7, 0xb8, 0x46, 0xe9, 0xae, 0xaa, 0xae, 0x51, 0x04, 0x4d, 0xa8, 0x51, 0x7d, 0x07, 0xa9, - 0x5f, 0x80, 0xb5, 0xc2, 0xed, 0x7d, 0x6d, 0x4a, 0x83, 0x09, 0xa4, 0xf9, 0xe6, 0x4c, 0x48, 0x9a, - 0xbd, 0xb9, 0xfc, 0xf5, 0xd3, 0x87, 0x37, 0x95, 0x83, 0xce, 0xa3, 0xb3, 0x96, 0xf2, 0xf8, 0xac, - 0xa5, 0xfc, 0x71, 0xd6, 0x52, 0x7e, 0x38, 0x6f, 0xd5, 0x1e, 0x9f, 0xb7, 0x6a, 0xbf, 0x9d, 0xb7, - 0x6a, 0x9f, 0x19, 0x1e, 0xe6, 0xbd, 0xbe, 0xad, 0x3b, 0x34, 0x30, 0xa0, 0xef, 0x63, 0x62, 0x63, - 0xce, 0x0c, 0xf1, 0xf9, 0x7f, 0xdf, 0x28, 0xfe, 0x0b, 0x10, 0x1f, 0x58, 0xf6, 0x8a, 0xf8, 0x03, - 0xf0, 0xde, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x54, 0xa0, 0xc5, 0xf0, 0x9a, 0x0d, 0x00, 0x00, + // 1349 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4d, 0x6c, 0x1b, 0x45, + 0x14, 0xce, 0xe6, 0xaf, 0xcd, 0x24, 0xb4, 0x64, 0x9b, 0x36, 0xb6, 0x29, 0x76, 0xba, 0x08, 0x1a, + 0x4a, 0xbb, 0xdb, 0x04, 0x68, 0xa5, 0xa8, 0x42, 0x6a, 0x12, 0x2a, 0x22, 0x64, 0x11, 0x6d, 0x45, + 0x91, 0x00, 0x61, 0xcd, 0xee, 0x4e, 0xd7, 0xa3, 0x78, 0x67, 0xcc, 0xce, 0xd8, 0x69, 0x90, 0x90, + 0x10, 0x07, 0x04, 0x9c, 0xe0, 0xc8, 0xad, 0x47, 0xc4, 0xa9, 0x07, 0xce, 0x9c, 0x7b, 0x2c, 0x9c, + 0x10, 0x87, 0x82, 0x52, 0x89, 0x72, 0xe2, 0xc0, 0x1d, 0x09, 0xed, 0xec, 0xec, 0x78, 0x6d, 0x8f, + 0x7f, 0x5a, 0xa0, 0x97, 0xc4, 0x33, 0xef, 0x7b, 0x7f, 0xdf, 0x7b, 0x33, 0xf3, 0xb4, 0xa0, 0xd8, + 0x86, 0x90, 0x39, 0xcd, 0x98, 0xb6, 0x71, 0x80, 0x62, 0xa7, 0xbd, 0xe6, 0xf0, 0x5b, 0x76, 0x33, + 0xa6, 0x9c, 0x9a, 0x4f, 0x27, 0x22, 0x3b, 0x13, 0xd9, 0xed, 0xb5, 0xd2, 0x22, 0x8c, 0x30, 0xa1, + 0x8e, 0xf8, 0x9b, 0x82, 0x4a, 0x65, 0x9f, 0xb2, 0x88, 0x32, 0xc7, 0x83, 0x0c, 0x39, 0xed, 0x35, + 0x0f, 0x71, 0xb8, 0xe6, 0xf8, 0x14, 0x13, 0x29, 0x5f, 0x96, 0xf2, 0x88, 0x85, 0x89, 0xf1, 0x88, + 0x85, 0x52, 0x50, 0x4c, 0x05, 0x35, 0xb1, 0x72, 0xd2, 0x85, 0x14, 0x2d, 0x85, 0x34, 0xa4, 0xe9, + 0x7e, 0xf2, 0x4b, 0xee, 0x9e, 0x0e, 0x29, 0x0d, 0x1b, 0xc8, 0x81, 0x4d, 0xec, 0x40, 0x42, 0x28, + 0x87, 0x1c, 0x53, 0x92, 0xe9, 0x14, 0xa5, 0x54, 0xac, 0xbc, 0xd6, 0x4d, 0x07, 0x92, 0x83, 0x2c, + 0xc4, 0x5e, 0x51, 0xd0, 0x8a, 0x85, 0xae, 0x94, 0x57, 0x7a, 0xe5, 0x1c, 0x47, 0x88, 0x71, 0x18, + 0x35, 0x33, 0x00, 0xf6, 0x7c, 0xc7, 0xa7, 0x31, 0x72, 0xfc, 0x06, 0x46, 0x84, 0x27, 0x89, 0xa4, + 0xbf, 0x24, 0xc0, 0x49, 0x00, 0x0d, 0x1c, 0xd6, 0x79, 0xba, 0xcd, 0x1c, 0x8e, 0x48, 0x80, 0xe2, + 0x08, 0xa7, 0xe0, 0xce, 0x2a, 0xb3, 0x98, 0x93, 0xf3, 0x83, 0x26, 0x62, 0x0e, 0x4a, 0x48, 0x26, + 0x3e, 0xca, 0x00, 0x7d, 0x65, 0x51, 0x75, 0x10, 0x00, 0xeb, 0x17, 0x03, 0x2c, 0x55, 0x59, 0x78, + 0x95, 0x31, 0x1c, 0x92, 0x2d, 0x4a, 0x58, 0x2b, 0x42, 0xf1, 0x9b, 0xe8, 0xc0, 0xac, 0x80, 0x79, + 0x5f, 0x2e, 0x6b, 0x38, 0x28, 0x18, 0x2b, 0xc6, 0xea, 0xb4, 0x0b, 0xb2, 0xad, 0x9d, 0xc0, 0xbc, + 0x0c, 0x9e, 0xca, 0x6c, 0xd5, 0x60, 0x10, 0xc4, 0x85, 0xc9, 0x15, 0x63, 0x75, 0x6e, 0xd3, 0xfc, + 0xeb, 0x7e, 0xe5, 0xd8, 0x01, 0x8c, 0x1a, 0x1b, 0x56, 0xb2, 0x8b, 0x18, 0xb3, 0xdc, 0x85, 0x0c, + 0x78, 0x35, 0x08, 0x62, 0xf3, 0x0c, 0x58, 0x50, 0x96, 0xf7, 0xd0, 0x41, 0x61, 0x2a, 0xd1, 0x73, + 0x95, 0xb7, 0xc4, 0xf9, 0x45, 0x30, 0x9b, 0xc4, 0x83, 0xe2, 0xc2, 0xb4, 0x30, 0x5a, 0xf8, 0xe9, + 0xfb, 0x0b, 0x4b, 0xb2, 0xb6, 0x57, 0x53, 0xab, 0xd7, 0x79, 0x8c, 0x49, 0xe8, 0x4a, 0xdc, 0xc6, + 0x89, 0xcf, 0x6f, 0x57, 0x26, 0xfe, 0xb8, 0x5d, 0x99, 0xf8, 0xf4, 0xe1, 0x9d, 0x73, 0x72, 0xd3, + 0x2a, 0x83, 0xd3, 0xba, 0xdc, 0x5c, 0xc4, 0x9a, 0x94, 0x30, 0x64, 0x1d, 0x1a, 0xe0, 0xd9, 0x2a, + 0x0b, 0xaf, 0xb7, 0xbc, 0x08, 0xf3, 0x0c, 0x50, 0xc5, 0xcc, 0x43, 0x75, 0xd8, 0xc6, 0xb4, 0x15, + 0x9b, 0x97, 0xc0, 0x1c, 0x13, 0x52, 0x8e, 0x62, 0xc1, 0xc1, 0xb0, 0x58, 0x3a, 0x50, 0x73, 0x17, + 0x2c, 0x44, 0x39, 0x3b, 0x82, 0x9b, 0xf9, 0xf5, 0xf3, 0x36, 0xf6, 0x7c, 0x3b, 0x5f, 0x60, 0x3b, + 0x57, 0xd2, 0xf6, 0x9a, 0x9d, 0xf7, 0xed, 0x76, 0x59, 0xe8, 0xad, 0xc7, 0x54, 0x6f, 0x3d, 0x36, + 0x4e, 0xe5, 0x19, 0xe8, 0x84, 0x62, 0x9d, 0x05, 0xcf, 0x0f, 0xcd, 0x51, 0xb1, 0xf1, 0xe3, 0xa4, + 0x86, 0x8d, 0x6d, 0xda, 0xf2, 0x1a, 0xe8, 0x06, 0xe5, 0x98, 0x84, 0x8f, 0xcd, 0x46, 0x0d, 0x2c, + 0x07, 0xad, 0x66, 0x03, 0xfb, 0x90, 0xa3, 0x5a, 0x9b, 0x72, 0x54, 0xcb, 0xda, 0x54, 0x12, 0x73, + 0x36, 0xcf, 0x83, 0x68, 0x64, 0x7b, 0x3b, 0x53, 0xb8, 0x41, 0x39, 0x7a, 0x5d, 0xc2, 0xdd, 0x93, + 0x81, 0x6e, 0xdb, 0xfc, 0x00, 0x2c, 0x63, 0x72, 0x33, 0x86, 0x7e, 0x72, 0x1c, 0x6b, 0x5e, 0x83, + 0xfa, 0x7b, 0xb5, 0x3a, 0x82, 0x01, 0x8a, 0x05, 0x51, 0xf3, 0xeb, 0x2f, 0x8c, 0x62, 0xfe, 0x0d, + 0x81, 0x76, 0x4f, 0x76, 0xcc, 0x6c, 0x26, 0x56, 0xd2, 0xed, 0x5e, 0xf2, 0xa7, 0xff, 0x15, 0xf9, + 0x79, 0x4a, 0x15, 0xf9, 0x5f, 0x1b, 0xe0, 0x78, 0x95, 0x85, 0x6f, 0x37, 0x03, 0xc8, 0xd1, 0x2e, + 0x8c, 0x61, 0xc4, 0x12, 0xba, 0x61, 0x8b, 0xd7, 0x69, 0x8c, 0xf9, 0xc1, 0x68, 0xba, 0x15, 0xd4, + 0xbc, 0x04, 0x66, 0x9b, 0xc2, 0x82, 0x64, 0xb7, 0x60, 0xf7, 0xde, 0xc0, 0x76, 0xea, 0x61, 0x73, + 0xfa, 0xee, 0xfd, 0xca, 0x84, 0x2b, 0xd1, 0x1b, 0xc7, 0x44, 0xf0, 0xca, 0x8e, 0x55, 0x04, 0xcb, + 0x3d, 0x21, 0xa9, 0x70, 0x9b, 0x60, 0xb1, 0xca, 0x42, 0x17, 0x45, 0xb4, 0x8d, 0xb2, 0xbc, 0x46, + 0x5f, 0x19, 0x36, 0x98, 0xa1, 0xfb, 0xc9, 0xa9, 0x9e, 0x1c, 0x91, 0x4c, 0x0a, 0xdb, 0x00, 0x49, + 0x40, 0xe9, 0x6f, 0xeb, 0x19, 0x50, 0xec, 0xf3, 0xa8, 0xc2, 0xf9, 0x72, 0x4a, 0xc4, 0xb3, 0x15, + 0x23, 0xc8, 0x3b, 0xf1, 0x3c, 0x6e, 0xbb, 0x16, 0xc1, 0x51, 0xbf, 0x0e, 0x31, 0x49, 0x92, 0x10, + 0x91, 0xba, 0x47, 0xc4, 0x7a, 0x27, 0x30, 0xb7, 0xc1, 0xd1, 0x08, 0x71, 0x18, 0x40, 0x0e, 0x65, + 0x67, 0x59, 0xfd, 0xe4, 0xaa, 0x53, 0x26, 0x91, 0x92, 0x66, 0xa5, 0x69, 0x52, 0x50, 0xc4, 0x04, + 0x73, 0x0c, 0x1b, 0xf8, 0x23, 0xf1, 0x82, 0xd4, 0x44, 0x05, 0x10, 0x47, 0x31, 0x13, 0xcd, 0x35, + 0xbf, 0xbe, 0x3e, 0xd8, 0xec, 0x4e, 0x97, 0xea, 0xae, 0xd2, 0x74, 0x0b, 0x78, 0x80, 0xc4, 0x7c, + 0x0f, 0xe4, 0x1a, 0x3b, 0xef, 0x6c, 0x46, 0x9e, 0x8e, 0x3e, 0x67, 0x3b, 0x0a, 0x9e, 0x73, 0xb0, + 0x84, 0x35, 0xbb, 0xb2, 0x6d, 0x3a, 0x3d, 0x7f, 0x45, 0x54, 0xaa, 0xbb, 0x16, 0x59, 0xa5, 0x46, + 0xf6, 0x88, 0xf5, 0x7b, 0x5a, 0xca, 0xb4, 0xeb, 0x54, 0x29, 0x55, 0xe7, 0x18, 0x63, 0x75, 0x4e, + 0xaf, 0x9b, 0xc9, 0xbe, 0x56, 0xdc, 0x06, 0x8b, 0x04, 0xed, 0xd7, 0x04, 0xba, 0x26, 0x1f, 0xaa, + 0xf4, 0x25, 0x1a, 0x62, 0xfc, 0x38, 0x41, 0xfb, 0x6f, 0x25, 0x1a, 0x72, 0xdb, 0x7c, 0x2d, 0xd7, + 0x0e, 0xd3, 0xe3, 0xb6, 0xc3, 0xb8, 0x8d, 0x30, 0xf3, 0x3f, 0x34, 0xc2, 0x0a, 0x58, 0x48, 0xd2, + 0x56, 0xed, 0x3d, 0x2b, 0xda, 0x1b, 0x10, 0xb4, 0xbf, 0x25, 0x3b, 0x7c, 0x60, 0xab, 0x1c, 0xf9, + 0x0f, 0x5a, 0xa5, 0xff, 0x40, 0x77, 0xd7, 0x59, 0x1d, 0xe8, 0x1f, 0x0c, 0x70, 0xaa, 0xca, 0xc2, + 0x6b, 0x2d, 0x12, 0x64, 0xb2, 0x6b, 0x08, 0xed, 0x52, 0xda, 0xc8, 0xcd, 0x06, 0xc6, 0x78, 0xb3, + 0x81, 0xae, 0x19, 0xe6, 0xba, 0x9a, 0xe1, 0x0a, 0x98, 0x85, 0x11, 0x6d, 0x11, 0x2e, 0xcf, 0x74, + 0xd1, 0x96, 0xf6, 0x92, 0x69, 0xd4, 0x96, 0xd3, 0xa8, 0xbd, 0x45, 0x31, 0xd9, 0x9c, 0x4b, 0x8e, + 0xf2, 0xb7, 0x0f, 0xef, 0x9c, 0x33, 0x5c, 0xa9, 0xa3, 0x1f, 0x3d, 0x56, 0x40, 0x59, 0x1f, 0xbf, + 0x4a, 0xf1, 0x4f, 0x03, 0x94, 0xaa, 0x2c, 0x7c, 0x07, 0xf3, 0x7a, 0x10, 0xc3, 0xfd, 0x27, 0x90, + 0x66, 0x3d, 0x97, 0xe6, 0xd4, 0xf0, 0x34, 0x5f, 0x4d, 0xd2, 0xfc, 0xee, 0xd7, 0xca, 0x6a, 0x88, + 0x79, 0xbd, 0xe5, 0xd9, 0x3e, 0x8d, 0xe4, 0x6c, 0x2d, 0xff, 0x5d, 0x60, 0xc1, 0x5e, 0x3a, 0x72, + 0x0a, 0x05, 0x36, 0x06, 0x25, 0x5f, 0x18, 0xc0, 0x1a, 0x9c, 0xb0, 0xba, 0x21, 0x7c, 0x15, 0xa5, + 0x31, 0x2a, 0xca, 0x8b, 0x8f, 0x1a, 0x65, 0x16, 0xa0, 0xf5, 0x8d, 0x21, 0xde, 0xb6, 0xeb, 0xfb, + 0x08, 0x35, 0x9f, 0x00, 0xf3, 0xa7, 0xc0, 0x6c, 0x80, 0x08, 0x8d, 0x98, 0x60, 0x7e, 0xce, 0x95, + 0x2b, 0x3d, 0x4f, 0x67, 0x40, 0x65, 0x40, 0x68, 0x19, 0x47, 0xeb, 0x7f, 0x1f, 0x05, 0x53, 0x55, + 0x16, 0x9a, 0x7b, 0x60, 0xb1, 0x7f, 0x72, 0xd7, 0x1c, 0x51, 0xdd, 0x14, 0x5c, 0xb2, 0xc7, 0xc3, + 0xa9, 0xc2, 0x7c, 0x66, 0x80, 0xd2, 0x90, 0x51, 0xd9, 0xd1, 0x9a, 0x1b, 0xac, 0x50, 0xba, 0xfc, + 0x88, 0x0a, 0x43, 0x02, 0xe9, 0x9a, 0x52, 0xc7, 0x09, 0x24, 0xaf, 0x30, 0x56, 0x20, 0xba, 0xa1, + 0xcd, 0xf4, 0xc0, 0xb1, 0x9e, 0x91, 0xe3, 0x39, 0xad, 0xa9, 0x6e, 0x50, 0xe9, 0xa5, 0x31, 0x40, + 0x79, 0x1f, 0x3d, 0x6f, 0xa1, 0xde, 0x47, 0x37, 0x68, 0x80, 0x0f, 0xfd, 0x6d, 0x9b, 0xf8, 0xe8, + 0x19, 0xe5, 0xf4, 0x3e, 0xba, 0x41, 0x03, 0x7c, 0xe8, 0x47, 0x34, 0xf3, 0x7d, 0xb0, 0xd0, 0x35, + 0xdc, 0x9e, 0x19, 0x12, 0x60, 0x0a, 0x29, 0xbd, 0x38, 0x12, 0xa2, 0xac, 0x7f, 0x08, 0x4e, 0xe8, + 0xde, 0x8a, 0x55, 0xad, 0x05, 0x0d, 0xb2, 0x74, 0x71, 0x5c, 0xa4, 0x72, 0xf9, 0x31, 0x58, 0x1e, + 0x74, 0x77, 0x9f, 0xd7, 0x1a, 0x1b, 0x80, 0x2e, 0xbd, 0xf2, 0x28, 0x68, 0xe5, 0x9e, 0x83, 0x25, + 0xed, 0xed, 0xa5, 0x27, 0x4d, 0x07, 0x2d, 0xad, 0x8d, 0x0d, 0xcd, 0xbc, 0x96, 0x66, 0x3e, 0x49, + 0xee, 0xf9, 0xcd, 0x9d, 0xbb, 0x87, 0x65, 0xe3, 0xde, 0x61, 0xd9, 0xf8, 0xed, 0xb0, 0x6c, 0x7c, + 0xf5, 0xa0, 0x3c, 0x71, 0xef, 0x41, 0x79, 0xe2, 0xe7, 0x07, 0xe5, 0x89, 0x77, 0x9d, 0xdc, 0x55, + 0x0c, 0x1b, 0x0d, 0x4c, 0x3c, 0xcc, 0x99, 0x23, 0xbe, 0x42, 0xdc, 0x72, 0xba, 0x3f, 0x46, 0x88, + 0x7b, 0xd9, 0x9b, 0x15, 0xdf, 0x21, 0x5e, 0xfe, 0x27, 0x00, 0x00, 0xff, 0xff, 0x65, 0x47, 0x0d, + 0xe3, 0x41, 0x12, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -841,6 +1115,9 @@ type MsgClient interface { UpdateConsumer(ctx context.Context, in *MsgUpdateConsumer, opts ...grpc.CallOption) (*MsgUpdateConsumerResponse, error) RemoveConsumer(ctx context.Context, in *MsgRemoveConsumer, opts ...grpc.CallOption) (*MsgRemoveConsumerResponse, error) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) + FundConsumerFeePool(ctx context.Context, in *MsgFundConsumerFeePool, opts ...grpc.CallOption) (*MsgFundConsumerFeePoolResponse, error) + WithdrawConsumerFeePool(ctx context.Context, in *MsgWithdrawConsumerFeePool, opts ...grpc.CallOption) (*MsgWithdrawConsumerFeePoolResponse, error) + SweepConsumerFeePool(ctx context.Context, in *MsgSweepConsumerFeePool, opts ...grpc.CallOption) (*MsgSweepConsumerFeePoolResponse, error) } type msgClient struct { @@ -914,6 +1191,33 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts return out, nil } +func (c *msgClient) FundConsumerFeePool(ctx context.Context, in *MsgFundConsumerFeePool, opts ...grpc.CallOption) (*MsgFundConsumerFeePoolResponse, error) { + out := new(MsgFundConsumerFeePoolResponse) + err := c.cc.Invoke(ctx, "/vaas.provider.v1.Msg/FundConsumerFeePool", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) WithdrawConsumerFeePool(ctx context.Context, in *MsgWithdrawConsumerFeePool, opts ...grpc.CallOption) (*MsgWithdrawConsumerFeePoolResponse, error) { + out := new(MsgWithdrawConsumerFeePoolResponse) + err := c.cc.Invoke(ctx, "/vaas.provider.v1.Msg/WithdrawConsumerFeePool", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) SweepConsumerFeePool(ctx context.Context, in *MsgSweepConsumerFeePool, opts ...grpc.CallOption) (*MsgSweepConsumerFeePoolResponse, error) { + out := new(MsgSweepConsumerFeePoolResponse) + err := c.cc.Invoke(ctx, "/vaas.provider.v1.Msg/SweepConsumerFeePool", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { AssignConsumerKey(context.Context, *MsgAssignConsumerKey) (*MsgAssignConsumerKeyResponse, error) @@ -923,6 +1227,9 @@ type MsgServer interface { UpdateConsumer(context.Context, *MsgUpdateConsumer) (*MsgUpdateConsumerResponse, error) RemoveConsumer(context.Context, *MsgRemoveConsumer) (*MsgRemoveConsumerResponse, error) UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) + FundConsumerFeePool(context.Context, *MsgFundConsumerFeePool) (*MsgFundConsumerFeePoolResponse, error) + WithdrawConsumerFeePool(context.Context, *MsgWithdrawConsumerFeePool) (*MsgWithdrawConsumerFeePoolResponse, error) + SweepConsumerFeePool(context.Context, *MsgSweepConsumerFeePool) (*MsgSweepConsumerFeePoolResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -950,6 +1257,15 @@ func (*UnimplementedMsgServer) RemoveConsumer(ctx context.Context, req *MsgRemov func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") } +func (*UnimplementedMsgServer) FundConsumerFeePool(ctx context.Context, req *MsgFundConsumerFeePool) (*MsgFundConsumerFeePoolResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FundConsumerFeePool not implemented") +} +func (*UnimplementedMsgServer) WithdrawConsumerFeePool(ctx context.Context, req *MsgWithdrawConsumerFeePool) (*MsgWithdrawConsumerFeePoolResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method WithdrawConsumerFeePool not implemented") +} +func (*UnimplementedMsgServer) SweepConsumerFeePool(ctx context.Context, req *MsgSweepConsumerFeePool) (*MsgSweepConsumerFeePoolResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SweepConsumerFeePool not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -1081,6 +1397,60 @@ func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } +func _Msg_FundConsumerFeePool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgFundConsumerFeePool) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).FundConsumerFeePool(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/vaas.provider.v1.Msg/FundConsumerFeePool", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).FundConsumerFeePool(ctx, req.(*MsgFundConsumerFeePool)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_WithdrawConsumerFeePool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgWithdrawConsumerFeePool) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).WithdrawConsumerFeePool(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/vaas.provider.v1.Msg/WithdrawConsumerFeePool", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).WithdrawConsumerFeePool(ctx, req.(*MsgWithdrawConsumerFeePool)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_SweepConsumerFeePool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSweepConsumerFeePool) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SweepConsumerFeePool(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/vaas.provider.v1.Msg/SweepConsumerFeePool", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SweepConsumerFeePool(ctx, req.(*MsgSweepConsumerFeePool)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "vaas.provider.v1.Msg", HandlerType: (*MsgServer)(nil), @@ -1113,6 +1483,18 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "UpdateParams", Handler: _Msg_UpdateParams_Handler, }, + { + MethodName: "FundConsumerFeePool", + Handler: _Msg_FundConsumerFeePool_Handler, + }, + { + MethodName: "WithdrawConsumerFeePool", + Handler: _Msg_WithdrawConsumerFeePool_Handler, + }, + { + MethodName: "SweepConsumerFeePool", + Handler: _Msg_SweepConsumerFeePool_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "vaas/provider/v1/tx.proto", @@ -1670,44 +2052,271 @@ func (m *MsgUpdateConsumerResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } -func encodeVarintTx(dAtA []byte, offset int, v uint64) int { - offset -= sovTx(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *MsgFundConsumerFeePool) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *MsgAssignConsumerKey) Size() (n int) { - if m == nil { - return 0 - } + +func (m *MsgFundConsumerFeePool) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgFundConsumerFeePool) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.ConsumerId != 0 { - n += 1 + sovTx(uint64(m.ConsumerId)) - } - l = len(m.ProviderAddr) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) } - l = len(m.ConsumerKey) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + i-- + dAtA[i] = 0x1a + if len(m.ConsumerId) > 0 { + i -= len(m.ConsumerId) + copy(dAtA[i:], m.ConsumerId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ConsumerId))) + i-- + dAtA[i] = 0x12 } - l = len(m.Signer) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *MsgAssignConsumerKeyResponse) Size() (n int) { - if m == nil { - return 0 +func (m *MsgFundConsumerFeePoolResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgFundConsumerFeePoolResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgFundConsumerFeePoolResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawConsumerFeePool) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgWithdrawConsumerFeePool) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawConsumerFeePool) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.ConsumerId) > 0 { + i -= len(m.ConsumerId) + copy(dAtA[i:], m.ConsumerId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ConsumerId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgWithdrawConsumerFeePoolResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgWithdrawConsumerFeePoolResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgWithdrawConsumerFeePoolResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *MsgSweepConsumerFeePool) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSweepConsumerFeePool) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSweepConsumerFeePool) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denoms) > 0 { + for iNdEx := len(m.Denoms) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Denoms[iNdEx]) + copy(dAtA[i:], m.Denoms[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Denoms[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.ConsumerId) > 0 { + i -= len(m.ConsumerId) + copy(dAtA[i:], m.ConsumerId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ConsumerId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSweepConsumerFeePoolResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSweepConsumerFeePoolResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSweepConsumerFeePoolResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgAssignConsumerKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ConsumerId != 0 { + n += 1 + sovTx(uint64(m.ConsumerId)) + } + l = len(m.ProviderAddr) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ConsumerKey) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgAssignConsumerKeyResponse) Size() (n int) { + if m == nil { + return 0 } var l int _ = l @@ -1909,6 +2518,104 @@ func (m *MsgUpdateConsumerResponse) Size() (n int) { return n } +func (m *MsgFundConsumerFeePool) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ConsumerId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgFundConsumerFeePoolResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgWithdrawConsumerFeePool) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ConsumerId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgWithdrawConsumerFeePoolResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgSweepConsumerFeePool) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ConsumerId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Denoms) > 0 { + for _, s := range m.Denoms { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgSweepConsumerFeePoolResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -3467,6 +4174,631 @@ func (m *MsgUpdateConsumerResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgFundConsumerFeePool) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgFundConsumerFeePool: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgFundConsumerFeePool: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgFundConsumerFeePoolResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgFundConsumerFeePoolResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgFundConsumerFeePoolResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgWithdrawConsumerFeePool) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgWithdrawConsumerFeePool: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawConsumerFeePool: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types1.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgWithdrawConsumerFeePoolResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgWithdrawConsumerFeePoolResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgWithdrawConsumerFeePoolResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types1.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSweepConsumerFeePool) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSweepConsumerFeePool: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSweepConsumerFeePool: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denoms", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denoms = append(m.Denoms, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSweepConsumerFeePoolResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSweepConsumerFeePoolResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSweepConsumerFeePoolResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From 948351ce14fa94b1d15ea2aa6d1a46bce22620f3 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 16:53:10 +0200 Subject: [PATCH 02/18] wire distribution keeper and register share collections --- app/provider/app.go | 1 + testutil/keeper/mocks.go | 52 ++++++++++++++++++++++++++++ testutil/keeper/unit_test_helpers.go | 15 ++++---- x/vaas/provider/keeper/keeper.go | 45 +++++++++++++++++++----- x/vaas/types/expected_keepers.go | 7 ++++ 5 files changed, 106 insertions(+), 14 deletions(-) diff --git a/app/provider/app.go b/app/provider/app.go index 40e11d1..b83a857 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -392,6 +392,7 @@ func New( app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, + app.DistrKeeper, govkeeper.Keeper{}, // will be set after the GovKeeper is created authtypes.NewModuleAddress(govtypes.ModuleName).String(), authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()), diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 0f38214..231fcca 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -877,3 +877,55 @@ func (mr *MockIBCTransferKeeperMockRecorder) Transfer(arg0, arg1 any) *gomock.Ca mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Transfer", reflect.TypeOf((*MockIBCTransferKeeper)(nil).Transfer), arg0, arg1) } + +// MockDistributionKeeper is a mock of DistributionKeeper interface. +type MockDistributionKeeper struct { + ctrl *gomock.Controller + recorder *MockDistributionKeeperMockRecorder + isgomock struct{} +} + +// MockDistributionKeeperMockRecorder is the mock recorder for MockDistributionKeeper. +type MockDistributionKeeperMockRecorder struct { + mock *MockDistributionKeeper +} + +// NewMockDistributionKeeper creates a new mock instance. +func NewMockDistributionKeeper(ctrl *gomock.Controller) *MockDistributionKeeper { + mock := &MockDistributionKeeper{ctrl: ctrl} + mock.recorder = &MockDistributionKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDistributionKeeper) EXPECT() *MockDistributionKeeperMockRecorder { + return m.recorder +} + +// DistributeFromFeePool mocks base method. +func (m *MockDistributionKeeper) DistributeFromFeePool(ctx context.Context, amount types.Coins, receiveAddr types.AccAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DistributeFromFeePool", ctx, amount, receiveAddr) + ret0, _ := ret[0].(error) + return ret0 +} + +// DistributeFromFeePool indicates an expected call of DistributeFromFeePool. +func (mr *MockDistributionKeeperMockRecorder) DistributeFromFeePool(ctx, amount, receiveAddr any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DistributeFromFeePool", reflect.TypeOf((*MockDistributionKeeper)(nil).DistributeFromFeePool), ctx, amount, receiveAddr) +} + +// FundCommunityPool mocks base method. +func (m *MockDistributionKeeper) FundCommunityPool(ctx context.Context, amount types.Coins, sender types.AccAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FundCommunityPool", ctx, amount, sender) + ret0, _ := ret[0].(error) + return ret0 +} + +// FundCommunityPool indicates an expected call of FundCommunityPool. +func (mr *MockDistributionKeeperMockRecorder) FundCommunityPool(ctx, amount, sender any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FundCommunityPool", reflect.TypeOf((*MockDistributionKeeper)(nil).FundCommunityPool), ctx, amount, sender) +} diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index 4c00289..be2d657 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -75,17 +75,19 @@ type MockedKeepers struct { *MockSlashingKeeper *MockAccountKeeper *MockBankKeeper + *MockDistributionKeeper } // NewMockedKeepers instantiates a struct with pointers to properly instantiated mocked keepers. func NewMockedKeepers(ctrl *gomock.Controller) MockedKeepers { mocks := MockedKeepers{ - MockClientKeeper: NewMockClientKeeper(ctrl), - MockClientV2Keeper: NewMockClientV2Keeper(ctrl), - MockStakingKeeper: NewMockStakingKeeper(ctrl), - MockSlashingKeeper: NewMockSlashingKeeper(ctrl), - MockAccountKeeper: NewMockAccountKeeper(ctrl), - MockBankKeeper: NewMockBankKeeper(ctrl), + MockClientKeeper: NewMockClientKeeper(ctrl), + MockClientV2Keeper: NewMockClientV2Keeper(ctrl), + MockStakingKeeper: NewMockStakingKeeper(ctrl), + MockSlashingKeeper: NewMockSlashingKeeper(ctrl), + MockAccountKeeper: NewMockAccountKeeper(ctrl), + MockBankKeeper: NewMockBankKeeper(ctrl), + MockDistributionKeeper: NewMockDistributionKeeper(ctrl), } mocks.MockClientV2Keeper.EXPECT().GetClientCounterparty(gomock.Any(), gomock.Any()).Return(clientv2types.CounterpartyInfo{}, false).AnyTimes() mocks.MockClientV2Keeper.EXPECT().SetClientCounterparty(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() @@ -104,6 +106,7 @@ func NewInMemProviderKeeper(params InMemKeeperParams, mocks MockedKeepers) provi mocks.MockSlashingKeeper, mocks.MockAccountKeeper, mocks.MockBankKeeper, + mocks.MockDistributionKeeper, govkeeper.Keeper{}, // HACK: to make parts of the test work authtypes.NewModuleAddress(govtypes.ModuleName).String(), address.NewBech32Codec("cosmosvaloper"), diff --git a/x/vaas/provider/keeper/keeper.go b/x/vaas/provider/keeper/keeper.go index a3db49e..1be5860 100644 --- a/x/vaas/provider/keeper/keeper.go +++ b/x/vaas/provider/keeper/keeper.go @@ -17,6 +17,7 @@ import ( addresscodec "cosmossdk.io/core/address" corestoretypes "cosmossdk.io/core/store" "cosmossdk.io/log" + "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -35,11 +36,12 @@ type Keeper struct { accountKeeper vaastypes.AccountKeeper clientKeeper vaastypes.ClientKeeper clientV2Keeper vaastypes.ClientV2Keeper - stakingKeeper vaastypes.StakingKeeper - slashingKeeper vaastypes.SlashingKeeper - bankKeeper vaastypes.BankKeeper - govKeeper govkeeper.Keeper - feeCollectorName string + stakingKeeper vaastypes.StakingKeeper + slashingKeeper vaastypes.SlashingKeeper + bankKeeper vaastypes.BankKeeper + distributionKeeper vaastypes.DistributionKeeper + govKeeper govkeeper.Keeper + feeCollectorName string validatorAddressCodec addresscodec.Codec consensusAddressCodec addresscodec.Codec @@ -76,6 +78,11 @@ type Keeper struct { // Validator set collections ConsumerValidators collections.Map[collections.Pair[uint64, []byte], types.ConsensusValidator] LastProviderConsensusVals collections.Map[[]byte, types.ConsensusValidator] + + // Fee pool collections + ConsumerFeePoolShares collections.Map[collections.Triple[string, sdk.AccAddress, string], math.Int] + ConsumerFeePoolTotalShares collections.Map[collections.Pair[string, string], math.Int] + FeePoolAddressToConsumerId collections.Map[sdk.AccAddress, string] } // NewKeeper creates a new provider Keeper instance @@ -85,9 +92,10 @@ func NewKeeper( clientV2Keeper vaastypes.ClientV2Keeper, stakingKeeper vaastypes.StakingKeeper, slashingKeeper vaastypes.SlashingKeeper, accountKeeper vaastypes.AccountKeeper, - bankKeeper vaastypes.BankKeeper, - govKeeper govkeeper.Keeper, - authority string, + bankKeeper vaastypes.BankKeeper, + distributionKeeper vaastypes.DistributionKeeper, + govKeeper govkeeper.Keeper, + authority string, validatorAddressCodec, consensusAddressCodec addresscodec.Codec, feeCollectorName string, ) Keeper { @@ -103,6 +111,7 @@ func NewKeeper( slashingKeeper: slashingKeeper, accountKeeper: accountKeeper, bankKeeper: bankKeeper, + distributionKeeper: distributionKeeper, feeCollectorName: feeCollectorName, validatorAddressCodec: validatorAddressCodec, consensusAddressCodec: consensusAddressCodec, @@ -156,6 +165,26 @@ func NewKeeper( LastProviderConsensusVals: collections.NewMap(sb, types.LastProviderConsensusVals, "last_provider_consensus_vals", collections.BytesKey, codec.CollValue[types.ConsensusValidator](cdc)), } + // Fee pool collections + k.ConsumerFeePoolShares = collections.NewMap( + sb, types.ConsumerFeePoolSharesKeyPrefix, + types.ConsumerFeePoolSharesKeyName, + collections.TripleKeyCodec(collections.StringKey, sdk.AccAddressKey, collections.StringKey), + sdk.IntValue, + ) + k.ConsumerFeePoolTotalShares = collections.NewMap( + sb, types.ConsumerFeePoolTotalSharesKeyPrefix, + types.ConsumerFeePoolTotalSharesKeyName, + collections.PairKeyCodec(collections.StringKey, collections.StringKey), + sdk.IntValue, + ) + k.FeePoolAddressToConsumerId = collections.NewMap( + sb, types.FeePoolAddressToConsumerIdKeyPrefix, + types.FeePoolAddressToConsumerIdKeyName, + sdk.AccAddressKey, + collections.StringValue, + ) + schema, err := sb.Build() if err != nil { panic(err) diff --git a/x/vaas/types/expected_keepers.go b/x/vaas/types/expected_keepers.go index 9f002ba..94d0252 100644 --- a/x/vaas/types/expected_keepers.go +++ b/x/vaas/types/expected_keepers.go @@ -105,3 +105,10 @@ type ChannelV2Keeper interface { type IBCTransferKeeper interface { Transfer(context.Context, *transfertypes.MsgTransfer) (*transfertypes.MsgTransferResponse, error) } + +// DistributionKeeper defines the expected interface needed to fund and spend +// from the cosmos-sdk x/distribution community pool. +type DistributionKeeper interface { + FundCommunityPool(ctx context.Context, amount sdk.Coins, sender sdk.AccAddress) error + DistributeFromFeePool(ctx context.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) error +} From 2c49bd084c0ec681b10a32e98f7256defd9816f6 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 17:11:38 +0200 Subject: [PATCH 03/18] share-math helpers: compute, mint, withdraw, sweep --- testutil/keeper/mocks.go | 14 + x/vaas/provider/keeper/fee_pool_shares.go | 360 ++++++++++++++ .../provider/keeper/fee_pool_shares_test.go | 445 ++++++++++++++++++ x/vaas/types/expected_keepers.go | 1 + 4 files changed, 820 insertions(+) create mode 100644 x/vaas/provider/keeper/fee_pool_shares.go create mode 100644 x/vaas/provider/keeper/fee_pool_shares_test.go diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index 231fcca..57a20b9 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -692,6 +692,20 @@ func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder { return m.recorder } +// GetAllBalances mocks base method. +func (m *MockBankKeeper) GetAllBalances(ctx context.Context, addr types.AccAddress) types.Coins { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllBalances", ctx, addr) + ret0, _ := ret[0].(types.Coins) + return ret0 +} + +// GetAllBalances indicates an expected call of GetAllBalances. +func (mr *MockBankKeeperMockRecorder) GetAllBalances(ctx, addr any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllBalances", reflect.TypeOf((*MockBankKeeper)(nil).GetAllBalances), ctx, addr) +} + // GetBalance mocks base method. func (m *MockBankKeeper) GetBalance(ctx context.Context, addr types.AccAddress, denom string) types.Coin { m.ctrl.T.Helper() diff --git a/x/vaas/provider/keeper/fee_pool_shares.go b/x/vaas/provider/keeper/fee_pool_shares.go new file mode 100644 index 0000000..5a79630 --- /dev/null +++ b/x/vaas/provider/keeper/fee_pool_shares.go @@ -0,0 +1,360 @@ +package keeper + +import ( + "sort" + + "github.com/allinbits/vaas/x/vaas/provider/types" + + "cosmossdk.io/collections" + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" +) + +// ComputeClaim returns the depositor's claimable tokens for one denom on the +// given consumer's fee pool. Returns math.ZeroInt() if the depositor has no +// shares or total_shares is zero. +func (k Keeper) ComputeClaim( + ctx sdk.Context, consumerId string, depositor sdk.AccAddress, denom string, +) math.Int { + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + balance := k.bankKeeper.GetBalance(ctx, poolAddr, denom) + if balance.Amount.IsZero() { + return math.ZeroInt() + } + shares, err := k.ConsumerFeePoolShares.Get(ctx, + collections.Join3(consumerId, depositor, denom)) + if err != nil { + return math.ZeroInt() + } + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) + if err != nil || total.IsZero() { + return math.ZeroInt() + } + // claim = floor(shares * balance / total) + return shares.Mul(balance.Amount).Quo(total) +} + +// MintShares credits the depositor with shares for the given amount in the +// specified consumer's fee pool. Handles the lazy-invalidation case: +// if balance == 0 but total_shares > 0, all existing shares for this +// (consumer, denom) are deleted first (they represent worthless claims). +// +// Caller is responsible for the bank-side movement of funds into the pool. +func (k Keeper) MintShares( + ctx sdk.Context, consumerId string, depositor sdk.AccAddress, amount sdk.Coin, +) error { + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + balance := k.bankKeeper.GetBalance(ctx, poolAddr, amount.Denom) + + totalKey := collections.Join(consumerId, amount.Denom) + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, totalKey) + if err != nil { + total = math.ZeroInt() + } + + // Lazy invalidation: balance == 0 with leftover shares means everyone's + // claim is zero. Clear stale shares before treating as initial deposit. + if balance.Amount.IsZero() && total.IsPositive() { + if err := k.clearAllShares(ctx, consumerId, amount.Denom); err != nil { + return err + } + total = math.ZeroInt() + } + + var shares math.Int + if total.IsZero() { + shares = amount.Amount + } else { + // shares_to_mint = amount * total / balance + // (balance is balance BEFORE this deposit lands) + shares = amount.Amount.Mul(total).Quo(balance.Amount) + } + if !shares.IsPositive() { + // sub-share deposit (extreme dilution) — should be very rare but + // refuse rather than silently dropping + return errorsmod.Wrap(types.ErrInvalidFundDenom, + "deposit too small to mint any shares") + } + + depKey := collections.Join3(consumerId, depositor, amount.Denom) + existing, err := k.ConsumerFeePoolShares.Get(ctx, depKey) + if err != nil { + existing = math.ZeroInt() + } + if err := k.ConsumerFeePoolShares.Set(ctx, depKey, existing.Add(shares)); err != nil { + return err + } + return k.ConsumerFeePoolTotalShares.Set(ctx, totalKey, total.Add(shares)) +} + +// WithdrawShares burns shares for the given depositor and returns the tokens +// to send. If amount >= claim, burns all of the depositor's shares (full +// branch). Otherwise burns a proportional amount (partial branch), truncated +// downward so the depositor never over-withdraws. Caller is responsible for +// dispatching the bank send. +func (k Keeper) WithdrawShares( + ctx sdk.Context, consumerId string, depositor sdk.AccAddress, amount sdk.Coin, +) (sdk.Coin, error) { + depKey := collections.Join3(consumerId, depositor, amount.Denom) + shares, err := k.ConsumerFeePoolShares.Get(ctx, depKey) + if err != nil { + return sdk.Coin{}, errorsmod.Wrapf(types.ErrUnauthorized, + "depositor %s has no shares in (%s, %s)", depositor, consumerId, amount.Denom) + } + totalKey := collections.Join(consumerId, amount.Denom) + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, totalKey) + if err != nil || total.IsZero() { + return sdk.Coin{}, errorsmod.Wrap(types.ErrPoolEmpty, + "no shares accounted for this denom") + } + + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + balance := k.bankKeeper.GetBalance(ctx, poolAddr, amount.Denom) + if balance.Amount.IsZero() { + return sdk.Coin{}, errorsmod.Wrapf(types.ErrPoolEmpty, + "pool has zero balance for denom %s", amount.Denom) + } + + claim := shares.Mul(balance.Amount).Quo(total) + + var sharesToBurn, tokensToSend math.Int + if amount.Amount.GTE(claim) { + // Full branch: burn all shares, deliver exact claim + sharesToBurn = shares + tokensToSend = claim + } else { + // Partial branch: shares_to_burn = floor(amount * total / balance) + sharesToBurn = amount.Amount.Mul(total).Quo(balance.Amount) + if sharesToBurn.IsZero() { + return sdk.Coin{}, errorsmod.Wrap(types.ErrPoolEmpty, + "requested amount too small to burn any shares") + } + tokensToSend = sharesToBurn.Mul(balance.Amount).Quo(total) + } + + remainingShares := shares.Sub(sharesToBurn) + if remainingShares.IsZero() { + if err := k.ConsumerFeePoolShares.Remove(ctx, depKey); err != nil { + return sdk.Coin{}, err + } + } else { + if err := k.ConsumerFeePoolShares.Set(ctx, depKey, remainingShares); err != nil { + return sdk.Coin{}, err + } + } + + newTotal := total.Sub(sharesToBurn) + if newTotal.IsZero() { + if err := k.ConsumerFeePoolTotalShares.Remove(ctx, totalKey); err != nil { + return sdk.Coin{}, err + } + } else { + if err := k.ConsumerFeePoolTotalShares.Set(ctx, totalKey, newTotal); err != nil { + return sdk.Coin{}, err + } + } + + return sdk.NewCoin(amount.Denom, tokensToSend), nil +} + +// SweepConsumerFeePoolDenom drains the consumer's pool for the given denom, +// distributing pro-rata to all share-holders and routing the truncation +// residue to the community pool. Share records and total for the +// (consumer, denom) pair are deleted. +// +// Distribution to the distribution module account uses FundCommunityPool +// rather than a raw bank send, so the community pool's FeePool DecCoins are +// credited correctly. +// +// Handles the orphan-balance defensive case: if total_shares == 0 but +// balance > 0, forwards the balance to the community pool. +func (k Keeper) SweepConsumerFeePoolDenom( + ctx sdk.Context, consumerId, denom string, +) error { + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + balance := k.bankKeeper.GetBalance(ctx, poolAddr, denom) + totalKey := collections.Join(consumerId, denom) + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, totalKey) + if err != nil { + total = math.ZeroInt() + } + + // Trivial cases + if balance.Amount.IsZero() && total.IsZero() { + return nil + } + + providerModule := types.ModuleName + providerAddr := authtypes.NewModuleAddress(providerModule) + distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) + + // Orphan balance: no shares but balance > 0. Forward to community pool. + if total.IsZero() { + if err := k.bankKeeper.SendCoinsFromAccountToModule( + ctx, poolAddr, providerModule, sdk.NewCoins(balance), + ); err != nil { + return err + } + return k.distributionKeeper.FundCommunityPool(ctx, sdk.NewCoins(balance), providerAddr) + } + + // Orphan shares: shares > 0 but balance == 0. Burn all shares, no transfer. + if balance.Amount.IsZero() { + return k.clearAllShares(ctx, consumerId, denom) + } + + // Normal pro-rata distribution. + // Move full balance into provider module account in one hop. + if err := k.bankKeeper.SendCoinsFromAccountToModule( + ctx, poolAddr, providerModule, sdk.NewCoins(balance), + ); err != nil { + return err + } + + // Collect share-holders in deterministic order (by address bytes). + type holder struct { + addr sdk.AccAddress + shares math.Int + } + var holders []holder + prefix := collections.NewPrefixedTripleRange[string, sdk.AccAddress, string](consumerId) + iter, err := k.ConsumerFeePoolShares.Iterate(ctx, prefix) + if err != nil { + return err + } + for ; iter.Valid(); iter.Next() { + key, err := iter.Key() + if err != nil { + iter.Close() + return err + } + if key.K3() != denom { + continue + } + v, err := iter.Value() + if err != nil { + iter.Close() + return err + } + holders = append(holders, holder{addr: key.K2(), shares: v}) + } + iter.Close() + + // Distribute pro-rata. + distributed := math.ZeroInt() + for _, h := range holders { + slice := h.shares.Mul(balance.Amount).Quo(total) + if slice.IsZero() { + continue + } + coins := sdk.NewCoins(sdk.NewCoin(denom, slice)) + if h.addr.Equals(distrAddr) { + if err := k.distributionKeeper.FundCommunityPool(ctx, coins, providerAddr); err != nil { + return err + } + } else { + if err := k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, providerModule, h.addr, coins, + ); err != nil { + return err + } + } + distributed = distributed.Add(slice) + } + + // Truncation residue → community pool. + dust := balance.Amount.Sub(distributed) + if dust.IsPositive() { + if err := k.distributionKeeper.FundCommunityPool( + ctx, sdk.NewCoins(sdk.NewCoin(denom, dust)), providerAddr, + ); err != nil { + return err + } + } + + // Burn all share records for this (consumer, denom). + return k.clearAllShares(ctx, consumerId, denom) +} + +// SweepConsumerFeePool sweeps each denom in `denoms`, or every denom that +// has either non-zero shares or non-zero pool balance if `denoms` is nil/empty. +func (k Keeper) SweepConsumerFeePool( + ctx sdk.Context, consumerId string, denoms []string, +) error { + if len(denoms) > 0 { + for _, d := range denoms { + if err := k.SweepConsumerFeePoolDenom(ctx, consumerId, d); err != nil { + return err + } + } + return nil + } + + // Union of denoms-with-shares and denoms-with-balance. + set := map[string]struct{}{} + prefix := collections.NewPrefixedPairRange[string, string](consumerId) + iter, err := k.ConsumerFeePoolTotalShares.Iterate(ctx, prefix) + if err != nil { + return err + } + for ; iter.Valid(); iter.Next() { + key, err := iter.Key() + if err != nil { + iter.Close() + return err + } + set[key.K2()] = struct{}{} + } + iter.Close() + + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + for _, c := range k.bankKeeper.GetAllBalances(ctx, poolAddr) { + set[c.Denom] = struct{}{} + } + + // Deterministic iteration. + keys := make([]string, 0, len(set)) + for d := range set { + keys = append(keys, d) + } + sort.Strings(keys) + for _, d := range keys { + if err := k.SweepConsumerFeePoolDenom(ctx, consumerId, d); err != nil { + return err + } + } + return nil +} + +// clearAllShares deletes every share record for the given (consumer, denom). +// Used by lazy invalidation and by sweep finalization. +func (k Keeper) clearAllShares(ctx sdk.Context, consumerId, denom string) error { + prefix := collections.NewPrefixedTripleRange[string, sdk.AccAddress, string](consumerId) + iter, err := k.ConsumerFeePoolShares.Iterate(ctx, prefix) + if err != nil { + return err + } + defer iter.Close() + + var toDelete []collections.Triple[string, sdk.AccAddress, string] + for ; iter.Valid(); iter.Next() { + key, err := iter.Key() + if err != nil { + return err + } + if key.K3() != denom { + continue + } + toDelete = append(toDelete, key) + } + for _, key := range toDelete { + if err := k.ConsumerFeePoolShares.Remove(ctx, key); err != nil { + return err + } + } + return k.ConsumerFeePoolTotalShares.Remove(ctx, collections.Join(consumerId, denom)) +} diff --git a/x/vaas/provider/keeper/fee_pool_shares_test.go b/x/vaas/provider/keeper/fee_pool_shares_test.go new file mode 100644 index 0000000..a83d1b4 --- /dev/null +++ b/x/vaas/provider/keeper/fee_pool_shares_test.go @@ -0,0 +1,445 @@ +package keeper_test + +import ( + "testing" + + "cosmossdk.io/collections" + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + + "github.com/stretchr/testify/require" + + testkeeper "github.com/allinbits/vaas/testutil/keeper" + providertypes "github.com/allinbits/vaas/x/vaas/provider/types" +) + +func TestComputeClaim(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + + // No shares yet: claim is zero + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 0)) + require.True(t, k.ComputeClaim(ctx, consumerId, alice, denom).IsZero()) + + // Seed: alice has 100 shares of 100 total, balance 50 + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(100))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 50)) + require.Equal(t, math.NewInt(50), k.ComputeClaim(ctx, consumerId, alice, denom)) +} + +func TestMintShares_Initial(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // Initial deposit: total_shares == 0; mint = amount + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 0)) + require.NoError(t, k.MintShares(ctx, consumerId, alice, sdk.NewInt64Coin(denom, 100))) + + shares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + require.NoError(t, err) + require.Equal(t, math.NewInt(100), shares) + + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) + require.NoError(t, err) + require.Equal(t, math.NewInt(100), total) +} + +func TestMintShares_Subsequent(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // Seed: alice has 100 shares against balance 50 (consumed via fees) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(100))) + + // Bob deposits 100 when balance is 50 (PRE-deposit) and 150 (POST-deposit) + // The mint formula uses balance BEFORE the new deposit lands. + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 50)) + require.NoError(t, k.MintShares(ctx, consumerId, bob, sdk.NewInt64Coin(denom, 100))) + + // Bob: shares = 100 * 100 / 50 = 200 + shares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, bob, denom)) + require.NoError(t, err) + require.Equal(t, math.NewInt(200), shares) + + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) + require.NoError(t, err) + require.Equal(t, math.NewInt(300), total) +} + +func TestMintShares_LazyInvalidation(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // Seed: alice has 100 shares, balance is 0 (pool fully consumed by fees) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(100))) + + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 0)) + require.NoError(t, k.MintShares(ctx, consumerId, bob, sdk.NewInt64Coin(denom, 50))) + + // Alice's shares should be wiped (lazy invalidation), Bob's recorded as initial + _, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + require.ErrorIs(t, err, collections.ErrNotFound) + + bobShares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, bob, denom)) + require.NoError(t, err) + require.Equal(t, math.NewInt(50), bobShares) + + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) + require.NoError(t, err) + require.Equal(t, math.NewInt(50), total) +} + +func TestMintShares_SubShareDeposit(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // Seed: alice has 1_000_000 shares of 1_000_000 total, balance is huge (1_000_000_000). + // Bob's tiny 1-unit deposit would mint floor(1 * 1_000_000 / 1_000_000_000) = 0 shares. + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(1_000_000))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(1_000_000))) + + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 1_000_000_000)) + err := k.MintShares(ctx, consumerId, bob, sdk.NewInt64Coin(denom, 1)) + require.ErrorIs(t, err, providertypes.ErrInvalidFundDenom) + + // No state mutation: bob has no entry, total unchanged, alice unchanged. + _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, bob, denom)) + require.ErrorIs(t, err, collections.ErrNotFound) + + aliceShares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + require.NoError(t, err) + require.Equal(t, math.NewInt(1_000_000), aliceShares) + + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) + require.NoError(t, err) + require.Equal(t, math.NewInt(1_000_000), total) +} + +func TestWithdrawShares_Full(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // Alice sole depositor with 100 shares against balance 100 + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(100))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 100)) + + // Request 200 (over claim) — should burn all shares, return claim=100 + tokens, err := k.WithdrawShares(ctx, consumerId, alice, sdk.NewInt64Coin(denom, 200)) + require.NoError(t, err) + require.Equal(t, math.NewInt(100), tokens.Amount) + + _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + require.ErrorIs(t, err, collections.ErrNotFound) + + _, err = k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) + require.ErrorIs(t, err, collections.ErrNotFound) +} + +func TestWithdrawShares_Partial(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // Two depositors, balance 200, total 200 + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, bob, denom), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(200))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 200)) + + // Alice withdraws 50 (partial, well below claim 100) + tokens, err := k.WithdrawShares(ctx, consumerId, alice, sdk.NewInt64Coin(denom, 50)) + require.NoError(t, err) + require.Equal(t, math.NewInt(50), tokens.Amount) + + // Alice burned 50 shares; total = 150; alice = 50 + aliceShares, _ := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + require.Equal(t, math.NewInt(50), aliceShares) + total, _ := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) + require.Equal(t, math.NewInt(150), total) +} + +func TestWithdrawShares_Empty(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(100))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 0)) + + _, err := k.WithdrawShares(ctx, consumerId, alice, sdk.NewInt64Coin(denom, 50)) + require.ErrorIs(t, err, providertypes.ErrPoolEmpty) +} + +func TestWithdrawShares_SubShareGuard(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // Seed: alice has 100 shares of 100 total against a huge balance (1_000_000). + // Claim = 100 * 1_000_000 / 100 = 1_000_000. A tiny 1-unit withdrawal hits + // the partial branch and computes sharesToBurn = floor(1 * 100 / 1_000_000) = 0, + // which must trigger the sub-share guard. + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(100))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 1_000_000)) + + tokens, err := k.WithdrawShares(ctx, consumerId, alice, sdk.NewInt64Coin(denom, 1)) + require.ErrorIs(t, err, providertypes.ErrPoolEmpty) + require.Equal(t, sdk.Coin{}, tokens) + + // No state mutation: alice still has 100 shares, total still 100. + aliceShares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + require.NoError(t, err) + require.Equal(t, math.NewInt(100), aliceShares) + + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) + require.NoError(t, err) + require.Equal(t, math.NewInt(100), total) +} + +func TestSweepConsumerFeePoolDenom(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // alice 30, bob 70, total 100, balance 100 — no dust + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(30))) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, bob, denom), math.NewInt(70))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(100))) + + providerModuleName := providertypes.ModuleName + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 100)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providerModuleName, sdk.NewCoins(sdk.NewInt64Coin(denom, 100))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providerModuleName, alice, sdk.NewCoins(sdk.NewInt64Coin(denom, 30))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providerModuleName, bob, sdk.NewCoins(sdk.NewInt64Coin(denom, 70))).Return(nil) + // No dust → no FundCommunityPool call + + require.NoError(t, k.SweepConsumerFeePoolDenom(ctx, consumerId, denom)) + + // All share records and total cleared + _, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + require.ErrorIs(t, err, collections.ErrNotFound) + _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, bob, denom)) + require.ErrorIs(t, err, collections.ErrNotFound) + _, err = k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) + require.ErrorIs(t, err, collections.ErrNotFound) +} + +func TestSweepConsumerFeePoolDenom_WithDust(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // alice 1, bob 2, total 3, balance 10 + // alice claim: floor(1*10/3) = 3; bob claim: floor(2*10/3) = 6; dust = 1 + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(1))) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, bob, denom), math.NewInt(2))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(3))) + + providerModuleName := providertypes.ModuleName + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 10)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providerModuleName, sdk.NewCoins(sdk.NewInt64Coin(denom, 10))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providerModuleName, alice, sdk.NewCoins(sdk.NewInt64Coin(denom, 3))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providerModuleName, bob, sdk.NewCoins(sdk.NewInt64Coin(denom, 6))).Return(nil) + mocks.MockDistributionKeeper.EXPECT().FundCommunityPool( + ctx, sdk.NewCoins(sdk.NewInt64Coin(denom, 1)), + authtypes.NewModuleAddress(providertypes.ModuleName)).Return(nil) + + require.NoError(t, k.SweepConsumerFeePoolDenom(ctx, consumerId, denom)) +} + +func TestSweepConsumerFeePoolDenom_DistrModuleRecipientUsesCommunityPool(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, distrAddr, denom), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(100))) + + providerModuleName := providertypes.ModuleName + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 100)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providerModuleName, sdk.NewCoins(sdk.NewInt64Coin(denom, 100))).Return(nil) + // Distribution module account share goes via FundCommunityPool, NOT raw bank send + mocks.MockDistributionKeeper.EXPECT().FundCommunityPool( + ctx, sdk.NewCoins(sdk.NewInt64Coin(denom, 100)), + authtypes.NewModuleAddress(providertypes.ModuleName)).Return(nil) + + require.NoError(t, k.SweepConsumerFeePoolDenom(ctx, consumerId, denom)) +} + +func TestSweepConsumerFeePoolDenom_AllFloorToZero(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + denom := "uphoton" + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // alice 1 share, bob 1 share, total 2, balance 1. + // alice slice: floor(1*1/2) = 0 → skipped + // bob slice: floor(1*1/2) = 0 → skipped + // distributed = 0; dust = 1 → entire balance routed to community pool. + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, denom), math.NewInt(1))) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, bob, denom), math.NewInt(1))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), math.NewInt(2))) + + providerModuleName := providertypes.ModuleName + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 1)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providerModuleName, sdk.NewCoins(sdk.NewInt64Coin(denom, 1))).Return(nil) + // No per-holder SendCoinsFromModuleToAccount: every slice floors to zero. + mocks.MockDistributionKeeper.EXPECT().FundCommunityPool( + ctx, sdk.NewCoins(sdk.NewInt64Coin(denom, 1)), + authtypes.NewModuleAddress(providertypes.ModuleName)).Return(nil) + + require.NoError(t, k.SweepConsumerFeePoolDenom(ctx, consumerId, denom)) + + // All share records and total cleared. + _, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + require.ErrorIs(t, err, collections.ErrNotFound) + _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, bob, denom)) + require.ErrorIs(t, err, collections.ErrNotFound) + _, err = k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) + require.ErrorIs(t, err, collections.ErrNotFound) +} + +func TestSweepConsumerFeePool_AllDenoms(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // alice has shares in two denoms + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, "uphoton"), math.NewInt(10))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uphoton"), math.NewInt(10))) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, "uatone"), math.NewInt(5))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uatone"), math.NewInt(5))) + + mocks.MockBankKeeper.EXPECT().GetAllBalances(ctx, poolAddr).Return( + sdk.NewCoins(sdk.NewInt64Coin("uphoton", 10), sdk.NewInt64Coin("uatone", 5))) + + // Two per-denom sweeps. Expect bank ops for each. + for _, c := range []sdk.Coin{ + sdk.NewInt64Coin("uatone", 5), + sdk.NewInt64Coin("uphoton", 10), + } { + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, c.Denom).Return(c) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providertypes.ModuleName, sdk.NewCoins(c)).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, alice, sdk.NewCoins(c)).Return(nil) + } + + require.NoError(t, k.SweepConsumerFeePool(ctx, consumerId, nil)) +} diff --git a/x/vaas/types/expected_keepers.go b/x/vaas/types/expected_keepers.go index 94d0252..b741f25 100644 --- a/x/vaas/types/expected_keepers.go +++ b/x/vaas/types/expected_keepers.go @@ -84,6 +84,7 @@ type ConsumerHooks interface { // BankKeeper defines the expected interface needed to retrieve account balances. type BankKeeper interface { GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin + GetAllBalances(ctx context.Context, addr sdk.AccAddress) sdk.Coins SendCoinsFromAccountToModule(ctx context.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error SendCoinsFromModuleToModule(ctx context.Context, senderModule, recipientModule string, amt sdk.Coins) error SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error From 965ff228991cf486b66e7048cf2a874702ad48ce Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 17:44:19 +0200 Subject: [PATCH 04/18] populate and remove pool reverse-lookup on consumer create/delete --- x/vaas/provider/keeper/consumer_lifecycle.go | 4 +++ .../keeper/consumer_lifecycle_test.go | 28 +++++++++++++++++++ x/vaas/provider/keeper/msg_server.go | 7 +++++ x/vaas/provider/keeper/msg_server_test.go | 18 ++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 x/vaas/provider/keeper/consumer_lifecycle_test.go diff --git a/x/vaas/provider/keeper/consumer_lifecycle.go b/x/vaas/provider/keeper/consumer_lifecycle.go index d4d9360..9a93fca 100644 --- a/x/vaas/provider/keeper/consumer_lifecycle.go +++ b/x/vaas/provider/keeper/consumer_lifecycle.go @@ -409,6 +409,10 @@ func (k Keeper) DeleteConsumerChain(ctx sdk.Context, consumerId uint64) (err err k.DeleteConsumerRemovalTime(ctx, consumerId) k.DeleteConsumerDebt(ctx, consumerId) + if err := k.FeePoolAddressToConsumerId.Remove(ctx, k.GetConsumerFeePoolAddress(consumerId)); err != nil { + return err + } + // TODO (PERMISSIONLESS) add newly-added state to be deleted // Note that we do not delete ConsumerIdToChainIdKey and ConsumerIdToPhase, as well diff --git a/x/vaas/provider/keeper/consumer_lifecycle_test.go b/x/vaas/provider/keeper/consumer_lifecycle_test.go new file mode 100644 index 0000000..a5837ee --- /dev/null +++ b/x/vaas/provider/keeper/consumer_lifecycle_test.go @@ -0,0 +1,28 @@ +package keeper_test + +import ( + "testing" + + "cosmossdk.io/collections" + + "github.com/stretchr/testify/require" + + testkeeper "github.com/allinbits/vaas/testutil/keeper" + providertypes "github.com/allinbits/vaas/x/vaas/provider/types" +) + +func TestDeleteConsumerChain_RemovesReverseLookup(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := k.FetchAndIncrementConsumerId(ctx) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, poolAddr, consumerId)) + k.SetConsumerClientId(ctx, consumerId, "07-tendermint-0") + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_STOPPED) + + require.NoError(t, k.DeleteConsumerChain(ctx, consumerId)) + + _, err := k.FeePoolAddressToConsumerId.Get(ctx, poolAddr) + require.ErrorIs(t, err, collections.ErrNotFound) +} diff --git a/x/vaas/provider/keeper/msg_server.go b/x/vaas/provider/keeper/msg_server.go index fb17411..aba7512 100644 --- a/x/vaas/provider/keeper/msg_server.go +++ b/x/vaas/provider/keeper/msg_server.go @@ -257,6 +257,13 @@ func (k msgServer) CreateConsumer(goCtx context.Context, msg *types.MsgCreateCon ) resp.ConsumerId = consumerId + + if err := k.FeePoolAddressToConsumerId.Set(ctx, + k.GetConsumerFeePoolAddress(consumerId), consumerId, + ); err != nil { + return &resp, err + } + return &resp, nil } diff --git a/x/vaas/provider/keeper/msg_server_test.go b/x/vaas/provider/keeper/msg_server_test.go index 9b610fb..5ec3d48 100644 --- a/x/vaas/provider/keeper/msg_server_test.go +++ b/x/vaas/provider/keeper/msg_server_test.go @@ -61,6 +61,24 @@ func TestCreateConsumer(t *testing.T) { require.Equal(t, providertypes.CONSUMER_PHASE_REGISTERED, phase) } +func TestCreateConsumer_PopulatesReverseLookup(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + resp, err := ms.CreateConsumer(ctx, &providertypes.MsgCreateConsumer{ + Submitter: "submitter", ChainId: "chainId", + Metadata: providertypes.ConsumerMetadata{Name: "n", Description: "d"}, + InitializationParameters: &providertypes.ConsumerInitializationParameters{}, + }) + require.NoError(t, err) + + poolAddr := k.GetConsumerFeePoolAddress(resp.ConsumerId) + consumerId, err := k.FeePoolAddressToConsumerId.Get(ctx, poolAddr) + require.NoError(t, err) + require.Equal(t, resp.ConsumerId, consumerId) +} + func TestCreateConsumerDuplicateChainId(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() From fd2d043330f432f7848a9ad51adba56f0fc6b0f9 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 17:52:31 +0200 Subject: [PATCH 05/18] register bank send-restriction for consumer pool addresses --- app/provider/app.go | 1 + x/vaas/provider/keeper/send_restriction.go | 33 ++++++++++++++ .../provider/keeper/send_restriction_test.go | 43 +++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 x/vaas/provider/keeper/send_restriction.go create mode 100644 x/vaas/provider/keeper/send_restriction_test.go diff --git a/app/provider/app.go b/app/provider/app.go index b83a857..3ccd3aa 100644 --- a/app/provider/app.go +++ b/app/provider/app.go @@ -399,6 +399,7 @@ func New( authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()), authtypes.FeeCollectorName, ) + app.BankKeeper.AppendSendRestriction(app.ProviderKeeper.FeePoolSendRestriction()) govConfig := govtypes.DefaultConfig() app.GovKeeper = govkeeper.NewKeeper( diff --git a/x/vaas/provider/keeper/send_restriction.go b/x/vaas/provider/keeper/send_restriction.go new file mode 100644 index 0000000..2afdc3f --- /dev/null +++ b/x/vaas/provider/keeper/send_restriction.go @@ -0,0 +1,33 @@ +package keeper + +import ( + "context" + + "github.com/allinbits/vaas/x/vaas/provider/types" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// FeePoolSendRestriction returns a bank send-restriction that rejects any +// send to a known active consumer fee pool address unless the source is the +// provider module account itself. +func (k Keeper) FeePoolSendRestriction() func( + ctx context.Context, fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, +) (sdk.AccAddress, error) { + providerAddr := authtypes.NewModuleAddress(types.ModuleName) + return func( + ctx context.Context, fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, + ) (sdk.AccAddress, error) { + if _, err := k.FeePoolAddressToConsumerId.Get(ctx, toAddr); err != nil { + return toAddr, nil + } + if fromAddr.Equals(providerAddr) { + return toAddr, nil + } + return nil, errorsmod.Wrapf(types.ErrUnsolicitedFeePoolDeposit, + "direct send to consumer fee pool %s blocked", toAddr.String()) + } +} diff --git a/x/vaas/provider/keeper/send_restriction_test.go b/x/vaas/provider/keeper/send_restriction_test.go new file mode 100644 index 0000000..9b9dbea --- /dev/null +++ b/x/vaas/provider/keeper/send_restriction_test.go @@ -0,0 +1,43 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + testkeeper "github.com/allinbits/vaas/testutil/keeper" + providertypes "github.com/allinbits/vaas/x/vaas/provider/types" +) + +func TestFeePoolSendRestriction(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + providerAddr := authtypes.NewModuleAddress(providertypes.ModuleName) + user := sdk.AccAddress([]byte("user____________")) + other := sdk.AccAddress([]byte("other___________")) + + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, poolAddr, consumerId)) + + restrict := k.FeePoolSendRestriction() + amt := sdk.NewCoins(sdk.NewInt64Coin("uphoton", 1)) + + // unrelated destination passes through + to, err := restrict(ctx, user, other, amt) + require.NoError(t, err) + require.Equal(t, other, to) + + // direct send to fee pool blocked + _, err = restrict(ctx, user, poolAddr, amt) + require.ErrorIs(t, err, providertypes.ErrUnsolicitedFeePoolDeposit) + + // sanctioned 2-hop send from provider module allowed + to, err = restrict(ctx, providerAddr, poolAddr, amt) + require.NoError(t, err) + require.Equal(t, poolAddr, to) +} From 0a3a564fc8335985afeb2712c7fddcad9eb4c70c Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 18:02:56 +0200 Subject: [PATCH 06/18] add MsgServer handlers for fund, withdraw, and sweep --- x/vaas/provider/keeper/msg_server.go | 166 ++++++++++++- x/vaas/provider/keeper/msg_server_test.go | 276 ++++++++++++++++++++++ 2 files changed, 436 insertions(+), 6 deletions(-) diff --git a/x/vaas/provider/keeper/msg_server.go b/x/vaas/provider/keeper/msg_server.go index aba7512..67c9fce 100644 --- a/x/vaas/provider/keeper/msg_server.go +++ b/x/vaas/provider/keeper/msg_server.go @@ -15,6 +15,8 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -475,14 +477,166 @@ func (k msgServer) RemoveConsumer(goCtx context.Context, msg *types.MsgRemoveCon } // FundConsumerFeePool deposits funds into a consumer's fee pool. -func (k msgServer) FundConsumerFeePool(_ context.Context, _ *types.MsgFundConsumerFeePool) (*types.MsgFundConsumerFeePoolResponse, error) { - panic("not implemented") +func (k msgServer) FundConsumerFeePool( + goCtx context.Context, msg *types.MsgFundConsumerFeePool, +) (*types.MsgFundConsumerFeePoolResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // Phase + existence check + phase := k.GetConsumerPhase(ctx, msg.ConsumerId) + if phase == types.CONSUMER_PHASE_UNSPECIFIED { + return nil, errorsmod.Wrapf(types.ErrUnknownConsumerId, + "consumer %s does not exist", msg.ConsumerId) + } + if phase == types.CONSUMER_PHASE_DELETED { + return nil, errorsmod.Wrapf(types.ErrInvalidPhase, + "consumer %s is deleted", msg.ConsumerId) + } + + // Denom check (stateful — reads params) + params := k.GetParams(ctx) + if msg.Amount.Denom != params.FeesPerBlock.Denom { + return nil, errorsmod.Wrapf(types.ErrInvalidFundDenom, + "expected denom %s, got %s", params.FeesPerBlock.Denom, msg.Amount.Denom) + } + + poolAddr := k.GetConsumerFeePoolAddress(msg.ConsumerId) + providerAddr := authtypes.NewModuleAddress(types.ModuleName) + coins := sdk.NewCoins(msg.Amount) + + // Determine depositor identity and source-of-funds path. + var depositor sdk.AccAddress + if msg.Signer == k.GetAuthority() { + if err := k.distributionKeeper.DistributeFromFeePool(ctx, coins, providerAddr); err != nil { + return nil, err + } + depositor = authtypes.NewModuleAddress(disttypes.ModuleName) + } else { + signerAddr, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return nil, err + } + if err := k.bankKeeper.SendCoinsFromAccountToModule( + ctx, signerAddr, types.ModuleName, coins, + ); err != nil { + return nil, err + } + depositor = signerAddr + } + + // Mint shares using PRE-deposit balance. + if err := k.MintShares(ctx, msg.ConsumerId, depositor, msg.Amount); err != nil { + return nil, err + } + + // Second hop: provider module → fee pool address (SendRestriction allows this). + if err := k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, types.ModuleName, poolAddr, coins, + ); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeConsumerFeePoolFund, + sdk.NewAttribute(types.AttributeConsumerId, msg.ConsumerId), + sdk.NewAttribute(types.AttributeDepositor, depositor.String()), + sdk.NewAttribute(types.AttributeAmount, msg.Amount.String()), + )) + return &types.MsgFundConsumerFeePoolResponse{}, nil } -func (k msgServer) WithdrawConsumerFeePool(_ context.Context, _ *types.MsgWithdrawConsumerFeePool) (*types.MsgWithdrawConsumerFeePoolResponse, error) { - panic("not implemented") +// WithdrawConsumerFeePool burns the depositor's shares across one or more +// denoms and returns the corresponding tokens. The handler is atomic: any +// per-denom failure rolls back share burns from prior denoms in the same +// request. When the signer is the gov authority, the tokens are routed back +// to the community pool rather than to the signer. +func (k msgServer) WithdrawConsumerFeePool( + goCtx context.Context, msg *types.MsgWithdrawConsumerFeePool, +) (*types.MsgWithdrawConsumerFeePoolResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // Resolve depositor identity + isGov := msg.Signer == k.GetAuthority() + var depositor sdk.AccAddress + if isGov { + depositor = authtypes.NewModuleAddress(disttypes.ModuleName) + } else { + addr, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + return nil, err + } + depositor = addr + } + + // Process per-denom, accumulate. The share-burn loop runs inside a + // cache-context so a mid-loop failure rolls back any prior burns, even + // when the handler is invoked outside of the SDK tx machinery (e.g. + // nested calls or direct invocations in tests). + cachedCtx, write := ctx.CacheContext() + delivered := sdk.NewCoins() + for _, amt := range msg.Amount { + tokens, err := k.WithdrawShares(cachedCtx, msg.ConsumerId, depositor, amt) + if err != nil { + return nil, err + } + if !tokens.Amount.IsZero() { + delivered = delivered.Add(tokens) + } + } + write() + + if delivered.IsZero() { + return &types.MsgWithdrawConsumerFeePoolResponse{Amount: delivered}, nil + } + + poolAddr := k.GetConsumerFeePoolAddress(msg.ConsumerId) + providerAddr := authtypes.NewModuleAddress(types.ModuleName) + if err := k.bankKeeper.SendCoinsFromAccountToModule( + ctx, poolAddr, types.ModuleName, delivered, + ); err != nil { + return nil, err + } + if isGov { + if err := k.distributionKeeper.FundCommunityPool(ctx, delivered, providerAddr); err != nil { + return nil, err + } + } else { + if err := k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, types.ModuleName, depositor, delivered, + ); err != nil { + return nil, err + } + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeConsumerFeePoolWithdraw, + sdk.NewAttribute(types.AttributeConsumerId, msg.ConsumerId), + sdk.NewAttribute(types.AttributeDepositor, depositor.String()), + sdk.NewAttribute(types.AttributeRecipient, depositor.String()), + sdk.NewAttribute(types.AttributeAmount, delivered.String()), + )) + return &types.MsgWithdrawConsumerFeePoolResponse{Amount: delivered}, nil } -func (k msgServer) SweepConsumerFeePool(_ context.Context, _ *types.MsgSweepConsumerFeePool) (*types.MsgSweepConsumerFeePoolResponse, error) { - panic("not implemented") +func (k msgServer) SweepConsumerFeePool( + goCtx context.Context, msg *types.MsgSweepConsumerFeePool, +) (*types.MsgSweepConsumerFeePoolResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + ownerAddr, err := k.GetConsumerOwnerAddress(ctx, msg.ConsumerId) + if err != nil { + return nil, errorsmod.Wrapf(types.ErrNoOwnerAddress, + "consumer %s has no owner: %s", msg.ConsumerId, err) + } + if msg.Signer != ownerAddr { + return nil, errorsmod.Wrapf(types.ErrUnauthorized, + "only consumer owner %s may sweep, got %s", ownerAddr, msg.Signer) + } + + // The msgServer's SweepConsumerFeePool shadows the embedded Keeper's + // SweepConsumerFeePool. Call the keeper's via the embedded field. + if err := k.Keeper.SweepConsumerFeePool(ctx, msg.ConsumerId, msg.Denoms); err != nil { + return nil, errorsmod.Wrap(types.ErrFeePoolSweepFailed, err.Error()) + } + return &types.MsgSweepConsumerFeePoolResponse{}, nil } diff --git a/x/vaas/provider/keeper/msg_server_test.go b/x/vaas/provider/keeper/msg_server_test.go index 5ec3d48..4ae088c 100644 --- a/x/vaas/provider/keeper/msg_server_test.go +++ b/x/vaas/provider/keeper/msg_server_test.go @@ -4,8 +4,15 @@ import ( "testing" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "cosmossdk.io/collections" + "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec/address" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" testkeeper "github.com/allinbits/vaas/testutil/keeper" providerkeeper "github.com/allinbits/vaas/x/vaas/provider/keeper" @@ -227,3 +234,272 @@ func TestUpdateConsumerDuplicateChainId(t *testing.T) { require.NoError(t, err) require.Equal(t, chainId2, actualChainId) } + +func TestFundConsumerFeePool_RegularSigner(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_REGISTERED) + k.SetParams(ctx, providertypes.DefaultParams()) + params := k.GetParams(ctx) + params.FeesPerBlock = sdk.NewInt64Coin("uphoton", 10) + k.SetParams(ctx, params) + + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + amount := sdk.NewInt64Coin("uphoton", 100) + + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 0)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, alice, providertypes.ModuleName, sdk.NewCoins(amount)).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, poolAddr, sdk.NewCoins(amount)).Return(nil) + + _, err := ms.FundConsumerFeePool(ctx, &providertypes.MsgFundConsumerFeePool{ + Signer: alice.String(), ConsumerId: consumerId, Amount: amount, + }) + require.NoError(t, err) + + shares, _ := k.ConsumerFeePoolShares.Get(ctx, + collections.Join3(consumerId, alice, "uphoton")) + require.Equal(t, math.NewInt(100), shares) +} + +func TestFundConsumerFeePool_GovAuthority(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_REGISTERED) + k.SetParams(ctx, providertypes.DefaultParams()) + params := k.GetParams(ctx) + params.FeesPerBlock = sdk.NewInt64Coin("uphoton", 10) + k.SetParams(ctx, params) + + govAddr := k.GetAuthority() + distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) + providerAddr := authtypes.NewModuleAddress(providertypes.ModuleName) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + amount := sdk.NewInt64Coin("uphoton", 1000) + + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 0)) + mocks.MockDistributionKeeper.EXPECT().DistributeFromFeePool( + ctx, sdk.NewCoins(amount), providerAddr).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, poolAddr, sdk.NewCoins(amount)).Return(nil) + + _, err := ms.FundConsumerFeePool(ctx, &providertypes.MsgFundConsumerFeePool{ + Signer: govAddr, ConsumerId: consumerId, Amount: amount, + }) + require.NoError(t, err) + + shares, _ := k.ConsumerFeePoolShares.Get(ctx, + collections.Join3(consumerId, distrAddr, "uphoton")) + require.Equal(t, math.NewInt(1000), shares) +} + +func TestFundConsumerFeePool_RejectsUnknownConsumer(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + alice := sdk.AccAddress([]byte("alice___________")) + + _, err := ms.FundConsumerFeePool(ctx, &providertypes.MsgFundConsumerFeePool{ + Signer: alice.String(), ConsumerId: "999", + Amount: sdk.NewInt64Coin("uphoton", 1), + }) + require.ErrorIs(t, err, providertypes.ErrUnknownConsumerId) +} + +func TestFundConsumerFeePool_RejectsDeleted(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_DELETED) + alice := sdk.AccAddress([]byte("alice___________")) + + _, err := ms.FundConsumerFeePool(ctx, &providertypes.MsgFundConsumerFeePool{ + Signer: alice.String(), ConsumerId: consumerId, + Amount: sdk.NewInt64Coin("uphoton", 1), + }) + require.ErrorIs(t, err, providertypes.ErrInvalidPhase) +} + +func TestWithdrawConsumerFeePool_Regular(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED) + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // alice sole depositor: 100 shares, balance 80 + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, "uphoton"), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uphoton"), math.NewInt(100))) + + mocks.MockBankKeeper.EXPECT().GetBalance(gomock.Any(), poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 80)) + // alice asks for 30, partial path: shares_to_burn = 30*100/80 = 37, tokens = 37*80/100 = 29 + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 29))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, alice, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 29))).Return(nil) + + resp, err := ms.WithdrawConsumerFeePool(ctx, &providertypes.MsgWithdrawConsumerFeePool{ + Signer: alice.String(), ConsumerId: consumerId, + Amount: sdk.NewCoins(sdk.NewInt64Coin("uphoton", 30)), + }) + require.NoError(t, err) + require.Equal(t, "29uphoton", resp.Amount.String()) +} + +func TestWithdrawConsumerFeePool_GovClawback(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED) + distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) + providerAddr := authtypes.NewModuleAddress(providertypes.ModuleName) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, distrAddr, "uphoton"), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uphoton"), math.NewInt(100))) + + mocks.MockBankKeeper.EXPECT().GetBalance(gomock.Any(), poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 100)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))).Return(nil) + // Gov clawback: tokens forwarded to community pool, not raw bank send + mocks.MockDistributionKeeper.EXPECT().FundCommunityPool( + ctx, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), providerAddr).Return(nil) + + _, err := ms.WithdrawConsumerFeePool(ctx, &providertypes.MsgWithdrawConsumerFeePool{ + Signer: k.GetAuthority(), ConsumerId: consumerId, + Amount: sdk.NewCoins(sdk.NewInt64Coin("uphoton", 1_000_000)), + }) + require.NoError(t, err) +} + +func TestWithdrawConsumerFeePool_AtomicMultiDenomAbort(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED) + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + // alice has shares in uatone (alphabetically first, so iterated first + // inside the handler) but NOT in uphoton. The first iteration burns + // shares; the second must fail and the cache-context rollback must + // restore alice's uatone shares to their pre-call value. + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, "uatone"), math.NewInt(50))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uatone"), math.NewInt(50))) + + mocks.MockBankKeeper.EXPECT().GetBalance(gomock.Any(), poolAddr, "uatone"). + Return(sdk.NewInt64Coin("uatone", 50)).AnyTimes() + + // Requesting both: uatone succeeds (mutating cached state), uphoton + // fails (no shares for alice). The handler returns the error and the + // cache-context is discarded, leaving uatone shares untouched. + _, err := ms.WithdrawConsumerFeePool(ctx, &providertypes.MsgWithdrawConsumerFeePool{ + Signer: alice.String(), ConsumerId: consumerId, + Amount: sdk.NewCoins( + sdk.NewInt64Coin("uatone", 10), + sdk.NewInt64Coin("uphoton", 10), + ), + }) + require.Error(t, err) + + // alice's uatone shares should remain 50 (rollback proved) + s, _ := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, "uatone")) + require.Equal(t, math.NewInt(50), s) +} + +func TestSweepConsumerFeePool_OwnerOnly(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED) + // Use a valid bech32 owner address + owner := sdk.AccAddress([]byte("owner___________")) + k.SetConsumerOwnerAddress(ctx, consumerId, owner.String()) + + notOwner := sdk.AccAddress([]byte("not-owner_______")) + _, err := ms.SweepConsumerFeePool(ctx, &providertypes.MsgSweepConsumerFeePool{ + Signer: notOwner.String(), ConsumerId: consumerId, Denoms: nil, + }) + require.ErrorIs(t, err, providertypes.ErrUnauthorized) +} + +func TestSweepConsumerFeePool_OwnerTriggers(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED) + owner := sdk.AccAddress([]byte("owner___________")) + k.SetConsumerOwnerAddress(ctx, consumerId, owner.String()) + + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, "uphoton"), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uphoton"), math.NewInt(100))) + + mocks.MockBankKeeper.EXPECT().GetAllBalances(ctx, poolAddr). + Return(sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 100)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, alice, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))).Return(nil) + + _, err := ms.SweepConsumerFeePool(ctx, &providertypes.MsgSweepConsumerFeePool{ + Signer: owner.String(), ConsumerId: consumerId, Denoms: nil, + }) + require.NoError(t, err) +} + +func TestFundConsumerFeePool_RejectsWrongDenom(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_REGISTERED) + k.SetParams(ctx, providertypes.DefaultParams()) + params := k.GetParams(ctx) + params.FeesPerBlock = sdk.NewInt64Coin("uphoton", 10) + k.SetParams(ctx, params) + alice := sdk.AccAddress([]byte("alice___________")) + + _, err := ms.FundConsumerFeePool(ctx, &providertypes.MsgFundConsumerFeePool{ + Signer: alice.String(), ConsumerId: consumerId, + Amount: sdk.NewInt64Coin("uatone", 1), + }) + require.ErrorIs(t, err, providertypes.ErrInvalidFundDenom) +} From 97dd342bfd82c42c91fcc7f88ef6f753655a2fee Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 18:22:31 +0200 Subject: [PATCH 07/18] auto-sweep fee pool on consumer delete --- x/vaas/provider/keeper/consumer_lifecycle.go | 6 ++ .../keeper/consumer_lifecycle_test.go | 60 ++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/x/vaas/provider/keeper/consumer_lifecycle.go b/x/vaas/provider/keeper/consumer_lifecycle.go index 9a93fca..3797fae 100644 --- a/x/vaas/provider/keeper/consumer_lifecycle.go +++ b/x/vaas/provider/keeper/consumer_lifecycle.go @@ -394,6 +394,12 @@ func (k Keeper) DeleteConsumerChain(ctx sdk.Context, consumerId uint64) (err err return fmt.Errorf("cannot delete non-stopped chain: %d", consumerId) } + // Auto-sweep the fee pool. If it fails, abort the delete; consumer + // stays STOPPED so funds aren't silently stranded. + if err := k.SweepConsumerFeePool(ctx, consumerId, nil); err != nil { + return errorsmod.Wrap(types.ErrFeePoolSweepFailed, err.Error()) + } + // clean up states k.DeleteConsumerClientId(ctx, consumerId) k.DeleteConsumerGenesis(ctx, consumerId) diff --git a/x/vaas/provider/keeper/consumer_lifecycle_test.go b/x/vaas/provider/keeper/consumer_lifecycle_test.go index a5837ee..44efac6 100644 --- a/x/vaas/provider/keeper/consumer_lifecycle_test.go +++ b/x/vaas/provider/keeper/consumer_lifecycle_test.go @@ -1,18 +1,22 @@ package keeper_test import ( + "fmt" "testing" "cosmossdk.io/collections" + "cosmossdk.io/math" "github.com/stretchr/testify/require" + sdk "github.com/cosmos/cosmos-sdk/types" + testkeeper "github.com/allinbits/vaas/testutil/keeper" providertypes "github.com/allinbits/vaas/x/vaas/provider/types" ) func TestDeleteConsumerChain_RemovesReverseLookup(t *testing.T) { - k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() consumerId := k.FetchAndIncrementConsumerId(ctx) @@ -21,8 +25,62 @@ func TestDeleteConsumerChain_RemovesReverseLookup(t *testing.T) { k.SetConsumerClientId(ctx, consumerId, "07-tendermint-0") k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_STOPPED) + mocks.MockBankKeeper.EXPECT().GetAllBalances(ctx, poolAddr).Return(sdk.NewCoins()) + require.NoError(t, k.DeleteConsumerChain(ctx, consumerId)) _, err := k.FeePoolAddressToConsumerId.Get(ctx, poolAddr) require.ErrorIs(t, err, collections.ErrNotFound) } + +func TestDeleteConsumerChain_AutoSweep(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerClientId(ctx, consumerId, "07-tendermint-0") // required for cleanup block + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_STOPPED) + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, poolAddr, consumerId)) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, "uphoton"), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uphoton"), math.NewInt(100))) + + mocks.MockBankKeeper.EXPECT().GetAllBalances(ctx, poolAddr). + Return(sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 100)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, alice, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))).Return(nil) + + require.NoError(t, k.DeleteConsumerChain(ctx, consumerId)) + + require.Equal(t, providertypes.CONSUMER_PHASE_DELETED, k.GetConsumerPhase(ctx, consumerId)) +} + +func TestDeleteConsumerChain_AutoSweepFailureAborts(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := k.FetchAndIncrementConsumerId(ctx) + // No SetConsumerClientId — sweep fails before the cleanup block runs + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_STOPPED) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + mocks.MockBankKeeper.EXPECT().GetAllBalances(ctx, poolAddr). + Return(sdk.NewCoins(sdk.NewInt64Coin("uphoton", 50))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 50)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 50))). + Return(fmt.Errorf("forced bank error")) + + err := k.DeleteConsumerChain(ctx, consumerId) + require.Error(t, err) + // Phase remains STOPPED, not DELETED + require.Equal(t, providertypes.CONSUMER_PHASE_STOPPED, k.GetConsumerPhase(ctx, consumerId)) +} From 83de05e5677205d0a89b73b053fa677c1b76e6c6 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 18:27:35 +0200 Subject: [PATCH 08/18] export and rebuild share records across genesis round-trip --- x/vaas/provider/keeper/genesis.go | 123 ++++++++++++++++++++++++- x/vaas/provider/keeper/genesis_test.go | 75 +++++++++++++++ 2 files changed, 197 insertions(+), 1 deletion(-) diff --git a/x/vaas/provider/keeper/genesis.go b/x/vaas/provider/keeper/genesis.go index 473a2e7..cb358f0 100644 --- a/x/vaas/provider/keeper/genesis.go +++ b/x/vaas/provider/keeper/genesis.go @@ -11,6 +11,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" "cosmossdk.io/collections" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -139,6 +140,66 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) []abc } } + // Load primary share records + for _, s := range genState.ConsumerFeePoolShares { + addr, err := sdk.AccAddressFromBech32(s.Depositor) + if err != nil { + panic(fmt.Errorf("invalid depositor in genesis: %w", err)) + } + if err := k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(s.ConsumerId, addr, s.Denom), s.Shares, + ); err != nil { + panic(err) + } + } + + // Rebuild totals by summing per (consumer_id, denom) + totals := map[string]map[string]math.Int{} + for _, s := range genState.ConsumerFeePoolShares { + if _, ok := totals[s.ConsumerId]; !ok { + totals[s.ConsumerId] = map[string]math.Int{} + } + if cur, ok := totals[s.ConsumerId][s.Denom]; ok { + totals[s.ConsumerId][s.Denom] = cur.Add(s.Shares) + } else { + totals[s.ConsumerId][s.Denom] = s.Shares + } + } + for consumerId, byDenom := range totals { + for denom, sum := range byDenom { + if err := k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, denom), sum, + ); err != nil { + panic(err) + } + } + } + + // Rebuild reverse-lookup from non-DELETED consumers (read phase collection) + phaseIter, err := k.ConsumerPhase.Iterate(ctx, nil) + if err != nil { + panic(err) + } + defer phaseIter.Close() + for ; phaseIter.Valid(); phaseIter.Next() { + consumerId, err := phaseIter.Key() + if err != nil { + panic(err) + } + phaseRaw, err := phaseIter.Value() + if err != nil { + panic(err) + } + if types.ConsumerPhase(phaseRaw) == types.CONSUMER_PHASE_DELETED { + continue + } + if err := k.FeePoolAddressToConsumerId.Set(ctx, + k.GetConsumerFeePoolAddress(consumerId), consumerId, + ); err != nil { + panic(err) + } + } + k.SetParams(ctx, genState.Params) return k.InitGenesisValUpdates(ctx) } @@ -257,7 +318,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { } // TODO (PERMISSIONLESS) - return types.NewGenesisState( + gs := types.NewGenesisState( k.GetValidatorSetUpdateId(ctx), k.GetAllValsetUpdateBlockHeights(ctx), consumerStates, @@ -266,4 +327,64 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { k.GetAllValidatorsByConsumerAddr(ctx, nil), consumerAddrsToPrune, ) + + // Export share records + iter, err := k.ConsumerFeePoolShares.Iterate(ctx, nil) + if err != nil { + panic(err) + } + defer iter.Close() + for ; iter.Valid(); iter.Next() { + key, err := iter.Key() + if err != nil { + panic(err) + } + val, err := iter.Value() + if err != nil { + panic(err) + } + gs.ConsumerFeePoolShares = append(gs.ConsumerFeePoolShares, types.ConsumerFeePoolShare{ + ConsumerId: key.K1(), + Depositor: key.K2().String(), + Denom: key.K3(), + Shares: val, + }) + } + + // Sanity check: rebuild totals from shares and warn on divergence + recomputed := map[string]math.Int{} + for _, s := range gs.ConsumerFeePoolShares { + key := s.ConsumerId + "|" + s.Denom + if cur, ok := recomputed[key]; ok { + recomputed[key] = cur.Add(s.Shares) + } else { + recomputed[key] = s.Shares + } + } + totIter, err := k.ConsumerFeePoolTotalShares.Iterate(ctx, nil) + if err != nil { + panic(err) + } + for ; totIter.Valid(); totIter.Next() { + key, err := totIter.Key() + if err != nil { + panic(err) + } + val, err := totIter.Value() + if err != nil { + panic(err) + } + composite := key.K1() + "|" + key.K2() + expected, ok := recomputed[composite] + if !ok || !expected.Equal(val) { + k.Logger(ctx).Error( + "fee-pool total_shares mismatch at export", + "consumer_id", key.K1(), "denom", key.K2(), + "stored", val.String(), + ) + } + } + totIter.Close() + + return gs } diff --git a/x/vaas/provider/keeper/genesis_test.go b/x/vaas/provider/keeper/genesis_test.go index 5114d75..2562521 100644 --- a/x/vaas/provider/keeper/genesis_test.go +++ b/x/vaas/provider/keeper/genesis_test.go @@ -9,6 +9,9 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "cosmossdk.io/collections" + "cosmossdk.io/math" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -403,3 +406,75 @@ func TestGenesisRoundTrip(t *testing.T) { require.Equal(t, expA, expB, "round-trip must be a fixed point") } + +func TestExportGenesis_IncludesShares(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + k.SetParams(ctx, providertypes.DefaultParams()) + + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3("0", alice, "uphoton"), math.NewInt(60))) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3("0", bob, "uphoton"), math.NewInt(40))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join("0", "uphoton"), math.NewInt(100))) + + gs := k.ExportGenesis(ctx) + require.Len(t, gs.ConsumerFeePoolShares, 2) + found := map[string]math.Int{} + for _, s := range gs.ConsumerFeePoolShares { + found[s.Depositor] = s.Shares + } + require.Equal(t, math.NewInt(60), found[alice.String()]) + require.Equal(t, math.NewInt(40), found[bob.String()]) +} + +func TestInitGenesis_RebuildsDerivedCollections(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // InitGenesisValUpdates queries the staking keeper for the validator set. + mocks.MockStakingKeeper.EXPECT().GetBondedValidatorsByPower(gomock.Any()).Return(nil, nil).Times(1) + + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + gs := &providertypes.GenesisState{ + Params: providertypes.DefaultParams(), + ConsumerStates: []providertypes.ConsumerState{ + { + ChainId: "0", + Phase: providertypes.CONSUMER_PHASE_LAUNCHED, + ConsumerGenesis: *vaastypes.DefaultConsumerGenesisState(), + }, + { + ChainId: "1", + Phase: providertypes.CONSUMER_PHASE_DELETED, + ConsumerGenesis: *vaastypes.DefaultConsumerGenesisState(), + }, + }, + ConsumerFeePoolShares: []providertypes.ConsumerFeePoolShare{ + {ConsumerId: "0", Depositor: alice.String(), Denom: "uphoton", Shares: math.NewInt(60)}, + {ConsumerId: "0", Depositor: bob.String(), Denom: "uphoton", Shares: math.NewInt(40)}, + }, + } + + k.InitGenesis(ctx, gs) + + s, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3("0", alice, "uphoton")) + require.NoError(t, err) + require.Equal(t, math.NewInt(60), s) + + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join("0", "uphoton")) + require.NoError(t, err) + require.Equal(t, math.NewInt(100), total) + + cid, err := k.FeePoolAddressToConsumerId.Get(ctx, k.GetConsumerFeePoolAddress("0")) + require.NoError(t, err) + require.Equal(t, "0", cid) + + _, err = k.FeePoolAddressToConsumerId.Get(ctx, k.GetConsumerFeePoolAddress("1")) + require.ErrorIs(t, err, collections.ErrNotFound) +} From f27c71d6008017f55f249a450368bc2b4b588783 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 18:35:14 +0200 Subject: [PATCH 09/18] add paginated gRPC queries for depositor claims --- x/vaas/provider/keeper/grpc_query.go | 117 +++++++++++++++++++++- x/vaas/provider/keeper/grpc_query_test.go | 72 +++++++++++++ 2 files changed, 185 insertions(+), 4 deletions(-) diff --git a/x/vaas/provider/keeper/grpc_query.go b/x/vaas/provider/keeper/grpc_query.go index c144951..5462da0 100644 --- a/x/vaas/provider/keeper/grpc_query.go +++ b/x/vaas/provider/keeper/grpc_query.go @@ -12,10 +12,13 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "cosmossdk.io/collections" errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" ) var _ types.QueryServer = Keeper{} @@ -321,12 +324,118 @@ func (k Keeper) QueryConsumerChain(goCtx context.Context, req *types.QueryConsum }, nil } -func (k Keeper) ConsumerFeePoolClaim(_ context.Context, _ *types.QueryConsumerFeePoolClaimRequest) (*types.QueryConsumerFeePoolClaimResponse, error) { - panic("not implemented") +func (k Keeper) ConsumerFeePoolClaim( + goCtx context.Context, req *types.QueryConsumerFeePoolClaimRequest, +) (*types.QueryConsumerFeePoolClaimResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + depositorBech := req.Depositor + if depositorBech == k.GetAuthority() { + depositorBech = authtypes.NewModuleAddress(disttypes.ModuleName).String() + } + depositor, err := sdk.AccAddressFromBech32(depositorBech) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid depositor: %s", err) + } + + coins := sdk.NewCoins() + prefix := collections.NewPrefixedPairRange[string, string](req.ConsumerId) + iter, err := k.ConsumerFeePoolTotalShares.Iterate(ctx, prefix) + if err != nil { + return nil, status.Errorf(codes.Internal, "iterate totals: %s", err) + } + defer iter.Close() + for ; iter.Valid(); iter.Next() { + key, err := iter.Key() + if err != nil { + return nil, status.Errorf(codes.Internal, "key: %s", err) + } + denom := key.K2() + claim := k.ComputeClaim(ctx, req.ConsumerId, depositor, denom) + if claim.IsPositive() { + coins = coins.Add(sdk.NewCoin(denom, claim)) + } + } + return &types.QueryConsumerFeePoolClaimResponse{Claim: coins}, nil } -func (k Keeper) ConsumerFeePoolClaims(_ context.Context, _ *types.QueryConsumerFeePoolClaimsRequest) (*types.QueryConsumerFeePoolClaimsResponse, error) { - panic("not implemented") +func (k Keeper) ConsumerFeePoolClaims( + goCtx context.Context, req *types.QueryConsumerFeePoolClaimsRequest, +) (*types.QueryConsumerFeePoolClaimsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + type acc struct { + addr sdk.AccAddress + coins sdk.Coins + } + perDepositor := map[string]*acc{} + + prefix := collections.NewPrefixedTripleRange[string, sdk.AccAddress, string](req.ConsumerId) + iter, err := k.ConsumerFeePoolShares.Iterate(ctx, prefix) + if err != nil { + return nil, status.Errorf(codes.Internal, "%s", err) + } + for ; iter.Valid(); iter.Next() { + key, _ := iter.Key() + addr := key.K2() + denom := key.K3() + claim := k.ComputeClaim(ctx, req.ConsumerId, addr, denom) + if claim.IsZero() { + continue + } + if entry, ok := perDepositor[addr.String()]; ok { + entry.coins = entry.coins.Add(sdk.NewCoin(denom, claim)) + } else { + perDepositor[addr.String()] = &acc{ + addr: addr, + coins: sdk.NewCoins(sdk.NewCoin(denom, claim)), + } + } + } + iter.Close() + + keys := make([]string, 0, len(perDepositor)) + for key := range perDepositor { + keys = append(keys, key) + } + sort.Strings(keys) + + offset, limit := uint64(0), uint64(100) + if req.Pagination != nil { + offset = req.Pagination.Offset + if req.Pagination.Limit > 0 { + limit = req.Pagination.Limit + } + } + + end := offset + limit + if end > uint64(len(keys)) { + end = uint64(len(keys)) + } + if offset > uint64(len(keys)) { + offset = uint64(len(keys)) + } + + claims := make([]types.DepositorClaim, 0, end-offset) + for _, key := range keys[offset:end] { + entry := perDepositor[key] + claims = append(claims, types.DepositorClaim{ + Depositor: entry.addr.String(), + Claim: entry.coins, + }) + } + return &types.QueryConsumerFeePoolClaimsResponse{ + Claims: claims, + Pagination: &query.PageResponse{ + Total: uint64(len(keys)), + }, + }, nil } func (k Keeper) QueryConsumerGenesisTime(goCtx context.Context, req *types.QueryConsumerGenesisTimeRequest) (*types.QueryConsumerGenesisTimeResponse, error) { diff --git a/x/vaas/provider/keeper/grpc_query_test.go b/x/vaas/provider/keeper/grpc_query_test.go index 49b85e5..640aca1 100644 --- a/x/vaas/provider/keeper/grpc_query_test.go +++ b/x/vaas/provider/keeper/grpc_query_test.go @@ -4,10 +4,15 @@ import ( "testing" "time" + "cosmossdk.io/collections" "cosmossdk.io/math" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + testkeeper "github.com/allinbits/vaas/testutil/keeper" providertypes "github.com/allinbits/vaas/x/vaas/provider/types" ) @@ -37,3 +42,70 @@ func TestQueryConsumerChainIncludesFeePoolAddress(t *testing.T) { require.NoError(t, err) require.Equal(t, expected, chain.FeePoolAddress) } + +func TestQueryConsumerFeePoolClaim(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, "uphoton"), math.NewInt(50))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uphoton"), math.NewInt(100))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 200)) + + res, err := k.ConsumerFeePoolClaim(ctx, &providertypes.QueryConsumerFeePoolClaimRequest{ + ConsumerId: consumerId, Depositor: alice.String(), + }) + require.NoError(t, err) + require.Equal(t, "100uphoton", res.Claim.String()) +} + +func TestQueryConsumerFeePoolClaim_GovAlias(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, distrAddr, "uphoton"), math.NewInt(100))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uphoton"), math.NewInt(100))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 50)) + + res, err := k.ConsumerFeePoolClaim(ctx, &providertypes.QueryConsumerFeePoolClaimRequest{ + ConsumerId: consumerId, Depositor: k.GetAuthority(), + }) + require.NoError(t, err) + require.Equal(t, "50uphoton", res.Claim.String()) +} + +func TestQueryConsumerFeePoolClaims(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, alice, "uphoton"), math.NewInt(30))) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, bob, "uphoton"), math.NewInt(70))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uphoton"), math.NewInt(100))) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 100)).AnyTimes() + + res, err := k.ConsumerFeePoolClaims(ctx, &providertypes.QueryConsumerFeePoolClaimsRequest{ + ConsumerId: consumerId, + }) + require.NoError(t, err) + require.Len(t, res.Claims, 2) +} From 7d39ed879f41ce87b888c942f3f172c14afc0073 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 18:39:13 +0200 Subject: [PATCH 10/18] add CLI commands for the new tx messages and queries --- x/vaas/provider/client/cli/query.go | 57 ++++++++++++++++++++ x/vaas/provider/client/cli/tx.go | 83 +++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/x/vaas/provider/client/cli/query.go b/x/vaas/provider/client/cli/query.go index 5a6ee8d..99ce7a1 100644 --- a/x/vaas/provider/client/cli/query.go +++ b/x/vaas/provider/client/cli/query.go @@ -44,6 +44,8 @@ func NewQueryCmd() *cobra.Command { cmd.AddCommand(CmdConsumerIdFromClientId()) cmd.AddCommand(CmdConsumerChain()) cmd.AddCommand(CmdConsumerGenesisTime()) + cmd.AddCommand(CmdConsumerFeePoolClaim()) + cmd.AddCommand(CmdConsumerFeePoolClaims()) return cmd } @@ -449,3 +451,58 @@ func CmdConsumerGenesisTime() *cobra.Command { return cmd } + +func CmdConsumerFeePoolClaim() *cobra.Command { + cmd := &cobra.Command{ + Use: "consumer-fee-pool-claim [consumer-id] [depositor]", + Short: "Query a depositor's claimable balance on a consumer fee pool", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + qc := types.NewQueryClient(clientCtx) + res, err := qc.ConsumerFeePoolClaim(cmd.Context(), &types.QueryConsumerFeePoolClaimRequest{ + ConsumerId: args[0], + Depositor: args[1], + }) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +func CmdConsumerFeePoolClaims() *cobra.Command { + cmd := &cobra.Command{ + Use: "consumer-fee-pool-claims [consumer-id]", + Short: "Query all depositor claims on a consumer fee pool (paginated)", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + qc := types.NewQueryClient(clientCtx) + res, err := qc.ConsumerFeePoolClaims(cmd.Context(), &types.QueryConsumerFeePoolClaimsRequest{ + ConsumerId: args[0], + Pagination: pageReq, + }) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + } + flags.AddPaginationFlagsToCmd(cmd, "consumer-fee-pool-claims") + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/x/vaas/provider/client/cli/tx.go b/x/vaas/provider/client/cli/tx.go index 865b5d9..413ee5f 100644 --- a/x/vaas/provider/client/cli/tx.go +++ b/x/vaas/provider/client/cli/tx.go @@ -37,6 +37,9 @@ func GetTxCmd() *cobra.Command { cmd.AddCommand(NewCreateConsumerCmd()) cmd.AddCommand(NewUpdateConsumerCmd()) cmd.AddCommand(NewRemoveConsumerCmd()) + cmd.AddCommand(NewFundConsumerFeePoolCmd()) + cmd.AddCommand(NewWithdrawConsumerFeePoolCmd()) + cmd.AddCommand(NewSweepConsumerFeePoolCmd()) return cmd } @@ -456,3 +459,83 @@ Example: return cmd } + +func NewFundConsumerFeePoolCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "fund-consumer-fee-pool [consumer-id] [amount]", + Short: "Deposit funds into a consumer's fee pool, crediting the signer with shares", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + amount, err := sdk.ParseCoinNormalized(args[1]) + if err != nil { + return err + } + msg := &types.MsgFundConsumerFeePool{ + Signer: clientCtx.GetFromAddress().String(), + ConsumerId: args[0], + Amount: amount, + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func NewWithdrawConsumerFeePoolCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "withdraw-consumer-fee-pool [consumer-id] [coins]", + Short: "Withdraw tokens from your share in a consumer's fee pool (multi-denom)", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + coins, err := sdk.ParseCoinsNormalized(args[1]) + if err != nil { + return err + } + msg := &types.MsgWithdrawConsumerFeePool{ + Signer: clientCtx.GetFromAddress().String(), + ConsumerId: args[0], + Amount: coins, + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func NewSweepConsumerFeePoolCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "sweep-consumer-fee-pool [consumer-id]", + Short: "Owner-triggered pro-rata distribution of a consumer's fee pool", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + denomsCSV, _ := cmd.Flags().GetString("denoms") + var denoms []string + if strings.TrimSpace(denomsCSV) != "" { + denoms = strings.Split(denomsCSV, ",") + } + msg := &types.MsgSweepConsumerFeePool{ + Signer: clientCtx.GetFromAddress().String(), + ConsumerId: args[0], + Denoms: denoms, + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + cmd.Flags().String("denoms", "", "comma-separated denoms to sweep (default: all denoms with shares or balance)") + flags.AddTxFlagsToCmd(cmd) + return cmd +} From 94f26ea242e045d4de4861bf7b0d23903175e063 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 18:43:36 +0200 Subject: [PATCH 11/18] clean up proto imports and lint --- proto/vaas/provider/v1/genesis.proto | 1 - x/vaas/provider/keeper/keeper.go | 14 +-- x/vaas/provider/types/events.go | 12 +-- x/vaas/provider/types/genesis.pb.go | 122 +++++++++++++-------------- 4 files changed, 73 insertions(+), 76 deletions(-) diff --git a/proto/vaas/provider/v1/genesis.proto b/proto/vaas/provider/v1/genesis.proto index 44e13e2..290e738 100644 --- a/proto/vaas/provider/v1/genesis.proto +++ b/proto/vaas/provider/v1/genesis.proto @@ -7,7 +7,6 @@ option go_package = "github.com/allinbits/vaas/x/vaas/provider/types"; import "gogoproto/gogo.proto"; import "google/protobuf/timestamp.proto"; import "cosmos_proto/cosmos.proto"; -import "cosmos/base/v1beta1/coin.proto"; import "vaas/v1/shared_consumer.proto"; import "vaas/v1/wire.proto"; import "vaas/provider/v1/provider.proto"; diff --git a/x/vaas/provider/keeper/keeper.go b/x/vaas/provider/keeper/keeper.go index 1be5860..32955cc 100644 --- a/x/vaas/provider/keeper/keeper.go +++ b/x/vaas/provider/keeper/keeper.go @@ -32,10 +32,10 @@ type Keeper struct { storeService corestoretypes.KVStoreService - cdc codec.BinaryCodec - accountKeeper vaastypes.AccountKeeper - clientKeeper vaastypes.ClientKeeper - clientV2Keeper vaastypes.ClientV2Keeper + cdc codec.BinaryCodec + accountKeeper vaastypes.AccountKeeper + clientKeeper vaastypes.ClientKeeper + clientV2Keeper vaastypes.ClientV2Keeper stakingKeeper vaastypes.StakingKeeper slashingKeeper vaastypes.SlashingKeeper bankKeeper vaastypes.BankKeeper @@ -92,10 +92,10 @@ func NewKeeper( clientV2Keeper vaastypes.ClientV2Keeper, stakingKeeper vaastypes.StakingKeeper, slashingKeeper vaastypes.SlashingKeeper, accountKeeper vaastypes.AccountKeeper, - bankKeeper vaastypes.BankKeeper, + bankKeeper vaastypes.BankKeeper, distributionKeeper vaastypes.DistributionKeeper, - govKeeper govkeeper.Keeper, - authority string, + govKeeper govkeeper.Keeper, + authority string, validatorAddressCodec, consensusAddressCodec addresscodec.Codec, feeCollectorName string, ) Keeper { diff --git a/x/vaas/provider/types/events.go b/x/vaas/provider/types/events.go index 6d76b2a..625b7ee 100644 --- a/x/vaas/provider/types/events.go +++ b/x/vaas/provider/types/events.go @@ -26,10 +26,10 @@ const ( AttributeConsumerOwner = "consumer_owner" AttributeConsumerSpawnTime = "consumer_spawn_time" AttributeConsumerPhase = "consumer_phase" - AttributeDepositor = "depositor" - AttributeRecipient = "recipient" - AttributeAmount = "amount" - AttributeDenom = "denom" - AttributeTotalDistributed = "total_distributed" - AttributeDust = "dust" + AttributeDepositor = "depositor" + AttributeRecipient = "recipient" + AttributeAmount = "amount" + AttributeDenom = "denom" + AttributeTotalDistributed = "total_distributed" + AttributeDust = "dust" ) diff --git a/x/vaas/provider/types/genesis.pb.go b/x/vaas/provider/types/genesis.pb.go index d5d71fa..42f0e32 100644 --- a/x/vaas/provider/types/genesis.pb.go +++ b/x/vaas/provider/types/genesis.pb.go @@ -8,7 +8,6 @@ import ( fmt "fmt" types "github.com/allinbits/vaas/x/vaas/types" _ "github.com/cosmos/cosmos-proto" - _ "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" @@ -425,67 +424,66 @@ func init() { func init() { proto.RegisterFile("vaas/provider/v1/genesis.proto", fileDescriptor_c9071b84cde652f9) } var fileDescriptor_c9071b84cde652f9 = []byte{ - // 956 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xd1, 0x6e, 0xdb, 0x36, - 0x17, 0x8e, 0x12, 0x3b, 0xb5, 0xe9, 0x24, 0x7f, 0x40, 0xb8, 0xfe, 0xd5, 0x14, 0xb5, 0x0d, 0x0f, - 0x1d, 0x3c, 0x6c, 0x95, 0xe0, 0x0c, 0xeb, 0xc5, 0x2e, 0x06, 0xc4, 0x29, 0xb6, 0x19, 0xc3, 0x06, - 0x43, 0xce, 0x76, 0xd1, 0x1b, 0x81, 0x16, 0x59, 0x89, 0xb3, 0x44, 0x0a, 0x22, 0xad, 0xcc, 0x7b, - 0x8a, 0x3e, 0xc5, 0x9e, 0xa0, 0x0f, 0x51, 0xec, 0xaa, 0xe8, 0xd5, 0xb0, 0x8b, 0x6c, 0x48, 0x9e, - 0x60, 0x7b, 0x82, 0x41, 0x24, 0xa5, 0xc6, 0x89, 0xb3, 0x62, 0x77, 0xe2, 0xf9, 0x3e, 0x7e, 0xdf, - 0xa1, 0xce, 0x39, 0x24, 0xe8, 0xe6, 0x08, 0x09, 0x37, 0xcd, 0x78, 0x4e, 0x31, 0xc9, 0xdc, 0x7c, - 0xe4, 0x86, 0x84, 0x11, 0x41, 0x85, 0x93, 0x66, 0x5c, 0x72, 0x78, 0x58, 0xe0, 0x4e, 0x89, 0x3b, - 0xf9, 0xe8, 0xa8, 0x1d, 0xf2, 0x90, 0x2b, 0xd0, 0x2d, 0xbe, 0x34, 0xef, 0xa8, 0x17, 0x72, 0x1e, - 0xc6, 0xc4, 0x55, 0xab, 0xf9, 0xf2, 0x85, 0x2b, 0x69, 0x42, 0x84, 0x44, 0x49, 0x6a, 0x08, 0x0f, - 0x02, 0x2e, 0x12, 0x2e, 0x7c, 0xbd, 0x53, 0x2f, 0x0c, 0xd4, 0xd5, 0x2b, 0x77, 0x8e, 0x04, 0x71, - 0xf3, 0xd1, 0x9c, 0x48, 0x34, 0x72, 0x03, 0x4e, 0x99, 0xc1, 0x1f, 0xa9, 0x1c, 0xf3, 0x91, 0x2b, - 0x22, 0x94, 0x11, 0xec, 0x07, 0x9c, 0x89, 0x65, 0x42, 0x32, 0x03, 0xc3, 0x12, 0x3e, 0xa7, 0x19, - 0x29, 0xd3, 0xb9, 0x75, 0xac, 0xea, 0x08, 0x8a, 0x30, 0xf8, 0xab, 0x0e, 0xf6, 0xbe, 0xd2, 0x27, - 0x9d, 0x49, 0x24, 0x09, 0x1c, 0x82, 0xc3, 0x1c, 0xc5, 0x82, 0x48, 0x7f, 0x99, 0x62, 0x24, 0x89, - 0x4f, 0xb1, 0x6d, 0xf5, 0xad, 0x61, 0xcd, 0x3b, 0xd0, 0xf1, 0xef, 0x55, 0x78, 0x82, 0x61, 0x04, - 0xfe, 0x57, 0x66, 0xe0, 0x8b, 0x62, 0xaf, 0xb0, 0xb7, 0xfb, 0x3b, 0xc3, 0xd6, 0x71, 0xcf, 0xb9, - 0xf9, 0xb3, 0x9c, 0x53, 0x43, 0x54, 0x1e, 0xe3, 0xee, 0xeb, 0x8b, 0xde, 0xd6, 0xdf, 0x17, 0xbd, - 0xce, 0x0a, 0x25, 0xf1, 0xe7, 0x83, 0x1b, 0x2a, 0x03, 0xef, 0x20, 0xb8, 0x4e, 0x17, 0xf0, 0x47, - 0x70, 0x74, 0x33, 0x27, 0x5f, 0x72, 0x3f, 0x22, 0x34, 0x8c, 0xa4, 0xbd, 0xa3, 0x4c, 0x87, 0xb7, - 0x4d, 0x7f, 0x58, 0xcb, 0xf7, 0x8c, 0x7f, 0xad, 0xf8, 0xe3, 0x5a, 0xe1, 0xee, 0x75, 0xf2, 0x8d, - 0x28, 0x7c, 0x0a, 0x76, 0x53, 0x94, 0xa1, 0x44, 0xd8, 0xb5, 0xbe, 0x35, 0x6c, 0x1d, 0xdb, 0xb7, - 0x75, 0xa7, 0x0a, 0x37, 0x3a, 0x86, 0x0d, 0x13, 0x95, 0x23, 0xc5, 0x48, 0xf2, 0xac, 0xaa, 0x8c, - 0x9f, 0x2e, 0xe7, 0x0b, 0xb2, 0x12, 0x76, 0x5d, 0xe5, 0xf8, 0xd1, 0xc6, 0x1c, 0xf5, 0x9e, 0xf2, - 0x0f, 0x4d, 0x97, 0xf3, 0x6f, 0xc8, 0xca, 0x88, 0xdb, 0xf9, 0x06, 0xb8, 0x10, 0x84, 0x0c, 0x3c, - 0xac, 0x30, 0xe1, 0xcf, 0x57, 0xef, 0x2c, 0x11, 0xc6, 0x99, 0xbd, 0xfb, 0x5e, 0xbf, 0xf1, 0xaa, - 0x94, 0x3c, 0xc1, 0x38, 0xbb, 0xe5, 0x27, 0xd6, 0x71, 0x18, 0x80, 0xff, 0xaf, 0x39, 0x88, 0xa2, - 0x00, 0x69, 0xb6, 0x64, 0xc4, 0xbe, 0xa7, 0xbc, 0x3e, 0xbc, 0xbb, 0xe8, 0x85, 0x80, 0x38, 0xe3, - 0xd3, 0x82, 0x6d, 0x8c, 0xda, 0xc1, 0x06, 0x0c, 0x12, 0x60, 0x57, 0x26, 0x2f, 0x08, 0xf1, 0x53, - 0xce, 0x63, 0x5f, 0x35, 0xbb, 0xb0, 0x1b, 0xef, 0x73, 0xf9, 0x92, 0x90, 0x29, 0xe7, 0xf1, 0xac, - 0xa0, 0x1b, 0x97, 0xfb, 0xc1, 0x06, 0x4c, 0x0c, 0x7e, 0xa9, 0x83, 0xfd, 0xb5, 0x86, 0x84, 0x3d, - 0xd0, 0xaa, 0x8c, 0xab, 0x7e, 0x07, 0x65, 0x68, 0x82, 0xe1, 0x03, 0xd0, 0x08, 0x22, 0x44, 0x59, - 0x81, 0x6e, 0xf7, 0xad, 0x61, 0xd3, 0xbb, 0xa7, 0xd6, 0x13, 0x0c, 0x1f, 0x82, 0x66, 0x10, 0x53, - 0xc2, 0x64, 0x81, 0xed, 0x28, 0xac, 0xa1, 0x03, 0x13, 0x0c, 0x1f, 0x83, 0x03, 0xca, 0xa8, 0xa4, - 0x28, 0x2e, 0xbb, 0xb5, 0xa6, 0xb4, 0xf7, 0x4d, 0xd4, 0x34, 0xdd, 0x77, 0xe0, 0xb0, 0xf2, 0x37, - 0xf7, 0x8e, 0x5d, 0x57, 0xed, 0xf7, 0x48, 0x1f, 0xf8, 0xda, 0x39, 0xaf, 0x4f, 0xab, 0x39, 0x67, - 0x35, 0x87, 0x06, 0x83, 0x08, 0x74, 0x52, 0xc2, 0x30, 0x65, 0xa1, 0x6f, 0x06, 0x27, 0x88, 0x10, - 0x0b, 0x89, 0x30, 0x8d, 0xf1, 0xb8, 0x52, 0xad, 0xfa, 0x61, 0x46, 0xe4, 0xa9, 0xe2, 0x4c, 0x51, - 0xb0, 0x20, 0xf2, 0x19, 0x92, 0xa8, 0xac, 0x95, 0x91, 0xd2, 0xe3, 0xa4, 0x49, 0x02, 0x7e, 0x02, - 0xa0, 0x88, 0x91, 0x88, 0x7c, 0xcc, 0xcf, 0x59, 0x71, 0xc9, 0xf9, 0x28, 0x58, 0xa8, 0x5e, 0x68, - 0x7a, 0x87, 0x0a, 0x79, 0x66, 0x80, 0x93, 0x60, 0x01, 0x3f, 0x03, 0xf5, 0x34, 0x42, 0x82, 0xd8, - 0x8d, 0xbe, 0x35, 0x3c, 0xf8, 0xb7, 0x1b, 0x62, 0x5a, 0xd0, 0x3c, 0xcd, 0x86, 0x1f, 0x80, 0x7d, - 0x7e, 0xce, 0x4c, 0xcb, 0x11, 0x21, 0xec, 0xa6, 0xfa, 0xbf, 0x7b, 0x2a, 0x78, 0xa2, 0x63, 0xf0, - 0x0b, 0xd0, 0x48, 0x88, 0x44, 0x18, 0x49, 0x64, 0x03, 0xf5, 0xd3, 0x06, 0x77, 0xcb, 0x7f, 0x6b, - 0x98, 0x5e, 0xb5, 0x07, 0xce, 0x40, 0xab, 0xa8, 0x86, 0x6f, 0xc6, 0xbe, 0xa5, 0x24, 0x8e, 0xef, - 0x96, 0x98, 0xe8, 0xd2, 0xd1, 0x9f, 0x91, 0xa4, 0x9c, 0xa9, 0xcb, 0x80, 0x48, 0x92, 0x09, 0x0f, - 0x14, 0x32, 0xfa, 0x72, 0x80, 0xa7, 0x60, 0x2f, 0x23, 0x09, 0xcf, 0x51, 0xec, 0x17, 0xff, 0xc0, - 0xde, 0x53, 0xaa, 0x47, 0x8e, 0x7e, 0x1e, 0x9c, 0xf2, 0x79, 0x70, 0xce, 0xca, 0xe7, 0x61, 0x5c, - 0x7b, 0xf9, 0x47, 0xcf, 0xf2, 0x5a, 0x66, 0x57, 0x11, 0x1f, 0x3c, 0x07, 0x9d, 0xcd, 0x77, 0xd8, - 0x7f, 0xb8, 0xa5, 0x3b, 0x60, 0xd7, 0x74, 0xde, 0xb6, 0xc2, 0xcd, 0x6a, 0xf0, 0xab, 0x05, 0xda, - 0x9b, 0x46, 0x67, 0xd3, 0x2c, 0x34, 0xd7, 0x66, 0xe1, 0x29, 0x68, 0x62, 0x92, 0x72, 0x41, 0x25, - 0xcf, 0xf4, 0x30, 0x8c, 0xed, 0xb7, 0xaf, 0x9e, 0xb4, 0xcd, 0x5b, 0x66, 0xca, 0x32, 0x93, 0x19, - 0x65, 0xa1, 0xf7, 0x8e, 0x0a, 0xdb, 0xa0, 0x8e, 0x09, 0xe3, 0x89, 0x19, 0x12, 0xbd, 0x80, 0xa7, - 0x60, 0xd7, 0x4c, 0x78, 0x4d, 0x49, 0x7d, 0x5c, 0xf4, 0xdc, 0xef, 0x17, 0xbd, 0xfb, 0x5a, 0x4e, - 0xe0, 0x85, 0x43, 0xb9, 0x9b, 0x20, 0x19, 0x39, 0x13, 0x26, 0xdf, 0xbe, 0x7a, 0x02, 0x8c, 0xcf, - 0x84, 0x49, 0xcf, 0x6c, 0x1d, 0x4f, 0x5e, 0x5f, 0x76, 0xad, 0x37, 0x97, 0x5d, 0xeb, 0xcf, 0xcb, - 0xae, 0xf5, 0xf2, 0xaa, 0xbb, 0xf5, 0xe6, 0xaa, 0xbb, 0xf5, 0xdb, 0x55, 0x77, 0xeb, 0xb9, 0x1b, - 0x52, 0x19, 0x2d, 0xe7, 0x4e, 0xc0, 0x13, 0x17, 0xc5, 0x31, 0x65, 0x73, 0x2a, 0x85, 0xab, 0x5e, - 0xc5, 0x9f, 0xdc, 0xf5, 0xc7, 0x51, 0xae, 0x52, 0x22, 0xe6, 0xbb, 0xaa, 0x34, 0x9f, 0xfe, 0x13, - 0x00, 0x00, 0xff, 0xff, 0x51, 0x56, 0x9f, 0xcf, 0x11, 0x08, 0x00, 0x00, + // 938 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xcd, 0x6e, 0xdb, 0x46, + 0x17, 0x35, 0x6d, 0x49, 0x91, 0x46, 0xb6, 0x3f, 0x63, 0xa0, 0xe8, 0x63, 0x1c, 0x44, 0x12, 0x54, + 0xa4, 0x50, 0xd1, 0x86, 0x84, 0x5d, 0x34, 0x8b, 0x2e, 0x0a, 0x58, 0x0e, 0xda, 0x0a, 0x45, 0x0b, + 0x81, 0x72, 0xbb, 0xc8, 0x86, 0x18, 0x71, 0x26, 0xe4, 0x54, 0x24, 0x87, 0xe0, 0x8c, 0xe8, 0xaa, + 0x4f, 0x91, 0xa7, 0xe8, 0x13, 0xe4, 0x21, 0x82, 0xae, 0x82, 0xac, 0x8a, 0x2e, 0xdc, 0xc2, 0x7e, + 0x82, 0xf6, 0x09, 0x8a, 0xf9, 0x21, 0x63, 0xd9, 0x72, 0x83, 0xee, 0x34, 0xf7, 0x9c, 0x39, 0xe7, + 0x72, 0xee, 0x8f, 0x40, 0xaf, 0x40, 0x88, 0xbb, 0x59, 0xce, 0x0a, 0x8a, 0x49, 0xee, 0x16, 0x47, + 0x6e, 0x48, 0x52, 0xc2, 0x29, 0x77, 0xb2, 0x9c, 0x09, 0x06, 0x0f, 0x24, 0xee, 0x94, 0xb8, 0x53, + 0x1c, 0x1d, 0x76, 0x42, 0x16, 0x32, 0x05, 0xba, 0xf2, 0x97, 0xe6, 0x1d, 0xf6, 0x43, 0xc6, 0xc2, + 0x98, 0xb8, 0xea, 0x34, 0x5f, 0xbe, 0x70, 0x05, 0x4d, 0x08, 0x17, 0x28, 0xc9, 0x0c, 0xe1, 0x41, + 0xc0, 0x78, 0xc2, 0xb8, 0xaf, 0x6f, 0xea, 0x83, 0x81, 0x1e, 0xa9, 0x1c, 0x8a, 0x23, 0x97, 0x47, + 0x28, 0x27, 0xd8, 0x0f, 0x58, 0xca, 0x97, 0x09, 0xc9, 0x0d, 0x0c, 0x4b, 0xf8, 0x9c, 0xe6, 0xa4, + 0xb4, 0xbb, 0x95, 0x76, 0x95, 0xa2, 0x22, 0x0c, 0xff, 0xaa, 0x83, 0xdd, 0xaf, 0xf4, 0x97, 0xcc, + 0x04, 0x12, 0x04, 0x8e, 0xc0, 0x41, 0x81, 0x62, 0x4e, 0x84, 0xbf, 0xcc, 0x30, 0x12, 0xc4, 0xa7, + 0xd8, 0xb6, 0x06, 0xd6, 0xa8, 0xe6, 0xed, 0xeb, 0xf8, 0xf7, 0x2a, 0x3c, 0xc1, 0x30, 0x02, 0xff, + 0x2b, 0x33, 0xf0, 0xb9, 0xbc, 0xcb, 0xed, 0xed, 0xc1, 0xce, 0xa8, 0x7d, 0xdc, 0x77, 0x6e, 0x3e, + 0x86, 0x73, 0x6a, 0x88, 0xca, 0x63, 0xdc, 0x7b, 0x7d, 0xd1, 0xdf, 0xfa, 0xfb, 0xa2, 0xdf, 0x5d, + 0xa1, 0x24, 0xfe, 0x7c, 0x78, 0x43, 0x65, 0xe8, 0xed, 0x07, 0xd7, 0xe9, 0x1c, 0xfe, 0x08, 0x0e, + 0x6f, 0xe6, 0xe4, 0x0b, 0xe6, 0x47, 0x84, 0x86, 0x91, 0xb0, 0x77, 0x94, 0xe9, 0xe8, 0xb6, 0xe9, + 0x0f, 0x6b, 0xf9, 0x9e, 0xb1, 0xaf, 0x15, 0x7f, 0x5c, 0x93, 0xee, 0x5e, 0xb7, 0xd8, 0x88, 0xc2, + 0xa7, 0xa0, 0x91, 0xa1, 0x1c, 0x25, 0xdc, 0xae, 0x0d, 0xac, 0x51, 0xfb, 0xd8, 0xbe, 0xad, 0x3b, + 0x55, 0xb8, 0xd1, 0x31, 0x6c, 0x98, 0xa8, 0x1c, 0x29, 0x46, 0x82, 0xe5, 0x55, 0x65, 0xfc, 0x6c, + 0x39, 0x5f, 0x90, 0x15, 0xb7, 0xeb, 0x2a, 0xc7, 0x8f, 0x36, 0xe6, 0xa8, 0xef, 0x94, 0x2f, 0x34, + 0x5d, 0xce, 0xbf, 0x21, 0x2b, 0x23, 0x6e, 0x17, 0x1b, 0x60, 0x29, 0x08, 0x53, 0xf0, 0xb0, 0xc2, + 0xb8, 0x3f, 0x5f, 0xbd, 0xb3, 0x44, 0x18, 0xe7, 0x76, 0xe3, 0xbd, 0x7e, 0xe3, 0x55, 0x29, 0x79, + 0x82, 0x71, 0x7e, 0xcb, 0x8f, 0xaf, 0xe3, 0x30, 0x00, 0xff, 0x5f, 0x73, 0xe0, 0xb2, 0x00, 0x59, + 0xbe, 0x4c, 0x89, 0x7d, 0x4f, 0x79, 0x7d, 0x78, 0x77, 0xd1, 0xa5, 0x00, 0x3f, 0x63, 0x53, 0xc9, + 0x36, 0x46, 0x9d, 0x60, 0x03, 0x06, 0x09, 0xb0, 0x2b, 0x93, 0x17, 0x84, 0xf8, 0x19, 0x63, 0xb1, + 0xaf, 0x9a, 0x9d, 0xdb, 0xcd, 0xf7, 0xb9, 0x7c, 0x49, 0xc8, 0x94, 0xb1, 0x78, 0x26, 0xe9, 0xc6, + 0xe5, 0x7e, 0xb0, 0x01, 0xe3, 0xc3, 0x5f, 0xea, 0x60, 0x6f, 0xad, 0x21, 0x61, 0x1f, 0xb4, 0x2b, + 0xe3, 0xaa, 0xdf, 0x41, 0x19, 0x9a, 0x60, 0xf8, 0x00, 0x34, 0x83, 0x08, 0xd1, 0x54, 0xa2, 0xdb, + 0x03, 0x6b, 0xd4, 0xf2, 0xee, 0xa9, 0xf3, 0x04, 0xc3, 0x87, 0xa0, 0x15, 0xc4, 0x94, 0xa4, 0x42, + 0x62, 0x3b, 0x0a, 0x6b, 0xea, 0xc0, 0x04, 0xc3, 0xc7, 0x60, 0x9f, 0xa6, 0x54, 0x50, 0x14, 0x97, + 0xdd, 0x5a, 0x53, 0xda, 0x7b, 0x26, 0x6a, 0x9a, 0xee, 0x3b, 0x70, 0x50, 0xf9, 0x9b, 0xbd, 0x62, + 0xd7, 0x55, 0xfb, 0x3d, 0xd2, 0x1f, 0x7c, 0xed, 0x3b, 0xaf, 0x4f, 0xab, 0xf9, 0xce, 0x6a, 0x0e, + 0x0d, 0x06, 0x11, 0xe8, 0x66, 0x24, 0xc5, 0x34, 0x0d, 0x7d, 0x33, 0x38, 0x41, 0x84, 0xd2, 0x90, + 0x70, 0xd3, 0x18, 0x8f, 0x2b, 0xd5, 0xaa, 0x1f, 0x66, 0x44, 0x9c, 0x2a, 0xce, 0x14, 0x05, 0x0b, + 0x22, 0x9e, 0x21, 0x81, 0xca, 0x5a, 0x19, 0x29, 0x3d, 0x4e, 0x9a, 0xc4, 0xe1, 0x27, 0x00, 0xf2, + 0x18, 0xf1, 0xc8, 0xc7, 0xec, 0x3c, 0x95, 0x4b, 0xcc, 0x47, 0xc1, 0x42, 0xf5, 0x42, 0xcb, 0x3b, + 0x50, 0xc8, 0x33, 0x03, 0x9c, 0x04, 0x0b, 0xf8, 0x19, 0xa8, 0x67, 0x11, 0xe2, 0xc4, 0x6e, 0x0e, + 0xac, 0xd1, 0xfe, 0xbf, 0x6d, 0x88, 0xa9, 0xa4, 0x79, 0x9a, 0x0d, 0x3f, 0x00, 0x7b, 0xec, 0x3c, + 0x35, 0x2d, 0x47, 0x38, 0xb7, 0x5b, 0xea, 0x7d, 0x77, 0x55, 0xf0, 0x44, 0xc7, 0xe0, 0x17, 0xa0, + 0x99, 0x10, 0x81, 0x30, 0x12, 0xc8, 0x06, 0xea, 0xd1, 0x86, 0x77, 0xcb, 0x7f, 0x6b, 0x98, 0x5e, + 0x75, 0x07, 0xce, 0x40, 0x5b, 0x56, 0xc3, 0x37, 0x63, 0xdf, 0x56, 0x12, 0xc7, 0x77, 0x4b, 0x4c, + 0x74, 0xe9, 0xe8, 0xcf, 0x48, 0x50, 0x96, 0xaa, 0x65, 0x40, 0x04, 0xc9, 0xb9, 0x07, 0xa4, 0x8c, + 0x5e, 0x0e, 0xf0, 0x14, 0xec, 0xe6, 0x24, 0x61, 0x05, 0x8a, 0x7d, 0xf9, 0x06, 0xf6, 0xae, 0x52, + 0x3d, 0x74, 0xf4, 0xfa, 0x77, 0xca, 0xf5, 0xef, 0x9c, 0x95, 0xeb, 0x7f, 0x5c, 0x7b, 0xf9, 0x47, + 0xdf, 0xf2, 0xda, 0xe6, 0x96, 0x8c, 0x0f, 0x9f, 0x83, 0xee, 0xe6, 0x1d, 0xf6, 0x1f, 0xb6, 0x74, + 0x17, 0x34, 0x4c, 0xe7, 0x6d, 0x2b, 0xdc, 0x9c, 0x86, 0xbf, 0x5a, 0xa0, 0xb3, 0x69, 0x74, 0x36, + 0xcd, 0x42, 0x6b, 0x6d, 0x16, 0x9e, 0x82, 0x16, 0x26, 0x19, 0xe3, 0x54, 0xb0, 0x5c, 0x0f, 0xc3, + 0xd8, 0x7e, 0xfb, 0xea, 0x49, 0xc7, 0xfc, 0x57, 0x99, 0xb2, 0xcc, 0x44, 0x4e, 0xd3, 0xd0, 0x7b, + 0x47, 0x85, 0x1d, 0x50, 0xc7, 0x24, 0x65, 0x89, 0x19, 0x12, 0x7d, 0x80, 0xa7, 0xa0, 0x61, 0x26, + 0xbc, 0xa6, 0xa4, 0x3e, 0x96, 0x3d, 0xf7, 0xfb, 0x45, 0xff, 0xbe, 0x96, 0xe3, 0x78, 0xe1, 0x50, + 0xe6, 0x26, 0x48, 0x44, 0xce, 0x24, 0x15, 0x6f, 0x5f, 0x3d, 0x01, 0xc6, 0x67, 0x92, 0x0a, 0xcf, + 0x5c, 0x1d, 0x4f, 0x5e, 0x5f, 0xf6, 0xac, 0x37, 0x97, 0x3d, 0xeb, 0xcf, 0xcb, 0x9e, 0xf5, 0xf2, + 0xaa, 0xb7, 0xf5, 0xe6, 0xaa, 0xb7, 0xf5, 0xdb, 0x55, 0x6f, 0xeb, 0xb9, 0x1b, 0x52, 0x11, 0x2d, + 0xe7, 0x4e, 0xc0, 0x12, 0x17, 0xc5, 0x31, 0x4d, 0xe7, 0x54, 0x70, 0x57, 0xfd, 0x2b, 0xfe, 0xe4, + 0xae, 0xff, 0x39, 0x8a, 0x55, 0x46, 0xf8, 0xbc, 0xa1, 0x4a, 0xf3, 0xe9, 0x3f, 0x01, 0x00, 0x00, + 0xff, 0xff, 0xc6, 0xd1, 0x61, 0x40, 0xf1, 0x07, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { From 08e9bd5e47a315f5ef68aea1af2cf90a3cbd3dc1 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Tue, 19 May 2026 18:45:31 +0200 Subject: [PATCH 12/18] add consumer fee pool operator guide --- docs/consumer-fee-pool.md | 92 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 docs/consumer-fee-pool.md diff --git a/docs/consumer-fee-pool.md b/docs/consumer-fee-pool.md new file mode 100644 index 0000000..547ea2d --- /dev/null +++ b/docs/consumer-fee-pool.md @@ -0,0 +1,92 @@ +# Consumer Fee Pool + +Every consumer chain on VAAS has a dedicated fee pool on the provider chain, +held at a deterministic account address derived from the consumer ID: + + fee_pool_address = NewModuleAddress("vaas-consumer-fee-pool-") + +This account funds the per-block service charge that the provider drains +from the pool every block (`fees_per_block`) while the consumer is in +`CONSUMER_PHASE_LAUNCHED`. If the pool is short, the consumer is flagged as +in-debt and its ante gate blocks user transactions until funding is restored. + +## Funding + +Funding the pool MUST go through `MsgFundConsumerFeePool`. Direct bank sends +to the fee pool address are rejected by a `bank.SendRestriction` registered +on the provider chain — funds sent that way will either bounce (IBC) or fail +the transaction (direct `MsgSend`). This restriction exists so the +share-accounting (see below) never gets out of sync with the actual pool +balance. + +`MsgFundConsumerFeePool` accepts a single `Coin` whose denom must match the +current `fees_per_block.Denom`. Anyone may sign. The signer is credited with +shares. + +### Cross-chain funding via ICA + +To fund a pool from another chain, register an Interchain Account on the +provider, IBC-transfer funds into the ICA's account, and have the controller +side send a `MsgFundConsumerFeePool` from the ICA. The ICA becomes the +depositor of record. + +### Funding from the community pool + +A governance proposal containing `MsgFundConsumerFeePool` with the gov +module authority as `signer` will pull funds from the cosmos-sdk +distribution community pool and credit the distribution module account as +the depositor. + +## Withdrawing + +Each depositor controls their own shares and can withdraw at any time via +`MsgWithdrawConsumerFeePool`. The message accepts multi-denom `Coins` and +is atomic — if any denom in the request fails its share check, the whole +transaction reverts. + +### Share math (TL;DR) + +- Shares are minted when you deposit. Initial deposit mints + `shares = amount`; subsequent deposits mint + `amount × total_shares / pool_balance` (balance BEFORE this deposit). +- Your claim at any time is + `your_shares × pool_balance / total_shares`. +- A withdraw of `amount ≥ claim` burns all your shares and delivers your + exact claim. Partial withdraws (`amount < claim`) burn proportional + shares and may deliver marginally less than requested due to integer + truncation. + +This is the same accounting pattern used by ERC-4626 vaults and liquid +staking modules: per-block fee consumption reduces share value, not share +count, so consumption is borne pro-rata by current share-holders. + +## Sweeping + +The consumer owner can trigger a full settlement via +`MsgSweepConsumerFeePool`, distributing the pool pro-rata to all +share-holders. The message takes an optional list of denoms; if empty, all +denoms with shares or balance are swept. Any truncation residue per denom +is forwarded to the community pool. + +The same sweep runs automatically when a consumer is deleted (auto-sweep +on `DeleteConsumerChain`). If the auto-sweep fails for any reason, the +delete aborts and the consumer stays in `STOPPED` — funds are never +silently lost. + +## Trust model + +- Producer governance has **no** unilateral authority over consumer-owned + funds. Gov interacts as a single depositor (via the community pool path) + using the same messages as everyone else. +- The consumer owner can trigger settlement but cannot redirect funds to + arbitrary recipients — pro-rata distribution to known depositors is the + only outcome. +- Each depositor controls their own shares independently. + +## Queries + +- `vaas query consumer-fee-pool-claim ` — one + depositor's claim across all denoms. Pass the gov authority address to + query the community pool's holdings. +- `vaas query consumer-fee-pool-claims ` — paginated list of + all depositors with non-zero claims. From 006538475ddfe2c4d38877215c7951bd40a43171 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Thu, 21 May 2026 19:33:59 +0200 Subject: [PATCH 13/18] consumer_id to uint64 --- proto/vaas/provider/v1/genesis.proto | 2 +- proto/vaas/provider/v1/query.proto | 4 +- proto/vaas/provider/v1/tx.proto | 6 +- x/vaas/provider/client/cli/query.go | 12 +- x/vaas/provider/client/cli/tx.go | 18 +- x/vaas/provider/keeper/fee_pool_shares.go | 22 +- .../provider/keeper/fee_pool_shares_test.go | 28 +- x/vaas/provider/keeper/genesis.go | 6 +- x/vaas/provider/keeper/genesis_test.go | 26 +- x/vaas/provider/keeper/grpc_query.go | 4 +- x/vaas/provider/keeper/grpc_query_test.go | 6 +- x/vaas/provider/keeper/keeper.go | 12 +- x/vaas/provider/keeper/msg_server.go | 10 +- x/vaas/provider/keeper/msg_server_test.go | 2 +- .../provider/keeper/send_restriction_test.go | 2 +- x/vaas/provider/types/genesis.pb.go | 158 +++++----- x/vaas/provider/types/msg.go | 9 - x/vaas/provider/types/msg_test.go | 41 +-- x/vaas/provider/types/query.pb.go | 160 +++++------ x/vaas/provider/types/query.pb.gw.go | 8 +- x/vaas/provider/types/tx.pb.go | 272 ++++++++---------- 21 files changed, 355 insertions(+), 453 deletions(-) diff --git a/proto/vaas/provider/v1/genesis.proto b/proto/vaas/provider/v1/genesis.proto index 290e738..7aed386 100644 --- a/proto/vaas/provider/v1/genesis.proto +++ b/proto/vaas/provider/v1/genesis.proto @@ -93,7 +93,7 @@ message ValsetUpdateIdToHeight { // fee pool, scoped to one denom. The triple (consumer_id, depositor, denom) // is unique. message ConsumerFeePoolShare { - string consumer_id = 1; + uint64 consumer_id = 1; string depositor = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; string denom = 3; string shares = 4 [ diff --git a/proto/vaas/provider/v1/query.proto b/proto/vaas/provider/v1/query.proto index 38052a6..c677213 100644 --- a/proto/vaas/provider/v1/query.proto +++ b/proto/vaas/provider/v1/query.proto @@ -287,7 +287,7 @@ message QueryConsumerGenesisTimeResponse { } message QueryConsumerFeePoolClaimRequest { - string consumer_id = 1; + uint64 consumer_id = 1; // bech32 address; if equal to the gov module authority, aliases to the // distribution module account address string depositor = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; @@ -310,7 +310,7 @@ message DepositorClaim { } message QueryConsumerFeePoolClaimsRequest { - string consumer_id = 1; + uint64 consumer_id = 1; cosmos.base.query.v1beta1.PageRequest pagination = 2; } diff --git a/proto/vaas/provider/v1/tx.proto b/proto/vaas/provider/v1/tx.proto index bd4bb5b..e4d8661 100644 --- a/proto/vaas/provider/v1/tx.proto +++ b/proto/vaas/provider/v1/tx.proto @@ -180,7 +180,7 @@ message MsgFundConsumerFeePool { option (gogoproto.goproto_getters) = false; string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - string consumer_id = 2; + uint64 consumer_id = 2; cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true @@ -201,7 +201,7 @@ message MsgWithdrawConsumerFeePool { option (gogoproto.goproto_getters) = false; string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - string consumer_id = 2; + uint64 consumer_id = 2; repeated cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", @@ -228,7 +228,7 @@ message MsgSweepConsumerFeePool { option (gogoproto.goproto_getters) = false; string signer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - string consumer_id = 2; + uint64 consumer_id = 2; // empty = all denoms with shares or balance for this consumer repeated string denoms = 3; } diff --git a/x/vaas/provider/client/cli/query.go b/x/vaas/provider/client/cli/query.go index 99ce7a1..7c5e6d5 100644 --- a/x/vaas/provider/client/cli/query.go +++ b/x/vaas/provider/client/cli/query.go @@ -462,9 +462,13 @@ func CmdConsumerFeePoolClaim() *cobra.Command { if err != nil { return err } + consumerId, err := parseConsumerIdArg(args[0]) + if err != nil { + return err + } qc := types.NewQueryClient(clientCtx) res, err := qc.ConsumerFeePoolClaim(cmd.Context(), &types.QueryConsumerFeePoolClaimRequest{ - ConsumerId: args[0], + ConsumerId: consumerId, Depositor: args[1], }) if err != nil { @@ -487,13 +491,17 @@ func CmdConsumerFeePoolClaims() *cobra.Command { if err != nil { return err } + consumerId, err := parseConsumerIdArg(args[0]) + if err != nil { + return err + } pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { return err } qc := types.NewQueryClient(clientCtx) res, err := qc.ConsumerFeePoolClaims(cmd.Context(), &types.QueryConsumerFeePoolClaimsRequest{ - ConsumerId: args[0], + ConsumerId: consumerId, Pagination: pageReq, }) if err != nil { diff --git a/x/vaas/provider/client/cli/tx.go b/x/vaas/provider/client/cli/tx.go index 413ee5f..71487a9 100644 --- a/x/vaas/provider/client/cli/tx.go +++ b/x/vaas/provider/client/cli/tx.go @@ -470,13 +470,17 @@ func NewFundConsumerFeePoolCmd() *cobra.Command { if err != nil { return err } + consumerId, err := parseConsumerIdArg(args[0]) + if err != nil { + return err + } amount, err := sdk.ParseCoinNormalized(args[1]) if err != nil { return err } msg := &types.MsgFundConsumerFeePool{ Signer: clientCtx.GetFromAddress().String(), - ConsumerId: args[0], + ConsumerId: consumerId, Amount: amount, } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) @@ -496,13 +500,17 @@ func NewWithdrawConsumerFeePoolCmd() *cobra.Command { if err != nil { return err } + consumerId, err := parseConsumerIdArg(args[0]) + if err != nil { + return err + } coins, err := sdk.ParseCoinsNormalized(args[1]) if err != nil { return err } msg := &types.MsgWithdrawConsumerFeePool{ Signer: clientCtx.GetFromAddress().String(), - ConsumerId: args[0], + ConsumerId: consumerId, Amount: coins, } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) @@ -522,6 +530,10 @@ func NewSweepConsumerFeePoolCmd() *cobra.Command { if err != nil { return err } + consumerId, err := parseConsumerIdArg(args[0]) + if err != nil { + return err + } denomsCSV, _ := cmd.Flags().GetString("denoms") var denoms []string if strings.TrimSpace(denomsCSV) != "" { @@ -529,7 +541,7 @@ func NewSweepConsumerFeePoolCmd() *cobra.Command { } msg := &types.MsgSweepConsumerFeePool{ Signer: clientCtx.GetFromAddress().String(), - ConsumerId: args[0], + ConsumerId: consumerId, Denoms: denoms, } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) diff --git a/x/vaas/provider/keeper/fee_pool_shares.go b/x/vaas/provider/keeper/fee_pool_shares.go index 5a79630..49062c6 100644 --- a/x/vaas/provider/keeper/fee_pool_shares.go +++ b/x/vaas/provider/keeper/fee_pool_shares.go @@ -18,7 +18,7 @@ import ( // given consumer's fee pool. Returns math.ZeroInt() if the depositor has no // shares or total_shares is zero. func (k Keeper) ComputeClaim( - ctx sdk.Context, consumerId string, depositor sdk.AccAddress, denom string, + ctx sdk.Context, consumerId uint64, depositor sdk.AccAddress, denom string, ) math.Int { poolAddr := k.GetConsumerFeePoolAddress(consumerId) balance := k.bankKeeper.GetBalance(ctx, poolAddr, denom) @@ -45,7 +45,7 @@ func (k Keeper) ComputeClaim( // // Caller is responsible for the bank-side movement of funds into the pool. func (k Keeper) MintShares( - ctx sdk.Context, consumerId string, depositor sdk.AccAddress, amount sdk.Coin, + ctx sdk.Context, consumerId uint64, depositor sdk.AccAddress, amount sdk.Coin, ) error { poolAddr := k.GetConsumerFeePoolAddress(consumerId) balance := k.bankKeeper.GetBalance(ctx, poolAddr, amount.Denom) @@ -97,13 +97,13 @@ func (k Keeper) MintShares( // downward so the depositor never over-withdraws. Caller is responsible for // dispatching the bank send. func (k Keeper) WithdrawShares( - ctx sdk.Context, consumerId string, depositor sdk.AccAddress, amount sdk.Coin, + ctx sdk.Context, consumerId uint64, depositor sdk.AccAddress, amount sdk.Coin, ) (sdk.Coin, error) { depKey := collections.Join3(consumerId, depositor, amount.Denom) shares, err := k.ConsumerFeePoolShares.Get(ctx, depKey) if err != nil { return sdk.Coin{}, errorsmod.Wrapf(types.ErrUnauthorized, - "depositor %s has no shares in (%s, %s)", depositor, consumerId, amount.Denom) + "depositor %s has no shares in (%d, %s)", depositor, consumerId, amount.Denom) } totalKey := collections.Join(consumerId, amount.Denom) total, err := k.ConsumerFeePoolTotalShares.Get(ctx, totalKey) @@ -173,7 +173,7 @@ func (k Keeper) WithdrawShares( // Handles the orphan-balance defensive case: if total_shares == 0 but // balance > 0, forwards the balance to the community pool. func (k Keeper) SweepConsumerFeePoolDenom( - ctx sdk.Context, consumerId, denom string, + ctx sdk.Context, consumerId uint64, denom string, ) error { poolAddr := k.GetConsumerFeePoolAddress(consumerId) balance := k.bankKeeper.GetBalance(ctx, poolAddr, denom) @@ -221,7 +221,7 @@ func (k Keeper) SweepConsumerFeePoolDenom( shares math.Int } var holders []holder - prefix := collections.NewPrefixedTripleRange[string, sdk.AccAddress, string](consumerId) + prefix := collections.NewPrefixedTripleRange[uint64, sdk.AccAddress, string](consumerId) iter, err := k.ConsumerFeePoolShares.Iterate(ctx, prefix) if err != nil { return err @@ -283,7 +283,7 @@ func (k Keeper) SweepConsumerFeePoolDenom( // SweepConsumerFeePool sweeps each denom in `denoms`, or every denom that // has either non-zero shares or non-zero pool balance if `denoms` is nil/empty. func (k Keeper) SweepConsumerFeePool( - ctx sdk.Context, consumerId string, denoms []string, + ctx sdk.Context, consumerId uint64, denoms []string, ) error { if len(denoms) > 0 { for _, d := range denoms { @@ -296,7 +296,7 @@ func (k Keeper) SweepConsumerFeePool( // Union of denoms-with-shares and denoms-with-balance. set := map[string]struct{}{} - prefix := collections.NewPrefixedPairRange[string, string](consumerId) + prefix := collections.NewPrefixedPairRange[uint64, string](consumerId) iter, err := k.ConsumerFeePoolTotalShares.Iterate(ctx, prefix) if err != nil { return err @@ -332,15 +332,15 @@ func (k Keeper) SweepConsumerFeePool( // clearAllShares deletes every share record for the given (consumer, denom). // Used by lazy invalidation and by sweep finalization. -func (k Keeper) clearAllShares(ctx sdk.Context, consumerId, denom string) error { - prefix := collections.NewPrefixedTripleRange[string, sdk.AccAddress, string](consumerId) +func (k Keeper) clearAllShares(ctx sdk.Context, consumerId uint64, denom string) error { + prefix := collections.NewPrefixedTripleRange[uint64, sdk.AccAddress, string](consumerId) iter, err := k.ConsumerFeePoolShares.Iterate(ctx, prefix) if err != nil { return err } defer iter.Close() - var toDelete []collections.Triple[string, sdk.AccAddress, string] + var toDelete []collections.Triple[uint64, sdk.AccAddress, string] for ; iter.Valid(); iter.Next() { key, err := iter.Key() if err != nil { diff --git a/x/vaas/provider/keeper/fee_pool_shares_test.go b/x/vaas/provider/keeper/fee_pool_shares_test.go index a83d1b4..631535a 100644 --- a/x/vaas/provider/keeper/fee_pool_shares_test.go +++ b/x/vaas/provider/keeper/fee_pool_shares_test.go @@ -20,7 +20,7 @@ func TestComputeClaim(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) @@ -42,7 +42,7 @@ func TestMintShares_Initial(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) poolAddr := k.GetConsumerFeePoolAddress(consumerId) @@ -64,7 +64,7 @@ func TestMintShares_Subsequent(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) @@ -95,7 +95,7 @@ func TestMintShares_LazyInvalidation(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) @@ -127,7 +127,7 @@ func TestMintShares_SubShareDeposit(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) @@ -161,7 +161,7 @@ func TestWithdrawShares_Full(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) poolAddr := k.GetConsumerFeePoolAddress(consumerId) @@ -189,7 +189,7 @@ func TestWithdrawShares_Partial(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) @@ -220,7 +220,7 @@ func TestWithdrawShares_Empty(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) poolAddr := k.GetConsumerFeePoolAddress(consumerId) @@ -239,7 +239,7 @@ func TestWithdrawShares_SubShareGuard(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) poolAddr := k.GetConsumerFeePoolAddress(consumerId) @@ -272,7 +272,7 @@ func TestSweepConsumerFeePoolDenom(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) @@ -311,7 +311,7 @@ func TestSweepConsumerFeePoolDenom_WithDust(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) @@ -345,7 +345,7 @@ func TestSweepConsumerFeePoolDenom_DistrModuleRecipientUsesCommunityPool(t *test k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) poolAddr := k.GetConsumerFeePoolAddress(consumerId) @@ -371,7 +371,7 @@ func TestSweepConsumerFeePoolDenom_AllFloorToZero(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) denom := "uphoton" alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) @@ -412,7 +412,7 @@ func TestSweepConsumerFeePool_AllDenoms(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) alice := sdk.AccAddress([]byte("alice___________")) poolAddr := k.GetConsumerFeePoolAddress(consumerId) diff --git a/x/vaas/provider/keeper/genesis.go b/x/vaas/provider/keeper/genesis.go index cb358f0..735e789 100644 --- a/x/vaas/provider/keeper/genesis.go +++ b/x/vaas/provider/keeper/genesis.go @@ -154,7 +154,7 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) []abc } // Rebuild totals by summing per (consumer_id, denom) - totals := map[string]map[string]math.Int{} + totals := map[uint64]map[string]math.Int{} for _, s := range genState.ConsumerFeePoolShares { if _, ok := totals[s.ConsumerId]; !ok { totals[s.ConsumerId] = map[string]math.Int{} @@ -354,7 +354,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { // Sanity check: rebuild totals from shares and warn on divergence recomputed := map[string]math.Int{} for _, s := range gs.ConsumerFeePoolShares { - key := s.ConsumerId + "|" + s.Denom + key := fmt.Sprintf("%d|%s", s.ConsumerId, s.Denom) if cur, ok := recomputed[key]; ok { recomputed[key] = cur.Add(s.Shares) } else { @@ -374,7 +374,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { if err != nil { panic(err) } - composite := key.K1() + "|" + key.K2() + composite := fmt.Sprintf("%d|%s", key.K1(), key.K2()) expected, ok := recomputed[composite] if !ok || !expected.Equal(val) { k.Logger(ctx).Error( diff --git a/x/vaas/provider/keeper/genesis_test.go b/x/vaas/provider/keeper/genesis_test.go index 2562521..78cfb3e 100644 --- a/x/vaas/provider/keeper/genesis_test.go +++ b/x/vaas/provider/keeper/genesis_test.go @@ -416,11 +416,11 @@ func TestExportGenesis_IncludesShares(t *testing.T) { alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3("0", alice, "uphoton"), math.NewInt(60))) + collections.Join3(uint64(0), alice, "uphoton"), math.NewInt(60))) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3("0", bob, "uphoton"), math.NewInt(40))) + collections.Join3(uint64(0), bob, "uphoton"), math.NewInt(40))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, - collections.Join("0", "uphoton"), math.NewInt(100))) + collections.Join(uint64(0), "uphoton"), math.NewInt(100))) gs := k.ExportGenesis(ctx) require.Len(t, gs.ConsumerFeePoolShares, 2) @@ -445,36 +445,38 @@ func TestInitGenesis_RebuildsDerivedCollections(t *testing.T) { Params: providertypes.DefaultParams(), ConsumerStates: []providertypes.ConsumerState{ { - ChainId: "0", + ConsumerId: 0, + ChainId: "chain-a", Phase: providertypes.CONSUMER_PHASE_LAUNCHED, ConsumerGenesis: *vaastypes.DefaultConsumerGenesisState(), }, { - ChainId: "1", + ConsumerId: 1, + ChainId: "chain-b", Phase: providertypes.CONSUMER_PHASE_DELETED, ConsumerGenesis: *vaastypes.DefaultConsumerGenesisState(), }, }, ConsumerFeePoolShares: []providertypes.ConsumerFeePoolShare{ - {ConsumerId: "0", Depositor: alice.String(), Denom: "uphoton", Shares: math.NewInt(60)}, - {ConsumerId: "0", Depositor: bob.String(), Denom: "uphoton", Shares: math.NewInt(40)}, + {ConsumerId: 0, Depositor: alice.String(), Denom: "uphoton", Shares: math.NewInt(60)}, + {ConsumerId: 0, Depositor: bob.String(), Denom: "uphoton", Shares: math.NewInt(40)}, }, } k.InitGenesis(ctx, gs) - s, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3("0", alice, "uphoton")) + s, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(uint64(0), alice, "uphoton")) require.NoError(t, err) require.Equal(t, math.NewInt(60), s) - total, err := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join("0", "uphoton")) + total, err := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(uint64(0), "uphoton")) require.NoError(t, err) require.Equal(t, math.NewInt(100), total) - cid, err := k.FeePoolAddressToConsumerId.Get(ctx, k.GetConsumerFeePoolAddress("0")) + cid, err := k.FeePoolAddressToConsumerId.Get(ctx, k.GetConsumerFeePoolAddress(0)) require.NoError(t, err) - require.Equal(t, "0", cid) + require.Equal(t, uint64(0), cid) - _, err = k.FeePoolAddressToConsumerId.Get(ctx, k.GetConsumerFeePoolAddress("1")) + _, err = k.FeePoolAddressToConsumerId.Get(ctx, k.GetConsumerFeePoolAddress(1)) require.ErrorIs(t, err, collections.ErrNotFound) } diff --git a/x/vaas/provider/keeper/grpc_query.go b/x/vaas/provider/keeper/grpc_query.go index 5462da0..c95d343 100644 --- a/x/vaas/provider/keeper/grpc_query.go +++ b/x/vaas/provider/keeper/grpc_query.go @@ -342,7 +342,7 @@ func (k Keeper) ConsumerFeePoolClaim( } coins := sdk.NewCoins() - prefix := collections.NewPrefixedPairRange[string, string](req.ConsumerId) + prefix := collections.NewPrefixedPairRange[uint64, string](req.ConsumerId) iter, err := k.ConsumerFeePoolTotalShares.Iterate(ctx, prefix) if err != nil { return nil, status.Errorf(codes.Internal, "iterate totals: %s", err) @@ -376,7 +376,7 @@ func (k Keeper) ConsumerFeePoolClaims( } perDepositor := map[string]*acc{} - prefix := collections.NewPrefixedTripleRange[string, sdk.AccAddress, string](req.ConsumerId) + prefix := collections.NewPrefixedTripleRange[uint64, sdk.AccAddress, string](req.ConsumerId) iter, err := k.ConsumerFeePoolShares.Iterate(ctx, prefix) if err != nil { return nil, status.Errorf(codes.Internal, "%s", err) diff --git a/x/vaas/provider/keeper/grpc_query_test.go b/x/vaas/provider/keeper/grpc_query_test.go index 640aca1..26370ce 100644 --- a/x/vaas/provider/keeper/grpc_query_test.go +++ b/x/vaas/provider/keeper/grpc_query_test.go @@ -47,7 +47,7 @@ func TestQueryConsumerFeePoolClaim(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) alice := sdk.AccAddress([]byte("alice___________")) poolAddr := k.GetConsumerFeePoolAddress(consumerId) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, @@ -68,7 +68,7 @@ func TestQueryConsumerFeePoolClaim_GovAlias(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) poolAddr := k.GetConsumerFeePoolAddress(consumerId) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, @@ -89,7 +89,7 @@ func TestQueryConsumerFeePoolClaims(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) poolAddr := k.GetConsumerFeePoolAddress(consumerId) diff --git a/x/vaas/provider/keeper/keeper.go b/x/vaas/provider/keeper/keeper.go index 32955cc..2b3d8fc 100644 --- a/x/vaas/provider/keeper/keeper.go +++ b/x/vaas/provider/keeper/keeper.go @@ -80,9 +80,9 @@ type Keeper struct { LastProviderConsensusVals collections.Map[[]byte, types.ConsensusValidator] // Fee pool collections - ConsumerFeePoolShares collections.Map[collections.Triple[string, sdk.AccAddress, string], math.Int] - ConsumerFeePoolTotalShares collections.Map[collections.Pair[string, string], math.Int] - FeePoolAddressToConsumerId collections.Map[sdk.AccAddress, string] + ConsumerFeePoolShares collections.Map[collections.Triple[uint64, sdk.AccAddress, string], math.Int] + ConsumerFeePoolTotalShares collections.Map[collections.Pair[uint64, string], math.Int] + FeePoolAddressToConsumerId collections.Map[sdk.AccAddress, uint64] } // NewKeeper creates a new provider Keeper instance @@ -169,20 +169,20 @@ func NewKeeper( k.ConsumerFeePoolShares = collections.NewMap( sb, types.ConsumerFeePoolSharesKeyPrefix, types.ConsumerFeePoolSharesKeyName, - collections.TripleKeyCodec(collections.StringKey, sdk.AccAddressKey, collections.StringKey), + collections.TripleKeyCodec(collections.Uint64Key, sdk.AccAddressKey, collections.StringKey), sdk.IntValue, ) k.ConsumerFeePoolTotalShares = collections.NewMap( sb, types.ConsumerFeePoolTotalSharesKeyPrefix, types.ConsumerFeePoolTotalSharesKeyName, - collections.PairKeyCodec(collections.StringKey, collections.StringKey), + collections.PairKeyCodec(collections.Uint64Key, collections.StringKey), sdk.IntValue, ) k.FeePoolAddressToConsumerId = collections.NewMap( sb, types.FeePoolAddressToConsumerIdKeyPrefix, types.FeePoolAddressToConsumerIdKeyName, sdk.AccAddressKey, - collections.StringValue, + collections.Uint64Value, ) schema, err := sb.Build() diff --git a/x/vaas/provider/keeper/msg_server.go b/x/vaas/provider/keeper/msg_server.go index 67c9fce..46d4c7e 100644 --- a/x/vaas/provider/keeper/msg_server.go +++ b/x/vaas/provider/keeper/msg_server.go @@ -486,11 +486,11 @@ func (k msgServer) FundConsumerFeePool( phase := k.GetConsumerPhase(ctx, msg.ConsumerId) if phase == types.CONSUMER_PHASE_UNSPECIFIED { return nil, errorsmod.Wrapf(types.ErrUnknownConsumerId, - "consumer %s does not exist", msg.ConsumerId) + "consumer %d does not exist", msg.ConsumerId) } if phase == types.CONSUMER_PHASE_DELETED { return nil, errorsmod.Wrapf(types.ErrInvalidPhase, - "consumer %s is deleted", msg.ConsumerId) + "consumer %d is deleted", msg.ConsumerId) } // Denom check (stateful — reads params) @@ -538,7 +538,7 @@ func (k msgServer) FundConsumerFeePool( ctx.EventManager().EmitEvent(sdk.NewEvent( types.EventTypeConsumerFeePoolFund, - sdk.NewAttribute(types.AttributeConsumerId, msg.ConsumerId), + sdk.NewAttribute(types.AttributeConsumerId, strconv.FormatUint(msg.ConsumerId, 10)), sdk.NewAttribute(types.AttributeDepositor, depositor.String()), sdk.NewAttribute(types.AttributeAmount, msg.Amount.String()), )) @@ -610,7 +610,7 @@ func (k msgServer) WithdrawConsumerFeePool( ctx.EventManager().EmitEvent(sdk.NewEvent( types.EventTypeConsumerFeePoolWithdraw, - sdk.NewAttribute(types.AttributeConsumerId, msg.ConsumerId), + sdk.NewAttribute(types.AttributeConsumerId, strconv.FormatUint(msg.ConsumerId, 10)), sdk.NewAttribute(types.AttributeDepositor, depositor.String()), sdk.NewAttribute(types.AttributeRecipient, depositor.String()), sdk.NewAttribute(types.AttributeAmount, delivered.String()), @@ -626,7 +626,7 @@ func (k msgServer) SweepConsumerFeePool( ownerAddr, err := k.GetConsumerOwnerAddress(ctx, msg.ConsumerId) if err != nil { return nil, errorsmod.Wrapf(types.ErrNoOwnerAddress, - "consumer %s has no owner: %s", msg.ConsumerId, err) + "consumer %d has no owner: %s", msg.ConsumerId, err) } if msg.Signer != ownerAddr { return nil, errorsmod.Wrapf(types.ErrUnauthorized, diff --git a/x/vaas/provider/keeper/msg_server_test.go b/x/vaas/provider/keeper/msg_server_test.go index 4ae088c..a53aa45 100644 --- a/x/vaas/provider/keeper/msg_server_test.go +++ b/x/vaas/provider/keeper/msg_server_test.go @@ -310,7 +310,7 @@ func TestFundConsumerFeePool_RejectsUnknownConsumer(t *testing.T) { alice := sdk.AccAddress([]byte("alice___________")) _, err := ms.FundConsumerFeePool(ctx, &providertypes.MsgFundConsumerFeePool{ - Signer: alice.String(), ConsumerId: "999", + Signer: alice.String(), ConsumerId: 999, Amount: sdk.NewInt64Coin("uphoton", 1), }) require.ErrorIs(t, err, providertypes.ErrUnknownConsumerId) diff --git a/x/vaas/provider/keeper/send_restriction_test.go b/x/vaas/provider/keeper/send_restriction_test.go index 9b9dbea..fea833b 100644 --- a/x/vaas/provider/keeper/send_restriction_test.go +++ b/x/vaas/provider/keeper/send_restriction_test.go @@ -16,7 +16,7 @@ func TestFeePoolSendRestriction(t *testing.T) { k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - consumerId := "0" + consumerId := uint64(0) poolAddr := k.GetConsumerFeePoolAddress(consumerId) providerAddr := authtypes.NewModuleAddress(providertypes.ModuleName) user := sdk.AccAddress([]byte("user____________")) diff --git a/x/vaas/provider/types/genesis.pb.go b/x/vaas/provider/types/genesis.pb.go index 42f0e32..85f626e 100644 --- a/x/vaas/provider/types/genesis.pb.go +++ b/x/vaas/provider/types/genesis.pb.go @@ -354,7 +354,7 @@ func (m *ValsetUpdateIdToHeight) GetHeight() uint64 { // fee pool, scoped to one denom. The triple (consumer_id, depositor, denom) // is unique. type ConsumerFeePoolShare struct { - ConsumerId string `protobuf:"bytes,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + ConsumerId uint64 `protobuf:"varint,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` Depositor string `protobuf:"bytes,2,opt,name=depositor,proto3" json:"depositor,omitempty"` Denom string `protobuf:"bytes,3,opt,name=denom,proto3" json:"denom,omitempty"` Shares cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=shares,proto3,customtype=cosmossdk.io/math.Int" json:"shares"` @@ -393,11 +393,11 @@ func (m *ConsumerFeePoolShare) XXX_DiscardUnknown() { var xxx_messageInfo_ConsumerFeePoolShare proto.InternalMessageInfo -func (m *ConsumerFeePoolShare) GetConsumerId() string { +func (m *ConsumerFeePoolShare) GetConsumerId() uint64 { if m != nil { return m.ConsumerId } - return "" + return 0 } func (m *ConsumerFeePoolShare) GetDepositor() string { @@ -424,66 +424,66 @@ func init() { func init() { proto.RegisterFile("vaas/provider/v1/genesis.proto", fileDescriptor_c9071b84cde652f9) } var fileDescriptor_c9071b84cde652f9 = []byte{ - // 938 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xcd, 0x6e, 0xdb, 0x46, - 0x17, 0x35, 0x6d, 0x49, 0x91, 0x46, 0xb6, 0x3f, 0x63, 0xa0, 0xe8, 0x63, 0x1c, 0x44, 0x12, 0x54, - 0xa4, 0x50, 0xd1, 0x86, 0x84, 0x5d, 0x34, 0x8b, 0x2e, 0x0a, 0x58, 0x0e, 0xda, 0x0a, 0x45, 0x0b, - 0x81, 0x72, 0xbb, 0xc8, 0x86, 0x18, 0x71, 0x26, 0xe4, 0x54, 0x24, 0x87, 0xe0, 0x8c, 0xe8, 0xaa, - 0x4f, 0x91, 0xa7, 0xe8, 0x13, 0xe4, 0x21, 0x82, 0xae, 0x82, 0xac, 0x8a, 0x2e, 0xdc, 0xc2, 0x7e, - 0x82, 0xf6, 0x09, 0x8a, 0xf9, 0x21, 0x63, 0xd9, 0x72, 0x83, 0xee, 0x34, 0xf7, 0x9c, 0x39, 0xe7, - 0x72, 0xee, 0x8f, 0x40, 0xaf, 0x40, 0x88, 0xbb, 0x59, 0xce, 0x0a, 0x8a, 0x49, 0xee, 0x16, 0x47, - 0x6e, 0x48, 0x52, 0xc2, 0x29, 0x77, 0xb2, 0x9c, 0x09, 0x06, 0x0f, 0x24, 0xee, 0x94, 0xb8, 0x53, - 0x1c, 0x1d, 0x76, 0x42, 0x16, 0x32, 0x05, 0xba, 0xf2, 0x97, 0xe6, 0x1d, 0xf6, 0x43, 0xc6, 0xc2, - 0x98, 0xb8, 0xea, 0x34, 0x5f, 0xbe, 0x70, 0x05, 0x4d, 0x08, 0x17, 0x28, 0xc9, 0x0c, 0xe1, 0x41, - 0xc0, 0x78, 0xc2, 0xb8, 0xaf, 0x6f, 0xea, 0x83, 0x81, 0x1e, 0xa9, 0x1c, 0x8a, 0x23, 0x97, 0x47, - 0x28, 0x27, 0xd8, 0x0f, 0x58, 0xca, 0x97, 0x09, 0xc9, 0x0d, 0x0c, 0x4b, 0xf8, 0x9c, 0xe6, 0xa4, - 0xb4, 0xbb, 0x95, 0x76, 0x95, 0xa2, 0x22, 0x0c, 0xff, 0xaa, 0x83, 0xdd, 0xaf, 0xf4, 0x97, 0xcc, - 0x04, 0x12, 0x04, 0x8e, 0xc0, 0x41, 0x81, 0x62, 0x4e, 0x84, 0xbf, 0xcc, 0x30, 0x12, 0xc4, 0xa7, - 0xd8, 0xb6, 0x06, 0xd6, 0xa8, 0xe6, 0xed, 0xeb, 0xf8, 0xf7, 0x2a, 0x3c, 0xc1, 0x30, 0x02, 0xff, - 0x2b, 0x33, 0xf0, 0xb9, 0xbc, 0xcb, 0xed, 0xed, 0xc1, 0xce, 0xa8, 0x7d, 0xdc, 0x77, 0x6e, 0x3e, - 0x86, 0x73, 0x6a, 0x88, 0xca, 0x63, 0xdc, 0x7b, 0x7d, 0xd1, 0xdf, 0xfa, 0xfb, 0xa2, 0xdf, 0x5d, - 0xa1, 0x24, 0xfe, 0x7c, 0x78, 0x43, 0x65, 0xe8, 0xed, 0x07, 0xd7, 0xe9, 0x1c, 0xfe, 0x08, 0x0e, - 0x6f, 0xe6, 0xe4, 0x0b, 0xe6, 0x47, 0x84, 0x86, 0x91, 0xb0, 0x77, 0x94, 0xe9, 0xe8, 0xb6, 0xe9, - 0x0f, 0x6b, 0xf9, 0x9e, 0xb1, 0xaf, 0x15, 0x7f, 0x5c, 0x93, 0xee, 0x5e, 0xb7, 0xd8, 0x88, 0xc2, - 0xa7, 0xa0, 0x91, 0xa1, 0x1c, 0x25, 0xdc, 0xae, 0x0d, 0xac, 0x51, 0xfb, 0xd8, 0xbe, 0xad, 0x3b, - 0x55, 0xb8, 0xd1, 0x31, 0x6c, 0x98, 0xa8, 0x1c, 0x29, 0x46, 0x82, 0xe5, 0x55, 0x65, 0xfc, 0x6c, - 0x39, 0x5f, 0x90, 0x15, 0xb7, 0xeb, 0x2a, 0xc7, 0x8f, 0x36, 0xe6, 0xa8, 0xef, 0x94, 0x2f, 0x34, - 0x5d, 0xce, 0xbf, 0x21, 0x2b, 0x23, 0x6e, 0x17, 0x1b, 0x60, 0x29, 0x08, 0x53, 0xf0, 0xb0, 0xc2, - 0xb8, 0x3f, 0x5f, 0xbd, 0xb3, 0x44, 0x18, 0xe7, 0x76, 0xe3, 0xbd, 0x7e, 0xe3, 0x55, 0x29, 0x79, - 0x82, 0x71, 0x7e, 0xcb, 0x8f, 0xaf, 0xe3, 0x30, 0x00, 0xff, 0x5f, 0x73, 0xe0, 0xb2, 0x00, 0x59, - 0xbe, 0x4c, 0x89, 0x7d, 0x4f, 0x79, 0x7d, 0x78, 0x77, 0xd1, 0xa5, 0x00, 0x3f, 0x63, 0x53, 0xc9, - 0x36, 0x46, 0x9d, 0x60, 0x03, 0x06, 0x09, 0xb0, 0x2b, 0x93, 0x17, 0x84, 0xf8, 0x19, 0x63, 0xb1, - 0xaf, 0x9a, 0x9d, 0xdb, 0xcd, 0xf7, 0xb9, 0x7c, 0x49, 0xc8, 0x94, 0xb1, 0x78, 0x26, 0xe9, 0xc6, - 0xe5, 0x7e, 0xb0, 0x01, 0xe3, 0xc3, 0x5f, 0xea, 0x60, 0x6f, 0xad, 0x21, 0x61, 0x1f, 0xb4, 0x2b, - 0xe3, 0xaa, 0xdf, 0x41, 0x19, 0x9a, 0x60, 0xf8, 0x00, 0x34, 0x83, 0x08, 0xd1, 0x54, 0xa2, 0xdb, - 0x03, 0x6b, 0xd4, 0xf2, 0xee, 0xa9, 0xf3, 0x04, 0xc3, 0x87, 0xa0, 0x15, 0xc4, 0x94, 0xa4, 0x42, - 0x62, 0x3b, 0x0a, 0x6b, 0xea, 0xc0, 0x04, 0xc3, 0xc7, 0x60, 0x9f, 0xa6, 0x54, 0x50, 0x14, 0x97, - 0xdd, 0x5a, 0x53, 0xda, 0x7b, 0x26, 0x6a, 0x9a, 0xee, 0x3b, 0x70, 0x50, 0xf9, 0x9b, 0xbd, 0x62, - 0xd7, 0x55, 0xfb, 0x3d, 0xd2, 0x1f, 0x7c, 0xed, 0x3b, 0xaf, 0x4f, 0xab, 0xf9, 0xce, 0x6a, 0x0e, - 0x0d, 0x06, 0x11, 0xe8, 0x66, 0x24, 0xc5, 0x34, 0x0d, 0x7d, 0x33, 0x38, 0x41, 0x84, 0xd2, 0x90, - 0x70, 0xd3, 0x18, 0x8f, 0x2b, 0xd5, 0xaa, 0x1f, 0x66, 0x44, 0x9c, 0x2a, 0xce, 0x14, 0x05, 0x0b, - 0x22, 0x9e, 0x21, 0x81, 0xca, 0x5a, 0x19, 0x29, 0x3d, 0x4e, 0x9a, 0xc4, 0xe1, 0x27, 0x00, 0xf2, - 0x18, 0xf1, 0xc8, 0xc7, 0xec, 0x3c, 0x95, 0x4b, 0xcc, 0x47, 0xc1, 0x42, 0xf5, 0x42, 0xcb, 0x3b, - 0x50, 0xc8, 0x33, 0x03, 0x9c, 0x04, 0x0b, 0xf8, 0x19, 0xa8, 0x67, 0x11, 0xe2, 0xc4, 0x6e, 0x0e, - 0xac, 0xd1, 0xfe, 0xbf, 0x6d, 0x88, 0xa9, 0xa4, 0x79, 0x9a, 0x0d, 0x3f, 0x00, 0x7b, 0xec, 0x3c, - 0x35, 0x2d, 0x47, 0x38, 0xb7, 0x5b, 0xea, 0x7d, 0x77, 0x55, 0xf0, 0x44, 0xc7, 0xe0, 0x17, 0xa0, - 0x99, 0x10, 0x81, 0x30, 0x12, 0xc8, 0x06, 0xea, 0xd1, 0x86, 0x77, 0xcb, 0x7f, 0x6b, 0x98, 0x5e, - 0x75, 0x07, 0xce, 0x40, 0x5b, 0x56, 0xc3, 0x37, 0x63, 0xdf, 0x56, 0x12, 0xc7, 0x77, 0x4b, 0x4c, - 0x74, 0xe9, 0xe8, 0xcf, 0x48, 0x50, 0x96, 0xaa, 0x65, 0x40, 0x04, 0xc9, 0xb9, 0x07, 0xa4, 0x8c, - 0x5e, 0x0e, 0xf0, 0x14, 0xec, 0xe6, 0x24, 0x61, 0x05, 0x8a, 0x7d, 0xf9, 0x06, 0xf6, 0xae, 0x52, - 0x3d, 0x74, 0xf4, 0xfa, 0x77, 0xca, 0xf5, 0xef, 0x9c, 0x95, 0xeb, 0x7f, 0x5c, 0x7b, 0xf9, 0x47, - 0xdf, 0xf2, 0xda, 0xe6, 0x96, 0x8c, 0x0f, 0x9f, 0x83, 0xee, 0xe6, 0x1d, 0xf6, 0x1f, 0xb6, 0x74, - 0x17, 0x34, 0x4c, 0xe7, 0x6d, 0x2b, 0xdc, 0x9c, 0x86, 0xbf, 0x5a, 0xa0, 0xb3, 0x69, 0x74, 0x36, - 0xcd, 0x42, 0x6b, 0x6d, 0x16, 0x9e, 0x82, 0x16, 0x26, 0x19, 0xe3, 0x54, 0xb0, 0x5c, 0x0f, 0xc3, - 0xd8, 0x7e, 0xfb, 0xea, 0x49, 0xc7, 0xfc, 0x57, 0x99, 0xb2, 0xcc, 0x44, 0x4e, 0xd3, 0xd0, 0x7b, - 0x47, 0x85, 0x1d, 0x50, 0xc7, 0x24, 0x65, 0x89, 0x19, 0x12, 0x7d, 0x80, 0xa7, 0xa0, 0x61, 0x26, - 0xbc, 0xa6, 0xa4, 0x3e, 0x96, 0x3d, 0xf7, 0xfb, 0x45, 0xff, 0xbe, 0x96, 0xe3, 0x78, 0xe1, 0x50, - 0xe6, 0x26, 0x48, 0x44, 0xce, 0x24, 0x15, 0x6f, 0x5f, 0x3d, 0x01, 0xc6, 0x67, 0x92, 0x0a, 0xcf, - 0x5c, 0x1d, 0x4f, 0x5e, 0x5f, 0xf6, 0xac, 0x37, 0x97, 0x3d, 0xeb, 0xcf, 0xcb, 0x9e, 0xf5, 0xf2, - 0xaa, 0xb7, 0xf5, 0xe6, 0xaa, 0xb7, 0xf5, 0xdb, 0x55, 0x6f, 0xeb, 0xb9, 0x1b, 0x52, 0x11, 0x2d, - 0xe7, 0x4e, 0xc0, 0x12, 0x17, 0xc5, 0x31, 0x4d, 0xe7, 0x54, 0x70, 0x57, 0xfd, 0x2b, 0xfe, 0xe4, - 0xae, 0xff, 0x39, 0x8a, 0x55, 0x46, 0xf8, 0xbc, 0xa1, 0x4a, 0xf3, 0xe9, 0x3f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xc6, 0xd1, 0x61, 0x40, 0xf1, 0x07, 0x00, 0x00, + // 933 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xdd, 0x6e, 0x1b, 0x45, + 0x18, 0xcd, 0x26, 0x76, 0x6a, 0x8f, 0x93, 0x10, 0x8d, 0x5c, 0xb3, 0x4d, 0x55, 0xdb, 0x32, 0x2a, + 0x32, 0x82, 0xee, 0x2a, 0x41, 0xf4, 0x82, 0x0b, 0xa4, 0x38, 0x15, 0x60, 0x21, 0x90, 0xb5, 0x0e, + 0x5c, 0xf4, 0x66, 0x35, 0xde, 0x99, 0xee, 0x0e, 0xde, 0xdd, 0x59, 0xed, 0x8c, 0x37, 0x98, 0xa7, + 0xe8, 0x53, 0xf0, 0x04, 0x7d, 0x88, 0x8a, 0xab, 0xaa, 0x57, 0x88, 0x8b, 0x80, 0x92, 0x27, 0x80, + 0x27, 0x40, 0xf3, 0xb3, 0xdb, 0x38, 0x71, 0x88, 0x7a, 0xe7, 0xf9, 0xce, 0x99, 0x73, 0xbe, 0x9d, + 0xef, 0xc7, 0xa0, 0x5b, 0x20, 0xc4, 0xdd, 0x2c, 0x67, 0x05, 0xc5, 0x24, 0x77, 0x8b, 0x43, 0x37, + 0x24, 0x29, 0xe1, 0x94, 0x3b, 0x59, 0xce, 0x04, 0x83, 0xfb, 0x12, 0x77, 0x4a, 0xdc, 0x29, 0x0e, + 0x0f, 0xda, 0x21, 0x0b, 0x99, 0x02, 0x5d, 0xf9, 0x4b, 0xf3, 0x0e, 0x7a, 0x21, 0x63, 0x61, 0x4c, + 0x5c, 0x75, 0x9a, 0x2d, 0x5e, 0xb8, 0x82, 0x26, 0x84, 0x0b, 0x94, 0x64, 0x86, 0xf0, 0x20, 0x60, + 0x3c, 0x61, 0xdc, 0xd7, 0x37, 0xf5, 0xc1, 0x40, 0x8f, 0x54, 0x0e, 0xc5, 0xa1, 0xcb, 0x23, 0x94, + 0x13, 0xec, 0x07, 0x2c, 0xe5, 0x8b, 0x84, 0xe4, 0x06, 0x86, 0x25, 0x7c, 0x46, 0x73, 0x52, 0xda, + 0xdd, 0x48, 0xbb, 0x4a, 0x51, 0x11, 0x06, 0xff, 0xd4, 0xc1, 0xce, 0x37, 0xfa, 0x4b, 0xa6, 0x02, + 0x09, 0x02, 0x87, 0x60, 0xbf, 0x40, 0x31, 0x27, 0xc2, 0x5f, 0x64, 0x18, 0x09, 0xe2, 0x53, 0x6c, + 0x5b, 0x7d, 0x6b, 0x58, 0xf3, 0xf6, 0x74, 0xfc, 0x47, 0x15, 0x1e, 0x63, 0x18, 0x81, 0x0f, 0xca, + 0x0c, 0x7c, 0x2e, 0xef, 0x72, 0x7b, 0xb3, 0xbf, 0x35, 0x6c, 0x1d, 0xf5, 0x9c, 0xeb, 0x8f, 0xe1, + 0x9c, 0x18, 0xa2, 0xf2, 0x18, 0x75, 0x5f, 0x9f, 0xf7, 0x36, 0xfe, 0x3d, 0xef, 0x75, 0x96, 0x28, + 0x89, 0xbf, 0x1c, 0x5c, 0x53, 0x19, 0x78, 0x7b, 0xc1, 0x55, 0x3a, 0x87, 0x3f, 0x83, 0x83, 0xeb, + 0x39, 0xf9, 0x82, 0xf9, 0x11, 0xa1, 0x61, 0x24, 0xec, 0x2d, 0x65, 0x3a, 0xbc, 0x69, 0xfa, 0xd3, + 0x4a, 0xbe, 0xa7, 0xec, 0x5b, 0xc5, 0x1f, 0xd5, 0xa4, 0xbb, 0xd7, 0x29, 0xd6, 0xa2, 0xf0, 0x29, + 0xd8, 0xce, 0x50, 0x8e, 0x12, 0x6e, 0xd7, 0xfa, 0xd6, 0xb0, 0x75, 0x64, 0xdf, 0xd4, 0x9d, 0x28, + 0xdc, 0xe8, 0x18, 0x36, 0x4c, 0x54, 0x8e, 0x14, 0x23, 0xc1, 0xf2, 0xaa, 0x32, 0x7e, 0xb6, 0x98, + 0xcd, 0xc9, 0x92, 0xdb, 0x75, 0x95, 0xe3, 0x27, 0x6b, 0x73, 0xd4, 0x77, 0xca, 0x17, 0x9a, 0x2c, + 0x66, 0xdf, 0x91, 0xa5, 0x11, 0xb7, 0x8b, 0x35, 0xb0, 0x14, 0x84, 0x29, 0x78, 0x58, 0x61, 0xdc, + 0x9f, 0x2d, 0xdf, 0x59, 0x22, 0x8c, 0x73, 0x7b, 0xfb, 0x4e, 0xbf, 0xd1, 0xb2, 0x94, 0x3c, 0xc6, + 0x38, 0xbf, 0xe1, 0xc7, 0x57, 0x71, 0x18, 0x80, 0x0f, 0x57, 0x1c, 0xb8, 0x2c, 0x40, 0x96, 0x2f, + 0x52, 0x62, 0xdf, 0x53, 0x5e, 0x1f, 0xdf, 0x5e, 0x74, 0x29, 0xc0, 0x4f, 0xd9, 0x44, 0xb2, 0x8d, + 0x51, 0x3b, 0x58, 0x83, 0x41, 0x02, 0xec, 0xca, 0xe4, 0x05, 0x21, 0x7e, 0xc6, 0x58, 0xec, 0xab, + 0x66, 0xe7, 0x76, 0xe3, 0x2e, 0x97, 0xaf, 0x09, 0x99, 0x30, 0x16, 0x4f, 0x25, 0xdd, 0xb8, 0xdc, + 0x0f, 0xd6, 0x60, 0x7c, 0xf0, 0x5b, 0x1d, 0xec, 0xae, 0x34, 0x24, 0xec, 0x81, 0x56, 0x65, 0x5c, + 0xf5, 0x3b, 0x28, 0x43, 0x63, 0x0c, 0x1f, 0x80, 0x46, 0x10, 0x21, 0x9a, 0x4a, 0x74, 0xb3, 0x6f, + 0x0d, 0x9b, 0xde, 0x3d, 0x75, 0x1e, 0x63, 0xf8, 0x10, 0x34, 0x83, 0x98, 0x92, 0x54, 0x48, 0x6c, + 0x4b, 0x61, 0x0d, 0x1d, 0x18, 0x63, 0xf8, 0x18, 0xec, 0xd1, 0x94, 0x0a, 0x8a, 0xe2, 0xb2, 0x5b, + 0x6b, 0x4a, 0x7b, 0xd7, 0x44, 0x4d, 0xd3, 0xfd, 0x00, 0xf6, 0x2b, 0x7f, 0xb3, 0x57, 0xec, 0xba, + 0x6a, 0xbf, 0x47, 0xfa, 0x83, 0xaf, 0x7c, 0xe7, 0xd5, 0x69, 0x35, 0xdf, 0x59, 0xcd, 0xa1, 0xc1, + 0x20, 0x02, 0x9d, 0x8c, 0xa4, 0x98, 0xa6, 0xa1, 0x6f, 0x06, 0x27, 0x88, 0x50, 0x1a, 0x12, 0x6e, + 0x1a, 0xe3, 0x71, 0xa5, 0x5a, 0xf5, 0xc3, 0x94, 0x88, 0x13, 0xc5, 0x99, 0xa0, 0x60, 0x4e, 0xc4, + 0x33, 0x24, 0x50, 0x59, 0x2b, 0x23, 0xa5, 0xc7, 0x49, 0x93, 0x38, 0xfc, 0x0c, 0x40, 0x1e, 0x23, + 0x1e, 0xf9, 0x98, 0x9d, 0xa5, 0x72, 0x89, 0xf9, 0x28, 0x98, 0xab, 0x5e, 0x68, 0x7a, 0xfb, 0x0a, + 0x79, 0x66, 0x80, 0xe3, 0x60, 0x0e, 0xbf, 0x00, 0xf5, 0x2c, 0x42, 0x9c, 0xd8, 0x8d, 0xbe, 0x35, + 0xdc, 0xfb, 0xbf, 0x0d, 0x31, 0x91, 0x34, 0x4f, 0xb3, 0xe1, 0x47, 0x60, 0x97, 0x9d, 0xa5, 0xa6, + 0xe5, 0x08, 0xe7, 0x76, 0x53, 0xbd, 0xef, 0x8e, 0x0a, 0x1e, 0xeb, 0x18, 0xfc, 0x0a, 0x34, 0x12, + 0x22, 0x10, 0x46, 0x02, 0xd9, 0x40, 0x3d, 0xda, 0xe0, 0x76, 0xf9, 0xef, 0x0d, 0xd3, 0xab, 0xee, + 0xc0, 0x29, 0x68, 0xc9, 0x6a, 0xf8, 0x66, 0xec, 0x5b, 0x4a, 0xe2, 0xe8, 0x76, 0x89, 0xb1, 0x2e, + 0x1d, 0xfd, 0x15, 0x09, 0xca, 0x52, 0xb5, 0x0c, 0x88, 0x20, 0x39, 0xf7, 0x80, 0x94, 0xd1, 0xcb, + 0x01, 0x9e, 0x80, 0x9d, 0x9c, 0x24, 0xac, 0x40, 0xb1, 0x2f, 0xdf, 0xc0, 0xde, 0x51, 0xaa, 0x07, + 0x8e, 0x5e, 0xff, 0x4e, 0xb9, 0xfe, 0x9d, 0xd3, 0x72, 0xfd, 0x8f, 0x6a, 0x2f, 0xff, 0xea, 0x59, + 0x5e, 0xcb, 0xdc, 0x92, 0xf1, 0xc1, 0x73, 0xd0, 0x59, 0xbf, 0xc3, 0xde, 0x63, 0x4b, 0x77, 0xc0, + 0xb6, 0xe9, 0xbc, 0x4d, 0x85, 0x9b, 0xd3, 0xe0, 0x77, 0x0b, 0xb4, 0xd7, 0x8d, 0xce, 0xdd, 0xb3, + 0xf0, 0x14, 0x34, 0x31, 0xc9, 0x18, 0xa7, 0x82, 0xe5, 0x7a, 0x18, 0x46, 0xf6, 0xdb, 0x57, 0x4f, + 0xda, 0xe6, 0xbf, 0xca, 0x94, 0x65, 0x2a, 0x72, 0x9a, 0x86, 0xde, 0x3b, 0x2a, 0x6c, 0x83, 0x3a, + 0x26, 0x29, 0x4b, 0xcc, 0x90, 0xe8, 0x03, 0x3c, 0x01, 0xdb, 0x66, 0xc2, 0x6b, 0x4a, 0xea, 0x53, + 0xd9, 0x73, 0x7f, 0x9e, 0xf7, 0xee, 0x6b, 0x39, 0x8e, 0xe7, 0x0e, 0x65, 0x6e, 0x82, 0x44, 0xe4, + 0x8c, 0x53, 0xf1, 0xf6, 0xd5, 0x13, 0x60, 0x7c, 0xc6, 0xa9, 0xf0, 0xcc, 0xd5, 0xd1, 0xf8, 0xf5, + 0x45, 0xd7, 0x7a, 0x73, 0xd1, 0xb5, 0xfe, 0xbe, 0xe8, 0x5a, 0x2f, 0x2f, 0xbb, 0x1b, 0x6f, 0x2e, + 0xbb, 0x1b, 0x7f, 0x5c, 0x76, 0x37, 0x9e, 0xbb, 0x21, 0x15, 0xd1, 0x62, 0xe6, 0x04, 0x2c, 0x71, + 0x51, 0x1c, 0xd3, 0x74, 0x46, 0x05, 0x77, 0xd5, 0xbf, 0xe2, 0x2f, 0xee, 0xea, 0x9f, 0xa3, 0x58, + 0x66, 0x84, 0xcf, 0xb6, 0x55, 0x69, 0x3e, 0xff, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x3c, 0xbe, 0x09, + 0x4a, 0xf1, 0x07, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -811,12 +811,10 @@ func (m *ConsumerFeePoolShare) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if len(m.ConsumerId) > 0 { - i -= len(m.ConsumerId) - copy(dAtA[i:], m.ConsumerId) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.ConsumerId))) + if m.ConsumerId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.ConsumerId)) i-- - dAtA[i] = 0xa + dAtA[i] = 0x8 } return len(dAtA) - i, nil } @@ -959,9 +957,8 @@ func (m *ConsumerFeePoolShare) Size() (n int) { } var l int _ = l - l = len(m.ConsumerId) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) + if m.ConsumerId != 0 { + n += 1 + sovGenesis(uint64(m.ConsumerId)) } l = len(m.Depositor) if l > 0 { @@ -1816,10 +1813,10 @@ func (m *ConsumerFeePoolShare) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 2 { + if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) } - var stringLen uint64 + m.ConsumerId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -1829,24 +1826,11 @@ func (m *ConsumerFeePoolShare) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.ConsumerId |= uint64(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ConsumerId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) diff --git a/x/vaas/provider/types/msg.go b/x/vaas/provider/types/msg.go index 62c39fc..7f196d1 100644 --- a/x/vaas/provider/types/msg.go +++ b/x/vaas/provider/types/msg.go @@ -431,9 +431,6 @@ func (msg MsgFundConsumerFeePool) ValidateBasic() error { if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid signer: %s", err) } - if strings.TrimSpace(msg.ConsumerId) == "" { - return errorsmod.Wrap(ErrNoConsumerId, "consumer_id must not be empty") - } if err := msg.Amount.Validate(); err != nil { return errorsmod.Wrapf(ErrInvalidFundDenom, "invalid amount: %s", err) } @@ -448,9 +445,6 @@ func (msg MsgWithdrawConsumerFeePool) ValidateBasic() error { if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid signer: %s", err) } - if strings.TrimSpace(msg.ConsumerId) == "" { - return errorsmod.Wrap(ErrNoConsumerId, "consumer_id must not be empty") - } if len(msg.Amount) == 0 { return errorsmod.Wrap(ErrInvalidFundDenom, "amount must not be empty") } @@ -468,9 +462,6 @@ func (msg MsgSweepConsumerFeePool) ValidateBasic() error { if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid signer: %s", err) } - if strings.TrimSpace(msg.ConsumerId) == "" { - return errorsmod.Wrap(ErrNoConsumerId, "consumer_id must not be empty") - } for _, d := range msg.Denoms { if err := sdk.ValidateDenom(d); err != nil { return errorsmod.Wrapf(ErrInvalidFundDenom, "invalid denom %q: %s", d, err) diff --git a/x/vaas/provider/types/msg_test.go b/x/vaas/provider/types/msg_test.go index d8bbc01..5d9a361 100644 --- a/x/vaas/provider/types/msg_test.go +++ b/x/vaas/provider/types/msg_test.go @@ -552,27 +552,22 @@ func TestMsgFundConsumerFeePool_ValidateBasic(t *testing.T) { }{ {"valid", types.MsgFundConsumerFeePool{ Signer: validSigner, - ConsumerId: "0", + ConsumerId: 0, Amount: sdk.NewInt64Coin("uphoton", 100), }, false}, {"invalid signer", types.MsgFundConsumerFeePool{ Signer: "not-bech32", - ConsumerId: "0", - Amount: sdk.NewInt64Coin("uphoton", 100), - }, true}, - {"empty consumer id", types.MsgFundConsumerFeePool{ - Signer: validSigner, - ConsumerId: "", + ConsumerId: 0, Amount: sdk.NewInt64Coin("uphoton", 100), }, true}, {"zero amount", types.MsgFundConsumerFeePool{ Signer: validSigner, - ConsumerId: "0", + ConsumerId: 0, Amount: sdk.NewInt64Coin("uphoton", 0), }, true}, {"invalid denom", types.MsgFundConsumerFeePool{ Signer: validSigner, - ConsumerId: "0", + ConsumerId: 0, Amount: sdk.Coin{Denom: "", Amount: math.NewInt(100)}, }, true}, } @@ -597,32 +592,27 @@ func TestMsgWithdrawConsumerFeePool_ValidateBasic(t *testing.T) { }{ {"valid", types.MsgWithdrawConsumerFeePool{ Signer: validSigner, - ConsumerId: "0", + ConsumerId: 0, Amount: sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), }, false}, {"invalid signer", types.MsgWithdrawConsumerFeePool{ Signer: "not-bech32", - ConsumerId: "0", - Amount: sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), - }, true}, - {"empty consumer id", types.MsgWithdrawConsumerFeePool{ - Signer: validSigner, - ConsumerId: "", + ConsumerId: 0, Amount: sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), }, true}, {"empty coins", types.MsgWithdrawConsumerFeePool{ Signer: validSigner, - ConsumerId: "0", + ConsumerId: 0, Amount: sdk.Coins{}, }, true}, {"coins with zero amount", types.MsgWithdrawConsumerFeePool{ Signer: validSigner, - ConsumerId: "0", + ConsumerId: 0, Amount: sdk.Coins{sdk.NewInt64Coin("uphoton", 0)}, }, true}, {"coins with duplicate denom", types.MsgWithdrawConsumerFeePool{ Signer: validSigner, - ConsumerId: "0", + ConsumerId: 0, Amount: sdk.Coins{sdk.NewInt64Coin("uphoton", 50), sdk.NewInt64Coin("uphoton", 50)}, }, true}, } @@ -647,27 +637,22 @@ func TestMsgSweepConsumerFeePool_ValidateBasic(t *testing.T) { }{ {"valid with explicit denoms", types.MsgSweepConsumerFeePool{ Signer: validSigner, - ConsumerId: "0", + ConsumerId: 0, Denoms: []string{"uphoton", "uatom"}, }, false}, {"valid with empty denoms", types.MsgSweepConsumerFeePool{ Signer: validSigner, - ConsumerId: "0", + ConsumerId: 0, Denoms: []string{}, }, false}, {"invalid signer", types.MsgSweepConsumerFeePool{ Signer: "not-bech32", - ConsumerId: "0", - Denoms: []string{"uphoton"}, - }, true}, - {"empty consumer id", types.MsgSweepConsumerFeePool{ - Signer: validSigner, - ConsumerId: "", + ConsumerId: 0, Denoms: []string{"uphoton"}, }, true}, {"invalid denom string", types.MsgSweepConsumerFeePool{ Signer: validSigner, - ConsumerId: "0", + ConsumerId: 0, Denoms: []string{"INVALID DENOM WITH SPACES"}, }, true}, } diff --git a/x/vaas/provider/types/query.pb.go b/x/vaas/provider/types/query.pb.go index efcb9d8..5d18480 100644 --- a/x/vaas/provider/types/query.pb.go +++ b/x/vaas/provider/types/query.pb.go @@ -1364,7 +1364,7 @@ func (m *QueryConsumerGenesisTimeResponse) GetGenesisTime() time.Time { } type QueryConsumerFeePoolClaimRequest struct { - ConsumerId string `protobuf:"bytes,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + ConsumerId uint64 `protobuf:"varint,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` // bech32 address; if equal to the gov module authority, aliases to the // distribution module account address Depositor string `protobuf:"bytes,2,opt,name=depositor,proto3" json:"depositor,omitempty"` @@ -1403,11 +1403,11 @@ func (m *QueryConsumerFeePoolClaimRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryConsumerFeePoolClaimRequest proto.InternalMessageInfo -func (m *QueryConsumerFeePoolClaimRequest) GetConsumerId() string { +func (m *QueryConsumerFeePoolClaimRequest) GetConsumerId() uint64 { if m != nil { return m.ConsumerId } - return "" + return 0 } func (m *QueryConsumerFeePoolClaimRequest) GetDepositor() string { @@ -1515,7 +1515,7 @@ func (m *DepositorClaim) GetClaim() github_com_cosmos_cosmos_sdk_types.Coins { } type QueryConsumerFeePoolClaimsRequest struct { - ConsumerId string `protobuf:"bytes,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + ConsumerId uint64 `protobuf:"varint,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -1552,11 +1552,11 @@ func (m *QueryConsumerFeePoolClaimsRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryConsumerFeePoolClaimsRequest proto.InternalMessageInfo -func (m *QueryConsumerFeePoolClaimsRequest) GetConsumerId() string { +func (m *QueryConsumerFeePoolClaimsRequest) GetConsumerId() uint64 { if m != nil { return m.ConsumerId } - return "" + return 0 } func (m *QueryConsumerFeePoolClaimsRequest) GetPagination() *query.PageRequest { @@ -1654,7 +1654,7 @@ func init() { func init() { proto.RegisterFile("vaas/provider/v1/query.proto", fileDescriptor_71b3f55ed407aa51) } var fileDescriptor_71b3f55ed407aa51 = []byte{ - // 2037 bytes of a gzipped FileDescriptorProto + // 2034 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0x4d, 0x70, 0x1c, 0x47, 0x15, 0xd6, 0xac, 0x25, 0x59, 0x6a, 0xd9, 0x8a, 0xe9, 0x48, 0x68, 0xb5, 0x96, 0xb5, 0xf6, 0x38, 0x09, 0x8a, 0x6d, 0xcd, 0x58, 0x2b, 0xdb, 0x95, 0x12, 0x21, 0xe0, 0x95, 0x23, 0xb3, 0x65, 0x82, @@ -1742,47 +1742,47 @@ var fileDescriptor_71b3f55ed407aa51 = []byte{ 0x17, 0x0e, 0x8c, 0x5d, 0xa5, 0xb0, 0xa4, 0x74, 0xf0, 0xe8, 0xb8, 0x0d, 0x44, 0x27, 0x65, 0x27, 0xdd, 0x2f, 0x2f, 0x7f, 0x15, 0x83, 0xb5, 0xc6, 0x86, 0x68, 0x8d, 0x8d, 0xfb, 0xa2, 0x35, 0xae, 0x4f, 0x25, 0x47, 0xf4, 0xfe, 0xa7, 0x55, 0xcd, 0x9a, 0x69, 0x1f, 0x2a, 0xd4, 0xf7, 0x94, 0xcd, - 0xb6, 0x98, 0x3d, 0x9b, 0x2e, 0x22, 0x9d, 0x21, 0x88, 0xa7, 0x53, 0xa1, 0x78, 0x03, 0x4c, 0x3b, - 0x38, 0xf0, 0x23, 0x12, 0xfb, 0x21, 0x67, 0x0d, 0xe5, 0x27, 0x8f, 0x57, 0xe7, 0x78, 0x72, 0x4c, - 0x67, 0xf6, 0x43, 0x51, 0xfd, 0x67, 0x82, 0xa0, 0x66, 0xef, 0xce, 0x6d, 0x45, 0x60, 0xa2, 0x95, - 0x0c, 0xf0, 0x04, 0xb6, 0x98, 0xea, 0x98, 0x44, 0x56, 0xdf, 0xf4, 0x89, 0x57, 0xbf, 0x9a, 0xd8, - 0xf8, 0xfb, 0x4f, 0xab, 0x2b, 0x6d, 0x12, 0xef, 0x74, 0x9b, 0x46, 0xcb, 0xef, 0xf0, 0x66, 0x9c, - 0xff, 0x59, 0x8d, 0x9c, 0x5d, 0x33, 0xee, 0x07, 0x38, 0xa2, 0x0b, 0x22, 0x8b, 0x69, 0xd6, 0xff, - 0xa0, 0x81, 0xd9, 0x5b, 0x02, 0x16, 0xdd, 0x3d, 0x6d, 0x93, 0x56, 0xd8, 0xa6, 0x43, 0xb4, 0xa5, - 0x2f, 0x0d, 0xed, 0x7b, 0xc3, 0xdc, 0x16, 0x15, 0x3e, 0xb5, 0xe7, 0xd5, 0x27, 0xff, 0x49, 0x53, - 0x52, 0xb2, 0x02, 0x87, 0x1f, 0xe3, 0x1b, 0x60, 0x92, 0xc2, 0x17, 0x85, 0xe8, 0xfc, 0xd1, 0xfb, - 0x9a, 0x3e, 0x02, 0xc1, 0xd9, 0xd8, 0xaa, 0xe7, 0xd6, 0x3d, 0xd7, 0x7e, 0xf9, 0x22, 0x98, 0xa0, - 0x78, 0xe1, 0x1f, 0x35, 0x30, 0x97, 0x75, 0xd5, 0xe0, 0xea, 0x88, 0x22, 0x99, 0x7e, 0x52, 0xa9, - 0x18, 0x45, 0xc5, 0x19, 0x1a, 0xfd, 0xfa, 0x4f, 0x3f, 0xfe, 0xf7, 0xaf, 0x4a, 0x26, 0x5c, 0x35, - 0xd3, 0x2f, 0x55, 0xf2, 0xbc, 0xf8, 0x0d, 0x35, 0xf7, 0x06, 0x4e, 0x70, 0x1f, 0xfe, 0x56, 0xe3, - 0x2c, 0x38, 0xfd, 0x20, 0x01, 0xaf, 0x8c, 0xd8, 0x3e, 0xf5, 0xaa, 0x52, 0x59, 0x2d, 0x28, 0xcd, - 0xb1, 0x1a, 0x14, 0xeb, 0x0a, 0x7c, 0x25, 0x0f, 0x2b, 0x7b, 0xdc, 0x30, 0xf7, 0x68, 0xfd, 0xd8, - 0x87, 0x9f, 0x88, 0x37, 0x9d, 0xcc, 0x36, 0x16, 0xae, 0xe7, 0xec, 0x3e, 0xac, 0x07, 0xaf, 0x5c, - 0x3b, 0xde, 0x22, 0x8e, 0xfc, 0x2e, 0x45, 0xde, 0x80, 0xb7, 0x15, 0xe4, 0x92, 0xcc, 0xd8, 0xa9, - 0x7e, 0x26, 0xed, 0x6c, 0x73, 0x4f, 0x25, 0xee, 0x59, 0xa6, 0x0d, 0x36, 0xb0, 0xa3, 0x4d, 0xcb, - 0xe8, 0xbe, 0x47, 0x9b, 0x96, 0xd5, 0x23, 0x17, 0x30, 0x2d, 0x85, 0x5e, 0x35, 0x4d, 0xed, 0xe3, - 0xf6, 0xe1, 0xc7, 0xe2, 0x0e, 0x0f, 0xed, 0x7d, 0xe1, 0xd7, 0x73, 0xd0, 0x16, 0x69, 0xc0, 0x2b, - 0xaf, 0x7f, 0xbe, 0xc5, 0xdc, 0xe4, 0x1a, 0x35, 0xf9, 0x0a, 0xbc, 0xa4, 0x98, 0xcc, 0x4d, 0xb0, - 0x93, 0xee, 0x59, 0xbd, 0x30, 0x7d, 0x30, 0x33, 0xd0, 0x35, 0xc2, 0x97, 0x72, 0x00, 0xa4, 0x5a, - 0xcd, 0xca, 0xcb, 0x23, 0xa4, 0x38, 0x9e, 0x73, 0x14, 0xcf, 0x02, 0x9c, 0x57, 0xf0, 0x30, 0xca, - 0x03, 0xff, 0xac, 0x81, 0x85, 0x1c, 0x5e, 0x0d, 0xaf, 0x16, 0xa6, 0xe0, 0x02, 0xd3, 0xda, 0x31, - 0x56, 0x70, 0x7c, 0xaf, 0x51, 0x7c, 0x35, 0x78, 0x35, 0xef, 0xde, 0x1e, 0x72, 0x7a, 0xc5, 0x6b, - 0x8f, 0x35, 0xce, 0x6b, 0xb3, 0xe8, 0x3b, 0xcc, 0xeb, 0x1f, 0x86, 0xf4, 0x03, 0x95, 0xf5, 0x63, - 0xad, 0x19, 0x91, 0x78, 0x72, 0x9a, 0x06, 0xf8, 0x17, 0xf5, 0xb9, 0x36, 0x4d, 0xeb, 0xe1, 0xb5, - 0x11, 0x3e, 0xcc, 0x6c, 0x24, 0x2a, 0xd7, 0x8f, 0xb9, 0xaa, 0x68, 0xd6, 0x24, 0x8e, 0xb9, 0x27, - 0x09, 0xe7, 0x3e, 0xfc, 0x9d, 0xc6, 0x9f, 0x3d, 0x52, 0x59, 0x18, 0x5e, 0x2e, 0x92, 0xab, 0x05, - 0xd4, 0x2b, 0xc5, 0x84, 0x39, 0xc2, 0x75, 0x8a, 0x70, 0x15, 0x5e, 0x1e, 0x9a, 0xd7, 0x95, 0xd0, - 0xf8, 0xab, 0x06, 0xca, 0x79, 0xdc, 0x14, 0xae, 0x15, 0xab, 0x82, 0x03, 0x5c, 0xb8, 0x52, 0x3b, - 0xce, 0x12, 0x0e, 0x7c, 0x83, 0x02, 0xbf, 0x06, 0x6b, 0x23, 0x8a, 0x27, 0x25, 0xc6, 0x0a, 0xfe, - 0x7f, 0x68, 0x60, 0x2e, 0x8b, 0xa5, 0xc0, 0x51, 0x40, 0x32, 0x68, 0x71, 0x6e, 0x54, 0x0f, 0x23, - 0xb3, 0xfa, 0x1d, 0x8a, 0xfe, 0x4d, 0xb8, 0x69, 0x1e, 0xf9, 0x27, 0x95, 0x44, 0x2a, 0x7b, 0x0d, - 0xca, 0x7c, 0xd4, 0xe4, 0x2d, 0xa9, 0xe6, 0x3e, 0xfc, 0xbb, 0x06, 0xe6, 0x33, 0x49, 0x17, 0x3c, - 0x0e, 0xb6, 0x68, 0x54, 0x2d, 0x1a, 0xca, 0xeb, 0xf4, 0x6f, 0x51, 0x8b, 0x36, 0xe0, 0x6b, 0x85, - 0x2d, 0x52, 0x12, 0x4e, 0xbd, 0xf1, 0xe1, 0xd3, 0x65, 0xed, 0xa3, 0xa7, 0xcb, 0xda, 0xbf, 0x9e, - 0x2e, 0x6b, 0xef, 0x3f, 0x5b, 0x1e, 0xfb, 0xe8, 0xd9, 0xf2, 0xd8, 0x27, 0xcf, 0x96, 0xc7, 0xde, - 0x31, 0x07, 0xa8, 0x31, 0x72, 0x5d, 0xe2, 0x35, 0x49, 0x1c, 0xb1, 0x7d, 0x1e, 0x29, 0xdb, 0x51, - 0x9e, 0xdc, 0x9c, 0xa4, 0x9d, 0xcf, 0xfa, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x28, 0x47, 0x02, - 0x10, 0x88, 0x1c, 0x00, 0x00, + 0xb6, 0x98, 0x3d, 0x9b, 0x2e, 0x22, 0x9d, 0xa2, 0x88, 0xe1, 0x0d, 0x30, 0xed, 0xe0, 0xc0, 0x8f, + 0x48, 0xec, 0x87, 0x9c, 0x35, 0x94, 0x9f, 0x3c, 0x5e, 0x9d, 0xe3, 0xc9, 0x31, 0x9d, 0xd9, 0x0f, + 0x45, 0xf5, 0x9f, 0x09, 0x82, 0x9a, 0xbd, 0x3b, 0xb7, 0x15, 0x81, 0x89, 0x56, 0x32, 0xc0, 0x13, + 0xd8, 0x62, 0xaa, 0x63, 0x12, 0x59, 0x7d, 0xd3, 0x27, 0x5e, 0xfd, 0x6a, 0x62, 0xe3, 0xef, 0x3f, + 0xad, 0xae, 0xb4, 0x49, 0xbc, 0xd3, 0x6d, 0x1a, 0x2d, 0xbf, 0xc3, 0x9b, 0x71, 0xfe, 0x67, 0x35, + 0x72, 0x76, 0xcd, 0xb8, 0x1f, 0xe0, 0x88, 0x2e, 0x88, 0x2c, 0xa6, 0x59, 0xff, 0x83, 0x06, 0x66, + 0x6f, 0x09, 0x58, 0x74, 0xf7, 0xb4, 0x4d, 0x5a, 0x61, 0x9b, 0x0e, 0xd1, 0x96, 0xbe, 0x34, 0xb4, + 0xef, 0x0d, 0x73, 0x5b, 0x61, 0x06, 0xf3, 0xdc, 0xfa, 0xe4, 0x3f, 0x69, 0x4a, 0x4a, 0x56, 0xe0, + 0xf0, 0x63, 0x7c, 0x03, 0x4c, 0x52, 0xf8, 0xa2, 0x10, 0x9d, 0x3f, 0x7a, 0x5f, 0xd3, 0x47, 0x20, + 0x38, 0x1b, 0x5b, 0xf5, 0xdc, 0xba, 0xe7, 0xda, 0x2f, 0x5f, 0x04, 0x13, 0x14, 0x2f, 0xfc, 0xa3, + 0x06, 0xe6, 0xb2, 0xae, 0x1a, 0x5c, 0x1d, 0x51, 0x24, 0xd3, 0x4f, 0x2a, 0x15, 0xa3, 0xa8, 0x38, + 0x43, 0xa3, 0x5f, 0xff, 0xe9, 0xc7, 0xff, 0xfe, 0x55, 0xc9, 0x84, 0xab, 0x66, 0xfa, 0xa5, 0x4a, + 0x9e, 0x17, 0xbf, 0xa1, 0xe6, 0xde, 0xc0, 0x09, 0xee, 0xc3, 0xdf, 0x6a, 0x9c, 0x05, 0xa7, 0x1f, + 0x24, 0xe0, 0x95, 0x11, 0xdb, 0xa7, 0x5e, 0x55, 0x2a, 0xab, 0x05, 0xa5, 0x39, 0x56, 0x83, 0x62, + 0x5d, 0x81, 0xaf, 0xe4, 0x61, 0x65, 0x8f, 0x1b, 0xe6, 0x1e, 0xad, 0x1f, 0xfb, 0xf0, 0x13, 0xf1, + 0xa6, 0x93, 0xd9, 0xc6, 0xc2, 0xf5, 0x9c, 0xdd, 0x87, 0xf5, 0xe0, 0x95, 0x6b, 0xc7, 0x5b, 0xc4, + 0x91, 0xdf, 0xa5, 0xc8, 0x1b, 0xf0, 0xb6, 0x82, 0x5c, 0x92, 0x19, 0x3b, 0xd5, 0xcf, 0xa4, 0x9d, + 0x6d, 0xee, 0xa9, 0xc4, 0x3d, 0xcb, 0xb4, 0xc1, 0x06, 0x76, 0xb4, 0x69, 0x19, 0xdd, 0xf7, 0x68, + 0xd3, 0xb2, 0x7a, 0xe4, 0x02, 0xa6, 0xa5, 0xd0, 0xab, 0xa6, 0xa9, 0x7d, 0xdc, 0x3e, 0xfc, 0x58, + 0xdc, 0xe1, 0xa1, 0xbd, 0x2f, 0xfc, 0x7a, 0x0e, 0xda, 0x22, 0x0d, 0x78, 0xe5, 0xf5, 0xcf, 0xb7, + 0x98, 0x9b, 0x5c, 0xa3, 0x26, 0x5f, 0x81, 0x97, 0x14, 0x93, 0xb9, 0x09, 0x76, 0xd2, 0x3d, 0xab, + 0x17, 0xa6, 0x0f, 0x66, 0x06, 0xba, 0x46, 0xf8, 0x52, 0x0e, 0x80, 0x54, 0xab, 0x59, 0x79, 0x79, + 0x84, 0x14, 0xc7, 0x73, 0x8e, 0xe2, 0x59, 0x80, 0xf3, 0x0a, 0x1e, 0x46, 0x79, 0xe0, 0x9f, 0x35, + 0xb0, 0x90, 0xc3, 0xab, 0xe1, 0xd5, 0xc2, 0x14, 0x5c, 0x60, 0x5a, 0x3b, 0xc6, 0x0a, 0x8e, 0xef, + 0x35, 0x8a, 0xaf, 0x06, 0xaf, 0xe6, 0xdd, 0xdb, 0x43, 0x4e, 0xaf, 0x78, 0xed, 0xb1, 0xc6, 0x79, + 0x6d, 0x16, 0x7d, 0x87, 0x79, 0xfd, 0xc3, 0x90, 0x7e, 0xa0, 0xb2, 0x7e, 0xac, 0x35, 0x23, 0x12, + 0x4f, 0x4e, 0xd3, 0x00, 0xff, 0xa2, 0x3e, 0xd7, 0xa6, 0x69, 0x3d, 0xbc, 0x36, 0xc2, 0x87, 0x99, + 0x8d, 0x44, 0xe5, 0xfa, 0x31, 0x57, 0x15, 0xcd, 0x9a, 0xc4, 0x31, 0xf7, 0x24, 0xe1, 0xdc, 0x87, + 0xbf, 0xd3, 0xf8, 0xb3, 0x47, 0x2a, 0x0b, 0xc3, 0xcb, 0x45, 0x72, 0xb5, 0x80, 0x7a, 0xa5, 0x98, + 0x30, 0x47, 0xb8, 0x4e, 0x11, 0xae, 0xc2, 0xcb, 0x43, 0xf3, 0xba, 0x12, 0x1a, 0x7f, 0xd5, 0x40, + 0x39, 0x8f, 0x9b, 0xc2, 0xb5, 0x62, 0x55, 0x70, 0x80, 0x0b, 0x57, 0x6a, 0xc7, 0x59, 0xc2, 0x81, + 0x6f, 0x50, 0xe0, 0xd7, 0x60, 0x6d, 0x44, 0xf1, 0xa4, 0xc4, 0x58, 0xc1, 0xff, 0x0f, 0x0d, 0xcc, + 0x65, 0xb1, 0x14, 0x38, 0x0a, 0x48, 0x06, 0x2d, 0xce, 0x8d, 0xea, 0x61, 0x64, 0x56, 0xbf, 0x43, + 0xd1, 0xbf, 0x09, 0x37, 0xcd, 0x23, 0xff, 0xa4, 0x92, 0x48, 0x65, 0xaf, 0x41, 0x99, 0x8f, 0x9a, + 0xbc, 0x25, 0xd5, 0xdc, 0x87, 0x7f, 0xd7, 0xc0, 0x7c, 0x26, 0xe9, 0x82, 0xc7, 0xc1, 0x16, 0x8d, + 0xaa, 0x45, 0x43, 0x79, 0x9d, 0xfe, 0x2d, 0x6a, 0xd1, 0x06, 0x7c, 0xad, 0xb0, 0x45, 0x4a, 0xc2, + 0xa9, 0x37, 0x3e, 0x7c, 0xba, 0xac, 0x7d, 0xf4, 0x74, 0x59, 0xfb, 0xd7, 0xd3, 0x65, 0xed, 0xfd, + 0x67, 0xcb, 0x63, 0x1f, 0x3d, 0x5b, 0x1e, 0xfb, 0xe4, 0xd9, 0xf2, 0xd8, 0x3b, 0xe6, 0x00, 0x35, + 0x46, 0xae, 0x4b, 0xbc, 0x26, 0x89, 0x23, 0xb6, 0xcf, 0x23, 0x65, 0x3b, 0xca, 0x93, 0x9b, 0x93, + 0xb4, 0xf3, 0x59, 0xff, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4a, 0x42, 0xd0, 0x46, 0x88, 0x1c, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3358,12 +3358,10 @@ func (m *QueryConsumerFeePoolClaimRequest) MarshalToSizedBuffer(dAtA []byte) (in i-- dAtA[i] = 0x12 } - if len(m.ConsumerId) > 0 { - i -= len(m.ConsumerId) - copy(dAtA[i:], m.ConsumerId) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ConsumerId))) + if m.ConsumerId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.ConsumerId)) i-- - dAtA[i] = 0xa + dAtA[i] = 0x8 } return len(dAtA) - i, nil } @@ -3481,12 +3479,10 @@ func (m *QueryConsumerFeePoolClaimsRequest) MarshalToSizedBuffer(dAtA []byte) (i i-- dAtA[i] = 0x12 } - if len(m.ConsumerId) > 0 { - i -= len(m.ConsumerId) - copy(dAtA[i:], m.ConsumerId) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ConsumerId))) + if m.ConsumerId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.ConsumerId)) i-- - dAtA[i] = 0xa + dAtA[i] = 0x8 } return len(dAtA) - i, nil } @@ -3965,9 +3961,8 @@ func (m *QueryConsumerFeePoolClaimRequest) Size() (n int) { } var l int _ = l - l = len(m.ConsumerId) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) + if m.ConsumerId != 0 { + n += 1 + sovQuery(uint64(m.ConsumerId)) } l = len(m.Depositor) if l > 0 { @@ -4016,9 +4011,8 @@ func (m *QueryConsumerFeePoolClaimsRequest) Size() (n int) { } var l int _ = l - l = len(m.ConsumerId) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) + if m.ConsumerId != 0 { + n += 1 + sovQuery(uint64(m.ConsumerId)) } if m.Pagination != nil { l = m.Pagination.Size() @@ -6819,10 +6813,10 @@ func (m *QueryConsumerFeePoolClaimRequest) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 2 { + if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) } - var stringLen uint64 + m.ConsumerId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -6832,24 +6826,11 @@ func (m *QueryConsumerFeePoolClaimRequest) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.ConsumerId |= uint64(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ConsumerId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Depositor", wireType) @@ -7133,10 +7114,10 @@ func (m *QueryConsumerFeePoolClaimsRequest) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 2 { + if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) } - var stringLen uint64 + m.ConsumerId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -7146,24 +7127,11 @@ func (m *QueryConsumerFeePoolClaimsRequest) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.ConsumerId |= uint64(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ConsumerId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) diff --git a/x/vaas/provider/types/query.pb.gw.go b/x/vaas/provider/types/query.pb.gw.go index 4fc9e91..de5a88c 100644 --- a/x/vaas/provider/types/query.pb.gw.go +++ b/x/vaas/provider/types/query.pb.gw.go @@ -639,7 +639,7 @@ func request_Query_ConsumerFeePoolClaim_0(ctx context.Context, marshaler runtime return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "consumer_id") } - protoReq.ConsumerId, err = runtime.String(val) + protoReq.ConsumerId, err = runtime.Uint64(val) if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "consumer_id", err) @@ -677,7 +677,7 @@ func local_request_Query_ConsumerFeePoolClaim_0(ctx context.Context, marshaler r return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "consumer_id") } - protoReq.ConsumerId, err = runtime.String(val) + protoReq.ConsumerId, err = runtime.Uint64(val) if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "consumer_id", err) @@ -719,7 +719,7 @@ func request_Query_ConsumerFeePoolClaims_0(ctx context.Context, marshaler runtim return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "consumer_id") } - protoReq.ConsumerId, err = runtime.String(val) + protoReq.ConsumerId, err = runtime.Uint64(val) if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "consumer_id", err) @@ -753,7 +753,7 @@ func local_request_Query_ConsumerFeePoolClaims_0(ctx context.Context, marshaler return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "consumer_id") } - protoReq.ConsumerId, err = runtime.String(val) + protoReq.ConsumerId, err = runtime.Uint64(val) if err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "consumer_id", err) diff --git a/x/vaas/provider/types/tx.pb.go b/x/vaas/provider/types/tx.pb.go index 4f3a16b..357685d 100644 --- a/x/vaas/provider/types/tx.pb.go +++ b/x/vaas/provider/types/tx.pb.go @@ -738,7 +738,7 @@ var xxx_messageInfo_MsgUpdateConsumerResponse proto.InternalMessageInfo // distribution module account is credited as the depositor. type MsgFundConsumerFeePool struct { Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` - ConsumerId string `protobuf:"bytes,2,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + ConsumerId uint64 `protobuf:"varint,2,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` Amount types1.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` } @@ -819,7 +819,7 @@ var xxx_messageInfo_MsgFundConsumerFeePoolResponse proto.InternalMessageInfo // community pool. type MsgWithdrawConsumerFeePool struct { Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` - ConsumerId string `protobuf:"bytes,2,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + ConsumerId uint64 `protobuf:"varint,2,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` } @@ -908,7 +908,7 @@ func (m *MsgWithdrawConsumerFeePoolResponse) GetAmount() github_com_cosmos_cosmo // Only the consumer owner may sign. type MsgSweepConsumerFeePool struct { Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` - ConsumerId string `protobuf:"bytes,2,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + ConsumerId uint64 `protobuf:"varint,2,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` // empty = all denoms with shares or balance for this consumer Denoms []string `protobuf:"bytes,3,rep,name=denoms,proto3" json:"denoms,omitempty"` } @@ -1008,92 +1008,92 @@ func init() { func init() { proto.RegisterFile("vaas/provider/v1/tx.proto", fileDescriptor_a07778b1d094765c) } var fileDescriptor_a07778b1d094765c = []byte{ - // 1349 bytes of a gzipped FileDescriptorProto + // 1346 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4d, 0x6c, 0x1b, 0x45, - 0x14, 0xce, 0xe6, 0xaf, 0xcd, 0x24, 0xb4, 0x64, 0x9b, 0x36, 0xb6, 0x29, 0x76, 0xba, 0x08, 0x1a, - 0x4a, 0xbb, 0xdb, 0x04, 0x68, 0xa5, 0xa8, 0x42, 0x6a, 0x12, 0x2a, 0x22, 0x64, 0x11, 0x6d, 0x45, - 0x91, 0x00, 0x61, 0xcd, 0xee, 0x4e, 0xd7, 0xa3, 0x78, 0x67, 0xcc, 0xce, 0xd8, 0x69, 0x90, 0x90, - 0x10, 0x07, 0x04, 0x9c, 0xe0, 0xc8, 0xad, 0x47, 0xc4, 0xa9, 0x07, 0xce, 0x9c, 0x7b, 0x2c, 0x9c, - 0x10, 0x87, 0x82, 0x52, 0x89, 0x72, 0xe2, 0xc0, 0x1d, 0x09, 0xed, 0xec, 0xec, 0x78, 0x6d, 0x8f, - 0x7f, 0x5a, 0xa0, 0x97, 0xc4, 0x33, 0xef, 0x7b, 0x7f, 0xdf, 0x7b, 0x33, 0xf3, 0xb4, 0xa0, 0xd8, - 0x86, 0x90, 0x39, 0xcd, 0x98, 0xb6, 0x71, 0x80, 0x62, 0xa7, 0xbd, 0xe6, 0xf0, 0x5b, 0x76, 0x33, - 0xa6, 0x9c, 0x9a, 0x4f, 0x27, 0x22, 0x3b, 0x13, 0xd9, 0xed, 0xb5, 0xd2, 0x22, 0x8c, 0x30, 0xa1, - 0x8e, 0xf8, 0x9b, 0x82, 0x4a, 0x65, 0x9f, 0xb2, 0x88, 0x32, 0xc7, 0x83, 0x0c, 0x39, 0xed, 0x35, - 0x0f, 0x71, 0xb8, 0xe6, 0xf8, 0x14, 0x13, 0x29, 0x5f, 0x96, 0xf2, 0x88, 0x85, 0x89, 0xf1, 0x88, - 0x85, 0x52, 0x50, 0x4c, 0x05, 0x35, 0xb1, 0x72, 0xd2, 0x85, 0x14, 0x2d, 0x85, 0x34, 0xa4, 0xe9, - 0x7e, 0xf2, 0x4b, 0xee, 0x9e, 0x0e, 0x29, 0x0d, 0x1b, 0xc8, 0x81, 0x4d, 0xec, 0x40, 0x42, 0x28, - 0x87, 0x1c, 0x53, 0x92, 0xe9, 0x14, 0xa5, 0x54, 0xac, 0xbc, 0xd6, 0x4d, 0x07, 0x92, 0x83, 0x2c, - 0xc4, 0x5e, 0x51, 0xd0, 0x8a, 0x85, 0xae, 0x94, 0x57, 0x7a, 0xe5, 0x1c, 0x47, 0x88, 0x71, 0x18, - 0x35, 0x33, 0x00, 0xf6, 0x7c, 0xc7, 0xa7, 0x31, 0x72, 0xfc, 0x06, 0x46, 0x84, 0x27, 0x89, 0xa4, - 0xbf, 0x24, 0xc0, 0x49, 0x00, 0x0d, 0x1c, 0xd6, 0x79, 0xba, 0xcd, 0x1c, 0x8e, 0x48, 0x80, 0xe2, - 0x08, 0xa7, 0xe0, 0xce, 0x2a, 0xb3, 0x98, 0x93, 0xf3, 0x83, 0x26, 0x62, 0x0e, 0x4a, 0x48, 0x26, - 0x3e, 0xca, 0x00, 0x7d, 0x65, 0x51, 0x75, 0x10, 0x00, 0xeb, 0x17, 0x03, 0x2c, 0x55, 0x59, 0x78, - 0x95, 0x31, 0x1c, 0x92, 0x2d, 0x4a, 0x58, 0x2b, 0x42, 0xf1, 0x9b, 0xe8, 0xc0, 0xac, 0x80, 0x79, - 0x5f, 0x2e, 0x6b, 0x38, 0x28, 0x18, 0x2b, 0xc6, 0xea, 0xb4, 0x0b, 0xb2, 0xad, 0x9d, 0xc0, 0xbc, - 0x0c, 0x9e, 0xca, 0x6c, 0xd5, 0x60, 0x10, 0xc4, 0x85, 0xc9, 0x15, 0x63, 0x75, 0x6e, 0xd3, 0xfc, - 0xeb, 0x7e, 0xe5, 0xd8, 0x01, 0x8c, 0x1a, 0x1b, 0x56, 0xb2, 0x8b, 0x18, 0xb3, 0xdc, 0x85, 0x0c, - 0x78, 0x35, 0x08, 0x62, 0xf3, 0x0c, 0x58, 0x50, 0x96, 0xf7, 0xd0, 0x41, 0x61, 0x2a, 0xd1, 0x73, - 0x95, 0xb7, 0xc4, 0xf9, 0x45, 0x30, 0x9b, 0xc4, 0x83, 0xe2, 0xc2, 0xb4, 0x30, 0x5a, 0xf8, 0xe9, - 0xfb, 0x0b, 0x4b, 0xb2, 0xb6, 0x57, 0x53, 0xab, 0xd7, 0x79, 0x8c, 0x49, 0xe8, 0x4a, 0xdc, 0xc6, - 0x89, 0xcf, 0x6f, 0x57, 0x26, 0xfe, 0xb8, 0x5d, 0x99, 0xf8, 0xf4, 0xe1, 0x9d, 0x73, 0x72, 0xd3, - 0x2a, 0x83, 0xd3, 0xba, 0xdc, 0x5c, 0xc4, 0x9a, 0x94, 0x30, 0x64, 0x1d, 0x1a, 0xe0, 0xd9, 0x2a, - 0x0b, 0xaf, 0xb7, 0xbc, 0x08, 0xf3, 0x0c, 0x50, 0xc5, 0xcc, 0x43, 0x75, 0xd8, 0xc6, 0xb4, 0x15, - 0x9b, 0x97, 0xc0, 0x1c, 0x13, 0x52, 0x8e, 0x62, 0xc1, 0xc1, 0xb0, 0x58, 0x3a, 0x50, 0x73, 0x17, - 0x2c, 0x44, 0x39, 0x3b, 0x82, 0x9b, 0xf9, 0xf5, 0xf3, 0x36, 0xf6, 0x7c, 0x3b, 0x5f, 0x60, 0x3b, - 0x57, 0xd2, 0xf6, 0x9a, 0x9d, 0xf7, 0xed, 0x76, 0x59, 0xe8, 0xad, 0xc7, 0x54, 0x6f, 0x3d, 0x36, - 0x4e, 0xe5, 0x19, 0xe8, 0x84, 0x62, 0x9d, 0x05, 0xcf, 0x0f, 0xcd, 0x51, 0xb1, 0xf1, 0xe3, 0xa4, - 0x86, 0x8d, 0x6d, 0xda, 0xf2, 0x1a, 0xe8, 0x06, 0xe5, 0x98, 0x84, 0x8f, 0xcd, 0x46, 0x0d, 0x2c, - 0x07, 0xad, 0x66, 0x03, 0xfb, 0x90, 0xa3, 0x5a, 0x9b, 0x72, 0x54, 0xcb, 0xda, 0x54, 0x12, 0x73, - 0x36, 0xcf, 0x83, 0x68, 0x64, 0x7b, 0x3b, 0x53, 0xb8, 0x41, 0x39, 0x7a, 0x5d, 0xc2, 0xdd, 0x93, - 0x81, 0x6e, 0xdb, 0xfc, 0x00, 0x2c, 0x63, 0x72, 0x33, 0x86, 0x7e, 0x72, 0x1c, 0x6b, 0x5e, 0x83, - 0xfa, 0x7b, 0xb5, 0x3a, 0x82, 0x01, 0x8a, 0x05, 0x51, 0xf3, 0xeb, 0x2f, 0x8c, 0x62, 0xfe, 0x0d, - 0x81, 0x76, 0x4f, 0x76, 0xcc, 0x6c, 0x26, 0x56, 0xd2, 0xed, 0x5e, 0xf2, 0xa7, 0xff, 0x15, 0xf9, - 0x79, 0x4a, 0x15, 0xf9, 0x5f, 0x1b, 0xe0, 0x78, 0x95, 0x85, 0x6f, 0x37, 0x03, 0xc8, 0xd1, 0x2e, - 0x8c, 0x61, 0xc4, 0x12, 0xba, 0x61, 0x8b, 0xd7, 0x69, 0x8c, 0xf9, 0xc1, 0x68, 0xba, 0x15, 0xd4, - 0xbc, 0x04, 0x66, 0x9b, 0xc2, 0x82, 0x64, 0xb7, 0x60, 0xf7, 0xde, 0xc0, 0x76, 0xea, 0x61, 0x73, - 0xfa, 0xee, 0xfd, 0xca, 0x84, 0x2b, 0xd1, 0x1b, 0xc7, 0x44, 0xf0, 0xca, 0x8e, 0x55, 0x04, 0xcb, - 0x3d, 0x21, 0xa9, 0x70, 0x9b, 0x60, 0xb1, 0xca, 0x42, 0x17, 0x45, 0xb4, 0x8d, 0xb2, 0xbc, 0x46, - 0x5f, 0x19, 0x36, 0x98, 0xa1, 0xfb, 0xc9, 0xa9, 0x9e, 0x1c, 0x91, 0x4c, 0x0a, 0xdb, 0x00, 0x49, - 0x40, 0xe9, 0x6f, 0xeb, 0x19, 0x50, 0xec, 0xf3, 0xa8, 0xc2, 0xf9, 0x72, 0x4a, 0xc4, 0xb3, 0x15, - 0x23, 0xc8, 0x3b, 0xf1, 0x3c, 0x6e, 0xbb, 0x16, 0xc1, 0x51, 0xbf, 0x0e, 0x31, 0x49, 0x92, 0x10, - 0x91, 0xba, 0x47, 0xc4, 0x7a, 0x27, 0x30, 0xb7, 0xc1, 0xd1, 0x08, 0x71, 0x18, 0x40, 0x0e, 0x65, - 0x67, 0x59, 0xfd, 0xe4, 0xaa, 0x53, 0x26, 0x91, 0x92, 0x66, 0xa5, 0x69, 0x52, 0x50, 0xc4, 0x04, - 0x73, 0x0c, 0x1b, 0xf8, 0x23, 0xf1, 0x82, 0xd4, 0x44, 0x05, 0x10, 0x47, 0x31, 0x13, 0xcd, 0x35, - 0xbf, 0xbe, 0x3e, 0xd8, 0xec, 0x4e, 0x97, 0xea, 0xae, 0xd2, 0x74, 0x0b, 0x78, 0x80, 0xc4, 0x7c, - 0x0f, 0xe4, 0x1a, 0x3b, 0xef, 0x6c, 0x46, 0x9e, 0x8e, 0x3e, 0x67, 0x3b, 0x0a, 0x9e, 0x73, 0xb0, - 0x84, 0x35, 0xbb, 0xb2, 0x6d, 0x3a, 0x3d, 0x7f, 0x45, 0x54, 0xaa, 0xbb, 0x16, 0x59, 0xa5, 0x46, - 0xf6, 0x88, 0xf5, 0x7b, 0x5a, 0xca, 0xb4, 0xeb, 0x54, 0x29, 0x55, 0xe7, 0x18, 0x63, 0x75, 0x4e, - 0xaf, 0x9b, 0xc9, 0xbe, 0x56, 0xdc, 0x06, 0x8b, 0x04, 0xed, 0xd7, 0x04, 0xba, 0x26, 0x1f, 0xaa, - 0xf4, 0x25, 0x1a, 0x62, 0xfc, 0x38, 0x41, 0xfb, 0x6f, 0x25, 0x1a, 0x72, 0xdb, 0x7c, 0x2d, 0xd7, - 0x0e, 0xd3, 0xe3, 0xb6, 0xc3, 0xb8, 0x8d, 0x30, 0xf3, 0x3f, 0x34, 0xc2, 0x0a, 0x58, 0x48, 0xd2, - 0x56, 0xed, 0x3d, 0x2b, 0xda, 0x1b, 0x10, 0xb4, 0xbf, 0x25, 0x3b, 0x7c, 0x60, 0xab, 0x1c, 0xf9, - 0x0f, 0x5a, 0xa5, 0xff, 0x40, 0x77, 0xd7, 0x59, 0x1d, 0xe8, 0x1f, 0x0c, 0x70, 0xaa, 0xca, 0xc2, - 0x6b, 0x2d, 0x12, 0x64, 0xb2, 0x6b, 0x08, 0xed, 0x52, 0xda, 0xc8, 0xcd, 0x06, 0xc6, 0x78, 0xb3, - 0x81, 0xae, 0x19, 0xe6, 0xba, 0x9a, 0xe1, 0x0a, 0x98, 0x85, 0x11, 0x6d, 0x11, 0x2e, 0xcf, 0x74, - 0xd1, 0x96, 0xf6, 0x92, 0x69, 0xd4, 0x96, 0xd3, 0xa8, 0xbd, 0x45, 0x31, 0xd9, 0x9c, 0x4b, 0x8e, - 0xf2, 0xb7, 0x0f, 0xef, 0x9c, 0x33, 0x5c, 0xa9, 0xa3, 0x1f, 0x3d, 0x56, 0x40, 0x59, 0x1f, 0xbf, - 0x4a, 0xf1, 0x4f, 0x03, 0x94, 0xaa, 0x2c, 0x7c, 0x07, 0xf3, 0x7a, 0x10, 0xc3, 0xfd, 0x27, 0x90, - 0x66, 0x3d, 0x97, 0xe6, 0xd4, 0xf0, 0x34, 0x5f, 0x4d, 0xd2, 0xfc, 0xee, 0xd7, 0xca, 0x6a, 0x88, - 0x79, 0xbd, 0xe5, 0xd9, 0x3e, 0x8d, 0xe4, 0x6c, 0x2d, 0xff, 0x5d, 0x60, 0xc1, 0x5e, 0x3a, 0x72, - 0x0a, 0x05, 0x36, 0x06, 0x25, 0x5f, 0x18, 0xc0, 0x1a, 0x9c, 0xb0, 0xba, 0x21, 0x7c, 0x15, 0xa5, - 0x31, 0x2a, 0xca, 0x8b, 0x8f, 0x1a, 0x65, 0x16, 0xa0, 0xf5, 0x8d, 0x21, 0xde, 0xb6, 0xeb, 0xfb, - 0x08, 0x35, 0x9f, 0x00, 0xf3, 0xa7, 0xc0, 0x6c, 0x80, 0x08, 0x8d, 0x98, 0x60, 0x7e, 0xce, 0x95, - 0x2b, 0x3d, 0x4f, 0x67, 0x40, 0x65, 0x40, 0x68, 0x19, 0x47, 0xeb, 0x7f, 0x1f, 0x05, 0x53, 0x55, - 0x16, 0x9a, 0x7b, 0x60, 0xb1, 0x7f, 0x72, 0xd7, 0x1c, 0x51, 0xdd, 0x14, 0x5c, 0xb2, 0xc7, 0xc3, - 0xa9, 0xc2, 0x7c, 0x66, 0x80, 0xd2, 0x90, 0x51, 0xd9, 0xd1, 0x9a, 0x1b, 0xac, 0x50, 0xba, 0xfc, - 0x88, 0x0a, 0x43, 0x02, 0xe9, 0x9a, 0x52, 0xc7, 0x09, 0x24, 0xaf, 0x30, 0x56, 0x20, 0xba, 0xa1, - 0xcd, 0xf4, 0xc0, 0xb1, 0x9e, 0x91, 0xe3, 0x39, 0xad, 0xa9, 0x6e, 0x50, 0xe9, 0xa5, 0x31, 0x40, - 0x79, 0x1f, 0x3d, 0x6f, 0xa1, 0xde, 0x47, 0x37, 0x68, 0x80, 0x0f, 0xfd, 0x6d, 0x9b, 0xf8, 0xe8, - 0x19, 0xe5, 0xf4, 0x3e, 0xba, 0x41, 0x03, 0x7c, 0xe8, 0x47, 0x34, 0xf3, 0x7d, 0xb0, 0xd0, 0x35, - 0xdc, 0x9e, 0x19, 0x12, 0x60, 0x0a, 0x29, 0xbd, 0x38, 0x12, 0xa2, 0xac, 0x7f, 0x08, 0x4e, 0xe8, - 0xde, 0x8a, 0x55, 0xad, 0x05, 0x0d, 0xb2, 0x74, 0x71, 0x5c, 0xa4, 0x72, 0xf9, 0x31, 0x58, 0x1e, - 0x74, 0x77, 0x9f, 0xd7, 0x1a, 0x1b, 0x80, 0x2e, 0xbd, 0xf2, 0x28, 0x68, 0xe5, 0x9e, 0x83, 0x25, - 0xed, 0xed, 0xa5, 0x27, 0x4d, 0x07, 0x2d, 0xad, 0x8d, 0x0d, 0xcd, 0xbc, 0x96, 0x66, 0x3e, 0x49, - 0xee, 0xf9, 0xcd, 0x9d, 0xbb, 0x87, 0x65, 0xe3, 0xde, 0x61, 0xd9, 0xf8, 0xed, 0xb0, 0x6c, 0x7c, - 0xf5, 0xa0, 0x3c, 0x71, 0xef, 0x41, 0x79, 0xe2, 0xe7, 0x07, 0xe5, 0x89, 0x77, 0x9d, 0xdc, 0x55, - 0x0c, 0x1b, 0x0d, 0x4c, 0x3c, 0xcc, 0x99, 0x23, 0xbe, 0x42, 0xdc, 0x72, 0xba, 0x3f, 0x46, 0x88, - 0x7b, 0xd9, 0x9b, 0x15, 0xdf, 0x21, 0x5e, 0xfe, 0x27, 0x00, 0x00, 0xff, 0xff, 0x65, 0x47, 0x0d, - 0xe3, 0x41, 0x12, 0x00, 0x00, + 0x14, 0xce, 0xe6, 0xaf, 0xcd, 0x24, 0xb4, 0x64, 0x9b, 0x36, 0xf6, 0x52, 0xec, 0x74, 0x11, 0x34, + 0x94, 0x76, 0xb7, 0x09, 0xd0, 0x4a, 0x51, 0x85, 0xd4, 0x24, 0x54, 0x44, 0xc8, 0x22, 0xda, 0x8a, + 0x22, 0x01, 0xc2, 0x9a, 0xdd, 0x9d, 0xae, 0x47, 0xf1, 0xce, 0x98, 0x9d, 0xb1, 0x5d, 0x23, 0x21, + 0x21, 0x0e, 0x08, 0x38, 0xc1, 0x91, 0x5b, 0x8f, 0x88, 0x53, 0x0f, 0x9c, 0x39, 0xf7, 0x58, 0x38, + 0x21, 0x0e, 0x05, 0xa5, 0x12, 0xe5, 0xc4, 0x81, 0x3b, 0x12, 0xda, 0xd9, 0xd9, 0xf1, 0xda, 0x5e, + 0xff, 0xb4, 0x40, 0x2f, 0x89, 0x67, 0xde, 0xf7, 0xfe, 0xbe, 0xf7, 0x66, 0xe6, 0x69, 0x41, 0xb1, + 0x05, 0x21, 0xb3, 0x1b, 0x11, 0x6d, 0x61, 0x1f, 0x45, 0x76, 0x6b, 0xc3, 0xe6, 0xb7, 0xac, 0x46, + 0x44, 0x39, 0xd5, 0x9f, 0x8e, 0x45, 0x56, 0x2a, 0xb2, 0x5a, 0x1b, 0xc6, 0x32, 0x0c, 0x31, 0xa1, + 0xb6, 0xf8, 0x9b, 0x80, 0x8c, 0x92, 0x47, 0x59, 0x48, 0x99, 0xed, 0x42, 0x86, 0xec, 0xd6, 0x86, + 0x8b, 0x38, 0xdc, 0xb0, 0x3d, 0x8a, 0x89, 0x94, 0xaf, 0x4a, 0x79, 0xc8, 0x82, 0xd8, 0x78, 0xc8, + 0x02, 0x29, 0x28, 0x26, 0x82, 0xaa, 0x58, 0xd9, 0xc9, 0x42, 0x8a, 0x56, 0x02, 0x1a, 0xd0, 0x64, + 0x3f, 0xfe, 0x25, 0x77, 0x4f, 0x07, 0x94, 0x06, 0x75, 0x64, 0xc3, 0x06, 0xb6, 0x21, 0x21, 0x94, + 0x43, 0x8e, 0x29, 0x49, 0x75, 0x8a, 0x52, 0x2a, 0x56, 0x6e, 0xf3, 0xa6, 0x0d, 0x49, 0x27, 0x0d, + 0xb1, 0x5f, 0xe4, 0x37, 0x23, 0xa1, 0x2b, 0xe5, 0xe5, 0x7e, 0x39, 0xc7, 0x21, 0x62, 0x1c, 0x86, + 0x8d, 0x14, 0x80, 0x5d, 0xcf, 0xf6, 0x68, 0x84, 0x6c, 0xaf, 0x8e, 0x11, 0xe1, 0x71, 0x22, 0xc9, + 0x2f, 0x09, 0xb0, 0x63, 0x40, 0x1d, 0x07, 0x35, 0x9e, 0x6c, 0x33, 0x9b, 0x23, 0xe2, 0xa3, 0x28, + 0xc4, 0x09, 0xb8, 0xbb, 0x4a, 0x2d, 0x66, 0xe4, 0xbc, 0xd3, 0x40, 0xcc, 0x46, 0x31, 0xc9, 0xc4, + 0x43, 0x29, 0x60, 0xa0, 0x2c, 0xaa, 0x0e, 0x02, 0x60, 0xfe, 0xa2, 0x81, 0x95, 0x0a, 0x0b, 0xae, + 0x32, 0x86, 0x03, 0xb2, 0x43, 0x09, 0x6b, 0x86, 0x28, 0x7a, 0x13, 0x75, 0xf4, 0x32, 0x58, 0xf4, + 0xe4, 0xb2, 0x8a, 0xfd, 0x82, 0xb6, 0xa6, 0xad, 0xcf, 0x3a, 0x20, 0xdd, 0xda, 0xf3, 0xf5, 0xcb, + 0xe0, 0xa9, 0xd4, 0x56, 0x15, 0xfa, 0x7e, 0x54, 0x98, 0x5e, 0xd3, 0xd6, 0x17, 0xb6, 0xf5, 0xbf, + 0xee, 0x97, 0x8f, 0x75, 0x60, 0x58, 0xdf, 0x32, 0xe3, 0x5d, 0xc4, 0x98, 0xe9, 0x2c, 0xa5, 0xc0, + 0xab, 0xbe, 0x1f, 0xe9, 0x67, 0xc0, 0x92, 0xb2, 0x7c, 0x80, 0x3a, 0x85, 0x99, 0x58, 0xcf, 0x51, + 0xde, 0x62, 0xe7, 0x17, 0xc1, 0x7c, 0x1c, 0x0f, 0x8a, 0x0a, 0xb3, 0xc2, 0x68, 0xe1, 0xa7, 0xef, + 0x2f, 0xac, 0xc8, 0xda, 0x5e, 0x4d, 0xac, 0x5e, 0xe7, 0x11, 0x26, 0x81, 0x23, 0x71, 0x5b, 0x27, + 0x3e, 0xbf, 0x5d, 0x9e, 0xfa, 0xe3, 0x76, 0x79, 0xea, 0xd3, 0x87, 0x77, 0xce, 0xc9, 0x4d, 0xb3, + 0x04, 0x4e, 0xe7, 0xe5, 0xe6, 0x20, 0xd6, 0xa0, 0x84, 0x21, 0xf3, 0x50, 0x03, 0xcf, 0x56, 0x58, + 0x70, 0xbd, 0xe9, 0x86, 0x98, 0xa7, 0x80, 0x0a, 0x66, 0x2e, 0xaa, 0xc1, 0x16, 0xa6, 0xcd, 0x48, + 0xbf, 0x04, 0x16, 0x98, 0x90, 0x72, 0x14, 0x09, 0x0e, 0x46, 0xc5, 0xd2, 0x85, 0xea, 0xfb, 0x60, + 0x29, 0xcc, 0xd8, 0x11, 0xdc, 0x2c, 0x6e, 0x9e, 0xb7, 0xb0, 0xeb, 0x59, 0xd9, 0x02, 0x5b, 0x99, + 0x92, 0xb6, 0x36, 0xac, 0xac, 0x6f, 0xa7, 0xc7, 0x42, 0x7f, 0x3d, 0x66, 0xfa, 0xeb, 0xb1, 0x75, + 0x2a, 0xcb, 0x40, 0x37, 0x14, 0xf3, 0x2c, 0x78, 0x7e, 0x64, 0x8e, 0x8a, 0x8d, 0x1f, 0xa7, 0x73, + 0xd8, 0xd8, 0xa5, 0x4d, 0xb7, 0x8e, 0x6e, 0x50, 0x8e, 0x49, 0xf0, 0xd8, 0x6c, 0x54, 0xc1, 0xaa, + 0xdf, 0x6c, 0xd4, 0xb1, 0x07, 0x39, 0xaa, 0xb6, 0x28, 0x47, 0xd5, 0xb4, 0x4d, 0x25, 0x31, 0x67, + 0xb3, 0x3c, 0x88, 0x46, 0xb6, 0x76, 0x53, 0x85, 0x1b, 0x94, 0xa3, 0xd7, 0x25, 0xdc, 0x39, 0xe9, + 0xe7, 0x6d, 0xeb, 0x1f, 0x80, 0x55, 0x4c, 0x6e, 0x46, 0xd0, 0x8b, 0x8f, 0x63, 0xd5, 0xad, 0x53, + 0xef, 0xa0, 0x5a, 0x43, 0xd0, 0x47, 0x91, 0x20, 0x6a, 0x71, 0xf3, 0x85, 0x71, 0xcc, 0xbf, 0x21, + 0xd0, 0xce, 0xc9, 0xae, 0x99, 0xed, 0xd8, 0x4a, 0xb2, 0xdd, 0x4f, 0xfe, 0xec, 0xbf, 0x22, 0x3f, + 0x4b, 0xa9, 0x22, 0xff, 0x6b, 0x0d, 0x1c, 0xaf, 0xb0, 0xe0, 0xed, 0x86, 0x0f, 0x39, 0xda, 0x87, + 0x11, 0x0c, 0x59, 0x4c, 0x37, 0x6c, 0xf2, 0x1a, 0x8d, 0x30, 0xef, 0x8c, 0xa7, 0x5b, 0x41, 0xf5, + 0x4b, 0x60, 0xbe, 0x21, 0x2c, 0x48, 0x76, 0x0b, 0x56, 0xff, 0x0d, 0x6c, 0x25, 0x1e, 0xb6, 0x67, + 0xef, 0xde, 0x2f, 0x4f, 0x39, 0x12, 0xbd, 0x75, 0x4c, 0x04, 0xaf, 0xec, 0x98, 0x45, 0xb0, 0xda, + 0x17, 0x92, 0x0a, 0xb7, 0x01, 0x96, 0x2b, 0x2c, 0x70, 0x50, 0x48, 0x5b, 0x28, 0xcd, 0x6b, 0xfc, + 0x95, 0x61, 0x81, 0x39, 0xda, 0x8e, 0x4f, 0xf5, 0xf4, 0x98, 0x64, 0x12, 0xd8, 0x16, 0x88, 0x03, + 0x4a, 0x7e, 0x9b, 0xcf, 0x80, 0xe2, 0x80, 0x47, 0x15, 0xce, 0x97, 0x33, 0x22, 0x9e, 0x9d, 0x08, + 0x41, 0xde, 0x8d, 0xe7, 0x71, 0xdb, 0xb5, 0x08, 0x8e, 0x7a, 0x35, 0x88, 0x49, 0x9c, 0x84, 0x88, + 0xd4, 0x39, 0x22, 0xd6, 0x7b, 0xbe, 0xbe, 0x0b, 0x8e, 0x86, 0x88, 0x43, 0x1f, 0x72, 0x28, 0x3b, + 0xcb, 0x1c, 0x24, 0x57, 0x9d, 0x32, 0x89, 0x94, 0x34, 0x2b, 0x4d, 0x9d, 0x82, 0x22, 0x26, 0x98, + 0x63, 0x58, 0xc7, 0x1f, 0x89, 0x17, 0xa4, 0x2a, 0x2a, 0x80, 0x38, 0x8a, 0x98, 0x68, 0xae, 0xc5, + 0xcd, 0xcd, 0xe1, 0x66, 0xf7, 0x7a, 0x54, 0xf7, 0x95, 0xa6, 0x53, 0xc0, 0x43, 0x24, 0xfa, 0x7b, + 0x20, 0xd3, 0xd8, 0x59, 0x67, 0x73, 0xf2, 0x74, 0x0c, 0x38, 0xdb, 0x53, 0xf0, 0x8c, 0x83, 0x15, + 0x9c, 0xb3, 0x2b, 0xdb, 0xa6, 0xdb, 0xf3, 0x57, 0x44, 0xa5, 0x7a, 0x6b, 0x91, 0x56, 0x6a, 0x6c, + 0x8f, 0x98, 0xbf, 0x27, 0xa5, 0x4c, 0xba, 0x4e, 0x95, 0x52, 0x75, 0x8e, 0x36, 0x51, 0xe7, 0xf4, + 0xbb, 0x99, 0x1e, 0x68, 0xc5, 0x5d, 0xb0, 0x4c, 0x50, 0xbb, 0x2a, 0xd0, 0x55, 0xf9, 0x50, 0x25, + 0x2f, 0xd1, 0x08, 0xe3, 0xc7, 0x09, 0x6a, 0xbf, 0x15, 0x6b, 0xc8, 0x6d, 0xfd, 0xb5, 0x4c, 0x3b, + 0xcc, 0x4e, 0xda, 0x0e, 0x93, 0x36, 0xc2, 0xdc, 0xff, 0xd0, 0x08, 0x6b, 0x60, 0x29, 0x4e, 0x5b, + 0xb5, 0xf7, 0xbc, 0x68, 0x6f, 0x40, 0x50, 0x7b, 0x47, 0x76, 0xf8, 0xd0, 0x56, 0x39, 0xf2, 0x1f, + 0xb4, 0xca, 0xe0, 0x81, 0xee, 0xad, 0xb3, 0x3a, 0xd0, 0x3f, 0x68, 0xe0, 0x54, 0x85, 0x05, 0xd7, + 0x9a, 0xc4, 0x4f, 0x65, 0xd7, 0x10, 0xda, 0xa7, 0xb4, 0x9e, 0x99, 0x0d, 0xb4, 0xc9, 0x66, 0x83, + 0xf1, 0xcd, 0x70, 0x05, 0xcc, 0xc3, 0x90, 0x36, 0x09, 0x97, 0x67, 0xba, 0x68, 0x49, 0x7b, 0xf1, + 0x34, 0x6a, 0xc9, 0x69, 0xd4, 0xda, 0xa1, 0x98, 0x6c, 0x2f, 0xc4, 0x47, 0xf9, 0xdb, 0x87, 0x77, + 0xce, 0x69, 0x8e, 0xd4, 0xc9, 0x1f, 0x3d, 0xd6, 0x40, 0x29, 0x3f, 0x7e, 0x95, 0xe2, 0x9f, 0x1a, + 0x30, 0x2a, 0x2c, 0x78, 0x07, 0xf3, 0x9a, 0x1f, 0xc1, 0xf6, 0x13, 0x48, 0xb3, 0x96, 0x49, 0x73, + 0x66, 0x74, 0x9a, 0xaf, 0xc6, 0x69, 0x7e, 0xf7, 0x6b, 0x79, 0x3d, 0xc0, 0xbc, 0xd6, 0x74, 0x2d, + 0x8f, 0x86, 0x72, 0xb6, 0x96, 0xff, 0x2e, 0x30, 0xff, 0x20, 0x19, 0x39, 0x85, 0x02, 0x9b, 0x80, + 0x92, 0x2f, 0x34, 0x60, 0x0e, 0x4f, 0x58, 0xdd, 0x10, 0x9e, 0x8a, 0x52, 0x1b, 0x17, 0xe5, 0xc5, + 0x47, 0x8d, 0x32, 0x0d, 0xd0, 0xfc, 0x46, 0x13, 0x6f, 0xdb, 0xf5, 0x36, 0x42, 0x8d, 0x27, 0xc0, + 0xfc, 0x29, 0x30, 0xef, 0x23, 0x42, 0x43, 0x26, 0x98, 0x5f, 0x70, 0xe4, 0x2a, 0x9f, 0xa7, 0x33, + 0xa0, 0x3c, 0x24, 0xb4, 0x94, 0xa3, 0xcd, 0xbf, 0x8f, 0x82, 0x99, 0x0a, 0x0b, 0xf4, 0x03, 0xb0, + 0x3c, 0x38, 0xb9, 0xe7, 0x1c, 0xd1, 0xbc, 0x29, 0xd8, 0xb0, 0x26, 0xc3, 0xa9, 0xc2, 0x7c, 0xa6, + 0x01, 0x63, 0xc4, 0xa8, 0x6c, 0xe7, 0x9a, 0x1b, 0xae, 0x60, 0x5c, 0x7e, 0x44, 0x85, 0x11, 0x81, + 0xf4, 0x4c, 0xa9, 0x93, 0x04, 0x92, 0x55, 0x98, 0x28, 0x90, 0xbc, 0xa1, 0x4d, 0x77, 0xc1, 0xb1, + 0xbe, 0x91, 0xe3, 0xb9, 0x5c, 0x53, 0xbd, 0x20, 0xe3, 0xa5, 0x09, 0x40, 0x59, 0x1f, 0x7d, 0x6f, + 0x61, 0xbe, 0x8f, 0x5e, 0xd0, 0x10, 0x1f, 0xf9, 0xb7, 0x6d, 0xec, 0xa3, 0x6f, 0x94, 0xcb, 0xf7, + 0xd1, 0x0b, 0x1a, 0xe2, 0x23, 0x7f, 0x44, 0xd3, 0xdf, 0x07, 0x4b, 0x3d, 0xc3, 0xed, 0x99, 0x11, + 0x01, 0x26, 0x10, 0xe3, 0xc5, 0xb1, 0x10, 0x65, 0xfd, 0x43, 0x70, 0x22, 0xef, 0xad, 0x58, 0xcf, + 0xb5, 0x90, 0x83, 0x34, 0x2e, 0x4e, 0x8a, 0x54, 0x2e, 0x3f, 0x06, 0xab, 0xc3, 0xee, 0xee, 0xf3, + 0xb9, 0xc6, 0x86, 0xa0, 0x8d, 0x57, 0x1e, 0x05, 0xad, 0xdc, 0x73, 0xb0, 0x92, 0x7b, 0x7b, 0xe5, + 0x93, 0x96, 0x07, 0x35, 0x36, 0x26, 0x86, 0xa6, 0x5e, 0x8d, 0xb9, 0x4f, 0xe2, 0x7b, 0x7e, 0x7b, + 0xef, 0xee, 0x61, 0x49, 0xbb, 0x77, 0x58, 0xd2, 0x7e, 0x3b, 0x2c, 0x69, 0x5f, 0x3d, 0x28, 0x4d, + 0xdd, 0x7b, 0x50, 0x9a, 0xfa, 0xf9, 0x41, 0x69, 0xea, 0x5d, 0x3b, 0x73, 0x15, 0xc3, 0x7a, 0x1d, + 0x13, 0x17, 0x73, 0x66, 0x8b, 0xaf, 0x10, 0xb7, 0xec, 0xde, 0x8f, 0x11, 0xe2, 0x5e, 0x76, 0xe7, + 0xc5, 0x77, 0x88, 0x97, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x54, 0x53, 0x7a, 0x78, 0x41, 0x12, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2082,12 +2082,10 @@ func (m *MsgFundConsumerFeePool) MarshalToSizedBuffer(dAtA []byte) (int, error) } i-- dAtA[i] = 0x1a - if len(m.ConsumerId) > 0 { - i -= len(m.ConsumerId) - copy(dAtA[i:], m.ConsumerId) - i = encodeVarintTx(dAtA, i, uint64(len(m.ConsumerId))) + if m.ConsumerId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ConsumerId)) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x10 } if len(m.Signer) > 0 { i -= len(m.Signer) @@ -2156,12 +2154,10 @@ func (m *MsgWithdrawConsumerFeePool) MarshalToSizedBuffer(dAtA []byte) (int, err dAtA[i] = 0x1a } } - if len(m.ConsumerId) > 0 { - i -= len(m.ConsumerId) - copy(dAtA[i:], m.ConsumerId) - i = encodeVarintTx(dAtA, i, uint64(len(m.ConsumerId))) + if m.ConsumerId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ConsumerId)) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x10 } if len(m.Signer) > 0 { i -= len(m.Signer) @@ -2239,12 +2235,10 @@ func (m *MsgSweepConsumerFeePool) MarshalToSizedBuffer(dAtA []byte) (int, error) dAtA[i] = 0x1a } } - if len(m.ConsumerId) > 0 { - i -= len(m.ConsumerId) - copy(dAtA[i:], m.ConsumerId) - i = encodeVarintTx(dAtA, i, uint64(len(m.ConsumerId))) + if m.ConsumerId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ConsumerId)) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x10 } if len(m.Signer) > 0 { i -= len(m.Signer) @@ -2528,9 +2522,8 @@ func (m *MsgFundConsumerFeePool) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ConsumerId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if m.ConsumerId != 0 { + n += 1 + sovTx(uint64(m.ConsumerId)) } l = m.Amount.Size() n += 1 + l + sovTx(uint64(l)) @@ -2556,9 +2549,8 @@ func (m *MsgWithdrawConsumerFeePool) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ConsumerId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if m.ConsumerId != 0 { + n += 1 + sovTx(uint64(m.ConsumerId)) } if len(m.Amount) > 0 { for _, e := range m.Amount { @@ -2594,9 +2586,8 @@ func (m *MsgSweepConsumerFeePool) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ConsumerId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if m.ConsumerId != 0 { + n += 1 + sovTx(uint64(m.ConsumerId)) } if len(m.Denoms) > 0 { for _, s := range m.Denoms { @@ -4236,10 +4227,10 @@ func (m *MsgFundConsumerFeePool) Unmarshal(dAtA []byte) error { m.Signer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 2 { + if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) } - var stringLen uint64 + m.ConsumerId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4249,24 +4240,11 @@ func (m *MsgFundConsumerFeePool) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.ConsumerId |= uint64(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ConsumerId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) @@ -4433,10 +4411,10 @@ func (m *MsgWithdrawConsumerFeePool) Unmarshal(dAtA []byte) error { m.Signer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 2 { + if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) } - var stringLen uint64 + m.ConsumerId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4446,24 +4424,11 @@ func (m *MsgWithdrawConsumerFeePool) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.ConsumerId |= uint64(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ConsumerId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) @@ -4665,10 +4630,10 @@ func (m *MsgSweepConsumerFeePool) Unmarshal(dAtA []byte) error { m.Signer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 2 { + if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field ConsumerId", wireType) } - var stringLen uint64 + m.ConsumerId = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4678,24 +4643,11 @@ func (m *MsgSweepConsumerFeePool) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.ConsumerId |= uint64(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ConsumerId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Denoms", wireType) From b57319cd24ccea1e622d292e8063c116e94a33e0 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Fri, 22 May 2026 16:15:30 +0200 Subject: [PATCH 14/18] various fixes --- docs/consumer-fee-pool.md | 26 ++++ x/vaas/provider/client/cli/tx.go | 21 ++- .../keeper/consumer_lifecycle_test.go | 88 +++++++++++- x/vaas/provider/keeper/fee_pool_shares.go | 48 ++++--- .../provider/keeper/fee_pool_shares_test.go | 66 ++++----- x/vaas/provider/keeper/genesis.go | 110 ++++++++++----- x/vaas/provider/keeper/genesis_test.go | 6 +- x/vaas/provider/keeper/grpc_query.go | 132 +++++++++++++++--- x/vaas/provider/keeper/grpc_query_test.go | 44 +++++- x/vaas/provider/keeper/keeper.go | 11 +- x/vaas/provider/keeper/msg_server.go | 73 +++++----- x/vaas/provider/keeper/msg_server_test.go | 68 +++++++-- x/vaas/provider/keeper/send_restriction.go | 7 +- .../provider/keeper/send_restriction_test.go | 115 +++++++++++++++ x/vaas/provider/types/errors.go | 2 + x/vaas/provider/types/genesis.go | 49 +++++++ x/vaas/provider/types/genesis_test.go | 110 +++++++++++++++ x/vaas/provider/types/msg.go | 5 + 18 files changed, 812 insertions(+), 169 deletions(-) diff --git a/docs/consumer-fee-pool.md b/docs/consumer-fee-pool.md index 547ea2d..ed417fe 100644 --- a/docs/consumer-fee-pool.md +++ b/docs/consumer-fee-pool.md @@ -30,6 +30,11 @@ provider, IBC-transfer funds into the ICA's account, and have the controller side send a `MsgFundConsumerFeePool` from the ICA. The ICA becomes the depositor of record. +A direct IBC transfer addressed to a fee pool fails losslessly: the bank +send-restriction rejects the receive on the provider, the packet acks with an +error, and the source-chain transfer module refunds the sender via standard +IBC semantics. The funds are not lost, just not deposited. + ### Funding from the community pool A governance proposal containing `MsgFundConsumerFeePool` with the gov @@ -90,3 +95,24 @@ silently lost. query the community pool's holdings. - `vaas query consumer-fee-pool-claims ` — paginated list of all depositors with non-zero claims. + +## CLI examples + + # fund a pool with 1000uphoton from your key + vaas tx fund-consumer-fee-pool 5 1000uphoton --from operator + + # withdraw a mix of denoms from your share in pool 5 + vaas tx withdraw-consumer-fee-pool 5 250uphoton,30uatone --from operator + + # owner sweeps all denoms with shares or balance + vaas tx sweep-consumer-fee-pool 5 --from owner + + # owner sweeps only the listed denoms (comma-separated or repeated flag) + vaas tx sweep-consumer-fee-pool 5 --denoms=uphoton,uatone --from owner + vaas tx sweep-consumer-fee-pool 5 --denoms=uphoton --denoms=uatone --from owner + + # query a single depositor's claim + vaas query consumer-fee-pool-claim 5 cosmos1... + + # paginated list of all depositors with non-zero claims + vaas query consumer-fee-pool-claims 5 --page 1 --limit 100 diff --git a/x/vaas/provider/client/cli/tx.go b/x/vaas/provider/client/cli/tx.go index 71487a9..88e23e9 100644 --- a/x/vaas/provider/client/cli/tx.go +++ b/x/vaas/provider/client/cli/tx.go @@ -483,10 +483,14 @@ func NewFundConsumerFeePoolCmd() *cobra.Command { ConsumerId: consumerId, Amount: amount, } + if err := msg.ValidateBasic(); err != nil { + return err + } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } flags.AddTxFlagsToCmd(cmd) + _ = cmd.MarkFlagRequired(flags.FlagFrom) return cmd } @@ -513,10 +517,14 @@ func NewWithdrawConsumerFeePoolCmd() *cobra.Command { ConsumerId: consumerId, Amount: coins, } + if err := msg.ValidateBasic(); err != nil { + return err + } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } flags.AddTxFlagsToCmd(cmd) + _ = cmd.MarkFlagRequired(flags.FlagFrom) return cmd } @@ -534,20 +542,21 @@ func NewSweepConsumerFeePoolCmd() *cobra.Command { if err != nil { return err } - denomsCSV, _ := cmd.Flags().GetString("denoms") - var denoms []string - if strings.TrimSpace(denomsCSV) != "" { - denoms = strings.Split(denomsCSV, ",") - } + denoms, _ := cmd.Flags().GetStringSlice("denoms") msg := &types.MsgSweepConsumerFeePool{ Signer: clientCtx.GetFromAddress().String(), ConsumerId: consumerId, Denoms: denoms, } + if err := msg.ValidateBasic(); err != nil { + return err + } return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } - cmd.Flags().String("denoms", "", "comma-separated denoms to sweep (default: all denoms with shares or balance)") + cmd.Flags().StringSlice("denoms", nil, + "denoms to sweep; repeat flag or pass comma-separated (default: all denoms with shares or balance)") flags.AddTxFlagsToCmd(cmd) + _ = cmd.MarkFlagRequired(flags.FlagFrom) return cmd } diff --git a/x/vaas/provider/keeper/consumer_lifecycle_test.go b/x/vaas/provider/keeper/consumer_lifecycle_test.go index 44efac6..4f3dd9a 100644 --- a/x/vaas/provider/keeper/consumer_lifecycle_test.go +++ b/x/vaas/provider/keeper/consumer_lifecycle_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" testkeeper "github.com/allinbits/vaas/testutil/keeper" providertypes "github.com/allinbits/vaas/x/vaas/provider/types" @@ -44,7 +45,7 @@ func TestDeleteConsumerChain_AutoSweep(t *testing.T) { poolAddr := k.GetConsumerFeePoolAddress(consumerId) require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, poolAddr, consumerId)) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, "uphoton"), math.NewInt(100))) + collections.Join3(consumerId, "uphoton", alice), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uphoton"), math.NewInt(100))) @@ -62,6 +63,91 @@ func TestDeleteConsumerChain_AutoSweep(t *testing.T) { require.Equal(t, providertypes.CONSUMER_PHASE_DELETED, k.GetConsumerPhase(ctx, consumerId)) } +// TestDeleteConsumerChain_AutoSweepMultiDenomDust verifies that auto-sweep +// during consumer delete handles multiple denoms with truncation dust +// correctly: each share-holder gets their floor-rounded slice, the residue +// goes to the community pool, and the reverse-lookup is removed. +func TestDeleteConsumerChain_AutoSweepMultiDenomDust(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerClientId(ctx, consumerId, "07-tendermint-0") + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_STOPPED) + + alice := sdk.AccAddress([]byte("alice___________")) + bob := sdk.AccAddress([]byte("bob_____________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + providerAddr := authtypes.NewModuleAddress(providertypes.ModuleName) + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, poolAddr, consumerId)) + + // uphoton: 3 shares total (alice=1, bob=2) against balance 10 → alice + // gets floor(1*10/3)=3, bob gets floor(2*10/3)=6, dust 1. + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, "uphoton", alice), math.NewInt(1))) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, "uphoton", bob), math.NewInt(2))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uphoton"), math.NewInt(3))) + + // uatone: 7 shares total (alice=4, bob=3) against balance 20 → alice + // gets floor(4*20/7)=11, bob gets floor(3*20/7)=8, dust 1. + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, "uatone", alice), math.NewInt(4))) + require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, + collections.Join3(consumerId, "uatone", bob), math.NewInt(3))) + require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, + collections.Join(consumerId, "uatone"), math.NewInt(7))) + + mocks.MockBankKeeper.EXPECT().GetAllBalances(ctx, poolAddr).Return(sdk.NewCoins( + sdk.NewInt64Coin("uphoton", 10), + sdk.NewInt64Coin("uatone", 20), + )) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 10)) + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uatone"). + Return(sdk.NewInt64Coin("uatone", 20)) + + // Per-denom pool drain + per-holder send + dust to community pool. + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providertypes.ModuleName, + sdk.NewCoins(sdk.NewInt64Coin("uatone", 20))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, alice, + sdk.NewCoins(sdk.NewInt64Coin("uatone", 11))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, bob, + sdk.NewCoins(sdk.NewInt64Coin("uatone", 8))).Return(nil) + mocks.MockDistributionKeeper.EXPECT().FundCommunityPool( + ctx, sdk.NewCoins(sdk.NewInt64Coin("uatone", 1)), providerAddr).Return(nil) + + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, poolAddr, providertypes.ModuleName, + sdk.NewCoins(sdk.NewInt64Coin("uphoton", 10))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, alice, + sdk.NewCoins(sdk.NewInt64Coin("uphoton", 3))).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, bob, + sdk.NewCoins(sdk.NewInt64Coin("uphoton", 6))).Return(nil) + mocks.MockDistributionKeeper.EXPECT().FundCommunityPool( + ctx, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 1)), providerAddr).Return(nil) + + require.NoError(t, k.DeleteConsumerChain(ctx, consumerId)) + + require.Equal(t, providertypes.CONSUMER_PHASE_DELETED, k.GetConsumerPhase(ctx, consumerId)) + + // Reverse-lookup entry removed. + _, err := k.FeePoolAddressToConsumerId.Get(ctx, poolAddr) + require.ErrorIs(t, err, collections.ErrNotFound) + + // All share records cleared. + _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, "uphoton", alice)) + require.ErrorIs(t, err, collections.ErrNotFound) + _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, "uatone", bob)) + require.ErrorIs(t, err, collections.ErrNotFound) +} + func TestDeleteConsumerChain_AutoSweepFailureAborts(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() diff --git a/x/vaas/provider/keeper/fee_pool_shares.go b/x/vaas/provider/keeper/fee_pool_shares.go index 49062c6..0ac8049 100644 --- a/x/vaas/provider/keeper/fee_pool_shares.go +++ b/x/vaas/provider/keeper/fee_pool_shares.go @@ -26,7 +26,7 @@ func (k Keeper) ComputeClaim( return math.ZeroInt() } shares, err := k.ConsumerFeePoolShares.Get(ctx, - collections.Join3(consumerId, depositor, denom)) + collections.Join3(consumerId, denom, depositor)) if err != nil { return math.ZeroInt() } @@ -42,6 +42,10 @@ func (k Keeper) ComputeClaim( // specified consumer's fee pool. Handles the lazy-invalidation case: // if balance == 0 but total_shares > 0, all existing shares for this // (consumer, denom) are deleted first (they represent worthless claims). +// If state corruption ever leaves balance > 0 with total_shares == 0 +// (invariant violation, unreachable from valid ops), the orphan balance is +// forwarded to the community pool before the new deposit is credited, so the +// new depositor cannot capture it. // // Caller is responsible for the bank-side movement of funds into the pool. func (k Keeper) MintShares( @@ -65,6 +69,23 @@ func (k Keeper) MintShares( total = math.ZeroInt() } + // Defensive: balance > 0 with no shares is unreachable from valid ops. + // If it ever occurs (state corruption, external manipulation), forward + // the orphan balance to the community pool before crediting the new + // depositor, so the deposit doesn't capture the orphan funds. + if total.IsZero() && balance.Amount.IsPositive() { + providerAddr := authtypes.NewModuleAddress(types.ModuleName) + orphan := sdk.NewCoins(balance) + if err := k.bankKeeper.SendCoinsFromAccountToModule( + ctx, poolAddr, types.ModuleName, orphan, + ); err != nil { + return err + } + if err := k.distributionKeeper.FundCommunityPool(ctx, orphan, providerAddr); err != nil { + return err + } + } + var shares math.Int if total.IsZero() { shares = amount.Amount @@ -76,11 +97,11 @@ func (k Keeper) MintShares( if !shares.IsPositive() { // sub-share deposit (extreme dilution) — should be very rare but // refuse rather than silently dropping - return errorsmod.Wrap(types.ErrInvalidFundDenom, + return errorsmod.Wrap(types.ErrDepositTooSmall, "deposit too small to mint any shares") } - depKey := collections.Join3(consumerId, depositor, amount.Denom) + depKey := collections.Join3(consumerId, amount.Denom, depositor) existing, err := k.ConsumerFeePoolShares.Get(ctx, depKey) if err != nil { existing = math.ZeroInt() @@ -99,7 +120,7 @@ func (k Keeper) MintShares( func (k Keeper) WithdrawShares( ctx sdk.Context, consumerId uint64, depositor sdk.AccAddress, amount sdk.Coin, ) (sdk.Coin, error) { - depKey := collections.Join3(consumerId, depositor, amount.Denom) + depKey := collections.Join3(consumerId, amount.Denom, depositor) shares, err := k.ConsumerFeePoolShares.Get(ctx, depKey) if err != nil { return sdk.Coin{}, errorsmod.Wrapf(types.ErrUnauthorized, @@ -130,8 +151,9 @@ func (k Keeper) WithdrawShares( // Partial branch: shares_to_burn = floor(amount * total / balance) sharesToBurn = amount.Amount.Mul(total).Quo(balance.Amount) if sharesToBurn.IsZero() { - return sdk.Coin{}, errorsmod.Wrap(types.ErrPoolEmpty, - "requested amount too small to burn any shares") + return sdk.Coin{}, errorsmod.Wrapf(types.ErrSubShareWithdraw, + "requested %s but pool is too diluted to burn any shares", + amount.String()) } tokensToSend = sharesToBurn.Mul(balance.Amount).Quo(total) } @@ -221,7 +243,7 @@ func (k Keeper) SweepConsumerFeePoolDenom( shares math.Int } var holders []holder - prefix := collections.NewPrefixedTripleRange[uint64, sdk.AccAddress, string](consumerId) + prefix := collections.NewSuperPrefixedTripleRange[uint64, string, sdk.AccAddress](consumerId, denom) iter, err := k.ConsumerFeePoolShares.Iterate(ctx, prefix) if err != nil { return err @@ -232,15 +254,12 @@ func (k Keeper) SweepConsumerFeePoolDenom( iter.Close() return err } - if key.K3() != denom { - continue - } v, err := iter.Value() if err != nil { iter.Close() return err } - holders = append(holders, holder{addr: key.K2(), shares: v}) + holders = append(holders, holder{addr: key.K3(), shares: v}) } iter.Close() @@ -333,22 +352,19 @@ func (k Keeper) SweepConsumerFeePool( // clearAllShares deletes every share record for the given (consumer, denom). // Used by lazy invalidation and by sweep finalization. func (k Keeper) clearAllShares(ctx sdk.Context, consumerId uint64, denom string) error { - prefix := collections.NewPrefixedTripleRange[uint64, sdk.AccAddress, string](consumerId) + prefix := collections.NewSuperPrefixedTripleRange[uint64, string, sdk.AccAddress](consumerId, denom) iter, err := k.ConsumerFeePoolShares.Iterate(ctx, prefix) if err != nil { return err } defer iter.Close() - var toDelete []collections.Triple[uint64, sdk.AccAddress, string] + var toDelete []collections.Triple[uint64, string, sdk.AccAddress] for ; iter.Valid(); iter.Next() { key, err := iter.Key() if err != nil { return err } - if key.K3() != denom { - continue - } toDelete = append(toDelete, key) } for _, key := range toDelete { diff --git a/x/vaas/provider/keeper/fee_pool_shares_test.go b/x/vaas/provider/keeper/fee_pool_shares_test.go index 631535a..8a27fe2 100644 --- a/x/vaas/provider/keeper/fee_pool_shares_test.go +++ b/x/vaas/provider/keeper/fee_pool_shares_test.go @@ -31,7 +31,7 @@ func TestComputeClaim(t *testing.T) { // Seed: alice has 100 shares of 100 total, balance 50 require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(100))) + collections.Join3(consumerId, denom, alice), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(100))) mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 50)) @@ -51,7 +51,7 @@ func TestMintShares_Initial(t *testing.T) { mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 0)) require.NoError(t, k.MintShares(ctx, consumerId, alice, sdk.NewInt64Coin(denom, 100))) - shares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + shares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, alice)) require.NoError(t, err) require.Equal(t, math.NewInt(100), shares) @@ -72,7 +72,7 @@ func TestMintShares_Subsequent(t *testing.T) { // Seed: alice has 100 shares against balance 50 (consumed via fees) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(100))) + collections.Join3(consumerId, denom, alice), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(100))) @@ -82,7 +82,7 @@ func TestMintShares_Subsequent(t *testing.T) { require.NoError(t, k.MintShares(ctx, consumerId, bob, sdk.NewInt64Coin(denom, 100))) // Bob: shares = 100 * 100 / 50 = 200 - shares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, bob, denom)) + shares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, bob)) require.NoError(t, err) require.Equal(t, math.NewInt(200), shares) @@ -103,7 +103,7 @@ func TestMintShares_LazyInvalidation(t *testing.T) { // Seed: alice has 100 shares, balance is 0 (pool fully consumed by fees) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(100))) + collections.Join3(consumerId, denom, alice), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(100))) @@ -111,10 +111,10 @@ func TestMintShares_LazyInvalidation(t *testing.T) { require.NoError(t, k.MintShares(ctx, consumerId, bob, sdk.NewInt64Coin(denom, 50))) // Alice's shares should be wiped (lazy invalidation), Bob's recorded as initial - _, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + _, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, alice)) require.ErrorIs(t, err, collections.ErrNotFound) - bobShares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, bob, denom)) + bobShares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, bob)) require.NoError(t, err) require.Equal(t, math.NewInt(50), bobShares) @@ -136,19 +136,19 @@ func TestMintShares_SubShareDeposit(t *testing.T) { // Seed: alice has 1_000_000 shares of 1_000_000 total, balance is huge (1_000_000_000). // Bob's tiny 1-unit deposit would mint floor(1 * 1_000_000 / 1_000_000_000) = 0 shares. require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(1_000_000))) + collections.Join3(consumerId, denom, alice), math.NewInt(1_000_000))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(1_000_000))) mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 1_000_000_000)) err := k.MintShares(ctx, consumerId, bob, sdk.NewInt64Coin(denom, 1)) - require.ErrorIs(t, err, providertypes.ErrInvalidFundDenom) + require.ErrorIs(t, err, providertypes.ErrDepositTooSmall) // No state mutation: bob has no entry, total unchanged, alice unchanged. - _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, bob, denom)) + _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, bob)) require.ErrorIs(t, err, collections.ErrNotFound) - aliceShares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + aliceShares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, alice)) require.NoError(t, err) require.Equal(t, math.NewInt(1_000_000), aliceShares) @@ -168,7 +168,7 @@ func TestWithdrawShares_Full(t *testing.T) { // Alice sole depositor with 100 shares against balance 100 require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(100))) + collections.Join3(consumerId, denom, alice), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(100))) mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 100)) @@ -178,7 +178,7 @@ func TestWithdrawShares_Full(t *testing.T) { require.NoError(t, err) require.Equal(t, math.NewInt(100), tokens.Amount) - _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, alice)) require.ErrorIs(t, err, collections.ErrNotFound) _, err = k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) @@ -197,9 +197,9 @@ func TestWithdrawShares_Partial(t *testing.T) { // Two depositors, balance 200, total 200 require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(100))) + collections.Join3(consumerId, denom, alice), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, bob, denom), math.NewInt(100))) + collections.Join3(consumerId, denom, bob), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(200))) mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 200)) @@ -210,7 +210,7 @@ func TestWithdrawShares_Partial(t *testing.T) { require.Equal(t, math.NewInt(50), tokens.Amount) // Alice burned 50 shares; total = 150; alice = 50 - aliceShares, _ := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + aliceShares, _ := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, alice)) require.Equal(t, math.NewInt(50), aliceShares) total, _ := k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) require.Equal(t, math.NewInt(150), total) @@ -226,7 +226,7 @@ func TestWithdrawShares_Empty(t *testing.T) { poolAddr := k.GetConsumerFeePoolAddress(consumerId) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(100))) + collections.Join3(consumerId, denom, alice), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(100))) mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 0)) @@ -249,17 +249,17 @@ func TestWithdrawShares_SubShareGuard(t *testing.T) { // the partial branch and computes sharesToBurn = floor(1 * 100 / 1_000_000) = 0, // which must trigger the sub-share guard. require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(100))) + collections.Join3(consumerId, denom, alice), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(100))) mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, denom).Return(sdk.NewInt64Coin(denom, 1_000_000)) tokens, err := k.WithdrawShares(ctx, consumerId, alice, sdk.NewInt64Coin(denom, 1)) - require.ErrorIs(t, err, providertypes.ErrPoolEmpty) + require.ErrorIs(t, err, providertypes.ErrSubShareWithdraw) require.Equal(t, sdk.Coin{}, tokens) // No state mutation: alice still has 100 shares, total still 100. - aliceShares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + aliceShares, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, alice)) require.NoError(t, err) require.Equal(t, math.NewInt(100), aliceShares) @@ -280,9 +280,9 @@ func TestSweepConsumerFeePoolDenom(t *testing.T) { // alice 30, bob 70, total 100, balance 100 — no dust require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(30))) + collections.Join3(consumerId, denom, alice), math.NewInt(30))) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, bob, denom), math.NewInt(70))) + collections.Join3(consumerId, denom, bob), math.NewInt(70))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(100))) @@ -299,9 +299,9 @@ func TestSweepConsumerFeePoolDenom(t *testing.T) { require.NoError(t, k.SweepConsumerFeePoolDenom(ctx, consumerId, denom)) // All share records and total cleared - _, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + _, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, alice)) require.ErrorIs(t, err, collections.ErrNotFound) - _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, bob, denom)) + _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, bob)) require.ErrorIs(t, err, collections.ErrNotFound) _, err = k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) require.ErrorIs(t, err, collections.ErrNotFound) @@ -320,9 +320,9 @@ func TestSweepConsumerFeePoolDenom_WithDust(t *testing.T) { // alice 1, bob 2, total 3, balance 10 // alice claim: floor(1*10/3) = 3; bob claim: floor(2*10/3) = 6; dust = 1 require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(1))) + collections.Join3(consumerId, denom, alice), math.NewInt(1))) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, bob, denom), math.NewInt(2))) + collections.Join3(consumerId, denom, bob), math.NewInt(2))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(3))) @@ -351,7 +351,7 @@ func TestSweepConsumerFeePoolDenom_DistrModuleRecipientUsesCommunityPool(t *test poolAddr := k.GetConsumerFeePoolAddress(consumerId) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, distrAddr, denom), math.NewInt(100))) + collections.Join3(consumerId, denom, distrAddr), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(100))) @@ -382,9 +382,9 @@ func TestSweepConsumerFeePoolDenom_AllFloorToZero(t *testing.T) { // bob slice: floor(1*1/2) = 0 → skipped // distributed = 0; dust = 1 → entire balance routed to community pool. require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, denom), math.NewInt(1))) + collections.Join3(consumerId, denom, alice), math.NewInt(1))) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, bob, denom), math.NewInt(1))) + collections.Join3(consumerId, denom, bob), math.NewInt(1))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, denom), math.NewInt(2))) @@ -400,9 +400,9 @@ func TestSweepConsumerFeePoolDenom_AllFloorToZero(t *testing.T) { require.NoError(t, k.SweepConsumerFeePoolDenom(ctx, consumerId, denom)) // All share records and total cleared. - _, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, denom)) + _, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, alice)) require.ErrorIs(t, err, collections.ErrNotFound) - _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, bob, denom)) + _, err = k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, denom, bob)) require.ErrorIs(t, err, collections.ErrNotFound) _, err = k.ConsumerFeePoolTotalShares.Get(ctx, collections.Join(consumerId, denom)) require.ErrorIs(t, err, collections.ErrNotFound) @@ -418,11 +418,11 @@ func TestSweepConsumerFeePool_AllDenoms(t *testing.T) { // alice has shares in two denoms require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, "uphoton"), math.NewInt(10))) + collections.Join3(consumerId, "uphoton", alice), math.NewInt(10))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uphoton"), math.NewInt(10))) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, "uatone"), math.NewInt(5))) + collections.Join3(consumerId, "uatone", alice), math.NewInt(5))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uatone"), math.NewInt(5))) diff --git a/x/vaas/provider/keeper/genesis.go b/x/vaas/provider/keeper/genesis.go index 735e789..29fe496 100644 --- a/x/vaas/provider/keeper/genesis.go +++ b/x/vaas/provider/keeper/genesis.go @@ -140,22 +140,19 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) []abc } } - // Load primary share records + // Load primary share records and accumulate per-(consumer, denom) totals + // in a single pass. GenesisState.Validate has already vetted the input. + totals := map[uint64]map[string]math.Int{} for _, s := range genState.ConsumerFeePoolShares { addr, err := sdk.AccAddressFromBech32(s.Depositor) if err != nil { panic(fmt.Errorf("invalid depositor in genesis: %w", err)) } if err := k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(s.ConsumerId, addr, s.Denom), s.Shares, + collections.Join3(s.ConsumerId, s.Denom, addr), s.Shares, ); err != nil { panic(err) } - } - - // Rebuild totals by summing per (consumer_id, denom) - totals := map[uint64]map[string]math.Int{} - for _, s := range genState.ConsumerFeePoolShares { if _, ok := totals[s.ConsumerId]; !ok { totals[s.ConsumerId] = map[string]math.Int{} } @@ -317,8 +314,18 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { k.GetAllConsumerAddrsToPrune(ctx, consumerId)...) } + // Export share records and accumulate per-(consumer, denom) totals in + // a single pass for the sanity check below. + feePoolShares, recomputedTotals := k.exportFeePoolShares(ctx) + + // Sanity check: compare stored ConsumerFeePoolTotalShares against the + // totals we just recomputed. Divergence is logged but not blocking — + // export should never fail on a sanity check (spec section "Genesis + // export/import"). + k.checkFeePoolTotalsConsistency(ctx, recomputedTotals) + // TODO (PERMISSIONLESS) - gs := types.NewGenesisState( + return types.NewGenesisState( k.GetValidatorSetUpdateId(ctx), k.GetAllValsetUpdateBlockHeights(ctx), consumerStates, @@ -326,65 +333,100 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { k.GetAllValidatorConsumerPubKeys(ctx, nil), k.GetAllValidatorsByConsumerAddr(ctx, nil), consumerAddrsToPrune, + feePoolShares, ) +} - // Export share records +// exportFeePoolShares walks ConsumerFeePoolShares once, emitting both the +// flat list for genesis export and a per-(consumer, denom) recomputed-totals +// map for the export-time sanity check. +func (k Keeper) exportFeePoolShares( + ctx sdk.Context, +) ([]types.ConsumerFeePoolShare, map[uint64]map[string]math.Int) { + shares := []types.ConsumerFeePoolShare{} + totals := map[uint64]map[string]math.Int{} iter, err := k.ConsumerFeePoolShares.Iterate(ctx, nil) if err != nil { - panic(err) + k.Logger(ctx).Error("fee-pool shares: iterate failed at export", "error", err.Error()) + return shares, totals } defer iter.Close() for ; iter.Valid(); iter.Next() { key, err := iter.Key() if err != nil { - panic(err) + k.Logger(ctx).Error("fee-pool shares: key read failed at export", "error", err.Error()) + return shares, totals } val, err := iter.Value() if err != nil { - panic(err) + k.Logger(ctx).Error("fee-pool shares: value read failed at export", "error", err.Error()) + return shares, totals } - gs.ConsumerFeePoolShares = append(gs.ConsumerFeePoolShares, types.ConsumerFeePoolShare{ + shares = append(shares, types.ConsumerFeePoolShare{ ConsumerId: key.K1(), - Depositor: key.K2().String(), - Denom: key.K3(), + Depositor: key.K3().String(), + Denom: key.K2(), Shares: val, }) - } - - // Sanity check: rebuild totals from shares and warn on divergence - recomputed := map[string]math.Int{} - for _, s := range gs.ConsumerFeePoolShares { - key := fmt.Sprintf("%d|%s", s.ConsumerId, s.Denom) - if cur, ok := recomputed[key]; ok { - recomputed[key] = cur.Add(s.Shares) + if _, ok := totals[key.K1()]; !ok { + totals[key.K1()] = map[string]math.Int{} + } + if cur, ok := totals[key.K1()][key.K2()]; ok { + totals[key.K1()][key.K2()] = cur.Add(val) } else { - recomputed[key] = s.Shares + totals[key.K1()][key.K2()] = val } } + return shares, totals +} + +// checkFeePoolTotalsConsistency compares stored ConsumerFeePoolTotalShares +// against a recomputed total map and logs both directions of mismatch. +func (k Keeper) checkFeePoolTotalsConsistency( + ctx sdk.Context, recomputed map[uint64]map[string]math.Int, +) { + seen := map[uint64]map[string]bool{} totIter, err := k.ConsumerFeePoolTotalShares.Iterate(ctx, nil) if err != nil { - panic(err) + k.Logger(ctx).Error("fee-pool totals: iterate failed at export", "error", err.Error()) + return } + defer totIter.Close() for ; totIter.Valid(); totIter.Next() { key, err := totIter.Key() if err != nil { - panic(err) + k.Logger(ctx).Error("fee-pool totals: key read failed at export", "error", err.Error()) + return } val, err := totIter.Value() if err != nil { - panic(err) + k.Logger(ctx).Error("fee-pool totals: value read failed at export", "error", err.Error()) + return } - composite := fmt.Sprintf("%d|%s", key.K1(), key.K2()) - expected, ok := recomputed[composite] + consumerId, denom := key.K1(), key.K2() + if _, ok := seen[consumerId]; !ok { + seen[consumerId] = map[string]bool{} + } + seen[consumerId][denom] = true + + expected, ok := recomputed[consumerId][denom] if !ok || !expected.Equal(val) { k.Logger(ctx).Error( - "fee-pool total_shares mismatch at export", - "consumer_id", key.K1(), "denom", key.K2(), + "fee-pool total_shares: stored != recomputed at export", + "consumer_id", consumerId, "denom", denom, "stored", val.String(), ) } } - totIter.Close() - - return gs + // Reverse direction: recomputed total exists but no stored total. + for consumerId, byDenom := range recomputed { + for denom := range byDenom { + if !seen[consumerId][denom] { + k.Logger(ctx).Error( + "fee-pool total_shares: shares exist without stored total at export", + "consumer_id", consumerId, "denom", denom, + ) + } + } + } } diff --git a/x/vaas/provider/keeper/genesis_test.go b/x/vaas/provider/keeper/genesis_test.go index 78cfb3e..62a9c94 100644 --- a/x/vaas/provider/keeper/genesis_test.go +++ b/x/vaas/provider/keeper/genesis_test.go @@ -416,9 +416,9 @@ func TestExportGenesis_IncludesShares(t *testing.T) { alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(uint64(0), alice, "uphoton"), math.NewInt(60))) + collections.Join3(uint64(0), "uphoton", alice), math.NewInt(60))) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(uint64(0), bob, "uphoton"), math.NewInt(40))) + collections.Join3(uint64(0), "uphoton", bob), math.NewInt(40))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(uint64(0), "uphoton"), math.NewInt(100))) @@ -465,7 +465,7 @@ func TestInitGenesis_RebuildsDerivedCollections(t *testing.T) { k.InitGenesis(ctx, gs) - s, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(uint64(0), alice, "uphoton")) + s, err := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(uint64(0), "uphoton", alice)) require.NoError(t, err) require.Equal(t, math.NewInt(60), s) diff --git a/x/vaas/provider/keeper/grpc_query.go b/x/vaas/provider/keeper/grpc_query.go index c95d343..9845a08 100644 --- a/x/vaas/provider/keeper/grpc_query.go +++ b/x/vaas/provider/keeper/grpc_query.go @@ -14,6 +14,7 @@ import ( "cosmossdk.io/collections" errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" @@ -332,6 +333,14 @@ func (k Keeper) ConsumerFeePoolClaim( } ctx := sdk.UnwrapSDKContext(goCtx) + exists, err := k.ConsumerPhase.Has(ctx, req.ConsumerId) + if err != nil { + return nil, status.Errorf(codes.Internal, "phase lookup: %s", err) + } + if !exists { + return nil, status.Errorf(codes.NotFound, "consumer %d does not exist", req.ConsumerId) + } + depositorBech := req.Depositor if depositorBech == k.GetAuthority() { depositorBech = authtypes.NewModuleAddress(disttypes.ModuleName).String() @@ -341,6 +350,7 @@ func (k Keeper) ConsumerFeePoolClaim( return nil, status.Errorf(codes.InvalidArgument, "invalid depositor: %s", err) } + poolAddr := k.GetConsumerFeePoolAddress(req.ConsumerId) coins := sdk.NewCoins() prefix := collections.NewPrefixedPairRange[uint64, string](req.ConsumerId) iter, err := k.ConsumerFeePoolTotalShares.Iterate(ctx, prefix) @@ -353,8 +363,25 @@ func (k Keeper) ConsumerFeePoolClaim( if err != nil { return nil, status.Errorf(codes.Internal, "key: %s", err) } + total, err := iter.Value() + if err != nil { + return nil, status.Errorf(codes.Internal, "value: %s", err) + } denom := key.K2() - claim := k.ComputeClaim(ctx, req.ConsumerId, depositor, denom) + if total.IsZero() { + continue + } + shares, err := k.ConsumerFeePoolShares.Get(ctx, + collections.Join3(req.ConsumerId, denom, depositor)) + if err != nil { + // No shares for this (consumer, depositor, denom) — skip. + continue + } + balance := k.bankKeeper.GetBalance(ctx, poolAddr, denom) + if balance.Amount.IsZero() { + continue + } + claim := shares.Mul(balance.Amount).Quo(total) if claim.IsPositive() { coins = coins.Add(sdk.NewCoin(denom, claim)) } @@ -370,22 +397,67 @@ func (k Keeper) ConsumerFeePoolClaims( } ctx := sdk.UnwrapSDKContext(goCtx) + exists, err := k.ConsumerPhase.Has(ctx, req.ConsumerId) + if err != nil { + return nil, status.Errorf(codes.Internal, "phase lookup: %s", err) + } + if !exists { + return nil, status.Errorf(codes.NotFound, "consumer %d does not exist", req.ConsumerId) + } + type acc struct { addr sdk.AccAddress coins sdk.Coins } perDepositor := map[string]*acc{} - prefix := collections.NewPrefixedTripleRange[uint64, sdk.AccAddress, string](req.ConsumerId) + // Cache per-denom (balance, total) so we don't pay one bank read + + // one collection read per (depositor, denom) tuple. + poolAddr := k.GetConsumerFeePoolAddress(req.ConsumerId) + balances := map[string]math.Int{} + totals := map[string]math.Int{} + + prefix := collections.NewPrefixedTripleRange[uint64, string, sdk.AccAddress](req.ConsumerId) iter, err := k.ConsumerFeePoolShares.Iterate(ctx, prefix) if err != nil { return nil, status.Errorf(codes.Internal, "%s", err) } for ; iter.Valid(); iter.Next() { - key, _ := iter.Key() - addr := key.K2() - denom := key.K3() - claim := k.ComputeClaim(ctx, req.ConsumerId, addr, denom) + key, err := iter.Key() + if err != nil { + iter.Close() + return nil, status.Errorf(codes.Internal, "%s", err) + } + shares, err := iter.Value() + if err != nil { + iter.Close() + return nil, status.Errorf(codes.Internal, "%s", err) + } + denom := key.K2() + addr := key.K3() + + balance, ok := balances[denom] + if !ok { + balance = k.bankKeeper.GetBalance(ctx, poolAddr, denom).Amount + balances[denom] = balance + } + if balance.IsZero() { + continue + } + total, ok := totals[denom] + if !ok { + t, err := k.ConsumerFeePoolTotalShares.Get(ctx, + collections.Join(req.ConsumerId, denom)) + if err != nil { + continue + } + total = t + totals[denom] = total + } + if total.IsZero() { + continue + } + claim := shares.Mul(balance).Quo(total) if claim.IsZero() { continue } @@ -406,20 +478,33 @@ func (k Keeper) ConsumerFeePoolClaims( } sort.Strings(keys) - offset, limit := uint64(0), uint64(100) + total := uint64(len(keys)) + + // Decode pagination request. Key takes precedence over Offset: cosmos + // paging clients walk a result set with NextKey, so a non-nil Key means + // "resume from this depositor". + var offset, limit uint64 = 0, query.DefaultLimit + countTotal := true if req.Pagination != nil { - offset = req.Pagination.Offset if req.Pagination.Limit > 0 { limit = req.Pagination.Limit } + countTotal = req.Pagination.CountTotal + if len(req.Pagination.Key) > 0 { + // Find the first depositor >= Key. + cursor := string(req.Pagination.Key) + idx := sort.SearchStrings(keys, cursor) + offset = uint64(idx) + } else { + offset = req.Pagination.Offset + } } - - end := offset + limit - if end > uint64(len(keys)) { - end = uint64(len(keys)) + if offset > total { + offset = total } - if offset > uint64(len(keys)) { - offset = uint64(len(keys)) + end := offset + limit + if end > total { + end = total } claims := make([]types.DepositorClaim, 0, end-offset) @@ -430,12 +515,19 @@ func (k Keeper) ConsumerFeePoolClaims( Claim: entry.coins, }) } - return &types.QueryConsumerFeePoolClaimsResponse{ - Claims: claims, - Pagination: &query.PageResponse{ - Total: uint64(len(keys)), - }, - }, nil + + resp := &types.QueryConsumerFeePoolClaimsResponse{ + Claims: claims, + Pagination: &query.PageResponse{}, + } + if countTotal { + resp.Pagination.Total = total + } + if end < total { + // Encode the next page cursor as the depositor at the boundary. + resp.Pagination.NextKey = []byte(keys[end]) + } + return resp, nil } func (k Keeper) QueryConsumerGenesisTime(goCtx context.Context, req *types.QueryConsumerGenesisTimeRequest) (*types.QueryConsumerGenesisTimeResponse, error) { diff --git a/x/vaas/provider/keeper/grpc_query_test.go b/x/vaas/provider/keeper/grpc_query_test.go index 26370ce..ff9e691 100644 --- a/x/vaas/provider/keeper/grpc_query_test.go +++ b/x/vaas/provider/keeper/grpc_query_test.go @@ -8,6 +8,8 @@ import ( "cosmossdk.io/math" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -48,10 +50,11 @@ func TestQueryConsumerFeePoolClaim(t *testing.T) { defer ctrl.Finish() consumerId := uint64(0) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED) alice := sdk.AccAddress([]byte("alice___________")) poolAddr := k.GetConsumerFeePoolAddress(consumerId) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, "uphoton"), math.NewInt(50))) + collections.Join3(consumerId, "uphoton", alice), math.NewInt(50))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uphoton"), math.NewInt(100))) mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). @@ -64,15 +67,28 @@ func TestQueryConsumerFeePoolClaim(t *testing.T) { require.Equal(t, "100uphoton", res.Claim.String()) } +func TestQueryConsumerFeePoolClaim_UnknownConsumer(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + alice := sdk.AccAddress([]byte("alice___________")) + _, err := k.ConsumerFeePoolClaim(ctx, &providertypes.QueryConsumerFeePoolClaimRequest{ + ConsumerId: 999, Depositor: alice.String(), + }) + require.Error(t, err) + require.Equal(t, codes.NotFound, status.Code(err)) +} + func TestQueryConsumerFeePoolClaim_GovAlias(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() consumerId := uint64(0) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED) distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) poolAddr := k.GetConsumerFeePoolAddress(consumerId) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, distrAddr, "uphoton"), math.NewInt(100))) + collections.Join3(consumerId, "uphoton", distrAddr), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uphoton"), math.NewInt(100))) mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). @@ -90,14 +106,15 @@ func TestQueryConsumerFeePoolClaims(t *testing.T) { defer ctrl.Finish() consumerId := uint64(0) + k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED) alice := sdk.AccAddress([]byte("alice___________")) bob := sdk.AccAddress([]byte("bob_____________")) poolAddr := k.GetConsumerFeePoolAddress(consumerId) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, "uphoton"), math.NewInt(30))) + collections.Join3(consumerId, "uphoton", alice), math.NewInt(30))) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, bob, "uphoton"), math.NewInt(70))) + collections.Join3(consumerId, "uphoton", bob), math.NewInt(70))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uphoton"), math.NewInt(100))) mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). @@ -108,4 +125,23 @@ func TestQueryConsumerFeePoolClaims(t *testing.T) { }) require.NoError(t, err) require.Len(t, res.Claims, 2) + + // Strong assertions: alice 30 shares × 100 / 100 = 30; bob 70 × 100 / 100 = 70. + got := map[string]string{} + for _, c := range res.Claims { + got[c.Depositor] = c.Claim.String() + } + require.Equal(t, "30uphoton", got[alice.String()]) + require.Equal(t, "70uphoton", got[bob.String()]) +} + +func TestQueryConsumerFeePoolClaims_UnknownConsumer(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + _, err := k.ConsumerFeePoolClaims(ctx, &providertypes.QueryConsumerFeePoolClaimsRequest{ + ConsumerId: 999, + }) + require.Error(t, err) + require.Equal(t, codes.NotFound, status.Code(err)) } diff --git a/x/vaas/provider/keeper/keeper.go b/x/vaas/provider/keeper/keeper.go index 2b3d8fc..b57033f 100644 --- a/x/vaas/provider/keeper/keeper.go +++ b/x/vaas/provider/keeper/keeper.go @@ -79,8 +79,13 @@ type Keeper struct { ConsumerValidators collections.Map[collections.Pair[uint64, []byte], types.ConsensusValidator] LastProviderConsensusVals collections.Map[[]byte, types.ConsensusValidator] - // Fee pool collections - ConsumerFeePoolShares collections.Map[collections.Triple[uint64, sdk.AccAddress, string], math.Int] + // Fee pool collections. + // + // ConsumerFeePoolShares is keyed (consumer_id, denom, depositor): denom + // is the second component so that per-denom operations (sweep, claim, + // invalidation) can prefix-iterate a single (consumer_id, denom) range + // without scanning across the full depositor set for the consumer. + ConsumerFeePoolShares collections.Map[collections.Triple[uint64, string, sdk.AccAddress], math.Int] ConsumerFeePoolTotalShares collections.Map[collections.Pair[uint64, string], math.Int] FeePoolAddressToConsumerId collections.Map[sdk.AccAddress, uint64] } @@ -169,7 +174,7 @@ func NewKeeper( k.ConsumerFeePoolShares = collections.NewMap( sb, types.ConsumerFeePoolSharesKeyPrefix, types.ConsumerFeePoolSharesKeyName, - collections.TripleKeyCodec(collections.Uint64Key, sdk.AccAddressKey, collections.StringKey), + collections.TripleKeyCodec(collections.Uint64Key, collections.StringKey, sdk.AccAddressKey), sdk.IntValue, ) k.ConsumerFeePoolTotalShares = collections.NewMap( diff --git a/x/vaas/provider/keeper/msg_server.go b/x/vaas/provider/keeper/msg_server.go index 46d4c7e..3c2dbf2 100644 --- a/x/vaas/provider/keeper/msg_server.go +++ b/x/vaas/provider/keeper/msg_server.go @@ -483,12 +483,15 @@ func (k msgServer) FundConsumerFeePool( ctx := sdk.UnwrapSDKContext(goCtx) // Phase + existence check - phase := k.GetConsumerPhase(ctx, msg.ConsumerId) - if phase == types.CONSUMER_PHASE_UNSPECIFIED { + exists, err := k.ConsumerPhase.Has(ctx, msg.ConsumerId) + if err != nil { + return nil, err + } + if !exists { return nil, errorsmod.Wrapf(types.ErrUnknownConsumerId, "consumer %d does not exist", msg.ConsumerId) } - if phase == types.CONSUMER_PHASE_DELETED { + if k.GetConsumerPhase(ctx, msg.ConsumerId) == types.CONSUMER_PHASE_DELETED { return nil, errorsmod.Wrapf(types.ErrInvalidPhase, "consumer %d is deleted", msg.ConsumerId) } @@ -546,16 +549,20 @@ func (k msgServer) FundConsumerFeePool( } // WithdrawConsumerFeePool burns the depositor's shares across one or more -// denoms and returns the corresponding tokens. The handler is atomic: any -// per-denom failure rolls back share burns from prior denoms in the same -// request. When the signer is the gov authority, the tokens are routed back -// to the community pool rather than to the signer. +// denoms and returns the corresponding tokens. The handler is atomic: all +// share burns and bank movements are staged in a cache-context that is only +// committed on full success, so a mid-flight failure rolls back the entire +// request even when the handler is invoked outside of the SDK tx machinery +// (nested calls or direct invocations in tests). +// +// When the signer is the gov authority, the depositor identity is the +// distribution module account and the tokens are routed back to the community +// pool rather than to the signer. func (k msgServer) WithdrawConsumerFeePool( goCtx context.Context, msg *types.MsgWithdrawConsumerFeePool, ) (*types.MsgWithdrawConsumerFeePoolResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // Resolve depositor identity isGov := msg.Signer == k.GetAuthority() var depositor sdk.AccAddress if isGov { @@ -568,10 +575,6 @@ func (k msgServer) WithdrawConsumerFeePool( depositor = addr } - // Process per-denom, accumulate. The share-burn loop runs inside a - // cache-context so a mid-loop failure rolls back any prior burns, even - // when the handler is invoked outside of the SDK tx machinery (e.g. - // nested calls or direct invocations in tests). cachedCtx, write := ctx.CacheContext() delivered := sdk.NewCoins() for _, amt := range msg.Amount { @@ -579,40 +582,40 @@ func (k msgServer) WithdrawConsumerFeePool( if err != nil { return nil, err } - if !tokens.Amount.IsZero() { - delivered = delivered.Add(tokens) - } - } - write() - - if delivered.IsZero() { - return &types.MsgWithdrawConsumerFeePoolResponse{Amount: delivered}, nil + delivered = delivered.Add(tokens) } - poolAddr := k.GetConsumerFeePoolAddress(msg.ConsumerId) - providerAddr := authtypes.NewModuleAddress(types.ModuleName) - if err := k.bankKeeper.SendCoinsFromAccountToModule( - ctx, poolAddr, types.ModuleName, delivered, - ); err != nil { - return nil, err - } - if isGov { - if err := k.distributionKeeper.FundCommunityPool(ctx, delivered, providerAddr); err != nil { - return nil, err - } - } else { - if err := k.bankKeeper.SendCoinsFromModuleToAccount( - ctx, types.ModuleName, depositor, delivered, + if !delivered.IsZero() { + poolAddr := k.GetConsumerFeePoolAddress(msg.ConsumerId) + providerAddr := authtypes.NewModuleAddress(types.ModuleName) + if err := k.bankKeeper.SendCoinsFromAccountToModule( + cachedCtx, poolAddr, types.ModuleName, delivered, ); err != nil { return nil, err } + if isGov { + if err := k.distributionKeeper.FundCommunityPool(cachedCtx, delivered, providerAddr); err != nil { + return nil, err + } + } else { + if err := k.bankKeeper.SendCoinsFromModuleToAccount( + cachedCtx, types.ModuleName, depositor, delivered, + ); err != nil { + return nil, err + } + } } + write() + recipient := depositor.String() + if isGov { + recipient = "community_pool" + } ctx.EventManager().EmitEvent(sdk.NewEvent( types.EventTypeConsumerFeePoolWithdraw, sdk.NewAttribute(types.AttributeConsumerId, strconv.FormatUint(msg.ConsumerId, 10)), sdk.NewAttribute(types.AttributeDepositor, depositor.String()), - sdk.NewAttribute(types.AttributeRecipient, depositor.String()), + sdk.NewAttribute(types.AttributeRecipient, recipient), sdk.NewAttribute(types.AttributeAmount, delivered.String()), )) return &types.MsgWithdrawConsumerFeePoolResponse{Amount: delivered}, nil diff --git a/x/vaas/provider/keeper/msg_server_test.go b/x/vaas/provider/keeper/msg_server_test.go index a53aa45..5149484 100644 --- a/x/vaas/provider/keeper/msg_server_test.go +++ b/x/vaas/provider/keeper/msg_server_test.go @@ -264,7 +264,7 @@ func TestFundConsumerFeePool_RegularSigner(t *testing.T) { require.NoError(t, err) shares, _ := k.ConsumerFeePoolShares.Get(ctx, - collections.Join3(consumerId, alice, "uphoton")) + collections.Join3(consumerId, "uphoton", alice)) require.Equal(t, math.NewInt(100), shares) } @@ -299,7 +299,7 @@ func TestFundConsumerFeePool_GovAuthority(t *testing.T) { require.NoError(t, err) shares, _ := k.ConsumerFeePoolShares.Get(ctx, - collections.Join3(consumerId, distrAddr, "uphoton")) + collections.Join3(consumerId, "uphoton", distrAddr)) require.Equal(t, math.NewInt(1000), shares) } @@ -316,6 +316,47 @@ func TestFundConsumerFeePool_RejectsUnknownConsumer(t *testing.T) { require.ErrorIs(t, err, providertypes.ErrUnknownConsumerId) } +// TestFundConsumerFeePool_AllowedInActivePhases verifies fund is accepted in +// every phase except DELETED (REGISTERED, INITIALIZED, LAUNCHED, STOPPED). +func TestFundConsumerFeePool_AllowedInActivePhases(t *testing.T) { + allowedPhases := []providertypes.ConsumerPhase{ + providertypes.CONSUMER_PHASE_REGISTERED, + providertypes.CONSUMER_PHASE_INITIALIZED, + providertypes.CONSUMER_PHASE_LAUNCHED, + providertypes.CONSUMER_PHASE_STOPPED, + } + for _, phase := range allowedPhases { + t.Run(phase.String(), func(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + ms := providerkeeper.NewMsgServerImpl(&k) + + consumerId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, consumerId, phase) + k.SetParams(ctx, providertypes.DefaultParams()) + params := k.GetParams(ctx) + params.FeesPerBlock = sdk.NewInt64Coin("uphoton", 10) + k.SetParams(ctx, params) + + alice := sdk.AccAddress([]byte("alice___________")) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + amount := sdk.NewInt64Coin("uphoton", 100) + + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 0)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + ctx, alice, providertypes.ModuleName, sdk.NewCoins(amount)).Return(nil) + mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( + ctx, providertypes.ModuleName, poolAddr, sdk.NewCoins(amount)).Return(nil) + + _, err := ms.FundConsumerFeePool(ctx, &providertypes.MsgFundConsumerFeePool{ + Signer: alice.String(), ConsumerId: consumerId, Amount: amount, + }) + require.NoError(t, err) + }) + } +} + func TestFundConsumerFeePool_RejectsDeleted(t *testing.T) { k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() @@ -344,17 +385,18 @@ func TestWithdrawConsumerFeePool_Regular(t *testing.T) { // alice sole depositor: 100 shares, balance 80 require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, "uphoton"), math.NewInt(100))) + collections.Join3(consumerId, "uphoton", alice), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uphoton"), math.NewInt(100))) mocks.MockBankKeeper.EXPECT().GetBalance(gomock.Any(), poolAddr, "uphoton"). Return(sdk.NewInt64Coin("uphoton", 80)) - // alice asks for 30, partial path: shares_to_burn = 30*100/80 = 37, tokens = 37*80/100 = 29 + // alice asks for 30, partial path: shares_to_burn = 30*100/80 = 37, tokens = 37*80/100 = 29. + // Bank ops execute on a cache-context wrapped around the outer ctx, so match with gomock.Any(). mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( - ctx, poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 29))).Return(nil) + gomock.Any(), poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 29))).Return(nil) mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( - ctx, providertypes.ModuleName, alice, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 29))).Return(nil) + gomock.Any(), providertypes.ModuleName, alice, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 29))).Return(nil) resp, err := ms.WithdrawConsumerFeePool(ctx, &providertypes.MsgWithdrawConsumerFeePool{ Signer: alice.String(), ConsumerId: consumerId, @@ -376,17 +418,17 @@ func TestWithdrawConsumerFeePool_GovClawback(t *testing.T) { poolAddr := k.GetConsumerFeePoolAddress(consumerId) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, distrAddr, "uphoton"), math.NewInt(100))) + collections.Join3(consumerId, "uphoton", distrAddr), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uphoton"), math.NewInt(100))) mocks.MockBankKeeper.EXPECT().GetBalance(gomock.Any(), poolAddr, "uphoton"). Return(sdk.NewInt64Coin("uphoton", 100)) mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( - ctx, poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))).Return(nil) - // Gov clawback: tokens forwarded to community pool, not raw bank send + gomock.Any(), poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))).Return(nil) + // Gov clawback: tokens forwarded to community pool via cache-context, not raw bank send. mocks.MockDistributionKeeper.EXPECT().FundCommunityPool( - ctx, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), providerAddr).Return(nil) + gomock.Any(), sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), providerAddr).Return(nil) _, err := ms.WithdrawConsumerFeePool(ctx, &providertypes.MsgWithdrawConsumerFeePool{ Signer: k.GetAuthority(), ConsumerId: consumerId, @@ -410,7 +452,7 @@ func TestWithdrawConsumerFeePool_AtomicMultiDenomAbort(t *testing.T) { // shares; the second must fail and the cache-context rollback must // restore alice's uatone shares to their pre-call value. require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, "uatone"), math.NewInt(50))) + collections.Join3(consumerId, "uatone", alice), math.NewInt(50))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uatone"), math.NewInt(50))) @@ -430,7 +472,7 @@ func TestWithdrawConsumerFeePool_AtomicMultiDenomAbort(t *testing.T) { require.Error(t, err) // alice's uatone shares should remain 50 (rollback proved) - s, _ := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, alice, "uatone")) + s, _ := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, "uatone", alice)) require.Equal(t, math.NewInt(50), s) } @@ -465,7 +507,7 @@ func TestSweepConsumerFeePool_OwnerTriggers(t *testing.T) { alice := sdk.AccAddress([]byte("alice___________")) poolAddr := k.GetConsumerFeePoolAddress(consumerId) require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, alice, "uphoton"), math.NewInt(100))) + collections.Join3(consumerId, "uphoton", alice), math.NewInt(100))) require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uphoton"), math.NewInt(100))) diff --git a/x/vaas/provider/keeper/send_restriction.go b/x/vaas/provider/keeper/send_restriction.go index 2afdc3f..234a99f 100644 --- a/x/vaas/provider/keeper/send_restriction.go +++ b/x/vaas/provider/keeper/send_restriction.go @@ -21,7 +21,12 @@ func (k Keeper) FeePoolSendRestriction() func( return func( ctx context.Context, fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, ) (sdk.AccAddress, error) { - if _, err := k.FeePoolAddressToConsumerId.Get(ctx, toAddr); err != nil { + isFeePool, err := k.FeePoolAddressToConsumerId.Has(ctx, toAddr) + if err != nil { + return nil, errorsmod.Wrapf(err, + "fee-pool send restriction lookup for %s", toAddr.String()) + } + if !isFeePool { return toAddr, nil } if fromAddr.Equals(providerAddr) { diff --git a/x/vaas/provider/keeper/send_restriction_test.go b/x/vaas/provider/keeper/send_restriction_test.go index fea833b..510da69 100644 --- a/x/vaas/provider/keeper/send_restriction_test.go +++ b/x/vaas/provider/keeper/send_restriction_test.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" testkeeper "github.com/allinbits/vaas/testutil/keeper" providertypes "github.com/allinbits/vaas/x/vaas/provider/types" @@ -41,3 +42,117 @@ func TestFeePoolSendRestriction(t *testing.T) { require.NoError(t, err) require.Equal(t, poolAddr, to) } + +// TestFeePoolSendRestriction_BlocksAllNonProviderSenders ensures that the +// restriction blocks sends from arbitrary module accounts (gov, distribution, +// IBC transfer, etc.), not only from end-user EOAs. Only the provider module +// is whitelisted. +func TestFeePoolSendRestriction_BlocksAllNonProviderSenders(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := uint64(0) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, poolAddr, consumerId)) + restrict := k.FeePoolSendRestriction() + amt := sdk.NewCoins(sdk.NewInt64Coin("uphoton", 1)) + + // Cosmos-SDK module accounts and an arbitrary EOA must all be rejected. + senders := []sdk.AccAddress{ + authtypes.NewModuleAddress(disttypes.ModuleName), + authtypes.NewModuleAddress("gov"), + authtypes.NewModuleAddress("transfer"), + sdk.AccAddress([]byte("attacker________")), + } + for _, from := range senders { + _, err := restrict(ctx, from, poolAddr, amt) + require.ErrorIs(t, err, providertypes.ErrUnsolicitedFeePoolDeposit, + "sender %s should be blocked", from.String()) + } +} + +// TestFeePoolSendRestriction_CrossConsumerIsolation: a send to one consumer's +// fee pool from another consumer's fee pool is still blocked (only the +// provider module bypasses the restriction). +func TestFeePoolSendRestriction_CrossConsumerIsolation(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + poolA := k.GetConsumerFeePoolAddress(0) + poolB := k.GetConsumerFeePoolAddress(1) + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, poolA, uint64(0))) + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, poolB, uint64(1))) + + restrict := k.FeePoolSendRestriction() + amt := sdk.NewCoins(sdk.NewInt64Coin("uphoton", 1)) + _, err := restrict(ctx, poolA, poolB, amt) + require.ErrorIs(t, err, providertypes.ErrUnsolicitedFeePoolDeposit) +} + +// TestFeePoolSendRestriction_DeletedConsumerPassesThrough: once a consumer is +// deleted its reverse-lookup entry is gone, so sends to its (now-orphan) +// pool address pass through. This is the documented behavior — funds sent +// after delete are an unrecoverable user error, but the bank layer doesn't +// block them. +func TestFeePoolSendRestriction_DeletedConsumerPassesThrough(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + deletedPool := k.GetConsumerFeePoolAddress(42) + // Reverse-lookup entry intentionally NOT set. + restrict := k.FeePoolSendRestriction() + user := sdk.AccAddress([]byte("user____________")) + amt := sdk.NewCoins(sdk.NewInt64Coin("uphoton", 1)) + + to, err := restrict(ctx, user, deletedPool, amt) + require.NoError(t, err) + require.Equal(t, deletedPool, to) +} + +// TestFeePoolSendRestriction_OutboundFromPoolUnaffected: sends FROM a fee +// pool (fee collection, withdraw, sweep) pass regardless of the destination. +func TestFeePoolSendRestriction_OutboundFromPoolUnaffected(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := uint64(0) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, poolAddr, consumerId)) + + restrict := k.FeePoolSendRestriction() + recipient := sdk.AccAddress([]byte("recipient_______")) + amt := sdk.NewCoins(sdk.NewInt64Coin("uphoton", 1)) + + to, err := restrict(ctx, poolAddr, recipient, amt) + require.NoError(t, err) + require.Equal(t, recipient, to) +} + +// TestFeePoolSendRestriction_GovDistributionFundingBlocked: gov funding from +// the distribution module account goes through `DistributeFromFeePool` → +// provider module → fee pool. The first hop's destination is the provider +// module account (not a pool), so the restriction passes that hop. A direct +// send from the distribution module to a pool, however, is NOT sanctioned +// and must be blocked. +func TestFeePoolSendRestriction_GovDistributionFundingBlocked(t *testing.T) { + k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := uint64(0) + poolAddr := k.GetConsumerFeePoolAddress(consumerId) + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, poolAddr, consumerId)) + + restrict := k.FeePoolSendRestriction() + distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) + providerAddr := authtypes.NewModuleAddress(providertypes.ModuleName) + amt := sdk.NewCoins(sdk.NewInt64Coin("uphoton", 1)) + + // distribution → provider module: passes (destination not a pool). + to, err := restrict(ctx, distrAddr, providerAddr, amt) + require.NoError(t, err) + require.Equal(t, providerAddr, to) + + // distribution → pool directly: blocked. + _, err = restrict(ctx, distrAddr, poolAddr, amt) + require.ErrorIs(t, err, providertypes.ErrUnsolicitedFeePoolDeposit) +} diff --git a/x/vaas/provider/types/errors.go b/x/vaas/provider/types/errors.go index 6fc64de..aca8d81 100644 --- a/x/vaas/provider/types/errors.go +++ b/x/vaas/provider/types/errors.go @@ -32,4 +32,6 @@ var ( ErrUnsolicitedFeePoolDeposit = errorsmod.Register(ModuleName, 24, "direct sends to consumer fee pool addresses are not permitted; use MsgFundConsumerFeePool") ErrInvalidFundDenom = errorsmod.Register(ModuleName, 25, "deposit denom does not match the current fees_per_block denom") ErrFeePoolSweepFailed = errorsmod.Register(ModuleName, 26, "consumer fee pool sweep failed") + ErrDepositTooSmall = errorsmod.Register(ModuleName, 27, "deposit too small to mint any shares") + ErrSubShareWithdraw = errorsmod.Register(ModuleName, 28, "withdraw amount too small to burn any shares") ) diff --git a/x/vaas/provider/types/genesis.go b/x/vaas/provider/types/genesis.go index aadad2b..0bc0e40 100644 --- a/x/vaas/provider/types/genesis.go +++ b/x/vaas/provider/types/genesis.go @@ -19,6 +19,7 @@ func NewGenesisState( validatorConsumerPubkeys []ValidatorConsumerPubKey, validatorsByConsumerAddr []ValidatorByConsumerAddr, consumerAddrsToPrune []ConsumerAddrsToPrune, + consumerFeePoolShares []ConsumerFeePoolShare, ) *GenesisState { return &GenesisState{ ValsetUpdateId: vscID, @@ -28,6 +29,7 @@ func NewGenesisState( ValidatorConsumerPubkeys: validatorConsumerPubkeys, ValidatorsByConsumerAddr: validatorsByConsumerAddr, ConsumerAddrsToPrune: consumerAddrsToPrune, + ConsumerFeePoolShares: consumerFeePoolShares, } } @@ -75,6 +77,53 @@ func (gs GenesisState) Validate() error { return err } + if err := validateConsumerFeePoolShares(gs.ConsumerFeePoolShares, seenConsumerIds); err != nil { + return errorsmod.Wrap(vaastypes.ErrInvalidGenesis, err.Error()) + } + + return nil +} + +// validateConsumerFeePoolShares rejects malformed share records before +// InitGenesis would otherwise panic on them: bad bech32, empty denom, +// non-positive shares, duplicate (consumer, depositor, denom) triples, +// and orphan consumer ids not present in ConsumerStates. +func validateConsumerFeePoolShares( + shares []ConsumerFeePoolShare, knownConsumerIds map[uint64]bool, +) error { + type triple struct { + consumerId uint64 + depositor string + denom string + } + seen := map[triple]bool{} + for _, s := range shares { + if _, err := sdk.AccAddressFromBech32(s.Depositor); err != nil { + return fmt.Errorf("invalid depositor %q for consumer %d: %w", + s.Depositor, s.ConsumerId, err) + } + if err := sdk.ValidateDenom(s.Denom); err != nil { + return fmt.Errorf("invalid denom %q for consumer %d depositor %s: %w", + s.Denom, s.ConsumerId, s.Depositor, err) + } + if s.Shares.IsNil() { + return fmt.Errorf("nil shares for consumer %d depositor %s denom %s", + s.ConsumerId, s.Depositor, s.Denom) + } + if !s.Shares.IsPositive() { + return fmt.Errorf("non-positive shares for consumer %d depositor %s denom %s: %s", + s.ConsumerId, s.Depositor, s.Denom, s.Shares) + } + if !knownConsumerIds[s.ConsumerId] { + return fmt.Errorf("share record references unknown consumer %d", s.ConsumerId) + } + k := triple{s.ConsumerId, s.Depositor, s.Denom} + if seen[k] { + return fmt.Errorf("duplicate share record (consumer=%d, depositor=%s, denom=%s)", + s.ConsumerId, s.Depositor, s.Denom) + } + seen[k] = true + } return nil } diff --git a/x/vaas/provider/types/genesis_test.go b/x/vaas/provider/types/genesis_test.go index 58e7550..9ed7317 100644 --- a/x/vaas/provider/types/genesis_test.go +++ b/x/vaas/provider/types/genesis_test.go @@ -4,6 +4,8 @@ import ( "testing" "time" + sdkmath "cosmossdk.io/math" + "github.com/allinbits/vaas/testutil/crypto" "github.com/allinbits/vaas/x/vaas/provider/types" vaastypes "github.com/allinbits/vaas/x/vaas/types" @@ -53,6 +55,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), true, }, @@ -71,6 +74,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), true, }, @@ -85,6 +89,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), true, }, @@ -98,6 +103,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -111,6 +117,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -126,6 +133,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -142,6 +150,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -155,6 +164,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -168,6 +178,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), true, }, @@ -185,6 +196,7 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, nil, + nil, ), false, }, @@ -203,6 +215,104 @@ func TestValidateGenesisState(t *testing.T) { } } +func TestValidateGenesisState_FeePoolShares(t *testing.T) { + alice := sdk.AccAddress([]byte("alice___________")).String() + bob := sdk.AccAddress([]byte("bob_____________")).String() + cs := types.ConsumerState{ + ConsumerId: 0, + ChainId: "chain-1", + Phase: types.CONSUMER_PHASE_REGISTERED, + OwnerAddress: sdk.AccAddress([]byte("vaas-test-owner-1234")).String(), + } + + build := func(shares ...types.ConsumerFeePoolShare) *types.GenesisState { + gs := types.NewGenesisState( + types.DefaultValsetUpdateID, nil, + []types.ConsumerState{cs}, + types.DefaultParams(), + nil, nil, nil, + shares, + ) + return gs + } + + t.Run("valid share record", func(t *testing.T) { + err := build(types.ConsumerFeePoolShare{ + ConsumerId: 0, Depositor: alice, Denom: "uphoton", + Shares: sdkmath.NewInt(100), + }).Validate() + require.NoError(t, err) + }) + + t.Run("invalid depositor bech32", func(t *testing.T) { + err := build(types.ConsumerFeePoolShare{ + ConsumerId: 0, Depositor: "not-a-bech32", Denom: "uphoton", + Shares: sdkmath.NewInt(100), + }).Validate() + require.Error(t, err) + }) + + t.Run("invalid denom", func(t *testing.T) { + err := build(types.ConsumerFeePoolShare{ + ConsumerId: 0, Depositor: alice, Denom: "", + Shares: sdkmath.NewInt(100), + }).Validate() + require.Error(t, err) + }) + + t.Run("zero shares", func(t *testing.T) { + err := build(types.ConsumerFeePoolShare{ + ConsumerId: 0, Depositor: alice, Denom: "uphoton", + Shares: sdkmath.ZeroInt(), + }).Validate() + require.Error(t, err) + }) + + t.Run("negative shares", func(t *testing.T) { + err := build(types.ConsumerFeePoolShare{ + ConsumerId: 0, Depositor: alice, Denom: "uphoton", + Shares: sdkmath.NewInt(-1), + }).Validate() + require.Error(t, err) + }) + + t.Run("orphan consumer id", func(t *testing.T) { + err := build(types.ConsumerFeePoolShare{ + ConsumerId: 99, Depositor: alice, Denom: "uphoton", + Shares: sdkmath.NewInt(100), + }).Validate() + require.Error(t, err) + }) + + t.Run("duplicate triple", func(t *testing.T) { + err := build( + types.ConsumerFeePoolShare{ + ConsumerId: 0, Depositor: alice, Denom: "uphoton", + Shares: sdkmath.NewInt(50), + }, + types.ConsumerFeePoolShare{ + ConsumerId: 0, Depositor: alice, Denom: "uphoton", + Shares: sdkmath.NewInt(50), + }, + ).Validate() + require.Error(t, err) + }) + + t.Run("two depositors same denom is allowed", func(t *testing.T) { + err := build( + types.ConsumerFeePoolShare{ + ConsumerId: 0, Depositor: alice, Denom: "uphoton", + Shares: sdkmath.NewInt(60), + }, + types.ConsumerFeePoolShare{ + ConsumerId: 0, Depositor: bob, Denom: "uphoton", + Shares: sdkmath.NewInt(40), + }, + ).Validate() + require.NoError(t, err) + }) +} + func TestConsumerStateValidatePerPhase(t *testing.T) { validMetadata := types.ConsumerMetadata{Name: "n", Description: "d", Metadata: "m"} validInit := &types.ConsumerInitializationParameters{ diff --git a/x/vaas/provider/types/msg.go b/x/vaas/provider/types/msg.go index 7f196d1..6a166a7 100644 --- a/x/vaas/provider/types/msg.go +++ b/x/vaas/provider/types/msg.go @@ -462,10 +462,15 @@ func (msg MsgSweepConsumerFeePool) ValidateBasic() error { if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid signer: %s", err) } + seen := make(map[string]struct{}, len(msg.Denoms)) for _, d := range msg.Denoms { if err := sdk.ValidateDenom(d); err != nil { return errorsmod.Wrapf(ErrInvalidFundDenom, "invalid denom %q: %s", d, err) } + if _, dup := seen[d]; dup { + return errorsmod.Wrapf(ErrInvalidFundDenom, "duplicate denom %q", d) + } + seen[d] = struct{}{} } return nil } From 8a8a1276bf7bd81cff9bd9fa179b653b9f678beb Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Fri, 22 May 2026 19:53:18 +0200 Subject: [PATCH 15/18] route gov-authority deposits directly to the pool --- docs/consumer-fee-pool.md | 4 ++- x/vaas/provider/keeper/msg_server.go | 27 +++++++------- x/vaas/provider/keeper/msg_server_test.go | 5 +-- x/vaas/provider/keeper/send_restriction.go | 10 +++--- .../provider/keeper/send_restriction_test.go | 36 +++++++------------ 5 files changed, 37 insertions(+), 45 deletions(-) diff --git a/docs/consumer-fee-pool.md b/docs/consumer-fee-pool.md index ed417fe..0445158 100644 --- a/docs/consumer-fee-pool.md +++ b/docs/consumer-fee-pool.md @@ -92,7 +92,9 @@ silently lost. - `vaas query consumer-fee-pool-claim ` — one depositor's claim across all denoms. Pass the gov authority address to - query the community pool's holdings. + query the community pool's holdings (the query aliases the gov authority + to the distribution module account, which is the depositor of record for + community-pool funding). - `vaas query consumer-fee-pool-claims ` — paginated list of all depositors with non-zero claims. diff --git a/x/vaas/provider/keeper/msg_server.go b/x/vaas/provider/keeper/msg_server.go index 3c2dbf2..315e699 100644 --- a/x/vaas/provider/keeper/msg_server.go +++ b/x/vaas/provider/keeper/msg_server.go @@ -504,15 +504,11 @@ func (k msgServer) FundConsumerFeePool( } poolAddr := k.GetConsumerFeePoolAddress(msg.ConsumerId) - providerAddr := authtypes.NewModuleAddress(types.ModuleName) coins := sdk.NewCoins(msg.Amount) - // Determine depositor identity and source-of-funds path. var depositor sdk.AccAddress - if msg.Signer == k.GetAuthority() { - if err := k.distributionKeeper.DistributeFromFeePool(ctx, coins, providerAddr); err != nil { - return nil, err - } + isGov := msg.Signer == k.GetAuthority() + if isGov { depositor = authtypes.NewModuleAddress(disttypes.ModuleName) } else { signerAddr, err := sdk.AccAddressFromBech32(msg.Signer) @@ -527,16 +523,23 @@ func (k msgServer) FundConsumerFeePool( depositor = signerAddr } - // Mint shares using PRE-deposit balance. + // MintShares reads the pool balance, so it must run before the + // bank-into-pool move below; otherwise share math sees the post-deposit + // balance. if err := k.MintShares(ctx, msg.ConsumerId, depositor, msg.Amount); err != nil { return nil, err } - // Second hop: provider module → fee pool address (SendRestriction allows this). - if err := k.bankKeeper.SendCoinsFromModuleToAccount( - ctx, types.ModuleName, poolAddr, coins, - ); err != nil { - return nil, err + if isGov { + if err := k.distributionKeeper.DistributeFromFeePool(ctx, coins, poolAddr); err != nil { + return nil, err + } + } else { + if err := k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, types.ModuleName, poolAddr, coins, + ); err != nil { + return nil, err + } } ctx.EventManager().EmitEvent(sdk.NewEvent( diff --git a/x/vaas/provider/keeper/msg_server_test.go b/x/vaas/provider/keeper/msg_server_test.go index 5149484..4294583 100644 --- a/x/vaas/provider/keeper/msg_server_test.go +++ b/x/vaas/provider/keeper/msg_server_test.go @@ -282,16 +282,13 @@ func TestFundConsumerFeePool_GovAuthority(t *testing.T) { govAddr := k.GetAuthority() distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) - providerAddr := authtypes.NewModuleAddress(providertypes.ModuleName) poolAddr := k.GetConsumerFeePoolAddress(consumerId) amount := sdk.NewInt64Coin("uphoton", 1000) mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). Return(sdk.NewInt64Coin("uphoton", 0)) mocks.MockDistributionKeeper.EXPECT().DistributeFromFeePool( - ctx, sdk.NewCoins(amount), providerAddr).Return(nil) - mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( - ctx, providertypes.ModuleName, poolAddr, sdk.NewCoins(amount)).Return(nil) + ctx, sdk.NewCoins(amount), poolAddr).Return(nil) _, err := ms.FundConsumerFeePool(ctx, &providertypes.MsgFundConsumerFeePool{ Signer: govAddr, ConsumerId: consumerId, Amount: amount, diff --git a/x/vaas/provider/keeper/send_restriction.go b/x/vaas/provider/keeper/send_restriction.go index 234a99f..86eb098 100644 --- a/x/vaas/provider/keeper/send_restriction.go +++ b/x/vaas/provider/keeper/send_restriction.go @@ -9,15 +9,17 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" ) -// FeePoolSendRestriction returns a bank send-restriction that rejects any -// send to a known active consumer fee pool address unless the source is the -// provider module account itself. +// FeePoolSendRestriction returns a bank send-restriction that rejects sends +// to a known active consumer fee pool address unless the sender is the +// provider module account or the distribution module account. func (k Keeper) FeePoolSendRestriction() func( ctx context.Context, fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, ) (sdk.AccAddress, error) { providerAddr := authtypes.NewModuleAddress(types.ModuleName) + distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) return func( ctx context.Context, fromAddr, toAddr sdk.AccAddress, amount sdk.Coins, ) (sdk.AccAddress, error) { @@ -29,7 +31,7 @@ func (k Keeper) FeePoolSendRestriction() func( if !isFeePool { return toAddr, nil } - if fromAddr.Equals(providerAddr) { + if fromAddr.Equals(providerAddr) || fromAddr.Equals(distrAddr) { return toAddr, nil } return nil, errorsmod.Wrapf(types.ErrUnsolicitedFeePoolDeposit, diff --git a/x/vaas/provider/keeper/send_restriction_test.go b/x/vaas/provider/keeper/send_restriction_test.go index 510da69..c20a565 100644 --- a/x/vaas/provider/keeper/send_restriction_test.go +++ b/x/vaas/provider/keeper/send_restriction_test.go @@ -43,11 +43,10 @@ func TestFeePoolSendRestriction(t *testing.T) { require.Equal(t, poolAddr, to) } -// TestFeePoolSendRestriction_BlocksAllNonProviderSenders ensures that the -// restriction blocks sends from arbitrary module accounts (gov, distribution, -// IBC transfer, etc.), not only from end-user EOAs. Only the provider module -// is whitelisted. -func TestFeePoolSendRestriction_BlocksAllNonProviderSenders(t *testing.T) { +// TestFeePoolSendRestriction_BlocksUnsanctionedSenders ensures that the +// restriction blocks sends from module accounts and EOAs other than the two +// sanctioned ones (provider, distribution). +func TestFeePoolSendRestriction_BlocksUnsanctionedSenders(t *testing.T) { k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() @@ -57,9 +56,7 @@ func TestFeePoolSendRestriction_BlocksAllNonProviderSenders(t *testing.T) { restrict := k.FeePoolSendRestriction() amt := sdk.NewCoins(sdk.NewInt64Coin("uphoton", 1)) - // Cosmos-SDK module accounts and an arbitrary EOA must all be rejected. senders := []sdk.AccAddress{ - authtypes.NewModuleAddress(disttypes.ModuleName), authtypes.NewModuleAddress("gov"), authtypes.NewModuleAddress("transfer"), sdk.AccAddress([]byte("attacker________")), @@ -72,8 +69,8 @@ func TestFeePoolSendRestriction_BlocksAllNonProviderSenders(t *testing.T) { } // TestFeePoolSendRestriction_CrossConsumerIsolation: a send to one consumer's -// fee pool from another consumer's fee pool is still blocked (only the -// provider module bypasses the restriction). +// fee pool from another consumer's fee pool is blocked — fee pool addresses +// are not on the sanctioned-sender list. func TestFeePoolSendRestriction_CrossConsumerIsolation(t *testing.T) { k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() @@ -128,13 +125,10 @@ func TestFeePoolSendRestriction_OutboundFromPoolUnaffected(t *testing.T) { require.Equal(t, recipient, to) } -// TestFeePoolSendRestriction_GovDistributionFundingBlocked: gov funding from -// the distribution module account goes through `DistributeFromFeePool` → -// provider module → fee pool. The first hop's destination is the provider -// module account (not a pool), so the restriction passes that hop. A direct -// send from the distribution module to a pool, however, is NOT sanctioned -// and must be blocked. -func TestFeePoolSendRestriction_GovDistributionFundingBlocked(t *testing.T) { +// TestFeePoolSendRestriction_DistributionSenderAllowed: sends from the +// distribution module account to a fee pool are allowed (gov-fund path uses +// DistributeFromFeePool to deposit directly). +func TestFeePoolSendRestriction_DistributionSenderAllowed(t *testing.T) { k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() @@ -144,15 +138,9 @@ func TestFeePoolSendRestriction_GovDistributionFundingBlocked(t *testing.T) { restrict := k.FeePoolSendRestriction() distrAddr := authtypes.NewModuleAddress(disttypes.ModuleName) - providerAddr := authtypes.NewModuleAddress(providertypes.ModuleName) amt := sdk.NewCoins(sdk.NewInt64Coin("uphoton", 1)) - // distribution → provider module: passes (destination not a pool). - to, err := restrict(ctx, distrAddr, providerAddr, amt) + to, err := restrict(ctx, distrAddr, poolAddr, amt) require.NoError(t, err) - require.Equal(t, providerAddr, to) - - // distribution → pool directly: blocked. - _, err = restrict(ctx, distrAddr, poolAddr, amt) - require.ErrorIs(t, err, providertypes.ErrUnsolicitedFeePoolDeposit) + require.Equal(t, poolAddr, to) } From 381b62d67a8ea0e6b8fc4a7d8ff8dc615b8b45ca Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Fri, 22 May 2026 16:28:03 +0200 Subject: [PATCH 16/18] e2e tests for fund/withdraw/sweep, send restriction, and gov subsidy --- tests/e2e/e2e_debt_test.go | 35 ++- tests/e2e/e2e_fee_pool_test.go | 287 ++++++++++++++++++++++++ tests/e2e/e2e_test.go | 3 + tests/e2e/gov_proposal_helpers_test.go | 294 +++++++++++++++++++++++++ 4 files changed, 616 insertions(+), 3 deletions(-) create mode 100644 tests/e2e/e2e_fee_pool_test.go create mode 100644 tests/e2e/gov_proposal_helpers_test.go diff --git a/tests/e2e/e2e_debt_test.go b/tests/e2e/e2e_debt_test.go index fbace25..aa88eb7 100644 --- a/tests/e2e/e2e_debt_test.go +++ b/tests/e2e/e2e_debt_test.go @@ -4,6 +4,8 @@ import ( "encoding/json" "strings" "time" + + sdk "github.com/cosmos/cosmos-sdk/types" ) // queryConsumerFeePoolAddress returns the provider-side fee pool account for a @@ -55,9 +57,15 @@ func (s *IntegrationTestSuite) consumerBankSendDryRun() (string, error) { return stderr.String(), err } -// providerFundAddress sends tokens from val to addr on the provider chain. +// providerFundAddress sends `amount` from val to `addr` on the provider chain +// and blocks until the recipient's balance for the funded denom has grown, +// so callers can immediately issue txs from `addr`. func (s *IntegrationTestSuite) providerFundAddress(addr, amount string) { - _, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + coin, err := sdk.ParseCoinNormalized(amount) + s.Require().NoError(err, "invalid amount %q", amount) + before := s.providerQueryBalance(addr, coin.Denom) + + _, _, err = s.dockerExec(s.providerValRes[0].Container.ID, []string{ providerBinary, "tx", "bank", "send", "val", addr, amount, "--from", "val", "--home", providerHomePath, @@ -67,6 +75,27 @@ func (s *IntegrationTestSuite) providerFundAddress(addr, amount string) { "-y", }) s.Require().NoError(err, "failed to fund provider address %s", addr) + + s.Require().Eventuallyf(func() bool { + return s.providerQueryBalance(addr, coin.Denom) > before + }, 30*time.Second, 2*time.Second, + "balance of %s in %s did not grow after fund (before=%d)", addr, coin.Denom, before) +} + +// providerFundConsumerFeePool deposits `amount` into the named consumer's +// fee pool via MsgFundConsumerFeePool, signed by val. +func (s *IntegrationTestSuite) providerFundConsumerFeePool(consumerID, amount string) { + _, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "tx", "provider", "fund-consumer-fee-pool", + consumerID, amount, + "--from", "val", + "--home", providerHomePath, + "--keyring-backend", "test", + "--chain-id", providerChainID, + "--fees", "10000" + bondDenom, + "-y", + }) + s.Require().NoError(err, "failed to fund consumer %s fee pool", consumerID) time.Sleep(3 * time.Second) } @@ -93,7 +122,7 @@ func (s *IntegrationTestSuite) testConsumerDebtFlow() { "consumer did not enter debt; last dry-run did not surface debt error") s.T().Log("funding consumer fee pool on provider...") - s.providerFundAddress(feePoolAddr, "10000000"+bondDenom) + s.providerFundConsumerFeePool("0", "10000000"+bondDenom) s.T().Log("waiting for consumer to exit debt (bank send should succeed)...") s.Require().Eventuallyf(func() bool { diff --git a/tests/e2e/e2e_fee_pool_test.go b/tests/e2e/e2e_fee_pool_test.go new file mode 100644 index 0000000..f611c00 --- /dev/null +++ b/tests/e2e/e2e_fee_pool_test.go @@ -0,0 +1,287 @@ +package e2e + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// providerQueryBalance returns the bech32-addressed account's balance for +// `denom` on the provider, as an int64. +func (s *IntegrationTestSuite) providerQueryBalance(addr, denom string) int64 { + stdout, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "query", "bank", "balances", addr, + "--home", providerHomePath, + "--output", "json", + }) + s.Require().NoError(err) + var res struct { + Balances []struct { + Denom string `json:"denom"` + Amount string `json:"amount"` + } `json:"balances"` + } + s.Require().NoError(json.Unmarshal(stdout.Bytes(), &res)) + for _, b := range res.Balances { + if b.Denom == denom { + var n int64 + fmt.Sscanf(b.Amount, "%d", &n) + return n + } + } + return 0 +} + +// providerQueryFeePoolClaim returns the depositor's claim on the consumer's +// fee pool in the given denom (returns 0 if no claim). +func (s *IntegrationTestSuite) providerQueryFeePoolClaim(consumerID, depositor, denom string) int64 { + stdout, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "query", "provider", "consumer-fee-pool-claim", + consumerID, depositor, + "--home", providerHomePath, + "--output", "json", + }) + s.Require().NoError(err) + var res struct { + Claim []struct { + Denom string `json:"denom"` + Amount string `json:"amount"` + } `json:"claim"` + } + s.Require().NoError(json.Unmarshal(stdout.Bytes(), &res)) + for _, c := range res.Claim { + if c.Denom == denom { + var n int64 + fmt.Sscanf(c.Amount, "%d", &n) + return n + } + } + return 0 +} + +// providerKeyAddress returns the bech32 address of the named key on the +// provider. +func (s *IntegrationTestSuite) providerKeyAddress(key string) string { + stdout, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "keys", "show", key, "-a", + "--home", providerHomePath, + "--keyring-backend", "test", + }) + s.Require().NoError(err) + return strings.TrimSpace(stdout.String()) +} + +// providerFundConsumerFeePoolFrom is the multi-signer variant of +// providerFundConsumerFeePool (which is hardcoded to --from val). +func (s *IntegrationTestSuite) providerFundConsumerFeePoolFrom(consumerID, from, amount string) { + _, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "tx", "provider", "fund-consumer-fee-pool", + consumerID, amount, + "--from", from, + "--home", providerHomePath, + "--keyring-backend", "test", + "--chain-id", providerChainID, + "--fees", "10000" + bondDenom, + "-y", + }) + s.Require().NoError(err) + time.Sleep(3 * time.Second) +} + +// providerWithdrawFeePool calls `tx provider withdraw-consumer-fee-pool`. +func (s *IntegrationTestSuite) providerWithdrawFeePool(consumerID, from, coins string) { + _, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "tx", "provider", "withdraw-consumer-fee-pool", + consumerID, coins, + "--from", from, + "--home", providerHomePath, + "--keyring-backend", "test", + "--chain-id", providerChainID, + "--fees", "10000" + bondDenom, + "-y", + }) + s.Require().NoError(err) + time.Sleep(3 * time.Second) +} + +// providerSweepFeePool calls `tx provider sweep-consumer-fee-pool`. +func (s *IntegrationTestSuite) providerSweepFeePool(consumerID, from string) { + _, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "tx", "provider", "sweep-consumer-fee-pool", + consumerID, + "--from", from, + "--home", providerHomePath, + "--keyring-backend", "test", + "--chain-id", providerChainID, + "--fees", "10000" + bondDenom, + "-y", + }) + s.Require().NoError(err) + time.Sleep(3 * time.Second) +} + +// providerFundCommunityPool funds the community pool from val on the provider +// and blocks until the community-pool balance for the funded denom has grown, +// so callers can immediately issue follow-up txs without racing the previous +// tx's account-sequence commit. +func (s *IntegrationTestSuite) providerFundCommunityPool(amount string) { + coin, err := sdk.ParseCoinNormalized(amount) + s.Require().NoError(err, "invalid amount %q", amount) + before := s.queryCommunityPoolBalance(coin.Denom) + + _, _, err = s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "tx", "distribution", "fund-community-pool", amount, + "--from", "val", + "--home", providerHomePath, + "--keyring-backend", "test", + "--chain-id", providerChainID, + "--fees", "10000" + bondDenom, + "-y", + }) + s.Require().NoError(err) + + s.Require().Eventuallyf(func() bool { + return s.queryCommunityPoolBalance(coin.Denom) > before + }, 30*time.Second, 2*time.Second, + "community pool %s did not grow after fund (before=%d)", coin.Denom, before) +} + +// testFeePoolFundWithdrawSweep exercises deposit + per-depositor withdraw + +// owner-triggered sweep with two distinct funders. val owns consumer 0 +// (registered during suite setup); user is a second funder. +// +// Assertions are deliberately tolerant: the consumer is in LAUNCHED phase, +// so CollectFeesFromConsumers is actively draining the pool every block. +// Exact equality would race the fee EndBlocker. The test verifies the +// wiring (CLI dispatches to handlers, share math runs, sweep distributes), +// not exact share-math results — those are covered by unit tests. +func (s *IntegrationTestSuite) testFeePoolFundWithdrawSweep() { + s.Run("fee pool fund/withdraw/sweep", func() { + const consumerID = "0" + denom := bondDenom + valAddr := s.providerKeyAddress("val") + userAddr := s.providerKeyAddress("user") + + // Make sure user has enough balance to fund + pay fees. + s.providerFundAddress(userAddr, "20000000"+denom) + + // Two funders. + s.providerFundConsumerFeePool(consumerID, "5000"+denom) // --from val + s.providerFundConsumerFeePoolFrom(consumerID, "user", "3000"+denom) // --from user + + valClaim := s.providerQueryFeePoolClaim(consumerID, valAddr, denom) + userClaim := s.providerQueryFeePoolClaim(consumerID, userAddr, denom) + s.Require().Greater(valClaim, int64(0), "val should have a non-zero claim") + s.Require().Greater(userClaim, int64(0), "user should have a non-zero claim") + + // Partial withdraw by val. Claim should shrink (or stay zero if fees + // consumed everything in the interim, which is unlikely but possible). + s.providerWithdrawFeePool(consumerID, "val", "1000"+denom) + valClaimAfter := s.providerQueryFeePoolClaim(consumerID, valAddr, denom) + s.Require().LessOrEqual(valClaimAfter, valClaim, "claim should not grow after a partial withdraw") + + // Owner sweep. Both should receive a share; their share records are + // gone afterward. + userBalBefore := s.providerQueryBalance(userAddr, denom) + s.providerSweepFeePool(consumerID, "val") + + s.Require().Eventuallyf(func() bool { + return s.providerQueryBalance(userAddr, denom) > userBalBefore + }, 30*time.Second, 2*time.Second, + "user should have received their proportional share from the sweep (before=%d)", userBalBefore) + + // Post-sweep, user's claim is zero (shares were burned). + s.Require().Eventuallyf(func() bool { + return s.providerQueryFeePoolClaim(consumerID, userAddr, denom) == 0 + }, 30*time.Second, 2*time.Second, + "user claim should be zero after sweep burned shares") + }) +} + +// testFeePoolSendRestriction verifies that direct bank sends to a consumer +// fee pool address are blocked by the SendRestriction. Uses --dry-run so +// the ante chain runs (which is where the restriction fires) without +// burning fees on a doomed transaction. +func (s *IntegrationTestSuite) testFeePoolSendRestriction() { + s.Run("fee pool send restriction", func() { + feePoolAddr := s.queryConsumerFeePoolAddress("0") + valAddr := s.providerKeyAddress("val") + + _, stderr, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "tx", "bank", "send", valAddr, feePoolAddr, "1" + bondDenom, + "--from", "val", + "--home", providerHomePath, + "--keyring-backend", "test", + "--chain-id", providerChainID, + "--fees", "10000" + bondDenom, + "--dry-run", + "-y", + }) + combined := stderr.String() + // The restriction's error message contains "consumer fee pool". + // Match on a distinctive substring rather than the exact error code + // so the test tolerates future error-message tweaks. + s.Require().True(err != nil || strings.Contains(combined, "consumer fee pool"), + "direct bank send to fee pool should be rejected: stderr=%q, err=%v", combined, err) + }) +} + +// testFeePoolGovSubsidyClawback verifies the gov-conditional path: +// gov can fund a consumer fee pool from the community pool (with the +// distribution module account credited as the depositor), and gov can +// claw back the unconsumed portion via a withdrawal proposal. +func (s *IntegrationTestSuite) testFeePoolGovSubsidyClawback() { + s.Run("fee pool gov subsidy + clawback", func() { + const consumerID = "0" + denom := bondDenom + govAddr := s.queryGovAuthority() + distrAddr := s.queryModuleAccountAddress("distribution") + + // Seed the community pool so gov has something to spend. + s.providerFundCommunityPool("10000000" + denom) + cpBefore := s.queryCommunityPoolBalance(denom) + s.Require().Greater(cpBefore, int64(0), "community pool seeded") + + fundJSON := fmt.Sprintf(`{ + "messages": [{ + "@type": "/vaas.provider.v1.MsgFundConsumerFeePool", + "signer": %q, + "consumer_id": %q, + "amount": {"denom": %q, "amount": "5000"} + }], + "metadata": "ipfs://test", + "deposit": "10000000%s", + "title": "Subsidize consumer %s", + "summary": "e2e gov subsidy test" +}`, govAddr, consumerID, denom, denom, consumerID) + + s.submitAndPassProposal(fundJSON) + + cpAfterFund := s.queryCommunityPoolBalance(denom) + s.Require().Less(cpAfterFund, cpBefore, "community pool debited by subsidy") + + distrClaim := s.providerQueryFeePoolClaim(consumerID, distrAddr, denom) + s.Require().Greater(distrClaim, int64(0), "distribution module account has a non-zero claim after gov fund") + + clawbackJSON := fmt.Sprintf(`{ + "messages": [{ + "@type": "/vaas.provider.v1.MsgWithdrawConsumerFeePool", + "signer": %q, + "consumer_id": %q, + "amount": [{"denom": %q, "amount": "5000"}] + }], + "metadata": "ipfs://test", + "deposit": "10000000%s", + "title": "Clawback consumer %s subsidy", + "summary": "e2e gov clawback test" +}`, govAddr, consumerID, denom, denom, consumerID) + + s.submitAndPassProposal(clawbackJSON) + + cpAfterClawback := s.queryCommunityPoolBalance(denom) + s.Require().Greater(cpAfterClawback, cpAfterFund, "community pool grew back after clawback") + }) +} diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index b176c90..7711d3a 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -8,6 +8,9 @@ func (s *IntegrationTestSuite) TestVAAS() { s.testProviderOnConsumer() s.testValidatorSetSync() s.testConsumerDebtFlow() + s.testFeePoolSendRestriction() + s.testFeePoolFundWithdrawSweep() + s.testFeePoolGovSubsidyClawback() // Run last: stops the provider container and replaces it with a fresh // one started from the exported genesis. s.testGenesisRoundTrip() diff --git a/tests/e2e/gov_proposal_helpers_test.go b/tests/e2e/gov_proposal_helpers_test.go new file mode 100644 index 0000000..15ed76d --- /dev/null +++ b/tests/e2e/gov_proposal_helpers_test.go @@ -0,0 +1,294 @@ +package e2e + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "strconv" + "strings" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// queryModuleAccountAddress returns the bech32 address of the named module +// account on the provider chain. +func (s *IntegrationTestSuite) queryModuleAccountAddress(name string) string { + stdout, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "query", "auth", "module-account", name, + "--home", providerHomePath, + "--output", "json", + }) + s.Require().NoError(err, "failed to query module account %s", name) + + // JSON shape varies across SDK versions: try the common nests in order. + var res struct { + Account struct { + Address string `json:"address"` + BaseAccount struct { + Address string `json:"address"` + } `json:"base_account"` + Value struct { + Address string `json:"address"` + BaseAccount struct { + Address string `json:"address"` + } `json:"base_account"` + } `json:"value"` + } `json:"account"` + } + s.Require().NoError(json.Unmarshal(stdout.Bytes(), &res), + "failed to decode module-account response: %s", stdout.String()) + + candidates := []string{ + res.Account.BaseAccount.Address, + res.Account.Value.Address, + res.Account.Value.BaseAccount.Address, + res.Account.Address, + } + for _, addr := range candidates { + if addr != "" { + return addr + } + } + + s.T().Logf("module-account response for %s: %s", name, stdout.String()) + s.Require().Failf("module account address not found", "name=%s", name) + return "" +} + +// queryGovAuthority is a thin wrapper for queryModuleAccountAddress("gov"). +func (s *IntegrationTestSuite) queryGovAuthority() string { + return s.queryModuleAccountAddress("gov") +} + +// queryCommunityPoolBalance returns the current community-pool balance for the +// given denom, truncated to int64 (on-chain value is DecCoins). Returns 0 if +// denom not present. +func (s *IntegrationTestSuite) queryCommunityPoolBalance(denom string) int64 { + stdout, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "query", "distribution", "community-pool", + "--home", providerHomePath, + "--output", "json", + }) + s.Require().NoError(err, "failed to query community pool") + + var res struct { + Pool []string `json:"pool"` + } + s.Require().NoError(json.Unmarshal(stdout.Bytes(), &res), + "failed to decode community-pool response: %s", stdout.String()) + + for _, raw := range res.Pool { + dc, err := sdk.ParseDecCoin(raw) + if err != nil { + continue + } + if dc.Denom == denom { + return dc.Amount.TruncateInt64() + } + } + return 0 +} + +// submitAndPassProposal writes proposalJSON to /tmp/proposal.json in the +// provider container, submits the proposal from "val", votes YES from val, +// waits for tally to execute (15s voting period + a couple of blocks), and +// returns the proposal ID. Fails the test on submit/vote/tally errors. +// +// proposalJSON must be a valid gov v1 proposal body. The submitter and voting +// fees are paid in bondDenom by val. +func (s *IntegrationTestSuite) submitAndPassProposal(proposalJSON string) uint64 { + containerID := s.providerValRes[0].Container.ID + + // 1. Write the proposal body to /tmp/proposal.json via base64 to avoid + // shell-quoting headaches. + payload := base64.StdEncoding.EncodeToString([]byte(proposalJSON)) + _, _, err := s.dockerExec(containerID, []string{ + "sh", "-c", + fmt.Sprintf("echo %s | base64 -d > /tmp/proposal.json", payload), + }) + s.Require().NoError(err, "failed to write proposal.json") + + // 2. Submit the proposal. + stdout, stderr, err := s.dockerExec(containerID, []string{ + providerBinary, "tx", "gov", "submit-proposal", "/tmp/proposal.json", + "--from", "val", + "--home", providerHomePath, + "--keyring-backend", "test", + "--chain-id", providerChainID, + "--fees", "10000" + bondDenom, + "--yes", + "-o", "json", + }) + s.Require().NoErrorf(err, "failed to submit proposal: stdout=%s stderr=%s", + stdout.String(), stderr.String()) + + var submitRes struct { + TxHash string `json:"txhash"` + Code int `json:"code"` + RawLog string `json:"raw_log"` + } + s.Require().NoError(json.Unmarshal(stdout.Bytes(), &submitRes), + "failed to decode submit-proposal response: %s", stdout.String()) + s.Require().Equalf(0, submitRes.Code, "submit-proposal failed: %s", submitRes.RawLog) + s.Require().NotEmpty(submitRes.TxHash, "submit-proposal returned empty txhash: %s", stdout.String()) + + // Poll for the submit tx to land and yield a proposal_id. + var proposalID uint64 + var lastTxOut string + s.Require().Eventuallyf(func() bool { + txOut, _, qerr := s.dockerExec(containerID, []string{ + providerBinary, "query", "tx", submitRes.TxHash, + "--home", providerHomePath, + "--output", "json", + }) + if qerr != nil || txOut.Len() == 0 { + return false + } + lastTxOut = txOut.String() + proposalID = extractProposalID(txOut.Bytes()) + return proposalID != 0 + }, 30*time.Second, 2*time.Second, + "could not parse proposal_id from tx events for %s: last stdout=%s", + submitRes.TxHash, lastTxOut) + + // 3. Vote yes from val. + voteStdout, voteStderr, err := s.dockerExec(containerID, []string{ + providerBinary, "tx", "gov", "vote", fmt.Sprintf("%d", proposalID), "yes", + "--from", "val", + "--home", providerHomePath, + "--keyring-backend", "test", + "--chain-id", providerChainID, + "--fees", "10000" + bondDenom, + "--yes", + }) + s.Require().NoErrorf(err, "failed to vote on proposal %d: stdout=%s stderr=%s", + proposalID, voteStdout.String(), voteStderr.String()) + + // 4. Wait for tally. 30s timeout (15s voting + buffer), 2s tick. + s.Require().Eventuallyf(func() bool { + status := s.queryProposalStatus(proposalID) + switch status { + case "PROPOSAL_STATUS_PASSED": + return true + case "PROPOSAL_STATUS_REJECTED", "PROPOSAL_STATUS_FAILED": + body := s.dumpProposal(proposalID) + s.Require().Failf("proposal terminated unsuccessfully", + "proposal %d ended with status %s; full body: %s", + proposalID, status, body) + return true + default: + return false + } + }, 30*time.Second, 2*time.Second, + "proposal %d did not pass within timeout", proposalID) + + return proposalID +} + +// dumpProposal returns the raw JSON of a gov proposal query, used to surface +// the failed_reason / messages on terminal-bad status. +func (s *IntegrationTestSuite) dumpProposal(proposalID uint64) string { + stdout, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "query", "gov", "proposal", fmt.Sprintf("%d", proposalID), + "--home", providerHomePath, + "--output", "json", + }) + if err != nil { + return fmt.Sprintf("", err) + } + return stdout.String() +} + +// queryProposalStatus returns the textual status of a gov proposal (e.g. +// "PROPOSAL_STATUS_PASSED"). +func (s *IntegrationTestSuite) queryProposalStatus(proposalID uint64) string { + stdout, _, err := s.dockerExec(s.providerValRes[0].Container.ID, []string{ + providerBinary, "query", "gov", "proposal", fmt.Sprintf("%d", proposalID), + "--home", providerHomePath, + "--output", "json", + }) + if err != nil { + s.T().Logf("queryProposalStatus failed: %v", err) + return "" + } + var res struct { + Status string `json:"status"` + Proposal struct { + Status string `json:"status"` + } `json:"proposal"` + } + if err := json.Unmarshal(stdout.Bytes(), &res); err != nil { + s.T().Logf("queryProposalStatus failed: %v", err) + return "" + } + if res.Status != "" { + return res.Status + } + return res.Proposal.Status +} + +// extractProposalID walks a tx-query JSON response and returns the +// submit_proposal.proposal_id event attribute as uint64. Returns 0 if not +// found. +func extractProposalID(raw []byte) uint64 { + type event struct { + Type string `json:"type"` + Attributes []struct { + Key string `json:"key"` + Value string `json:"value"` + } `json:"attributes"` + } + var doc struct { + Events []event `json:"events"` + TxResponse struct { + Events []event `json:"events"` + Logs []struct { + Events []event `json:"events"` + } `json:"logs"` + } `json:"tx_response"` + Logs []struct { + Events []event `json:"events"` + } `json:"logs"` + } + if err := json.Unmarshal(raw, &doc); err != nil { + return 0 + } + + scan := func(events []event) uint64 { + for _, ev := range events { + if ev.Type != "submit_proposal" { + continue + } + for _, attr := range ev.Attributes { + if attr.Key == "proposal_id" { + v := strings.Trim(strings.TrimSpace(attr.Value), "\" ") + id, err := strconv.ParseUint(v, 10, 64) + if err != nil { + continue + } + return id + } + } + } + return 0 + } + + if id := scan(doc.Events); id != 0 { + return id + } + if id := scan(doc.TxResponse.Events); id != 0 { + return id + } + for _, lg := range doc.TxResponse.Logs { + if id := scan(lg.Events); id != 0 { + return id + } + } + for _, lg := range doc.Logs { + if id := scan(lg.Events); id != 0 { + return id + } + } + return 0 +} From ed4f39a6d3c8c97dec994185ce4ae5fded8b1847 Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Fri, 22 May 2026 21:24:16 +0200 Subject: [PATCH 17/18] harden fee pool handlers and queries: sweep events, phase gates, error sentinels, withdraw_path --- proto/vaas/provider/v1/tx.proto | 8 ++- x/vaas/provider/keeper/fee_pool_shares.go | 85 ++++++++++++++++++----- x/vaas/provider/keeper/grpc_query.go | 10 ++- x/vaas/provider/keeper/msg_server.go | 47 ++++++++----- x/vaas/provider/keeper/msg_server_test.go | 55 ++------------- x/vaas/provider/types/errors.go | 1 + x/vaas/provider/types/events.go | 5 ++ x/vaas/provider/types/msg_test.go | 5 ++ x/vaas/provider/types/tx.pb.go | 8 ++- 9 files changed, 138 insertions(+), 86 deletions(-) diff --git a/proto/vaas/provider/v1/tx.proto b/proto/vaas/provider/v1/tx.proto index e4d8661..17f7f93 100644 --- a/proto/vaas/provider/v1/tx.proto +++ b/proto/vaas/provider/v1/tx.proto @@ -190,8 +190,12 @@ message MsgFundConsumerFeePool { message MsgFundConsumerFeePoolResponse {} // MsgWithdrawConsumerFeePool withdraws tokens from the signer's share in a -// consumer fee pool across one or more denoms. The transaction is atomic: -// if any denom in `amount` fails its share check, the whole tx aborts. +// consumer fee pool across one or more denoms. Each amount is interpreted as +// "up to this much": if the signer's claim for a denom is less than the +// requested amount the handler delivers the full claim and burns all of the +// signer's shares for that denom. The transaction is atomic: if the signer +// has no shares at all for any denom in `amount` (or the pool has zero +// balance for that denom), the whole tx aborts. // If the signer is the gov module authority, the withdrawal targets the // distribution module account's shares and tokens are routed back to the // community pool. diff --git a/x/vaas/provider/keeper/fee_pool_shares.go b/x/vaas/provider/keeper/fee_pool_shares.go index 0ac8049..d7efe30 100644 --- a/x/vaas/provider/keeper/fee_pool_shares.go +++ b/x/vaas/provider/keeper/fee_pool_shares.go @@ -2,6 +2,7 @@ package keeper import ( "sort" + "strconv" "github.com/allinbits/vaas/x/vaas/provider/types" @@ -14,6 +15,41 @@ import ( disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" ) +// forwardOrphanToCommunityPool moves a fee-pool balance to the community pool +// when no share records exist for the denom. The orphan case is unreachable +// from valid operations; firing this path indicates state corruption and is +// logged at Error level. +func (k Keeper) forwardOrphanToCommunityPool( + ctx sdk.Context, consumerId uint64, poolAddr sdk.AccAddress, balance sdk.Coin, site string, +) error { + k.Logger(ctx).Error("fee-pool orphan balance forwarded to community pool", + "site", site, + "consumer_id", consumerId, + "denom", balance.Denom, + "amount", balance.Amount.String()) + orphan := sdk.NewCoins(balance) + if err := k.bankKeeper.SendCoinsFromAccountToModule( + ctx, poolAddr, types.ModuleName, orphan, + ); err != nil { + return err + } + providerAddr := authtypes.NewModuleAddress(types.ModuleName) + return k.distributionKeeper.FundCommunityPool(ctx, orphan, providerAddr) +} + +// emitSweepEvent emits one ConsumerFeePoolSweep event per swept denom. +func (k Keeper) emitSweepEvent( + ctx sdk.Context, consumerId uint64, denom string, distributed, dust math.Int, +) { + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeConsumerFeePoolSweep, + sdk.NewAttribute(types.AttributeConsumerId, strconv.FormatUint(consumerId, 10)), + sdk.NewAttribute(types.AttributeDenom, denom), + sdk.NewAttribute(types.AttributeTotalDistributed, distributed.String()), + sdk.NewAttribute(types.AttributeDust, dust.String()), + )) +} + // ComputeClaim returns the depositor's claimable tokens for one denom on the // given consumer's fee pool. Returns math.ZeroInt() if the depositor has no // shares or total_shares is zero. @@ -74,14 +110,7 @@ func (k Keeper) MintShares( // the orphan balance to the community pool before crediting the new // depositor, so the deposit doesn't capture the orphan funds. if total.IsZero() && balance.Amount.IsPositive() { - providerAddr := authtypes.NewModuleAddress(types.ModuleName) - orphan := sdk.NewCoins(balance) - if err := k.bankKeeper.SendCoinsFromAccountToModule( - ctx, poolAddr, types.ModuleName, orphan, - ); err != nil { - return err - } - if err := k.distributionKeeper.FundCommunityPool(ctx, orphan, providerAddr); err != nil { + if err := k.forwardOrphanToCommunityPool(ctx, consumerId, poolAddr, balance, "mint"); err != nil { return err } } @@ -123,7 +152,7 @@ func (k Keeper) WithdrawShares( depKey := collections.Join3(consumerId, amount.Denom, depositor) shares, err := k.ConsumerFeePoolShares.Get(ctx, depKey) if err != nil { - return sdk.Coin{}, errorsmod.Wrapf(types.ErrUnauthorized, + return sdk.Coin{}, errorsmod.Wrapf(types.ErrNoSharesForDepositor, "depositor %s has no shares in (%d, %s)", depositor, consumerId, amount.Denom) } totalKey := collections.Join(consumerId, amount.Denom) @@ -216,17 +245,20 @@ func (k Keeper) SweepConsumerFeePoolDenom( // Orphan balance: no shares but balance > 0. Forward to community pool. if total.IsZero() { - if err := k.bankKeeper.SendCoinsFromAccountToModule( - ctx, poolAddr, providerModule, sdk.NewCoins(balance), - ); err != nil { + if err := k.forwardOrphanToCommunityPool(ctx, consumerId, poolAddr, balance, "sweep"); err != nil { return err } - return k.distributionKeeper.FundCommunityPool(ctx, sdk.NewCoins(balance), providerAddr) + k.emitSweepEvent(ctx, consumerId, denom, math.ZeroInt(), balance.Amount) + return nil } // Orphan shares: shares > 0 but balance == 0. Burn all shares, no transfer. if balance.Amount.IsZero() { - return k.clearAllShares(ctx, consumerId, denom) + if err := k.clearAllShares(ctx, consumerId, denom); err != nil { + return err + } + k.emitSweepEvent(ctx, consumerId, denom, math.ZeroInt(), math.ZeroInt()) + return nil } // Normal pro-rata distribution. @@ -296,7 +328,11 @@ func (k Keeper) SweepConsumerFeePoolDenom( } // Burn all share records for this (consumer, denom). - return k.clearAllShares(ctx, consumerId, denom) + if err := k.clearAllShares(ctx, consumerId, denom); err != nil { + return err + } + k.emitSweepEvent(ctx, consumerId, denom, distributed, dust) + return nil } // SweepConsumerFeePool sweeps each denom in `denoms`, or every denom that @@ -350,8 +386,15 @@ func (k Keeper) SweepConsumerFeePool( } // clearAllShares deletes every share record for the given (consumer, denom). -// Used by lazy invalidation and by sweep finalization. +// Used by lazy invalidation and by sweep finalization. No-op if nothing is +// stored — collections.Remove on a missing key would otherwise error. func (k Keeper) clearAllShares(ctx sdk.Context, consumerId uint64, denom string) error { + totalKey := collections.Join(consumerId, denom) + totalExists, err := k.ConsumerFeePoolTotalShares.Has(ctx, totalKey) + if err != nil { + return err + } + prefix := collections.NewSuperPrefixedTripleRange[uint64, string, sdk.AccAddress](consumerId, denom) iter, err := k.ConsumerFeePoolShares.Iterate(ctx, prefix) if err != nil { @@ -359,6 +402,10 @@ func (k Keeper) clearAllShares(ctx sdk.Context, consumerId uint64, denom string) } defer iter.Close() + if !iter.Valid() && !totalExists { + return nil + } + var toDelete []collections.Triple[uint64, string, sdk.AccAddress] for ; iter.Valid(); iter.Next() { key, err := iter.Key() @@ -367,10 +414,14 @@ func (k Keeper) clearAllShares(ctx sdk.Context, consumerId uint64, denom string) } toDelete = append(toDelete, key) } + for _, key := range toDelete { if err := k.ConsumerFeePoolShares.Remove(ctx, key); err != nil { return err } } - return k.ConsumerFeePoolTotalShares.Remove(ctx, collections.Join(consumerId, denom)) + if totalExists { + return k.ConsumerFeePoolTotalShares.Remove(ctx, totalKey) + } + return nil } diff --git a/x/vaas/provider/keeper/grpc_query.go b/x/vaas/provider/keeper/grpc_query.go index 9845a08..c57396f 100644 --- a/x/vaas/provider/keeper/grpc_query.go +++ b/x/vaas/provider/keeper/grpc_query.go @@ -340,6 +340,9 @@ func (k Keeper) ConsumerFeePoolClaim( if !exists { return nil, status.Errorf(codes.NotFound, "consumer %d does not exist", req.ConsumerId) } + if k.GetConsumerPhase(ctx, req.ConsumerId) == types.CONSUMER_PHASE_DELETED { + return nil, status.Errorf(codes.NotFound, "consumer %d is deleted", req.ConsumerId) + } depositorBech := req.Depositor if depositorBech == k.GetAuthority() { @@ -404,6 +407,9 @@ func (k Keeper) ConsumerFeePoolClaims( if !exists { return nil, status.Errorf(codes.NotFound, "consumer %d does not exist", req.ConsumerId) } + if k.GetConsumerPhase(ctx, req.ConsumerId) == types.CONSUMER_PHASE_DELETED { + return nil, status.Errorf(codes.NotFound, "consumer %d is deleted", req.ConsumerId) + } type acc struct { addr sdk.AccAddress @@ -524,7 +530,9 @@ func (k Keeper) ConsumerFeePoolClaims( resp.Pagination.Total = total } if end < total { - // Encode the next page cursor as the depositor at the boundary. + // NextKey is the bech32 depositor at the boundary, encoded as bytes + // for the PageResponse contract. Resume decodes it back via + // string(req.Pagination.Key) and binary-searches the same sort order. resp.Pagination.NextKey = []byte(keys[end]) } return resp, nil diff --git a/x/vaas/provider/keeper/msg_server.go b/x/vaas/provider/keeper/msg_server.go index 315e699..de151be 100644 --- a/x/vaas/provider/keeper/msg_server.go +++ b/x/vaas/provider/keeper/msg_server.go @@ -552,11 +552,9 @@ func (k msgServer) FundConsumerFeePool( } // WithdrawConsumerFeePool burns the depositor's shares across one or more -// denoms and returns the corresponding tokens. The handler is atomic: all -// share burns and bank movements are staged in a cache-context that is only -// committed on full success, so a mid-flight failure rolls back the entire -// request even when the handler is invoked outside of the SDK tx machinery -// (nested calls or direct invocations in tests). +// denoms and returns the corresponding tokens. The handler is all-or-nothing +// at the tx boundary: a mid-flight failure on any denom returns an error and +// the SDK rolls back the entire tx. // // When the signer is the gov authority, the depositor identity is the // distribution module account and the tokens are routed back to the community @@ -578,10 +576,9 @@ func (k msgServer) WithdrawConsumerFeePool( depositor = addr } - cachedCtx, write := ctx.CacheContext() delivered := sdk.NewCoins() for _, amt := range msg.Amount { - tokens, err := k.WithdrawShares(cachedCtx, msg.ConsumerId, depositor, amt) + tokens, err := k.WithdrawShares(ctx, msg.ConsumerId, depositor, amt) if err != nil { return nil, err } @@ -592,34 +589,40 @@ func (k msgServer) WithdrawConsumerFeePool( poolAddr := k.GetConsumerFeePoolAddress(msg.ConsumerId) providerAddr := authtypes.NewModuleAddress(types.ModuleName) if err := k.bankKeeper.SendCoinsFromAccountToModule( - cachedCtx, poolAddr, types.ModuleName, delivered, + ctx, poolAddr, types.ModuleName, delivered, ); err != nil { return nil, err } if isGov { - if err := k.distributionKeeper.FundCommunityPool(cachedCtx, delivered, providerAddr); err != nil { + if err := k.distributionKeeper.FundCommunityPool(ctx, delivered, providerAddr); err != nil { return nil, err } } else { if err := k.bankKeeper.SendCoinsFromModuleToAccount( - cachedCtx, types.ModuleName, depositor, delivered, + ctx, types.ModuleName, depositor, delivered, ); err != nil { return nil, err } } } - write() - recipient := depositor.String() + // On the gov path depositor and recipient are both the distribution + // module account: tokens land there via FundCommunityPool, which then + // credits the community-pool DecCoins ledger entry on top of the same + // bank balance. The withdraw_path attribute lets indexers distinguish + // "regular withdraw to depositor" from "gov clawback to community pool" + // without inferring it from the signer. + withdrawPath := types.WithdrawPathDirect if isGov { - recipient = "community_pool" + withdrawPath = types.WithdrawPathCommunityPool } ctx.EventManager().EmitEvent(sdk.NewEvent( types.EventTypeConsumerFeePoolWithdraw, sdk.NewAttribute(types.AttributeConsumerId, strconv.FormatUint(msg.ConsumerId, 10)), sdk.NewAttribute(types.AttributeDepositor, depositor.String()), - sdk.NewAttribute(types.AttributeRecipient, recipient), + sdk.NewAttribute(types.AttributeRecipient, depositor.String()), sdk.NewAttribute(types.AttributeAmount, delivered.String()), + sdk.NewAttribute(types.AttributeWithdrawPath, withdrawPath), )) return &types.MsgWithdrawConsumerFeePoolResponse{Amount: delivered}, nil } @@ -629,6 +632,19 @@ func (k msgServer) SweepConsumerFeePool( ) (*types.MsgSweepConsumerFeePoolResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + exists, err := k.ConsumerPhase.Has(ctx, msg.ConsumerId) + if err != nil { + return nil, err + } + if !exists { + return nil, errorsmod.Wrapf(types.ErrUnknownConsumerId, + "consumer %d does not exist", msg.ConsumerId) + } + if k.GetConsumerPhase(ctx, msg.ConsumerId) == types.CONSUMER_PHASE_DELETED { + return nil, errorsmod.Wrapf(types.ErrInvalidPhase, + "consumer %d is deleted; pool already auto-swept on delete", msg.ConsumerId) + } + ownerAddr, err := k.GetConsumerOwnerAddress(ctx, msg.ConsumerId) if err != nil { return nil, errorsmod.Wrapf(types.ErrNoOwnerAddress, @@ -639,8 +655,7 @@ func (k msgServer) SweepConsumerFeePool( "only consumer owner %s may sweep, got %s", ownerAddr, msg.Signer) } - // The msgServer's SweepConsumerFeePool shadows the embedded Keeper's - // SweepConsumerFeePool. Call the keeper's via the embedded field. + // k.SweepConsumerFeePool here would recurse; call the embedded Keeper's. if err := k.Keeper.SweepConsumerFeePool(ctx, msg.ConsumerId, msg.Denoms); err != nil { return nil, errorsmod.Wrap(types.ErrFeePoolSweepFailed, err.Error()) } diff --git a/x/vaas/provider/keeper/msg_server_test.go b/x/vaas/provider/keeper/msg_server_test.go index 4294583..737bb63 100644 --- a/x/vaas/provider/keeper/msg_server_test.go +++ b/x/vaas/provider/keeper/msg_server_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" "cosmossdk.io/collections" "cosmossdk.io/math" @@ -386,14 +385,13 @@ func TestWithdrawConsumerFeePool_Regular(t *testing.T) { require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uphoton"), math.NewInt(100))) - mocks.MockBankKeeper.EXPECT().GetBalance(gomock.Any(), poolAddr, "uphoton"). + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). Return(sdk.NewInt64Coin("uphoton", 80)) // alice asks for 30, partial path: shares_to_burn = 30*100/80 = 37, tokens = 37*80/100 = 29. - // Bank ops execute on a cache-context wrapped around the outer ctx, so match with gomock.Any(). mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( - gomock.Any(), poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 29))).Return(nil) + ctx, poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 29))).Return(nil) mocks.MockBankKeeper.EXPECT().SendCoinsFromModuleToAccount( - gomock.Any(), providertypes.ModuleName, alice, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 29))).Return(nil) + ctx, providertypes.ModuleName, alice, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 29))).Return(nil) resp, err := ms.WithdrawConsumerFeePool(ctx, &providertypes.MsgWithdrawConsumerFeePool{ Signer: alice.String(), ConsumerId: consumerId, @@ -419,13 +417,13 @@ func TestWithdrawConsumerFeePool_GovClawback(t *testing.T) { require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, collections.Join(consumerId, "uphoton"), math.NewInt(100))) - mocks.MockBankKeeper.EXPECT().GetBalance(gomock.Any(), poolAddr, "uphoton"). + mocks.MockBankKeeper.EXPECT().GetBalance(ctx, poolAddr, "uphoton"). Return(sdk.NewInt64Coin("uphoton", 100)) mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( - gomock.Any(), poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))).Return(nil) - // Gov clawback: tokens forwarded to community pool via cache-context, not raw bank send. + ctx, poolAddr, providertypes.ModuleName, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100))).Return(nil) + // Gov clawback: tokens forwarded to community pool via FundCommunityPool. mocks.MockDistributionKeeper.EXPECT().FundCommunityPool( - gomock.Any(), sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), providerAddr).Return(nil) + ctx, sdk.NewCoins(sdk.NewInt64Coin("uphoton", 100)), providerAddr).Return(nil) _, err := ms.WithdrawConsumerFeePool(ctx, &providertypes.MsgWithdrawConsumerFeePool{ Signer: k.GetAuthority(), ConsumerId: consumerId, @@ -434,45 +432,6 @@ func TestWithdrawConsumerFeePool_GovClawback(t *testing.T) { require.NoError(t, err) } -func TestWithdrawConsumerFeePool_AtomicMultiDenomAbort(t *testing.T) { - k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - ms := providerkeeper.NewMsgServerImpl(&k) - - consumerId := k.FetchAndIncrementConsumerId(ctx) - k.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED) - alice := sdk.AccAddress([]byte("alice___________")) - poolAddr := k.GetConsumerFeePoolAddress(consumerId) - - // alice has shares in uatone (alphabetically first, so iterated first - // inside the handler) but NOT in uphoton. The first iteration burns - // shares; the second must fail and the cache-context rollback must - // restore alice's uatone shares to their pre-call value. - require.NoError(t, k.ConsumerFeePoolShares.Set(ctx, - collections.Join3(consumerId, "uatone", alice), math.NewInt(50))) - require.NoError(t, k.ConsumerFeePoolTotalShares.Set(ctx, - collections.Join(consumerId, "uatone"), math.NewInt(50))) - - mocks.MockBankKeeper.EXPECT().GetBalance(gomock.Any(), poolAddr, "uatone"). - Return(sdk.NewInt64Coin("uatone", 50)).AnyTimes() - - // Requesting both: uatone succeeds (mutating cached state), uphoton - // fails (no shares for alice). The handler returns the error and the - // cache-context is discarded, leaving uatone shares untouched. - _, err := ms.WithdrawConsumerFeePool(ctx, &providertypes.MsgWithdrawConsumerFeePool{ - Signer: alice.String(), ConsumerId: consumerId, - Amount: sdk.NewCoins( - sdk.NewInt64Coin("uatone", 10), - sdk.NewInt64Coin("uphoton", 10), - ), - }) - require.Error(t, err) - - // alice's uatone shares should remain 50 (rollback proved) - s, _ := k.ConsumerFeePoolShares.Get(ctx, collections.Join3(consumerId, "uatone", alice)) - require.Equal(t, math.NewInt(50), s) -} - func TestSweepConsumerFeePool_OwnerOnly(t *testing.T) { k, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() diff --git a/x/vaas/provider/types/errors.go b/x/vaas/provider/types/errors.go index aca8d81..3f7010f 100644 --- a/x/vaas/provider/types/errors.go +++ b/x/vaas/provider/types/errors.go @@ -34,4 +34,5 @@ var ( ErrFeePoolSweepFailed = errorsmod.Register(ModuleName, 26, "consumer fee pool sweep failed") ErrDepositTooSmall = errorsmod.Register(ModuleName, 27, "deposit too small to mint any shares") ErrSubShareWithdraw = errorsmod.Register(ModuleName, 28, "withdraw amount too small to burn any shares") + ErrNoSharesForDepositor = errorsmod.Register(ModuleName, 29, "depositor has no shares in the consumer fee pool for the requested denom") ) diff --git a/x/vaas/provider/types/events.go b/x/vaas/provider/types/events.go index 625b7ee..b89e89a 100644 --- a/x/vaas/provider/types/events.go +++ b/x/vaas/provider/types/events.go @@ -32,4 +32,9 @@ const ( AttributeDenom = "denom" AttributeTotalDistributed = "total_distributed" AttributeDust = "dust" + AttributeWithdrawPath = "withdraw_path" + + // AttributeWithdrawPath values + WithdrawPathDirect = "direct" + WithdrawPathCommunityPool = "community_pool" ) diff --git a/x/vaas/provider/types/msg_test.go b/x/vaas/provider/types/msg_test.go index 5d9a361..4bf3a1d 100644 --- a/x/vaas/provider/types/msg_test.go +++ b/x/vaas/provider/types/msg_test.go @@ -655,6 +655,11 @@ func TestMsgSweepConsumerFeePool_ValidateBasic(t *testing.T) { ConsumerId: 0, Denoms: []string{"INVALID DENOM WITH SPACES"}, }, true}, + {"duplicate denom", types.MsgSweepConsumerFeePool{ + Signer: validSigner, + ConsumerId: 0, + Denoms: []string{"uphoton", "uphoton"}, + }, true}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { diff --git a/x/vaas/provider/types/tx.pb.go b/x/vaas/provider/types/tx.pb.go index 357685d..c4cbdc3 100644 --- a/x/vaas/provider/types/tx.pb.go +++ b/x/vaas/provider/types/tx.pb.go @@ -812,8 +812,12 @@ func (m *MsgFundConsumerFeePoolResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgFundConsumerFeePoolResponse proto.InternalMessageInfo // MsgWithdrawConsumerFeePool withdraws tokens from the signer's share in a -// consumer fee pool across one or more denoms. The transaction is atomic: -// if any denom in `amount` fails its share check, the whole tx aborts. +// consumer fee pool across one or more denoms. Each amount is interpreted as +// "up to this much": if the signer's claim for a denom is less than the +// requested amount the handler delivers the full claim and burns all of the +// signer's shares for that denom. The transaction is atomic: if the signer +// has no shares at all for any denom in `amount` (or the pool has zero +// balance for that denom), the whole tx aborts. // If the signer is the gov module authority, the withdrawal targets the // distribution module account's shares and tokens are routed back to the // community pool. From 723bd0ba2744b12398cb86d56766a95e2e9ba19d Mon Sep 17 00:00:00 2001 From: Giuseppe Natale <12249307+giunatale@users.noreply.github.com> Date: Fri, 22 May 2026 22:32:20 +0200 Subject: [PATCH 18/18] test per-consumer rollback in delete BeginBlocker --- .../keeper/consumer_lifecycle_test.go | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/x/vaas/provider/keeper/consumer_lifecycle_test.go b/x/vaas/provider/keeper/consumer_lifecycle_test.go index 4f3dd9a..1153d6b 100644 --- a/x/vaas/provider/keeper/consumer_lifecycle_test.go +++ b/x/vaas/provider/keeper/consumer_lifecycle_test.go @@ -3,11 +3,13 @@ package keeper_test import ( "fmt" "testing" + "time" "cosmossdk.io/collections" "cosmossdk.io/math" "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -148,6 +150,61 @@ func TestDeleteConsumerChain_AutoSweepMultiDenomDust(t *testing.T) { require.ErrorIs(t, err, collections.ErrNotFound) } +// TestBeginBlockRemoveConsumers_PerConsumerRollback verifies that a +// failing delete on one consumer (sweep returns an error) does not bleed +// state mutations into siblings whose deletes succeed in the same block. +// The first consumer's sweep fails; the second's succeeds. After the call, +// the first stays in STOPPED with its state intact and the second is gone. +func TestBeginBlockRemoveConsumers_PerConsumerRollback(t *testing.T) { + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + removalTime := time.Unix(1000, 0) + ctx = ctx.WithBlockTime(removalTime.Add(time.Hour)) + + // failing consumer: no client id, balance present but bank-pull errors out. + failId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerPhase(ctx, failId, providertypes.CONSUMER_PHASE_STOPPED) + require.NoError(t, k.SetConsumerRemovalTime(ctx, failId, removalTime)) + require.NoError(t, k.AppendConsumerToBeRemoved(ctx, failId, removalTime)) + failPoolAddr := k.GetConsumerFeePoolAddress(failId) + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, failPoolAddr, failId)) + + // succeeding consumer: pool empty, cleanup succeeds. + okId := k.FetchAndIncrementConsumerId(ctx) + k.SetConsumerClientId(ctx, okId, "07-tendermint-0") + k.SetConsumerPhase(ctx, okId, providertypes.CONSUMER_PHASE_STOPPED) + require.NoError(t, k.SetConsumerRemovalTime(ctx, okId, removalTime)) + require.NoError(t, k.AppendConsumerToBeRemoved(ctx, okId, removalTime)) + okPoolAddr := k.GetConsumerFeePoolAddress(okId) + require.NoError(t, k.FeePoolAddressToConsumerId.Set(ctx, okPoolAddr, okId)) + + // BeginBlockRemoveConsumers wraps each per-consumer delete in a + // cache-context, so match the ctx argument with gomock.Any(). + mocks.MockBankKeeper.EXPECT().GetAllBalances(gomock.Any(), failPoolAddr). + Return(sdk.NewCoins(sdk.NewInt64Coin("uphoton", 50))) + mocks.MockBankKeeper.EXPECT().GetBalance(gomock.Any(), failPoolAddr, "uphoton"). + Return(sdk.NewInt64Coin("uphoton", 50)) + mocks.MockBankKeeper.EXPECT().SendCoinsFromAccountToModule( + gomock.Any(), failPoolAddr, providertypes.ModuleName, + sdk.NewCoins(sdk.NewInt64Coin("uphoton", 50))). + Return(fmt.Errorf("forced bank error")) + + mocks.MockBankKeeper.EXPECT().GetAllBalances(gomock.Any(), okPoolAddr).Return(sdk.NewCoins()) + + require.NoError(t, k.BeginBlockRemoveConsumers(ctx)) + + // Failing consumer: state preserved (cache-context rolled back). + require.Equal(t, providertypes.CONSUMER_PHASE_STOPPED, k.GetConsumerPhase(ctx, failId)) + _, err := k.FeePoolAddressToConsumerId.Get(ctx, failPoolAddr) + require.NoError(t, err, "failing consumer's reverse-lookup entry should remain") + + // Succeeding consumer: deleted. + require.Equal(t, providertypes.CONSUMER_PHASE_DELETED, k.GetConsumerPhase(ctx, okId)) + _, err = k.FeePoolAddressToConsumerId.Get(ctx, okPoolAddr) + require.ErrorIs(t, err, collections.ErrNotFound) +} + func TestDeleteConsumerChain_AutoSweepFailureAborts(t *testing.T) { k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish()