Skip to content

Commit

Permalink
Update query to return weightBalance info & update weight breaking fe…
Browse files Browse the repository at this point in the history
…e calculation
  • Loading branch information
jelysn committed Dec 15, 2023
1 parent d2bb3f1 commit 17dd5d3
Show file tree
Hide file tree
Showing 26 changed files with 403 additions and 365 deletions.
25 changes: 4 additions & 21 deletions proto/elys/amm/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,73 +17,54 @@ option go_package = "github.com/elys-network/elys/x/amm/types";

// Query defines the gRPC querier service.
service Query {

// Parameters queries the parameters of the module.
rpc Params (QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/elys-network/elys/amm/params";

}

// Queries a list of Pool items.
rpc Pool (QueryGetPoolRequest) returns (QueryGetPoolResponse) {
option (google.api.http).get = "/elys-network/elys/amm/pool/{pool_id}";

}
rpc PoolAll (QueryAllPoolRequest) returns (QueryAllPoolResponse) {
option (google.api.http).get = "/elys-network/elys/amm/pool";

}

// Queries a list of DenomLiquidity items.
rpc DenomLiquidity (QueryGetDenomLiquidityRequest) returns (QueryGetDenomLiquidityResponse) {
option (google.api.http).get = "/elys-network/elys/amm/denom_liquidity/{denom}";

}
rpc DenomLiquidityAll (QueryAllDenomLiquidityRequest) returns (QueryAllDenomLiquidityResponse) {
option (google.api.http).get = "/elys-network/elys/amm/denom_liquidity";

}

// Queries a list of SwapEstimation items.
rpc SwapEstimation (QuerySwapEstimationRequest) returns (QuerySwapEstimationResponse) {
option (google.api.http).get = "/elys-network/elys/amm/swap_estimation";

}

// Queries slippage track for a week.
rpc SlippageTrack (QuerySlippageTrackRequest) returns (QuerySlippageTrackResponse) {
option (google.api.http).get = "/elys-network/elys/amm/slippage_track/{pool_id}";

}

// Queries all slippage tracks for a week.
rpc SlippageTrackAll (QuerySlippageTrackAllRequest) returns (QuerySlippageTrackAllResponse) {
option (google.api.http).get = "/elys-network/elys/amm/slippage_tracks";

}

// Queries a list of Balance items.
rpc Balance (QueryBalanceRequest) returns (QueryBalanceResponse) {
option (google.api.http).get = "/elys-network/elys/amm/balance/{address}/{denom}";

}

// Queries a list of InRouteByDenom items.
rpc InRouteByDenom (QueryInRouteByDenomRequest) returns (QueryInRouteByDenomResponse) {
option (google.api.http).get = "/elys-network/elys/amm/in_route_by_denom/{denom_in}/{denom_out}";

}

// Queries a list of OutRouteByDenom items.
rpc OutRouteByDenom (QueryOutRouteByDenomRequest) returns (QueryOutRouteByDenomResponse) {
option (google.api.http).get = "/elys-network/elys/amm/out_route_by_denom/{denom_out}/{denom_in}";

}

// Queries a list of SwapEstimationByDenom items.
rpc SwapEstimationByDenom (QuerySwapEstimationByDenomRequest) returns (QuerySwapEstimationByDenomResponse) {
option (google.api.http).get = "/elys-network/elys/amm/swap_estimation_by_denom";

}
}
// QueryParamsRequest is request type for the Query/Params RPC method.
Expand Down Expand Up @@ -141,7 +122,8 @@ message QuerySwapEstimationResponse {
cosmos.base.v1beta1.Coin token_out = 2 [(gogoproto.nullable) = false ] ;
string swap_fee = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string discount = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin available_liquidity = 5 [(gogoproto.nullable) = false ] ;
cosmos.base.v1beta1.Coin available_liquidity = 5 [(gogoproto.nullable) = false];
string weight_balance_ratio = 6 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

message QuerySlippageTrackRequest {
Expand Down Expand Up @@ -199,7 +181,8 @@ message QuerySwapEstimationByDenomResponse {
cosmos.base.v1beta1.Coin amount = 4 [(gogoproto.nullable) = false];
string swap_fee = 5 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string discount = 6 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin available_liquidity = 7 [(gogoproto.nullable) = false ] ;
cosmos.base.v1beta1.Coin available_liquidity = 7 [(gogoproto.nullable) = false ] ;
string weight_balance_ratio = 8 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

message QueryAMMPriceRequest {
Expand Down
1 change: 0 additions & 1 deletion proto/elys/amm/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ message MsgJoinPool {
uint64 pool_id = 2;
repeated cosmos.base.v1beta1.Coin max_amounts_in = 3 [(gogoproto.nullable) = false ] ;
string share_amount_out = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false];
bool no_remaining = 5;
}

message MsgJoinPoolResponse {
Expand Down
7 changes: 1 addition & 6 deletions x/amm/client/cli/tx_join_pool.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package cli

import (
"strconv"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
Expand All @@ -16,7 +14,7 @@ func CmdJoinPool() *cobra.Command {
cmd := &cobra.Command{
Use: "join-pool [pool-id] [max-amounts-in] [share-amount-out]",
Short: "join a new pool and provide the liquidity to it",
Example: `elysd tx amm join-pool 0 2000uatom,2000uusdc 200000000000000000 true --from=treasury --keyring-backend=test --chain-id=elystestnet-1 --yes --gas=1000000`,
Example: `elysd tx amm join-pool 0 2000uatom,2000uusdc 200000000000000000 --from=treasury --keyring-backend=test --chain-id=elystestnet-1 --yes --gas=1000000`,
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) (err error) {
poolId, err := cast.ToUint64E(args[0])
Expand All @@ -37,14 +35,11 @@ func CmdJoinPool() *cobra.Command {
return err
}

noRemaining, err := strconv.ParseBool(args[3])

msg := types.NewMsgJoinPool(
clientCtx.GetFromAddress().String(),
poolId,
maxAmountsIn,
shareAmountOut,
noRemaining,
)
if err := msg.ValidateBasic(); err != nil {
return err
Expand Down
5 changes: 1 addition & 4 deletions x/amm/client/wasm/msg_join_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ func (m *Messenger) msgJoinPool(ctx sdk.Context, contractAddr sdk.AccAddress, ms
return nil, nil, errorsmod.Wrap(err, "failed validating msg")
}

res, err := msgServer.JoinPool(
sdk.WrapSDKContext(ctx),
msg,
)
res, err := msgServer.JoinPool(sdk.WrapSDKContext(ctx), msg)
if err != nil {
return nil, nil, errorsmod.Wrap(err, "join pool msg")
}
Expand Down
27 changes: 16 additions & 11 deletions x/amm/keeper/calc_in_route_spot_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
)

// CalcInRouteSpotPrice calculates the spot price of the given token and in route
func (k Keeper) CalcInRouteSpotPrice(ctx sdk.Context, tokenIn sdk.Coin, routes []*types.SwapAmountInRoute, discount sdk.Dec, overrideSwapFee sdk.Dec) (sdk.Dec, sdk.Coin, sdk.Dec, sdk.Dec, sdk.Coin, error) {
func (k Keeper) CalcInRouteSpotPrice(ctx sdk.Context, tokenIn sdk.Coin, routes []*types.SwapAmountInRoute, discount sdk.Dec, overrideSwapFee sdk.Dec) (sdk.Dec, sdk.Coin, sdk.Dec, sdk.Dec, sdk.Coin, sdk.Dec, error) {
if routes == nil || len(routes) == 0 {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrEmptyRoutes
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), types.ErrEmptyRoutes
}

// Start with the initial token input
Expand All @@ -23,13 +23,15 @@ func (k Keeper) CalcInRouteSpotPrice(ctx sdk.Context, tokenIn sdk.Coin, routes [
// Track the total available liquidity in the pool for final token out denom
var availableLiquidity sdk.Coin

weightBalance := sdk.ZeroDec()

for _, route := range routes {
poolId := route.PoolId
tokenOutDenom = route.TokenOutDenom

pool, found := k.GetPool(ctx, poolId)
if !found {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrPoolNotFound
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), types.ErrPoolNotFound
}

// Get Pool swap fee
Expand All @@ -48,29 +50,32 @@ func (k Keeper) CalcInRouteSpotPrice(ctx sdk.Context, tokenIn sdk.Coin, routes [

// Estimate swap
snapshot := k.GetPoolSnapshotOrSet(ctx, pool)
swapResult, err := k.CalcOutAmtGivenIn(ctx, pool.PoolId, k.oracleKeeper, &snapshot, tokensIn, tokenOutDenom, swapFee)
cacheCtx, _ := ctx.CacheContext()
tokenOut, _, weightBalanceBonus, err := k.SwapOutAmtGivenIn(cacheCtx, pool.PoolId, k.oracleKeeper, &snapshot, tokensIn, tokenOutDenom, swapFee)
if err != nil {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, err
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), err
}

if swapResult.IsZero() {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrAmountTooLow
if tokenOut.IsZero() {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), types.ErrAmountTooLow
}

// Use the current swap result as the input for the next iteration
tokensIn = sdk.Coins{swapResult}
tokensIn = sdk.Coins{tokenOut}

// Get the available liquidity for the final token out denom
_, poolAsset, err := pool.GetPoolAssetAndIndex(tokenOutDenom)
if err != nil {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, err
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), err
}
availableLiquidity = poolAsset.Token

weightBalance = weightBalanceBonus
}

// Ensure tokenIn.Amount is not zero to avoid division by zero
if tokenIn.IsZero() {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrAmountTooLow
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), types.ErrAmountTooLow
}

// Calculate the spot price given the initial token in and the final token out
Expand All @@ -82,5 +87,5 @@ func (k Keeper) CalcInRouteSpotPrice(ctx sdk.Context, tokenIn sdk.Coin, routes [
// Construct the token out coin
tokenOut := sdk.NewCoin(tokenOutDenom, tokenOutAmt.TruncateInt())

return spotPrice, tokenOut, totalDiscountedSwapFee, discount, availableLiquidity, nil
return spotPrice, tokenOut, totalDiscountedSwapFee, discount, availableLiquidity, weightBalance, nil
}
8 changes: 4 additions & 4 deletions x/amm/keeper/calc_in_route_spot_price_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestCalcInRouteSpotPrice(t *testing.T) {
accountedPoolKeeper.On("GetAccountedBalance", ctx, uint64(1), "denom1").Return(sdk.NewInt(1000))
accountedPoolKeeper.On("GetAccountedBalance", ctx, uint64(1), "denom2").Return(sdk.NewInt(1000))
routes := []*types.SwapAmountInRoute{{PoolId: 1, TokenOutDenom: "denom2"}}
spotPrice, _, _, _, _, err := k.CalcInRouteSpotPrice(ctx, tokenIn, routes, sdk.ZeroDec(), sdk.ZeroDec())
spotPrice, _, _, _, _, _, err := k.CalcInRouteSpotPrice(ctx, tokenIn, routes, sdk.ZeroDec(), sdk.ZeroDec())
require.NoError(t, err)
require.NotZero(t, spotPrice)
accountedPoolKeeper.AssertExpectations(t)
Expand All @@ -34,17 +34,17 @@ func TestCalcInRouteSpotPrice(t *testing.T) {
{PoolId: 2, TokenOutDenom: "baseCurrency"},
{PoolId: 3, TokenOutDenom: "denom3"},
}
spotPrice, _, _, _, _, err = k.CalcInRouteSpotPrice(ctx, tokenIn, routes, sdk.ZeroDec(), sdk.ZeroDec())
spotPrice, _, _, _, _, _, err = k.CalcInRouteSpotPrice(ctx, tokenIn, routes, sdk.ZeroDec(), sdk.ZeroDec())
require.NoError(t, err)
require.NotZero(t, spotPrice)
accountedPoolKeeper.AssertExpectations(t)

// Test no routes
_, _, _, _, _, err = k.CalcInRouteSpotPrice(ctx, tokenIn, nil, sdk.ZeroDec(), sdk.ZeroDec())
_, _, _, _, _, _, err = k.CalcInRouteSpotPrice(ctx, tokenIn, nil, sdk.ZeroDec(), sdk.ZeroDec())
require.Error(t, err)

// Test invalid pool
routes = []*types.SwapAmountInRoute{{PoolId: 9999, TokenOutDenom: "denom2"}}
_, _, _, _, _, err = k.CalcInRouteSpotPrice(ctx, tokenIn, routes, sdk.ZeroDec(), sdk.ZeroDec())
_, _, _, _, _, _, err = k.CalcInRouteSpotPrice(ctx, tokenIn, routes, sdk.ZeroDec(), sdk.ZeroDec())
require.Error(t, err)
}
22 changes: 13 additions & 9 deletions x/amm/keeper/calc_out_route_spot_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
)

// CalcOutRouteSpotPrice calculates the spot price of the given token and out route
func (k Keeper) CalcOutRouteSpotPrice(ctx sdk.Context, tokenOut sdk.Coin, routes []*types.SwapAmountOutRoute, discount sdk.Dec, overrideSwapFee sdk.Dec) (sdk.Dec, sdk.Coin, sdk.Dec, sdk.Dec, sdk.Coin, error) {
func (k Keeper) CalcOutRouteSpotPrice(ctx sdk.Context, tokenOut sdk.Coin, routes []*types.SwapAmountOutRoute, discount sdk.Dec, overrideSwapFee sdk.Dec) (sdk.Dec, sdk.Coin, sdk.Dec, sdk.Dec, sdk.Coin, sdk.Dec, error) {
if routes == nil || len(routes) == 0 {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrEmptyRoutes
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), types.ErrEmptyRoutes
}

// Start with the initial token input
Expand All @@ -23,13 +23,15 @@ func (k Keeper) CalcOutRouteSpotPrice(ctx sdk.Context, tokenOut sdk.Coin, routes
// Track the total available liquidity in the pool for final token out denom
var availableLiquidity sdk.Coin

weightBonus := sdk.ZeroDec()

for _, route := range routes {
poolId := route.PoolId
tokenInDenom = route.TokenInDenom

pool, found := k.GetPool(ctx, poolId)
if !found {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrPoolNotFound
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), types.ErrPoolNotFound
}

// Get Pool swap fee
Expand All @@ -48,13 +50,14 @@ func (k Keeper) CalcOutRouteSpotPrice(ctx sdk.Context, tokenOut sdk.Coin, routes

// Estimate swap
snapshot := k.GetPoolSnapshotOrSet(ctx, pool)
swapResult, err := k.CalcInAmtGivenOut(ctx, pool.PoolId, k.oracleKeeper, &snapshot, tokensOut, tokenInDenom, swapFee)
cacheCtx, _ := ctx.CacheContext()
swapResult, _, weightBalanceBonus, err := k.SwapInAmtGivenOut(cacheCtx, pool.PoolId, k.oracleKeeper, &snapshot, tokensOut, tokenInDenom, swapFee)
if err != nil {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, err
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), err
}

if swapResult.IsZero() {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrAmountTooLow
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), types.ErrAmountTooLow
}

// Use the current swap result as the input for the next iteration
Expand All @@ -63,14 +66,15 @@ func (k Keeper) CalcOutRouteSpotPrice(ctx sdk.Context, tokenOut sdk.Coin, routes
// Get the available liquidity for the final token in denom
_, poolAsset, err := pool.GetPoolAssetAndIndex(tokenInDenom)
if err != nil {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, err
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), err
}
availableLiquidity = poolAsset.Token
weightBonus = weightBalanceBonus
}

// Ensure tokenIn.Amount is not zero to avoid division by zero
if tokenOut.IsZero() {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrAmountTooLow
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), types.ErrAmountTooLow
}

// Calculate the spot price given the initial token in and the final token in
Expand All @@ -82,5 +86,5 @@ func (k Keeper) CalcOutRouteSpotPrice(ctx sdk.Context, tokenOut sdk.Coin, routes
// Construct the token out coin
tokenIn := sdk.NewCoin(tokenInDenom, tokenInAmt.TruncateInt())

return spotPrice, tokenIn, totalDiscountedSwapFee, discount, availableLiquidity, nil
return spotPrice, tokenIn, totalDiscountedSwapFee, discount, availableLiquidity, weightBonus, nil
}
8 changes: 4 additions & 4 deletions x/amm/keeper/calc_out_route_spot_price_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestCalcOutRouteSpotPrice(t *testing.T) {
accountedPoolKeeper.On("GetAccountedBalance", ctx, uint64(1), "denom2").Return(sdk.NewInt(1000))
accountedPoolKeeper.On("GetAccountedBalance", ctx, uint64(1), "denom1").Return(sdk.NewInt(1000))
routes := []*types.SwapAmountOutRoute{{PoolId: 1, TokenInDenom: "denom1"}}
spotPrice, _, _, _, _, err := k.CalcOutRouteSpotPrice(ctx, tokenOut, routes, sdk.ZeroDec(), sdk.ZeroDec())
spotPrice, _, _, _, _, _, err := k.CalcOutRouteSpotPrice(ctx, tokenOut, routes, sdk.ZeroDec(), sdk.ZeroDec())
require.NoError(t, err)
require.NotZero(t, spotPrice)
accountedPoolKeeper.AssertExpectations(t)
Expand All @@ -33,17 +33,17 @@ func TestCalcOutRouteSpotPrice(t *testing.T) {
{PoolId: 3, TokenInDenom: "baseCurrency"},
{PoolId: 2, TokenInDenom: "denom1"},
}
spotPrice, _, _, _, _, err = k.CalcOutRouteSpotPrice(ctx, tokenOut, routes, sdk.ZeroDec(), sdk.ZeroDec())
spotPrice, _, _, _, _, _, err = k.CalcOutRouteSpotPrice(ctx, tokenOut, routes, sdk.ZeroDec(), sdk.ZeroDec())
require.NoError(t, err)
require.NotZero(t, spotPrice)
accountedPoolKeeper.AssertExpectations(t)

// Test no routes
_, _, _, _, _, err = k.CalcOutRouteSpotPrice(ctx, tokenOut, nil, sdk.ZeroDec(), sdk.ZeroDec())
_, _, _, _, _, _, err = k.CalcOutRouteSpotPrice(ctx, tokenOut, nil, sdk.ZeroDec(), sdk.ZeroDec())
require.Error(t, err)

// Test invalid pool
routes = []*types.SwapAmountOutRoute{{PoolId: 9999, TokenInDenom: "denom2"}}
_, _, _, _, _, err = k.CalcOutRouteSpotPrice(ctx, tokenOut, routes, sdk.ZeroDec(), sdk.ZeroDec())
_, _, _, _, _, _, err = k.CalcOutRouteSpotPrice(ctx, tokenOut, routes, sdk.ZeroDec(), sdk.ZeroDec())
require.Error(t, err)
}
Loading

0 comments on commit 17dd5d3

Please sign in to comment.