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 }