@@ -60,6 +60,7 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
6060 * @param authority_ The address of the authority contract which manages permissions.
6161 */
6262 constructor (address authority_ ) AccessManaged (authority_) {
63+ require (authority_ != address (0 ), InvalidAddress ());
6364 _liquidationConfig.closeFactor = Constants.HEALTH_FACTOR_LIQUIDATION_THRESHOLD;
6465 emit LiquidationConfigUpdate (_liquidationConfig);
6566 }
@@ -68,10 +69,13 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
6869 // Governance
6970 // /////
7071
72+ /// @inheritdoc ISpoke
7173 function updateOracle (address newOracle ) external restricted {
72- require (newOracle != address (0 ), InvalidOracle ());
7374 oracle = IAaveOracle (newOracle);
74- require (oracle.DECIMALS () == 8 , InvalidOracle ());
75+ require (
76+ newOracle != address (0 ) && oracle.DECIMALS () == Constants.ORACLE_DECIMALS,
77+ InvalidOracle ()
78+ );
7579 emit OracleUpdate (newOracle);
7680 }
7781
@@ -95,10 +99,11 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
9599 DataTypes.ReserveConfig calldata config ,
96100 DataTypes.DynamicReserveConfig calldata dynamicConfig
97101 ) external restricted returns (uint256 ) {
98- require (hub != address (0 ), InvalidHubAddress ());
102+ require (hub != address (0 ), InvalidAddress ());
99103 require (! _reserveExists[hub][assetId], ReserveExists ());
100104
101105 _validateReserveConfig (config);
106+ _validateDynamicReserveConfig (dynamicConfig);
102107 uint256 reserveId = _reserveCount++ ;
103108 uint16 dynamicConfigKey; // 0 as first key to use
104109
@@ -222,7 +227,6 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
222227
223228 userPosition.suppliedShares -= withdrawnShares.toUint128 ();
224229
225- // calc needs new user position, just updating drawn debt is enough
226230 uint256 newUserRiskPremium = _refreshAndValidateUserPosition (onBehalfOf); // validates HF
227231 _notifyRiskPremiumUpdate (onBehalfOf, newUserRiskPremium);
228232
@@ -250,7 +254,6 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
250254 positionStatus.setBorrowing (reserveId, true );
251255 }
252256
253- // calc needs new user position, just updating drawn debt is enough
254257 uint256 newUserRiskPremium = _refreshAndValidateUserPosition (onBehalfOf); // validates HF
255258 _notifyRiskPremiumUpdate (onBehalfOf, newUserRiskPremium);
256259
@@ -503,13 +506,11 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
503506 return drawnDebt + premiumDebt;
504507 }
505508
506- /// @dev We do not differentiate between duplicate reserves (assetId) on the same hub
507509 function getReserveSuppliedAmount (uint256 reserveId ) external view returns (uint256 ) {
508510 DataTypes.Reserve storage reserve = _reserves[reserveId];
509511 return reserve.hub.getSpokeAddedAmount (reserve.assetId, address (this ));
510512 }
511513
512- /// @dev We do not differentiate between duplicate reserves (assetId) on the same hub
513514 function getReserveSuppliedShares (uint256 reserveId ) external view returns (uint256 ) {
514515 DataTypes.Reserve storage reserve = _reserves[reserveId];
515516 return reserve.hub.getSpokeAddedShares (reserve.assetId, address (this ));
@@ -676,15 +677,10 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
676677
677678 /**
678679 * @dev Calculates the user's premium debt offset in assets amount from a given share amount.
679- * @dev Rounds down to the nearest assets amount.
680- * @dev Uses the opposite rounding direction of the debt shares-to-assets conversion to prevent underflow
681- * in premium debt.
682- * @param hub The liquidity hub of the reserve.
683- * @param assetId The identifier of the asset.
684- * @param shares The amount of shares to convert to assets amount.
685- * @return The amount of assets converted corresponding to user's premium offset.
680+ * @dev Rounds down to the nearest assets amount. Uses the opposite rounding direction of the
681+ * debt shares-to-assets conversion to prevent underflow in premium debt.
686682 */
687- function _previewOffset (
683+ function _previewPremiumOffset (
688684 IHub hub ,
689685 uint256 assetId ,
690686 uint256 shares
@@ -728,7 +724,10 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
728724 }
729725
730726 function _validateLiquidationConfig (DataTypes.LiquidationConfig calldata config ) internal pure {
731- _validateCloseFactor (config.closeFactor);
727+ require (
728+ config.closeFactor >= Constants.HEALTH_FACTOR_LIQUIDATION_THRESHOLD,
729+ InvalidCloseFactor ()
730+ );
732731 require (
733732 config.liquidationBonusFactor <= PercentageMath.PERCENTAGE_FACTOR,
734733 InvalidLiquidationBonusFactor ()
@@ -739,10 +738,6 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
739738 );
740739 }
741740
742- function _validateCloseFactor (uint256 closeFactor ) internal pure {
743- require (closeFactor >= Constants.HEALTH_FACTOR_LIQUIDATION_THRESHOLD, InvalidCloseFactor ());
744- }
745-
746741 /**
747742 * @dev Validates the reserve can be set as collateral.
748743 * @dev Collateral can be disabled if the reserve is frozen.
@@ -847,21 +842,23 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
847842 ? (userPosition.configKey = reserve.dynamicConfigKey)
848843 : userPosition.configKey
849844 ];
850-
851- vars.userCollateralInBaseCurrency = _getUserBalanceInBaseCurrency (
852- userPosition,
853- hub,
854- vars.assetId,
855- vars.assetPrice,
856- vars.assetUnit
857- );
858-
859- vars.totalCollateralInBaseCurrency += vars.userCollateralInBaseCurrency;
860- list.add (vars.i, reserve.collateralRisk, vars.userCollateralInBaseCurrency);
861- vars.avgCollateralFactor += vars.userCollateralInBaseCurrency * dynConfig.collateralFactor;
862-
863- unchecked {
864- ++ vars.i;
845+ uint256 collateralFactor = dynConfig.collateralFactor;
846+ if (collateralFactor != 0 ) {
847+ vars.userCollateralInBaseCurrency = _getUserBalanceInBaseCurrency (
848+ userPosition,
849+ hub,
850+ vars.assetId,
851+ vars.assetPrice,
852+ vars.assetUnit
853+ );
854+
855+ vars.totalCollateralInBaseCurrency += vars.userCollateralInBaseCurrency;
856+ list.add (vars.i, reserve.collateralRisk, vars.userCollateralInBaseCurrency);
857+ vars.avgCollateralFactor += vars.userCollateralInBaseCurrency * collateralFactor;
858+
859+ unchecked {
860+ ++ vars.i;
861+ }
865862 }
866863 }
867864
@@ -899,7 +896,6 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
899896 // @dev from this point onwards, `collateralCounterInBaseCurrency` represents running collateral
900897 // value used in risk premium, `debtCounterInBaseCurrency` represents running outstanding debt
901898 while (vars.i < list.length () && vars.debtCounterInBaseCurrency > 0 ) {
902- if (vars.debtCounterInBaseCurrency == 0 ) break ;
903899 (vars.collateralRisk, vars.userCollateralInBaseCurrency) = list.get (vars.i);
904900 if (vars.userCollateralInBaseCurrency > vars.debtCounterInBaseCurrency) {
905901 vars.userCollateralInBaseCurrency = vars.debtCounterInBaseCurrency;
@@ -933,7 +929,8 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
933929 uint256 assetUnit
934930 ) internal view returns (uint256 ) {
935931 (uint256 drawnDebt , uint256 premiumDebt , ) = _getUserDebt (hub, assetId, userPosition);
936- return ((drawnDebt + premiumDebt) * assetPrice).wadDivUp (assetUnit);
932+ return
933+ (drawnDebt * assetPrice).wadDivUp (assetUnit) + (premiumDebt * assetPrice).wadDivUp (assetUnit);
937934 }
938935
939936 function _getUserBalanceInBaseCurrency (
@@ -996,7 +993,7 @@ contract Spoke is ISpoke, Multicall, AccessManaged, EIP712 {
996993 .drawnShares
997994 .percentMulUp (newUserRiskPremium)
998995 .toUint128 ());
999- uint256 newPremiumOffset = (userPosition.premiumOffset = _previewOffset (
996+ uint256 newPremiumOffset = (userPosition.premiumOffset = _previewPremiumOffset (
1000997 vars.hub,
1001998 vars.assetId,
1002999 userPosition.premiumShares
0 commit comments