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: pools module #8

Merged
merged 49 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
8ad68bc
feat: add address to service
RiccardoM Jun 13, 2024
b10d87d
chore: run code linting
RiccardoM Jun 3, 2024
0eb02da
feat: add Proto files
RiccardoM Jun 3, 2024
54a8e90
chore: generate Proto implementations
RiccardoM Jun 3, 2024
3d7ccc6
chore: rename tx.proto to messages.proto
RiccardoM Jun 3, 2024
33595a6
refactor: add missing fields from Proto definitions
RiccardoM Jun 3, 2024
eaae8bd
feat: add message and genesis implementations
RiccardoM Jun 3, 2024
501e055
feat: add queries
RiccardoM Jun 3, 2024
af9a8b8
refactor: use uint32 for AVS IDs instead of uint64
RiccardoM Jun 3, 2024
08ec13e
feat: add AVS-related keys
RiccardoM Jun 3, 2024
5020c32
fix: query Proto definition
RiccardoM Jun 3, 2024
9d7f08a
feat: add AVS hooks
RiccardoM Jun 3, 2024
ff995df
feat(tests): add tests for genesis, models and params
RiccardoM Jun 3, 2024
50fc5ac
feat: add keeper
RiccardoM Jun 3, 2024
1683735
feat: add keeper methods to save AVS information
RiccardoM Jun 4, 2024
1c44cec
feat: add message update AVS
RiccardoM Jun 4, 2024
fffadad
refactor: improve genesis and messages definitions
RiccardoM Jun 4, 2024
88d6928
feat: add msg server
RiccardoM Jun 4, 2024
185f8ed
feat: add genesis import/export
RiccardoM Jun 4, 2024
9c972cf
feat: add gRPC query
RiccardoM Jun 4, 2024
dfa8bd7
feat: add module definition
RiccardoM Jun 4, 2024
ba96f82
chore: fix comments and variables name
RiccardoM Jun 4, 2024
294ae0a
chore: rename avs module to services
RiccardoM Jun 4, 2024
6f358f5
chore: renamed AVS to Service
RiccardoM Jun 4, 2024
5e05ebb
feat: add query command
RiccardoM Jun 4, 2024
1e1c14e
refactor: rename AVSs to Services
RiccardoM Jun 4, 2024
93c368f
feat: add invariants
RiccardoM Jun 5, 2024
072c231
refactor: improve genesis usage
RiccardoM Jun 5, 2024
6b724e8
refactor: improve msg server and gRPC querier
RiccardoM Jun 5, 2024
db80558
chore(tests): setup keeper tests
RiccardoM Jun 6, 2024
17de184
refactor: move expected keeper into types
RiccardoM Jun 6, 2024
76256f1
refactor: improve msg service
RiccardoM Jun 10, 2024
05fe218
revert: api codebase formatting
RiccardoM Jun 13, 2024
7b0c770
refactor: store service account inside keeper
RiccardoM Jun 13, 2024
42b2a01
feat: add keeper and types
RiccardoM Jun 8, 2024
c06c767
feat(tests): add models tests
RiccardoM Jun 9, 2024
1653179
refactor: remove unused authority
RiccardoM Jun 9, 2024
d6719f6
feat(tests): add keeper tests
RiccardoM Jun 9, 2024
045c815
feat: add gRPC query server
RiccardoM Jun 9, 2024
2447331
feat: add CLI commands
RiccardoM Jun 9, 2024
15d0dd8
feat: add genesis export and initialization
RiccardoM Jun 9, 2024
152975e
feat: add genesis keeper tests
RiccardoM Jun 10, 2024
f73f295
feat: add invariants
RiccardoM Jun 10, 2024
c4b1198
chore: add pools module to app.go
RiccardoM Jun 10, 2024
f95524a
chore: fix test method name
RiccardoM Jun 10, 2024
eab4c33
feat: add pool address
RiccardoM Jun 13, 2024
0bb2890
build: remove unwanted Makefile entry
RiccardoM Jun 14, 2024
284d4c6
feat: add invariant to check for duplicated pools by denom
RiccardoM Jun 17, 2024
c5ba1f0
feat(tests): improve CreateOrGetPoolByDenom tests
RiccardoM Jun 17, 2024
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
16 changes: 14 additions & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ import (
"github.com/milkyway-labs/milkyway/x/operators"
operatorskeeper "github.com/milkyway-labs/milkyway/x/operators/keeper"
operatorstypes "github.com/milkyway-labs/milkyway/x/operators/types"
"github.com/milkyway-labs/milkyway/x/pools"
poolskeeper "github.com/milkyway-labs/milkyway/x/pools/keeper"
poolstypes "github.com/milkyway-labs/milkyway/x/pools/types"
"github.com/milkyway-labs/milkyway/x/records"
recordskeeper "github.com/milkyway-labs/milkyway/x/records/keeper"
recordstypes "github.com/milkyway-labs/milkyway/x/records/types"
Expand Down Expand Up @@ -284,6 +287,7 @@ type MilkyWayApp struct {

ServicesKeeper *serviceskeeper.Keeper
OperatorsKeeper *operatorskeeper.Keeper
PoolsKeeper *poolskeeper.Keeper

// make scoped keepers public for test purposes
ScopedIBCKeeper capabilitykeeper.ScopedKeeper
Expand Down Expand Up @@ -347,7 +351,7 @@ func NewMilkyWayApp(
icacallbackstypes.StoreKey, recordstypes.StoreKey, stakeibctypes.StoreKey,

// Custom modules
servicestypes.StoreKey, operatorstypes.StoreKey,
servicestypes.StoreKey, operatorstypes.StoreKey, poolstypes.StoreKey,
)
tkeys := storetypes.NewTransientStoreKeys(forwardingtypes.TransientStoreKey)
memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
Expand Down Expand Up @@ -874,6 +878,11 @@ func NewMilkyWayApp(
communityPoolKeeper,
authorityAddr,
)
app.PoolsKeeper = poolskeeper.NewKeeper(
app.appCodec,
keys[poolstypes.StoreKey],
app.AccountKeeper,
)

/**** Module Options ****/

Expand Down Expand Up @@ -923,6 +932,7 @@ func NewMilkyWayApp(
// custom modules
services.NewAppModule(appCodec, app.ServicesKeeper),
operators.NewAppModule(appCodec, app.OperatorsKeeper),
pools.NewAppModule(appCodec, app.PoolsKeeper),
)

if err := app.setupIndexer(appOpts, homePath, ac, vc, appCodec); err != nil {
Expand Down Expand Up @@ -963,6 +973,7 @@ func NewMilkyWayApp(

servicestypes.ModuleName,
operatorstypes.ModuleName,
poolstypes.ModuleName,
)

app.ModuleManager.SetOrderEndBlockers(
Expand All @@ -979,6 +990,7 @@ func NewMilkyWayApp(

servicestypes.ModuleName,
operatorstypes.ModuleName,
poolstypes.ModuleName,
)

// NOTE: The genutils module must occur after staking so that pools are
Expand All @@ -998,7 +1010,7 @@ func NewMilkyWayApp(
stakeibctypes.ModuleName, epochstypes.ModuleName, icqtypes.ModuleName,
recordstypes.ModuleName, ratelimittypes.ModuleName, icacallbackstypes.ModuleName,

servicestypes.ModuleName, operatorstypes.ModuleName,
servicestypes.ModuleName, operatorstypes.ModuleName, poolstypes.ModuleName,
}

app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...)
Expand Down
22 changes: 22 additions & 0 deletions proto/milkyway/pools/v1/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
syntax = "proto3";
package milkyway.pools.v1;

import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";
import "milkyway/pools/v1/models.proto";

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

// GenesisState defines the pools module's genesis state.
message GenesisState {

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

// Operators defines the list of pools.
repeated Pool pools = 2
[ (gogoproto.moretags) = "yaml:\"pools\"", (gogoproto.nullable) = false ];
}
20 changes: 20 additions & 0 deletions proto/milkyway/pools/v1/models.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
syntax = "proto3";
package milkyway.pools.v1;

import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";

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

// Pool defines the structure of a restaking pool
message Pool {
// ID is the auto-generated unique identifier for the pool
uint32 id = 1 [ (gogoproto.customname) = "ID" ];

// Denom represents the denomination of the tokens that are staked in the pool
string denom = 2;

// 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" ];
}
62 changes: 62 additions & 0 deletions proto/milkyway/pools/v1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
syntax = "proto3";
package milkyway.pools.v1;

import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "milkyway/pools/v1/models.proto";

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

// Query defines the gRPC querier service.
service Query {
// PoolById defines a gRPC query method that returns the pool by the given ID.
rpc PoolById(QueryPoolByIdRequest) returns (QueryPoolResponse) {
option (google.api.http).get = "/milkyway/pool/v1/pool/{pool_id}";
}

// PoolByDenom defines a gRPC query method that returns the pool by the given
// denom.
rpc PoolByDenom(QueryPoolByDenomRequest) returns (QueryPoolResponse) {
option (google.api.http).get = "/milkyway/pool/v1/pool/denom/{denom}";
}

// Pools defines a gRPC query method that returns all pools.
rpc Pools(QueryPoolsRequest) returns (QueryPoolsResponse) {
option (google.api.http).get = "/milkyway/pool/v1/pools";
}
}

// QueryPoolByIdRequest is the request type for the Query/PoolById RPC method.
message QueryPoolByIdRequest {
// PoolID is the ID of the pool to query
uint32 pool_id = 1;
}

// QueryPoolByDenomRequest is the request type for the Query/PollByDenom RPC
// method.
message QueryPoolByDenomRequest {
// Denom is the denom for which the pool is to be queried
string denom = 1;
}

// QueryOperatorRPoolsesponse is the response type for the Query/PoolById and
// Query/PoolByDenom RPC methods.
message QueryPoolResponse {
// Pool is the queried pool
Pool pool = 1 [ (gogoproto.nullable) = false ];
}

// QueryPoolsRequest is the request type for the Query/Pools RPC method.
message QueryPoolsRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}

// QueryPoolsResponse is the response type for the Query/Pools RPC method.
message QueryPoolsResponse {
// Pools is the list of pool
repeated Pool pools = 1 [ (gogoproto.nullable) = false ];

// Pagination defines the pagination response
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
22 changes: 22 additions & 0 deletions utils/slices.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,25 @@ func FindDuplicate[T any](slice []T, compare func(a T, b T) bool) *T {
}
return nil
}

// Map applies the given function to each element in the slice and returns a new slice with the results.
func Map[T, U any](slice []T, f func(T) U) []U {
result := make([]U, len(slice))
for i, v := range slice {
result[i] = f(v)
}
return result
}

// RemoveDuplicates removes all duplicate elements from the slice.
func RemoveDuplicates[T comparable](slice []T) []T {
seen := make(map[T]bool)
result := make([]T, 0, len(slice))
for _, v := range slice {
if _, ok := seen[v]; !ok {
seen[v] = true
result = append(result, v)
}
}
return result
}
126 changes: 126 additions & 0 deletions x/pools/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package cli

import (
"fmt"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/version"
"github.com/spf13/cobra"

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

// GetQueryCmd returns the command allowing to perform queries
func GetQueryCmd() *cobra.Command {
servicesQueryCmd := &cobra.Command{
Use: types.ModuleName,
Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

servicesQueryCmd.AddCommand(
getCmdQueryPoolByID(),
getCmdQueryPoolByDenom(),
getCmdQueryPools(),
)

return servicesQueryCmd
}

// getCmdQueryPoolByID returns the command allowing to query a service
func getCmdQueryPoolByID() *cobra.Command {
cmd := &cobra.Command{
Use: "pool [pool-id]",
Short: "Query the pool with the given id",
Example: fmt.Sprintf(`%s query %s pool 1`, version.AppName, types.ModuleName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

poolID, err := types.ParsePoolID(args[0])
if err != nil {
return err
}

res, err := queryClient.PoolById(cmd.Context(), types.NewQueryPoolByIdRequest(poolID))
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// getCmdQueryPoolByDenom returns the command allowing to query services
func getCmdQueryPoolByDenom() *cobra.Command {
cmd := &cobra.Command{
Use: "pool-by-denom [denom]",
Short: "Query the pool associated with the given denom",
Example: fmt.Sprintf(`%s query %s pool umilk`, version.AppName, types.ModuleName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

res, err := queryClient.PoolByDenom(cmd.Context(), types.NewQueryPoolByDenomRequest(args[0]))
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// getCmdQueryPools returns the command to query the stored pools
func getCmdQueryPools() *cobra.Command {
cmd := &cobra.Command{
Use: "pools",
Short: "Query the pools",
Example: fmt.Sprintf(`%s query %s pools --page=2 --limit=100`, version.AppName, types.ModuleName),
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}

res, err := queryClient.Pools(cmd.Context(), types.NewQueryPoolsRequest(pageReq))
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "pools")

return cmd
}
Loading
Loading