Skip to content

Commit

Permalink
feat: improved open estimation query
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmic-vagabond committed Dec 2, 2023
1 parent 309aef2 commit e99e163
Show file tree
Hide file tree
Showing 33 changed files with 1,337 additions and 457 deletions.
324 changes: 226 additions & 98 deletions docs/static/openapi.yml

Large diffs are not rendered by default.

45 changes: 28 additions & 17 deletions proto/elys/margin/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,61 +21,63 @@ service Query {

}

// Queries a list of GetPositions items.
// Queries a list of positions.
rpc GetPositions (PositionsRequest) returns (PositionsResponse) {
option (google.api.http).get = "/elys-network/elys/margin/positions/{pagination.key}";

}

// Queries a list of GetPositionsByPool items.
// Queries a list of mtp positions by pool.
rpc GetPositionsByPool (PositionsByPoolRequest) returns (PositionsByPoolResponse) {
option (google.api.http).get = "/elys-network/elys/margin/mtps-by-pool/{amm_pool_id}/{pagination.key}";

}

// Queries a list of GetStatus items.
// Retuns the total number of open and lifetime mtps.
rpc GetStatus (StatusRequest) returns (StatusResponse) {
option (google.api.http).get = "/elys-network/elys/margin/status";

}

// Queries a list of GetPositionsForAddress items.
// Queries a list of mtp positions for a given address.
rpc GetPositionsForAddress (PositionsForAddressRequest) returns (PositionsForAddressResponse) {
option (google.api.http).get = "/elys-network/elys/margin/mtps-for-address/{address}/{pagination.key}";

}

// Queries a list of GetWhitelist items.
// Queries a list of whitelisted addresses.
rpc GetWhitelist (WhitelistRequest) returns (WhitelistResponse) {
option (google.api.http).get = "/elys-network/elys/margin/whitelist/{pagination.key}";

}

// Queries a list of IsWhitelisted items.
// Is an address whitelisted?
rpc IsWhitelisted (IsWhitelistedRequest) returns (IsWhitelistedResponse) {
option (google.api.http).get = "/elys-network/elys/margin/is-whitelisted";

}

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

}

// Queries a list of all pools.
rpc Pools (QueryAllPoolRequest) returns (QueryAllPoolResponse) {
option (google.api.http).get = "/elys-network/elys/margin/pool/{pagination.key}";

}

// Queries a list of MTP items.
// Queries a single mtp position given its address and id.
rpc MTP (MTPRequest) returns (MTPResponse) {
option (google.api.http).get = "/elys-network/elys/margin/mtp/{address}/{id}";

}

// Queries a list of MinCollateral items.
rpc MinCollateral (QueryMinCollateralRequest) returns (QueryMinCollateralResponse) {
option (google.api.http).get = "/elys-network/elys/margin/min_collateral";
// Queries an estimation of a new open position details.
rpc OpenEstimation (QueryOpenEstimationRequest) returns (QueryOpenEstimationResponse) {
option (google.api.http).get = "/elys-network/elys/margin/open-estimation";

}
}
Expand Down Expand Up @@ -169,19 +171,28 @@ message MTPResponse {
MTP mtp = 1;
}

message QueryMinCollateralRequest {
message QueryOpenEstimationRequest {
Position position = 1;
string leverage = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string trading_asset = 3;
string collateral_asset = 4;
cosmos.base.v1beta1.Coin collateral = 4 [(gogoproto.nullable) = false ] ;
string discount = 5 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string take_profit_price = 6 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

message QueryMinCollateralResponse {
message QueryOpenEstimationResponse {
Position position = 1;
string leverage = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string trading_asset = 3;
cosmos.base.v1beta1.DecCoin min_collateral = 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 collateral = 4 [(gogoproto.nullable) = false ] ;
cosmos.base.v1beta1.Coin min_collateral = 5 [(gogoproto.nullable) = false ] ;
bool valid_collateral = 6;
cosmos.base.v1beta1.Coin position_size = 7 [(gogoproto.nullable) = false ] ;
string swap_fee = 8 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string discount = 9 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string open_price = 10 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string take_profit_price = 11 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string liquidation_price = 12 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string estimated_pnl = 13 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin available_liquidity = 14 [(gogoproto.nullable) = false ] ;
}
2 changes: 1 addition & 1 deletion wasmbindings/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ type ElysQuery struct {
MarginPool *margintypes.QueryGetPoolRequest `json:"margin_pool,omitempty"`
MarginPools *margintypes.QueryAllPoolRequest `json:"margin_pools,omitempty"`
MarginMTP *margintypes.MTPRequest `json:"margin_mtp,omitempty"`
MarginMinCollateral *margintypes.QueryMinCollateralRequest `json:"margin_min_collateral,omitempty"`
MarginOpenEstimation *margintypes.QueryOpenEstimationRequest `json:"margin_open_estimation,omitempty"`

// oracle queriers
OracleParams *oracletypes.QueryParamsRequest `json:"oracle_params,omitempty"`
Expand Down
2 changes: 1 addition & 1 deletion x/amm/client/wasm/query_amm_price_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (oq *Querier) queryAmmPriceByDenom(ctx sdk.Context, query *ammtypes.QueryAM
tokenIn := query.TokenIn
discount := query.Discount

spotPrice, _, _, _, _, err := oq.keeper.CalcInRouteSpotPrice(ctx, tokenIn, routes, discount)
spotPrice, _, _, _, _, err := oq.keeper.CalcInRouteSpotPrice(ctx, tokenIn, routes, discount, sdk.ZeroDec())
if err != nil {
return nil, errorsmod.Wrap(err, "failed to get in route by denom")
}
Expand Down
7 changes: 6 additions & 1 deletion x/amm/keeper/calc_in_route_spot_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ 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) (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, error) {
if routes == nil || len(routes) == 0 {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrEmptyRoutes
}
Expand Down Expand Up @@ -35,6 +35,11 @@ func (k Keeper) CalcInRouteSpotPrice(ctx sdk.Context, tokenIn sdk.Coin, routes [
// Get Pool swap fee
swapFee := pool.GetPoolParams().SwapFee

// Override swap fee if applicable
if overrideSwapFee.IsPositive() {
swapFee = overrideSwapFee
}

// Apply discount to swap fee if applicable
swapFee, _, err := k.ApplyDiscount(ctx, swapFee, discount, k.BrokerAddress(ctx))
if err != nil {
Expand Down
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())
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())
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())
_, _, _, _, _, 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())
_, _, _, _, _, err = k.CalcInRouteSpotPrice(ctx, tokenIn, routes, sdk.ZeroDec(), sdk.ZeroDec())
require.Error(t, err)
}
7 changes: 6 additions & 1 deletion x/amm/keeper/calc_out_route_spot_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ 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) (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, error) {
if routes == nil || len(routes) == 0 {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrEmptyRoutes
}
Expand Down Expand Up @@ -35,6 +35,11 @@ func (k Keeper) CalcOutRouteSpotPrice(ctx sdk.Context, tokenOut sdk.Coin, routes
// Get Pool swap fee
swapFee := pool.GetPoolParams().SwapFee

// Override swap fee if applicable
if overrideSwapFee.IsPositive() {
swapFee = overrideSwapFee
}

// Apply discount to swap fee if applicable
swapFee, _, err := k.ApplyDiscount(ctx, swapFee, discount, k.BrokerAddress(ctx))
if err != nil {
Expand Down
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())
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())
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())
_, _, _, _, _, 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())
_, _, _, _, _, err = k.CalcOutRouteSpotPrice(ctx, tokenOut, routes, sdk.ZeroDec(), sdk.ZeroDec())
require.Error(t, err)
}
11 changes: 6 additions & 5 deletions x/amm/keeper/calc_swap_estimation_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ func (k Keeper) CalcSwapEstimationByDenom(
denomOut string,
baseCurrency string,
discount sdk.Dec,
overrideSwapFee sdk.Dec,
) (
inRoute []*types.SwapAmountInRoute,
outRoute []*types.SwapAmountOutRoute,
outAmount sdk.Coin,
spotPrice sdk.Dec,
swapFee sdk.Dec,
swapFeeOut sdk.Dec,
discountOut sdk.Dec,
availableLiquidity sdk.Coin,
err error,
Expand All @@ -29,11 +30,11 @@ func (k Keeper) CalcSwapEstimationByDenom(
if err != nil {
return nil, nil, sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, err
}
spotPrice, tokenOut, swapFee, _, availableLiquidity, err := k.CalcInRouteSpotPrice(ctx, amount, inRoute, discount)
spotPrice, tokenOut, swapFeeOut, _, availableLiquidity, err := k.CalcInRouteSpotPrice(ctx, amount, inRoute, discount, overrideSwapFee)
if err != nil {
return nil, nil, sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, err
}
return inRoute, nil, tokenOut, spotPrice, swapFee, discount, availableLiquidity, nil
return inRoute, nil, tokenOut, spotPrice, swapFeeOut, discount, availableLiquidity, nil
}

// if amount denom is equal to denomOut, calculate swap estimation by denomOut
Expand All @@ -42,11 +43,11 @@ func (k Keeper) CalcSwapEstimationByDenom(
if err != nil {
return nil, nil, sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, err
}
spotPrice, tokenIn, swapFee, _, availableLiquidity, err := k.CalcOutRouteSpotPrice(ctx, amount, outRoute, discount)
spotPrice, tokenIn, swapFeeOut, _, availableLiquidity, err := k.CalcOutRouteSpotPrice(ctx, amount, outRoute, discount, overrideSwapFee)
if err != nil {
return nil, nil, sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, err
}
return nil, outRoute, tokenIn, spotPrice, swapFee, discount, availableLiquidity, nil
return nil, outRoute, tokenIn, spotPrice, swapFeeOut, discount, availableLiquidity, nil
}

// if amount denom is neither equal to denomIn nor denomOut, return error
Expand Down
6 changes: 3 additions & 3 deletions x/amm/keeper/calc_swap_estimation_by_denom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestCalcSwapEstimationByDenom(t *testing.T) {
amount := sdk.NewCoin("denom1", sdk.NewInt(100))
accountedPoolKeeper.On("GetAccountedBalance", ctx, uint64(1), "denom1").Return(sdk.NewInt(1000))
accountedPoolKeeper.On("GetAccountedBalance", ctx, uint64(1), "denom2").Return(sdk.NewInt(1000))
inRoute, outRoute, tokenOut, spotPrice, _, _, _, err := k.CalcSwapEstimationByDenom(ctx, amount, "denom1", "denom2", "baseCurrency", sdk.ZeroDec())
inRoute, outRoute, tokenOut, spotPrice, _, _, _, err := k.CalcSwapEstimationByDenom(ctx, amount, "denom1", "denom2", "baseCurrency", sdk.ZeroDec(), sdk.ZeroDec())
require.NoError(t, err)
require.NotNil(t, inRoute)
require.Nil(t, outRoute)
Expand All @@ -27,7 +27,7 @@ func TestCalcSwapEstimationByDenom(t *testing.T) {
amount = sdk.NewCoin("denom2", sdk.NewInt(100))
accountedPoolKeeper.On("GetAccountedBalance", ctx, uint64(1), "denom2").Return(sdk.NewInt(1000))
accountedPoolKeeper.On("GetAccountedBalance", ctx, uint64(1), "denom1").Return(sdk.NewInt(1000))
inRoute, outRoute, tokenOut, spotPrice, _, _, _, err = k.CalcSwapEstimationByDenom(ctx, amount, "denom1", "denom2", "baseCurrency", sdk.ZeroDec())
inRoute, outRoute, tokenOut, spotPrice, _, _, _, err = k.CalcSwapEstimationByDenom(ctx, amount, "denom1", "denom2", "baseCurrency", sdk.ZeroDec(), sdk.ZeroDec())
require.NoError(t, err)
require.Nil(t, inRoute)
require.NotNil(t, outRoute)
Expand All @@ -36,6 +36,6 @@ func TestCalcSwapEstimationByDenom(t *testing.T) {

// Test with invalid amount denom
amount = sdk.NewCoin("invalid", sdk.NewInt(1000))
_, _, _, _, _, _, _, err = k.CalcSwapEstimationByDenom(ctx, amount, "denom1", "denom2", "baseCurrency", sdk.ZeroDec())
_, _, _, _, _, _, _, err = k.CalcSwapEstimationByDenom(ctx, amount, "denom1", "denom2", "baseCurrency", sdk.ZeroDec(), sdk.ZeroDec())
require.Error(t, err)
}
2 changes: 1 addition & 1 deletion x/amm/keeper/msg_server_swap_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func (k msgServer) SwapByDenom(goCtx context.Context, msg *types.MsgSwapByDenom)
}
baseCurrency := entry.Denom

inRoute, outRoute, _, spotPrice, _, _, _, err := k.CalcSwapEstimationByDenom(ctx, msg.Amount, msg.DenomIn, msg.DenomOut, baseCurrency, msg.Discount)
inRoute, outRoute, _, spotPrice, _, _, _, err := k.CalcSwapEstimationByDenom(ctx, msg.Amount, msg.DenomIn, msg.DenomOut, baseCurrency, msg.Discount, sdk.ZeroDec())
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion x/amm/keeper/query_swap_estimation.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (k Keeper) SwapEstimation(goCtx context.Context, req *types.QuerySwapEstima

ctx := sdk.UnwrapSDKContext(goCtx)

spotPrice, tokenOut, swapFee, discount, availableLiquidity, err := k.CalcInRouteSpotPrice(ctx, req.TokenIn, req.Routes, req.Discount)
spotPrice, tokenOut, swapFee, discount, availableLiquidity, err := k.CalcInRouteSpotPrice(ctx, req.TokenIn, req.Routes, req.Discount, sdk.ZeroDec())
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion x/amm/keeper/query_swap_estimation_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (k Keeper) SwapEstimationByDenom(goCtx context.Context, req *types.QuerySwa

_ = baseCurrency

inRoute, outRoute, amount, spotPrice, swapFee, discount, availableLiquidity, err := k.CalcSwapEstimationByDenom(ctx, req.Amount, req.DenomIn, req.DenomOut, baseCurrency, req.Discount)
inRoute, outRoute, amount, spotPrice, swapFee, discount, availableLiquidity, err := k.CalcSwapEstimationByDenom(ctx, req.Amount, req.DenomIn, req.DenomOut, baseCurrency, req.Discount, sdk.ZeroDec())
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion x/margin/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func GetQueryCmd(queryRoute string) *cobra.Command {
cmd.AddCommand(CmdListPool())
cmd.AddCommand(CmdShowPool())
cmd.AddCommand(CmdMtp())
cmd.AddCommand(CmdMinCollateral())
cmd.AddCommand(CmdOpenEstimation())

// this line is used by starport scaffolding # 1

Expand Down
Loading

0 comments on commit e99e163

Please sign in to comment.