Skip to content

Commit

Permalink
simplfy router endpoint results
Browse files Browse the repository at this point in the history
  • Loading branch information
p0mvn committed Nov 8, 2023
1 parent 38a462c commit 3d9358e
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 53 deletions.
9 changes: 9 additions & 0 deletions ingest/sqs/domain/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ type Route interface {

GetTokenOutDenom() string

// PrepareResultPools strips away unnecessary fields
// from each pool in the route,
// leaving only the data needed by client
// Note that it mutates the route.
// Returns the resulting pools.
PrepareResultPools() []RoutablePool

String() string
}

Expand Down Expand Up @@ -57,6 +64,8 @@ type Quote interface {
GetAmountIn() sdk.Coin
GetAmountOut() osmomath.Int
GetRoute() []SplitRoute

PrepareResultRoutes()
}

type RouterConfig struct {
Expand Down
25 changes: 21 additions & 4 deletions ingest/sqs/router/usecase/optimized_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ type quoteImpl struct {
Route []domain.SplitRoute "json:\"route\""
}

// PrepareResultRoutes implements domain.Quote.
func (q *quoteImpl) PrepareResultRoutes() {
for _, route := range q.Route {
route.PrepareResultPools()
}
}

// GetAmountIn implements Quote.
func (q *quoteImpl) GetAmountIn() sdk.Coin {
return q.AmountIn
Expand Down Expand Up @@ -126,11 +133,16 @@ func (r *Router) estimateBestSingleRouteQuote(routes []domain.Route, tokenIn sdk
return nil, errors.New("did not find a working direct route")
}

return &quoteImpl{
finalQuote := &quoteImpl{
AmountIn: tokenIn,
AmountOut: bestRoute.OutAmount,
Route: []domain.SplitRoute{bestRoute},
}, nil
}

// Prepare result for return to client.
finalQuote.PrepareResultRoutes()

return finalQuote, nil
}

// CONTRACT: all routes are valid. Must be validated by the caller with validateRoutes method.
Expand All @@ -150,11 +162,16 @@ func (r *Router) estimateBestSplitRouteQuote(routes []domain.Route, tokenIn sdk.

r.logger.Debug("bestSplit", zap.Any("value", bestSplit))

return &quoteImpl{
finalQuote := &quoteImpl{
AmountIn: tokenIn,
AmountOut: bestSplit.CurrentTotalOut,
Route: bestSplit.Routes,
}, nil
}

// Prepare result for return to client.
finalQuote.PrepareResultRoutes()

return finalQuote, nil
}

// validateAndFilterRoutes validates all routes. Specifically:
Expand Down
99 changes: 99 additions & 0 deletions ingest/sqs/router/usecase/routable_cfmm_pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package usecase

import (
"fmt"
"reflect"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/osmosis-labs/osmosis/osmomath"
"github.com/osmosis-labs/osmosis/v20/ingest/sqs/domain"
"github.com/osmosis-labs/osmosis/v20/x/poolmanager"

gammtypes "github.com/osmosis-labs/osmosis/v20/x/gamm/types"
poolmanagertypes "github.com/osmosis-labs/osmosis/v20/x/poolmanager/types"
)

var _ domain.RoutablePool = &routableCFMMPoolImpl{}

type routableCFMMPoolImpl struct {
domain.PoolI
TokenOutDenom string "json:\"token_out_denom\""
TakerFee osmomath.Dec "json:\"taker_fee\""
}

// NewRoutablePool creates a new RoutablePool.
func NewRoutablePool(pool domain.PoolI, tokenOutDenom string, takerFee osmomath.Dec) domain.RoutablePool {
if pool.GetType() == poolmanagertypes.Concentrated {
return &routableConcentratedPoolImpl{
PoolI: pool,
TokenOutDenom: tokenOutDenom,
TakerFee: takerFee,
}
}

if pool.GetType() == poolmanagertypes.CosmWasm {
return &routableTransmuterPoolImpl{
PoolI: pool,
TokenOutDenom: tokenOutDenom,
TakerFee: takerFee,
}
}

return &routableCFMMPoolImpl{
PoolI: pool,
TokenOutDenom: tokenOutDenom,
TakerFee: takerFee,
}
}

// CalculateTokenOutByTokenIn implements RoutablePool.
func (r *routableCFMMPoolImpl) CalculateTokenOutByTokenIn(tokenIn sdk.Coin) (sdk.Coin, error) {
poolType := r.GetType()

if poolType != poolmanagertypes.Balancer && poolType != poolmanagertypes.Stableswap {
return sdk.Coin{}, domain.InvalidPoolTypeError{PoolType: int32(poolType)}
}

osmosisPool := r.PoolI.GetUnderlyingPool()

// Cast to CFMM extension
cfmmPool, ok := osmosisPool.(gammtypes.CFMMPoolI)
if !ok {
return sdk.Coin{}, FailedToCastPoolModelError{
ExpectedModel: reflect.TypeOf((gammtypes.CFMMPoolI)(nil)).Elem().Name(),
ActualModel: reflect.TypeOf(r).Elem().Name(),
}
}

// TODO: remove context from interface as it is unusded
tokenOut, err := cfmmPool.CalcOutAmtGivenIn(sdk.Context{}, sdk.NewCoins(tokenIn), r.TokenOutDenom, cfmmPool.GetSpreadFactor(sdk.Context{}))
if err != nil {
return sdk.Coin{}, err
}

return tokenOut, nil
}

// GetTokenOutDenom implements RoutablePool.
func (rp *routableCFMMPoolImpl) GetTokenOutDenom() string {
return rp.TokenOutDenom
}

// String implements domain.RoutablePool.
func (r *routableCFMMPoolImpl) String() string {
return fmt.Sprintf("pool (%d), pool type (%d), pool denoms (%v)", r.PoolI.GetId(), r.PoolI.GetType(), r.PoolI.GetPoolDenoms())
}

// ChargeTakerFee implements domain.RoutablePool.
// Charges the taker fee for the given token in and returns the token in after the fee has been charged.
func (r *routableCFMMPoolImpl) ChargeTakerFeeExactIn(tokenIn sdk.Coin) (tokenInAfterFee sdk.Coin) {
tokenInAfterTakerFee, _ := poolmanager.CalcTakerFeeExactIn(tokenIn, r.TakerFee)
return tokenInAfterTakerFee
}

// GetTakerFee implements domain.RoutablePool.
func (r *routableCFMMPoolImpl) GetTakerFee() math.LegacyDec {
return r.TakerFee
}
100 changes: 51 additions & 49 deletions ingest/sqs/router/usecase/routable_pool.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package usecase

import (
"errors"
"fmt"
"reflect"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -11,89 +11,91 @@ import (
"github.com/osmosis-labs/osmosis/v20/ingest/sqs/domain"
"github.com/osmosis-labs/osmosis/v20/x/poolmanager"

gammtypes "github.com/osmosis-labs/osmosis/v20/x/gamm/types"
poolmanagertypes "github.com/osmosis-labs/osmosis/v20/x/poolmanager/types"
)

var _ domain.RoutablePool = &routableCFMMPoolImpl{}

type routableCFMMPoolImpl struct {
domain.PoolI
type routablePoolImpl struct {
ID uint64
Type poolmanagertypes.PoolType
Balances sdk.Coins
SpreadFactor osmomath.Dec
TokenOutDenom string "json:\"token_out_denom\""
TakerFee osmomath.Dec "json:\"taker_fee\""
}

// NewRoutablePool creates a new RoutablePool.
func NewRoutablePool(pool domain.PoolI, tokenOutDenom string, takerFee osmomath.Dec) domain.RoutablePool {
if pool.GetType() == poolmanagertypes.Concentrated {
return &routableConcentratedPoolImpl{
PoolI: pool,
TokenOutDenom: tokenOutDenom,
TakerFee: takerFee,
}
}
// GetId implements domain.RoutablePool.
func (r *routablePoolImpl) GetId() uint64 {
return r.ID
}

if pool.GetType() == poolmanagertypes.CosmWasm {
return &routableTransmuterPoolImpl{
PoolI: pool,
TokenOutDenom: tokenOutDenom,
TakerFee: takerFee,
}
// GetPoolDenoms implements domain.RoutablePool.
func (r *routablePoolImpl) GetPoolDenoms() []string {
denoms := make([]string, len(r.Balances))
for _, balance := range r.Balances {
denoms = append(denoms, balance.Denom)
}

return &routableCFMMPoolImpl{
PoolI: pool,
TokenOutDenom: tokenOutDenom,
TakerFee: takerFee,
return denoms
}

// GetSQSPoolModel implements domain.RoutablePool.
func (r *routablePoolImpl) GetSQSPoolModel() domain.SQSPool {
return domain.SQSPool{
Balances: r.Balances,
PoolDenoms: r.GetPoolDenoms(),
}
}

// CalculateTokenOutByTokenIn implements RoutablePool.
func (r *routableCFMMPoolImpl) CalculateTokenOutByTokenIn(tokenIn sdk.Coin) (sdk.Coin, error) {
poolType := r.GetType()
// GetTickModel implements domain.RoutablePool.
func (r *routablePoolImpl) GetTickModel() (*domain.TickModel, error) {
return nil, errors.New("not implemented")
}

if poolType != poolmanagertypes.Balancer && poolType != poolmanagertypes.Stableswap {
return sdk.Coin{}, domain.InvalidPoolTypeError{PoolType: int32(poolType)}
}
// GetTotalValueLockedUOSMO implements domain.RoutablePool.
func (*routablePoolImpl) GetTotalValueLockedUOSMO() math.Int {
return osmomath.Int{}
}

osmosisPool := r.PoolI.GetUnderlyingPool()
// GetType implements domain.RoutablePool.
func (r *routablePoolImpl) GetType() poolmanagertypes.PoolType {
return r.Type
}

// Cast to CFMM extension
cfmmPool, ok := osmosisPool.(gammtypes.CFMMPoolI)
if !ok {
return sdk.Coin{}, FailedToCastPoolModelError{
ExpectedModel: reflect.TypeOf((gammtypes.CFMMPoolI)(nil)).Elem().Name(),
ActualModel: reflect.TypeOf(r).Elem().Name(),
}
}
// GetUnderlyingPool implements domain.RoutablePool.
func (*routablePoolImpl) GetUnderlyingPool() poolmanagertypes.PoolI {
return nil
}

// TODO: remove context from interface as it is unusded
tokenOut, err := cfmmPool.CalcOutAmtGivenIn(sdk.Context{}, sdk.NewCoins(tokenIn), r.TokenOutDenom, cfmmPool.GetSpreadFactor(sdk.Context{}))
if err != nil {
return sdk.Coin{}, err
}
// Validate implements domain.RoutablePool.
func (*routablePoolImpl) Validate(minUOSMOTVL math.Int) error {
return nil
}

return tokenOut, nil
// CalculateTokenOutByTokenIn implements RoutablePool.
func (r *routablePoolImpl) CalculateTokenOutByTokenIn(tokenIn sdk.Coin) (sdk.Coin, error) {
return sdk.Coin{}, errors.New("not implemented")
}

// GetTokenOutDenom implements RoutablePool.
func (rp *routableCFMMPoolImpl) GetTokenOutDenom() string {
func (rp *routablePoolImpl) GetTokenOutDenom() string {
return rp.TokenOutDenom
}

// String implements domain.RoutablePool.
func (r *routableCFMMPoolImpl) String() string {
return fmt.Sprintf("pool (%d), pool type (%d), pool denoms (%v)", r.PoolI.GetId(), r.PoolI.GetType(), r.PoolI.GetPoolDenoms())
func (r *routablePoolImpl) String() string {
return fmt.Sprintf("pool (%d), pool type (%d), pool denoms (%v)", r.GetId(), r.GetType(), r.GetPoolDenoms())
}

// ChargeTakerFee implements domain.RoutablePool.
// Charges the taker fee for the given token in and returns the token in after the fee has been charged.
func (r *routableCFMMPoolImpl) ChargeTakerFeeExactIn(tokenIn sdk.Coin) (tokenInAfterFee sdk.Coin) {
func (r *routablePoolImpl) ChargeTakerFeeExactIn(tokenIn sdk.Coin) (tokenInAfterFee sdk.Coin) {
tokenInAfterTakerFee, _ := poolmanager.CalcTakerFeeExactIn(tokenIn, r.TakerFee)
return tokenInAfterTakerFee
}

// GetTakerFee implements domain.RoutablePool.
func (r *routableCFMMPoolImpl) GetTakerFee() math.LegacyDec {
func (r *routablePoolImpl) GetTakerFee() math.LegacyDec {
return r.TakerFee
}
24 changes: 24 additions & 0 deletions ingest/sqs/router/usecase/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,30 @@ type routeImpl struct {
Pools []domain.RoutablePool
}

// Result implements domain.Route.
// Strips away unnecessary fields from each pool in the route,
// leaving only the data needed by client
// Note that it mutates the route.
// Returns the resulting pools.
func (r *routeImpl) PrepareResultPools() []domain.RoutablePool {
newPools := make([]domain.RoutablePool, len(r.Pools))

for _, pool := range r.Pools {
newPools = append(newPools, &routablePoolImpl{
ID: pool.GetId(),
Type: pool.GetType(),
Balances: pool.GetSQSPoolModel().Balances,
SpreadFactor: pool.GetUnderlyingPool().GetSpreadFactor(sdk.Context{}),
TokenOutDenom: pool.GetTokenOutDenom(),
TakerFee: pool.GetTakerFee(),
})
}

r.Pools = newPools

return newPools
}

// GetPools implements Route.
func (r *routeImpl) GetPools() []domain.RoutablePool {
return r.Pools
Expand Down

0 comments on commit 3d9358e

Please sign in to comment.