Skip to content

Commit

Permalink
Refactor coinswap (#219)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhiqiang Zhang authored Aug 10, 2021
1 parent a943bf5 commit cc9a8f0
Show file tree
Hide file tree
Showing 22 changed files with 1,318 additions and 321 deletions.
22 changes: 13 additions & 9 deletions modules/coinswap/client/rest/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ func (s *IntegrationTestSuite) SetupSuite() {

_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)

sdk.SetCoinDenomRegex(func() string {
return `[a-zA-Z][a-zA-Z0-9/\-]{2,127}`
})
}

func (s *IntegrationTestSuite) TearDownSuite() {
Expand All @@ -73,7 +77,7 @@ func (s *IntegrationTestSuite) TestCoinswap() {
maxSupply := int64(200000000)
mintable := true
baseURL := val.APIAddress
uniKitty := coinswaptypes.GetUniDenomFromDenom(symbol)
lptDenom := "lpt-1"

//------test GetCmdIssueToken()-------------
args := []string{
Expand Down Expand Up @@ -167,7 +171,7 @@ func (s *IntegrationTestSuite) TestCoinswap() {
coins := balances.Balances
s.Require().Equal("99999000", coins.AmountOf(symbol).String())
s.Require().Equal("399985965", coins.AmountOf(sdk.DefaultBondDenom).String())
s.Require().Equal("1000", coins.AmountOf(uniKitty).String())
s.Require().Equal("1000", coins.AmountOf(lptDenom).String())

url := fmt.Sprintf("%s/coinswap/liquidities/%s", baseURL, symbol)
resp, err := rest.GetRequest(url)
Expand Down Expand Up @@ -229,7 +233,7 @@ func (s *IntegrationTestSuite) TestCoinswap() {
coins = balances.Balances
s.Require().Equal("99996999", coins.AmountOf(symbol).String())
s.Require().Equal("399983955", coins.AmountOf(sdk.DefaultBondDenom).String())
s.Require().Equal("3000", coins.AmountOf(uniKitty).String())
s.Require().Equal("3000", coins.AmountOf(lptDenom).String())

url = fmt.Sprintf("%s/coinswap/liquidities/%s", baseURL, symbol)
resp, err = rest.GetRequest(url)
Expand Down Expand Up @@ -291,7 +295,7 @@ func (s *IntegrationTestSuite) TestCoinswap() {
coins = balances.Balances
s.Require().Equal("99995999", coins.AmountOf(symbol).String())
s.Require().Equal("399984693", coins.AmountOf(sdk.DefaultBondDenom).String())
s.Require().Equal("3000", coins.AmountOf(uniKitty).String())
s.Require().Equal("3000", coins.AmountOf(lptDenom).String())

url = fmt.Sprintf("%s/coinswap/liquidities/%s", baseURL, symbol)
resp, err = rest.GetRequest(url)
Expand Down Expand Up @@ -353,7 +357,7 @@ func (s *IntegrationTestSuite) TestCoinswap() {
coins = balances.Balances
s.Require().Equal("99996999", coins.AmountOf(symbol).String())
s.Require().Equal("399983930", coins.AmountOf(sdk.DefaultBondDenom).String())
s.Require().Equal("3000", coins.AmountOf(uniKitty).String())
s.Require().Equal("3000", coins.AmountOf(lptDenom).String())

url = fmt.Sprintf("%s/coinswap/liquidities/%s", baseURL, symbol)
resp, err = rest.GetRequest(url)
Expand All @@ -364,7 +368,7 @@ func (s *IntegrationTestSuite) TestCoinswap() {

// Test remove liquidity (remove part)
msgRemoveLiquidity := &coinswaptypes.MsgRemoveLiquidity{
WithdrawLiquidity: sdk.NewCoin(uniKitty, sdk.NewInt(2000)),
WithdrawLiquidity: sdk.NewCoin(lptDenom, sdk.NewInt(2000)),
MinToken: sdk.NewInt(2000),
MinStandardAmt: sdk.NewInt(2000),
Deadline: deadline.Unix(),
Expand Down Expand Up @@ -410,7 +414,7 @@ func (s *IntegrationTestSuite) TestCoinswap() {
coins = balances.Balances
s.Require().Equal("99998999", coins.AmountOf(symbol).String())
s.Require().Equal("399985923", coins.AmountOf(sdk.DefaultBondDenom).String())
s.Require().Equal("1000", coins.AmountOf(uniKitty).String())
s.Require().Equal("1000", coins.AmountOf(lptDenom).String())

url = fmt.Sprintf("%s/coinswap/liquidities/%s", baseURL, symbol)
resp, err = rest.GetRequest(url)
Expand All @@ -421,7 +425,7 @@ func (s *IntegrationTestSuite) TestCoinswap() {

// Test remove liquidity (remove all)
msgRemoveLiquidity = &coinswaptypes.MsgRemoveLiquidity{
WithdrawLiquidity: sdk.NewCoin(uniKitty, sdk.NewInt(1000)),
WithdrawLiquidity: sdk.NewCoin(lptDenom, sdk.NewInt(1000)),
MinToken: sdk.NewInt(1000),
MinStandardAmt: sdk.NewInt(1000),
Deadline: deadline.Unix(),
Expand Down Expand Up @@ -467,7 +471,7 @@ func (s *IntegrationTestSuite) TestCoinswap() {
coins = balances.Balances
s.Require().Equal("100000000", coins.AmountOf(symbol).String())
s.Require().Equal("399986915", coins.AmountOf(sdk.DefaultBondDenom).String())
s.Require().Equal("0", coins.AmountOf(uniKitty).String())
s.Require().Equal("0", coins.AmountOf(lptDenom).String())

url = fmt.Sprintf("%s/coinswap/liquidities/%s", baseURL, symbol)
resp, err = rest.GetRequest(url)
Expand Down
8 changes: 3 additions & 5 deletions modules/coinswap/client/rest/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ func addLiquidityHandlerFn(cliCtx client.Context) http.HandlerFunc {
func removeLiquidityHandlerFn(cliCtx client.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
denom := vars[RestPoolID]
lptDenom := vars[RestPoolID]

if err := sdk.ValidateDenom(denom); err != nil {
if err := sdk.ValidateDenom(lptDenom); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
Expand Down Expand Up @@ -151,10 +151,8 @@ func removeLiquidityHandlerFn(cliCtx client.Context) http.HandlerFunc {
return
}

uniDenom := types.GetUniDenomFromDenom(denom)

msg := types.NewMsgRemoveLiquidity(
minToken, sdk.NewCoin(uniDenom, liquidityAmt), minStandard, deadline.Unix(), req.Sender,
minToken, sdk.NewCoin(lptDenom, liquidityAmt), minStandard, deadline.Unix(), req.Sender,
)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
Expand Down
18 changes: 11 additions & 7 deletions modules/coinswap/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"google.golang.org/grpc/status"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

"github.com/irisnet/irismod/modules/coinswap/types"
)
Expand All @@ -19,19 +20,22 @@ func (k Keeper) Liquidity(c context.Context, req *types.QueryLiquidityRequest) (
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}

tokenDenom := req.Denom
uniDenom := types.GetUniDenomFromDenom(tokenDenom)

ctx := sdk.UnwrapSDKContext(c)
reservePool, err := k.GetReservePool(ctx, uniDenom)
poolId := types.GetPoolId(req.Denom)
pool, exists := k.GetPool(ctx, poolId)
if !exists {
return nil, sdkerrors.Wrapf(types.ErrReservePoolNotExists, "liquidity pool token: %s", req.Denom)
}

standardDenom := k.GetStandardDenom(ctx)
reservePool, err := k.GetPoolBalancesByLptDenom(ctx, pool.LptDenom)
if err != nil {
return nil, err
}

standardDenom := k.GetStandardDenom(ctx)
standard := sdk.NewCoin(standardDenom, reservePool.AmountOf(standardDenom))
token := sdk.NewCoin(tokenDenom, reservePool.AmountOf(tokenDenom))
liquidity := sdk.NewCoin(uniDenom, k.bk.GetSupply(ctx).GetTotal().AmountOf(uniDenom))
token := sdk.NewCoin(pool.CounterpartyDenom, reservePool.AmountOf(pool.CounterpartyDenom))
liquidity := sdk.NewCoin(pool.LptDenom, k.bk.GetSupply(ctx).GetTotal().AmountOf(pool.LptDenom))

swapParams := k.GetParams(ctx)
fee := swapParams.Fee.String()
Expand Down
104 changes: 40 additions & 64 deletions modules/coinswap/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,30 +105,31 @@ func (k Keeper) AddLiquidity(ctx sdk.Context, msg *types.MsgAddLiquidity) (sdk.C
return sdk.Coin{}, sdkerrors.Wrapf(types.ErrInvalidDenom,
"MaxToken: %s should not be StandardDenom", msg.MaxToken.String())
}
uniDenom := types.GetUniDenomFromDenom(msg.MaxToken.Denom)

liquidity := k.bk.GetSupply(ctx).GetTotal().AmountOf(uniDenom)

var mintLiquidityAmt sdk.Int
var depositToken sdk.Coin
var standardCoin = sdk.NewCoin(standardDenom, msg.ExactStandardAmt)

poolId := types.GetPoolId(msg.MaxToken.Denom)
pool, exists := k.GetPool(ctx, poolId)

// calculate amount of UNI to be minted for sender
// and coin amount to be deposited
if liquidity.IsZero() {
if !exists {
mintLiquidityAmt = msg.ExactStandardAmt
if mintLiquidityAmt.LT(msg.MinLiquidity) {
return sdk.Coin{}, sdkerrors.Wrap(types.ErrConstraintNotMet, fmt.Sprintf("liquidity amount not met, user expected: no less than %s, actual: %s", msg.MinLiquidity.String(), mintLiquidityAmt.String()))
}
depositToken = sdk.NewCoin(msg.MaxToken.Denom, msg.MaxToken.Amount)
pool = k.CreatePool(ctx, msg.MaxToken.Denom)
} else {
reservePool, err := k.GetReservePool(ctx, uniDenom)
balances, err := k.GetPoolBalances(ctx, pool.EscrowAddress)
if err != nil {
return sdk.Coin{}, err
}

standardReserveAmt := reservePool.AmountOf(standardDenom)
tokenReserveAmt := reservePool.AmountOf(msg.MaxToken.Denom)
standardReserveAmt := balances.AmountOf(standardDenom)
tokenReserveAmt := balances.AmountOf(msg.MaxToken.Denom)
liquidity := k.bk.GetSupply(ctx).GetTotal().AmountOf(pool.LptDenom)

mintLiquidityAmt = (liquidity.Mul(msg.ExactStandardAmt)).Quo(standardReserveAmt)
if mintLiquidityAmt.LT(msg.MinLiquidity) {
Expand All @@ -147,26 +148,35 @@ func (k Keeper) AddLiquidity(ctx sdk.Context, msg *types.MsgAddLiquidity) (sdk.C
return sdk.Coin{}, err
}

reservePoolAddress, err := sdk.AccAddressFromBech32(pool.EscrowAddress)
if err != nil {
return sdk.Coin{}, err
}

ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeAddLiquidity,
sdk.NewAttribute(types.AttributeValueSender, msg.Sender),
sdk.NewAttribute(types.AttributeValueTokenPair, types.GetTokenPairByDenom(msg.MaxToken.Denom, standardDenom)),
),
)

return k.addLiquidity(ctx, sender, standardCoin, depositToken, uniDenom, mintLiquidityAmt)
return k.addLiquidity(ctx, sender, reservePoolAddress, standardCoin, depositToken, pool.LptDenom, mintLiquidityAmt)
}

func (k Keeper) addLiquidity(ctx sdk.Context, sender sdk.AccAddress, standardCoin, token sdk.Coin, uniDenom string, mintLiquidityAmt sdk.Int) (sdk.Coin, error) {
func (k Keeper) addLiquidity(ctx sdk.Context,
sender sdk.AccAddress,
reservePoolAddress sdk.AccAddress,
standardCoin, token sdk.Coin,
lptDenom string,
mintLiquidityAmt sdk.Int,
) (sdk.Coin, error) {
depositedTokens := sdk.NewCoins(standardCoin, token)
poolAddr := types.GetReservePoolAddr(uniDenom)
// transfer deposited token into coinswaps Account
if err := k.bk.SendCoins(ctx, sender, poolAddr, depositedTokens); err != nil {
if err := k.bk.SendCoins(ctx, sender, reservePoolAddress, depositedTokens); err != nil {
return sdk.Coin{}, err
}

mintToken := sdk.NewCoin(uniDenom, mintLiquidityAmt)
mintToken := sdk.NewCoin(lptDenom, mintLiquidityAmt)
mintTokens := sdk.NewCoins(mintToken)
if err := k.bk.MintCoins(ctx, types.ModuleName, mintTokens); err != nil {
return sdk.Coin{}, err
Expand All @@ -181,30 +191,31 @@ func (k Keeper) addLiquidity(ctx sdk.Context, sender sdk.AccAddress, standardCoi
// RemoveLiquidity removes liquidity from the specified pool
func (k Keeper) RemoveLiquidity(ctx sdk.Context, msg *types.MsgRemoveLiquidity) (sdk.Coins, error) {
standardDenom := k.GetStandardDenom(ctx)
uniDenom := msg.WithdrawLiquidity.Denom

minTokenDenom, err := types.GetCoinDenomFromUniDenom(uniDenom)
if err != nil {
return nil, err
pool, exists := k.GetPoolByLptDenom(ctx, msg.WithdrawLiquidity.Denom)
if !exists {
return nil, sdkerrors.Wrapf(types.ErrReservePoolNotExists, "liquidity pool token: %s", msg.WithdrawLiquidity.Denom)
}

// check if reserve pool exists
reservePool, err := k.GetReservePool(ctx, uniDenom)
balances, err := k.GetPoolBalances(ctx, pool.EscrowAddress)
if err != nil {
return nil, err
}

standardReserveAmt := reservePool.AmountOf(standardDenom)
tokenReserveAmt := reservePool.AmountOf(minTokenDenom)
liquidityReserve := k.bk.GetSupply(ctx).GetTotal().AmountOf(uniDenom)
lptDenom := msg.WithdrawLiquidity.Denom
minTokenDenom := pool.CounterpartyDenom

standardReserveAmt := balances.AmountOf(standardDenom)
tokenReserveAmt := balances.AmountOf(minTokenDenom)
liquidityReserve := k.bk.GetSupply(ctx).GetTotal().AmountOf(lptDenom)
if standardReserveAmt.LT(msg.MinStandardAmt) {
return nil, sdkerrors.Wrap(types.ErrInsufficientFunds, fmt.Sprintf("insufficient %s funds, user expected: %s, actual: %s", standardDenom, msg.MinStandardAmt.String(), standardReserveAmt.String()))
}
if tokenReserveAmt.LT(msg.MinToken) {
return nil, sdkerrors.Wrap(types.ErrInsufficientFunds, fmt.Sprintf("insufficient %s funds, user expected: %s, actual: %s", minTokenDenom, msg.MinToken.String(), tokenReserveAmt.String()))
}
if liquidityReserve.LT(msg.WithdrawLiquidity.Amount) {
return nil, sdkerrors.Wrap(types.ErrInsufficientFunds, fmt.Sprintf("insufficient %s funds, user expected: %s, actual: %s", uniDenom, msg.WithdrawLiquidity.Amount.String(), liquidityReserve.String()))
return nil, sdkerrors.Wrap(types.ErrInsufficientFunds, fmt.Sprintf("insufficient %s funds, user expected: %s, actual: %s", lptDenom, msg.WithdrawLiquidity.Amount.String(), liquidityReserve.String()))
}

// calculate amount of UNI to be burned for sender
Expand All @@ -222,7 +233,6 @@ func (k Keeper) RemoveLiquidity(ctx sdk.Context, msg *types.MsgRemoveLiquidity)
if tokenWithdrawCoin.Amount.LT(msg.MinToken) {
return nil, sdkerrors.Wrap(types.ErrConstraintNotMet, fmt.Sprintf("token amount not met, user expected: no less than %s, actual: %s", sdk.NewCoin(minTokenDenom, msg.MinToken).String(), tokenWithdrawCoin.String()))
}
poolAddr := types.GetReservePoolAddr(uniDenom)

ctx.EventManager().EmitEvent(
sdk.NewEvent(
Expand All @@ -237,6 +247,11 @@ func (k Keeper) RemoveLiquidity(ctx sdk.Context, msg *types.MsgRemoveLiquidity)
return nil, err
}

poolAddr, err := sdk.AccAddressFromBech32(pool.EscrowAddress)
if err != nil {
return nil, err
}

return k.removeLiquidity(ctx, poolAddr, sender, deductUniCoin, irisWithdrawCoin, tokenWithdrawCoin)
}

Expand All @@ -258,29 +273,6 @@ func (k Keeper) removeLiquidity(ctx sdk.Context, poolAddr, sender sdk.AccAddress
return coins, k.bk.SendCoins(ctx, poolAddr, sender, coins)
}

// GetReservePool returns the total balance of the reserve pool at the provided denomination.
func (k Keeper) GetReservePool(ctx sdk.Context, uniDenom string) (coins sdk.Coins, err error) {
swapPoolAccAddr := types.GetReservePoolAddr(uniDenom)
acc := k.ak.GetAccount(ctx, swapPoolAccAddr)
if acc == nil {
return nil, sdkerrors.Wrap(types.ErrReservePoolNotExists, uniDenom)
}
return k.bk.GetAllBalances(ctx, acc.GetAddress()), nil
}

// ValidatePool Verify the legitimacy of the liquidity pool
func (k Keeper) ValidatePool(ctx sdk.Context, uniDenom string) error {
if err := types.ValidateUniDenom(uniDenom); err != nil {
return err
}

_, err := k.GetReservePool(ctx, uniDenom)
if err != nil {
return err
}
return nil
}

// GetParams gets the parameters for the coinswap module.
func (k Keeper) GetParams(ctx sdk.Context) types.Params {
var swapParams types.Params
Expand Down Expand Up @@ -310,19 +302,3 @@ func (k Keeper) GetStandardDenom(ctx sdk.Context) string {
k.cdc.MustUnmarshalBinaryBare(bz, &denomWrap)
return denomWrap.Value
}

// GetUniDenomFromDenoms returns the uni denom for the provided denominations.
func (k Keeper) GetUniDenomFromDenoms(ctx sdk.Context, denom1, denom2 string) (string, error) {
if denom1 == denom2 {
return "", types.ErrEqualDenom
}

standardDenom := k.GetStandardDenom(ctx)
if denom1 != standardDenom && denom2 != standardDenom {
return "", sdkerrors.Wrap(types.ErrNotContainStandardDenom, fmt.Sprintf("standard denom: %s,denom1: %s,denom2: %s", standardDenom, denom1, denom2))
}
if denom1 == standardDenom {
return fmt.Sprintf(types.FormatUniDenom, denom2), nil
}
return fmt.Sprintf(types.FormatUniDenom, denom1), nil
}
Loading

0 comments on commit cc9a8f0

Please sign in to comment.