Hard Audit: don't let users borrow from reserves (#827)

* don't borrow from reserves

* use safesub and throw error
This commit is contained in:
Denali Marsh 2021-02-16 15:45:57 +01:00 committed by GitHub
parent 58573e7b26
commit 53eab47c07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 47 deletions

View File

@ -83,52 +83,54 @@ var (
RegisterCodec = types.RegisterCodec RegisterCodec = types.RegisterCodec
// variable aliases // variable aliases
BorrowInterestFactorPrefix = types.BorrowInterestFactorPrefix BorrowInterestFactorPrefix = types.BorrowInterestFactorPrefix
BorrowedCoinsPrefix = types.BorrowedCoinsPrefix BorrowedCoinsPrefix = types.BorrowedCoinsPrefix
BorrowsKeyPrefix = types.BorrowsKeyPrefix BorrowsKeyPrefix = types.BorrowsKeyPrefix
DefaultAccumulationTimes = types.DefaultAccumulationTimes DefaultAccumulationTimes = types.DefaultAccumulationTimes
DefaultBorrows = types.DefaultBorrows DefaultBorrows = types.DefaultBorrows
DefaultDeposits = types.DefaultDeposits DefaultDeposits = types.DefaultDeposits
DefaultMoneyMarkets = types.DefaultMoneyMarkets DefaultMoneyMarkets = types.DefaultMoneyMarkets
DefaultTotalBorrowed = types.DefaultTotalBorrowed DefaultTotalBorrowed = types.DefaultTotalBorrowed
DefaultTotalReserves = types.DefaultTotalReserves DefaultTotalReserves = types.DefaultTotalReserves
DefaultTotalSupplied = types.DefaultTotalSupplied DefaultTotalSupplied = types.DefaultTotalSupplied
DepositsKeyPrefix = types.DepositsKeyPrefix DepositsKeyPrefix = types.DepositsKeyPrefix
ErrAccountNotFound = types.ErrAccountNotFound ErrAccountNotFound = types.ErrAccountNotFound
ErrBorrowEmptyCoins = types.ErrBorrowEmptyCoins ErrBorrowEmptyCoins = types.ErrBorrowEmptyCoins
ErrBorrowExceedsAvailableBalance = types.ErrBorrowExceedsAvailableBalance ErrBorrowExceedsAvailableBalance = types.ErrBorrowExceedsAvailableBalance
ErrBorrowNotFound = types.ErrBorrowNotFound ErrExceedsProtocolBorrowableBalance = types.ErrExceedsProtocolBorrowableBalance
ErrBorrowNotLiquidatable = types.ErrBorrowNotLiquidatable ErrBorrowNotFound = types.ErrBorrowNotFound
ErrBorrowedCoinsNotFound = types.ErrBorrowedCoinsNotFound ErrBorrowNotLiquidatable = types.ErrBorrowNotLiquidatable
ErrDepositNotFound = types.ErrDepositNotFound ErrBorrowedCoinsNotFound = types.ErrBorrowedCoinsNotFound
ErrDepositsNotFound = types.ErrDepositsNotFound ErrDepositNotFound = types.ErrDepositNotFound
ErrGreaterThanAssetBorrowLimit = types.ErrGreaterThanAssetBorrowLimit ErrDepositsNotFound = types.ErrDepositsNotFound
ErrInsufficientBalanceForBorrow = types.ErrInsufficientBalanceForBorrow ErrGreaterThanAssetBorrowLimit = types.ErrGreaterThanAssetBorrowLimit
ErrInsufficientBalanceForRepay = types.ErrInsufficientBalanceForRepay ErrInsufficientBalanceForBorrow = types.ErrInsufficientBalanceForBorrow
ErrInsufficientCoins = types.ErrInsufficientCoins ErrInsufficientBalanceForRepay = types.ErrInsufficientBalanceForRepay
ErrInsufficientLoanToValue = types.ErrInsufficientLoanToValue ErrInsufficientCoins = types.ErrInsufficientCoins
ErrInsufficientModAccountBalance = types.ErrInsufficientModAccountBalance ErrInsufficientLoanToValue = types.ErrInsufficientLoanToValue
ErrInvalidAccountType = types.ErrInvalidAccountType ErrInsufficientModAccountBalance = types.ErrInsufficientModAccountBalance
ErrInvalidDepositDenom = types.ErrInvalidDepositDenom ErrInvalidAccountType = types.ErrInvalidAccountType
ErrInvalidReceiver = types.ErrInvalidReceiver ErrInvalidDepositDenom = types.ErrInvalidDepositDenom
ErrInvalidRepaymentDenom = types.ErrInvalidRepaymentDenom ErrInvalidReceiver = types.ErrInvalidReceiver
ErrInvalidWithdrawAmount = types.ErrInvalidWithdrawAmount ErrInvalidRepaymentDenom = types.ErrInvalidRepaymentDenom
ErrInvalidWithdrawDenom = types.ErrInvalidWithdrawDenom ErrInvalidWithdrawAmount = types.ErrInvalidWithdrawAmount
ErrMarketNotFound = types.ErrMarketNotFound ErrInvalidWithdrawDenom = types.ErrInvalidWithdrawDenom
ErrMoneyMarketNotFound = types.ErrMoneyMarketNotFound ErrMarketNotFound = types.ErrMarketNotFound
ErrNegativeBorrowedCoins = types.ErrNegativeBorrowedCoins ErrMoneyMarketNotFound = types.ErrMoneyMarketNotFound
ErrNegativeSuppliedCoins = types.ErrNegativeSuppliedCoins ErrNegativeBorrowedCoins = types.ErrNegativeBorrowedCoins
ErrPreviousAccrualTimeNotFound = types.ErrPreviousAccrualTimeNotFound ErrNegativeSuppliedCoins = types.ErrNegativeSuppliedCoins
ErrPriceNotFound = types.ErrPriceNotFound ErrPreviousAccrualTimeNotFound = types.ErrPreviousAccrualTimeNotFound
ErrSuppliedCoinsNotFound = types.ErrSuppliedCoinsNotFound ErrPriceNotFound = types.ErrPriceNotFound
GovDenom = types.GovDenom ErrSuppliedCoinsNotFound = types.ErrSuppliedCoinsNotFound
KeyMoneyMarkets = types.KeyMoneyMarkets ErrReservesExceedCash = types.ErrReservesExceedCash
ModuleCdc = types.ModuleCdc GovDenom = types.GovDenom
MoneyMarketsPrefix = types.MoneyMarketsPrefix KeyMoneyMarkets = types.KeyMoneyMarkets
PreviousAccrualTimePrefix = types.PreviousAccrualTimePrefix ModuleCdc = types.ModuleCdc
SuppliedCoinsPrefix = types.SuppliedCoinsPrefix MoneyMarketsPrefix = types.MoneyMarketsPrefix
SupplyInterestFactorPrefix = types.SupplyInterestFactorPrefix PreviousAccrualTimePrefix = types.PreviousAccrualTimePrefix
TotalReservesPrefix = types.TotalReservesPrefix SuppliedCoinsPrefix = types.SuppliedCoinsPrefix
SupplyInterestFactorPrefix = types.SupplyInterestFactorPrefix
TotalReservesPrefix = types.TotalReservesPrefix
) )
type ( type (

View File

@ -116,6 +116,20 @@ func (k Keeper) ValidateBorrow(ctx sdk.Context, borrower sdk.AccAddress, amount
return types.ErrBorrowEmptyCoins 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 // Get the proposed borrow USD value
moneyMarketCache := map[string]types.MoneyMarket{} moneyMarketCache := map[string]types.MoneyMarket{}
proprosedBorrowUSDValue := sdk.ZeroDec() proprosedBorrowUSDValue := sdk.ZeroDec()

View File

@ -220,7 +220,7 @@ func (suite *KeeperTestSuite) TestBorrow() {
}, },
errArgs{ errArgs{
expectPass: false, expectPass: false,
contains: "exceeds module account balance:", contains: "exceeds borrowable module account balance",
}, },
}, },
{ {

View File

@ -65,4 +65,8 @@ var (
ErrInvalidIndexFactorDenom = sdkerrors.Register(ModuleName, 29, "no index factor found for denom") 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 error for when a proposed borrow position is less than the minimum USD value
ErrBelowMinimumBorrowValue = sdkerrors.Register(ModuleName, 30, "invalid proposed borrow 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")
) )