Skip to content

Commit

Permalink
Merge branch 'main' into feat/incentive-apr
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmic-vagabond authored Nov 28, 2023
2 parents 7b6953e + 6576463 commit 0a2761d
Show file tree
Hide file tree
Showing 43 changed files with 1,446 additions and 285 deletions.
9 changes: 9 additions & 0 deletions proto/elys/amm/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,15 @@ message QueryAllDenomLiquidityResponse {
message QuerySwapEstimationRequest {
repeated SwapAmountInRoute routes = 1;
cosmos.base.v1beta1.Coin token_in = 2 [(gogoproto.nullable) = false];
string discount = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

message QuerySwapEstimationResponse {
string spot_price = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin token_out = 2 [(gogoproto.nullable) = false ] ;
string swapFee = 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 ] ;
}

message QuerySlippageTrackRequest {
Expand Down Expand Up @@ -185,15 +189,20 @@ message QuerySwapEstimationByDenomRequest {
cosmos.base.v1beta1.Coin amount = 1 [(gogoproto.nullable) = false];
string denom_in = 2;
string denom_out = 3;
string discount = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

message QuerySwapEstimationByDenomResponse {
repeated SwapAmountInRoute in_route = 1;
repeated SwapAmountOutRoute out_route = 2;
string spot_price = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin amount = 4 [(gogoproto.nullable) = false];
string swapFee = 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 ] ;
}

message QueryAMMPriceRequest {
cosmos.base.v1beta1.Coin token_in = 1 [(gogoproto.nullable) = false];
string discount = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}
16 changes: 12 additions & 4 deletions proto/elys/amm/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,14 @@ message MsgSwapExactAmountIn {
cosmos.base.v1beta1.Coin token_in = 3 [(gogoproto.nullable) = false ] ;
string token_out_min_amount = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false];
string discount = 5 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];

string recipient = 6;
}

message MsgSwapExactAmountInResponse {
string token_out_amount = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false];
string discount = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string swap_fee = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string discount = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string recipient = 4;
}

message MsgSwapExactAmountOut {
Expand All @@ -77,11 +79,14 @@ message MsgSwapExactAmountOut {
cosmos.base.v1beta1.Coin token_out = 3 [(gogoproto.nullable) = false ] ;
string token_in_max_amount = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false];
string discount = 5 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string recipient = 6;
}

message MsgSwapExactAmountOutResponse {
string token_in_amount = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false];
string discount = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string swap_fee = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string discount = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string recipient = 4;
}

message MsgFeedMultipleExternalLiquidity {
Expand Down Expand Up @@ -111,12 +116,15 @@ message MsgSwapByDenom {
string denom_in = 5;
string denom_out = 6;
string discount = 7 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string recipient = 8;
}

message MsgSwapByDenomResponse {
cosmos.base.v1beta1.Coin amount = 1 [(gogoproto.nullable) = false ] ;
repeated SwapAmountInRoute in_route = 2;
repeated SwapAmountOutRoute out_route = 3;
string spot_price = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string discount = 5 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (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];
string recipient = 7;
}
16 changes: 14 additions & 2 deletions x/amm/client/cli/query_swap_estimation.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ func CmdSwapEstimation() *cobra.Command {
})
}

discountStr, err := cmd.Flags().GetString(FlagDiscount)
if err != nil {
return err
}
discount, err := sdk.NewDecFromStr(discountStr)
if err != nil {
return err
}

clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
Expand All @@ -48,8 +57,9 @@ func CmdSwapEstimation() *cobra.Command {
queryClient := types.NewQueryClient(clientCtx)

params := &types.QuerySwapEstimationRequest{
Routes: reqRoutes,
TokenIn: reqTokenIn,
Routes: reqRoutes,
TokenIn: reqTokenIn,
Discount: discount,
}

res, err := queryClient.SwapEstimation(cmd.Context(), params)
Expand All @@ -63,5 +73,7 @@ func CmdSwapEstimation() *cobra.Command {

flags.AddQueryFlagsToCmd(cmd)

cmd.Flags().String(FlagDiscount, "0.0", "discount to apply to the swap fee")

return cmd
}
13 changes: 12 additions & 1 deletion x/amm/client/cli/query_swap_estimation_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ func CmdSwapEstimationByDenom() *cobra.Command {
reqDenomIn := args[1]
reqDenomOut := args[2]

discountStr, err := cmd.Flags().GetString(FlagDiscount)
if err != nil {
return err
}
discount, err := sdk.NewDecFromStr(discountStr)
if err != nil {
return err
}

clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
Expand All @@ -34,10 +43,10 @@ func CmdSwapEstimationByDenom() *cobra.Command {
queryClient := types.NewQueryClient(clientCtx)

params := &types.QuerySwapEstimationByDenomRequest{

Amount: reqAmount,
DenomIn: reqDenomIn,
DenomOut: reqDenomOut,
Discount: discount,
}

res, err := queryClient.SwapEstimationByDenom(cmd.Context(), params)
Expand All @@ -51,5 +60,7 @@ func CmdSwapEstimationByDenom() *cobra.Command {

flags.AddQueryFlagsToCmd(cmd)

cmd.Flags().String(FlagDiscount, "0.0", "discount to apply to the swap fee")

return cmd
}
1 change: 1 addition & 0 deletions x/amm/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var (

const (
FlagDiscount = "discount"
FlagRecipient = "recipient"
flagPacketTimeoutTimestamp = "packet-timeout-timestamp"
listSeparator = ","
)
Expand Down
7 changes: 7 additions & 0 deletions x/amm/client/cli/tx_swap_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,19 @@ func CmdSwapByDenom() *cobra.Command {
return err
}

recipient, err := cmd.Flags().GetString(FlagRecipient)
if err != nil {
return err
}

clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := types.NewMsgSwapByDenom(
clientCtx.GetFromAddress().String(),
recipient,
argAmount,
minAmount,
maxAmount,
Expand All @@ -91,6 +97,7 @@ func CmdSwapByDenom() *cobra.Command {
cmd.Flags().String(FlagMinAmount, "", "minimum amount of tokens to receive")
cmd.Flags().String(FlagMaxAmount, "", "maximum amount of tokens to send")
cmd.Flags().String(FlagDiscount, "0.0", "discount to apply to the swap fee (only smart contract broker can apply the discount)")
cmd.Flags().String(FlagRecipient, "", "optional recipient field for the tokens swapped to be sent to")

return cmd
}
7 changes: 7 additions & 0 deletions x/amm/client/cli/tx_swap_exact_amount_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,19 @@ func CmdSwapExactAmountIn() *cobra.Command {
return err
}

recipient, err := cmd.Flags().GetString(FlagRecipient)
if err != nil {
return err
}

clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := types.NewMsgSwapExactAmountIn(
clientCtx.GetFromAddress().String(),
recipient,
argTokenIn,
argTokenOutMinAmount,
argSwapRoutePoolIds,
Expand All @@ -76,6 +82,7 @@ func CmdSwapExactAmountIn() *cobra.Command {
flags.AddTxFlagsToCmd(cmd)

cmd.Flags().String(FlagDiscount, "0.0", "discount to apply to the swap fee (only smart contract broker can apply the discount)")
cmd.Flags().String(FlagRecipient, "", "optional recipient field for the tokens swapped to be sent to")

return cmd
}
7 changes: 7 additions & 0 deletions x/amm/client/cli/tx_swap_exact_amount_out.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,19 @@ func CmdSwapExactAmountOut() *cobra.Command {
return err
}

recipient, err := cmd.Flags().GetString(FlagRecipient)
if err != nil {
return err
}

clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := types.NewMsgSwapExactAmountOut(
clientCtx.GetFromAddress().String(),
recipient,
argTokenOut,
argTokenOutMaxAmount,
argSwapRoutePoolIds,
Expand All @@ -76,6 +82,7 @@ func CmdSwapExactAmountOut() *cobra.Command {
flags.AddTxFlagsToCmd(cmd)

cmd.Flags().String(FlagDiscount, "0.0", "discount to apply to the swap fee (only smart contract broker can apply the discount)")
cmd.Flags().String(FlagRecipient, "", "optional recipient field for the tokens swapped to be sent to")

return cmd
}
3 changes: 2 additions & 1 deletion x/amm/client/wasm/query_amm_price_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ func (oq *Querier) queryAmmPriceByDenom(ctx sdk.Context, query *ammtypes.QueryAM

routes := resp.InRoute
tokenIn := query.TokenIn
discount := query.Discount

spotPrice, _, err := oq.keeper.CalcInRouteSpotPrice(ctx, tokenIn, routes)
spotPrice, _, _, _, _, err := oq.keeper.CalcInRouteSpotPrice(ctx, tokenIn, routes, discount)
if err != nil {
return nil, errorsmod.Wrap(err, "failed to get in route by denom")
}
Expand Down
12 changes: 10 additions & 2 deletions x/amm/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ func (k Keeper) ApplySwapRequest(ctx sdk.Context, msg sdk.Msg) error {
if err != nil {
return err
}
_, err = k.RouteExactAmountIn(ctx, sender, msg.Routes, msg.TokenIn, math.Int(msg.TokenOutMinAmount), msg.Discount)
recipient, err := sdk.AccAddressFromBech32(msg.Recipient)
if err != nil {
recipient = sender
}
_, _, _, err = k.RouteExactAmountIn(ctx, sender, recipient, msg.Routes, msg.TokenIn, math.Int(msg.TokenOutMinAmount), msg.Discount)
if err != nil {
return err
}
Expand All @@ -38,7 +42,11 @@ func (k Keeper) ApplySwapRequest(ctx sdk.Context, msg sdk.Msg) error {
if err != nil {
return err
}
_, err = k.RouteExactAmountOut(ctx, sender, msg.Routes, msg.TokenInMaxAmount, msg.TokenOut, msg.Discount)
recipient, err := sdk.AccAddressFromBech32(msg.Recipient)
if err != nil {
recipient = sender
}
_, _, _, err = k.RouteExactAmountOut(ctx, sender, recipient, msg.Routes, msg.TokenInMaxAmount, msg.TokenOut, msg.Discount)
if err != nil {
return err
}
Expand Down
39 changes: 32 additions & 7 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) (sdk.Dec, sdk.Coin, error) {
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) {
if routes == nil || len(routes) == 0 {
return sdk.ZeroDec(), sdk.Coin{}, types.ErrEmptyRoutes
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, types.ErrEmptyRoutes
}

// Start with the initial token input
Expand All @@ -17,29 +17,54 @@ func (k Keeper) CalcInRouteSpotPrice(ctx sdk.Context, tokenIn sdk.Coin, routes [
// The final token out denom
var tokenOutDenom string

// Initialize the total discounted swap fee
totalDiscountedSwapFee := sdk.ZeroDec()

// Track the total available liquidity in the pool for final token out denom
var availableLiquidity sdk.Coin

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

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

// Get Pool swap fee
swapFee := pool.GetPoolParams().SwapFee

// Apply discount to swap fee if applicable
swapFee, _, err := k.ApplyDiscount(ctx, swapFee, discount, k.BrokerAddress(ctx))
if err != nil {
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, err
}

// Calculate the total discounted swap fee
totalDiscountedSwapFee = totalDiscountedSwapFee.Add(swapFee)

// Estimate swap
snapshot := k.GetPoolSnapshotOrSet(ctx, pool)
swapResult, err := k.CalcOutAmtGivenIn(ctx, pool.PoolId, k.oracleKeeper, &snapshot, tokensIn, tokenOutDenom, sdk.ZeroDec())
swapResult, err := k.CalcOutAmtGivenIn(ctx, pool.PoolId, k.oracleKeeper, &snapshot, tokensIn, tokenOutDenom, swapFee)

if err != nil {
return sdk.ZeroDec(), sdk.Coin{}, err
return sdk.ZeroDec(), sdk.Coin{}, sdk.ZeroDec(), sdk.ZeroDec(), sdk.Coin{}, err
}

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

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

// 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
}
availableLiquidity = poolAsset.Token
}

// Calculate the spot price given the initial token in and the final token out
Expand All @@ -51,5 +76,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, nil
return spotPrice, tokenOut, totalDiscountedSwapFee, discount, availableLiquidity, 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)
spotPrice, _, _, _, _, err := k.CalcInRouteSpotPrice(ctx, tokenIn, routes, 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)
spotPrice, _, _, _, _, err = k.CalcInRouteSpotPrice(ctx, tokenIn, routes, sdk.ZeroDec())
require.NoError(t, err)
require.NotZero(t, spotPrice)
accountedPoolKeeper.AssertExpectations(t)

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

// Test invalid pool
routes = []*types.SwapAmountInRoute{{PoolId: 9999, TokenOutDenom: "denom2"}}
_, _, err = k.CalcInRouteSpotPrice(ctx, tokenIn, routes)
_, _, _, _, _, err = k.CalcInRouteSpotPrice(ctx, tokenIn, routes, sdk.ZeroDec())
require.Error(t, err)
}
Loading

0 comments on commit 0a2761d

Please sign in to comment.