Skip to content

Commit

Permalink
feat: apply discount to swap msgs (#271)
Browse files Browse the repository at this point in the history
* feat: apply discount to swap msgs

* test: fix
  • Loading branch information
cosmic-vagabond authored Nov 24, 2023
1 parent b810796 commit f19ae6f
Show file tree
Hide file tree
Showing 34 changed files with 970 additions and 148 deletions.
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

0 comments on commit f19ae6f

Please sign in to comment.