From 33cbe34991c3b27e8eab2bfd9a706477d7afe94a Mon Sep 17 00:00:00 2001 From: Denali Marsh Date: Mon, 9 Nov 2020 22:52:08 +0100 Subject: [PATCH] Harvest: deposit multiple assets supplying multiple assets (#712) * introduce local cache * apply LTV for borrowable amount calculation * add multiple previous borrow tests * remove unused functions * address revisions --- x/harvest/keeper/borrow.go | 109 +++++++++++++++++++------------- x/harvest/keeper/borrow_test.go | 107 +++++++++++++++++++++++++++---- 2 files changed, 158 insertions(+), 58 deletions(-) diff --git a/x/harvest/keeper/borrow.go b/x/harvest/keeper/borrow.go index ba039859..58977471 100644 --- a/x/harvest/keeper/borrow.go +++ b/x/harvest/keeper/borrow.go @@ -9,8 +9,7 @@ import ( // Borrow funds func (k Keeper) Borrow(ctx sdk.Context, borrower sdk.AccAddress, coins sdk.Coins) error { - // TODO: Here we assume borrower only has one coin. To be addressed in future card. - err := k.ValidateBorrow(ctx, borrower, coins[0]) + err := k.ValidateBorrow(ctx, borrower, coins) if err != nil { return err } @@ -40,66 +39,88 @@ func (k Keeper) Borrow(ctx sdk.Context, borrower sdk.AccAddress, coins sdk.Coins } // ValidateBorrow validates a borrow request against borrower and protocol requirements -func (k Keeper) ValidateBorrow(ctx sdk.Context, borrower sdk.AccAddress, amount sdk.Coin) error { - proprosedBorrowUSDValue, err := k.calculateUSDValue(ctx, amount.Amount, amount.Denom) - if err != nil { - return err +func (k Keeper) ValidateBorrow(ctx sdk.Context, borrower sdk.AccAddress, amount sdk.Coins) error { + // Get the proposed borrow USD value + moneyMarketCache := map[string]types.MoneyMarket{} + proprosedBorrowUSDValue := sdk.ZeroDec() + for _, coin := range amount { + moneyMarket, ok := moneyMarketCache[coin.Denom] + // Fetch money market and store in local cache + if !ok { + newMoneyMarket, found := k.GetMoneyMarket(ctx, coin.Denom) + if !found { + return sdkerrors.Wrapf(types.ErrMarketNotFound, "no market found for denom %s", coin.Denom) + } + moneyMarketCache[coin.Denom] = newMoneyMarket + moneyMarket = newMoneyMarket + } + + // Calculate this coin's USD value and add it borrow's total USD value + assetPriceInfo, err := k.pricefeedKeeper.GetCurrentPrice(ctx, moneyMarket.SpotMarketID) + if err != nil { + return sdkerrors.Wrapf(types.ErrPriceNotFound, "no price found for market %s", moneyMarket.SpotMarketID) + } + coinUSDValue := sdk.NewDecFromInt(coin.Amount).Quo(sdk.NewDecFromInt(moneyMarket.ConversionFactor)).Mul(assetPriceInfo.Price) + proprosedBorrowUSDValue = proprosedBorrowUSDValue.Add(coinUSDValue) } - // Get the total value of the user's deposits + // Get the total borrowable USD amount at user's existing deposits deposits := k.GetDepositsByUser(ctx, borrower) if len(deposits) == 0 { return sdkerrors.Wrapf(types.ErrDepositsNotFound, "no deposits found for %s", borrower) } totalBorrowableAmount := sdk.ZeroDec() for _, deposit := range deposits { - borrowableAmountForDeposit, err := k.getBorrowableAmountForDeposit(ctx, deposit) - if err != nil { - return err + moneyMarket, ok := moneyMarketCache[deposit.Amount.Denom] + // Fetch money market and store in local cache + if !ok { + newMoneyMarket, found := k.GetMoneyMarket(ctx, deposit.Amount.Denom) + if !found { + return sdkerrors.Wrapf(types.ErrMarketNotFound, "no market found for denom %s", deposit.Amount.Denom) + } + moneyMarketCache[deposit.Amount.Denom] = newMoneyMarket + moneyMarket = newMoneyMarket } + + // Calculate the borrowable amount and add it to the user's total borrowable amount + assetPriceInfo, err := k.pricefeedKeeper.GetCurrentPrice(ctx, moneyMarket.SpotMarketID) + if err != nil { + sdkerrors.Wrapf(types.ErrPriceNotFound, "no price found for market %s", moneyMarket.SpotMarketID) + } + depositUSDValue := sdk.NewDecFromInt(deposit.Amount.Amount).Quo(sdk.NewDecFromInt(moneyMarket.ConversionFactor)).Mul(assetPriceInfo.Price) + borrowableAmountForDeposit := depositUSDValue.Mul(moneyMarket.BorrowLimit.LoanToValue) totalBorrowableAmount = totalBorrowableAmount.Add(borrowableAmountForDeposit) } - previousBorrowsUSDValue := sdk.ZeroDec() - previousBorrows, found := k.GetBorrow(ctx, borrower) + // Get the total USD value of user's existing borrows + existingBorrowUSDValue := sdk.ZeroDec() + existingBorrow, found := k.GetBorrow(ctx, borrower) if found { - // TODO: here we're assuming that the user only has 1 previous borrow. To be addressed in future cards. - previousBorrow := previousBorrows.Amount[0] - previousBorrowUSDValue, err := k.calculateUSDValue(ctx, previousBorrow.Amount, previousBorrow.Denom) - if err != nil { - return err + for _, borrowedCoin := range existingBorrow.Amount { + moneyMarket, ok := moneyMarketCache[borrowedCoin.Denom] + // Fetch money market and store in local cache + if !ok { + newMoneyMarket, found := k.GetMoneyMarket(ctx, borrowedCoin.Denom) + if !found { + return sdkerrors.Wrapf(types.ErrMarketNotFound, "no market found for denom %s", borrowedCoin.Denom) + } + moneyMarketCache[borrowedCoin.Denom] = newMoneyMarket + moneyMarket = newMoneyMarket + } + + // Calculate this borrow coin's USD value and add it to the total previous borrowed USD value + assetPriceInfo, err := k.pricefeedKeeper.GetCurrentPrice(ctx, moneyMarket.SpotMarketID) + if err != nil { + return sdkerrors.Wrapf(types.ErrPriceNotFound, "no price found for market %s", moneyMarket.SpotMarketID) + } + coinUSDValue := sdk.NewDecFromInt(borrowedCoin.Amount).Quo(sdk.NewDecFromInt(moneyMarket.ConversionFactor)).Mul(assetPriceInfo.Price) + existingBorrowUSDValue = existingBorrowUSDValue.Add(coinUSDValue) } - previousBorrowsUSDValue = previousBorrowsUSDValue.Add(previousBorrowUSDValue) } // Validate that the proposed borrow's USD value is within user's borrowable limit - if proprosedBorrowUSDValue.GT(totalBorrowableAmount.Sub(previousBorrowsUSDValue)) { + if proprosedBorrowUSDValue.GT(totalBorrowableAmount.Sub(existingBorrowUSDValue)) { return sdkerrors.Wrapf(types.ErrInsufficientLoanToValue, "requested borrow %s is greater than maximum valid borrow", amount) } return nil } - -func (k Keeper) calculateUSDValue(ctx sdk.Context, amount sdk.Int, denom string) (sdk.Dec, error) { - moneyMarket, found := k.GetMoneyMarket(ctx, denom) - if !found { - return sdk.ZeroDec(), sdkerrors.Wrapf(types.ErrMarketNotFound, "no market found for denom %s", denom) - } - assetPriceInfo, err := k.pricefeedKeeper.GetCurrentPrice(ctx, moneyMarket.SpotMarketID) - if err != nil { - return sdk.ZeroDec(), sdkerrors.Wrapf(types.ErrPriceNotFound, "no price found for market %s", moneyMarket.SpotMarketID) - } - return sdk.NewDecFromInt(amount).Quo(sdk.NewDecFromInt(moneyMarket.ConversionFactor)).Mul(assetPriceInfo.Price), nil -} - -func (k Keeper) getBorrowableAmountForDeposit(ctx sdk.Context, deposit types.Deposit) (sdk.Dec, error) { - moneyMarket, found := k.GetMoneyMarket(ctx, deposit.Amount.Denom) - if !found { - return sdk.ZeroDec(), sdkerrors.Wrapf(types.ErrMarketNotFound, "no market found for denom %s", deposit.Amount.Denom) - } - assetPriceInfo, err := k.pricefeedKeeper.GetCurrentPrice(ctx, moneyMarket.SpotMarketID) - if err != nil { - return sdk.ZeroDec(), sdkerrors.Wrapf(types.ErrPriceNotFound, "no price found for market %s", moneyMarket.SpotMarketID) - } - usdValue := sdk.NewDecFromInt(deposit.Amount.Amount).Quo(sdk.NewDecFromInt(moneyMarket.ConversionFactor)).Mul(assetPriceInfo.Price) - return usdValue.Mul(moneyMarket.BorrowLimit.LoanToValue), nil -} diff --git a/x/harvest/keeper/borrow_test.go b/x/harvest/keeper/borrow_test.go index 9511e9aa..3c9df2ed 100644 --- a/x/harvest/keeper/borrow_test.go +++ b/x/harvest/keeper/borrow_test.go @@ -18,6 +18,8 @@ const ( USDX_CF = 1000000 KAVA_CF = 1000000 BTCB_CF = 100000000 + BNB_CF = 100000000 + BUSD_CF = 100000000 ) func (suite *KeeperTestSuite) TestBorrow() { @@ -27,8 +29,11 @@ func (suite *KeeperTestSuite) TestBorrow() { loanToValueKAVA sdk.Dec priceBTCB sdk.Dec loanToValueBTCB sdk.Dec + priceBNB sdk.Dec + loanToValueBNB sdk.Dec borrower sdk.AccAddress depositCoins []sdk.Coin + previousBorrowCoins sdk.Coins borrowCoins sdk.Coins expectedAccountBalance sdk.Coins expectedModAccountBalance sdk.Coins @@ -50,11 +55,14 @@ func (suite *KeeperTestSuite) TestBorrow() { loanToValueKAVA: sdk.MustNewDecFromStr("0.6"), priceBTCB: sdk.MustNewDecFromStr("0.00"), loanToValueBTCB: sdk.MustNewDecFromStr("0.01"), + priceBNB: sdk.MustNewDecFromStr("0.00"), + loanToValueBNB: sdk.MustNewDecFromStr("0.01"), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), depositCoins: []sdk.Coin{sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF))}, + previousBorrowCoins: sdk.NewCoins(), borrowCoins: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(20*KAVA_CF))), - expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(20*KAVA_CF)), sdk.NewCoin("btcb", sdk.NewInt(100*BTCB_CF))), - expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1080*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(200*USDX_CF))), + expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(20*KAVA_CF)), sdk.NewCoin("btcb", sdk.NewInt(100*BTCB_CF)), sdk.NewCoin("bnb", sdk.NewInt(100*BNB_CF))), + expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1080*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(200*USDX_CF)), sdk.NewCoin("busd", sdk.NewInt(100*BUSD_CF))), }, errArgs{ expectPass: true, @@ -68,11 +76,13 @@ func (suite *KeeperTestSuite) TestBorrow() { loanToValueKAVA: sdk.MustNewDecFromStr("0.6"), priceBTCB: sdk.MustNewDecFromStr("0.00"), loanToValueBTCB: sdk.MustNewDecFromStr("0.01"), + priceBNB: sdk.MustNewDecFromStr("0.00"), + loanToValueBNB: sdk.MustNewDecFromStr("0.01"), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), depositCoins: []sdk.Coin{sdk.NewCoin("ukava", sdk.NewInt(20*KAVA_CF))}, // 20 KAVA x $5.00 price = $100 borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(61*USDX_CF))), // 61 USDX x $1 price = $61 - expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(80*KAVA_CF)), sdk.NewCoin("btcb", sdk.NewInt(100*BTCB_CF))), - expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1020*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(261*USDX_CF))), + expectedAccountBalance: sdk.NewCoins(), + expectedModAccountBalance: sdk.NewCoins(), }, errArgs{ expectPass: false, @@ -86,11 +96,13 @@ func (suite *KeeperTestSuite) TestBorrow() { loanToValueKAVA: sdk.MustNewDecFromStr("0.80"), priceBTCB: sdk.MustNewDecFromStr("10000.00"), loanToValueBTCB: sdk.MustNewDecFromStr("0.10"), + priceBNB: sdk.MustNewDecFromStr("0.00"), + loanToValueBNB: sdk.MustNewDecFromStr("0.01"), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), depositCoins: []sdk.Coin{sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdk.NewInt(0.1*BTCB_CF))}, borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(180*USDX_CF))), - expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdk.NewInt(99.9*BTCB_CF)), sdk.NewCoin("usdx", sdk.NewInt(180*USDX_CF))), - expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1050*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(20*USDX_CF)), sdk.NewCoin("btcb", sdk.NewInt(0.1*BTCB_CF))), + expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdk.NewInt(99.9*BTCB_CF)), sdk.NewCoin("usdx", sdk.NewInt(180*USDX_CF)), sdk.NewCoin("bnb", sdk.NewInt(100*BNB_CF))), + expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1050*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(20*USDX_CF)), sdk.NewCoin("btcb", sdk.NewInt(0.1*BTCB_CF)), sdk.NewCoin("busd", sdk.NewInt(100*BUSD_CF))), }, errArgs{ expectPass: true, @@ -104,17 +116,61 @@ func (suite *KeeperTestSuite) TestBorrow() { loanToValueKAVA: sdk.MustNewDecFromStr("0.80"), priceBTCB: sdk.MustNewDecFromStr("10000.00"), loanToValueBTCB: sdk.MustNewDecFromStr("0.10"), + priceBNB: sdk.MustNewDecFromStr("0.00"), + loanToValueBNB: sdk.MustNewDecFromStr("0.01"), borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), depositCoins: []sdk.Coin{sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdk.NewInt(0.1*BTCB_CF))}, borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(181*USDX_CF))), - expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdk.NewInt(99.9*BTCB_CF)), sdk.NewCoin("usdx", sdk.NewInt(180*USDX_CF))), - expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1050*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(20*USDX_CF)), sdk.NewCoin("btcb", sdk.NewInt(0.1*BTCB_CF))), + expectedAccountBalance: sdk.NewCoins(), + expectedModAccountBalance: sdk.NewCoins(), }, errArgs{ expectPass: false, contains: "total deposited value is insufficient for borrow request", }, }, + { + "valid: multiple previous borrows", + args{ + priceKAVA: sdk.MustNewDecFromStr("2.00"), + loanToValueKAVA: sdk.MustNewDecFromStr("0.8"), + priceBTCB: sdk.MustNewDecFromStr("0.00"), + loanToValueBTCB: sdk.MustNewDecFromStr("0.01"), + priceBNB: sdk.MustNewDecFromStr("5.00"), + loanToValueBNB: sdk.MustNewDecFromStr("0.8"), + borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), + depositCoins: []sdk.Coin{sdk.NewCoin("bnb", sdk.NewInt(30*BNB_CF)), sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF))}, // (50 KAVA x $2.00 price = $100) + (30 BNB x $5.00 price = $150) = $250 + previousBorrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(99*USDX_CF)), sdk.NewCoin("busd", sdk.NewInt(100*BUSD_CF))), + borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(1*USDX_CF))), + expectedAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF)), sdk.NewCoin("btcb", sdk.NewInt(100*BTCB_CF)), sdk.NewCoin("usdx", sdk.NewInt(100*USDX_CF)), sdk.NewCoin("busd", sdk.NewInt(100*BUSD_CF)), sdk.NewCoin("bnb", sdk.NewInt(70*BNB_CF))), + expectedModAccountBalance: sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1050*KAVA_CF)), sdk.NewCoin("bnb", sdk.NewInt(30*BUSD_CF)), sdk.NewCoin("usdx", sdk.NewInt(100*USDX_CF))), + }, + errArgs{ + expectPass: true, + contains: "", + }, + }, + { + "invalid: over loan-to-value with multiple previous borrows", + args{ + priceKAVA: sdk.MustNewDecFromStr("2.00"), + loanToValueKAVA: sdk.MustNewDecFromStr("0.8"), + priceBTCB: sdk.MustNewDecFromStr("0.00"), + loanToValueBTCB: sdk.MustNewDecFromStr("0.01"), + priceBNB: sdk.MustNewDecFromStr("5.00"), + loanToValueBNB: sdk.MustNewDecFromStr("0.8"), + borrower: sdk.AccAddress(crypto.AddressHash([]byte("test"))), + depositCoins: []sdk.Coin{sdk.NewCoin("bnb", sdk.NewInt(30*BNB_CF)), sdk.NewCoin("ukava", sdk.NewInt(50*KAVA_CF))}, // (50 KAVA x $2.00 price = $100) + (30 BNB x $5.00 price = $150) = $250 + previousBorrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(100*USDX_CF)), sdk.NewCoin("busd", sdk.NewInt(100*BUSD_CF))), + borrowCoins: sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(1*USDX_CF))), + expectedAccountBalance: sdk.NewCoins(), + expectedModAccountBalance: sdk.NewCoins(), + }, + errArgs{ + expectPass: false, + contains: "requested borrow 1000000usdx is greater than maximum valid borrow", + }, + }, } for _, tc := range testCases { suite.Run(tc.name, func() { @@ -125,7 +181,8 @@ func (suite *KeeperTestSuite) TestBorrow() { // Auth module genesis state authGS := app.NewAuthGenState( []sdk.AccAddress{tc.args.borrower}, - []sdk.Coins{sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF)), sdk.NewCoin("btcb", sdk.NewInt(100*BTCB_CF)))}) + []sdk.Coins{sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(100*KAVA_CF)), + sdk.NewCoin("btcb", sdk.NewInt(100*BTCB_CF)), sdk.NewCoin("bnb", sdk.NewInt(100*BNB_CF)))}) // Harvest module genesis state harvestGS := types.NewGenesisState(types.NewParams( @@ -134,6 +191,8 @@ func (suite *KeeperTestSuite) TestBorrow() { types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}), types.NewDistributionSchedule(true, "ukava", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}), types.NewDistributionSchedule(true, "btcb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}), + types.NewDistributionSchedule(true, "busd", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}), + types.NewDistributionSchedule(true, "bnb", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2020, 11, 22, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(5000)), time.Date(2021, 11, 22, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}), }, types.DelegatorDistributionSchedules{types.NewDelegatorDistributionSchedule( types.NewDistributionSchedule(true, "usdx", time.Date(2020, 10, 8, 14, 0, 0, 0, time.UTC), time.Date(2025, 10, 8, 14, 0, 0, 0, time.UTC), sdk.NewCoin("hard", sdk.NewInt(500)), time.Date(2026, 10, 8, 14, 0, 0, 0, time.UTC), types.Multipliers{types.NewMultiplier(types.Small, 0, sdk.MustNewDecFromStr("0.33")), types.NewMultiplier(types.Medium, 6, sdk.MustNewDecFromStr("0.5")), types.NewMultiplier(types.Medium, 24, sdk.OneDec())}), @@ -141,9 +200,11 @@ func (suite *KeeperTestSuite) TestBorrow() { ), }, types.MoneyMarkets{ - types.NewMoneyMarket("usdx", sdk.NewInt(100000000*USDX_CF), sdk.MustNewDecFromStr("0.01"), "usdx:usd", sdk.NewInt(USDX_CF)), + types.NewMoneyMarket("usdx", sdk.NewInt(100000000*USDX_CF), sdk.MustNewDecFromStr("1"), "usdx:usd", sdk.NewInt(USDX_CF)), + types.NewMoneyMarket("busd", sdk.NewInt(100000000*BUSD_CF), sdk.MustNewDecFromStr("1"), "busd:usd", sdk.NewInt(BUSD_CF)), types.NewMoneyMarket("ukava", sdk.NewInt(100000000*KAVA_CF), tc.args.loanToValueKAVA, "kava:usd", sdk.NewInt(KAVA_CF)), types.NewMoneyMarket("btcb", sdk.NewInt(100000000*BTCB_CF), tc.args.loanToValueBTCB, "btcb:usd", sdk.NewInt(BTCB_CF)), + types.NewMoneyMarket("bnb", sdk.NewInt(100000000*BNB_CF), tc.args.loanToValueBNB, "bnb:usd", sdk.NewInt(BNB_CF)), }, ), types.DefaultPreviousBlockTime, types.DefaultDistributionTimes) @@ -151,9 +212,11 @@ func (suite *KeeperTestSuite) TestBorrow() { pricefeedGS := pricefeed.GenesisState{ Params: pricefeed.Params{ Markets: []pricefeed.Market{ - {MarketID: "usdx:usd", BaseAsset: "bnb", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, + {MarketID: "usdx:usd", BaseAsset: "usdx", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, + {MarketID: "busd:usd", BaseAsset: "busd", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, {MarketID: "kava:usd", BaseAsset: "kava", QuoteAsset: "usd", Oracles: []sdk.AccAddress{}, Active: true}, {MarketID: "btcb: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{ @@ -163,6 +226,12 @@ func (suite *KeeperTestSuite) TestBorrow() { Price: sdk.MustNewDecFromStr("1.00"), Expiry: time.Now().Add(1 * time.Hour), }, + { + MarketID: "busd:usd", + OracleAddress: sdk.AccAddress{}, + Price: sdk.MustNewDecFromStr("1.00"), + Expiry: time.Now().Add(1 * time.Hour), + }, { MarketID: "kava:usd", OracleAddress: sdk.AccAddress{}, @@ -175,6 +244,12 @@ func (suite *KeeperTestSuite) TestBorrow() { Price: tc.args.priceBTCB, Expiry: time.Now().Add(1 * time.Hour), }, + { + MarketID: "bnb:usd", + OracleAddress: sdk.AccAddress{}, + Price: tc.args.priceBNB, + Expiry: time.Now().Add(1 * time.Hour), + }, }, } @@ -185,7 +260,8 @@ func (suite *KeeperTestSuite) TestBorrow() { // Mint coins to Harvest module account supplyKeeper := tApp.GetSupplyKeeper() - harvestMaccCoins := sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000*KAVA_CF)), sdk.NewCoin("usdx", sdk.NewInt(200*USDX_CF))) + harvestMaccCoins := sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(1000*KAVA_CF)), + sdk.NewCoin("usdx", sdk.NewInt(200*USDX_CF)), sdk.NewCoin("busd", sdk.NewInt(100*BUSD_CF))) supplyKeeper.MintCoins(ctx, types.ModuleAccountName, harvestMaccCoins) keeper := tApp.GetHarvestKeeper() @@ -203,10 +279,13 @@ func (suite *KeeperTestSuite) TestBorrow() { depositedCoins.Add(depositCoin) } - // run the test + // Execute user's previous borrows + err = suite.keeper.Borrow(suite.ctx, tc.args.borrower, tc.args.previousBorrowCoins) + suite.Require().NoError(err) + + // Now that our state is properly set up, execute the last borrow err = suite.keeper.Borrow(suite.ctx, tc.args.borrower, tc.args.borrowCoins) - // verify results if tc.errArgs.expectPass { suite.Require().NoError(err)