Skip to content

Commit

Permalink
format results per FE requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
p0mvn committed Nov 9, 2023
1 parent 38a462c commit 02cd400
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 11 deletions.
5 changes: 3 additions & 2 deletions ingest/sqs/domain/pools.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ type SQSPool struct {
TotalValueLockedUSDC osmomath.Int `json:"total_value_locked_uosmo"`
TotalValueLockedError string `json:"total_value_locked_error,omitempty"`
// Only CL and Cosmwasm pools need balances appended
Balances sdk.Coins `json:"balances,string"`
PoolDenoms []string `json:"pool_denoms"`
Balances sdk.Coins `json:"balances,string"`
PoolDenoms []string `json:"pool_denoms"`
SpreadFactor osmomath.Dec `json:"spread_factor"`
}

type LiquidityDepthsWithRange = clqueryproto.LiquidityDepthWithRange
Expand Down
11 changes: 11 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,10 @@ type Quote interface {
GetAmountIn() sdk.Coin
GetAmountOut() osmomath.Int
GetRoute() []SplitRoute

// PrepareResult mutates the quote to prepare
// it with the data formatted for output to the client.
PrepareResult()
}

type RouterConfig struct {
Expand Down
5 changes: 4 additions & 1 deletion ingest/sqs/pools/ingester/redis/pool_ingester.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ func (pi *poolIngester) convertPool(
poolDenomsMap[poolDenom] = struct{}{}
}

// Note that this must follow the call to GetPoolDenoms()
spreadFactor := pool.GetSpreadFactor(ctx)

// Note that this must follow the call to GetPoolDenoms() and GetSpreadFactor.
// Otherwise, the CosmWasmPool model panics.
pool = pool.AsSerializablePool()

Expand Down Expand Up @@ -311,6 +313,7 @@ func (pi *poolIngester) convertPool(
TotalValueLockedError: errorInTVLStr,
Balances: balances,
PoolDenoms: denoms,
SpreadFactor: spreadFactor,
},
TickModel: tickModel,
}, nil
Expand Down
2 changes: 2 additions & 0 deletions ingest/sqs/router/delivery/http/router_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ func (a *RouterHandler) GetOptimalQuote(c echo.Context) error {
return c.JSON(getStatusCode(err), ResponseError{Message: err.Error()})
}

quote.PrepareResult()

return c.JSON(http.StatusOK, quote)
}

Expand Down
7 changes: 7 additions & 0 deletions ingest/sqs/router/usecase/candidate_routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type mockPool struct {
poolType poolmanagertypes.PoolType
tokenOutDenom string
takerFee osmomath.Dec
spreadFactor osmomath.Dec
}

var (
Expand All @@ -39,6 +40,7 @@ func (mp *mockPool) GetSQSPoolModel() domain.SQSPool {
return domain.SQSPool{
Balances: mp.Balances,
TotalValueLockedUSDC: mp.totalValueLockedUSDC,
SpreadFactor: defaultSpreadFactor,
}
}

Expand Down Expand Up @@ -108,6 +110,8 @@ func deepCopyPool(mp *mockPool) *mockPool {

newTotalValueLocker := osmomath.NewIntFromBigInt(mp.totalValueLockedUSDC.BigInt())

newBalances := sdk.NewCoins(mp.Balances...)

return &mockPool{
ID: mp.ID,
denoms: newDenoms,
Expand All @@ -117,6 +121,9 @@ func deepCopyPool(mp *mockPool) *mockPool {
// Note these are not deep copied.
ChainPoolModel: mp.ChainPoolModel,
tokenOutDenom: mp.tokenOutDenom,
Balances: newBalances,
takerFee: mp.takerFee.Clone(),
spreadFactor: mp.spreadFactor.Clone(),
}
}

Expand Down
1 change: 1 addition & 0 deletions ingest/sqs/router/usecase/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type (
RoutableCFMMPoolImpl = routableCFMMPoolImpl
RoutableConcentratedPoolImpl = routableConcentratedPoolImpl
RoutableTransmuterPoolImpl = routableTransmuterPoolImpl
RoutableResultPoolImpl = routableResultPoolImpl
)

const (
Expand Down
54 changes: 47 additions & 7 deletions ingest/sqs/router/usecase/optimized_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,45 @@ import (
)

type quoteImpl struct {
AmountIn sdk.Coin "json:\"amount_in\""
AmountOut osmomath.Int "json:\"amount_out\""
Route []domain.SplitRoute "json:\"route\""
AmountIn sdk.Coin "json:\"amount_in\""
AmountOut osmomath.Int "json:\"amount_out\""
Route []domain.SplitRoute "json:\"route\""
EffectiveSpreadFactor osmomath.Dec "json:\"effective_spread_factor\""
}

var _ domain.Quote = &quoteImpl{}

// PrepareResult implements domain.Quote.
// PrepareResult mutates the quote to prepare
// it with the data formatted for output to the client.
// Specifically:
// It strips away unnecessary fields from each pool in the route.
// Computes an effective spread factor from all routes.
func (q *quoteImpl) PrepareResult() {

totalAmountIn := q.AmountIn.Amount.ToLegacyDec()
totalSpreadFactorAcrossRoutes := osmomath.ZeroDec()

for _, route := range q.Route {

routeSpreadFactor := osmomath.ZeroDec()
routeAmountInFraction := route.GetAmountIn().ToLegacyDec().Quo(totalAmountIn)

// Calculate the spread factor across pools in the route
for _, pool := range route.GetPools() {
spreadFactor := pool.GetSQSPoolModel().SpreadFactor

routeSpreadFactor = routeSpreadFactor.AddMut(
osmomath.OneDec().SubMut(routeSpreadFactor).MulTruncateMut(spreadFactor),
)
}

totalSpreadFactorAcrossRoutes = totalSpreadFactorAcrossRoutes.AddMut(routeSpreadFactor.MulMut(routeAmountInFraction))

route.PrepareResultPools()
}

q.EffectiveSpreadFactor = totalSpreadFactorAcrossRoutes
}

// GetAmountIn implements Quote.
Expand Down Expand Up @@ -126,11 +162,13 @@ 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
}

return finalQuote, nil
}

// CONTRACT: all routes are valid. Must be validated by the caller with validateRoutes method.
Expand All @@ -150,11 +188,13 @@ 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
}

return finalQuote, nil
}

// validateAndFilterRoutes validates all routes. Specifically:
Expand Down
10 changes: 10 additions & 0 deletions ingest/sqs/router/usecase/optimized_routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,21 @@ const defaultPoolID = uint64(1)

// TODO: copy exists in candidate_routes_test.go - share & reuse
var (
defaultTakerFee = osmomath.MustNewDecFromStr("0.002")
defaultPoolBalances = sdk.NewCoins(
sdk.NewCoin(denomOne, DefaultAmt0),
sdk.NewCoin(denomTwo, DefaultAmt1),
)
defaultSpreadFactor = osmomath.MustNewDecFromStr("0.005")

defaultPool = &mockPool{
ID: defaultPoolID,
denoms: []string{denomOne, denomTwo},
totalValueLockedUSDC: osmomath.NewInt(10),
poolType: poolmanagertypes.Balancer,
Balances: defaultPoolBalances,
takerFee: defaultTakerFee,
spreadFactor: defaultSpreadFactor,
}
emptyRoute = &routerusecase.RouteImpl{}

Expand Down
File renamed without changes.
104 changes: 104 additions & 0 deletions ingest/sqs/router/usecase/routable_result_pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package usecase

import (
"errors"
"fmt"

"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"

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

var _ domain.RoutablePool = &routableCFMMPoolImpl{}

// routableResultPoolImpl is a generalized implementation that is returned to the client
// side in quotes. It contains all the relevant pool data needed for Osmosis frontend
type routableResultPoolImpl struct {
ID uint64 "json:\"id\""
Type poolmanagertypes.PoolType "json:\"type\""
Balances sdk.Coins "json:\"balances\""
SpreadFactor osmomath.Dec "json:\"spread_factor\""
TokenOutDenom string "json:\"token_out_denom\""
TakerFee osmomath.Dec "json:\"taker_fee\""
}

// GetId implements domain.RoutablePool.
func (r *routableResultPoolImpl) GetId() uint64 {
return r.ID
}

// GetPoolDenoms implements domain.RoutablePool.
func (r *routableResultPoolImpl) GetPoolDenoms() []string {
denoms := make([]string, len(r.Balances))
for _, balance := range r.Balances {
denoms = append(denoms, balance.Denom)
}

return denoms
}

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

// GetTickModel implements domain.RoutablePool.
func (r *routableResultPoolImpl) GetTickModel() (*domain.TickModel, error) {
return nil, errors.New("not implemented")
}

// GetTotalValueLockedUOSMO implements domain.RoutablePool.
func (*routableResultPoolImpl) GetTotalValueLockedUOSMO() math.Int {
return osmomath.Int{}
}

// GetType implements domain.RoutablePool.
func (r *routableResultPoolImpl) GetType() poolmanagertypes.PoolType {
return r.Type
}

// GetUnderlyingPool implements domain.RoutablePool.
func (*routableResultPoolImpl) GetUnderlyingPool() poolmanagertypes.PoolI {
return nil
}

// Validate implements domain.RoutablePool.
func (*routableResultPoolImpl) Validate(minUOSMOTVL math.Int) error {
return nil
}

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

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

// String implements domain.RoutablePool.
func (r *routableResultPoolImpl) 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 *routableResultPoolImpl) ChargeTakerFeeExactIn(tokenIn sdk.Coin) (tokenInAfterFee sdk.Coin) {
tokenInAfterTakerFee, _ := poolmanager.CalcTakerFeeExactIn(tokenIn, r.TakerFee)
return tokenInAfterTakerFee
}

// GetTakerFee implements domain.RoutablePool.
func (r *routableResultPoolImpl) GetTakerFee() math.LegacyDec {
return r.TakerFee
}
34 changes: 33 additions & 1 deletion ingest/sqs/router/usecase/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,39 @@ import (
var _ domain.Route = &routeImpl{}

type routeImpl struct {
Pools []domain.RoutablePool
Pools []domain.RoutablePool "json:\"pools\""
}

// PrepareResultPools implements domain.Route.
// Strips away unnecessary fields from each pool in the route,
// leaving only the data needed by client
// The following are the list of fields that are returned to the client in each pool:
// - ID
// - Type
// - Balances
// - Spread Factor
// - Token Out Denom
// - Taker Fee
// Note that it mutates the route.
// Returns the resulting pools.
func (r *routeImpl) PrepareResultPools() []domain.RoutablePool {
for i, pool := range r.Pools {

sqsModel := pool.GetSQSPoolModel()

r.Pools[i] = &routableResultPoolImpl{
ID: pool.GetId(),
Type: pool.GetType(),
Balances: sqsModel.Balances,
// Note that we cannot get the SpreadFactor method on
// the CosmWasm pool models as it does not implement it.
// As a result, we propagate it via SQS model.
SpreadFactor: sqsModel.SpreadFactor,
TokenOutDenom: pool.GetTokenOutDenom(),
TakerFee: pool.GetTakerFee(),
}
}
return r.Pools
}

// GetPools implements Route.
Expand Down
Loading

0 comments on commit 02cd400

Please sign in to comment.