Skip to content

Commit

Permalink
fix cosmwasm pool config issue
Browse files Browse the repository at this point in the history
  • Loading branch information
p0mvn committed Mar 12, 2024
1 parent a179f97 commit 6cf9b43
Show file tree
Hide file tree
Showing 17 changed files with 112 additions and 37 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ Ref: https://keepachangelog.com/en/1.0.0/

# Changelog

## v0.7.3

Fixes cosmwasm pools config issue where unsupported pools were getting into the router and breaking it.

## v0.7.2

* [#100](https://github.com/osmosis-labs/sqs/pull/100) Format in over out spot price in quotes.
Expand Down
2 changes: 1 addition & 1 deletion app/sidecar_query_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func NewSideCarQueryServer(appCodec codec.Codec, config domain.Config, logger lo

// Initialize router repository, usecase
routerRepository := routerredisrepo.New(redisTxManager, 0)
routerUsecase := routerUseCase.WithOverwriteRoutesPath(routerUseCase.NewRouterUsecase(timeoutContext, routerRepository, poolsUseCase, *config.Router, logger, cache.New(), cache.New()), overwriteRoutesPath)
routerUsecase := routerUseCase.WithOverwriteRoutesPath(routerUseCase.NewRouterUsecase(timeoutContext, routerRepository, poolsUseCase, *config.Router, poolsUseCase.GetCosmWasmPoolConfig(), logger, cache.New(), cache.New()), overwriteRoutesPath)

// Initialize system handler
chainInfoRepository := chaininforedisrepo.New(redisTxManager)
Expand Down
3 changes: 2 additions & 1 deletion domain/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ func (e InvalidPoolTypeError) Error() string {

// UnsupportedCosmWasmPoolTypeError is an error type for invalid cosmwasm pool type.
type UnsupportedCosmWasmPoolTypeError struct {
PoolType int32
PoolType string
PoolId uint64
}

func (e UnsupportedCosmWasmPoolTypeError) Error() string {
Expand Down
9 changes: 9 additions & 0 deletions domain/mocks/pools_usecase_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ type PoolsUsecaseMock struct {
TickModelMap map[uint64]sqsdomain.TickModel
}

// GetCosmWasmPoolConfig implements mvc.PoolsUsecase.
func (pm *PoolsUsecaseMock) GetCosmWasmPoolConfig() domain.CosmWasmPoolRouterConfig {
return domain.CosmWasmPoolRouterConfig{
TransmuterCodeIDs: map[uint64]struct{}{},
GeneralCosmWasmCodeIDs: map[uint64]struct{}{},
NodeURI: "",
}
}

// GetPools implements mvc.PoolsUsecase.
func (*PoolsUsecaseMock) GetPools(ctx context.Context, poolIDs []uint64) ([]sqsdomain.PoolI, error) {
panic("unimplemented")
Expand Down
3 changes: 3 additions & 0 deletions domain/mvc/pools.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"

"github.com/osmosis-labs/osmosis/osmomath"
"github.com/osmosis-labs/sqs/domain"
"github.com/osmosis-labs/sqs/sqsdomain"

"github.com/osmosis-labs/sqs/router/usecase/route"
Expand All @@ -25,4 +26,6 @@ type PoolsUsecase interface {
GetPool(ctx context.Context, poolID uint64) (sqsdomain.PoolI, error)
// GetPoolSpotPrice returns the spot price of the given pool given the taker fee, quote and base assets.
GetPoolSpotPrice(ctx context.Context, poolID uint64, takerFee osmomath.Dec, quoteAsset, baseAsset string) (osmomath.BigDec, error)

GetCosmWasmPoolConfig() domain.CosmWasmPoolRouterConfig
}
2 changes: 1 addition & 1 deletion domain/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ type Quote interface {
// scalingFactor is the spot price scaling factor according to chain precision.
// scalingFactor of zero is a valid value. It might occur if we do not have precision information
// for the tokens. In that case, we invalidate spot price by setting it to zero.
PrepareResult(ctx context.Context, scalingFactor osmomath.Dec) ([]SplitRoute, osmomath.Dec)
PrepareResult(ctx context.Context, scalingFactor osmomath.Dec) ([]SplitRoute, osmomath.Dec, error)

String() string
}
Expand Down
5 changes: 5 additions & 0 deletions pools/usecase/pools_usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,8 @@ func (p *poolsUseCase) GetPools(ctx context.Context, poolIDs []uint64) ([]sqsdom

return pools, nil
}

// GetCosmWasmPoolConfig implements mvc.PoolsUsecase.
func (p *poolsUseCase) GetCosmWasmPoolConfig() domain.CosmWasmPoolRouterConfig {
return p.cosmWasmConfig
}
20 changes: 16 additions & 4 deletions router/delivery/http/router_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ func (a *RouterHandler) GetOptimalQuote(c echo.Context) (err error) {

scalingFactor := a.getSpotPriceScalingFactor(ctx, tokenInDenom, tokenOutDenom)

quote.PrepareResult(ctx, scalingFactor)
_, _, err = quote.PrepareResult(ctx, scalingFactor)
if err != nil {
return c.JSON(domain.GetStatusCode(err), domain.ResponseError{Message: err.Error()})
}

return c.JSON(http.StatusOK, quote)
}
Expand All @@ -117,7 +120,10 @@ func (a *RouterHandler) GetBestSingleRouteQuote(c echo.Context) error {

scalingFactor := a.getSpotPriceScalingFactor(ctx, tokenIn.Denom, tokenOutDenom)

quote.PrepareResult(ctx, scalingFactor)
_, _, err = quote.PrepareResult(ctx, scalingFactor)
if err != nil {
return c.JSON(domain.GetStatusCode(err), domain.ResponseError{Message: err.Error()})
}

return c.JSON(http.StatusOK, quote)
}
Expand Down Expand Up @@ -150,7 +156,10 @@ func (a *RouterHandler) GetCustomQuote(c echo.Context) error {

scalingFactor := a.getSpotPriceScalingFactor(ctx, tokenIn.Denom, tokenOutDenom)

quote.PrepareResult(ctx, scalingFactor)
_, _, err = quote.PrepareResult(ctx, scalingFactor)
if err != nil {
return c.JSON(domain.GetStatusCode(err), domain.ResponseError{Message: err.Error()})
}

return c.JSON(http.StatusOK, quote)
}
Expand Down Expand Up @@ -183,7 +192,10 @@ func (a *RouterHandler) GetDirectCustomQuote(c echo.Context) error {

scalingFactor := a.getSpotPriceScalingFactor(ctx, tokenIn.Denom, tokenOutDenom)

quote.PrepareResult(ctx, scalingFactor)
_, _, err = quote.PrepareResult(ctx, scalingFactor)
if err != nil {
return c.JSON(domain.GetStatusCode(err), domain.ResponseError{Message: err.Error()})
}

return c.JSON(http.StatusOK, quote)
}
Expand Down
6 changes: 3 additions & 3 deletions router/usecase/optimized_routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func (s *RouterTestSuite) TestGetBestSplitRoutesQuote() {

r := routerusecase.NewRouter(domain.RouterConfig{
MaxSplitIterations: tc.maxSplitIterations,
}, logger)
}, emptyCosmWasmPoolsRouterConfig, logger)

quote, err := r.GetSplitQuote(context.TODO(), tc.routes, tc.tokenIn)

Expand Down Expand Up @@ -538,7 +538,7 @@ func (s *RouterTestSuite) TestValidateAndFilterRoutes() {
tc := tc
s.Run(name, func() {

router := routerusecase.NewRouter(domain.RouterConfig{}, &log.NoOpLogger{})
router := routerusecase.NewRouter(domain.RouterConfig{}, emptyCosmWasmPoolsRouterConfig, &log.NoOpLogger{})

filteredCandidateRoutes, err := router.ValidateAndFilterRoutes(tc.routes, tc.tokenInDenom)

Expand Down Expand Up @@ -679,7 +679,7 @@ func (s *RouterTestSuite) TestGetCustomQuote_GetCustomDirectQuote_Mainnet_UOSMOU
poolsUsecase := poolsusecase.NewPoolsUsecase(time.Hour, &poolsRepositoryMock, nil, &domain.PoolsConfig{}, "node-uri-placeholder")
routerusecase.WithPoolsUsecase(router, poolsUsecase)

routerUsecase := routerusecase.NewRouterUsecase(time.Hour, &routerRepositoryMock, poolsUsecase, config, &log.NoOpLogger{}, cache.New(), cache.New())
routerUsecase := routerusecase.NewRouterUsecase(time.Hour, &routerRepositoryMock, poolsUsecase, config, emptyCosmWasmPoolsRouterConfig, &log.NoOpLogger{}, cache.New(), cache.New())

// This pool ID is second best: https://app.osmosis.zone/pool/2
// The top one is https://app.osmosis.zone/pool/1110 which is not selected
Expand Down
3 changes: 2 additions & 1 deletion router/usecase/pools/pool_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ func newRoutableCosmWasmPool(pool sqsdomain.PoolI, cosmWasmConfig domain.CosmWas
}

return nil, domain.UnsupportedCosmWasmPoolTypeError{
PoolType: int32(poolType),
PoolType: poolmanagertypes.PoolType_name[int32(poolType)],
PoolId: cosmwasmPool.PoolId,
}
}
6 changes: 3 additions & 3 deletions router/usecase/quote.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var _ domain.Quote = &quoteImpl{}
// Computes an effective spread factor from all routes.
//
// Returns the updated route and the effective spread factor.
func (q *quoteImpl) PrepareResult(ctx context.Context, scalingFactor osmomath.Dec) ([]domain.SplitRoute, osmomath.Dec) {
func (q *quoteImpl) PrepareResult(ctx context.Context, scalingFactor osmomath.Dec) ([]domain.SplitRoute, osmomath.Dec, error) {
totalAmountIn := q.AmountIn.Amount.ToLegacyDec()
totalFeeAcrossRoutes := osmomath.ZeroDec()

Expand Down Expand Up @@ -67,7 +67,7 @@ func (q *quoteImpl) PrepareResult(ctx context.Context, scalingFactor osmomath.De

newPools, routeSpotPriceInOverOut, effectiveSpotPriceInOverOut, err := curRoute.PrepareResultPools(ctx, q.AmountIn)
if err != nil {
panic(err)
return nil, osmomath.Dec{}, err
}

totalSpotPriceInOverOut = totalSpotPriceInOverOut.AddMut(routeSpotPriceInOverOut.MulMut(routeAmountInFraction))
Expand All @@ -92,7 +92,7 @@ func (q *quoteImpl) PrepareResult(ctx context.Context, scalingFactor osmomath.De
q.Route = resultRoutes
q.InOutSpotPrice = totalSpotPriceInOverOut.Mul(scalingFactor)

return q.Route, q.EffectiveFee
return q.Route, q.EffectiveFee, nil
}

// GetAmountIn implements Quote.
Expand Down
3 changes: 2 additions & 1 deletion router/usecase/quote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ func (s *RouterTestSuite) TestPrepareResult() {
expectedEffectiveSpreadFactor := expectedRouteOneFee.Add(expectedRouteTwoFee)

// System under test
routes, effectiveSpreadFactor := testQuote.PrepareResult(context.TODO(), defaultSpotPriceScalingFactor)
routes, effectiveSpreadFactor, err := testQuote.PrepareResult(context.TODO(), defaultSpotPriceScalingFactor)
s.Require().NoError(err)

// Validate routes.
s.validateRoutes(expectedRoutes, routes)
Expand Down
32 changes: 28 additions & 4 deletions router/usecase/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package usecase
import (
"sort"

cosmwasmpooltypes "github.com/osmosis-labs/osmosis/v23/x/cosmwasmpool/types"
"github.com/osmosis-labs/sqs/domain"
"github.com/osmosis-labs/sqs/sqsdomain"
routerredisrepo "github.com/osmosis-labs/sqs/sqsdomain/repository/redis/router"
Expand All @@ -18,7 +19,8 @@ import (
type Router struct {
sortedPools []sqsdomain.PoolI

config domain.RouterConfig
config domain.RouterConfig
cosmWasmPoolConfig domain.CosmWasmPoolRouterConfig

routerRepository routerredisrepo.RouterRepository

Expand Down Expand Up @@ -48,14 +50,15 @@ const (
// Each pool has a flag indicating whether there was an error in estimating its on-chain TVL.
// If that is the case, the pool is to be sorted towards the end. However, the preferredPoolIDs overwrites this rule
// and prioritizes the preferred pools.
func NewRouter(config domain.RouterConfig, logger log.Logger) *Router {
func NewRouter(config domain.RouterConfig, cosmWasmPoolConfig domain.CosmWasmPoolRouterConfig, logger log.Logger) *Router {
if logger == nil {
logger = &log.NoOpLogger{}
}

return &Router{
config: config,
logger: logger,
config: config,
cosmWasmPoolConfig: cosmWasmPoolConfig,
logger: logger,
}
}

Expand All @@ -64,6 +67,11 @@ func (r Router) GetConfig() domain.RouterConfig {
return r.config
}

// GetConfig returns the router config.
func (r Router) GetCosmWasmPoolConfig() domain.CosmWasmPoolRouterConfig {
return r.cosmWasmPoolConfig
}

// GetMaxHops returns the maximum number of hops configured.
func (r Router) GetMaxHops() int {
return r.config.MaxPoolsPerRoute
Expand Down Expand Up @@ -102,6 +110,22 @@ func WithSortedPools(router *Router, allPools []sqsdomain.PoolI) *Router {
continue
}

// Confirm that a cosmwasm code ID is whitelisted via config.
if pool.GetType() == poolmanagertypes.CosmWasm {
cosmWasmPool, ok := pool.GetUnderlyingPool().(cosmwasmpooltypes.CosmWasmExtension)
if !ok {
router.logger.Debug("failed to cast a cosm wasm pool, skip silently", zap.Uint64("pool_id", pool.GetId()))
continue
}

_, isGeneralCosmWasmCodeID := router.cosmWasmPoolConfig.GeneralCosmWasmCodeIDs[cosmWasmPool.GetCodeId()]
_, isTransmuterCodeID := router.cosmWasmPoolConfig.TransmuterCodeIDs[cosmWasmPool.GetCodeId()]
if !(isGeneralCosmWasmCodeID || isTransmuterCodeID) {
router.logger.Debug("cw pool code id is enot added to config, skip silently", zap.Uint64("pool_id", pool.GetId()))
continue
}
}

router.sortedPools = append(router.sortedPools, pool)

totalTVL = totalTVL.Add(pool.GetTotalValueLockedUOSMO())
Expand Down
8 changes: 8 additions & 0 deletions router/usecase/router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ var (
}

noTakerFee = osmomath.ZeroDec()

emptyCosmWasmPoolsRouterConfig = routertesting.EmpyCosmWasmPoolRouterConfig
)

// This test validates a happy path expected behavior that
Expand Down Expand Up @@ -192,6 +194,12 @@ func (s *RouterTestSuite) TestNewRouter() {
MaxSplitRoutes: maxSplitRoutes,
MaxSplitIterations: maxSplitIterations,
MinOSMOLiquidity: minOsmoLiquidity,
}, domain.CosmWasmPoolRouterConfig{
TransmuterCodeIDs: map[uint64]struct{}{
1: {},
},
GeneralCosmWasmCodeIDs: map[uint64]struct{}{},
NodeURI: "",
}, logger)
router = routerusecase.WithSortedPools(router, defaultAllPools)

Expand Down
28 changes: 15 additions & 13 deletions router/usecase/router_usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ import (
var _ mvc.RouterUsecase = &routerUseCaseImpl{}

type routerUseCaseImpl struct {
contextTimeout time.Duration
routerRepository routerredisrepo.RouterRepository
poolsUsecase mvc.PoolsUsecase
config domain.RouterConfig
logger log.Logger
contextTimeout time.Duration
routerRepository routerredisrepo.RouterRepository
poolsUsecase mvc.PoolsUsecase
config domain.RouterConfig
cosmWasmPoolsConfig domain.CosmWasmPoolRouterConfig
logger log.Logger

rankedRouteCache *cache.Cache
candidateRouteCache *cache.Cache
Expand Down Expand Up @@ -82,13 +83,14 @@ func init() {
}

// NewRouterUsecase will create a new pools use case object
func NewRouterUsecase(timeout time.Duration, routerRepository routerredisrepo.RouterRepository, poolsUsecase mvc.PoolsUsecase, config domain.RouterConfig, logger log.Logger, rankedRouteCache *cache.Cache, candidateRouteCache *cache.Cache) mvc.RouterUsecase {
func NewRouterUsecase(timeout time.Duration, routerRepository routerredisrepo.RouterRepository, poolsUsecase mvc.PoolsUsecase, config domain.RouterConfig, cosmWasmPoolsConfig domain.CosmWasmPoolRouterConfig, logger log.Logger, rankedRouteCache *cache.Cache, candidateRouteCache *cache.Cache) mvc.RouterUsecase {
return &routerUseCaseImpl{
contextTimeout: timeout,
routerRepository: routerRepository,
poolsUsecase: poolsUsecase,
config: config,
logger: logger,
contextTimeout: timeout,
routerRepository: routerRepository,
poolsUsecase: poolsUsecase,
config: config,
cosmWasmPoolsConfig: cosmWasmPoolsConfig,
logger: logger,

rankedRouteCache: rankedRouteCache,
candidateRouteCache: candidateRouteCache,
Expand Down Expand Up @@ -607,15 +609,15 @@ func (r *routerUseCaseImpl) GetConfig() domain.RouterConfig {
// - there is an error retrieving taker fees from the store
// TODO: test
func (r *routerUseCaseImpl) initializeDefaultRouter() *Router {
router := NewRouter(r.config, r.logger)
router := NewRouter(r.config, r.cosmWasmPoolsConfig, r.logger)
router = WithRouterRepository(router, r.routerRepository)
router = WithPoolsUsecase(router, r.poolsUsecase)

return router
}

func (r *routerUseCaseImpl) initializeRouter(config domain.RouterConfig) *Router {
router := NewRouter(config, r.logger)
router := NewRouter(config, r.cosmWasmPoolsConfig, r.logger)
router = WithRouterRepository(router, r.routerRepository)
router = WithPoolsUsecase(router, r.poolsUsecase)

Expand Down
4 changes: 2 additions & 2 deletions router/usecase/router_usecase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,13 @@ func (s *RouterTestSuite) TestHandleRoutes() {

routerUseCase := usecase.NewRouterUsecase(defaultTimeoutDuration, routerRepositoryMock, poolsUseCaseMock, domain.RouterConfig{
RouteCacheEnabled: !tc.isCacheDisabled,
}, &log.NoOpLogger{}, cache.New(), candidateRouteCache)
}, emptyCosmWasmPoolsRouterConfig, &log.NoOpLogger{}, cache.New(), candidateRouteCache)

routerUseCaseImpl, ok := routerUseCase.(*usecase.RouterUseCaseImpl)
s.Require().True(ok)

// Initialize router
router := usecase.NewRouter(defaultRouterConfig, &log.NoOpLogger{})
router := usecase.NewRouter(defaultRouterConfig, emptyCosmWasmPoolsRouterConfig, &log.NoOpLogger{})
router = usecase.WithSortedPools(router, poolsUseCaseMock.Pools)

// System under test
Expand Down
11 changes: 8 additions & 3 deletions router/usecase/routertesting/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,12 @@ var (
TakerFee: DefaultTakerFee,
SpreadFactor: DefaultSpreadFactor,
}
EmptyRoute = route.RouteImpl{}
EmptyRoute = route.RouteImpl{}
EmpyCosmWasmPoolRouterConfig = domain.CosmWasmPoolRouterConfig{
TransmuterCodeIDs: map[uint64]struct{}{},
GeneralCosmWasmCodeIDs: map[uint64]struct{}{},
NodeURI: "",
}

// Test denoms
DenomOne = denomNum(1)
Expand Down Expand Up @@ -264,7 +269,7 @@ func (s *RouterTestHelper) SetupMainnetRouter(config domain.RouterConfig) (*rout
// N.B. uncomment if logs are needed.
// logger, err := log.NewLogger(false, "", "info")
// s.Require().NoError(err)
router := routerusecase.NewRouter(config, &log.NoOpLogger{})
router := routerusecase.NewRouter(config, EmpyCosmWasmPoolRouterConfig, &log.NoOpLogger{})
router = routerusecase.WithSortedPools(router, pools)

return router, MockMainnetState{
Expand All @@ -291,7 +296,7 @@ func (s *RouterTestHelper) SetupRouterAndPoolsUsecase(router *routerusecase.Rout
poolsUsecase := poolsusecase.NewPoolsUsecase(time.Hour, &poolsRepositoryMock, nil, &DefaultPoolsConfig, "node-uri-placeholder")
routerusecase.WithPoolsUsecase(router, poolsUsecase)

routerUsecase := routerusecase.NewRouterUsecase(time.Hour, &routerRepositoryMock, poolsUsecase, router.GetConfig(), &log.NoOpLogger{}, rankedRoutesCache, candidateRouteCache)
routerUsecase := routerusecase.NewRouterUsecase(time.Hour, &routerRepositoryMock, poolsUsecase, router.GetConfig(), router.GetCosmWasmPoolConfig(), &log.NoOpLogger{}, rankedRoutesCache, candidateRouteCache)

tokensUsecase := tokensusecase.NewTokensUsecase(time.Hour, mainnetState.TokensMetadata)

Expand Down

0 comments on commit 6cf9b43

Please sign in to comment.