Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add pool/operator/service params #61

Merged
merged 2 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions proto/milkyway/pools/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ package milkyway.pools.v1;
import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";
import "milkyway/pools/v1/models.proto";
import "milkyway/pools/v1/params.proto";

option go_package = "github.com/milkyway-labs/milkyway/x/pools/types";

// GenesisState defines the pools module's genesis state.
message GenesisState {
// Params defines the parameters of the module.
Params params = 1 [ (gogoproto.nullable) = false ];

// NextPoolID represents the id to be used when creating the next pool.
uint32 next_pool_id = 1 [
uint32 next_pool_id = 2 [
(gogoproto.customname) = "NextPoolID",
(gogoproto.moretags) = "yaml:\"next_pool_id\""
];

// Operators defines the list of pools.
repeated Pool pools = 2
repeated Pool pools = 3
[ (gogoproto.moretags) = "yaml:\"pools\"", (gogoproto.nullable) = false ];
}
16 changes: 16 additions & 0 deletions proto/milkyway/pools/v1/params.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
syntax = "proto3";
package milkyway.pools.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/pools/types";

// Params defines the parameters for the pools module.
message Params {
// AllowedServiceIDs defines the list of service IDs that the module allows
// to join by pools.
repeated uint32 allowed_service_ids = 1
[ (gogoproto.customname) = "AllowedServiceIDs" ];
}
20 changes: 19 additions & 1 deletion proto/milkyway/restaking/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,29 @@ import "milkyway/restaking/v1/params.proto";

option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types";

message OperatorParamsRecord {
uint32 operator_id = 1 [ (gogoproto.customname) = "OperatorID" ];

OperatorParams params = 2 [ (gogoproto.nullable) = false ];
}

message ServiceParamsRecord {
uint32 service_id = 1 [ (gogoproto.customname) = "ServiceID" ];

ServiceParams params = 2 [ (gogoproto.nullable) = false ];
}

// GenesisState defines the restaking module's genesis state.
message GenesisState {
// Params defines the parameters of the module.
Params params = 1 [ (gogoproto.nullable) = false ];

repeated OperatorParamsRecord operator_params = 2
[ (gogoproto.nullable) = false ];

repeated ServiceParamsRecord service_params = 3
[ (gogoproto.nullable) = false ];

// Delegations represents the delegations.
repeated Delegation delegations = 2 [ (gogoproto.nullable) = false ];
repeated Delegation delegations = 4 [ (gogoproto.nullable) = false ];
}
34 changes: 34 additions & 0 deletions proto/milkyway/restaking/v1/messages.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,22 @@ import "cosmos/bank/v1beta1/bank.proto";
import "cosmos/msg/v1/msg.proto";
import "gogoproto/gogo.proto";
import "milkyway/restaking/v1/params.proto";
import "milkyway/restaking/v1/models.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;

// UpdateOperatorParams defines the operation for joining a service as an
// operator.
rpc UpdateOperatorParams(MsgUpdateOperatorParams)
returns (MsgUpdateOperatorParamsResponse);

rpc UpdateServiceParams(MsgUpdateServiceParams)
returns (MsgUpdateServiceParamsResponse);

// 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.
Expand All @@ -35,6 +44,31 @@ service Msg {
rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse);
}

// MsgUpdateOperatorParams defines the message structure for the
// UpdateOperatorParams gRPC service method. It allows the operator admin to
// update the operator's parameters.
message MsgUpdateOperatorParams {
string sender = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];

uint32 operator_id = 2 [ (gogoproto.customname) = "OperatorID" ];

OperatorParams operator_params = 3 [ (gogoproto.nullable) = false ];
}

// MsgUpdateOperatorParamsResponse is the return value of
// MsgUpdateOperatorParams.
message MsgUpdateOperatorParamsResponse {}

message MsgUpdateServiceParams {
string sender = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];

uint32 service_id = 2 [ (gogoproto.customname) = "ServiceID" ];

ServiceParams service_params = 3 [ (gogoproto.nullable) = false ];
}

message MsgUpdateServiceParamsResponse {}

// 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
Expand Down
25 changes: 25 additions & 0 deletions proto/milkyway/restaking/v1/models.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,31 @@ import "cosmos/base/v1beta1/coin.proto";

option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types";

message OperatorParams {
// CommissionRate defines the commission rate charged to delegators, as a
// fraction.
string commission_rate = 1 [
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];

repeated uint32 joined_service_ids = 2
[ (gogoproto.customname) = "JoinedServiceIDs" ];
}

message ServiceParams {
string slash_fraction = 1 [
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];

repeated uint32 whitelisted_pool_ids = 2
[ (gogoproto.customname) = "WhitelistedPoolIDs" ];

repeated uint32 whitelisted_operator_ids = 3
[ (gogoproto.customname) = "WhitelistedOperatorIDs" ];
}

// DelegationType defines the type of delegation.
enum DelegationType {
option (gogoproto.goproto_enum_prefix) = false;
Expand Down
39 changes: 39 additions & 0 deletions proto/milkyway/restaking/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ option go_package = "github.com/milkyway-labs/milkyway/x/restaking/types";

// Query defines the gRPC querier service.
service Query {
rpc OperatorParams(QueryOperatorParamsRequest)
returns (QueryOperatorParamsResponse) {
option (cosmos.query.v1.module_query_safe) = true;
option (google.api.http).get =
"/milkyway/restaking/v1/operator_params/{operator_id}";
}

rpc ServiceParams(QueryServiceParamsRequest)
returns (QueryServiceParamsResponse) {
option (cosmos.query.v1.module_query_safe) = true;
option (google.api.http).get =
"/milkyway/restaking/v1/service_params/{service_id}";
}

// PoolDelegations queries the delegations info for the given pool.
rpc PoolDelegations(QueryPoolDelegationsRequest)
Expand Down Expand Up @@ -157,6 +170,32 @@ service Query {
}
}

// QueryOperatorParamsRequest is request type for the Query/OperatorParams
// RPC method.
message QueryOperatorParamsRequest {
// OperatorId is the ID of the operator to query
uint32 operator_id = 1;
}

// QueryOperatorParamsResponse is response type for the Query/OperatorParams
// RPC method.
message QueryOperatorParamsResponse {
OperatorParams operator_params = 1 [ (gogoproto.nullable) = false ];
}

// QueryServiceParamsRequest is request type for the Query/ServiceParams
// RPC method.
message QueryServiceParamsRequest {
// ServiceId is the ID of the service to query
uint32 service_id = 1;
}

// QueryServiceParamsResponse is response type for the Query/ServiceParams
// RPC method.
message QueryServiceParamsResponse {
ServiceParams service_params = 1 [ (gogoproto.nullable) = false ];
}

// QueryPoolDelegationsRequest is request type for the Query/PoolDelegations RPC
// method.
message QueryPoolDelegationsRequest {
Expand Down
26 changes: 26 additions & 0 deletions utils/key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package utils

import (
"bytes"
"encoding/binary"
)

func CompositeKey(parts ...[]byte) []byte {
return bytes.Join(parts, nil)
}

// Uint32ToBigEndian marshals uint32 to a bigendian byte slice so it can be sorted
func Uint32ToBigEndian(i uint32) []byte {
b := make([]byte, 4)
binary.BigEndian.PutUint32(b, i)
return b
}

// BigEndianToUint32 returns an uint32 from big endian encoded bytes. If encoding
// is empty, zero is returned.
func BigEndianToUint32(bz []byte) uint32 {
if len(bz) == 0 {
return 0
}
return binary.BigEndian.Uint32(bz)
}
10 changes: 9 additions & 1 deletion utils/slices.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@ package utils

// FindDuplicate returns the first duplicate element in the slice.
// If no duplicates are found, it returns nil instead.
func FindDuplicate[T any](slice []T, compare func(a T, b T) bool) *T {
func FindDuplicate[T comparable](slice []T) *T {
return FindDuplicateFunc(slice, func(a, b T) bool {
return a == b
})
}

// FindDuplicateFunc returns the first duplicate element in the slice.
// If no duplicates are found, it returns nil instead.
func FindDuplicateFunc[T any](slice []T, compare func(a T, b T) bool) *T {
for i, a := range slice {
for j, b := range slice {
if i != j && compare(a, b) {
Expand Down
21 changes: 21 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,24 @@ func VerifyTxHash(txHash string) (err error) {
}
return nil
}

func ParseUint32Slice(s string) ([]uint32, error) {
ss := strings.Split(s, ",")
out := make([]uint32, len(ss))
for i, d := range ss {
u, err := strconv.ParseUint(d, 10, 32)
if err != nil {
return nil, err
}
out[i] = uint32(u)
}
return out, nil
}

func FormatUint32Slice(s []uint32) string {
ss := make([]string, len(s))
for i, u := range s {
ss[i] = fmt.Sprint(u)
}
return strings.Join(ss, ",")
}
4 changes: 2 additions & 2 deletions x/operators/types/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ func (data *GenesisState) Validate() error {
// findDuplicateOperators returns the first duplicated operator in the slice.
// If no duplicates are found, it returns nil instead.
func findDuplicateOperators(operators []Operator) *Operator {
return utils.FindDuplicate(operators, func(a, b Operator) bool {
return utils.FindDuplicateFunc(operators, func(a, b Operator) bool {
return a.ID == b.ID
})
}

// findDuplicateUnbondingOperators returns the first duplicated unbonding operator in the slice.
// If no duplicates are found, it returns nil instead.
func findDuplicateUnbondingOperators(operators []UnbondingOperator) *UnbondingOperator {
return utils.FindDuplicate(operators, func(a, b UnbondingOperator) bool {
return utils.FindDuplicateFunc(operators, func(a, b UnbondingOperator) bool {
return a.OperatorID == b.OperatorID
})
}
Expand Down
2 changes: 1 addition & 1 deletion x/operators/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func GetOperatorIDFromBytes(bz []byte) (operatorID uint32) {
return binary.BigEndian.Uint32(bz)
}

// OperatorStoreKey turns a operator ID into a key used to store a operator in the KVStore
// OperatorStoreKey returns a operator ID into a key used to store a operator in the KVStore
func OperatorStoreKey(operatorID uint32) []byte {
return append(OperatorPrefix, GetOperatorIDBytes(operatorID)...)
}
Expand Down
3 changes: 3 additions & 0 deletions x/pools/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
// ExportGenesis returns a new GenesisState instance containing the information currently present inside the store
func (k *Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
return types.NewGenesis(
k.GetParams(ctx),
k.exportNextPoolID(ctx),
k.GetPools(ctx),
)
Expand All @@ -27,6 +28,8 @@ func (k *Keeper) exportNextPoolID(ctx sdk.Context) uint32 {

// InitGenesis initializes the genesis store using the provided data
func (k *Keeper) InitGenesis(ctx sdk.Context, data *types.GenesisState) {
k.SetParams(ctx, data.Params)

// Set the next pool id
k.SetNextPoolID(ctx, data.NextPoolID)

Expand Down
1 change: 1 addition & 0 deletions x/pools/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ func (suite *KeeperTestSuite) TestKeeper_InitGenesis() {
{
name: "genesis with pools is initialized properly",
genesis: types.NewGenesis(
types.DefaultParams(),
10,
[]types.Pool{
types.NewPool(1, "umilk"),
Expand Down
25 changes: 25 additions & 0 deletions x/pools/keeper/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/milkyway-labs/milkyway/x/pools/types"
)

// SetParams sets module parameters
func (k *Keeper) SetParams(ctx sdk.Context, params types.Params) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&params)
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
}
12 changes: 9 additions & 3 deletions x/pools/types/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,34 @@ import (
)

// NewGenesis creates a new GenesisState instance
func NewGenesis(nextPoolID uint32, pools []Pool) *GenesisState {
func NewGenesis(params Params, nextPoolID uint32, pools []Pool) *GenesisState {
return &GenesisState{
Params: params,
NextPoolID: nextPoolID,
Pools: pools,
}
}

// DefaultGenesis returns the default GenesisState
func DefaultGenesis() *GenesisState {
return NewGenesis(1, nil)
return NewGenesis(DefaultParams(), 1, nil)
}

// Validate checks if the GenesisState is valid
func (data *GenesisState) Validate() error {
err := data.Params.Validate()
if err != nil {
return fmt.Errorf("invalid params: %w", err)
}

// Validate the next pool ID
if data.NextPoolID == 0 {
return fmt.Errorf("invalid next pool id")
}

// Validate the pools
for _, pool := range data.Pools {
err := pool.Validate()
err = pool.Validate()
if err != nil {
return fmt.Errorf("invalid pool with id %d: %w", pool.ID, err)
}
Expand Down
Loading
Loading