Skip to content

Commit

Permalink
BE-675 | InGivenOut APIs for balancer, stableswap, transmuter pools (#…
Browse files Browse the repository at this point in the history
…603)

* BE-675 | InGivenOut APIs for balancer, stableswap, transmuter pools
  • Loading branch information
deividaspetraitis authored Jan 21, 2025
1 parent e083e06 commit f4e918c
Show file tree
Hide file tree
Showing 23 changed files with 641 additions and 94 deletions.
39 changes: 35 additions & 4 deletions domain/mocks/pool_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

type MockRoutablePool struct {
CalculateTokenOutByTokenInFunc func(ctx context.Context, tokenIn sdk.Coin) (sdk.Coin, error)
CalculateTokenInByTokenOutFunc func(ctx context.Context, tokenOut sdk.Coin) (sdk.Coin, error)

ChainPoolModel poolmanagertypes.PoolI
TickModel *ingesttypes.TickModel
Expand All @@ -33,6 +34,7 @@ type MockRoutablePool struct {
TakerFee osmomath.Dec
SpreadFactor osmomath.Dec
mockedTokenOut sdk.Coin
mockedTokenIn sdk.Coin
IncentiveType api.IncentiveType

APRData sqspassthroughdomain.PoolAPRDataStatusWrap
Expand Down Expand Up @@ -68,7 +70,7 @@ func (mp *MockRoutablePool) CalcSpotPrice(ctx context.Context, baseDenom string,
return osmomath.OneBigDec(), nil
}

spotPrice, err := mp.ChainPoolModel.SpotPrice(sdk.Context{}, quoteDenom, baseDenom)
spotPrice, err := mp.ChainPoolModel.SpotPrice(sdk.Context{}.WithContext(ctx), quoteDenom, baseDenom)
if err != nil {
return osmomath.BigDec{}, err
}
Expand Down Expand Up @@ -109,9 +111,9 @@ func (mp *MockRoutablePool) GetSQSPoolModel() ingesttypes.SQSPool {
}

// CalculateTokenOutByTokenIn implements routerusecase.RoutablePool.
func (mp *MockRoutablePool) CalculateTokenOutByTokenIn(_ctx context.Context, tokenIn sdk.Coin) (sdk.Coin, error) {
func (mp *MockRoutablePool) CalculateTokenOutByTokenIn(ctx context.Context, tokenIn sdk.Coin) (sdk.Coin, error) {
if mp.CalculateTokenOutByTokenInFunc != nil {
return mp.CalculateTokenOutByTokenInFunc(_ctx, tokenIn)
return mp.CalculateTokenOutByTokenInFunc(ctx, tokenIn)
}

// We allow the ability to mock out the token out amount.
Expand All @@ -129,7 +131,31 @@ func (mp *MockRoutablePool) CalculateTokenOutByTokenIn(_ctx context.Context, tok
panic("not a balancer pool")
}

return balancerPool.CalcOutAmtGivenIn(sdk.Context{}, sdk.NewCoins(tokenIn), mp.TokenOutDenom, mp.SpreadFactor)
return balancerPool.CalcOutAmtGivenIn(sdk.Context{}.WithContext(ctx), sdk.NewCoins(tokenIn), mp.TokenOutDenom, mp.SpreadFactor)
}

// CalculateTokenInByTokenOut implements routerusecase.RoutablePool.
func (mp *MockRoutablePool) CalculateTokenInByTokenOut(ctx context.Context, tokenOut sdk.Coin) (sdk.Coin, error) {
if mp.CalculateTokenInByTokenOutFunc != nil {
return mp.CalculateTokenInByTokenOutFunc(ctx, tokenOut)
}

// We allow the ability to mock out the token out amount.
if !mp.mockedTokenIn.IsNil() {
return mp.mockedTokenIn, nil
}

if mp.PoolType == poolmanagertypes.CosmWasm {
return sdk.NewCoin(mp.TokenInDenom, tokenOut.Amount), nil
}

// Cast to balancer
balancerPool, ok := mp.ChainPoolModel.(*balancer.Pool)
if !ok {
panic("not a balancer pool")
}

return balancerPool.CalcInAmtGivenOut(sdk.Context{}.WithContext(ctx), sdk.NewCoins(tokenOut), mp.TokenInDenom, mp.SpreadFactor)
}

// String implements domain.RoutablePool.
Expand Down Expand Up @@ -174,6 +200,11 @@ func (mp *MockRoutablePool) ChargeTakerFeeExactIn(tokenIn sdk.Coin) (tokenInAfte
return tokenIn.Sub(sdk.NewCoin(tokenIn.Denom, mp.TakerFee.Mul(tokenIn.Amount.ToLegacyDec()).TruncateInt()))
}

// ChargeTakerFeeExactOut implements domain.RoutablePool.
func (mp *MockRoutablePool) ChargeTakerFeeExactOut(tokenOut sdk.Coin) (tokenInAfterFee sdk.Coin) {
return tokenOut.Add(sdk.NewCoin(tokenOut.Denom, mp.TakerFee.Mul(tokenOut.Amount.ToLegacyDec()).TruncateInt()))
}

// GetTakerFee implements ingesttypes.PoolI.
func (mp *MockRoutablePool) GetTakerFee() math.LegacyDec {
return mp.TakerFee
Expand Down
2 changes: 1 addition & 1 deletion domain/mocks/pools_usecase_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (pm *PoolsUsecaseMock) GetRoutesFromCandidates(candidateRoutes ingesttypes.
}

// TODO: note that taker fee is force set to zero
routablePool, err := pools.NewRoutablePool(foundPool, candidatePool.TokenOutDenom, osmomath.ZeroDec(), cosmwasmdomain.CosmWasmPoolsParams{
routablePool, err := pools.NewRoutablePool(foundPool, candidatePool.TokenInDenom, candidatePool.TokenOutDenom, osmomath.ZeroDec(), cosmwasmdomain.CosmWasmPoolsParams{
ScalingFactorGetterCb: domain.UnsetScalingFactorGetterCb,
})
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions domain/routable_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ type RoutablePool interface {
CalcSpotPrice(ctx context.Context, baseDenom string, quoteDenom string) (osmomath.BigDec, error)

CalculateTokenOutByTokenIn(ctx context.Context, tokenIn sdk.Coin) (sdk.Coin, error)
CalculateTokenInByTokenOut(ctx context.Context, tokenOut sdk.Coin) (sdk.Coin, error)

ChargeTakerFeeExactIn(tokenIn sdk.Coin) (tokenInAfterFee sdk.Coin)
ChargeTakerFeeExactOut(tokenOut sdk.Coin) (tokenOutAfterFee sdk.Coin)

GetTakerFee() osmomath.Dec

Expand Down
1 change: 1 addition & 0 deletions ingest/types/candidate_route.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package types
// candidate pool to be used for routing.
type CandidatePool struct {
ID uint64
TokenInDenom string
TokenOutDenom string
}

Expand Down
6 changes: 3 additions & 3 deletions pools/usecase/pools_usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func (p *poolsUseCase) GetRoutesFromCandidates(candidateRoutes ingesttypes.Candi
takerFee = ingesttypes.DefaultTakerFee
}

routablePool, err := pools.NewRoutablePool(pool, candidatePool.TokenOutDenom, takerFee, p.cosmWasmPoolsParams)
routablePool, err := pools.NewRoutablePool(pool, candidatePool.TokenInDenom, candidatePool.TokenOutDenom, takerFee, p.cosmWasmPoolsParams)
if err != nil {
skipErrorRoute = true
break
Expand Down Expand Up @@ -263,9 +263,9 @@ func (p *poolsUseCase) GetPoolSpotPrice(ctx context.Context, poolID uint64, take
return osmomath.BigDec{}, err
}

// N.B.: Empty string for token out denom because it is irrelevant for calculating spot price.
// N.B.: Empty string for token in/out denom because it is irrelevant for calculating spot price.
// It is only relevant in the context of routing
routablePool, err := pools.NewRoutablePool(pool, "", takerFee, p.cosmWasmPoolsParams)
routablePool, err := pools.NewRoutablePool(pool, "", "", takerFee, p.cosmWasmPoolsParams)
if err != nil {
return osmomath.BigDec{}, err
}
Expand Down
12 changes: 6 additions & 6 deletions pools/usecase/pools_usecase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (s *PoolsUsecaseTestSuite) TestGetRoutesFromCandidates() {
cosmWasmPoolsParams := cosmwasmdomain.CosmWasmPoolsParams{
ScalingFactorGetterCb: domain.UnsetScalingFactorGetterCb,
}
_, err = pools.NewRoutablePool(&brokenChainPool, denomTwo, defaultTakerFee, cosmWasmPoolsParams)
_, err = pools.NewRoutablePool(&brokenChainPool, denomOne, denomTwo, defaultTakerFee, cosmWasmPoolsParams)
// Validate that it is indeed broken.
s.Require().Error(err)

Expand Down Expand Up @@ -157,7 +157,7 @@ func (s *PoolsUsecaseTestSuite) TestGetRoutesFromCandidates() {
expectedRoutes: []route.RouteImpl{
{
Pools: []domain.RoutablePool{
s.newRoutablePool(defaultPool, denomTwo, defaultTakerFee),
s.newRoutablePool(defaultPool, denomOne, denomTwo, defaultTakerFee),
},
},
},
Expand All @@ -177,7 +177,7 @@ func (s *PoolsUsecaseTestSuite) TestGetRoutesFromCandidates() {
expectedRoutes: []route.RouteImpl{
{
Pools: []domain.RoutablePool{
s.newRoutablePool(defaultPool, denomTwo, ingesttypes.DefaultTakerFee),
s.newRoutablePool(defaultPool, denomOne, denomTwo, ingesttypes.DefaultTakerFee),
},
},
},
Expand Down Expand Up @@ -211,7 +211,7 @@ func (s *PoolsUsecaseTestSuite) TestGetRoutesFromCandidates() {
expectedRoutes: []route.RouteImpl{
{
Pools: []domain.RoutablePool{
s.newRoutablePool(defaultPool, denomTwo, defaultTakerFee),
s.newRoutablePool(defaultPool, denomOne, denomTwo, defaultTakerFee),
},
},
},
Expand Down Expand Up @@ -1015,11 +1015,11 @@ func (s *PoolsUsecaseTestSuite) TestSetPoolAPRAndFeeDataIfConfigured() {
}
}

func (s *PoolsUsecaseTestSuite) newRoutablePool(pool ingesttypes.PoolI, tokenOutDenom string, takerFee osmomath.Dec) domain.RoutablePool {
func (s *PoolsUsecaseTestSuite) newRoutablePool(pool ingesttypes.PoolI, tokenInDenom string, tokenOutDenom string, takerFee osmomath.Dec) domain.RoutablePool {
cosmWasmPoolsParams := cosmwasmdomain.CosmWasmPoolsParams{
ScalingFactorGetterCb: domain.UnsetScalingFactorGetterCb,
}
routablePool, err := pools.NewRoutablePool(pool, tokenOutDenom, takerFee, cosmWasmPoolsParams)
routablePool, err := pools.NewRoutablePool(pool, tokenInDenom, tokenOutDenom, takerFee, cosmWasmPoolsParams)
s.Require().NoError(err)
return routablePool
}
Expand Down
10 changes: 7 additions & 3 deletions router/usecase/pools/pool_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

// NewRoutablePool creates a new RoutablePool.
// Panics if pool is of invalid type or if does not contain tick data when a concentrated pool.
func NewRoutablePool(pool ingesttypes.PoolI, tokenOutDenom string, takerFee osmomath.Dec, cosmWasmPoolsParams cosmwasmdomain.CosmWasmPoolsParams) (domain.RoutablePool, error) {
func NewRoutablePool(pool ingesttypes.PoolI, tokenInDenom string, tokenOutDenom string, takerFee osmomath.Dec, cosmWasmPoolsParams cosmwasmdomain.CosmWasmPoolsParams) (domain.RoutablePool, error) {
poolType := pool.GetType()
chainPool := pool.GetUnderlyingPool()
if poolType == poolmanagertypes.Concentrated {
Expand All @@ -37,6 +37,7 @@ func NewRoutablePool(pool ingesttypes.PoolI, tokenOutDenom string, takerFee osmo
return &routableConcentratedPoolImpl{
ChainPool: concentratedPool,
TickModel: tickModel,
TokenInDenom: tokenInDenom,
TokenOutDenom: tokenOutDenom,
TakerFee: takerFee,
}, nil
Expand All @@ -56,6 +57,7 @@ func NewRoutablePool(pool ingesttypes.PoolI, tokenOutDenom string, takerFee osmo

return &routableBalancerPoolImpl{
ChainPool: balancerPool,
TokenInDenom: tokenInDenom,
TokenOutDenom: tokenOutDenom,
TakerFee: takerFee,
}, nil
Expand All @@ -80,17 +82,18 @@ func NewRoutablePool(pool ingesttypes.PoolI, tokenOutDenom string, takerFee osmo

return &routableStableswapPoolImpl{
ChainPool: stableswapPool,
TokenInDenom: tokenInDenom,
TokenOutDenom: tokenOutDenom,
TakerFee: takerFee,
}, nil
}

return newRoutableCosmWasmPool(pool, tokenOutDenom, takerFee, cosmWasmPoolsParams)
return newRoutableCosmWasmPool(pool, tokenInDenom, tokenOutDenom, takerFee, cosmWasmPoolsParams)
}

// newRoutableCosmWasmPool creates a new RoutablePool for CosmWasm pools.
// Panics if the given pool is not a cosmwasm pool or if the
func newRoutableCosmWasmPool(pool ingesttypes.PoolI, tokenOutDenom string, takerFee osmomath.Dec, cosmWasmPoolsParams cosmwasmdomain.CosmWasmPoolsParams) (domain.RoutablePool, error) {
func newRoutableCosmWasmPool(pool ingesttypes.PoolI, tokenInDenom string, tokenOutDenom string, takerFee osmomath.Dec, cosmWasmPoolsParams cosmwasmdomain.CosmWasmPoolsParams) (domain.RoutablePool, error) {
chainPool := pool.GetUnderlyingPool()
poolType := pool.GetType()

Expand All @@ -113,6 +116,7 @@ func newRoutableCosmWasmPool(pool ingesttypes.PoolI, tokenOutDenom string, taker
return &routableTransmuterPoolImpl{
ChainPool: cosmwasmPool,
Balances: balances,
TokenInDenom: tokenInDenom,
TokenOutDenom: tokenOutDenom,
TakerFee: takerFee,
SpreadFactor: spreadFactor,
Expand Down
29 changes: 23 additions & 6 deletions router/usecase/pools/routable_balancer_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,32 @@ import (
var _ domain.RoutablePool = &routableBalancerPoolImpl{}

type routableBalancerPoolImpl struct {
ChainPool *balancer.Pool "json:\"pool\""
TokenInDenom string "json:\"token_in_denom,omitempty\""
TokenOutDenom string "json:\"token_out_denom,omitempty\""
TakerFee osmomath.Dec "json:\"taker_fee\""
ChainPool *balancer.Pool `json:"pool"`
TokenInDenom string `json:"token_in_denom,omitempty"`
TokenOutDenom string `json:"token_out_denom,omitempty"`
TakerFee osmomath.Dec `json:"taker_fee"`
}

// CalculateTokenOutByTokenIn implements RoutablePool.
func (r *routableBalancerPoolImpl) CalculateTokenOutByTokenIn(ctx context.Context, tokenIn sdk.Coin) (sdk.Coin, error) {
tokenOut, err := r.ChainPool.CalcOutAmtGivenIn(sdk.Context{}, sdk.Coins{tokenIn}, r.TokenOutDenom, r.GetSpreadFactor())
tokenOut, err := r.ChainPool.CalcOutAmtGivenIn(sdk.Context{}.WithContext(ctx), sdk.Coins{tokenIn}, r.TokenOutDenom, r.GetSpreadFactor())
if err != nil {
return sdk.Coin{}, err
}

return tokenOut, nil
}

// CalculateTokenInByTokenOut implements RoutablePool.
func (r *routableBalancerPoolImpl) CalculateTokenInByTokenOut(ctx context.Context, tokenOut sdk.Coin) (sdk.Coin, error) {
tokenIn, err := r.ChainPool.CalcInAmtGivenOut(sdk.Context{}.WithContext(ctx), sdk.Coins{tokenOut}, r.TokenInDenom, r.GetSpreadFactor())
if err != nil {
return sdk.Coin{}, err
}

return tokenIn, nil
}

// GetTokenOutDenom implements RoutablePool.
func (r *routableBalancerPoolImpl) GetTokenOutDenom() string {
return r.TokenOutDenom
Expand All @@ -57,6 +67,13 @@ func (r *routableBalancerPoolImpl) ChargeTakerFeeExactIn(tokenIn sdk.Coin) (toke
return tokenInAfterTakerFee
}

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

// GetTakerFee implements domain.RoutablePool.
func (r *routableBalancerPoolImpl) GetTakerFee() math.LegacyDec {
return r.TakerFee
Expand Down Expand Up @@ -94,7 +111,7 @@ func (*routableBalancerPoolImpl) GetType() poolmanagertypes.PoolType {

// CalcSpotPrice implements domain.RoutablePool.
func (r *routableBalancerPoolImpl) CalcSpotPrice(ctx context.Context, baseDenom string, quoteDenom string) (osmomath.BigDec, error) {
spotPrice, err := r.ChainPool.SpotPrice(sdk.Context{}, quoteDenom, baseDenom)
spotPrice, err := r.ChainPool.SpotPrice(sdk.Context{}.WithContext(ctx), quoteDenom, baseDenom)
if err != nil {
return osmomath.BigDec{}, err
}
Expand Down
24 changes: 18 additions & 6 deletions router/usecase/pools/routable_concentrated_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pools

import (
"context"
"errors"
"fmt"

"cosmossdk.io/math"
Expand All @@ -24,11 +25,11 @@ var _ domain.RoutablePool = &routableConcentratedPoolImpl{}
var smallestDec = osmomath.BigDecFromDec(osmomath.SmallestDec())

type routableConcentratedPoolImpl struct {
ChainPool *concentratedmodel.Pool "json:\"cl_pool\""
TickModel *ingesttypes.TickModel "json:\"tick_model\""
TokenInDenom string "json:\"token_in_denom,omitempty\""
TokenOutDenom string "json:\"token_out_denom,omitempty\""
TakerFee osmomath.Dec "json:\"taker_fee\""
ChainPool *concentratedmodel.Pool `json:"cl_pool"`
TickModel *ingesttypes.TickModel `json:"tick_model"`
TokenInDenom string `json:"token_in_denom,omitempty"`
TokenOutDenom string `json:"token_out_denom,omitempty"`
TakerFee osmomath.Dec `json:"taker_fee"`
}

// Size is roughly `keys * (2.5 * Key_size + 2*value_size)`. (Plus whatever excess overhead hashmaps internally have)
Expand Down Expand Up @@ -193,6 +194,11 @@ func (r *routableConcentratedPoolImpl) CalculateTokenOutByTokenIn(ctx context.Co
return sdk.Coin{Denom: tokenOutDenom, Amount: amountOutTotal.TruncateInt()}, nil
}

// CalculateTokenInByTokenOut implements domain.RoutablePool.
func (r *routableConcentratedPoolImpl) CalculateTokenInByTokenOut(ctx context.Context, tokenOut sdk.Coin) (sdk.Coin, error) {
return sdk.Coin{}, errors.New("not implemented")
}

// GetTokenOutDenom implements RoutablePool.
func (r *routableConcentratedPoolImpl) GetTokenOutDenom() string {
return r.TokenOutDenom
Expand All @@ -216,6 +222,12 @@ func (r *routableConcentratedPoolImpl) ChargeTakerFeeExactIn(tokenIn sdk.Coin) (
return tokenInAfterTakerFee
}

// ChargeTakerFee implements domain.RoutablePool.
// Charges the taker fee for the given token out and returns the token out after the fee has been charged.
func (r *routableConcentratedPoolImpl) ChargeTakerFeeExactOut(tokenOut sdk.Coin) (tokenOutAfterFee sdk.Coin) {
return sdk.Coin{}
}

// SetTokenInDenom implements domain.RoutablePool.
func (r *routableConcentratedPoolImpl) SetTokenInDenom(tokenInDenom string) {
r.TokenInDenom = tokenInDenom
Expand All @@ -228,7 +240,7 @@ func (r *routableConcentratedPoolImpl) SetTokenOutDenom(tokenOutDenom string) {

// CalcSpotPrice implements domain.RoutablePool.
func (r *routableConcentratedPoolImpl) CalcSpotPrice(ctx context.Context, baseDenom string, quoteDenom string) (osmomath.BigDec, error) {
spotPrice, err := r.ChainPool.SpotPrice(sdk.Context{}, quoteDenom, baseDenom)
spotPrice, err := r.ChainPool.SpotPrice(sdk.Context{}.WithContext(ctx), quoteDenom, baseDenom)
if err != nil {
return osmomath.BigDec{}, err
}
Expand Down
2 changes: 1 addition & 1 deletion router/usecase/pools/routable_concentrated_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (s *RoutablePoolTestSuite) TestCalculateTokenOutByTokenIn_Concentrated_Succ
cosmWasmPoolsParams := cosmwasmdomain.CosmWasmPoolsParams{
ScalingFactorGetterCb: domain.UnsetScalingFactorGetterCb,
}
routablePool, err := pools.NewRoutablePool(poolWrapper, tc.TokenOutDenom, noTakerFee, cosmWasmPoolsParams)
routablePool, err := pools.NewRoutablePool(poolWrapper, tc.TokenInDenom, tc.TokenOutDenom, noTakerFee, cosmWasmPoolsParams)
s.Require().NoError(err)

tokenOut, err := routablePool.CalculateTokenOutByTokenIn(context.TODO(), tc.TokenIn)
Expand Down
Loading

0 comments on commit f4e918c

Please sign in to comment.