From 53eab47c075288f35e34f682e28acbb489929cc8 Mon Sep 17 00:00:00 2001 From: Denali Marsh Date: Tue, 16 Feb 2021 15:45:57 +0100 Subject: [PATCH] Hard Audit: don't let users borrow from reserves (#827) * don't borrow from reserves * use safesub and throw error --- x/hard/alias.go | 94 ++++++++++++++++++------------------ x/hard/keeper/borrow.go | 14 ++++++ x/hard/keeper/borrow_test.go | 2 +- x/hard/types/errors.go | 4 ++ 4 files changed, 67 insertions(+), 47 deletions(-) diff --git a/x/hard/alias.go b/x/hard/alias.go index bf530e60..aa9b7d1a 100644 --- a/x/hard/alias.go +++ b/x/hard/alias.go @@ -83,52 +83,54 @@ var ( RegisterCodec = types.RegisterCodec // variable aliases - BorrowInterestFactorPrefix = types.BorrowInterestFactorPrefix - BorrowedCoinsPrefix = types.BorrowedCoinsPrefix - BorrowsKeyPrefix = types.BorrowsKeyPrefix - DefaultAccumulationTimes = types.DefaultAccumulationTimes - DefaultBorrows = types.DefaultBorrows - DefaultDeposits = types.DefaultDeposits - DefaultMoneyMarkets = types.DefaultMoneyMarkets - DefaultTotalBorrowed = types.DefaultTotalBorrowed - DefaultTotalReserves = types.DefaultTotalReserves - DefaultTotalSupplied = types.DefaultTotalSupplied - DepositsKeyPrefix = types.DepositsKeyPrefix - ErrAccountNotFound = types.ErrAccountNotFound - ErrBorrowEmptyCoins = types.ErrBorrowEmptyCoins - ErrBorrowExceedsAvailableBalance = types.ErrBorrowExceedsAvailableBalance - ErrBorrowNotFound = types.ErrBorrowNotFound - ErrBorrowNotLiquidatable = types.ErrBorrowNotLiquidatable - ErrBorrowedCoinsNotFound = types.ErrBorrowedCoinsNotFound - ErrDepositNotFound = types.ErrDepositNotFound - ErrDepositsNotFound = types.ErrDepositsNotFound - ErrGreaterThanAssetBorrowLimit = types.ErrGreaterThanAssetBorrowLimit - ErrInsufficientBalanceForBorrow = types.ErrInsufficientBalanceForBorrow - ErrInsufficientBalanceForRepay = types.ErrInsufficientBalanceForRepay - ErrInsufficientCoins = types.ErrInsufficientCoins - ErrInsufficientLoanToValue = types.ErrInsufficientLoanToValue - ErrInsufficientModAccountBalance = types.ErrInsufficientModAccountBalance - ErrInvalidAccountType = types.ErrInvalidAccountType - ErrInvalidDepositDenom = types.ErrInvalidDepositDenom - ErrInvalidReceiver = types.ErrInvalidReceiver - ErrInvalidRepaymentDenom = types.ErrInvalidRepaymentDenom - ErrInvalidWithdrawAmount = types.ErrInvalidWithdrawAmount - ErrInvalidWithdrawDenom = types.ErrInvalidWithdrawDenom - ErrMarketNotFound = types.ErrMarketNotFound - ErrMoneyMarketNotFound = types.ErrMoneyMarketNotFound - ErrNegativeBorrowedCoins = types.ErrNegativeBorrowedCoins - ErrNegativeSuppliedCoins = types.ErrNegativeSuppliedCoins - ErrPreviousAccrualTimeNotFound = types.ErrPreviousAccrualTimeNotFound - ErrPriceNotFound = types.ErrPriceNotFound - ErrSuppliedCoinsNotFound = types.ErrSuppliedCoinsNotFound - GovDenom = types.GovDenom - KeyMoneyMarkets = types.KeyMoneyMarkets - ModuleCdc = types.ModuleCdc - MoneyMarketsPrefix = types.MoneyMarketsPrefix - PreviousAccrualTimePrefix = types.PreviousAccrualTimePrefix - SuppliedCoinsPrefix = types.SuppliedCoinsPrefix - SupplyInterestFactorPrefix = types.SupplyInterestFactorPrefix - TotalReservesPrefix = types.TotalReservesPrefix + BorrowInterestFactorPrefix = types.BorrowInterestFactorPrefix + BorrowedCoinsPrefix = types.BorrowedCoinsPrefix + BorrowsKeyPrefix = types.BorrowsKeyPrefix + DefaultAccumulationTimes = types.DefaultAccumulationTimes + DefaultBorrows = types.DefaultBorrows + DefaultDeposits = types.DefaultDeposits + DefaultMoneyMarkets = types.DefaultMoneyMarkets + DefaultTotalBorrowed = types.DefaultTotalBorrowed + DefaultTotalReserves = types.DefaultTotalReserves + DefaultTotalSupplied = types.DefaultTotalSupplied + DepositsKeyPrefix = types.DepositsKeyPrefix + ErrAccountNotFound = types.ErrAccountNotFound + ErrBorrowEmptyCoins = types.ErrBorrowEmptyCoins + ErrBorrowExceedsAvailableBalance = types.ErrBorrowExceedsAvailableBalance + ErrExceedsProtocolBorrowableBalance = types.ErrExceedsProtocolBorrowableBalance + ErrBorrowNotFound = types.ErrBorrowNotFound + ErrBorrowNotLiquidatable = types.ErrBorrowNotLiquidatable + ErrBorrowedCoinsNotFound = types.ErrBorrowedCoinsNotFound + ErrDepositNotFound = types.ErrDepositNotFound + ErrDepositsNotFound = types.ErrDepositsNotFound + ErrGreaterThanAssetBorrowLimit = types.ErrGreaterThanAssetBorrowLimit + ErrInsufficientBalanceForBorrow = types.ErrInsufficientBalanceForBorrow + ErrInsufficientBalanceForRepay = types.ErrInsufficientBalanceForRepay + ErrInsufficientCoins = types.ErrInsufficientCoins + ErrInsufficientLoanToValue = types.ErrInsufficientLoanToValue + ErrInsufficientModAccountBalance = types.ErrInsufficientModAccountBalance + ErrInvalidAccountType = types.ErrInvalidAccountType + ErrInvalidDepositDenom = types.ErrInvalidDepositDenom + ErrInvalidReceiver = types.ErrInvalidReceiver + ErrInvalidRepaymentDenom = types.ErrInvalidRepaymentDenom + ErrInvalidWithdrawAmount = types.ErrInvalidWithdrawAmount + ErrInvalidWithdrawDenom = types.ErrInvalidWithdrawDenom + ErrMarketNotFound = types.ErrMarketNotFound + ErrMoneyMarketNotFound = types.ErrMoneyMarketNotFound + ErrNegativeBorrowedCoins = types.ErrNegativeBorrowedCoins + ErrNegativeSuppliedCoins = types.ErrNegativeSuppliedCoins + ErrPreviousAccrualTimeNotFound = types.ErrPreviousAccrualTimeNotFound + ErrPriceNotFound = types.ErrPriceNotFound + ErrSuppliedCoinsNotFound = types.ErrSuppliedCoinsNotFound + ErrReservesExceedCash = types.ErrReservesExceedCash + GovDenom = types.GovDenom + KeyMoneyMarkets = types.KeyMoneyMarkets + ModuleCdc = types.ModuleCdc + MoneyMarketsPrefix = types.MoneyMarketsPrefix + PreviousAccrualTimePrefix = types.PreviousAccrualTimePrefix + SuppliedCoinsPrefix = types.SuppliedCoinsPrefix + SupplyInterestFactorPrefix = types.SupplyInterestFactorPrefix + TotalReservesPrefix = types.TotalReservesPrefix ) type ( diff --git a/x/hard/keeper/borrow.go b/x/hard/keeper/borrow.go index 40c42bc4..e600494b 100644 --- a/x/hard/keeper/borrow.go +++ b/x/hard/keeper/borrow.go @@ -116,6 +116,20 @@ func (k Keeper) ValidateBorrow(ctx sdk.Context, borrower sdk.AccAddress, amount return types.ErrBorrowEmptyCoins } + // The reserve coins aren't available for users to borrow + hardMaccCoins := k.supplyKeeper.GetModuleAccount(ctx, types.ModuleName).GetCoins() + reserveCoins, foundReserveCoins := k.GetTotalReserves(ctx) + if !foundReserveCoins { + reserveCoins = sdk.NewCoins() + } + fundsAvailableToBorrow, isNegative := hardMaccCoins.SafeSub(reserveCoins) + if isNegative { + return sdkerrors.Wrapf(types.ErrReservesExceedCash, "reserves %s > cash %s", reserveCoins, hardMaccCoins) + } + if amount.IsAnyGT(fundsAvailableToBorrow) { + return sdkerrors.Wrapf(types.ErrExceedsProtocolBorrowableBalance, "requested borrow %s > available to borrow %s", amount, fundsAvailableToBorrow) + } + // Get the proposed borrow USD value moneyMarketCache := map[string]types.MoneyMarket{} proprosedBorrowUSDValue := sdk.ZeroDec() diff --git a/x/hard/keeper/borrow_test.go b/x/hard/keeper/borrow_test.go index 4217c9f5..297c55f1 100644 --- a/x/hard/keeper/borrow_test.go +++ b/x/hard/keeper/borrow_test.go @@ -220,7 +220,7 @@ func (suite *KeeperTestSuite) TestBorrow() { }, errArgs{ expectPass: false, - contains: "exceeds module account balance:", + contains: "exceeds borrowable module account balance", }, }, { diff --git a/x/hard/types/errors.go b/x/hard/types/errors.go index 9de2cafb..b424726d 100644 --- a/x/hard/types/errors.go +++ b/x/hard/types/errors.go @@ -65,4 +65,8 @@ var ( ErrInvalidIndexFactorDenom = sdkerrors.Register(ModuleName, 29, "no index factor found for denom") // ErrBelowMinimumBorrowValue error for when a proposed borrow position is less than the minimum USD value ErrBelowMinimumBorrowValue = sdkerrors.Register(ModuleName, 30, "invalid proposed borrow value") + // ErrExceedsProtocolBorrowableBalance for when a requested borrow exceeds the module account's borrowable balance + ErrExceedsProtocolBorrowableBalance = sdkerrors.Register(ModuleName, 31, "exceeds borrowable module account balance") + // ErrReservesExceedCash for when the protocol is insolvent because available reserves exceeds available cash + ErrReservesExceedCash = sdkerrors.Register(ModuleName, 32, "insolvency - protocol reserves exceed available cash") )