Skip to content

Commit

Permalink
implement best pool finder
Browse files Browse the repository at this point in the history
  • Loading branch information
jelysn committed Jan 30, 2024
1 parent 57031c5 commit 54308a1
Show file tree
Hide file tree
Showing 16 changed files with 56 additions and 188 deletions.
2 changes: 0 additions & 2 deletions x/accountedpool/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ type AccountKeeper interface {
//
//go:generate mockery --srcpkg . --name AmmKeeper --structname AmmKeeper --filename amm_keeper.go --with-expecter
type AmmKeeper interface {
// Get pool Ids that contains the denom in pool assets
GetAllPoolIdsWithDenom(sdk.Context, string) []uint64
// GetPool returns a pool from its index
GetPool(sdk.Context, uint64) (ammtypes.Pool, bool)
// Get all pools
Expand Down
44 changes: 0 additions & 44 deletions x/accountedpool/types/mocks/amm_keeper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions x/amm/keeper/calc_in_route_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,34 @@ func (k Keeper) CalcInRouteByDenom(ctx sdk.Context, denomIn string, denomOut str
var route []*types.SwapAmountInRoute

// Check for a direct pool between the denoms
if poolId, found := k.GetPoolIdWithAllDenoms(ctx, []string{denomIn, denomOut}); found {
if pool, found := k.GetBestPoolWithDenoms(ctx, []string{denomIn, denomOut}); found {
// If the pool exists, return the route
route = append(route, &types.SwapAmountInRoute{
PoolId: poolId,
PoolId: pool.PoolId,
TokenOutDenom: denomOut,
})
return route, nil
}

// Find pool for initial denom to base currency
poolId, found := k.GetPoolIdWithAllDenoms(ctx, []string{denomIn, baseCurrency})
pool, found := k.GetBestPoolWithDenoms(ctx, []string{denomIn, baseCurrency})
if !found {
return nil, fmt.Errorf("no available pool for %s to base currency", denomIn)
}
// If the pool exists, append the route
route = append(route, &types.SwapAmountInRoute{
PoolId: poolId,
PoolId: pool.PoolId,
TokenOutDenom: baseCurrency,
})

// Find pool for base currency to target denom
poolId, found = k.GetPoolIdWithAllDenoms(ctx, []string{baseCurrency, denomOut})
pool, found = k.GetBestPoolWithDenoms(ctx, []string{baseCurrency, denomOut})
if !found {
return nil, fmt.Errorf("no available pool for base currency to %s", denomOut)
}
// If the pool exists, append the route
route = append(route, &types.SwapAmountInRoute{
PoolId: poolId,
PoolId: pool.PoolId,
TokenOutDenom: denomOut,
})

Expand Down
12 changes: 6 additions & 6 deletions x/amm/keeper/calc_out_route_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,34 @@ func (k Keeper) CalcOutRouteByDenom(ctx sdk.Context, denomOut string, denomIn st
}

// Check for a direct pool between the denoms
if poolId, found := k.GetPoolIdWithAllDenoms(ctx, []string{denomOut, denomIn}); found {
if pool, found := k.GetBestPoolWithDenoms(ctx, []string{denomOut, denomIn}); found {
// If the pool exists, return the route
route = append(route, &types.SwapAmountOutRoute{
PoolId: poolId,
PoolId: pool.PoolId,
TokenInDenom: denomIn,
})
return route, nil
}

// Find pool for initial denom to base currency
poolId, found := k.GetPoolIdWithAllDenoms(ctx, []string{denomOut, baseCurrency})
pool, found := k.GetBestPoolWithDenoms(ctx, []string{denomOut, baseCurrency})
if !found {
return nil, fmt.Errorf("no available pool for %s to base currency", denomOut)
}
// If the pool exists, append the route
route = append(route, &types.SwapAmountOutRoute{
PoolId: poolId,
PoolId: pool.PoolId,
TokenInDenom: baseCurrency,
})

// Find pool for base currency to target denom
poolId, found = k.GetPoolIdWithAllDenoms(ctx, []string{baseCurrency, denomIn})
pool, found = k.GetBestPoolWithDenoms(ctx, []string{baseCurrency, denomIn})
if !found {
return nil, fmt.Errorf("no available pool for base currency to %s", denomIn)
}
// If the pool exists, append the route
route = append(route, &types.SwapAmountOutRoute{
PoolId: poolId,
PoolId: pool.PoolId,
TokenInDenom: denomIn,
})

Expand Down
34 changes: 13 additions & 21 deletions x/amm/keeper/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,13 @@ func (k Keeper) PoolExists(ctx sdk.Context, poolId uint64) bool {
return b != nil
}

// Get pool Ids that contains the denom in pool assets
func (k Keeper) GetAllPoolIdsWithDenom(ctx sdk.Context, denom string) (list []uint64) {
pools := k.GetAllPool(ctx)

for _, p := range pools {
for _, asset := range p.PoolAssets {
if denom == asset.Token.Denom {
list = append(list, p.PoolId)
break
}
}
}

return list
}

// GetPoolIdWithAllDenoms returns the first pool id that contains all specified denominations
func (k Keeper) GetPoolIdWithAllDenoms(ctx sdk.Context, denoms []string) (poolId uint64, found bool) {
// GetBestPoolWithDenoms returns the first pool id that contains all specified denominations
func (k Keeper) GetBestPoolWithDenoms(ctx sdk.Context, denoms []string) (pool types.Pool, found bool) {
// Get all pools
pools := k.GetAllPool(ctx)

maxTvl := sdk.NewDec(-1)
bestPool := types.Pool{}
for _, p := range pools {
// If the number of assets in the pool is less than the number of denoms, skip
if len(p.PoolAssets) < len(denoms) {
Expand All @@ -125,13 +111,19 @@ func (k Keeper) GetPoolIdWithAllDenoms(ctx sdk.Context, denoms []string) (poolId
}
}

poolTvl, err := p.TVL(ctx, k.oracleKeeper)
if err != nil {
poolTvl = sdk.ZeroDec()
}

// If all denoms are found in this pool, return the pool id
if allDenomsFound {
return p.PoolId, true
if allDenomsFound && maxTvl.LT(poolTvl) {
maxTvl = poolTvl
bestPool = p
}
}

return 0, false
return bestPool, !maxTvl.IsNegative()
}

// IterateLiquidty iterates over all LiquidityPools and performs a
Expand Down
8 changes: 4 additions & 4 deletions x/amm/keeper/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestPoolGetAll(t *testing.T) {
)
}

func TestGetPoolIdWithAllDenoms(t *testing.T) {
func TestGetBestPoolWithDenoms(t *testing.T) {
keeper, ctx, _, _ := keepertest.AmmKeeper(t)
items := createNPool(keeper, ctx, 10)

Expand All @@ -93,11 +93,11 @@ func TestGetPoolIdWithAllDenoms(t *testing.T) {
}

// Test case where pool is found
poolId, found := keeper.GetPoolIdWithAllDenoms(ctx, []string{"denom2", "usdc"})
pool, found := keeper.GetBestPoolWithDenoms(ctx, []string{"denom2", "usdc"})
require.True(t, found)
require.Equal(t, uint64(2), poolId)
require.Equal(t, uint64(2), pool.PoolId)

// Test case where pool is not found
_, found = keeper.GetPoolIdWithAllDenoms(ctx, []string{"nonexistent", "usdc"})
_, found = keeper.GetBestPoolWithDenoms(ctx, []string{"nonexistent", "usdc"})
require.False(t, found)
}
2 changes: 1 addition & 1 deletion x/incentive/keeper/estimate_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
// Estimate the price : eg, 1 Eden -> x usdc
func (k Keeper) EstimatePrice(ctx sdk.Context, tokenIn sdk.Coin, baseCurrency string) sdk.Int {
// Find a pool that can convert tokenIn to usdc
pool, found := k.FindPool(ctx, tokenIn.Denom, baseCurrency)
pool, found := k.amm.GetBestPoolWithDenoms(ctx, []string{tokenIn.Denom, baseCurrency})
if !found {
return sdk.ZeroInt()
}
Expand Down
27 changes: 1 addition & 26 deletions x/incentive/keeper/keeper_fees.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,6 @@ import (
ptypes "github.com/elys-network/elys/x/parameter/types"
)

// FindPool function gets a pool that can convert in_denom token to out_denom token
// TODO:
// Later on: add a logic to choose best pool
func (k Keeper) FindPool(ctx sdk.Context, inDenom string, outDenom string) (ammtypes.Pool, bool) {
// Get pool ids that can convert tokenIn
poolIds := k.amm.GetAllPoolIdsWithDenom(ctx, inDenom)

for _, pId := range poolIds {
// Get a pool with poolId
pool, found := k.amm.GetPool(ctx, pId)
if !found {
continue
}

// Loop pool assets to find out pair
for _, asset := range pool.PoolAssets {
if asset.Token.Denom == outDenom {
return pool, true
}
}
}

return ammtypes.Pool{}, false
}

// Move gas fees collected to dex revenue wallet
// Convert it into USDC
func (k Keeper) CollectGasFeesToIncentiveModule(ctx sdk.Context, baseCurrency string) sdk.Coins {
Expand Down Expand Up @@ -59,7 +34,7 @@ func (k Keeper) CollectGasFeesToIncentiveModule(ctx sdk.Context, baseCurrency st
}

// Find a pool that can convert tokenIn to usdc
pool, found := k.FindPool(ctx, tokenIn.Denom, baseCurrency)
pool, found := k.amm.GetBestPoolWithDenoms(ctx, []string{tokenIn.Denom, baseCurrency})
if !found {
continue
}
Expand Down
3 changes: 1 addition & 2 deletions x/incentive/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ type AmmKeeper interface {
swapFeeOut sdk.Dec,
weightBalanceBonus sdk.Dec,
) (sdk.Int, error)
// Get pool Ids that contains the denom in pool assets
GetAllPoolIdsWithDenom(sdk.Context, string) []uint64
GetBestPoolWithDenoms(ctx sdk.Context, denoms []string) (pool ammtypes.Pool, found bool)
// GetPool returns a pool from its index
GetPool(sdk.Context, uint64) (ammtypes.Pool, bool)
// Get all pools
Expand Down
2 changes: 0 additions & 2 deletions x/leveragelp/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ type AccountKeeper interface {

// AmmKeeper defines the expected interface needed to swap tokens
type AmmKeeper interface {
// Get pool Ids that contains the denom in pool assets
GetAllPoolIdsWithDenom(sdk.Context, string) []uint64
// GetPool returns a pool from its index
GetPool(sdk.Context, uint64) (ammtypes.Pool, bool)
// Get all pools
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (
"github.com/elys-network/elys/x/perpetual/types"
)

func (k Keeper) GetFirstValidPool(ctx sdk.Context, collateralAsset string, tradingAsset string) (uint64, error) {
func (k Keeper) GetBestPool(ctx sdk.Context, collateralAsset string, tradingAsset string) (uint64, error) {
denoms := []string{collateralAsset, tradingAsset}
poolId, found := k.amm.GetPoolIdWithAllDenoms(ctx, denoms)
pool, found := k.amm.GetBestPoolWithDenoms(ctx, denoms)
if !found {
return 0, errorsmod.Wrap(types.ErrPoolDoesNotExist, fmt.Sprintf("%s", denoms))
}
return poolId, nil
return pool.PoolId, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/stretchr/testify/assert"
)

func TestGetFirstValidPool_NoPoolID(t *testing.T) {
func TestGetBestPool_NoPoolID(t *testing.T) {
app := simapp.InitElysTestApp(true)
ctx := app.BaseApp.NewContext(true, tmproto.Header{})

Expand All @@ -22,13 +22,12 @@ func TestGetFirstValidPool_NoPoolID(t *testing.T) {
collateralAsset := ptypes.BaseCurrency
borrowAsset := "testAsset"

_, err := perpetual.GetFirstValidPool(ctx, collateralAsset, borrowAsset)

// Expect an error about the pool not existing
_, err := perpetual.GetBestPool(ctx, collateralAsset, borrowAsset)
assert.True(t, errors.Is(err, types.ErrPoolDoesNotExist))
}

func TestGetFirstValidPool_ValidPoolID(t *testing.T) {
func TestGetBestPool_ValidPoolID(t *testing.T) {
app := simapp.InitElysTestApp(true)
ctx := app.BaseApp.NewContext(true, tmproto.Header{})

Expand Down Expand Up @@ -66,9 +65,7 @@ func TestGetFirstValidPool_ValidPoolID(t *testing.T) {
}
app.AmmKeeper.SetPool(ctx, pool)

poolID, err := perpetual.GetFirstValidPool(ctx, collateralAsset, borrowAsset)

// Expect no error and the first pool ID to be returned
poolID, err := perpetual.GetBestPool(ctx, collateralAsset, borrowAsset)
assert.Nil(t, err)
assert.Equal(t, uint64(1), poolID)
}
2 changes: 1 addition & 1 deletion x/perpetual/keeper/prepare_pools.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

// PreparePools creates accounted pools
func (k Keeper) PreparePools(ctx sdk.Context, collateralAsset, tradingAsset string) (poolId uint64, ammPool ammtypes.Pool, pool types.Pool, err error) {
poolId, err = k.GetFirstValidPool(ctx, collateralAsset, tradingAsset)
poolId, err = k.GetBestPool(ctx, collateralAsset, tradingAsset)
if err != nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion x/perpetual/keeper/query_open_estimation.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (k Keeper) OpenEstimation(goCtx context.Context, req *types.QueryOpenEstima
liquidationPrice = liquidationPrice.Add(openPrice)

// get pool rates
poolId, err := k.GetFirstValidPool(ctx, req.Collateral.Denom, req.TradingAsset)
poolId, err := k.GetBestPool(ctx, req.Collateral.Denom, req.TradingAsset)
if err != nil {
return nil, err
}
Expand Down
4 changes: 1 addition & 3 deletions x/perpetual/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,8 @@ type AccountKeeper interface {
//
//go:generate mockery --srcpkg . --name AmmKeeper --structname AmmKeeper --filename amm_keeper.go --with-expecter
type AmmKeeper interface {
// Get pool Ids that contains the denom in pool assets
GetAllPoolIdsWithDenom(sdk.Context, string) []uint64
// Get first pool id that contains all denoms in pool assets
GetPoolIdWithAllDenoms(ctx sdk.Context, denoms []string) (poolId uint64, found bool)
GetBestPoolWithDenoms(ctx sdk.Context, denoms []string) (pool ammtypes.Pool, found bool)
// GetPool returns a pool from its index
GetPool(sdk.Context, uint64) (ammtypes.Pool, bool)
// Get all pools
Expand Down
Loading

0 comments on commit 54308a1

Please sign in to comment.