Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: apply discount to swap msgs #271

Merged
merged 2 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions docs/static/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37851,6 +37851,8 @@ paths:
pool_creation_fee:
type: string
format: uint64
broker_address:
type: string
description: >-
QueryParamsResponse is response type for the Query/Params RPC
method.
Expand Down Expand Up @@ -82920,10 +82922,28 @@ definitions:

NOTE: The amount field is an Int which implements the custom method
signatures required by gogoproto.
route:
in_route:
type: array
items:
type: string
type: object
properties:
pool_id:
type: string
format: uint64
token_out_denom:
type: string
out_route:
type: array
items:
type: object
properties:
pool_id:
type: string
format: uint64
token_in_denom:
type: string
spot_price:
type: string
discount:
type: string
elys.amm.MsgSwapExactAmountInResponse:
Expand Down Expand Up @@ -82965,6 +82985,8 @@ definitions:
pool_creation_fee:
type: string
format: uint64
broker_address:
type: string
description: Params defines the parameters for the module.
elys.amm.Pool:
type: object
Expand Down Expand Up @@ -83339,6 +83361,8 @@ definitions:
pool_creation_fee:
type: string
format: uint64
broker_address:
type: string
description: QueryParamsResponse is response type for the Query/Params RPC method.
elys.amm.QuerySlippageTrackAllResponse:
type: object
Expand Down
1 change: 1 addition & 0 deletions proto/elys/amm/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ message Params {
option (gogoproto.goproto_stringer) = false;

uint64 pool_creation_fee = 1;
string broker_address = 2;
}
29 changes: 18 additions & 11 deletions proto/elys/amm/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package elys.amm;

import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
import "elys/amm/params.proto";
import "elys/amm/swap_route.proto";
import "elys/amm/pool_params.proto";
import "elys/amm/pool_asset.proto";
Expand All @@ -17,9 +18,10 @@ service Msg {
rpc ExitPool (MsgExitPool ) returns (MsgExitPoolResponse );
rpc SwapExactAmountIn (MsgSwapExactAmountIn ) returns (MsgSwapExactAmountInResponse );
rpc SwapExactAmountOut (MsgSwapExactAmountOut ) returns (MsgSwapExactAmountOutResponse );
rpc FeedMultipleExternalLiquidity (MsgFeedMultipleExternalLiquidity) returns (MsgFeedMultipleExternalLiquidityResponse);
rpc SwapByDenom (MsgSwapByDenom ) returns (MsgSwapByDenomResponse );
rpc FeedMultipleExternalLiquidity (MsgFeedMultipleExternalLiquidity) returns (MsgFeedMultipleExternalLiquidityResponse);
}

message MsgCreatePool {
string sender = 1;
PoolParams pool_params = 2;
Expand Down Expand Up @@ -60,21 +62,26 @@ message MsgSwapExactAmountIn {
repeated SwapAmountInRoute routes = 2 [(gogoproto.nullable) = false ] ;
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];

}

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];
}

message MsgSwapExactAmountOut {
string sender = 1;
repeated SwapAmountOutRoute routes = 2 [(gogoproto.nullable) = false ] ;
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];
}

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];
}

message MsgFeedMultipleExternalLiquidity {
Expand All @@ -97,19 +104,19 @@ message ExternalLiquidity {
}

message MsgSwapByDenom {
string sender = 1;
cosmos.base.v1beta1.Coin amount = 2 [(gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin min_amount = 3 [(gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin max_amount = 4 [(gogoproto.nullable) = false];
string sender = 1;
cosmos.base.v1beta1.Coin amount = 2 [(gogoproto.nullable) = false ] ;
cosmos.base.v1beta1.Coin min_amount = 3 [(gogoproto.nullable) = false ] ;
cosmos.base.v1beta1.Coin max_amount = 4 [(gogoproto.nullable) = false ] ;
string denom_in = 5;
string denom_out = 6;
string discount = 7 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string discount = 7 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

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

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

const (
FlagDiscount = "discount"
flagPacketTimeoutTimestamp = "packet-timeout-timestamp"
listSeparator = ","
)
Expand Down
1 change: 0 additions & 1 deletion x/amm/client/cli/tx_swap_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ var _ = strconv.Itoa(0)
const (
FlagMinAmount = "min-amount"
FlagMaxAmount = "max-amount"
FlagDiscount = "discount"
)

func CmdSwapByDenom() *cobra.Command {
Expand Down
12 changes: 12 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 @@ -44,6 +44,15 @@ func CmdSwapExactAmountIn() *cobra.Command {
}
argSwapRouteDenoms := strings.Split(args[3], listSeparator)

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

clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
Expand All @@ -55,6 +64,7 @@ func CmdSwapExactAmountIn() *cobra.Command {
argTokenOutMinAmount,
argSwapRoutePoolIds,
argSwapRouteDenoms,
discount,
)
if err := msg.ValidateBasic(); err != nil {
return err
Expand All @@ -65,5 +75,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)")

return cmd
}
12 changes: 12 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 @@ -44,6 +44,15 @@ func CmdSwapExactAmountOut() *cobra.Command {
}
argSwapRouteDenoms := strings.Split(args[3], listSeparator)

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

clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
Expand All @@ -55,6 +64,7 @@ func CmdSwapExactAmountOut() *cobra.Command {
argTokenOutMaxAmount,
argSwapRoutePoolIds,
argSwapRouteDenoms,
discount,
)
if err := msg.ValidateBasic(); err != nil {
return err
Expand All @@ -65,5 +75,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)")

return cmd
}
4 changes: 2 additions & 2 deletions x/amm/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ 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))
_, err = k.RouteExactAmountIn(ctx, sender, msg.Routes, msg.TokenIn, math.Int(msg.TokenOutMinAmount), msg.Discount)
if err != nil {
return err
}
Expand All @@ -38,7 +38,7 @@ 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)
_, err = k.RouteExactAmountOut(ctx, sender, msg.Routes, msg.TokenInMaxAmount, msg.TokenOut, msg.Discount)
if err != nil {
return err
}
Expand Down
12 changes: 12 additions & 0 deletions x/amm/keeper/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenIn: sdk.NewInt64Coin(ptypes.Elys, 10000),
TokenOutMinAmount: sdk.ZeroInt(),
Discount: sdk.ZeroDec(),
},
},
expSwapOrder: []uint64{0},
Expand All @@ -52,6 +53,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenIn: sdk.NewInt64Coin(ptypes.Elys, 10000),
TokenOutMinAmount: sdk.ZeroInt(),
Discount: sdk.ZeroDec(),
},
&types.MsgSwapExactAmountIn{
Sender: sender.String(),
Expand All @@ -63,6 +65,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenIn: sdk.NewInt64Coin(ptypes.BaseCurrency, 8000),
TokenOutMinAmount: sdk.ZeroInt(),
Discount: sdk.ZeroDec(),
},
},
expSwapOrder: []uint64{1, 0},
Expand All @@ -81,6 +84,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenIn: sdk.NewInt64Coin(ptypes.Elys, 11000),
TokenOutMinAmount: sdk.ZeroInt(),
Discount: sdk.ZeroDec(),
},
&types.MsgSwapExactAmountIn{
Sender: sender.String(),
Expand All @@ -92,6 +96,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenIn: sdk.NewInt64Coin(ptypes.BaseCurrency, 8000),
TokenOutMinAmount: sdk.ZeroInt(),
Discount: sdk.ZeroDec(),
},
&types.MsgSwapExactAmountIn{
Sender: sender.String(),
Expand All @@ -103,6 +108,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenIn: sdk.NewInt64Coin(ptypes.BaseCurrency, 1000),
TokenOutMinAmount: sdk.ZeroInt(),
Discount: sdk.ZeroDec(),
},
},
expSwapOrder: []uint64{1, 0, 2},
Expand All @@ -121,6 +127,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenIn: sdk.NewInt64Coin(ptypes.Elys, 11000),
TokenOutMinAmount: sdk.ZeroInt(),
Discount: sdk.ZeroDec(),
},
&types.MsgSwapExactAmountOut{
Sender: sender.String(),
Expand All @@ -132,6 +139,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenOut: sdk.NewInt64Coin(ptypes.Elys, 8000),
TokenInMaxAmount: sdk.NewInt(1000000),
Discount: sdk.ZeroDec(),
},
&types.MsgSwapExactAmountIn{
Sender: sender.String(),
Expand All @@ -143,6 +151,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenIn: sdk.NewInt64Coin(ptypes.BaseCurrency, 1000),
TokenOutMinAmount: sdk.ZeroInt(),
Discount: sdk.ZeroDec(),
},
},
expSwapOrder: []uint64{2, 1, 0},
Expand All @@ -161,6 +170,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenIn: sdk.NewInt64Coin(ptypes.Elys, 11000),
TokenOutMinAmount: sdk.ZeroInt(),
Discount: sdk.ZeroDec(),
},
&types.MsgSwapExactAmountOut{
Sender: sender.String(),
Expand All @@ -172,6 +182,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenOut: sdk.NewInt64Coin(ptypes.Elys, 8000),
TokenInMaxAmount: sdk.NewInt(1000000),
Discount: sdk.ZeroDec(),
},
&types.MsgSwapExactAmountIn{
Sender: sender.String(),
Expand All @@ -187,6 +198,7 @@ func (suite *KeeperTestSuite) TestExecuteSwapRequests() {
},
TokenIn: sdk.NewInt64Coin(ptypes.BaseCurrency, 1000),
TokenOutMinAmount: sdk.ZeroInt(),
Discount: sdk.ZeroDec(),
},
},
expSwapOrder: []uint64{2, 1, 0},
Expand Down
24 changes: 24 additions & 0 deletions x/amm/keeper/apply_discount.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/elys-network/elys/x/amm/types"
)

// ApplyDiscount applies discount to swap fee if applicable
func (k Keeper) ApplyDiscount(ctx sdk.Context, swapFee sdk.Dec, discount sdk.Dec, sender string) (sdk.Dec, sdk.Dec, error) {
if discount.IsZero() {
return swapFee, sdk.ZeroDec(), nil
}

// check if discount is positive and signer address is broker address otherwise throw an error
if discount.IsPositive() && sender != k.BrokerAddress(ctx) {
return sdk.ZeroDec(), sdk.ZeroDec(), sdkerrors.Wrapf(types.ErrInvalidDiscount, "discount %s is positive and signer address %s is not broker address %s", discount, sender, k.BrokerAddress(ctx))
}

// apply discount percentage to swap fee
swapFee = swapFee.Mul(sdk.OneDec().Sub(discount))

return swapFee, discount, nil
}
Loading
Loading