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

BE-636 | Add pagination + sorting + query filtering support for /pools endpoint #553

Merged
merged 67 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
c8e684f
chore: add mergify backport on tag action (#542)
deividaspetraitis Oct 31, 2024
8f2df57
BE-586 | Claimbot (#524)
deividaspetraitis Nov 3, 2024
863d154
refactor: gas estimation APIs (#546)
p0mvn Nov 3, 2024
eb7d0f9
feat: simulate swap as part of quotes (#547)
p0mvn Nov 4, 2024
b99e5ad
changelog
p0mvn Nov 4, 2024
3383831
refactor: decouple base fee fetching as part of quote from simulation…
p0mvn Nov 5, 2024
72774d6
Update CHANGELOG.md for v26.2.0 (#560)
deividaspetraitis Nov 13, 2024
acf0e1c
BE-636 | pipeline package: add transformer
deividaspetraitis Nov 7, 2024
e954a37
BE-636 pipeline: add iterator
deividaspetraitis Nov 7, 2024
6ec4257
BE-636 | pipeline: add paginator
deividaspetraitis Nov 7, 2024
b1666b6
BE-636 | Test wiring
deividaspetraitis Nov 7, 2024
c7eba69
BE-636 | GetPools request init
deividaspetraitis Nov 8, 2024
1a8ed70
BE-636 | Add pagination.proto, move to pkg/api
deividaspetraitis Nov 8, 2024
2ff2403
BE-636 | Add pagination
deividaspetraitis Nov 8, 2024
b98e193
BE-636 | pagination: test UnmarshalHTTPRequest
deividaspetraitis Nov 8, 2024
9feff67
BE-636 | proto files, pools.pb.go regenerate
deividaspetraitis Nov 8, 2024
815c5ff
BE-636 | Paginate pools results
deividaspetraitis Nov 8, 2024
456a488
BE-636 | Fix docs
deividaspetraitis Nov 8, 2024
66742e0
BE-636 | Sort api
deividaspetraitis Nov 9, 2024
2f41239
BE-636 | swagger docs
deividaspetraitis Nov 10, 2024
5ca9cba
BE-636 | Implement sorting
deividaspetraitis Nov 12, 2024
b3230d8
BE-636 | Add remaining sort keys
deividaspetraitis Nov 13, 2024
016073a
BE-636 | Bug fix
deividaspetraitis Nov 15, 2024
c36e2d2
BE-636 | Sorting, filtering fixes
deividaspetraitis Nov 18, 2024
06a7aee
BE-636 | Pools: include total count of items in the response
deividaspetraitis Nov 18, 2024
f71d6b5
BE-636 | Add cursor strategy support for PaginationRequest
deividaspetraitis Nov 19, 2024
aeeb2fd
BE-636 | Paginator refactor to support multiple paging strategies.
deividaspetraitis Nov 19, 2024
a6f7d1c
BE-636 | Paginator set start offset
deividaspetraitis Nov 19, 2024
46e1e27
BE-636 | Paginator add support for FetchPageByCursor
deividaspetraitis Nov 19, 2024
34c5f75
BE-636 | pagination: next cursor calculation
deividaspetraitis Nov 20, 2024
cfb0c89
BE-636 | Filters rework
deividaspetraitis Nov 22, 2024
378ea7d
BE-636 | Add tests for pool filters
deividaspetraitis Nov 22, 2024
0801289
BE-636 | Add http helpers
deividaspetraitis Nov 22, 2024
5fc3430
BE-636 | Fix tests
deividaspetraitis Nov 22, 2024
2be2b43
BE-636 | Add swagger1
deividaspetraitis Nov 22, 2024
0922115
BE-636 | Number package
deividaspetraitis Nov 22, 2024
9ef7a3d
BE-636 | Fix rebase v27
deividaspetraitis Nov 25, 2024
598cd97
BE-636 | Fix rebase #2
deividaspetraitis Nov 25, 2024
0587519
BE-636 | Pools: not in filter
deividaspetraitis Nov 26, 2024
cd0efd9
BE-636 | Filtering pools by incentive
deividaspetraitis Nov 26, 2024
8ca92c7
BE-636 | Pools endpoint: add support for search
deividaspetraitis Nov 27, 2024
26a25df
BE-636 | Pools search: Find by ID quick fix
deividaspetraitis Nov 27, 2024
852092f
BE-636 | Transformer cover Range with tests
deividaspetraitis Nov 28, 2024
b414693
BE-636 | Transformer cover Keys with tests
deividaspetraitis Nov 28, 2024
0eb06e1
BE-636 | Transformer cover Values with tests
deividaspetraitis Nov 28, 2024
a72dc9f
BE-636 | Transformer cover Clone with tests
deividaspetraitis Nov 28, 2024
e9e2d8c
BE-636 | Iterator cover Next with tests
deividaspetraitis Nov 28, 2024
54d5680
BE-636 | Iterator cover SetOffset with tests
deividaspetraitis Nov 28, 2024
2eb8251
BE-636 | Iterator cover HasNext with tests
deividaspetraitis Nov 28, 2024
873e54b
BE-636 | Iterator cover Reset with tests
deividaspetraitis Nov 28, 2024
005960e
BE-636 | Paginator cover GetPage with tests
deividaspetraitis Nov 28, 2024
44549c2
Merge remote-tracking branch 'upstream/v27.x' into BE-636
deividaspetraitis Nov 29, 2024
4c3d479
Merge remote-tracking branch 'upstream/v27.x' into BE-636
deividaspetraitis Nov 29, 2024
0a8665d
Merge remote-tracking branch 'upstream/v27.x' into BE-636
deividaspetraitis Nov 29, 2024
1f3a037
BE-636 | Regroup imports
deividaspetraitis Nov 29, 2024
6e3a8ef
Merge remote-tracking branch 'upstream/v27.x' into BE-636
deividaspetraitis Nov 29, 2024
9a6c568
Merge remote-tracking branch 'upstream/v27.x' into BE-636
deividaspetraitis Nov 29, 2024
97b9f53
Merge remote-tracking branch 'upstream/v27.x' into BE-636
deividaspetraitis Dec 2, 2024
3a11a9a
Merge remote-tracking branch 'upstream/v27.x' into BE-636
deividaspetraitis Dec 2, 2024
e8174b7
BE-636 | Revert changes to reduce noise
deividaspetraitis Dec 2, 2024
fdda814
BE-636 | Revert not related changes
deividaspetraitis Dec 2, 2024
4986e8d
BE-636 | Omit swagger related changes
deividaspetraitis Dec 2, 2024
f1eafd1
BE-636 | Move some filters out of getPools
deividaspetraitis Dec 2, 2024
2837dcb
Merge remote-tracking branch 'upstream/v27.x' into BE-636
deividaspetraitis Dec 2, 2024
eed3b1d
BE-636 | Extend tests for GetPools method
deividaspetraitis Dec 2, 2024
8bc9a12
BE-636 | Requested changes
deividaspetraitis Dec 2, 2024
799688a
BE-636 | Bump sqsdomain package version
deividaspetraitis Dec 2, 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
9 changes: 8 additions & 1 deletion app/sidecar_query_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,14 @@ func NewSideCarQueryServer(appCodec codec.Codec, config domain.Config, logger lo
}

// Initialize pools repository, usecase and HTTP handler
poolsUseCase, err := poolsUseCase.NewPoolsUsecase(config.Pools, config.ChainGRPCGatewayEndpoint, routerRepository, tokensUseCase.GetChainScalingFactorByDenomMut, logger)
poolsUseCase, err := poolsUseCase.NewPoolsUsecase(
config.Pools,
config.ChainGRPCGatewayEndpoint,
routerRepository,
tokensUseCase.GetChainScalingFactorByDenomMut,
tokensUseCase,
logger,
)
if err != nil {
return nil, err
}
Expand Down
23 changes: 10 additions & 13 deletions domain/mocks/pool_handler_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,19 @@ type PoolHandlerMock struct {
var _ mvc.PoolHandler = &PoolHandlerMock{}

// GetPools implements mvc.PoolHandler.
func (p *PoolHandlerMock) GetPools(opts ...domain.PoolsOption) ([]sqsdomain.PoolI, error) {
func (p *PoolHandlerMock) GetPools(opts ...domain.PoolsOption) ([]sqsdomain.PoolI, uint64, error) {
if p.ForceGetPoolsError != nil {
return nil, p.ForceGetPoolsError
}

options := domain.PoolsOptions{
MinPoolLiquidityCap: 0,
PoolIDFilter: []uint64{},
return nil, 0, p.ForceGetPoolsError
}

var options domain.PoolsOptions
for _, opt := range opts {
opt(&options)
}

result := make([]sqsdomain.PoolI, 0)

if len(options.PoolIDFilter) > 0 {
for _, id := range options.PoolIDFilter {
if f := options.Filter; f != nil && len(f.PoolId) > 0 {
for _, id := range f.PoolId {
for _, pool := range p.Pools {
if pool.GetId() == id {
result = append(result, pool)
Expand All @@ -43,13 +38,15 @@ func (p *PoolHandlerMock) GetPools(opts ...domain.PoolsOption) ([]sqsdomain.Pool
}
} else {
for _, pool := range p.Pools {
if pool.GetLiquidityCap().Uint64() > options.MinPoolLiquidityCap {
result = append(result, pool)
if f := options.Filter; f != nil {
if pool.GetLiquidityCap().Uint64() > f.MinLiquidityCap {
result = append(result, pool)
}
}
}
}

return result, nil
return result, uint64(len(result)), nil
}

// StorePools implements mvc.PoolHandler.
Expand Down
4 changes: 2 additions & 2 deletions domain/mocks/pools_usecase_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var _ mvc.PoolsUsecase = &PoolsUsecaseMock{}

type PoolsUsecaseMock struct {
GetAllPoolsFunc func() ([]sqsdomain.PoolI, error)
GetPoolsFunc func(opts ...domain.PoolsOption) ([]sqsdomain.PoolI, error)
GetPoolsFunc func(opts ...domain.PoolsOption) ([]sqsdomain.PoolI, uint64, error)
StorePoolsFunc func(pools []sqsdomain.PoolI) error
GetRoutesFromCandidatesFunc func(candidateRoutes sqsdomain.CandidateRoutes, tokenInDenom, tokenOutDenom string) ([]route.RouteImpl, error)
GetTickModelMapFunc func(poolIDs []uint64) (map[uint64]*sqsdomain.TickModel, error)
Expand Down Expand Up @@ -79,7 +79,7 @@ func (pm *PoolsUsecaseMock) GetCosmWasmPoolConfig() domain.CosmWasmPoolRouterCon
}

// GetPools implements mvc.PoolsUsecase.
func (pm *PoolsUsecaseMock) GetPools(opts ...domain.PoolsOption) ([]sqsdomain.PoolI, error) {
func (pm *PoolsUsecaseMock) GetPools(opts ...domain.PoolsOption) ([]sqsdomain.PoolI, uint64, error) {
if pm.GetPoolsFunc != nil {
return pm.GetPoolsFunc(opts...)
}
Expand Down
5 changes: 3 additions & 2 deletions domain/mvc/pools.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ type PoolsUsecase interface {
}

type PoolHandler interface {
// GetPools returns the pools corresponding to the given IDs.
GetPools(opts ...domain.PoolsOption) ([]sqsdomain.PoolI, error)
// GetPools returns the pools corresponding to the given options and the total number of pools.
// If pagination is provided, returns the pools corresponding to the pagination.
GetPools(opts ...domain.PoolsOption) ([]sqsdomain.PoolI, uint64, error)

// StorePools stores the given pools in the usecase
StorePools(pools []sqsdomain.PoolI) error
Expand Down
60 changes: 43 additions & 17 deletions domain/pools.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package domain
import (
"context"

v1beta1 "github.com/osmosis-labs/sqs/pkg/api/v1beta1"
api "github.com/osmosis-labs/sqs/pkg/api/v1beta1/pools"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/osmosis-labs/osmosis/osmomath"
)
Expand Down Expand Up @@ -85,40 +88,63 @@ func (c CanonicalOrderBooksResult) Validate() error {
}

type PoolsOptions struct {
MinPoolLiquidityCap uint64
PoolIDFilter []uint64
WithMarketIncentives bool
// HadEmptyFilter is true if the pool ID filter was empty.
// This signifies avoid getting all pools and rather exit early.
HadEmptyFilter bool
Filter *api.GetPoolsRequestFilter
Pagination *v1beta1.PaginationRequest
Sort *v1beta1.SortRequest
}

// PoolsOption configures the pools filter options.
type PoolsOption func(*PoolsOptions)

// WithNonNilFilter ensures the Filter field in PoolsOptions is not nil and applies the provided configuration function.
func WithNonNilFilter(configure func(*api.GetPoolsRequestFilter)) PoolsOption {
return func(o *PoolsOptions) {
if o.Filter == nil {
o.Filter = &api.GetPoolsRequestFilter{} // Initialize Filter if nil
}
configure(o.Filter) // Apply the configuration function
}
}

// WithMinPooslLiquidityCap configures with the min pool liquidity
// capitalization.
func WithMinPoolsLiquidityCap(minPoolLiquidityCap uint64) PoolsOption {
return func(o *PoolsOptions) {
o.MinPoolLiquidityCap = minPoolLiquidityCap
}
return WithNonNilFilter(func(filter *api.GetPoolsRequestFilter) {
filter.MinLiquidityCap = minPoolLiquidityCap
})
}

// WithPoolIDFilter configures the pools options with the pool ID filter.
func WithPoolIDFilter(poolIDFilter []uint64) PoolsOption {
return WithNonNilFilter(func(filter *api.GetPoolsRequestFilter) {
filter.PoolId = poolIDFilter
})
}

// WithMarketIncentives configures the pools options with the market incentives filter.
func WithMarketIncentives(withMarketIncentives bool) PoolsOption {
return WithNonNilFilter(func(filter *api.GetPoolsRequestFilter) {
filter.WithMarketIncentives = withMarketIncentives
})
}

// WithPagination configures the pools options with the pagination request.
func WithFilter(f *api.GetPoolsRequestFilter) PoolsOption {
return func(o *PoolsOptions) {
// We should simply return early rather than attempting to get all pools.
if len(poolIDFilter) == 0 {
o.HadEmptyFilter = true
return
}
o.Filter = f
}
}

o.PoolIDFilter = poolIDFilter
// WithPagination configures the pools options with the pagination request.
func WithPagination(p *v1beta1.PaginationRequest) PoolsOption {
return func(o *PoolsOptions) {
o.Pagination = p
}
}

func WithMarketIncentives(withMarketIncentives bool) PoolsOption {
// WithSort configures the pools options with the sort request.
func WithSort(s *v1beta1.SortRequest) PoolsOption {
return func(o *PoolsOptions) {
o.WithMarketIncentives = withMarketIncentives
o.Sort = s
}
}
61 changes: 25 additions & 36 deletions pools/delivery/http/pools_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import (
deliveryhttp "github.com/osmosis-labs/sqs/delivery/http"
"github.com/osmosis-labs/sqs/domain"
"github.com/osmosis-labs/sqs/domain/mvc"
"github.com/osmosis-labs/sqs/domain/number"
v1beta1 "github.com/osmosis-labs/sqs/pkg/api/v1beta1"
api "github.com/osmosis-labs/sqs/pkg/api/v1beta1/pools"
"github.com/osmosis-labs/sqs/sqsdomain"

"github.com/osmosis-labs/osmosis/osmomath"
Expand Down Expand Up @@ -45,6 +46,12 @@ type PoolResponse struct {
FeesData sqspassthroughdomain.PoolFeesDataStatusWrap `json:"fees_data,omitempty"`
}

// GetPoolsResponse is a structure for serializing pools result returned to clients.
type GetPoolsResponse struct {
Data []PoolResponse `json:"data"`
Meta *v1beta1.PaginationResponse `json:"meta"`
}

const resourcePrefix = "/pools"

func formatPoolsResource(resource string) string {
Expand Down Expand Up @@ -74,53 +81,31 @@ func NewPoolsHandler(e *echo.Echo, us mvc.PoolsUsecase) {
// @Success 200 {array} sqsdomain.PoolI "List of pool(s) details"
// @Router /pools [get]
func (a *PoolsHandler) GetPools(c echo.Context) error {
// Get pool ID parameters as strings.
poolIDsStr := c.QueryParam("IDs")
minLiquidityCapStr := c.QueryParam("min_liquidity_cap")
withMarketIncentives, err := deliveryhttp.ParseBooleanQueryParam(c, "with_market_incentives")
if err != nil {
return c.JSON(http.StatusBadRequest, ResponseError{Message: err.Error()})
var req api.GetPoolsRequest
if err := deliveryhttp.ParseRequest(c, &req); err != nil {
return c.JSON(http.StatusBadRequest, domain.ResponseError{Message: err.Error()})
deividaspetraitis marked this conversation as resolved.
Show resolved Hide resolved
}

var (
pools []sqsdomain.PoolI
)

// Parse numbers
poolIDs, err := number.ParseNumbers(poolIDsStr)
if err != nil {
return c.JSON(http.StatusBadRequest, ResponseError{Message: err.Error()})
}

// Parse min liquidity cap if provided
var minLiquidityCap uint64
if minLiquidityCapStr != "" {
minLiquidityCap, err = strconv.ParseUint(minLiquidityCapStr, 10, 64)
if err != nil {
return c.JSON(http.StatusBadRequest, ResponseError{Message: "Invalid min_liquidity_cap value"})
}
}

filters := []domain.PoolsOption{
domain.WithMinPoolsLiquidityCap(minLiquidityCap),
domain.WithMarketIncentives(withMarketIncentives),
}

// Only add pool ID filter if it is not empty.
if len(poolIDs) > 0 {
filters = append(filters, domain.WithPoolIDFilter(poolIDs))
domain.WithFilter(req.Filter),
domain.WithPagination(req.Pagination),
domain.WithSort(req.Sort),
}

// Get pools
pools, err = a.PUsecase.GetPools(
pools, total, err := a.PUsecase.GetPools(
filters...,
)
if err != nil {
return c.JSON(getStatusCode(err), ResponseError{Message: err.Error()})
}

// Convert pools to the appropriate format
resultPools := convertPoolsToResponse(pools)
resultPools := convertPoolsToResponse(&req, pools, total)

return c.JSON(http.StatusOK, resultPools)
}
Expand Down Expand Up @@ -225,10 +210,14 @@ func convertPoolToResponse(pool sqsdomain.PoolI) PoolResponse {
}

// convertPoolsToResponse converts the given pools to the appropriate response type.
func convertPoolsToResponse(pools []sqsdomain.PoolI) []PoolResponse {
resultPools := make([]PoolResponse, 0, len(pools))
for _, pool := range pools {
resultPools = append(resultPools, convertPoolToResponse(pool))
func convertPoolsToResponse(req *api.GetPoolsRequest, p []sqsdomain.PoolI, total uint64) *GetPoolsResponse {
pools := make([]PoolResponse, 0, len(p))
for _, pool := range p {
pools = append(pools, convertPoolToResponse(pool))
}

return &GetPoolsResponse{
Data: pools,
Meta: v1beta1.NewPaginationResponse(req.Pagination, total),
}
return resultPools
}
6 changes: 1 addition & 5 deletions pools/usecase/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,10 @@ func (p *poolsUseCase) StoreInvalidOrderBookEntry(baseDenom, quoteDenom string)
p.canonicalOrderBookForBaseQuoteDenom.Store(formatBaseQuoteDenom(baseDenom, quoteDenom), invalidEntryType)
}

func (p poolsUseCase) SetPoolAPRAndFeeDataIfConfigured(pool sqsdomain.PoolI, options domain.PoolsOptions) {
func (p *poolsUseCase) SetPoolAPRAndFeeDataIfConfigured(pool sqsdomain.PoolI, options domain.PoolsOptions) {
p.setPoolAPRAndFeeDataIfConfigured(pool, options)
}

func (p *poolsUseCase) RetainPoolIfMatchesOptions(poolsToUpdate []sqsdomain.PoolI, poolConsidered sqsdomain.PoolI, options domain.PoolsOptions) []sqsdomain.PoolI {
return p.retainPoolIfMatchesOptions(poolsToUpdate, poolConsidered, options)
}

func (p *poolsUseCase) CalcExitPool(ctx sdk.Context, pool types.CFMMPoolI, exitingSharesIn osmomath.Int, exitFee osmomath.Dec) (sdk.Coins, error) {
return calcExitPool(ctx, pool, exitingSharesIn, exitFee)
}
Loading
Loading