github.com/gravity-devs/liquidity@v1.5.3/x/liquidity/keeper/liquidity_pool_test.go (about) 1 package keeper_test 2 3 import ( 4 "fmt" 5 "math/rand" 6 "testing" 7 8 sdk "github.com/cosmos/cosmos-sdk/types" 9 distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/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/keeper" 15 "github.com/gravity-devs/liquidity/x/liquidity/types" 16 ) 17 18 func TestLiquidityPool(t *testing.T) { 19 app, ctx := createTestInput() 20 lp := types.Pool{ 21 Id: 0, 22 TypeId: 0, 23 ReserveCoinDenoms: []string{"a", "b"}, 24 ReserveAccountAddress: "", 25 PoolCoinDenom: "poolCoin", 26 } 27 app.LiquidityKeeper.SetPool(ctx, lp) 28 29 lpGet, found := app.LiquidityKeeper.GetPool(ctx, 0) 30 require.True(t, found) 31 require.Equal(t, lp, lpGet) 32 } 33 34 func TestCreatePool(t *testing.T) { 35 simapp, ctx := createTestInput() 36 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 37 params := simapp.LiquidityKeeper.GetParams(ctx) 38 39 poolTypeID := types.DefaultPoolTypeID 40 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 41 42 denomA := "uETH" 43 denomB := "uUSD" 44 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 45 46 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) 47 app.SaveAccount(simapp, ctx, addrs[0], deposit) 48 49 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 50 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 51 depositBalance := sdk.NewCoins(depositA, depositB) 52 53 require.Equal(t, deposit, depositBalance) 54 55 msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 56 _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) 57 require.NoError(t, err) 58 59 invalidMsg := types.NewMsgCreatePool(addrs[0], 2, depositBalance) 60 _, err = simapp.LiquidityKeeper.CreatePool(ctx, invalidMsg) 61 require.ErrorIs(t, err, types.ErrPoolTypeNotExists) 62 63 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 64 require.Equal(t, 1, len(pools)) 65 require.Equal(t, uint64(1), pools[0].Id) 66 require.Equal(t, uint64(1), simapp.LiquidityKeeper.GetNextPoolID(ctx)-1) 67 require.Equal(t, denomA, pools[0].ReserveCoinDenoms[0]) 68 require.Equal(t, denomB, pools[0].ReserveCoinDenoms[1]) 69 70 poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) 71 creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) 72 require.Equal(t, poolCoin, creatorBalance.Amount) 73 74 _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) 75 require.ErrorIs(t, err, types.ErrPoolAlreadyExists) 76 } 77 78 func TestCreatePoolInsufficientAmount(t *testing.T) { 79 simapp, ctx := createTestInput() 80 params := simapp.LiquidityKeeper.GetParams(ctx) 81 82 depositCoins := sdk.NewCoins(sdk.NewInt64Coin(DenomX, 1000), sdk.NewInt64Coin(DenomY, 1000)) 83 creator := app.AddRandomTestAddr(simapp, ctx, depositCoins.Add(params.PoolCreationFee...)) 84 85 // Depositing coins that are less than params.MinInitDepositAmount. 86 _, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creator, types.DefaultPoolTypeID, depositCoins)) 87 require.ErrorIs(t, err, types.ErrLessThanMinInitDeposit) 88 89 fakeDepositCoins := depositCoins.Add( 90 sdk.NewCoin(DenomX, params.MinInitDepositAmount), 91 sdk.NewCoin(DenomY, params.MinInitDepositAmount), 92 ) 93 // Depositing coins that are greater than the depositor has. 94 _, err = simapp.LiquidityKeeper.CreatePool( 95 ctx, types.NewMsgCreatePool(creator, types.DefaultPoolTypeID, fakeDepositCoins), 96 ) 97 require.ErrorIs(t, err, types.ErrInsufficientBalance) 98 } 99 100 func TestPoolCreationFee(t *testing.T) { 101 simapp, ctx := createTestInput() 102 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 103 params := simapp.LiquidityKeeper.GetParams(ctx) 104 105 poolTypeID := types.DefaultPoolTypeID 106 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 107 108 denomA := "uETH" 109 denomB := "uUSD" 110 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 111 112 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) 113 app.SaveAccount(simapp, ctx, addrs[0], deposit) 114 115 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 116 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 117 depositBalance := sdk.NewCoins(depositA, depositB) 118 119 require.Equal(t, deposit, depositBalance) 120 121 // Set PoolCreationFee for fail (insufficient balances for pool creation fee) 122 params.PoolCreationFee = depositBalance 123 simapp.LiquidityKeeper.SetParams(ctx, params) 124 125 msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 126 _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) 127 require.ErrorIs(t, types.ErrInsufficientPoolCreationFee, err) 128 129 // Set PoolCreationFee for success 130 params.PoolCreationFee = types.DefaultPoolCreationFee 131 simapp.LiquidityKeeper.SetParams(ctx, params) 132 feePoolAcc := simapp.AccountKeeper.GetModuleAddress(distrtypes.ModuleName) 133 feePoolBalance := simapp.BankKeeper.GetAllBalances(ctx, feePoolAcc) 134 msg = types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 135 _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) 136 require.NoError(t, err) 137 138 // Verify PoolCreationFee pay successfully 139 feePoolBalance = feePoolBalance.Add(params.PoolCreationFee...) 140 require.Equal(t, params.PoolCreationFee, feePoolBalance) 141 require.Equal(t, feePoolBalance, simapp.BankKeeper.GetAllBalances(ctx, feePoolAcc)) 142 } 143 144 func TestExecuteDeposit(t *testing.T) { 145 simapp, ctx := createTestInput() 146 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 147 params := simapp.LiquidityKeeper.GetParams(ctx) 148 149 poolTypeID := types.DefaultPoolTypeID 150 addrs := app.AddTestAddrs(simapp, ctx, 4, params.PoolCreationFee) 151 152 denomA := "uETH" 153 denomB := "uUSD" 154 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 155 156 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) 157 app.SaveAccount(simapp, ctx, addrs[0], deposit) 158 app.SaveAccount(simapp, ctx, addrs[1], deposit) 159 160 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 161 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 162 depositBalance := sdk.NewCoins(depositA, depositB) 163 164 require.Equal(t, deposit, depositBalance) 165 166 depositA = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA) 167 depositB = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB) 168 depositBalance = sdk.NewCoins(depositA, depositB) 169 170 require.Equal(t, deposit, depositBalance) 171 172 createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 173 174 _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) 175 require.NoError(t, err) 176 177 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 178 pool := pools[0] 179 180 poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 181 182 depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) 183 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) 184 require.NoError(t, err) 185 186 poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) 187 require.True(t, found) 188 msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) 189 require.Equal(t, 1, len(msgs)) 190 191 err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) 192 require.NoError(t, err) 193 194 poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 195 depositorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) 196 require.Equal(t, poolCoin.Sub(poolCoinBefore), depositorBalance.Amount) 197 } 198 199 func TestExecuteDepositTruncation(t *testing.T) { 200 simapp, ctx := createTestInput() 201 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 202 params := simapp.LiquidityKeeper.GetParams(ctx) 203 204 poolTypeID := types.DefaultPoolTypeID 205 addrs := app.AddTestAddrs(simapp, ctx, 4, params.PoolCreationFee) 206 207 denomA := "uETH" 208 denomB := "uUSD" 209 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 210 211 initDeposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(10000000*1000000)), sdk.NewCoin(denomB, sdk.NewInt(200000000*1000000))) 212 app.SaveAccount(simapp, ctx, addrs[0], initDeposit) 213 app.SaveAccount(simapp, ctx, addrs[1], initDeposit) 214 215 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 216 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 217 depositBalance := sdk.NewCoins(depositA, depositB) 218 219 require.Equal(t, initDeposit, depositBalance) 220 221 depositA = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA) 222 depositB = simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB) 223 depositBalance = sdk.NewCoins(depositA, depositB) 224 225 require.Equal(t, initDeposit, depositBalance) 226 227 createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 228 229 _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) 230 require.NoError(t, err) 231 232 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 233 pool := pools[0] 234 235 poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 236 237 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(19*1000000)), sdk.NewCoin(denomB, sdk.NewInt(400*1000000))) 238 depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) 239 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) 240 require.NoError(t, err) 241 242 poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) 243 require.True(t, found) 244 msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) 245 require.Equal(t, 1, len(msgs)) 246 247 err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) 248 require.NoError(t, err) 249 250 poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 251 depositorBalancePoolCoin := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) 252 depositorBalanceDenomA := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA) 253 depositorBalanceDenomB := simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB) 254 require.Equal(t, depositBalance.AmountOf(denomA).Sub(sdk.NewInt(10*1000000)), depositorBalanceDenomA.Amount) 255 require.Equal(t, depositBalance.AmountOf(denomB).Sub(sdk.NewInt(200*1000000)), depositorBalanceDenomB.Amount) 256 require.Equal(t, depositorBalancePoolCoin.Amount, sdk.OneInt()) 257 require.Equal(t, poolCoin.Sub(poolCoinBefore), depositorBalancePoolCoin.Amount) 258 } 259 260 func TestDepositDecimalTruncation(t *testing.T) { 261 simapp, ctx := createTestInput() 262 params := simapp.LiquidityKeeper.GetParams(ctx) 263 params.WithdrawFeeRate = sdk.ZeroDec() 264 265 // Suppose that atom price is $40. 266 denomA := "uatom" 267 denomB := "uusd" 268 269 addrs := app.AddTestAddrs(simapp, ctx, 2, sdk.NewCoins()) 270 creator, depositor := addrs[0], addrs[1] 271 272 // Create a pool with initial value of $10M. 273 depositCoins := sdk.NewCoins(sdk.NewInt64Coin(denomA, 125000*1000000), sdk.NewInt64Coin(denomB, 5000000*1000000)) 274 err := app.FundAccount(simapp, ctx, creator, depositCoins.Add(params.PoolCreationFee...)) 275 require.NoError(t, err) 276 pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creator, types.DefaultPoolTypeID, depositCoins)) 277 require.NoError(t, err) 278 279 // Deposit 19$. 280 depositCoins = sdk.NewCoins(sdk.NewInt64Coin(denomA, 0.2375*1000000), sdk.NewInt64Coin(denomB, 9.5*1000000)) 281 err = app.FundAccount(simapp, ctx, depositor, depositCoins) 282 require.NoError(t, err) 283 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch(depositor, pool.Id, depositCoins)) 284 require.NoError(t, err) 285 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 286 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 287 depositMsgStates := simapp.LiquidityKeeper.GetAllDepositMsgStates(ctx) 288 require.Len(t, depositMsgStates, 0) 289 290 depositorPoolCoin := simapp.BankKeeper.GetBalance(ctx, depositor, pool.PoolCoinDenom) 291 require.True(sdk.IntEq(t, sdk.OneInt(), depositorPoolCoin.Amount)) 292 require.True(t, simapp.BankKeeper.GetBalance(ctx, depositor, denomA).Amount.IsPositive()) 293 require.True(t, simapp.BankKeeper.GetBalance(ctx, depositor, denomB).Amount.IsPositive()) 294 295 // Withdraw. 296 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(depositor, pool.Id, depositorPoolCoin)) 297 require.NoError(t, err) 298 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 299 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 300 withdrawMsgStates := simapp.LiquidityKeeper.GetAllWithdrawMsgStates(ctx) 301 require.Len(t, withdrawMsgStates, 0) 302 303 depositorCoinsDelta := depositCoins.Sub(simapp.BankKeeper.GetAllBalances(ctx, depositor)) 304 require.True(t, depositorCoinsDelta.IsZero()) 305 } 306 307 func TestDepositDecimalTruncation2(t *testing.T) { 308 simapp, ctx := createTestInput() 309 params := simapp.LiquidityKeeper.GetParams(ctx) 310 params.WithdrawFeeRate = sdk.ZeroDec() 311 312 // Suppose that atom price is $40. 313 denomA := "uatom" 314 denomB := "uusd" 315 316 addrs := app.AddTestAddrs(simapp, ctx, 2, sdk.NewCoins()) 317 creator, depositor := addrs[0], addrs[1] 318 319 // Create a pool with initial value of $10M. 320 depositCoins := sdk.NewCoins(sdk.NewInt64Coin(denomA, 125000*1000000), sdk.NewInt64Coin(denomB, 5000000*1000000)) 321 err := app.FundAccount(simapp, ctx, creator, depositCoins.Add(params.PoolCreationFee...)) 322 require.NoError(t, err) 323 pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creator, types.DefaultPoolTypeID, depositCoins)) 324 require.NoError(t, err) 325 326 // Deposit 9$. 327 depositCoins = sdk.NewCoins(sdk.NewInt64Coin(denomA, 0.1125*1000000), sdk.NewInt64Coin(denomB, 4.5*1000000)) 328 err = app.FundAccount(simapp, ctx, depositor, depositCoins) 329 require.NoError(t, err) 330 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch(depositor, pool.Id, depositCoins)) 331 require.NoError(t, err) 332 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 333 334 depositorPoolCoin := simapp.BankKeeper.GetBalance(ctx, depositor, pool.PoolCoinDenom) 335 require.True(sdk.IntEq(t, sdk.ZeroInt(), depositorPoolCoin.Amount)) 336 require.True(t, simapp.BankKeeper.GetAllBalances(ctx, depositor).IsEqual(depositCoins)) 337 depositMsgStates := simapp.LiquidityKeeper.GetAllDepositMsgStates(ctx) 338 require.Len(t, depositMsgStates, 1) 339 require.True(t, depositMsgStates[0].Executed) 340 require.False(t, depositMsgStates[0].Succeeded) 341 require.True(t, depositMsgStates[0].ToBeDeleted) 342 343 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 344 depositMsgStates = simapp.LiquidityKeeper.GetAllDepositMsgStates(ctx) 345 require.Len(t, depositMsgStates, 0) 346 } 347 348 func TestReserveCoinLimit(t *testing.T) { 349 simapp, ctx := createTestInput() 350 params := types.DefaultParams() 351 params.MaxReserveCoinAmount = sdk.NewInt(1000000000000) 352 simapp.LiquidityKeeper.SetParams(ctx, params) 353 354 poolTypeID := types.DefaultPoolTypeID 355 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 356 357 denomA := "uETH" 358 denomB := "uUSD" 359 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 360 361 deposit := sdk.NewCoins(sdk.NewCoin(denomA, params.MaxReserveCoinAmount), sdk.NewCoin(denomB, sdk.NewInt(1000000))) 362 app.SaveAccount(simapp, ctx, addrs[0], deposit) 363 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 364 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 365 depositBalance := sdk.NewCoins(depositA, depositB) 366 require.Equal(t, deposit, depositBalance) 367 368 msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 369 _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) 370 require.Equal(t, types.ErrExceededReserveCoinLimit, err) 371 372 params.MaxReserveCoinAmount = sdk.ZeroInt() 373 simapp.LiquidityKeeper.SetParams(ctx, params) 374 _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) 375 require.NoError(t, err) 376 377 params.MaxReserveCoinAmount = sdk.NewInt(1000000000000) 378 simapp.LiquidityKeeper.SetParams(ctx, params) 379 380 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 381 pool := pools[0] 382 383 deposit = sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(1000000)), sdk.NewCoin(denomB, sdk.NewInt(1000000))) 384 app.SaveAccount(simapp, ctx, addrs[1], deposit) 385 depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) 386 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) 387 require.Equal(t, types.ErrExceededReserveCoinLimit, err) 388 389 params.MaxReserveCoinAmount = sdk.ZeroInt() 390 simapp.LiquidityKeeper.SetParams(ctx, params) 391 392 depositMsg = types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) 393 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) 394 require.NoError(t, err) 395 396 poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) 397 require.True(t, found) 398 msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) 399 require.Equal(t, 1, len(msgs)) 400 401 simapp.LiquidityKeeper.ExecutePoolBatches(ctx) 402 require.NoError(t, err) 403 404 ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) 405 simapp.LiquidityKeeper.DeleteAndInitPoolBatches(ctx) 406 app.SaveAccount(simapp, ctx, addrs[1], deposit) 407 depositMsg = types.NewMsgDepositWithinBatch(addrs[1], pool.Id, deposit) 408 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) 409 require.NoError(t, err) 410 411 params.MaxReserveCoinAmount = sdk.NewInt(1000000000000) 412 simapp.LiquidityKeeper.SetParams(ctx, params) 413 414 poolBatch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) 415 require.True(t, found) 416 msgs = simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) 417 require.Equal(t, 1, len(msgs)) 418 419 err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) 420 require.Equal(t, types.ErrExceededReserveCoinLimit, err) 421 } 422 423 func TestExecuteWithdrawal(t *testing.T) { 424 simapp, ctx := createTestInput() 425 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 426 params := simapp.LiquidityKeeper.GetParams(ctx) 427 428 poolTypeID := types.DefaultPoolTypeID 429 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 430 431 denomA := "uETH" 432 denomB := "uUSD" 433 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 434 435 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) 436 app.SaveAccount(simapp, ctx, addrs[0], deposit) 437 438 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 439 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 440 depositBalance := sdk.NewCoins(depositA, depositB) 441 442 require.Equal(t, deposit, depositBalance) 443 444 createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 445 446 _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) 447 require.NoError(t, err) 448 449 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 450 pool := pools[0] 451 452 // Case for normal withdrawing 453 poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 454 withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 455 456 require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount) 457 withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, withdrawerPoolCoinBefore.Amount.QuoRaw(2))) 458 459 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) 460 require.NoError(t, err) 461 462 poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) 463 require.True(t, found) 464 msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) 465 require.Equal(t, 1, len(msgs)) 466 467 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 468 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 469 470 poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 471 withdrawerPoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 472 473 require.Equal(t, poolCoinAfter, poolCoinBefore.QuoRaw(2)) 474 require.Equal(t, withdrawerPoolCoinAfter.Amount, withdrawerPoolCoinBefore.Amount.QuoRaw(2)) 475 withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) 476 withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) 477 require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]).QuoRaw(2).ToDec().Mul(sdk.OneDec().Sub(params.WithdrawFeeRate)).TruncateInt(), withdrawerDenomABalance.Amount) 478 require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]).QuoRaw(2).ToDec().Mul(sdk.OneDec().Sub(params.WithdrawFeeRate)).TruncateInt(), withdrawerDenomBBalance.Amount) 479 480 // Case for withdrawing all reserve coins 481 poolCoinBefore = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 482 withdrawerPoolCoinBefore = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 483 484 require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount) 485 withdrawMsg = types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore)) 486 487 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) 488 require.NoError(t, err) 489 490 poolBatch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) 491 require.True(t, found) 492 msgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) 493 require.Equal(t, 1, len(msgs)) 494 495 err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, msgs[0], poolBatch) 496 require.NoError(t, err) 497 498 poolCoinAfter = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 499 withdrawerPoolCoinAfter = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 500 501 require.True(t, true, poolCoinAfter.IsZero()) 502 require.True(t, true, withdrawerPoolCoinAfter.IsZero()) 503 withdrawerDenomABalance = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) 504 withdrawerDenomBBalance = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) 505 require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]), withdrawerDenomABalance.Amount) 506 require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), withdrawerDenomBBalance.Amount) 507 } 508 509 func TestSmallWithdrawalCase(t *testing.T) { 510 simapp, ctx := createTestInput() 511 params := types.DefaultParams() 512 params.InitPoolCoinMintAmount = sdk.NewInt(1_000000_000000) 513 simapp.LiquidityKeeper.SetParams(ctx, params) 514 515 poolTypeID := types.DefaultPoolTypeID 516 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 517 518 denomA := "uETH" 519 denomB := "uUSD" 520 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 521 522 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(1250001*1000000)), sdk.NewCoin(denomB, sdk.NewInt(9*1000000))) 523 app.SaveAccount(simapp, ctx, addrs[0], deposit) 524 525 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 526 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 527 depositBalance := sdk.NewCoins(depositA, depositB) 528 529 require.Equal(t, deposit, depositBalance) 530 531 createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 532 533 _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) 534 require.NoError(t, err) 535 536 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 537 pool := pools[0] 538 539 // Case for normal withdrawing 540 poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 541 withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 542 543 withdrawerDenomABalanceBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) 544 withdrawerDenomBBalanceBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) 545 546 require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount) 547 withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, sdk.NewInt(1))) 548 549 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) 550 require.NoError(t, err) 551 552 poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) 553 require.True(t, found) 554 msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) 555 require.Equal(t, 1, len(msgs)) 556 557 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 558 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 559 560 poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 561 withdrawerPoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 562 563 require.Equal(t, poolCoinAfter, poolCoinBefore) 564 require.Equal(t, withdrawerPoolCoinAfter.Amount, withdrawerPoolCoinBefore.Amount) 565 withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) 566 withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) 567 568 reservePoolBalanceA := simapp.BankKeeper.GetBalance(ctx, pool.GetReserveAccount(), pool.ReserveCoinDenoms[0]) 569 reservePoolBalanceB := simapp.BankKeeper.GetBalance(ctx, pool.GetReserveAccount(), pool.ReserveCoinDenoms[1]) 570 require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]), reservePoolBalanceA.Amount) 571 require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), reservePoolBalanceB.Amount) 572 require.Equal(t, withdrawerDenomABalanceBefore, withdrawerDenomABalance) 573 require.Equal(t, withdrawerDenomBBalanceBefore, withdrawerDenomBBalance) 574 } 575 576 func TestReinitializePool(t *testing.T) { 577 simapp, ctx := createTestInput() 578 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 579 params := simapp.LiquidityKeeper.GetParams(ctx) 580 params.WithdrawFeeRate = sdk.ZeroDec() 581 simapp.LiquidityKeeper.SetParams(ctx, params) 582 583 poolTypeID := types.DefaultPoolTypeID 584 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 585 586 denomA := "uETH" 587 denomB := "uUSD" 588 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 589 590 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(100*1000000))) 591 app.SaveAccount(simapp, ctx, addrs[0], deposit) 592 593 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 594 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 595 depositBalance := sdk.NewCoins(depositA, depositB) 596 597 require.Equal(t, deposit, depositBalance) 598 599 createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 600 601 _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) 602 require.NoError(t, err) 603 604 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 605 pool := pools[0] 606 607 poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 608 withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 609 610 reserveCoins := simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) 611 require.True(t, reserveCoins.IsEqual(deposit)) 612 613 require.Equal(t, poolCoinBefore, withdrawerPoolCoinBefore.Amount) 614 withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore)) 615 616 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) 617 require.NoError(t, err) 618 619 poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) 620 require.True(t, found) 621 msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) 622 require.Equal(t, 1, len(msgs)) 623 624 err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, msgs[0], poolBatch) 625 require.NoError(t, err) 626 627 poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 628 withdrawerPoolCoinAfter := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 629 require.True(t, true, poolCoinAfter.IsZero()) 630 require.True(t, true, withdrawerPoolCoinAfter.IsZero()) 631 withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) 632 withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) 633 require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[0]), withdrawerDenomABalance.Amount) 634 require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), withdrawerDenomBBalance.Amount) 635 636 reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) 637 require.True(t, reserveCoins.IsZero()) 638 639 // error when swap request to depleted pool 640 offerCoin := sdk.NewCoin(denomA, withdrawerDenomABalance.Amount.QuoRaw(2)) 641 swapMsg := types.NewMsgSwapWithinBatch(addrs[0], pool.Id, types.DefaultSwapTypeID, offerCoin, denomB, sdk.MustNewDecFromStr("0.1"), params.SwapFeeRate) 642 _, err = simapp.LiquidityKeeper.SwapWithinBatch(ctx, swapMsg, 0) 643 require.ErrorIs(t, err, types.ErrDepletedPool) 644 645 depositMsg := types.NewMsgDepositWithinBatch(addrs[0], pool.Id, deposit) 646 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) 647 require.NoError(t, err) 648 649 depositMsgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) 650 require.Equal(t, 1, len(depositMsgs)) 651 652 err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, depositMsgs[0], poolBatch) 653 require.NoError(t, err) 654 655 poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 656 depositorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 657 require.Equal(t, poolCoin, depositorBalance.Amount) 658 659 reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) 660 require.True(t, reserveCoins.IsEqual(deposit)) 661 } 662 663 func TestReserveAccManipulation(t *testing.T) { 664 simapp, ctx := createTestInput() 665 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 666 params := simapp.LiquidityKeeper.GetParams(ctx) 667 668 poolTypeID := types.DefaultPoolTypeID 669 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 670 671 denomA := "uETH" 672 denomB := "uUSD" 673 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 674 675 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) 676 677 // depositor, withdrawer 678 app.SaveAccount(simapp, ctx, addrs[0], deposit) 679 // reserveAccount manipulator 680 app.SaveAccount(simapp, ctx, addrs[1], deposit) 681 682 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 683 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 684 depositBalance := sdk.NewCoins(depositA, depositB) 685 686 // reserveAcc manipulation coinA 687 manipulationReserveA1 := sdk.NewCoin(denomA, sdk.NewInt(30*1000000)) 688 manipulationReserveA2 := sdk.NewCoin(denomA, sdk.NewInt(70*1000000)) 689 // reserveAcc manipulation coin other than reserve coins 690 manipulationReserveOther := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100*1000000)) 691 // manipulated reserve coinA 692 addedDepositA := depositA.Add(manipulationReserveA1).Add(manipulationReserveA2) 693 694 createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 695 696 _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) 697 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 698 pool := pools[0] 699 700 reserveAcc := pool.GetReserveAccount() 701 reserveAccBalances := simapp.BankKeeper.GetAllBalances(ctx, reserveAcc) 702 require.Equal(t, reserveAccBalances, sdk.NewCoins(depositA, depositB)) 703 704 // send coin to manipulate reserve account 705 simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveA1)) 706 metadata := simapp.LiquidityKeeper.GetPoolMetaData(ctx, pool) 707 require.Equal(t, depositA.Add(manipulationReserveA1).Amount, metadata.ReserveCoins.AmountOf(denomA)) 708 709 poolCoinBefore := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 710 withdrawerPoolCoinBefore := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 711 withdrawMsg := types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, withdrawerPoolCoinBefore.Amount.QuoRaw(2))) 712 simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) 713 714 poolBatch, _ := simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) 715 msgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) 716 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 717 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 718 719 // send coin to manipulate reserve account 720 simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveA2)) 721 simapp.BankKeeper.SendCoins(ctx, addrs[1], reserveAcc, sdk.NewCoins(manipulationReserveOther)) 722 reserveAccBalances = simapp.BankKeeper.GetAllBalances(ctx, reserveAcc) 723 metadata = simapp.LiquidityKeeper.GetPoolMetaData(ctx, pool) 724 require.NotEqual(t, manipulationReserveOther, metadata.ReserveCoins.AmountOf(sdk.DefaultBondDenom)) 725 726 // Case for withdrawing all reserve coins after manipulation 727 poolCoinBefore = simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 728 withdrawerPoolCoinBefore = simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.PoolCoinDenom) 729 withdrawMsg = types.NewMsgWithdrawWithinBatch(addrs[0], pool.Id, sdk.NewCoin(pool.PoolCoinDenom, poolCoinBefore)) 730 731 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, withdrawMsg) 732 require.NoError(t, err) 733 734 poolBatch, _ = simapp.LiquidityKeeper.GetPoolBatch(ctx, withdrawMsg.PoolId) 735 msgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) 736 737 err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, msgs[0], poolBatch) 738 require.NoError(t, err) 739 740 withdrawerDenomABalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[0]) 741 withdrawerDenomBBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pool.ReserveCoinDenoms[1]) 742 withdrawerDenomOtherBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], sdk.DefaultBondDenom) 743 require.Equal(t, addedDepositA, withdrawerDenomABalance) 744 require.Equal(t, deposit.AmountOf(pool.ReserveCoinDenoms[1]), withdrawerDenomBBalance.Amount) 745 require.NotEqual(t, manipulationReserveOther, withdrawerDenomOtherBalance) 746 } 747 748 func TestGetLiquidityPoolMetadata(t *testing.T) { 749 simapp, ctx := createTestInput() 750 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 751 params := simapp.LiquidityKeeper.GetParams(ctx) 752 753 poolTypeID := types.DefaultPoolTypeID 754 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 755 756 denomA := "uETH" 757 denomB := "uUSD" 758 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 759 760 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) 761 app.SaveAccount(simapp, ctx, addrs[0], deposit) 762 763 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 764 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 765 depositBalance := sdk.NewCoins(depositA, depositB) 766 767 require.Equal(t, deposit, depositBalance) 768 769 msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 770 771 _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) 772 require.NoError(t, err) 773 774 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 775 require.Equal(t, 1, len(pools)) 776 require.Equal(t, uint64(1), pools[0].Id) 777 require.Equal(t, uint64(1), simapp.LiquidityKeeper.GetNextPoolID(ctx)-1) 778 require.Equal(t, denomA, pools[0].ReserveCoinDenoms[0]) 779 require.Equal(t, denomB, pools[0].ReserveCoinDenoms[1]) 780 781 poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) 782 creatorBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) 783 require.Equal(t, poolCoin, creatorBalance.Amount) 784 785 _, err = simapp.LiquidityKeeper.CreatePool(ctx, msg) 786 require.ErrorIs(t, err, types.ErrPoolAlreadyExists) 787 788 metaData := simapp.LiquidityKeeper.GetPoolMetaData(ctx, pools[0]) 789 require.Equal(t, pools[0].Id, metaData.PoolId) 790 791 reserveCoin := simapp.LiquidityKeeper.GetReserveCoins(ctx, pools[0]) 792 require.Equal(t, reserveCoin, metaData.ReserveCoins) 793 require.Equal(t, msg.DepositCoins, metaData.ReserveCoins) 794 795 totalSupply := sdk.NewCoin(pools[0].PoolCoinDenom, simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0])) 796 require.Equal(t, totalSupply, metaData.PoolCoinTotalSupply) 797 require.Equal(t, creatorBalance, metaData.PoolCoinTotalSupply) 798 } 799 800 func TestIsPoolCoinDenom(t *testing.T) { 801 simapp, ctx := createTestInput() 802 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 803 params := simapp.LiquidityKeeper.GetParams(ctx) 804 805 poolTypeID := types.DefaultPoolTypeID 806 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 807 808 denomA := "denomA" 809 denomB := "denomB" 810 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 811 812 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) 813 app.SaveAccount(simapp, ctx, addrs[0], deposit) 814 815 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 816 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 817 depositBalance := sdk.NewCoins(depositA, depositB) 818 819 msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 820 821 pool, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) 822 require.NoError(t, err) 823 getPool, found := simapp.LiquidityKeeper.GetPool(ctx, pool.Id) 824 require.True(t, found) 825 require.Equal(t, pool, getPool) 826 827 require.Equal(t, "denomA/denomB/1", pool.Name()) 828 poolCoinDenom := types.GetPoolCoinDenom(pool.Name()) 829 require.Equal(t, pool.PoolCoinDenom, poolCoinDenom) 830 require.True(t, simapp.LiquidityKeeper.IsPoolCoinDenom(ctx, pool.PoolCoinDenom)) 831 require.False(t, simapp.LiquidityKeeper.IsPoolCoinDenom(ctx, pool.Name())) 832 } 833 834 func TestGetPoolByReserveAccIndex(t *testing.T) { 835 simapp, ctx := createTestInput() 836 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 837 params := simapp.LiquidityKeeper.GetParams(ctx) 838 839 poolTypeID := types.DefaultPoolTypeID 840 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 841 842 denomA := "uETH" 843 denomB := "uUSD" 844 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 845 846 deposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(100*1000000)), sdk.NewCoin(denomB, sdk.NewInt(2000*1000000))) 847 app.SaveAccount(simapp, ctx, addrs[0], deposit) 848 849 depositA := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomA) 850 depositB := simapp.BankKeeper.GetBalance(ctx, addrs[0], denomB) 851 depositBalance := sdk.NewCoins(depositA, depositB) 852 853 require.Equal(t, deposit, depositBalance) 854 855 msg := types.NewMsgCreatePool(addrs[0], poolTypeID, depositBalance) 856 pool, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) 857 require.NoError(t, err) 858 859 fmt.Println(pool) 860 poolStored, found := simapp.LiquidityKeeper.GetPool(ctx, pool.Id) 861 require.True(t, found) 862 require.Equal(t, pool, poolStored) 863 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 864 require.Equal(t, pool, pools[0]) 865 866 poolByReserveAcc, found := simapp.LiquidityKeeper.GetPoolByReserveAccIndex(ctx, pool.GetReserveAccount()) 867 require.True(t, found) 868 require.Equal(t, pool, poolByReserveAcc) 869 870 poolCoinDenom := types.GetPoolCoinDenom(pool.Name()) 871 require.Equal(t, pool.PoolCoinDenom, poolCoinDenom) 872 require.True(t, simapp.LiquidityKeeper.IsPoolCoinDenom(ctx, pool.PoolCoinDenom)) 873 require.False(t, simapp.LiquidityKeeper.IsPoolCoinDenom(ctx, pool.Name())) 874 //SetPoolByReserveAccIndex 875 } 876 877 func TestDepositWithdrawEdgecase(t *testing.T) { 878 for seed := int64(0); seed < 20; seed++ { 879 r := rand.New(rand.NewSource(seed)) 880 881 simapp, ctx := createTestInput() 882 params := simapp.LiquidityKeeper.GetParams(ctx) 883 884 X := params.MinInitDepositAmount.Add(app.GetRandRange(r, 0, 1_000_000)) 885 Y := params.MinInitDepositAmount.Add(app.GetRandRange(r, 0, 1_000_000)) 886 887 creatorCoins := sdk.NewCoins(sdk.NewCoin(DenomX, X), sdk.NewCoin(DenomY, Y)) 888 creatorAddr := app.AddRandomTestAddr(simapp, ctx, creatorCoins.Add(params.PoolCreationFee...)) 889 890 pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creatorAddr, types.DefaultPoolTypeID, creatorCoins)) 891 require.NoError(t, err) 892 893 for i := 0; i < 500; i++ { 894 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 895 type action int 896 const ( 897 deposit action = iota + 1 898 withdraw 899 ) 900 actions := []action{} 901 balanceX := simapp.BankKeeper.GetBalance(ctx, creatorAddr, DenomX) 902 balanceY := simapp.BankKeeper.GetBalance(ctx, creatorAddr, DenomY) 903 balancePoolCoin := simapp.BankKeeper.GetBalance(ctx, creatorAddr, pool.PoolCoinDenom) 904 if balanceX.IsPositive() || balanceY.IsPositive() { 905 actions = append(actions, deposit) 906 } 907 if balancePoolCoin.Amount.GT(sdk.OneInt()) { 908 actions = append(actions, withdraw) 909 } 910 require.Positive(t, len(actions)) 911 switch actions[r.Intn(len(actions))] { 912 case deposit: 913 depositAmtA := sdk.OneInt().Add(sdk.NewInt(r.Int63n(balanceX.Amount.Int64()))) 914 depositAmtB := sdk.OneInt().Add(sdk.NewInt(r.Int63n(balanceY.Amount.Int64()))) 915 depositCoins := sdk.NewCoins(sdk.NewCoin(DenomX, depositAmtA), sdk.NewCoin(DenomY, depositAmtB)) 916 _, err := simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch( 917 creatorAddr, pool.Id, depositCoins)) 918 require.NoError(t, err) 919 case withdraw: 920 totalPoolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 921 withdrawAmt := sdk.OneInt().Add(sdk.NewInt(r.Int63n(balancePoolCoin.Amount.Int64()))) 922 withdrawCoin := sdk.NewCoin(pool.PoolCoinDenom, sdk.MinInt(totalPoolCoin.Sub(sdk.OneInt()), withdrawAmt)) 923 _, err := simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch( 924 creatorAddr, pool.Id, withdrawCoin)) 925 require.NoError(t, err) 926 } 927 928 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 929 } 930 } 931 } 932 933 func TestWithdrawEdgecase(t *testing.T) { 934 simapp, ctx := createTestInput() 935 params := simapp.LiquidityKeeper.GetParams(ctx) 936 937 X, Y := sdk.NewInt(1_000_000), sdk.NewInt(10_000_000) 938 939 depositCoins := sdk.NewCoins(sdk.NewCoin(DenomX, X), sdk.NewCoin(DenomY, Y)) 940 creatorAddr := app.AddRandomTestAddr(simapp, ctx, depositCoins.Add(params.PoolCreationFee...)) 941 942 pool, err := simapp.LiquidityKeeper.CreatePool(ctx, types.NewMsgCreatePool(creatorAddr, types.DefaultPoolTypeID, depositCoins)) 943 require.NoError(t, err) 944 945 creatorBalance := simapp.BankKeeper.GetBalance(ctx, creatorAddr, pool.PoolCoinDenom).Sub(sdk.NewCoin(pool.PoolCoinDenom, sdk.NewInt(2))) 946 947 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 948 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, creatorBalance)) 949 require.NoError(t, err) 950 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 951 952 fmt.Println(simapp.LiquidityKeeper.GetPoolCoinTotal(ctx, pool)) 953 fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, creatorAddr)) 954 fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, pool.GetReserveAccount())) 955 956 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 957 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewCoin(pool.PoolCoinDenom, sdk.OneInt()))) 958 require.NoError(t, err) 959 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 960 961 fmt.Println(simapp.LiquidityKeeper.GetPoolCoinTotal(ctx, pool)) 962 fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, creatorAddr)) 963 fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, pool.GetReserveAccount())) 964 965 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewCoin(pool.PoolCoinDenom, sdk.OneInt()))) 966 require.NoError(t, err) 967 968 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 969 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 970 971 fmt.Println(simapp.LiquidityKeeper.GetPoolCoinTotal(ctx, pool)) 972 fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, creatorAddr)) 973 fmt.Println(simapp.BankKeeper.GetAllBalances(ctx, pool.GetReserveAccount())) 974 } 975 976 func TestWithdrawEdgecase2(t *testing.T) { 977 simapp, ctx, pool, creatorAddr, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1500000)) 978 require.NoError(t, err) 979 980 for i := 0; i < 1002; i++ { 981 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 982 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewInt64Coin(pool.PoolCoinDenom, 998))) 983 require.NoError(t, err) 984 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 985 } 986 987 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 988 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewInt64Coin(pool.PoolCoinDenom, 1))) 989 require.NoError(t, err) 990 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 991 } 992 993 func TestWithdrawSmallAmount(t *testing.T) { 994 simapp, ctx, pool, creatorAddr, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1500000)) 995 require.NoError(t, err) 996 997 require.NotPanics(t, func() { 998 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 999 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewInt64Coin(pool.PoolCoinDenom, 1))) 1000 require.NoError(t, err) 1001 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 1002 }) 1003 } 1004 1005 func TestGetReserveCoins(t *testing.T) { 1006 simapp, ctx, pool, creatorAddr, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1000000)) 1007 require.NoError(t, err) 1008 1009 reserveCoins := simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) 1010 require.Len(t, reserveCoins, 2) 1011 require.True(t, reserveCoins.AmountOf(DenomX).Equal(sdk.NewInt(1000000))) 1012 require.True(t, reserveCoins.AmountOf(DenomY).Equal(sdk.NewInt(1000000))) 1013 1014 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 1015 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, sdk.NewInt64Coin(pool.PoolCoinDenom, 1000000))) 1016 require.NoError(t, err) 1017 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 1018 1019 reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) 1020 require.Len(t, reserveCoins, 2) 1021 require.True(t, reserveCoins.AmountOf(DenomX).IsZero()) 1022 require.True(t, reserveCoins.AmountOf(DenomY).IsZero()) 1023 } 1024 1025 func TestDepositToDepletedPool(t *testing.T) { 1026 simapp, ctx, pool, creatorAddr, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1000000)) 1027 require.NoError(t, err) 1028 params := simapp.LiquidityKeeper.GetParams(ctx) 1029 1030 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 1031 pc := simapp.BankKeeper.GetBalance(ctx, creatorAddr, pool.PoolCoinDenom) 1032 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(creatorAddr, pool.Id, pc)) 1033 require.NoError(t, err) 1034 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 1035 1036 reserveCoins := simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) 1037 require.True(t, reserveCoins.AmountOf(DenomX).IsZero()) 1038 require.True(t, reserveCoins.AmountOf(DenomY).IsZero()) 1039 1040 require.True(t, simapp.LiquidityKeeper.IsDepletedPool(ctx, pool)) 1041 1042 err = simapp.BankKeeper.SendCoins(ctx, creatorAddr, pool.GetReserveAccount(), sdk.NewCoins(sdk.NewInt64Coin(DenomX, 10000))) 1043 require.NoError(t, err) 1044 1045 // Deposit request must be rejected since the pool is depleted and 1046 // depositing coins amount is smaller than MinInitDepositAmount. 1047 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 1048 depositCoins := sdk.NewCoins(sdk.NewInt64Coin(DenomX, 10000), sdk.NewInt64Coin(DenomY, 10000)) 1049 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch(creatorAddr, pool.Id, depositCoins)) 1050 require.NoError(t, err) 1051 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 1052 1053 reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) 1054 require.True(t, reserveCoins.AmountOf(DenomX).Equal(sdk.NewInt(10000))) 1055 require.True(t, reserveCoins.AmountOf(DenomY).IsZero()) 1056 creatorCoins := simapp.BankKeeper.GetAllBalances(ctx, creatorAddr) 1057 require.True(t, creatorCoins.AmountOf(DenomX).Equal(sdk.NewInt(990000))) 1058 require.True(t, creatorCoins.AmountOf(DenomY).Equal(sdk.NewInt(1000000))) 1059 1060 // This time the request will be accepted since depositCoins + reserveCoins > MinInitDepositAmount. 1061 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 1062 depositCoins = sdk.NewCoins(sdk.NewInt64Coin(DenomX, 990000), sdk.NewInt64Coin(DenomY, 1000000)) 1063 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch(creatorAddr, pool.Id, depositCoins)) 1064 require.NoError(t, err) 1065 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 1066 1067 reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) 1068 require.True(t, reserveCoins.AmountOf(DenomX).Equal(sdk.NewInt(1000000))) 1069 require.True(t, reserveCoins.AmountOf(DenomY).Equal(sdk.NewInt(1000000))) 1070 creatorCoins = simapp.BankKeeper.GetAllBalances(ctx, creatorAddr) 1071 require.True(t, creatorCoins.AmountOf(DenomX).Equal(sdk.NewInt(0))) 1072 require.True(t, creatorCoins.AmountOf(DenomY).Equal(sdk.NewInt(0))) 1073 require.True(t, creatorCoins.AmountOf(pool.PoolCoinDenom).Equal(params.InitPoolCoinMintAmount)) 1074 } 1075 1076 func TestDepositWithCoinsSent(t *testing.T) { 1077 simapp, ctx, pool, _, err := createTestPool(sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 1000000)) 1078 require.NoError(t, err) 1079 1080 // Send extra coins to the pool reserve account, which causes the pool price to change. 1081 // Any other coins(coins with denom "denomZ" here) than pool's reserve coins will not have any effect. 1082 extraCoins := sdk.NewCoins( 1083 sdk.NewInt64Coin(DenomX, 1000000), sdk.NewInt64Coin(DenomY, 2000000), sdk.NewInt64Coin("denomZ", 1000000)) 1084 addr := app.AddRandomTestAddr(simapp, ctx, extraCoins) 1085 err = simapp.BankKeeper.SendCoins(ctx, addr, pool.GetReserveAccount(), extraCoins) 1086 require.NoError(t, err) 1087 reserveCoins := simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) 1088 require.Len(t, reserveCoins, 2) // denomZ coins are ignored 1089 require.True(sdk.IntEq(t, sdk.NewInt(2000000), reserveCoins.AmountOf(DenomX))) 1090 require.True(sdk.IntEq(t, sdk.NewInt(3000000), reserveCoins.AmountOf(DenomY))) 1091 1092 // Add more coins to deposit. 1093 depositCoins := sdk.NewCoins(sdk.NewInt64Coin(DenomX, 3000000), sdk.NewInt64Coin(DenomY, 3000000)) 1094 app.SaveAccount(simapp, ctx, addr, depositCoins) 1095 1096 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 1097 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, types.NewMsgDepositWithinBatch(addr, pool.Id, depositCoins)) 1098 require.NoError(t, err) 1099 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 1100 1101 reserveCoins = simapp.LiquidityKeeper.GetReserveCoins(ctx, pool) 1102 require.True(sdk.IntEq(t, sdk.NewInt(4000000), reserveCoins.AmountOf(DenomX))) 1103 require.True(sdk.IntEq(t, sdk.NewInt(6000000), reserveCoins.AmountOf(DenomY))) 1104 balances := simapp.BankKeeper.GetAllBalances(ctx, addr) 1105 require.True(sdk.IntEq(t, sdk.NewInt(1000000), balances.AmountOf(DenomX))) 1106 require.True(sdk.IntEq(t, sdk.NewInt(0), balances.AmountOf(DenomY))) 1107 require.True(sdk.IntEq(t, sdk.NewInt(1000000), balances.AmountOf(pool.PoolCoinDenom))) 1108 } 1109 1110 func TestCreatePoolEqualDenom(t *testing.T) { 1111 simapp, ctx := createTestInput() 1112 params := types.DefaultParams() 1113 simapp.LiquidityKeeper.SetParams(ctx, params) 1114 addrs := app.AddTestAddrs(simapp, ctx, 1, params.PoolCreationFee) 1115 1116 msg := types.NewMsgCreatePool(addrs[0], types.DefaultPoolTypeID, 1117 sdk.Coins{ 1118 sdk.NewCoin(DenomA, sdk.NewInt(1000000)), 1119 sdk.NewCoin(DenomA, sdk.NewInt(1000000))}) 1120 _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) 1121 require.ErrorIs(t, err, types.ErrEqualDenom) 1122 } 1123 1124 func TestOverflowAndZeroCases(t *testing.T) { 1125 simapp, ctx := createTestInput() 1126 params := types.DefaultParams() 1127 simapp.LiquidityKeeper.SetParams(ctx, params) 1128 keeper.BatchLogicInvariantCheckFlag = false 1129 1130 poolTypeID := types.DefaultPoolTypeID 1131 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 1132 1133 denomA := "uETH" 1134 denomB := "uUSD" 1135 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 1136 1137 // Check overflow case on deposit 1138 deposit := sdk.NewCoins( 1139 sdk.NewCoin(denomA, sdk.NewInt(1_000_000)), 1140 sdk.NewCoin(denomB, sdk.NewInt(2_000_000_000_000*1_000_000).MulRaw(1_000_000))) 1141 hugeCoins := sdk.NewCoins( 1142 sdk.NewCoin(denomA, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000)), 1143 sdk.NewCoin(denomB, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000))) 1144 hugeCoins2 := sdk.NewCoins( 1145 sdk.NewCoin(denomA, sdk.NewInt(1_000_000_000_000_000_000)), 1146 sdk.NewCoin(denomB, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000))) 1147 app.SaveAccount(simapp, ctx, addrs[0], deposit.Add(hugeCoins.Add(hugeCoins2...)...)) 1148 1149 msg := types.NewMsgCreatePool(addrs[0], poolTypeID, deposit) 1150 _, err := simapp.LiquidityKeeper.CreatePool(ctx, msg) 1151 require.NoError(t, err) 1152 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 1153 poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) 1154 1155 depositorBalance := simapp.BankKeeper.GetAllBalances(ctx, addrs[0]) 1156 depositMsg := types.NewMsgDepositWithinBatch(addrs[0], pools[0].Id, hugeCoins) 1157 depositMsg2 := types.NewMsgDepositWithinBatch(addrs[0], pools[0].Id, hugeCoins2) 1158 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) 1159 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg2) 1160 require.NoError(t, err) 1161 1162 poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) 1163 require.True(t, found) 1164 msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) 1165 require.Equal(t, 2, len(msgs)) 1166 err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) 1167 require.ErrorIs(t, err, types.ErrOverflowAmount) 1168 err = simapp.LiquidityKeeper.RefundDeposit(ctx, msgs[0], poolBatch) 1169 require.NoError(t, err) 1170 err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[1], poolBatch) 1171 require.ErrorIs(t, err, types.ErrOverflowAmount) 1172 err = simapp.LiquidityKeeper.RefundDeposit(ctx, msgs[1], poolBatch) 1173 require.NoError(t, err) 1174 1175 poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pools[0]) 1176 depositorPoolCoinBalance := simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) 1177 require.Equal(t, poolCoin, poolCoinAfter) 1178 require.Equal(t, poolCoinAfter, depositorPoolCoinBalance.Amount) 1179 require.Equal(t, depositorBalance.AmountOf(pools[0].PoolCoinDenom), depositorPoolCoinBalance.Amount) 1180 1181 hugeCoins3 := sdk.NewCoins( 1182 sdk.NewCoin(denomA, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000)), 1183 sdk.NewCoin(denomB, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000))) 1184 depositMsg = types.NewMsgDepositWithinBatch(addrs[0], pools[0].Id, hugeCoins3) 1185 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) 1186 require.NoError(t, err) 1187 msgs = simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) 1188 require.Equal(t, 3, len(msgs)) 1189 err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[2], poolBatch) 1190 require.NoError(t, err) 1191 1192 // Check overflow case on withdraw 1193 depositorPoolCoinBalance = simapp.BankKeeper.GetBalance(ctx, addrs[0], pools[0].PoolCoinDenom) 1194 _, err = simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(addrs[0], pools[0].Id, depositorPoolCoinBalance.SubAmount(sdk.NewInt(1)))) 1195 require.NoError(t, err) 1196 1197 poolBatch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) 1198 require.True(t, found) 1199 withdrawMsgs := simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) 1200 require.Equal(t, 1, len(withdrawMsgs)) 1201 err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, withdrawMsgs[0], poolBatch) 1202 require.ErrorIs(t, err, types.ErrOverflowAmount) 1203 err = simapp.LiquidityKeeper.RefundWithdrawal(ctx, withdrawMsgs[0], poolBatch) 1204 require.NoError(t, err) 1205 1206 // Check overflow, division by zero case on swap 1207 swapUserBalanceBefore := simapp.BankKeeper.GetAllBalances(ctx, addrs[0]) 1208 offerCoinA := sdk.NewCoin(denomA, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000)) 1209 orderPriceA := sdk.MustNewDecFromStr("110000000000000000000000000000000000000000000000000000000000.000000000000000001") 1210 offerCoinB := sdk.NewCoin(denomB, sdk.NewInt(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000_000_000).MulRaw(1_000_000_000_000)) 1211 orderPriceB := sdk.MustNewDecFromStr("0.000000000000000001") 1212 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 1213 _, err = simapp.LiquidityKeeper.SwapWithinBatch( 1214 ctx, 1215 types.NewMsgSwapWithinBatch(addrs[0], pools[0].Id, types.DefaultSwapTypeID, offerCoinA, denomB, orderPriceA, params.SwapFeeRate), 1216 0) 1217 require.ErrorIs(t, err, types.ErrOverflowAmount) 1218 _, err = simapp.LiquidityKeeper.SwapWithinBatch( 1219 ctx, 1220 types.NewMsgSwapWithinBatch(addrs[0], pools[0].Id, types.DefaultSwapTypeID, offerCoinB, denomA, orderPriceB, params.SwapFeeRate), 1221 0) 1222 require.NoError(t, err) 1223 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 1224 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 1225 swapUserBalanceAfter := simapp.BankKeeper.GetAllBalances(ctx, addrs[0]) 1226 require.Equal(t, swapUserBalanceBefore, swapUserBalanceAfter) 1227 depositMsgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) 1228 require.Equal(t, 0, len(depositMsgs)) 1229 withdrawMsgs = simapp.LiquidityKeeper.GetAllPoolBatchWithdrawMsgStates(ctx, poolBatch) 1230 require.Equal(t, 0, len(withdrawMsgs)) 1231 swapMsgs := simapp.LiquidityKeeper.GetAllPoolBatchSwapMsgStates(ctx, poolBatch) 1232 require.Equal(t, 0, len(swapMsgs)) 1233 } 1234 1235 func TestExecuteBigDeposit(t *testing.T) { 1236 simapp, ctx := createTestInput() 1237 simapp.LiquidityKeeper.SetParams(ctx, types.DefaultParams()) 1238 params := simapp.LiquidityKeeper.GetParams(ctx) 1239 keeper.BatchLogicInvariantCheckFlag = false 1240 1241 poolTypeID := types.DefaultPoolTypeID 1242 addrs := app.AddTestAddrs(simapp, ctx, 3, params.PoolCreationFee) 1243 1244 denomA := "uETH" 1245 denomB := "uUSD" 1246 denomA, denomB = types.AlphabeticalDenomPair(denomA, denomB) 1247 1248 // 2^63-1 1249 hugeInt := int64(9223372036854775807) 1250 initDeposit := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(hugeInt)), sdk.NewCoin(denomB, sdk.NewInt(hugeInt))) 1251 app.SaveAccount(simapp, ctx, addrs[0], initDeposit) 1252 app.SaveAccount(simapp, ctx, addrs[1], initDeposit) 1253 app.SaveAccount(simapp, ctx, addrs[2], initDeposit) 1254 1255 createBalance := sdk.NewCoins(sdk.NewCoin(denomA, sdk.NewInt(1*1000000)), sdk.NewCoin(denomB, sdk.NewInt(1*1000000))) 1256 1257 createMsg := types.NewMsgCreatePool(addrs[0], poolTypeID, createBalance) 1258 1259 _, err := simapp.LiquidityKeeper.CreatePool(ctx, createMsg) 1260 require.NoError(t, err) 1261 1262 pools := simapp.LiquidityKeeper.GetAllPools(ctx) 1263 pool := pools[0] 1264 1265 poolCoinInit := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 1266 require.Equal(t, poolCoinInit, sdk.NewInt(1*1000000)) 1267 1268 depositMsg := types.NewMsgDepositWithinBatch(addrs[1], pool.Id, initDeposit) 1269 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) 1270 require.NoError(t, err) 1271 1272 poolBatch, found := simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) 1273 require.True(t, found) 1274 msgs := simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) 1275 require.Equal(t, 1, len(msgs)) 1276 1277 err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) 1278 require.NoError(t, err) 1279 1280 poolCoin := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 1281 require.Equal(t, poolCoin.Sub(poolCoinInit), simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom).Amount) 1282 1283 simapp.LiquidityKeeper.DeleteAllReadyPoolBatchDepositMsgStates(ctx, poolBatch) 1284 1285 depositMsg = types.NewMsgDepositWithinBatch(addrs[2], pool.Id, initDeposit) 1286 _, err = simapp.LiquidityKeeper.DepositWithinBatch(ctx, depositMsg) 1287 require.NoError(t, err) 1288 1289 poolBatch, found = simapp.LiquidityKeeper.GetPoolBatch(ctx, depositMsg.PoolId) 1290 require.True(t, found) 1291 msgs = simapp.LiquidityKeeper.GetAllPoolBatchDepositMsgs(ctx, poolBatch) 1292 require.Equal(t, 1, len(msgs)) 1293 1294 err = simapp.LiquidityKeeper.ExecuteDeposit(ctx, msgs[0], poolBatch) 1295 require.NoError(t, err) 1296 1297 poolCoinAfter := simapp.LiquidityKeeper.GetPoolCoinTotalSupply(ctx, pool) 1298 require.Equal(t, poolCoinAfter.Sub(poolCoin), simapp.BankKeeper.GetBalance(ctx, addrs[2], pool.PoolCoinDenom).Amount) 1299 require.Equal(t, simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom).Amount, simapp.BankKeeper.GetBalance(ctx, addrs[2], pool.PoolCoinDenom).Amount) 1300 1301 require.True(t, simapp.BankKeeper.GetBalance(ctx, addrs[1], denomA).IsZero()) 1302 require.True(t, simapp.BankKeeper.GetBalance(ctx, addrs[1], denomB).IsZero()) 1303 1304 // Error due to decimal operation exceeding precision 1305 require.Equal(t, sdk.NewInt(8), simapp.BankKeeper.GetBalance(ctx, addrs[2], denomA).Amount) 1306 require.Equal(t, sdk.NewInt(8), simapp.BankKeeper.GetBalance(ctx, addrs[2], denomB).Amount) 1307 1308 poolCoinAmt := simapp.BankKeeper.GetBalance(ctx, addrs[1], pool.PoolCoinDenom) 1309 state, err := simapp.LiquidityKeeper.WithdrawWithinBatch(ctx, types.NewMsgWithdrawWithinBatch(addrs[1], pool.Id, poolCoinAmt)) 1310 require.NoError(t, err) 1311 1312 err = simapp.LiquidityKeeper.ExecuteWithdrawal(ctx, state, poolBatch) 1313 require.NoError(t, err) 1314 1315 balanceAfter := simapp.BankKeeper.GetAllBalances(ctx, addrs[1]) 1316 liquidity.EndBlocker(ctx, simapp.LiquidityKeeper) 1317 liquidity.BeginBlocker(ctx, simapp.LiquidityKeeper) 1318 1319 // Error due to decimal operation exceeding precision 1320 require.Equal(t, sdk.ZeroInt(), balanceAfter.AmountOf(pool.PoolCoinDenom)) 1321 require.Equal(t, sdk.NewInt(-4), balanceAfter.AmountOf(denomA).SubRaw(hugeInt)) 1322 require.Equal(t, sdk.NewInt(-4), balanceAfter.AmountOf(denomB).SubRaw(hugeInt)) 1323 }