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

     1  package simulation_test
     2  
     3  import (
     4  	"math/rand"
     5  	"strings"
     6  	"testing"
     7  
     8  	sdk "github.com/cosmos/cosmos-sdk/types"
     9  	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
    10  	minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
    11  	"github.com/stretchr/testify/require"
    12  	abci "github.com/tendermint/tendermint/abci/types"
    13  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    14  
    15  	lapp "github.com/gravity-devs/liquidity/app"
    16  	liquidityparams "github.com/gravity-devs/liquidity/app/params"
    17  	"github.com/gravity-devs/liquidity/x/liquidity/simulation"
    18  	"github.com/gravity-devs/liquidity/x/liquidity/types"
    19  )
    20  
    21  // TestWeightedOperations tests the weights of the operations.
    22  func TestWeightedOperations(t *testing.T) {
    23  	app, ctx := createTestApp(false)
    24  
    25  	ctx.WithChainID("test-chain")
    26  
    27  	cdc := app.AppCodec()
    28  	appParams := make(simtypes.AppParams)
    29  
    30  	weightedOps := simulation.WeightedOperations(appParams, cdc, app.AccountKeeper, app.BankKeeper, app.LiquidityKeeper)
    31  
    32  	s := rand.NewSource(1)
    33  	r := rand.New(s)
    34  	accs := simtypes.RandomAccounts(r, 3)
    35  
    36  	expected := []struct {
    37  		weight     int
    38  		opMsgRoute string
    39  		opMsgName  string
    40  	}{
    41  		{liquidityparams.DefaultWeightMsgCreatePool, types.ModuleName, types.TypeMsgCreatePool},
    42  		{liquidityparams.DefaultWeightMsgDepositWithinBatch, types.ModuleName, types.TypeMsgDepositWithinBatch},
    43  		{liquidityparams.DefaultWeightMsgWithdrawWithinBatch, types.ModuleName, types.TypeMsgWithdrawWithinBatch},
    44  		{liquidityparams.DefaultWeightMsgSwapWithinBatch, types.ModuleName, types.TypeMsgSwapWithinBatch},
    45  	}
    46  
    47  	for i, w := range weightedOps {
    48  		operationMsg, _, _ := w.Op()(r, app.BaseApp, ctx, accs, ctx.ChainID())
    49  		// the following checks are very much dependent from the ordering of the output given
    50  		// by WeightedOperations. if the ordering in WeightedOperations changes some tests
    51  		// will fail
    52  		require.Equal(t, expected[i].weight, w.Weight(), "weight should be the same")
    53  		require.Equal(t, expected[i].opMsgRoute, operationMsg.Route, "route should be the same")
    54  		require.Equal(t, expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same")
    55  	}
    56  }
    57  
    58  // TestSimulateMsgCreatePool tests the normal scenario of a valid message of type TypeMsgCreatePool.
    59  // Abnormal scenarios, where the message are created by an errors are not tested here.
    60  func TestSimulateMsgCreatePool(t *testing.T) {
    61  	app, ctx := createTestApp(false)
    62  
    63  	// setup a single account
    64  	s := rand.NewSource(1)
    65  	r := rand.New(s)
    66  	accounts := getTestingAccounts(t, r, app, ctx, 1)
    67  
    68  	// setup randomly generated liquidity pool creation fees
    69  	feeCoins := simulation.GenPoolCreationFee(r)
    70  	params := app.LiquidityKeeper.GetParams(ctx)
    71  	params.PoolCreationFee = feeCoins
    72  	app.LiquidityKeeper.SetParams(ctx, params)
    73  
    74  	// begin a new block
    75  	app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}})
    76  
    77  	// execute operation
    78  	op := simulation.SimulateMsgCreatePool(app.AccountKeeper, app.BankKeeper, app.LiquidityKeeper)
    79  	operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "")
    80  	require.NoError(t, err)
    81  
    82  	var msg types.MsgCreatePool
    83  	require.NoError(t, types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg))
    84  
    85  	require.True(t, operationMsg.OK)
    86  	require.Equal(t, "cosmos10kn7aww37y27c4lggjx6mycyhr927677rkp7x0", msg.GetPoolCreator().String())
    87  	require.Equal(t, types.DefaultPoolTypeID, msg.PoolTypeId)
    88  	require.Equal(t, "90341750hsuk,28960633ijmo", msg.DepositCoins.String())
    89  	require.Equal(t, types.TypeMsgCreatePool, msg.Type())
    90  	require.Len(t, futureOperations, 0)
    91  }
    92  
    93  // TestSimulateMsgDepositWithinBatch tests the normal scenario of a valid message of type TypeMsgDepositWithinBatch.
    94  // Abnormal scenarios, where the message are created by an errors are not tested here.
    95  func TestSimulateMsgDepositWithinBatch(t *testing.T) {
    96  	app, ctx := createTestApp(false)
    97  
    98  	// setup accounts
    99  	s := rand.NewSource(1)
   100  	r := rand.New(s)
   101  	accounts := getTestingAccounts(t, r, app, ctx, 1)
   102  
   103  	// setup random liquidity pools
   104  	setupLiquidityPools(t, r, app, ctx, accounts)
   105  
   106  	// begin a new block
   107  	app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}})
   108  
   109  	// execute operation
   110  	op := simulation.SimulateMsgDepositWithinBatch(app.AccountKeeper, app.BankKeeper, app.LiquidityKeeper)
   111  	operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "")
   112  	require.NoError(t, err)
   113  
   114  	var msg types.MsgDepositWithinBatch
   115  	require.NoError(t, types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg))
   116  
   117  	require.True(t, operationMsg.OK)
   118  	require.Equal(t, "cosmos10kn7aww37y27c4lggjx6mycyhr927677rkp7x0", msg.GetDepositor().String())
   119  	require.Equal(t, "38511541fgae,71186277jxulr", msg.DepositCoins.String())
   120  	require.Equal(t, types.TypeMsgDepositWithinBatch, msg.Type())
   121  	require.Len(t, futureOperations, 0)
   122  }
   123  
   124  // TestSimulateMsgWithdrawWithinBatch tests the normal scenario of a valid message of type TypeMsgWithdrawWithinBatch.
   125  // Abnormal scenarios, where the message are created by an errors are not tested here.
   126  func TestSimulateMsgWithdrawWithinBatch(t *testing.T) {
   127  	app, ctx := createTestApp(false)
   128  
   129  	// setup accounts
   130  	s := rand.NewSource(1)
   131  	r := rand.New(s)
   132  	accounts := getTestingAccounts(t, r, app, ctx, 1)
   133  
   134  	// setup random liquidity pools
   135  	setupLiquidityPools(t, r, app, ctx, accounts)
   136  
   137  	// begin a new block
   138  	app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}})
   139  
   140  	// execute operation
   141  	op := simulation.SimulateMsgWithdrawWithinBatch(app.AccountKeeper, app.BankKeeper, app.LiquidityKeeper)
   142  	operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "")
   143  	require.NoError(t, err)
   144  
   145  	var msg types.MsgWithdrawWithinBatch
   146  	require.NoError(t, types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg))
   147  
   148  	require.True(t, operationMsg.OK)
   149  	require.Equal(t, "cosmos10kn7aww37y27c4lggjx6mycyhr927677rkp7x0", msg.GetWithdrawer().String())
   150  	require.Equal(t, "3402627138556poolA295B958C22781F58E51E1E4E8205F5E8E041D65F7E7AB5D7DDECCFFA7A75B01", msg.PoolCoin.String())
   151  	require.Equal(t, types.TypeMsgWithdrawWithinBatch, msg.Type())
   152  	require.Len(t, futureOperations, 0)
   153  }
   154  
   155  // TestSimulateMsgSwapWithinBatch tests the normal scenario of a valid message of type TypeMsgSwapWithinBatch.
   156  // Abnormal scenarios, where the message are created by an errors are not tested here.
   157  func TestSimulateMsgSwapWithinBatch(t *testing.T) {
   158  	app, ctx := createTestApp(false)
   159  
   160  	// setup a single account
   161  	s := rand.NewSource(1)
   162  	r := rand.New(s)
   163  	accounts := getTestingAccounts(t, r, app, ctx, 1)
   164  
   165  	// setup random liquidity pools
   166  	setupLiquidityPools(t, r, app, ctx, accounts)
   167  
   168  	// begin a new block
   169  	app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}})
   170  
   171  	// execute operation
   172  	op := simulation.SimulateMsgSwapWithinBatch(app.AccountKeeper, app.BankKeeper, app.LiquidityKeeper)
   173  	operationMsg, futureOperations, err := op(r, app.BaseApp, ctx, accounts, "")
   174  	require.NoError(t, err)
   175  
   176  	var msg types.MsgSwapWithinBatch
   177  	require.NoError(t, types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg))
   178  
   179  	require.True(t, operationMsg.OK)
   180  	require.Equal(t, "cosmos10kn7aww37y27c4lggjx6mycyhr927677rkp7x0", msg.GetSwapRequester().String())
   181  	require.Equal(t, "6453297fgae", msg.OfferCoin.String())
   182  	require.Equal(t, "jxulr", msg.DemandCoinDenom)
   183  	require.Equal(t, types.TypeMsgSwapWithinBatch, msg.Type())
   184  	require.Len(t, futureOperations, 0)
   185  }
   186  
   187  func createTestApp(isCheckTx bool) (*lapp.LiquidityApp, sdk.Context) {
   188  	app := lapp.Setup(false)
   189  
   190  	ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{})
   191  	app.MintKeeper.SetParams(ctx, minttypes.DefaultParams())
   192  	app.MintKeeper.SetMinter(ctx, minttypes.DefaultInitialMinter())
   193  
   194  	return app, ctx
   195  }
   196  
   197  func getTestingAccounts(t *testing.T, r *rand.Rand, app *lapp.LiquidityApp, ctx sdk.Context, n int) []simtypes.Account {
   198  	accounts := simtypes.RandomAccounts(r, n)
   199  
   200  	initAmt := sdk.TokensFromConsensusPower(1_000_000, sdk.DefaultPowerReduction)
   201  	initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt))
   202  
   203  	// add coins to the accounts
   204  	for _, account := range accounts {
   205  		acc := app.AccountKeeper.NewAccountWithAddress(ctx, account.Address)
   206  		app.AccountKeeper.SetAccount(ctx, acc)
   207  		lapp.SaveAccount(app, ctx, account.Address, initCoins)
   208  	}
   209  
   210  	return accounts
   211  }
   212  
   213  func setupLiquidityPools(t *testing.T, r *rand.Rand, app *lapp.LiquidityApp, ctx sdk.Context, accounts []simtypes.Account) {
   214  	params := app.StakingKeeper.GetParams(ctx)
   215  
   216  	for _, account := range accounts {
   217  		// random denom with a length from 4 to 6 characters
   218  		denomA := simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 4, 6))
   219  		denomB := simtypes.RandStringOfLength(r, simtypes.RandIntBetween(r, 4, 6))
   220  		denomA, denomB = types.AlphabeticalDenomPair(strings.ToLower(denomA), strings.ToLower(denomB))
   221  
   222  		fees := sdk.NewCoin(params.GetBondDenom(), sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e10, 1e12))))
   223  
   224  		// mint random amounts of denomA and denomB coins
   225  		mintCoinA := sdk.NewCoin(denomA, sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e14, 1e15))))
   226  		mintCoinB := sdk.NewCoin(denomB, sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e14, 1e15))))
   227  		mintCoins := sdk.NewCoins(mintCoinA, mintCoinB, fees)
   228  		err := app.BankKeeper.MintCoins(ctx, types.ModuleName, mintCoins)
   229  		require.NoError(t, err)
   230  
   231  		// transfer random amounts to the simulated random account
   232  		coinA := sdk.NewCoin(denomA, sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e12, 1e14))))
   233  		coinB := sdk.NewCoin(denomB, sdk.NewInt(int64(simtypes.RandIntBetween(r, 1e12, 1e14))))
   234  		coins := sdk.NewCoins(coinA, coinB, fees)
   235  		err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, account.Address, coins)
   236  		require.NoError(t, err)
   237  
   238  		// create liquidity pool with random deposit amounts
   239  		account := app.AccountKeeper.GetAccount(ctx, account.Address)
   240  		depositCoinA := sdk.NewCoin(denomA, sdk.NewInt(int64(simtypes.RandIntBetween(r, int(types.DefaultMinInitDepositAmount.Int64()), 1e8))))
   241  		depositCoinB := sdk.NewCoin(denomB, sdk.NewInt(int64(simtypes.RandIntBetween(r, int(types.DefaultMinInitDepositAmount.Int64()), 1e8))))
   242  		depositCoins := sdk.NewCoins(depositCoinA, depositCoinB)
   243  
   244  		createPoolMsg := types.NewMsgCreatePool(account.GetAddress(), types.DefaultPoolTypeID, depositCoins)
   245  
   246  		_, err = app.LiquidityKeeper.CreatePool(ctx, createPoolMsg)
   247  		require.NoError(t, err)
   248  	}
   249  }