github.com/gravity-devs/liquidity@v1.5.3/x/liquidity/handler_test.go (about)

     1  package liquidity_test
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	sdk "github.com/cosmos/cosmos-sdk/types"
     8  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
     9  	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/gravity-devs/liquidity/app"
    13  	"github.com/gravity-devs/liquidity/x/liquidity"
    14  	"github.com/gravity-devs/liquidity/x/liquidity/types"
    15  )
    16  
    17  func TestBadMsg(t *testing.T) {
    18  	simapp, ctx := app.CreateTestInput()
    19  	simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams())
    20  	handler := liquidity.NewHandler(simapp.LiquidityKeeper)
    21  	_, err := handler(ctx, nil)
    22  	require.ErrorIs(t, err, sdkerrors.ErrUnknownRequest)
    23  	_, err = handler(ctx, banktypes.NewMsgMultiSend(nil, nil))
    24  	require.ErrorIs(t, err, sdkerrors.ErrUnknownRequest)
    25  }
    26  
    27  func TestMsgServerCreatePool(t *testing.T) {
    28  	simapp, ctx := app.CreateTestInput()
    29  	simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams())
    30  	params := simapp.LiquidityKeeper.GetParams(ctx)
    31  
    32  	poolTypeID := types.DefaultPoolTypeID
    33  	addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee)
    34  
    35  	denomA := "uETH"
    36  	denomB := "uUSD"
    37  	denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB)
    38  
    39  	deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000)))
    40  	app.SaveAccount(simapp, ctx, addrs[0], deposit)
    41  
    42  	depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA)
    43  	depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB)
    44  	depositBalance := sdk.NewCoins(depositA, depositB)
    45  
    46  	require.Equal(t, deposit, depositBalance)
    47  
    48  	msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance)
    49  
    50  	handler := liquidity.NewHandler(simapp.LiquidityKeeper)
    51  	_, err := handler(ctx, msg)
    52  	require.NoError(t, err)
    53  
    54  	pools := simapp.LiquidityKeeper.GetAllPools(ctx)
    55  	require.Equal(t, 1, len(pools))
    56  	require.Equal(t, uint64(1), pools[0].Id)
    57  	require.Equal(t, uint64(1), simapp.LiquidityKeeper.GetNextPoolID(ctx)-1)
    58  	require.Equal(t, denomA, pools[0].ReserveCoinDenoms[0])
    59  	require.Equal(t, denomB, pools[0].ReserveCoinDenoms[1])
    60  
    61  	poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0])
    62  	creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom)
    63  	require.Equal(t, poolCoin, creatorBalance.Amount)
    64  
    65  	_, err = simapp.LiquidityKeeper.CreatePool(ctx, msg)
    66  	require.ErrorIs(t, err, types.ErrPoolAlreadyExists)
    67  }
    68  
    69  func TestMsgServerExecuteDeposit(t *testing.T) {
    70  	simapp, ctx := app.CreateTestInput()
    71  	simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams())
    72  	params := simapp.LiquidityKeeper.GetParams(ctx)
    73  
    74  	poolTypeID := types.DefaultPoolTypeID
    75  	addrs := app.AddTestAddrs(simapp, ctx, 4, params.PoolCreationFee)
    76  
    77  	denomA := "uETH"
    78  	denomB := "uUSD"
    79  	denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB)
    80  
    81  	deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000)))
    82  	app.SaveAccount(simapp, ctx, addrs[0], deposit)
    83  	app.SaveAccount(simapp, ctx, addrs[1], deposit)
    84  
    85  	depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA)
    86  	depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB)
    87  	depositBalance := sdk.NewCoins(depositA, depositB)
    88  
    89  	require.Equal(t, deposit, depositBalance)
    90  
    91  	depositA = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA)
    92  	depositB = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB)
    93  	depositBalance = sdk.NewCoins(depositA, depositB)
    94  
    95  	require.Equal(t, deposit, depositBalance)
    96  
    97  	createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance)
    98  
    99  	_, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg)
   100  	require.NoError(t, err)
   101  
   102  	pools := simapp.LiquidityKeeper.GetAllPools(ctx)
   103  	pool := pools[0]
   104  
   105  	poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool)
   106  
   107  	depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit)
   108  
   109  	handler := liquidity.NewHandler(simapp.LiquidityKeeper)
   110  	_, err = handler(ctx, depositMsg)
   111  	require.NoError(t, err)
   112  
   113  	poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId)
   114  	require.True(t, found)
   115  	msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch)
   116  	require.Equal(t, 1, len(msgs))
   117  
   118  	err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch)
   119  	require.NoError(t, err)
   120  
   121  	poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool)
   122  	depositorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom)
   123  	require.Equal(t, poolCoin.Sub(poolCoinBefore), depositorBalance.Amount)
   124  }
   125  
   126  func TestMsgServerExecuteWithdrawal(t *testing.T) {
   127  	simapp, ctx := app.CreateTestInput()
   128  	simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams())
   129  	params := simapp.LiquidityKeeper.GetParams(ctx)
   130  
   131  	poolTypeID := types.DefaultPoolTypeID
   132  	addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee)
   133  
   134  	denomA := "uETH"
   135  	denomB := "uUSD"
   136  	denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB)
   137  
   138  	deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000)))
   139  	app.SaveAccount(simapp, ctx, addrs[0], deposit)
   140  
   141  	depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA)
   142  	depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB)
   143  	depositBalance := sdk.NewCoins(depositA, depositB)
   144  
   145  	require.Equal(t, deposit, depositBalance)
   146  
   147  	createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance)
   148  
   149  	_, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg)
   150  	require.NoError(t, err)
   151  
   152  	pools := simapp.LiquidityKeeper.GetAllPools(ctx)
   153  	pool := pools[0]
   154  
   155  	poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool)
   156  	withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom)
   157  
   158  	fmt.Println(poolCoinBefore, withdrawerPoolCoinBefore.Amount)
   159  	require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount)
   160  	withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore))
   161  
   162  	handler := liquidity.NewHandler(simapp.LiquidityKeeper)
   163  	_, err = handler(ctx, withdrawMsg)
   164  	require.NoError(t, err)
   165  
   166  	poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId)
   167  	require.True(t, found)
   168  	msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch)
   169  	require.Equal(t, 1, len(msgs))
   170  
   171  	err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, msgs[0], poolBatch)
   172  	require.NoError(t, err)
   173  
   174  	poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool)
   175  	withdrawerPoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom)
   176  	require.True(t, true, poolCoinAfter.IsZero())
   177  	require.True(t, true, withdrawerPoolCoinAfter.IsZero())
   178  	withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0])
   179  	withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1])
   180  	require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]), withdrawerDenomABalance.Amount)
   181  	require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), withdrawerDenomBBalance.Amount)
   182  
   183  }
   184  
   185  func TestMsgServerGetLiquidityPoolMetadata(t *testing.T) {
   186  	simapp, ctx := app.CreateTestInput()
   187  	simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams())
   188  	params := simapp.LiquidityKeeper.GetParams(ctx)
   189  
   190  	poolTypeID := types.DefaultPoolTypeID
   191  	addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee)
   192  
   193  	denomA := "uETH"
   194  	denomB := "uUSD"
   195  	denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB)
   196  
   197  	deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000)))
   198  	app.SaveAccount(simapp, ctx, addrs[0], deposit)
   199  
   200  	depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA)
   201  	depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB)
   202  	depositBalance := sdk.NewCoins(depositA, depositB)
   203  
   204  	require.Equal(t, deposit, depositBalance)
   205  
   206  	msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance)
   207  
   208  	handler := liquidity.NewHandler(simapp.LiquidityKeeper)
   209  	_, err := handler(ctx, msg)
   210  	require.NoError(t, err)
   211  
   212  	pools := simapp.LiquidityKeeper.GetAllPools(ctx)
   213  	require.Equal(t, 1, len(pools))
   214  	require.Equal(t, uint64(1), pools[0].Id)
   215  	require.Equal(t, uint64(1), simapp.LiquidityKeeper.GetNextPoolID(ctx)-1)
   216  	require.Equal(t, denomA, pools[0].ReserveCoinDenoms[0])
   217  	require.Equal(t, denomB, pools[0].ReserveCoinDenoms[1])
   218  
   219  	poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0])
   220  	creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom)
   221  	require.Equal(t, poolCoin, creatorBalance.Amount)
   222  
   223  	_, err = simapp.LiquidityKeeper.CreatePool(ctx, msg)
   224  	require.ErrorIs(t, err, types.ErrPoolAlreadyExists)
   225  
   226  	metaData := simapp.LiquidityKeeper.GetPoolMetaData(ctx, pools[0])
   227  	require.Equal(t, pools[0].Id, metaData.PoolId)
   228  
   229  	reserveCoin := simapp.LiquidityKeeper.GetReserveCoins(ctx, pools[0])
   230  	require.Equal(t, reserveCoin, metaData.ReserveCoins)
   231  	require.Equal(t, msg.DepositCoins, metaData.ReserveCoins)
   232  
   233  	totalSupply := sdk.NewCoin(pools[0].PoolCoinDenom, simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]))
   234  	require.Equal(t, totalSupply, metaData.PoolCoinTotalSupply)
   235  	require.Equal(t, creatorBalance, metaData.PoolCoinTotalSupply)
   236  }
   237  
   238  func TestMsgServerSwap(t *testing.T) {
   239  	simapp, ctx := app.CreateTestInput()
   240  	simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams())
   241  	params := simapp.LiquidityKeeper.GetParams(ctx)
   242  	// init test app and context
   243  
   244  	// define test denom X, Y for Liquidity Pool
   245  	denomX, denomY := types.AlphabeticalDenomPair("denomX", "denomY")
   246  	X := params.MinInitDepositAmount
   247  	Y := params.MinInitDepositAmount
   248  
   249  	// init addresses for the test
   250  	addrs := app.AddTestAddrs(simapp, ctx, 20, params.PoolCreationFee)
   251  
   252  	// Create pool
   253  	// The create pool msg is not run in batch, but is processed immediately.
   254  	poolID := app.TestCreatePool(t, simapp, ctx, X, Y, denomX, denomY, addrs[0])
   255  
   256  	// In case of deposit, withdraw, and swap msg, unlike other normal tx msgs,
   257  	// collect them in the batch and perform an execution at once at the endblock.
   258  
   259  	// add a deposit to pool and run batch execution on endblock
   260  	app.TestDepositPool(t, simapp, ctx, X, Y, addrs[1:2], poolID, true)
   261  
   262  	// next block, reinitialize batch and increase batchIndex at beginBlocker,
   263  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
   264  	liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper)
   265  
   266  	// Create swap msg for test purposes and put it in the batch.
   267  	price, _ := sdk.NewDecFromStr("1.1")
   268  	priceY, _ := sdk.NewDecFromStr("1.2")
   269  	xOfferCoins := []sdk.Coin{sdk.NewCoin(denomX, sdk.NewInt(10000)),
   270  		sdk.NewCoin(denomX, sdk.NewInt(10000)),
   271  		sdk.NewCoin(denomX, sdk.NewInt(10000))}
   272  	yOfferCoins := []sdk.Coin{sdk.NewCoin(denomY, sdk.NewInt(5000))}
   273  	xOrderPrices := []sdk.Dec{price, price, price}
   274  	yOrderPrices := []sdk.Dec{priceY}
   275  	xOrderAddrs := addrs[1:4]
   276  	yOrderAddrs := addrs[5:6]
   277  
   278  	msg1 := app.GetSwapMsg(t, simapp, ctx, xOfferCoins, xOrderPrices, xOrderAddrs, poolID)
   279  	msg4 := app.GetSwapMsg(t, simapp, ctx, yOfferCoins, yOrderPrices, yOrderAddrs, poolID)
   280  
   281  	handler := liquidity.NewHandler(simapp.LiquidityKeeper)
   282  	_, err := handler(ctx, msg1[0])
   283  	require.NoError(t, err)
   284  	_, err = handler(ctx, msg1[1])
   285  	require.NoError(t, err)
   286  	_, err = handler(ctx, msg1[2])
   287  	require.NoError(t, err)
   288  	_, err = handler(ctx, msg4[0])
   289  	require.NoError(t, err)
   290  	batch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, poolID)
   291  	require.True(t, found)
   292  	notProcessedMsgs := simapp.LiquidityKeeper.GetAllNotProcessedPoolBatchSwapMsgStates(ctx, batch)
   293  	msgs := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStatesAsPointer(ctx, batch)
   294  	require.Equal(t, 4, len(msgs))
   295  	require.Equal(t, 4, len(notProcessedMsgs))
   296  }