From 829aed52562bb71dab937365e13736841be2b102 Mon Sep 17 00:00:00 2001 From: Kevin Davis Date: Wed, 10 Mar 2021 10:56:08 -0700 Subject: [PATCH] fix: decrement coins for supply/borrow properly (#862) * fix: decrement coins for supply/borrow properly * fix: decrement keeper liquidation reward coins from hard total supply (#865) * fix: use proper safe subtraction for withdraw/repay methods * fix: decrement keeper liquidation rewards from total supply * address review comments --- x/hard/keeper/borrow.go | 20 +++-- x/hard/keeper/deposit.go | 20 +++-- x/hard/keeper/deposit_test.go | 136 ++++++++++++++++++++++++++++++ x/hard/keeper/liquidation.go | 1 + x/hard/keeper/liquidation_test.go | 118 +++++++++++++++----------- 5 files changed, 230 insertions(+), 65 deletions(-) diff --git a/x/hard/keeper/borrow.go b/x/hard/keeper/borrow.go index aa0f109a..833cf966 100644 --- a/x/hard/keeper/borrow.go +++ b/x/hard/keeper/borrow.go @@ -238,15 +238,19 @@ func (k Keeper) DecrementBorrowedCoins(ctx sdk.Context, coins sdk.Coins) error { return sdkerrors.Wrapf(types.ErrBorrowedCoinsNotFound, "cannot repay coins if no coins are currently borrowed") } - updatedBorrowedCoins := sdk.NewCoins() - for _, coin := range coins { - // If amount is greater than total borrowed amount due to rounding, set total borrowed amount to 0 - // by skipping the coin such that it's not included in the updatedBorrowedCoins object - if coin.Amount.GTE(borrowedCoins.AmountOf(coin.Denom)) { - continue + updatedBorrowedCoins, isNegative := borrowedCoins.SafeSub(coins) + if isNegative { + coinsToSubtract := sdk.NewCoins() + for _, coin := range coins { + if borrowedCoins.AmountOf(coin.Denom).LT(coin.Amount) { + if borrowedCoins.AmountOf(coin.Denom).GT(sdk.ZeroInt()) { + coinsToSubtract = coinsToSubtract.Add(sdk.NewCoin(coin.Denom, borrowedCoins.AmountOf(coin.Denom))) + } + } else { + coinsToSubtract = coinsToSubtract.Add(coin) + } } - updatedBorrowCoin := sdk.NewCoin(coin.Denom, borrowedCoins.AmountOf(coin.Denom).Sub(coin.Amount)) - updatedBorrowedCoins = updatedBorrowedCoins.Add(updatedBorrowCoin) + updatedBorrowedCoins = borrowedCoins.Sub(coinsToSubtract) } k.SetBorrowedCoins(ctx, updatedBorrowedCoins) diff --git a/x/hard/keeper/deposit.go b/x/hard/keeper/deposit.go index 63390ca8..9df0127c 100644 --- a/x/hard/keeper/deposit.go +++ b/x/hard/keeper/deposit.go @@ -145,15 +145,19 @@ func (k Keeper) DecrementSuppliedCoins(ctx sdk.Context, coins sdk.Coins) error { return sdkerrors.Wrapf(types.ErrSuppliedCoinsNotFound, "cannot withdraw if no coins are deposited") } - updatedSuppliedCoins := sdk.NewCoins() - for _, coin := range coins { - // If amount is greater than total supplied amount due to rounding, set total supplied amount to 0 - // by skipping the coin such that it's not included in the updatedSuppliedCoins object - if coin.Amount.GTE(suppliedCoins.AmountOf(coin.Denom)) { - continue + updatedSuppliedCoins, isNegative := suppliedCoins.SafeSub(coins) + if isNegative { + coinsToSubtract := sdk.NewCoins() + for _, coin := range coins { + if suppliedCoins.AmountOf(coin.Denom).LT(coin.Amount) { + if suppliedCoins.AmountOf(coin.Denom).GT(sdk.ZeroInt()) { + coinsToSubtract = coinsToSubtract.Add(sdk.NewCoin(coin.Denom, suppliedCoins.AmountOf(coin.Denom))) + } + } else { + coinsToSubtract = coinsToSubtract.Add(coin) + } } - updatedSupplyCoin := sdk.NewCoin(coin.Denom, suppliedCoins.AmountOf(coin.Denom).Sub(coin.Amount)) - updatedSuppliedCoins = updatedSuppliedCoins.Add(updatedSupplyCoin) + updatedSuppliedCoins = suppliedCoins.Sub(coinsToSubtract) } k.SetSuppliedCoins(ctx, updatedSuppliedCoins) diff --git a/x/hard/keeper/deposit_test.go b/x/hard/keeper/deposit_test.go index 4855e9f0..a6152b8d 100644 --- a/x/hard/keeper/deposit_test.go +++ b/x/hard/keeper/deposit_test.go @@ -189,3 +189,139 @@ func (suite *KeeperTestSuite) TestDeposit() { }) } } + +func (suite *KeeperTestSuite) TestDecrementSuppliedCoins() { + type args struct { + suppliedInitial sdk.Coins + decrementCoins sdk.Coins + expectedSuppliedFinal sdk.Coins + } + type errArgs struct { + expectPass bool + contains string + } + type decrementTest struct { + name string + args args + errArgs errArgs + } + testCases := []decrementTest{ + { + "valid", + args{ + suppliedInitial: cs(c("bnb", 10000000000000), c("busd", 3000000000000), c("xrpb", 2500000000000)), + decrementCoins: cs(c("bnb", 5000000000000)), + expectedSuppliedFinal: cs(c("bnb", 5000000000000), c("busd", 3000000000000), c("xrpb", 2500000000000)), + }, + errArgs{ + expectPass: true, + contains: "", + }, + }, + { + "valid-negative", + args{ + suppliedInitial: cs(c("bnb", 10000000000000), c("busd", 3000000000000), c("xrpb", 2500000000000)), + decrementCoins: cs(c("bnb", 10000000000001)), + expectedSuppliedFinal: cs(c("busd", 3000000000000), c("xrpb", 2500000000000)), + }, + errArgs{ + expectPass: true, + contains: "", + }, + }, + { + "valid-multiple negative", + args{ + suppliedInitial: cs(c("bnb", 10000000000000), c("busd", 3000000000000), c("xrpb", 2500000000000)), + decrementCoins: cs(c("bnb", 10000000000001), c("busd", 5000000000000)), + expectedSuppliedFinal: cs(c("xrpb", 2500000000000)), + }, + errArgs{ + expectPass: true, + contains: "", + }, + }, + { + "valid-absent coin denom", + args{ + suppliedInitial: cs(c("bnb", 10000000000000), c("xrpb", 2500000000000)), + decrementCoins: cs(c("busd", 5)), + expectedSuppliedFinal: cs(c("bnb", 10000000000000), c("xrpb", 2500000000000)), + }, + errArgs{ + expectPass: true, + contains: "", + }, + }, + } + for _, tc := range testCases { + suite.Run(tc.name, func() { + // Initialize test app and set context + tApp := app.NewTestApp() + ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) + loanToValue, _ := sdk.NewDecFromStr("0.6") + depositor := sdk.AccAddress(crypto.AddressHash([]byte("test"))) + authGS := app.NewAuthGenState([]sdk.AccAddress{depositor}, []sdk.Coins{tc.args.suppliedInitial}) + hardGS := types.NewGenesisState(types.NewParams( + types.MoneyMarkets{ + types.NewMoneyMarket("bnb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "bnb:usd", sdk.NewInt(100000000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()), + types.NewMoneyMarket("busd", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "busd:usd", sdk.NewInt(100000000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()), + types.NewMoneyMarket("xrpb", types.NewBorrowLimit(false, sdk.NewDec(1000000000000000), loanToValue), "xrpb:usd", sdk.NewInt(100000000), types.NewInterestRateModel(sdk.MustNewDecFromStr("0.05"), sdk.MustNewDecFromStr("2"), sdk.MustNewDecFromStr("0.8"), sdk.MustNewDecFromStr("10")), sdk.MustNewDecFromStr("0.05"), sdk.ZeroDec()), + }, + sdk.MustNewDecFromStr("10"), + ), types.DefaultAccumulationTimes, types.DefaultDeposits, types.DefaultBorrows, + types.DefaultTotalSupplied, types.DefaultTotalBorrowed, types.DefaultTotalReserves, + ) + // Pricefeed module genesis state + pricefeedGS := pricefeed.GenesisState{ + Params: pricefeed.Params{ + Markets: []pricefeed.Market{ + {MarketID: "xrpb:usd", BaseAsset: "kava", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, + {MarketID: "busd:usd", BaseAsset: "btcb", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, + {MarketID: "bnb:usd", BaseAsset: "bnb", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, + }, + }, + PostedPrices: []pricefeed.PostedPrice{ + { + MarketID: "busd:usd", + OracleAddress: sdk.AccAddress{}, + Price: sdk.MustNewDecFromStr("1.00"), + Expiry: time.Now().Add(1 * time.Hour), + }, + { + MarketID: "xrpb:usd", + OracleAddress: sdk.AccAddress{}, + Price: sdk.MustNewDecFromStr("2.00"), + Expiry: time.Now().Add(1 * time.Hour), + }, + { + MarketID: "bnb:usd", + OracleAddress: sdk.AccAddress{}, + Price: sdk.MustNewDecFromStr("200.00"), + Expiry: time.Now().Add(1 * time.Hour), + }, + }, + } + tApp.InitializeFromGenesisStates(authGS, + app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pricefeedGS)}, + app.GenesisState{types.ModuleName: types.ModuleCdc.MustMarshalJSON(hardGS)}, + ) + keeper := tApp.GetHardKeeper() + suite.app = tApp + suite.ctx = ctx + suite.keeper = keeper + + // Run BeginBlocker once to transition MoneyMarkets + hard.BeginBlocker(suite.ctx, suite.keeper) + + err := suite.keeper.Deposit(suite.ctx, depositor, tc.args.suppliedInitial) + suite.Require().NoError(err) + err = suite.keeper.DecrementSuppliedCoins(ctx, tc.args.decrementCoins) + suite.Require().NoError(err) + totalSuppliedActual, found := suite.keeper.GetSuppliedCoins(suite.ctx) + suite.Require().True(found) + suite.Require().Equal(totalSuppliedActual, tc.args.expectedSuppliedFinal) + }) + } +} diff --git a/x/hard/keeper/liquidation.go b/x/hard/keeper/liquidation.go index 35b98197..aaee1a3a 100644 --- a/x/hard/keeper/liquidation.go +++ b/x/hard/keeper/liquidation.go @@ -86,6 +86,7 @@ func (k Keeper) SeizeDeposits(ctx sdk.Context, keeper sdk.AccAddress, deposit ty } } if !keeperRewardCoins.Empty() { + k.DecrementSuppliedCoins(ctx, keeperRewardCoins) err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleAccountName, keeper, keeperRewardCoins) if err != nil { return err diff --git a/x/hard/keeper/liquidation_test.go b/x/hard/keeper/liquidation_test.go index 597bd1fc..a34615ae 100644 --- a/x/hard/keeper/liquidation_test.go +++ b/x/hard/keeper/liquidation_test.go @@ -72,7 +72,7 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() { depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(10*KAVA_CF))), borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(8*KAVA_CF))), liquidateAfter: oneMonthInSeconds, - expectedTotalSuppliedCoins: sdk.NewCoins(sdk.NewInt64Coin("ukava", 504138)), + expectedTotalSuppliedCoins: sdk.NewCoins(sdk.NewInt64Coin("ukava", 100004118)), expectedTotalBorrowedCoins: nil, expectedKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100500020))), expectedBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(98000001))), // initial - deposit + borrow + liquidation leftovers @@ -102,16 +102,21 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() { { "valid: single deposit, multiple borrows", args{ - borrower: borrower, - keeper: keeper, - keeperRewardPercent: sdk.MustNewDecFromStr("0.05"), - initialModuleCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(1000*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(1000*BTCB_CF))), - initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))), - initialKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))), - depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF))), // $100 * 0.8 = $80 borrowable - borrowCoins: sdk.NewCoins(sdk.NewCoin("usdc", sdk.NewInt(20*KAVA_CF)), sdk.NewCoin("ukava", sdk.NewInt(10*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(2*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(0.2*BTCB_CF))), // $20+$20+$20 = $80 borrowed - liquidateAfter: oneMonthInSeconds, - expectedTotalSuppliedCoins: sdk.NewCoins(sdk.NewInt64Coin("ukava", 2500711)), + borrower: borrower, + keeper: keeper, + keeperRewardPercent: sdk.MustNewDecFromStr("0.05"), + initialModuleCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(1000*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(1000*BTCB_CF))), + initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))), + initialKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))), + depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF))), // $100 * 0.8 = $80 borrowable + borrowCoins: sdk.NewCoins(sdk.NewCoin("usdc", sdk.NewInt(20*KAVA_CF)), sdk.NewCoin("ukava", sdk.NewInt(10*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(2*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(0.2*BTCB_CF))), // $20+$20+$20 = $80 borrowed + liquidateAfter: oneMonthInSeconds, + expectedTotalSuppliedCoins: sdk.NewCoins( + sdk.NewInt64Coin("ukava", 1000000710), + sdk.NewInt64Coin("usdc", 1000003120), + sdk.NewInt64Coin("bnb", 100000003123), + sdk.NewInt64Coin("btc", 100000000031), + ), expectedTotalBorrowedCoins: nil, expectedKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(102500001))), expectedBorrowerCoins: sdk.NewCoins(sdk.NewCoin("usdc", sdk.NewInt(20*KAVA_CF)), sdk.NewCoin("ukava", sdk.NewInt(60000002)), sdk.NewCoin("bnb", sdk.NewInt(2*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(0.2*BTCB_CF))), // initial - deposit + borrow + liquidation leftovers @@ -186,16 +191,18 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() { { "valid: multiple deposits, single borrow", args{ - borrower: borrower, - keeper: keeper, - keeperRewardPercent: sdk.MustNewDecFromStr("0.05"), - initialModuleCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000*KAVA_CF))), - initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(100*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(100*BTCB_CF))), - initialKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))), - depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(10*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(1*BTCB_CF))), // $100 + $100 + $100 = $300 * 0.8 = $240 borrowable // $100 * 0.8 = $80 borrowable - borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(120*KAVA_CF))), // $240 borrowed - liquidateAfter: oneMonthInSeconds, - expectedTotalSuppliedCoins: nil, + borrower: borrower, + keeper: keeper, + keeperRewardPercent: sdk.MustNewDecFromStr("0.05"), + initialModuleCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000*KAVA_CF))), + initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(100*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(100*BTCB_CF))), + initialKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))), + depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(10*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(1*BTCB_CF))), // $100 + $100 + $100 = $300 * 0.8 = $240 borrowable // $100 * 0.8 = $80 borrowable + borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(120*KAVA_CF))), // $240 borrowed + liquidateAfter: oneMonthInSeconds, + expectedTotalSuppliedCoins: sdk.NewCoins( + sdk.NewInt64Coin("ukava", 1000101456), + ), expectedTotalBorrowedCoins: nil, expectedKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(102500253)), sdk.NewCoin("bnb", sdk.NewInt(0.5*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(0.05*BTCB_CF))), // 5% of each seized coin + initial balances expectedBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(170.000001*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(90*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(99*BTCB_CF))), @@ -253,19 +260,24 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() { }, }, { - "valid: mutliple stablecoin deposits, multiple variable coin borrows", + "valid: multiple stablecoin deposits, multiple variable coin borrows", // Auctions: total lot value = $285 ($300 of deposits - $15 keeper reward), total max bid value = $270 args{ - borrower: borrower, - keeper: keeper, - keeperRewardPercent: sdk.MustNewDecFromStr("0.05"), - initialModuleCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(1000*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(1000*BTCB_CF))), - initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(100*KAVA_CF))), - initialKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))), - depositCoins: sdk.NewCoins(sdk.NewCoin("usdc", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(100*KAVA_CF))), // $100 + $100 + $100 = $300 * 0.9 = $270 borrowable - borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(35*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(10*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(1*BTCB_CF))), // $270 borrowed - liquidateAfter: oneMonthInSeconds, - expectedTotalSuppliedCoins: nil, + borrower: borrower, + keeper: keeper, + keeperRewardPercent: sdk.MustNewDecFromStr("0.05"), + initialModuleCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(1000*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(1000*BTCB_CF))), + initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(100*KAVA_CF))), + initialKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))), + depositCoins: sdk.NewCoins(sdk.NewCoin("usdc", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(100*KAVA_CF))), // $100 + $100 + $100 = $300 * 0.9 = $270 borrowable + borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(35*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(10*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(1*BTCB_CF))), // $270 borrowed + liquidateAfter: oneMonthInSeconds, + expectedTotalSuppliedCoins: sdk.NewCoins( + sdk.NewInt64Coin("bnb", 100000078047), + sdk.NewInt64Coin("btc", 100000000780), + sdk.NewInt64Coin("ukava", 1000009550), + sdk.NewInt64Coin("usdx", 1), + ), expectedTotalBorrowedCoins: nil, expectedKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(5*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(5*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(5*KAVA_CF))), // 5% of each seized coin + initial balances expectedBorrowerCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(135*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(10*BNB_CF)), sdk.NewCoin("btc", sdk.NewInt(1*BTCB_CF)), sdk.NewCoin("usdx", sdk.NewInt(0.000001*KAVA_CF))), @@ -355,16 +367,21 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() { { "valid: multiple stablecoin deposits, multiple stablecoin borrows", args{ - borrower: borrower, - keeper: keeper, - keeperRewardPercent: sdk.MustNewDecFromStr("0.05"), - initialModuleCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("dai", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(1000*KAVA_CF))), - initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("dai", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(1000*KAVA_CF))), - initialKeeperCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("dai", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(1000*KAVA_CF))), - depositCoins: sdk.NewCoins(sdk.NewCoin("dai", sdk.NewInt(350*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(200*KAVA_CF))), - borrowCoins: sdk.NewCoins(sdk.NewCoin("usdt", sdk.NewInt(250*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(245*KAVA_CF))), - liquidateAfter: oneMonthInSeconds, - expectedTotalSuppliedCoins: nil, + borrower: borrower, + keeper: keeper, + keeperRewardPercent: sdk.MustNewDecFromStr("0.05"), + initialModuleCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("dai", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(1000*KAVA_CF))), + initialBorrowerCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("dai", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(1000*KAVA_CF))), + initialKeeperCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("dai", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(1000*KAVA_CF))), + depositCoins: sdk.NewCoins(sdk.NewCoin("dai", sdk.NewInt(350*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(200*KAVA_CF))), + borrowCoins: sdk.NewCoins(sdk.NewCoin("usdt", sdk.NewInt(250*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(245*KAVA_CF))), + liquidateAfter: oneMonthInSeconds, + expectedTotalSuppliedCoins: sdk.NewCoins( + sdk.NewInt64Coin("dai", 1000000000), + sdk.NewInt64Coin("usdc", 1000000001), + sdk.NewInt64Coin("usdt", 1000482503), + sdk.NewInt64Coin("usdx", 1000463500), + ), expectedTotalBorrowedCoins: nil, expectedKeeperCoins: sdk.NewCoins(sdk.NewCoin("dai", sdk.NewInt(1017.50*KAVA_CF)), sdk.NewCoin("usdt", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(1010*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(1000*KAVA_CF))), expectedBorrowerCoins: sdk.NewCoins(sdk.NewCoin("dai", sdk.NewInt(650*KAVA_CF)), sdk.NewCoin("usdc", sdk.NewInt(800000001)), sdk.NewCoin("usdt", sdk.NewInt(1250*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(1245*KAVA_CF))), @@ -433,7 +450,7 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() { depositCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(20*KAVA_CF))), // Deposit 20 KAVA borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(5*KAVA_CF))), // Borrow 5 KAVA liquidateAfter: oneMonthInSeconds, - expectedTotalSuppliedCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(20001624))), + expectedTotalSuppliedCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(120001624))), expectedTotalBorrowedCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(5001709))), expectedKeeperCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100.5*KAVA_CF))), expectedBorrowerCoins: sdk.NewCoins(), @@ -452,10 +469,13 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() { tApp := app.NewTestApp() ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) + // account which will deposit "initial module account coins" + depositor := sdk.AccAddress(crypto.AddressHash([]byte("testdepositor"))) + // Auth module genesis state authGS := app.NewAuthGenState( - []sdk.AccAddress{tc.args.borrower, tc.args.keeper}, - []sdk.Coins{tc.args.initialBorrowerCoins, tc.args.initialKeeperCoins}, + []sdk.AccAddress{tc.args.borrower, tc.args.keeper, depositor}, + []sdk.Coins{tc.args.initialBorrowerCoins, tc.args.initialKeeperCoins, tc.args.initialModuleCoins}, ) // Hard module genesis state @@ -580,10 +600,6 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() { app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pricefeedGS)}, app.GenesisState{types.ModuleName: types.ModuleCdc.MustMarshalJSON(hardGS)}) - // Mint coins to Hard module account - supplyKeeper := tApp.GetSupplyKeeper() - supplyKeeper.MintCoins(ctx, types.ModuleAccountName, tc.args.initialModuleCoins) - auctionKeeper := tApp.GetAuctionKeeper() keeper := tApp.GetHardKeeper() @@ -597,6 +613,10 @@ func (suite *KeeperTestSuite) TestKeeperLiquidation() { // Run begin blocker to set up state hard.BeginBlocker(suite.ctx, suite.keeper) + // Deposit initial module account coins + err = suite.keeper.Deposit(suite.ctx, depositor, tc.args.initialModuleCoins) + suite.Require().NoError(err) + // Deposit coins err = suite.keeper.Deposit(suite.ctx, tc.args.borrower, tc.args.depositCoins) suite.Require().NoError(err)