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

refactor(coinswap): returns the result value of swap #379

Closed
wants to merge 3 commits into from
Closed
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
259 changes: 176 additions & 83 deletions api/irismod/coinswap/tx.pulsar.go

Large diffs are not rendered by default.

39 changes: 18 additions & 21 deletions modules/coinswap/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Keeper struct {
feeCollectorName string
authority string
blockedAddrs map[string]bool
tradeFuncs map[types.TradeType]types.TradeFunc
}

// NewKeeper returns a coinswap keeper. It handles:
Expand All @@ -44,7 +45,7 @@ func NewKeeper(
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
}

return Keeper{
k := Keeper{
storeKey: key,
bk: bk,
ak: ak,
Expand All @@ -53,6 +54,13 @@ func NewKeeper(
feeCollectorName: feeCollectorName,
authority: authority,
}
k.tradeFuncs = map[types.TradeType]types.TradeFunc{
types.Buy: k.TradeInputForExactOutput,
types.Sell: k.TradeExactInputForOutput,
types.BuyDouble: k.doubleTradeInputForExactOutput,
types.SellDouble: k.doubleTradeExactInputForOutput,
}
return k
}

// Logger returns a module-specific logger.
Expand All @@ -61,25 +69,15 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
}

// Swap execute swap order in specified pool
func (k Keeper) Swap(ctx sdk.Context, msg *types.MsgSwapOrder) error {
var amount sdkmath.Int
var err error

standardDenom := k.GetStandardDenom(ctx)
isDoubleSwap := (msg.Input.Coin.Denom != standardDenom) &&
(msg.Output.Coin.Denom != standardDenom)

if msg.IsBuyOrder && isDoubleSwap {
amount, err = k.doubleTradeInputForExactOutput(ctx, msg.Input, msg.Output)
} else if msg.IsBuyOrder && !isDoubleSwap {
amount, err = k.TradeInputForExactOutput(ctx, msg.Input, msg.Output)
} else if !msg.IsBuyOrder && isDoubleSwap {
amount, err = k.doubleTradeExactInputForOutput(ctx, msg.Input, msg.Output)
} else if !msg.IsBuyOrder && !isDoubleSwap {
amount, err = k.TradeExactInputForOutput(ctx, msg.Input, msg.Output)
}
func (k Keeper) Swap(ctx sdk.Context, msg *types.MsgSwapOrder) (sdk.Coin, error) {
tradeType := types.GetTradeType(msg.IsBuyOrder,
k.GetStandardDenom(ctx),
msg.Input.Coin.Denom,
msg.Output.Coin.Denom,
)
amount, err := k.tradeFuncs[tradeType](ctx, msg.Input, msg.Output)
if err != nil {
return err
return amount, err
}

ctx.EventManager().EmitEvent(
Expand All @@ -95,8 +93,7 @@ func (k Keeper) Swap(ctx sdk.Context, msg *types.MsgSwapOrder) error {
),
),
)

return nil
return amount, nil
}

// AddLiquidity adds liquidity to the specified pool
Expand Down
7 changes: 5 additions & 2 deletions modules/coinswap/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,13 @@ func (m msgServer) SwapCoin(
)
}

if err := m.k.Swap(ctx, msg); err != nil {
amount, err := m.k.Swap(ctx, msg)
if err != nil {
return nil, err
}
return &types.MsgSwapCoinResponse{}, nil
return &types.MsgSwapCoinResponse{
Amount: amount,
}, nil
}

func (m msgServer) UpdateParams(
Expand Down
76 changes: 40 additions & 36 deletions modules/coinswap/keeper/swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,80 +69,82 @@ Sell exact amount of a token for buying another, one of them must be standard to
@param receipt: address of the receiver
@return: actual amount of the token to be bought
*/
func (k Keeper) TradeExactInputForOutput(ctx sdk.Context, input types.Input, output types.Output) (sdkmath.Int, error) {
func (k Keeper) TradeExactInputForOutput(ctx sdk.Context, input types.Input, output types.Output) (sdk.Coin, error) {
boughtTokenAmt, err := k.calculateWithExactInput(ctx, input.Coin, output.Coin.Denom)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
// assert that the calculated amount is more than the
// minimum amount the buyer is willing to buy.
if boughtTokenAmt.LT(output.Coin.Amount) {
return sdk.ZeroInt(), sdkerrors.Wrap(types.ErrConstraintNotMet, fmt.Sprintf("insufficient amount of %s, user expected: %s, actual: %s", output.Coin.Denom, output.Coin.Amount.String(), boughtTokenAmt.String()))
return sdk.Coin{}, sdkerrors.Wrap(types.ErrConstraintNotMet, fmt.Sprintf("insufficient amount of %s, user expected: %s, actual: %s", output.Coin.Denom, output.Coin.Amount.String(), boughtTokenAmt.String()))
}
boughtToken := sdk.NewCoin(output.Coin.Denom, boughtTokenAmt)

inputAddress, err := sdk.AccAddressFromBech32(input.Address)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
outputAddress, err := sdk.AccAddressFromBech32(output.Address)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}

if err := k.swapCoins(ctx, inputAddress, outputAddress, input.Coin, boughtToken); err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
return boughtTokenAmt, nil
return boughtToken, nil
}

/**
/*
*
Sell exact amount of a token for buying another, non of them are standard token
@param input: exact amount of the token to be sold
@param output: min amount of the token to be bought
@param sender: address of the sender
@param receipt: address of the receiver
@return: actual amount of the token to be bought
*/
func (k Keeper) doubleTradeExactInputForOutput(ctx sdk.Context, input types.Input, output types.Output) (sdkmath.Int, error) {
func (k Keeper) doubleTradeExactInputForOutput(ctx sdk.Context, input types.Input, output types.Output) (sdk.Coin, error) {
standardDenom := k.GetStandardDenom(ctx)
standardAmount, err := k.calculateWithExactInput(ctx, input.Coin, standardDenom)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
standardCoin := sdk.NewCoin(standardDenom, standardAmount)

inputAddress, err := sdk.AccAddressFromBech32(input.Address)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
outputAddress, err := sdk.AccAddressFromBech32(output.Address)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}

if err := k.swapCoins(ctx, inputAddress, outputAddress, input.Coin, standardCoin); err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}

boughtAmt, err := k.calculateWithExactInput(ctx, standardCoin, output.Coin.Denom)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
boughtToken := sdk.NewCoin(output.Coin.Denom, boughtAmt)
// assert that the calculated amount is less than the
// minimum amount the buyer is willing to buy.
if boughtAmt.LT(output.Coin.Amount) {
return sdk.ZeroInt(), sdkerrors.Wrap(types.ErrConstraintNotMet, fmt.Sprintf("insufficient amount of %s, user expected: %s, actual: %s", output.Coin.Denom, output.Coin.Amount.String(), boughtAmt.String()))
return sdk.Coin{}, sdkerrors.Wrap(types.ErrConstraintNotMet, fmt.Sprintf("insufficient amount of %s, user expected: %s, actual: %s", output.Coin.Denom, output.Coin.Amount.String(), boughtAmt.String()))
}

if err := k.swapCoins(ctx, inputAddress, outputAddress, standardCoin, boughtToken); err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
return boughtAmt, nil
return boughtToken, nil
}

/**
/*
*
Calculate the amount of the token to be paid based on the exact amount of the token to be bought
@param exactBoughtCoin
@param soldTokenDenom
Expand Down Expand Up @@ -178,85 +180,87 @@ func (k Keeper) calculateWithExactOutput(ctx sdk.Context, exactBoughtCoin sdk.Co
return soldTokenAmt, nil
}

/**
/*
*
Buy exact amount of a token by specifying the max amount of another token, one of them must be standard token
@param input : max amount of the token to be paid
@param output : exact amount of the token to be bought
@param sender : address of the sender
@param receipt : address of the receiver
@return : actual amount of the token to be paid
*/
func (k Keeper) TradeInputForExactOutput(ctx sdk.Context, input types.Input, output types.Output) (sdkmath.Int, error) {
func (k Keeper) TradeInputForExactOutput(ctx sdk.Context, input types.Input, output types.Output) (sdk.Coin, error) {
soldTokenAmt, err := k.calculateWithExactOutput(ctx, output.Coin, input.Coin.Denom)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
// assert that the calculated amount is less than the
// max amount the buyer is willing to pay.
if soldTokenAmt.GT(input.Coin.Amount) {
return sdk.ZeroInt(), sdkerrors.Wrap(types.ErrConstraintNotMet, fmt.Sprintf("insufficient amount of %s, user expected: %s, actual: %s", input.Coin.Denom, input.Coin.Amount.String(), soldTokenAmt.String()))
return sdk.Coin{}, sdkerrors.Wrap(types.ErrConstraintNotMet, fmt.Sprintf("insufficient amount of %s, user expected: %s, actual: %s", input.Coin.Denom, input.Coin.Amount.String(), soldTokenAmt.String()))
}
soldToken := sdk.NewCoin(input.Coin.Denom, soldTokenAmt)

inputAddress, err := sdk.AccAddressFromBech32(input.Address)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
outputAddress, err := sdk.AccAddressFromBech32(output.Address)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}

if err := k.swapCoins(ctx, inputAddress, outputAddress, soldToken, output.Coin); err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
return soldTokenAmt, nil
return soldToken, nil
}

/**
/*
*
Buy exact amount of a token by specifying the max amount of another token, non of them are standard token
@param input : max amount of the token to be paid
@param output : exact amount of the token to be bought
@param sender : address of the sender
@param receipt : address of the receiver
@return : actual amount of the token to be paid
*/
func (k Keeper) doubleTradeInputForExactOutput(ctx sdk.Context, input types.Input, output types.Output) (sdkmath.Int, error) {
func (k Keeper) doubleTradeInputForExactOutput(ctx sdk.Context, input types.Input, output types.Output) (sdk.Coin, error) {
standardDenom := k.GetStandardDenom(ctx)
soldStandardAmount, err := k.calculateWithExactOutput(ctx, output.Coin, standardDenom)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
soldStandardCoin := sdk.NewCoin(standardDenom, soldStandardAmount)

soldTokenAmt, err := k.calculateWithExactOutput(ctx, soldStandardCoin, input.Coin.Denom)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
soldTokenCoin := sdk.NewCoin(input.Coin.Denom, soldTokenAmt)

// assert that the calculated amount is less than the
// max amount the buyer is willing to sell.
if soldTokenAmt.GT(input.Coin.Amount) {
return sdk.ZeroInt(), sdkerrors.Wrap(types.ErrConstraintNotMet, fmt.Sprintf("insufficient amount of %s, user expected: %s, actual: %s", input.Coin.Denom, input.Coin.Amount.String(), soldTokenAmt.String()))
return sdk.Coin{}, sdkerrors.Wrap(types.ErrConstraintNotMet, fmt.Sprintf("insufficient amount of %s, user expected: %s, actual: %s", input.Coin.Denom, input.Coin.Amount.String(), soldTokenAmt.String()))
}

inputAddress, err := sdk.AccAddressFromBech32(input.Address)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
outputAddress, err := sdk.AccAddressFromBech32(output.Address)
if err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}

if err := k.swapCoins(ctx, inputAddress, outputAddress, soldTokenCoin, soldStandardCoin); err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
if err := k.swapCoins(ctx, inputAddress, outputAddress, soldStandardCoin, output.Coin); err != nil {
return sdk.ZeroInt(), err
return sdk.Coin{}, err
}
return soldTokenAmt, nil
return soldTokenCoin, nil
}

// GetInputPrice returns the amount of coins bought (calculated) given the input amount being sold (exact)
Expand Down
20 changes: 10 additions & 10 deletions modules/coinswap/keeper/swap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (suite *TestSuite) TestSwap() {
lptDenom := pool.LptDenom

// first swap buy order
err := suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
_, err := suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
suite.NoError(err)
reservePoolBalances := suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddr)
senderBalances := suite.app.BankKeeper.GetAllBalances(suite.ctx, sender)
Expand All @@ -112,7 +112,7 @@ func (suite *TestSuite) TestSwap() {
suite.Equal(expCoins.Sort().String(), senderBalances.Sort().String())

// second swap buy order
err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
_, err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
suite.NoError(err)
reservePoolBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddr)
senderBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, sender)
Expand All @@ -139,7 +139,7 @@ func (suite *TestSuite) TestSwap() {
)

// first swap sell order
err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
_, err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
suite.NoError(err)
reservePoolBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddr)
senderBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, sender)
Expand All @@ -157,7 +157,7 @@ func (suite *TestSuite) TestSwap() {
suite.Equal(expCoins.Sort().String(), senderBalances.Sort().String())

// second swap sell order
err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
_, err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
suite.NoError(err)
reservePoolBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddr)
senderBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, sender)
Expand Down Expand Up @@ -199,7 +199,7 @@ func (suite *TestSuite) TestDoubleSwap() {
lptDenom := pool.LptDenom

// first swap buy order
err := suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
_, err := suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
suite.NoError(err)
reservePoolBTCBalances := suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddrBTC)
reservePoolETHBalances := suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddrETH)
Expand All @@ -225,7 +225,7 @@ func (suite *TestSuite) TestDoubleSwap() {
suite.Equal(expCoins.Sort().String(), sender1Balances.Sort().String())

// second swap buy order
err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
_, err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
suite.NoError(err)
reservePoolBTCBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddrBTC)
reservePoolETHBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddrETH)
Expand Down Expand Up @@ -260,7 +260,7 @@ func (suite *TestSuite) TestDoubleSwap() {
)

// first swap sell order
err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
_, err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
suite.NoError(err)
reservePoolBTCBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddrBTC)
reservePoolETHBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddrETH)
Expand All @@ -286,7 +286,7 @@ func (suite *TestSuite) TestDoubleSwap() {
suite.Equal(expCoins.Sort().String(), sender2Balances.Sort().String())

// second swap sell order
err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
_, err = suite.app.CoinswapKeeper.Swap(suite.ctx, msg)
suite.NoError(err)
reservePoolBTCBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddrBTC)
reservePoolETHBalances = suite.app.BankKeeper.GetAllBalances(suite.ctx, reservePoolAddrETH)
Expand Down Expand Up @@ -391,7 +391,7 @@ func (suite *TestSuite) TestTradeInputForExactOutput() {
suite.NoError(err)

bought := sdk.NewCoins(outputCoin)
sold := sdk.NewCoins(sdk.NewCoin(denomStandard, amt))
sold := sdk.NewCoins(sdk.NewCoin(denomStandard, amt.Amount))

pb := poolBalances.Add(sold...).Sub(bought...)
sb := senderBlances.Add(bought...).Sub(sold...)
Expand Down Expand Up @@ -425,7 +425,7 @@ func (suite *TestSuite) TestTradeExactInputForOutput() {
suite.NoError(err)

sold := sdk.NewCoins(inputCoin)
bought := sdk.NewCoins(sdk.NewCoin(denomBTC, amt))
bought := sdk.NewCoins(sdk.NewCoin(denomBTC, amt.Amount))

pb := poolBalances.Add(sold...).Sub(bought...)
sb := senderBlances.Add(bought...).Sub(sold...)
Expand Down
Loading