Skip to content

Commit

Permalink
feat: implement pool liquidity query in pool manager, deprecate the o…
Browse files Browse the repository at this point in the history
…ne in gamm (#4951)

* sis/01-total-liq-query

* setup gamm

* added fix

* added changelog

* linter

* nit

* pass lint

* roman and matts comments

* linter

* added balancer pool type

* rebuild proto
  • Loading branch information
stackman27 authored Apr 25, 2023
1 parent 465f8ef commit 3022bd3
Show file tree
Hide file tree
Showing 16 changed files with 956 additions and 295 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#4682](https://github.com/osmosis-labs/osmosis/pull/4682) Deprecate x/gamm SpotPrice v2 query. The new one is located in x/poolmanager.
* [#4801](https://github.com/osmosis-labs/osmosis/pull/4801) remove GetTotalShares, GetTotalLiquidity and GetExitFee from PoolI. Define all on CFMMPoolI, define GetTotalLiquidity on PoolModuleI only.
* [#4868](https://github.com/osmosis-labs/osmosis/pull/4868) Remove wasmEnabledProposals []wasm.ProposalType from NewOsmosisApp

* [#4951](https://github.com/osmosis-labs/osmosis/pull/4951) Implement pool liquidity query in pool manager, deprecate the one in gamm

## v15.1.0

Expand Down
6 changes: 6 additions & 0 deletions proto/osmosis/gamm/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ service Query {
"/osmosis/gamm/v1beta1/pools/{pool_id}/params";
}

// Deprecated: please use the alternative in x/poolmanager
rpc TotalPoolLiquidity(QueryTotalPoolLiquidityRequest)
returns (QueryTotalPoolLiquidityResponse) {
option deprecated = true;
option (google.api.http).get =
"/osmosis/gamm/v1beta1/pools/{pool_id}/total_pool_liquidity";
}
Expand Down Expand Up @@ -197,11 +199,15 @@ message QueryPoolParamsRequest {
message QueryPoolParamsResponse { google.protobuf.Any params = 1; }

//=============================== PoolLiquidity
// Deprecated: please use the alternative in x/poolmanager
message QueryTotalPoolLiquidityRequest {
option deprecated = true;
uint64 pool_id = 1 [ (gogoproto.moretags) = "yaml:\"pool_id\"" ];
}

// Deprecated: please use the alternative in x/poolmanager
message QueryTotalPoolLiquidityResponse {
option deprecated = true;
repeated cosmos.base.v1beta1.Coin liquidity = 1 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "yaml:\"liquidity\"",
Expand Down
19 changes: 19 additions & 0 deletions proto/osmosis/poolmanager/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ service Query {
option (google.api.http).get =
"/osmosis/poolmanager/pools/{pool_id}/prices";
}

rpc TotalPoolLiquidity(TotalPoolLiquidityRequest)
returns (TotalPoolLiquidityResponse) {
option (google.api.http).get =
"/osmosis/poolmanager/v1beta1/pools/{pool_id}/total_pool_liquidity";
}
}

//=============================== Params
Expand Down Expand Up @@ -170,3 +176,16 @@ message SpotPriceResponse {
// String of the Dec. Ex) 10.203uatom
string spot_price = 1 [ (gogoproto.moretags) = "yaml:\"spot_price\"" ];
}

//=============================== PoolLiquidity
message TotalPoolLiquidityRequest {
uint64 pool_id = 1 [ (gogoproto.moretags) = "yaml:\"pool_id\"" ];
}

message TotalPoolLiquidityResponse {
repeated cosmos.base.v1beta1.Coin liquidity = 1 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "yaml:\"liquidity\"",
(gogoproto.nullable) = false
];
}
7 changes: 6 additions & 1 deletion proto/osmosis/poolmanager/v1beta1/query.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
keeper:
keeper:
path: "github.com/osmosis-labs/osmosis/v15/x/poolmanager"
struct: "Keeper"
client_path: "github.com/osmosis-labs/osmosis/v15/x/poolmanager/client"
Expand Down Expand Up @@ -50,3 +50,8 @@ queries:
query_func: "k.RouteCalculateSpotPrice"
cli:
cmd: "SpotPrice"
TotalPoolLiquidity:
proto_wrapper:
query_func: "k.TotalPoolLiquidity"
cli:
cmd: "TotalPoolLiquidity"
151 changes: 75 additions & 76 deletions x/concentrated-liquidity/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,82 +266,6 @@ func (s *KeeperTestSuite) TestCalculateSpotPrice() {
s.Require().True(spotPrice.IsNil())
}

func (s *KeeperTestSuite) TestGetTotalPoolLiquidity() {
var (
defaultPoolCoinOne = sdk.NewCoin(USDC, sdk.OneInt())
defaultPoolCoinTwo = sdk.NewCoin(ETH, sdk.NewInt(2))
nonPoolCool = sdk.NewCoin("uosmo", sdk.NewInt(3))

defaultCoins = sdk.NewCoins(defaultPoolCoinOne, defaultPoolCoinTwo)
)

tests := []struct {
name string
poolId uint64
poolLiquidity sdk.Coins
expectedResult sdk.Coins
expectedErr error
}{
{
name: "valid with 2 coins",
poolId: defaultPoolId,
poolLiquidity: defaultCoins,
expectedResult: defaultCoins,
},
{
name: "valid with 1 coin",
poolId: defaultPoolId,
poolLiquidity: sdk.NewCoins(defaultPoolCoinTwo),
expectedResult: sdk.NewCoins(defaultPoolCoinTwo),
},
{
// can only happen if someone sends extra tokens to pool
// address. Should not occur in practice.
name: "valid with 3 coins",
poolId: defaultPoolId,
poolLiquidity: sdk.NewCoins(defaultPoolCoinTwo, defaultPoolCoinOne, nonPoolCool),
expectedResult: defaultCoins,
},
{
// this can happen if someone sends random dust to pool address.
name: "only non-pool coin - does not show up in result",
poolId: defaultPoolId,
poolLiquidity: sdk.NewCoins(nonPoolCool),
expectedResult: sdk.Coins(nil),
},
{
name: "invalid pool id",
poolId: defaultPoolId + 1,
expectedErr: types.PoolNotFoundError{PoolId: defaultPoolId + 1},
},
}

for _, tc := range tests {
tc := tc
s.Run(tc.name, func() {
s.SetupTest()

// Create default CL pool
pool := s.PrepareConcentratedPool()

s.FundAcc(pool.GetAddress(), tc.poolLiquidity)

// Get pool defined in test case
actual, err := s.App.ConcentratedLiquidityKeeper.GetTotalPoolLiquidity(s.Ctx, tc.poolId)

if tc.expectedErr != nil {
s.Require().Error(err)
s.Require().ErrorIs(err, tc.expectedErr)
s.Require().Nil(actual)
return
}

s.Require().NoError(err)
s.Require().Equal(tc.expectedResult, actual)
})
}
}

func (s *KeeperTestSuite) TestValidateSwapFee() {
tests := []struct {
name string
Expand Down Expand Up @@ -487,7 +411,82 @@ func (s *KeeperTestSuite) TestDecreaseConcentratedPoolTickSpacing() {
return
}
s.Require().NoError(err)
})
}
}

func (s *KeeperTestSuite) TestGetTotalPoolLiquidity() {
var (
defaultPoolCoinOne = sdk.NewCoin(USDC, sdk.OneInt())
defaultPoolCoinTwo = sdk.NewCoin(ETH, sdk.NewInt(2))
nonPoolCool = sdk.NewCoin("uosmo", sdk.NewInt(3))

defaultCoins = sdk.NewCoins(defaultPoolCoinOne, defaultPoolCoinTwo)
)

tests := []struct {
name string
poolId uint64
poolLiquidity sdk.Coins
expectedResult sdk.Coins
expectedErr error
}{
{
name: "valid with 2 coins",
poolId: defaultPoolId,
poolLiquidity: defaultCoins,
expectedResult: defaultCoins,
},
{
name: "valid with 1 coin",
poolId: defaultPoolId,
poolLiquidity: sdk.NewCoins(defaultPoolCoinTwo),
expectedResult: sdk.NewCoins(defaultPoolCoinTwo),
},
{
// can only happen if someone sends extra tokens to pool
// address. Should not occur in practice.
name: "valid with 3 coins",
poolId: defaultPoolId,
poolLiquidity: sdk.NewCoins(defaultPoolCoinTwo, defaultPoolCoinOne, nonPoolCool),
expectedResult: defaultCoins,
},
{
// this can happen if someone sends random dust to pool address.
name: "only non-pool coin - does not show up in result",
poolId: defaultPoolId,
poolLiquidity: sdk.NewCoins(nonPoolCool),
expectedResult: sdk.Coins(nil),
},
{
name: "invalid pool id",
poolId: defaultPoolId + 1,
expectedErr: types.PoolNotFoundError{PoolId: defaultPoolId + 1},
},
}

for _, tc := range tests {
tc := tc
s.Run(tc.name, func() {
s.SetupTest()

// Create default CL pool
pool := s.PrepareConcentratedPool()

s.FundAcc(pool.GetAddress(), tc.poolLiquidity)

// Get pool defined in test case
actual, err := s.App.ConcentratedLiquidityKeeper.GetTotalPoolLiquidity(s.Ctx, tc.poolId)

if tc.expectedErr != nil {
s.Require().Error(err)
s.Require().ErrorIs(err, tc.expectedErr)
s.Require().Nil(actual)
return
}

s.Require().NoError(err)
s.Require().Equal(tc.expectedResult, actual)
})
}
}
27 changes: 15 additions & 12 deletions x/gamm/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,18 +158,6 @@ $ %s query gamm pool-params 1
return cmd
}

func GetCmdTotalPoolLiquidity() *cobra.Command {
return osmocli.SimpleQueryCmd[*types.QueryTotalPoolLiquidityRequest](
"total-pool-liquidity [poolID]",
"Query total-pool-liquidity",
`Query total-pool-liquidity.
Example:
{{.CommandPrefix}} total-pool-liquidity 1
`,
types.ModuleName, types.NewQueryClient,
)
}

func GetCmdTotalShares() *cobra.Command {
return osmocli.SimpleQueryCmd[*types.QueryTotalSharesRequest](
"total-share [poolID]",
Expand Down Expand Up @@ -333,3 +321,18 @@ Example:
types.ModuleName, types.NewQueryClient,
)
}

// GetCmdTotalPoolLiquidity returns total liquidity in pool.
// Deprecated: please use the alternative in x/poolmanager
// nolint: staticcheck
func GetCmdTotalPoolLiquidity() *cobra.Command {
return osmocli.SimpleQueryCmd[*types.QueryTotalPoolLiquidityRequest](
"total-pool-liquidity [poolID]",
"Query total-pool-liquidity",
`Query total-pool-liquidity.
Example:
{{.CommandPrefix}} total-pool-liquidity 1
`,
types.ModuleName, types.NewQueryClient,
)
}
2 changes: 2 additions & 0 deletions x/gamm/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ func (q Querier) PoolParams(ctx context.Context, req *types.QueryPoolParamsReque
}

// TotalPoolLiquidity returns total liquidity in pool.
// Deprecated: please use the alternative in x/poolmanager
// nolint: staticcheck
func (q Querier) TotalPoolLiquidity(ctx context.Context, req *types.QueryTotalPoolLiquidityRequest) (*types.QueryTotalPoolLiquidityResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
Expand Down
Loading

0 comments on commit 3022bd3

Please sign in to comment.