Skip to content

Commit

Permalink
Add Query pools by coin denom (osmosis-labs#6766)
Browse files Browse the repository at this point in the history
* Add Cli query pools by denom

* revert

* minor

* minor

* Update x/poolmanager/client/query_proto_wrap.go

Co-authored-by: Ruslan Akhtariev <[email protected]>

* Update x/poolmanager/client/query_proto_wrap.go

Co-authored-by: Ruslan Akhtariev <[email protected]>

* Update x/poolmanager/router.go

Co-authored-by: Ruslan Akhtariev <[email protected]>

* Update proto/osmosis/poolmanager/v1beta1/query.proto

Co-authored-by: Matt, Park <[email protected]>

* Update x/poolmanager/router.go

Co-authored-by: Matt, Park <[email protected]>

* Update proto/osmosis/poolmanager/v1beta1/query.proto

Co-authored-by: Matt, Park <[email protected]>

* Update x/poolmanager/router.go

Co-authored-by: Matt, Park <[email protected]>

* Update x/poolmanager/router.go

Co-authored-by: Matt, Park <[email protected]>

* minor and lint

* Use dynamic slice instead of Allocate the slice

* changelog

* make proto-gen

* lint proto

* add test

* Update x/poolmanager/router_test.go

Co-authored-by: Matt, Park <[email protected]>

* Update x/poolmanager/router_test.go

Co-authored-by: Matt, Park <[email protected]>

* make proto-all

* use a few poolType Concentrated

---------

Co-authored-by: Ruslan Akhtariev <[email protected]>
Co-authored-by: Matt, Park <[email protected]>
Co-authored-by: Hieu Vu <[email protected]>
  • Loading branch information
4 people authored and doggystylez committed Feb 14, 2024
1 parent 5640a99 commit 22e8db8
Show file tree
Hide file tree
Showing 9 changed files with 789 additions and 136 deletions.
17 changes: 17 additions & 0 deletions proto/osmosis/poolmanager/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ service Query {
rpc AllPools(AllPoolsRequest) returns (AllPoolsResponse) {
option (google.api.http).get = "/osmosis/poolmanager/v1beta1/all-pools";
}
// ListPoolsByDenom return all pools by denom
rpc ListPoolsByDenom(ListPoolsByDenomRequest)
returns (ListPoolsByDenomResponse) {
option (google.api.http).get =
"/osmosis/poolmanager/v1beta1/list-pools-by-denom";
}

// SpotPrice defines a gRPC query handler that returns the spot price given
// a base denomination and a quote denomination.
Expand Down Expand Up @@ -234,6 +240,17 @@ message AllPoolsResponse {
[ (cosmos_proto.accepts_interface) = "PoolI" ];
}

// =======================================================
// ListPoolsByDenomRequest
message ListPoolsByDenomRequest {
string denom = 1 [ (gogoproto.moretags) = "yaml:\"denom\"" ];
}

message ListPoolsByDenomResponse {
repeated google.protobuf.Any pools = 1
[ (cosmos_proto.accepts_interface) = "PoolI" ];
}
// ==========================================================
// SpotPriceRequest defines the gRPC request structure for a SpotPrice
// query.
message SpotPriceRequest {
Expand Down
2 changes: 1 addition & 1 deletion scripts/setup_superfluid.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ sleep 7
osmosisd tx gov vote 1 yes --from=validator1 --keyring-backend=test --chain-id=testing --yes --home=$HOME/.osmosisd/validator1
sleep 7
osmosisd tx gov vote 1 yes --from=validator2 --keyring-backend=test --chain-id=testing --yes --home=$HOME/.osmosisd/validator2
sleep 7
sleep 7
10 changes: 10 additions & 0 deletions x/poolmanager/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func GetQueryCmd() *cobra.Command {
osmocli.AddQueryCmd(cmd, queryproto.NewQueryClient, GetCmdTotalVolumeForPool)
osmocli.AddQueryCmd(cmd, queryproto.NewQueryClient, GetCmdTradingPairTakerFee)
osmocli.AddQueryCmd(cmd, queryproto.NewQueryClient, GetCmdEstimateTradeBasedOnPriceImpact)
osmocli.AddQueryCmd(cmd, queryproto.NewQueryClient, GetCmdListPoolsByDenom)
cmd.AddCommand(
osmocli.GetParams[*queryproto.ParamsRequest](
types.ModuleName, queryproto.NewQueryClient),
Expand Down Expand Up @@ -105,6 +106,15 @@ func GetCmdSpotPrice() (*osmocli.QueryDescriptor, *queryproto.SpotPriceRequest)
`,
}, &queryproto.SpotPriceRequest{}
}
func GetCmdListPoolsByDenom() (*osmocli.QueryDescriptor, *queryproto.ListPoolsByDenomRequest) {
return &osmocli.QueryDescriptor{
Use: "list-pools-by-denom",
Short: "Query list-pools-by-denom",
Long: `Query list-pools-by-denom
{{.CommandPrefix}} list-pools-by-denom uosmo
`,
}, &queryproto.ListPoolsByDenomRequest{}
}

func EstimateSwapExactAmountInParseArgs(args []string, fs *flag.FlagSet) (proto.Message, error) {
poolID, err := strconv.Atoi(args[0])
Expand Down
10 changes: 10 additions & 0 deletions x/poolmanager/client/grpc/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ func (q Querier) SpotPrice(grpcCtx context.Context,
return q.Q.SpotPrice(ctx, *req)
}

func (q Querier) ListPoolsByDenom(grpcCtx context.Context,
req *queryproto.ListPoolsByDenomRequest,
) (*queryproto.ListPoolsByDenomResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(grpcCtx)
return q.Q.ListPoolsByDenom(ctx, *req)
}

func (q Querier) Pool(grpcCtx context.Context,
req *queryproto.PoolRequest,
) (*queryproto.PoolResponse, error) {
Expand Down
24 changes: 24 additions & 0 deletions x/poolmanager/client/query_proto_wrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,30 @@ func (q Querier) AllPools(ctx sdk.Context, req queryproto.AllPoolsRequest) (*que
}, nil
}

// ListPoolsByDenom returns a list of pools filtered by denom
func (q Querier) ListPoolsByDenom(ctx sdk.Context, req queryproto.ListPoolsByDenomRequest) (*queryproto.ListPoolsByDenomResponse, error) {
if req.Denom == "" {
return nil, status.Error(codes.InvalidArgument, "invalid denom")
}
pools, err := q.K.ListPoolsByDenom(ctx, req.Denom)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}

var anyPools []*codectypes.Any
for _, pool := range pools {
any, err := codectypes.NewAnyWithValue(pool.AsSerializablePool())
if err != nil {
return nil, err
}
anyPools = append(anyPools, any)
}

return &queryproto.ListPoolsByDenomResponse{
Pools: anyPools,
}, nil
}

// SpotPrice returns the spot price of the pool with the given quote and base asset denoms. 18 decimals.
func (q Querier) SpotPrice(ctx sdk.Context, req queryproto.SpotPriceRequest) (*queryproto.SpotPriceResponse, error) {
if req.BaseAssetDenom == "" {
Expand Down
668 changes: 533 additions & 135 deletions x/poolmanager/client/queryproto/query.pb.go

Large diffs are not rendered by default.

83 changes: 83 additions & 0 deletions x/poolmanager/client/queryproto/query.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions x/poolmanager/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,38 @@ func (k Keeper) AllPools(
return sortedPools, nil
}

// ListPoolsByDenom returns all pools by denom sorted by their ids
// from every pool module registered in the
// pool manager keeper.
func (k Keeper) ListPoolsByDenom(
ctx sdk.Context,
denom string,
) ([]types.PoolI, error) {
less := func(i, j types.PoolI) bool {
return i.GetId() < j.GetId()
}
var sortedPools []types.PoolI
for _, poolModule := range k.poolModules {
currentModulePools, err := poolModule.GetPools(ctx)
if err != nil {
return nil, err
}

var poolsByDenom []types.PoolI
for _, pool := range currentModulePools {
coins, err := k.GetTotalPoolLiquidity(ctx, pool.GetId())
if err != nil {
return nil, err
}
if coins.AmountOf(denom).GT(osmomath.ZeroInt()) {
poolsByDenom = append(poolsByDenom, pool)
}
}
sortedPools = osmoutils.MergeSlices(sortedPools, poolsByDenom, less)
}
return sortedPools, nil
}

// createMultihopExpectedSwapOuts defines the output denom and output amount for the last pool in
// the routeStep of pools the caller is intending to hop through in a fixed-output multihop tx. It estimates the input
// amount for this last pool and then chains that input as the output of the previous pool in the routeStep, repeating
Expand Down
79 changes: 79 additions & 0 deletions x/poolmanager/router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3785,3 +3785,82 @@ func (s *KeeperTestSuite) testSwapExactAmpountInVolumeTracked(noTakerFeeVariant
totalVolume = s.App.PoolManagerKeeper.GetTotalVolumeForPool(s.Ctx, concentratedPool.GetId())
s.Require().Equal(tokenIn.String(), totalVolume.String())
}

func (suite *KeeperTestSuite) TestListPoolsByDenom() {
suite.Setup()

tests := map[string]struct {
denom string
poolCoins []sdk.Coins
expectedNumPools int
expectedError bool
poolType []types.PoolType
}{
"Single pool, pool contain denom": {
poolType: []types.PoolType{types.Balancer},
poolCoins: []sdk.Coins{
sdk.NewCoins(sdk.NewCoin(BAR, defaultInitPoolAmount), sdk.NewCoin(UOSMO, defaultInitPoolAmount)), // pool 1 bar-uosmo
},
denom: BAR,
expectedNumPools: 1,
},
"Single pool, pool does not contain denom": {
poolType: []types.PoolType{types.Balancer},
poolCoins: []sdk.Coins{
sdk.NewCoins(sdk.NewCoin(BAR, defaultInitPoolAmount), sdk.NewCoin(UOSMO, defaultInitPoolAmount)), // pool 1 bar-uosmo
},
denom: FOO,
expectedNumPools: 0,
},
"Two pools, pools contains denom": {
poolType: []types.PoolType{types.Balancer, types.Balancer},
poolCoins: []sdk.Coins{
sdk.NewCoins(sdk.NewCoin(BAR, defaultInitPoolAmount), sdk.NewCoin(UOSMO, defaultInitPoolAmount)), // pool 1 bar-uosmo
sdk.NewCoins(sdk.NewCoin(BAR, defaultInitPoolAmount), sdk.NewCoin(FOO, defaultInitPoolAmount)), // pool 2. baz-foo
},
denom: BAR,
expectedNumPools: 2,
},
"Two pools, pools does not contains denom": {
poolType: []types.PoolType{types.Balancer, types.Concentrated},
poolCoins: []sdk.Coins{
sdk.NewCoins(sdk.NewCoin(BAR, defaultInitPoolAmount), sdk.NewCoin(UOSMO, defaultInitPoolAmount)), // pool 1 bar-uosmo
sdk.NewCoins(sdk.NewCoin(BAZ, defaultInitPoolAmount), sdk.NewCoin(UOSMO, defaultInitPoolAmount)), // pool 2. baz-foo
},
denom: FOO,
expectedNumPools: 0,
},
"Many pools": {
poolType: []types.PoolType{types.Concentrated, types.Balancer, types.Concentrated, types.Balancer},
poolCoins: []sdk.Coins{
sdk.NewCoins(sdk.NewCoin(BAR, defaultInitPoolAmount), sdk.NewCoin(UOSMO, defaultInitPoolAmount)), // pool 1 bar-uosmo
sdk.NewCoins(sdk.NewCoin(BAZ, defaultInitPoolAmount), sdk.NewCoin(FOO, defaultInitPoolAmount)), // pool 2. baz-foo
sdk.NewCoins(sdk.NewCoin(BAR, defaultInitPoolAmount), sdk.NewCoin(BAZ, defaultInitPoolAmount)), // pool 3. bar-baz
sdk.NewCoins(sdk.NewCoin(BAZ, defaultInitPoolAmount), sdk.NewCoin(UOSMO, defaultInitPoolAmount)), // pool 4. baz-uosmo
},
denom: BAR,
expectedNumPools: 2,
},
}

for name, tc := range tests {
suite.Run(name, func() {
suite.SetupTest()
ctx := suite.Ctx
poolManagerKeeper := suite.App.PoolManagerKeeper

for i := range tc.poolType {
suite.FundAcc(suite.TestAccs[0], tc.poolCoins[i])
suite.CreatePoolFromTypeWithCoins(tc.poolType[i], tc.poolCoins[i])
}

poolsResult, err := poolManagerKeeper.ListPoolsByDenom(ctx, tc.denom)
if tc.expectedError {
suite.Require().Error(err)
} else {
suite.Require().NoError(err)
suite.Require().Equal(tc.expectedNumPools, len(poolsResult))
}
})
}
}

0 comments on commit 22e8db8

Please sign in to comment.