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

Add custom recipient field for amm swap functions #278

Merged
merged 4 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
8 changes: 5 additions & 3 deletions proto/elys/amm/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ 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 discount = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

message MsgSwapExactAmountOut {
Expand All @@ -77,11 +77,12 @@ 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;
cosmic-vagabond marked this conversation as resolved.
Show resolved Hide resolved
}

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 discount = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

message MsgFeedMultipleExternalLiquidity {
Expand Down Expand Up @@ -111,6 +112,7 @@ 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 {
Expand Down
6 changes: 4 additions & 2 deletions x/amm/client/cli/tx_swap_by_denom.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ const (

func CmdSwapByDenom() *cobra.Command {
cmd := &cobra.Command{
Use: "swap-by-denom [amount] [denom-in] [denom-out]",
Use: "swap-by-denom [amount] [denom-in] [denom-out] [recipient]",
Short: "Swap an exact amount of tokens for a minimum of another token or a maximum amount of tokens for an exact amount on another token, similar to swapping a token on the trade screen GUI.",
Example: "elysd tx amm swap-by-denom 1000000000uatom uatom uusd --min-amount=1000000000uatom --max-amount=1000000000uatom --discount=0.1 --from jack --keyring-backend test",
Args: cobra.ExactArgs(3),
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) (err error) {
argAmount, err := sdk.ParseCoinNormalized(args[0])
if err != nil {
return err
}
argDenomIn := args[1]
argDenomOut := args[2]
argRecipient := args[3]
cosmic-vagabond marked this conversation as resolved.
Show resolved Hide resolved

minAmountStr, err := cmd.Flags().GetString(FlagMinAmount)
if err != nil {
Expand Down Expand Up @@ -72,6 +73,7 @@ func CmdSwapByDenom() *cobra.Command {

msg := types.NewMsgSwapByDenom(
clientCtx.GetFromAddress().String(),
argRecipient,
argAmount,
minAmount,
maxAmount,
Expand Down
7 changes: 5 additions & 2 deletions x/amm/client/cli/tx_swap_exact_amount_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ var _ = strconv.Itoa(0)

func CmdSwapExactAmountIn() *cobra.Command {
cmd := &cobra.Command{
Use: "swap-exact-amount-in [token-in] [token-out-min-amount] [swap-route-pool-ids] [swap-route-denoms]",
Use: "swap-exact-amount-in [token-in] [token-out-min-amount] [swap-route-pool-ids] [swap-route-denoms] [recipient]",
Short: "Swap an exact amount of tokens for a minimum of another token, similar to swapping a token on the trade screen GUI.",
Example: `elysd tx amm swap-exact-amount-in 100000uusdc 10000 0 uatom --from=treasury --keyring-backend=test --chain-id=elystestnet-1 --yes --gas=1000000`,
Args: cobra.ExactArgs(4),
Args: cobra.ExactArgs(5),
RunE: func(cmd *cobra.Command, args []string) (err error) {
argTokenIn, err := sdk.ParseCoinNormalized(args[0])
if err != nil {
Expand Down Expand Up @@ -53,13 +53,16 @@ func CmdSwapExactAmountIn() *cobra.Command {
return err
}

argRecipient := args[4]

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

msg := types.NewMsgSwapExactAmountIn(
clientCtx.GetFromAddress().String(),
argRecipient,
argTokenIn,
argTokenOutMinAmount,
argSwapRoutePoolIds,
Expand Down
7 changes: 5 additions & 2 deletions x/amm/client/cli/tx_swap_exact_amount_out.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ var _ = strconv.Itoa(0)

func CmdSwapExactAmountOut() *cobra.Command {
cmd := &cobra.Command{
Use: "swap-exact-amount-out [token-out] [token-out-max-amount] [swap-route-pool-ids] [swap-route-denoms]",
Use: "swap-exact-amount-out [token-out] [token-out-max-amount] [swap-route-pool-ids] [swap-route-denoms] [recipient]",
Short: "Swap a maximum amount of tokens for an exact amount of another token, similar to swapping a token on the trade screen GUI.",
Example: `elysd tx amm swap-exact-amount-out 100000uatom 200000 0 uusdc --from=treasury --keyring-backend=test --chain-id=elystestnet-1 --yes --gas=1000000`,
Args: cobra.ExactArgs(4),
Args: cobra.ExactArgs(5),
RunE: func(cmd *cobra.Command, args []string) (err error) {
argTokenOut, err := sdk.ParseCoinNormalized(args[0])
if err != nil {
Expand Down Expand Up @@ -53,13 +53,16 @@ func CmdSwapExactAmountOut() *cobra.Command {
return err
}

argRecipient := args[4]

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

msg := types.NewMsgSwapExactAmountOut(
clientCtx.GetFromAddress().String(),
argRecipient,
argTokenOut,
argTokenOutMaxAmount,
argSwapRoutePoolIds,
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
2 changes: 1 addition & 1 deletion x/amm/keeper/fee.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (k Keeper) SwapFeesToRevenueToken(ctx sdk.Context, pool types.Pool, fee sdk

// Settles balances between the tx sender and the pool to match the swap that was executed earlier.
// Also emits a swap event and updates related liquidity metrics.
err, _ = k.UpdatePoolForSwap(ctx, pool, poolRevenueAddress, tokenIn, tokenOutCoin, sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
err, _ = k.UpdatePoolForSwap(ctx, pool, poolRevenueAddress, poolRevenueAddress, tokenIn, tokenOutCoin, sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion x/amm/keeper/keeper_swap_exact_amount_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
func (k Keeper) SwapExactAmountIn(
ctx sdk.Context,
sender sdk.AccAddress,
recipient sdk.AccAddress,
pool types.Pool,
tokenIn sdk.Coin,
tokenOutDenom string,
Expand Down Expand Up @@ -61,7 +62,7 @@ func (k Keeper) SwapExactAmountIn(

// Settles balances between the tx sender and the pool to match the swap that was executed earlier.
// Also emits a swap event and updates related liquidity metrics.
err, swapOutFee := k.UpdatePoolForSwap(ctx, pool, sender, tokenIn, tokenOutCoin, sdk.ZeroDec(), swapFee, weightBalanceBonus)
err, swapOutFee := k.UpdatePoolForSwap(ctx, pool, sender, recipient, tokenIn, tokenOutCoin, sdk.ZeroDec(), swapFee, weightBalanceBonus)
if err != nil {
return math.Int{}, err
}
Expand Down
47 changes: 46 additions & 1 deletion x/amm/keeper/keeper_swap_exact_amount_in_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {
tokenOut sdk.Coin
weightBalanceBonus sdk.Dec
isOraclePool bool
useNewRecipient bool
expSenderBalance sdk.Coins
expRecipientBalance sdk.Coins
expPoolBalance sdk.Coins
expTreasuryBalance sdk.Coins
expPass bool
Expand All @@ -38,7 +40,9 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {
tokenOut: sdk.NewInt64Coin(ptypes.BaseCurrency, 10000),
weightBalanceBonus: sdk.ZeroDec(),
isOraclePool: false,
useNewRecipient: false,
expSenderBalance: sdk.Coins{},
expRecipientBalance: sdk.Coins{},
expPoolBalance: sdk.Coins{},
expTreasuryBalance: sdk.Coins{},
expPass: false,
Expand All @@ -55,7 +59,9 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {
tokenOut: sdk.NewInt64Coin(ptypes.BaseCurrency, 10000),
weightBalanceBonus: sdk.ZeroDec(),
isOraclePool: false,
useNewRecipient: false,
expSenderBalance: sdk.Coins{},
expRecipientBalance: sdk.Coins{},
expPoolBalance: sdk.Coins{},
expTreasuryBalance: sdk.Coins{},
expPass: false,
Expand All @@ -72,7 +78,9 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {
tokenOut: sdk.NewInt64Coin(ptypes.BaseCurrency, 9704),
weightBalanceBonus: sdk.ZeroDec(),
isOraclePool: false,
useNewRecipient: false,
expSenderBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 990000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1009704)},
expRecipientBalance: sdk.Coins{},
expPoolBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1010000), sdk.NewInt64Coin(ptypes.BaseCurrency, 990198)},
expTreasuryBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1000000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1000010)},
expPass: true,
Expand All @@ -89,7 +97,9 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {
tokenOut: sdk.NewInt64Coin(ptypes.BaseCurrency, 9900),
weightBalanceBonus: sdk.ZeroDec(),
isOraclePool: false,
useNewRecipient: false,
expSenderBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 990000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1009900)},
expRecipientBalance: sdk.Coins{},
expPoolBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1010000), sdk.NewInt64Coin(ptypes.BaseCurrency, 990100)},
expTreasuryBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1000000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1000000)},
expPass: true,
Expand All @@ -106,7 +116,9 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {
tokenOut: sdk.NewInt64Coin(ptypes.BaseCurrency, 9975),
weightBalanceBonus: sdk.ZeroDec(),
isOraclePool: true,
useNewRecipient: false,
expSenderBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 990000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1009975)},
expRecipientBalance: sdk.Coins{},
expPoolBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1010000), sdk.NewInt64Coin(ptypes.BaseCurrency, 990025)},
expTreasuryBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1000000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1000000)},
expPass: true,
Expand All @@ -123,7 +135,9 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {
tokenOut: sdk.NewInt64Coin(ptypes.BaseCurrency, 9900),
weightBalanceBonus: sdk.NewDecWithPrec(3, 1), // 30% bonus
isOraclePool: false,
useNewRecipient: false,
expSenderBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 990000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1009900)},
expRecipientBalance: sdk.Coins{},
expPoolBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1010000), sdk.NewInt64Coin(ptypes.BaseCurrency, 990100)},
expTreasuryBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1000000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1000000)},
expPass: true,
Expand All @@ -140,7 +154,28 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {
tokenOut: sdk.NewInt64Coin(ptypes.BaseCurrency, 9900),
weightBalanceBonus: sdk.NewDecWithPrec(3, 1), // 30% bonus
isOraclePool: false,
useNewRecipient: false,
expSenderBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 990000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1009900)},
expRecipientBalance: sdk.Coins{},
expPoolBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1010000), sdk.NewInt64Coin(ptypes.BaseCurrency, 990100)},
expTreasuryBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1000000), sdk.NewInt64Coin(ptypes.BaseCurrency, 100)},
expPass: true,
},
{
desc: "new recipient address",
senderInitBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1000000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1000000)},
poolInitBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1000000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1000000)},
treasuryInitBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1000000), sdk.NewInt64Coin(ptypes.BaseCurrency, 100)},
swapFeeIn: sdk.ZeroDec(),
swapFeeOut: sdk.ZeroDec(),
tokenIn: sdk.NewInt64Coin("uusda", 10000),
tokenOutMin: sdk.ZeroInt(),
tokenOut: sdk.NewInt64Coin(ptypes.BaseCurrency, 9900),
weightBalanceBonus: sdk.NewDecWithPrec(3, 1), // 30% bonus
isOraclePool: false,
useNewRecipient: true,
expSenderBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 990000), sdk.NewInt64Coin(ptypes.BaseCurrency, 1000000)},
expRecipientBalance: sdk.Coins{sdk.NewInt64Coin(ptypes.BaseCurrency, 9900)},
expPoolBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1010000), sdk.NewInt64Coin(ptypes.BaseCurrency, 990100)},
expTreasuryBalance: sdk.Coins{sdk.NewInt64Coin("uusda", 1000000), sdk.NewInt64Coin(ptypes.BaseCurrency, 100)},
expPass: true,
Expand All @@ -152,8 +187,12 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {

// bootstrap accounts
sender := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
recipient := sender
poolAddr := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
treasuryAddr := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
if tc.useNewRecipient {
recipient = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
}

// bootstrap balances
err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, tc.senderInitBalance)
Expand Down Expand Up @@ -205,7 +244,7 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {
TotalWeight: sdk.ZeroInt(),
}

tokenOut, err := suite.app.AmmKeeper.SwapExactAmountIn(suite.ctx, sender, pool, tc.tokenIn, tc.tokenOut.Denom, tc.tokenOutMin, tc.swapFeeIn)
tokenOut, err := suite.app.AmmKeeper.SwapExactAmountIn(suite.ctx, sender, recipient, pool, tc.tokenIn, tc.tokenOut.Denom, tc.tokenOutMin, tc.swapFeeIn)
if !tc.expPass {
suite.Require().Error(err)
} else {
Expand All @@ -220,6 +259,12 @@ func (suite *KeeperTestSuite) TestSwapExactAmountIn() {
balances = suite.app.BankKeeper.GetAllBalances(suite.ctx, sender)
suite.Require().Equal(balances.String(), tc.expSenderBalance.String())

if tc.useNewRecipient {
// check balance change on recipient
balances = suite.app.BankKeeper.GetAllBalances(suite.ctx, recipient)
suite.Require().Equal(balances.String(), tc.expRecipientBalance.String())
}

// check balance change on treasury
balances = suite.app.BankKeeper.GetAllBalances(suite.ctx, treasuryAddr)
suite.Require().Equal(balances.String(), tc.expTreasuryBalance.String())
Expand Down
3 changes: 2 additions & 1 deletion x/amm/keeper/keeper_swap_exact_amount_out.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
func (k Keeper) SwapExactAmountOut(
ctx sdk.Context,
sender sdk.AccAddress,
recipient sdk.AccAddress,
pool types.Pool,
tokenInDenom string,
tokenInMaxAmount math.Int,
Expand Down Expand Up @@ -54,7 +55,7 @@ func (k Keeper) SwapExactAmountOut(
return math.Int{}, sdkerrors.Wrapf(types.ErrLimitMaxAmount, "swap requires %s, which is greater than the amount %s", tokenIn, tokenInMaxAmount)
}

err, _ = k.UpdatePoolForSwap(ctx, pool, sender, tokenIn, tokenOut, swapFee, sdk.ZeroDec(), weightBalanceBonus)
err, _ = k.UpdatePoolForSwap(ctx, pool, sender, recipient, tokenIn, tokenOut, swapFee, sdk.ZeroDec(), weightBalanceBonus)
if err != nil {
return math.Int{}, err
}
Expand Down
Loading
Loading