From 60e81c0f82e5de1a72c62fbde31097c69be51aab Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Sat, 8 Jun 2024 12:03:53 -0500 Subject: [PATCH 01/37] feat: add proto files --- proto/milkyway/restaking/v1/genesis.proto | 13 +++ proto/milkyway/restaking/v1/messages.proto | 116 +++++++++++++++++++++ proto/milkyway/restaking/v1/params.proto | 17 +++ x/restaking/keeper/keeper.go | 9 ++ x/restaking/types/expected_keepers.go | 16 +++ x/restaking/types/keys.go | 6 ++ 6 files changed, 177 insertions(+) create mode 100644 proto/milkyway/restaking/v1/genesis.proto create mode 100644 proto/milkyway/restaking/v1/messages.proto create mode 100644 proto/milkyway/restaking/v1/params.proto create mode 100644 x/restaking/keeper/keeper.go create mode 100644 x/restaking/types/expected_keepers.go create mode 100644 x/restaking/types/keys.go diff --git a/proto/milkyway/restaking/v1/genesis.proto b/proto/milkyway/restaking/v1/genesis.proto new file mode 100644 index 000000000..53bc74dd4 --- /dev/null +++ b/proto/milkyway/restaking/v1/genesis.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; +package milkyway.restaking.v1; + +import "gogoproto/gogo.proto"; +import "milkyway/restaking/v1/params.proto"; + +option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types"; + +// GenesisState defines the restaking module's genesis state. +message GenesisState { + // Params defines the parameters of the module. + Params params = 1 [ (gogoproto.nullable) = false ]; +} \ No newline at end of file diff --git a/proto/milkyway/restaking/v1/messages.proto b/proto/milkyway/restaking/v1/messages.proto new file mode 100644 index 000000000..0237ab689 --- /dev/null +++ b/proto/milkyway/restaking/v1/messages.proto @@ -0,0 +1,116 @@ +syntax = "proto3"; +package milkyway.restaking.v1; + +import "amino/amino.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos/bank/v1beta1/bank.proto"; +import "cosmos/msg/v1/msg.proto"; +import "gogoproto/gogo.proto"; +import "milkyway/restaking/v1/params.proto"; + +option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types"; + +// Msg defines the restaking module's gRPC message service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // PoolRestake defines the operation that allows users to join a restaking + // pool with a given amount of assets. The pool can then be used to provide + // services with cryptoeconomic security. + rpc PoolRestake(MsgJoinRestakingPool) returns (MsgJoinRestakingPoolResponse); + + // OperatorRestake defines the operation that allows users to delegate their + // assets to a specific operator. + rpc OperatorRestake(MsgDelegateOperator) + returns (MsgDelegateOperatorResponse); + + // ServiceRestake defines the operation that allows users to delegate their + // assets to a specific service. + rpc ServiceRestake(MsgDelegateService) returns (MsgDelegateServiceResponse); + + // UpdateParams defines a (governance) operation for updating the module + // parameters. + // The authority defaults to the x/gov module account. + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgJoinRestakingPool defines the message structure for the PoolRestake gRPC +// service method. It allows a user to put their assets into a restaking pool +// that will later be used to provide cryptoeconomic security to services that +// chose it. +message MsgJoinRestakingPool { + option (cosmos.msg.v1.signer) = "delegator"; + option (amino.name) = "milkyway/MsgJoinRestakingPool"; + + // Delegator is the address of the user joining the pool + string delegator = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // Amount is the amount of coins to be staked + cosmos.base.v1beta1.Coin amount = 2 [ (gogoproto.customname) = "Amount" ]; +} + +// MsgJoinRestakingPoolResponse defines the return value of +// MsgJoinRestakingPool. +message MsgJoinRestakingPoolResponse {} + +// MsgDelegateOperator defines the message structure for the OperatorRestake +// gRPC service method. It allows a user to delegate their assets to an +// operator. +message MsgDelegateOperator { + option (cosmos.msg.v1.signer) = "delegator"; + option (amino.name) = "milkyway/MsgDelegateOperator"; + + // Delegator is the address of the user delegating to the operator + string delegator = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // OperatorID is the ID of the operator to delegate to + string operator_id = 2 [ (gogoproto.customname) = "OperatorID" ]; + + // Amount is the amount of coins to be delegated + cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.customname) = "Amount" ]; +} + +// MsgDelegateOperatorResponse is the return value of MsgDelegateOperator. +message MsgDelegateOperatorResponse {} + +// MsgDelegateService defines the message structure for the ServiceRestake gRPC +// service method. It allows a user to delegate their assets to a service. +message MsgDelegateService { + option (cosmos.msg.v1.signer) = "delegator"; + option (amino.name) = "milkyway/MsgDelegateService"; + + // Delegator is the address of the user delegating to the service + string delegator = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // ServiceID is the ID of the service to delegate to + string service_id = 2 [ (gogoproto.customname) = "ServiceID" ]; + + // Amount is the amount of coins to be delegated + cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.customname) = "Amount" ]; +} + +// MsgDelegateServiceResponse is the return value of MsgDelegateService. +message MsgDelegateServiceResponse {} + +// MsgDeactivateService defines the message structure for the UpdateParams gRPC +// service method. It allows the authority to update the module parameters. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "milkyway/x/restaking/MsgUpdateParams"; + + // Authority is the address that controls the module (defaults to x/gov unless + // overwritten). + string authority = 1 [ + (gogoproto.moretags) = "yaml:\"authority\"", + (cosmos_proto.scalar) = "cosmos.AddressString" + ]; + + // Params define the parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [ (gogoproto.nullable) = false ]; +} + +// MsgDeactivateServiceResponse is the return value of MsgUpdateParams. +message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/proto/milkyway/restaking/v1/params.proto b/proto/milkyway/restaking/v1/params.proto new file mode 100644 index 000000000..165178d7b --- /dev/null +++ b/proto/milkyway/restaking/v1/params.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package milkyway.restaking.v1; + +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types"; + +// Params defines the parameters for the module. +message Params { + + // UnbondingTime represents the time that will take for assets to be unbonded + // after the user initiates an unbonding request. This will be applied to all + // types of restaking: pool, operator and service restaking. + int64 unbonding_time = 1 [ (gogoproto.stdduration) = true ]; +} \ No newline at end of file diff --git a/x/restaking/keeper/keeper.go b/x/restaking/keeper/keeper.go new file mode 100644 index 000000000..acab24e91 --- /dev/null +++ b/x/restaking/keeper/keeper.go @@ -0,0 +1,9 @@ +package keeper + +type Keeper struct { + authority string +} + +func NewKeeper(authority string) *Keeper { + +} diff --git a/x/restaking/types/expected_keepers.go b/x/restaking/types/expected_keepers.go new file mode 100644 index 000000000..10fa0872b --- /dev/null +++ b/x/restaking/types/expected_keepers.go @@ -0,0 +1,16 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + operatorstypes "github.com/milkyway-labs/milkyway/x/operators/types" + servicestypes "github.com/milkyway-labs/milkyway/x/services/types" +) + +type ServicesKeeper interface { + GetService(ctx sdk.Context, serviceID uint32) (servicestypes.Service, bool) +} + +type OperatorsKeeper interface { + GetOperator(ctx sdk.Context, operatorID uint32) (operatorstypes.Operator, bool) +} diff --git a/x/restaking/types/keys.go b/x/restaking/types/keys.go new file mode 100644 index 000000000..9cb85c6d6 --- /dev/null +++ b/x/restaking/types/keys.go @@ -0,0 +1,6 @@ +package types + +const ( + ModuleName = "restaking" + StoreKey = ModuleName +) From 531dccc34122ea019bd5fecef99f7cb865fe960b Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 10 Jun 2024 08:12:57 -0500 Subject: [PATCH 02/37] chore: add new keeper method --- x/restaking/keeper/keeper.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/x/restaking/keeper/keeper.go b/x/restaking/keeper/keeper.go index acab24e91..d6a448862 100644 --- a/x/restaking/keeper/keeper.go +++ b/x/restaking/keeper/keeper.go @@ -1,9 +1,21 @@ package keeper +import ( + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" +) + type Keeper struct { + storeKey storetypes.StoreKey + cdc codec.Codec + authority string } -func NewKeeper(authority string) *Keeper { - +func NewKeeper(cdc codec.Codec, storeKey storetypes.StoreKey, authority string) *Keeper { + return &Keeper{ + storeKey: storeKey, + cdc: cdc, + authority: authority, + } } From 481907a41ba388716a127808e701171513209d9e Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 10 Jun 2024 08:13:12 -0500 Subject: [PATCH 03/37] feat: add genesis and params types and tests --- proto/milkyway/restaking/v1/genesis.proto | 57 + x/restaking/types/genesis.go | 149 +++ x/restaking/types/genesis.pb.go | 1323 +++++++++++++++++++++ x/restaking/types/genesis_test.go | 297 +++++ x/restaking/types/params.go | 27 + x/restaking/types/params.pb.go | 314 +++++ x/restaking/types/params_test.go | 45 + 7 files changed, 2212 insertions(+) create mode 100644 x/restaking/types/genesis.go create mode 100644 x/restaking/types/genesis.pb.go create mode 100644 x/restaking/types/genesis_test.go create mode 100644 x/restaking/types/params.go create mode 100644 x/restaking/types/params.pb.go create mode 100644 x/restaking/types/params_test.go diff --git a/proto/milkyway/restaking/v1/genesis.proto b/proto/milkyway/restaking/v1/genesis.proto index 53bc74dd4..e6498e33d 100644 --- a/proto/milkyway/restaking/v1/genesis.proto +++ b/proto/milkyway/restaking/v1/genesis.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package milkyway.restaking.v1; import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; import "milkyway/restaking/v1/params.proto"; option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types"; @@ -10,4 +11,60 @@ option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types"; message GenesisState { // Params defines the parameters of the module. Params params = 1 [ (gogoproto.nullable) = false ]; + + // PoolDelegations represents the delegations to pools. + repeated PoolDelegationEntry pools_delegations = 2 + [ (gogoproto.nullable) = false ]; + + // ServiceDelegations represents the delegations to services. + repeated ServiceDelegationEntry services_delegations = 3 + [ (gogoproto.nullable) = false ]; + + // OperatorDelegations represents the delegations to operators. + repeated OperatorDelegationEntry operators_delegations = 4 + [ (gogoproto.nullable) = false ]; +} + +// PoolDelegationEntry contains the data of a single restake delegation to a +// pool. +message PoolDelegationEntry { + // PoolID represents the ID of the pool to which the tokens have been restaked + uint32 pool_id = 1 [ (gogoproto.customname) = "PoolID" ]; + + // UserAddress represents the address of the user who has restaked the tokens + string user_address = 2; + + // Amount represents the amount of tokens that have been restaked + cosmos.base.v1beta1.Coin amount = 3 + [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; +} + +// ServiceDelegationEntry contains the data of a single restake delegation to a +// service. +message ServiceDelegationEntry { + // ServiceID represents the ID of the service to which the tokens have been + // restaked + uint32 service_id = 1 [ (gogoproto.customname) = "ServiceID" ]; + + // UserAddress represents the address of the user who has restaked the tokens + string user_address = 2; + + // Amount represents the amount of tokens that have been restaked + cosmos.base.v1beta1.Coin amount = 3 + [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; +} + +// OperatorDelegationEntry contains the data of a single restake delegation to +// an operator. +message OperatorDelegationEntry { + // OperatorID represents the ID of the operator to which the tokens have been + // restaked + uint32 operator_id = 1 [ (gogoproto.customname) = "OperatorID" ]; + + // UserAddress represents the address of the user who has restaked the tokens + string user_address = 2; + + // Amount represents the amount of tokens that have been restaked + cosmos.base.v1beta1.Coin amount = 3 + [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; } \ No newline at end of file diff --git a/x/restaking/types/genesis.go b/x/restaking/types/genesis.go new file mode 100644 index 000000000..70a562108 --- /dev/null +++ b/x/restaking/types/genesis.go @@ -0,0 +1,149 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// NewGenesis creates a new genesis state +func NewGenesis( + poolsDelegations []PoolDelegationEntry, + servicesDelegations []ServiceDelegationEntry, + operatorsDelegations []OperatorDelegationEntry, + params Params, +) *GenesisState { + return &GenesisState{ + PoolsDelegations: poolsDelegations, + ServicesDelegations: servicesDelegations, + OperatorsDelegations: operatorsDelegations, + Params: params, + } +} + +// DefaultGenesis returns a default genesis state +func DefaultGenesis() *GenesisState { + return NewGenesis(nil, nil, nil, DefaultParams()) +} + +// Validate performs basic validation of genesis data +func (g *GenesisState) Validate() error { + // Validate pools delegations + for _, entry := range g.PoolsDelegations { + err := entry.Validate() + if err != nil { + return fmt.Errorf("invalid pool delegation entry: %w", err) + } + } + + // Validate services delegations + for _, entry := range g.ServicesDelegations { + err := entry.Validate() + if err != nil { + return fmt.Errorf("invalid service delegation entry: %w", err) + } + } + + // Validate operators delegations + for _, entry := range g.OperatorsDelegations { + err := entry.Validate() + if err != nil { + return fmt.Errorf("invalid operator delegation entry: %w", err) + } + } + + // Validate the params + err := g.Params.Validate() + if err != nil { + return fmt.Errorf("invalid params: %w", err) + } + + return nil +} + +// -------------------------------------------------------------------------------------------------------------------- + +// NewPoolDelegationEntry returns a new PoolDelegationEntry +func NewPoolDelegationEntry(poolID uint32, userAddress string, amount sdk.Coin) PoolDelegationEntry { + return PoolDelegationEntry{ + PoolID: poolID, + UserAddress: userAddress, + Amount: amount, + } +} + +// Validate performs basic validation of a pool delegation entry +func (e *PoolDelegationEntry) Validate() error { + if e.PoolID == 0 { + return fmt.Errorf("invalid pool id: %d", e.PoolID) + } + + _, err := sdk.AccAddressFromBech32(e.UserAddress) + if err != nil { + return fmt.Errorf("invalid user address: %s", e.UserAddress) + } + + if !e.Amount.IsValid() || e.Amount.IsZero() { + return fmt.Errorf("invalid amount: %s", e.Amount) + } + + return nil +} + +// -------------------------------------------------------------------------------------------------------------------- + +// NewServiceDelegationEntry returns a new ServiceDelegationEntry +func NewServiceDelegationEntry(serviceID uint32, userAddress string, amount sdk.Coin) ServiceDelegationEntry { + return ServiceDelegationEntry{ + ServiceID: serviceID, + UserAddress: userAddress, + Amount: amount, + } +} + +// Validate performs basic validation of a service delegation entry +func (e *ServiceDelegationEntry) Validate() error { + if e.ServiceID == 0 { + return fmt.Errorf("invalid service id: %d", e.ServiceID) + } + + _, err := sdk.AccAddressFromBech32(e.UserAddress) + if err != nil { + return fmt.Errorf("invalid user address: %s", e.UserAddress) + } + + if !e.Amount.IsValid() || e.Amount.IsZero() { + return fmt.Errorf("invalid amount: %s", e.Amount) + } + + return nil +} + +// -------------------------------------------------------------------------------------------------------------------- + +// NewOperatorDelegationEntry returns a new OperatorDelegationEntry +func NewOperatorDelegationEntry(operatorID uint32, userAddress string, amount sdk.Coin) OperatorDelegationEntry { + return OperatorDelegationEntry{ + OperatorID: operatorID, + UserAddress: userAddress, + Amount: amount, + } +} + +// Validate performs basic validation of an operator delegation entry +func (e *OperatorDelegationEntry) Validate() error { + if e.OperatorID == 0 { + return fmt.Errorf("invalid operator id: %d", e.OperatorID) + } + + _, err := sdk.AccAddressFromBech32(e.UserAddress) + if err != nil { + return fmt.Errorf("invalid user address: %s", e.UserAddress) + } + + if !e.Amount.IsValid() || e.Amount.IsZero() { + return fmt.Errorf("invalid amount: %s", e.Amount) + } + + return nil +} diff --git a/x/restaking/types/genesis.pb.go b/x/restaking/types/genesis.pb.go new file mode 100644 index 000000000..2bef9fa26 --- /dev/null +++ b/x/restaking/types/genesis.pb.go @@ -0,0 +1,1323 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: milkyway/restaking/v1/genesis.proto + +package types + +import ( + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the restaking module's genesis state. +type GenesisState struct { + // Params defines the parameters of the module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + // PoolDelegations represents the delegations to pools. + PoolsDelegations []PoolDelegationEntry `protobuf:"bytes,2,rep,name=pools_delegations,json=poolsDelegations,proto3" json:"pools_delegations"` + // ServiceDelegations represents the delegations to services. + ServicesDelegations []ServiceDelegationEntry `protobuf:"bytes,3,rep,name=services_delegations,json=servicesDelegations,proto3" json:"services_delegations"` + // OperatorDelegations represents the delegations to operators. + OperatorsDelegations []OperatorDelegationEntry `protobuf:"bytes,4,rep,name=operators_delegations,json=operatorsDelegations,proto3" json:"operators_delegations"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_0378bd63cae7d256, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.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 *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetPoolsDelegations() []PoolDelegationEntry { + if m != nil { + return m.PoolsDelegations + } + return nil +} + +func (m *GenesisState) GetServicesDelegations() []ServiceDelegationEntry { + if m != nil { + return m.ServicesDelegations + } + return nil +} + +func (m *GenesisState) GetOperatorsDelegations() []OperatorDelegationEntry { + if m != nil { + return m.OperatorsDelegations + } + return nil +} + +// PoolDelegationEntry contains the data of a single restake delegation to a +// pool. +type PoolDelegationEntry struct { + // PoolID represents the ID of the pool to which the tokens have been restaked + PoolID uint32 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // UserAddress represents the address of the user who has restaked the tokens + UserAddress string `protobuf:"bytes,2,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` + // Amount represents the amount of tokens that have been restaked + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *PoolDelegationEntry) Reset() { *m = PoolDelegationEntry{} } +func (m *PoolDelegationEntry) String() string { return proto.CompactTextString(m) } +func (*PoolDelegationEntry) ProtoMessage() {} +func (*PoolDelegationEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_0378bd63cae7d256, []int{1} +} +func (m *PoolDelegationEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PoolDelegationEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PoolDelegationEntry.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 *PoolDelegationEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_PoolDelegationEntry.Merge(m, src) +} +func (m *PoolDelegationEntry) XXX_Size() int { + return m.Size() +} +func (m *PoolDelegationEntry) XXX_DiscardUnknown() { + xxx_messageInfo_PoolDelegationEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_PoolDelegationEntry proto.InternalMessageInfo + +func (m *PoolDelegationEntry) GetPoolID() uint32 { + if m != nil { + return m.PoolID + } + return 0 +} + +func (m *PoolDelegationEntry) GetUserAddress() string { + if m != nil { + return m.UserAddress + } + return "" +} + +func (m *PoolDelegationEntry) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +// ServiceDelegationEntry contains the data of a single restake delegation to a +// service. +type ServiceDelegationEntry struct { + // ServiceID represents the ID of the service to which the tokens have been + // restaked + ServiceID uint32 `protobuf:"varint,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + // UserAddress represents the address of the user who has restaked the tokens + UserAddress string `protobuf:"bytes,2,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` + // Amount represents the amount of tokens that have been restaked + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *ServiceDelegationEntry) Reset() { *m = ServiceDelegationEntry{} } +func (m *ServiceDelegationEntry) String() string { return proto.CompactTextString(m) } +func (*ServiceDelegationEntry) ProtoMessage() {} +func (*ServiceDelegationEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_0378bd63cae7d256, []int{2} +} +func (m *ServiceDelegationEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ServiceDelegationEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ServiceDelegationEntry.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 *ServiceDelegationEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_ServiceDelegationEntry.Merge(m, src) +} +func (m *ServiceDelegationEntry) XXX_Size() int { + return m.Size() +} +func (m *ServiceDelegationEntry) XXX_DiscardUnknown() { + xxx_messageInfo_ServiceDelegationEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_ServiceDelegationEntry proto.InternalMessageInfo + +func (m *ServiceDelegationEntry) GetServiceID() uint32 { + if m != nil { + return m.ServiceID + } + return 0 +} + +func (m *ServiceDelegationEntry) GetUserAddress() string { + if m != nil { + return m.UserAddress + } + return "" +} + +func (m *ServiceDelegationEntry) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +// OperatorDelegationEntry contains the data of a single restake delegation to +// an operator. +type OperatorDelegationEntry struct { + // OperatorID represents the ID of the operator to which the tokens have been + // restaked + OperatorID uint32 `protobuf:"varint,1,opt,name=operator_id,json=operatorId,proto3" json:"operator_id,omitempty"` + // UserAddress represents the address of the user who has restaked the tokens + UserAddress string `protobuf:"bytes,2,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` + // Amount represents the amount of tokens that have been restaked + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *OperatorDelegationEntry) Reset() { *m = OperatorDelegationEntry{} } +func (m *OperatorDelegationEntry) String() string { return proto.CompactTextString(m) } +func (*OperatorDelegationEntry) ProtoMessage() {} +func (*OperatorDelegationEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_0378bd63cae7d256, []int{3} +} +func (m *OperatorDelegationEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OperatorDelegationEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_OperatorDelegationEntry.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 *OperatorDelegationEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_OperatorDelegationEntry.Merge(m, src) +} +func (m *OperatorDelegationEntry) XXX_Size() int { + return m.Size() +} +func (m *OperatorDelegationEntry) XXX_DiscardUnknown() { + xxx_messageInfo_OperatorDelegationEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_OperatorDelegationEntry proto.InternalMessageInfo + +func (m *OperatorDelegationEntry) GetOperatorID() uint32 { + if m != nil { + return m.OperatorID + } + return 0 +} + +func (m *OperatorDelegationEntry) GetUserAddress() string { + if m != nil { + return m.UserAddress + } + return "" +} + +func (m *OperatorDelegationEntry) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "milkyway.restaking.v1.GenesisState") + proto.RegisterType((*PoolDelegationEntry)(nil), "milkyway.restaking.v1.PoolDelegationEntry") + proto.RegisterType((*ServiceDelegationEntry)(nil), "milkyway.restaking.v1.ServiceDelegationEntry") + proto.RegisterType((*OperatorDelegationEntry)(nil), "milkyway.restaking.v1.OperatorDelegationEntry") +} + +func init() { + proto.RegisterFile("milkyway/restaking/v1/genesis.proto", fileDescriptor_0378bd63cae7d256) +} + +var fileDescriptor_0378bd63cae7d256 = []byte{ + // 495 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x93, 0xc1, 0x6e, 0xd3, 0x4c, + 0x14, 0x85, 0xe3, 0xa6, 0xf2, 0xaf, 0xdc, 0xb4, 0xd5, 0x8f, 0x9b, 0x42, 0xa8, 0x84, 0x53, 0xd2, + 0x4d, 0x84, 0xe8, 0x8c, 0xd2, 0x2e, 0x59, 0x25, 0x04, 0xa1, 0x2c, 0x10, 0xc8, 0xdd, 0x21, 0xa1, + 0x68, 0x1c, 0x0f, 0x66, 0x54, 0xdb, 0x63, 0x79, 0x26, 0x81, 0xbc, 0x05, 0x8f, 0xc0, 0x03, 0xb0, + 0xe0, 0x31, 0xba, 0xec, 0x92, 0x55, 0x84, 0x9c, 0xe7, 0x40, 0x42, 0x33, 0x1e, 0x27, 0xa9, 0xe4, + 0x6c, 0xbb, 0x4b, 0x66, 0xce, 0xb9, 0xdf, 0xf1, 0xbd, 0x77, 0xe0, 0x3c, 0x66, 0xd1, 0xcd, 0xe2, + 0x2b, 0x59, 0xe0, 0x8c, 0x0a, 0x49, 0x6e, 0x58, 0x12, 0xe2, 0x79, 0x1f, 0x87, 0x34, 0xa1, 0x82, + 0x09, 0x94, 0x66, 0x5c, 0x72, 0xe7, 0xa4, 0x14, 0xa1, 0xb5, 0x08, 0xcd, 0xfb, 0xa7, 0xad, 0x90, + 0x87, 0x5c, 0x2b, 0xb0, 0xfa, 0x55, 0x88, 0x4f, 0xdd, 0x29, 0x17, 0x31, 0x17, 0xd8, 0x27, 0x82, + 0xe2, 0x79, 0xdf, 0xa7, 0x92, 0xf4, 0xf1, 0x94, 0xb3, 0xc4, 0xdc, 0x77, 0xab, 0x89, 0x29, 0xc9, + 0x48, 0x6c, 0x80, 0xdd, 0xbf, 0x7b, 0x70, 0xf0, 0xb6, 0x88, 0x70, 0x2d, 0x89, 0xa4, 0xce, 0x2b, + 0xb0, 0x0b, 0x41, 0xdb, 0x3a, 0xb3, 0x7a, 0xcd, 0xcb, 0x67, 0xa8, 0x32, 0x12, 0xfa, 0xa0, 0x45, + 0xc3, 0xfd, 0xdb, 0x65, 0xa7, 0xe6, 0x19, 0x8b, 0xf3, 0x09, 0x1e, 0xa5, 0x9c, 0x47, 0x62, 0x12, + 0xd0, 0x88, 0x86, 0x44, 0x32, 0x9e, 0x88, 0xf6, 0xde, 0x59, 0xbd, 0xd7, 0xbc, 0x7c, 0xb1, 0xab, + 0x0e, 0xe7, 0xd1, 0x68, 0xad, 0x7e, 0x93, 0xc8, 0x6c, 0x61, 0x8a, 0xfe, 0xaf, 0x4b, 0x6d, 0xee, + 0x84, 0xf3, 0x19, 0x5a, 0x82, 0x66, 0x73, 0x36, 0xa5, 0xf7, 0x09, 0x75, 0x4d, 0xb8, 0xd8, 0x41, + 0xb8, 0x2e, 0x2c, 0xd5, 0x90, 0xe3, 0xb2, 0xe0, 0x36, 0x87, 0xc1, 0x09, 0x4f, 0x69, 0x46, 0x24, + 0xcf, 0xee, 0x83, 0xf6, 0x35, 0x08, 0xed, 0x00, 0xbd, 0x37, 0x9e, 0x6a, 0x52, 0x6b, 0x5d, 0x72, + 0x0b, 0xd5, 0xfd, 0x61, 0xc1, 0x71, 0x45, 0x0b, 0x9c, 0x73, 0xf8, 0x4f, 0x7d, 0xfe, 0x84, 0x05, + 0x7a, 0x0e, 0x87, 0x43, 0xc8, 0x97, 0x1d, 0x5b, 0x29, 0xc7, 0x23, 0xcf, 0x56, 0x57, 0xe3, 0xc0, + 0x79, 0x0e, 0x07, 0x33, 0x41, 0xb3, 0x09, 0x09, 0x82, 0x8c, 0x0a, 0xd5, 0x69, 0xab, 0xd7, 0xf0, + 0x9a, 0xea, 0x6c, 0x50, 0x1c, 0x39, 0x03, 0xb0, 0x49, 0xcc, 0x67, 0x89, 0x6c, 0xd7, 0xf5, 0x38, + 0x9f, 0xa2, 0x62, 0x69, 0x90, 0x5a, 0x1a, 0x64, 0x96, 0x06, 0xbd, 0xe6, 0x2c, 0x19, 0x1e, 0xa9, + 0x98, 0x8a, 0x32, 0xd0, 0x06, 0xcf, 0x18, 0xbb, 0x3f, 0x2d, 0x78, 0x5c, 0xdd, 0x43, 0xe7, 0x25, + 0x80, 0xe9, 0xdf, 0x26, 0xe8, 0x61, 0xbe, 0xec, 0x34, 0x8c, 0x7e, 0x3c, 0xf2, 0x1a, 0x46, 0xf0, + 0x60, 0x71, 0x7f, 0x59, 0xf0, 0x64, 0xc7, 0x24, 0x1c, 0x0c, 0xcd, 0x72, 0x0a, 0x9b, 0xc0, 0x47, + 0xf9, 0xb2, 0x03, 0xa5, 0x63, 0x3c, 0xf2, 0xa0, 0x94, 0x3c, 0x54, 0xe4, 0xe1, 0xbb, 0xdb, 0xdc, + 0xb5, 0xee, 0x72, 0xd7, 0xfa, 0x93, 0xbb, 0xd6, 0xf7, 0x95, 0x5b, 0xbb, 0x5b, 0xb9, 0xb5, 0xdf, + 0x2b, 0xb7, 0xf6, 0xf1, 0x2a, 0x64, 0xf2, 0xcb, 0xcc, 0x47, 0x53, 0x1e, 0xe3, 0x72, 0xe9, 0x2e, + 0x22, 0xe2, 0x8b, 0xf5, 0x3f, 0xfc, 0x6d, 0xeb, 0x75, 0xcb, 0x45, 0x4a, 0x85, 0x6f, 0xeb, 0xa7, + 0x7d, 0xf5, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x21, 0x29, 0xab, 0x04, 0x72, 0x04, 0x00, 0x00, +} + +func (m *GenesisState) 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 *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.OperatorsDelegations) > 0 { + for iNdEx := len(m.OperatorsDelegations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.OperatorsDelegations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.ServicesDelegations) > 0 { + for iNdEx := len(m.ServicesDelegations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ServicesDelegations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.PoolsDelegations) > 0 { + for iNdEx := len(m.PoolsDelegations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PoolsDelegations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *PoolDelegationEntry) 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 *PoolDelegationEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PoolDelegationEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.UserAddress) > 0 { + i -= len(m.UserAddress) + copy(dAtA[i:], m.UserAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.UserAddress))) + i-- + dAtA[i] = 0x12 + } + if m.PoolID != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.PoolID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ServiceDelegationEntry) 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 *ServiceDelegationEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ServiceDelegationEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.UserAddress) > 0 { + i -= len(m.UserAddress) + copy(dAtA[i:], m.UserAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.UserAddress))) + i-- + dAtA[i] = 0x12 + } + if m.ServiceID != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.ServiceID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *OperatorDelegationEntry) 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 *OperatorDelegationEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OperatorDelegationEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.UserAddress) > 0 { + i -= len(m.UserAddress) + copy(dAtA[i:], m.UserAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.UserAddress))) + i-- + dAtA[i] = 0x12 + } + if m.OperatorID != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.OperatorID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.PoolsDelegations) > 0 { + for _, e := range m.PoolsDelegations { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ServicesDelegations) > 0 { + for _, e := range m.ServicesDelegations { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.OperatorsDelegations) > 0 { + for _, e := range m.OperatorsDelegations { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *PoolDelegationEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolID != 0 { + n += 1 + sovGenesis(uint64(m.PoolID)) + } + l = len(m.UserAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func (m *ServiceDelegationEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ServiceID != 0 { + n += 1 + sovGenesis(uint64(m.ServiceID)) + } + l = len(m.UserAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func (m *OperatorDelegationEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.OperatorID != 0 { + n += 1 + sovGenesis(uint64(m.OperatorID)) + } + l = len(m.UserAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) 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: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", 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 + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolsDelegations", 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.PoolsDelegations = append(m.PoolsDelegations, PoolDelegationEntry{}) + if err := m.PoolsDelegations[len(m.PoolsDelegations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServicesDelegations", 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.ServicesDelegations = append(m.ServicesDelegations, ServiceDelegationEntry{}) + if err := m.ServicesDelegations[len(m.ServicesDelegations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorsDelegations", 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.OperatorsDelegations = append(m.OperatorsDelegations, OperatorDelegationEntry{}) + if err := m.OperatorsDelegations[len(m.OperatorsDelegations)-1].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 (m *PoolDelegationEntry) 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: PoolDelegationEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PoolDelegationEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolID", wireType) + } + m.PoolID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolID |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", 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.UserAddress = 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 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 + } + if err := m.Amount.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 (m *ServiceDelegationEntry) 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: ServiceDelegationEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ServiceDelegationEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ServiceID", wireType) + } + m.ServiceID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ServiceID |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", 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.UserAddress = 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 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 + } + if err := m.Amount.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 (m *OperatorDelegationEntry) 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: OperatorDelegationEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OperatorDelegationEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorID", wireType) + } + m.OperatorID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OperatorID |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", 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.UserAddress = 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 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 + } + if err := m.Amount.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 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/restaking/types/genesis_test.go b/x/restaking/types/genesis_test.go new file mode 100644 index 000000000..14f7edcd7 --- /dev/null +++ b/x/restaking/types/genesis_test.go @@ -0,0 +1,297 @@ +package types_test + +import ( + "testing" + "time" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +func TestGenesis_Validate(t *testing.T) { + testCases := []struct { + name string + genesis *types.GenesisState + shouldErr bool + }{ + { + name: "invalid pool delegation entry returns error", + genesis: types.NewGenesis( + []types.PoolDelegationEntry{ + types.NewPoolDelegationEntry( + 0, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + }, + nil, + nil, + types.DefaultParams(), + ), + shouldErr: true, + }, + { + name: "invalid service delegation entry returns error", + genesis: types.NewGenesis( + nil, + []types.ServiceDelegationEntry{ + types.NewServiceDelegationEntry( + 0, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + }, + nil, + types.DefaultParams(), + ), + shouldErr: true, + }, + { + name: "invalid operator delegation entry returns error", + genesis: types.NewGenesis( + nil, + nil, + []types.OperatorDelegationEntry{ + types.NewOperatorDelegationEntry( + 0, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + }, + types.DefaultParams(), + ), + shouldErr: true, + }, + { + name: "invalid params return error", + genesis: types.NewGenesis( + nil, + nil, + nil, + types.NewParams(0), + ), + shouldErr: true, + }, + { + name: "default genesis returns no error", + genesis: types.DefaultGenesis(), + shouldErr: false, + }, + { + name: "valid genesis returns no error", + genesis: types.NewGenesis( + []types.PoolDelegationEntry{ + types.NewPoolDelegationEntry( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + }, + []types.ServiceDelegationEntry{ + types.NewServiceDelegationEntry( + 2, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + }, + []types.OperatorDelegationEntry{ + types.NewOperatorDelegationEntry( + 3, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + }, + types.NewParams(5*24*time.Hour), + ), + shouldErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.genesis.Validate() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +func TestPoolDelegationEntry_Validate(t *testing.T) { + testCases := []struct { + name string + entry types.PoolDelegationEntry + shouldErr bool + }{ + { + name: "invalid pool id returns error", + entry: types.NewPoolDelegationEntry( + 0, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + shouldErr: true, + }, + { + name: "invalid user address returns error", + entry: types.NewPoolDelegationEntry( + 1, + "", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + shouldErr: true, + }, + { + name: "invalid amount returns error", + entry: types.NewPoolDelegationEntry( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.Coin{}, + ), + shouldErr: true, + }, + { + name: "valid entry returns no error", + entry: types.NewPoolDelegationEntry( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + shouldErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.entry.Validate() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +func TestServiceDelegationEntry_Validate(t *testing.T) { + testCases := []struct { + name string + entry types.ServiceDelegationEntry + shouldErr bool + }{ + { + name: "invalid service id returns error", + entry: types.NewServiceDelegationEntry( + 0, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + shouldErr: true, + }, + { + name: "invalid user address returns error", + entry: types.NewServiceDelegationEntry( + 1, + "", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + shouldErr: true, + }, + { + name: "invalid amount returns error", + entry: types.NewServiceDelegationEntry( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.Coin{}, + ), + shouldErr: true, + }, + { + name: "valid entry returns no error", + entry: types.NewServiceDelegationEntry( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + shouldErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.entry.Validate() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +func TestOperatorDelegationEntry_Validate(t *testing.T) { + testCases := []struct { + name string + entry types.OperatorDelegationEntry + shouldErr bool + }{ + { + name: "invalid operator id returns error", + entry: types.NewOperatorDelegationEntry( + 0, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + shouldErr: true, + }, + { + name: "invalid user address returns error", + entry: types.NewOperatorDelegationEntry( + 1, + "", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + shouldErr: true, + }, + { + name: "invalid amount returns error", + entry: types.NewOperatorDelegationEntry( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.Coin{}, + ), + shouldErr: true, + }, + { + name: "valid entry returns no error", + entry: types.NewOperatorDelegationEntry( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + shouldErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.entry.Validate() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/restaking/types/params.go b/x/restaking/types/params.go new file mode 100644 index 000000000..94edad9e3 --- /dev/null +++ b/x/restaking/types/params.go @@ -0,0 +1,27 @@ +package types + +import ( + "fmt" + "time" +) + +// NewParams returns a new Params instance +func NewParams(unbondingTime time.Duration) Params { + return Params{ + UnbondingTime: unbondingTime, + } +} + +// DefaultParams return a Params instance with default values set +func DefaultParams() Params { + return NewParams(3 * 24 * time.Hour) +} + +// Validate performs basic validation of params +func (p *Params) Validate() error { + if p.UnbondingTime == 0 { + return fmt.Errorf("invalid unbonding time: %s", p.UnbondingTime) + } + + return nil +} diff --git a/x/restaking/types/params.pb.go b/x/restaking/types/params.pb.go new file mode 100644 index 000000000..33270d737 --- /dev/null +++ b/x/restaking/types/params.pb.go @@ -0,0 +1,314 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: milkyway/restaking/v1/params.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the parameters for the module. +type Params struct { + // UnbondingTime represents the time that will take for assets to be unbonded + // after the user initiates an unbonding request. This will be applied to all + // types of restaking: pool, operator and service restaking. + UnbondingTime time.Duration `protobuf:"varint,1,opt,name=unbonding_time,json=unbondingTime,proto3,stdduration" json:"unbonding_time,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_342e630197fca2bb, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetUnbondingTime() time.Duration { + if m != nil { + return m.UnbondingTime + } + return 0 +} + +func init() { + proto.RegisterType((*Params)(nil), "milkyway.restaking.v1.Params") +} + +func init() { + proto.RegisterFile("milkyway/restaking/v1/params.proto", fileDescriptor_342e630197fca2bb) +} + +var fileDescriptor_342e630197fca2bb = []byte{ + // 229 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xca, 0xcd, 0xcc, 0xc9, + 0xae, 0x2c, 0x4f, 0xac, 0xd4, 0x2f, 0x4a, 0x2d, 0x2e, 0x49, 0xcc, 0xce, 0xcc, 0x4b, 0xd7, 0x2f, + 0x33, 0xd4, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, + 0x85, 0xa9, 0xd1, 0x83, 0xab, 0xd1, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xab, + 0xd0, 0x07, 0xb1, 0x20, 0x8a, 0xa5, 0x24, 0x93, 0xf3, 0x8b, 0x73, 0xf3, 0x8b, 0xe3, 0x21, 0x12, + 0x10, 0x0e, 0x54, 0x4a, 0x0e, 0xc2, 0xd3, 0x4f, 0x4a, 0x2c, 0x4e, 0xd5, 0x2f, 0x33, 0x4c, 0x4a, + 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0xce, 0xcf, 0xcc, 0x83, 0xc8, 0x2b, 0x99, 0x72, 0xb1, 0x05, 0x80, + 0xed, 0x15, 0xd2, 0xe6, 0xe2, 0x2b, 0xcd, 0x4b, 0xca, 0xcf, 0x4b, 0xc9, 0xcc, 0x4b, 0x8f, 0x2f, + 0xc9, 0xcc, 0x4d, 0x95, 0x60, 0x54, 0x60, 0xd4, 0x60, 0x76, 0x62, 0x99, 0x71, 0x5f, 0x9e, 0x31, + 0x88, 0x17, 0x2e, 0x17, 0x92, 0x99, 0x9b, 0xea, 0xe4, 0x7b, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, + 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, + 0xc7, 0x72, 0x0c, 0x51, 0xc6, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, + 0x30, 0x3f, 0xe8, 0xe6, 0x24, 0x26, 0x15, 0xc3, 0x79, 0xfa, 0x15, 0x48, 0xfe, 0x2e, 0xa9, 0x2c, + 0x48, 0x2d, 0x4e, 0x62, 0x03, 0x3b, 0xc6, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x28, 0xb9, 0x7d, + 0x57, 0x1a, 0x01, 0x00, 0x00, +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.UnbondingTime != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.UnbondingTime)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintParams(dAtA []byte, offset int, v uint64) int { + offset -= sovParams(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.UnbondingTime != 0 { + n += 1 + sovParams(uint64(m.UnbondingTime)) + } + return n +} + +func sovParams(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozParams(x uint64) (n int) { + return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) 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 ErrIntOverflowParams + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingTime", wireType) + } + m.UnbondingTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnbondingTime |= time.Duration(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipParams(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthParams + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupParams + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthParams + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/restaking/types/params_test.go b/x/restaking/types/params_test.go new file mode 100644 index 000000000..e821977aa --- /dev/null +++ b/x/restaking/types/params_test.go @@ -0,0 +1,45 @@ +package types_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +func TestParams_Validate(t *testing.T) { + testCases := []struct { + name string + params types.Params + shouldErr bool + }{ + { + name: "invalid unbonding time returns error", + params: types.NewParams(0), + shouldErr: true, + }, + { + name: "default params return no error", + params: types.DefaultParams(), + shouldErr: false, + }, + { + name: "valid params return no error", + params: types.NewParams(5 * time.Hour), + shouldErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.params.Validate() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} From df6ffee0cbfb056d8171d22a1c4bd2ae736232b9 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 10 Jun 2024 08:51:14 -0500 Subject: [PATCH 04/37] feat: add messages types and tests --- proto/milkyway/restaking/v1/messages.proto | 13 +- x/restaking/types/codec.go | 45 + x/restaking/types/messages.go | 154 ++ x/restaking/types/messages.pb.go | 1864 ++++++++++++++++++++ x/restaking/types/messages_test.go | 265 +++ 5 files changed, 2336 insertions(+), 5 deletions(-) create mode 100644 x/restaking/types/codec.go create mode 100644 x/restaking/types/messages.go create mode 100644 x/restaking/types/messages.pb.go create mode 100644 x/restaking/types/messages_test.go diff --git a/proto/milkyway/restaking/v1/messages.proto b/proto/milkyway/restaking/v1/messages.proto index 0237ab689..c3ebea418 100644 --- a/proto/milkyway/restaking/v1/messages.proto +++ b/proto/milkyway/restaking/v1/messages.proto @@ -47,7 +47,8 @@ message MsgJoinRestakingPool { string delegator = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; // Amount is the amount of coins to be staked - cosmos.base.v1beta1.Coin amount = 2 [ (gogoproto.customname) = "Amount" ]; + cosmos.base.v1beta1.Coin amount = 2 + [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; } // MsgJoinRestakingPoolResponse defines the return value of @@ -65,10 +66,11 @@ message MsgDelegateOperator { string delegator = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; // OperatorID is the ID of the operator to delegate to - string operator_id = 2 [ (gogoproto.customname) = "OperatorID" ]; + uint32 operator_id = 2 [ (gogoproto.customname) = "OperatorID" ]; // Amount is the amount of coins to be delegated - cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.customname) = "Amount" ]; + cosmos.base.v1beta1.Coin amount = 3 + [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; } // MsgDelegateOperatorResponse is the return value of MsgDelegateOperator. @@ -84,10 +86,11 @@ message MsgDelegateService { string delegator = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; // ServiceID is the ID of the service to delegate to - string service_id = 2 [ (gogoproto.customname) = "ServiceID" ]; + uint32 service_id = 2 [ (gogoproto.customname) = "ServiceID" ]; // Amount is the amount of coins to be delegated - cosmos.base.v1beta1.Coin amount = 3 [ (gogoproto.customname) = "Amount" ]; + cosmos.base.v1beta1.Coin amount = 3 + [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; } // MsgDelegateServiceResponse is the return value of MsgDelegateService. diff --git a/x/restaking/types/codec.go b/x/restaking/types/codec.go new file mode 100644 index 000000000..1ac8bb296 --- /dev/null +++ b/x/restaking/types/codec.go @@ -0,0 +1,45 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/legacy" + "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + legacy.RegisterAminoMsg(cdc, &MsgDelegateService{}, "milkyway/MsgDelegateService") + legacy.RegisterAminoMsg(cdc, &MsgJoinRestakingPool{}, "milkyway/MsgJoinRestakingPool") + legacy.RegisterAminoMsg(cdc, &MsgDelegateOperator{}, "milkyway/MsgDelegateOperator") + legacy.RegisterAminoMsg(cdc, &MsgUpdateParams{}, "milkyway/restaking/MsgUpdateParams") + +} + +func RegisterInterfaces(registry types.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgJoinRestakingPool{}, + &MsgDelegateService{}, + &MsgDelegateOperator{}, + &MsgUpdateParams{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + // AminoCdc references the global x/services module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/services and + // defined at the application level. + AminoCdc = codec.NewLegacyAmino() +) + +func init() { + RegisterLegacyAminoCodec(AminoCdc) + cryptocodec.RegisterCrypto(AminoCdc) + sdk.RegisterLegacyAminoCodec(AminoCdc) +} diff --git a/x/restaking/types/messages.go b/x/restaking/types/messages.go new file mode 100644 index 000000000..7eb434499 --- /dev/null +++ b/x/restaking/types/messages.go @@ -0,0 +1,154 @@ +package types + +import ( + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// NewMsgJoinRestakingPool creates a new MsgJoinRestakePool instance +func NewMsgJoinRestakingPool(amount sdk.Coin, delegator string) *MsgJoinRestakingPool { + return &MsgJoinRestakingPool{ + Amount: amount, + Delegator: delegator, + } +} + +// ValidateBasic implements sdk.Msg +func (msg *MsgJoinRestakingPool) ValidateBasic() error { + if !msg.Amount.IsValid() || msg.Amount.IsZero() { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "invalid amount") + } + + _, err := sdk.AccAddressFromBech32(msg.Delegator) + if err != nil { + return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid delegator address") + } + + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg *MsgJoinRestakingPool) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg *MsgJoinRestakingPool) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.Delegator) + return []sdk.AccAddress{addr} +} + +// -------------------------------------------------------------------------------------------------------------------- + +// NewMsgDelegateOperator creates a new MsgDelegateOperator instance +func NewMsgDelegateOperator(operatorID uint32, amount sdk.Coin, delegator string) *MsgDelegateOperator { + return &MsgDelegateOperator{ + OperatorID: operatorID, + Amount: amount, + Delegator: delegator, + } +} + +// ValidateBasic implements sdk.Msg +func (msg *MsgDelegateOperator) ValidateBasic() error { + if msg.OperatorID == 0 { + return errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid operator id") + } + + if !msg.Amount.IsValid() || msg.Amount.IsZero() { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "invalid amount") + } + + _, err := sdk.AccAddressFromBech32(msg.Delegator) + if err != nil { + return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid delegator address") + } + + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg *MsgDelegateOperator) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg *MsgDelegateOperator) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.Delegator) + return []sdk.AccAddress{addr} +} + +// -------------------------------------------------------------------------------------------------------------------- + +func NewMsgDelegateService(serviceID uint32, amount sdk.Coin, delegator string) *MsgDelegateService { + return &MsgDelegateService{ + ServiceID: serviceID, + Amount: amount, + Delegator: delegator, + } +} + +// ValidateBasic implements sdk.Msg +func (msg *MsgDelegateService) ValidateBasic() error { + if msg.ServiceID == 0 { + return errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid service id") + } + + if !msg.Amount.IsValid() || msg.Amount.IsZero() { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "invalid amount") + } + + _, err := sdk.AccAddressFromBech32(msg.Delegator) + if err != nil { + return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid delegator address") + } + + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg *MsgDelegateService) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg *MsgDelegateService) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.Delegator) + return []sdk.AccAddress{addr} +} + +// -------------------------------------------------------------------------------------------------------------------- + +func NewMsgUpdateParams(params Params, authority string) *MsgUpdateParams { + return &MsgUpdateParams{ + Params: params, + Authority: authority, + } +} + +// ValidateBasic implements sdk.Msg +func (msg *MsgUpdateParams) ValidateBasic() error { + err := msg.Params.Validate() + if err != nil { + return errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid params: %s", err) + } + + _, err = sdk.AccAddressFromBech32(msg.Authority) + if err != nil { + return errors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address") + } + + return nil +} + +// GetSignBytes implements sdk.Msg +func (msg *MsgUpdateParams) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(msg)) +} + +// GetSigners implements sdk.Msg +func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.Authority) + return []sdk.AccAddress{addr} +} diff --git a/x/restaking/types/messages.pb.go b/x/restaking/types/messages.pb.go new file mode 100644 index 000000000..1688b1e1c --- /dev/null +++ b/x/restaking/types/messages.pb.go @@ -0,0 +1,1864 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: milkyway/restaking/v1/messages.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/cosmos-sdk/x/bank/types" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgJoinRestakingPool defines the message structure for the PoolRestake gRPC +// service method. It allows a user to put their assets into a restaking pool +// that will later be used to provide cryptoeconomic security to services that +// chose it. +type MsgJoinRestakingPool struct { + // Delegator is the address of the user joining the pool + Delegator string `protobuf:"bytes,1,opt,name=delegator,proto3" json:"delegator,omitempty"` + // Amount is the amount of coins to be staked + Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgJoinRestakingPool) Reset() { *m = MsgJoinRestakingPool{} } +func (m *MsgJoinRestakingPool) String() string { return proto.CompactTextString(m) } +func (*MsgJoinRestakingPool) ProtoMessage() {} +func (*MsgJoinRestakingPool) Descriptor() ([]byte, []int) { + return fileDescriptor_9772be2b1a923bdb, []int{0} +} +func (m *MsgJoinRestakingPool) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgJoinRestakingPool) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgJoinRestakingPool.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 *MsgJoinRestakingPool) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgJoinRestakingPool.Merge(m, src) +} +func (m *MsgJoinRestakingPool) XXX_Size() int { + return m.Size() +} +func (m *MsgJoinRestakingPool) XXX_DiscardUnknown() { + xxx_messageInfo_MsgJoinRestakingPool.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgJoinRestakingPool proto.InternalMessageInfo + +func (m *MsgJoinRestakingPool) GetDelegator() string { + if m != nil { + return m.Delegator + } + return "" +} + +func (m *MsgJoinRestakingPool) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +// MsgJoinRestakingPoolResponse defines the return value of +// MsgJoinRestakingPool. +type MsgJoinRestakingPoolResponse struct { +} + +func (m *MsgJoinRestakingPoolResponse) Reset() { *m = MsgJoinRestakingPoolResponse{} } +func (m *MsgJoinRestakingPoolResponse) String() string { return proto.CompactTextString(m) } +func (*MsgJoinRestakingPoolResponse) ProtoMessage() {} +func (*MsgJoinRestakingPoolResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9772be2b1a923bdb, []int{1} +} +func (m *MsgJoinRestakingPoolResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgJoinRestakingPoolResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgJoinRestakingPoolResponse.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 *MsgJoinRestakingPoolResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgJoinRestakingPoolResponse.Merge(m, src) +} +func (m *MsgJoinRestakingPoolResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgJoinRestakingPoolResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgJoinRestakingPoolResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgJoinRestakingPoolResponse proto.InternalMessageInfo + +// MsgDelegateOperator defines the message structure for the OperatorRestake +// gRPC service method. It allows a user to delegate their assets to an +// operator. +type MsgDelegateOperator struct { + // Delegator is the address of the user delegating to the operator + Delegator string `protobuf:"bytes,1,opt,name=delegator,proto3" json:"delegator,omitempty"` + // OperatorID is the ID of the operator to delegate to + OperatorID uint32 `protobuf:"varint,2,opt,name=operator_id,json=operatorId,proto3" json:"operator_id,omitempty"` + // Amount is the amount of coins to be delegated + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgDelegateOperator) Reset() { *m = MsgDelegateOperator{} } +func (m *MsgDelegateOperator) String() string { return proto.CompactTextString(m) } +func (*MsgDelegateOperator) ProtoMessage() {} +func (*MsgDelegateOperator) Descriptor() ([]byte, []int) { + return fileDescriptor_9772be2b1a923bdb, []int{2} +} +func (m *MsgDelegateOperator) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDelegateOperator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDelegateOperator.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 *MsgDelegateOperator) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDelegateOperator.Merge(m, src) +} +func (m *MsgDelegateOperator) XXX_Size() int { + return m.Size() +} +func (m *MsgDelegateOperator) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDelegateOperator.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDelegateOperator proto.InternalMessageInfo + +func (m *MsgDelegateOperator) GetDelegator() string { + if m != nil { + return m.Delegator + } + return "" +} + +func (m *MsgDelegateOperator) GetOperatorID() uint32 { + if m != nil { + return m.OperatorID + } + return 0 +} + +func (m *MsgDelegateOperator) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +// MsgDelegateOperatorResponse is the return value of MsgDelegateOperator. +type MsgDelegateOperatorResponse struct { +} + +func (m *MsgDelegateOperatorResponse) Reset() { *m = MsgDelegateOperatorResponse{} } +func (m *MsgDelegateOperatorResponse) String() string { return proto.CompactTextString(m) } +func (*MsgDelegateOperatorResponse) ProtoMessage() {} +func (*MsgDelegateOperatorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9772be2b1a923bdb, []int{3} +} +func (m *MsgDelegateOperatorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDelegateOperatorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDelegateOperatorResponse.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 *MsgDelegateOperatorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDelegateOperatorResponse.Merge(m, src) +} +func (m *MsgDelegateOperatorResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgDelegateOperatorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDelegateOperatorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDelegateOperatorResponse proto.InternalMessageInfo + +// MsgDelegateService defines the message structure for the ServiceRestake gRPC +// service method. It allows a user to delegate their assets to a service. +type MsgDelegateService struct { + // Delegator is the address of the user delegating to the service + Delegator string `protobuf:"bytes,1,opt,name=delegator,proto3" json:"delegator,omitempty"` + // ServiceID is the ID of the service to delegate to + ServiceID uint32 `protobuf:"varint,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + // Amount is the amount of coins to be delegated + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgDelegateService) Reset() { *m = MsgDelegateService{} } +func (m *MsgDelegateService) String() string { return proto.CompactTextString(m) } +func (*MsgDelegateService) ProtoMessage() {} +func (*MsgDelegateService) Descriptor() ([]byte, []int) { + return fileDescriptor_9772be2b1a923bdb, []int{4} +} +func (m *MsgDelegateService) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDelegateService) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDelegateService.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 *MsgDelegateService) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDelegateService.Merge(m, src) +} +func (m *MsgDelegateService) XXX_Size() int { + return m.Size() +} +func (m *MsgDelegateService) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDelegateService.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDelegateService proto.InternalMessageInfo + +func (m *MsgDelegateService) GetDelegator() string { + if m != nil { + return m.Delegator + } + return "" +} + +func (m *MsgDelegateService) GetServiceID() uint32 { + if m != nil { + return m.ServiceID + } + return 0 +} + +func (m *MsgDelegateService) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +// MsgDelegateServiceResponse is the return value of MsgDelegateService. +type MsgDelegateServiceResponse struct { +} + +func (m *MsgDelegateServiceResponse) Reset() { *m = MsgDelegateServiceResponse{} } +func (m *MsgDelegateServiceResponse) String() string { return proto.CompactTextString(m) } +func (*MsgDelegateServiceResponse) ProtoMessage() {} +func (*MsgDelegateServiceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9772be2b1a923bdb, []int{5} +} +func (m *MsgDelegateServiceResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDelegateServiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDelegateServiceResponse.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 *MsgDelegateServiceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDelegateServiceResponse.Merge(m, src) +} +func (m *MsgDelegateServiceResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgDelegateServiceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDelegateServiceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDelegateServiceResponse proto.InternalMessageInfo + +// MsgDeactivateService defines the message structure for the UpdateParams gRPC +// service method. It allows the authority to update the module parameters. +type MsgUpdateParams struct { + // Authority is the address that controls the module (defaults to x/gov unless + // overwritten). + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty" yaml:"authority"` + // Params define the parameters to update. + // + // NOTE: All parameters must be supplied. + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } +func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParams) ProtoMessage() {} +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return fileDescriptor_9772be2b1a923bdb, []int{6} +} +func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParams.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 *MsgUpdateParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParams.Merge(m, src) +} +func (m *MsgUpdateParams) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo + +func (m *MsgUpdateParams) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateParams) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// MsgDeactivateServiceResponse is the return value of MsgUpdateParams. +type MsgUpdateParamsResponse struct { +} + +func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse{} } +func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParamsResponse) ProtoMessage() {} +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9772be2b1a923bdb, []int{7} +} +func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParamsResponse.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 *MsgUpdateParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParamsResponse.Merge(m, src) +} +func (m *MsgUpdateParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgJoinRestakingPool)(nil), "milkyway.restaking.v1.MsgJoinRestakingPool") + proto.RegisterType((*MsgJoinRestakingPoolResponse)(nil), "milkyway.restaking.v1.MsgJoinRestakingPoolResponse") + proto.RegisterType((*MsgDelegateOperator)(nil), "milkyway.restaking.v1.MsgDelegateOperator") + proto.RegisterType((*MsgDelegateOperatorResponse)(nil), "milkyway.restaking.v1.MsgDelegateOperatorResponse") + proto.RegisterType((*MsgDelegateService)(nil), "milkyway.restaking.v1.MsgDelegateService") + proto.RegisterType((*MsgDelegateServiceResponse)(nil), "milkyway.restaking.v1.MsgDelegateServiceResponse") + proto.RegisterType((*MsgUpdateParams)(nil), "milkyway.restaking.v1.MsgUpdateParams") + proto.RegisterType((*MsgUpdateParamsResponse)(nil), "milkyway.restaking.v1.MsgUpdateParamsResponse") +} + +func init() { + proto.RegisterFile("milkyway/restaking/v1/messages.proto", fileDescriptor_9772be2b1a923bdb) +} + +var fileDescriptor_9772be2b1a923bdb = []byte{ + // 668 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0x8e, 0x29, 0x44, 0xca, 0x95, 0xb6, 0x60, 0x8a, 0xda, 0xba, 0xad, 0x53, 0x59, 0x08, 0x95, + 0xd0, 0xfa, 0x48, 0x2b, 0x81, 0x54, 0xa6, 0x86, 0x2e, 0xa9, 0x14, 0x51, 0xb9, 0x62, 0x61, 0xa9, + 0x2e, 0xf1, 0x71, 0xb5, 0x12, 0xfb, 0x8c, 0xef, 0x12, 0xc8, 0x86, 0x18, 0x99, 0xf8, 0x29, 0x19, + 0xf8, 0x07, 0x2c, 0x19, 0x2b, 0x58, 0x98, 0x22, 0xe4, 0x0c, 0x99, 0x58, 0xfa, 0x0b, 0x50, 0xec, + 0xb3, 0x63, 0x12, 0x47, 0x84, 0x88, 0x25, 0xca, 0xbd, 0xf7, 0xbd, 0xef, 0xbd, 0xef, 0xcb, 0xbd, + 0x0b, 0x78, 0x60, 0x5b, 0x8d, 0x7a, 0xfb, 0x1d, 0x6a, 0x43, 0x0f, 0x33, 0x8e, 0xea, 0x96, 0x43, + 0x60, 0xab, 0x08, 0x6d, 0xcc, 0x18, 0x22, 0x98, 0xe9, 0xae, 0x47, 0x39, 0x95, 0xef, 0x47, 0x28, + 0x3d, 0x46, 0xe9, 0xad, 0xa2, 0x72, 0x17, 0xd9, 0x96, 0x43, 0x61, 0xf0, 0x19, 0x22, 0x95, 0x8d, + 0x1a, 0x65, 0x36, 0x65, 0x17, 0xc1, 0x09, 0x86, 0x07, 0x91, 0x52, 0xc3, 0x13, 0xac, 0x22, 0x86, + 0x61, 0xab, 0x58, 0xc5, 0x1c, 0x15, 0x61, 0x8d, 0x5a, 0xce, 0x44, 0xde, 0xa9, 0xc7, 0xf9, 0xe1, + 0x41, 0xe4, 0xd7, 0x44, 0xde, 0x66, 0xe1, 0x88, 0x8c, 0x88, 0xc4, 0x2a, 0xa1, 0x84, 0x86, 0x0d, + 0x87, 0xdf, 0x44, 0x54, 0x4b, 0x57, 0xe6, 0x22, 0x0f, 0xd9, 0x62, 0x24, 0xed, 0xab, 0x04, 0x56, + 0x2b, 0x8c, 0x9c, 0x52, 0xcb, 0x31, 0x22, 0xd0, 0x19, 0xa5, 0x0d, 0xf9, 0x29, 0xc8, 0x99, 0xb8, + 0x81, 0x09, 0xe2, 0xd4, 0x5b, 0x97, 0x76, 0xa4, 0xdd, 0x5c, 0x69, 0xfd, 0xdb, 0x97, 0xfd, 0x55, + 0x21, 0xe8, 0xd8, 0x34, 0x3d, 0xcc, 0xd8, 0x39, 0xf7, 0x2c, 0x87, 0x18, 0x23, 0xa8, 0x7c, 0x0c, + 0xb2, 0xc8, 0xa6, 0x4d, 0x87, 0xaf, 0xdf, 0xd8, 0x91, 0x76, 0x17, 0x0f, 0x36, 0x74, 0x51, 0x31, + 0x14, 0xad, 0x0b, 0x51, 0xfa, 0x0b, 0x6a, 0x39, 0xa5, 0xe5, 0x6e, 0x2f, 0x9f, 0xf1, 0x7b, 0xf9, + 0xec, 0x71, 0x50, 0x60, 0x88, 0xc2, 0xa3, 0x27, 0x1f, 0x07, 0x9d, 0xc2, 0x88, 0xf2, 0xd3, 0xa0, + 0x53, 0xd8, 0x8e, 0xa5, 0xa4, 0x0d, 0xab, 0xa9, 0x60, 0x2b, 0x2d, 0x6e, 0x60, 0xe6, 0x52, 0x87, + 0x61, 0xed, 0x5a, 0x02, 0xf7, 0x2a, 0x8c, 0x9c, 0x84, 0x94, 0xf8, 0xa5, 0x8b, 0xbd, 0x60, 0xd8, + 0x79, 0x45, 0x42, 0xb0, 0x48, 0x05, 0xc7, 0x85, 0x65, 0x06, 0x4a, 0x97, 0x4a, 0xcb, 0x7e, 0x2f, + 0x0f, 0x22, 0xea, 0xf2, 0x89, 0x01, 0x22, 0x48, 0xd9, 0x4c, 0xb8, 0xb2, 0x30, 0xaf, 0x2b, 0x70, + 0xd2, 0x95, 0xad, 0xa4, 0x2b, 0xe3, 0xe2, 0xb4, 0x6d, 0xb0, 0x99, 0x12, 0x8e, 0x3d, 0xf9, 0x25, + 0x01, 0x39, 0x91, 0x3f, 0xc7, 0x5e, 0xcb, 0xaa, 0xe1, 0xb9, 0x2d, 0xd9, 0x03, 0x80, 0x85, 0x14, + 0x23, 0x47, 0x96, 0xfc, 0x5e, 0x3e, 0x27, 0x88, 0xcb, 0x27, 0x46, 0x4e, 0x00, 0xfe, 0x8f, 0x1f, + 0xfa, 0xa4, 0x1f, 0x9b, 0x69, 0x7e, 0x88, 0xfe, 0xda, 0x16, 0x50, 0x26, 0xa3, 0xb1, 0x1b, 0xdf, + 0x25, 0xb0, 0x52, 0x61, 0xe4, 0x95, 0x6b, 0x22, 0x8e, 0xcf, 0x82, 0x0d, 0x91, 0x4f, 0x41, 0x0e, + 0x35, 0xf9, 0x25, 0xf5, 0x2c, 0xde, 0x16, 0x56, 0xec, 0x5d, 0xf7, 0xf2, 0x77, 0xda, 0xc8, 0x6e, + 0x1c, 0x69, 0x71, 0x4a, 0x9b, 0x6e, 0x4f, 0x8c, 0x91, 0x9f, 0x83, 0x6c, 0xb8, 0x77, 0x62, 0x2d, + 0xb6, 0xf5, 0xd4, 0x07, 0x45, 0x0f, 0x5b, 0x97, 0x6e, 0x0e, 0x45, 0x1b, 0xa2, 0xe4, 0xe8, 0x59, + 0x20, 0x35, 0x26, 0x1b, 0x4a, 0x1d, 0xbd, 0x5a, 0xef, 0x13, 0xdb, 0x3d, 0xa6, 0x40, 0xdb, 0x00, + 0x6b, 0x63, 0xa1, 0x48, 0xf0, 0x41, 0x77, 0x01, 0x2c, 0x54, 0x18, 0x91, 0x29, 0x58, 0x14, 0xab, + 0xc2, 0x51, 0x1d, 0xcb, 0x8f, 0xa7, 0xcc, 0x95, 0xb6, 0x5e, 0xca, 0xe1, 0x3f, 0x80, 0xa3, 0xc6, + 0xf2, 0x5b, 0xb0, 0x92, 0xb8, 0x8b, 0x41, 0xd3, 0xc2, 0x74, 0x9e, 0xf1, 0xeb, 0xab, 0x1c, 0xcc, + 0x8e, 0x8d, 0x5b, 0x3a, 0x60, 0x79, 0xf4, 0x7b, 0x07, 0x1d, 0x1f, 0xfd, 0x9d, 0x45, 0x54, 0x28, + 0xc5, 0x99, 0xa1, 0x71, 0xbf, 0x37, 0xe0, 0xf6, 0x1f, 0x17, 0xe9, 0xe1, 0x74, 0x8a, 0x24, 0x4e, + 0xd1, 0x67, 0xc3, 0x45, 0x7d, 0x94, 0x5b, 0x1f, 0x06, 0x9d, 0x82, 0x54, 0xaa, 0x74, 0x7d, 0x55, + 0xba, 0xf2, 0x55, 0xe9, 0xa7, 0xaf, 0x4a, 0x9f, 0xfb, 0x6a, 0xe6, 0xaa, 0xaf, 0x66, 0x7e, 0xf4, + 0xd5, 0xcc, 0xeb, 0x43, 0x62, 0xf1, 0xcb, 0x66, 0x55, 0xaf, 0x51, 0x1b, 0x46, 0xd4, 0xfb, 0x0d, + 0x54, 0x65, 0x30, 0xf5, 0xfa, 0xf0, 0xb6, 0x8b, 0x59, 0x35, 0x1b, 0xfc, 0x33, 0x1c, 0xfe, 0x0e, + 0x00, 0x00, 0xff, 0xff, 0x37, 0xc9, 0x43, 0x40, 0x19, 0x07, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // PoolRestake defines the operation that allows users to join a restaking + // pool with a given amount of assets. The pool can then be used to provide + // services with cryptoeconomic security. + PoolRestake(ctx context.Context, in *MsgJoinRestakingPool, opts ...grpc.CallOption) (*MsgJoinRestakingPoolResponse, error) + // OperatorRestake defines the operation that allows users to delegate their + // assets to a specific operator. + OperatorRestake(ctx context.Context, in *MsgDelegateOperator, opts ...grpc.CallOption) (*MsgDelegateOperatorResponse, error) + // ServiceRestake defines the operation that allows users to delegate their + // assets to a specific service. + ServiceRestake(ctx context.Context, in *MsgDelegateService, opts ...grpc.CallOption) (*MsgDelegateServiceResponse, error) + // UpdateParams defines a (governance) operation for updating the module + // parameters. + // The authority defaults to the x/gov module account. + UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) PoolRestake(ctx context.Context, in *MsgJoinRestakingPool, opts ...grpc.CallOption) (*MsgJoinRestakingPoolResponse, error) { + out := new(MsgJoinRestakingPoolResponse) + err := c.cc.Invoke(ctx, "/milkyway.restaking.v1.Msg/PoolRestake", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) OperatorRestake(ctx context.Context, in *MsgDelegateOperator, opts ...grpc.CallOption) (*MsgDelegateOperatorResponse, error) { + out := new(MsgDelegateOperatorResponse) + err := c.cc.Invoke(ctx, "/milkyway.restaking.v1.Msg/OperatorRestake", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ServiceRestake(ctx context.Context, in *MsgDelegateService, opts ...grpc.CallOption) (*MsgDelegateServiceResponse, error) { + out := new(MsgDelegateServiceResponse) + err := c.cc.Invoke(ctx, "/milkyway.restaking.v1.Msg/ServiceRestake", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, "/milkyway.restaking.v1.Msg/UpdateParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // PoolRestake defines the operation that allows users to join a restaking + // pool with a given amount of assets. The pool can then be used to provide + // services with cryptoeconomic security. + PoolRestake(context.Context, *MsgJoinRestakingPool) (*MsgJoinRestakingPoolResponse, error) + // OperatorRestake defines the operation that allows users to delegate their + // assets to a specific operator. + OperatorRestake(context.Context, *MsgDelegateOperator) (*MsgDelegateOperatorResponse, error) + // ServiceRestake defines the operation that allows users to delegate their + // assets to a specific service. + ServiceRestake(context.Context, *MsgDelegateService) (*MsgDelegateServiceResponse, error) + // UpdateParams defines a (governance) operation for updating the module + // parameters. + // The authority defaults to the x/gov module account. + UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) PoolRestake(ctx context.Context, req *MsgJoinRestakingPool) (*MsgJoinRestakingPoolResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PoolRestake not implemented") +} +func (*UnimplementedMsgServer) OperatorRestake(ctx context.Context, req *MsgDelegateOperator) (*MsgDelegateOperatorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OperatorRestake not implemented") +} +func (*UnimplementedMsgServer) ServiceRestake(ctx context.Context, req *MsgDelegateService) (*MsgDelegateServiceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ServiceRestake not implemented") +} +func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_PoolRestake_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgJoinRestakingPool) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).PoolRestake(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/milkyway.restaking.v1.Msg/PoolRestake", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).PoolRestake(ctx, req.(*MsgJoinRestakingPool)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_OperatorRestake_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgDelegateOperator) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).OperatorRestake(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/milkyway.restaking.v1.Msg/OperatorRestake", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).OperatorRestake(ctx, req.(*MsgDelegateOperator)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ServiceRestake_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgDelegateService) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ServiceRestake(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/milkyway.restaking.v1.Msg/ServiceRestake", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ServiceRestake(ctx, req.(*MsgDelegateService)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/milkyway.restaking.v1.Msg/UpdateParams", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "milkyway.restaking.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "PoolRestake", + Handler: _Msg_PoolRestake_Handler, + }, + { + MethodName: "OperatorRestake", + Handler: _Msg_OperatorRestake_Handler, + }, + { + MethodName: "ServiceRestake", + Handler: _Msg_ServiceRestake_Handler, + }, + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "milkyway/restaking/v1/messages.proto", +} + +func (m *MsgJoinRestakingPool) 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 *MsgJoinRestakingPool) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgJoinRestakingPool) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMessages(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Delegator) > 0 { + i -= len(m.Delegator) + copy(dAtA[i:], m.Delegator) + i = encodeVarintMessages(dAtA, i, uint64(len(m.Delegator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgJoinRestakingPoolResponse) 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 *MsgJoinRestakingPoolResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgJoinRestakingPoolResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgDelegateOperator) 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 *MsgDelegateOperator) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDelegateOperator) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMessages(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.OperatorID != 0 { + i = encodeVarintMessages(dAtA, i, uint64(m.OperatorID)) + i-- + dAtA[i] = 0x10 + } + if len(m.Delegator) > 0 { + i -= len(m.Delegator) + copy(dAtA[i:], m.Delegator) + i = encodeVarintMessages(dAtA, i, uint64(len(m.Delegator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgDelegateOperatorResponse) 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 *MsgDelegateOperatorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDelegateOperatorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgDelegateService) 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 *MsgDelegateService) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDelegateService) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMessages(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.ServiceID != 0 { + i = encodeVarintMessages(dAtA, i, uint64(m.ServiceID)) + i-- + dAtA[i] = 0x10 + } + if len(m.Delegator) > 0 { + i -= len(m.Delegator) + copy(dAtA[i:], m.Delegator) + i = encodeVarintMessages(dAtA, i, uint64(len(m.Delegator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgDelegateServiceResponse) 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 *MsgDelegateServiceResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDelegateServiceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParams) 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 *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMessages(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintMessages(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) 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 *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintMessages(dAtA []byte, offset int, v uint64) int { + offset -= sovMessages(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgJoinRestakingPool) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Delegator) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovMessages(uint64(l)) + return n +} + +func (m *MsgJoinRestakingPoolResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgDelegateOperator) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Delegator) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } + if m.OperatorID != 0 { + n += 1 + sovMessages(uint64(m.OperatorID)) + } + l = m.Amount.Size() + n += 1 + l + sovMessages(uint64(l)) + return n +} + +func (m *MsgDelegateOperatorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgDelegateService) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Delegator) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } + if m.ServiceID != 0 { + n += 1 + sovMessages(uint64(m.ServiceID)) + } + l = m.Amount.Size() + n += 1 + l + sovMessages(uint64(l)) + return n +} + +func (m *MsgDelegateServiceResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovMessages(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovMessages(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovMessages(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozMessages(x uint64) (n int) { + return sovMessages(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgJoinRestakingPool) 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 ErrIntOverflowMessages + } + 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: MsgJoinRestakingPool: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgJoinRestakingPool: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Delegator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + 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 ErrInvalidLengthMessages + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Delegator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + 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 ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMessages + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + 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 := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgJoinRestakingPoolResponse) 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 ErrIntOverflowMessages + } + 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: MsgJoinRestakingPoolResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgJoinRestakingPoolResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDelegateOperator) 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 ErrIntOverflowMessages + } + 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: MsgDelegateOperator: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDelegateOperator: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Delegator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + 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 ErrInvalidLengthMessages + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Delegator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorID", wireType) + } + m.OperatorID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OperatorID |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMessages + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + 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 := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDelegateOperatorResponse) 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 ErrIntOverflowMessages + } + 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: MsgDelegateOperatorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDelegateOperatorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDelegateService) 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 ErrIntOverflowMessages + } + 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: MsgDelegateService: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDelegateService: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Delegator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + 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 ErrInvalidLengthMessages + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Delegator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ServiceID", wireType) + } + m.ServiceID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ServiceID |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMessages + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + 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 := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDelegateServiceResponse) 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 ErrIntOverflowMessages + } + 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: MsgDelegateServiceResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDelegateServiceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParams) 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 ErrIntOverflowMessages + } + 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: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + 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 ErrInvalidLengthMessages + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMessages + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthMessages + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthMessages + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParamsResponse) 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 ErrIntOverflowMessages + } + 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: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipMessages(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMessages + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipMessages(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMessages + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMessages + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMessages + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthMessages + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupMessages + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthMessages + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthMessages = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowMessages = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupMessages = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/restaking/types/messages_test.go b/x/restaking/types/messages_test.go new file mode 100644 index 000000000..4a85a4c4d --- /dev/null +++ b/x/restaking/types/messages_test.go @@ -0,0 +1,265 @@ +package types_test + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +var msgJoinRestakingPool = types.NewMsgJoinRestakingPool( + sdk.NewCoin("umilk", sdkmath.NewInt(100_000_000)), + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", +) + +func TestMsgJoinRestakingPool_ValidateBasic(t *testing.T) { + testCases := []struct { + name string + msg *types.MsgJoinRestakingPool + shouldErr bool + }{ + { + name: "invalid amount returns error", + msg: types.NewMsgJoinRestakingPool( + sdk.Coin{Denom: "invalid!", Amount: sdkmath.NewInt(100_000_000)}, + msgJoinRestakingPool.Delegator, + ), + shouldErr: true, + }, + { + name: "invalid delegator address returns error", + msg: types.NewMsgJoinRestakingPool( + msgJoinRestakingPool.Amount, + "invalid", + ), + shouldErr: true, + }, + { + name: "valid message returns no error", + msg: msgJoinRestakingPool, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestMsgJoinRestakingPool_GetSignBytes(t *testing.T) { + expected := `{"type":"milkyway/MsgJoinRestakingPool","value":{"amount":{"amount":"100000000","denom":"umilk"},"delegator":"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd"}}` + require.Equal(t, expected, string(msgJoinRestakingPool.GetSignBytes())) +} + +func TestMsgJoinRestakingPool_GetSigners(t *testing.T) { + addr, _ := sdk.AccAddressFromBech32(msgJoinRestakingPool.Delegator) + require.Equal(t, []sdk.AccAddress{addr}, msgJoinRestakingPool.GetSigners()) +} + +// -------------------------------------------------------------------------------------------------------------------- + +var msgDelegateOperator = types.NewMsgDelegateOperator( + 1, + sdk.NewCoin("umilk", sdkmath.NewInt(100_000_000)), + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", +) + +func TestMsgDelegateOperator_ValidateBasic(t *testing.T) { + testCases := []struct { + name string + msg *types.MsgDelegateOperator + shouldErr bool + }{ + { + name: "invalid operator id returns error", + msg: types.NewMsgDelegateOperator( + 0, + msgDelegateOperator.Amount, + msgDelegateOperator.Delegator, + ), + shouldErr: true, + }, + { + name: "invalid amount returns error", + msg: types.NewMsgDelegateOperator( + msgDelegateOperator.OperatorID, + sdk.Coin{Denom: "invalid!", Amount: sdkmath.NewInt(100_000_000)}, + msgDelegateOperator.Delegator, + ), + shouldErr: true, + }, + { + name: "invalid delegator address returns error", + msg: types.NewMsgDelegateOperator( + msgDelegateOperator.OperatorID, + msgDelegateOperator.Amount, + "invalid", + ), + shouldErr: true, + }, + { + name: "valid message returns no error", + msg: msgDelegateOperator, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestMsgDelegateOperator_GetSignBytes(t *testing.T) { + expected := `{"type":"milkyway/MsgDelegateOperator","value":{"amount":{"amount":"100000000","denom":"umilk"},"delegator":"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd","operator_id":1}}` + require.Equal(t, expected, string(msgDelegateOperator.GetSignBytes())) +} + +func TestMsgDelegateOperator_GetSigners(t *testing.T) { + addr, _ := sdk.AccAddressFromBech32(msgDelegateOperator.Delegator) + require.Equal(t, []sdk.AccAddress{addr}, msgDelegateOperator.GetSigners()) +} + +// -------------------------------------------------------------------------------------------------------------------- + +var msgDelegateService = types.NewMsgDelegateService( + 1, + sdk.NewCoin("umilk", sdkmath.NewInt(100_000_000)), + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", +) + +func TestMsgDelegateService_ValidateBasic(t *testing.T) { + testCases := []struct { + name string + msg *types.MsgDelegateService + shouldErr bool + }{ + { + name: "invalid service id returns error", + msg: types.NewMsgDelegateService( + 0, + msgDelegateService.Amount, + msgDelegateService.Delegator, + ), + shouldErr: true, + }, + { + name: "invalid amount returns error", + msg: types.NewMsgDelegateService( + msgDelegateService.ServiceID, + sdk.Coin{Denom: "invalid!", Amount: sdkmath.NewInt(100_000_000)}, + msgDelegateService.Delegator, + ), + shouldErr: true, + }, + { + name: "invalid delegator address returns error", + msg: types.NewMsgDelegateService( + msgDelegateService.ServiceID, + msgDelegateService.Amount, + "invalid", + ), + shouldErr: true, + }, + { + name: "valid message returns no error", + msg: msgDelegateService, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestMsgDelegateService_GetSignBytes(t *testing.T) { + expected := `{"type":"milkyway/MsgDelegateService","value":{"amount":{"amount":"100000000","denom":"umilk"},"delegator":"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd","service_id":1}}` + require.Equal(t, expected, string(msgDelegateService.GetSignBytes())) +} + +func TestMsgDelegateService_GetSigners(t *testing.T) { + addr, _ := sdk.AccAddressFromBech32(msgDelegateService.Delegator) + require.Equal(t, []sdk.AccAddress{addr}, msgDelegateOperator.GetSigners()) +} + +// -------------------------------------------------------------------------------------------------------------------- + +var msgUpdateParams = types.NewMsgUpdateParams( + types.DefaultParams(), + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", +) + +func TestMsgUpdateParams_ValidateBasic(t *testing.T) { + testCases := []struct { + name string + msg *types.MsgUpdateParams + shouldErr bool + }{ + { + name: "invalid params return error", + msg: types.NewMsgUpdateParams( + types.NewParams(0), + msgUpdateParams.Authority, + ), + shouldErr: true, + }, + { + name: "invalid authority address returns error", + msg: types.NewMsgUpdateParams( + msgUpdateParams.Params, + "invalid", + ), + shouldErr: true, + }, + { + name: "valid message returns no error", + msg: msgUpdateParams, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestMsgUpdateParams_GetSignBytes(t *testing.T) { + expected := `{"type":"milkyway/restaking/MsgUpdateParams","value":{"authority":"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd","params":{"unbonding_time":"259200000000000"}}}` + require.Equal(t, expected, string(msgUpdateParams.GetSignBytes())) +} + +func TestMsgUpdateParams_GetSigners(t *testing.T) { + addr, _ := sdk.AccAddressFromBech32(msgUpdateParams.Authority) + require.Equal(t, []sdk.AccAddress{addr}, msgDelegateOperator.GetSigners()) +} From 068810e933af56ecd442c4af6e5d2f74e708b3f0 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 10 Jun 2024 10:05:15 -0500 Subject: [PATCH 05/37] feat: implement pool delegation --- x/restaking/keeper/keeper.go | 5 ++ x/restaking/keeper/pool_restaking.go | 70 +++++++++++++++++++++++++++ x/restaking/types/expected_keepers.go | 11 +++++ x/restaking/types/keys.go | 49 +++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 x/restaking/keeper/pool_restaking.go diff --git a/x/restaking/keeper/keeper.go b/x/restaking/keeper/keeper.go index d6a448862..bf6e7a5df 100644 --- a/x/restaking/keeper/keeper.go +++ b/x/restaking/keeper/keeper.go @@ -3,6 +3,8 @@ package keeper import ( storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" + + "github.com/milkyway-labs/milkyway/x/restaking/types" ) type Keeper struct { @@ -10,6 +12,9 @@ type Keeper struct { cdc codec.Codec authority string + + bankKeeper types.BankKeeper + poolsKeeper types.PoolsKeeper } func NewKeeper(cdc codec.Codec, storeKey storetypes.StoreKey, authority string) *Keeper { diff --git a/x/restaking/keeper/pool_restaking.go b/x/restaking/keeper/pool_restaking.go new file mode 100644 index 000000000..b64370a6b --- /dev/null +++ b/x/restaking/keeper/pool_restaking.go @@ -0,0 +1,70 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +// PerformPoolDelegation sends the given amount to the pool account and saves the delegation for the given user +func (k *Keeper) PerformPoolDelegation(ctx sdk.Context, amount sdk.Coin, delegator string) error { + // Get or create the pool for the given amount denom + pool, err := k.poolsKeeper.CreateOrGetPoolByDenom(ctx, amount.Denom) + if err != nil { + return err + } + + // Send the funds to the pool account + delegatorAddr, err := sdk.AccAddressFromBech32(delegator) + if err != nil { + return err + } + poolAddr, err := sdk.AccAddressFromBech32(pool.AccountAddress) + if err != nil { + return err + } + err = k.bankKeeper.SendCoins(ctx, delegatorAddr, poolAddr, sdk.NewCoins(amount)) + if err != nil { + return err + } + + // Get the current delegation for the user + delegationAmount, found, err := k.GetUserPoolDelegationAmount(ctx, pool.ID, delegator) + if err != nil { + return err + } + + // If a delegation already exists, add the new amount to the existing one + if found { + amount = amount.AddAmount(delegationAmount.Amount) + } + + // Save the new delegation amount + k.SavePoolDelegation(ctx, pool.ID, amount, delegator) + + return nil +} + +// SavePoolDelegation stores the given amount as the delegation for the given user in the given pool +func (k *Keeper) SavePoolDelegation(ctx sdk.Context, poolID uint32, amount sdk.Coin, delegator string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.UserPoolDelegationStoreKey(poolID, delegator), []byte(amount.String())) +} + +// GetUserPoolDelegationAmount returns the delegation amount for the given user in the given pool +func (k *Keeper) GetUserPoolDelegationAmount(ctx sdk.Context, poolID uint32, userAddress string) (sdk.Coin, bool, error) { + // Get the delegation amount from the store + store := ctx.KVStore(k.storeKey) + delegationAmountBz := store.Get(types.UserPoolDelegationStoreKey(poolID, userAddress)) + if delegationAmountBz == nil { + return sdk.Coin{}, false, nil + } + + // Parse the delegation amount + amount, err := sdk.ParseCoinNormalized(string(delegationAmountBz)) + if err != nil { + return sdk.Coin{}, false, err + } + + return amount, true, nil +} diff --git a/x/restaking/types/expected_keepers.go b/x/restaking/types/expected_keepers.go index 10fa0872b..38de27461 100644 --- a/x/restaking/types/expected_keepers.go +++ b/x/restaking/types/expected_keepers.go @@ -1,12 +1,23 @@ package types import ( + "context" + sdk "github.com/cosmos/cosmos-sdk/types" operatorstypes "github.com/milkyway-labs/milkyway/x/operators/types" + poolstypes "github.com/milkyway-labs/milkyway/x/pools/types" servicestypes "github.com/milkyway-labs/milkyway/x/services/types" ) +type BankKeeper interface { + SendCoins(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) error +} + +type PoolsKeeper interface { + CreateOrGetPoolByDenom(ctx sdk.Context, denom string) (poolstypes.Pool, error) +} + type ServicesKeeper interface { GetService(ctx sdk.Context, serviceID uint32) (servicestypes.Service, bool) } diff --git a/x/restaking/types/keys.go b/x/restaking/types/keys.go index 9cb85c6d6..88daf36db 100644 --- a/x/restaking/types/keys.go +++ b/x/restaking/types/keys.go @@ -1,6 +1,55 @@ package types +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + + poolstypes "github.com/milkyway-labs/milkyway/x/pools/types" +) + const ( ModuleName = "restaking" StoreKey = ModuleName ) + +var ( + ParamsKey = []byte{0x01} + + PoolDelegationPrefix = []byte{0xa1} + UnbondingPoolDelegationPrefix = []byte{0xa2} + + ServiceDelegationPrefix = []byte{0xb1} + UnbondingServiceDelegationPrefix = []byte{0xb2} + + OperatorDelegationPrefix = []byte{0xc1} + UnbondingOperatorDelegationPrefix = []byte{0xc2} +) + +// PoolDelegationsStorePrefix returns the prefix used to store all the delegations to a given pool +func PoolDelegationsStorePrefix(poolID uint32) []byte { + return append(PoolDelegationPrefix, poolstypes.GetPoolIDBytes(poolID)...) +} + +// UserPoolDelegationStoreKey returns the key used to store the delegation of a user to a given pool +func UserPoolDelegationStoreKey(poolID uint32, delegator string) []byte { + return append(PoolDelegationsStorePrefix(poolID), []byte(delegator)...) +} + +// UnbondingDelegationsByTimeStorePrefix returns the prefix used to store all the unbonding delegations +// that expire at the given time +func UnbondingDelegationsByTimeStorePrefix(endTime time.Time) []byte { + return append(UnbondingPoolDelegationPrefix, sdk.FormatTimeBytes(endTime)...) +} + +// UnbondingPoolDelegationsStorePrefix returns the prefix used to store all the unbonding delegations +// to a given pool that expire at the given time +func UnbondingPoolDelegationsStorePrefix(poolID uint32, endTime time.Time) []byte { + return append(UnbondingDelegationsByTimeStorePrefix(endTime), poolstypes.GetPoolIDBytes(poolID)...) +} + +// UserUnbondingPoolDelegationStoreKey returns the key used to store the unbonding delegation of a user +// to a given pool that expires at the given time +func UserUnbondingPoolDelegationStoreKey(poolID uint32, delegator string, endTime time.Time) []byte { + return append(UnbondingPoolDelegationsStorePrefix(poolID, endTime), []byte(delegator)...) +} From ec0400ce37b1a8e4b7cf5de10ddcfac09f4bd6ed Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Fri, 14 Jun 2024 13:25:56 -0500 Subject: [PATCH 06/37] chore: fix pool address field name --- x/restaking/keeper/pool_restaking.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/restaking/keeper/pool_restaking.go b/x/restaking/keeper/pool_restaking.go index b64370a6b..8637baeea 100644 --- a/x/restaking/keeper/pool_restaking.go +++ b/x/restaking/keeper/pool_restaking.go @@ -19,7 +19,7 @@ func (k *Keeper) PerformPoolDelegation(ctx sdk.Context, amount sdk.Coin, delegat if err != nil { return err } - poolAddr, err := sdk.AccAddressFromBech32(pool.AccountAddress) + poolAddr, err := sdk.AccAddressFromBech32(pool.Address) if err != nil { return err } From 6399bd37af27e2ae6853d4629896e47e0618ed8f Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Fri, 14 Jun 2024 14:48:55 -0500 Subject: [PATCH 07/37] feat: add shares and tokens to pool type --- proto/milkyway/pools/v1/models.proto | 14 +++ x/pools/types/errors.go | 3 +- x/pools/types/models.go | 52 ++++++++++- x/pools/types/models.pb.go | 135 +++++++++++++++++++++++---- 4 files changed, 183 insertions(+), 21 deletions(-) diff --git a/proto/milkyway/pools/v1/models.proto b/proto/milkyway/pools/v1/models.proto index cf20ec163..7244d0f82 100644 --- a/proto/milkyway/pools/v1/models.proto +++ b/proto/milkyway/pools/v1/models.proto @@ -17,4 +17,18 @@ message Pool { // Address represents the address of the account that is associated with this // pool. This will be used to store tokens that users delegate to this pool. string address = 3 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // Tokens define the delegated tokens. + string tokens = 4 [ + (cosmos_proto.scalar) = "cosmos.Int", + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false + ]; + + // DelegatorShares defines total shares issued to a pool's delegators. + string delegator_shares = 5 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; } diff --git a/x/pools/types/errors.go b/x/pools/types/errors.go index ab08baa2d..7bf8a20f9 100644 --- a/x/pools/types/errors.go +++ b/x/pools/types/errors.go @@ -5,5 +5,6 @@ import ( ) var ( - ErrInvalidGenesis = errors.Register(ModuleName, 1, "invalid genesis state") + ErrInvalidGenesis = errors.Register(ModuleName, 1, "invalid genesis state") + ErrInsufficientShares = errors.Register(ModuleName, 2, "insufficient delegation shares") ) diff --git a/x/pools/types/models.go b/x/pools/types/models.go index f2f98181a..037c19f0b 100644 --- a/x/pools/types/models.go +++ b/x/pools/types/models.go @@ -4,6 +4,7 @@ import ( "fmt" "strconv" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -27,14 +28,16 @@ func ParsePoolID(value string) (uint32, error) { // NewPool creates a new Pool instance func NewPool(id uint32, denom string) Pool { return Pool{ - ID: id, - Denom: denom, - Address: GetPoolAddress(id).String(), + ID: id, + Denom: denom, + Address: GetPoolAddress(id).String(), + Tokens: sdkmath.ZeroInt(), + DelegatorShares: sdkmath.LegacyZeroDec(), } } // Validate checks if the pool is valid -func (p *Pool) Validate() error { +func (p Pool) Validate() error { if p.ID == 0 { return fmt.Errorf("invalid pool id") } @@ -50,3 +53,44 @@ func (p *Pool) Validate() error { return nil } + +// InvalidExRate returns whether the exchange rates is invalid. +// This can happen e.g. if Pool loses all tokens due to slashing. In this case, +// make all future delegations invalid. +func (p Pool) InvalidExRate() bool { + return p.Tokens.IsZero() && p.DelegatorShares.IsPositive() +} + +// SharesFromTokens returns the shares of a delegation given a bond amount. It +// returns an error if the pool has no tokens. +func (p Pool) SharesFromTokens(amt sdkmath.Int) (sdkmath.LegacyDec, error) { + if p.Tokens.IsZero() { + return sdkmath.LegacyZeroDec(), ErrInsufficientShares + } + + return p.DelegatorShares.MulInt(amt).QuoInt(p.Tokens), nil +} + +// AddTokensFromDelegation adds the given amount of tokens to the pool's total tokens, +// also updating the pool's delegator shares. +// It returns the updated pool and the shares issued. +func (p Pool) AddTokensFromDelegation(amount sdkmath.Int) (Pool, sdkmath.LegacyDec) { + // calculate the shares to issue + var issuedShares sdkmath.LegacyDec + if p.DelegatorShares.IsZero() { + // the first delegation to a validator sets the exchange rate to one + issuedShares = sdkmath.LegacyNewDecFromInt(amount) + } else { + shares, err := p.SharesFromTokens(amount) + if err != nil { + panic(err) + } + + issuedShares = shares + } + + p.Tokens = p.Tokens.Add(amount) + p.DelegatorShares = p.DelegatorShares.Add(issuedShares) + + return p, issuedShares +} diff --git a/x/pools/types/models.pb.go b/x/pools/types/models.pb.go index cb329e852..5991bcf43 100644 --- a/x/pools/types/models.pb.go +++ b/x/pools/types/models.pb.go @@ -4,6 +4,7 @@ package types import ( + cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" _ "github.com/cosmos/cosmos-proto" _ "github.com/cosmos/gogoproto/gogoproto" @@ -33,6 +34,10 @@ type Pool struct { // Address represents the address of the account that is associated with this // pool. This will be used to store tokens that users delegate to this pool. Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` + // Tokens define the delegated tokens. + Tokens cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=tokens,proto3,customtype=cosmossdk.io/math.Int" json:"tokens"` + // DelegatorShares defines total shares issued to a pool's delegators. + DelegatorShares cosmossdk_io_math.LegacyDec `protobuf:"bytes,5,opt,name=delegator_shares,json=delegatorShares,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"delegator_shares"` } func (m *Pool) Reset() { *m = Pool{} } @@ -96,22 +101,28 @@ func init() { func init() { proto.RegisterFile("milkyway/pools/v1/models.proto", fileDescriptor_b29c6df2abe9a338) } var fileDescriptor_b29c6df2abe9a338 = []byte{ - // 242 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xcb, 0xcd, 0xcc, 0xc9, - 0xae, 0x2c, 0x4f, 0xac, 0xd4, 0x2f, 0xc8, 0xcf, 0xcf, 0x29, 0xd6, 0x2f, 0x33, 0xd4, 0xcf, 0xcd, - 0x4f, 0x49, 0xcd, 0x29, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x84, 0xc9, 0xeb, 0x81, - 0xe5, 0xf5, 0xca, 0x0c, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0xb2, 0xfa, 0x20, 0x16, 0x44, - 0xa1, 0x94, 0x64, 0x72, 0x7e, 0x71, 0x6e, 0x7e, 0x71, 0x3c, 0x44, 0x02, 0xc2, 0x81, 0x48, 0x29, - 0x65, 0x70, 0xb1, 0x04, 0xe4, 0xe7, 0xe7, 0x08, 0x89, 0x71, 0x31, 0x65, 0xa6, 0x48, 0x30, 0x2a, - 0x30, 0x6a, 0xf0, 0x3a, 0xb1, 0x3d, 0xba, 0x27, 0xcf, 0xe4, 0xe9, 0x12, 0xc4, 0x94, 0x99, 0x22, - 0x24, 0xc2, 0xc5, 0x9a, 0x92, 0x9a, 0x97, 0x9f, 0x2b, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1, 0x19, 0x04, - 0xe1, 0x08, 0x19, 0x71, 0xb1, 0x27, 0xa6, 0xa4, 0x14, 0xa5, 0x16, 0x17, 0x4b, 0x30, 0x83, 0xc4, - 0x9d, 0x24, 0x2e, 0x6d, 0xd1, 0x15, 0x81, 0x1a, 0xec, 0x08, 0x91, 0x09, 0x2e, 0x29, 0xca, 0xcc, - 0x4b, 0x0f, 0x82, 0x29, 0x74, 0xf2, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, - 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, - 0x28, 0xfd, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0x98, 0x97, 0x74, - 0x73, 0x12, 0x93, 0x8a, 0xe1, 0x3c, 0xfd, 0x0a, 0x68, 0x10, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x27, - 0xb1, 0x81, 0xdd, 0x6e, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xee, 0x3f, 0xe7, 0x79, 0x21, 0x01, + // 338 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x4a, 0xc3, 0x40, + 0x14, 0x86, 0x93, 0xd8, 0x56, 0x1c, 0x10, 0x35, 0x54, 0x89, 0x15, 0xa6, 0xc5, 0x55, 0x41, 0x9a, + 0xa1, 0x7a, 0x02, 0x6b, 0x37, 0x01, 0x17, 0x92, 0xee, 0x44, 0x28, 0xd3, 0xcc, 0x90, 0x86, 0x26, + 0x79, 0x25, 0x33, 0x56, 0x73, 0x06, 0x37, 0x1e, 0xa6, 0x87, 0xe8, 0xb2, 0x74, 0x25, 0x2e, 0x8a, + 0xa4, 0x17, 0x91, 0xce, 0xa4, 0x45, 0x70, 0x37, 0xff, 0x7c, 0xef, 0xff, 0x16, 0xef, 0x21, 0x9c, + 0x44, 0xf1, 0x24, 0x7f, 0xa3, 0x39, 0x99, 0x02, 0xc4, 0x82, 0xcc, 0xba, 0x24, 0x01, 0xc6, 0x63, + 0xe1, 0x4e, 0x33, 0x90, 0x60, 0x9f, 0xed, 0xb8, 0xab, 0xb8, 0x3b, 0xeb, 0x36, 0xea, 0x21, 0x84, + 0xa0, 0x28, 0xd9, 0xbe, 0xf4, 0x60, 0xe3, 0x32, 0x00, 0x91, 0x80, 0x18, 0x6a, 0xa0, 0x83, 0x46, + 0xd7, 0x1f, 0x16, 0xaa, 0x3c, 0x01, 0xc4, 0xf6, 0x05, 0xb2, 0x22, 0xe6, 0x98, 0x2d, 0xb3, 0x7d, + 0xdc, 0xab, 0x15, 0xeb, 0xa6, 0xe5, 0xf5, 0x7d, 0x2b, 0x62, 0x76, 0x1d, 0x55, 0x19, 0x4f, 0x21, + 0x71, 0xac, 0x96, 0xd9, 0x3e, 0xf2, 0x75, 0xb0, 0x6f, 0xd1, 0x21, 0x65, 0x2c, 0xe3, 0x42, 0x38, + 0x07, 0xdb, 0xff, 0x9e, 0xb3, 0x9a, 0x77, 0xea, 0xa5, 0xf9, 0x5e, 0x93, 0x81, 0xcc, 0xa2, 0x34, + 0xf4, 0x77, 0x83, 0xf6, 0x03, 0xaa, 0x49, 0x98, 0xf0, 0x54, 0x38, 0x15, 0x55, 0xb9, 0x59, 0xac, + 0x9b, 0xc6, 0xf7, 0xba, 0x79, 0xae, 0x6b, 0x82, 0x4d, 0xdc, 0x08, 0x48, 0x42, 0xe5, 0xd8, 0xf5, + 0x52, 0xb9, 0x9a, 0x77, 0x50, 0xe9, 0xf3, 0x52, 0xe9, 0x97, 0x55, 0xfb, 0x05, 0x9d, 0x32, 0x1e, + 0xf3, 0x90, 0x4a, 0xc8, 0x86, 0x62, 0x4c, 0x33, 0x2e, 0x9c, 0xaa, 0xd2, 0x75, 0x4b, 0xdd, 0xd5, + 0x7f, 0xdd, 0x23, 0x0f, 0x69, 0x90, 0xf7, 0x79, 0xf0, 0x47, 0xda, 0xe7, 0x81, 0x7f, 0xb2, 0x57, + 0x0d, 0x94, 0xa9, 0xe7, 0x2d, 0x0a, 0x6c, 0x2e, 0x0b, 0x6c, 0xfe, 0x14, 0xd8, 0xfc, 0xdc, 0x60, + 0x63, 0xb9, 0xc1, 0xc6, 0xd7, 0x06, 0x1b, 0xcf, 0x24, 0x8c, 0xe4, 0xf8, 0x75, 0xe4, 0x06, 0x90, + 0x90, 0xdd, 0xda, 0x3b, 0x31, 0x1d, 0x89, 0x7d, 0x22, 0xef, 0xe5, 0x99, 0x64, 0x3e, 0xe5, 0x62, + 0x54, 0x53, 0xfb, 0xbd, 0xfb, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xf0, 0xfd, 0xb0, 0x49, 0xc5, 0x01, 0x00, 0x00, } @@ -135,6 +146,26 @@ func (m *Pool) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.DelegatorShares.Size() + i -= size + if _, err := m.DelegatorShares.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + { + size := m.Tokens.Size() + i -= size + if _, err := m.Tokens.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 if len(m.Address) > 0 { i -= len(m.Address) copy(dAtA[i:], m.Address) @@ -185,6 +216,10 @@ func (m *Pool) Size() (n int) { if l > 0 { n += 1 + l + sovModels(uint64(l)) } + l = m.Tokens.Size() + n += 1 + l + sovModels(uint64(l)) + l = m.DelegatorShares.Size() + n += 1 + l + sovModels(uint64(l)) return n } @@ -306,6 +341,74 @@ func (m *Pool) Unmarshal(dAtA []byte) error { } m.Address = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tokens", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + 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 ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Tokens.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorShares", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + 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 ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.DelegatorShares.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipModels(dAtA[iNdEx:]) From 1d46a48d917b00d2c321709a17f5205f5825cc21 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Fri, 14 Jun 2024 14:49:05 -0500 Subject: [PATCH 08/37] feat: implement pool-based delegation --- proto/milkyway/restaking/v1/models.proto | 29 ++ x/restaking/keeper/hooks.go | 33 ++ x/restaking/keeper/keeper.go | 48 ++- x/restaking/keeper/pool_restaking.go | 139 +++++--- x/restaking/types/errors.go | 11 + x/restaking/types/expected_keepers.go | 6 + x/restaking/types/hooks.go | 11 + x/restaking/types/models.go | 13 + x/restaking/types/models.pb.go | 404 +++++++++++++++++++++++ 9 files changed, 652 insertions(+), 42 deletions(-) create mode 100644 proto/milkyway/restaking/v1/models.proto create mode 100644 x/restaking/keeper/hooks.go create mode 100644 x/restaking/types/errors.go create mode 100644 x/restaking/types/hooks.go create mode 100644 x/restaking/types/models.go create mode 100644 x/restaking/types/models.pb.go diff --git a/proto/milkyway/restaking/v1/models.proto b/proto/milkyway/restaking/v1/models.proto new file mode 100644 index 000000000..ceb228d17 --- /dev/null +++ b/proto/milkyway/restaking/v1/models.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; +package milkyway.restaking.v1; + +import "amino/amino.proto"; +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types"; + +// PoolDelegation represents the bond with tokens held by an account with a +// given pool. It is owned by one delegator, and is associated with a pool. +message PoolDelegation { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // UserAddress is the encoded address of the user. + string user_address = 1 + [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // PoolID is the id of the pool. + uint32 pool_id = 2 [ (gogoproto.customname) = "PoolID" ]; + + // Shares define the delegation shares received. + string shares = 3 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; +} \ No newline at end of file diff --git a/x/restaking/keeper/hooks.go b/x/restaking/keeper/hooks.go new file mode 100644 index 000000000..134f60c79 --- /dev/null +++ b/x/restaking/keeper/hooks.go @@ -0,0 +1,33 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +var _ types.RestakingHooks = &Keeper{} + +// BeforePoolDelegationCreated implements types.RestakingHooks +func (k *Keeper) BeforePoolDelegationCreated(ctx sdk.Context, poolID uint32, delegator string) error { + if k.hooks != nil { + return k.hooks.BeforePoolDelegationCreated(ctx, poolID, delegator) + } + return nil +} + +// BeforePoolDelegationSharesModified implements types.RestakingHooks +func (k *Keeper) BeforePoolDelegationSharesModified(ctx sdk.Context, poolID uint32, delegator string) error { + if k.hooks != nil { + return k.hooks.BeforePoolDelegationSharesModified(ctx, poolID, delegator) + } + return nil +} + +// AfterPoolDelegationModified implements types.RestakingHooks +func (k *Keeper) AfterPoolDelegationModified(ctx sdk.Context, poolID uint32, delegator string) error { + if k.hooks != nil { + return k.hooks.AfterPoolDelegationModified(ctx, poolID, delegator) + } + return nil +} diff --git a/x/restaking/keeper/keeper.go b/x/restaking/keeper/keeper.go index bf6e7a5df..8f6763664 100644 --- a/x/restaking/keeper/keeper.go +++ b/x/restaking/keeper/keeper.go @@ -1,8 +1,10 @@ package keeper import ( + "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/milkyway-labs/milkyway/x/restaking/types" ) @@ -13,14 +15,50 @@ type Keeper struct { authority string - bankKeeper types.BankKeeper - poolsKeeper types.PoolsKeeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper + poolsKeeper types.PoolsKeeper + + hooks types.RestakingHooks } -func NewKeeper(cdc codec.Codec, storeKey storetypes.StoreKey, authority string) *Keeper { +func NewKeeper( + cdc codec.Codec, + storeKey storetypes.StoreKey, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, + poolsKeeper types.PoolsKeeper, + authority string, +) *Keeper { + + // Ensure that authority is a valid AccAddress + if _, err := accountKeeper.AddressCodec().StringToBytes(authority); err != nil { + panic("authority is not a valid account address") + } + return &Keeper{ - storeKey: storeKey, - cdc: cdc, + storeKey: storeKey, + cdc: cdc, + + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + poolsKeeper: poolsKeeper, + authority: authority, } } + +// Logger returns a module-specific logger. +func (k *Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", "x/"+types.ModuleName) +} + +// SetHooks allows to set the reactions hooks +func (k *Keeper) SetHooks(rs types.RestakingHooks) *Keeper { + if k.hooks != nil { + panic("cannot set services hooks twice") + } + + k.hooks = rs + return k +} diff --git a/x/restaking/keeper/pool_restaking.go b/x/restaking/keeper/pool_restaking.go index 8637baeea..c248f781d 100644 --- a/x/restaking/keeper/pool_restaking.go +++ b/x/restaking/keeper/pool_restaking.go @@ -1,70 +1,135 @@ package keeper import ( + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + poolstypes "github.com/milkyway-labs/milkyway/x/pools/types" "github.com/milkyway-labs/milkyway/x/restaking/types" ) -// PerformPoolDelegation sends the given amount to the pool account and saves the delegation for the given user -func (k *Keeper) PerformPoolDelegation(ctx sdk.Context, amount sdk.Coin, delegator string) error { - // Get or create the pool for the given amount denom - pool, err := k.poolsKeeper.CreateOrGetPoolByDenom(ctx, amount.Denom) +// SavePoolDelegation stores the given pool delegation in the store +func (k *Keeper) SavePoolDelegation(ctx sdk.Context, delegation types.PoolDelegation) error { + store := ctx.KVStore(k.storeKey) + + delegationBz, err := k.cdc.Marshal(&delegation) if err != nil { return err } - // Send the funds to the pool account - delegatorAddr, err := sdk.AccAddressFromBech32(delegator) - if err != nil { - return err + store.Set(types.UserPoolDelegationStoreKey(delegation.PoolID, delegation.UserAddress), delegationBz) + return nil +} + +// GetPoolDelegation retrieves the delegation for the given user and pool +// If the delegation does not exist, false is returned instead +func (k *Keeper) GetPoolDelegation(ctx sdk.Context, poolID uint32, userAddress string) (types.PoolDelegation, bool, error) { + // Get the delegation amount from the store + store := ctx.KVStore(k.storeKey) + delegationAmountBz := store.Get(types.UserPoolDelegationStoreKey(poolID, userAddress)) + if delegationAmountBz == nil { + return types.PoolDelegation{}, false, nil } - poolAddr, err := sdk.AccAddressFromBech32(pool.Address) + + // Parse the delegation amount + var delegation types.PoolDelegation + err := k.cdc.Unmarshal(delegationAmountBz, &delegation) if err != nil { - return err + return types.PoolDelegation{}, false, err } - err = k.bankKeeper.SendCoins(ctx, delegatorAddr, poolAddr, sdk.NewCoins(amount)) + + return delegation, true, nil +} + +// AddPoolTokensAndShares adds the given amount of tokens to the pool and returns the added shares +func (k *Keeper) AddPoolTokensAndShares( + ctx sdk.Context, pool poolstypes.Pool, tokensToAdd sdkmath.Int, +) (poolOut poolstypes.Pool, addedShares sdkmath.LegacyDec, err error) { + + // Update the pool tokens and shares and get the added shares + pool, addedShares = pool.AddTokensFromDelegation(tokensToAdd) + + // Save the pool + err = k.poolsKeeper.SavePool(ctx, pool) + return pool, addedShares, err +} + +// -------------------------------------------------------------------------------------------------------------------- + +// DelegateToPool sends the given amount to the pool account and saves the delegation for the given user +func (k *Keeper) DelegateToPool(ctx sdk.Context, amount sdk.Coin, delegator string) (sdkmath.LegacyDec, error) { + // Get or create the pool for the given amount denom + pool, err := k.poolsKeeper.CreateOrGetPoolByDenom(ctx, amount.Denom) if err != nil { - return err + return sdkmath.LegacyZeroDec(), err + } + + // In some situations, the exchange rate becomes invalid, e.g. if + // Pool loses all tokens due to slashing. In this case, + // make all future delegations invalid. + if pool.InvalidExRate() { + return sdkmath.LegacyZeroDec(), types.ErrDelegatorShareExRateInvalid } - // Get the current delegation for the user - delegationAmount, found, err := k.GetUserPoolDelegationAmount(ctx, pool.ID, delegator) + // Get or create the delegation object and call the appropriate hook if present + delegation, found, err := k.GetPoolDelegation(ctx, pool.ID, delegator) if err != nil { - return err + return sdkmath.LegacyZeroDec(), err } - // If a delegation already exists, add the new amount to the existing one if found { - amount = amount.AddAmount(delegationAmount.Amount) + // Delegation was found + err = k.BeforePoolDelegationSharesModified(ctx, pool.ID, delegator) + if err != nil { + return sdkmath.LegacyZeroDec(), err + } + } else { + // Delegation was not found + delegation = types.NewPoolDelegation(pool.ID, delegator, sdkmath.LegacyZeroDec()) + err = k.BeforePoolDelegationCreated(ctx, pool.ID, delegator) + if err != nil { + return sdkmath.LegacyZeroDec(), err + } } - // Save the new delegation amount - k.SavePoolDelegation(ctx, pool.ID, amount, delegator) + // Convert the addresses to sdk.AccAddress + delegatorAddress, err := k.accountKeeper.AddressCodec().StringToBytes(delegator) + if err != nil { + return sdkmath.LegacyZeroDec(), err + } + poolAddress, err := k.accountKeeper.AddressCodec().StringToBytes(pool.Address) + if err != nil { + return sdkmath.LegacyZeroDec(), err + } - return nil -} + // Get the bond amount + bondAmount := amount.Amount -// SavePoolDelegation stores the given amount as the delegation for the given user in the given pool -func (k *Keeper) SavePoolDelegation(ctx sdk.Context, poolID uint32, amount sdk.Coin, delegator string) { - store := ctx.KVStore(k.storeKey) - store.Set(types.UserPoolDelegationStoreKey(poolID, delegator), []byte(amount.String())) -} + // Send the funds to the pool account + coins := sdk.NewCoins(sdk.NewCoin(pool.Denom, bondAmount)) + err = k.bankKeeper.SendCoins(ctx, delegatorAddress, poolAddress, coins) + if err != nil { + return sdkmath.LegacyDec{}, err + } -// GetUserPoolDelegationAmount returns the delegation amount for the given user in the given pool -func (k *Keeper) GetUserPoolDelegationAmount(ctx sdk.Context, poolID uint32, userAddress string) (sdk.Coin, bool, error) { - // Get the delegation amount from the store - store := ctx.KVStore(k.storeKey) - delegationAmountBz := store.Get(types.UserPoolDelegationStoreKey(poolID, userAddress)) - if delegationAmountBz == nil { - return sdk.Coin{}, false, nil + // Calculate the new shares and add the tokens to the pool + _, newShares, err := k.AddPoolTokensAndShares(ctx, pool, bondAmount) + if err != nil { + return newShares, err } - // Parse the delegation amount - amount, err := sdk.ParseCoinNormalized(string(delegationAmountBz)) + // Update delegation + delegation.Shares = delegation.Shares.Add(newShares) + err = k.SavePoolDelegation(ctx, delegation) + if err != nil { + return newShares, err + } + + // Call the after-modification hook + err = k.AfterPoolDelegationModified(ctx, pool.ID, delegator) if err != nil { - return sdk.Coin{}, false, err + return newShares, err } - return amount, true, nil + return newShares, nil } diff --git a/x/restaking/types/errors.go b/x/restaking/types/errors.go new file mode 100644 index 000000000..3fa3268ea --- /dev/null +++ b/x/restaking/types/errors.go @@ -0,0 +1,11 @@ +package types + +import ( + "cosmossdk.io/errors" +) + +var ( + ErrInvalidGenesis = errors.Register(ModuleName, 1, "invalid genesis state") + ErrDelegationNotFound = errors.Register(ModuleName, 2, "delegation not found") + ErrDelegatorShareExRateInvalid = errors.Register(ModuleName, 34, "cannot delegate to pool/operator/service with invalid (zero) ex-rate") +) diff --git a/x/restaking/types/expected_keepers.go b/x/restaking/types/expected_keepers.go index 38de27461..68bb05566 100644 --- a/x/restaking/types/expected_keepers.go +++ b/x/restaking/types/expected_keepers.go @@ -3,6 +3,7 @@ package types import ( "context" + "cosmossdk.io/core/address" sdk "github.com/cosmos/cosmos-sdk/types" operatorstypes "github.com/milkyway-labs/milkyway/x/operators/types" @@ -10,12 +11,17 @@ import ( servicestypes "github.com/milkyway-labs/milkyway/x/services/types" ) +type AccountKeeper interface { + AddressCodec() address.Codec +} + type BankKeeper interface { SendCoins(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) error } type PoolsKeeper interface { CreateOrGetPoolByDenom(ctx sdk.Context, denom string) (poolstypes.Pool, error) + SavePool(ctx sdk.Context, pool poolstypes.Pool) error } type ServicesKeeper interface { diff --git a/x/restaking/types/hooks.go b/x/restaking/types/hooks.go new file mode 100644 index 000000000..2dfddb799 --- /dev/null +++ b/x/restaking/types/hooks.go @@ -0,0 +1,11 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type RestakingHooks interface { + BeforePoolDelegationCreated(ctx sdk.Context, poolID uint32, delegator string) error + BeforePoolDelegationSharesModified(ctx sdk.Context, poolID uint32, delegator string) error + AfterPoolDelegationModified(ctx sdk.Context, poolID uint32, delegator string) error +} diff --git a/x/restaking/types/models.go b/x/restaking/types/models.go new file mode 100644 index 000000000..f549ea5ac --- /dev/null +++ b/x/restaking/types/models.go @@ -0,0 +1,13 @@ +package types + +import ( + sdkmath "cosmossdk.io/math" +) + +func NewPoolDelegation(poolID uint32, userAddress string, shares sdkmath.LegacyDec) PoolDelegation { + return PoolDelegation{ + PoolID: poolID, + UserAddress: userAddress, + Shares: shares, + } +} diff --git a/x/restaking/types/models.pb.go b/x/restaking/types/models.pb.go new file mode 100644 index 000000000..24b62cbce --- /dev/null +++ b/x/restaking/types/models.pb.go @@ -0,0 +1,404 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: milkyway/restaking/v1/models.proto + +package types + +import ( + cosmossdk_io_math "cosmossdk.io/math" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// PoolDelegation represents the bond with tokens held by an account with a +// given pool. It is owned by one delegator, and is associated with a pool. +type PoolDelegation struct { + // UserAddress is the encoded address of the user. + UserAddress string `protobuf:"bytes,1,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` + // PoolID is the id of the pool. + PoolID uint32 `protobuf:"varint,2,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // Shares define the delegation shares received. + Shares cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=shares,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"shares"` +} + +func (m *PoolDelegation) Reset() { *m = PoolDelegation{} } +func (m *PoolDelegation) String() string { return proto.CompactTextString(m) } +func (*PoolDelegation) ProtoMessage() {} +func (*PoolDelegation) Descriptor() ([]byte, []int) { + return fileDescriptor_86f4cd48423b1e2f, []int{0} +} +func (m *PoolDelegation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PoolDelegation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PoolDelegation.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 *PoolDelegation) XXX_Merge(src proto.Message) { + xxx_messageInfo_PoolDelegation.Merge(m, src) +} +func (m *PoolDelegation) XXX_Size() int { + return m.Size() +} +func (m *PoolDelegation) XXX_DiscardUnknown() { + xxx_messageInfo_PoolDelegation.DiscardUnknown(m) +} + +var xxx_messageInfo_PoolDelegation proto.InternalMessageInfo + +func init() { + proto.RegisterType((*PoolDelegation)(nil), "milkyway.restaking.v1.PoolDelegation") +} + +func init() { + proto.RegisterFile("milkyway/restaking/v1/models.proto", fileDescriptor_86f4cd48423b1e2f) +} + +var fileDescriptor_86f4cd48423b1e2f = []byte{ + // 336 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x90, 0xcb, 0x4a, 0xf3, 0x40, + 0x18, 0x86, 0x33, 0xff, 0x0f, 0x51, 0xc7, 0x03, 0x18, 0x2a, 0xc4, 0x0a, 0x49, 0xa9, 0x9b, 0x6e, + 0x9a, 0xa1, 0x74, 0xa7, 0x2b, 0x4b, 0x36, 0x05, 0x05, 0xa9, 0x3b, 0x37, 0x65, 0x9a, 0x0c, 0xd3, + 0xa1, 0x49, 0xbe, 0x92, 0x99, 0x56, 0x73, 0x07, 0x2e, 0xbd, 0x84, 0x5e, 0x44, 0xef, 0xc1, 0x2e, + 0x4b, 0x57, 0xe2, 0xa2, 0x48, 0xb2, 0xf1, 0x32, 0x24, 0x87, 0x16, 0x37, 0xc3, 0xbc, 0x07, 0x9e, + 0x0f, 0x5e, 0xdc, 0x0c, 0x45, 0x30, 0x49, 0x5e, 0x68, 0x42, 0x62, 0x26, 0x15, 0x9d, 0x88, 0x88, + 0x93, 0x79, 0x87, 0x84, 0xe0, 0xb3, 0x40, 0x3a, 0xd3, 0x18, 0x14, 0x18, 0x17, 0xbb, 0x8e, 0xb3, + 0xef, 0x38, 0xf3, 0x4e, 0xfd, 0x9c, 0x86, 0x22, 0x02, 0x52, 0xbc, 0x65, 0xb3, 0x7e, 0xe9, 0x81, + 0x0c, 0x41, 0x0e, 0x0b, 0x45, 0x4a, 0x51, 0x45, 0x35, 0x0e, 0x1c, 0x4a, 0x3f, 0xff, 0x95, 0x6e, + 0xf3, 0x03, 0xe1, 0xb3, 0x47, 0x80, 0xc0, 0x65, 0x01, 0xe3, 0x54, 0x09, 0x88, 0x8c, 0x5b, 0x7c, + 0x32, 0x93, 0x2c, 0x1e, 0x52, 0xdf, 0x8f, 0x99, 0x94, 0x26, 0x6a, 0xa0, 0xd6, 0x51, 0xcf, 0xdc, + 0x2c, 0xdb, 0xb5, 0x0a, 0x78, 0x57, 0x26, 0x4f, 0x2a, 0x16, 0x11, 0x1f, 0x1c, 0xe7, 0xed, 0xca, + 0x32, 0xae, 0xf1, 0xc1, 0x14, 0x20, 0x18, 0x0a, 0xdf, 0xfc, 0xd7, 0x40, 0xad, 0xd3, 0x1e, 0x4e, + 0xb7, 0xb6, 0x9e, 0x5f, 0xe8, 0xbb, 0x03, 0x3d, 0x8f, 0xfa, 0xbe, 0xd1, 0xc7, 0xba, 0x1c, 0xd3, + 0x98, 0x49, 0xf3, 0x7f, 0xc1, 0xee, 0xac, 0xb6, 0xb6, 0xf6, 0xb5, 0xb5, 0xaf, 0x4a, 0xbe, 0xf4, + 0x27, 0x8e, 0x00, 0x12, 0x52, 0x35, 0x76, 0xee, 0x19, 0xa7, 0x5e, 0xe2, 0x32, 0x6f, 0xb3, 0x6c, + 0xe3, 0xea, 0xbc, 0xcb, 0xbc, 0x41, 0x05, 0xb8, 0x39, 0x7c, 0x5b, 0xd8, 0xda, 0xcf, 0xc2, 0xd6, + 0x7a, 0x0f, 0xab, 0xd4, 0x42, 0xeb, 0xd4, 0x42, 0xdf, 0xa9, 0x85, 0xde, 0x33, 0x4b, 0x5b, 0x67, + 0x96, 0xf6, 0x99, 0x59, 0xda, 0x73, 0x97, 0x0b, 0x35, 0x9e, 0x8d, 0x1c, 0x0f, 0x42, 0xb2, 0x5b, + 0xb2, 0x1d, 0xd0, 0x91, 0xdc, 0x2b, 0xf2, 0xfa, 0x67, 0x7d, 0x95, 0x4c, 0x99, 0x1c, 0xe9, 0xc5, + 0x3e, 0xdd, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2a, 0x1a, 0x78, 0x81, 0xa0, 0x01, 0x00, 0x00, +} + +func (m *PoolDelegation) 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 *PoolDelegation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PoolDelegation) 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 = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.PoolID != 0 { + i = encodeVarintModels(dAtA, i, uint64(m.PoolID)) + i-- + dAtA[i] = 0x10 + } + if len(m.UserAddress) > 0 { + i -= len(m.UserAddress) + copy(dAtA[i:], m.UserAddress) + i = encodeVarintModels(dAtA, i, uint64(len(m.UserAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintModels(dAtA []byte, offset int, v uint64) int { + offset -= sovModels(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PoolDelegation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UserAddress) + if l > 0 { + n += 1 + l + sovModels(uint64(l)) + } + if m.PoolID != 0 { + n += 1 + sovModels(uint64(m.PoolID)) + } + l = m.Shares.Size() + n += 1 + l + sovModels(uint64(l)) + return n +} + +func sovModels(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozModels(x uint64) (n int) { + return sovModels(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PoolDelegation) 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 ErrIntOverflowModels + } + 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: PoolDelegation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PoolDelegation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + 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 ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UserAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolID", wireType) + } + m.PoolID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolID |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + 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 ErrIntOverflowModels + } + 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 ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + 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 := skipModels(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthModels + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipModels(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowModels + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowModels + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowModels + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthModels + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupModels + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthModels + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthModels = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowModels = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupModels = fmt.Errorf("proto: unexpected end of group") +) From fdf704e54fca5f76942649e687106e6d8069ccaa Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 18 Jun 2024 10:18:28 -0500 Subject: [PATCH 09/37] feat: add delegations-by-pool-id key --- x/restaking/keeper/pool_restaking.go | 37 +++++++------------- x/restaking/types/keys.go | 52 +++++++++++++++++----------- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/x/restaking/keeper/pool_restaking.go b/x/restaking/keeper/pool_restaking.go index c248f781d..01d142950 100644 --- a/x/restaking/keeper/pool_restaking.go +++ b/x/restaking/keeper/pool_restaking.go @@ -9,36 +9,29 @@ import ( ) // SavePoolDelegation stores the given pool delegation in the store -func (k *Keeper) SavePoolDelegation(ctx sdk.Context, delegation types.PoolDelegation) error { +func (k *Keeper) SavePoolDelegation(ctx sdk.Context, delegation types.PoolDelegation) { store := ctx.KVStore(k.storeKey) - delegationBz, err := k.cdc.Marshal(&delegation) - if err != nil { - return err - } + // Marshal and store the delegation + delegationBz := types.MustMarshalPoolDelegation(k.cdc, delegation) + store.Set(types.UserPoolDelegationStoreKey(delegation.UserAddress, delegation.PoolID), delegationBz) - store.Set(types.UserPoolDelegationStoreKey(delegation.PoolID, delegation.UserAddress), delegationBz) - return nil + // Store the delegation in the delegations by pool ID store + store.Set(types.DelegationsByPoolIDStoreKey(delegation.PoolID, delegation.UserAddress), []byte{}) } // GetPoolDelegation retrieves the delegation for the given user and pool // If the delegation does not exist, false is returned instead -func (k *Keeper) GetPoolDelegation(ctx sdk.Context, poolID uint32, userAddress string) (types.PoolDelegation, bool, error) { +func (k *Keeper) GetPoolDelegation(ctx sdk.Context, poolID uint32, userAddress string) (types.PoolDelegation, bool) { // Get the delegation amount from the store store := ctx.KVStore(k.storeKey) - delegationAmountBz := store.Get(types.UserPoolDelegationStoreKey(poolID, userAddress)) + delegationAmountBz := store.Get(types.UserPoolDelegationStoreKey(userAddress, poolID)) if delegationAmountBz == nil { - return types.PoolDelegation{}, false, nil + return types.PoolDelegation{}, false } // Parse the delegation amount - var delegation types.PoolDelegation - err := k.cdc.Unmarshal(delegationAmountBz, &delegation) - if err != nil { - return types.PoolDelegation{}, false, err - } - - return delegation, true, nil + return types.MustUnmarshalPoolDelegation(k.cdc, delegationAmountBz), true } // AddPoolTokensAndShares adds the given amount of tokens to the pool and returns the added shares @@ -72,10 +65,7 @@ func (k *Keeper) DelegateToPool(ctx sdk.Context, amount sdk.Coin, delegator stri } // Get or create the delegation object and call the appropriate hook if present - delegation, found, err := k.GetPoolDelegation(ctx, pool.ID, delegator) - if err != nil { - return sdkmath.LegacyZeroDec(), err - } + delegation, found := k.GetPoolDelegation(ctx, pool.ID, delegator) if found { // Delegation was found @@ -120,10 +110,7 @@ func (k *Keeper) DelegateToPool(ctx sdk.Context, amount sdk.Coin, delegator stri // Update delegation delegation.Shares = delegation.Shares.Add(newShares) - err = k.SavePoolDelegation(ctx, delegation) - if err != nil { - return newShares, err - } + k.SavePoolDelegation(ctx, delegation) // Call the after-modification hook err = k.AfterPoolDelegationModified(ctx, pool.ID, delegator) diff --git a/x/restaking/types/keys.go b/x/restaking/types/keys.go index 88daf36db..4e44fb463 100644 --- a/x/restaking/types/keys.go +++ b/x/restaking/types/keys.go @@ -1,9 +1,8 @@ package types import ( - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" + "bytes" + "fmt" poolstypes "github.com/milkyway-labs/milkyway/x/pools/types" ) @@ -18,6 +17,7 @@ var ( PoolDelegationPrefix = []byte{0xa1} UnbondingPoolDelegationPrefix = []byte{0xa2} + PoolDelegationsByPoolIDPrefix = []byte{0x71} ServiceDelegationPrefix = []byte{0xb1} UnbondingServiceDelegationPrefix = []byte{0xb2} @@ -26,30 +26,42 @@ var ( UnbondingOperatorDelegationPrefix = []byte{0xc2} ) -// PoolDelegationsStorePrefix returns the prefix used to store all the delegations to a given pool -func PoolDelegationsStorePrefix(poolID uint32) []byte { - return append(PoolDelegationPrefix, poolstypes.GetPoolIDBytes(poolID)...) +// UserPoolDelegationsStorePrefix returns the prefix used to store all the delegations to a given pool +func UserPoolDelegationsStorePrefix(userAddress string) []byte { + return append(PoolDelegationPrefix, []byte(userAddress)...) } // UserPoolDelegationStoreKey returns the key used to store the delegation of a user to a given pool -func UserPoolDelegationStoreKey(poolID uint32, delegator string) []byte { - return append(PoolDelegationsStorePrefix(poolID), []byte(delegator)...) +func UserPoolDelegationStoreKey(delegator string, poolID uint32) []byte { + return append(UserPoolDelegationsStorePrefix(delegator), poolstypes.GetPoolIDBytes(poolID)...) } -// UnbondingDelegationsByTimeStorePrefix returns the prefix used to store all the unbonding delegations -// that expire at the given time -func UnbondingDelegationsByTimeStorePrefix(endTime time.Time) []byte { - return append(UnbondingPoolDelegationPrefix, sdk.FormatTimeBytes(endTime)...) +// DelegationsByPoolIDStorePrefix returns the prefix used to store the delegations to a given pool +func DelegationsByPoolIDStorePrefix(poolID uint32) []byte { + return append(PoolDelegationsByPoolIDPrefix, poolstypes.GetPoolIDBytes(poolID)...) } -// UnbondingPoolDelegationsStorePrefix returns the prefix used to store all the unbonding delegations -// to a given pool that expire at the given time -func UnbondingPoolDelegationsStorePrefix(poolID uint32, endTime time.Time) []byte { - return append(UnbondingDelegationsByTimeStorePrefix(endTime), poolstypes.GetPoolIDBytes(poolID)...) +// DelegationsByPoolIDStoreKey returns the key used to store the delegations to a given pool +func DelegationsByPoolIDStoreKey(poolID uint32, delegatorAddress string) []byte { + return append(DelegationsByPoolIDStorePrefix(poolID), []byte(delegatorAddress)...) } -// UserUnbondingPoolDelegationStoreKey returns the key used to store the unbonding delegation of a user -// to a given pool that expires at the given time -func UserUnbondingPoolDelegationStoreKey(poolID uint32, delegator string, endTime time.Time) []byte { - return append(UnbondingPoolDelegationsStorePrefix(poolID, endTime), []byte(delegator)...) +// ParseDelegationsByPoolIDKey parses the pool ID and delegator address from the given key +func ParseDelegationsByPoolIDKey(bz []byte) (poolID uint32, delegatorAddress string, err error) { + prefixLength := len(PoolDelegationsByPoolIDPrefix) + if prefix := bz[:prefixLength]; !bytes.Equal(prefix, PoolDelegationsByPoolIDPrefix) { + return 0, "", fmt.Errorf("invalid prefix; expected: %X, got: %x", PoolDelegationsByPoolIDPrefix, prefix) + } + + // Remove the prefix + bz = bz[prefixLength:] + + // Read the pool ID + poolID = poolstypes.GetPoolIDFromBytes(bz[:4]) + bz = bz[4:] + + // Read the delegator address + delegatorAddress = string(bz) + + return poolID, delegatorAddress, nil } From e75a7aaa46820f84333db457aced1f3339f8d21f Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 18 Jun 2024 10:18:43 -0500 Subject: [PATCH 10/37] feat: add alias functions and tests --- x/restaking/keeper/alias_functions.go | 76 ++++++ x/restaking/keeper/alias_functions_test.go | 282 +++++++++++++++++++++ x/restaking/keeper/common_test.go | 106 ++++++++ x/restaking/types/models.go | 32 +++ 4 files changed, 496 insertions(+) create mode 100644 x/restaking/keeper/alias_functions.go create mode 100644 x/restaking/keeper/alias_functions_test.go create mode 100644 x/restaking/keeper/common_test.go diff --git a/x/restaking/keeper/alias_functions.go b/x/restaking/keeper/alias_functions.go new file mode 100644 index 000000000..0e291f228 --- /dev/null +++ b/x/restaking/keeper/alias_functions.go @@ -0,0 +1,76 @@ +package keeper + +import ( + storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +// IterateAllPoolDelegations iterates over all the pool delegations and performs a callback function +func (k *Keeper) IterateAllPoolDelegations(ctx sdk.Context, cb func(delegation types.PoolDelegation) (stop bool)) { + store := ctx.KVStore(k.storeKey) + iterator := store.Iterator(types.PoolDelegationPrefix, storetypes.PrefixEndBytes(types.PoolDelegationPrefix)) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + delegation := types.MustUnmarshalPoolDelegation(k.cdc, iterator.Value()) + if cb(delegation) { + break + } + } +} + +// GetAllPoolDelegations returns all the pool delegations +func (k *Keeper) GetAllPoolDelegations(ctx sdk.Context) []types.PoolDelegation { + var delegations []types.PoolDelegation + k.IterateAllPoolDelegations(ctx, func(delegation types.PoolDelegation) bool { + delegations = append(delegations, delegation) + return false + }) + return delegations +} + +// GetAllDelegatorPoolDelegations returns all the pool delegations of a given delegator +func (k *Keeper) GetAllDelegatorPoolDelegations(ctx sdk.Context, delegator string) []types.PoolDelegation { + store := ctx.KVStore(k.storeKey) + delegatorPrefixKey := types.UserPoolDelegationsStorePrefix(delegator) + + iterator := store.Iterator(delegatorPrefixKey, storetypes.PrefixEndBytes(delegatorPrefixKey)) // Smallest to largest + defer iterator.Close() + + var delegations []types.PoolDelegation + for i := 0; iterator.Valid(); iterator.Next() { + delegation := types.MustUnmarshalPoolDelegation(k.cdc, iterator.Value()) + delegations = append(delegations, delegation) + i++ + } + + return delegations +} + +// GetPoolDelegations returns all the delegations to a given pool +func (k *Keeper) GetPoolDelegations(ctx sdk.Context, poolID uint32) ([]types.PoolDelegation, error) { + store := ctx.KVStore(k.storeKey) + prefix := types.DelegationsByPoolIDStorePrefix(poolID) + iterator := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + defer iterator.Close() + + var delegations []types.PoolDelegation + for ; iterator.Valid(); iterator.Next() { + _, delegatorAddress, err := types.ParseDelegationsByPoolIDKey(iterator.Key()) + if err != nil { + return nil, err + } + + bz := store.Get(types.UserPoolDelegationStoreKey(delegatorAddress, poolID)) + delegation, err := types.UnmarshalPoolDelegation(k.cdc, bz) + if err != nil { + return nil, err + } + + delegations = append(delegations, delegation) + } + + return delegations, nil +} diff --git a/x/restaking/keeper/alias_functions_test.go b/x/restaking/keeper/alias_functions_test.go new file mode 100644 index 000000000..294999f04 --- /dev/null +++ b/x/restaking/keeper/alias_functions_test.go @@ -0,0 +1,282 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +func (suite *KeeperTestSuite) TestKeeper_GetAllPoolDelegations() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + shouldErr bool + expDelegations []types.PoolDelegation + check func(ctx sdk.Context) + }{ + { + name: "delegations are returned properly", + store: func(ctx sdk.Context) { + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + )) + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 2, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(50), + )) + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + )) + }, + expDelegations: []types.PoolDelegation{ + types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + ), + types.NewPoolDelegation( + 2, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(50), + ), + types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + ), + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + delegations := suite.k.GetAllPoolDelegations(ctx) + suite.Require().Equal(tc.expDelegations, delegations) + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +func (suite *KeeperTestSuite) TestKeeper_GetAllDelegatorPoolDelegations() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + delegator string + expDelegations []types.PoolDelegation + check func(ctx sdk.Context) + }{ + { + name: "user without delegations returns empty list", + delegator: "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + expDelegations: nil, + }, + { + name: "user with single delegation returns it properly", + store: func(ctx sdk.Context) { + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + )) + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 2, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(50), + )) + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + )) + }, + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + expDelegations: []types.PoolDelegation{ + types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + ), + }, + }, + { + name: "user with multiple delegations returns them properly", + store: func(ctx sdk.Context) { + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + )) + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 2, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(50), + )) + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + )) + }, + delegator: "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + expDelegations: []types.PoolDelegation{ + types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + ), + types.NewPoolDelegation( + 2, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(50), + ), + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + delegations := suite.k.GetAllDelegatorPoolDelegations(ctx, tc.delegator) + suite.Require().Equal(tc.expDelegations, delegations) + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +func (suite *KeeperTestSuite) TestKeeper_GetPoolDelegations() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + poolID uint32 + shouldErr bool + expDelegations []types.PoolDelegation + check func(ctx sdk.Context) + }{ + { + name: "pool without delegations returns empty list", + poolID: 1, + shouldErr: false, + expDelegations: nil, + }, + { + name: "pool with single delegation returns it properly", + store: func(ctx sdk.Context) { + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + )) + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 2, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(50), + )) + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + )) + }, + poolID: 2, + shouldErr: false, + expDelegations: []types.PoolDelegation{ + types.NewPoolDelegation( + 2, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(50), + ), + }, + }, + { + name: "pool with multiple delegations returns them properly", + store: func(ctx sdk.Context) { + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + )) + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 2, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(50), + )) + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + )) + }, + poolID: 1, + shouldErr: false, + expDelegations: []types.PoolDelegation{ + types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + ), + types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + ), + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + delegations, err := suite.k.GetPoolDelegations(ctx, tc.poolID) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + suite.Require().Equal(tc.expDelegations, delegations) + } + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} diff --git a/x/restaking/keeper/common_test.go b/x/restaking/keeper/common_test.go new file mode 100644 index 000000000..518d3832f --- /dev/null +++ b/x/restaking/keeper/common_test.go @@ -0,0 +1,106 @@ +package keeper_test + +import ( + "testing" + + "cosmossdk.io/log" + "cosmossdk.io/store" + "cosmossdk.io/store/metrics" + "github.com/cosmos/cosmos-sdk/runtime" + authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/milkyway-labs/milkyway/app" + bankkeeper "github.com/milkyway-labs/milkyway/x/bank/keeper" + poolskeeper "github.com/milkyway-labs/milkyway/x/pools/keeper" + "github.com/milkyway-labs/milkyway/x/restaking/keeper" + "github.com/milkyway-labs/milkyway/x/restaking/types" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + + storetypes "cosmossdk.io/store/types" + db "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" +) + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +type KeeperTestSuite struct { + suite.Suite + + cdc codec.Codec + legacyAminoCdc *codec.LegacyAmino + ctx sdk.Context + + storeKey storetypes.StoreKey + + ak authkeeper.AccountKeeper + bk bankkeeper.Keeper + pk *poolskeeper.Keeper + k *keeper.Keeper +} + +func (suite *KeeperTestSuite) SetupTest() { + // Define store keys + keys := storetypes.NewKVStoreKeys(types.StoreKey, authtypes.StoreKey, banktypes.StoreKey) + suite.storeKey = keys[types.StoreKey] + + // Create logger + logger := log.NewNopLogger() + + // Create an in-memory db + memDB := db.NewMemDB() + ms := store.NewCommitMultiStore(memDB, logger, metrics.NewNoOpMetrics()) + for _, key := range keys { + ms.MountStoreWithDB(key, storetypes.StoreTypeIAVL, memDB) + } + + if err := ms.LoadLatestVersion(); err != nil { + panic(err) + } + + suite.ctx = sdk.NewContext(ms, tmproto.Header{ChainID: "test-chain"}, false, log.NewNopLogger()) + suite.cdc, suite.legacyAminoCdc = app.MakeCodecs() + + // Authority address + authorityAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() + + // Build keepers + suite.ak = authkeeper.NewAccountKeeper( + suite.cdc, + runtime.NewKVStoreService(keys[authtypes.StoreKey]), + authtypes.ProtoBaseAccount, + app.GetMaccPerms(), + authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()), + sdk.GetConfig().GetBech32AccountAddrPrefix(), + authorityAddr, + ) + suite.bk = bankkeeper.NewKeeper( + suite.cdc, + runtime.NewKVStoreService(keys[banktypes.StoreKey]), + suite.ak, + nil, + authorityAddr, + logger, + ) + suite.pk = poolskeeper.NewKeeper( + suite.cdc, + suite.storeKey, + suite.ak, + ) + suite.k = keeper.NewKeeper( + suite.cdc, + suite.storeKey, + suite.ak, + suite.bk, + suite.pk, + authorityAddr, + ) +} diff --git a/x/restaking/types/models.go b/x/restaking/types/models.go index f549ea5ac..54b632ff4 100644 --- a/x/restaking/types/models.go +++ b/x/restaking/types/models.go @@ -2,8 +2,10 @@ package types import ( sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/codec" ) +// NewPoolDelegation creates a new PoolDelegation instance func NewPoolDelegation(poolID uint32, userAddress string, shares sdkmath.LegacyDec) PoolDelegation { return PoolDelegation{ PoolID: poolID, @@ -11,3 +13,33 @@ func NewPoolDelegation(poolID uint32, userAddress string, shares sdkmath.LegacyD Shares: shares, } } + +// -------------------------------------------------------------------------------------------------------------------- + +// MustMarshalPoolDelegation marshals the given pool delegation using the provided codec +func MustMarshalPoolDelegation(cdc codec.BinaryCodec, delegation PoolDelegation) []byte { + bz, err := cdc.Marshal(&delegation) + if err != nil { + panic(err) + } + return bz +} + +// UnmarshalPoolDelegation unmarshals a pool delegation from the given bytes using the provided codec +func UnmarshalPoolDelegation(cdc codec.BinaryCodec, bz []byte) (PoolDelegation, error) { + var delegation PoolDelegation + err := cdc.Unmarshal(bz, &delegation) + if err != nil { + return PoolDelegation{}, err + } + return delegation, nil +} + +// MustUnmarshalPoolDelegation unmarshals a pool delegation from the given bytes using the provided codec +func MustUnmarshalPoolDelegation(cdc codec.BinaryCodec, bz []byte) PoolDelegation { + delegation, err := UnmarshalPoolDelegation(cdc, bz) + if err != nil { + panic(err) + } + return delegation +} From c41706021f293416cb8981b368e1c492abf71100 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 18 Jun 2024 11:22:00 -0500 Subject: [PATCH 11/37] feat(tests): add pool restaking tests --- x/restaking/keeper/common_test.go | 46 ++- x/restaking/keeper/pool_restaking.go | 2 +- x/restaking/keeper/pool_restaking_test.go | 475 ++++++++++++++++++++++ x/restaking/types/keys.go | 6 +- 4 files changed, 524 insertions(+), 5 deletions(-) create mode 100644 x/restaking/keeper/pool_restaking_test.go diff --git a/x/restaking/keeper/common_test.go b/x/restaking/keeper/common_test.go index 518d3832f..b0cbcd9e9 100644 --- a/x/restaking/keeper/common_test.go +++ b/x/restaking/keeper/common_test.go @@ -102,5 +102,49 @@ func (suite *KeeperTestSuite) SetupTest() { suite.bk, suite.pk, authorityAddr, - ) + ).SetHooks(newMockHooks()) +} + +// -------------------------------------------------------------------------------------------------------------------- + +// fundAccount adds the given amount of coins to the account with the given address +func (suite *KeeperTestSuite) fundAccount(ctx sdk.Context, address string, amount sdk.Coins) { + // Mint the coins + moduleAcc := suite.ak.GetModuleAccount(ctx, authtypes.Minter) + + err := suite.bk.MintCoins(ctx, moduleAcc.GetName(), amount) + suite.Require().NoError(err) + + // Get the amount to the user + userAddress, err := sdk.AccAddressFromBech32(address) + suite.Require().NoError(err) + err = suite.bk.SendCoinsFromModuleToAccount(ctx, moduleAcc.GetName(), userAddress, amount) + suite.Require().NoError(err) +} + +// -------------------------------------------------------------------------------------------------------------------- + +var _ types.RestakingHooks = &mockHooks{} + +type mockHooks struct { + CalledMap map[string]bool +} + +func newMockHooks() *mockHooks { + return &mockHooks{CalledMap: make(map[string]bool)} +} + +func (m mockHooks) BeforePoolDelegationCreated(ctx sdk.Context, poolID uint32, delegator string) error { + m.CalledMap["BeforePoolDelegationCreated"] = true + return nil +} + +func (m mockHooks) BeforePoolDelegationSharesModified(ctx sdk.Context, poolID uint32, delegator string) error { + m.CalledMap["BeforePoolDelegationSharesModified"] = true + return nil +} + +func (m mockHooks) AfterPoolDelegationModified(ctx sdk.Context, poolID uint32, delegator string) error { + m.CalledMap["AfterPoolDelegationModified"] = true + return nil } diff --git a/x/restaking/keeper/pool_restaking.go b/x/restaking/keeper/pool_restaking.go index 01d142950..558913be1 100644 --- a/x/restaking/keeper/pool_restaking.go +++ b/x/restaking/keeper/pool_restaking.go @@ -17,7 +17,7 @@ func (k *Keeper) SavePoolDelegation(ctx sdk.Context, delegation types.PoolDelega store.Set(types.UserPoolDelegationStoreKey(delegation.UserAddress, delegation.PoolID), delegationBz) // Store the delegation in the delegations by pool ID store - store.Set(types.DelegationsByPoolIDStoreKey(delegation.PoolID, delegation.UserAddress), []byte{}) + store.Set(types.DelegationByPoolIDStoreKey(delegation.PoolID, delegation.UserAddress), []byte{}) } // GetPoolDelegation retrieves the delegation for the given user and pool diff --git a/x/restaking/keeper/pool_restaking_test.go b/x/restaking/keeper/pool_restaking_test.go new file mode 100644 index 000000000..622ba4b75 --- /dev/null +++ b/x/restaking/keeper/pool_restaking_test.go @@ -0,0 +1,475 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + poolstypes "github.com/milkyway-labs/milkyway/x/pools/types" + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +func (suite *KeeperTestSuite) TestKeeper_SavePoolDelegation() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + delegation types.PoolDelegation + check func(ctx sdk.Context) + }{ + { + name: "pool delegation is stored properly", + delegation: types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + ), + check: func(ctx sdk.Context) { + store := ctx.KVStore(suite.storeKey) + + // Make sure the user-pool delegation key exists and contains the delegation + delegationBz := store.Get(types.UserPoolDelegationStoreKey("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", 1)) + suite.Require().NotNil(delegationBz) + + delegation, err := types.UnmarshalPoolDelegation(suite.cdc, delegationBz) + suite.Require().NoError(err) + + suite.Require().Equal(types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + ), delegation) + + // Make sure the pool-user delegation key exists + hasDelegationsByPoolKey := store.Has(types.DelegationByPoolIDStoreKey(1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4")) + suite.Require().True(hasDelegationsByPoolKey) + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + suite.k.SavePoolDelegation(ctx, tc.delegation) + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +func (suite *KeeperTestSuite) TestKeeper_GetPoolDelegation() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + poolID uint32 + userAddress string + expFound bool + expDelegation types.PoolDelegation + check func(ctx sdk.Context) + }{ + { + name: "not found delegation returns false", + poolID: 1, + userAddress: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + expFound: false, + }, + { + name: "found delegation is returned properly", + store: func(ctx sdk.Context) { + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + )) + }, + poolID: 1, + userAddress: "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + expFound: true, + expDelegation: types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + ), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + delegation, found := suite.k.GetPoolDelegation(ctx, tc.poolID, tc.userAddress) + if !tc.expFound { + suite.Require().False(found) + } else { + suite.Require().True(found) + suite.Require().Equal(tc.expDelegation, delegation) + } + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +func (suite *KeeperTestSuite) TestKeeper_AddPoolTokensAndShares() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + pool poolstypes.Pool + tokensToAdd sdkmath.Int + shouldErr bool + expPool poolstypes.Pool + expAddedShares sdkmath.LegacyDec + check func(ctx sdk.Context) + }{ + { + name: "adding tokens to an empty pool works properly", + pool: poolstypes.NewPool(1, "umilk"), + tokensToAdd: sdkmath.NewInt(100), + shouldErr: false, + expPool: poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.NewInt(100), + DelegatorShares: sdkmath.LegacyNewDec(100), + }, + expAddedShares: sdkmath.LegacyNewDec(100), + }, + { + name: "adding tokens to a non-empty pool works properly", + pool: poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.NewInt(50), + DelegatorShares: sdkmath.LegacyNewDec(100), + }, + tokensToAdd: sdkmath.NewInt(20), + shouldErr: false, + expPool: poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.NewInt(70), + DelegatorShares: sdkmath.LegacyNewDec(140), + }, + expAddedShares: sdkmath.LegacyNewDec(40), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + pool, addedShares, err := suite.k.AddPoolTokensAndShares(ctx, tc.pool, tc.tokensToAdd) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + suite.Require().Equal(tc.expPool, pool) + suite.Require().Equal(tc.expAddedShares, addedShares) + } + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +func (suite *KeeperTestSuite) TestKeeper_DelegateToPool() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + amount sdk.Coin + delegator string + shouldErr bool + expShares sdkmath.LegacyDec + check func(ctx sdk.Context) + }{ + { + name: "invalid exchange rate pool returns error", + store: func(ctx sdk.Context) { + err := suite.pk.SavePool(ctx, poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.ZeroInt(), + DelegatorShares: sdkmath.LegacyNewDec(100), + }) + suite.Require().NoError(err) + }, + amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: true, + }, + { + name: "invalid delegator address returns error", + store: func(ctx sdk.Context) { + err := suite.pk.SavePool(ctx, poolstypes.NewPool(1, "umilk")) + suite.Require().NoError(err) + }, + amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), + delegator: "invalid", + shouldErr: true, + }, + { + name: "insufficient funds return error", + store: func(ctx sdk.Context) { + // Create the pool + err := suite.pk.SavePool(ctx, poolstypes.NewPool(1, "umilk")) + suite.Require().NoError(err) + + // Set the next pool id + suite.pk.SetNextPoolID(ctx, 2) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(50))), + ) + }, + amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: true, + }, + { + name: "delegating to a non-existing pool works properly", + store: func(ctx sdk.Context) { + // Set the next pool id + suite.pk.SetNextPoolID(ctx, 1) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: false, + expShares: sdkmath.LegacyNewDec(100), + check: func(ctx sdk.Context) { + // Make sure the pool now exists + pool, found := suite.pk.GetPool(ctx, 1) + suite.Require().True(found) + suite.Require().Equal(poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.NewInt(100), + DelegatorShares: sdkmath.LegacyNewDec(100), + }, pool) + + // Make sure the delegation exists + delegation, found := suite.k.GetPoolDelegation(ctx, 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4") + suite.Require().True(found) + suite.Require().Equal(types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + ), delegation) + + // Make sure the user balance has been reduced properly + userBalance := suite.bk.GetBalance(ctx, sdk.AccAddress("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(0)), userBalance) + + // Make sure the pool account balance has increased properly + poolBalance := suite.bk.GetBalance(ctx, poolstypes.GetPoolAddress(1), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(100)), poolBalance) + }, + }, + { + name: "delegating to an existing pool works properly", + store: func(ctx sdk.Context) { + // Create the pool + err := suite.pk.SavePool(ctx, poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.NewInt(20), + DelegatorShares: sdkmath.LegacyNewDec(100), + }) + suite.Require().NoError(err) + + // Set the correct pool tokens amount + suite.fundAccount( + ctx, + poolstypes.GetPoolAddress(1).String(), + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), + ) + + // Set the next pool id + suite.pk.SetNextPoolID(ctx, 2) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: false, + expShares: sdkmath.LegacyNewDec(500), + check: func(ctx sdk.Context) { + // Make sure the pool now exists + pool, found := suite.pk.GetPool(ctx, 1) + suite.Require().True(found) + suite.Require().Equal(poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.NewInt(120), + DelegatorShares: sdkmath.LegacyNewDec(600), + }, pool) + + // Make sure the delegation exists + delegation, found := suite.k.GetPoolDelegation(ctx, 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4") + suite.Require().True(found) + suite.Require().Equal(types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(500), + ), delegation) + + // Make sure the user balance has been reduced properly + userBalance := suite.bk.GetBalance(ctx, sdk.AccAddress("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(0)), userBalance) + + // Make sure the pool account balance has increased properly + poolBalance := suite.bk.GetBalance(ctx, poolstypes.GetPoolAddress(1), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(120)), poolBalance) + }, + }, + { + name: "delegating more tokens works properly", + store: func(ctx sdk.Context) { + // Create the pool + err := suite.pk.SavePool(ctx, poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.NewInt(80), + DelegatorShares: sdkmath.LegacyNewDec(125), + }) + suite.Require().NoError(err) + + // Set the correct pool tokens amount + suite.fundAccount( + ctx, + poolstypes.GetPoolAddress(1).String(), + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(80))), + ) + + // Set the next pool id + suite.pk.SetNextPoolID(ctx, 2) + + // Save the existing delegation + suite.k.SavePoolDelegation(ctx, types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDec(100), + )) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: false, + expShares: sdkmath.LegacyNewDecWithPrec(15625, 2), + check: func(ctx sdk.Context) { + // Make sure the pool now exists + pool, found := suite.pk.GetPool(ctx, 1) + suite.Require().True(found) + suite.Require().Equal(poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.NewInt(180), + DelegatorShares: sdkmath.LegacyNewDecWithPrec(28125, 2), + }, pool) + + // Make sure the delegation has been updated properly + delegation, found := suite.k.GetPoolDelegation(ctx, 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4") + suite.Require().True(found) + suite.Require().Equal(types.NewPoolDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdkmath.LegacyNewDecWithPrec(25625, 2), // 100 (existing) + 156.25 (new) + ), delegation) + + // Make sure the user balance has been reduced properly + userBalance := suite.bk.GetBalance(ctx, sdk.AccAddress("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(0)), userBalance) + + // Make sure the pool account balance has increased properly + poolBalance := suite.bk.GetBalance(ctx, poolstypes.GetPoolAddress(1), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(180)), poolBalance) + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + shares, err := suite.k.DelegateToPool(ctx, tc.amount, tc.delegator) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + suite.Require().Equal(tc.expShares, shares) + } + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} diff --git a/x/restaking/types/keys.go b/x/restaking/types/keys.go index 4e44fb463..b0527c95b 100644 --- a/x/restaking/types/keys.go +++ b/x/restaking/types/keys.go @@ -31,7 +31,7 @@ func UserPoolDelegationsStorePrefix(userAddress string) []byte { return append(PoolDelegationPrefix, []byte(userAddress)...) } -// UserPoolDelegationStoreKey returns the key used to store the delegation of a user to a given pool +// UserPoolDelegationStoreKey returns the key used to store the user -> pool delegation association func UserPoolDelegationStoreKey(delegator string, poolID uint32) []byte { return append(UserPoolDelegationsStorePrefix(delegator), poolstypes.GetPoolIDBytes(poolID)...) } @@ -41,8 +41,8 @@ func DelegationsByPoolIDStorePrefix(poolID uint32) []byte { return append(PoolDelegationsByPoolIDPrefix, poolstypes.GetPoolIDBytes(poolID)...) } -// DelegationsByPoolIDStoreKey returns the key used to store the delegations to a given pool -func DelegationsByPoolIDStoreKey(poolID uint32, delegatorAddress string) []byte { +// DelegationByPoolIDStoreKey returns the key used to store the pool -> user delegation association +func DelegationByPoolIDStoreKey(poolID uint32, delegatorAddress string) []byte { return append(DelegationsByPoolIDStorePrefix(poolID), []byte(delegatorAddress)...) } From 60b17a6569babfc8dfccfb5e2aac83b199e2562d Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 18 Jun 2024 11:44:18 -0500 Subject: [PATCH 12/37] refactor: use delegations inside genesis --- proto/milkyway/pools/v1/models.proto | 8 +- proto/milkyway/restaking/v1/genesis.proto | 51 +- proto/milkyway/restaking/v1/models.proto | 45 +- x/restaking/types/errors.go | 4 +- x/restaking/types/genesis.go | 101 +-- x/restaking/types/genesis.pb.go | 865 +--------------------- x/restaking/types/genesis_test.go | 103 ++- x/restaking/types/models.go | 74 +- x/restaking/types/models.pb.go | 537 +++++++++++++- 9 files changed, 730 insertions(+), 1058 deletions(-) diff --git a/proto/milkyway/pools/v1/models.proto b/proto/milkyway/pools/v1/models.proto index 7244d0f82..6664725ed 100644 --- a/proto/milkyway/pools/v1/models.proto +++ b/proto/milkyway/pools/v1/models.proto @@ -20,15 +20,15 @@ message Pool { // Tokens define the delegated tokens. string tokens = 4 [ - (cosmos_proto.scalar) = "cosmos.Int", + (cosmos_proto.scalar) = "cosmos.Int", (gogoproto.customtype) = "cosmossdk.io/math.Int", - (gogoproto.nullable) = false + (gogoproto.nullable) = false ]; // DelegatorShares defines total shares issued to a pool's delegators. string delegator_shares = 5 [ - (cosmos_proto.scalar) = "cosmos.Dec", + (cosmos_proto.scalar) = "cosmos.Dec", (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", - (gogoproto.nullable) = false + (gogoproto.nullable) = false ]; } diff --git a/proto/milkyway/restaking/v1/genesis.proto b/proto/milkyway/restaking/v1/genesis.proto index e6498e33d..d001dc13e 100644 --- a/proto/milkyway/restaking/v1/genesis.proto +++ b/proto/milkyway/restaking/v1/genesis.proto @@ -3,6 +3,7 @@ package milkyway.restaking.v1; import "gogoproto/gogo.proto"; import "cosmos/base/v1beta1/coin.proto"; +import "milkyway/restaking/v1/models.proto"; import "milkyway/restaking/v1/params.proto"; option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types"; @@ -13,58 +14,14 @@ message GenesisState { Params params = 1 [ (gogoproto.nullable) = false ]; // PoolDelegations represents the delegations to pools. - repeated PoolDelegationEntry pools_delegations = 2 + repeated PoolDelegation pools_delegations = 2 [ (gogoproto.nullable) = false ]; // ServiceDelegations represents the delegations to services. - repeated ServiceDelegationEntry services_delegations = 3 + repeated ServiceDelegation services_delegations = 3 [ (gogoproto.nullable) = false ]; // OperatorDelegations represents the delegations to operators. - repeated OperatorDelegationEntry operators_delegations = 4 + repeated OperatorDelegation operators_delegations = 4 [ (gogoproto.nullable) = false ]; } - -// PoolDelegationEntry contains the data of a single restake delegation to a -// pool. -message PoolDelegationEntry { - // PoolID represents the ID of the pool to which the tokens have been restaked - uint32 pool_id = 1 [ (gogoproto.customname) = "PoolID" ]; - - // UserAddress represents the address of the user who has restaked the tokens - string user_address = 2; - - // Amount represents the amount of tokens that have been restaked - cosmos.base.v1beta1.Coin amount = 3 - [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; -} - -// ServiceDelegationEntry contains the data of a single restake delegation to a -// service. -message ServiceDelegationEntry { - // ServiceID represents the ID of the service to which the tokens have been - // restaked - uint32 service_id = 1 [ (gogoproto.customname) = "ServiceID" ]; - - // UserAddress represents the address of the user who has restaked the tokens - string user_address = 2; - - // Amount represents the amount of tokens that have been restaked - cosmos.base.v1beta1.Coin amount = 3 - [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; -} - -// OperatorDelegationEntry contains the data of a single restake delegation to -// an operator. -message OperatorDelegationEntry { - // OperatorID represents the ID of the operator to which the tokens have been - // restaked - uint32 operator_id = 1 [ (gogoproto.customname) = "OperatorID" ]; - - // UserAddress represents the address of the user who has restaked the tokens - string user_address = 2; - - // Amount represents the amount of tokens that have been restaked - cosmos.base.v1beta1.Coin amount = 3 - [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; -} \ No newline at end of file diff --git a/proto/milkyway/restaking/v1/models.proto b/proto/milkyway/restaking/v1/models.proto index ceb228d17..a2f2ed27b 100644 --- a/proto/milkyway/restaking/v1/models.proto +++ b/proto/milkyway/restaking/v1/models.proto @@ -14,12 +14,53 @@ message PoolDelegation { option (gogoproto.goproto_getters) = false; // UserAddress is the encoded address of the user. - string user_address = 1 - [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + string user_address = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; // PoolID is the id of the pool. uint32 pool_id = 2 [ (gogoproto.customname) = "PoolID" ]; + // Shares define the delegation shares received. + string shares = 3 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; +} + +// OperatorDelegation represents the bond with tokens held by an account with a +// given operator. It is owned by one delegator, and is associated with a +// operator. +message OperatorDelegation { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // UserAddress is the encoded address of the user. + string user_address = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // OperatorID is the id of the operator. + uint32 operator_id = 2 [ (gogoproto.customname) = "OperatorID" ]; + + // Shares define the delegation shares received. + string shares = 3 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; +} + +// ServiceDelegation represents the bond with tokens held by an account with a +// given service. It is owned by one delegator, and is associated with a +// service. +message ServiceDelegation { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // UserAddress is the encoded address of the user. + string user_address = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // ServiceID is the id of the service. + uint32 service_id = 2 [ (gogoproto.customname) = "ServiceID" ]; + // Shares define the delegation shares received. string shares = 3 [ (cosmos_proto.scalar) = "cosmos.Dec", diff --git a/x/restaking/types/errors.go b/x/restaking/types/errors.go index 3fa3268ea..afc438c8e 100644 --- a/x/restaking/types/errors.go +++ b/x/restaking/types/errors.go @@ -6,6 +6,6 @@ import ( var ( ErrInvalidGenesis = errors.Register(ModuleName, 1, "invalid genesis state") - ErrDelegationNotFound = errors.Register(ModuleName, 2, "delegation not found") - ErrDelegatorShareExRateInvalid = errors.Register(ModuleName, 34, "cannot delegate to pool/operator/service with invalid (zero) ex-rate") + ErrInvalidShares = errors.Register(ModuleName, 2, "invalid shares amount") + ErrDelegatorShareExRateInvalid = errors.Register(ModuleName, 3, "cannot delegate to pool/operator/service with invalid (zero) ex-rate") ) diff --git a/x/restaking/types/genesis.go b/x/restaking/types/genesis.go index 70a562108..121b6d7b9 100644 --- a/x/restaking/types/genesis.go +++ b/x/restaking/types/genesis.go @@ -2,15 +2,13 @@ package types import ( "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" ) // NewGenesis creates a new genesis state func NewGenesis( - poolsDelegations []PoolDelegationEntry, - servicesDelegations []ServiceDelegationEntry, - operatorsDelegations []OperatorDelegationEntry, + poolsDelegations []PoolDelegation, + servicesDelegations []ServiceDelegation, + operatorsDelegations []OperatorDelegation, params Params, ) *GenesisState { return &GenesisState{ @@ -32,7 +30,7 @@ func (g *GenesisState) Validate() error { for _, entry := range g.PoolsDelegations { err := entry.Validate() if err != nil { - return fmt.Errorf("invalid pool delegation entry: %w", err) + return fmt.Errorf("invalid pool delegation: %w", err) } } @@ -40,7 +38,7 @@ func (g *GenesisState) Validate() error { for _, entry := range g.ServicesDelegations { err := entry.Validate() if err != nil { - return fmt.Errorf("invalid service delegation entry: %w", err) + return fmt.Errorf("invalid service delegation: %w", err) } } @@ -48,7 +46,7 @@ func (g *GenesisState) Validate() error { for _, entry := range g.OperatorsDelegations { err := entry.Validate() if err != nil { - return fmt.Errorf("invalid operator delegation entry: %w", err) + return fmt.Errorf("invalid operator delegation: %w", err) } } @@ -60,90 +58,3 @@ func (g *GenesisState) Validate() error { return nil } - -// -------------------------------------------------------------------------------------------------------------------- - -// NewPoolDelegationEntry returns a new PoolDelegationEntry -func NewPoolDelegationEntry(poolID uint32, userAddress string, amount sdk.Coin) PoolDelegationEntry { - return PoolDelegationEntry{ - PoolID: poolID, - UserAddress: userAddress, - Amount: amount, - } -} - -// Validate performs basic validation of a pool delegation entry -func (e *PoolDelegationEntry) Validate() error { - if e.PoolID == 0 { - return fmt.Errorf("invalid pool id: %d", e.PoolID) - } - - _, err := sdk.AccAddressFromBech32(e.UserAddress) - if err != nil { - return fmt.Errorf("invalid user address: %s", e.UserAddress) - } - - if !e.Amount.IsValid() || e.Amount.IsZero() { - return fmt.Errorf("invalid amount: %s", e.Amount) - } - - return nil -} - -// -------------------------------------------------------------------------------------------------------------------- - -// NewServiceDelegationEntry returns a new ServiceDelegationEntry -func NewServiceDelegationEntry(serviceID uint32, userAddress string, amount sdk.Coin) ServiceDelegationEntry { - return ServiceDelegationEntry{ - ServiceID: serviceID, - UserAddress: userAddress, - Amount: amount, - } -} - -// Validate performs basic validation of a service delegation entry -func (e *ServiceDelegationEntry) Validate() error { - if e.ServiceID == 0 { - return fmt.Errorf("invalid service id: %d", e.ServiceID) - } - - _, err := sdk.AccAddressFromBech32(e.UserAddress) - if err != nil { - return fmt.Errorf("invalid user address: %s", e.UserAddress) - } - - if !e.Amount.IsValid() || e.Amount.IsZero() { - return fmt.Errorf("invalid amount: %s", e.Amount) - } - - return nil -} - -// -------------------------------------------------------------------------------------------------------------------- - -// NewOperatorDelegationEntry returns a new OperatorDelegationEntry -func NewOperatorDelegationEntry(operatorID uint32, userAddress string, amount sdk.Coin) OperatorDelegationEntry { - return OperatorDelegationEntry{ - OperatorID: operatorID, - UserAddress: userAddress, - Amount: amount, - } -} - -// Validate performs basic validation of an operator delegation entry -func (e *OperatorDelegationEntry) Validate() error { - if e.OperatorID == 0 { - return fmt.Errorf("invalid operator id: %d", e.OperatorID) - } - - _, err := sdk.AccAddressFromBech32(e.UserAddress) - if err != nil { - return fmt.Errorf("invalid user address: %s", e.UserAddress) - } - - if !e.Amount.IsValid() || e.Amount.IsZero() { - return fmt.Errorf("invalid amount: %s", e.Amount) - } - - return nil -} diff --git a/x/restaking/types/genesis.pb.go b/x/restaking/types/genesis.pb.go index 2bef9fa26..05dc74b36 100644 --- a/x/restaking/types/genesis.pb.go +++ b/x/restaking/types/genesis.pb.go @@ -5,7 +5,7 @@ package types import ( fmt "fmt" - types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" @@ -29,11 +29,11 @@ type GenesisState struct { // Params defines the parameters of the module. Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` // PoolDelegations represents the delegations to pools. - PoolsDelegations []PoolDelegationEntry `protobuf:"bytes,2,rep,name=pools_delegations,json=poolsDelegations,proto3" json:"pools_delegations"` + PoolsDelegations []PoolDelegation `protobuf:"bytes,2,rep,name=pools_delegations,json=poolsDelegations,proto3" json:"pools_delegations"` // ServiceDelegations represents the delegations to services. - ServicesDelegations []ServiceDelegationEntry `protobuf:"bytes,3,rep,name=services_delegations,json=servicesDelegations,proto3" json:"services_delegations"` + ServicesDelegations []ServiceDelegation `protobuf:"bytes,3,rep,name=services_delegations,json=servicesDelegations,proto3" json:"services_delegations"` // OperatorDelegations represents the delegations to operators. - OperatorsDelegations []OperatorDelegationEntry `protobuf:"bytes,4,rep,name=operators_delegations,json=operatorsDelegations,proto3" json:"operators_delegations"` + OperatorsDelegations []OperatorDelegation `protobuf:"bytes,4,rep,name=operators_delegations,json=operatorsDelegations,proto3" json:"operators_delegations"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -76,229 +76,29 @@ func (m *GenesisState) GetParams() Params { return Params{} } -func (m *GenesisState) GetPoolsDelegations() []PoolDelegationEntry { +func (m *GenesisState) GetPoolsDelegations() []PoolDelegation { if m != nil { return m.PoolsDelegations } return nil } -func (m *GenesisState) GetServicesDelegations() []ServiceDelegationEntry { +func (m *GenesisState) GetServicesDelegations() []ServiceDelegation { if m != nil { return m.ServicesDelegations } return nil } -func (m *GenesisState) GetOperatorsDelegations() []OperatorDelegationEntry { +func (m *GenesisState) GetOperatorsDelegations() []OperatorDelegation { if m != nil { return m.OperatorsDelegations } return nil } -// PoolDelegationEntry contains the data of a single restake delegation to a -// pool. -type PoolDelegationEntry struct { - // PoolID represents the ID of the pool to which the tokens have been restaked - PoolID uint32 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` - // UserAddress represents the address of the user who has restaked the tokens - UserAddress string `protobuf:"bytes,2,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` - // Amount represents the amount of tokens that have been restaked - Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` -} - -func (m *PoolDelegationEntry) Reset() { *m = PoolDelegationEntry{} } -func (m *PoolDelegationEntry) String() string { return proto.CompactTextString(m) } -func (*PoolDelegationEntry) ProtoMessage() {} -func (*PoolDelegationEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_0378bd63cae7d256, []int{1} -} -func (m *PoolDelegationEntry) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PoolDelegationEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_PoolDelegationEntry.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 *PoolDelegationEntry) XXX_Merge(src proto.Message) { - xxx_messageInfo_PoolDelegationEntry.Merge(m, src) -} -func (m *PoolDelegationEntry) XXX_Size() int { - return m.Size() -} -func (m *PoolDelegationEntry) XXX_DiscardUnknown() { - xxx_messageInfo_PoolDelegationEntry.DiscardUnknown(m) -} - -var xxx_messageInfo_PoolDelegationEntry proto.InternalMessageInfo - -func (m *PoolDelegationEntry) GetPoolID() uint32 { - if m != nil { - return m.PoolID - } - return 0 -} - -func (m *PoolDelegationEntry) GetUserAddress() string { - if m != nil { - return m.UserAddress - } - return "" -} - -func (m *PoolDelegationEntry) GetAmount() types.Coin { - if m != nil { - return m.Amount - } - return types.Coin{} -} - -// ServiceDelegationEntry contains the data of a single restake delegation to a -// service. -type ServiceDelegationEntry struct { - // ServiceID represents the ID of the service to which the tokens have been - // restaked - ServiceID uint32 `protobuf:"varint,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` - // UserAddress represents the address of the user who has restaked the tokens - UserAddress string `protobuf:"bytes,2,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` - // Amount represents the amount of tokens that have been restaked - Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` -} - -func (m *ServiceDelegationEntry) Reset() { *m = ServiceDelegationEntry{} } -func (m *ServiceDelegationEntry) String() string { return proto.CompactTextString(m) } -func (*ServiceDelegationEntry) ProtoMessage() {} -func (*ServiceDelegationEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_0378bd63cae7d256, []int{2} -} -func (m *ServiceDelegationEntry) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ServiceDelegationEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ServiceDelegationEntry.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 *ServiceDelegationEntry) XXX_Merge(src proto.Message) { - xxx_messageInfo_ServiceDelegationEntry.Merge(m, src) -} -func (m *ServiceDelegationEntry) XXX_Size() int { - return m.Size() -} -func (m *ServiceDelegationEntry) XXX_DiscardUnknown() { - xxx_messageInfo_ServiceDelegationEntry.DiscardUnknown(m) -} - -var xxx_messageInfo_ServiceDelegationEntry proto.InternalMessageInfo - -func (m *ServiceDelegationEntry) GetServiceID() uint32 { - if m != nil { - return m.ServiceID - } - return 0 -} - -func (m *ServiceDelegationEntry) GetUserAddress() string { - if m != nil { - return m.UserAddress - } - return "" -} - -func (m *ServiceDelegationEntry) GetAmount() types.Coin { - if m != nil { - return m.Amount - } - return types.Coin{} -} - -// OperatorDelegationEntry contains the data of a single restake delegation to -// an operator. -type OperatorDelegationEntry struct { - // OperatorID represents the ID of the operator to which the tokens have been - // restaked - OperatorID uint32 `protobuf:"varint,1,opt,name=operator_id,json=operatorId,proto3" json:"operator_id,omitempty"` - // UserAddress represents the address of the user who has restaked the tokens - UserAddress string `protobuf:"bytes,2,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` - // Amount represents the amount of tokens that have been restaked - Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` -} - -func (m *OperatorDelegationEntry) Reset() { *m = OperatorDelegationEntry{} } -func (m *OperatorDelegationEntry) String() string { return proto.CompactTextString(m) } -func (*OperatorDelegationEntry) ProtoMessage() {} -func (*OperatorDelegationEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_0378bd63cae7d256, []int{3} -} -func (m *OperatorDelegationEntry) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *OperatorDelegationEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_OperatorDelegationEntry.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 *OperatorDelegationEntry) XXX_Merge(src proto.Message) { - xxx_messageInfo_OperatorDelegationEntry.Merge(m, src) -} -func (m *OperatorDelegationEntry) XXX_Size() int { - return m.Size() -} -func (m *OperatorDelegationEntry) XXX_DiscardUnknown() { - xxx_messageInfo_OperatorDelegationEntry.DiscardUnknown(m) -} - -var xxx_messageInfo_OperatorDelegationEntry proto.InternalMessageInfo - -func (m *OperatorDelegationEntry) GetOperatorID() uint32 { - if m != nil { - return m.OperatorID - } - return 0 -} - -func (m *OperatorDelegationEntry) GetUserAddress() string { - if m != nil { - return m.UserAddress - } - return "" -} - -func (m *OperatorDelegationEntry) GetAmount() types.Coin { - if m != nil { - return m.Amount - } - return types.Coin{} -} - func init() { proto.RegisterType((*GenesisState)(nil), "milkyway.restaking.v1.GenesisState") - proto.RegisterType((*PoolDelegationEntry)(nil), "milkyway.restaking.v1.PoolDelegationEntry") - proto.RegisterType((*ServiceDelegationEntry)(nil), "milkyway.restaking.v1.ServiceDelegationEntry") - proto.RegisterType((*OperatorDelegationEntry)(nil), "milkyway.restaking.v1.OperatorDelegationEntry") } func init() { @@ -306,38 +106,28 @@ func init() { } var fileDescriptor_0378bd63cae7d256 = []byte{ - // 495 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x93, 0xc1, 0x6e, 0xd3, 0x4c, - 0x14, 0x85, 0xe3, 0xa6, 0xf2, 0xaf, 0xdc, 0xb4, 0xd5, 0x8f, 0x9b, 0x42, 0xa8, 0x84, 0x53, 0xd2, - 0x4d, 0x84, 0xe8, 0x8c, 0xd2, 0x2e, 0x59, 0x25, 0x04, 0xa1, 0x2c, 0x10, 0xc8, 0xdd, 0x21, 0xa1, - 0x68, 0x1c, 0x0f, 0x66, 0x54, 0xdb, 0x63, 0x79, 0x26, 0x81, 0xbc, 0x05, 0x8f, 0xc0, 0x03, 0xb0, - 0xe0, 0x31, 0xba, 0xec, 0x92, 0x55, 0x84, 0x9c, 0xe7, 0x40, 0x42, 0x33, 0x1e, 0x27, 0xa9, 0xe4, - 0x6c, 0xbb, 0x4b, 0x66, 0xce, 0xb9, 0xdf, 0xf1, 0xbd, 0x77, 0xe0, 0x3c, 0x66, 0xd1, 0xcd, 0xe2, - 0x2b, 0x59, 0xe0, 0x8c, 0x0a, 0x49, 0x6e, 0x58, 0x12, 0xe2, 0x79, 0x1f, 0x87, 0x34, 0xa1, 0x82, - 0x09, 0x94, 0x66, 0x5c, 0x72, 0xe7, 0xa4, 0x14, 0xa1, 0xb5, 0x08, 0xcd, 0xfb, 0xa7, 0xad, 0x90, - 0x87, 0x5c, 0x2b, 0xb0, 0xfa, 0x55, 0x88, 0x4f, 0xdd, 0x29, 0x17, 0x31, 0x17, 0xd8, 0x27, 0x82, - 0xe2, 0x79, 0xdf, 0xa7, 0x92, 0xf4, 0xf1, 0x94, 0xb3, 0xc4, 0xdc, 0x77, 0xab, 0x89, 0x29, 0xc9, - 0x48, 0x6c, 0x80, 0xdd, 0xbf, 0x7b, 0x70, 0xf0, 0xb6, 0x88, 0x70, 0x2d, 0x89, 0xa4, 0xce, 0x2b, - 0xb0, 0x0b, 0x41, 0xdb, 0x3a, 0xb3, 0x7a, 0xcd, 0xcb, 0x67, 0xa8, 0x32, 0x12, 0xfa, 0xa0, 0x45, - 0xc3, 0xfd, 0xdb, 0x65, 0xa7, 0xe6, 0x19, 0x8b, 0xf3, 0x09, 0x1e, 0xa5, 0x9c, 0x47, 0x62, 0x12, - 0xd0, 0x88, 0x86, 0x44, 0x32, 0x9e, 0x88, 0xf6, 0xde, 0x59, 0xbd, 0xd7, 0xbc, 0x7c, 0xb1, 0xab, - 0x0e, 0xe7, 0xd1, 0x68, 0xad, 0x7e, 0x93, 0xc8, 0x6c, 0x61, 0x8a, 0xfe, 0xaf, 0x4b, 0x6d, 0xee, - 0x84, 0xf3, 0x19, 0x5a, 0x82, 0x66, 0x73, 0x36, 0xa5, 0xf7, 0x09, 0x75, 0x4d, 0xb8, 0xd8, 0x41, - 0xb8, 0x2e, 0x2c, 0xd5, 0x90, 0xe3, 0xb2, 0xe0, 0x36, 0x87, 0xc1, 0x09, 0x4f, 0x69, 0x46, 0x24, - 0xcf, 0xee, 0x83, 0xf6, 0x35, 0x08, 0xed, 0x00, 0xbd, 0x37, 0x9e, 0x6a, 0x52, 0x6b, 0x5d, 0x72, - 0x0b, 0xd5, 0xfd, 0x61, 0xc1, 0x71, 0x45, 0x0b, 0x9c, 0x73, 0xf8, 0x4f, 0x7d, 0xfe, 0x84, 0x05, - 0x7a, 0x0e, 0x87, 0x43, 0xc8, 0x97, 0x1d, 0x5b, 0x29, 0xc7, 0x23, 0xcf, 0x56, 0x57, 0xe3, 0xc0, - 0x79, 0x0e, 0x07, 0x33, 0x41, 0xb3, 0x09, 0x09, 0x82, 0x8c, 0x0a, 0xd5, 0x69, 0xab, 0xd7, 0xf0, - 0x9a, 0xea, 0x6c, 0x50, 0x1c, 0x39, 0x03, 0xb0, 0x49, 0xcc, 0x67, 0x89, 0x6c, 0xd7, 0xf5, 0x38, - 0x9f, 0xa2, 0x62, 0x69, 0x90, 0x5a, 0x1a, 0x64, 0x96, 0x06, 0xbd, 0xe6, 0x2c, 0x19, 0x1e, 0xa9, - 0x98, 0x8a, 0x32, 0xd0, 0x06, 0xcf, 0x18, 0xbb, 0x3f, 0x2d, 0x78, 0x5c, 0xdd, 0x43, 0xe7, 0x25, - 0x80, 0xe9, 0xdf, 0x26, 0xe8, 0x61, 0xbe, 0xec, 0x34, 0x8c, 0x7e, 0x3c, 0xf2, 0x1a, 0x46, 0xf0, - 0x60, 0x71, 0x7f, 0x59, 0xf0, 0x64, 0xc7, 0x24, 0x1c, 0x0c, 0xcd, 0x72, 0x0a, 0x9b, 0xc0, 0x47, - 0xf9, 0xb2, 0x03, 0xa5, 0x63, 0x3c, 0xf2, 0xa0, 0x94, 0x3c, 0x54, 0xe4, 0xe1, 0xbb, 0xdb, 0xdc, - 0xb5, 0xee, 0x72, 0xd7, 0xfa, 0x93, 0xbb, 0xd6, 0xf7, 0x95, 0x5b, 0xbb, 0x5b, 0xb9, 0xb5, 0xdf, - 0x2b, 0xb7, 0xf6, 0xf1, 0x2a, 0x64, 0xf2, 0xcb, 0xcc, 0x47, 0x53, 0x1e, 0xe3, 0x72, 0xe9, 0x2e, - 0x22, 0xe2, 0x8b, 0xf5, 0x3f, 0xfc, 0x6d, 0xeb, 0x75, 0xcb, 0x45, 0x4a, 0x85, 0x6f, 0xeb, 0xa7, - 0x7d, 0xf5, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x21, 0x29, 0xab, 0x04, 0x72, 0x04, 0x00, 0x00, + // 336 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xbf, 0x4e, 0xfa, 0x50, + 0x14, 0x80, 0x5b, 0x20, 0x0c, 0xe5, 0x37, 0xfc, 0xac, 0x90, 0x10, 0x12, 0xaf, 0x04, 0x63, 0x82, + 0x83, 0xbd, 0x29, 0x8c, 0x6e, 0xc4, 0xc4, 0xc9, 0x68, 0x64, 0x31, 0x2e, 0xe6, 0xb6, 0x9c, 0xd4, + 0x1b, 0xda, 0x9e, 0xa6, 0xe7, 0x5a, 0xe5, 0x2d, 0x7c, 0x2c, 0x46, 0x46, 0x27, 0x63, 0x60, 0xf7, + 0x19, 0x8c, 0x6d, 0xa9, 0x10, 0xa8, 0x5b, 0xff, 0x7c, 0xe7, 0xfb, 0x4e, 0x72, 0x8c, 0x93, 0x40, + 0xfa, 0xd3, 0xd9, 0x8b, 0x98, 0xf1, 0x18, 0x48, 0x89, 0xa9, 0x0c, 0x3d, 0x9e, 0xd8, 0xdc, 0x83, + 0x10, 0x48, 0x92, 0x15, 0xc5, 0xa8, 0xd0, 0x6c, 0xad, 0x21, 0xab, 0x80, 0xac, 0xc4, 0xee, 0x34, + 0x3d, 0xf4, 0x30, 0x25, 0xf8, 0xcf, 0x53, 0x06, 0x77, 0x98, 0x8b, 0x14, 0x20, 0x71, 0x47, 0x10, + 0xf0, 0xc4, 0x76, 0x40, 0x09, 0x9b, 0xbb, 0x28, 0xc3, 0xfc, 0x7f, 0x6f, 0x7f, 0x31, 0xc0, 0x09, + 0xf8, 0xf4, 0x37, 0x13, 0x89, 0x58, 0x04, 0x39, 0xd3, 0xfb, 0xaa, 0x18, 0xff, 0xae, 0xb2, 0x35, + 0xc7, 0x4a, 0x28, 0x30, 0x2f, 0x8c, 0x7a, 0x06, 0xb4, 0xf5, 0xae, 0xde, 0x6f, 0x0c, 0x8e, 0xac, + 0xbd, 0x6b, 0x5b, 0xb7, 0x29, 0x34, 0xaa, 0xcd, 0x3f, 0x8e, 0xb5, 0xbb, 0x7c, 0xc4, 0xbc, 0x37, + 0x0e, 0x22, 0x44, 0x9f, 0x1e, 0x27, 0xe0, 0x83, 0x27, 0x94, 0xc4, 0x90, 0xda, 0x95, 0x6e, 0xb5, + 0xdf, 0x18, 0x9c, 0x96, 0x79, 0x10, 0xfd, 0xcb, 0x82, 0xce, 0x7d, 0xff, 0x53, 0xcb, 0xef, 0x67, + 0x32, 0x85, 0xd1, 0x24, 0x88, 0x13, 0xe9, 0xc2, 0xb6, 0xbc, 0x9a, 0xca, 0xfb, 0x25, 0xf2, 0x71, + 0x36, 0xb2, 0xe3, 0x3f, 0x5c, 0xbb, 0x36, 0x13, 0x13, 0xa3, 0x85, 0x11, 0xc4, 0x42, 0x61, 0xbc, + 0xdd, 0xa8, 0xa5, 0x8d, 0xb3, 0x92, 0xc6, 0x4d, 0x3e, 0xb3, 0x13, 0x69, 0x16, 0xb6, 0x8d, 0xca, + 0xe8, 0x7a, 0xbe, 0x64, 0xfa, 0x62, 0xc9, 0xf4, 0xcf, 0x25, 0xd3, 0xdf, 0x56, 0x4c, 0x5b, 0xac, + 0x98, 0xf6, 0xbe, 0x62, 0xda, 0xc3, 0xd0, 0x93, 0xea, 0xe9, 0xd9, 0xb1, 0x5c, 0x0c, 0xf8, 0x3a, + 0x75, 0xee, 0x0b, 0x87, 0x8a, 0x37, 0xfe, 0xba, 0x71, 0x49, 0x35, 0x8b, 0x80, 0x9c, 0x7a, 0x7a, + 0xc6, 0xe1, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x35, 0xb2, 0x3d, 0x77, 0x82, 0x02, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -415,141 +205,6 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *PoolDelegationEntry) 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 *PoolDelegationEntry) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PoolDelegationEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - if len(m.UserAddress) > 0 { - i -= len(m.UserAddress) - copy(dAtA[i:], m.UserAddress) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.UserAddress))) - i-- - dAtA[i] = 0x12 - } - if m.PoolID != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.PoolID)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *ServiceDelegationEntry) 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 *ServiceDelegationEntry) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ServiceDelegationEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - if len(m.UserAddress) > 0 { - i -= len(m.UserAddress) - copy(dAtA[i:], m.UserAddress) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.UserAddress))) - i-- - dAtA[i] = 0x12 - } - if m.ServiceID != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.ServiceID)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *OperatorDelegationEntry) 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 *OperatorDelegationEntry) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *OperatorDelegationEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - if len(m.UserAddress) > 0 { - i -= len(m.UserAddress) - copy(dAtA[i:], m.UserAddress) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.UserAddress))) - i-- - dAtA[i] = 0x12 - } - if m.OperatorID != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.OperatorID)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { offset -= sovGenesis(v) base := offset @@ -590,60 +245,6 @@ func (m *GenesisState) Size() (n int) { return n } -func (m *PoolDelegationEntry) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.PoolID != 0 { - n += 1 + sovGenesis(uint64(m.PoolID)) - } - l = len(m.UserAddress) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - l = m.Amount.Size() - n += 1 + l + sovGenesis(uint64(l)) - return n -} - -func (m *ServiceDelegationEntry) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ServiceID != 0 { - n += 1 + sovGenesis(uint64(m.ServiceID)) - } - l = len(m.UserAddress) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - l = m.Amount.Size() - n += 1 + l + sovGenesis(uint64(l)) - return n -} - -func (m *OperatorDelegationEntry) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.OperatorID != 0 { - n += 1 + sovGenesis(uint64(m.OperatorID)) - } - l = len(m.UserAddress) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - l = m.Amount.Size() - n += 1 + l + sovGenesis(uint64(l)) - return n -} - func sovGenesis(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -741,7 +342,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.PoolsDelegations = append(m.PoolsDelegations, PoolDelegationEntry{}) + m.PoolsDelegations = append(m.PoolsDelegations, PoolDelegation{}) if err := m.PoolsDelegations[len(m.PoolsDelegations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -775,7 +376,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ServicesDelegations = append(m.ServicesDelegations, ServiceDelegationEntry{}) + m.ServicesDelegations = append(m.ServicesDelegations, ServiceDelegation{}) if err := m.ServicesDelegations[len(m.ServicesDelegations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -809,7 +410,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.OperatorsDelegations = append(m.OperatorsDelegations, OperatorDelegationEntry{}) + m.OperatorsDelegations = append(m.OperatorsDelegations, OperatorDelegation{}) if err := m.OperatorsDelegations[len(m.OperatorsDelegations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -835,408 +436,6 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } return nil } -func (m *PoolDelegationEntry) 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: PoolDelegationEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: PoolDelegationEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PoolID", wireType) - } - m.PoolID = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PoolID |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", 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.UserAddress = 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 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 - } - if err := m.Amount.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 (m *ServiceDelegationEntry) 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: ServiceDelegationEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ServiceDelegationEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ServiceID", wireType) - } - m.ServiceID = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ServiceID |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", 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.UserAddress = 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 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 - } - if err := m.Amount.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 (m *OperatorDelegationEntry) 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: OperatorDelegationEntry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: OperatorDelegationEntry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OperatorID", wireType) - } - m.OperatorID = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OperatorID |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", 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.UserAddress = 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 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 - } - if err := m.Amount.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/restaking/types/genesis_test.go b/x/restaking/types/genesis_test.go index 14f7edcd7..cb36249c7 100644 --- a/x/restaking/types/genesis_test.go +++ b/x/restaking/types/genesis_test.go @@ -5,7 +5,6 @@ import ( "time" sdkmath "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/milkyway-labs/milkyway/x/restaking/types" @@ -20,11 +19,11 @@ func TestGenesis_Validate(t *testing.T) { { name: "invalid pool delegation entry returns error", genesis: types.NewGenesis( - []types.PoolDelegationEntry{ - types.NewPoolDelegationEntry( + []types.PoolDelegation{ + types.NewPoolDelegation( 0, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), }, nil, @@ -37,11 +36,11 @@ func TestGenesis_Validate(t *testing.T) { name: "invalid service delegation entry returns error", genesis: types.NewGenesis( nil, - []types.ServiceDelegationEntry{ - types.NewServiceDelegationEntry( + []types.ServiceDelegation{ + types.NewServiceDelegation( 0, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), }, nil, @@ -54,11 +53,11 @@ func TestGenesis_Validate(t *testing.T) { genesis: types.NewGenesis( nil, nil, - []types.OperatorDelegationEntry{ - types.NewOperatorDelegationEntry( + []types.OperatorDelegation{ + types.NewOperatorDelegation( 0, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), }, types.DefaultParams(), @@ -83,25 +82,25 @@ func TestGenesis_Validate(t *testing.T) { { name: "valid genesis returns no error", genesis: types.NewGenesis( - []types.PoolDelegationEntry{ - types.NewPoolDelegationEntry( + []types.PoolDelegation{ + types.NewPoolDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), }, - []types.ServiceDelegationEntry{ - types.NewServiceDelegationEntry( + []types.ServiceDelegation{ + types.NewServiceDelegation( 2, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), }, - []types.OperatorDelegationEntry{ - types.NewOperatorDelegationEntry( + []types.OperatorDelegation{ + types.NewOperatorDelegation( 3, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), }, types.NewParams(5*24*time.Hour), @@ -124,45 +123,45 @@ func TestGenesis_Validate(t *testing.T) { // -------------------------------------------------------------------------------------------------------------------- -func TestPoolDelegationEntry_Validate(t *testing.T) { +func TestPoolDelegation_Validate(t *testing.T) { testCases := []struct { name string - entry types.PoolDelegationEntry + entry types.PoolDelegation shouldErr bool }{ { name: "invalid pool id returns error", - entry: types.NewPoolDelegationEntry( + entry: types.NewPoolDelegation( 0, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), shouldErr: true, }, { name: "invalid user address returns error", - entry: types.NewPoolDelegationEntry( + entry: types.NewPoolDelegation( 1, "", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), shouldErr: true, }, { - name: "invalid amount returns error", - entry: types.NewPoolDelegationEntry( + name: "invalid shares returns error", + entry: types.NewPoolDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.Coin{}, + sdkmath.LegacyNewDec(-100), ), shouldErr: true, }, { name: "valid entry returns no error", - entry: types.NewPoolDelegationEntry( + entry: types.NewPoolDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), shouldErr: false, }, @@ -182,45 +181,45 @@ func TestPoolDelegationEntry_Validate(t *testing.T) { // -------------------------------------------------------------------------------------------------------------------- -func TestServiceDelegationEntry_Validate(t *testing.T) { +func TestServiceDelegation_Validate(t *testing.T) { testCases := []struct { name string - entry types.ServiceDelegationEntry + entry types.ServiceDelegation shouldErr bool }{ { name: "invalid service id returns error", - entry: types.NewServiceDelegationEntry( + entry: types.NewServiceDelegation( 0, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), shouldErr: true, }, { name: "invalid user address returns error", - entry: types.NewServiceDelegationEntry( + entry: types.NewServiceDelegation( 1, "", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), shouldErr: true, }, { - name: "invalid amount returns error", - entry: types.NewServiceDelegationEntry( + name: "invalid shares returns error", + entry: types.NewServiceDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.Coin{}, + sdkmath.LegacyNewDec(-100), ), shouldErr: true, }, { name: "valid entry returns no error", - entry: types.NewServiceDelegationEntry( + entry: types.NewServiceDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), shouldErr: false, }, @@ -240,45 +239,45 @@ func TestServiceDelegationEntry_Validate(t *testing.T) { // -------------------------------------------------------------------------------------------------------------------- -func TestOperatorDelegationEntry_Validate(t *testing.T) { +func TestOperatorDelegation_Validate(t *testing.T) { testCases := []struct { name string - entry types.OperatorDelegationEntry + entry types.OperatorDelegation shouldErr bool }{ { name: "invalid operator id returns error", - entry: types.NewOperatorDelegationEntry( + entry: types.NewOperatorDelegation( 0, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), shouldErr: true, }, { name: "invalid user address returns error", - entry: types.NewOperatorDelegationEntry( + entry: types.NewOperatorDelegation( 1, "", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), shouldErr: true, }, { - name: "invalid amount returns error", - entry: types.NewOperatorDelegationEntry( + name: "invalid shares returns error", + entry: types.NewOperatorDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.Coin{}, + sdkmath.LegacyNewDec(-100), ), shouldErr: true, }, { name: "valid entry returns no error", - entry: types.NewOperatorDelegationEntry( + entry: types.NewOperatorDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdkmath.LegacyNewDec(100), ), shouldErr: false, }, diff --git a/x/restaking/types/models.go b/x/restaking/types/models.go index 54b632ff4..47e7aed82 100644 --- a/x/restaking/types/models.go +++ b/x/restaking/types/models.go @@ -1,8 +1,11 @@ package types import ( + "fmt" + sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" ) // NewPoolDelegation creates a new PoolDelegation instance @@ -14,7 +17,22 @@ func NewPoolDelegation(poolID uint32, userAddress string, shares sdkmath.LegacyD } } -// -------------------------------------------------------------------------------------------------------------------- +func (d PoolDelegation) Validate() error { + if d.PoolID == 0 { + return fmt.Errorf("invalid pool id") + } + + _, err := sdk.AccAddressFromBech32(d.UserAddress) + if err != nil { + return fmt.Errorf("invalid user address: %s", d.UserAddress) + } + + if d.Shares.IsNegative() { + return ErrInvalidShares + } + + return nil +} // MustMarshalPoolDelegation marshals the given pool delegation using the provided codec func MustMarshalPoolDelegation(cdc codec.BinaryCodec, delegation PoolDelegation) []byte { @@ -43,3 +61,57 @@ func MustUnmarshalPoolDelegation(cdc codec.BinaryCodec, bz []byte) PoolDelegatio } return delegation } + +// -------------------------------------------------------------------------------------------------------------------- + +func NewOperatorDelegation(operatorID uint32, userAddress string, shares sdkmath.LegacyDec) OperatorDelegation { + return OperatorDelegation{ + OperatorID: operatorID, + UserAddress: userAddress, + Shares: shares, + } +} + +func (d OperatorDelegation) Validate() error { + if d.OperatorID == 0 { + return fmt.Errorf("invalid operator id") + } + + _, err := sdk.AccAddressFromBech32(d.UserAddress) + if err != nil { + return fmt.Errorf("invalid user address: %s", d.UserAddress) + } + + if d.Shares.IsNegative() { + return ErrInvalidShares + } + + return nil +} + +// -------------------------------------------------------------------------------------------------------------------- + +func NewServiceDelegation(serviceID uint32, userAddress string, shares sdkmath.LegacyDec) ServiceDelegation { + return ServiceDelegation{ + ServiceID: serviceID, + UserAddress: userAddress, + Shares: shares, + } +} + +func (d ServiceDelegation) Validate() error { + if d.ServiceID == 0 { + return fmt.Errorf("invalid service id") + } + + _, err := sdk.AccAddressFromBech32(d.UserAddress) + if err != nil { + return fmt.Errorf("invalid user address: %s", d.UserAddress) + } + + if d.Shares.IsNegative() { + return ErrInvalidShares + } + + return nil +} diff --git a/x/restaking/types/models.pb.go b/x/restaking/types/models.pb.go index 24b62cbce..a0c1e8b45 100644 --- a/x/restaking/types/models.pb.go +++ b/x/restaking/types/models.pb.go @@ -70,8 +70,100 @@ func (m *PoolDelegation) XXX_DiscardUnknown() { var xxx_messageInfo_PoolDelegation proto.InternalMessageInfo +// OperatorDelegation represents the bond with tokens held by an account with a +// given operator. It is owned by one delegator, and is associated with a +// operator. +type OperatorDelegation struct { + // UserAddress is the encoded address of the user. + UserAddress string `protobuf:"bytes,1,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` + // OperatorID is the id of the operator. + OperatorID uint32 `protobuf:"varint,2,opt,name=operator_id,json=operatorId,proto3" json:"operator_id,omitempty"` + // Shares define the delegation shares received. + Shares cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=shares,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"shares"` +} + +func (m *OperatorDelegation) Reset() { *m = OperatorDelegation{} } +func (m *OperatorDelegation) String() string { return proto.CompactTextString(m) } +func (*OperatorDelegation) ProtoMessage() {} +func (*OperatorDelegation) Descriptor() ([]byte, []int) { + return fileDescriptor_86f4cd48423b1e2f, []int{1} +} +func (m *OperatorDelegation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OperatorDelegation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_OperatorDelegation.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 *OperatorDelegation) XXX_Merge(src proto.Message) { + xxx_messageInfo_OperatorDelegation.Merge(m, src) +} +func (m *OperatorDelegation) XXX_Size() int { + return m.Size() +} +func (m *OperatorDelegation) XXX_DiscardUnknown() { + xxx_messageInfo_OperatorDelegation.DiscardUnknown(m) +} + +var xxx_messageInfo_OperatorDelegation proto.InternalMessageInfo + +// ServiceDelegation represents the bond with tokens held by an account with a +// given service. It is owned by one delegator, and is associated with a +// service. +type ServiceDelegation struct { + // UserAddress is the encoded address of the user. + UserAddress string `protobuf:"bytes,1,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` + // ServiceID is the id of the service. + ServiceID uint32 `protobuf:"varint,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + // Shares define the delegation shares received. + Shares cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=shares,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"shares"` +} + +func (m *ServiceDelegation) Reset() { *m = ServiceDelegation{} } +func (m *ServiceDelegation) String() string { return proto.CompactTextString(m) } +func (*ServiceDelegation) ProtoMessage() {} +func (*ServiceDelegation) Descriptor() ([]byte, []int) { + return fileDescriptor_86f4cd48423b1e2f, []int{2} +} +func (m *ServiceDelegation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ServiceDelegation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ServiceDelegation.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 *ServiceDelegation) XXX_Merge(src proto.Message) { + xxx_messageInfo_ServiceDelegation.Merge(m, src) +} +func (m *ServiceDelegation) XXX_Size() int { + return m.Size() +} +func (m *ServiceDelegation) XXX_DiscardUnknown() { + xxx_messageInfo_ServiceDelegation.DiscardUnknown(m) +} + +var xxx_messageInfo_ServiceDelegation proto.InternalMessageInfo + func init() { proto.RegisterType((*PoolDelegation)(nil), "milkyway.restaking.v1.PoolDelegation") + proto.RegisterType((*OperatorDelegation)(nil), "milkyway.restaking.v1.OperatorDelegation") + proto.RegisterType((*ServiceDelegation)(nil), "milkyway.restaking.v1.ServiceDelegation") } func init() { @@ -79,28 +171,33 @@ func init() { } var fileDescriptor_86f4cd48423b1e2f = []byte{ - // 336 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x90, 0xcb, 0x4a, 0xf3, 0x40, - 0x18, 0x86, 0x33, 0xff, 0x0f, 0x51, 0xc7, 0x03, 0x18, 0x2a, 0xc4, 0x0a, 0x49, 0xa9, 0x9b, 0x6e, - 0x9a, 0xa1, 0x74, 0xa7, 0x2b, 0x4b, 0x36, 0x05, 0x05, 0xa9, 0x3b, 0x37, 0x65, 0x9a, 0x0c, 0xd3, - 0xa1, 0x49, 0xbe, 0x92, 0x99, 0x56, 0x73, 0x07, 0x2e, 0xbd, 0x84, 0x5e, 0x44, 0xef, 0xc1, 0x2e, - 0x4b, 0x57, 0xe2, 0xa2, 0x48, 0xb2, 0xf1, 0x32, 0x24, 0x87, 0x16, 0x37, 0xc3, 0xbc, 0x07, 0x9e, - 0x0f, 0x5e, 0xdc, 0x0c, 0x45, 0x30, 0x49, 0x5e, 0x68, 0x42, 0x62, 0x26, 0x15, 0x9d, 0x88, 0x88, - 0x93, 0x79, 0x87, 0x84, 0xe0, 0xb3, 0x40, 0x3a, 0xd3, 0x18, 0x14, 0x18, 0x17, 0xbb, 0x8e, 0xb3, - 0xef, 0x38, 0xf3, 0x4e, 0xfd, 0x9c, 0x86, 0x22, 0x02, 0x52, 0xbc, 0x65, 0xb3, 0x7e, 0xe9, 0x81, - 0x0c, 0x41, 0x0e, 0x0b, 0x45, 0x4a, 0x51, 0x45, 0x35, 0x0e, 0x1c, 0x4a, 0x3f, 0xff, 0x95, 0x6e, - 0xf3, 0x03, 0xe1, 0xb3, 0x47, 0x80, 0xc0, 0x65, 0x01, 0xe3, 0x54, 0x09, 0x88, 0x8c, 0x5b, 0x7c, - 0x32, 0x93, 0x2c, 0x1e, 0x52, 0xdf, 0x8f, 0x99, 0x94, 0x26, 0x6a, 0xa0, 0xd6, 0x51, 0xcf, 0xdc, - 0x2c, 0xdb, 0xb5, 0x0a, 0x78, 0x57, 0x26, 0x4f, 0x2a, 0x16, 0x11, 0x1f, 0x1c, 0xe7, 0xed, 0xca, - 0x32, 0xae, 0xf1, 0xc1, 0x14, 0x20, 0x18, 0x0a, 0xdf, 0xfc, 0xd7, 0x40, 0xad, 0xd3, 0x1e, 0x4e, - 0xb7, 0xb6, 0x9e, 0x5f, 0xe8, 0xbb, 0x03, 0x3d, 0x8f, 0xfa, 0xbe, 0xd1, 0xc7, 0xba, 0x1c, 0xd3, - 0x98, 0x49, 0xf3, 0x7f, 0xc1, 0xee, 0xac, 0xb6, 0xb6, 0xf6, 0xb5, 0xb5, 0xaf, 0x4a, 0xbe, 0xf4, - 0x27, 0x8e, 0x00, 0x12, 0x52, 0x35, 0x76, 0xee, 0x19, 0xa7, 0x5e, 0xe2, 0x32, 0x6f, 0xb3, 0x6c, - 0xe3, 0xea, 0xbc, 0xcb, 0xbc, 0x41, 0x05, 0xb8, 0x39, 0x7c, 0x5b, 0xd8, 0xda, 0xcf, 0xc2, 0xd6, - 0x7a, 0x0f, 0xab, 0xd4, 0x42, 0xeb, 0xd4, 0x42, 0xdf, 0xa9, 0x85, 0xde, 0x33, 0x4b, 0x5b, 0x67, - 0x96, 0xf6, 0x99, 0x59, 0xda, 0x73, 0x97, 0x0b, 0x35, 0x9e, 0x8d, 0x1c, 0x0f, 0x42, 0xb2, 0x5b, - 0xb2, 0x1d, 0xd0, 0x91, 0xdc, 0x2b, 0xf2, 0xfa, 0x67, 0x7d, 0x95, 0x4c, 0x99, 0x1c, 0xe9, 0xc5, - 0x3e, 0xdd, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2a, 0x1a, 0x78, 0x81, 0xa0, 0x01, 0x00, 0x00, + // 410 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0xc1, 0x8a, 0xd3, 0x40, + 0x18, 0xc7, 0x33, 0x0a, 0xd1, 0xce, 0xba, 0x0b, 0x1b, 0x56, 0x88, 0x2b, 0x24, 0x4b, 0xbd, 0xec, + 0xc1, 0x66, 0x28, 0x7b, 0xd3, 0x93, 0x25, 0x97, 0x80, 0xa2, 0x64, 0x6f, 0x5e, 0xca, 0x34, 0x19, + 0xd2, 0xa1, 0x49, 0xbe, 0x30, 0x33, 0x5b, 0xcd, 0x1b, 0x78, 0xf4, 0x11, 0xf6, 0x21, 0xf6, 0x1d, + 0xdc, 0x63, 0xa9, 0x07, 0xc5, 0x43, 0x90, 0xf4, 0xe2, 0x63, 0x48, 0x92, 0x49, 0xbb, 0x0f, 0xd0, + 0x5e, 0x42, 0xbe, 0xef, 0xff, 0xe7, 0xff, 0xe7, 0x07, 0xdf, 0xe0, 0x61, 0xc6, 0xd3, 0x45, 0xf9, + 0x85, 0x96, 0x44, 0x30, 0xa9, 0xe8, 0x82, 0xe7, 0x09, 0x59, 0x8e, 0x49, 0x06, 0x31, 0x4b, 0xa5, + 0x57, 0x08, 0x50, 0x60, 0x3d, 0xef, 0x3d, 0xde, 0xd6, 0xe3, 0x2d, 0xc7, 0xe7, 0xa7, 0x34, 0xe3, + 0x39, 0x90, 0xf6, 0xdb, 0x39, 0xcf, 0x5f, 0x44, 0x20, 0x33, 0x90, 0xd3, 0x76, 0x22, 0xdd, 0xa0, + 0xa5, 0xb3, 0x04, 0x12, 0xe8, 0xf6, 0xcd, 0x5f, 0xb7, 0x1d, 0xfe, 0x40, 0xf8, 0xe4, 0x13, 0x40, + 0xea, 0xb3, 0x94, 0x25, 0x54, 0x71, 0xc8, 0xad, 0xb7, 0xf8, 0xd9, 0x8d, 0x64, 0x62, 0x4a, 0xe3, + 0x58, 0x30, 0x29, 0x6d, 0x74, 0x81, 0x2e, 0x07, 0x13, 0x7b, 0x7d, 0x37, 0x3a, 0xd3, 0x81, 0xef, + 0x3a, 0xe5, 0x5a, 0x09, 0x9e, 0x27, 0xe1, 0x51, 0xe3, 0xd6, 0x2b, 0xeb, 0x15, 0x7e, 0x52, 0x00, + 0xa4, 0x53, 0x1e, 0xdb, 0x8f, 0x2e, 0xd0, 0xe5, 0xf1, 0x04, 0xd7, 0x95, 0x6b, 0x36, 0x0d, 0x81, + 0x1f, 0x9a, 0x8d, 0x14, 0xc4, 0x56, 0x80, 0x4d, 0x39, 0xa7, 0x82, 0x49, 0xfb, 0x71, 0x9b, 0x3d, + 0xbe, 0xaf, 0x5c, 0xe3, 0x4f, 0xe5, 0xbe, 0xec, 0xf2, 0x65, 0xbc, 0xf0, 0x38, 0x90, 0x8c, 0xaa, + 0xb9, 0xf7, 0x9e, 0x25, 0x34, 0x2a, 0x7d, 0x16, 0xad, 0xef, 0x46, 0x58, 0xd7, 0xfb, 0x2c, 0x0a, + 0x75, 0xc0, 0x9b, 0xa7, 0xdf, 0x6e, 0x5d, 0xe3, 0xdf, 0xad, 0x6b, 0x0c, 0x7f, 0x21, 0x6c, 0x7d, + 0x2c, 0x98, 0xa0, 0x0a, 0xc4, 0xbe, 0x68, 0x08, 0x3e, 0x02, 0x1d, 0xb9, 0x23, 0x3a, 0xa9, 0x2b, + 0x17, 0xf7, 0x4d, 0x81, 0x1f, 0xe2, 0xde, 0x72, 0x28, 0xb2, 0x9f, 0x08, 0x9f, 0x5e, 0x33, 0xb1, + 0xe4, 0x11, 0xdb, 0x17, 0xd8, 0x6b, 0x8c, 0x65, 0x97, 0xb8, 0xe3, 0x3a, 0xae, 0x2b, 0x77, 0xa0, + 0x7b, 0x02, 0x3f, 0x1c, 0x68, 0xc3, 0x81, 0xa8, 0x26, 0x1f, 0xee, 0x6b, 0x07, 0xad, 0x6a, 0x07, + 0xfd, 0xad, 0x1d, 0xf4, 0x7d, 0xe3, 0x18, 0xab, 0x8d, 0x63, 0xfc, 0xde, 0x38, 0xc6, 0xe7, 0xab, + 0x84, 0xab, 0xf9, 0xcd, 0xcc, 0x8b, 0x20, 0x23, 0xfd, 0xe5, 0x8f, 0x52, 0x3a, 0x93, 0xdb, 0x89, + 0x7c, 0x7d, 0xf0, 0x5a, 0x54, 0x59, 0x30, 0x39, 0x33, 0xdb, 0x7b, 0xbe, 0xfa, 0x1f, 0x00, 0x00, + 0xff, 0xff, 0xe2, 0x92, 0x5c, 0xce, 0x50, 0x03, 0x00, 0x00, } func (m *PoolDelegation) Marshal() (dAtA []byte, err error) { @@ -148,6 +245,96 @@ func (m *PoolDelegation) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *OperatorDelegation) 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 *OperatorDelegation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OperatorDelegation) 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 = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.OperatorID != 0 { + i = encodeVarintModels(dAtA, i, uint64(m.OperatorID)) + i-- + dAtA[i] = 0x10 + } + if len(m.UserAddress) > 0 { + i -= len(m.UserAddress) + copy(dAtA[i:], m.UserAddress) + i = encodeVarintModels(dAtA, i, uint64(len(m.UserAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ServiceDelegation) 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 *ServiceDelegation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ServiceDelegation) 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 = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.ServiceID != 0 { + i = encodeVarintModels(dAtA, i, uint64(m.ServiceID)) + i-- + dAtA[i] = 0x10 + } + if len(m.UserAddress) > 0 { + i -= len(m.UserAddress) + copy(dAtA[i:], m.UserAddress) + i = encodeVarintModels(dAtA, i, uint64(len(m.UserAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintModels(dAtA []byte, offset int, v uint64) int { offset -= sovModels(v) base := offset @@ -177,6 +364,42 @@ func (m *PoolDelegation) Size() (n int) { return n } +func (m *OperatorDelegation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UserAddress) + if l > 0 { + n += 1 + l + sovModels(uint64(l)) + } + if m.OperatorID != 0 { + n += 1 + sovModels(uint64(m.OperatorID)) + } + l = m.Shares.Size() + n += 1 + l + sovModels(uint64(l)) + return n +} + +func (m *ServiceDelegation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UserAddress) + if l > 0 { + n += 1 + l + sovModels(uint64(l)) + } + if m.ServiceID != 0 { + n += 1 + sovModels(uint64(m.ServiceID)) + } + l = m.Shares.Size() + n += 1 + l + sovModels(uint64(l)) + return n +} + func sovModels(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -318,6 +541,276 @@ func (m *PoolDelegation) Unmarshal(dAtA []byte) error { } return nil } +func (m *OperatorDelegation) 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 ErrIntOverflowModels + } + 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: OperatorDelegation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OperatorDelegation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + 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 ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UserAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorID", wireType) + } + m.OperatorID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OperatorID |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + 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 ErrIntOverflowModels + } + 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 ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + 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 := skipModels(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthModels + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ServiceDelegation) 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 ErrIntOverflowModels + } + 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: ServiceDelegation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ServiceDelegation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + 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 ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UserAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ServiceID", wireType) + } + m.ServiceID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ServiceID |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + 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 ErrIntOverflowModels + } + 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 ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + 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 := skipModels(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthModels + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipModels(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From 97d86be1b635d1e269f5631fbacc5642a58f1188 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 10:44:58 -0500 Subject: [PATCH 13/37] refactor: implement abstract function to work with all delegation types --- x/operators/types/messages.pb.go | 92 ++++++++++++------------ x/restaking/keeper/pool_restaking.go | 102 +++++++++++---------------- x/restaking/keeper/restaking.go | 75 ++++++++++++++++++++ x/restaking/types/delegation.go | 41 +++++++++++ x/restaking/types/models.go | 4 ++ x/services/types/messages.pb.go | 99 +++++++++++++------------- x/services/types/models.pb.go | 57 +++++++-------- 7 files changed, 284 insertions(+), 186 deletions(-) create mode 100644 x/restaking/keeper/restaking.go create mode 100644 x/restaking/types/delegation.go diff --git a/x/operators/types/messages.pb.go b/x/operators/types/messages.pb.go index 5b5944267..0e499b4e9 100644 --- a/x/operators/types/messages.pb.go +++ b/x/operators/types/messages.pb.go @@ -488,52 +488,52 @@ func init() { } var fileDescriptor_376ca0aafe99868c = []byte{ - // 720 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x3f, 0x6f, 0xd3, 0x4e, - 0x18, 0x8e, 0xd3, 0x3f, 0x3f, 0xf5, 0xf2, 0xeb, 0x3f, 0xd3, 0xaa, 0xa9, 0x4b, 0x6d, 0x64, 0x55, - 0xa8, 0x84, 0xd4, 0x6e, 0x5a, 0x16, 0xc2, 0x44, 0x54, 0x06, 0x10, 0x81, 0xca, 0xa8, 0x12, 0x62, - 0x89, 0x2e, 0xc9, 0xe1, 0x5a, 0x8d, 0x7d, 0xd1, 0xdd, 0x25, 0x69, 0x36, 0xc4, 0xc8, 0xc4, 0xc8, - 0x67, 0x60, 0xea, 0xc0, 0x27, 0x60, 0xa1, 0x63, 0xc5, 0xc4, 0x64, 0xa1, 0x74, 0xe8, 0x9e, 0x4f, - 0x80, 0xe2, 0x3b, 0xbb, 0x6e, 0xe2, 0x88, 0x16, 0x24, 0x96, 0x28, 0xef, 0xfb, 0x3c, 0xef, 0xbd, - 0xef, 0xf3, 0xbc, 0x3e, 0x1b, 0x6c, 0xb8, 0x4e, 0xe3, 0xa8, 0xdb, 0x81, 0x5d, 0x13, 0x37, 0x11, - 0x81, 0x0c, 0x13, 0x6a, 0xb6, 0x0b, 0xa6, 0x8b, 0x28, 0x85, 0x36, 0xa2, 0x46, 0x93, 0x60, 0x86, - 0xe5, 0xe5, 0x90, 0x65, 0x44, 0x2c, 0xa3, 0x5d, 0x50, 0x16, 0xa1, 0xeb, 0x78, 0xd8, 0x0c, 0x7e, - 0x39, 0x53, 0x59, 0xad, 0x61, 0xea, 0x62, 0x5a, 0x09, 0x22, 0x93, 0x07, 0x02, 0x52, 0x79, 0x64, - 0x56, 0x21, 0x45, 0x66, 0xbb, 0x50, 0x45, 0x0c, 0x16, 0xcc, 0x1a, 0x76, 0xbc, 0x11, 0xdc, 0x3b, - 0x8a, 0xf0, 0x41, 0x20, 0xf0, 0x15, 0x81, 0xbb, 0xd4, 0x0e, 0x46, 0xa4, 0xb6, 0x00, 0x96, 0x6c, - 0x6c, 0x63, 0xde, 0x70, 0xf0, 0x4f, 0x64, 0xf5, 0x64, 0x65, 0x4d, 0x48, 0xa0, 0x2b, 0x46, 0xd2, - 0x3f, 0xa5, 0xc1, 0xad, 0x32, 0xb5, 0x2d, 0x64, 0x3b, 0x94, 0x21, 0xf2, 0x52, 0x10, 0xe5, 0x6d, - 0x30, 0x4d, 0x91, 0x57, 0x47, 0x24, 0x2b, 0xdd, 0x91, 0x36, 0x67, 0x4a, 0xd9, 0xef, 0x5f, 0xb6, - 0x96, 0x84, 0x98, 0xc7, 0xf5, 0x3a, 0x41, 0x94, 0xbe, 0x62, 0xc4, 0xf1, 0x6c, 0x4b, 0xf0, 0xe4, - 0x3c, 0xf8, 0xcf, 0xc5, 0x9e, 0x73, 0x84, 0x48, 0x36, 0x1d, 0x94, 0xc8, 0x7d, 0x5f, 0x9b, 0xeb, - 0x42, 0xb7, 0x51, 0xd4, 0x05, 0xa0, 0x5b, 0x21, 0x65, 0xc0, 0xee, 0xa0, 0x2a, 0x75, 0x18, 0xca, - 0x4e, 0x0c, 0xb3, 0x05, 0xa0, 0x5b, 0x21, 0x45, 0x7e, 0x02, 0x32, 0x4d, 0xa7, 0xc6, 0x5a, 0x04, - 0x55, 0x5a, 0xa4, 0x91, 0x9d, 0x0c, 0x2a, 0x36, 0x7a, 0xbe, 0x06, 0xf6, 0x79, 0xfa, 0xc0, 0x7a, - 0xde, 0xf7, 0x35, 0x99, 0xd7, 0xc7, 0xa8, 0xba, 0x05, 0x44, 0x74, 0x40, 0x1a, 0xc5, 0xfc, 0xfb, - 0x8b, 0x93, 0x9c, 0x98, 0xf7, 0xc3, 0xc5, 0x49, 0xee, 0x76, 0x64, 0x50, 0x82, 0x05, 0xfa, 0x6b, - 0xb0, 0x96, 0x90, 0xb6, 0x10, 0x6d, 0x62, 0x8f, 0x22, 0xf9, 0x21, 0x98, 0xf7, 0x50, 0xa7, 0x12, - 0x5a, 0x5b, 0x71, 0xea, 0x81, 0x55, 0xb3, 0xa5, 0xc5, 0x9e, 0xaf, 0xcd, 0xbe, 0x40, 0x9d, 0xb0, - 0xe2, 0xe9, 0x9e, 0x35, 0xeb, 0xc5, 0xc2, 0xba, 0xfe, 0x35, 0x0d, 0x16, 0xcb, 0xd4, 0x3e, 0x68, - 0xd6, 0x21, 0x43, 0x7f, 0x61, 0xb9, 0x09, 0x32, 0xf1, 0xf6, 0xe9, 0xa0, 0xfd, 0xdc, 0xc0, 0x96, - 0x58, 0x6f, 0x80, 0xa3, 0xc6, 0xf2, 0xbd, 0xcb, 0x1d, 0x71, 0xd7, 0xe7, 0xfb, 0xbe, 0x96, 0xe1, - 0xae, 0x79, 0xd0, 0x45, 0xc9, 0x0b, 0x9a, 0xbc, 0xf1, 0x82, 0xa6, 0xfe, 0x70, 0x41, 0xb9, 0xa1, - 0x05, 0x29, 0xf1, 0x05, 0x5d, 0xb5, 0x4b, 0x5f, 0x03, 0xab, 0x23, 0xc9, 0x70, 0x39, 0xfa, 0x67, - 0x09, 0x2c, 0x97, 0xa9, 0xbd, 0x87, 0x60, 0x8d, 0x39, 0xed, 0x7f, 0xeb, 0x72, 0xd1, 0x18, 0x52, - 0xa1, 0xc6, 0x55, 0x8c, 0x8e, 0xa4, 0x6b, 0x60, 0x3d, 0x11, 0x88, 0xd4, 0x7c, 0x93, 0xc0, 0x7c, - 0xa4, 0x75, 0x3f, 0xb8, 0xbe, 0xf2, 0x33, 0x30, 0x03, 0x5b, 0xec, 0x10, 0x13, 0x87, 0x75, 0x85, - 0x94, 0x7c, 0xdf, 0xd7, 0x16, 0xb8, 0xc3, 0x11, 0xa4, 0x8f, 0x95, 0x77, 0x59, 0x2e, 0x3f, 0x02, - 0xd3, 0xfc, 0xa5, 0x10, 0x88, 0xcb, 0xec, 0xac, 0x1b, 0x89, 0x6f, 0x3b, 0x83, 0xb7, 0x2e, 0x4d, - 0x9e, 0xfa, 0x5a, 0xca, 0x12, 0x25, 0xc5, 0xfb, 0x03, 0xb5, 0x97, 0x87, 0x0d, 0x04, 0x67, 0x47, - 0xd7, 0xc6, 0x4b, 0xf5, 0x55, 0xb0, 0x32, 0x94, 0x0a, 0x45, 0xee, 0x9c, 0x4d, 0x80, 0x89, 0x32, - 0xb5, 0x65, 0x02, 0x16, 0x46, 0xde, 0x46, 0xb9, 0x31, 0x03, 0x25, 0xdc, 0x4f, 0x65, 0xe7, 0xfa, - 0xdc, 0xe8, 0x2e, 0x37, 0xc0, 0xdc, 0xd0, 0x65, 0xdc, 0x1c, 0x7f, 0xca, 0x55, 0xa6, 0xb2, 0x7d, - 0x5d, 0x66, 0xd4, 0xed, 0x18, 0xc8, 0x09, 0x0f, 0x66, 0x7e, 0xfc, 0x39, 0xa3, 0x6c, 0xe5, 0xc1, - 0x4d, 0xd8, 0x51, 0xe7, 0xb7, 0xe0, 0xff, 0x2b, 0x0f, 0xd1, 0xdd, 0xdf, 0xcd, 0xce, 0x79, 0x8a, - 0x71, 0x3d, 0x5e, 0xd8, 0x47, 0x99, 0x7a, 0x77, 0x71, 0x92, 0x93, 0x4a, 0xe5, 0xd3, 0x9e, 0x2a, - 0x9d, 0xf5, 0x54, 0xe9, 0x67, 0x4f, 0x95, 0x3e, 0x9e, 0xab, 0xa9, 0xb3, 0x73, 0x35, 0xf5, 0xe3, - 0x5c, 0x4d, 0xbd, 0xd9, 0xb5, 0x1d, 0x76, 0xd8, 0xaa, 0x1a, 0x35, 0xec, 0x9a, 0xe1, 0xd1, 0x5b, - 0x0d, 0x58, 0xa5, 0x51, 0x64, 0x1e, 0xc7, 0xbe, 0x5a, 0xac, 0xdb, 0x44, 0xb4, 0x3a, 0x1d, 0x7c, - 0xb2, 0x76, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0xbb, 0xc1, 0xb6, 0xc4, 0xb2, 0x07, 0x00, 0x00, + // 718 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x3d, 0x6f, 0xd3, 0x4e, + 0x1c, 0x8e, 0xd3, 0x97, 0xbf, 0x7a, 0xf9, 0xf7, 0xcd, 0xb4, 0x6a, 0x92, 0xaa, 0x36, 0xb2, 0x2a, + 0x54, 0x42, 0x6a, 0x37, 0x2d, 0x0b, 0x61, 0x22, 0x2a, 0x03, 0x88, 0x40, 0x65, 0x54, 0x09, 0xb1, + 0x44, 0x97, 0xe4, 0x70, 0xad, 0xc6, 0x3e, 0xeb, 0xee, 0x92, 0x34, 0x1b, 0x62, 0x64, 0x62, 0xe5, + 0x33, 0xb0, 0x74, 0xe0, 0x1b, 0xb0, 0x74, 0xac, 0x98, 0x98, 0x2c, 0x94, 0x0e, 0xdd, 0xf3, 0x09, + 0x50, 0x7c, 0x67, 0xe7, 0xcd, 0x11, 0x2d, 0x48, 0x2c, 0x51, 0x7e, 0xf7, 0x3c, 0xbf, 0x97, 0xe7, + 0xf9, 0xf9, 0x6c, 0xb0, 0xed, 0xd8, 0x8d, 0xd3, 0x4e, 0x1b, 0x76, 0x0c, 0xec, 0x21, 0x02, 0x19, + 0x26, 0xd4, 0x68, 0x15, 0x0c, 0x07, 0x51, 0x0a, 0x2d, 0x44, 0x75, 0x8f, 0x60, 0x86, 0xe5, 0xf5, + 0x90, 0xa5, 0x47, 0x2c, 0xbd, 0x55, 0xc8, 0xae, 0x42, 0xc7, 0x76, 0xb1, 0x11, 0xfc, 0x72, 0x66, + 0x36, 0x53, 0xc3, 0xd4, 0xc1, 0xb4, 0x12, 0x44, 0x06, 0x0f, 0x04, 0xa4, 0xf0, 0xc8, 0xa8, 0x42, + 0x8a, 0x8c, 0x56, 0xa1, 0x8a, 0x18, 0x2c, 0x18, 0x35, 0x6c, 0xbb, 0x13, 0xb8, 0x7b, 0x1a, 0xe1, + 0xfd, 0x40, 0xe0, 0x1b, 0x02, 0x77, 0xa8, 0x15, 0x8c, 0x48, 0x2d, 0x01, 0xac, 0x59, 0xd8, 0xc2, + 0xbc, 0x61, 0xff, 0x9f, 0x38, 0xd5, 0xe2, 0x95, 0x79, 0x90, 0x40, 0x47, 0x8c, 0xa4, 0x7d, 0x4e, + 0x82, 0x3b, 0x65, 0x6a, 0x99, 0xc8, 0xb2, 0x29, 0x43, 0xe4, 0x95, 0x20, 0xca, 0x7b, 0x60, 0x9e, + 0x22, 0xb7, 0x8e, 0x48, 0x5a, 0xba, 0x2b, 0xed, 0x2c, 0x94, 0xd2, 0xdf, 0xbf, 0xee, 0xae, 0x09, + 0x31, 0x4f, 0xea, 0x75, 0x82, 0x28, 0x7d, 0xcd, 0x88, 0xed, 0x5a, 0xa6, 0xe0, 0xc9, 0x79, 0xf0, + 0x9f, 0x83, 0x5d, 0xfb, 0x14, 0x91, 0x74, 0x32, 0x48, 0x91, 0x7b, 0xbe, 0xba, 0xd4, 0x81, 0x4e, + 0xa3, 0xa8, 0x09, 0x40, 0x33, 0x43, 0x4a, 0x9f, 0xdd, 0x46, 0x55, 0x6a, 0x33, 0x94, 0x9e, 0x19, + 0x67, 0x0b, 0x40, 0x33, 0x43, 0x8a, 0xfc, 0x14, 0xa4, 0x3c, 0xbb, 0xc6, 0x9a, 0x04, 0x55, 0x9a, + 0xa4, 0x91, 0x9e, 0x0d, 0x32, 0xb6, 0xbb, 0xbe, 0x0a, 0x8e, 0xf8, 0xf1, 0xb1, 0xf9, 0xa2, 0xe7, + 0xab, 0x32, 0xcf, 0x1f, 0xa2, 0x6a, 0x26, 0x10, 0xd1, 0x31, 0x69, 0x14, 0x77, 0x3f, 0x5c, 0x9f, + 0xe7, 0xc4, 0xbc, 0x1f, 0xaf, 0xcf, 0x73, 0x5b, 0x03, 0x5f, 0x62, 0x3c, 0xd0, 0xde, 0x80, 0xcd, + 0x98, 0x63, 0x13, 0x51, 0x0f, 0xbb, 0x14, 0xc9, 0x8f, 0xc0, 0xb2, 0x8b, 0xda, 0x95, 0xb0, 0x46, + 0xc5, 0xae, 0x07, 0x5e, 0x2d, 0x96, 0x56, 0xbb, 0xbe, 0xba, 0xf8, 0x12, 0xb5, 0xc3, 0x8c, 0x67, + 0x87, 0xe6, 0xa2, 0x3b, 0x14, 0xd6, 0xb5, 0x6f, 0x49, 0xb0, 0x5a, 0xa6, 0xd6, 0xb1, 0x57, 0x87, + 0x0c, 0xfd, 0x85, 0xe7, 0x06, 0x48, 0x0d, 0xb7, 0x4f, 0x06, 0xed, 0x97, 0xfa, 0xbe, 0x0c, 0xf5, + 0x06, 0x38, 0x6a, 0x2c, 0xdf, 0x1f, 0x2c, 0x89, 0xdb, 0xbe, 0xdc, 0xf3, 0xd5, 0x14, 0xb7, 0xcd, + 0x85, 0x0e, 0x8a, 0xdf, 0xd0, 0xec, 0xad, 0x37, 0x34, 0xf7, 0x87, 0x1b, 0x7a, 0x30, 0xb6, 0xa1, + 0xcd, 0x91, 0x0d, 0x8d, 0xfa, 0xa5, 0x6d, 0x82, 0xcc, 0xc4, 0x61, 0xb8, 0x1d, 0xed, 0x8b, 0x04, + 0xd6, 0xcb, 0xd4, 0x3a, 0x44, 0xb0, 0xc6, 0xec, 0xd6, 0xbf, 0xb5, 0xb9, 0x68, 0x8c, 0xc9, 0x50, + 0x47, 0x64, 0x4c, 0xce, 0xa4, 0xa9, 0x60, 0x2b, 0x16, 0x88, 0xe4, 0x5c, 0x48, 0x60, 0x39, 0x12, + 0x7b, 0x14, 0xdc, 0x60, 0xf9, 0x39, 0x58, 0x80, 0x4d, 0x76, 0x82, 0x89, 0xcd, 0x3a, 0x42, 0x4b, + 0xbe, 0xe7, 0xab, 0x2b, 0xdc, 0xe3, 0x08, 0xd2, 0xa6, 0xea, 0x1b, 0xa4, 0xcb, 0x8f, 0xc1, 0x3c, + 0x7f, 0x2f, 0x04, 0xea, 0x52, 0xfb, 0x5b, 0x7a, 0xec, 0x0b, 0x4f, 0xe7, 0xad, 0x4b, 0xb3, 0x17, + 0xbe, 0x9a, 0x30, 0x45, 0x4a, 0x31, 0xdf, 0x97, 0x3b, 0x28, 0xd6, 0x57, 0x9c, 0x89, 0x59, 0x1c, + 0xcf, 0xd5, 0x32, 0x60, 0x63, 0xec, 0x28, 0x54, 0xb9, 0x7f, 0x39, 0x03, 0x66, 0xca, 0xd4, 0x92, + 0x09, 0x58, 0x99, 0x78, 0x23, 0xe5, 0xa6, 0x4c, 0x14, 0x73, 0x45, 0xb3, 0xfb, 0x37, 0xe7, 0x46, + 0xd7, 0xb9, 0x01, 0x96, 0xc6, 0xee, 0xe3, 0xce, 0xf4, 0x2a, 0xa3, 0xcc, 0xec, 0xde, 0x4d, 0x99, + 0x51, 0xb7, 0x33, 0x20, 0xc7, 0x3c, 0x9a, 0xf9, 0xe9, 0x75, 0x26, 0xd9, 0xd9, 0x87, 0xb7, 0x61, + 0x47, 0x9d, 0xdf, 0x81, 0xff, 0x47, 0x9e, 0xa2, 0x7b, 0xbf, 0x9b, 0x9d, 0xf3, 0xb2, 0xfa, 0xcd, + 0x78, 0x61, 0x9f, 0xec, 0xdc, 0xfb, 0xeb, 0xf3, 0x9c, 0x54, 0x2a, 0x5f, 0x74, 0x15, 0xe9, 0xb2, + 0xab, 0x48, 0x3f, 0xbb, 0x8a, 0xf4, 0xe9, 0x4a, 0x49, 0x5c, 0x5e, 0x29, 0x89, 0x1f, 0x57, 0x4a, + 0xe2, 0xed, 0x81, 0x65, 0xb3, 0x93, 0x66, 0x55, 0xaf, 0x61, 0xc7, 0x08, 0x4b, 0xef, 0x36, 0x60, + 0x95, 0x46, 0x91, 0x71, 0x36, 0xf4, 0xe5, 0x62, 0x1d, 0x0f, 0xd1, 0xea, 0x7c, 0xf0, 0xd9, 0x3a, + 0xf8, 0x15, 0x00, 0x00, 0xff, 0xff, 0xd9, 0xd0, 0x71, 0xf1, 0xb6, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/restaking/keeper/pool_restaking.go b/x/restaking/keeper/pool_restaking.go index 558913be1..22b0b5fd1 100644 --- a/x/restaking/keeper/pool_restaking.go +++ b/x/restaking/keeper/pool_restaking.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" @@ -57,66 +59,42 @@ func (k *Keeper) DelegateToPool(ctx sdk.Context, amount sdk.Coin, delegator stri return sdkmath.LegacyZeroDec(), err } - // In some situations, the exchange rate becomes invalid, e.g. if - // Pool loses all tokens due to slashing. In this case, - // make all future delegations invalid. - if pool.InvalidExRate() { - return sdkmath.LegacyZeroDec(), types.ErrDelegatorShareExRateInvalid - } - - // Get or create the delegation object and call the appropriate hook if present - delegation, found := k.GetPoolDelegation(ctx, pool.ID, delegator) - - if found { - // Delegation was found - err = k.BeforePoolDelegationSharesModified(ctx, pool.ID, delegator) - if err != nil { - return sdkmath.LegacyZeroDec(), err - } - } else { - // Delegation was not found - delegation = types.NewPoolDelegation(pool.ID, delegator, sdkmath.LegacyZeroDec()) - err = k.BeforePoolDelegationCreated(ctx, pool.ID, delegator) - if err != nil { - return sdkmath.LegacyZeroDec(), err - } - } - - // Convert the addresses to sdk.AccAddress - delegatorAddress, err := k.accountKeeper.AddressCodec().StringToBytes(delegator) - if err != nil { - return sdkmath.LegacyZeroDec(), err - } - poolAddress, err := k.accountKeeper.AddressCodec().StringToBytes(pool.Address) - if err != nil { - return sdkmath.LegacyZeroDec(), err - } - - // Get the bond amount - bondAmount := amount.Amount - - // Send the funds to the pool account - coins := sdk.NewCoins(sdk.NewCoin(pool.Denom, bondAmount)) - err = k.bankKeeper.SendCoins(ctx, delegatorAddress, poolAddress, coins) - if err != nil { - return sdkmath.LegacyDec{}, err - } - - // Calculate the new shares and add the tokens to the pool - _, newShares, err := k.AddPoolTokensAndShares(ctx, pool, bondAmount) - if err != nil { - return newShares, err - } - - // Update delegation - delegation.Shares = delegation.Shares.Add(newShares) - k.SavePoolDelegation(ctx, delegation) - - // Call the after-modification hook - err = k.AfterPoolDelegationModified(ctx, pool.ID, delegator) - if err != nil { - return newShares, err - } - - return newShares, nil + // Get the amount to be bonded + coins := sdk.NewCoins(sdk.NewCoin(pool.Denom, amount.Amount)) + + return k.PerformDelegation(ctx, types.DelegationData{ + Amount: coins, + Delegator: delegator, + Receiver: &pool, + GetDelegation: func(ctx sdk.Context, receiverID uint32, delegator string) (types.Delegation, bool) { + return k.GetPoolDelegation(ctx, receiverID, delegator) + }, + BuildDelegation: func(receiverID uint32, delegator string, shares sdkmath.LegacyDec) types.Delegation { + return types.NewPoolDelegation(receiverID, delegator, shares) + }, + UpdateDelegation: func(ctx sdk.Context, delegation types.Delegation) (newShares sdkmath.LegacyDec, err error) { + // Calculate the new shares and add the tokens to the pool + _, newShares, err = k.AddPoolTokensAndShares(ctx, pool, amount.Amount) + if err != nil { + return newShares, err + } + + // Update the delegation shares + poolDelegation, ok := delegation.(types.PoolDelegation) + if !ok { + return newShares, fmt.Errorf("invalid delegation type: %T", delegation) + } + poolDelegation.Shares = poolDelegation.Shares.Add(newShares) + + // Store the updated delegation + k.SavePoolDelegation(ctx, poolDelegation) + + return newShares, err + }, + Hooks: types.DelegationHooks{ + BeforeDelegationSharesModified: k.BeforePoolDelegationSharesModified, + BeforeDelegationCreated: k.BeforePoolDelegationCreated, + AfterDelegationModified: k.AfterPoolDelegationModified, + }, + }) } diff --git a/x/restaking/keeper/restaking.go b/x/restaking/keeper/restaking.go new file mode 100644 index 000000000..7a934cee5 --- /dev/null +++ b/x/restaking/keeper/restaking.go @@ -0,0 +1,75 @@ +package keeper + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +// PerformDelegation performs a delegation of the given amount from the delegator to the receiver. +// It sends the coins to the receiver address and updates the delegation object and returns the new +// shares of the delegation. +// NOTE: This is done so that if we implement other delegation types in the future we can have a single +// function that performs common operations for all of them. +func (k *Keeper) PerformDelegation(ctx sdk.Context, data types.DelegationData) (sdkmath.LegacyDec, error) { + // Get the data + receiver := data.Receiver + delegator := data.Delegator + hooks := data.Hooks + + // In some situations, the exchange rate becomes invalid, e.g. if + // the receives loses all tokens due to slashing. In this case, + // make all future delegations invalid. + if receiver.InvalidExRate() { + return sdkmath.LegacyZeroDec(), types.ErrDelegatorShareExRateInvalid + } + + // Get or create the delegation object and call the appropriate hook if present + delegation, found := data.GetDelegation(ctx, receiver.GetID(), delegator) + + if found { + // Delegation was found + err := hooks.BeforeDelegationSharesModified(ctx, receiver.GetID(), delegator) + if err != nil { + return sdkmath.LegacyZeroDec(), err + } + } else { + // Delegation was not found + delegation = data.BuildDelegation(receiver.GetID(), delegator, sdkmath.LegacyZeroDec()) + err := hooks.BeforeDelegationCreated(ctx, receiver.GetID(), delegator) + if err != nil { + return sdkmath.LegacyZeroDec(), err + } + } + + // Convert the addresses to sdk.AccAddress + delegatorAddress, err := k.accountKeeper.AddressCodec().StringToBytes(delegator) + if err != nil { + return sdkmath.LegacyZeroDec(), err + } + receiverAddress, err := k.accountKeeper.AddressCodec().StringToBytes(receiver.GetAddress()) + if err != nil { + return sdkmath.LegacyZeroDec(), err + } + + // Send the coins to the receiver address + err = k.bankKeeper.SendCoins(ctx, delegatorAddress, receiverAddress, data.Amount) + if err != nil { + return sdkmath.LegacyZeroDec(), err + } + + // Update the delegation + newShares, err := data.UpdateDelegation(ctx, delegation) + if err != nil { + return sdkmath.LegacyZeroDec(), err + } + + // Call the after-modification hook + err = hooks.AfterDelegationModified(ctx, receiver.GetID(), delegator) + if err != nil { + return newShares, err + } + + return newShares, nil +} diff --git a/x/restaking/types/delegation.go b/x/restaking/types/delegation.go new file mode 100644 index 000000000..7a94ee768 --- /dev/null +++ b/x/restaking/types/delegation.go @@ -0,0 +1,41 @@ +package types + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type DelegationReceiver interface { + GetID() uint32 + GetAddress() string + InvalidExRate() bool +} + +type DelegationGetter func(ctx sdk.Context, receiverID uint32, delegator string) (Delegation, bool) + +type DelegationBuilder func(receiverID uint32, delegator string, shares sdkmath.LegacyDec) Delegation + +type DelegationUpdater func(ctx sdk.Context, delegation Delegation) (newShares sdkmath.LegacyDec, err error) + +// Delegation is an interface that represents a delegation object. +type Delegation interface { + isDelegation() +} + +// DelegationHooks contains the hooks that can be called before and after a delegation is modified. +type DelegationHooks struct { + BeforeDelegationSharesModified func(ctx sdk.Context, receiverID uint32, delegator string) error + BeforeDelegationCreated func(ctx sdk.Context, receiverID uint32, delegator string) error + AfterDelegationModified func(ctx sdk.Context, receiverID uint32, delegator string) error +} + +// DelegationData contains the data required to perform a delegation. +type DelegationData struct { + Amount sdk.Coins + Delegator string + Receiver DelegationReceiver + GetDelegation DelegationGetter + BuildDelegation DelegationBuilder + UpdateDelegation DelegationUpdater + Hooks DelegationHooks +} diff --git a/x/restaking/types/models.go b/x/restaking/types/models.go index 47e7aed82..5272c421a 100644 --- a/x/restaking/types/models.go +++ b/x/restaking/types/models.go @@ -17,6 +17,10 @@ func NewPoolDelegation(poolID uint32, userAddress string, shares sdkmath.LegacyD } } +// isDelegation implements Delegation +func (d PoolDelegation) isDelegation() {} + +// Validate validates the pool delegation func (d PoolDelegation) Validate() error { if d.PoolID == 0 { return fmt.Errorf("invalid pool id") diff --git a/x/services/types/messages.pb.go b/x/services/types/messages.pb.go index 27434885f..d22bbd4ac 100644 --- a/x/services/types/messages.pb.go +++ b/x/services/types/messages.pb.go @@ -599,56 +599,55 @@ func init() { } var fileDescriptor_47bb30a8b53f4868 = []byte{ - // 771 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xbf, 0x6f, 0xda, 0x4c, - 0x18, 0xc6, 0x09, 0xe1, 0x13, 0x47, 0xc8, 0x8f, 0x13, 0xfa, 0x42, 0xfc, 0xe5, 0xb3, 0xdb, 0x4b, - 0x5b, 0xa5, 0x34, 0xe0, 0x40, 0xa5, 0xa8, 0x62, 0x0b, 0x4d, 0x87, 0x56, 0xa1, 0x8a, 0x1c, 0x65, - 0xe9, 0x82, 0x0c, 0x3e, 0x39, 0x56, 0xb0, 0x8d, 0x7c, 0x06, 0xca, 0x56, 0x75, 0xec, 0xd4, 0x7f, - 0xa1, 0x43, 0xa5, 0x8e, 0x19, 0xfa, 0x1f, 0x74, 0xc9, 0x98, 0x76, 0xea, 0x64, 0x55, 0x64, 0xc8, - 0x5c, 0xfe, 0x82, 0x8a, 0xf3, 0xd9, 0x80, 0x81, 0x96, 0xb4, 0x6a, 0x16, 0xc4, 0xfb, 0xbe, 0xcf, - 0xdd, 0xf3, 0x3e, 0xf7, 0xdc, 0xbd, 0x00, 0x36, 0x0d, 0xbd, 0x7e, 0xda, 0x69, 0x2b, 0x1d, 0x89, - 0x60, 0xbb, 0xa5, 0xd7, 0x30, 0x91, 0x5a, 0x79, 0xc9, 0xc0, 0x84, 0x28, 0x1a, 0x26, 0xb9, 0x86, - 0x6d, 0x39, 0x16, 0x4c, 0xf9, 0xa0, 0x9c, 0x0f, 0xca, 0xb5, 0xf2, 0xfc, 0xaa, 0x62, 0xe8, 0xa6, - 0x25, 0xd1, 0x4f, 0x0f, 0xc8, 0xaf, 0xd7, 0x2c, 0x62, 0x58, 0xa4, 0x42, 0x23, 0xc9, 0x0b, 0x58, - 0x49, 0xf0, 0x22, 0xa9, 0xaa, 0x10, 0x2c, 0xb5, 0xf2, 0x55, 0xec, 0x28, 0x79, 0xa9, 0x66, 0xe9, - 0xe6, 0x58, 0xdd, 0x3c, 0x0d, 0xea, 0xfd, 0x80, 0xd5, 0xd7, 0x58, 0xdd, 0x20, 0x1a, 0xed, 0x90, - 0x68, 0xac, 0x90, 0xd2, 0x2c, 0xcd, 0xf2, 0x08, 0xfb, 0xdf, 0x58, 0xf6, 0xf6, 0x44, 0x5d, 0x0d, - 0xc5, 0x56, 0x0c, 0xd6, 0x11, 0xfa, 0x34, 0x07, 0x56, 0xca, 0x44, 0x7b, 0x6c, 0x63, 0xc5, 0xc1, - 0x47, 0x1e, 0x0a, 0xee, 0x80, 0x18, 0xc1, 0xa6, 0x8a, 0xed, 0x34, 0x77, 0x8b, 0xdb, 0x8a, 0x97, - 0xd2, 0x5f, 0x3e, 0x66, 0x53, 0x4c, 0xc8, 0x9e, 0xaa, 0xda, 0x98, 0x90, 0x23, 0xc7, 0xd6, 0x4d, - 0x4d, 0x66, 0x38, 0xb8, 0x09, 0xa2, 0xa6, 0x62, 0xe0, 0xf4, 0x1c, 0xc5, 0x2f, 0xf7, 0x5c, 0x31, - 0xd1, 0x51, 0x8c, 0x7a, 0x11, 0xf5, 0xb3, 0x48, 0xa6, 0x45, 0xf8, 0x08, 0x24, 0x54, 0x4c, 0x6a, - 0xb6, 0xde, 0x70, 0x74, 0xcb, 0x4c, 0xcf, 0x53, 0xec, 0xbf, 0x3d, 0x57, 0x84, 0x1e, 0x76, 0xa8, - 0x88, 0xe4, 0x61, 0x28, 0xdc, 0x06, 0xff, 0xb4, 0x71, 0x95, 0xe8, 0x0e, 0x4e, 0x47, 0xe9, 0x2a, - 0xd8, 0x73, 0xc5, 0x25, 0x6f, 0x15, 0x2b, 0x20, 0xd9, 0x87, 0xc0, 0x27, 0x20, 0xd1, 0xd0, 0x6b, - 0x4e, 0xd3, 0xc6, 0x95, 0xa6, 0x5d, 0x4f, 0x2f, 0xd0, 0x15, 0x77, 0xba, 0xae, 0x08, 0x0e, 0xbd, - 0xf4, 0xb1, 0x7c, 0x30, 0x60, 0x1d, 0x82, 0x22, 0x19, 0xb0, 0xe8, 0xd8, 0xae, 0x17, 0xef, 0xbf, - 0xbe, 0x3a, 0xcb, 0x30, 0x81, 0x6f, 0xae, 0xce, 0x32, 0xeb, 0xc1, 0x69, 0x86, 0x0f, 0x0c, 0xc9, - 0x20, 0x1d, 0xce, 0xc9, 0x98, 0x34, 0x2c, 0x93, 0x60, 0xb8, 0x0b, 0x96, 0x4c, 0xdc, 0xae, 0x30, - 0x07, 0x2a, 0xba, 0x4a, 0x0f, 0x35, 0x59, 0x5a, 0xe9, 0xba, 0xe2, 0xe2, 0x73, 0xdc, 0x66, 0xf8, - 0xa7, 0xfb, 0xf2, 0xa2, 0x39, 0x88, 0x54, 0xf4, 0xdd, 0x73, 0xe6, 0xb8, 0xa1, 0xfe, 0x91, 0x33, - 0xdb, 0x00, 0x0c, 0x51, 0xcf, 0x51, 0xea, 0x64, 0xd7, 0x15, 0xe3, 0x03, 0xde, 0x38, 0xf1, 0x49, - 0x03, 0x1f, 0xe7, 0xaf, 0xe1, 0x63, 0xf4, 0xb7, 0x7c, 0x5c, 0xb8, 0xb6, 0x8f, 0xb1, 0xbf, 0xe1, - 0xe3, 0xc8, 0xf1, 0x22, 0x9e, 0xfa, 0x38, 0x92, 0xf3, 0x7d, 0x44, 0xef, 0x38, 0x00, 0xcb, 0x44, - 0xdb, 0xab, 0x39, 0x7a, 0xeb, 0xe6, 0x1c, 0x29, 0x3e, 0x08, 0x75, 0xff, 0xdf, 0x70, 0xf7, 0xa1, - 0x66, 0xd0, 0x06, 0xe0, 0xc7, 0xb3, 0x81, 0x82, 0xf7, 0x1c, 0x48, 0x95, 0x89, 0xb6, 0x8f, 0x95, - 0x1b, 0xd6, 0x90, 0x0d, 0x69, 0xf8, 0x7f, 0x58, 0xc3, 0x58, 0x3b, 0x48, 0x00, 0x1b, 0x93, 0xf2, - 0x81, 0x8e, 0xcf, 0x1c, 0x58, 0x0e, 0x6c, 0x3a, 0xa4, 0xd3, 0x0c, 0x3e, 0x03, 0x71, 0xa5, 0xe9, - 0x9c, 0x58, 0xb6, 0xee, 0x74, 0x98, 0x8a, 0xed, 0x9e, 0x2b, 0xae, 0x78, 0x77, 0x23, 0x28, 0xa1, - 0xa9, 0xca, 0x06, 0xcb, 0x61, 0x11, 0xc4, 0xbc, 0x19, 0x49, 0x85, 0x25, 0x0a, 0x1b, 0xb9, 0x49, - 0xa3, 0x3f, 0xe7, 0x31, 0x97, 0xa2, 0xe7, 0xae, 0x18, 0x91, 0xd9, 0x8a, 0xe2, 0x6e, 0x5f, 0xea, - 0x60, 0xaf, 0xbe, 0xda, 0xc1, 0xaf, 0xcb, 0xcb, 0xc1, 0x1c, 0x0e, 0xf5, 0x8f, 0xd6, 0xc1, 0x5a, - 0x28, 0xe5, 0xcb, 0x2d, 0x7c, 0x88, 0x82, 0xf9, 0x32, 0xd1, 0xa0, 0x06, 0x92, 0xa3, 0x63, 0xfa, - 0xde, 0xe4, 0xbe, 0xc2, 0x93, 0x88, 0xcf, 0xcd, 0x86, 0x0b, 0x26, 0x96, 0x06, 0x92, 0xa3, 0x53, - 0x67, 0x3a, 0xd1, 0x08, 0xee, 0x27, 0x44, 0x13, 0x9f, 0x14, 0x34, 0xc0, 0x72, 0xf8, 0x39, 0x6d, - 0x4d, 0xdd, 0x22, 0x84, 0xe4, 0x77, 0x66, 0x45, 0x06, 0x74, 0x04, 0xac, 0x8e, 0xdf, 0xfd, 0xcc, - 0xd4, 0x6d, 0xc6, 0xb0, 0x7c, 0x61, 0x76, 0x6c, 0x40, 0xaa, 0x82, 0xc5, 0x91, 0x8b, 0x7a, 0xf7, - 0x17, 0x67, 0xe4, 0xc1, 0xf8, 0xec, 0x4c, 0x30, 0x9f, 0x85, 0x5f, 0x78, 0x75, 0x75, 0x96, 0xe1, - 0x4a, 0x07, 0xe7, 0x5d, 0x81, 0xbb, 0xe8, 0x0a, 0xdc, 0xb7, 0xae, 0xc0, 0xbd, 0xbd, 0x14, 0x22, - 0x17, 0x97, 0x42, 0xe4, 0xeb, 0xa5, 0x10, 0x79, 0x51, 0xd0, 0x74, 0xe7, 0xa4, 0x59, 0xcd, 0xd5, - 0x2c, 0x43, 0xf2, 0x77, 0xce, 0xd6, 0x95, 0x2a, 0x91, 0x26, 0xdd, 0x4e, 0xa7, 0xd3, 0xc0, 0xa4, - 0x1a, 0xa3, 0x7f, 0x11, 0x1e, 0xfe, 0x08, 0x00, 0x00, 0xff, 0xff, 0x4f, 0xc8, 0x35, 0x03, 0x1f, - 0x09, 0x00, 0x00, + // 768 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x3f, 0x6f, 0xd3, 0x5e, + 0x14, 0x8d, 0xdb, 0x34, 0x3f, 0xe5, 0xa5, 0xe9, 0x1f, 0x2b, 0xfa, 0xd5, 0x35, 0xc5, 0x06, 0x17, + 0x50, 0x09, 0x4d, 0xdc, 0x04, 0x09, 0xa1, 0x6c, 0x0d, 0x65, 0x00, 0x35, 0xa8, 0x72, 0xd5, 0x85, + 0x25, 0x72, 0xe2, 0x27, 0xd7, 0x6a, 0xfc, 0x47, 0x7e, 0x4e, 0x42, 0x36, 0xc4, 0xc8, 0xc4, 0x57, + 0x60, 0x40, 0x62, 0xec, 0xc0, 0x37, 0x40, 0x42, 0x1d, 0x2b, 0x26, 0x26, 0x0b, 0xa5, 0x43, 0x67, + 0xf2, 0x09, 0x50, 0xde, 0x7b, 0x76, 0x12, 0x27, 0x81, 0x14, 0x44, 0x97, 0xaa, 0xf7, 0xde, 0x73, + 0xdf, 0xb9, 0xe7, 0x9d, 0x97, 0x2b, 0x83, 0x4d, 0xd3, 0x68, 0x9c, 0x74, 0xda, 0x6a, 0x47, 0x46, + 0xd0, 0x6d, 0x19, 0x75, 0x88, 0xe4, 0x56, 0x41, 0x36, 0x21, 0x42, 0xaa, 0x0e, 0x51, 0xde, 0x71, + 0x6d, 0xcf, 0x66, 0x33, 0x01, 0x28, 0x1f, 0x80, 0xf2, 0xad, 0x02, 0xbf, 0xaa, 0x9a, 0x86, 0x65, + 0xcb, 0xf8, 0x2f, 0x01, 0xf2, 0xeb, 0x75, 0x1b, 0x99, 0x36, 0xaa, 0xe2, 0x48, 0x26, 0x01, 0x2d, + 0x09, 0x24, 0x92, 0x6b, 0x2a, 0x82, 0x72, 0xab, 0x50, 0x83, 0x9e, 0x5a, 0x90, 0xeb, 0xb6, 0x61, + 0x8d, 0xd5, 0xad, 0x93, 0xb0, 0xde, 0x0f, 0x68, 0x7d, 0x8d, 0xd6, 0x4d, 0xa4, 0xe3, 0x09, 0x91, + 0x4e, 0x0b, 0x19, 0xdd, 0xd6, 0x6d, 0x42, 0xd8, 0xff, 0x8f, 0x66, 0x6f, 0x4f, 0xd4, 0xe5, 0xa8, + 0xae, 0x6a, 0xd2, 0x89, 0xa4, 0xcf, 0x73, 0x60, 0xa5, 0x82, 0xf4, 0x27, 0x2e, 0x54, 0x3d, 0x78, + 0x48, 0x50, 0xec, 0x0e, 0x48, 0x20, 0x68, 0x69, 0xd0, 0xe5, 0x98, 0x5b, 0xcc, 0x56, 0xb2, 0xcc, + 0x7d, 0xfd, 0x94, 0xcb, 0x50, 0x21, 0xbb, 0x9a, 0xe6, 0x42, 0x84, 0x0e, 0x3d, 0xd7, 0xb0, 0x74, + 0x85, 0xe2, 0xd8, 0x4d, 0x10, 0xb7, 0x54, 0x13, 0x72, 0x73, 0x18, 0xbf, 0xdc, 0xf3, 0xc5, 0x54, + 0x47, 0x35, 0x1b, 0x25, 0xa9, 0x9f, 0x95, 0x14, 0x5c, 0x64, 0x1f, 0x83, 0x94, 0x06, 0x51, 0xdd, + 0x35, 0x1c, 0xcf, 0xb0, 0x2d, 0x6e, 0x1e, 0x63, 0xff, 0xef, 0xf9, 0x22, 0x4b, 0xb0, 0x43, 0x45, + 0x49, 0x19, 0x86, 0xb2, 0xdb, 0xe0, 0xbf, 0x36, 0xac, 0x21, 0xc3, 0x83, 0x5c, 0x1c, 0x77, 0xb1, + 0x3d, 0x5f, 0x5c, 0x22, 0x5d, 0xb4, 0x20, 0x29, 0x01, 0x84, 0x7d, 0x0a, 0x52, 0x8e, 0x51, 0xf7, + 0x9a, 0x2e, 0xac, 0x36, 0xdd, 0x06, 0xb7, 0x80, 0x3b, 0xee, 0x74, 0x7d, 0x11, 0x1c, 0x90, 0xf4, + 0x91, 0xb2, 0x3f, 0x60, 0x1d, 0x82, 0x4a, 0x0a, 0xa0, 0xd1, 0x91, 0xdb, 0x28, 0xdd, 0x7f, 0x73, + 0x79, 0x9a, 0xa5, 0x02, 0xdf, 0x5e, 0x9e, 0x66, 0xd7, 0xc3, 0x4b, 0x8c, 0x5e, 0x98, 0xa4, 0x00, + 0x2e, 0x9a, 0x53, 0x20, 0x72, 0x6c, 0x0b, 0x41, 0xf6, 0x11, 0x58, 0xb2, 0x60, 0xbb, 0x4a, 0x9b, + 0xab, 0x86, 0x86, 0x2f, 0x35, 0x5d, 0x5e, 0xe9, 0xfa, 0xe2, 0xe2, 0x0b, 0xd8, 0xa6, 0xf8, 0x67, + 0x7b, 0xca, 0xa2, 0x35, 0x88, 0x34, 0xe9, 0x07, 0x71, 0xe6, 0xc8, 0xd1, 0xfe, 0xca, 0x99, 0x6d, + 0x00, 0x86, 0xa8, 0xe7, 0x30, 0x75, 0xba, 0xeb, 0x8b, 0xc9, 0x01, 0x6f, 0x12, 0x05, 0xa4, 0xa1, + 0x8f, 0xf3, 0x57, 0xf0, 0x31, 0xfe, 0x47, 0x3e, 0x2e, 0x5c, 0xd9, 0xc7, 0xc4, 0xbf, 0xf0, 0x71, + 0xe4, 0x7a, 0x25, 0x1e, 0xfb, 0x38, 0x92, 0x0b, 0x7c, 0x94, 0xde, 0x33, 0x80, 0xad, 0x20, 0x7d, + 0xb7, 0xee, 0x19, 0xad, 0xeb, 0x73, 0xa4, 0xf4, 0x20, 0x32, 0xfd, 0x8d, 0xe1, 0xe9, 0x23, 0xc3, + 0x48, 0x1b, 0x80, 0x1f, 0xcf, 0x86, 0x0a, 0x3e, 0x30, 0x20, 0x53, 0x41, 0xfa, 0x1e, 0x54, 0xaf, + 0x59, 0x43, 0x2e, 0xa2, 0xe1, 0xe6, 0xb0, 0x86, 0xb1, 0x71, 0x24, 0x01, 0x6c, 0x4c, 0xca, 0x87, + 0x3a, 0xbe, 0x30, 0x60, 0x39, 0xb4, 0xe9, 0x00, 0x6f, 0x33, 0xf6, 0x39, 0x48, 0xaa, 0x4d, 0xef, + 0xd8, 0x76, 0x0d, 0xaf, 0x43, 0x55, 0x6c, 0xf7, 0x7c, 0x71, 0x85, 0xbc, 0x8d, 0xb0, 0x24, 0x4d, + 0x55, 0x36, 0x68, 0x67, 0x4b, 0x20, 0x41, 0x76, 0x24, 0x16, 0x96, 0x2a, 0x6e, 0xe4, 0x27, 0xad, + 0xfe, 0x3c, 0x61, 0x2e, 0xc7, 0xcf, 0x7c, 0x31, 0xa6, 0xd0, 0x0e, 0x62, 0xd7, 0xe0, 0xac, 0xbe, + 0x5a, 0x6e, 0xfc, 0xbd, 0x91, 0x56, 0x69, 0x1d, 0xac, 0x45, 0x52, 0x81, 0xc6, 0xe2, 0xc7, 0x38, + 0x98, 0xaf, 0x20, 0x9d, 0xd5, 0x41, 0x7a, 0x74, 0x37, 0xdf, 0x9b, 0x3c, 0x4c, 0x74, 0xfd, 0xf0, + 0xf9, 0xd9, 0x70, 0xe1, 0x9a, 0xd2, 0x41, 0x7a, 0x74, 0xd5, 0x4c, 0x27, 0x1a, 0xc1, 0xfd, 0x82, + 0x68, 0xe2, 0xef, 0x88, 0x35, 0xc1, 0x72, 0xf4, 0x37, 0xb4, 0x35, 0xf5, 0x88, 0x08, 0x92, 0xdf, + 0x99, 0x15, 0x19, 0xd2, 0x21, 0xb0, 0x3a, 0xfe, 0xe0, 0xb3, 0x53, 0x8f, 0x19, 0xc3, 0xf2, 0xc5, + 0xd9, 0xb1, 0x21, 0xa9, 0x06, 0x16, 0x47, 0x5e, 0xe7, 0xdd, 0xdf, 0xdc, 0x11, 0x81, 0xf1, 0xb9, + 0x99, 0x60, 0x01, 0x0b, 0xbf, 0xf0, 0xfa, 0xf2, 0x34, 0xcb, 0x94, 0xf7, 0xcf, 0xba, 0x02, 0x73, + 0xde, 0x15, 0x98, 0xef, 0x5d, 0x81, 0x79, 0x77, 0x21, 0xc4, 0xce, 0x2f, 0x84, 0xd8, 0xb7, 0x0b, + 0x21, 0xf6, 0xb2, 0xa8, 0x1b, 0xde, 0x71, 0xb3, 0x96, 0xaf, 0xdb, 0xa6, 0x1c, 0x9c, 0x9c, 0x6b, + 0xa8, 0x35, 0x14, 0x46, 0xf2, 0xab, 0xc1, 0xa7, 0x81, 0xd7, 0x71, 0x20, 0xaa, 0x25, 0xf0, 0x77, + 0xc1, 0xc3, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa5, 0x1c, 0x08, 0x5f, 0x14, 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/services/types/models.pb.go b/x/services/types/models.pb.go index 72714dfec..deda66fd1 100644 --- a/x/services/types/models.pb.go +++ b/x/services/types/models.pb.go @@ -77,7 +77,7 @@ type Service struct { // Website is the website of the service Website string `protobuf:"bytes,6,opt,name=website,proto3" json:"website,omitempty"` // PictureURL is the URL of the picture of the service - PictureURL string `protobuf:"bytes,7,opt,name=pictureURL,proto3" json:"pictureURL,omitempty"` + PictureURL string `protobuf:"bytes,7,opt,name=picture_url,json=pictureUrl,proto3" json:"picture_url,omitempty"` // Address is the address of the account associated with the service. // This will be used in order to store all the tokens that are delegated to // this service by various users. @@ -181,34 +181,35 @@ func init() { func init() { proto.RegisterFile("milkyway/services/v1/models.proto", fileDescriptor_4411e719afee9a70) } var fileDescriptor_4411e719afee9a70 = []byte{ - // 426 bytes of a gzipped FileDescriptorProto + // 443 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0x80, 0xbd, 0x6e, 0x9a, 0xc0, 0xa0, 0xa2, 0x68, 0x15, 0xca, 0xd6, 0x48, 0x4b, 0x80, 0x4b, - 0x84, 0x54, 0x5b, 0x0d, 0x47, 0x4e, 0xf9, 0x31, 0x92, 0xa5, 0xaa, 0x42, 0x76, 0xd2, 0x03, 0x97, - 0xc8, 0x3f, 0x2b, 0xb3, 0x22, 0xf6, 0x5a, 0xde, 0x4d, 0x4a, 0xde, 0x00, 0x6e, 0xbc, 0x03, 0x6f, - 0x80, 0x78, 0x08, 0x8e, 0x15, 0x27, 0x4e, 0x08, 0x39, 0x2f, 0x82, 0xea, 0x1f, 0x08, 0x11, 0x52, - 0x6f, 0x33, 0xf3, 0x7d, 0x3b, 0x3b, 0xab, 0x1d, 0x78, 0x92, 0xf0, 0xe5, 0xbb, 0xcd, 0x95, 0xbf, - 0xb1, 0x24, 0xcb, 0xd7, 0x3c, 0x64, 0xd2, 0x5a, 0x9f, 0x59, 0x89, 0x88, 0xd8, 0x52, 0x9a, 0x59, - 0x2e, 0x94, 0xc0, 0xbd, 0x46, 0x31, 0x1b, 0xc5, 0x5c, 0x9f, 0x19, 0xbd, 0x58, 0xc4, 0xa2, 0x14, - 0xac, 0x9b, 0xa8, 0x72, 0x8d, 0x93, 0x50, 0xc8, 0x44, 0xc8, 0x45, 0x05, 0xaa, 0xa4, 0x42, 0x4f, - 0xbf, 0xe8, 0xd0, 0xf1, 0xaa, 0x06, 0xf8, 0x18, 0x74, 0x1e, 0x11, 0xd4, 0x47, 0x83, 0xa3, 0x71, - 0xbb, 0xf8, 0xf9, 0x58, 0x77, 0xa6, 0xae, 0xce, 0x23, 0xfc, 0x12, 0xda, 0x52, 0xf9, 0x6a, 0x25, - 0x89, 0xde, 0x47, 0x83, 0xfb, 0xc3, 0x67, 0xe6, 0xff, 0xee, 0x36, 0xeb, 0x36, 0x5e, 0xa9, 0xba, - 0xf5, 0x11, 0x6c, 0xc2, 0xa1, 0x1f, 0x25, 0x3c, 0x25, 0x07, 0x7d, 0x34, 0xb8, 0x3b, 0x26, 0xdf, - 0xbf, 0x9e, 0xf6, 0xea, 0x09, 0x46, 0x51, 0x94, 0x33, 0x29, 0x3d, 0x95, 0xf3, 0x34, 0x76, 0x2b, - 0x0d, 0x63, 0x68, 0xa5, 0x7e, 0xc2, 0x48, 0xeb, 0x46, 0x77, 0xcb, 0x18, 0xf7, 0xe1, 0x5e, 0xc4, - 0x64, 0x98, 0xf3, 0x4c, 0x71, 0x91, 0x92, 0xc3, 0x12, 0xed, 0x96, 0x30, 0x81, 0xce, 0x15, 0x0b, - 0x24, 0x57, 0x8c, 0xb4, 0x4b, 0xda, 0xa4, 0x98, 0x02, 0x64, 0x3c, 0x54, 0xab, 0x9c, 0xcd, 0xdd, - 0x73, 0xd2, 0x29, 0xe1, 0x4e, 0x05, 0x0f, 0xa1, 0xe3, 0x57, 0x73, 0x90, 0x3b, 0xb7, 0x4c, 0xd8, - 0x88, 0xcf, 0x3f, 0x22, 0x38, 0xfa, 0xe7, 0xb5, 0x98, 0x82, 0xe1, 0xd9, 0xee, 0xa5, 0x33, 0xb1, - 0x17, 0xde, 0x6c, 0x34, 0x9b, 0x7b, 0x8b, 0xf9, 0x85, 0xf7, 0xda, 0x9e, 0x38, 0xaf, 0x1c, 0x7b, - 0xda, 0xd5, 0xb0, 0x01, 0xc7, 0x7b, 0x7c, 0xe2, 0xda, 0xa3, 0x99, 0x3d, 0xed, 0x22, 0x7c, 0x02, - 0x0f, 0xf6, 0xd8, 0x68, 0x32, 0x73, 0x2e, 0xed, 0xae, 0x8e, 0x1f, 0xc1, 0xc3, 0x3d, 0xe4, 0x5c, - 0xd4, 0xf0, 0xc0, 0x68, 0x7d, 0xf8, 0x4c, 0xb5, 0xf1, 0xf9, 0xb7, 0x82, 0xa2, 0xeb, 0x82, 0xa2, - 0x5f, 0x05, 0x45, 0x9f, 0xb6, 0x54, 0xbb, 0xde, 0x52, 0xed, 0xc7, 0x96, 0x6a, 0x6f, 0x86, 0x31, - 0x57, 0x6f, 0x57, 0x81, 0x19, 0x8a, 0xc4, 0x6a, 0x3e, 0xec, 0x74, 0xe9, 0x07, 0xf2, 0x4f, 0x66, - 0xbd, 0xff, 0xbb, 0x5f, 0x6a, 0x93, 0x31, 0x19, 0xb4, 0xcb, 0xad, 0x78, 0xf1, 0x3b, 0x00, 0x00, - 0xff, 0xff, 0x40, 0x5a, 0x2a, 0x1e, 0x81, 0x02, 0x00, 0x00, + 0x10, 0xc7, 0xbd, 0x6e, 0x9a, 0xc0, 0x54, 0xad, 0xa2, 0x55, 0x28, 0x5b, 0x23, 0xb9, 0x01, 0x2e, + 0x11, 0x52, 0x6d, 0x35, 0x1c, 0x39, 0xe5, 0xc3, 0x48, 0x96, 0xaa, 0xaa, 0xb2, 0x93, 0x1e, 0xb8, + 0x44, 0x8e, 0xbd, 0x0a, 0x2b, 0xec, 0x6c, 0xb4, 0xbb, 0x49, 0xc9, 0x1b, 0xc0, 0x8d, 0x77, 0xe0, + 0x15, 0x78, 0x03, 0x2e, 0x1c, 0x2b, 0x4e, 0x9c, 0x2a, 0xe4, 0xbc, 0x08, 0x8a, 0xd7, 0xe6, 0x23, + 0x42, 0xea, 0x6d, 0x66, 0x7e, 0x3f, 0x8f, 0xff, 0x96, 0x07, 0x9e, 0x66, 0x2c, 0x7d, 0xb7, 0xbe, + 0x89, 0xd6, 0xae, 0xa4, 0x62, 0xc5, 0x62, 0x2a, 0xdd, 0xd5, 0xb9, 0x9b, 0xf1, 0x84, 0xa6, 0xd2, + 0x59, 0x08, 0xae, 0x38, 0x6e, 0x55, 0x8a, 0x53, 0x29, 0xce, 0xea, 0xdc, 0x6a, 0xcd, 0xf8, 0x8c, + 0x17, 0x82, 0xbb, 0xad, 0xb4, 0x6b, 0x9d, 0xc4, 0x5c, 0x66, 0x5c, 0x4e, 0x34, 0xd0, 0x8d, 0x46, + 0xcf, 0xbe, 0x9a, 0xd0, 0x08, 0xf5, 0x02, 0x7c, 0x0c, 0x26, 0x4b, 0x08, 0x6a, 0xa3, 0xce, 0x61, + 0xbf, 0x9e, 0xdf, 0x9d, 0x9a, 0xfe, 0x30, 0x30, 0x59, 0x82, 0x5f, 0x41, 0x5d, 0xaa, 0x48, 0x2d, + 0x25, 0x31, 0xdb, 0xa8, 0x73, 0xd4, 0x7d, 0xee, 0xfc, 0xef, 0xdd, 0x4e, 0xb9, 0x26, 0x2c, 0xd4, + 0xa0, 0x7c, 0x04, 0x3b, 0xb0, 0x1f, 0x25, 0x19, 0x9b, 0x93, 0xbd, 0x36, 0xea, 0x3c, 0xec, 0x93, + 0xef, 0x5f, 0xce, 0x5a, 0x65, 0x82, 0x5e, 0x92, 0x08, 0x2a, 0x65, 0xa8, 0x04, 0x9b, 0xcf, 0x02, + 0xad, 0x61, 0x0c, 0xb5, 0x79, 0x94, 0x51, 0x52, 0xdb, 0xea, 0x41, 0x51, 0xe3, 0x36, 0x1c, 0x24, + 0x54, 0xc6, 0x82, 0x2d, 0x14, 0xe3, 0x73, 0xb2, 0x5f, 0xa0, 0xbf, 0x47, 0x98, 0x40, 0xe3, 0x86, + 0x4e, 0x25, 0x53, 0x94, 0xd4, 0x0b, 0x5a, 0xb5, 0xd8, 0x85, 0x83, 0x05, 0x8b, 0xd5, 0x52, 0xd0, + 0xc9, 0x52, 0xa4, 0xa4, 0x51, 0xa4, 0x38, 0xca, 0xef, 0x4e, 0xe1, 0x4a, 0x8f, 0xc7, 0xc1, 0x45, + 0x00, 0xa5, 0x32, 0x16, 0x29, 0xee, 0x42, 0x23, 0xd2, 0xc1, 0xc8, 0x83, 0x7b, 0x22, 0x57, 0xe2, + 0x8b, 0x8f, 0x08, 0x0e, 0xff, 0xf9, 0x7c, 0x6c, 0x83, 0x15, 0x7a, 0xc1, 0xb5, 0x3f, 0xf0, 0x26, + 0xe1, 0xa8, 0x37, 0x1a, 0x87, 0x93, 0xf1, 0x65, 0x78, 0xe5, 0x0d, 0xfc, 0xd7, 0xbe, 0x37, 0x6c, + 0x1a, 0xd8, 0x82, 0xe3, 0x1d, 0x3e, 0x08, 0xbc, 0xde, 0xc8, 0x1b, 0x36, 0x11, 0x3e, 0x81, 0x47, + 0x3b, 0xac, 0x37, 0x18, 0xf9, 0xd7, 0x5e, 0xd3, 0xc4, 0x4f, 0xe0, 0xf1, 0x0e, 0xf2, 0x2f, 0x4b, + 0xb8, 0x67, 0xd5, 0x3e, 0x7c, 0xb6, 0x8d, 0xfe, 0xc5, 0xb7, 0xdc, 0x46, 0xb7, 0xb9, 0x8d, 0x7e, + 0xe6, 0x36, 0xfa, 0xb4, 0xb1, 0x8d, 0xdb, 0x8d, 0x6d, 0xfc, 0xd8, 0xd8, 0xc6, 0x9b, 0xee, 0x8c, + 0xa9, 0xb7, 0xcb, 0xa9, 0x13, 0xf3, 0xcc, 0xad, 0xfe, 0xe0, 0x59, 0x1a, 0x4d, 0xe5, 0xef, 0xce, + 0x7d, 0xff, 0xe7, 0xe0, 0xd4, 0x7a, 0x41, 0xe5, 0xb4, 0x5e, 0x9c, 0xc9, 0xcb, 0x5f, 0x01, 0x00, + 0x00, 0xff, 0xff, 0x1a, 0xcb, 0x5b, 0x2b, 0x92, 0x02, 0x00, 0x00, } func (m *Service) Marshal() (dAtA []byte, err error) { From 216471862fb27d4ef5d81cf862c1597921d94d53 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 11:18:53 -0500 Subject: [PATCH 14/37] feat: add msg server --- x/restaking/keeper/msg_server.go | 85 ++++++++++++++++++++++++++++++++ x/restaking/keeper/params.go | 25 ++++++++++ x/restaking/types/events.go | 8 +++ 3 files changed, 118 insertions(+) create mode 100644 x/restaking/keeper/msg_server.go create mode 100644 x/restaking/keeper/params.go create mode 100644 x/restaking/types/events.go diff --git a/x/restaking/keeper/msg_server.go b/x/restaking/keeper/msg_server.go new file mode 100644 index 000000000..f0ace2bf1 --- /dev/null +++ b/x/restaking/keeper/msg_server.go @@ -0,0 +1,85 @@ +package keeper + +import ( + "context" + + "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/hashicorp/go-metrics" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +var ( + _ types.MsgServer = msgServer{} +) + +type msgServer struct { + *Keeper +} + +func NewMsgServerImpl(keeper *Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +// PoolRestake defines the rpc method for Msg/PoolRestake +func (k msgServer) PoolRestake(goCtx context.Context, msg *types.MsgJoinRestakingPool) (*types.MsgJoinRestakingPoolResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + newShares, err := k.Keeper.DelegateToPool(ctx, msg.Amount, msg.Delegator) + if err != nil { + return nil, err + } + + if msg.Amount.Amount.IsInt64() { + defer func() { + telemetry.IncrCounter(1, types.ModuleName, "pool restake") + telemetry.SetGaugeWithLabels( + []string{"tx", "msg", sdk.MsgTypeURL(msg)}, + float32(msg.Amount.Amount.Int64()), + []metrics.Label{telemetry.NewLabel("denom", msg.Amount.Denom)}, + ) + }() + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + sdkCtx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypePoolRestake, + sdk.NewAttribute(types.AttributeKeyDelegator, msg.Delegator), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(types.AttributeKeyNewShares, newShares.String()), + ), + }) + + return &types.MsgJoinRestakingPoolResponse{}, nil +} + +// OperatorRestake defines the rpc method for Msg/OperatorRestake +func (k msgServer) OperatorRestake(goCtx context.Context, msg *types.MsgDelegateOperator) (*types.MsgDelegateOperatorResponse, error) { + //TODO implement me + panic("implement me") +} + +// ServiceRestake defines the rpc method for Msg/ServiceRestake +func (k msgServer) ServiceRestake(goCtx context.Context, msg *types.MsgDelegateService) (*types.MsgDelegateServiceResponse, error) { + //TODO implement me + panic("implement me") +} + +// UpdateParams defines the rpc method for Msg/UpdateParams +func (k msgServer) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { + // Check the authority + authority := k.authority + if authority != msg.Authority { + return nil, errors.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", authority, msg.Authority) + } + + // Update the params + ctx := sdk.UnwrapSDKContext(goCtx) + k.SetParams(ctx, msg.Params) + + return &types.MsgUpdateParamsResponse{}, nil +} diff --git a/x/restaking/keeper/params.go b/x/restaking/keeper/params.go new file mode 100644 index 000000000..b373b730a --- /dev/null +++ b/x/restaking/keeper/params.go @@ -0,0 +1,25 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +// SetParams sets module parameters +func (k *Keeper) SetParams(ctx sdk.Context, params types.Params) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshal(¶ms) + store.Set(types.ParamsKey, bz) +} + +// GetParams returns the module parameters +func (k *Keeper) GetParams(ctx sdk.Context) (p types.Params) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ParamsKey) + if bz == nil { + return p + } + k.cdc.MustUnmarshal(bz, &p) + return p +} diff --git a/x/restaking/types/events.go b/x/restaking/types/events.go new file mode 100644 index 000000000..acb8cdf73 --- /dev/null +++ b/x/restaking/types/events.go @@ -0,0 +1,8 @@ +package types + +const ( + EventTypePoolRestake = "pool_restake" + + AttributeKeyDelegator = "delegator" + AttributeKeyNewShares = "new_shares" +) From 67c82274e0db9edcf2059bc8126e526b793202b9 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 12:24:04 -0500 Subject: [PATCH 15/37] feat: add operator restaking --- proto/milkyway/operators/v1/models.proto | 13 ++ proto/milkyway/restaking/v1/models.proto | 6 +- proto/milkyway/services/v1/models.proto | 1 - x/operators/types/errors.go | 1 + x/operators/types/models.go | 53 ++++++ x/operators/types/models.pb.go | 192 ++++++++++++++++++---- x/restaking/keeper/common_test.go | 16 ++ x/restaking/keeper/hooks.go | 24 +++ x/restaking/keeper/keeper.go | 15 +- x/restaking/keeper/operator_restaking.go | 96 +++++++++++ x/restaking/keeper/pool_restaking.go | 18 +- x/restaking/keeper/pool_restaking_test.go | 8 +- x/restaking/keeper/restaking.go | 19 +-- x/restaking/types/delegation.go | 5 +- x/restaking/types/expected_keepers.go | 1 + x/restaking/types/genesis_test.go | 13 +- x/restaking/types/hooks.go | 11 ++ x/restaking/types/keys.go | 43 +++++ x/restaking/types/models.go | 34 +++- x/restaking/types/models.pb.go | 102 +++++++----- 20 files changed, 555 insertions(+), 116 deletions(-) create mode 100644 x/restaking/keeper/operator_restaking.go diff --git a/proto/milkyway/operators/v1/models.proto b/proto/milkyway/operators/v1/models.proto index 905dfc217..53741c910 100644 --- a/proto/milkyway/operators/v1/models.proto +++ b/proto/milkyway/operators/v1/models.proto @@ -3,6 +3,7 @@ package milkyway.operators.v1; import "gogoproto/gogo.proto"; import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; option go_package = "github.com/milkyway-labs/milkyway/x/operators/types"; @@ -49,4 +50,16 @@ message Operator { // Address is the address of the account associated to the operator. // This will be used to store tokens that are delegated to this operator. string address = 7 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // Tokens define the delegated tokens. + repeated cosmos.base.v1beta1.Coin tokens = 8 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.nullable) = false + ]; + + // DelegatorShares define the total shares issued to an operator's delegators. + repeated cosmos.base.v1beta1.DecCoin delegator_shares = 9 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.nullable) = false + ]; } diff --git a/proto/milkyway/restaking/v1/models.proto b/proto/milkyway/restaking/v1/models.proto index a2f2ed27b..75240f0fb 100644 --- a/proto/milkyway/restaking/v1/models.proto +++ b/proto/milkyway/restaking/v1/models.proto @@ -4,6 +4,7 @@ package milkyway.restaking.v1; import "amino/amino.proto"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types"; @@ -41,9 +42,8 @@ message OperatorDelegation { uint32 operator_id = 2 [ (gogoproto.customname) = "OperatorID" ]; // Shares define the delegation shares received. - string shares = 3 [ - (cosmos_proto.scalar) = "cosmos.Dec", - (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + repeated cosmos.base.v1beta1.DecCoin shares = 3 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", (gogoproto.nullable) = false ]; } diff --git a/proto/milkyway/services/v1/models.proto b/proto/milkyway/services/v1/models.proto index 14c3755f7..73b8765a9 100644 --- a/proto/milkyway/services/v1/models.proto +++ b/proto/milkyway/services/v1/models.proto @@ -48,7 +48,6 @@ message Service { // PictureURL is the URL of the picture of the service string picture_url = 7 [ (gogoproto.customname) = "PictureURL" ]; - // Address is the address of the account associated with the service. // This will be used in order to store all the tokens that are delegated to // this service by various users. diff --git a/x/operators/types/errors.go b/x/operators/types/errors.go index ef4b505ce..a0e6314fc 100644 --- a/x/operators/types/errors.go +++ b/x/operators/types/errors.go @@ -8,4 +8,5 @@ var ( ErrInvalidGenesis = errors.Register(ModuleName, 1, "invalid genesis state") ErrInvalidDeactivationTime = errors.Register(ModuleName, 2, "invalid deactivation time") ErrOperatorNotFound = errors.Register(ModuleName, 3, "operator not found") + ErrInsufficientShares = errors.Register(ModuleName, 4, "insufficient delegation shares") ) diff --git a/x/operators/types/models.go b/x/operators/types/models.go index 18ddd2615..37e624786 100644 --- a/x/operators/types/models.go +++ b/x/operators/types/models.go @@ -72,6 +72,59 @@ func (o *Operator) Validate() error { return nil } +// InvalidExRate returns whether the exchange rates is invalid. +// This can happen e.g. if Pool loses all tokens due to slashing. In this case, +// make all future delegations invalid. +func (o Operator) InvalidExRate() bool { + for _, token := range o.Tokens { + if token.IsZero() && o.DelegatorShares.AmountOf(token.Denom).IsPositive() { + return true + } + } + return false +} + +// SharesFromTokens returns the shares of a delegation given a bond amount. It +// returns an error if the pool has no tokens. +func (o Operator) SharesFromTokens(tokens sdk.Coins) (sdk.DecCoins, error) { + if o.Tokens.IsZero() { + return nil, ErrInsufficientShares + } + + shares := sdk.NewDecCoins() + for _, token := range tokens { + tokenDelegatorShares := o.DelegatorShares.AmountOf(token.Denom) + tokenAmount := o.Tokens.AmountOf(token.Denom) + shares = shares.Add(sdk.NewDecCoinFromDec(token.Denom, tokenDelegatorShares.MulInt(token.Amount).QuoInt(tokenAmount))) + } + + return shares, nil +} + +// AddTokensFromDelegation adds the given amount of tokens to the pool's total tokens, +// also updating the pool's delegator shares. +// It returns the updated pool and the shares issued. +func (o Operator) AddTokensFromDelegation(amount sdk.Coins) (Operator, sdk.DecCoins) { + // calculate the shares to issue + var issuedShares sdk.DecCoins + if o.DelegatorShares.IsZero() { + // the first delegation to a operator sets the exchange rate to one + issuedShares = sdk.NewDecCoinsFromCoins(amount...) + } else { + shares, err := o.SharesFromTokens(amount) + if err != nil { + panic(err) + } + + issuedShares = shares + } + + o.Tokens = o.Tokens.Add(amount...) + o.DelegatorShares = o.DelegatorShares.Add(issuedShares...) + + return o, issuedShares +} + // -------------------------------------------------------------------------------------------------------------------- // OperatorUpdate defines the fields that can be updated in an Operator. diff --git a/x/operators/types/models.pb.go b/x/operators/types/models.pb.go index 84af9ddb7..1bc674cd3 100644 --- a/x/operators/types/models.pb.go +++ b/x/operators/types/models.pb.go @@ -6,6 +6,8 @@ package types import ( fmt "fmt" _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" @@ -80,6 +82,10 @@ type Operator struct { // Address is the address of the account associated to the operator. // This will be used to store tokens that are delegated to this operator. Address string `protobuf:"bytes,7,opt,name=address,proto3" json:"address,omitempty"` + // Tokens define the delegated tokens. + Tokens github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,8,rep,name=tokens,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"tokens"` + // DelegatorShares define the total shares issued to an operator's delegators. + DelegatorShares github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,9,rep,name=delegator_shares,json=delegatorShares,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"delegator_shares"` } func (m *Operator) Reset() { *m = Operator{} } @@ -164,6 +170,20 @@ func (m *Operator) GetAddress() string { return "" } +func (m *Operator) GetTokens() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Tokens + } + return nil +} + +func (m *Operator) GetDelegatorShares() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.DelegatorShares + } + return nil +} + func init() { proto.RegisterEnum("milkyway.operators.v1.OperatorStatus", OperatorStatus_name, OperatorStatus_value) proto.RegisterType((*Operator)(nil), "milkyway.operators.v1.Operator") @@ -174,34 +194,42 @@ func init() { } var fileDescriptor_8fb40b1089c56c16 = []byte{ - // 432 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xc1, 0x6e, 0xd3, 0x30, - 0x18, 0xc7, 0xe3, 0x6c, 0x6b, 0xc1, 0x88, 0xaa, 0xb2, 0xc6, 0x64, 0xca, 0x94, 0x56, 0x93, 0x90, - 0x2a, 0xa4, 0x25, 0xda, 0x76, 0xe6, 0x90, 0x6e, 0x01, 0x45, 0x82, 0xb6, 0x72, 0x52, 0x0e, 0x5c, - 0xaa, 0xb4, 0xb1, 0x8a, 0xb5, 0xa4, 0x8e, 0x6c, 0x67, 0xa3, 0x6f, 0xc0, 0x11, 0x89, 0x47, 0xe0, - 0xc6, 0x99, 0x87, 0xe0, 0x38, 0x71, 0xe2, 0x34, 0xa1, 0xf4, 0x45, 0x50, 0xe3, 0x64, 0x82, 0x0a, - 0xc4, 0xcd, 0x7f, 0xff, 0x7f, 0xdf, 0xf7, 0xff, 0x2c, 0x7f, 0xf0, 0x28, 0x65, 0xc9, 0xe5, 0xea, - 0x3a, 0x5a, 0x39, 0x3c, 0xa3, 0x22, 0x52, 0x5c, 0x48, 0xe7, 0xea, 0xc4, 0x49, 0x79, 0x4c, 0x13, - 0x69, 0x67, 0x82, 0x2b, 0x8e, 0x1e, 0xd5, 0x8c, 0x7d, 0xc7, 0xd8, 0x57, 0x27, 0x9d, 0xfd, 0x05, - 0x5f, 0xf0, 0x92, 0x70, 0x36, 0x27, 0x0d, 0x77, 0x1e, 0xcf, 0xb9, 0x4c, 0xb9, 0x9c, 0x6a, 0x43, - 0x0b, 0x6d, 0x1d, 0x7d, 0x31, 0xe1, 0xbd, 0x51, 0xd5, 0x01, 0x1d, 0x40, 0x93, 0xc5, 0x18, 0xf4, - 0x40, 0xff, 0xe1, 0xa0, 0x51, 0xdc, 0x76, 0x4d, 0xff, 0x82, 0x98, 0x2c, 0x46, 0xcf, 0x61, 0x43, - 0xaa, 0x48, 0xe5, 0x12, 0x9b, 0x3d, 0xd0, 0x6f, 0x9d, 0x3e, 0xb5, 0xff, 0x9a, 0x6e, 0xd7, 0x8d, - 0x82, 0x12, 0x26, 0x55, 0x11, 0xb2, 0xe1, 0x5e, 0x14, 0xa7, 0x6c, 0x89, 0x77, 0x7a, 0xa0, 0x7f, - 0x7f, 0x80, 0xbf, 0x7f, 0x3d, 0xde, 0xaf, 0x86, 0x70, 0xe3, 0x58, 0x50, 0x29, 0x03, 0x25, 0xd8, - 0x72, 0x41, 0x34, 0x86, 0x30, 0x6c, 0xa6, 0x7c, 0xc9, 0x2e, 0xa9, 0xc0, 0xbb, 0x9b, 0x0a, 0x52, - 0xcb, 0x8d, 0x73, 0x4d, 0x67, 0x92, 0x29, 0x8a, 0xf7, 0xb4, 0x53, 0x49, 0xe4, 0xc0, 0x07, 0x19, - 0x9b, 0xab, 0x5c, 0xd0, 0x69, 0x2e, 0x12, 0xdc, 0x28, 0x93, 0x5a, 0xc5, 0x6d, 0x17, 0x8e, 0xf5, - 0xf5, 0x84, 0xbc, 0x22, 0xb0, 0x42, 0x26, 0x22, 0x41, 0xa7, 0xb0, 0x19, 0xe9, 0x70, 0xdc, 0xfc, - 0xcf, 0x58, 0x35, 0xf8, 0xec, 0x13, 0x80, 0xad, 0x3f, 0xdf, 0x88, 0xba, 0xf0, 0xc9, 0x68, 0xec, - 0x11, 0x37, 0x1c, 0x91, 0x69, 0x10, 0xba, 0xe1, 0x24, 0x98, 0x4e, 0x86, 0xc1, 0xd8, 0x3b, 0xf7, - 0x5f, 0xf8, 0xde, 0x45, 0xdb, 0x40, 0x1d, 0x78, 0xb0, 0x0d, 0xb8, 0xe7, 0xa1, 0xff, 0xc6, 0x6b, - 0x03, 0xd4, 0x83, 0x87, 0xdb, 0x9e, 0x3f, 0x2c, 0x5d, 0x37, 0xf4, 0x87, 0x2f, 0xdb, 0x26, 0x3a, - 0x84, 0xf8, 0x1f, 0x84, 0xd7, 0xde, 0xe9, 0xec, 0x7e, 0xf8, 0x6c, 0x19, 0x83, 0xd7, 0xdf, 0x0a, - 0x0b, 0xdc, 0x14, 0x16, 0xf8, 0x59, 0x58, 0xe0, 0xe3, 0xda, 0x32, 0x6e, 0xd6, 0x96, 0xf1, 0x63, - 0x6d, 0x19, 0x6f, 0xcf, 0x16, 0x4c, 0xbd, 0xcb, 0x67, 0xf6, 0x9c, 0xa7, 0x4e, 0xfd, 0x63, 0xc7, - 0x49, 0x34, 0x93, 0x77, 0xca, 0x79, 0xff, 0xdb, 0x8e, 0xa9, 0x55, 0x46, 0xe5, 0xac, 0x51, 0x2e, - 0xc6, 0xd9, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7b, 0xe3, 0xe9, 0x28, 0x86, 0x02, 0x00, 0x00, + // 545 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x4f, 0x8f, 0xd2, 0x40, + 0x18, 0xc6, 0x5b, 0x60, 0x61, 0x77, 0x36, 0x22, 0x99, 0xac, 0x9b, 0x59, 0x24, 0x85, 0x6c, 0x62, + 0x42, 0x34, 0xb4, 0x02, 0x67, 0x0f, 0xfc, 0xd3, 0x34, 0x51, 0x20, 0x2d, 0x78, 0xf0, 0x42, 0xfa, + 0x67, 0xc2, 0x4e, 0x68, 0x3b, 0xa4, 0x33, 0xb0, 0x92, 0xf8, 0x01, 0xbc, 0x98, 0x98, 0xf8, 0x11, + 0xbc, 0x79, 0xf6, 0x43, 0xec, 0x71, 0xe3, 0xc9, 0x13, 0x1a, 0xf8, 0x22, 0x86, 0x76, 0x4a, 0xd6, + 0xcd, 0x1a, 0xf7, 0xd4, 0x3e, 0x7d, 0x7e, 0xef, 0x3c, 0xef, 0xbc, 0x33, 0x05, 0xe7, 0x3e, 0xf1, + 0x66, 0xab, 0x4b, 0x6b, 0xa5, 0xd1, 0x39, 0x0e, 0x2d, 0x4e, 0x43, 0xa6, 0x2d, 0xeb, 0x9a, 0x4f, + 0x5d, 0xec, 0x31, 0x75, 0x1e, 0x52, 0x4e, 0xe1, 0xa3, 0x84, 0x51, 0xf7, 0x8c, 0xba, 0xac, 0x17, + 0x4f, 0xa6, 0x74, 0x4a, 0x23, 0x42, 0xdb, 0xbd, 0xc5, 0x70, 0xf1, 0xcc, 0xa1, 0xcc, 0xa7, 0x6c, + 0x12, 0x1b, 0xb1, 0x10, 0x96, 0x12, 0x2b, 0xcd, 0xb6, 0x18, 0xd6, 0x96, 0x75, 0x1b, 0x73, 0xab, + 0xae, 0x39, 0x94, 0x04, 0xb1, 0x7f, 0xfe, 0x29, 0x03, 0x0e, 0x07, 0x22, 0x01, 0x9e, 0x82, 0x14, + 0x71, 0x91, 0x5c, 0x91, 0xab, 0x0f, 0xda, 0xd9, 0xcd, 0xba, 0x9c, 0xd2, 0xbb, 0x46, 0x8a, 0xb8, + 0xf0, 0x05, 0xc8, 0x32, 0x6e, 0xf1, 0x05, 0x43, 0xa9, 0x8a, 0x5c, 0xcd, 0x37, 0x9e, 0xa8, 0x77, + 0x76, 0xa7, 0x26, 0x0b, 0x99, 0x11, 0x6c, 0x88, 0x22, 0xa8, 0x82, 0x03, 0xcb, 0xf5, 0x49, 0x80, + 0xd2, 0x15, 0xb9, 0x7a, 0xd4, 0x46, 0x3f, 0xbe, 0xd7, 0x4e, 0x44, 0x93, 0x2d, 0xd7, 0x0d, 0x31, + 0x63, 0x26, 0x0f, 0x49, 0x30, 0x35, 0x62, 0x0c, 0x22, 0x90, 0xf3, 0x69, 0x40, 0x66, 0x38, 0x44, + 0x99, 0x5d, 0x85, 0x91, 0xc8, 0x9d, 0x73, 0x89, 0x6d, 0x46, 0x38, 0x46, 0x07, 0xb1, 0x23, 0x24, + 0xd4, 0xc0, 0xf1, 0x9c, 0x38, 0x7c, 0x11, 0xe2, 0xc9, 0x22, 0xf4, 0x50, 0x36, 0x4a, 0xca, 0x6f, + 0xd6, 0x65, 0x30, 0x8c, 0x3f, 0x8f, 0x8d, 0xd7, 0x06, 0x10, 0xc8, 0x38, 0xf4, 0x60, 0x03, 0xe4, + 0xac, 0x38, 0x1c, 0xe5, 0xfe, 0xd3, 0x56, 0x02, 0x42, 0x07, 0x64, 0x39, 0x9d, 0xe1, 0x80, 0xa1, + 0xc3, 0x4a, 0xba, 0x7a, 0xdc, 0x38, 0x53, 0x05, 0xbf, 0x9b, 0xae, 0x2a, 0xa6, 0xab, 0x76, 0x28, + 0x09, 0xda, 0xcf, 0xaf, 0xd6, 0x65, 0xe9, 0xdb, 0xaf, 0x72, 0x75, 0x4a, 0xf8, 0xc5, 0xc2, 0x56, + 0x1d, 0xea, 0x8b, 0x83, 0x11, 0x8f, 0x1a, 0x73, 0x67, 0x1a, 0x5f, 0xcd, 0x31, 0x8b, 0x0a, 0x98, + 0x21, 0x96, 0x86, 0x1f, 0x40, 0xc1, 0xc5, 0x1e, 0x9e, 0xee, 0x06, 0x39, 0x61, 0x17, 0x56, 0x88, + 0x19, 0x3a, 0x8a, 0xe2, 0x4a, 0x77, 0xc6, 0x75, 0xb1, 0x13, 0x25, 0x36, 0x45, 0xe2, 0xb3, 0x7b, + 0x24, 0x8a, 0x1a, 0x66, 0x3c, 0xdc, 0x47, 0x99, 0x51, 0xd2, 0xd3, 0x2f, 0x32, 0xc8, 0xff, 0x7d, + 0x8c, 0xb0, 0x0c, 0x1e, 0x0f, 0x86, 0x3d, 0xa3, 0x35, 0x1a, 0x18, 0x13, 0x73, 0xd4, 0x1a, 0x8d, + 0xcd, 0xc9, 0xb8, 0x6f, 0x0e, 0x7b, 0x1d, 0xfd, 0xa5, 0xde, 0xeb, 0x16, 0x24, 0x58, 0x04, 0xa7, + 0xb7, 0x81, 0x56, 0x67, 0xa4, 0xbf, 0xed, 0x15, 0x64, 0x58, 0x01, 0xa5, 0xdb, 0x9e, 0xde, 0x8f, + 0xdc, 0xd6, 0x48, 0xef, 0xbf, 0x2a, 0xa4, 0x60, 0x09, 0xa0, 0x7f, 0x10, 0xbd, 0x42, 0xba, 0x98, + 0xf9, 0xf8, 0x55, 0x91, 0xda, 0x6f, 0xae, 0x36, 0x8a, 0x7c, 0xbd, 0x51, 0xe4, 0xdf, 0x1b, 0x45, + 0xfe, 0xbc, 0x55, 0xa4, 0xeb, 0xad, 0x22, 0xfd, 0xdc, 0x2a, 0xd2, 0xbb, 0xe6, 0x8d, 0xdd, 0x26, + 0x97, 0xb2, 0xe6, 0x59, 0x36, 0xdb, 0x2b, 0xed, 0xfd, 0x8d, 0xdf, 0x2c, 0xda, 0xbe, 0x9d, 0x8d, + 0xee, 0x7e, 0xf3, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x74, 0xda, 0x3b, 0x89, 0x03, 0x00, + 0x00, } func (m *Operator) Marshal() (dAtA []byte, err error) { @@ -224,6 +252,34 @@ func (m *Operator) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.DelegatorShares) > 0 { + for iNdEx := len(m.DelegatorShares) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DelegatorShares[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } + if len(m.Tokens) > 0 { + for iNdEx := len(m.Tokens) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Tokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } if len(m.Address) > 0 { i -= len(m.Address) copy(dAtA[i:], m.Address) @@ -315,6 +371,18 @@ func (m *Operator) Size() (n int) { if l > 0 { n += 1 + l + sovModels(uint64(l)) } + if len(m.Tokens) > 0 { + for _, e := range m.Tokens { + l = e.Size() + n += 1 + l + sovModels(uint64(l)) + } + } + if len(m.DelegatorShares) > 0 { + for _, e := range m.DelegatorShares { + l = e.Size() + n += 1 + l + sovModels(uint64(l)) + } + } return n } @@ -551,6 +619,74 @@ func (m *Operator) Unmarshal(dAtA []byte) error { } m.Address = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tokens", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthModels + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tokens = append(m.Tokens, types.Coin{}) + if err := m.Tokens[len(m.Tokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorShares", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthModels + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorShares = append(m.DelegatorShares, types.DecCoin{}) + if err := m.DelegatorShares[len(m.DelegatorShares)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipModels(dAtA[iNdEx:]) diff --git a/x/restaking/keeper/common_test.go b/x/restaking/keeper/common_test.go index b0cbcd9e9..e12ed0b7b 100644 --- a/x/restaking/keeper/common_test.go +++ b/x/restaking/keeper/common_test.go @@ -101,6 +101,7 @@ func (suite *KeeperTestSuite) SetupTest() { suite.ak, suite.bk, suite.pk, + nil, authorityAddr, ).SetHooks(newMockHooks()) } @@ -148,3 +149,18 @@ func (m mockHooks) AfterPoolDelegationModified(ctx sdk.Context, poolID uint32, d m.CalledMap["AfterPoolDelegationModified"] = true return nil } + +func (m mockHooks) BeforeOperatorDelegationCreated(ctx sdk.Context, operatorID uint32, delegator string) error { + m.CalledMap["BeforeOperatorDelegationCreated"] = true + return nil +} + +func (m mockHooks) BeforeOperatorDelegationSharesModified(ctx sdk.Context, operatorID uint32, delegator string) error { + m.CalledMap["BeforeOperatorDelegationSharesModified"] = true + return nil +} + +func (m mockHooks) AfterOperatorDelegationModified(ctx sdk.Context, operatorID uint32, delegator string) error { + m.CalledMap["AfterOperatorDelegationModified"] = true + return nil +} diff --git a/x/restaking/keeper/hooks.go b/x/restaking/keeper/hooks.go index 134f60c79..418588e2a 100644 --- a/x/restaking/keeper/hooks.go +++ b/x/restaking/keeper/hooks.go @@ -31,3 +31,27 @@ func (k *Keeper) AfterPoolDelegationModified(ctx sdk.Context, poolID uint32, del } return nil } + +// BeforeOperatorDelegationCreated implements types.RestakingHooks +func (k *Keeper) BeforeOperatorDelegationCreated(ctx sdk.Context, operatorID uint32, delegator string) error { + if k.hooks != nil { + return k.hooks.BeforeOperatorDelegationCreated(ctx, operatorID, delegator) + } + return nil +} + +// BeforeOperatorDelegationSharesModified implements types.RestakingHooks +func (k *Keeper) BeforeOperatorDelegationSharesModified(ctx sdk.Context, operatorID uint32, delegator string) error { + if k.hooks != nil { + return k.hooks.BeforeOperatorDelegationSharesModified(ctx, operatorID, delegator) + } + return nil +} + +// AfterOperatorDelegationModified implements types.RestakingHooks +func (k *Keeper) AfterOperatorDelegationModified(ctx sdk.Context, operatorID uint32, delegator string) error { + if k.hooks != nil { + return k.hooks.AfterOperatorDelegationModified(ctx, operatorID, delegator) + } + return nil +} diff --git a/x/restaking/keeper/keeper.go b/x/restaking/keeper/keeper.go index 8f6763664..a38fc6886 100644 --- a/x/restaking/keeper/keeper.go +++ b/x/restaking/keeper/keeper.go @@ -15,9 +15,10 @@ type Keeper struct { authority string - accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper - poolsKeeper types.PoolsKeeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper + poolsKeeper types.PoolsKeeper + operatorsKeeper types.OperatorsKeeper hooks types.RestakingHooks } @@ -28,6 +29,7 @@ func NewKeeper( accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, poolsKeeper types.PoolsKeeper, + operatorsKeeper types.OperatorsKeeper, authority string, ) *Keeper { @@ -40,9 +42,10 @@ func NewKeeper( storeKey: storeKey, cdc: cdc, - accountKeeper: accountKeeper, - bankKeeper: bankKeeper, - poolsKeeper: poolsKeeper, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + poolsKeeper: poolsKeeper, + operatorsKeeper: operatorsKeeper, authority: authority, } diff --git a/x/restaking/keeper/operator_restaking.go b/x/restaking/keeper/operator_restaking.go new file mode 100644 index 000000000..9043948ae --- /dev/null +++ b/x/restaking/keeper/operator_restaking.go @@ -0,0 +1,96 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + operatorstypes "github.com/milkyway-labs/milkyway/x/operators/types" + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +// SaveOperatorDelegation stores the given operator delegation in the store +func (k *Keeper) SaveOperatorDelegation(ctx sdk.Context, delegation types.OperatorDelegation) { + store := ctx.KVStore(k.storeKey) + + // Marshal and store the delegation + delegationBz := types.MustMarshalOperatorDelegation(k.cdc, delegation) + store.Set(types.UserOperatorDelegationStoreKey(delegation.UserAddress, delegation.OperatorID), delegationBz) + + // Store the delegation in the delegations by operator ID store + store.Set(types.DelegationByPoolIDStoreKey(delegation.OperatorID, delegation.UserAddress), []byte{}) +} + +// GetOperatorDelegation retrieves the delegation for the given user and operator +// If the delegation does not exist, false is returned instead +func (k *Keeper) GetOperatorDelegation(ctx sdk.Context, operatorID uint32, userAddress string) (types.OperatorDelegation, bool) { + // Get the delegation amount from the store + store := ctx.KVStore(k.storeKey) + delegationAmountBz := store.Get(types.UserOperatorDelegationStoreKey(userAddress, operatorID)) + if delegationAmountBz == nil { + return types.OperatorDelegation{}, false + } + + // Parse the delegation amount + return types.MustUnmarshalOperatorDelegation(k.cdc, delegationAmountBz), true +} + +// AddOperatorTokensAndShares adds the given amount of tokens to the operator and returns the added shares +func (k *Keeper) AddOperatorTokensAndShares( + ctx sdk.Context, operator operatorstypes.Operator, tokensToAdd sdk.Coins, +) (operatorOut operatorstypes.Operator, addedShares sdk.DecCoins, err error) { + + // Update the operator tokens and shares and get the added shares + operator, addedShares = operator.AddTokensFromDelegation(tokensToAdd) + + // Save the operator + err = k.operatorsKeeper.SaveOperator(ctx, operator) + return operator, addedShares, err +} + +// -------------------------------------------------------------------------------------------------------------------- + +// DelegateToOperator sends the given amount to the operator account and saves the delegation for the given user +func (k *Keeper) DelegateToOperator(ctx sdk.Context, operatorID uint32, amount sdk.Coins, delegator string) (sdk.DecCoins, error) { + // Get the operator + operator, found := k.operatorsKeeper.GetOperator(ctx, operatorID) + if !found { + return sdk.NewDecCoins(), operatorstypes.ErrOperatorNotFound + } + + return k.PerformDelegation(ctx, types.DelegationData{ + Amount: amount, + Delegator: delegator, + Receiver: &operator, + GetDelegation: func(ctx sdk.Context, receiverID uint32, delegator string) (types.Delegation, bool) { + return k.GetOperatorDelegation(ctx, receiverID, delegator) + }, + BuildDelegation: func(receiverID uint32, delegator string) types.Delegation { + return types.NewOperatorDelegation(receiverID, delegator, sdk.NewDecCoins()) + }, + UpdateDelegation: func(ctx sdk.Context, delegation types.Delegation) (newShares sdk.DecCoins, err error) { + // Calculate the new shares and add the tokens to the operator + _, newShares, err = k.AddOperatorTokensAndShares(ctx, operator, amount) + if err != nil { + return newShares, err + } + + // Update the delegation shares + operatorDelegation, ok := delegation.(types.OperatorDelegation) + if !ok { + return newShares, fmt.Errorf("invalid delegation type: %T", delegation) + } + operatorDelegation.Shares = operatorDelegation.Shares.Add(newShares...) + + // Store the updated delegation + k.SaveOperatorDelegation(ctx, operatorDelegation) + + return newShares, err + }, + Hooks: types.DelegationHooks{ + BeforeDelegationSharesModified: k.BeforeOperatorDelegationSharesModified, + BeforeDelegationCreated: k.BeforeOperatorDelegationCreated, + AfterDelegationModified: k.AfterOperatorDelegationModified, + }, + }) +} diff --git a/x/restaking/keeper/pool_restaking.go b/x/restaking/keeper/pool_restaking.go index 22b0b5fd1..27d3fb3b8 100644 --- a/x/restaking/keeper/pool_restaking.go +++ b/x/restaking/keeper/pool_restaking.go @@ -52,11 +52,11 @@ func (k *Keeper) AddPoolTokensAndShares( // -------------------------------------------------------------------------------------------------------------------- // DelegateToPool sends the given amount to the pool account and saves the delegation for the given user -func (k *Keeper) DelegateToPool(ctx sdk.Context, amount sdk.Coin, delegator string) (sdkmath.LegacyDec, error) { +func (k *Keeper) DelegateToPool(ctx sdk.Context, amount sdk.Coin, delegator string) (sdk.DecCoins, error) { // Get or create the pool for the given amount denom pool, err := k.poolsKeeper.CreateOrGetPoolByDenom(ctx, amount.Denom) if err != nil { - return sdkmath.LegacyZeroDec(), err + return sdk.NewDecCoins(), err } // Get the amount to be bonded @@ -69,27 +69,27 @@ func (k *Keeper) DelegateToPool(ctx sdk.Context, amount sdk.Coin, delegator stri GetDelegation: func(ctx sdk.Context, receiverID uint32, delegator string) (types.Delegation, bool) { return k.GetPoolDelegation(ctx, receiverID, delegator) }, - BuildDelegation: func(receiverID uint32, delegator string, shares sdkmath.LegacyDec) types.Delegation { - return types.NewPoolDelegation(receiverID, delegator, shares) + BuildDelegation: func(receiverID uint32, delegator string) types.Delegation { + return types.NewPoolDelegation(receiverID, delegator, sdkmath.LegacyZeroDec()) }, - UpdateDelegation: func(ctx sdk.Context, delegation types.Delegation) (newShares sdkmath.LegacyDec, err error) { + UpdateDelegation: func(ctx sdk.Context, delegation types.Delegation) (sdk.DecCoins, error) { // Calculate the new shares and add the tokens to the pool - _, newShares, err = k.AddPoolTokensAndShares(ctx, pool, amount.Amount) + _, newShares, err := k.AddPoolTokensAndShares(ctx, pool, amount.Amount) if err != nil { - return newShares, err + return nil, err } // Update the delegation shares poolDelegation, ok := delegation.(types.PoolDelegation) if !ok { - return newShares, fmt.Errorf("invalid delegation type: %T", delegation) + return nil, fmt.Errorf("invalid delegation type: %T", delegation) } poolDelegation.Shares = poolDelegation.Shares.Add(newShares) // Store the updated delegation k.SavePoolDelegation(ctx, poolDelegation) - return newShares, err + return sdk.NewDecCoins(sdk.NewDecCoinFromDec(amount.Denom, newShares)), err }, Hooks: types.DelegationHooks{ BeforeDelegationSharesModified: k.BeforePoolDelegationSharesModified, diff --git a/x/restaking/keeper/pool_restaking_test.go b/x/restaking/keeper/pool_restaking_test.go index 622ba4b75..cd1b4ffae 100644 --- a/x/restaking/keeper/pool_restaking_test.go +++ b/x/restaking/keeper/pool_restaking_test.go @@ -214,7 +214,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToPool() { amount sdk.Coin delegator string shouldErr bool - expShares sdkmath.LegacyDec + expShares sdk.DecCoins check func(ctx sdk.Context) }{ { @@ -280,7 +280,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToPool() { amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, - expShares: sdkmath.LegacyNewDec(100), + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), check: func(ctx sdk.Context) { // Make sure the pool now exists pool, found := suite.pk.GetPool(ctx, 1) @@ -344,7 +344,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToPool() { amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, - expShares: sdkmath.LegacyNewDec(500), + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(500))), check: func(ctx sdk.Context) { // Make sure the pool now exists pool, found := suite.pk.GetPool(ctx, 1) @@ -415,7 +415,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToPool() { amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, - expShares: sdkmath.LegacyNewDecWithPrec(15625, 2), + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(15625, 2))), check: func(ctx sdk.Context) { // Make sure the pool now exists pool, found := suite.pk.GetPool(ctx, 1) diff --git a/x/restaking/keeper/restaking.go b/x/restaking/keeper/restaking.go index 7a934cee5..046543863 100644 --- a/x/restaking/keeper/restaking.go +++ b/x/restaking/keeper/restaking.go @@ -1,7 +1,6 @@ package keeper import ( - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/milkyway-labs/milkyway/x/restaking/types" @@ -12,7 +11,7 @@ import ( // shares of the delegation. // NOTE: This is done so that if we implement other delegation types in the future we can have a single // function that performs common operations for all of them. -func (k *Keeper) PerformDelegation(ctx sdk.Context, data types.DelegationData) (sdkmath.LegacyDec, error) { +func (k *Keeper) PerformDelegation(ctx sdk.Context, data types.DelegationData) (sdk.DecCoins, error) { // Get the data receiver := data.Receiver delegator := data.Delegator @@ -22,7 +21,7 @@ func (k *Keeper) PerformDelegation(ctx sdk.Context, data types.DelegationData) ( // the receives loses all tokens due to slashing. In this case, // make all future delegations invalid. if receiver.InvalidExRate() { - return sdkmath.LegacyZeroDec(), types.ErrDelegatorShareExRateInvalid + return nil, types.ErrDelegatorShareExRateInvalid } // Get or create the delegation object and call the appropriate hook if present @@ -32,37 +31,37 @@ func (k *Keeper) PerformDelegation(ctx sdk.Context, data types.DelegationData) ( // Delegation was found err := hooks.BeforeDelegationSharesModified(ctx, receiver.GetID(), delegator) if err != nil { - return sdkmath.LegacyZeroDec(), err + return nil, err } } else { // Delegation was not found - delegation = data.BuildDelegation(receiver.GetID(), delegator, sdkmath.LegacyZeroDec()) + delegation = data.BuildDelegation(receiver.GetID(), delegator) err := hooks.BeforeDelegationCreated(ctx, receiver.GetID(), delegator) if err != nil { - return sdkmath.LegacyZeroDec(), err + return nil, err } } // Convert the addresses to sdk.AccAddress delegatorAddress, err := k.accountKeeper.AddressCodec().StringToBytes(delegator) if err != nil { - return sdkmath.LegacyZeroDec(), err + return nil, err } receiverAddress, err := k.accountKeeper.AddressCodec().StringToBytes(receiver.GetAddress()) if err != nil { - return sdkmath.LegacyZeroDec(), err + return nil, err } // Send the coins to the receiver address err = k.bankKeeper.SendCoins(ctx, delegatorAddress, receiverAddress, data.Amount) if err != nil { - return sdkmath.LegacyZeroDec(), err + return nil, err } // Update the delegation newShares, err := data.UpdateDelegation(ctx, delegation) if err != nil { - return sdkmath.LegacyZeroDec(), err + return nil, err } // Call the after-modification hook diff --git a/x/restaking/types/delegation.go b/x/restaking/types/delegation.go index 7a94ee768..83130a229 100644 --- a/x/restaking/types/delegation.go +++ b/x/restaking/types/delegation.go @@ -1,7 +1,6 @@ package types import ( - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -13,9 +12,9 @@ type DelegationReceiver interface { type DelegationGetter func(ctx sdk.Context, receiverID uint32, delegator string) (Delegation, bool) -type DelegationBuilder func(receiverID uint32, delegator string, shares sdkmath.LegacyDec) Delegation +type DelegationBuilder func(receiverID uint32, delegator string) Delegation -type DelegationUpdater func(ctx sdk.Context, delegation Delegation) (newShares sdkmath.LegacyDec, err error) +type DelegationUpdater func(ctx sdk.Context, delegation Delegation) (newShares sdk.DecCoins, err error) // Delegation is an interface that represents a delegation object. type Delegation interface { diff --git a/x/restaking/types/expected_keepers.go b/x/restaking/types/expected_keepers.go index 68bb05566..a7e2f87b3 100644 --- a/x/restaking/types/expected_keepers.go +++ b/x/restaking/types/expected_keepers.go @@ -30,4 +30,5 @@ type ServicesKeeper interface { type OperatorsKeeper interface { GetOperator(ctx sdk.Context, operatorID uint32) (operatorstypes.Operator, bool) + SaveOperator(ctx sdk.Context, operator operatorstypes.Operator) error } diff --git a/x/restaking/types/genesis_test.go b/x/restaking/types/genesis_test.go index cb36249c7..cb03aa130 100644 --- a/x/restaking/types/genesis_test.go +++ b/x/restaking/types/genesis_test.go @@ -5,6 +5,7 @@ import ( "time" sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/milkyway-labs/milkyway/x/restaking/types" @@ -57,7 +58,7 @@ func TestGenesis_Validate(t *testing.T) { types.NewOperatorDelegation( 0, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(100), + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), ), }, types.DefaultParams(), @@ -100,7 +101,7 @@ func TestGenesis_Validate(t *testing.T) { types.NewOperatorDelegation( 3, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(100), + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), ), }, types.NewParams(5*24*time.Hour), @@ -250,7 +251,7 @@ func TestOperatorDelegation_Validate(t *testing.T) { entry: types.NewOperatorDelegation( 0, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(100), + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), ), shouldErr: true, }, @@ -259,7 +260,7 @@ func TestOperatorDelegation_Validate(t *testing.T) { entry: types.NewOperatorDelegation( 1, "", - sdkmath.LegacyNewDec(100), + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), ), shouldErr: true, }, @@ -268,7 +269,7 @@ func TestOperatorDelegation_Validate(t *testing.T) { entry: types.NewOperatorDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(-100), + sdk.DecCoins{sdk.DecCoin{Denom: "umilk", Amount: sdkmath.LegacyNewDec(-100)}}, ), shouldErr: true, }, @@ -277,7 +278,7 @@ func TestOperatorDelegation_Validate(t *testing.T) { entry: types.NewOperatorDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(100), + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), ), shouldErr: false, }, diff --git a/x/restaking/types/hooks.go b/x/restaking/types/hooks.go index 2dfddb799..50c2b4ca4 100644 --- a/x/restaking/types/hooks.go +++ b/x/restaking/types/hooks.go @@ -5,7 +5,18 @@ import ( ) type RestakingHooks interface { + PoolRestakingHooks + OperatorRestakingHooks +} + +type PoolRestakingHooks interface { BeforePoolDelegationCreated(ctx sdk.Context, poolID uint32, delegator string) error BeforePoolDelegationSharesModified(ctx sdk.Context, poolID uint32, delegator string) error AfterPoolDelegationModified(ctx sdk.Context, poolID uint32, delegator string) error } + +type OperatorRestakingHooks interface { + BeforeOperatorDelegationCreated(ctx sdk.Context, operatorID uint32, delegator string) error + BeforeOperatorDelegationSharesModified(ctx sdk.Context, operatorID uint32, delegator string) error + AfterOperatorDelegationModified(ctx sdk.Context, operatorID uint32, delegator string) error +} diff --git a/x/restaking/types/keys.go b/x/restaking/types/keys.go index b0527c95b..7306973d3 100644 --- a/x/restaking/types/keys.go +++ b/x/restaking/types/keys.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" + operatorstypes "github.com/milkyway-labs/milkyway/x/operators/types" poolstypes "github.com/milkyway-labs/milkyway/x/pools/types" ) @@ -65,3 +66,45 @@ func ParseDelegationsByPoolIDKey(bz []byte) (poolID uint32, delegatorAddress str return poolID, delegatorAddress, nil } + +// -------------------------------------------------------------------------------------------------------------------- + +// UserOperatorDelegationsStorePrefix returns the prefix used to store all the delegations to a given operator +func UserOperatorDelegationsStorePrefix(userAddress string) []byte { + return append(OperatorDelegationPrefix, []byte(userAddress)...) +} + +// UserOperatorDelegationStoreKey returns the key used to store the user -> operator delegation association +func UserOperatorDelegationStoreKey(delegator string, operatorID uint32) []byte { + return append(UserOperatorDelegationsStorePrefix(delegator), operatorstypes.GetOperatorIDBytes(operatorID)...) +} + +// DelegationsByOperatorIDStorePrefix returns the prefix used to store the delegations to a given operator +func DelegationsByOperatorIDStorePrefix(operatorID uint32) []byte { + return append(OperatorDelegationPrefix, operatorstypes.GetOperatorIDBytes(operatorID)...) +} + +// DelegationByOperatorIDStoreKey returns the key used to store the operator -> user delegation association +func DelegationByOperatorIDStoreKey(operatorID uint32, delegatorAddress string) []byte { + return append(DelegationsByOperatorIDStorePrefix(operatorID), []byte(delegatorAddress)...) +} + +// ParseDelegationsByOperatorIDKey parses the operator ID and delegator address from the given key +func ParseDelegationsByOperatorIDKey(bz []byte) (operatorID uint32, delegatorAddress string, err error) { + prefixLength := len(OperatorDelegationPrefix) + if prefix := bz[:prefixLength]; !bytes.Equal(prefix, OperatorDelegationPrefix) { + return 0, "", fmt.Errorf("invalid prefix; expected: %X, got: %x", OperatorDelegationPrefix, prefix) + } + + // Remove the prefix + bz = bz[prefixLength:] + + // Read the operator ID + operatorID = operatorstypes.GetOperatorIDFromBytes(bz[:4]) + bz = bz[4:] + + // Read the delegator address + delegatorAddress = string(bz) + + return operatorID, delegatorAddress, nil +} diff --git a/x/restaking/types/models.go b/x/restaking/types/models.go index 5272c421a..34398ecda 100644 --- a/x/restaking/types/models.go +++ b/x/restaking/types/models.go @@ -68,7 +68,7 @@ func MustUnmarshalPoolDelegation(cdc codec.BinaryCodec, bz []byte) PoolDelegatio // -------------------------------------------------------------------------------------------------------------------- -func NewOperatorDelegation(operatorID uint32, userAddress string, shares sdkmath.LegacyDec) OperatorDelegation { +func NewOperatorDelegation(operatorID uint32, userAddress string, shares sdk.DecCoins) OperatorDelegation { return OperatorDelegation{ OperatorID: operatorID, UserAddress: userAddress, @@ -76,6 +76,8 @@ func NewOperatorDelegation(operatorID uint32, userAddress string, shares sdkmath } } +func (d OperatorDelegation) isDelegation() {} + func (d OperatorDelegation) Validate() error { if d.OperatorID == 0 { return fmt.Errorf("invalid operator id") @@ -86,13 +88,41 @@ func (d OperatorDelegation) Validate() error { return fmt.Errorf("invalid user address: %s", d.UserAddress) } - if d.Shares.IsNegative() { + if d.Shares.IsAnyNegative() { return ErrInvalidShares } return nil } +// MustMarshalOperatorDelegation marshals the given operator delegation using the provided codec +func MustMarshalOperatorDelegation(cdc codec.BinaryCodec, delegation OperatorDelegation) []byte { + bz, err := cdc.Marshal(&delegation) + if err != nil { + panic(err) + } + return bz +} + +// UnmarshalOperatorDelegation unmarshals an operator delegation from the given bytes using the provided codec +func UnmarshalOperatorDelegation(cdc codec.BinaryCodec, bz []byte) (OperatorDelegation, error) { + var delegation OperatorDelegation + err := cdc.Unmarshal(bz, &delegation) + if err != nil { + return OperatorDelegation{}, err + } + return delegation, nil +} + +// MustUnmarshalOperatorDelegation unmarshals an operator delegation from the given bytes using the provided codec +func MustUnmarshalOperatorDelegation(cdc codec.BinaryCodec, bz []byte) OperatorDelegation { + delegation, err := UnmarshalOperatorDelegation(cdc, bz) + if err != nil { + panic(err) + } + return delegation +} + // -------------------------------------------------------------------------------------------------------------------- func NewServiceDelegation(serviceID uint32, userAddress string, shares sdkmath.LegacyDec) ServiceDelegation { diff --git a/x/restaking/types/models.pb.go b/x/restaking/types/models.pb.go index a0c1e8b45..e43988d41 100644 --- a/x/restaking/types/models.pb.go +++ b/x/restaking/types/models.pb.go @@ -7,6 +7,8 @@ import ( cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/cosmos-sdk/types/tx/amino" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" @@ -79,7 +81,7 @@ type OperatorDelegation struct { // OperatorID is the id of the operator. OperatorID uint32 `protobuf:"varint,2,opt,name=operator_id,json=operatorId,proto3" json:"operator_id,omitempty"` // Shares define the delegation shares received. - Shares cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=shares,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"shares"` + Shares github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,3,rep,name=shares,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"shares"` } func (m *OperatorDelegation) Reset() { *m = OperatorDelegation{} } @@ -171,33 +173,37 @@ func init() { } var fileDescriptor_86f4cd48423b1e2f = []byte{ - // 410 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0xc1, 0x8a, 0xd3, 0x40, - 0x18, 0xc7, 0x33, 0x0a, 0xd1, 0xce, 0xba, 0x0b, 0x1b, 0x56, 0x88, 0x2b, 0x24, 0x4b, 0xbd, 0xec, - 0xc1, 0x66, 0x28, 0x7b, 0xd3, 0x93, 0x25, 0x97, 0x80, 0xa2, 0x64, 0x6f, 0x5e, 0xca, 0x34, 0x19, - 0xd2, 0xa1, 0x49, 0xbe, 0x30, 0x33, 0x5b, 0xcd, 0x1b, 0x78, 0xf4, 0x11, 0xf6, 0x21, 0xf6, 0x1d, - 0xdc, 0x63, 0xa9, 0x07, 0xc5, 0x43, 0x90, 0xf4, 0xe2, 0x63, 0x48, 0x92, 0x49, 0xbb, 0x0f, 0xd0, - 0x5e, 0x42, 0xbe, 0xef, 0xff, 0xe7, 0xff, 0xe7, 0x07, 0xdf, 0xe0, 0x61, 0xc6, 0xd3, 0x45, 0xf9, - 0x85, 0x96, 0x44, 0x30, 0xa9, 0xe8, 0x82, 0xe7, 0x09, 0x59, 0x8e, 0x49, 0x06, 0x31, 0x4b, 0xa5, - 0x57, 0x08, 0x50, 0x60, 0x3d, 0xef, 0x3d, 0xde, 0xd6, 0xe3, 0x2d, 0xc7, 0xe7, 0xa7, 0x34, 0xe3, - 0x39, 0x90, 0xf6, 0xdb, 0x39, 0xcf, 0x5f, 0x44, 0x20, 0x33, 0x90, 0xd3, 0x76, 0x22, 0xdd, 0xa0, - 0xa5, 0xb3, 0x04, 0x12, 0xe8, 0xf6, 0xcd, 0x5f, 0xb7, 0x1d, 0xfe, 0x40, 0xf8, 0xe4, 0x13, 0x40, - 0xea, 0xb3, 0x94, 0x25, 0x54, 0x71, 0xc8, 0xad, 0xb7, 0xf8, 0xd9, 0x8d, 0x64, 0x62, 0x4a, 0xe3, - 0x58, 0x30, 0x29, 0x6d, 0x74, 0x81, 0x2e, 0x07, 0x13, 0x7b, 0x7d, 0x37, 0x3a, 0xd3, 0x81, 0xef, - 0x3a, 0xe5, 0x5a, 0x09, 0x9e, 0x27, 0xe1, 0x51, 0xe3, 0xd6, 0x2b, 0xeb, 0x15, 0x7e, 0x52, 0x00, - 0xa4, 0x53, 0x1e, 0xdb, 0x8f, 0x2e, 0xd0, 0xe5, 0xf1, 0x04, 0xd7, 0x95, 0x6b, 0x36, 0x0d, 0x81, - 0x1f, 0x9a, 0x8d, 0x14, 0xc4, 0x56, 0x80, 0x4d, 0x39, 0xa7, 0x82, 0x49, 0xfb, 0x71, 0x9b, 0x3d, - 0xbe, 0xaf, 0x5c, 0xe3, 0x4f, 0xe5, 0xbe, 0xec, 0xf2, 0x65, 0xbc, 0xf0, 0x38, 0x90, 0x8c, 0xaa, - 0xb9, 0xf7, 0x9e, 0x25, 0x34, 0x2a, 0x7d, 0x16, 0xad, 0xef, 0x46, 0x58, 0xd7, 0xfb, 0x2c, 0x0a, - 0x75, 0xc0, 0x9b, 0xa7, 0xdf, 0x6e, 0x5d, 0xe3, 0xdf, 0xad, 0x6b, 0x0c, 0x7f, 0x21, 0x6c, 0x7d, - 0x2c, 0x98, 0xa0, 0x0a, 0xc4, 0xbe, 0x68, 0x08, 0x3e, 0x02, 0x1d, 0xb9, 0x23, 0x3a, 0xa9, 0x2b, - 0x17, 0xf7, 0x4d, 0x81, 0x1f, 0xe2, 0xde, 0x72, 0x28, 0xb2, 0x9f, 0x08, 0x9f, 0x5e, 0x33, 0xb1, - 0xe4, 0x11, 0xdb, 0x17, 0xd8, 0x6b, 0x8c, 0x65, 0x97, 0xb8, 0xe3, 0x3a, 0xae, 0x2b, 0x77, 0xa0, - 0x7b, 0x02, 0x3f, 0x1c, 0x68, 0xc3, 0x81, 0xa8, 0x26, 0x1f, 0xee, 0x6b, 0x07, 0xad, 0x6a, 0x07, - 0xfd, 0xad, 0x1d, 0xf4, 0x7d, 0xe3, 0x18, 0xab, 0x8d, 0x63, 0xfc, 0xde, 0x38, 0xc6, 0xe7, 0xab, - 0x84, 0xab, 0xf9, 0xcd, 0xcc, 0x8b, 0x20, 0x23, 0xfd, 0xe5, 0x8f, 0x52, 0x3a, 0x93, 0xdb, 0x89, - 0x7c, 0x7d, 0xf0, 0x5a, 0x54, 0x59, 0x30, 0x39, 0x33, 0xdb, 0x7b, 0xbe, 0xfa, 0x1f, 0x00, 0x00, - 0xff, 0xff, 0xe2, 0x92, 0x5c, 0xce, 0x50, 0x03, 0x00, 0x00, + // 473 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0xf6, 0x51, 0x29, 0x90, 0x0b, 0xad, 0x54, 0xab, 0x48, 0xa1, 0x20, 0xbb, 0x0a, 0x4b, 0x24, + 0x88, 0x4f, 0x26, 0x1b, 0x4c, 0x04, 0x2f, 0x96, 0x40, 0x20, 0x77, 0x63, 0x89, 0xce, 0xf6, 0xc9, + 0x39, 0xc5, 0xf6, 0x8b, 0xee, 0xae, 0x01, 0xff, 0x03, 0x46, 0x7e, 0x42, 0x67, 0xe6, 0xfe, 0x07, + 0x3a, 0x56, 0x65, 0x41, 0x0c, 0x06, 0x39, 0x0b, 0xff, 0x80, 0x15, 0xd9, 0x3e, 0xb7, 0x19, 0x18, + 0xdb, 0xc5, 0xf6, 0x7b, 0xef, 0xf3, 0xf7, 0xe9, 0xfb, 0xee, 0x1e, 0x1e, 0x65, 0x3c, 0x5d, 0x16, + 0x1f, 0x69, 0x41, 0x04, 0x93, 0x8a, 0x2e, 0x79, 0x9e, 0x90, 0xb5, 0x4b, 0x32, 0x88, 0x59, 0x2a, + 0x9d, 0x95, 0x00, 0x05, 0xe6, 0x83, 0x0e, 0xe3, 0x5c, 0x61, 0x9c, 0xb5, 0x7b, 0xb8, 0x4f, 0x33, + 0x9e, 0x03, 0x69, 0x9e, 0x2d, 0xf2, 0xf0, 0x61, 0x04, 0x32, 0x03, 0x39, 0x6f, 0x2a, 0xd2, 0x16, + 0x7a, 0x74, 0x90, 0x40, 0x02, 0x6d, 0xbf, 0xfe, 0xd2, 0x5d, 0xab, 0xc5, 0x90, 0x90, 0x4a, 0x46, + 0xd6, 0x6e, 0xc8, 0x14, 0x75, 0x49, 0x04, 0x3c, 0x6f, 0xe7, 0xa3, 0x6f, 0x08, 0xef, 0xbd, 0x07, + 0x48, 0x3d, 0x96, 0xb2, 0x84, 0x2a, 0x0e, 0xb9, 0xf9, 0x12, 0xdf, 0x3f, 0x91, 0x4c, 0xcc, 0x69, + 0x1c, 0x0b, 0x26, 0xe5, 0x10, 0x1d, 0xa1, 0x71, 0x7f, 0x36, 0xbc, 0x3c, 0x9b, 0x1c, 0x68, 0xc1, + 0x57, 0xed, 0xe4, 0x58, 0x09, 0x9e, 0x27, 0xc1, 0xa0, 0x46, 0xeb, 0x96, 0xf9, 0x04, 0xdf, 0x5d, + 0x01, 0xa4, 0x73, 0x1e, 0x0f, 0xef, 0x1c, 0xa1, 0xf1, 0xee, 0x0c, 0x57, 0xa5, 0xdd, 0xab, 0x15, + 0x7c, 0x2f, 0xe8, 0xd5, 0x23, 0x3f, 0x36, 0x7d, 0xdc, 0x93, 0x0b, 0x2a, 0x98, 0x1c, 0xee, 0x34, + 0xdc, 0xee, 0x79, 0x69, 0x1b, 0x3f, 0x4b, 0xfb, 0x51, 0xcb, 0x2f, 0xe3, 0xa5, 0xc3, 0x81, 0x64, + 0x54, 0x2d, 0x9c, 0x37, 0x2c, 0xa1, 0x51, 0xe1, 0xb1, 0xe8, 0xf2, 0x6c, 0x82, 0xb5, 0xbc, 0xc7, + 0xa2, 0x40, 0x13, 0xbc, 0xb8, 0xf7, 0xf9, 0xd4, 0x36, 0xfe, 0x9c, 0xda, 0xc6, 0xe8, 0x2f, 0xc2, + 0xe6, 0xbb, 0x15, 0x13, 0x54, 0x81, 0xb8, 0x29, 0x37, 0x04, 0x0f, 0x40, 0x53, 0x5e, 0x3b, 0xda, + 0xab, 0x4a, 0x1b, 0x77, 0x4a, 0xbe, 0x17, 0xe0, 0x0e, 0xe2, 0xc7, 0x26, 0xdf, 0x72, 0xb6, 0x33, + 0x1e, 0x3c, 0x7f, 0xec, 0x68, 0x91, 0x3a, 0x7f, 0x47, 0xe7, 0x5f, 0x1b, 0x78, 0x0d, 0x3c, 0x9f, + 0x4d, 0x6b, 0xdf, 0x5f, 0x7f, 0xd9, 0x4f, 0x13, 0xae, 0x16, 0x27, 0xa1, 0x13, 0x41, 0xa6, 0xcf, + 0x54, 0xbf, 0x26, 0x32, 0x5e, 0x12, 0x55, 0xac, 0x98, 0xec, 0xfe, 0x91, 0xff, 0x71, 0xfe, 0x1d, + 0xe1, 0xfd, 0x63, 0x26, 0xd6, 0x3c, 0x62, 0x37, 0x65, 0xfc, 0x19, 0xc6, 0xb2, 0x65, 0xbc, 0xf6, + 0xbd, 0x5b, 0x95, 0x76, 0x5f, 0xeb, 0xf8, 0x5e, 0xd0, 0xd7, 0x80, 0x5b, 0x3a, 0xcf, 0xd9, 0xdb, + 0xf3, 0xca, 0x42, 0x17, 0x95, 0x85, 0x7e, 0x57, 0x16, 0xfa, 0xb2, 0xb1, 0x8c, 0x8b, 0x8d, 0x65, + 0xfc, 0xd8, 0x58, 0xc6, 0x87, 0xe9, 0x56, 0x5c, 0xdd, 0xe6, 0x4c, 0x52, 0x1a, 0xca, 0xab, 0x8a, + 0x7c, 0xda, 0xda, 0xb6, 0x26, 0xbf, 0xb0, 0xd7, 0xdc, 0xf7, 0xe9, 0xbf, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x89, 0xe1, 0x7c, 0x0f, 0x90, 0x03, 0x00, 0x00, } func (m *PoolDelegation) Marshal() (dAtA []byte, err error) { @@ -265,16 +271,20 @@ func (m *OperatorDelegation) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size := m.Shares.Size() - i -= size - if _, err := m.Shares.MarshalTo(dAtA[i:]); err != nil { - return 0, err + if len(m.Shares) > 0 { + for iNdEx := len(m.Shares) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Shares[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a } - i = encodeVarintModels(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x1a if m.OperatorID != 0 { i = encodeVarintModels(dAtA, i, uint64(m.OperatorID)) i-- @@ -377,8 +387,12 @@ func (m *OperatorDelegation) Size() (n int) { if m.OperatorID != 0 { n += 1 + sovModels(uint64(m.OperatorID)) } - l = m.Shares.Size() - n += 1 + l + sovModels(uint64(l)) + if len(m.Shares) > 0 { + for _, e := range m.Shares { + l = e.Size() + n += 1 + l + sovModels(uint64(l)) + } + } return n } @@ -625,7 +639,7 @@ func (m *OperatorDelegation) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Shares", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowModels @@ -635,23 +649,23 @@ func (m *OperatorDelegation) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthModels } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthModels } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Shares.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Shares = append(m.Shares, types.DecCoin{}) + if err := m.Shares[len(m.Shares)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex From 08c13bc2591240da52bfc27ce6bd22e04449d5ef Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 12:36:21 -0500 Subject: [PATCH 16/37] feat: implement msg server for operator restaking --- proto/milkyway/restaking/v1/messages.proto | 7 +- x/restaking/keeper/msg_server.go | 35 +++++- x/restaking/types/events.go | 8 +- x/restaking/types/messages.go | 2 +- x/restaking/types/messages.pb.go | 126 +++++++++++---------- x/restaking/types/messages_test.go | 6 +- 6 files changed, 116 insertions(+), 68 deletions(-) diff --git a/proto/milkyway/restaking/v1/messages.proto b/proto/milkyway/restaking/v1/messages.proto index c3ebea418..c0f60b25b 100644 --- a/proto/milkyway/restaking/v1/messages.proto +++ b/proto/milkyway/restaking/v1/messages.proto @@ -69,8 +69,11 @@ message MsgDelegateOperator { uint32 operator_id = 2 [ (gogoproto.customname) = "OperatorID" ]; // Amount is the amount of coins to be delegated - cosmos.base.v1beta1.Coin amount = 3 - [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; + repeated cosmos.base.v1beta1.Coin amount = 3 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.customname) = "Amount", + (gogoproto.nullable) = false + ]; } // MsgDelegateOperatorResponse is the return value of MsgDelegateOperator. diff --git a/x/restaking/keeper/msg_server.go b/x/restaking/keeper/msg_server.go index f0ace2bf1..e6d88df3b 100644 --- a/x/restaking/keeper/msg_server.go +++ b/x/restaking/keeper/msg_server.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "fmt" "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/telemetry" @@ -59,8 +60,38 @@ func (k msgServer) PoolRestake(goCtx context.Context, msg *types.MsgJoinRestakin // OperatorRestake defines the rpc method for Msg/OperatorRestake func (k msgServer) OperatorRestake(goCtx context.Context, msg *types.MsgDelegateOperator) (*types.MsgDelegateOperatorResponse, error) { - //TODO implement me - panic("implement me") + ctx := sdk.UnwrapSDKContext(goCtx) + + newShares, err := k.Keeper.DelegateToOperator(ctx, msg.OperatorID, msg.Amount, msg.Delegator) + if err != nil { + return nil, err + } + + for _, token := range msg.Amount { + if token.Amount.IsInt64() { + defer func() { + telemetry.IncrCounter(1, types.ModuleName, "operator restake") + telemetry.SetGaugeWithLabels( + []string{"tx", "msg", sdk.MsgTypeURL(msg)}, + float32(token.Amount.Int64()), + []metrics.Label{telemetry.NewLabel("denom", token.Denom)}, + ) + }() + } + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + sdkCtx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeOperatorRestake, + sdk.NewAttribute(types.AttributeKeyDelegator, msg.Delegator), + sdk.NewAttribute(types.AttributeKeyOperatorID, fmt.Sprintf("%d", msg.OperatorID)), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(types.AttributeKeyNewShares, newShares.String()), + ), + }) + + return &types.MsgDelegateOperatorResponse{}, nil } // ServiceRestake defines the rpc method for Msg/ServiceRestake diff --git a/x/restaking/types/events.go b/x/restaking/types/events.go index acb8cdf73..d7f6e699e 100644 --- a/x/restaking/types/events.go +++ b/x/restaking/types/events.go @@ -1,8 +1,10 @@ package types const ( - EventTypePoolRestake = "pool_restake" + EventTypePoolRestake = "pool_restake" + EventTypeOperatorRestake = "operator_restake" - AttributeKeyDelegator = "delegator" - AttributeKeyNewShares = "new_shares" + AttributeKeyDelegator = "delegator" + AttributeKeyOperatorID = "operator_id" + AttributeKeyNewShares = "new_shares" ) diff --git a/x/restaking/types/messages.go b/x/restaking/types/messages.go index 7eb434499..9f85dabc9 100644 --- a/x/restaking/types/messages.go +++ b/x/restaking/types/messages.go @@ -42,7 +42,7 @@ func (msg *MsgJoinRestakingPool) GetSigners() []sdk.AccAddress { // -------------------------------------------------------------------------------------------------------------------- // NewMsgDelegateOperator creates a new MsgDelegateOperator instance -func NewMsgDelegateOperator(operatorID uint32, amount sdk.Coin, delegator string) *MsgDelegateOperator { +func NewMsgDelegateOperator(operatorID uint32, amount sdk.Coins, delegator string) *MsgDelegateOperator { return &MsgDelegateOperator{ OperatorID: operatorID, Amount: amount, diff --git a/x/restaking/types/messages.pb.go b/x/restaking/types/messages.pb.go index 1688b1e1c..59f49dc4c 100644 --- a/x/restaking/types/messages.pb.go +++ b/x/restaking/types/messages.pb.go @@ -7,6 +7,7 @@ import ( context "context" fmt "fmt" _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/cosmos-sdk/types/msgservice" _ "github.com/cosmos/cosmos-sdk/types/tx/amino" @@ -138,7 +139,7 @@ type MsgDelegateOperator struct { // OperatorID is the ID of the operator to delegate to OperatorID uint32 `protobuf:"varint,2,opt,name=operator_id,json=operatorId,proto3" json:"operator_id,omitempty"` // Amount is the amount of coins to be delegated - Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` + 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 *MsgDelegateOperator) Reset() { *m = MsgDelegateOperator{} } @@ -188,11 +189,11 @@ func (m *MsgDelegateOperator) GetOperatorID() uint32 { return 0 } -func (m *MsgDelegateOperator) GetAmount() types.Coin { +func (m *MsgDelegateOperator) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { if m != nil { return m.Amount } - return types.Coin{} + return nil } // MsgDelegateOperatorResponse is the return value of MsgDelegateOperator. @@ -446,49 +447,51 @@ func init() { } var fileDescriptor_9772be2b1a923bdb = []byte{ - // 668 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x31, 0x6f, 0xd3, 0x40, - 0x14, 0x8e, 0x29, 0x44, 0xca, 0x95, 0xb6, 0x60, 0x8a, 0xda, 0xba, 0xad, 0x53, 0x59, 0x08, 0x95, - 0xd0, 0xfa, 0x48, 0x2b, 0x81, 0x54, 0xa6, 0x86, 0x2e, 0xa9, 0x14, 0x51, 0xb9, 0x62, 0x61, 0xa9, - 0x2e, 0xf1, 0x71, 0xb5, 0x12, 0xfb, 0x8c, 0xef, 0x12, 0xc8, 0x86, 0x18, 0x99, 0xf8, 0x29, 0x19, - 0xf8, 0x07, 0x2c, 0x19, 0x2b, 0x58, 0x98, 0x22, 0xe4, 0x0c, 0x99, 0x58, 0xfa, 0x0b, 0x50, 0xec, - 0xb3, 0x63, 0x12, 0x47, 0x84, 0x88, 0x25, 0xca, 0xbd, 0xf7, 0xbd, 0xef, 0xbd, 0xef, 0xcb, 0xbd, - 0x0b, 0x78, 0x60, 0x5b, 0x8d, 0x7a, 0xfb, 0x1d, 0x6a, 0x43, 0x0f, 0x33, 0x8e, 0xea, 0x96, 0x43, - 0x60, 0xab, 0x08, 0x6d, 0xcc, 0x18, 0x22, 0x98, 0xe9, 0xae, 0x47, 0x39, 0x95, 0xef, 0x47, 0x28, - 0x3d, 0x46, 0xe9, 0xad, 0xa2, 0x72, 0x17, 0xd9, 0x96, 0x43, 0x61, 0xf0, 0x19, 0x22, 0x95, 0x8d, - 0x1a, 0x65, 0x36, 0x65, 0x17, 0xc1, 0x09, 0x86, 0x07, 0x91, 0x52, 0xc3, 0x13, 0xac, 0x22, 0x86, - 0x61, 0xab, 0x58, 0xc5, 0x1c, 0x15, 0x61, 0x8d, 0x5a, 0xce, 0x44, 0xde, 0xa9, 0xc7, 0xf9, 0xe1, - 0x41, 0xe4, 0xd7, 0x44, 0xde, 0x66, 0xe1, 0x88, 0x8c, 0x88, 0xc4, 0x2a, 0xa1, 0x84, 0x86, 0x0d, - 0x87, 0xdf, 0x44, 0x54, 0x4b, 0x57, 0xe6, 0x22, 0x0f, 0xd9, 0x62, 0x24, 0xed, 0xab, 0x04, 0x56, - 0x2b, 0x8c, 0x9c, 0x52, 0xcb, 0x31, 0x22, 0xd0, 0x19, 0xa5, 0x0d, 0xf9, 0x29, 0xc8, 0x99, 0xb8, - 0x81, 0x09, 0xe2, 0xd4, 0x5b, 0x97, 0x76, 0xa4, 0xdd, 0x5c, 0x69, 0xfd, 0xdb, 0x97, 0xfd, 0x55, - 0x21, 0xe8, 0xd8, 0x34, 0x3d, 0xcc, 0xd8, 0x39, 0xf7, 0x2c, 0x87, 0x18, 0x23, 0xa8, 0x7c, 0x0c, - 0xb2, 0xc8, 0xa6, 0x4d, 0x87, 0xaf, 0xdf, 0xd8, 0x91, 0x76, 0x17, 0x0f, 0x36, 0x74, 0x51, 0x31, - 0x14, 0xad, 0x0b, 0x51, 0xfa, 0x0b, 0x6a, 0x39, 0xa5, 0xe5, 0x6e, 0x2f, 0x9f, 0xf1, 0x7b, 0xf9, - 0xec, 0x71, 0x50, 0x60, 0x88, 0xc2, 0xa3, 0x27, 0x1f, 0x07, 0x9d, 0xc2, 0x88, 0xf2, 0xd3, 0xa0, - 0x53, 0xd8, 0x8e, 0xa5, 0xa4, 0x0d, 0xab, 0xa9, 0x60, 0x2b, 0x2d, 0x6e, 0x60, 0xe6, 0x52, 0x87, - 0x61, 0xed, 0x5a, 0x02, 0xf7, 0x2a, 0x8c, 0x9c, 0x84, 0x94, 0xf8, 0xa5, 0x8b, 0xbd, 0x60, 0xd8, - 0x79, 0x45, 0x42, 0xb0, 0x48, 0x05, 0xc7, 0x85, 0x65, 0x06, 0x4a, 0x97, 0x4a, 0xcb, 0x7e, 0x2f, - 0x0f, 0x22, 0xea, 0xf2, 0x89, 0x01, 0x22, 0x48, 0xd9, 0x4c, 0xb8, 0xb2, 0x30, 0xaf, 0x2b, 0x70, - 0xd2, 0x95, 0xad, 0xa4, 0x2b, 0xe3, 0xe2, 0xb4, 0x6d, 0xb0, 0x99, 0x12, 0x8e, 0x3d, 0xf9, 0x25, - 0x01, 0x39, 0x91, 0x3f, 0xc7, 0x5e, 0xcb, 0xaa, 0xe1, 0xb9, 0x2d, 0xd9, 0x03, 0x80, 0x85, 0x14, - 0x23, 0x47, 0x96, 0xfc, 0x5e, 0x3e, 0x27, 0x88, 0xcb, 0x27, 0x46, 0x4e, 0x00, 0xfe, 0x8f, 0x1f, - 0xfa, 0xa4, 0x1f, 0x9b, 0x69, 0x7e, 0x88, 0xfe, 0xda, 0x16, 0x50, 0x26, 0xa3, 0xb1, 0x1b, 0xdf, - 0x25, 0xb0, 0x52, 0x61, 0xe4, 0x95, 0x6b, 0x22, 0x8e, 0xcf, 0x82, 0x0d, 0x91, 0x4f, 0x41, 0x0e, - 0x35, 0xf9, 0x25, 0xf5, 0x2c, 0xde, 0x16, 0x56, 0xec, 0x5d, 0xf7, 0xf2, 0x77, 0xda, 0xc8, 0x6e, - 0x1c, 0x69, 0x71, 0x4a, 0x9b, 0x6e, 0x4f, 0x8c, 0x91, 0x9f, 0x83, 0x6c, 0xb8, 0x77, 0x62, 0x2d, - 0xb6, 0xf5, 0xd4, 0x07, 0x45, 0x0f, 0x5b, 0x97, 0x6e, 0x0e, 0x45, 0x1b, 0xa2, 0xe4, 0xe8, 0x59, - 0x20, 0x35, 0x26, 0x1b, 0x4a, 0x1d, 0xbd, 0x5a, 0xef, 0x13, 0xdb, 0x3d, 0xa6, 0x40, 0xdb, 0x00, - 0x6b, 0x63, 0xa1, 0x48, 0xf0, 0x41, 0x77, 0x01, 0x2c, 0x54, 0x18, 0x91, 0x29, 0x58, 0x14, 0xab, - 0xc2, 0x51, 0x1d, 0xcb, 0x8f, 0xa7, 0xcc, 0x95, 0xb6, 0x5e, 0xca, 0xe1, 0x3f, 0x80, 0xa3, 0xc6, - 0xf2, 0x5b, 0xb0, 0x92, 0xb8, 0x8b, 0x41, 0xd3, 0xc2, 0x74, 0x9e, 0xf1, 0xeb, 0xab, 0x1c, 0xcc, - 0x8e, 0x8d, 0x5b, 0x3a, 0x60, 0x79, 0xf4, 0x7b, 0x07, 0x1d, 0x1f, 0xfd, 0x9d, 0x45, 0x54, 0x28, - 0xc5, 0x99, 0xa1, 0x71, 0xbf, 0x37, 0xe0, 0xf6, 0x1f, 0x17, 0xe9, 0xe1, 0x74, 0x8a, 0x24, 0x4e, - 0xd1, 0x67, 0xc3, 0x45, 0x7d, 0x94, 0x5b, 0x1f, 0x06, 0x9d, 0x82, 0x54, 0xaa, 0x74, 0x7d, 0x55, - 0xba, 0xf2, 0x55, 0xe9, 0xa7, 0xaf, 0x4a, 0x9f, 0xfb, 0x6a, 0xe6, 0xaa, 0xaf, 0x66, 0x7e, 0xf4, - 0xd5, 0xcc, 0xeb, 0x43, 0x62, 0xf1, 0xcb, 0x66, 0x55, 0xaf, 0x51, 0x1b, 0x46, 0xd4, 0xfb, 0x0d, - 0x54, 0x65, 0x30, 0xf5, 0xfa, 0xf0, 0xb6, 0x8b, 0x59, 0x35, 0x1b, 0xfc, 0x33, 0x1c, 0xfe, 0x0e, - 0x00, 0x00, 0xff, 0xff, 0x37, 0xc9, 0x43, 0x40, 0x19, 0x07, 0x00, 0x00, + // 704 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x41, 0x4f, 0x13, 0x41, + 0x14, 0xee, 0x52, 0x6d, 0xd2, 0x41, 0x40, 0x57, 0x0c, 0xb0, 0xc0, 0x96, 0x6c, 0x8c, 0xc1, 0x0a, + 0xbb, 0x16, 0x12, 0x4d, 0xea, 0x89, 0xca, 0xa5, 0x24, 0x8d, 0x64, 0x89, 0x17, 0x2f, 0x64, 0xda, + 0x1d, 0x87, 0x4d, 0xbb, 0x3b, 0x75, 0x67, 0xa8, 0xf6, 0x66, 0x3c, 0x7a, 0xf2, 0x17, 0xf8, 0x03, + 0x3c, 0x71, 0xf0, 0x1f, 0x78, 0xe1, 0x48, 0xf4, 0xe2, 0xa9, 0x9a, 0xe5, 0xc0, 0xc9, 0x8b, 0xbf, + 0xc0, 0x74, 0x76, 0x76, 0xba, 0xb4, 0x5b, 0xc5, 0x5e, 0xa0, 0x33, 0xef, 0x7b, 0xdf, 0x9b, 0xef, + 0xeb, 0x7b, 0xaf, 0xe0, 0xae, 0xe7, 0xb6, 0x9a, 0xdd, 0xd7, 0xb0, 0x6b, 0x05, 0x88, 0x32, 0xd8, + 0x74, 0x7d, 0x6c, 0x75, 0x4a, 0x96, 0x87, 0x28, 0x85, 0x18, 0x51, 0xb3, 0x1d, 0x10, 0x46, 0xd4, + 0x3b, 0x31, 0xca, 0x94, 0x28, 0xb3, 0x53, 0xd2, 0x6e, 0x41, 0xcf, 0xf5, 0x89, 0xc5, 0xff, 0x46, + 0x48, 0x6d, 0xa9, 0x41, 0xa8, 0x47, 0xe8, 0x21, 0x3f, 0x59, 0xd1, 0x41, 0x84, 0xf4, 0xe8, 0x64, + 0xd5, 0x21, 0x45, 0x56, 0xa7, 0x54, 0x47, 0x0c, 0x96, 0xac, 0x06, 0x71, 0xfd, 0x91, 0xb8, 0xdf, + 0x94, 0xf1, 0xfe, 0x41, 0xc4, 0x17, 0x44, 0xdc, 0xa3, 0xd1, 0x13, 0x29, 0x16, 0x81, 0x79, 0x4c, + 0x30, 0x89, 0x0a, 0xf6, 0x3f, 0x89, 0x5b, 0x23, 0x5d, 0x59, 0x1b, 0x06, 0xd0, 0x13, 0x4f, 0x32, + 0xbe, 0x28, 0x60, 0xbe, 0x46, 0xf1, 0x1e, 0x71, 0x7d, 0x3b, 0x06, 0xed, 0x13, 0xd2, 0x52, 0x1f, + 0x81, 0xbc, 0x83, 0x5a, 0x08, 0x43, 0x46, 0x82, 0x45, 0x65, 0x4d, 0x59, 0xcf, 0x57, 0x16, 0xbf, + 0x7e, 0xde, 0x9c, 0x17, 0x82, 0x76, 0x1c, 0x27, 0x40, 0x94, 0x1e, 0xb0, 0xc0, 0xf5, 0xb1, 0x3d, + 0x80, 0xaa, 0x3b, 0x20, 0x07, 0x3d, 0x72, 0xec, 0xb3, 0xc5, 0xa9, 0x35, 0x65, 0x7d, 0x7a, 0x6b, + 0xc9, 0x14, 0x19, 0x7d, 0xd1, 0xa6, 0x10, 0x65, 0x3e, 0x25, 0xae, 0x5f, 0x99, 0x3d, 0xed, 0x15, + 0x32, 0x61, 0xaf, 0x90, 0xdb, 0xe1, 0x09, 0xb6, 0x48, 0x2c, 0x3f, 0x7c, 0x77, 0x71, 0x52, 0x1c, + 0x50, 0xbe, 0xbf, 0x38, 0x29, 0xae, 0x4a, 0x29, 0x69, 0x8f, 0x35, 0x74, 0xb0, 0x92, 0x76, 0x6f, + 0x23, 0xda, 0x26, 0x3e, 0x45, 0xc6, 0xc7, 0x29, 0x70, 0xbb, 0x46, 0xf1, 0x6e, 0x44, 0x89, 0x9e, + 0xb5, 0x51, 0xc0, 0x1f, 0x3b, 0xa9, 0x48, 0x0b, 0x4c, 0x13, 0xc1, 0x71, 0xe8, 0x3a, 0x5c, 0xe9, + 0x4c, 0x65, 0x36, 0xec, 0x15, 0x40, 0x4c, 0x5d, 0xdd, 0xb5, 0x41, 0x0c, 0xa9, 0x3a, 0xaa, 0x27, + 0x5d, 0xc9, 0xae, 0x65, 0xff, 0xee, 0x4a, 0xf9, 0xb2, 0x2b, 0x9f, 0x7e, 0x14, 0xd6, 0xb1, 0xcb, + 0x8e, 0x8e, 0xeb, 0x66, 0x83, 0x78, 0xa2, 0x9f, 0xc4, 0xbf, 0x4d, 0xea, 0x34, 0x2d, 0xd6, 0x6d, + 0x23, 0xca, 0x53, 0xa9, 0x74, 0xd0, 0x1a, 0x75, 0x70, 0x25, 0xe9, 0xe0, 0xb0, 0x11, 0xc6, 0x2a, + 0x58, 0x4e, 0xb9, 0x96, 0xfe, 0xfd, 0x52, 0x80, 0x9a, 0x88, 0x1f, 0xa0, 0xa0, 0xe3, 0x36, 0xd0, + 0xc4, 0xf6, 0x6d, 0x00, 0x40, 0x23, 0x8a, 0x81, 0x7b, 0x33, 0x61, 0xaf, 0x90, 0x17, 0xc4, 0xd5, + 0x5d, 0x3b, 0x2f, 0x00, 0x55, 0x27, 0xd1, 0x51, 0xd9, 0x49, 0x3b, 0xca, 0x1c, 0xf5, 0x63, 0x39, + 0xcd, 0x0f, 0x51, 0xdf, 0x58, 0x01, 0xda, 0xe8, 0xad, 0x74, 0xe3, 0x9b, 0x02, 0xe6, 0x6a, 0x14, + 0x3f, 0x6f, 0x3b, 0x90, 0xa1, 0x7d, 0x3e, 0x4d, 0xea, 0x1e, 0xc8, 0xc3, 0x63, 0x76, 0x44, 0x02, + 0x97, 0x75, 0x85, 0x15, 0x1b, 0xbf, 0x7b, 0x85, 0x9b, 0x5d, 0xe8, 0xb5, 0xca, 0x86, 0x0c, 0x19, + 0xe3, 0xed, 0x91, 0x18, 0xf5, 0x09, 0xc8, 0x45, 0x33, 0x2a, 0x46, 0x68, 0xd5, 0x4c, 0x5d, 0x3e, + 0x66, 0x54, 0xba, 0x72, 0xad, 0x2f, 0xda, 0x16, 0x29, 0xe5, 0xc7, 0x5c, 0xaa, 0x24, 0xeb, 0x4b, + 0x1d, 0x6c, 0xb8, 0x37, 0x89, 0x4d, 0x30, 0xa4, 0xc0, 0x58, 0x02, 0x0b, 0x43, 0x57, 0xb1, 0xe0, + 0xad, 0xd3, 0x2c, 0xc8, 0xd6, 0x28, 0x56, 0x09, 0x98, 0x16, 0x63, 0xc5, 0x60, 0x13, 0xa9, 0x0f, + 0xc6, 0xbc, 0x2b, 0x6d, 0x14, 0xb5, 0xed, 0xff, 0x00, 0xc7, 0x85, 0xd5, 0x57, 0x60, 0x2e, 0xd1, + 0x8b, 0xbc, 0x68, 0x71, 0x3c, 0xcf, 0x70, 0xfb, 0x6a, 0x5b, 0x57, 0xc7, 0xca, 0x92, 0x3e, 0x98, + 0x1d, 0x7c, 0xdf, 0xbc, 0xe2, 0xfd, 0x7f, 0xb3, 0x88, 0x0c, 0xad, 0x74, 0x65, 0xa8, 0xac, 0xf7, + 0x12, 0xdc, 0xb8, 0xd4, 0x48, 0xf7, 0xc6, 0x53, 0x24, 0x71, 0x9a, 0x79, 0x35, 0x5c, 0x5c, 0x47, + 0xbb, 0xfe, 0xf6, 0xe2, 0xa4, 0xa8, 0x54, 0x6a, 0xa7, 0xa1, 0xae, 0x9c, 0x85, 0xba, 0xf2, 0x33, + 0xd4, 0x95, 0x0f, 0xe7, 0x7a, 0xe6, 0xec, 0x5c, 0xcf, 0x7c, 0x3f, 0xd7, 0x33, 0x2f, 0xb6, 0x13, + 0x5b, 0x26, 0xa6, 0xde, 0x6c, 0xc1, 0x3a, 0xb5, 0x52, 0xdb, 0x87, 0xaf, 0x9d, 0x7a, 0x8e, 0xff, + 0x8a, 0x6c, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x0a, 0xf5, 0x8d, 0x96, 0x45, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -782,16 +785,20 @@ func (m *MsgDelegateOperator) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + 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 = encodeVarintMessages(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a } - i -= size - i = encodeVarintMessages(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x1a if m.OperatorID != 0 { i = encodeVarintMessages(dAtA, i, uint64(m.OperatorID)) i-- @@ -1009,8 +1016,12 @@ func (m *MsgDelegateOperator) Size() (n int) { if m.OperatorID != 0 { n += 1 + sovMessages(uint64(m.OperatorID)) } - l = m.Amount.Size() - n += 1 + l + sovMessages(uint64(l)) + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovMessages(uint64(l)) + } + } return n } @@ -1354,7 +1365,8 @@ func (m *MsgDelegateOperator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/restaking/types/messages_test.go b/x/restaking/types/messages_test.go index 4a85a4c4d..8360423b6 100644 --- a/x/restaking/types/messages_test.go +++ b/x/restaking/types/messages_test.go @@ -70,7 +70,7 @@ func TestMsgJoinRestakingPool_GetSigners(t *testing.T) { var msgDelegateOperator = types.NewMsgDelegateOperator( 1, - sdk.NewCoin("umilk", sdkmath.NewInt(100_000_000)), + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100_000_000))), "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", ) @@ -93,7 +93,7 @@ func TestMsgDelegateOperator_ValidateBasic(t *testing.T) { name: "invalid amount returns error", msg: types.NewMsgDelegateOperator( msgDelegateOperator.OperatorID, - sdk.Coin{Denom: "invalid!", Amount: sdkmath.NewInt(100_000_000)}, + sdk.Coins{sdk.Coin{Denom: "invalid!", Amount: sdkmath.NewInt(100_000_000)}}, msgDelegateOperator.Delegator, ), shouldErr: true, @@ -127,7 +127,7 @@ func TestMsgDelegateOperator_ValidateBasic(t *testing.T) { } func TestMsgDelegateOperator_GetSignBytes(t *testing.T) { - expected := `{"type":"milkyway/MsgDelegateOperator","value":{"amount":{"amount":"100000000","denom":"umilk"},"delegator":"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd","operator_id":1}}` + expected := `{"type":"milkyway/MsgDelegateOperator","value":{"amount":[{"amount":"100000000","denom":"umilk"}],"delegator":"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd","operator_id":1}}` require.Equal(t, expected, string(msgDelegateOperator.GetSignBytes())) } From 0a766d00a4f33ae70cf7c5bdd0a1f2c6c79b7dad Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 13:21:49 -0500 Subject: [PATCH 17/37] feat(tests): add operator restaking tests --- x/operators/types/models.go | 55 +- x/restaking/keeper/common_test.go | 26 +- x/restaking/keeper/operator_restaking.go | 4 +- x/restaking/keeper/operator_restaking_test.go | 551 ++++++++++++++++++ x/restaking/types/expected_keepers.go | 2 +- 5 files changed, 607 insertions(+), 31 deletions(-) create mode 100644 x/restaking/keeper/operator_restaking_test.go diff --git a/x/operators/types/models.go b/x/operators/types/models.go index 37e624786..37b901976 100644 --- a/x/operators/types/models.go +++ b/x/operators/types/models.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -35,13 +36,15 @@ func NewOperator( admin string, ) Operator { return Operator{ - ID: id, - Status: status, - Moniker: moniker, - Website: website, - PictureURL: pictureURL, - Admin: admin, - Address: GetOperatorAddress(id).String(), + ID: id, + Status: status, + Admin: admin, + Moniker: moniker, + Website: website, + PictureURL: pictureURL, + Address: GetOperatorAddress(id).String(), + Tokens: sdk.NewCoins(), + DelegatorShares: sdk.NewDecCoins(), } } @@ -86,19 +89,15 @@ func (o Operator) InvalidExRate() bool { // SharesFromTokens returns the shares of a delegation given a bond amount. It // returns an error if the pool has no tokens. -func (o Operator) SharesFromTokens(tokens sdk.Coins) (sdk.DecCoins, error) { +func (o Operator) SharesFromTokens(tokens sdk.Coin) (sdkmath.LegacyDec, error) { if o.Tokens.IsZero() { - return nil, ErrInsufficientShares + return sdkmath.LegacyZeroDec(), ErrInsufficientShares } - shares := sdk.NewDecCoins() - for _, token := range tokens { - tokenDelegatorShares := o.DelegatorShares.AmountOf(token.Denom) - tokenAmount := o.Tokens.AmountOf(token.Denom) - shares = shares.Add(sdk.NewDecCoinFromDec(token.Denom, tokenDelegatorShares.MulInt(token.Amount).QuoInt(tokenAmount))) - } + delegatorTokenShares := o.DelegatorShares.AmountOf(tokens.Denom) + operatorTokenAmount := o.Tokens.AmountOf(tokens.Denom) - return shares, nil + return delegatorTokenShares.MulInt(tokens.Amount).QuoInt(operatorTokenAmount), nil } // AddTokensFromDelegation adds the given amount of tokens to the pool's total tokens, @@ -106,17 +105,23 @@ func (o Operator) SharesFromTokens(tokens sdk.Coins) (sdk.DecCoins, error) { // It returns the updated pool and the shares issued. func (o Operator) AddTokensFromDelegation(amount sdk.Coins) (Operator, sdk.DecCoins) { // calculate the shares to issue - var issuedShares sdk.DecCoins - if o.DelegatorShares.IsZero() { - // the first delegation to a operator sets the exchange rate to one - issuedShares = sdk.NewDecCoinsFromCoins(amount...) - } else { - shares, err := o.SharesFromTokens(amount) - if err != nil { - panic(err) + issuedShares := sdk.NewDecCoins() + for _, token := range amount { + var tokenShares sdk.DecCoin + delegatorShares := o.DelegatorShares.AmountOf(token.Denom) + + if delegatorShares.IsZero() { + // The first delegation to an operator sets the exchange rate to one + tokenShares = sdk.NewDecCoinFromCoin(token) + } else { + shares, err := o.SharesFromTokens(token) + if err != nil { + panic(err) + } + tokenShares = sdk.NewDecCoinFromDec(token.Denom, shares) } - issuedShares = shares + issuedShares = issuedShares.Add(tokenShares) } o.Tokens = o.Tokens.Add(amount...) diff --git a/x/restaking/keeper/common_test.go b/x/restaking/keeper/common_test.go index e12ed0b7b..6606813ca 100644 --- a/x/restaking/keeper/common_test.go +++ b/x/restaking/keeper/common_test.go @@ -14,8 +14,12 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/milkyway-labs/milkyway/app" + appkeepers "github.com/milkyway-labs/milkyway/app/keepers" bankkeeper "github.com/milkyway-labs/milkyway/x/bank/keeper" + operatorskeeper "github.com/milkyway-labs/milkyway/x/operators/keeper" + operatorstypes "github.com/milkyway-labs/milkyway/x/operators/types" poolskeeper "github.com/milkyway-labs/milkyway/x/pools/keeper" + poolstypes "github.com/milkyway-labs/milkyway/x/pools/types" "github.com/milkyway-labs/milkyway/x/restaking/keeper" "github.com/milkyway-labs/milkyway/x/restaking/types" @@ -44,12 +48,16 @@ type KeeperTestSuite struct { ak authkeeper.AccountKeeper bk bankkeeper.Keeper pk *poolskeeper.Keeper + ok *operatorskeeper.Keeper k *keeper.Keeper } func (suite *KeeperTestSuite) SetupTest() { // Define store keys - keys := storetypes.NewKVStoreKeys(types.StoreKey, authtypes.StoreKey, banktypes.StoreKey) + keys := storetypes.NewKVStoreKeys( + types.StoreKey, + authtypes.StoreKey, banktypes.StoreKey, poolstypes.StoreKey, operatorstypes.StoreKey, + ) suite.storeKey = keys[types.StoreKey] // Create logger @@ -73,6 +81,7 @@ func (suite *KeeperTestSuite) SetupTest() { authorityAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() // Build keepers + suite.ak = authkeeper.NewAccountKeeper( suite.cdc, runtime.NewKVStoreService(keys[authtypes.StoreKey]), @@ -90,18 +99,29 @@ func (suite *KeeperTestSuite) SetupTest() { authorityAddr, logger, ) + communityPoolKeeper := appkeepers.NewCommunityPoolKeeper( + suite.bk, + authtypes.FeeCollectorName, + ) suite.pk = poolskeeper.NewKeeper( suite.cdc, - suite.storeKey, + keys[poolstypes.StoreKey], suite.ak, ) + suite.ok = operatorskeeper.NewKeeper( + suite.cdc, + keys[operatorstypes.StoreKey], + suite.ak, + communityPoolKeeper, + authorityAddr, + ) suite.k = keeper.NewKeeper( suite.cdc, suite.storeKey, suite.ak, suite.bk, suite.pk, - nil, + suite.ok, authorityAddr, ).SetHooks(newMockHooks()) } diff --git a/x/restaking/keeper/operator_restaking.go b/x/restaking/keeper/operator_restaking.go index 9043948ae..59eb70907 100644 --- a/x/restaking/keeper/operator_restaking.go +++ b/x/restaking/keeper/operator_restaking.go @@ -44,8 +44,8 @@ func (k *Keeper) AddOperatorTokensAndShares( operator, addedShares = operator.AddTokensFromDelegation(tokensToAdd) // Save the operator - err = k.operatorsKeeper.SaveOperator(ctx, operator) - return operator, addedShares, err + k.operatorsKeeper.SaveOperator(ctx, operator) + return operator, addedShares, nil } // -------------------------------------------------------------------------------------------------------------------- diff --git a/x/restaking/keeper/operator_restaking_test.go b/x/restaking/keeper/operator_restaking_test.go new file mode 100644 index 000000000..dc559cc6d --- /dev/null +++ b/x/restaking/keeper/operator_restaking_test.go @@ -0,0 +1,551 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + operatorstypes "github.com/milkyway-labs/milkyway/x/operators/types" + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +func (suite *KeeperTestSuite) TestKeeper_SaveOperatorDelegation() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + delegation types.OperatorDelegation + check func(ctx sdk.Context) + }{ + { + name: "operator delegation is stored properly", + delegation: types.NewOperatorDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), + check: func(ctx sdk.Context) { + store := ctx.KVStore(suite.storeKey) + + // Make sure the user-operator delegation key exists and contains the delegation + delegationBz := store.Get(types.UserOperatorDelegationStoreKey("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", 1)) + suite.Require().NotNil(delegationBz) + + delegation, err := types.UnmarshalOperatorDelegation(suite.cdc, delegationBz) + suite.Require().NoError(err) + + suite.Require().Equal(types.NewOperatorDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), delegation) + + // Make sure the operator-user delegation key exists + hasDelegationsByOperatorKey := store.Has(types.DelegationByOperatorIDStoreKey(1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4")) + suite.Require().True(hasDelegationsByOperatorKey) + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + suite.k.SaveOperatorDelegation(ctx, tc.delegation) + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +func (suite *KeeperTestSuite) TestKeeper_GetOperatorDelegation() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + operatorID uint32 + userAddress string + expFound bool + expDelegation types.OperatorDelegation + check func(ctx sdk.Context) + }{ + { + name: "not found delegation returns false", + operatorID: 1, + userAddress: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + expFound: false, + }, + { + name: "found delegation is returned properly", + store: func(ctx sdk.Context) { + suite.k.SaveOperatorDelegation(ctx, types.NewOperatorDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + )) + }, + operatorID: 1, + userAddress: "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + expFound: true, + expDelegation: types.NewOperatorDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + delegation, found := suite.k.GetOperatorDelegation(ctx, tc.operatorID, tc.userAddress) + if !tc.expFound { + suite.Require().False(found) + } else { + suite.Require().True(found) + suite.Require().Equal(tc.expDelegation, delegation) + } + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +func (suite *KeeperTestSuite) TestKeeper_AddOperatorTokensAndShares() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + operator operatorstypes.Operator + tokensToAdd sdk.Coins + shouldErr bool + expOperator operatorstypes.Operator + expAddedShares sdk.DecCoins + check func(ctx sdk.Context) + }{ + { + name: "adding tokens to an empty operator works properly", + operator: operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + }, + tokensToAdd: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + shouldErr: false, + expOperator: operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + }, + expAddedShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + }, + { + name: "adding tokens to a non-empty operator works properly", + operator: operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(50))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + }, + tokensToAdd: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), + shouldErr: false, + expOperator: operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(70))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(140))), + }, + expAddedShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(40))), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + operator, addedShares, err := suite.k.AddOperatorTokensAndShares(ctx, tc.operator, tc.tokensToAdd) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + suite.Require().Equal(tc.expOperator, operator) + suite.Require().Equal(tc.expAddedShares, addedShares) + } + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + operatorID uint32 + amount sdk.Coins + delegator string + shouldErr bool + expShares sdk.DecCoins + check func(ctx sdk.Context) + }{ + { + name: "operator not found returns error", + operatorID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: true, + }, + { + name: "invalid exchange rate operator returns error", + store: func(ctx sdk.Context) { + suite.ok.SaveOperator(ctx, operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins(), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + }) + }, + operatorID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: true, + }, + { + name: "invalid delegator address returns error", + store: func(ctx sdk.Context) { + suite.ok.SaveOperator(ctx, operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + }) + }, + operatorID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "invalid", + shouldErr: true, + }, + { + name: "insufficient funds return error", + store: func(ctx sdk.Context) { + // Create the operator + suite.ok.SaveOperator(ctx, operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + }) + + // Set the next operator id + suite.ok.SetNextOperatorID(ctx, 2) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(50))), + ) + }, + operatorID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: true, + }, + { + name: "delegating to an existing operator works properly", + store: func(ctx sdk.Context) { + // Create the operator + suite.ok.SaveOperator(ctx, operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + }) + + // Set the correct operator tokens amount + suite.fundAccount( + ctx, + operatorstypes.GetOperatorAddress(1).String(), + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), + ) + + // Set the next operator id + suite.ok.SetNextOperatorID(ctx, 2) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + operatorID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: false, + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(500))), + check: func(ctx sdk.Context) { + // Make sure the operator now exists + operator, found := suite.ok.GetOperator(ctx, 1) + suite.Require().True(found) + suite.Require().Equal(operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(120))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(600))), + }, operator) + + // Make sure the delegation exists + delegation, found := suite.k.GetOperatorDelegation(ctx, 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4") + suite.Require().True(found) + suite.Require().Equal(types.NewOperatorDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(500))), + ), delegation) + + // Make sure the user balance has been reduced properly + userBalance := suite.bk.GetBalance(ctx, sdk.AccAddress("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(0)), userBalance) + + // Make sure the operator account balance has increased properly + operatorBalance := suite.bk.GetBalance(ctx, operatorstypes.GetOperatorAddress(1), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(120)), operatorBalance) + }, + }, + { + name: "delegating another token denom works properly", + store: func(ctx sdk.Context) { + // Create the operator + suite.ok.SaveOperator(ctx, operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(80))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125))), + }) + + // Set the correct operator tokens amount + suite.fundAccount( + ctx, + operatorstypes.GetOperatorAddress(1).String(), + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(80))), + ) + + // Set the next operator id + suite.ok.SetNextOperatorID(ctx, 2) + + // Save the existing delegation + suite.k.SaveOperatorDelegation(ctx, types.NewOperatorDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125))), + )) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("uinit", sdkmath.NewInt(100))), + ) + }, + operatorID: 1, + amount: sdk.NewCoins(sdk.NewCoin("uinit", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: false, + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100))), + check: func(ctx sdk.Context) { + // Make sure the operator now exists + operator, found := suite.ok.GetOperator(ctx, 1) + suite.Require().True(found) + suite.Require().Equal(operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(80)), + sdk.NewCoin("uinit", sdkmath.NewInt(100)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100)), + ), + }, operator) + + // Make sure the delegation has been updated properly + delegation, found := suite.k.GetOperatorDelegation(ctx, 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4") + suite.Require().True(found) + suite.Require().Equal(types.NewOperatorDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100)), + ), + ), delegation) + + // Make sure the user balance has been reduced properly + userBalance := suite.bk.GetBalance(ctx, sdk.AccAddress("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(0)), userBalance) + + // Make sure the operator account balance has increased properly + operatorBalance := suite.bk.GetAllBalances(ctx, operatorstypes.GetOperatorAddress(1)) + suite.Require().Equal(sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(80)), + sdk.NewCoin("uinit", sdkmath.NewInt(100)), + ), operatorBalance) + }, + }, + { + name: "delegating more tokens works properly", + store: func(ctx sdk.Context) { + // Create the operator + suite.ok.SaveOperator(ctx, operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(80)), + sdk.NewCoin("uinit", sdkmath.NewInt(75)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(200)), + ), + }) + + // Set the correct operator tokens amount + suite.fundAccount( + ctx, + operatorstypes.GetOperatorAddress(1).String(), + sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(80)), + sdk.NewCoin("uinit", sdkmath.NewInt(75)), + ), + ) + + // Set the next operator id + suite.ok.SetNextOperatorID(ctx, 2) + + // Save the existing delegation + suite.k.SaveOperatorDelegation(ctx, types.NewOperatorDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(60)), + ), + )) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdk.NewCoin("uinit", sdkmath.NewInt(225)), + ), + ) + }, + operatorID: 1, + amount: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdk.NewCoin("uinit", sdkmath.NewInt(225)), + ), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: false, + expShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(15625, 2)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(600)), + ), + check: func(ctx sdk.Context) { + // Make sure the operator now exists + operator, found := suite.ok.GetOperator(ctx, 1) + suite.Require().True(found) + suite.Require().Equal(operatorstypes.Operator{ + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(180)), + sdk.NewCoin("uinit", sdkmath.NewInt(300)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(28125, 2)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(800)), + ), + }, operator) + + // Make sure the delegation has been updated properly + delegation, found := suite.k.GetOperatorDelegation(ctx, 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4") + suite.Require().True(found) + suite.Require().Equal(types.NewOperatorDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(25625, 2)), // 100 (existing) + 156.25 (new) + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(660)), // 60 (existing) + 600 (new) + ), + ), delegation) + + // Make sure the user balance has been reduced properly + userBalance := suite.bk.GetBalance(ctx, sdk.AccAddress("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(0)), userBalance) + + // Make sure the operator account balance has increased properly + operatorBalance := suite.bk.GetAllBalances(ctx, operatorstypes.GetOperatorAddress(1)) + suite.Require().Equal(sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(180)), + sdk.NewCoin("uinit", sdkmath.NewInt(300)), + ), operatorBalance) + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + shares, err := suite.k.DelegateToOperator(ctx, tc.operatorID, tc.amount, tc.delegator) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + suite.Require().Equal(tc.expShares, shares) + } + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} diff --git a/x/restaking/types/expected_keepers.go b/x/restaking/types/expected_keepers.go index a7e2f87b3..f4954deb4 100644 --- a/x/restaking/types/expected_keepers.go +++ b/x/restaking/types/expected_keepers.go @@ -30,5 +30,5 @@ type ServicesKeeper interface { type OperatorsKeeper interface { GetOperator(ctx sdk.Context, operatorID uint32) (operatorstypes.Operator, bool) - SaveOperator(ctx sdk.Context, operator operatorstypes.Operator) error + SaveOperator(ctx sdk.Context, operator operatorstypes.Operator) } From 83fab63f8026f7aaeecdde9e12ce0723b7b915c6 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 13:49:45 -0500 Subject: [PATCH 18/37] chore: add comments --- x/restaking/types/delegation.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/restaking/types/delegation.go b/x/restaking/types/delegation.go index 83130a229..d7f2e9c92 100644 --- a/x/restaking/types/delegation.go +++ b/x/restaking/types/delegation.go @@ -4,16 +4,20 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// DelegationReceiver is an interface that represents the receiver of a delegation (operator, pool, service, etc). type DelegationReceiver interface { GetID() uint32 GetAddress() string InvalidExRate() bool } +// DelegationGetter represents a function that allows to retrieve an existing delegation type DelegationGetter func(ctx sdk.Context, receiverID uint32, delegator string) (Delegation, bool) +// DelegationBuilder represents a function that allows to build a new delegation type DelegationBuilder func(receiverID uint32, delegator string) Delegation +// DelegationUpdater represents a function that allows to update an existing delegation type DelegationUpdater func(ctx sdk.Context, delegation Delegation) (newShares sdk.DecCoins, err error) // Delegation is an interface that represents a delegation object. From 94d236c773fdb29e56bc80660a8fc78f90ad20b6 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 14:32:23 -0500 Subject: [PATCH 19/37] feat: add check on operator status --- proto/milkyway/restaking/v1/models.proto | 5 ++--- proto/milkyway/services/v1/models.proto | 13 ++++++++++++ x/operators/types/errors.go | 3 ++- x/operators/types/models.go | 5 +++++ x/restaking/keeper/operator_restaking.go | 5 +++++ x/restaking/keeper/operator_restaking_test.go | 20 +++++++++++++++++++ 6 files changed, 47 insertions(+), 4 deletions(-) diff --git a/proto/milkyway/restaking/v1/models.proto b/proto/milkyway/restaking/v1/models.proto index 75240f0fb..753efd86e 100644 --- a/proto/milkyway/restaking/v1/models.proto +++ b/proto/milkyway/restaking/v1/models.proto @@ -62,9 +62,8 @@ message ServiceDelegation { uint32 service_id = 2 [ (gogoproto.customname) = "ServiceID" ]; // Shares define the delegation shares received. - string shares = 3 [ - (cosmos_proto.scalar) = "cosmos.Dec", - (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + repeated cosmos.base.v1beta1.DecCoin shares = 3 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", (gogoproto.nullable) = false ]; } \ No newline at end of file diff --git a/proto/milkyway/services/v1/models.proto b/proto/milkyway/services/v1/models.proto index 73b8765a9..59347523b 100644 --- a/proto/milkyway/services/v1/models.proto +++ b/proto/milkyway/services/v1/models.proto @@ -3,6 +3,7 @@ package milkyway.services.v1; import "gogoproto/gogo.proto"; import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; option go_package = "github.com/milkyway-labs/milkyway/x/services/types"; @@ -52,4 +53,16 @@ message Service { // This will be used in order to store all the tokens that are delegated to // this service by various users. string address = 8 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // Tokens define the delegated tokens. + repeated cosmos.base.v1beta1.Coin tokens = 9 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.nullable) = false + ]; + + // DelegatorShares define the total shares issued to an operator's delegators. + repeated cosmos.base.v1beta1.DecCoin delegator_shares = 10 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.nullable) = false + ]; } diff --git a/x/operators/types/errors.go b/x/operators/types/errors.go index a0e6314fc..dd51f5a96 100644 --- a/x/operators/types/errors.go +++ b/x/operators/types/errors.go @@ -8,5 +8,6 @@ var ( ErrInvalidGenesis = errors.Register(ModuleName, 1, "invalid genesis state") ErrInvalidDeactivationTime = errors.Register(ModuleName, 2, "invalid deactivation time") ErrOperatorNotFound = errors.Register(ModuleName, 3, "operator not found") - ErrInsufficientShares = errors.Register(ModuleName, 4, "insufficient delegation shares") + ErrOperatorNotActive = errors.Register(ModuleName, 4, "operator not active") + ErrInsufficientShares = errors.Register(ModuleName, 3, "insufficient delegation shares") ) diff --git a/x/operators/types/models.go b/x/operators/types/models.go index 37b901976..57ecba0c9 100644 --- a/x/operators/types/models.go +++ b/x/operators/types/models.go @@ -75,6 +75,11 @@ func (o *Operator) Validate() error { return nil } +// IsActive returns whether the operator is active. +func (o Operator) IsActive() bool { + return o.Status == OPERATOR_STATUS_ACTIVE +} + // InvalidExRate returns whether the exchange rates is invalid. // This can happen e.g. if Pool loses all tokens due to slashing. In this case, // make all future delegations invalid. diff --git a/x/restaking/keeper/operator_restaking.go b/x/restaking/keeper/operator_restaking.go index 59eb70907..3b88edd46 100644 --- a/x/restaking/keeper/operator_restaking.go +++ b/x/restaking/keeper/operator_restaking.go @@ -58,6 +58,11 @@ func (k *Keeper) DelegateToOperator(ctx sdk.Context, operatorID uint32, amount s return sdk.NewDecCoins(), operatorstypes.ErrOperatorNotFound } + // MAke sure the operator is active + if !operator.IsActive() { + return sdk.NewDecCoins(), operatorstypes.ErrOperatorNotActive + } + return k.PerformDelegation(ctx, types.DelegationData{ Amount: amount, Delegator: delegator, diff --git a/x/restaking/keeper/operator_restaking_test.go b/x/restaking/keeper/operator_restaking_test.go index dc559cc6d..f5f56a235 100644 --- a/x/restaking/keeper/operator_restaking_test.go +++ b/x/restaking/keeper/operator_restaking_test.go @@ -225,11 +225,28 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: true, }, + { + name: "inactive operator returns error", + store: func(ctx sdk.Context) { + suite.ok.SaveOperator(ctx, operatorstypes.Operator{ + ID: 1, + Status: operatorstypes.OPERATOR_STATUS_INACTIVE, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins(), + DelegatorShares: sdk.NewDecCoins(), + }) + }, + operatorID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: true, + }, { name: "invalid exchange rate operator returns error", store: func(ctx sdk.Context) { suite.ok.SaveOperator(ctx, operatorstypes.Operator{ ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, Address: operatorstypes.GetOperatorAddress(1).String(), Tokens: sdk.NewCoins(), DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), @@ -283,6 +300,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { // Create the operator suite.ok.SaveOperator(ctx, operatorstypes.Operator{ ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, Address: operatorstypes.GetOperatorAddress(1).String(), Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), @@ -316,6 +334,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { suite.Require().True(found) suite.Require().Equal(operatorstypes.Operator{ ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, Address: operatorstypes.GetOperatorAddress(1).String(), Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(120))), DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(600))), @@ -345,6 +364,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { // Create the operator suite.ok.SaveOperator(ctx, operatorstypes.Operator{ ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, Address: operatorstypes.GetOperatorAddress(1).String(), Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(80))), DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125))), From 8c949d7b4a2af99b14f05574014e0738174806a4 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 14:44:14 -0500 Subject: [PATCH 20/37] chore: improve operators comments --- x/operators/types/models.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x/operators/types/models.go b/x/operators/types/models.go index 57ecba0c9..b42146a38 100644 --- a/x/operators/types/models.go +++ b/x/operators/types/models.go @@ -81,7 +81,7 @@ func (o Operator) IsActive() bool { } // InvalidExRate returns whether the exchange rates is invalid. -// This can happen e.g. if Pool loses all tokens due to slashing. In this case, +// This can happen e.g. if Operator loses all tokens due to slashing. In this case, // make all future delegations invalid. func (o Operator) InvalidExRate() bool { for _, token := range o.Tokens { @@ -93,7 +93,7 @@ func (o Operator) InvalidExRate() bool { } // SharesFromTokens returns the shares of a delegation given a bond amount. It -// returns an error if the pool has no tokens. +// returns an error if the operator has no tokens. func (o Operator) SharesFromTokens(tokens sdk.Coin) (sdkmath.LegacyDec, error) { if o.Tokens.IsZero() { return sdkmath.LegacyZeroDec(), ErrInsufficientShares @@ -105,9 +105,9 @@ func (o Operator) SharesFromTokens(tokens sdk.Coin) (sdkmath.LegacyDec, error) { return delegatorTokenShares.MulInt(tokens.Amount).QuoInt(operatorTokenAmount), nil } -// AddTokensFromDelegation adds the given amount of tokens to the pool's total tokens, -// also updating the pool's delegator shares. -// It returns the updated pool and the shares issued. +// AddTokensFromDelegation adds the given amount of tokens to the operator's total tokens, +// also updating the operator's delegator shares. +// It returns the updated operator and the shares issued. func (o Operator) AddTokensFromDelegation(amount sdk.Coins) (Operator, sdk.DecCoins) { // calculate the shares to issue issuedShares := sdk.NewDecCoins() From 0472c11daba647581cbebbfd0b0c6b5e3a6b50df Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 14:44:23 -0500 Subject: [PATCH 21/37] feat: add service restaking keeper methods --- x/restaking/keeper/common_test.go | 15 ++ x/restaking/keeper/hooks.go | 28 ++++ x/restaking/keeper/keeper.go | 1 + x/restaking/keeper/service_restaking.go | 101 +++++++++++++ x/restaking/types/expected_keepers.go | 9 +- x/restaking/types/genesis_test.go | 12 +- x/restaking/types/hooks.go | 7 + x/restaking/types/keys.go | 43 ++++++ x/restaking/types/models.go | 36 ++++- x/restaking/types/models.pb.go | 102 +++++++------ x/services/types/errors.go | 1 + x/services/types/models.go | 79 ++++++++-- x/services/types/models.pb.go | 193 ++++++++++++++++++++---- 13 files changed, 530 insertions(+), 97 deletions(-) create mode 100644 x/restaking/keeper/service_restaking.go diff --git a/x/restaking/keeper/common_test.go b/x/restaking/keeper/common_test.go index 6606813ca..a515b9fc8 100644 --- a/x/restaking/keeper/common_test.go +++ b/x/restaking/keeper/common_test.go @@ -184,3 +184,18 @@ func (m mockHooks) AfterOperatorDelegationModified(ctx sdk.Context, operatorID u m.CalledMap["AfterOperatorDelegationModified"] = true return nil } + +func (m mockHooks) BeforeServiceDelegationCreated(ctx sdk.Context, serviceID uint32, delegator string) error { + m.CalledMap["BeforeServiceDelegationCreated"] = true + return nil +} + +func (m mockHooks) BeforeServiceDelegationSharesModified(ctx sdk.Context, serviceID uint32, delegator string) error { + m.CalledMap["BeforeServiceDelegationSharesModified"] = true + return nil +} + +func (m mockHooks) AfterServiceDelegationModified(ctx sdk.Context, serviceID uint32, delegator string) error { + m.CalledMap["AfterServiceDelegationModified"] = true + return nil +} diff --git a/x/restaking/keeper/hooks.go b/x/restaking/keeper/hooks.go index 418588e2a..960fda0e8 100644 --- a/x/restaking/keeper/hooks.go +++ b/x/restaking/keeper/hooks.go @@ -32,6 +32,8 @@ func (k *Keeper) AfterPoolDelegationModified(ctx sdk.Context, poolID uint32, del return nil } +// -------------------------------------------------------------------------------------------------------------------- + // BeforeOperatorDelegationCreated implements types.RestakingHooks func (k *Keeper) BeforeOperatorDelegationCreated(ctx sdk.Context, operatorID uint32, delegator string) error { if k.hooks != nil { @@ -55,3 +57,29 @@ func (k *Keeper) AfterOperatorDelegationModified(ctx sdk.Context, operatorID uin } return nil } + +// -------------------------------------------------------------------------------------------------------------------- + +// BeforeServiceDelegationCreated implements types.RestakingHooks +func (k *Keeper) BeforeServiceDelegationCreated(ctx sdk.Context, serviceID uint32, delegator string) error { + if k.hooks != nil { + return k.hooks.BeforeServiceDelegationCreated(ctx, serviceID, delegator) + } + return nil +} + +// BeforeServiceDelegationSharesModified implements types.RestakingHooks +func (k *Keeper) BeforeServiceDelegationSharesModified(ctx sdk.Context, serviceID uint32, delegator string) error { + if k.hooks != nil { + return k.hooks.BeforeServiceDelegationSharesModified(ctx, serviceID, delegator) + } + return nil +} + +// AfterServiceDelegationModified implements types.RestakingHooks +func (k *Keeper) AfterServiceDelegationModified(ctx sdk.Context, serviceID uint32, delegator string) error { + if k.hooks != nil { + return k.hooks.AfterServiceDelegationModified(ctx, serviceID, delegator) + } + return nil +} diff --git a/x/restaking/keeper/keeper.go b/x/restaking/keeper/keeper.go index a38fc6886..c09a3e2cd 100644 --- a/x/restaking/keeper/keeper.go +++ b/x/restaking/keeper/keeper.go @@ -19,6 +19,7 @@ type Keeper struct { bankKeeper types.BankKeeper poolsKeeper types.PoolsKeeper operatorsKeeper types.OperatorsKeeper + servicesKeeper types.ServicesKeeper hooks types.RestakingHooks } diff --git a/x/restaking/keeper/service_restaking.go b/x/restaking/keeper/service_restaking.go new file mode 100644 index 000000000..6ba6225f3 --- /dev/null +++ b/x/restaking/keeper/service_restaking.go @@ -0,0 +1,101 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/milkyway-labs/milkyway/x/restaking/types" + servicestypes "github.com/milkyway-labs/milkyway/x/services/types" +) + +// SaveServiceDelegation stores the given service delegation in the store +func (k *Keeper) SaveServiceDelegation(ctx sdk.Context, delegation types.ServiceDelegation) { + store := ctx.KVStore(k.storeKey) + + // Marshal and store the delegation + delegationBz := types.MustMarshalServiceDelegation(k.cdc, delegation) + store.Set(types.UserServiceDelegationStoreKey(delegation.UserAddress, delegation.ServiceID), delegationBz) + + // Store the delegation in the delegations by service ID store + store.Set(types.DelegationByPoolIDStoreKey(delegation.ServiceID, delegation.UserAddress), []byte{}) +} + +// GetServiceDelegation retrieves the delegation for the given user and service +// If the delegation does not exist, false is returned instead +func (k *Keeper) GetServiceDelegation(ctx sdk.Context, serviceID uint32, userAddress string) (types.ServiceDelegation, bool) { + // Get the delegation amount from the store + store := ctx.KVStore(k.storeKey) + delegationAmountBz := store.Get(types.UserServiceDelegationStoreKey(userAddress, serviceID)) + if delegationAmountBz == nil { + return types.ServiceDelegation{}, false + } + + // Parse the delegation amount + return types.MustUnmarshalServiceDelegation(k.cdc, delegationAmountBz), true +} + +// AddServiceTokensAndShares adds the given amount of tokens to the service and returns the added shares +func (k *Keeper) AddServiceTokensAndShares( + ctx sdk.Context, service servicestypes.Service, tokensToAdd sdk.Coins, +) (serviceOut servicestypes.Service, addedShares sdk.DecCoins, err error) { + + // Update the service tokens and shares and get the added shares + service, addedShares = service.AddTokensFromDelegation(tokensToAdd) + + // Save the service + k.servicesKeeper.SaveService(ctx, service) + return service, addedShares, nil +} + +// -------------------------------------------------------------------------------------------------------------------- + +// DelegateToService sends the given amount to the service account and saves the delegation for the given user +func (k *Keeper) DelegateToService(ctx sdk.Context, serviceID uint32, amount sdk.Coins, delegator string) (sdk.DecCoins, error) { + // Get the service + service, found := k.servicesKeeper.GetService(ctx, serviceID) + if !found { + return sdk.NewDecCoins(), servicestypes.ErrServiceNotFound + } + + // Make sure the service is active + if !service.IsActive() { + return sdk.NewDecCoins(), servicestypes.ErrServiceNotActive + } + + return k.PerformDelegation(ctx, types.DelegationData{ + Amount: amount, + Delegator: delegator, + Receiver: &service, + GetDelegation: func(ctx sdk.Context, receiverID uint32, delegator string) (types.Delegation, bool) { + return k.GetServiceDelegation(ctx, receiverID, delegator) + }, + BuildDelegation: func(receiverID uint32, delegator string) types.Delegation { + return types.NewServiceDelegation(receiverID, delegator, sdk.NewDecCoins()) + }, + UpdateDelegation: func(ctx sdk.Context, delegation types.Delegation) (newShares sdk.DecCoins, err error) { + // Calculate the new shares and add the tokens to the service + _, newShares, err = k.AddServiceTokensAndShares(ctx, service, amount) + if err != nil { + return newShares, err + } + + // Update the delegation shares + serviceDelegation, ok := delegation.(types.ServiceDelegation) + if !ok { + return newShares, fmt.Errorf("invalid delegation type: %T", delegation) + } + serviceDelegation.Shares = serviceDelegation.Shares.Add(newShares...) + + // Store the updated delegation + k.SaveServiceDelegation(ctx, serviceDelegation) + + return newShares, err + }, + Hooks: types.DelegationHooks{ + BeforeDelegationSharesModified: k.BeforeServiceDelegationSharesModified, + BeforeDelegationCreated: k.BeforeServiceDelegationCreated, + AfterDelegationModified: k.AfterServiceDelegationModified, + }, + }) +} diff --git a/x/restaking/types/expected_keepers.go b/x/restaking/types/expected_keepers.go index f4954deb4..e0505c813 100644 --- a/x/restaking/types/expected_keepers.go +++ b/x/restaking/types/expected_keepers.go @@ -24,11 +24,12 @@ type PoolsKeeper interface { SavePool(ctx sdk.Context, pool poolstypes.Pool) error } -type ServicesKeeper interface { - GetService(ctx sdk.Context, serviceID uint32) (servicestypes.Service, bool) -} - type OperatorsKeeper interface { GetOperator(ctx sdk.Context, operatorID uint32) (operatorstypes.Operator, bool) SaveOperator(ctx sdk.Context, operator operatorstypes.Operator) } + +type ServicesKeeper interface { + GetService(ctx sdk.Context, serviceID uint32) (servicestypes.Service, bool) + SaveService(ctx sdk.Context, service servicestypes.Service) +} diff --git a/x/restaking/types/genesis_test.go b/x/restaking/types/genesis_test.go index cb03aa130..b98fe6f65 100644 --- a/x/restaking/types/genesis_test.go +++ b/x/restaking/types/genesis_test.go @@ -41,7 +41,7 @@ func TestGenesis_Validate(t *testing.T) { types.NewServiceDelegation( 0, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(100), + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), ), }, nil, @@ -94,7 +94,7 @@ func TestGenesis_Validate(t *testing.T) { types.NewServiceDelegation( 2, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(100), + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), ), }, []types.OperatorDelegation{ @@ -193,7 +193,7 @@ func TestServiceDelegation_Validate(t *testing.T) { entry: types.NewServiceDelegation( 0, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(100), + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), ), shouldErr: true, }, @@ -202,7 +202,7 @@ func TestServiceDelegation_Validate(t *testing.T) { entry: types.NewServiceDelegation( 1, "", - sdkmath.LegacyNewDec(100), + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), ), shouldErr: true, }, @@ -211,7 +211,7 @@ func TestServiceDelegation_Validate(t *testing.T) { entry: types.NewServiceDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(-100), + sdk.DecCoins{sdk.DecCoin{Denom: "umilk", Amount: sdkmath.LegacyNewDec(100)}}, ), shouldErr: true, }, @@ -220,7 +220,7 @@ func TestServiceDelegation_Validate(t *testing.T) { entry: types.NewServiceDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(100), + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), ), shouldErr: false, }, diff --git a/x/restaking/types/hooks.go b/x/restaking/types/hooks.go index 50c2b4ca4..e13cda079 100644 --- a/x/restaking/types/hooks.go +++ b/x/restaking/types/hooks.go @@ -7,6 +7,7 @@ import ( type RestakingHooks interface { PoolRestakingHooks OperatorRestakingHooks + ServiceRestakingHooks } type PoolRestakingHooks interface { @@ -20,3 +21,9 @@ type OperatorRestakingHooks interface { BeforeOperatorDelegationSharesModified(ctx sdk.Context, operatorID uint32, delegator string) error AfterOperatorDelegationModified(ctx sdk.Context, operatorID uint32, delegator string) error } + +type ServiceRestakingHooks interface { + BeforeServiceDelegationCreated(ctx sdk.Context, serviceID uint32, delegator string) error + BeforeServiceDelegationSharesModified(ctx sdk.Context, serviceID uint32, delegator string) error + AfterServiceDelegationModified(ctx sdk.Context, serviceID uint32, delegator string) error +} diff --git a/x/restaking/types/keys.go b/x/restaking/types/keys.go index 7306973d3..226b644b6 100644 --- a/x/restaking/types/keys.go +++ b/x/restaking/types/keys.go @@ -6,6 +6,7 @@ import ( operatorstypes "github.com/milkyway-labs/milkyway/x/operators/types" poolstypes "github.com/milkyway-labs/milkyway/x/pools/types" + servicestypes "github.com/milkyway-labs/milkyway/x/services/types" ) const ( @@ -108,3 +109,45 @@ func ParseDelegationsByOperatorIDKey(bz []byte) (operatorID uint32, delegatorAdd return operatorID, delegatorAddress, nil } + +// -------------------------------------------------------------------------------------------------------------------- + +// UserServiceDelegationsStorePrefix returns the prefix used to store all the delegations to a given service +func UserServiceDelegationsStorePrefix(userAddress string) []byte { + return append(ServiceDelegationPrefix, []byte(userAddress)...) +} + +// UserServiceDelegationStoreKey returns the key used to store the user -> service delegation association +func UserServiceDelegationStoreKey(delegator string, serviceID uint32) []byte { + return append(UserServiceDelegationsStorePrefix(delegator), servicestypes.GetServiceIDBytes(serviceID)...) +} + +// DelegationsByServiceIDStorePrefix returns the prefix used to store the delegations to a given service +func DelegationsByServiceIDStorePrefix(serviceID uint32) []byte { + return append(ServiceDelegationPrefix, servicestypes.GetServiceIDBytes(serviceID)...) +} + +// DelegationByServiceIDStoreKey returns the key used to store the service -> user delegation association +func DelegationByServiceIDStoreKey(serviceID uint32, delegatorAddress string) []byte { + return append(DelegationsByServiceIDStorePrefix(serviceID), []byte(delegatorAddress)...) +} + +// ParseDelegationsByServiceIDKey parses the service ID and delegator address from the given key +func ParseDelegationsByServiceIDKey(bz []byte) (serviceID uint32, delegatorAddress string, err error) { + prefixLength := len(ServiceDelegationPrefix) + if prefix := bz[:prefixLength]; !bytes.Equal(prefix, ServiceDelegationPrefix) { + return 0, "", fmt.Errorf("invalid prefix; expected: %X, got: %x", ServiceDelegationPrefix, prefix) + } + + // Remove the prefix + bz = bz[prefixLength:] + + // Read the service ID + serviceID = servicestypes.GetServiceIDFromBytes(bz[:4]) + bz = bz[4:] + + // Read the delegator address + delegatorAddress = string(bz) + + return serviceID, delegatorAddress, nil +} diff --git a/x/restaking/types/models.go b/x/restaking/types/models.go index 34398ecda..0df899b75 100644 --- a/x/restaking/types/models.go +++ b/x/restaking/types/models.go @@ -125,7 +125,7 @@ func MustUnmarshalOperatorDelegation(cdc codec.BinaryCodec, bz []byte) OperatorD // -------------------------------------------------------------------------------------------------------------------- -func NewServiceDelegation(serviceID uint32, userAddress string, shares sdkmath.LegacyDec) ServiceDelegation { +func NewServiceDelegation(serviceID uint32, userAddress string, shares sdk.DecCoins) ServiceDelegation { return ServiceDelegation{ ServiceID: serviceID, UserAddress: userAddress, @@ -133,6 +133,10 @@ func NewServiceDelegation(serviceID uint32, userAddress string, shares sdkmath.L } } +// isDelegation implements Delegation +func (d ServiceDelegation) isDelegation() {} + +// Validate validates the service delegation func (d ServiceDelegation) Validate() error { if d.ServiceID == 0 { return fmt.Errorf("invalid service id") @@ -143,9 +147,37 @@ func (d ServiceDelegation) Validate() error { return fmt.Errorf("invalid user address: %s", d.UserAddress) } - if d.Shares.IsNegative() { + if d.Shares.IsAnyNegative() { return ErrInvalidShares } return nil } + +// MustMarshalServiceDelegation marshals the given service delegation using the provided codec +func MustMarshalServiceDelegation(cdc codec.BinaryCodec, delegation ServiceDelegation) []byte { + bz, err := cdc.Marshal(&delegation) + if err != nil { + panic(err) + } + return bz +} + +// UnmarshalServiceDelegation unmarshals a service delegation from the given bytes using the provided codec +func UnmarshalServiceDelegation(cdc codec.BinaryCodec, bz []byte) (ServiceDelegation, error) { + var delegation ServiceDelegation + err := cdc.Unmarshal(bz, &delegation) + if err != nil { + return ServiceDelegation{}, err + } + return delegation, nil +} + +// MustUnmarshalServiceDelegation unmarshals a service delegation from the given bytes using the provided codec +func MustUnmarshalServiceDelegation(cdc codec.BinaryCodec, bz []byte) ServiceDelegation { + delegation, err := UnmarshalServiceDelegation(cdc, bz) + if err != nil { + panic(err) + } + return delegation +} diff --git a/x/restaking/types/models.pb.go b/x/restaking/types/models.pb.go index e43988d41..e22875135 100644 --- a/x/restaking/types/models.pb.go +++ b/x/restaking/types/models.pb.go @@ -126,7 +126,7 @@ type ServiceDelegation struct { // ServiceID is the id of the service. ServiceID uint32 `protobuf:"varint,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` // Shares define the delegation shares received. - Shares cosmossdk_io_math.LegacyDec `protobuf:"bytes,3,opt,name=shares,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"shares"` + Shares github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,3,rep,name=shares,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"shares"` } func (m *ServiceDelegation) Reset() { *m = ServiceDelegation{} } @@ -174,36 +174,36 @@ func init() { var fileDescriptor_86f4cd48423b1e2f = []byte{ // 473 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x31, 0x6f, 0xd3, 0x40, - 0x14, 0xf6, 0x51, 0x29, 0x90, 0x0b, 0xad, 0x54, 0xab, 0x48, 0xa1, 0x20, 0xbb, 0x0a, 0x4b, 0x24, - 0x88, 0x4f, 0x26, 0x1b, 0x4c, 0x04, 0x2f, 0x96, 0x40, 0x20, 0x77, 0x63, 0x89, 0xce, 0xf6, 0xc9, - 0x39, 0xc5, 0xf6, 0x8b, 0xee, 0xae, 0x01, 0xff, 0x03, 0x46, 0x7e, 0x42, 0x67, 0xe6, 0xfe, 0x07, - 0x3a, 0x56, 0x65, 0x41, 0x0c, 0x06, 0x39, 0x0b, 0xff, 0x80, 0x15, 0xd9, 0x3e, 0xb7, 0x19, 0x18, - 0xdb, 0xc5, 0xf6, 0x7b, 0xef, 0xf3, 0xf7, 0xe9, 0xfb, 0xee, 0x1e, 0x1e, 0x65, 0x3c, 0x5d, 0x16, - 0x1f, 0x69, 0x41, 0x04, 0x93, 0x8a, 0x2e, 0x79, 0x9e, 0x90, 0xb5, 0x4b, 0x32, 0x88, 0x59, 0x2a, - 0x9d, 0x95, 0x00, 0x05, 0xe6, 0x83, 0x0e, 0xe3, 0x5c, 0x61, 0x9c, 0xb5, 0x7b, 0xb8, 0x4f, 0x33, - 0x9e, 0x03, 0x69, 0x9e, 0x2d, 0xf2, 0xf0, 0x61, 0x04, 0x32, 0x03, 0x39, 0x6f, 0x2a, 0xd2, 0x16, - 0x7a, 0x74, 0x90, 0x40, 0x02, 0x6d, 0xbf, 0xfe, 0xd2, 0x5d, 0xab, 0xc5, 0x90, 0x90, 0x4a, 0x46, - 0xd6, 0x6e, 0xc8, 0x14, 0x75, 0x49, 0x04, 0x3c, 0x6f, 0xe7, 0xa3, 0x6f, 0x08, 0xef, 0xbd, 0x07, - 0x48, 0x3d, 0x96, 0xb2, 0x84, 0x2a, 0x0e, 0xb9, 0xf9, 0x12, 0xdf, 0x3f, 0x91, 0x4c, 0xcc, 0x69, - 0x1c, 0x0b, 0x26, 0xe5, 0x10, 0x1d, 0xa1, 0x71, 0x7f, 0x36, 0xbc, 0x3c, 0x9b, 0x1c, 0x68, 0xc1, - 0x57, 0xed, 0xe4, 0x58, 0x09, 0x9e, 0x27, 0xc1, 0xa0, 0x46, 0xeb, 0x96, 0xf9, 0x04, 0xdf, 0x5d, - 0x01, 0xa4, 0x73, 0x1e, 0x0f, 0xef, 0x1c, 0xa1, 0xf1, 0xee, 0x0c, 0x57, 0xa5, 0xdd, 0xab, 0x15, - 0x7c, 0x2f, 0xe8, 0xd5, 0x23, 0x3f, 0x36, 0x7d, 0xdc, 0x93, 0x0b, 0x2a, 0x98, 0x1c, 0xee, 0x34, - 0xdc, 0xee, 0x79, 0x69, 0x1b, 0x3f, 0x4b, 0xfb, 0x51, 0xcb, 0x2f, 0xe3, 0xa5, 0xc3, 0x81, 0x64, - 0x54, 0x2d, 0x9c, 0x37, 0x2c, 0xa1, 0x51, 0xe1, 0xb1, 0xe8, 0xf2, 0x6c, 0x82, 0xb5, 0xbc, 0xc7, - 0xa2, 0x40, 0x13, 0xbc, 0xb8, 0xf7, 0xf9, 0xd4, 0x36, 0xfe, 0x9c, 0xda, 0xc6, 0xe8, 0x2f, 0xc2, - 0xe6, 0xbb, 0x15, 0x13, 0x54, 0x81, 0xb8, 0x29, 0x37, 0x04, 0x0f, 0x40, 0x53, 0x5e, 0x3b, 0xda, - 0xab, 0x4a, 0x1b, 0x77, 0x4a, 0xbe, 0x17, 0xe0, 0x0e, 0xe2, 0xc7, 0x26, 0xdf, 0x72, 0xb6, 0x33, - 0x1e, 0x3c, 0x7f, 0xec, 0x68, 0x91, 0x3a, 0x7f, 0x47, 0xe7, 0x5f, 0x1b, 0x78, 0x0d, 0x3c, 0x9f, - 0x4d, 0x6b, 0xdf, 0x5f, 0x7f, 0xd9, 0x4f, 0x13, 0xae, 0x16, 0x27, 0xa1, 0x13, 0x41, 0xa6, 0xcf, - 0x54, 0xbf, 0x26, 0x32, 0x5e, 0x12, 0x55, 0xac, 0x98, 0xec, 0xfe, 0x91, 0xff, 0x71, 0xfe, 0x1d, - 0xe1, 0xfd, 0x63, 0x26, 0xd6, 0x3c, 0x62, 0x37, 0x65, 0xfc, 0x19, 0xc6, 0xb2, 0x65, 0xbc, 0xf6, - 0xbd, 0x5b, 0x95, 0x76, 0x5f, 0xeb, 0xf8, 0x5e, 0xd0, 0xd7, 0x80, 0x5b, 0x3a, 0xcf, 0xd9, 0xdb, - 0xf3, 0xca, 0x42, 0x17, 0x95, 0x85, 0x7e, 0x57, 0x16, 0xfa, 0xb2, 0xb1, 0x8c, 0x8b, 0x8d, 0x65, - 0xfc, 0xd8, 0x58, 0xc6, 0x87, 0xe9, 0x56, 0x5c, 0xdd, 0xe6, 0x4c, 0x52, 0x1a, 0xca, 0xab, 0x8a, - 0x7c, 0xda, 0xda, 0xb6, 0x26, 0xbf, 0xb0, 0xd7, 0xdc, 0xf7, 0xe9, 0xbf, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x89, 0xe1, 0x7c, 0x0f, 0x90, 0x03, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x93, 0x31, 0x6f, 0xd3, 0x40, + 0x14, 0xc7, 0x7d, 0x54, 0x0a, 0xe4, 0x42, 0x2b, 0xd5, 0x2a, 0x52, 0x28, 0xc8, 0xae, 0xc2, 0x12, + 0x09, 0xe2, 0x93, 0xc9, 0x06, 0x13, 0xc1, 0x8b, 0x25, 0x10, 0xc8, 0xdd, 0x58, 0xa2, 0xb3, 0x7d, + 0x72, 0x4e, 0xb1, 0xfd, 0xa2, 0xbb, 0x6b, 0xc0, 0xdf, 0x80, 0x91, 0x8f, 0xd0, 0x99, 0xb9, 0xdf, + 0x81, 0x8e, 0x55, 0x27, 0xc4, 0x60, 0x90, 0xb3, 0xb0, 0x33, 0xb0, 0x22, 0xdb, 0xe7, 0x36, 0x03, + 0x63, 0xa5, 0x2e, 0xb6, 0xdf, 0x7b, 0x7f, 0xff, 0xff, 0xfa, 0xdd, 0xe9, 0xe1, 0x51, 0xc6, 0xd3, + 0x65, 0xf1, 0x91, 0x16, 0x44, 0x30, 0xa9, 0xe8, 0x92, 0xe7, 0x09, 0x59, 0xbb, 0x24, 0x83, 0x98, + 0xa5, 0xd2, 0x59, 0x09, 0x50, 0x60, 0x3e, 0xe8, 0x34, 0xce, 0x95, 0xc6, 0x59, 0xbb, 0x87, 0xfb, + 0x34, 0xe3, 0x39, 0x90, 0xe6, 0xd9, 0x2a, 0x0f, 0x1f, 0x46, 0x20, 0x33, 0x90, 0xf3, 0xa6, 0x22, + 0x6d, 0xa1, 0x47, 0x07, 0x09, 0x24, 0xd0, 0xf6, 0xeb, 0x2f, 0xdd, 0xb5, 0x5a, 0x0d, 0x09, 0xa9, + 0x64, 0x64, 0xed, 0x86, 0x4c, 0x51, 0x97, 0x44, 0xc0, 0xf3, 0x76, 0x3e, 0xfa, 0x86, 0xf0, 0xde, + 0x7b, 0x80, 0xd4, 0x63, 0x29, 0x4b, 0xa8, 0xe2, 0x90, 0x9b, 0x2f, 0xf1, 0xfd, 0x13, 0xc9, 0xc4, + 0x9c, 0xc6, 0xb1, 0x60, 0x52, 0x0e, 0xd1, 0x11, 0x1a, 0xf7, 0x67, 0xc3, 0xcb, 0xb3, 0xc9, 0x81, + 0x0e, 0x7c, 0xd5, 0x4e, 0x8e, 0x95, 0xe0, 0x79, 0x12, 0x0c, 0x6a, 0xb5, 0x6e, 0x99, 0x4f, 0xf0, + 0xdd, 0x15, 0x40, 0x3a, 0xe7, 0xf1, 0xf0, 0xce, 0x11, 0x1a, 0xef, 0xce, 0x70, 0x55, 0xda, 0xbd, + 0x3a, 0xc1, 0xf7, 0x82, 0x5e, 0x3d, 0xf2, 0x63, 0xd3, 0xc7, 0x3d, 0xb9, 0xa0, 0x82, 0xc9, 0xe1, + 0x4e, 0xe3, 0xed, 0x9e, 0x97, 0xb6, 0xf1, 0xa3, 0xb4, 0x1f, 0xb5, 0xfe, 0x32, 0x5e, 0x3a, 0x1c, + 0x48, 0x46, 0xd5, 0xc2, 0x79, 0xc3, 0x12, 0x1a, 0x15, 0x1e, 0x8b, 0x2e, 0xcf, 0x26, 0x58, 0xc7, + 0x7b, 0x2c, 0x0a, 0xb4, 0xc1, 0x8b, 0x7b, 0x9f, 0x4f, 0x6d, 0xe3, 0xf7, 0xa9, 0x6d, 0x8c, 0xfe, + 0x22, 0x6c, 0xbe, 0x5b, 0x31, 0x41, 0x15, 0x88, 0x9b, 0xa2, 0x21, 0x78, 0x00, 0xda, 0xf2, 0x9a, + 0x68, 0xaf, 0x2a, 0x6d, 0xdc, 0x25, 0xf9, 0x5e, 0x80, 0x3b, 0x89, 0x1f, 0x9b, 0x7c, 0x8b, 0x6c, + 0x67, 0x3c, 0x78, 0xfe, 0xd8, 0xd1, 0x21, 0xf5, 0xf9, 0x3b, 0xfa, 0xfc, 0x6b, 0x80, 0xd7, 0xc0, + 0xf3, 0xd9, 0xb4, 0xe6, 0xfe, 0xfa, 0xd3, 0x7e, 0x9a, 0x70, 0xb5, 0x38, 0x09, 0x9d, 0x08, 0x32, + 0x7d, 0xa7, 0xfa, 0x35, 0x91, 0xf1, 0x92, 0xa8, 0x62, 0xc5, 0x64, 0xf7, 0x8f, 0xfc, 0x0f, 0xf9, + 0x1f, 0x84, 0xf7, 0x8f, 0x99, 0x58, 0xf3, 0x88, 0xdd, 0x14, 0xf8, 0x33, 0x8c, 0x65, 0xeb, 0x78, + 0xcd, 0xbd, 0x5b, 0x95, 0x76, 0x5f, 0xe7, 0xf8, 0x5e, 0xd0, 0xd7, 0x82, 0x5b, 0xa2, 0x9e, 0xbd, + 0x3d, 0xaf, 0x2c, 0x74, 0x51, 0x59, 0xe8, 0x57, 0x65, 0xa1, 0x2f, 0x1b, 0xcb, 0xb8, 0xd8, 0x58, + 0xc6, 0xf7, 0x8d, 0x65, 0x7c, 0x98, 0x6e, 0x19, 0x77, 0x9b, 0x35, 0x49, 0x69, 0x28, 0xaf, 0x2a, + 0xf2, 0x69, 0x6b, 0x1b, 0x9b, 0xa4, 0xb0, 0xd7, 0xec, 0xc3, 0xf4, 0x5f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x09, 0xdd, 0x16, 0xcb, 0xb0, 0x03, 0x00, 0x00, } func (m *PoolDelegation) Marshal() (dAtA []byte, err error) { @@ -320,16 +320,20 @@ func (m *ServiceDelegation) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size := m.Shares.Size() - i -= size - if _, err := m.Shares.MarshalTo(dAtA[i:]); err != nil { - return 0, err + if len(m.Shares) > 0 { + for iNdEx := len(m.Shares) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Shares[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a } - i = encodeVarintModels(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x1a if m.ServiceID != 0 { i = encodeVarintModels(dAtA, i, uint64(m.ServiceID)) i-- @@ -409,8 +413,12 @@ func (m *ServiceDelegation) Size() (n int) { if m.ServiceID != 0 { n += 1 + sovModels(uint64(m.ServiceID)) } - l = m.Shares.Size() - n += 1 + l + sovModels(uint64(l)) + if len(m.Shares) > 0 { + for _, e := range m.Shares { + l = e.Size() + n += 1 + l + sovModels(uint64(l)) + } + } return n } @@ -774,7 +782,7 @@ func (m *ServiceDelegation) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Shares", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowModels @@ -784,23 +792,23 @@ func (m *ServiceDelegation) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthModels } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthModels } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Shares.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Shares = append(m.Shares, types.DecCoin{}) + if err := m.Shares[len(m.Shares)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/services/types/errors.go b/x/services/types/errors.go index 6e38d18e6..a2ab5ede4 100644 --- a/x/services/types/errors.go +++ b/x/services/types/errors.go @@ -9,4 +9,5 @@ var ( ErrServiceNotFound = errors.Register(ModuleName, 2, "service not found") ErrServiceAlreadyActive = errors.Register(ModuleName, 3, "service is already active") ErrServiceNotActive = errors.Register(ModuleName, 4, "service is not active") + ErrInsufficientShares = errors.Register(ModuleName, 5, "insufficient delegation shares") ) diff --git a/x/services/types/models.go b/x/services/types/models.go index a51ff89c6..116c5c3b2 100644 --- a/x/services/types/models.go +++ b/x/services/types/models.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -48,25 +49,25 @@ func NewService( } // Validate checks that the Service has valid values. -func (a *Service) Validate() error { - if a.Status == SERVICE_STATUS_UNSPECIFIED { - return fmt.Errorf("invalid status: %s", a.Status) +func (s Service) Validate() error { + if s.Status == SERVICE_STATUS_UNSPECIFIED { + return fmt.Errorf("invalid status: %s", s.Status) } - if a.ID == 0 { - return fmt.Errorf("invalid id: %d", a.ID) + if s.ID == 0 { + return fmt.Errorf("invalid id: %d", s.ID) } - if strings.TrimSpace(a.Name) == "" { - return fmt.Errorf("invalid name: %s", a.Name) + if strings.TrimSpace(s.Name) == "" { + return fmt.Errorf("invalid name: %s", s.Name) } - _, err := sdk.AccAddressFromBech32(a.Admin) + _, err := sdk.AccAddressFromBech32(s.Admin) if err != nil { return fmt.Errorf("invalid admin address") } - _, err = sdk.AccAddressFromBech32(a.Address) + _, err = sdk.AccAddressFromBech32(s.Address) if err != nil { return fmt.Errorf("invalid service address") } @@ -74,6 +75,66 @@ func (a *Service) Validate() error { return nil } +// IsActive returns whether the service is active. +func (s Service) IsActive() bool { + return s.Status == SERVICE_STATUS_ACTIVE +} + +// InvalidExRate returns whether the exchange rates is invalid. +// This can happen e.g. if Service loses all tokens due to slashing. In this case, +// make all future delegations invalid. +func (s Service) InvalidExRate() bool { + for _, token := range s.Tokens { + if token.IsZero() && s.DelegatorShares.AmountOf(token.Denom).IsPositive() { + return true + } + } + return false +} + +// SharesFromTokens returns the shares of a delegation given a bond amount. It +// returns an error if the service has no tokens. +func (s Service) SharesFromTokens(tokens sdk.Coin) (sdkmath.LegacyDec, error) { + if s.Tokens.IsZero() { + return sdkmath.LegacyZeroDec(), ErrInsufficientShares + } + + delegatorTokenShares := s.DelegatorShares.AmountOf(tokens.Denom) + operatorTokenAmount := s.Tokens.AmountOf(tokens.Denom) + + return delegatorTokenShares.MulInt(tokens.Amount).QuoInt(operatorTokenAmount), nil +} + +// AddTokensFromDelegation adds the given amount of tokens to the service's total tokens, +// also updating the service's delegator shares. +// It returns the updated service and the shares issued. +func (s Service) AddTokensFromDelegation(amount sdk.Coins) (Service, sdk.DecCoins) { + // calculate the shares to issue + issuedShares := sdk.NewDecCoins() + for _, token := range amount { + var tokenShares sdk.DecCoin + delegatorShares := s.DelegatorShares.AmountOf(token.Denom) + + if delegatorShares.IsZero() { + // The first delegation to an operator sets the exchange rate to one + tokenShares = sdk.NewDecCoinFromCoin(token) + } else { + shares, err := s.SharesFromTokens(token) + if err != nil { + panic(err) + } + tokenShares = sdk.NewDecCoinFromDec(token.Denom, shares) + } + + issuedShares = issuedShares.Add(tokenShares) + } + + s.Tokens = s.Tokens.Add(amount...) + s.DelegatorShares = s.DelegatorShares.Add(issuedShares...) + + return s, issuedShares +} + // -------------------------------------------------------------------------------------------------------------------- // ServiceUpdate defines the fields that can be updated in a Service. diff --git a/x/services/types/models.pb.go b/x/services/types/models.pb.go index deda66fd1..bbe3a3290 100644 --- a/x/services/types/models.pb.go +++ b/x/services/types/models.pb.go @@ -6,6 +6,8 @@ package types import ( fmt "fmt" _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" @@ -82,6 +84,10 @@ type Service struct { // This will be used in order to store all the tokens that are delegated to // this service by various users. Address string `protobuf:"bytes,8,opt,name=address,proto3" json:"address,omitempty"` + // Tokens define the delegated tokens. + Tokens github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,9,rep,name=tokens,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"tokens"` + // DelegatorShares define the total shares issued to an operator's delegators. + DelegatorShares github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,10,rep,name=delegator_shares,json=delegatorShares,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"delegator_shares"` } func (m *Service) Reset() { *m = Service{} } @@ -173,6 +179,20 @@ func (m *Service) GetAddress() string { return "" } +func (m *Service) GetTokens() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Tokens + } + return nil +} + +func (m *Service) GetDelegatorShares() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.DelegatorShares + } + return nil +} + func init() { proto.RegisterEnum("milkyway.services.v1.ServiceStatus", ServiceStatus_name, ServiceStatus_value) proto.RegisterType((*Service)(nil), "milkyway.services.v1.Service") @@ -181,35 +201,42 @@ func init() { func init() { proto.RegisterFile("milkyway/services/v1/models.proto", fileDescriptor_4411e719afee9a70) } var fileDescriptor_4411e719afee9a70 = []byte{ - // 443 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0xc7, 0xbd, 0x6e, 0x9a, 0xc0, 0x54, 0xad, 0xa2, 0x55, 0x28, 0x5b, 0x23, 0xb9, 0x01, 0x2e, - 0x11, 0x52, 0x6d, 0x35, 0x1c, 0x39, 0xe5, 0xc3, 0x48, 0x96, 0xaa, 0xaa, 0xb2, 0x93, 0x1e, 0xb8, - 0x44, 0x8e, 0xbd, 0x0a, 0x2b, 0xec, 0x6c, 0xb4, 0xbb, 0x49, 0xc9, 0x1b, 0xc0, 0x8d, 0x77, 0xe0, - 0x15, 0x78, 0x03, 0x2e, 0x1c, 0x2b, 0x4e, 0x9c, 0x2a, 0xe4, 0xbc, 0x08, 0x8a, 0xd7, 0xe6, 0x23, - 0x42, 0xea, 0x6d, 0x66, 0x7e, 0x3f, 0x8f, 0xff, 0x96, 0x07, 0x9e, 0x66, 0x2c, 0x7d, 0xb7, 0xbe, - 0x89, 0xd6, 0xae, 0xa4, 0x62, 0xc5, 0x62, 0x2a, 0xdd, 0xd5, 0xb9, 0x9b, 0xf1, 0x84, 0xa6, 0xd2, - 0x59, 0x08, 0xae, 0x38, 0x6e, 0x55, 0x8a, 0x53, 0x29, 0xce, 0xea, 0xdc, 0x6a, 0xcd, 0xf8, 0x8c, - 0x17, 0x82, 0xbb, 0xad, 0xb4, 0x6b, 0x9d, 0xc4, 0x5c, 0x66, 0x5c, 0x4e, 0x34, 0xd0, 0x8d, 0x46, - 0xcf, 0xbe, 0x9a, 0xd0, 0x08, 0xf5, 0x02, 0x7c, 0x0c, 0x26, 0x4b, 0x08, 0x6a, 0xa3, 0xce, 0x61, - 0xbf, 0x9e, 0xdf, 0x9d, 0x9a, 0xfe, 0x30, 0x30, 0x59, 0x82, 0x5f, 0x41, 0x5d, 0xaa, 0x48, 0x2d, - 0x25, 0x31, 0xdb, 0xa8, 0x73, 0xd4, 0x7d, 0xee, 0xfc, 0xef, 0xdd, 0x4e, 0xb9, 0x26, 0x2c, 0xd4, - 0xa0, 0x7c, 0x04, 0x3b, 0xb0, 0x1f, 0x25, 0x19, 0x9b, 0x93, 0xbd, 0x36, 0xea, 0x3c, 0xec, 0x93, - 0xef, 0x5f, 0xce, 0x5a, 0x65, 0x82, 0x5e, 0x92, 0x08, 0x2a, 0x65, 0xa8, 0x04, 0x9b, 0xcf, 0x02, - 0xad, 0x61, 0x0c, 0xb5, 0x79, 0x94, 0x51, 0x52, 0xdb, 0xea, 0x41, 0x51, 0xe3, 0x36, 0x1c, 0x24, - 0x54, 0xc6, 0x82, 0x2d, 0x14, 0xe3, 0x73, 0xb2, 0x5f, 0xa0, 0xbf, 0x47, 0x98, 0x40, 0xe3, 0x86, - 0x4e, 0x25, 0x53, 0x94, 0xd4, 0x0b, 0x5a, 0xb5, 0xd8, 0x85, 0x83, 0x05, 0x8b, 0xd5, 0x52, 0xd0, - 0xc9, 0x52, 0xa4, 0xa4, 0x51, 0xa4, 0x38, 0xca, 0xef, 0x4e, 0xe1, 0x4a, 0x8f, 0xc7, 0xc1, 0x45, - 0x00, 0xa5, 0x32, 0x16, 0x29, 0xee, 0x42, 0x23, 0xd2, 0xc1, 0xc8, 0x83, 0x7b, 0x22, 0x57, 0xe2, - 0x8b, 0x8f, 0x08, 0x0e, 0xff, 0xf9, 0x7c, 0x6c, 0x83, 0x15, 0x7a, 0xc1, 0xb5, 0x3f, 0xf0, 0x26, - 0xe1, 0xa8, 0x37, 0x1a, 0x87, 0x93, 0xf1, 0x65, 0x78, 0xe5, 0x0d, 0xfc, 0xd7, 0xbe, 0x37, 0x6c, - 0x1a, 0xd8, 0x82, 0xe3, 0x1d, 0x3e, 0x08, 0xbc, 0xde, 0xc8, 0x1b, 0x36, 0x11, 0x3e, 0x81, 0x47, - 0x3b, 0xac, 0x37, 0x18, 0xf9, 0xd7, 0x5e, 0xd3, 0xc4, 0x4f, 0xe0, 0xf1, 0x0e, 0xf2, 0x2f, 0x4b, - 0xb8, 0x67, 0xd5, 0x3e, 0x7c, 0xb6, 0x8d, 0xfe, 0xc5, 0xb7, 0xdc, 0x46, 0xb7, 0xb9, 0x8d, 0x7e, - 0xe6, 0x36, 0xfa, 0xb4, 0xb1, 0x8d, 0xdb, 0x8d, 0x6d, 0xfc, 0xd8, 0xd8, 0xc6, 0x9b, 0xee, 0x8c, - 0xa9, 0xb7, 0xcb, 0xa9, 0x13, 0xf3, 0xcc, 0xad, 0xfe, 0xe0, 0x59, 0x1a, 0x4d, 0xe5, 0xef, 0xce, - 0x7d, 0xff, 0xe7, 0xe0, 0xd4, 0x7a, 0x41, 0xe5, 0xb4, 0x5e, 0x9c, 0xc9, 0xcb, 0x5f, 0x01, 0x00, - 0x00, 0xff, 0xff, 0x1a, 0xcb, 0x5b, 0x2b, 0x92, 0x02, 0x00, 0x00, + // 556 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x4d, 0x6f, 0xd3, 0x30, + 0x1c, 0xc6, 0x93, 0xb6, 0x6b, 0x99, 0xab, 0x8d, 0xca, 0x2a, 0xc3, 0x2d, 0x28, 0x2d, 0x70, 0xa9, + 0x40, 0x4d, 0x68, 0x77, 0xe4, 0xd4, 0x97, 0x20, 0x45, 0x9a, 0xa6, 0x29, 0x69, 0x77, 0xe0, 0x52, + 0xe5, 0xc5, 0xea, 0xac, 0x26, 0x71, 0x15, 0xbb, 0x1d, 0x95, 0xf8, 0x00, 0x70, 0xe3, 0x3b, 0x20, + 0x71, 0xe0, 0xcc, 0x87, 0xd8, 0x71, 0xe2, 0xc4, 0xa9, 0xa0, 0xf6, 0x8b, 0xa0, 0x3a, 0xee, 0x18, + 0xd5, 0x24, 0x76, 0x8a, 0xff, 0x7e, 0x7e, 0x7f, 0x3f, 0x8f, 0xed, 0x18, 0x3c, 0x8b, 0x48, 0x38, + 0x59, 0x5c, 0xba, 0x0b, 0x83, 0xe1, 0x64, 0x4e, 0x7c, 0xcc, 0x8c, 0x79, 0xcb, 0x88, 0x68, 0x80, + 0x43, 0xa6, 0x4f, 0x13, 0xca, 0x29, 0x2c, 0x6f, 0x11, 0x7d, 0x8b, 0xe8, 0xf3, 0x56, 0xb5, 0x3c, + 0xa6, 0x63, 0x2a, 0x00, 0x63, 0x33, 0x4a, 0xd9, 0x6a, 0xc5, 0xa7, 0x2c, 0xa2, 0x6c, 0x94, 0x0a, + 0x69, 0x21, 0x25, 0x2d, 0xad, 0x0c, 0xcf, 0x65, 0xd8, 0x98, 0xb7, 0x3c, 0xcc, 0xdd, 0x96, 0xe1, + 0x53, 0x12, 0xa7, 0xfa, 0xf3, 0xaf, 0x39, 0x50, 0x70, 0x52, 0x03, 0x78, 0x04, 0x32, 0x24, 0x40, + 0x6a, 0x5d, 0x6d, 0x1c, 0x74, 0xf3, 0xab, 0x65, 0x2d, 0x63, 0xf5, 0xed, 0x0c, 0x09, 0xe0, 0x1b, + 0x90, 0x67, 0xdc, 0xe5, 0x33, 0x86, 0x32, 0x75, 0xb5, 0x71, 0xd8, 0x7e, 0xa1, 0xdf, 0x95, 0x4d, + 0x97, 0xcb, 0x38, 0x02, 0xb5, 0x65, 0x0b, 0xd4, 0xc1, 0x9e, 0x1b, 0x44, 0x24, 0x46, 0xd9, 0xba, + 0xda, 0xd8, 0xef, 0xa2, 0x1f, 0xdf, 0x9b, 0x65, 0x99, 0xb0, 0x13, 0x04, 0x09, 0x66, 0xcc, 0xe1, + 0x09, 0x89, 0xc7, 0x76, 0x8a, 0x41, 0x08, 0x72, 0xb1, 0x1b, 0x61, 0x94, 0xdb, 0xe0, 0xb6, 0x18, + 0xc3, 0x3a, 0x28, 0x06, 0x98, 0xf9, 0x09, 0x99, 0x72, 0x42, 0x63, 0xb4, 0x27, 0xa4, 0xdb, 0x53, + 0x10, 0x81, 0xc2, 0x25, 0xf6, 0x18, 0xe1, 0x18, 0xe5, 0x85, 0xba, 0x2d, 0xa1, 0x01, 0x8a, 0x53, + 0xe2, 0xf3, 0x59, 0x82, 0x47, 0xb3, 0x24, 0x44, 0x05, 0x91, 0xe2, 0x70, 0xb5, 0xac, 0x81, 0xb3, + 0x74, 0x7a, 0x68, 0x9f, 0xd8, 0x40, 0x22, 0xc3, 0x24, 0x84, 0x6d, 0x50, 0x70, 0xd3, 0x60, 0xe8, + 0xc1, 0x7f, 0x22, 0x6f, 0x41, 0xe8, 0x83, 0x3c, 0xa7, 0x13, 0x1c, 0x33, 0xb4, 0x5f, 0xcf, 0x36, + 0x8a, 0xed, 0x8a, 0x2e, 0xf9, 0xcd, 0xb1, 0xeb, 0xf2, 0xd8, 0xf5, 0x1e, 0x25, 0x71, 0xf7, 0xf5, + 0xd5, 0xb2, 0xa6, 0x7c, 0xfb, 0x55, 0x6b, 0x8c, 0x09, 0xbf, 0x98, 0x79, 0xba, 0x4f, 0x23, 0x79, + 0x63, 0xf2, 0xd3, 0x64, 0xc1, 0xc4, 0xe0, 0x8b, 0x29, 0x66, 0xa2, 0x81, 0xd9, 0x72, 0x69, 0xf8, + 0x01, 0x94, 0x02, 0x1c, 0xe2, 0xb1, 0xcb, 0x69, 0x32, 0x62, 0x17, 0x6e, 0x82, 0x19, 0x02, 0xc2, + 0xee, 0xe9, 0x9d, 0x76, 0x7d, 0xec, 0x0b, 0xc7, 0x63, 0xe9, 0xf8, 0xea, 0x1e, 0x8e, 0xb2, 0x87, + 0xd9, 0x0f, 0x6f, 0xac, 0x1c, 0xe1, 0xf4, 0xf2, 0x93, 0x0a, 0x0e, 0xfe, 0xb9, 0x61, 0xa8, 0x81, + 0xaa, 0x63, 0xda, 0xe7, 0x56, 0xcf, 0x1c, 0x39, 0x83, 0xce, 0x60, 0xe8, 0x8c, 0x86, 0xa7, 0xce, + 0x99, 0xd9, 0xb3, 0xde, 0x5a, 0x66, 0xbf, 0xa4, 0xc0, 0x2a, 0x38, 0xda, 0xd1, 0x7b, 0xb6, 0xd9, + 0x19, 0x98, 0xfd, 0x92, 0x0a, 0x2b, 0xe0, 0xd1, 0x8e, 0xd6, 0xe9, 0x0d, 0xac, 0x73, 0xb3, 0x94, + 0x81, 0x4f, 0xc0, 0xe3, 0x1d, 0xc9, 0x3a, 0x95, 0x62, 0xb6, 0x9a, 0xfb, 0xf8, 0x45, 0x53, 0xba, + 0x27, 0x57, 0x2b, 0x4d, 0xbd, 0x5e, 0x69, 0xea, 0xef, 0x95, 0xa6, 0x7e, 0x5e, 0x6b, 0xca, 0xf5, + 0x5a, 0x53, 0x7e, 0xae, 0x35, 0xe5, 0x5d, 0xfb, 0xd6, 0x1e, 0xb7, 0x3f, 0x69, 0x33, 0x74, 0x3d, + 0x76, 0x53, 0x19, 0xef, 0xff, 0xbe, 0x39, 0xb1, 0x67, 0x2f, 0x2f, 0x5e, 0xc2, 0xf1, 0x9f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x10, 0xa5, 0x37, 0xb3, 0x95, 0x03, 0x00, 0x00, } func (m *Service) Marshal() (dAtA []byte, err error) { @@ -232,6 +259,34 @@ func (m *Service) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.DelegatorShares) > 0 { + for iNdEx := len(m.DelegatorShares) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.DelegatorShares[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + } + if len(m.Tokens) > 0 { + for iNdEx := len(m.Tokens) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Tokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintModels(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } if len(m.Address) > 0 { i -= len(m.Address) copy(dAtA[i:], m.Address) @@ -334,6 +389,18 @@ func (m *Service) Size() (n int) { if l > 0 { n += 1 + l + sovModels(uint64(l)) } + if len(m.Tokens) > 0 { + for _, e := range m.Tokens { + l = e.Size() + n += 1 + l + sovModels(uint64(l)) + } + } + if len(m.DelegatorShares) > 0 { + for _, e := range m.DelegatorShares { + l = e.Size() + n += 1 + l + sovModels(uint64(l)) + } + } return n } @@ -602,6 +669,74 @@ func (m *Service) Unmarshal(dAtA []byte) error { } m.Address = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tokens", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthModels + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tokens = append(m.Tokens, types.Coin{}) + if err := m.Tokens[len(m.Tokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DelegatorShares", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthModels + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DelegatorShares = append(m.DelegatorShares, types.DecCoin{}) + if err := m.DelegatorShares[len(m.DelegatorShares)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipModels(dAtA[iNdEx:]) From 10373b49baef427172f3084b1444a60e6b1bb850 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 14:45:00 -0500 Subject: [PATCH 22/37] chore: remove param names from mockHooks --- x/restaking/keeper/common_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/x/restaking/keeper/common_test.go b/x/restaking/keeper/common_test.go index a515b9fc8..60333a1c6 100644 --- a/x/restaking/keeper/common_test.go +++ b/x/restaking/keeper/common_test.go @@ -155,47 +155,47 @@ func newMockHooks() *mockHooks { return &mockHooks{CalledMap: make(map[string]bool)} } -func (m mockHooks) BeforePoolDelegationCreated(ctx sdk.Context, poolID uint32, delegator string) error { +func (m mockHooks) BeforePoolDelegationCreated(sdk.Context, uint32, string) error { m.CalledMap["BeforePoolDelegationCreated"] = true return nil } -func (m mockHooks) BeforePoolDelegationSharesModified(ctx sdk.Context, poolID uint32, delegator string) error { +func (m mockHooks) BeforePoolDelegationSharesModified(sdk.Context, uint32, string) error { m.CalledMap["BeforePoolDelegationSharesModified"] = true return nil } -func (m mockHooks) AfterPoolDelegationModified(ctx sdk.Context, poolID uint32, delegator string) error { +func (m mockHooks) AfterPoolDelegationModified(sdk.Context, uint32, string) error { m.CalledMap["AfterPoolDelegationModified"] = true return nil } -func (m mockHooks) BeforeOperatorDelegationCreated(ctx sdk.Context, operatorID uint32, delegator string) error { +func (m mockHooks) BeforeOperatorDelegationCreated(sdk.Context, uint32, string) error { m.CalledMap["BeforeOperatorDelegationCreated"] = true return nil } -func (m mockHooks) BeforeOperatorDelegationSharesModified(ctx sdk.Context, operatorID uint32, delegator string) error { +func (m mockHooks) BeforeOperatorDelegationSharesModified(sdk.Context, uint32, string) error { m.CalledMap["BeforeOperatorDelegationSharesModified"] = true return nil } -func (m mockHooks) AfterOperatorDelegationModified(ctx sdk.Context, operatorID uint32, delegator string) error { +func (m mockHooks) AfterOperatorDelegationModified(sdk.Context, uint32, string) error { m.CalledMap["AfterOperatorDelegationModified"] = true return nil } -func (m mockHooks) BeforeServiceDelegationCreated(ctx sdk.Context, serviceID uint32, delegator string) error { +func (m mockHooks) BeforeServiceDelegationCreated(sdk.Context, uint32, string) error { m.CalledMap["BeforeServiceDelegationCreated"] = true return nil } -func (m mockHooks) BeforeServiceDelegationSharesModified(ctx sdk.Context, serviceID uint32, delegator string) error { +func (m mockHooks) BeforeServiceDelegationSharesModified(sdk.Context, uint32, string) error { m.CalledMap["BeforeServiceDelegationSharesModified"] = true return nil } -func (m mockHooks) AfterServiceDelegationModified(ctx sdk.Context, serviceID uint32, delegator string) error { +func (m mockHooks) AfterServiceDelegationModified(sdk.Context, uint32, string) error { m.CalledMap["AfterServiceDelegationModified"] = true return nil } From 832ac1b6bbf189ea8353ec1e3050858858333337 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 14:48:52 -0500 Subject: [PATCH 23/37] feat: add operator restake msg server --- proto/milkyway/restaking/v1/messages.proto | 7 +- x/restaking/keeper/msg_server.go | 56 ++++++++- x/restaking/types/events.go | 2 + x/restaking/types/messages.go | 2 +- x/restaking/types/messages.pb.go | 127 +++++++++++---------- x/restaking/types/messages_test.go | 4 +- 6 files changed, 132 insertions(+), 66 deletions(-) diff --git a/proto/milkyway/restaking/v1/messages.proto b/proto/milkyway/restaking/v1/messages.proto index c0f60b25b..9b91fd707 100644 --- a/proto/milkyway/restaking/v1/messages.proto +++ b/proto/milkyway/restaking/v1/messages.proto @@ -92,8 +92,11 @@ message MsgDelegateService { uint32 service_id = 2 [ (gogoproto.customname) = "ServiceID" ]; // Amount is the amount of coins to be delegated - cosmos.base.v1beta1.Coin amount = 3 - [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; + repeated cosmos.base.v1beta1.Coin amount = 3 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (gogoproto.customname) = "Amount", + (gogoproto.nullable) = false + ]; } // MsgDelegateServiceResponse is the return value of MsgDelegateService. diff --git a/x/restaking/keeper/msg_server.go b/x/restaking/keeper/msg_server.go index e6d88df3b..453994ae1 100644 --- a/x/restaking/keeper/msg_server.go +++ b/x/restaking/keeper/msg_server.go @@ -7,6 +7,7 @@ import ( "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/hashicorp/go-metrics" @@ -29,6 +30,13 @@ func NewMsgServerImpl(keeper *Keeper) types.MsgServer { func (k msgServer) PoolRestake(goCtx context.Context, msg *types.MsgJoinRestakingPool) (*types.MsgJoinRestakingPoolResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + if !msg.Amount.IsValid() || !msg.Amount.Amount.IsPositive() { + return nil, errors.Wrap( + sdkerrors.ErrInvalidRequest, + "invalid delegation amount", + ) + } + newShares, err := k.Keeper.DelegateToPool(ctx, msg.Amount, msg.Delegator) if err != nil { return nil, err @@ -62,6 +70,13 @@ func (k msgServer) PoolRestake(goCtx context.Context, msg *types.MsgJoinRestakin func (k msgServer) OperatorRestake(goCtx context.Context, msg *types.MsgDelegateOperator) (*types.MsgDelegateOperatorResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + if !msg.Amount.IsValid() || !msg.Amount.IsAllPositive() { + return nil, errors.Wrap( + sdkerrors.ErrInvalidRequest, + "invalid delegation amount", + ) + } + newShares, err := k.Keeper.DelegateToOperator(ctx, msg.OperatorID, msg.Amount, msg.Delegator) if err != nil { return nil, err @@ -96,8 +111,45 @@ func (k msgServer) OperatorRestake(goCtx context.Context, msg *types.MsgDelegate // ServiceRestake defines the rpc method for Msg/ServiceRestake func (k msgServer) ServiceRestake(goCtx context.Context, msg *types.MsgDelegateService) (*types.MsgDelegateServiceResponse, error) { - //TODO implement me - panic("implement me") + ctx := sdk.UnwrapSDKContext(goCtx) + + if !msg.Amount.IsValid() || !msg.Amount.IsAllPositive() { + return nil, errors.Wrap( + sdkerrors.ErrInvalidRequest, + "invalid delegation amount", + ) + } + + newShares, err := k.Keeper.DelegateToService(ctx, msg.ServiceID, msg.Amount, msg.Delegator) + if err != nil { + return nil, err + } + + for _, token := range msg.Amount { + if token.Amount.IsInt64() { + defer func() { + telemetry.IncrCounter(1, types.ModuleName, "service restake") + telemetry.SetGaugeWithLabels( + []string{"tx", "msg", sdk.MsgTypeURL(msg)}, + float32(token.Amount.Int64()), + []metrics.Label{telemetry.NewLabel("denom", token.Denom)}, + ) + }() + } + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + sdkCtx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeServiceRestake, + sdk.NewAttribute(types.AttributeKeyDelegator, msg.Delegator), + sdk.NewAttribute(types.AttributeKeyServiceID, fmt.Sprintf("%d", msg.ServiceID)), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(types.AttributeKeyNewShares, newShares.String()), + ), + }) + + return &types.MsgDelegateServiceResponse{}, nil } // UpdateParams defines the rpc method for Msg/UpdateParams diff --git a/x/restaking/types/events.go b/x/restaking/types/events.go index d7f6e699e..ec4000638 100644 --- a/x/restaking/types/events.go +++ b/x/restaking/types/events.go @@ -3,8 +3,10 @@ package types const ( EventTypePoolRestake = "pool_restake" EventTypeOperatorRestake = "operator_restake" + EventTypeServiceRestake = "service_restake" AttributeKeyDelegator = "delegator" AttributeKeyOperatorID = "operator_id" + AttributeKeyServiceID = "operator_id" AttributeKeyNewShares = "new_shares" ) diff --git a/x/restaking/types/messages.go b/x/restaking/types/messages.go index 9f85dabc9..54b941b0f 100644 --- a/x/restaking/types/messages.go +++ b/x/restaking/types/messages.go @@ -81,7 +81,7 @@ func (msg *MsgDelegateOperator) GetSigners() []sdk.AccAddress { // -------------------------------------------------------------------------------------------------------------------- -func NewMsgDelegateService(serviceID uint32, amount sdk.Coin, delegator string) *MsgDelegateService { +func NewMsgDelegateService(serviceID uint32, amount sdk.Coins, delegator string) *MsgDelegateService { return &MsgDelegateService{ ServiceID: serviceID, Amount: amount, diff --git a/x/restaking/types/messages.pb.go b/x/restaking/types/messages.pb.go index 59f49dc4c..d80832911 100644 --- a/x/restaking/types/messages.pb.go +++ b/x/restaking/types/messages.pb.go @@ -241,7 +241,7 @@ type MsgDelegateService struct { // ServiceID is the ID of the service to delegate to ServiceID uint32 `protobuf:"varint,2,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` // Amount is the amount of coins to be delegated - Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` + 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 *MsgDelegateService) Reset() { *m = MsgDelegateService{} } @@ -291,11 +291,11 @@ func (m *MsgDelegateService) GetServiceID() uint32 { return 0 } -func (m *MsgDelegateService) GetAmount() types.Coin { +func (m *MsgDelegateService) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { if m != nil { return m.Amount } - return types.Coin{} + return nil } // MsgDelegateServiceResponse is the return value of MsgDelegateService. @@ -447,51 +447,51 @@ func init() { } var fileDescriptor_9772be2b1a923bdb = []byte{ - // 704 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x41, 0x4f, 0x13, 0x41, - 0x14, 0xee, 0x52, 0x6d, 0xd2, 0x41, 0x40, 0x57, 0x0c, 0xb0, 0xc0, 0x96, 0x6c, 0x8c, 0xc1, 0x0a, - 0xbb, 0x16, 0x12, 0x4d, 0xea, 0x89, 0xca, 0xa5, 0x24, 0x8d, 0x64, 0x89, 0x17, 0x2f, 0x64, 0xda, - 0x1d, 0x87, 0x4d, 0xbb, 0x3b, 0x75, 0x67, 0xa8, 0xf6, 0x66, 0x3c, 0x7a, 0xf2, 0x17, 0xf8, 0x03, - 0x3c, 0x71, 0xf0, 0x1f, 0x78, 0xe1, 0x48, 0xf4, 0xe2, 0xa9, 0x9a, 0xe5, 0xc0, 0xc9, 0x8b, 0xbf, - 0xc0, 0x74, 0x76, 0x76, 0xba, 0xb4, 0x5b, 0xc5, 0x5e, 0xa0, 0x33, 0xef, 0x7b, 0xdf, 0x9b, 0xef, - 0xeb, 0x7b, 0xaf, 0xe0, 0xae, 0xe7, 0xb6, 0x9a, 0xdd, 0xd7, 0xb0, 0x6b, 0x05, 0x88, 0x32, 0xd8, - 0x74, 0x7d, 0x6c, 0x75, 0x4a, 0x96, 0x87, 0x28, 0x85, 0x18, 0x51, 0xb3, 0x1d, 0x10, 0x46, 0xd4, - 0x3b, 0x31, 0xca, 0x94, 0x28, 0xb3, 0x53, 0xd2, 0x6e, 0x41, 0xcf, 0xf5, 0x89, 0xc5, 0xff, 0x46, - 0x48, 0x6d, 0xa9, 0x41, 0xa8, 0x47, 0xe8, 0x21, 0x3f, 0x59, 0xd1, 0x41, 0x84, 0xf4, 0xe8, 0x64, - 0xd5, 0x21, 0x45, 0x56, 0xa7, 0x54, 0x47, 0x0c, 0x96, 0xac, 0x06, 0x71, 0xfd, 0x91, 0xb8, 0xdf, - 0x94, 0xf1, 0xfe, 0x41, 0xc4, 0x17, 0x44, 0xdc, 0xa3, 0xd1, 0x13, 0x29, 0x16, 0x81, 0x79, 0x4c, - 0x30, 0x89, 0x0a, 0xf6, 0x3f, 0x89, 0x5b, 0x23, 0x5d, 0x59, 0x1b, 0x06, 0xd0, 0x13, 0x4f, 0x32, - 0xbe, 0x28, 0x60, 0xbe, 0x46, 0xf1, 0x1e, 0x71, 0x7d, 0x3b, 0x06, 0xed, 0x13, 0xd2, 0x52, 0x1f, - 0x81, 0xbc, 0x83, 0x5a, 0x08, 0x43, 0x46, 0x82, 0x45, 0x65, 0x4d, 0x59, 0xcf, 0x57, 0x16, 0xbf, - 0x7e, 0xde, 0x9c, 0x17, 0x82, 0x76, 0x1c, 0x27, 0x40, 0x94, 0x1e, 0xb0, 0xc0, 0xf5, 0xb1, 0x3d, - 0x80, 0xaa, 0x3b, 0x20, 0x07, 0x3d, 0x72, 0xec, 0xb3, 0xc5, 0xa9, 0x35, 0x65, 0x7d, 0x7a, 0x6b, - 0xc9, 0x14, 0x19, 0x7d, 0xd1, 0xa6, 0x10, 0x65, 0x3e, 0x25, 0xae, 0x5f, 0x99, 0x3d, 0xed, 0x15, - 0x32, 0x61, 0xaf, 0x90, 0xdb, 0xe1, 0x09, 0xb6, 0x48, 0x2c, 0x3f, 0x7c, 0x77, 0x71, 0x52, 0x1c, - 0x50, 0xbe, 0xbf, 0x38, 0x29, 0xae, 0x4a, 0x29, 0x69, 0x8f, 0x35, 0x74, 0xb0, 0x92, 0x76, 0x6f, - 0x23, 0xda, 0x26, 0x3e, 0x45, 0xc6, 0xc7, 0x29, 0x70, 0xbb, 0x46, 0xf1, 0x6e, 0x44, 0x89, 0x9e, - 0xb5, 0x51, 0xc0, 0x1f, 0x3b, 0xa9, 0x48, 0x0b, 0x4c, 0x13, 0xc1, 0x71, 0xe8, 0x3a, 0x5c, 0xe9, - 0x4c, 0x65, 0x36, 0xec, 0x15, 0x40, 0x4c, 0x5d, 0xdd, 0xb5, 0x41, 0x0c, 0xa9, 0x3a, 0xaa, 0x27, - 0x5d, 0xc9, 0xae, 0x65, 0xff, 0xee, 0x4a, 0xf9, 0xb2, 0x2b, 0x9f, 0x7e, 0x14, 0xd6, 0xb1, 0xcb, - 0x8e, 0x8e, 0xeb, 0x66, 0x83, 0x78, 0xa2, 0x9f, 0xc4, 0xbf, 0x4d, 0xea, 0x34, 0x2d, 0xd6, 0x6d, - 0x23, 0xca, 0x53, 0xa9, 0x74, 0xd0, 0x1a, 0x75, 0x70, 0x25, 0xe9, 0xe0, 0xb0, 0x11, 0xc6, 0x2a, - 0x58, 0x4e, 0xb9, 0x96, 0xfe, 0xfd, 0x52, 0x80, 0x9a, 0x88, 0x1f, 0xa0, 0xa0, 0xe3, 0x36, 0xd0, - 0xc4, 0xf6, 0x6d, 0x00, 0x40, 0x23, 0x8a, 0x81, 0x7b, 0x33, 0x61, 0xaf, 0x90, 0x17, 0xc4, 0xd5, - 0x5d, 0x3b, 0x2f, 0x00, 0x55, 0x27, 0xd1, 0x51, 0xd9, 0x49, 0x3b, 0xca, 0x1c, 0xf5, 0x63, 0x39, - 0xcd, 0x0f, 0x51, 0xdf, 0x58, 0x01, 0xda, 0xe8, 0xad, 0x74, 0xe3, 0x9b, 0x02, 0xe6, 0x6a, 0x14, - 0x3f, 0x6f, 0x3b, 0x90, 0xa1, 0x7d, 0x3e, 0x4d, 0xea, 0x1e, 0xc8, 0xc3, 0x63, 0x76, 0x44, 0x02, - 0x97, 0x75, 0x85, 0x15, 0x1b, 0xbf, 0x7b, 0x85, 0x9b, 0x5d, 0xe8, 0xb5, 0xca, 0x86, 0x0c, 0x19, - 0xe3, 0xed, 0x91, 0x18, 0xf5, 0x09, 0xc8, 0x45, 0x33, 0x2a, 0x46, 0x68, 0xd5, 0x4c, 0x5d, 0x3e, - 0x66, 0x54, 0xba, 0x72, 0xad, 0x2f, 0xda, 0x16, 0x29, 0xe5, 0xc7, 0x5c, 0xaa, 0x24, 0xeb, 0x4b, - 0x1d, 0x6c, 0xb8, 0x37, 0x89, 0x4d, 0x30, 0xa4, 0xc0, 0x58, 0x02, 0x0b, 0x43, 0x57, 0xb1, 0xe0, - 0xad, 0xd3, 0x2c, 0xc8, 0xd6, 0x28, 0x56, 0x09, 0x98, 0x16, 0x63, 0xc5, 0x60, 0x13, 0xa9, 0x0f, - 0xc6, 0xbc, 0x2b, 0x6d, 0x14, 0xb5, 0xed, 0xff, 0x00, 0xc7, 0x85, 0xd5, 0x57, 0x60, 0x2e, 0xd1, - 0x8b, 0xbc, 0x68, 0x71, 0x3c, 0xcf, 0x70, 0xfb, 0x6a, 0x5b, 0x57, 0xc7, 0xca, 0x92, 0x3e, 0x98, - 0x1d, 0x7c, 0xdf, 0xbc, 0xe2, 0xfd, 0x7f, 0xb3, 0x88, 0x0c, 0xad, 0x74, 0x65, 0xa8, 0xac, 0xf7, - 0x12, 0xdc, 0xb8, 0xd4, 0x48, 0xf7, 0xc6, 0x53, 0x24, 0x71, 0x9a, 0x79, 0x35, 0x5c, 0x5c, 0x47, - 0xbb, 0xfe, 0xf6, 0xe2, 0xa4, 0xa8, 0x54, 0x6a, 0xa7, 0xa1, 0xae, 0x9c, 0x85, 0xba, 0xf2, 0x33, - 0xd4, 0x95, 0x0f, 0xe7, 0x7a, 0xe6, 0xec, 0x5c, 0xcf, 0x7c, 0x3f, 0xd7, 0x33, 0x2f, 0xb6, 0x13, - 0x5b, 0x26, 0xa6, 0xde, 0x6c, 0xc1, 0x3a, 0xb5, 0x52, 0xdb, 0x87, 0xaf, 0x9d, 0x7a, 0x8e, 0xff, - 0x8a, 0x6c, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x0a, 0xf5, 0x8d, 0x96, 0x45, 0x07, 0x00, 0x00, + // 701 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xc1, 0x4f, 0x13, 0x4f, + 0x14, 0xee, 0xd2, 0xdf, 0xaf, 0x49, 0x07, 0x01, 0x5d, 0x31, 0xc0, 0x02, 0x5b, 0xb2, 0x31, 0x06, + 0x2b, 0xec, 0x58, 0x48, 0x34, 0xa9, 0x27, 0x2a, 0x17, 0x48, 0x1a, 0xc9, 0x12, 0x2f, 0x5e, 0xc8, + 0xb4, 0x3b, 0x0e, 0x9b, 0x76, 0x77, 0xea, 0xce, 0x50, 0xed, 0xcd, 0x78, 0xf4, 0xe4, 0xd5, 0x8b, + 0x7f, 0x80, 0x27, 0x0e, 0xfe, 0x07, 0x5e, 0x38, 0x12, 0xbd, 0x78, 0xaa, 0xa6, 0x1c, 0xb8, 0xfb, + 0x17, 0x98, 0xce, 0xce, 0x4e, 0x97, 0x76, 0xab, 0xc8, 0xc1, 0x0b, 0x74, 0xe6, 0x7d, 0xef, 0x7b, + 0xef, 0xfb, 0xfa, 0xde, 0x14, 0xdc, 0xf6, 0xbd, 0x66, 0xa3, 0xf3, 0x12, 0x75, 0x60, 0x88, 0x19, + 0x47, 0x0d, 0x2f, 0x20, 0xb0, 0x5d, 0x82, 0x3e, 0x66, 0x0c, 0x11, 0xcc, 0xec, 0x56, 0x48, 0x39, + 0xd5, 0x6f, 0xc5, 0x28, 0x5b, 0xa1, 0xec, 0x76, 0xc9, 0xb8, 0x81, 0x7c, 0x2f, 0xa0, 0x50, 0xfc, + 0x8d, 0x90, 0xc6, 0x42, 0x9d, 0x32, 0x9f, 0xb2, 0x03, 0x71, 0x82, 0xd1, 0x41, 0x86, 0xcc, 0xe8, + 0x04, 0x6b, 0x88, 0x61, 0xd8, 0x2e, 0xd5, 0x30, 0x47, 0x25, 0x58, 0xa7, 0x5e, 0x30, 0x12, 0x0f, + 0x1a, 0x2a, 0xde, 0x3f, 0xc8, 0xf8, 0x9c, 0x8c, 0xfb, 0x2c, 0x6a, 0x91, 0x11, 0x19, 0x98, 0x25, + 0x94, 0xd0, 0xa8, 0x60, 0xff, 0x93, 0xbc, 0xb5, 0xd2, 0x95, 0xb5, 0x50, 0x88, 0x7c, 0xd9, 0x92, + 0xf5, 0x59, 0x03, 0xb3, 0x55, 0x46, 0x76, 0xa9, 0x17, 0x38, 0x31, 0x68, 0x8f, 0xd2, 0xa6, 0xfe, + 0x00, 0xe4, 0x5d, 0xdc, 0xc4, 0x04, 0x71, 0x1a, 0xce, 0x6b, 0x2b, 0xda, 0x6a, 0xbe, 0x32, 0xff, + 0xe5, 0xd3, 0xfa, 0xac, 0x14, 0xb4, 0xe5, 0xba, 0x21, 0x66, 0x6c, 0x9f, 0x87, 0x5e, 0x40, 0x9c, + 0x01, 0x54, 0xdf, 0x02, 0x39, 0xe4, 0xd3, 0xa3, 0x80, 0xcf, 0x4f, 0xac, 0x68, 0xab, 0x93, 0x1b, + 0x0b, 0xb6, 0xcc, 0xe8, 0x8b, 0xb6, 0xa5, 0x28, 0xfb, 0x31, 0xf5, 0x82, 0xca, 0xf4, 0x49, 0xb7, + 0x90, 0xe9, 0x75, 0x0b, 0xb9, 0x2d, 0x91, 0xe0, 0xc8, 0xc4, 0xf2, 0xfd, 0x37, 0xe7, 0xc7, 0xc5, + 0x01, 0xe5, 0xdb, 0xf3, 0xe3, 0xe2, 0xb2, 0x92, 0x92, 0xd6, 0xac, 0x65, 0x82, 0xa5, 0xb4, 0x7b, + 0x07, 0xb3, 0x16, 0x0d, 0x18, 0xb6, 0x3e, 0x4c, 0x80, 0x9b, 0x55, 0x46, 0xb6, 0x23, 0x4a, 0xfc, + 0xa4, 0x85, 0x43, 0xd1, 0xec, 0x55, 0x45, 0x42, 0x30, 0x49, 0x25, 0xc7, 0x81, 0xe7, 0x0a, 0xa5, + 0x53, 0x95, 0xe9, 0x5e, 0xb7, 0x00, 0x62, 0xea, 0x9d, 0x6d, 0x07, 0xc4, 0x90, 0x1d, 0x57, 0xf7, + 0x95, 0x2b, 0xd9, 0x95, 0xec, 0xef, 0x5d, 0x29, 0x5f, 0x74, 0xe5, 0xe3, 0xf7, 0xc2, 0x2a, 0xf1, + 0xf8, 0xe1, 0x51, 0xcd, 0xae, 0x53, 0x5f, 0xce, 0x93, 0xfc, 0xb7, 0xce, 0xdc, 0x06, 0xe4, 0x9d, + 0x16, 0x66, 0x22, 0x95, 0x29, 0x07, 0xe1, 0xa8, 0x83, 0x4b, 0x49, 0x07, 0x87, 0x8d, 0xb0, 0x96, + 0xc1, 0x62, 0xca, 0xb5, 0xf2, 0xef, 0xfd, 0x04, 0xd0, 0x13, 0xf1, 0x7d, 0x1c, 0xb6, 0xbd, 0x3a, + 0xbe, 0xb2, 0x7d, 0x6b, 0x00, 0xb0, 0x88, 0x62, 0xe0, 0xde, 0x54, 0xaf, 0x5b, 0xc8, 0x4b, 0xe2, + 0x9d, 0x6d, 0x27, 0x2f, 0x01, 0xff, 0xde, 0x3b, 0x7b, 0xd4, 0xbb, 0xc5, 0x34, 0xef, 0x64, 0xaf, + 0xd6, 0x12, 0x30, 0x46, 0x6f, 0x95, 0x73, 0x5f, 0x35, 0x30, 0x53, 0x65, 0xe4, 0x69, 0xcb, 0x45, + 0x1c, 0xef, 0x89, 0xcd, 0xd3, 0x77, 0x41, 0x1e, 0x1d, 0xf1, 0x43, 0x1a, 0x7a, 0xbc, 0x23, 0x6d, + 0x5b, 0xfb, 0xd9, 0x2d, 0x5c, 0xef, 0x20, 0xbf, 0x59, 0xb6, 0x54, 0xc8, 0x1a, 0x6f, 0xa5, 0xc2, + 0xe8, 0x8f, 0x40, 0x2e, 0xda, 0x67, 0xb9, 0x6e, 0xcb, 0x76, 0xea, 0x43, 0x65, 0x47, 0xa5, 0x2b, + 0xff, 0xf5, 0x0d, 0x72, 0x64, 0x4a, 0xf9, 0xa1, 0x90, 0xaa, 0xc8, 0xfa, 0x52, 0x07, 0xaf, 0xe1, + 0xab, 0xc4, 0xab, 0x31, 0xa4, 0xc0, 0x5a, 0x00, 0x73, 0x43, 0x57, 0xb1, 0xe0, 0x8d, 0x93, 0x2c, + 0xc8, 0x56, 0x19, 0xd1, 0x29, 0x98, 0x94, 0x2b, 0xc8, 0x51, 0x03, 0xeb, 0xf7, 0xc6, 0xf4, 0x95, + 0xb6, 0xb6, 0xc6, 0xe6, 0x5f, 0x80, 0xe3, 0xc2, 0xfa, 0x0b, 0x30, 0x93, 0x98, 0x5b, 0x51, 0xb4, + 0x38, 0x9e, 0x67, 0x78, 0xd4, 0x8d, 0x8d, 0xcb, 0x63, 0x55, 0xc9, 0x00, 0x4c, 0x0f, 0xbe, 0x6f, + 0x51, 0xf1, 0xee, 0x9f, 0x59, 0x64, 0x86, 0x51, 0xba, 0x34, 0x54, 0xd5, 0x7b, 0x0e, 0xae, 0x5d, + 0x18, 0xa4, 0x3b, 0xe3, 0x29, 0x92, 0x38, 0xc3, 0xbe, 0x1c, 0x2e, 0xae, 0x63, 0xfc, 0xff, 0xfa, + 0xfc, 0xb8, 0xa8, 0x55, 0xaa, 0x27, 0x3d, 0x53, 0x3b, 0xed, 0x99, 0xda, 0x8f, 0x9e, 0xa9, 0xbd, + 0x3b, 0x33, 0x33, 0xa7, 0x67, 0x66, 0xe6, 0xdb, 0x99, 0x99, 0x79, 0xb6, 0x99, 0xd8, 0xaa, 0x98, + 0x7a, 0xbd, 0x89, 0x6a, 0x0c, 0xa6, 0x8e, 0x8f, 0x58, 0xb3, 0x5a, 0x4e, 0xfc, 0xe2, 0x6c, 0xfe, + 0x0a, 0x00, 0x00, 0xff, 0xff, 0x26, 0x43, 0x66, 0xb9, 0x71, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -857,16 +857,20 @@ func (m *MsgDelegateService) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + 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 = encodeVarintMessages(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a } - i -= size - i = encodeVarintMessages(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x1a if m.ServiceID != 0 { i = encodeVarintMessages(dAtA, i, uint64(m.ServiceID)) i-- @@ -1047,8 +1051,12 @@ func (m *MsgDelegateService) Size() (n int) { if m.ServiceID != 0 { n += 1 + sovMessages(uint64(m.ServiceID)) } - l = m.Amount.Size() - n += 1 + l + sovMessages(uint64(l)) + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovMessages(uint64(l)) + } + } return n } @@ -1550,7 +1558,8 @@ func (m *MsgDelegateService) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/restaking/types/messages_test.go b/x/restaking/types/messages_test.go index 8360423b6..ea85c57c2 100644 --- a/x/restaking/types/messages_test.go +++ b/x/restaking/types/messages_test.go @@ -140,7 +140,7 @@ func TestMsgDelegateOperator_GetSigners(t *testing.T) { var msgDelegateService = types.NewMsgDelegateService( 1, - sdk.NewCoin("umilk", sdkmath.NewInt(100_000_000)), + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100_000_000))), "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", ) @@ -163,7 +163,7 @@ func TestMsgDelegateService_ValidateBasic(t *testing.T) { name: "invalid amount returns error", msg: types.NewMsgDelegateService( msgDelegateService.ServiceID, - sdk.Coin{Denom: "invalid!", Amount: sdkmath.NewInt(100_000_000)}, + sdk.Coins{sdk.Coin{Denom: "invalid!", Amount: sdkmath.NewInt(100_000_000)}}, msgDelegateService.Delegator, ), shouldErr: true, From 5e9f9003316b6e2f3a3746861c89a6e5c7fa15d3 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 15:15:54 -0500 Subject: [PATCH 24/37] fix: fix wrong error code --- x/operators/types/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/operators/types/errors.go b/x/operators/types/errors.go index dd51f5a96..6684402f7 100644 --- a/x/operators/types/errors.go +++ b/x/operators/types/errors.go @@ -9,5 +9,5 @@ var ( ErrInvalidDeactivationTime = errors.Register(ModuleName, 2, "invalid deactivation time") ErrOperatorNotFound = errors.Register(ModuleName, 3, "operator not found") ErrOperatorNotActive = errors.Register(ModuleName, 4, "operator not active") - ErrInsufficientShares = errors.Register(ModuleName, 3, "insufficient delegation shares") + ErrInsufficientShares = errors.Register(ModuleName, 5, "insufficient delegation shares") ) From f436dbfbad8fa159e8b25f416bf24bd3bf350bb7 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 15:16:07 -0500 Subject: [PATCH 25/37] fix(tests): fix operators restaking tests --- x/restaking/keeper/operator_restaking_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x/restaking/keeper/operator_restaking_test.go b/x/restaking/keeper/operator_restaking_test.go index f5f56a235..a122865d5 100644 --- a/x/restaking/keeper/operator_restaking_test.go +++ b/x/restaking/keeper/operator_restaking_test.go @@ -405,6 +405,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { suite.Require().True(found) suite.Require().Equal(operatorstypes.Operator{ ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, Address: operatorstypes.GetOperatorAddress(1).String(), Tokens: sdk.NewCoins( sdk.NewCoin("umilk", sdkmath.NewInt(80)), @@ -446,6 +447,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { // Create the operator suite.ok.SaveOperator(ctx, operatorstypes.Operator{ ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, Address: operatorstypes.GetOperatorAddress(1).String(), Tokens: sdk.NewCoins( sdk.NewCoin("umilk", sdkmath.NewInt(80)), @@ -507,6 +509,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { suite.Require().True(found) suite.Require().Equal(operatorstypes.Operator{ ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, Address: operatorstypes.GetOperatorAddress(1).String(), Tokens: sdk.NewCoins( sdk.NewCoin("umilk", sdkmath.NewInt(180)), From 954ea66dc6d13a75b2cd05267c3f01a4713c68cb Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 15:16:16 -0500 Subject: [PATCH 26/37] feat(tests): add service restaking tests --- x/restaking/keeper/common_test.go | 13 +- x/restaking/keeper/keeper.go | 2 + x/restaking/keeper/service_restaking_test.go | 574 +++++++++++++++++++ 3 files changed, 588 insertions(+), 1 deletion(-) create mode 100644 x/restaking/keeper/service_restaking_test.go diff --git a/x/restaking/keeper/common_test.go b/x/restaking/keeper/common_test.go index 60333a1c6..5cef6e5ae 100644 --- a/x/restaking/keeper/common_test.go +++ b/x/restaking/keeper/common_test.go @@ -22,6 +22,8 @@ import ( poolstypes "github.com/milkyway-labs/milkyway/x/pools/types" "github.com/milkyway-labs/milkyway/x/restaking/keeper" "github.com/milkyway-labs/milkyway/x/restaking/types" + serviceskeeper "github.com/milkyway-labs/milkyway/x/services/keeper" + servicestypes "github.com/milkyway-labs/milkyway/x/services/types" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" @@ -49,6 +51,7 @@ type KeeperTestSuite struct { bk bankkeeper.Keeper pk *poolskeeper.Keeper ok *operatorskeeper.Keeper + sk *serviceskeeper.Keeper k *keeper.Keeper } @@ -56,7 +59,7 @@ func (suite *KeeperTestSuite) SetupTest() { // Define store keys keys := storetypes.NewKVStoreKeys( types.StoreKey, - authtypes.StoreKey, banktypes.StoreKey, poolstypes.StoreKey, operatorstypes.StoreKey, + authtypes.StoreKey, banktypes.StoreKey, poolstypes.StoreKey, operatorstypes.StoreKey, servicestypes.StoreKey, ) suite.storeKey = keys[types.StoreKey] @@ -115,6 +118,13 @@ func (suite *KeeperTestSuite) SetupTest() { communityPoolKeeper, authorityAddr, ) + suite.sk = serviceskeeper.NewKeeper( + suite.cdc, + keys[servicestypes.StoreKey], + suite.ak, + communityPoolKeeper, + authorityAddr, + ) suite.k = keeper.NewKeeper( suite.cdc, suite.storeKey, @@ -122,6 +132,7 @@ func (suite *KeeperTestSuite) SetupTest() { suite.bk, suite.pk, suite.ok, + suite.sk, authorityAddr, ).SetHooks(newMockHooks()) } diff --git a/x/restaking/keeper/keeper.go b/x/restaking/keeper/keeper.go index c09a3e2cd..aa923804b 100644 --- a/x/restaking/keeper/keeper.go +++ b/x/restaking/keeper/keeper.go @@ -31,6 +31,7 @@ func NewKeeper( bankKeeper types.BankKeeper, poolsKeeper types.PoolsKeeper, operatorsKeeper types.OperatorsKeeper, + servicesKeeper types.ServicesKeeper, authority string, ) *Keeper { @@ -47,6 +48,7 @@ func NewKeeper( bankKeeper: bankKeeper, poolsKeeper: poolsKeeper, operatorsKeeper: operatorsKeeper, + servicesKeeper: servicesKeeper, authority: authority, } diff --git a/x/restaking/keeper/service_restaking_test.go b/x/restaking/keeper/service_restaking_test.go new file mode 100644 index 000000000..f39d50e22 --- /dev/null +++ b/x/restaking/keeper/service_restaking_test.go @@ -0,0 +1,574 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/milkyway-labs/milkyway/x/restaking/types" + servicestypes "github.com/milkyway-labs/milkyway/x/services/types" +) + +func (suite *KeeperTestSuite) TestKeeper_SaveServiceDelegation() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + delegation types.ServiceDelegation + check func(ctx sdk.Context) + }{ + { + name: "service delegation is stored properly", + delegation: types.NewServiceDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), + check: func(ctx sdk.Context) { + store := ctx.KVStore(suite.storeKey) + + // Make sure the user-service delegation key exists and contains the delegation + delegationBz := store.Get(types.UserServiceDelegationStoreKey("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", 1)) + suite.Require().NotNil(delegationBz) + + delegation, err := types.UnmarshalServiceDelegation(suite.cdc, delegationBz) + suite.Require().NoError(err) + + suite.Require().Equal(types.NewServiceDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), delegation) + + // Make sure the service-user delegation key exists + hasDelegationsByServiceKey := store.Has(types.DelegationByServiceIDStoreKey(1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4")) + suite.Require().True(hasDelegationsByServiceKey) + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + suite.k.SaveServiceDelegation(ctx, tc.delegation) + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +func (suite *KeeperTestSuite) TestKeeper_GetServiceDelegation() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + serviceID uint32 + userAddress string + expFound bool + expDelegation types.ServiceDelegation + check func(ctx sdk.Context) + }{ + { + name: "not found delegation returns false", + serviceID: 1, + userAddress: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + expFound: false, + }, + { + name: "found delegation is returned properly", + store: func(ctx sdk.Context) { + suite.k.SaveServiceDelegation(ctx, types.NewServiceDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + )) + }, + serviceID: 1, + userAddress: "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + expFound: true, + expDelegation: types.NewServiceDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + delegation, found := suite.k.GetServiceDelegation(ctx, tc.serviceID, tc.userAddress) + if !tc.expFound { + suite.Require().False(found) + } else { + suite.Require().True(found) + suite.Require().Equal(tc.expDelegation, delegation) + } + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +func (suite *KeeperTestSuite) TestKeeper_AddServiceTokensAndShares() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + service servicestypes.Service + tokensToAdd sdk.Coins + shouldErr bool + expService servicestypes.Service + expAddedShares sdk.DecCoins + check func(ctx sdk.Context) + }{ + { + name: "adding tokens to an empty service works properly", + service: servicestypes.Service{ + ID: 1, + Address: servicestypes.GetServiceAddress(1).String(), + }, + tokensToAdd: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + shouldErr: false, + expService: servicestypes.Service{ + ID: 1, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + }, + expAddedShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + }, + { + name: "adding tokens to a non-empty service works properly", + service: servicestypes.Service{ + ID: 1, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(50))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + }, + tokensToAdd: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), + shouldErr: false, + expService: servicestypes.Service{ + ID: 1, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(70))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(140))), + }, + expAddedShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(40))), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + service, addedShares, err := suite.k.AddServiceTokensAndShares(ctx, tc.service, tc.tokensToAdd) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + suite.Require().Equal(tc.expService, service) + suite.Require().Equal(tc.expAddedShares, addedShares) + } + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + serviceID uint32 + amount sdk.Coins + delegator string + shouldErr bool + expShares sdk.DecCoins + check func(ctx sdk.Context) + }{ + { + name: "service not found returns error", + serviceID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: true, + }, + { + name: "inactive service returns error", + store: func(ctx sdk.Context) { + suite.sk.SaveService(ctx, servicestypes.Service{ + ID: 1, + Status: servicestypes.SERVICE_STATUS_INACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins(), + DelegatorShares: sdk.NewDecCoins(), + }) + }, + serviceID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: true, + }, + { + name: "invalid exchange rate service returns error", + store: func(ctx sdk.Context) { + suite.sk.SaveService(ctx, servicestypes.Service{ + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins(), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + }) + }, + serviceID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: true, + }, + { + name: "invalid delegator address returns error", + store: func(ctx sdk.Context) { + suite.sk.SaveService(ctx, servicestypes.Service{ + ID: 1, + Address: servicestypes.GetServiceAddress(1).String(), + }) + }, + serviceID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "invalid", + shouldErr: true, + }, + { + name: "insufficient funds return error", + store: func(ctx sdk.Context) { + // Create the service + suite.sk.SaveService(ctx, servicestypes.Service{ + ID: 1, + Address: servicestypes.GetServiceAddress(1).String(), + }) + + // Set the next service id + suite.sk.SetNextServiceID(ctx, 2) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(50))), + ) + }, + serviceID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: true, + }, + { + name: "delegating to an existing service works properly", + store: func(ctx sdk.Context) { + // Create the service + suite.sk.SaveService(ctx, servicestypes.Service{ + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + }) + + // Set the correct service tokens amount + suite.fundAccount( + ctx, + servicestypes.GetServiceAddress(1).String(), + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), + ) + + // Set the next service id + suite.sk.SetNextServiceID(ctx, 2) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + serviceID: 1, + amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: false, + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(500))), + check: func(ctx sdk.Context) { + // Make sure the service now exists + service, found := suite.sk.GetService(ctx, 1) + suite.Require().True(found) + suite.Require().Equal(servicestypes.Service{ + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(120))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(600))), + }, service) + + // Make sure the delegation exists + delegation, found := suite.k.GetServiceDelegation(ctx, 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4") + suite.Require().True(found) + suite.Require().Equal(types.NewServiceDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(500))), + ), delegation) + + // Make sure the user balance has been reduced properly + userBalance := suite.bk.GetBalance(ctx, sdk.AccAddress("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(0)), userBalance) + + // Make sure the service account balance has increased properly + serviceBalance := suite.bk.GetBalance(ctx, servicestypes.GetServiceAddress(1), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(120)), serviceBalance) + }, + }, + { + name: "delegating another token denom works properly", + store: func(ctx sdk.Context) { + // Create the service + suite.sk.SaveService(ctx, servicestypes.Service{ + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(80))), + DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125))), + }) + + // Set the correct service tokens amount + suite.fundAccount( + ctx, + servicestypes.GetServiceAddress(1).String(), + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(80))), + ) + + // Set the next service id + suite.sk.SetNextServiceID(ctx, 2) + + // Save the existing delegation + suite.k.SaveServiceDelegation(ctx, types.NewServiceDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125))), + )) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("uinit", sdkmath.NewInt(100))), + ) + }, + serviceID: 1, + amount: sdk.NewCoins(sdk.NewCoin("uinit", sdkmath.NewInt(100))), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: false, + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100))), + check: func(ctx sdk.Context) { + // Make sure the service now exists + service, found := suite.sk.GetService(ctx, 1) + suite.Require().True(found) + suite.Require().Equal(servicestypes.Service{ + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(80)), + sdk.NewCoin("uinit", sdkmath.NewInt(100)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100)), + ), + }, service) + + // Make sure the delegation has been updated properly + delegation, found := suite.k.GetServiceDelegation(ctx, 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4") + suite.Require().True(found) + suite.Require().Equal(types.NewServiceDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100)), + ), + ), delegation) + + // Make sure the user balance has been reduced properly + userBalance := suite.bk.GetBalance(ctx, sdk.AccAddress("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(0)), userBalance) + + // Make sure the service account balance has increased properly + serviceBalance := suite.bk.GetAllBalances(ctx, servicestypes.GetServiceAddress(1)) + suite.Require().Equal(sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(80)), + sdk.NewCoin("uinit", sdkmath.NewInt(100)), + ), serviceBalance) + }, + }, + { + name: "delegating more tokens works properly", + store: func(ctx sdk.Context) { + // Create the service + suite.sk.SaveService(ctx, servicestypes.Service{ + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(80)), + sdk.NewCoin("uinit", sdkmath.NewInt(75)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(200)), + ), + }) + + // Set the correct service tokens amount + suite.fundAccount( + ctx, + servicestypes.GetServiceAddress(1).String(), + sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(80)), + sdk.NewCoin("uinit", sdkmath.NewInt(75)), + ), + ) + + // Set the next service id + suite.sk.SetNextServiceID(ctx, 2) + + // Save the existing delegation + suite.k.SaveServiceDelegation(ctx, types.NewServiceDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(60)), + ), + )) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdk.NewCoin("uinit", sdkmath.NewInt(225)), + ), + ) + }, + serviceID: 1, + amount: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + sdk.NewCoin("uinit", sdkmath.NewInt(225)), + ), + delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + shouldErr: false, + expShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(15625, 2)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(600)), + ), + check: func(ctx sdk.Context) { + // Make sure the service now exists + service, found := suite.sk.GetService(ctx, 1) + suite.Require().True(found) + suite.Require().Equal(servicestypes.Service{ + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(180)), + sdk.NewCoin("uinit", sdkmath.NewInt(300)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(28125, 2)), + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(800)), + ), + }, service) + + // Make sure the delegation has been updated properly + delegation, found := suite.k.GetServiceDelegation(ctx, 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4") + suite.Require().True(found) + suite.Require().Equal(types.NewServiceDelegation( + 1, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewDecCoins( + sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(25625, 2)), // 100 (existing) + 156.25 (new) + sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(660)), // 60 (existing) + 600 (new) + ), + ), delegation) + + // Make sure the user balance has been reduced properly + userBalance := suite.bk.GetBalance(ctx, sdk.AccAddress("cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), "umilk") + suite.Require().Equal(sdk.NewCoin("umilk", sdkmath.NewInt(0)), userBalance) + + // Make sure the service account balance has increased properly + serviceBalance := suite.bk.GetAllBalances(ctx, servicestypes.GetServiceAddress(1)) + suite.Require().Equal(sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(180)), + sdk.NewCoin("uinit", sdkmath.NewInt(300)), + ), serviceBalance) + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.store != nil { + tc.store(ctx) + } + + shares, err := suite.k.DelegateToService(ctx, tc.serviceID, tc.amount, tc.delegator) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + suite.Require().Equal(tc.expShares, shares) + } + + if tc.check != nil { + tc.check(ctx) + } + }) + } +} From 56fa29518cad8ad5fe3387d96c389c3d753351a2 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Mon, 1 Jul 2024 15:28:37 -0500 Subject: [PATCH 27/37] fix(test): fixed tests --- x/operators/types/models.go | 16 +++++++--------- x/restaking/keeper/operator_restaking.go | 2 +- x/restaking/keeper/service_restaking.go | 2 +- x/restaking/types/genesis_test.go | 2 +- x/restaking/types/messages_test.go | 2 +- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/x/operators/types/models.go b/x/operators/types/models.go index b42146a38..9d387d2e2 100644 --- a/x/operators/types/models.go +++ b/x/operators/types/models.go @@ -36,15 +36,13 @@ func NewOperator( admin string, ) Operator { return Operator{ - ID: id, - Status: status, - Admin: admin, - Moniker: moniker, - Website: website, - PictureURL: pictureURL, - Address: GetOperatorAddress(id).String(), - Tokens: sdk.NewCoins(), - DelegatorShares: sdk.NewDecCoins(), + ID: id, + Status: status, + Admin: admin, + Moniker: moniker, + Website: website, + PictureURL: pictureURL, + Address: GetOperatorAddress(id).String(), } } diff --git a/x/restaking/keeper/operator_restaking.go b/x/restaking/keeper/operator_restaking.go index 3b88edd46..bc80bb540 100644 --- a/x/restaking/keeper/operator_restaking.go +++ b/x/restaking/keeper/operator_restaking.go @@ -18,7 +18,7 @@ func (k *Keeper) SaveOperatorDelegation(ctx sdk.Context, delegation types.Operat store.Set(types.UserOperatorDelegationStoreKey(delegation.UserAddress, delegation.OperatorID), delegationBz) // Store the delegation in the delegations by operator ID store - store.Set(types.DelegationByPoolIDStoreKey(delegation.OperatorID, delegation.UserAddress), []byte{}) + store.Set(types.DelegationByOperatorIDStoreKey(delegation.OperatorID, delegation.UserAddress), []byte{}) } // GetOperatorDelegation retrieves the delegation for the given user and operator diff --git a/x/restaking/keeper/service_restaking.go b/x/restaking/keeper/service_restaking.go index 6ba6225f3..3a462ded8 100644 --- a/x/restaking/keeper/service_restaking.go +++ b/x/restaking/keeper/service_restaking.go @@ -18,7 +18,7 @@ func (k *Keeper) SaveServiceDelegation(ctx sdk.Context, delegation types.Service store.Set(types.UserServiceDelegationStoreKey(delegation.UserAddress, delegation.ServiceID), delegationBz) // Store the delegation in the delegations by service ID store - store.Set(types.DelegationByPoolIDStoreKey(delegation.ServiceID, delegation.UserAddress), []byte{}) + store.Set(types.DelegationByServiceIDStoreKey(delegation.ServiceID, delegation.UserAddress), []byte{}) } // GetServiceDelegation retrieves the delegation for the given user and service diff --git a/x/restaking/types/genesis_test.go b/x/restaking/types/genesis_test.go index b98fe6f65..20b8bac1d 100644 --- a/x/restaking/types/genesis_test.go +++ b/x/restaking/types/genesis_test.go @@ -211,7 +211,7 @@ func TestServiceDelegation_Validate(t *testing.T) { entry: types.NewServiceDelegation( 1, "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.DecCoins{sdk.DecCoin{Denom: "umilk", Amount: sdkmath.LegacyNewDec(100)}}, + sdk.DecCoins{sdk.DecCoin{Denom: "umilk", Amount: sdkmath.LegacyNewDec(-100)}}, ), shouldErr: true, }, diff --git a/x/restaking/types/messages_test.go b/x/restaking/types/messages_test.go index ea85c57c2..3c93ddf61 100644 --- a/x/restaking/types/messages_test.go +++ b/x/restaking/types/messages_test.go @@ -197,7 +197,7 @@ func TestMsgDelegateService_ValidateBasic(t *testing.T) { } func TestMsgDelegateService_GetSignBytes(t *testing.T) { - expected := `{"type":"milkyway/MsgDelegateService","value":{"amount":{"amount":"100000000","denom":"umilk"},"delegator":"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd","service_id":1}}` + expected := `{"type":"milkyway/MsgDelegateService","value":{"amount":[{"amount":"100000000","denom":"umilk"}],"delegator":"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd","service_id":1}}` require.Equal(t, expected, string(msgDelegateService.GetSignBytes())) } From fe1529cf8465f5c4d86e6fab0ed4b9a682dfe3e8 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 2 Jul 2024 09:51:53 -0500 Subject: [PATCH 28/37] refactor: remove unused i --- x/restaking/keeper/alias_functions.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/restaking/keeper/alias_functions.go b/x/restaking/keeper/alias_functions.go index 0e291f228..764e11b7c 100644 --- a/x/restaking/keeper/alias_functions.go +++ b/x/restaking/keeper/alias_functions.go @@ -40,10 +40,10 @@ func (k *Keeper) GetAllDelegatorPoolDelegations(ctx sdk.Context, delegator strin defer iterator.Close() var delegations []types.PoolDelegation - for i := 0; iterator.Valid(); iterator.Next() { + for ; iterator.Valid(); iterator.Next() { delegation := types.MustUnmarshalPoolDelegation(k.cdc, iterator.Value()) delegations = append(delegations, delegation) - i++ + } return delegations From d9b1f149912624b3fed4809f34ae208cc6115b24 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 2 Jul 2024 09:54:07 -0500 Subject: [PATCH 29/37] refactor: use GetPoolDelegation inside alias_functions --- x/restaking/keeper/alias_functions.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/x/restaking/keeper/alias_functions.go b/x/restaking/keeper/alias_functions.go index 764e11b7c..c8a9a4a7f 100644 --- a/x/restaking/keeper/alias_functions.go +++ b/x/restaking/keeper/alias_functions.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -63,10 +65,9 @@ func (k *Keeper) GetPoolDelegations(ctx sdk.Context, poolID uint32) ([]types.Poo return nil, err } - bz := store.Get(types.UserPoolDelegationStoreKey(delegatorAddress, poolID)) - delegation, err := types.UnmarshalPoolDelegation(k.cdc, bz) - if err != nil { - return nil, err + delegation, found := k.GetPoolDelegation(ctx, poolID, delegatorAddress) + if !found { + return nil, fmt.Errorf("delegation not found for pool %d and delegator %s", poolID, delegatorAddress) } delegations = append(delegations, delegation) From a2dc2e4ce9ded2fb588ae1cc209b0521ad6c0779 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 2 Jul 2024 09:55:12 -0500 Subject: [PATCH 30/37] chore: update delegation bytes variable name --- x/restaking/keeper/operator_restaking.go | 8 +++----- x/restaking/keeper/pool_restaking.go | 8 +++----- x/restaking/keeper/service_restaking.go | 8 +++----- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/x/restaking/keeper/operator_restaking.go b/x/restaking/keeper/operator_restaking.go index bc80bb540..e00ab8a62 100644 --- a/x/restaking/keeper/operator_restaking.go +++ b/x/restaking/keeper/operator_restaking.go @@ -24,15 +24,13 @@ func (k *Keeper) SaveOperatorDelegation(ctx sdk.Context, delegation types.Operat // GetOperatorDelegation retrieves the delegation for the given user and operator // If the delegation does not exist, false is returned instead func (k *Keeper) GetOperatorDelegation(ctx sdk.Context, operatorID uint32, userAddress string) (types.OperatorDelegation, bool) { - // Get the delegation amount from the store store := ctx.KVStore(k.storeKey) - delegationAmountBz := store.Get(types.UserOperatorDelegationStoreKey(userAddress, operatorID)) - if delegationAmountBz == nil { + delegationBz := store.Get(types.UserOperatorDelegationStoreKey(userAddress, operatorID)) + if delegationBz == nil { return types.OperatorDelegation{}, false } - // Parse the delegation amount - return types.MustUnmarshalOperatorDelegation(k.cdc, delegationAmountBz), true + return types.MustUnmarshalOperatorDelegation(k.cdc, delegationBz), true } // AddOperatorTokensAndShares adds the given amount of tokens to the operator and returns the added shares diff --git a/x/restaking/keeper/pool_restaking.go b/x/restaking/keeper/pool_restaking.go index 27d3fb3b8..1f243833d 100644 --- a/x/restaking/keeper/pool_restaking.go +++ b/x/restaking/keeper/pool_restaking.go @@ -25,15 +25,13 @@ func (k *Keeper) SavePoolDelegation(ctx sdk.Context, delegation types.PoolDelega // GetPoolDelegation retrieves the delegation for the given user and pool // If the delegation does not exist, false is returned instead func (k *Keeper) GetPoolDelegation(ctx sdk.Context, poolID uint32, userAddress string) (types.PoolDelegation, bool) { - // Get the delegation amount from the store store := ctx.KVStore(k.storeKey) - delegationAmountBz := store.Get(types.UserPoolDelegationStoreKey(userAddress, poolID)) - if delegationAmountBz == nil { + delegationBz := store.Get(types.UserPoolDelegationStoreKey(userAddress, poolID)) + if delegationBz == nil { return types.PoolDelegation{}, false } - // Parse the delegation amount - return types.MustUnmarshalPoolDelegation(k.cdc, delegationAmountBz), true + return types.MustUnmarshalPoolDelegation(k.cdc, delegationBz), true } // AddPoolTokensAndShares adds the given amount of tokens to the pool and returns the added shares diff --git a/x/restaking/keeper/service_restaking.go b/x/restaking/keeper/service_restaking.go index 3a462ded8..07fb87d05 100644 --- a/x/restaking/keeper/service_restaking.go +++ b/x/restaking/keeper/service_restaking.go @@ -24,15 +24,13 @@ func (k *Keeper) SaveServiceDelegation(ctx sdk.Context, delegation types.Service // GetServiceDelegation retrieves the delegation for the given user and service // If the delegation does not exist, false is returned instead func (k *Keeper) GetServiceDelegation(ctx sdk.Context, serviceID uint32, userAddress string) (types.ServiceDelegation, bool) { - // Get the delegation amount from the store store := ctx.KVStore(k.storeKey) - delegationAmountBz := store.Get(types.UserServiceDelegationStoreKey(userAddress, serviceID)) - if delegationAmountBz == nil { + delegationBz := store.Get(types.UserServiceDelegationStoreKey(userAddress, serviceID)) + if delegationBz == nil { return types.ServiceDelegation{}, false } - // Parse the delegation amount - return types.MustUnmarshalServiceDelegation(k.cdc, delegationAmountBz), true + return types.MustUnmarshalServiceDelegation(k.cdc, delegationBz), true } // AddServiceTokensAndShares adds the given amount of tokens to the service and returns the added shares From 60f91330a1d159d2ecc28480556c883f0b6ba8c0 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 2 Jul 2024 09:55:35 -0500 Subject: [PATCH 31/37] fix: update service id attribute --- x/restaking/types/events.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/restaking/types/events.go b/x/restaking/types/events.go index ec4000638..4c9ec768a 100644 --- a/x/restaking/types/events.go +++ b/x/restaking/types/events.go @@ -7,6 +7,6 @@ const ( AttributeKeyDelegator = "delegator" AttributeKeyOperatorID = "operator_id" - AttributeKeyServiceID = "operator_id" + AttributeKeyServiceID = "service_id" AttributeKeyNewShares = "new_shares" ) From 1b3f949c650770d5c111efb7001dd07709637549 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 2 Jul 2024 11:51:07 -0500 Subject: [PATCH 32/37] refactor: rename msg service methods names --- proto/milkyway/restaking/v1/messages.proto | 27 +- x/restaking/keeper/msg_server.go | 20 +- x/restaking/types/codec.go | 5 +- x/restaking/types/events.go | 6 +- x/restaking/types/messages.go | 12 +- x/restaking/types/messages.pb.go | 285 ++++++++++----------- x/restaking/types/messages_test.go | 28 +- 7 files changed, 190 insertions(+), 193 deletions(-) diff --git a/proto/milkyway/restaking/v1/messages.proto b/proto/milkyway/restaking/v1/messages.proto index 9b91fd707..683483ef3 100644 --- a/proto/milkyway/restaking/v1/messages.proto +++ b/proto/milkyway/restaking/v1/messages.proto @@ -15,19 +15,19 @@ option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types"; service Msg { option (cosmos.msg.v1.service) = true; - // PoolRestake defines the operation that allows users to join a restaking - // pool with a given amount of assets. The pool can then be used to provide - // services with cryptoeconomic security. - rpc PoolRestake(MsgJoinRestakingPool) returns (MsgJoinRestakingPoolResponse); + // DelegatePool defines the operation that allows users to delegate any amount + // of an asset to a pool that can then be used to provide services with + // cryptoeconomic security. + rpc DelegatePool(MsgDelegatePool) returns (MsgDelegatePoolResponse); - // OperatorRestake defines the operation that allows users to delegate their + // DelegateOperator defines the operation that allows users to delegate their // assets to a specific operator. - rpc OperatorRestake(MsgDelegateOperator) + rpc DelegateOperator(MsgDelegateOperator) returns (MsgDelegateOperatorResponse); - // ServiceRestake defines the operation that allows users to delegate their + // DelegateService defines the operation that allows users to delegate their // assets to a specific service. - rpc ServiceRestake(MsgDelegateService) returns (MsgDelegateServiceResponse); + rpc DelegateService(MsgDelegateService) returns (MsgDelegateServiceResponse); // UpdateParams defines a (governance) operation for updating the module // parameters. @@ -35,11 +35,11 @@ service Msg { rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); } -// MsgJoinRestakingPool defines the message structure for the PoolRestake gRPC +// MsgDelegatePool defines the message structure for the DelegatePool gRPC // service method. It allows a user to put their assets into a restaking pool // that will later be used to provide cryptoeconomic security to services that -// chose it. -message MsgJoinRestakingPool { +// choose it. +message MsgDelegatePool { option (cosmos.msg.v1.signer) = "delegator"; option (amino.name) = "milkyway/MsgJoinRestakingPool"; @@ -51,9 +51,8 @@ message MsgJoinRestakingPool { [ (gogoproto.customname) = "Amount", (gogoproto.nullable) = false ]; } -// MsgJoinRestakingPoolResponse defines the return value of -// MsgJoinRestakingPool. -message MsgJoinRestakingPoolResponse {} +// MsgDelegatePoolResponse defines the return value of MsgDelegatePool. +message MsgDelegatePoolResponse {} // MsgDelegateOperator defines the message structure for the OperatorRestake // gRPC service method. It allows a user to delegate their assets to an diff --git a/x/restaking/keeper/msg_server.go b/x/restaking/keeper/msg_server.go index 453994ae1..c241bbc09 100644 --- a/x/restaking/keeper/msg_server.go +++ b/x/restaking/keeper/msg_server.go @@ -26,8 +26,8 @@ func NewMsgServerImpl(keeper *Keeper) types.MsgServer { return &msgServer{Keeper: keeper} } -// PoolRestake defines the rpc method for Msg/PoolRestake -func (k msgServer) PoolRestake(goCtx context.Context, msg *types.MsgJoinRestakingPool) (*types.MsgJoinRestakingPoolResponse, error) { +// DelegatePool defines the rpc method for Msg/DelegatePool +func (k msgServer) DelegatePool(goCtx context.Context, msg *types.MsgDelegatePool) (*types.MsgDelegatePoolResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) if !msg.Amount.IsValid() || !msg.Amount.Amount.IsPositive() { @@ -56,18 +56,18 @@ func (k msgServer) PoolRestake(goCtx context.Context, msg *types.MsgJoinRestakin sdkCtx := sdk.UnwrapSDKContext(ctx) sdkCtx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - types.EventTypePoolRestake, + types.EventTypeDelegatePool, sdk.NewAttribute(types.AttributeKeyDelegator, msg.Delegator), sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), sdk.NewAttribute(types.AttributeKeyNewShares, newShares.String()), ), }) - return &types.MsgJoinRestakingPoolResponse{}, nil + return &types.MsgDelegatePoolResponse{}, nil } -// OperatorRestake defines the rpc method for Msg/OperatorRestake -func (k msgServer) OperatorRestake(goCtx context.Context, msg *types.MsgDelegateOperator) (*types.MsgDelegateOperatorResponse, error) { +// DelegateOperator defines the rpc method for Msg/DelegateOperator +func (k msgServer) DelegateOperator(goCtx context.Context, msg *types.MsgDelegateOperator) (*types.MsgDelegateOperatorResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) if !msg.Amount.IsValid() || !msg.Amount.IsAllPositive() { @@ -98,7 +98,7 @@ func (k msgServer) OperatorRestake(goCtx context.Context, msg *types.MsgDelegate sdkCtx := sdk.UnwrapSDKContext(ctx) sdkCtx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - types.EventTypeOperatorRestake, + types.EventTypeDelegateOperator, sdk.NewAttribute(types.AttributeKeyDelegator, msg.Delegator), sdk.NewAttribute(types.AttributeKeyOperatorID, fmt.Sprintf("%d", msg.OperatorID)), sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), @@ -109,8 +109,8 @@ func (k msgServer) OperatorRestake(goCtx context.Context, msg *types.MsgDelegate return &types.MsgDelegateOperatorResponse{}, nil } -// ServiceRestake defines the rpc method for Msg/ServiceRestake -func (k msgServer) ServiceRestake(goCtx context.Context, msg *types.MsgDelegateService) (*types.MsgDelegateServiceResponse, error) { +// DelegateService defines the rpc method for Msg/DelegateService +func (k msgServer) DelegateService(goCtx context.Context, msg *types.MsgDelegateService) (*types.MsgDelegateServiceResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) if !msg.Amount.IsValid() || !msg.Amount.IsAllPositive() { @@ -141,7 +141,7 @@ func (k msgServer) ServiceRestake(goCtx context.Context, msg *types.MsgDelegateS sdkCtx := sdk.UnwrapSDKContext(ctx) sdkCtx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( - types.EventTypeServiceRestake, + types.EventTypeDelegateService, sdk.NewAttribute(types.AttributeKeyDelegator, msg.Delegator), sdk.NewAttribute(types.AttributeKeyServiceID, fmt.Sprintf("%d", msg.ServiceID)), sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), diff --git a/x/restaking/types/codec.go b/x/restaking/types/codec.go index 1ac8bb296..0c0edf3af 100644 --- a/x/restaking/types/codec.go +++ b/x/restaking/types/codec.go @@ -11,15 +11,14 @@ import ( func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { legacy.RegisterAminoMsg(cdc, &MsgDelegateService{}, "milkyway/MsgDelegateService") - legacy.RegisterAminoMsg(cdc, &MsgJoinRestakingPool{}, "milkyway/MsgJoinRestakingPool") + legacy.RegisterAminoMsg(cdc, &MsgDelegatePool{}, "milkyway/MsgDelegatePool") legacy.RegisterAminoMsg(cdc, &MsgDelegateOperator{}, "milkyway/MsgDelegateOperator") legacy.RegisterAminoMsg(cdc, &MsgUpdateParams{}, "milkyway/restaking/MsgUpdateParams") - } func RegisterInterfaces(registry types.InterfaceRegistry) { registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgJoinRestakingPool{}, + &MsgDelegatePool{}, &MsgDelegateService{}, &MsgDelegateOperator{}, &MsgUpdateParams{}, diff --git a/x/restaking/types/events.go b/x/restaking/types/events.go index 4c9ec768a..c3917311a 100644 --- a/x/restaking/types/events.go +++ b/x/restaking/types/events.go @@ -1,9 +1,9 @@ package types const ( - EventTypePoolRestake = "pool_restake" - EventTypeOperatorRestake = "operator_restake" - EventTypeServiceRestake = "service_restake" + EventTypeDelegatePool = "delegate_pool" + EventTypeDelegateOperator = "delegate_operator" + EventTypeDelegateService = "delegate_service" AttributeKeyDelegator = "delegator" AttributeKeyOperatorID = "operator_id" diff --git a/x/restaking/types/messages.go b/x/restaking/types/messages.go index 54b941b0f..d91e47f4b 100644 --- a/x/restaking/types/messages.go +++ b/x/restaking/types/messages.go @@ -6,16 +6,16 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// NewMsgJoinRestakingPool creates a new MsgJoinRestakePool instance -func NewMsgJoinRestakingPool(amount sdk.Coin, delegator string) *MsgJoinRestakingPool { - return &MsgJoinRestakingPool{ +// NewMsgDelegatePool creates a new MsgDelegatePool instance +func NewMsgDelegatePool(amount sdk.Coin, delegator string) *MsgDelegatePool { + return &MsgDelegatePool{ Amount: amount, Delegator: delegator, } } // ValidateBasic implements sdk.Msg -func (msg *MsgJoinRestakingPool) ValidateBasic() error { +func (msg *MsgDelegatePool) ValidateBasic() error { if !msg.Amount.IsValid() || msg.Amount.IsZero() { return errors.Wrap(sdkerrors.ErrInvalidRequest, "invalid amount") } @@ -29,12 +29,12 @@ func (msg *MsgJoinRestakingPool) ValidateBasic() error { } // GetSignBytes implements sdk.Msg -func (msg *MsgJoinRestakingPool) GetSignBytes() []byte { +func (msg *MsgDelegatePool) GetSignBytes() []byte { return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(msg)) } // GetSigners implements sdk.Msg -func (msg *MsgJoinRestakingPool) GetSigners() []sdk.AccAddress { +func (msg *MsgDelegatePool) GetSigners() []sdk.AccAddress { addr, _ := sdk.AccAddressFromBech32(msg.Delegator) return []sdk.AccAddress{addr} } diff --git a/x/restaking/types/messages.pb.go b/x/restaking/types/messages.pb.go index d80832911..497aaa721 100644 --- a/x/restaking/types/messages.pb.go +++ b/x/restaking/types/messages.pb.go @@ -34,29 +34,29 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// MsgJoinRestakingPool defines the message structure for the PoolRestake gRPC +// MsgDelegatePool defines the message structure for the DelegatePool gRPC // service method. It allows a user to put their assets into a restaking pool // that will later be used to provide cryptoeconomic security to services that -// chose it. -type MsgJoinRestakingPool struct { +// choose it. +type MsgDelegatePool struct { // Delegator is the address of the user joining the pool Delegator string `protobuf:"bytes,1,opt,name=delegator,proto3" json:"delegator,omitempty"` // Amount is the amount of coins to be staked Amount types.Coin `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount"` } -func (m *MsgJoinRestakingPool) Reset() { *m = MsgJoinRestakingPool{} } -func (m *MsgJoinRestakingPool) String() string { return proto.CompactTextString(m) } -func (*MsgJoinRestakingPool) ProtoMessage() {} -func (*MsgJoinRestakingPool) Descriptor() ([]byte, []int) { +func (m *MsgDelegatePool) Reset() { *m = MsgDelegatePool{} } +func (m *MsgDelegatePool) String() string { return proto.CompactTextString(m) } +func (*MsgDelegatePool) ProtoMessage() {} +func (*MsgDelegatePool) Descriptor() ([]byte, []int) { return fileDescriptor_9772be2b1a923bdb, []int{0} } -func (m *MsgJoinRestakingPool) XXX_Unmarshal(b []byte) error { +func (m *MsgDelegatePool) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgJoinRestakingPool) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgDelegatePool) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgJoinRestakingPool.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgDelegatePool.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -66,49 +66,48 @@ func (m *MsgJoinRestakingPool) XXX_Marshal(b []byte, deterministic bool) ([]byte return b[:n], nil } } -func (m *MsgJoinRestakingPool) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgJoinRestakingPool.Merge(m, src) +func (m *MsgDelegatePool) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDelegatePool.Merge(m, src) } -func (m *MsgJoinRestakingPool) XXX_Size() int { +func (m *MsgDelegatePool) XXX_Size() int { return m.Size() } -func (m *MsgJoinRestakingPool) XXX_DiscardUnknown() { - xxx_messageInfo_MsgJoinRestakingPool.DiscardUnknown(m) +func (m *MsgDelegatePool) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDelegatePool.DiscardUnknown(m) } -var xxx_messageInfo_MsgJoinRestakingPool proto.InternalMessageInfo +var xxx_messageInfo_MsgDelegatePool proto.InternalMessageInfo -func (m *MsgJoinRestakingPool) GetDelegator() string { +func (m *MsgDelegatePool) GetDelegator() string { if m != nil { return m.Delegator } return "" } -func (m *MsgJoinRestakingPool) GetAmount() types.Coin { +func (m *MsgDelegatePool) GetAmount() types.Coin { if m != nil { return m.Amount } return types.Coin{} } -// MsgJoinRestakingPoolResponse defines the return value of -// MsgJoinRestakingPool. -type MsgJoinRestakingPoolResponse struct { +// MsgDelegatePoolResponse defines the return value of MsgDelegatePool. +type MsgDelegatePoolResponse struct { } -func (m *MsgJoinRestakingPoolResponse) Reset() { *m = MsgJoinRestakingPoolResponse{} } -func (m *MsgJoinRestakingPoolResponse) String() string { return proto.CompactTextString(m) } -func (*MsgJoinRestakingPoolResponse) ProtoMessage() {} -func (*MsgJoinRestakingPoolResponse) Descriptor() ([]byte, []int) { +func (m *MsgDelegatePoolResponse) Reset() { *m = MsgDelegatePoolResponse{} } +func (m *MsgDelegatePoolResponse) String() string { return proto.CompactTextString(m) } +func (*MsgDelegatePoolResponse) ProtoMessage() {} +func (*MsgDelegatePoolResponse) Descriptor() ([]byte, []int) { return fileDescriptor_9772be2b1a923bdb, []int{1} } -func (m *MsgJoinRestakingPoolResponse) XXX_Unmarshal(b []byte) error { +func (m *MsgDelegatePoolResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgJoinRestakingPoolResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgDelegatePoolResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgJoinRestakingPoolResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgDelegatePoolResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -118,17 +117,17 @@ func (m *MsgJoinRestakingPoolResponse) XXX_Marshal(b []byte, deterministic bool) return b[:n], nil } } -func (m *MsgJoinRestakingPoolResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgJoinRestakingPoolResponse.Merge(m, src) +func (m *MsgDelegatePoolResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDelegatePoolResponse.Merge(m, src) } -func (m *MsgJoinRestakingPoolResponse) XXX_Size() int { +func (m *MsgDelegatePoolResponse) XXX_Size() int { return m.Size() } -func (m *MsgJoinRestakingPoolResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgJoinRestakingPoolResponse.DiscardUnknown(m) +func (m *MsgDelegatePoolResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDelegatePoolResponse.DiscardUnknown(m) } -var xxx_messageInfo_MsgJoinRestakingPoolResponse proto.InternalMessageInfo +var xxx_messageInfo_MsgDelegatePoolResponse proto.InternalMessageInfo // MsgDelegateOperator defines the message structure for the OperatorRestake // gRPC service method. It allows a user to delegate their assets to an @@ -432,8 +431,8 @@ func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo func init() { - proto.RegisterType((*MsgJoinRestakingPool)(nil), "milkyway.restaking.v1.MsgJoinRestakingPool") - proto.RegisterType((*MsgJoinRestakingPoolResponse)(nil), "milkyway.restaking.v1.MsgJoinRestakingPoolResponse") + proto.RegisterType((*MsgDelegatePool)(nil), "milkyway.restaking.v1.MsgDelegatePool") + proto.RegisterType((*MsgDelegatePoolResponse)(nil), "milkyway.restaking.v1.MsgDelegatePoolResponse") proto.RegisterType((*MsgDelegateOperator)(nil), "milkyway.restaking.v1.MsgDelegateOperator") proto.RegisterType((*MsgDelegateOperatorResponse)(nil), "milkyway.restaking.v1.MsgDelegateOperatorResponse") proto.RegisterType((*MsgDelegateService)(nil), "milkyway.restaking.v1.MsgDelegateService") @@ -447,51 +446,51 @@ func init() { } var fileDescriptor_9772be2b1a923bdb = []byte{ - // 701 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xc1, 0x4f, 0x13, 0x4f, - 0x14, 0xee, 0xd2, 0xdf, 0xaf, 0x49, 0x07, 0x01, 0x5d, 0x31, 0xc0, 0x02, 0x5b, 0xb2, 0x31, 0x06, - 0x2b, 0xec, 0x58, 0x48, 0x34, 0xa9, 0x27, 0x2a, 0x17, 0x48, 0x1a, 0xc9, 0x12, 0x2f, 0x5e, 0xc8, - 0xb4, 0x3b, 0x0e, 0x9b, 0x76, 0x77, 0xea, 0xce, 0x50, 0xed, 0xcd, 0x78, 0xf4, 0xe4, 0xd5, 0x8b, - 0x7f, 0x80, 0x27, 0x0e, 0xfe, 0x07, 0x5e, 0x38, 0x12, 0xbd, 0x78, 0xaa, 0xa6, 0x1c, 0xb8, 0xfb, - 0x17, 0x98, 0xce, 0xce, 0x4e, 0x97, 0x76, 0xab, 0xc8, 0xc1, 0x0b, 0x74, 0xe6, 0x7d, 0xef, 0x7b, - 0xef, 0xfb, 0xfa, 0xde, 0x14, 0xdc, 0xf6, 0xbd, 0x66, 0xa3, 0xf3, 0x12, 0x75, 0x60, 0x88, 0x19, - 0x47, 0x0d, 0x2f, 0x20, 0xb0, 0x5d, 0x82, 0x3e, 0x66, 0x0c, 0x11, 0xcc, 0xec, 0x56, 0x48, 0x39, - 0xd5, 0x6f, 0xc5, 0x28, 0x5b, 0xa1, 0xec, 0x76, 0xc9, 0xb8, 0x81, 0x7c, 0x2f, 0xa0, 0x50, 0xfc, - 0x8d, 0x90, 0xc6, 0x42, 0x9d, 0x32, 0x9f, 0xb2, 0x03, 0x71, 0x82, 0xd1, 0x41, 0x86, 0xcc, 0xe8, - 0x04, 0x6b, 0x88, 0x61, 0xd8, 0x2e, 0xd5, 0x30, 0x47, 0x25, 0x58, 0xa7, 0x5e, 0x30, 0x12, 0x0f, - 0x1a, 0x2a, 0xde, 0x3f, 0xc8, 0xf8, 0x9c, 0x8c, 0xfb, 0x2c, 0x6a, 0x91, 0x11, 0x19, 0x98, 0x25, - 0x94, 0xd0, 0xa8, 0x60, 0xff, 0x93, 0xbc, 0xb5, 0xd2, 0x95, 0xb5, 0x50, 0x88, 0x7c, 0xd9, 0x92, - 0xf5, 0x59, 0x03, 0xb3, 0x55, 0x46, 0x76, 0xa9, 0x17, 0x38, 0x31, 0x68, 0x8f, 0xd2, 0xa6, 0xfe, - 0x00, 0xe4, 0x5d, 0xdc, 0xc4, 0x04, 0x71, 0x1a, 0xce, 0x6b, 0x2b, 0xda, 0x6a, 0xbe, 0x32, 0xff, - 0xe5, 0xd3, 0xfa, 0xac, 0x14, 0xb4, 0xe5, 0xba, 0x21, 0x66, 0x6c, 0x9f, 0x87, 0x5e, 0x40, 0x9c, - 0x01, 0x54, 0xdf, 0x02, 0x39, 0xe4, 0xd3, 0xa3, 0x80, 0xcf, 0x4f, 0xac, 0x68, 0xab, 0x93, 0x1b, - 0x0b, 0xb6, 0xcc, 0xe8, 0x8b, 0xb6, 0xa5, 0x28, 0xfb, 0x31, 0xf5, 0x82, 0xca, 0xf4, 0x49, 0xb7, - 0x90, 0xe9, 0x75, 0x0b, 0xb9, 0x2d, 0x91, 0xe0, 0xc8, 0xc4, 0xf2, 0xfd, 0x37, 0xe7, 0xc7, 0xc5, - 0x01, 0xe5, 0xdb, 0xf3, 0xe3, 0xe2, 0xb2, 0x92, 0x92, 0xd6, 0xac, 0x65, 0x82, 0xa5, 0xb4, 0x7b, - 0x07, 0xb3, 0x16, 0x0d, 0x18, 0xb6, 0x3e, 0x4c, 0x80, 0x9b, 0x55, 0x46, 0xb6, 0x23, 0x4a, 0xfc, - 0xa4, 0x85, 0x43, 0xd1, 0xec, 0x55, 0x45, 0x42, 0x30, 0x49, 0x25, 0xc7, 0x81, 0xe7, 0x0a, 0xa5, - 0x53, 0x95, 0xe9, 0x5e, 0xb7, 0x00, 0x62, 0xea, 0x9d, 0x6d, 0x07, 0xc4, 0x90, 0x1d, 0x57, 0xf7, - 0x95, 0x2b, 0xd9, 0x95, 0xec, 0xef, 0x5d, 0x29, 0x5f, 0x74, 0xe5, 0xe3, 0xf7, 0xc2, 0x2a, 0xf1, - 0xf8, 0xe1, 0x51, 0xcd, 0xae, 0x53, 0x5f, 0xce, 0x93, 0xfc, 0xb7, 0xce, 0xdc, 0x06, 0xe4, 0x9d, - 0x16, 0x66, 0x22, 0x95, 0x29, 0x07, 0xe1, 0xa8, 0x83, 0x4b, 0x49, 0x07, 0x87, 0x8d, 0xb0, 0x96, - 0xc1, 0x62, 0xca, 0xb5, 0xf2, 0xef, 0xfd, 0x04, 0xd0, 0x13, 0xf1, 0x7d, 0x1c, 0xb6, 0xbd, 0x3a, - 0xbe, 0xb2, 0x7d, 0x6b, 0x00, 0xb0, 0x88, 0x62, 0xe0, 0xde, 0x54, 0xaf, 0x5b, 0xc8, 0x4b, 0xe2, - 0x9d, 0x6d, 0x27, 0x2f, 0x01, 0xff, 0xde, 0x3b, 0x7b, 0xd4, 0xbb, 0xc5, 0x34, 0xef, 0x64, 0xaf, - 0xd6, 0x12, 0x30, 0x46, 0x6f, 0x95, 0x73, 0x5f, 0x35, 0x30, 0x53, 0x65, 0xe4, 0x69, 0xcb, 0x45, - 0x1c, 0xef, 0x89, 0xcd, 0xd3, 0x77, 0x41, 0x1e, 0x1d, 0xf1, 0x43, 0x1a, 0x7a, 0xbc, 0x23, 0x6d, - 0x5b, 0xfb, 0xd9, 0x2d, 0x5c, 0xef, 0x20, 0xbf, 0x59, 0xb6, 0x54, 0xc8, 0x1a, 0x6f, 0xa5, 0xc2, - 0xe8, 0x8f, 0x40, 0x2e, 0xda, 0x67, 0xb9, 0x6e, 0xcb, 0x76, 0xea, 0x43, 0x65, 0x47, 0xa5, 0x2b, - 0xff, 0xf5, 0x0d, 0x72, 0x64, 0x4a, 0xf9, 0xa1, 0x90, 0xaa, 0xc8, 0xfa, 0x52, 0x07, 0xaf, 0xe1, - 0xab, 0xc4, 0xab, 0x31, 0xa4, 0xc0, 0x5a, 0x00, 0x73, 0x43, 0x57, 0xb1, 0xe0, 0x8d, 0x93, 0x2c, - 0xc8, 0x56, 0x19, 0xd1, 0x29, 0x98, 0x94, 0x2b, 0xc8, 0x51, 0x03, 0xeb, 0xf7, 0xc6, 0xf4, 0x95, - 0xb6, 0xb6, 0xc6, 0xe6, 0x5f, 0x80, 0xe3, 0xc2, 0xfa, 0x0b, 0x30, 0x93, 0x98, 0x5b, 0x51, 0xb4, - 0x38, 0x9e, 0x67, 0x78, 0xd4, 0x8d, 0x8d, 0xcb, 0x63, 0x55, 0xc9, 0x00, 0x4c, 0x0f, 0xbe, 0x6f, - 0x51, 0xf1, 0xee, 0x9f, 0x59, 0x64, 0x86, 0x51, 0xba, 0x34, 0x54, 0xd5, 0x7b, 0x0e, 0xae, 0x5d, - 0x18, 0xa4, 0x3b, 0xe3, 0x29, 0x92, 0x38, 0xc3, 0xbe, 0x1c, 0x2e, 0xae, 0x63, 0xfc, 0xff, 0xfa, - 0xfc, 0xb8, 0xa8, 0x55, 0xaa, 0x27, 0x3d, 0x53, 0x3b, 0xed, 0x99, 0xda, 0x8f, 0x9e, 0xa9, 0xbd, - 0x3b, 0x33, 0x33, 0xa7, 0x67, 0x66, 0xe6, 0xdb, 0x99, 0x99, 0x79, 0xb6, 0x99, 0xd8, 0xaa, 0x98, - 0x7a, 0xbd, 0x89, 0x6a, 0x0c, 0xa6, 0x8e, 0x8f, 0x58, 0xb3, 0x5a, 0x4e, 0xfc, 0xe2, 0x6c, 0xfe, - 0x0a, 0x00, 0x00, 0xff, 0xff, 0x26, 0x43, 0x66, 0xb9, 0x71, 0x07, 0x00, 0x00, + // 689 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x3f, 0x6f, 0xd3, 0x4e, + 0x18, 0x8e, 0x9b, 0xdf, 0x2f, 0x52, 0xae, 0x7f, 0x31, 0x45, 0x6d, 0xdd, 0xd6, 0xae, 0x2c, 0x84, + 0x4a, 0xd4, 0xfa, 0x48, 0x2b, 0x81, 0x14, 0xa6, 0x86, 0x2e, 0xad, 0x14, 0x81, 0x5c, 0xb1, 0xb0, + 0x54, 0x97, 0xf8, 0xea, 0x5a, 0x89, 0x7d, 0x96, 0xcf, 0x0d, 0x64, 0x43, 0x8c, 0x4c, 0xac, 0x2c, + 0x7c, 0x00, 0xa6, 0x0e, 0xcc, 0x48, 0x6c, 0x1d, 0x2b, 0x58, 0x98, 0x02, 0x72, 0x87, 0xec, 0x7c, + 0x02, 0x64, 0xfb, 0x7c, 0x71, 0x12, 0x37, 0x8d, 0x3a, 0xb0, 0xb4, 0x79, 0xef, 0x7d, 0xde, 0x3f, + 0xcf, 0x93, 0x7b, 0x2e, 0xe0, 0xbe, 0x6d, 0xb5, 0x9a, 0x9d, 0xd7, 0xa8, 0x03, 0x3d, 0x4c, 0x7d, + 0xd4, 0xb4, 0x1c, 0x13, 0xb6, 0xcb, 0xd0, 0xc6, 0x94, 0x22, 0x13, 0x53, 0xcd, 0xf5, 0x88, 0x4f, + 0xc4, 0x7b, 0x09, 0x4a, 0xe3, 0x28, 0xad, 0x5d, 0x96, 0xee, 0x20, 0xdb, 0x72, 0x08, 0x8c, 0xfe, + 0xc6, 0x48, 0x69, 0xa5, 0x41, 0xa8, 0x4d, 0xe8, 0x71, 0x14, 0xc1, 0x38, 0x60, 0x29, 0x39, 0x8e, + 0x60, 0x1d, 0x51, 0x0c, 0xdb, 0xe5, 0x3a, 0xf6, 0x51, 0x19, 0x36, 0x88, 0xe5, 0x8c, 0xe4, 0x9d, + 0x26, 0xcf, 0x87, 0x01, 0xcb, 0x2f, 0xb1, 0xbc, 0x4d, 0xe3, 0x15, 0xa9, 0xc9, 0x12, 0x8b, 0x26, + 0x31, 0x49, 0x3c, 0x30, 0xfc, 0xc4, 0x4e, 0xd5, 0x6c, 0x66, 0x2e, 0xf2, 0x90, 0xcd, 0x56, 0x52, + 0xbf, 0x0a, 0x60, 0xbe, 0x46, 0xcd, 0x7d, 0xdc, 0xc2, 0x26, 0xf2, 0xf1, 0x0b, 0x42, 0x5a, 0xe2, + 0x63, 0x50, 0x34, 0xe2, 0x98, 0x78, 0xcb, 0xc2, 0x86, 0xb0, 0x59, 0xac, 0x2e, 0x7f, 0xff, 0xb2, + 0xbd, 0xc8, 0xb8, 0xec, 0x19, 0x86, 0x87, 0x29, 0x3d, 0xf2, 0x3d, 0xcb, 0x31, 0xf5, 0x3e, 0x54, + 0xdc, 0x03, 0x05, 0x64, 0x93, 0x33, 0xc7, 0x5f, 0x9e, 0xda, 0x10, 0x36, 0xa7, 0x77, 0x56, 0x34, + 0x56, 0x11, 0xf2, 0xd5, 0x18, 0x1f, 0xed, 0x19, 0xb1, 0x9c, 0xea, 0xdc, 0x45, 0x57, 0xc9, 0x05, + 0x5d, 0xa5, 0xb0, 0x17, 0x15, 0xe8, 0xac, 0xb0, 0xf2, 0xe8, 0x5d, 0xef, 0xbc, 0xd4, 0x6f, 0xf9, + 0xbe, 0x77, 0x5e, 0x5a, 0xe7, 0x2c, 0x6a, 0xd4, 0x3c, 0x24, 0x96, 0xa3, 0x27, 0x64, 0xc2, 0x65, + 0xd5, 0x15, 0xb0, 0x34, 0xb4, 0xbf, 0x8e, 0xa9, 0x4b, 0x1c, 0x8a, 0xd5, 0x4f, 0x53, 0xe0, 0x6e, + 0x2a, 0xf7, 0xdc, 0xc5, 0x5e, 0xb4, 0xe7, 0x6d, 0xf9, 0x41, 0x30, 0x4d, 0x58, 0x8f, 0x63, 0xcb, + 0x88, 0x48, 0xce, 0x56, 0xe7, 0x82, 0xae, 0x02, 0x92, 0xd6, 0x07, 0xfb, 0x3a, 0x48, 0x20, 0x07, + 0x86, 0x68, 0x73, 0x41, 0xf2, 0x1b, 0xf9, 0xf1, 0x82, 0x54, 0x06, 0x05, 0xf9, 0xfc, 0x4b, 0xd9, + 0x34, 0x2d, 0xff, 0xf4, 0xac, 0xae, 0x35, 0x88, 0xcd, 0x6e, 0x11, 0xfb, 0xb7, 0x4d, 0x8d, 0x26, + 0xf4, 0x3b, 0x2e, 0xa6, 0x51, 0x29, 0xe5, 0xe2, 0xc1, 0x51, 0xf1, 0xd6, 0xd2, 0xe2, 0x0d, 0x0b, + 0xa1, 0xae, 0x83, 0xd5, 0x8c, 0x63, 0xae, 0xdf, 0xc7, 0x29, 0x20, 0xa6, 0xf2, 0x47, 0xd8, 0x6b, + 0x5b, 0x0d, 0x7c, 0x6b, 0xf9, 0xb6, 0x00, 0xa0, 0x71, 0x8b, 0xbe, 0x7a, 0xb3, 0x41, 0x57, 0x29, + 0xb2, 0xc6, 0x07, 0xfb, 0x7a, 0x91, 0x01, 0xfe, 0xbd, 0x76, 0xda, 0xa8, 0x76, 0xab, 0x59, 0xda, + 0xb1, 0x5d, 0xd5, 0x35, 0x20, 0x8d, 0x9e, 0x72, 0xe5, 0x7e, 0xc4, 0xae, 0x7a, 0xe9, 0x1a, 0xe1, + 0x9d, 0x8c, 0xfc, 0x26, 0x1e, 0x82, 0x22, 0x3a, 0xf3, 0x4f, 0x89, 0x67, 0xf9, 0x1d, 0x26, 0xdb, + 0xd6, 0x9f, 0xae, 0xb2, 0xd0, 0x41, 0x76, 0xab, 0xa2, 0xf2, 0x94, 0x7a, 0xbd, 0x94, 0x1c, 0x23, + 0x3e, 0x05, 0x85, 0xd8, 0xc5, 0xcc, 0x69, 0xeb, 0x5a, 0xe6, 0xf3, 0xa4, 0xc5, 0xa3, 0xab, 0xff, + 0x85, 0x02, 0xe9, 0xac, 0xa4, 0xf2, 0x24, 0xa2, 0xca, 0x9b, 0x85, 0x54, 0xfb, 0x6f, 0xe0, 0x9b, + 0xd4, 0x5b, 0x31, 0xc4, 0x80, 0x59, 0x2d, 0x7d, 0x94, 0x10, 0xde, 0xf9, 0x96, 0x07, 0xf9, 0x1a, + 0x35, 0xc5, 0x13, 0x30, 0x33, 0xf0, 0x94, 0x3c, 0xb8, 0x66, 0xb1, 0x21, 0xcb, 0x4a, 0xda, 0x64, + 0xb8, 0x64, 0x9e, 0xe8, 0x81, 0x85, 0x11, 0x5b, 0x97, 0x6e, 0xee, 0x91, 0x60, 0xa5, 0x9d, 0xc9, + 0xb1, 0x7c, 0x26, 0x01, 0xf3, 0xc3, 0x56, 0x78, 0x78, 0x73, 0x1b, 0x06, 0x95, 0xca, 0x13, 0x43, + 0xf9, 0xc0, 0x13, 0x30, 0x33, 0x70, 0x83, 0xc6, 0x88, 0x99, 0xc6, 0x8d, 0x13, 0x33, 0xeb, 0xcb, + 0x93, 0xfe, 0x7f, 0xdb, 0x3b, 0x2f, 0x09, 0xd5, 0xda, 0x45, 0x20, 0x0b, 0x97, 0x81, 0x2c, 0xfc, + 0x0e, 0x64, 0xe1, 0xc3, 0x95, 0x9c, 0xbb, 0xbc, 0x92, 0x73, 0x3f, 0xaf, 0xe4, 0xdc, 0xab, 0xdd, + 0x94, 0x9d, 0x92, 0xd6, 0xdb, 0x2d, 0x54, 0xa7, 0x30, 0xf3, 0xde, 0x44, 0xfe, 0xaa, 0x17, 0xa2, + 0x1f, 0x98, 0xdd, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x9f, 0x6a, 0x1c, 0xc5, 0x60, 0x07, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -506,16 +505,16 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type MsgClient interface { - // PoolRestake defines the operation that allows users to join a restaking - // pool with a given amount of assets. The pool can then be used to provide - // services with cryptoeconomic security. - PoolRestake(ctx context.Context, in *MsgJoinRestakingPool, opts ...grpc.CallOption) (*MsgJoinRestakingPoolResponse, error) - // OperatorRestake defines the operation that allows users to delegate their + // DelegatePool defines the operation that allows users to delegate any amount + // of an asset to a pool that can then be used to provide services with + // cryptoeconomic security. + DelegatePool(ctx context.Context, in *MsgDelegatePool, opts ...grpc.CallOption) (*MsgDelegatePoolResponse, error) + // DelegateOperator defines the operation that allows users to delegate their // assets to a specific operator. - OperatorRestake(ctx context.Context, in *MsgDelegateOperator, opts ...grpc.CallOption) (*MsgDelegateOperatorResponse, error) - // ServiceRestake defines the operation that allows users to delegate their + DelegateOperator(ctx context.Context, in *MsgDelegateOperator, opts ...grpc.CallOption) (*MsgDelegateOperatorResponse, error) + // DelegateService defines the operation that allows users to delegate their // assets to a specific service. - ServiceRestake(ctx context.Context, in *MsgDelegateService, opts ...grpc.CallOption) (*MsgDelegateServiceResponse, error) + DelegateService(ctx context.Context, in *MsgDelegateService, opts ...grpc.CallOption) (*MsgDelegateServiceResponse, error) // UpdateParams defines a (governance) operation for updating the module // parameters. // The authority defaults to the x/gov module account. @@ -530,27 +529,27 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { return &msgClient{cc} } -func (c *msgClient) PoolRestake(ctx context.Context, in *MsgJoinRestakingPool, opts ...grpc.CallOption) (*MsgJoinRestakingPoolResponse, error) { - out := new(MsgJoinRestakingPoolResponse) - err := c.cc.Invoke(ctx, "/milkyway.restaking.v1.Msg/PoolRestake", in, out, opts...) +func (c *msgClient) DelegatePool(ctx context.Context, in *MsgDelegatePool, opts ...grpc.CallOption) (*MsgDelegatePoolResponse, error) { + out := new(MsgDelegatePoolResponse) + err := c.cc.Invoke(ctx, "/milkyway.restaking.v1.Msg/DelegatePool", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *msgClient) OperatorRestake(ctx context.Context, in *MsgDelegateOperator, opts ...grpc.CallOption) (*MsgDelegateOperatorResponse, error) { +func (c *msgClient) DelegateOperator(ctx context.Context, in *MsgDelegateOperator, opts ...grpc.CallOption) (*MsgDelegateOperatorResponse, error) { out := new(MsgDelegateOperatorResponse) - err := c.cc.Invoke(ctx, "/milkyway.restaking.v1.Msg/OperatorRestake", in, out, opts...) + err := c.cc.Invoke(ctx, "/milkyway.restaking.v1.Msg/DelegateOperator", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *msgClient) ServiceRestake(ctx context.Context, in *MsgDelegateService, opts ...grpc.CallOption) (*MsgDelegateServiceResponse, error) { +func (c *msgClient) DelegateService(ctx context.Context, in *MsgDelegateService, opts ...grpc.CallOption) (*MsgDelegateServiceResponse, error) { out := new(MsgDelegateServiceResponse) - err := c.cc.Invoke(ctx, "/milkyway.restaking.v1.Msg/ServiceRestake", in, out, opts...) + err := c.cc.Invoke(ctx, "/milkyway.restaking.v1.Msg/DelegateService", in, out, opts...) if err != nil { return nil, err } @@ -568,16 +567,16 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts // MsgServer is the server API for Msg service. type MsgServer interface { - // PoolRestake defines the operation that allows users to join a restaking - // pool with a given amount of assets. The pool can then be used to provide - // services with cryptoeconomic security. - PoolRestake(context.Context, *MsgJoinRestakingPool) (*MsgJoinRestakingPoolResponse, error) - // OperatorRestake defines the operation that allows users to delegate their + // DelegatePool defines the operation that allows users to delegate any amount + // of an asset to a pool that can then be used to provide services with + // cryptoeconomic security. + DelegatePool(context.Context, *MsgDelegatePool) (*MsgDelegatePoolResponse, error) + // DelegateOperator defines the operation that allows users to delegate their // assets to a specific operator. - OperatorRestake(context.Context, *MsgDelegateOperator) (*MsgDelegateOperatorResponse, error) - // ServiceRestake defines the operation that allows users to delegate their + DelegateOperator(context.Context, *MsgDelegateOperator) (*MsgDelegateOperatorResponse, error) + // DelegateService defines the operation that allows users to delegate their // assets to a specific service. - ServiceRestake(context.Context, *MsgDelegateService) (*MsgDelegateServiceResponse, error) + DelegateService(context.Context, *MsgDelegateService) (*MsgDelegateServiceResponse, error) // UpdateParams defines a (governance) operation for updating the module // parameters. // The authority defaults to the x/gov module account. @@ -588,14 +587,14 @@ type MsgServer interface { type UnimplementedMsgServer struct { } -func (*UnimplementedMsgServer) PoolRestake(ctx context.Context, req *MsgJoinRestakingPool) (*MsgJoinRestakingPoolResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method PoolRestake not implemented") +func (*UnimplementedMsgServer) DelegatePool(ctx context.Context, req *MsgDelegatePool) (*MsgDelegatePoolResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelegatePool not implemented") } -func (*UnimplementedMsgServer) OperatorRestake(ctx context.Context, req *MsgDelegateOperator) (*MsgDelegateOperatorResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method OperatorRestake not implemented") +func (*UnimplementedMsgServer) DelegateOperator(ctx context.Context, req *MsgDelegateOperator) (*MsgDelegateOperatorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelegateOperator not implemented") } -func (*UnimplementedMsgServer) ServiceRestake(ctx context.Context, req *MsgDelegateService) (*MsgDelegateServiceResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ServiceRestake not implemented") +func (*UnimplementedMsgServer) DelegateService(ctx context.Context, req *MsgDelegateService) (*MsgDelegateServiceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelegateService not implemented") } func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") @@ -605,56 +604,56 @@ func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) } -func _Msg_PoolRestake_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgJoinRestakingPool) +func _Msg_DelegatePool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgDelegatePool) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).PoolRestake(ctx, in) + return srv.(MsgServer).DelegatePool(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/milkyway.restaking.v1.Msg/PoolRestake", + FullMethod: "/milkyway.restaking.v1.Msg/DelegatePool", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).PoolRestake(ctx, req.(*MsgJoinRestakingPool)) + return srv.(MsgServer).DelegatePool(ctx, req.(*MsgDelegatePool)) } return interceptor(ctx, in, info, handler) } -func _Msg_OperatorRestake_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_DelegateOperator_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgDelegateOperator) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).OperatorRestake(ctx, in) + return srv.(MsgServer).DelegateOperator(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/milkyway.restaking.v1.Msg/OperatorRestake", + FullMethod: "/milkyway.restaking.v1.Msg/DelegateOperator", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).OperatorRestake(ctx, req.(*MsgDelegateOperator)) + return srv.(MsgServer).DelegateOperator(ctx, req.(*MsgDelegateOperator)) } return interceptor(ctx, in, info, handler) } -func _Msg_ServiceRestake_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _Msg_DelegateService_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgDelegateService) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).ServiceRestake(ctx, in) + return srv.(MsgServer).DelegateService(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/milkyway.restaking.v1.Msg/ServiceRestake", + FullMethod: "/milkyway.restaking.v1.Msg/DelegateService", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).ServiceRestake(ctx, req.(*MsgDelegateService)) + return srv.(MsgServer).DelegateService(ctx, req.(*MsgDelegateService)) } return interceptor(ctx, in, info, handler) } @@ -682,16 +681,16 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "PoolRestake", - Handler: _Msg_PoolRestake_Handler, + MethodName: "DelegatePool", + Handler: _Msg_DelegatePool_Handler, }, { - MethodName: "OperatorRestake", - Handler: _Msg_OperatorRestake_Handler, + MethodName: "DelegateOperator", + Handler: _Msg_DelegateOperator_Handler, }, { - MethodName: "ServiceRestake", - Handler: _Msg_ServiceRestake_Handler, + MethodName: "DelegateService", + Handler: _Msg_DelegateService_Handler, }, { MethodName: "UpdateParams", @@ -702,7 +701,7 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ Metadata: "milkyway/restaking/v1/messages.proto", } -func (m *MsgJoinRestakingPool) Marshal() (dAtA []byte, err error) { +func (m *MsgDelegatePool) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -712,12 +711,12 @@ func (m *MsgJoinRestakingPool) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgJoinRestakingPool) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgDelegatePool) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgJoinRestakingPool) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgDelegatePool) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -742,7 +741,7 @@ func (m *MsgJoinRestakingPool) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MsgJoinRestakingPoolResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgDelegatePoolResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -752,12 +751,12 @@ func (m *MsgJoinRestakingPoolResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgJoinRestakingPoolResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgDelegatePoolResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgJoinRestakingPoolResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgDelegatePoolResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -983,7 +982,7 @@ func encodeVarintMessages(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *MsgJoinRestakingPool) Size() (n int) { +func (m *MsgDelegatePool) Size() (n int) { if m == nil { return 0 } @@ -998,7 +997,7 @@ func (m *MsgJoinRestakingPool) Size() (n int) { return n } -func (m *MsgJoinRestakingPoolResponse) Size() (n int) { +func (m *MsgDelegatePoolResponse) Size() (n int) { if m == nil { return 0 } @@ -1099,7 +1098,7 @@ func sovMessages(x uint64) (n int) { func sozMessages(x uint64) (n int) { return sovMessages(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *MsgJoinRestakingPool) Unmarshal(dAtA []byte) error { +func (m *MsgDelegatePool) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1122,10 +1121,10 @@ func (m *MsgJoinRestakingPool) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgJoinRestakingPool: wiretype end group for non-group") + return fmt.Errorf("proto: MsgDelegatePool: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgJoinRestakingPool: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgDelegatePool: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1214,7 +1213,7 @@ func (m *MsgJoinRestakingPool) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgJoinRestakingPoolResponse) Unmarshal(dAtA []byte) error { +func (m *MsgDelegatePoolResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1237,10 +1236,10 @@ func (m *MsgJoinRestakingPoolResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgJoinRestakingPoolResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgDelegatePoolResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgJoinRestakingPoolResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgDelegatePoolResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: diff --git a/x/restaking/types/messages_test.go b/x/restaking/types/messages_test.go index 3c93ddf61..c6391ba4d 100644 --- a/x/restaking/types/messages_test.go +++ b/x/restaking/types/messages_test.go @@ -10,36 +10,36 @@ import ( "github.com/milkyway-labs/milkyway/x/restaking/types" ) -var msgJoinRestakingPool = types.NewMsgJoinRestakingPool( +var msgDelegatePool = types.NewMsgDelegatePool( sdk.NewCoin("umilk", sdkmath.NewInt(100_000_000)), "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", ) -func TestMsgJoinRestakingPool_ValidateBasic(t *testing.T) { +func TestMsgDelegatePool_ValidateBasic(t *testing.T) { testCases := []struct { name string - msg *types.MsgJoinRestakingPool + msg *types.MsgDelegatePool shouldErr bool }{ { name: "invalid amount returns error", - msg: types.NewMsgJoinRestakingPool( + msg: types.NewMsgDelegatePool( sdk.Coin{Denom: "invalid!", Amount: sdkmath.NewInt(100_000_000)}, - msgJoinRestakingPool.Delegator, + msgDelegatePool.Delegator, ), shouldErr: true, }, { name: "invalid delegator address returns error", - msg: types.NewMsgJoinRestakingPool( - msgJoinRestakingPool.Amount, + msg: types.NewMsgDelegatePool( + msgDelegatePool.Amount, "invalid", ), shouldErr: true, }, { name: "valid message returns no error", - msg: msgJoinRestakingPool, + msg: msgDelegatePool, }, } @@ -56,14 +56,14 @@ func TestMsgJoinRestakingPool_ValidateBasic(t *testing.T) { } } -func TestMsgJoinRestakingPool_GetSignBytes(t *testing.T) { - expected := `{"type":"milkyway/MsgJoinRestakingPool","value":{"amount":{"amount":"100000000","denom":"umilk"},"delegator":"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd"}}` - require.Equal(t, expected, string(msgJoinRestakingPool.GetSignBytes())) +func TestMsgDelegatePool_GetSignBytes(t *testing.T) { + expected := `{"type":"milkyway/MsgDelegatePool","value":{"amount":{"amount":"100000000","denom":"umilk"},"delegator":"cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd"}}` + require.Equal(t, expected, string(msgDelegatePool.GetSignBytes())) } -func TestMsgJoinRestakingPool_GetSigners(t *testing.T) { - addr, _ := sdk.AccAddressFromBech32(msgJoinRestakingPool.Delegator) - require.Equal(t, []sdk.AccAddress{addr}, msgJoinRestakingPool.GetSigners()) +func TestMsgDelegatePool_GetSigners(t *testing.T) { + addr, _ := sdk.AccAddressFromBech32(msgDelegatePool.Delegator) + require.Equal(t, []sdk.AccAddress{addr}, msgDelegatePool.GetSigners()) } // -------------------------------------------------------------------------------------------------------------------- From d6b50d205c383945b447a9fd4c8c713770eb0c62 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 2 Jul 2024 12:00:17 -0500 Subject: [PATCH 33/37] refactor: update how GetAllPoolDelegations is implemented --- x/restaking/keeper/alias_functions.go | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/x/restaking/keeper/alias_functions.go b/x/restaking/keeper/alias_functions.go index c8a9a4a7f..8b25557de 100644 --- a/x/restaking/keeper/alias_functions.go +++ b/x/restaking/keeper/alias_functions.go @@ -9,27 +9,18 @@ import ( "github.com/milkyway-labs/milkyway/x/restaking/types" ) -// IterateAllPoolDelegations iterates over all the pool delegations and performs a callback function -func (k *Keeper) IterateAllPoolDelegations(ctx sdk.Context, cb func(delegation types.PoolDelegation) (stop bool)) { +// GetAllPoolDelegations returns all the pool delegations +func (k *Keeper) GetAllPoolDelegations(ctx sdk.Context) []types.PoolDelegation { store := ctx.KVStore(k.storeKey) iterator := store.Iterator(types.PoolDelegationPrefix, storetypes.PrefixEndBytes(types.PoolDelegationPrefix)) defer iterator.Close() + var delegations []types.PoolDelegation for ; iterator.Valid(); iterator.Next() { delegation := types.MustUnmarshalPoolDelegation(k.cdc, iterator.Value()) - if cb(delegation) { - break - } + delegations = append(delegations, delegation) } -} -// GetAllPoolDelegations returns all the pool delegations -func (k *Keeper) GetAllPoolDelegations(ctx sdk.Context) []types.PoolDelegation { - var delegations []types.PoolDelegation - k.IterateAllPoolDelegations(ctx, func(delegation types.PoolDelegation) bool { - delegations = append(delegations, delegation) - return false - }) return delegations } @@ -45,7 +36,6 @@ func (k *Keeper) GetAllDelegatorPoolDelegations(ctx sdk.Context, delegator strin for ; iterator.Valid(); iterator.Next() { delegation := types.MustUnmarshalPoolDelegation(k.cdc, iterator.Value()) delegations = append(delegations, delegation) - } return delegations From d89b84425924743073a5ee114275d9943f579a67 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 2 Jul 2024 12:02:51 -0500 Subject: [PATCH 34/37] chore: return nil shares if hook error is not nil --- x/restaking/keeper/restaking.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/restaking/keeper/restaking.go b/x/restaking/keeper/restaking.go index 046543863..3a0b7e2e2 100644 --- a/x/restaking/keeper/restaking.go +++ b/x/restaking/keeper/restaking.go @@ -67,7 +67,7 @@ func (k *Keeper) PerformDelegation(ctx sdk.Context, data types.DelegationData) ( // Call the after-modification hook err = hooks.AfterDelegationModified(ctx, receiver.GetID(), delegator) if err != nil { - return newShares, err + return nil, err } return newShares, nil From 8b87a42a5a1205c3ae26a6299d34bc226e76b3e6 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 2 Jul 2024 14:40:53 -0500 Subject: [PATCH 35/37] refactor(tests): split models tests --- x/restaking/types/genesis_test.go | 174 ---------------------------- x/restaking/types/models_test.go | 183 ++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 174 deletions(-) create mode 100644 x/restaking/types/models_test.go diff --git a/x/restaking/types/genesis_test.go b/x/restaking/types/genesis_test.go index 20b8bac1d..ba2a600ce 100644 --- a/x/restaking/types/genesis_test.go +++ b/x/restaking/types/genesis_test.go @@ -121,177 +121,3 @@ func TestGenesis_Validate(t *testing.T) { }) } } - -// -------------------------------------------------------------------------------------------------------------------- - -func TestPoolDelegation_Validate(t *testing.T) { - testCases := []struct { - name string - entry types.PoolDelegation - shouldErr bool - }{ - { - name: "invalid pool id returns error", - entry: types.NewPoolDelegation( - 0, - "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(100), - ), - shouldErr: true, - }, - { - name: "invalid user address returns error", - entry: types.NewPoolDelegation( - 1, - "", - sdkmath.LegacyNewDec(100), - ), - shouldErr: true, - }, - { - name: "invalid shares returns error", - entry: types.NewPoolDelegation( - 1, - "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(-100), - ), - shouldErr: true, - }, - { - name: "valid entry returns no error", - entry: types.NewPoolDelegation( - 1, - "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdkmath.LegacyNewDec(100), - ), - shouldErr: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - err := tc.entry.Validate() - if tc.shouldErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - }) - } -} - -// -------------------------------------------------------------------------------------------------------------------- - -func TestServiceDelegation_Validate(t *testing.T) { - testCases := []struct { - name string - entry types.ServiceDelegation - shouldErr bool - }{ - { - name: "invalid service id returns error", - entry: types.NewServiceDelegation( - 0, - "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), - ), - shouldErr: true, - }, - { - name: "invalid user address returns error", - entry: types.NewServiceDelegation( - 1, - "", - sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), - ), - shouldErr: true, - }, - { - name: "invalid shares returns error", - entry: types.NewServiceDelegation( - 1, - "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.DecCoins{sdk.DecCoin{Denom: "umilk", Amount: sdkmath.LegacyNewDec(-100)}}, - ), - shouldErr: true, - }, - { - name: "valid entry returns no error", - entry: types.NewServiceDelegation( - 1, - "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), - ), - shouldErr: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - err := tc.entry.Validate() - if tc.shouldErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - }) - } -} - -// -------------------------------------------------------------------------------------------------------------------- - -func TestOperatorDelegation_Validate(t *testing.T) { - testCases := []struct { - name string - entry types.OperatorDelegation - shouldErr bool - }{ - { - name: "invalid operator id returns error", - entry: types.NewOperatorDelegation( - 0, - "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), - ), - shouldErr: true, - }, - { - name: "invalid user address returns error", - entry: types.NewOperatorDelegation( - 1, - "", - sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), - ), - shouldErr: true, - }, - { - name: "invalid shares returns error", - entry: types.NewOperatorDelegation( - 1, - "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.DecCoins{sdk.DecCoin{Denom: "umilk", Amount: sdkmath.LegacyNewDec(-100)}}, - ), - shouldErr: true, - }, - { - name: "valid entry returns no error", - entry: types.NewOperatorDelegation( - 1, - "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", - sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), - ), - shouldErr: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - err := tc.entry.Validate() - if tc.shouldErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - }) - } -} diff --git a/x/restaking/types/models_test.go b/x/restaking/types/models_test.go new file mode 100644 index 000000000..4e6823ba3 --- /dev/null +++ b/x/restaking/types/models_test.go @@ -0,0 +1,183 @@ +package types_test + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/milkyway-labs/milkyway/x/restaking/types" +) + +func TestPoolDelegation_Validate(t *testing.T) { + testCases := []struct { + name string + entry types.PoolDelegation + shouldErr bool + }{ + { + name: "invalid pool id returns error", + entry: types.NewPoolDelegation( + 0, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + ), + shouldErr: true, + }, + { + name: "invalid user address returns error", + entry: types.NewPoolDelegation( + 1, + "", + sdkmath.LegacyNewDec(100), + ), + shouldErr: true, + }, + { + name: "invalid shares returns error", + entry: types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(-100), + ), + shouldErr: true, + }, + { + name: "valid entry returns no error", + entry: types.NewPoolDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdkmath.LegacyNewDec(100), + ), + shouldErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.entry.Validate() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +func TestServiceDelegation_Validate(t *testing.T) { + testCases := []struct { + name string + entry types.ServiceDelegation + shouldErr bool + }{ + { + name: "invalid service id returns error", + entry: types.NewServiceDelegation( + 0, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), + shouldErr: true, + }, + { + name: "invalid user address returns error", + entry: types.NewServiceDelegation( + 1, + "", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), + shouldErr: true, + }, + { + name: "invalid shares returns error", + entry: types.NewServiceDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.DecCoins{sdk.DecCoin{Denom: "umilk", Amount: sdkmath.LegacyNewDec(-100)}}, + ), + shouldErr: true, + }, + { + name: "valid entry returns no error", + entry: types.NewServiceDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), + shouldErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.entry.Validate() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +func TestOperatorDelegation_Validate(t *testing.T) { + testCases := []struct { + name string + entry types.OperatorDelegation + shouldErr bool + }{ + { + name: "invalid operator id returns error", + entry: types.NewOperatorDelegation( + 0, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), + shouldErr: true, + }, + { + name: "invalid user address returns error", + entry: types.NewOperatorDelegation( + 1, + "", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), + shouldErr: true, + }, + { + name: "invalid shares returns error", + entry: types.NewOperatorDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.DecCoins{sdk.DecCoin{Denom: "umilk", Amount: sdkmath.LegacyNewDec(-100)}}, + ), + shouldErr: true, + }, + { + name: "valid entry returns no error", + entry: types.NewOperatorDelegation( + 1, + "cosmos13t6y2nnugtshwuy0zkrq287a95lyy8vzleaxmd", + sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ), + shouldErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.entry.Validate() + if tc.shouldErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} From 2eb1cc123da2d9d1a5b8703864f9d4b75654572f Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 2 Jul 2024 15:24:20 -0500 Subject: [PATCH 36/37] refactor: improve shares names --- x/operators/types/models.go | 15 +- x/pools/types/models.go | 5 + x/restaking/keeper/operator_restaking_test.go | 130 +++++++++++------- x/restaking/keeper/pool_restaking.go | 3 +- x/restaking/keeper/pool_restaking_test.go | 6 +- x/restaking/keeper/service_restaking_test.go | 126 ++++++++++------- x/services/types/models.go | 15 +- 7 files changed, 194 insertions(+), 106 deletions(-) diff --git a/x/operators/types/models.go b/x/operators/types/models.go index 9d387d2e2..93dce306f 100644 --- a/x/operators/types/models.go +++ b/x/operators/types/models.go @@ -73,6 +73,11 @@ func (o *Operator) Validate() error { return nil } +// GetSharesDenom returns the shares denom for an operator and token denom +func (o Operator) GetSharesDenom(tokenDenom string) string { + return fmt.Sprintf("operator/%d/%s", o.ID, tokenDenom) +} + // IsActive returns whether the operator is active. func (o Operator) IsActive() bool { return o.Status == OPERATOR_STATUS_ACTIVE @@ -97,7 +102,8 @@ func (o Operator) SharesFromTokens(tokens sdk.Coin) (sdkmath.LegacyDec, error) { return sdkmath.LegacyZeroDec(), ErrInsufficientShares } - delegatorTokenShares := o.DelegatorShares.AmountOf(tokens.Denom) + sharesDenom := o.GetSharesDenom(tokens.Denom) + delegatorTokenShares := o.DelegatorShares.AmountOf(sharesDenom) operatorTokenAmount := o.Tokens.AmountOf(tokens.Denom) return delegatorTokenShares.MulInt(tokens.Amount).QuoInt(operatorTokenAmount), nil @@ -111,17 +117,18 @@ func (o Operator) AddTokensFromDelegation(amount sdk.Coins) (Operator, sdk.DecCo issuedShares := sdk.NewDecCoins() for _, token := range amount { var tokenShares sdk.DecCoin - delegatorShares := o.DelegatorShares.AmountOf(token.Denom) + sharesDenom := o.GetSharesDenom(token.Denom) + delegatorShares := o.DelegatorShares.AmountOf(sharesDenom) if delegatorShares.IsZero() { // The first delegation to an operator sets the exchange rate to one - tokenShares = sdk.NewDecCoinFromCoin(token) + tokenShares = sdk.NewDecCoin(sharesDenom, token.Amount) } else { shares, err := o.SharesFromTokens(token) if err != nil { panic(err) } - tokenShares = sdk.NewDecCoinFromDec(token.Denom, shares) + tokenShares = sdk.NewDecCoinFromDec(sharesDenom, shares) } issuedShares = issuedShares.Add(tokenShares) diff --git a/x/pools/types/models.go b/x/pools/types/models.go index 037c19f0b..a8699e3e0 100644 --- a/x/pools/types/models.go +++ b/x/pools/types/models.go @@ -54,6 +54,11 @@ func (p Pool) Validate() error { return nil } +// GetSharesDenom returns the shares denom for a pool and token denom +func (p Pool) GetSharesDenom(tokenDenom string) string { + return fmt.Sprintf("pool/%d/%s", p.ID, tokenDenom) +} + // InvalidExRate returns whether the exchange rates is invalid. // This can happen e.g. if Pool loses all tokens due to slashing. In this case, // make all future delegations invalid. diff --git a/x/restaking/keeper/operator_restaking_test.go b/x/restaking/keeper/operator_restaking_test.go index a122865d5..e05428230 100644 --- a/x/restaking/keeper/operator_restaking_test.go +++ b/x/restaking/keeper/operator_restaking_test.go @@ -150,30 +150,46 @@ func (suite *KeeperTestSuite) TestKeeper_AddOperatorTokensAndShares() { tokensToAdd: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), shouldErr: false, expOperator: operatorstypes.Operator{ - ID: 1, - Address: operatorstypes.GetOperatorAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(100)), + ), }, - expAddedShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + expAddedShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(100)), + ), }, { name: "adding tokens to a non-empty operator works properly", operator: operatorstypes.Operator{ - ID: 1, - Address: operatorstypes.GetOperatorAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(50))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(50)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(100)), + ), }, tokensToAdd: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), shouldErr: false, expOperator: operatorstypes.Operator{ - ID: 1, - Address: operatorstypes.GetOperatorAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(70))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(140))), + ID: 1, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(70)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(140)), + ), }, - expAddedShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(40))), + expAddedShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(40)), + ), }, } @@ -299,11 +315,15 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { store: func(ctx sdk.Context) { // Create the operator suite.ok.SaveOperator(ctx, operatorstypes.Operator{ - ID: 1, - Status: operatorstypes.OPERATOR_STATUS_ACTIVE, - Address: operatorstypes.GetOperatorAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(20)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(100)), + ), }) // Set the correct operator tokens amount @@ -327,17 +347,23 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, - expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(500))), + expShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(500)), + ), check: func(ctx sdk.Context) { // Make sure the operator now exists operator, found := suite.ok.GetOperator(ctx, 1) suite.Require().True(found) suite.Require().Equal(operatorstypes.Operator{ - ID: 1, - Status: operatorstypes.OPERATOR_STATUS_ACTIVE, - Address: operatorstypes.GetOperatorAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(120))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(600))), + ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(120)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(600)), + ), }, operator) // Make sure the delegation exists @@ -346,7 +372,9 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { suite.Require().Equal(types.NewOperatorDelegation( 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", - sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(500))), + sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(500)), + ), ), delegation) // Make sure the user balance has been reduced properly @@ -363,11 +391,15 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { store: func(ctx sdk.Context) { // Create the operator suite.ok.SaveOperator(ctx, operatorstypes.Operator{ - ID: 1, - Status: operatorstypes.OPERATOR_STATUS_ACTIVE, - Address: operatorstypes.GetOperatorAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(80))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125))), + ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(80)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(125)), + ), }) // Set the correct operator tokens amount @@ -384,7 +416,9 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { suite.k.SaveOperatorDelegation(ctx, types.NewOperatorDelegation( 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", - sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125))), + sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(125)), + ), )) // Send some funds to the user @@ -398,7 +432,9 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { amount: sdk.NewCoins(sdk.NewCoin("uinit", sdkmath.NewInt(100))), delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, - expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100))), + expShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/uinit", sdkmath.LegacyNewDec(100)), + ), check: func(ctx sdk.Context) { // Make sure the operator now exists operator, found := suite.ok.GetOperator(ctx, 1) @@ -412,8 +448,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { sdk.NewCoin("uinit", sdkmath.NewInt(100)), ), DelegatorShares: sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100)), + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("operator/1/uinit", sdkmath.LegacyNewDec(100)), ), }, operator) @@ -424,8 +460,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100)), + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("operator/1/uinit", sdkmath.LegacyNewDec(100)), ), ), delegation) @@ -454,8 +490,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { sdk.NewCoin("uinit", sdkmath.NewInt(75)), ), DelegatorShares: sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(200)), + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("operator/1/uinit", sdkmath.LegacyNewDec(200)), ), }) @@ -477,8 +513,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(60)), + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(100)), + sdk.NewDecCoinFromDec("operator/1/uinit", sdkmath.LegacyNewDec(60)), ), )) @@ -500,8 +536,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, expShares: sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(15625, 2)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(600)), + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDecWithPrec(15625, 2)), + sdk.NewDecCoinFromDec("operator/1/uinit", sdkmath.LegacyNewDec(600)), ), check: func(ctx sdk.Context) { // Make sure the operator now exists @@ -516,8 +552,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { sdk.NewCoin("uinit", sdkmath.NewInt(300)), ), DelegatorShares: sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(28125, 2)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(800)), + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDecWithPrec(28125, 2)), + sdk.NewDecCoinFromDec("operator/1/uinit", sdkmath.LegacyNewDec(800)), ), }, operator) @@ -528,8 +564,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToOperator() { 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(25625, 2)), // 100 (existing) + 156.25 (new) - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(660)), // 60 (existing) + 600 (new) + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDecWithPrec(25625, 2)), // 100 (existing) + 156.25 (new) + sdk.NewDecCoinFromDec("operator/1/uinit", sdkmath.LegacyNewDec(660)), // 60 (existing) + 600 (new) ), ), delegation) diff --git a/x/restaking/keeper/pool_restaking.go b/x/restaking/keeper/pool_restaking.go index 1f243833d..5396dd458 100644 --- a/x/restaking/keeper/pool_restaking.go +++ b/x/restaking/keeper/pool_restaking.go @@ -87,7 +87,8 @@ func (k *Keeper) DelegateToPool(ctx sdk.Context, amount sdk.Coin, delegator stri // Store the updated delegation k.SavePoolDelegation(ctx, poolDelegation) - return sdk.NewDecCoins(sdk.NewDecCoinFromDec(amount.Denom, newShares)), err + sharesDenom := pool.GetSharesDenom(amount.Denom) + return sdk.NewDecCoins(sdk.NewDecCoinFromDec(sharesDenom, newShares)), err }, Hooks: types.DelegationHooks{ BeforeDelegationSharesModified: k.BeforePoolDelegationSharesModified, diff --git a/x/restaking/keeper/pool_restaking_test.go b/x/restaking/keeper/pool_restaking_test.go index cd1b4ffae..15eb817d5 100644 --- a/x/restaking/keeper/pool_restaking_test.go +++ b/x/restaking/keeper/pool_restaking_test.go @@ -280,7 +280,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToPool() { amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, - expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("pool/1/umilk", sdkmath.LegacyNewDec(100))), check: func(ctx sdk.Context) { // Make sure the pool now exists pool, found := suite.pk.GetPool(ctx, 1) @@ -344,7 +344,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToPool() { amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, - expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(500))), + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("pool/1/umilk", sdkmath.LegacyNewDec(500))), check: func(ctx sdk.Context) { // Make sure the pool now exists pool, found := suite.pk.GetPool(ctx, 1) @@ -415,7 +415,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToPool() { amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, - expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(15625, 2))), + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("pool/1/umilk", sdkmath.LegacyNewDecWithPrec(15625, 2))), check: func(ctx sdk.Context) { // Make sure the pool now exists pool, found := suite.pk.GetPool(ctx, 1) diff --git a/x/restaking/keeper/service_restaking_test.go b/x/restaking/keeper/service_restaking_test.go index f39d50e22..f2c02e7c2 100644 --- a/x/restaking/keeper/service_restaking_test.go +++ b/x/restaking/keeper/service_restaking_test.go @@ -150,30 +150,46 @@ func (suite *KeeperTestSuite) TestKeeper_AddServiceTokensAndShares() { tokensToAdd: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), shouldErr: false, expService: servicestypes.Service{ - ID: 1, - Address: servicestypes.GetServiceAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ID: 1, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(100)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(100)), + ), }, - expAddedShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + expAddedShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(100)), + ), }, { name: "adding tokens to a non-empty service works properly", service: servicestypes.Service{ - ID: 1, - Address: servicestypes.GetServiceAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(50))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ID: 1, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(50)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(100)), + ), }, tokensToAdd: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), shouldErr: false, expService: servicestypes.Service{ - ID: 1, - Address: servicestypes.GetServiceAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(70))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(140))), + ID: 1, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(70)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(140)), + ), }, - expAddedShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(40))), + expAddedShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(40)), + ), }, } @@ -299,11 +315,15 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { store: func(ctx sdk.Context) { // Create the service suite.sk.SaveService(ctx, servicestypes.Service{ - ID: 1, - Status: servicestypes.SERVICE_STATUS_ACTIVE, - Address: servicestypes.GetServiceAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(20))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100))), + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(20)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(100)), + ), }) // Set the correct service tokens amount @@ -327,17 +347,21 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, - expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(500))), + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(500))), check: func(ctx sdk.Context) { // Make sure the service now exists service, found := suite.sk.GetService(ctx, 1) suite.Require().True(found) suite.Require().Equal(servicestypes.Service{ - ID: 1, - Status: servicestypes.SERVICE_STATUS_ACTIVE, - Address: servicestypes.GetServiceAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(120))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(600))), + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(120)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(600)), + ), }, service) // Make sure the delegation exists @@ -346,7 +370,9 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { suite.Require().Equal(types.NewServiceDelegation( 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", - sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(500))), + sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(500)), + ), ), delegation) // Make sure the user balance has been reduced properly @@ -363,11 +389,15 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { store: func(ctx sdk.Context) { // Create the service suite.sk.SaveService(ctx, servicestypes.Service{ - ID: 1, - Status: servicestypes.SERVICE_STATUS_ACTIVE, - Address: servicestypes.GetServiceAddress(1).String(), - Tokens: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(80))), - DelegatorShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125))), + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(80)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(125)), + ), }) // Set the correct service tokens amount @@ -384,7 +414,9 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { suite.k.SaveServiceDelegation(ctx, types.NewServiceDelegation( 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", - sdk.NewDecCoins(sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125))), + sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(125)), + ), )) // Send some funds to the user @@ -398,7 +430,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { amount: sdk.NewCoins(sdk.NewCoin("uinit", sdkmath.NewInt(100))), delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, - expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100))), + expShares: sdk.NewDecCoins(sdk.NewDecCoinFromDec("service/1/uinit", sdkmath.LegacyNewDec(100))), check: func(ctx sdk.Context) { // Make sure the service now exists service, found := suite.sk.GetService(ctx, 1) @@ -412,8 +444,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { sdk.NewCoin("uinit", sdkmath.NewInt(100)), ), DelegatorShares: sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100)), + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("service/1/uinit", sdkmath.LegacyNewDec(100)), ), }, service) @@ -424,8 +456,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(100)), + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("service/1/uinit", sdkmath.LegacyNewDec(100)), ), ), delegation) @@ -454,8 +486,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { sdk.NewCoin("uinit", sdkmath.NewInt(75)), ), DelegatorShares: sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(125)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(200)), + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(125)), + sdk.NewDecCoinFromDec("service/1/uinit", sdkmath.LegacyNewDec(200)), ), }) @@ -477,8 +509,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDec(100)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(60)), + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(100)), + sdk.NewDecCoinFromDec("service/1/uinit", sdkmath.LegacyNewDec(60)), ), )) @@ -500,8 +532,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", shouldErr: false, expShares: sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(15625, 2)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(600)), + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDecWithPrec(15625, 2)), + sdk.NewDecCoinFromDec("service/1/uinit", sdkmath.LegacyNewDec(600)), ), check: func(ctx sdk.Context) { // Make sure the service now exists @@ -516,8 +548,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { sdk.NewCoin("uinit", sdkmath.NewInt(300)), ), DelegatorShares: sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(28125, 2)), - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(800)), + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDecWithPrec(28125, 2)), + sdk.NewDecCoinFromDec("service/1/uinit", sdkmath.LegacyNewDec(800)), ), }, service) @@ -528,8 +560,8 @@ func (suite *KeeperTestSuite) TestKeeper_DelegateToService() { 1, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", sdk.NewDecCoins( - sdk.NewDecCoinFromDec("umilk", sdkmath.LegacyNewDecWithPrec(25625, 2)), // 100 (existing) + 156.25 (new) - sdk.NewDecCoinFromDec("uinit", sdkmath.LegacyNewDec(660)), // 60 (existing) + 600 (new) + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDecWithPrec(25625, 2)), // 100 (existing) + 156.25 (new) + sdk.NewDecCoinFromDec("service/1/uinit", sdkmath.LegacyNewDec(660)), // 60 (existing) + 600 (new) ), ), delegation) diff --git a/x/services/types/models.go b/x/services/types/models.go index 116c5c3b2..59d5ef7d8 100644 --- a/x/services/types/models.go +++ b/x/services/types/models.go @@ -75,6 +75,11 @@ func (s Service) Validate() error { return nil } +// GetSharesDenom returns the shares denom for a service and token denom +func (s Service) GetSharesDenom(tokenDenom string) string { + return fmt.Sprintf("service/%d/%s", s.ID, tokenDenom) +} + // IsActive returns whether the service is active. func (s Service) IsActive() bool { return s.Status == SERVICE_STATUS_ACTIVE @@ -99,7 +104,8 @@ func (s Service) SharesFromTokens(tokens sdk.Coin) (sdkmath.LegacyDec, error) { return sdkmath.LegacyZeroDec(), ErrInsufficientShares } - delegatorTokenShares := s.DelegatorShares.AmountOf(tokens.Denom) + sharesDenom := s.GetSharesDenom(tokens.Denom) + delegatorTokenShares := s.DelegatorShares.AmountOf(sharesDenom) operatorTokenAmount := s.Tokens.AmountOf(tokens.Denom) return delegatorTokenShares.MulInt(tokens.Amount).QuoInt(operatorTokenAmount), nil @@ -113,17 +119,18 @@ func (s Service) AddTokensFromDelegation(amount sdk.Coins) (Service, sdk.DecCoin issuedShares := sdk.NewDecCoins() for _, token := range amount { var tokenShares sdk.DecCoin - delegatorShares := s.DelegatorShares.AmountOf(token.Denom) + sharesDenom := s.GetSharesDenom(token.Denom) + delegatorShares := s.DelegatorShares.AmountOf(sharesDenom) if delegatorShares.IsZero() { // The first delegation to an operator sets the exchange rate to one - tokenShares = sdk.NewDecCoinFromCoin(token) + tokenShares = sdk.NewDecCoin(sharesDenom, token.Amount) } else { shares, err := s.SharesFromTokens(token) if err != nil { panic(err) } - tokenShares = sdk.NewDecCoinFromDec(token.Denom, shares) + tokenShares = sdk.NewDecCoinFromDec(sharesDenom, shares) } issuedShares = issuedShares.Add(tokenShares) From edc3df9894dfd56bc84b84ddd7c7f89cc7f8a1b6 Mon Sep 17 00:00:00 2001 From: Riccardo Montagnin Date: Tue, 2 Jul 2024 15:33:28 -0500 Subject: [PATCH 37/37] feat(tests): add msg server tests --- x/restaking/keeper/msg_server.go | 2 +- x/restaking/keeper/msg_server_test.go | 412 ++++++++++++++++++++++++++ 2 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 x/restaking/keeper/msg_server_test.go diff --git a/x/restaking/keeper/msg_server.go b/x/restaking/keeper/msg_server.go index c241bbc09..790061188 100644 --- a/x/restaking/keeper/msg_server.go +++ b/x/restaking/keeper/msg_server.go @@ -22,7 +22,7 @@ type msgServer struct { *Keeper } -func NewMsgServerImpl(keeper *Keeper) types.MsgServer { +func NewMsgServer(keeper *Keeper) types.MsgServer { return &msgServer{Keeper: keeper} } diff --git a/x/restaking/keeper/msg_server_test.go b/x/restaking/keeper/msg_server_test.go new file mode 100644 index 000000000..059d971b7 --- /dev/null +++ b/x/restaking/keeper/msg_server_test.go @@ -0,0 +1,412 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + operatorstypes "github.com/milkyway-labs/milkyway/x/operators/types" + poolstypes "github.com/milkyway-labs/milkyway/x/pools/types" + "github.com/milkyway-labs/milkyway/x/restaking/keeper" + "github.com/milkyway-labs/milkyway/x/restaking/types" + servicestypes "github.com/milkyway-labs/milkyway/x/services/types" +) + +func (suite *KeeperTestSuite) TestMsgServer_DelegatePool() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + setupCtx func(ctx sdk.Context) sdk.Context + msg *types.MsgDelegatePool + shouldErr bool + expEvents sdk.Events + check func(ctx sdk.Context) + }{ + { + name: "invalid amount returns error", + store: func(ctx sdk.Context) { + // Create the pool + err := suite.pk.SavePool(ctx, poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.NewInt(20), + DelegatorShares: sdkmath.LegacyNewDec(100), + }) + suite.Require().NoError(err) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + msg: &types.MsgDelegatePool{ + Delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + Amount: sdk.NewCoin("umilk", sdkmath.NewInt(0)), + }, + shouldErr: true, + }, + { + name: "valid amount is delegated properly", + store: func(ctx sdk.Context) { + // Create the pool + err := suite.pk.SavePool(ctx, poolstypes.Pool{ + ID: 1, + Denom: "umilk", + Address: poolstypes.GetPoolAddress(1).String(), + Tokens: sdkmath.NewInt(20), + DelegatorShares: sdkmath.LegacyNewDec(100), + }) + suite.Require().NoError(err) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + msg: &types.MsgDelegatePool{ + Delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + Amount: sdk.NewCoin("umilk", sdkmath.NewInt(100)), + }, + shouldErr: false, + expEvents: sdk.Events{ + sdk.NewEvent( + types.EventTypeDelegatePool, + sdk.NewAttribute(types.AttributeKeyDelegator, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), + sdk.NewAttribute(sdk.AttributeKeyAmount, "100umilk"), + sdk.NewAttribute(types.AttributeKeyNewShares, "500.000000000000000000pool/1/umilk"), + ), + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.setupCtx != nil { + ctx = tc.setupCtx(ctx) + } + if tc.store != nil { + tc.store(ctx) + } + + msgServer := keeper.NewMsgServer(suite.k) + _, err := msgServer.DelegatePool(ctx, tc.msg) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + for _, event := range tc.expEvents { + suite.Require().Contains(ctx.EventManager().Events(), event) + } + + if tc.check != nil { + tc.check(ctx) + } + } + }) + } +} + +func (suite *KeeperTestSuite) TestMsgServer_DelegateOperator() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + setupCtx func(ctx sdk.Context) sdk.Context + msg *types.MsgDelegateOperator + shouldErr bool + expEvents sdk.Events + check func(ctx sdk.Context) + }{ + { + name: "invalid amount returns error", + store: func(ctx sdk.Context) { + // Create the operator + suite.ok.SaveOperator(ctx, operatorstypes.Operator{ + ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(20)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(100)), + ), + }) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + msg: &types.MsgDelegateOperator{ + OperatorID: 1, + Delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + Amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(0))), + }, + shouldErr: true, + }, + { + name: "valid amount is delegated properly", + store: func(ctx sdk.Context) { + // Create the operator + suite.ok.SaveOperator(ctx, operatorstypes.Operator{ + ID: 1, + Status: operatorstypes.OPERATOR_STATUS_ACTIVE, + Address: operatorstypes.GetOperatorAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(20)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("operator/1/umilk", sdkmath.LegacyNewDec(100)), + ), + }) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + msg: &types.MsgDelegateOperator{ + OperatorID: 1, + Delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + Amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + }, + shouldErr: false, + expEvents: sdk.Events{ + sdk.NewEvent( + types.EventTypeDelegateOperator, + sdk.NewAttribute(types.AttributeKeyDelegator, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), + sdk.NewAttribute(types.AttributeKeyOperatorID, "1"), + sdk.NewAttribute(sdk.AttributeKeyAmount, "100umilk"), + sdk.NewAttribute(types.AttributeKeyNewShares, "500.000000000000000000operator/1/umilk"), + ), + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.setupCtx != nil { + ctx = tc.setupCtx(ctx) + } + if tc.store != nil { + tc.store(ctx) + } + + msgServer := keeper.NewMsgServer(suite.k) + _, err := msgServer.DelegateOperator(ctx, tc.msg) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + for _, event := range tc.expEvents { + suite.Require().Contains(ctx.EventManager().Events(), event) + } + + if tc.check != nil { + tc.check(ctx) + } + } + }) + } +} + +func (suite *KeeperTestSuite) TestMsgServer_DelegateService() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + setupCtx func(ctx sdk.Context) sdk.Context + msg *types.MsgDelegateService + shouldErr bool + expEvents sdk.Events + check func(ctx sdk.Context) + }{ + { + name: "invalid amount returns error", + store: func(ctx sdk.Context) { + // Create the service + suite.sk.SaveService(ctx, servicestypes.Service{ + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(20)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(100)), + ), + }) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + msg: &types.MsgDelegateService{ + ServiceID: 1, + Delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + Amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(0))), + }, + shouldErr: true, + }, + { + name: "valid amount is delegated properly", + store: func(ctx sdk.Context) { + // Create the service + suite.sk.SaveService(ctx, servicestypes.Service{ + ID: 1, + Status: servicestypes.SERVICE_STATUS_ACTIVE, + Address: servicestypes.GetServiceAddress(1).String(), + Tokens: sdk.NewCoins( + sdk.NewCoin("umilk", sdkmath.NewInt(20)), + ), + DelegatorShares: sdk.NewDecCoins( + sdk.NewDecCoinFromDec("service/1/umilk", sdkmath.LegacyNewDec(100)), + ), + }) + + // Send some funds to the user + suite.fundAccount( + ctx, + "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + ) + }, + msg: &types.MsgDelegateService{ + ServiceID: 1, + Delegator: "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4", + Amount: sdk.NewCoins(sdk.NewCoin("umilk", sdkmath.NewInt(100))), + }, + shouldErr: false, + expEvents: sdk.Events{ + sdk.NewEvent( + types.EventTypeDelegateService, + sdk.NewAttribute(types.AttributeKeyDelegator, "cosmos167x6ehhple8gwz5ezy9x0464jltvdpzl6qfdt4"), + sdk.NewAttribute(types.AttributeKeyServiceID, "1"), + sdk.NewAttribute(sdk.AttributeKeyAmount, "100umilk"), + sdk.NewAttribute(types.AttributeKeyNewShares, "500.000000000000000000service/1/umilk"), + ), + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.setupCtx != nil { + ctx = tc.setupCtx(ctx) + } + if tc.store != nil { + tc.store(ctx) + } + + msgServer := keeper.NewMsgServer(suite.k) + _, err := msgServer.DelegateService(ctx, tc.msg) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + for _, event := range tc.expEvents { + suite.Require().Contains(ctx.EventManager().Events(), event) + } + + if tc.check != nil { + tc.check(ctx) + } + } + }) + } +} + +func (suite *KeeperTestSuite) TestMsgServer_UpdateParams() { + testCases := []struct { + name string + setup func() + store func(ctx sdk.Context) + setupCtx func(ctx sdk.Context) sdk.Context + msg *types.MsgUpdateParams + shouldErr bool + expEvents sdk.Events + check func(ctx sdk.Context) + }{ + { + name: "invalid authority return error", + msg: types.NewMsgUpdateParams( + types.DefaultParams(), + "invalid", + ), + shouldErr: true, + }, + { + name: "valid data returns no error", + msg: types.NewMsgUpdateParams( + types.DefaultParams(), + authtypes.NewModuleAddress("gov").String(), + ), + shouldErr: false, + expEvents: sdk.Events{}, + check: func(ctx sdk.Context) { + params := suite.k.GetParams(ctx) + suite.Require().Equal(types.DefaultParams(), params) + }, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + if tc.setupCtx != nil { + ctx = tc.setupCtx(ctx) + } + if tc.store != nil { + tc.store(ctx) + } + + msgServer := keeper.NewMsgServer(suite.k) + _, err := msgServer.UpdateParams(ctx, tc.msg) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + for _, event := range tc.expEvents { + suite.Require().Contains(ctx.EventManager().Events(), event) + } + + if tc.check != nil { + tc.check(ctx) + } + } + }) + } +}