diff --git a/contracts/protocol/lendingpool/LendingPool.sol b/contracts/protocol/lendingpool/LendingPool.sol
index 0c4ea068..06bfeb8e 100644
--- a/contracts/protocol/lendingpool/LendingPool.sol
+++ b/contracts/protocol/lendingpool/LendingPool.sol
@@ -288,28 +288,44 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
     reserve.updateState(cachedData);
 
     if (interestRateMode == DataTypes.InterestRateMode.STABLE) {
-      IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt);
-      IVariableDebtToken(reserve.variableDebtTokenAddress).mint(
+      IStableDebtToken(cachedData.stableDebtTokenAddress).burn(msg.sender, stableDebt);
+
+      cachedData.newPrincipalStableDebt = cachedData.newTotalStableDebt = cachedData
+        .oldTotalStableDebt
+        .sub(stableDebt);
+
+      IVariableDebtToken(cachedData.variableDebtTokenAddress).mint(
         msg.sender,
         msg.sender,
         stableDebt,
-        reserve.variableBorrowIndex
+        cachedData.newVariableBorrowIndex
+      );
+      cachedData.newScaledVariableDebt = cachedData.oldScaledVariableDebt.add(
+        stableDebt.rayDiv(cachedData.newVariableBorrowIndex)
       );
     } else {
-      IVariableDebtToken(reserve.variableDebtTokenAddress).burn(
+      IVariableDebtToken(cachedData.variableDebtTokenAddress).burn(
         msg.sender,
         variableDebt,
-        reserve.variableBorrowIndex
+        cachedData.newVariableBorrowIndex
       );
-      IStableDebtToken(reserve.stableDebtTokenAddress).mint(
+      cachedData.newScaledVariableDebt = cachedData.oldScaledVariableDebt.sub(
+        variableDebt.rayDiv(cachedData.newVariableBorrowIndex)
+      );
+
+      IStableDebtToken(cachedData.stableDebtTokenAddress).mint(
         msg.sender,
         msg.sender,
         variableDebt,
         reserve.currentStableBorrowRate
       );
+
+      cachedData.newPrincipalStableDebt = cachedData.newTotalStableDebt = cachedData
+        .oldTotalStableDebt
+        .add(stableDebt);
     }
 
-    reserve.updateInterestRates(asset, reserve.aTokenAddress, 0, 0);
+    reserve.updateInterestRates(cachedData, asset, 0, 0);
 
     emit Swap(asset, msg.sender, rateMode);
   }
@@ -327,10 +343,8 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
     DataTypes.ReserveData storage reserve = _reserves[asset];
     CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
 
-    IERC20 stableDebtToken = IERC20(reserve.stableDebtTokenAddress);
-    IERC20 variableDebtToken = IERC20(reserve.variableDebtTokenAddress);
-    address aTokenAddress = reserve.aTokenAddress;
-
+    IERC20 stableDebtToken = IERC20(cachedData.stableDebtTokenAddress);
+    IERC20 variableDebtToken = IERC20(cachedData.variableDebtTokenAddress);
     uint256 stableDebt = IERC20(stableDebtToken).balanceOf(user);
 
     ValidationLogic.validateRebalanceStableBorrowRate(
@@ -338,7 +352,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
       asset,
       stableDebtToken,
       variableDebtToken,
-      aTokenAddress
+      cachedData.aTokenAddress
     );
 
     reserve.updateState(cachedData);
@@ -351,7 +365,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
       reserve.currentStableBorrowRate
     );
 
-    reserve.updateInterestRates(asset, aTokenAddress, 0, 0);
+    reserve.updateInterestRates(cachedData, asset, 0, 0);
 
     emit RebalanceStableBorrowRate(asset, user);
   }
@@ -475,7 +489,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
 
     ValidationLogic.validateFlashloan(assets, amounts, _reserves);
 
-
     vars.receiver = IFlashLoanReceiver(receiverAddress);
 
     for (vars.i = 0; vars.i < assets.length; vars.i++) {
@@ -508,8 +521,8 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
           vars.currentPremium
         );
         reserve.updateInterestRates(
+          cachedData,
           vars.currentAsset,
-          vars.currentATokenAddress,
           vars.currentAmountPlusPremium,
           0
         );
@@ -553,11 +566,11 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
   function mintToTreasury(address[] calldata reserves) public {
     for (uint256 i = 0; i < reserves.length; i++) {
       address reserveAddress = reserves[i];
-      
+
       DataTypes.ReserveData storage reserve = _reserves[reserveAddress];
 
       // this cover both inactive reserves and invalid reserves since the flag will be 0 for both
-      if(!reserve.configuration.getActive()){
+      if (!reserve.configuration.getActive()) {
         continue;
       }
 
@@ -874,48 +887,49 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
     DataTypes.UserConfigurationMap storage userConfig = _usersConfig[vars.onBehalfOf];
     CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
 
-    address oracle = _addressesProvider.getPriceOracle();
-
-    uint256 amountInETH =
-      IPriceOracleGetter(oracle).getAssetPrice(vars.asset).mul(vars.amount).div(
-        10**reserve.configuration.getDecimals()
-      );
+    reserve.updateState(cachedData);
 
     ValidationLogic.validateBorrow(
+      cachedData,
       vars.asset,
-      reserve,
       vars.onBehalfOf,
       vars.amount,
-      amountInETH,
       vars.interestRateMode,
       _maxStableRateBorrowSizePercent,
       _reserves,
       userConfig,
       _reservesList,
       _reservesCount,
-      oracle
+      _addressesProvider.getPriceOracle()
     );
 
-    reserve.updateState(cachedData);
-
     uint256 currentStableRate = 0;
 
     bool isFirstBorrowing = false;
     if (DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE) {
       currentStableRate = reserve.currentStableBorrowRate;
 
-      isFirstBorrowing = IStableDebtToken(reserve.stableDebtTokenAddress).mint(
+      isFirstBorrowing = IStableDebtToken(cachedData.stableDebtTokenAddress).mint(
         vars.user,
         vars.onBehalfOf,
         vars.amount,
         currentStableRate
       );
+
+      cachedData.newPrincipalStableDebt = cachedData.newTotalStableDebt = cachedData
+        .oldTotalStableDebt
+        .add(vars.amount);
+      
     } else {
-      isFirstBorrowing = IVariableDebtToken(reserve.variableDebtTokenAddress).mint(
+      isFirstBorrowing = IVariableDebtToken(cachedData.variableDebtTokenAddress).mint(
         vars.user,
         vars.onBehalfOf,
         vars.amount,
-        reserve.variableBorrowIndex
+        cachedData.newVariableBorrowIndex
+      );
+
+      cachedData.newScaledVariableDebt = cachedData.newScaledVariableDebt.add(
+        vars.amount.rayDiv(cachedData.newVariableBorrowIndex)
       );
     }
 
@@ -924,14 +938,14 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
     }
 
     reserve.updateInterestRates(
+      cachedData,
       vars.asset,
-      vars.aTokenAddress,
       0,
       vars.releaseUnderlying ? vars.amount : 0
     );
 
     if (vars.releaseUnderlying) {
-      IAToken(vars.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount);
+      IAToken(cachedData.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount);
     }
 
     emit Borrow(
@@ -956,14 +970,16 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
     DataTypes.ReserveData storage reserve = _reserves[asset];
     CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
 
-    ValidationLogic.validateDeposit(reserve, amount);
-
     reserve.updateState(cachedData);
-    reserve.updateInterestRates(asset, cachedData.aTokenAddress, amount, 0);
+
+    ValidationLogic.validateDeposit(reserve, cachedData, amount);
+
+    reserve.updateInterestRates(cachedData, asset, amount, 0);
 
     IERC20(asset).safeTransferFrom(msg.sender, cachedData.aTokenAddress, amount);
 
-    bool isFirstDeposit = IAToken(cachedData.aTokenAddress).mint(onBehalfOf, amount, cachedData.newLiquidityIndex);
+    bool isFirstDeposit =
+      IAToken(cachedData.aTokenAddress).mint(onBehalfOf, amount, cachedData.newLiquidityIndex);
 
     if (isFirstDeposit) {
       _usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true);
@@ -982,11 +998,12 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
     DataTypes.UserConfigurationMap storage userConfig = _usersConfig[msg.sender];
     CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
 
-    address aToken = reserve.aTokenAddress;
-
     reserve.updateState(cachedData);
 
-    uint256 userBalance = IAToken(aToken).scaledBalanceOf(msg.sender).rayMul(cachedData.newLiquidityIndex);
+    uint256 userBalance =
+      IAToken(cachedData.aTokenAddress).scaledBalanceOf(msg.sender).rayMul(
+        cachedData.newLiquidityIndex
+      );
 
     uint256 amountToWithdraw = amount;
 
@@ -996,9 +1013,14 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
 
     ValidationLogic.validateWithdraw(reserve, amountToWithdraw, userBalance);
 
-    reserve.updateInterestRates(asset, aToken, 0, amountToWithdraw);
+    reserve.updateInterestRates(cachedData, asset, 0, amountToWithdraw);
 
-    IAToken(aToken).burn(msg.sender, to, amountToWithdraw, cachedData.newLiquidityIndex);
+    IAToken(cachedData.aTokenAddress).burn(
+      msg.sender,
+      to,
+      amountToWithdraw,
+      cachedData.newLiquidityIndex
+    );
 
     if (userConfig.isUsingAsCollateral(reserve.id)) {
       if (userConfig.isBorrowingAny()) {
@@ -1055,25 +1077,30 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
     reserve.updateState(cachedData);
 
     if (interestRateMode == DataTypes.InterestRateMode.STABLE) {
-      IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount);
+      IStableDebtToken(cachedData.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount);
+      cachedData.newPrincipalStableDebt = cachedData.newTotalStableDebt = cachedData
+        .oldTotalStableDebt
+        .sub(paybackAmount);
     } else {
-      IVariableDebtToken(reserve.variableDebtTokenAddress).burn(
+      IVariableDebtToken(cachedData.variableDebtTokenAddress).burn(
         onBehalfOf,
         paybackAmount,
-        reserve.variableBorrowIndex
+        cachedData.newVariableBorrowIndex
+      );
+      cachedData.newScaledVariableDebt = cachedData.oldScaledVariableDebt.sub(
+        paybackAmount.rayDiv(cachedData.newVariableBorrowIndex)
       );
     }
 
-    address aToken = reserve.aTokenAddress;
-    reserve.updateInterestRates(asset, aToken, paybackAmount, 0);
+    reserve.updateInterestRates(cachedData, asset, paybackAmount, 0);
 
     if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) {
       _usersConfig[onBehalfOf].setBorrowing(reserve.id, false);
     }
 
-    IERC20(asset).safeTransferFrom(msg.sender, aToken, paybackAmount);
+    IERC20(asset).safeTransferFrom(msg.sender, cachedData.aTokenAddress, paybackAmount);
 
-    IAToken(aToken).handleRepayment(msg.sender, paybackAmount);
+    IAToken(cachedData.aTokenAddress).handleRepayment(msg.sender, paybackAmount);
 
     emit Repay(asset, onBehalfOf, msg.sender, paybackAmount);
 
diff --git a/contracts/protocol/lendingpool/LendingPoolCollateralManager.sol b/contracts/protocol/lendingpool/LendingPoolCollateralManager.sol
index 5e6722b2..2f823d50 100644
--- a/contracts/protocol/lendingpool/LendingPoolCollateralManager.sol
+++ b/contracts/protocol/lendingpool/LendingPoolCollateralManager.sol
@@ -169,26 +169,37 @@ contract LendingPoolCollateralManager is
       IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
         user,
         vars.actualDebtToLiquidate,
-        debtReserve.variableBorrowIndex
+        debtReserveCachedData.newVariableBorrowIndex
+      );
+      debtReserveCachedData.newScaledVariableDebt = debtReserveCachedData.oldScaledVariableDebt.sub(
+        vars.actualDebtToLiquidate.rayDiv(debtReserveCachedData.newVariableBorrowIndex)
       );
     } else {
       // If the user doesn't have variable debt, no need to try to burn variable debt tokens
       if (vars.userVariableDebt > 0) {
-        IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
+        IVariableDebtToken(debtReserveCachedData.variableDebtTokenAddress).burn(
           user,
           vars.userVariableDebt,
-          debtReserve.variableBorrowIndex
+          debtReserveCachedData.newVariableBorrowIndex
         );
+        debtReserveCachedData.newScaledVariableDebt = debtReserveCachedData
+          .oldScaledVariableDebt
+          .sub(vars.userVariableDebt.rayDiv(debtReserveCachedData.newVariableBorrowIndex));
       }
-      IStableDebtToken(debtReserve.stableDebtTokenAddress).burn(
+      IStableDebtToken(debtReserveCachedData.stableDebtTokenAddress).burn(
         user,
         vars.actualDebtToLiquidate.sub(vars.userVariableDebt)
       );
+
+      debtReserveCachedData.newPrincipalStableDebt = debtReserveCachedData
+        .newTotalStableDebt = debtReserveCachedData.oldTotalStableDebt.sub(
+        vars.actualDebtToLiquidate.sub(vars.userVariableDebt)
+      );
     }
 
     debtReserve.updateInterestRates(
+      debtReserveCachedData,
       debtAsset,
-      debtReserve.aTokenAddress,
       vars.actualDebtToLiquidate,
       0
     );
@@ -203,12 +214,13 @@ contract LendingPoolCollateralManager is
         emit ReserveUsedAsCollateralEnabled(collateralAsset, msg.sender);
       }
     } else {
-      CachingHelper.CachedData memory collateralReserveCachedData = CachingHelper.fetchData(collateralReserve);
+      CachingHelper.CachedData memory collateralReserveCachedData =
+        CachingHelper.fetchData(collateralReserve);
 
       collateralReserve.updateState(collateralReserveCachedData);
       collateralReserve.updateInterestRates(
+        collateralReserveCachedData,
         collateralAsset,
-        address(vars.collateralAtoken),
         0,
         vars.maxCollateralToLiquidate
       );
diff --git a/contracts/protocol/libraries/configuration/ReserveConfiguration.sol b/contracts/protocol/libraries/configuration/ReserveConfiguration.sol
index 91d8bc50..389f5091 100644
--- a/contracts/protocol/libraries/configuration/ReserveConfiguration.sol
+++ b/contracts/protocol/libraries/configuration/ReserveConfiguration.sol
@@ -65,6 +65,16 @@ library ReserveConfiguration {
     return self.data & ~LTV_MASK;
   }
 
+    /**
+   * @dev Gets the Loan to Value of the reserve
+   * @param self The reserve configuration
+   * @return The loan to value
+   **/
+  function getLtvMemory(DataTypes.ReserveConfigurationMap memory self) internal view returns (uint256) {
+    return self.data & ~LTV_MASK;
+  }
+
+
   /**
    * @dev Sets the liquidation threshold of the reserve
    * @param self The reserve configuration
@@ -150,6 +160,20 @@ library ReserveConfiguration {
     return (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION;
   }
 
+
+  /**
+   * @dev Gets the decimals of the underlying asset of the reserve
+   * @param self The reserve configuration
+   * @return The decimals of the asset
+   **/
+  function getDecimalsMemory(DataTypes.ReserveConfigurationMap memory self)
+    internal
+    view
+    returns (uint256)
+  {
+    return (self.data & ~DECIMALS_MASK) >> RESERVE_DECIMALS_START_BIT_POSITION;
+  }
+
   /**
    * @dev Sets the active state of the reserve
    * @param self The reserve configuration
@@ -293,6 +317,19 @@ library ReserveConfiguration {
     return (self.data & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION;
   }
 
+  /**
+   * @dev Gets the reserve factor of the reserve
+   * @param self The reserve configuration
+   * @return The reserve factor
+   **/
+  function getReserveFactorMemory(DataTypes.ReserveConfigurationMap memory self)
+    internal
+    view
+    returns (uint256)
+  {
+    return (self.data & ~RESERVE_FACTOR_MASK) >> RESERVE_FACTOR_START_BIT_POSITION;
+  }
+
   /**
    * @dev Sets the borrow cap of the reserve
    * @param self The reserve configuration
diff --git a/contracts/protocol/libraries/helpers/CachingHelper.sol b/contracts/protocol/libraries/helpers/CachingHelper.sol
index bbfd959c..8bb739ef 100644
--- a/contracts/protocol/libraries/helpers/CachingHelper.sol
+++ b/contracts/protocol/libraries/helpers/CachingHelper.sol
@@ -4,13 +4,14 @@ pragma experimental ABIEncoderV2;
 
 import {DataTypes} from '../types/DataTypes.sol';
 import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol';
+import {IStableDebtToken} from '../../../interfaces/IStableDebtToken.sol';
 
 library CachingHelper {
   struct CachedData {
     uint256 oldScaledVariableDebt;
     uint256 oldTotalVariableDebt;
-    uint256 newSscaledVariableDebt;
-    uint256 newTtotalVariableDebt;
+    uint256 newScaledVariableDebt;
+    uint256 newTotalVariableDebt;
     uint256 oldPrincipalStableDebt;
     uint256 oldAvgStableBorrowRate;
     uint256 oldTotalStableDebt;
@@ -28,6 +29,7 @@ library CachingHelper {
     address stableDebtTokenAddress;
     address variableDebtTokenAddress;
     uint40 reserveLastUpdateTimestamp;
+    uint40 stableDebtLastUpdateTimestamp;
   }
 
   function fetchData(DataTypes.ReserveData storage reserveData)
@@ -51,9 +53,23 @@ library CachingHelper {
 
     cachedData.reserveLastUpdateTimestamp = reserveData.lastUpdateTimestamp;
 
-    cachedData.oldScaledVariableDebt = IVariableDebtToken(cachedData.variableDebtTokenAddress)
+    cachedData.oldScaledVariableDebt = cachedData.newScaledVariableDebt = IVariableDebtToken(
+      cachedData
+        .variableDebtTokenAddress
+    )
       .scaledTotalSupply();
-    
+
+    (
+      cachedData.oldPrincipalStableDebt,
+      cachedData.oldTotalStableDebt,
+      cachedData.oldAvgStableBorrowRate,
+      cachedData.stableDebtLastUpdateTimestamp
+    ) = IStableDebtToken(cachedData.stableDebtTokenAddress).getSupplyData();
+
+    cachedData.newPrincipalStableDebt = cachedData.oldPrincipalStableDebt;
+    cachedData.newTotalStableDebt = cachedData.oldTotalStableDebt;
+    cachedData.newAvgStableBorrowRate = cachedData.oldAvgStableBorrowRate;
+
     return cachedData;
   }
 }
diff --git a/contracts/protocol/libraries/logic/ReserveLogic.sol b/contracts/protocol/libraries/logic/ReserveLogic.sol
index 33ba2aaf..53c56454 100644
--- a/contracts/protocol/libraries/logic/ReserveLogic.sol
+++ b/contracts/protocol/libraries/logic/ReserveLogic.sol
@@ -108,23 +108,13 @@ library ReserveLogic {
    * @dev Updates the liquidity cumulative index and the variable borrow index.
    * @param reserve the reserve object
    **/
-  function updateState(DataTypes.ReserveData storage reserve, CachingHelper.CachedData memory cachedData) internal {
+  function updateState(
+    DataTypes.ReserveData storage reserve,
+    CachingHelper.CachedData memory cachedData
+  ) internal {
+    _updateIndexes(reserve, cachedData);
 
-      _updateIndexes(
-        reserve,
-        cachedData
-      );
-
-    
-
-    _accrueToTreasury(
-      reserve,
-      cachedData.oldScaledVariableDebt,
-      cachedData.oldVariableBorrowIndex,
-      cachedData.newLiquidityIndex,
-      cachedData.newVariableBorrowIndex,
-      cachedData.reserveLastUpdateTimestamp
-    );
+    _accrueToTreasury(reserve, cachedData);
   }
 
   /**
@@ -191,22 +181,21 @@ library ReserveLogic {
    **/
   function updateInterestRates(
     DataTypes.ReserveData storage reserve,
+    CachingHelper.CachedData memory cachedData,
     address reserveAddress,
-    address aTokenAddress,
     uint256 liquidityAdded,
     uint256 liquidityTaken
   ) internal {
     UpdateInterestRatesLocalVars memory vars;
 
-    vars.stableDebtTokenAddress = reserve.stableDebtTokenAddress;
+    if (cachedData.oldTotalStableDebt != cachedData.newTotalStableDebt) {
+      cachedData.newAvgStableBorrowRate = IStableDebtToken(cachedData.stableDebtTokenAddress)
+        .getAverageStableRate();
+    }
 
-    (vars.totalStableDebt, vars.avgStableRate) = IStableDebtToken(vars.stableDebtTokenAddress)
-      .getTotalSupplyAndAvgRate();
-
-
-    vars.totalVariableDebt = IVariableDebtToken(reserve.variableDebtTokenAddress)
-      .scaledTotalSupply()
-      .rayMul(reserve.variableBorrowIndex);
+    cachedData.newTotalVariableDebt = cachedData.newScaledVariableDebt.rayMul(
+      cachedData.newVariableBorrowIndex
+    );
 
     (
       vars.newLiquidityRate,
@@ -214,13 +203,13 @@ library ReserveLogic {
       vars.newVariableRate
     ) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
       reserveAddress,
-      aTokenAddress,
+      cachedData.aTokenAddress,
       liquidityAdded,
       liquidityTaken,
-      vars.totalStableDebt,
-      vars.totalVariableDebt,
-      vars.avgStableRate,
-      reserve.configuration.getReserveFactor()
+      cachedData.newTotalStableDebt,
+      cachedData.newTotalVariableDebt,
+      cachedData.newAvgStableBorrowRate,
+      cachedData.reserveConfiguration.getReserveFactorMemory()
     );
     require(vars.newLiquidityRate <= type(uint128).max, Errors.RL_LIQUIDITY_RATE_OVERFLOW);
     require(vars.newStableRate <= type(uint128).max, Errors.RL_STABLE_BORROW_RATE_OVERFLOW);
@@ -235,8 +224,8 @@ library ReserveLogic {
       vars.newLiquidityRate,
       vars.newStableRate,
       vars.newVariableRate,
-      reserve.liquidityIndex,
-      reserve.variableBorrowIndex
+      cachedData.newLiquidityIndex,
+      cachedData.newVariableBorrowIndex
     );
   }
 
@@ -258,46 +247,35 @@ library ReserveLogic {
    * @dev Mints part of the repaid interest to the reserve treasury as a function of the reserveFactor for the
    * specific asset.
    * @param reserve The reserve reserve to be updated
-   * @param scaledVariableDebt The current scaled total variable debt
-   * @param previousVariableBorrowIndex The variable borrow index before the last accumulation of the interest
-   * @param newLiquidityIndex The new liquidity index
-   * @param newVariableBorrowIndex The variable borrow index after the last accumulation of the interest
+   * @param cachedData The caching layer for the reserve data
    **/
   function _accrueToTreasury(
     DataTypes.ReserveData storage reserve,
-    uint256 scaledVariableDebt,
-    uint256 previousVariableBorrowIndex,
-    uint256 newLiquidityIndex,
-    uint256 newVariableBorrowIndex,
-    uint40 timestamp
+    CachingHelper.CachedData memory cachedData
   ) internal {
     MintToTreasuryLocalVars memory vars;
 
-    vars.reserveFactor = reserve.configuration.getReserveFactor();
+    vars.reserveFactor = cachedData.reserveConfiguration.getReserveFactorMemory();
 
     if (vars.reserveFactor == 0) {
       return;
     }
 
-    //fetching the principal, total stable debt and the avg stable rate
-    (
-      vars.principalStableDebt,
-      vars.currentStableDebt,
-      vars.avgStableRate,
-      vars.stableSupplyUpdatedTimestamp
-    ) = IStableDebtToken(reserve.stableDebtTokenAddress).getSupplyData();
-
     //calculate the last principal variable debt
-    vars.previousVariableDebt = scaledVariableDebt.rayMul(previousVariableBorrowIndex);
+    vars.previousVariableDebt = cachedData.oldScaledVariableDebt.rayMul(
+      cachedData.oldVariableBorrowIndex
+    );
 
     //calculate the new total supply after accumulation of the index
-    vars.currentVariableDebt = scaledVariableDebt.rayMul(newVariableBorrowIndex);
+    vars.currentVariableDebt = cachedData.oldScaledVariableDebt.rayMul(
+      cachedData.newVariableBorrowIndex
+    );
 
     //calculate the stable debt until the last timestamp update
     vars.cumulatedStableInterest = MathUtils.calculateCompoundedInterest(
       vars.avgStableRate,
       vars.stableSupplyUpdatedTimestamp,
-      timestamp
+      cachedData.reserveLastUpdateTimestamp
     );
 
     vars.previousStableDebt = vars.principalStableDebt.rayMul(vars.cumulatedStableInterest);
@@ -312,7 +290,9 @@ library ReserveLogic {
     vars.amountToMint = vars.totalDebtAccrued.percentMul(vars.reserveFactor);
 
     if (vars.amountToMint != 0) {
-      reserve.accruedToTreasury = reserve.accruedToTreasury.add(vars.amountToMint.rayDiv(newLiquidityIndex));
+      reserve.accruedToTreasury = reserve.accruedToTreasury.add(
+        vars.amountToMint.rayDiv(cachedData.newLiquidityIndex)
+      );
     }
   }
 
@@ -325,16 +305,23 @@ library ReserveLogic {
     DataTypes.ReserveData storage reserve,
     CachingHelper.CachedData memory cachedData
   ) internal {
-
     cachedData.newLiquidityIndex = cachedData.oldLiquidityIndex;
     cachedData.newVariableBorrowIndex = cachedData.oldVariableBorrowIndex;
 
     //only cumulating if there is any income being produced
     if (cachedData.oldLiquidityRate > 0) {
       uint256 cumulatedLiquidityInterest =
-        MathUtils.calculateLinearInterest(cachedData.oldLiquidityRate, cachedData.reserveLastUpdateTimestamp);
-       cachedData.newLiquidityIndex = cumulatedLiquidityInterest.rayMul(cachedData.oldLiquidityIndex);
-      require( cachedData.newLiquidityIndex <= type(uint128).max, Errors.RL_LIQUIDITY_INDEX_OVERFLOW);
+        MathUtils.calculateLinearInterest(
+          cachedData.oldLiquidityRate,
+          cachedData.reserveLastUpdateTimestamp
+        );
+      cachedData.newLiquidityIndex = cumulatedLiquidityInterest.rayMul(
+        cachedData.oldLiquidityIndex
+      );
+      require(
+        cachedData.newLiquidityIndex <= type(uint128).max,
+        Errors.RL_LIQUIDITY_INDEX_OVERFLOW
+      );
 
       reserve.liquidityIndex = uint128(cachedData.newLiquidityIndex);
 
@@ -342,8 +329,13 @@ library ReserveLogic {
       //that there is actual variable debt before accumulating
       if (cachedData.oldScaledVariableDebt != 0) {
         uint256 cumulatedVariableBorrowInterest =
-          MathUtils.calculateCompoundedInterest(cachedData.oldVariableBorrowRate, cachedData.reserveLastUpdateTimestamp);
-        cachedData.newVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(cachedData.oldVariableBorrowIndex);
+          MathUtils.calculateCompoundedInterest(
+            cachedData.oldVariableBorrowRate,
+            cachedData.reserveLastUpdateTimestamp
+          );
+        cachedData.newVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(
+          cachedData.oldVariableBorrowIndex
+        );
         require(
           cachedData.newVariableBorrowIndex <= type(uint128).max,
           Errors.RL_VARIABLE_BORROW_INDEX_OVERFLOW
diff --git a/contracts/protocol/libraries/logic/ValidationLogic.sol b/contracts/protocol/libraries/logic/ValidationLogic.sol
index 40ef23be..94cc3248 100644
--- a/contracts/protocol/libraries/logic/ValidationLogic.sol
+++ b/contracts/protocol/libraries/logic/ValidationLogic.sol
@@ -12,11 +12,14 @@ import {SafeERC20} from '../../../dependencies/openzeppelin/contracts/SafeERC20.
 import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol';
 import {UserConfiguration} from '../configuration/UserConfiguration.sol';
 import {Errors} from '../helpers/Errors.sol';
+import {CachingHelper} from '../helpers/CachingHelper.sol';
 import {Helpers} from '../helpers/Helpers.sol';
 import {IReserveInterestRateStrategy} from '../../../interfaces/IReserveInterestRateStrategy.sol';
 import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol';
 import {IStableDebtToken} from '../../../interfaces/IStableDebtToken.sol';
+import {IAToken} from '../../../interfaces/IAToken.sol';
 import {DataTypes} from '../types/DataTypes.sol';
+import {IPriceOracleGetter} from '../../../interfaces/IPriceOracleGetter.sol';
 
 /**
  * @title ReserveLogic library
@@ -40,11 +43,15 @@ library ValidationLogic {
    * @param reserve The reserve object on which the user is depositing
    * @param amount The amount to be deposited
    */
-  function validateDeposit(DataTypes.ReserveData storage reserve, uint256 amount) internal view {
-    DataTypes.ReserveConfigurationMap memory reserveConfiguration = reserve.configuration;
-    (bool isActive, bool isFrozen, , , bool isPaused) = reserveConfiguration.getFlagsMemory();
-    (, , , uint256 reserveDecimals, ) = reserveConfiguration.getParamsMemory();
-    uint256 supplyCap = reserveConfiguration.getSupplyCapMemory();
+  function validateDeposit(
+    DataTypes.ReserveData storage reserve,
+    CachingHelper.CachedData memory cachedData,
+    uint256 amount
+  ) internal view {
+    (bool isActive, bool isFrozen, , , bool isPaused) =
+      cachedData.reserveConfiguration.getFlagsMemory();
+    (, , , uint256 reserveDecimals, ) = cachedData.reserveConfiguration.getParamsMemory();
+    uint256 supplyCap = cachedData.reserveConfiguration.getSupplyCapMemory();
 
     require(amount != 0, Errors.VL_INVALID_AMOUNT);
     require(isActive, Errors.VL_NO_ACTIVE_RESERVE);
@@ -52,7 +59,11 @@ library ValidationLogic {
     require(!isFrozen, Errors.VL_RESERVE_FROZEN);
     require(
       supplyCap == 0 ||
-        IERC20(reserve.aTokenAddress).totalSupply().add(amount).div(10**reserveDecimals) <
+        IAToken(cachedData.aTokenAddress)
+          .scaledTotalSupply()
+          .rayMul(cachedData.newLiquidityIndex)
+          .add(amount)
+          .div(10**reserveDecimals) <
         supplyCap,
       Errors.VL_SUPPLY_CAP_EXCEEDED
     );
@@ -85,10 +96,11 @@ library ValidationLogic {
     uint256 userBorrowBalanceETH;
     uint256 availableLiquidity;
     uint256 healthFactor;
-    uint256 totalSupplyStableDebt;
+    uint256 totalDebt;
     uint256 totalSupplyVariableDebt;
     uint256 reserveDecimals;
     uint256 borrowCap;
+    uint256 amountInETH;
     bool isActive;
     bool isFrozen;
     bool isPaused;
@@ -99,10 +111,8 @@ library ValidationLogic {
   /**
    * @dev Validates a borrow action
    * @param asset The address of the asset to borrow
-   * @param reserve The reserve state from which the user is borrowing
    * @param userAddress The address of the user
    * @param amount The amount to be borrowed
-   * @param amountInETH The amount to be borrowed, in ETH
    * @param interestRateMode The interest rate mode at which the user is borrowing
    * @param maxStableLoanPercent The max amount of the liquidity that can be borrowed at stable rate, in percentage
    * @param reservesData The state of all the reserves
@@ -112,11 +122,10 @@ library ValidationLogic {
    */
 
   function validateBorrow(
+    CachingHelper.CachedData memory cachedData,
     address asset,
-    DataTypes.ReserveData storage reserve,
     address userAddress,
     uint256 amount,
-    uint256 amountInETH,
     uint256 interestRateMode,
     uint256 maxStableLoanPercent,
     mapping(address => DataTypes.ReserveData) storage reservesData,
@@ -127,8 +136,7 @@ library ValidationLogic {
   ) external view {
     ValidateBorrowLocalVars memory vars;
 
-    DataTypes.ReserveConfigurationMap memory reserveConfiguration = reserve.configuration;
-    (, , , vars.reserveDecimals, ) = reserveConfiguration.getParamsMemory();
+    (, , , vars.reserveDecimals, ) = cachedData.reserveConfiguration.getParamsMemory();
 
     (
       vars.isActive,
@@ -136,7 +144,7 @@ library ValidationLogic {
       vars.borrowingEnabled,
       vars.stableRateBorrowingEnabled,
       vars.isPaused
-    ) = reserveConfiguration.getFlagsMemory();
+    ) = cachedData.reserveConfiguration.getFlagsMemory();
 
     require(vars.isActive, Errors.VL_NO_ACTIVE_RESERVE);
     require(!vars.isPaused, Errors.VL_RESERVE_PAUSED);
@@ -152,18 +160,23 @@ library ValidationLogic {
       Errors.VL_INVALID_INTEREST_RATE_MODE_SELECTED
     );
 
-    vars.totalSupplyStableDebt = IERC20(reserve.stableDebtTokenAddress).totalSupply();
-    vars.borrowCap = reserveConfiguration.getBorrowCapMemory();
-    vars.totalSupplyVariableDebt = IERC20(reserve.variableDebtTokenAddress).totalSupply();
+    vars.borrowCap = cachedData.reserveConfiguration.getBorrowCapMemory();
 
-    require(
-      vars.borrowCap == 0 ||
-        vars.totalSupplyStableDebt.add(vars.totalSupplyVariableDebt).add(amount).div(
-          10**vars.reserveDecimals
-        ) <
-        vars.borrowCap,
-      Errors.VL_BORROW_CAP_EXCEEDED
-    );
+    if (vars.borrowCap > 0) {
+      {
+        vars.totalSupplyVariableDebt = cachedData.oldScaledVariableDebt.rayMul(
+          cachedData.newVariableBorrowIndex
+        );
+
+        vars.totalDebt = cachedData.oldTotalStableDebt.add(vars.totalSupplyVariableDebt).add(
+          amount
+        );
+        require(
+          vars.totalDebt.div(10**vars.reserveDecimals) < vars.borrowCap,
+          Errors.VL_BORROW_CAP_EXCEEDED
+        );
+      }
+    }
 
     (
       vars.userCollateralBalanceETH,
@@ -187,8 +200,11 @@ library ValidationLogic {
       Errors.VL_HEALTH_FACTOR_LOWER_THAN_LIQUIDATION_THRESHOLD
     );
 
+    vars.amountInETH = IPriceOracleGetter(oracle).getAssetPrice(asset);
+    vars.amountInETH = vars.amountInETH.mul(amount).div(10**vars.reserveDecimals);
+
     //add the current already borrowed amount to the amount requested to calculate the total collateral needed.
-    vars.amountOfCollateralNeededETH = vars.userBorrowBalanceETH.add(amountInETH).percentDiv(
+    vars.amountOfCollateralNeededETH = vars.userBorrowBalanceETH.add(vars.amountInETH).percentDiv(
       vars.currentLtv
     ); //LTV is calculated in percentage
 
@@ -211,13 +227,13 @@ library ValidationLogic {
       require(vars.stableRateBorrowingEnabled, Errors.VL_STABLE_BORROWING_NOT_ENABLED);
 
       require(
-        !userConfig.isUsingAsCollateral(reserve.id) ||
-          reserve.configuration.getLtv() == 0 ||
-          amount > IERC20(reserve.aTokenAddress).balanceOf(userAddress),
+        !userConfig.isUsingAsCollateral(reservesData[asset].id) ||
+          cachedData.reserveConfiguration.getLtvMemory() == 0 ||
+          amount > IERC20(cachedData.aTokenAddress).balanceOf(userAddress),
         Errors.VL_COLLATERAL_SAME_AS_BORROWING_CURRENCY
       );
 
-      vars.availableLiquidity = IERC20(asset).balanceOf(reserve.aTokenAddress);
+      vars.availableLiquidity = IERC20(asset).balanceOf(cachedData.aTokenAddress);
 
       //calculate the max available loan size in stable rate mode as a percentage of the
       //available liquidity