LCOV - code coverage report
Current view: top level - rewards - RewardsDistributor.sol (source / functions) Coverage Total Hit
Test: lcov.info.p Lines: 98.3 % 121 119
Test Date: 2024-09-24 09:34:24 Functions: 95.8 % 24 23
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: BUSL-1.1
       2                 :             : pragma solidity ^0.8.10;
       3                 :             : 
       4                 :             : import {IScaledBalanceToken} from '../interfaces/IScaledBalanceToken.sol';
       5                 :             : import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
       6                 :             : import {SafeCast} from '../dependencies/openzeppelin/contracts/SafeCast.sol';
       7                 :             : import {IRewardsDistributor} from './interfaces/IRewardsDistributor.sol';
       8                 :             : import {RewardsDataTypes} from './libraries/RewardsDataTypes.sol';
       9                 :             : 
      10                 :             : /**
      11                 :             :  * @title RewardsDistributor
      12                 :             :  * @notice Accounting contract to manage multiple staking distributions with multiple rewards
      13                 :             :  * @author Aave
      14                 :             :  **/
      15                 :             : abstract contract RewardsDistributor is IRewardsDistributor {
      16                 :             :   using SafeCast for uint256;
      17                 :             : 
      18                 :             :   // Manager of incentives
      19                 :             :   address public immutable EMISSION_MANAGER;
      20                 :             :   // Deprecated: This storage slot is kept for backwards compatibility purposes.
      21                 :             :   address internal _emissionManager;
      22                 :             : 
      23                 :             :   // Map of rewarded asset addresses and their data (assetAddress => assetData)
      24                 :             :   mapping(address => RewardsDataTypes.AssetData) internal _assets;
      25                 :             : 
      26                 :             :   // Map of reward assets (rewardAddress => enabled)
      27                 :             :   mapping(address => bool) internal _isRewardEnabled;
      28                 :             : 
      29                 :             :   // Rewards list
      30                 :             :   address[] internal _rewardsList;
      31                 :             : 
      32                 :             :   // Assets list
      33                 :             :   address[] internal _assetsList;
      34                 :             : 
      35                 :             :   modifier onlyEmissionManager() {
      36                 :           2 :     require(msg.sender == EMISSION_MANAGER, 'ONLY_EMISSION_MANAGER');
      37                 :             :     _;
      38                 :             :   }
      39                 :             : 
      40                 :             :   constructor(address emissionManager) {
      41                 :           0 :     EMISSION_MANAGER = emissionManager;
      42                 :             :   }
      43                 :             : 
      44                 :             :   /// @inheritdoc IRewardsDistributor
      45                 :             :   function getRewardsData(
      46                 :             :     address asset,
      47                 :             :     address reward
      48                 :             :   ) external view override returns (uint256, uint256, uint256, uint256) {
      49                 :           3 :     return (
      50                 :             :       _assets[asset].rewards[reward].index,
      51                 :             :       _assets[asset].rewards[reward].emissionPerSecond,
      52                 :             :       _assets[asset].rewards[reward].lastUpdateTimestamp,
      53                 :             :       _assets[asset].rewards[reward].distributionEnd
      54                 :             :     );
      55                 :             :   }
      56                 :             : 
      57                 :             :   /// @inheritdoc IRewardsDistributor
      58                 :             :   function getAssetIndex(
      59                 :             :     address asset,
      60                 :             :     address reward
      61                 :             :   ) external view override returns (uint256, uint256) {
      62                 :       37954 :     RewardsDataTypes.RewardData storage rewardData = _assets[asset].rewards[reward];
      63                 :       37954 :     return
      64                 :       37954 :       _getAssetIndex(
      65                 :             :         rewardData,
      66                 :             :         IScaledBalanceToken(asset).scaledTotalSupply(),
      67                 :             :         10 ** _assets[asset].decimals
      68                 :             :       );
      69                 :             :   }
      70                 :             : 
      71                 :             :   /// @inheritdoc IRewardsDistributor
      72                 :             :   function getDistributionEnd(
      73                 :             :     address asset,
      74                 :             :     address reward
      75                 :             :   ) external view override returns (uint256) {
      76                 :           1 :     return _assets[asset].rewards[reward].distributionEnd;
      77                 :             :   }
      78                 :             : 
      79                 :             :   /// @inheritdoc IRewardsDistributor
      80                 :             :   function getRewardsByAsset(address asset) external view override returns (address[] memory) {
      81                 :        9118 :     uint128 rewardsCount = _assets[asset].availableRewardsCount;
      82                 :        9118 :     address[] memory availableRewards = new address[](rewardsCount);
      83                 :             : 
      84                 :        9118 :     for (uint128 i = 0; i < rewardsCount; i++) {
      85                 :        9033 :       availableRewards[i] = _assets[asset].availableRewards[i];
      86                 :             :     }
      87                 :        9118 :     return availableRewards;
      88                 :             :   }
      89                 :             : 
      90                 :             :   /// @inheritdoc IRewardsDistributor
      91                 :             :   function getRewardsList() external view override returns (address[] memory) {
      92                 :          30 :     return _rewardsList;
      93                 :             :   }
      94                 :             : 
      95                 :             :   /// @inheritdoc IRewardsDistributor
      96                 :             :   function getUserAssetIndex(
      97                 :             :     address user,
      98                 :             :     address asset,
      99                 :             :     address reward
     100                 :             :   ) external view override returns (uint256) {
     101                 :           1 :     return _assets[asset].rewards[reward].usersData[user].index;
     102                 :             :   }
     103                 :             : 
     104                 :             :   /// @inheritdoc IRewardsDistributor
     105                 :             :   function getUserAccruedRewards(
     106                 :             :     address user,
     107                 :             :     address reward
     108                 :             :   ) external view override returns (uint256) {
     109                 :           1 :     uint256 totalAccrued;
     110                 :           1 :     for (uint256 i = 0; i < _assetsList.length; i++) {
     111                 :           1 :       totalAccrued += _assets[_assetsList[i]].rewards[reward].usersData[user].accrued;
     112                 :             :     }
     113                 :             : 
     114                 :           1 :     return totalAccrued;
     115                 :             :   }
     116                 :             : 
     117                 :             :   /// @inheritdoc IRewardsDistributor
     118                 :             :   function getUserRewards(
     119                 :             :     address[] calldata assets,
     120                 :             :     address user,
     121                 :             :     address reward
     122                 :             :   ) external view override returns (uint256) {
     123                 :        1011 :     return _getUserReward(user, reward, _getUserAssetBalances(assets, user));
     124                 :             :   }
     125                 :             : 
     126                 :             :   /// @inheritdoc IRewardsDistributor
     127                 :             :   function getAllUserRewards(
     128                 :             :     address[] calldata assets,
     129                 :             :     address user
     130                 :             :   )
     131                 :             :     external
     132                 :             :     view
     133                 :             :     override
     134                 :             :     returns (address[] memory rewardsList, uint256[] memory unclaimedAmounts)
     135                 :             :   {
     136                 :           1 :     RewardsDataTypes.UserAssetBalance[] memory userAssetBalances = _getUserAssetBalances(
     137                 :             :       assets,
     138                 :             :       user
     139                 :             :     );
     140                 :           1 :     rewardsList = new address[](_rewardsList.length);
     141                 :           1 :     unclaimedAmounts = new uint256[](rewardsList.length);
     142                 :             : 
     143                 :             :     // Add unrealized rewards from user to unclaimedRewards
     144                 :           1 :     for (uint256 i = 0; i < userAssetBalances.length; i++) {
     145                 :           1 :       for (uint256 r = 0; r < rewardsList.length; r++) {
     146                 :           1 :         rewardsList[r] = _rewardsList[r];
     147                 :           1 :         unclaimedAmounts[r] += _assets[userAssetBalances[i].asset]
     148                 :             :           .rewards[rewardsList[r]]
     149                 :             :           .usersData[user]
     150                 :             :           .accrued;
     151                 :             : 
     152                 :           1 :         if (userAssetBalances[i].userBalance == 0) {
     153                 :           1 :           continue;
     154                 :             :         }
     155                 :           1 :         unclaimedAmounts[r] += _getPendingRewards(user, rewardsList[r], userAssetBalances[i]);
     156                 :             :       }
     157                 :             :     }
     158                 :           1 :     return (rewardsList, unclaimedAmounts);
     159                 :             :   }
     160                 :             : 
     161                 :             :   /// @inheritdoc IRewardsDistributor
     162                 :             :   function setDistributionEnd(
     163                 :             :     address asset,
     164                 :             :     address reward,
     165                 :             :     uint32 newDistributionEnd
     166                 :             :   ) external override onlyEmissionManager {
     167                 :           2 :     uint256 oldDistributionEnd = _assets[asset].rewards[reward].distributionEnd;
     168                 :           2 :     _assets[asset].rewards[reward].distributionEnd = newDistributionEnd;
     169                 :             : 
     170                 :           2 :     emit AssetConfigUpdated(
     171                 :             :       asset,
     172                 :             :       reward,
     173                 :             :       _assets[asset].rewards[reward].emissionPerSecond,
     174                 :             :       _assets[asset].rewards[reward].emissionPerSecond,
     175                 :             :       oldDistributionEnd,
     176                 :             :       newDistributionEnd,
     177                 :             :       _assets[asset].rewards[reward].index
     178                 :             :     );
     179                 :             :   }
     180                 :             : 
     181                 :             :   /// @inheritdoc IRewardsDistributor
     182                 :             :   function setEmissionPerSecond(
     183                 :             :     address asset,
     184                 :             :     address[] calldata rewards,
     185                 :             :     uint88[] calldata newEmissionsPerSecond
     186                 :             :   ) external override onlyEmissionManager {
     187                 :           2 :     require(rewards.length == newEmissionsPerSecond.length, 'INVALID_INPUT');
     188                 :           2 :     for (uint256 i = 0; i < rewards.length; i++) {
     189                 :           2 :       RewardsDataTypes.AssetData storage assetConfig = _assets[asset];
     190                 :           2 :       RewardsDataTypes.RewardData storage rewardConfig = _assets[asset].rewards[rewards[i]];
     191                 :           2 :       uint256 decimals = assetConfig.decimals;
     192                 :           2 :       require(
     193                 :             :         decimals != 0 && rewardConfig.lastUpdateTimestamp != 0,
     194                 :             :         'DISTRIBUTION_DOES_NOT_EXIST'
     195                 :             :       );
     196                 :             : 
     197                 :           2 :       (uint256 newIndex, ) = _updateRewardData(
     198                 :             :         rewardConfig,
     199                 :             :         IScaledBalanceToken(asset).scaledTotalSupply(),
     200                 :             :         10 ** decimals
     201                 :             :       );
     202                 :             : 
     203                 :           2 :       uint256 oldEmissionPerSecond = rewardConfig.emissionPerSecond;
     204                 :           2 :       rewardConfig.emissionPerSecond = newEmissionsPerSecond[i];
     205                 :             : 
     206                 :           2 :       emit AssetConfigUpdated(
     207                 :             :         asset,
     208                 :             :         rewards[i],
     209                 :             :         oldEmissionPerSecond,
     210                 :             :         newEmissionsPerSecond[i],
     211                 :             :         rewardConfig.distributionEnd,
     212                 :             :         rewardConfig.distributionEnd,
     213                 :             :         newIndex
     214                 :             :       );
     215                 :             :     }
     216                 :             :   }
     217                 :             : 
     218                 :             :   /**
     219                 :             :    * @dev Configure the _assets for a specific emission
     220                 :             :    * @param rewardsInput The array of each asset configuration
     221                 :             :    **/
     222                 :             :   function _configureAssets(RewardsDataTypes.RewardsConfigInput[] memory rewardsInput) internal {
     223                 :        9023 :     for (uint256 i = 0; i < rewardsInput.length; i++) {
     224                 :        9023 :       if (_assets[rewardsInput[i].asset].decimals == 0) {
     225                 :             :         //never initialized before, adding to the list of assets
     226                 :        9023 :         _assetsList.push(rewardsInput[i].asset);
     227                 :             :       }
     228                 :             : 
     229                 :        9023 :       uint256 decimals = _assets[rewardsInput[i].asset].decimals = IERC20Detailed(
     230                 :             :         rewardsInput[i].asset
     231                 :             :       ).decimals();
     232                 :             : 
     233                 :        9023 :       RewardsDataTypes.RewardData storage rewardConfig = _assets[rewardsInput[i].asset].rewards[
     234                 :             :         rewardsInput[i].reward
     235                 :             :       ];
     236                 :             : 
     237                 :             :       // Add reward address to asset available rewards if latestUpdateTimestamp is zero
     238                 :        9023 :       if (rewardConfig.lastUpdateTimestamp == 0) {
     239                 :        9023 :         _assets[rewardsInput[i].asset].availableRewards[
     240                 :             :           _assets[rewardsInput[i].asset].availableRewardsCount
     241                 :             :         ] = rewardsInput[i].reward;
     242                 :        9023 :         _assets[rewardsInput[i].asset].availableRewardsCount++;
     243                 :             :       }
     244                 :             : 
     245                 :             :       // Add reward address to global rewards list if still not enabled
     246                 :        9023 :       if (_isRewardEnabled[rewardsInput[i].reward] == false) {
     247                 :        9023 :         _isRewardEnabled[rewardsInput[i].reward] = true;
     248                 :        9023 :         _rewardsList.push(rewardsInput[i].reward);
     249                 :             :       }
     250                 :             : 
     251                 :             :       // Due emissions is still zero, updates only latestUpdateTimestamp
     252                 :        9023 :       (uint256 newIndex, ) = _updateRewardData(
     253                 :             :         rewardConfig,
     254                 :             :         rewardsInput[i].totalSupply,
     255                 :             :         10 ** decimals
     256                 :             :       );
     257                 :             : 
     258                 :             :       // Configure emission and distribution end of the reward per asset
     259                 :        9023 :       uint88 oldEmissionsPerSecond = rewardConfig.emissionPerSecond;
     260                 :        9023 :       uint32 oldDistributionEnd = rewardConfig.distributionEnd;
     261                 :        9023 :       rewardConfig.emissionPerSecond = rewardsInput[i].emissionPerSecond;
     262                 :        9023 :       rewardConfig.distributionEnd = rewardsInput[i].distributionEnd;
     263                 :             : 
     264                 :        9023 :       emit AssetConfigUpdated(
     265                 :             :         rewardsInput[i].asset,
     266                 :             :         rewardsInput[i].reward,
     267                 :             :         oldEmissionsPerSecond,
     268                 :             :         rewardsInput[i].emissionPerSecond,
     269                 :             :         oldDistributionEnd,
     270                 :             :         rewardsInput[i].distributionEnd,
     271                 :             :         newIndex
     272                 :             :       );
     273                 :             :     }
     274                 :             :   }
     275                 :             : 
     276                 :             :   /**
     277                 :             :    * @dev Updates the state of the distribution for the specified reward
     278                 :             :    * @param rewardData Storage pointer to the distribution reward config
     279                 :             :    * @param totalSupply Current total of underlying assets for this distribution
     280                 :             :    * @param assetUnit One unit of asset (10**decimals)
     281                 :             :    * @return The new distribution index
     282                 :             :    * @return True if the index was updated, false otherwise
     283                 :             :    **/
     284                 :             :   function _updateRewardData(
     285                 :             :     RewardsDataTypes.RewardData storage rewardData,
     286                 :             :     uint256 totalSupply,
     287                 :             :     uint256 assetUnit
     288                 :             :   ) internal returns (uint256, bool) {
     289                 :       11558 :     (uint256 oldIndex, uint256 newIndex) = _getAssetIndex(rewardData, totalSupply, assetUnit);
     290                 :       11558 :     bool indexUpdated;
     291                 :       11558 :     if (newIndex != oldIndex) {
     292                 :        1903 :       require(newIndex <= type(uint104).max, 'INDEX_OVERFLOW');
     293                 :        1903 :       indexUpdated = true;
     294                 :             : 
     295                 :             :       //optimization: storing one after another saves one SSTORE
     296                 :        1903 :       rewardData.index = uint104(newIndex);
     297                 :        1903 :       rewardData.lastUpdateTimestamp = block.timestamp.toUint32();
     298                 :             :     } else {
     299                 :        9655 :       rewardData.lastUpdateTimestamp = block.timestamp.toUint32();
     300                 :             :     }
     301                 :             : 
     302                 :       11558 :     return (newIndex, indexUpdated);
     303                 :             :   }
     304                 :             : 
     305                 :             :   /**
     306                 :             :    * @dev Updates the state of the distribution for the specific user
     307                 :             :    * @param rewardData Storage pointer to the distribution reward config
     308                 :             :    * @param user The address of the user
     309                 :             :    * @param userBalance The user balance of the asset
     310                 :             :    * @param newAssetIndex The new index of the asset distribution
     311                 :             :    * @param assetUnit One unit of asset (10**decimals)
     312                 :             :    * @return The rewards accrued since the last update
     313                 :             :    **/
     314                 :             :   function _updateUserData(
     315                 :             :     RewardsDataTypes.RewardData storage rewardData,
     316                 :             :     address user,
     317                 :             :     uint256 userBalance,
     318                 :             :     uint256 newAssetIndex,
     319                 :             :     uint256 assetUnit
     320                 :             :   ) internal returns (uint256, bool) {
     321                 :        2533 :     uint256 userIndex = rewardData.usersData[user].index;
     322                 :        2533 :     uint256 rewardsAccrued;
     323                 :        2533 :     bool dataUpdated;
     324                 :        2533 :     if ((dataUpdated = userIndex != newAssetIndex)) {
     325                 :             :       // already checked for overflow in _updateRewardData
     326                 :        1903 :       rewardData.usersData[user].index = uint104(newAssetIndex);
     327                 :        1903 :       if (userBalance != 0) {
     328                 :        1903 :         rewardsAccrued = _getRewards(userBalance, newAssetIndex, userIndex, assetUnit);
     329                 :             : 
     330                 :        1903 :         rewardData.usersData[user].accrued += rewardsAccrued.toUint128();
     331                 :             :       }
     332                 :             :     }
     333                 :        2533 :     return (rewardsAccrued, dataUpdated);
     334                 :             :   }
     335                 :             : 
     336                 :             :   /**
     337                 :             :    * @dev Iterates and accrues all the rewards for asset of the specific user
     338                 :             :    * @param asset The address of the reference asset of the distribution
     339                 :             :    * @param user The user address
     340                 :             :    * @param userBalance The current user asset balance
     341                 :             :    * @param totalSupply Total supply of the asset
     342                 :             :    **/
     343                 :             :   function _updateData(
     344                 :             :     address asset,
     345                 :             :     address user,
     346                 :             :     uint256 userBalance,
     347                 :             :     uint256 totalSupply
     348                 :             :   ) internal {
     349                 :      141340 :     uint256 assetUnit;
     350                 :      141340 :     uint256 numAvailableRewards = _assets[asset].availableRewardsCount;
     351                 :             :     unchecked {
     352                 :      141340 :       assetUnit = 10 ** _assets[asset].decimals;
     353                 :             :     }
     354                 :             : 
     355                 :      141340 :     if (numAvailableRewards == 0) {
     356                 :      138807 :       return;
     357                 :             :     }
     358                 :             :     unchecked {
     359                 :        2533 :       for (uint128 r = 0; r < numAvailableRewards; r++) {
     360                 :        2533 :         address reward = _assets[asset].availableRewards[r];
     361                 :        2533 :         RewardsDataTypes.RewardData storage rewardData = _assets[asset].rewards[reward];
     362                 :             : 
     363                 :        2533 :         (uint256 newAssetIndex, bool rewardDataUpdated) = _updateRewardData(
     364                 :             :           rewardData,
     365                 :             :           totalSupply,
     366                 :             :           assetUnit
     367                 :             :         );
     368                 :             : 
     369                 :        2533 :         (uint256 rewardsAccrued, bool userDataUpdated) = _updateUserData(
     370                 :             :           rewardData,
     371                 :             :           user,
     372                 :             :           userBalance,
     373                 :             :           newAssetIndex,
     374                 :             :           assetUnit
     375                 :             :         );
     376                 :             : 
     377                 :        2533 :         if (rewardDataUpdated || userDataUpdated) {
     378                 :        1903 :           emit Accrued(asset, reward, user, newAssetIndex, newAssetIndex, rewardsAccrued);
     379                 :             :         }
     380                 :             :       }
     381                 :             :     }
     382                 :             :   }
     383                 :             : 
     384                 :             :   /**
     385                 :             :    * @dev Accrues all the rewards of the assets specified in the userAssetBalances list
     386                 :             :    * @param user The address of the user
     387                 :             :    * @param userAssetBalances List of structs with the user balance and total supply of a set of assets
     388                 :             :    **/
     389                 :             :   function _updateDataMultiple(
     390                 :             :     address user,
     391                 :             :     RewardsDataTypes.UserAssetBalance[] memory userAssetBalances
     392                 :             :   ) internal {
     393                 :        2525 :     for (uint256 i = 0; i < userAssetBalances.length; i++) {
     394                 :        2525 :       _updateData(
     395                 :             :         userAssetBalances[i].asset,
     396                 :             :         user,
     397                 :             :         userAssetBalances[i].userBalance,
     398                 :             :         userAssetBalances[i].totalSupply
     399                 :             :       );
     400                 :             :     }
     401                 :             :   }
     402                 :             : 
     403                 :             :   /**
     404                 :             :    * @dev Return the accrued unclaimed amount of a reward from a user over a list of distribution
     405                 :             :    * @param user The address of the user
     406                 :             :    * @param reward The address of the reward token
     407                 :             :    * @param userAssetBalances List of structs with the user balance and total supply of a set of assets
     408                 :             :    * @return unclaimedRewards The accrued rewards for the user until the moment
     409                 :             :    **/
     410                 :             :   function _getUserReward(
     411                 :             :     address user,
     412                 :             :     address reward,
     413                 :             :     RewardsDataTypes.UserAssetBalance[] memory userAssetBalances
     414                 :             :   ) internal view returns (uint256 unclaimedRewards) {
     415                 :             :     // Add unrealized rewards
     416                 :        1011 :     for (uint256 i = 0; i < userAssetBalances.length; i++) {
     417                 :        1011 :       if (userAssetBalances[i].userBalance == 0) {
     418                 :           3 :         unclaimedRewards += _assets[userAssetBalances[i].asset]
     419                 :             :           .rewards[reward]
     420                 :             :           .usersData[user]
     421                 :             :           .accrued;
     422                 :             :       } else {
     423                 :        1008 :         unclaimedRewards +=
     424                 :             :           _getPendingRewards(user, reward, userAssetBalances[i]) +
     425                 :             :           _assets[userAssetBalances[i].asset].rewards[reward].usersData[user].accrued;
     426                 :             :       }
     427                 :             :     }
     428                 :             : 
     429                 :           0 :     return unclaimedRewards;
     430                 :             :   }
     431                 :             : 
     432                 :             :   /**
     433                 :             :    * @dev Calculates the pending (not yet accrued) rewards since the last user action
     434                 :             :    * @param user The address of the user
     435                 :             :    * @param reward The address of the reward token
     436                 :             :    * @param userAssetBalance struct with the user balance and total supply of the incentivized asset
     437                 :             :    * @return The pending rewards for the user since the last user action
     438                 :             :    **/
     439                 :             :   function _getPendingRewards(
     440                 :             :     address user,
     441                 :             :     address reward,
     442                 :             :     RewardsDataTypes.UserAssetBalance memory userAssetBalance
     443                 :             :   ) internal view returns (uint256) {
     444                 :        1009 :     RewardsDataTypes.RewardData storage rewardData = _assets[userAssetBalance.asset].rewards[
     445                 :             :       reward
     446                 :             :     ];
     447                 :        1009 :     uint256 assetUnit = 10 ** _assets[userAssetBalance.asset].decimals;
     448                 :        1009 :     (, uint256 nextIndex) = _getAssetIndex(rewardData, userAssetBalance.totalSupply, assetUnit);
     449                 :             : 
     450                 :        1009 :     return
     451                 :        1009 :       _getRewards(
     452                 :             :         userAssetBalance.userBalance,
     453                 :             :         nextIndex,
     454                 :             :         rewardData.usersData[user].index,
     455                 :             :         assetUnit
     456                 :             :       );
     457                 :             :   }
     458                 :             : 
     459                 :             :   /**
     460                 :             :    * @dev Internal function for the calculation of user's rewards on a distribution
     461                 :             :    * @param userBalance Balance of the user asset on a distribution
     462                 :             :    * @param reserveIndex Current index of the distribution
     463                 :             :    * @param userIndex Index stored for the user, representation his staking moment
     464                 :             :    * @param assetUnit One unit of asset (10**decimals)
     465                 :             :    * @return The rewards
     466                 :             :    **/
     467                 :             :   function _getRewards(
     468                 :             :     uint256 userBalance,
     469                 :             :     uint256 reserveIndex,
     470                 :             :     uint256 userIndex,
     471                 :             :     uint256 assetUnit
     472                 :             :   ) internal pure returns (uint256) {
     473                 :        2912 :     uint256 result = userBalance * (reserveIndex - userIndex);
     474                 :             :     assembly {
     475                 :        2912 :       result := div(result, assetUnit)
     476                 :             :     }
     477                 :        2912 :     return result;
     478                 :             :   }
     479                 :             : 
     480                 :             :   /**
     481                 :             :    * @dev Calculates the next value of an specific distribution index, with validations
     482                 :             :    * @param rewardData Storage pointer to the distribution reward config
     483                 :             :    * @param totalSupply of the asset being rewarded
     484                 :             :    * @param assetUnit One unit of asset (10**decimals)
     485                 :             :    * @return The new index.
     486                 :             :    **/
     487                 :             :   function _getAssetIndex(
     488                 :             :     RewardsDataTypes.RewardData storage rewardData,
     489                 :             :     uint256 totalSupply,
     490                 :             :     uint256 assetUnit
     491                 :             :   ) internal view returns (uint256, uint256) {
     492                 :       50521 :     uint256 oldIndex = rewardData.index;
     493                 :       50521 :     uint256 distributionEnd = rewardData.distributionEnd;
     494                 :       50521 :     uint256 emissionPerSecond = rewardData.emissionPerSecond;
     495                 :       50521 :     uint256 lastUpdateTimestamp = rewardData.lastUpdateTimestamp;
     496                 :             : 
     497                 :             :     if (
     498                 :       50521 :       emissionPerSecond == 0 ||
     499                 :       40167 :       totalSupply == 0 ||
     500                 :       31462 :       lastUpdateTimestamp == block.timestamp ||
     501                 :       20033 :       lastUpdateTimestamp >= distributionEnd
     502                 :             :     ) {
     503                 :       31961 :       return (oldIndex, oldIndex);
     504                 :             :     }
     505                 :             : 
     506                 :       18560 :     uint256 currentTimestamp = block.timestamp > distributionEnd
     507                 :             :       ? distributionEnd
     508                 :             :       : block.timestamp;
     509                 :       18560 :     uint256 timeDelta = currentTimestamp - lastUpdateTimestamp;
     510                 :       18560 :     uint256 firstTerm = emissionPerSecond * timeDelta * assetUnit;
     511                 :             :     assembly {
     512                 :       18560 :       firstTerm := div(firstTerm, totalSupply)
     513                 :             :     }
     514                 :       18560 :     return (oldIndex, (firstTerm + oldIndex));
     515                 :             :   }
     516                 :             : 
     517                 :             :   /**
     518                 :             :    * @dev Get user balances and total supply of all the assets specified by the assets parameter
     519                 :             :    * @param assets List of assets to retrieve user balance and total supply
     520                 :             :    * @param user Address of the user
     521                 :             :    * @return userAssetBalances contains a list of structs with user balance and total supply of the given assets
     522                 :             :    */
     523                 :             :   function _getUserAssetBalances(
     524                 :             :     address[] calldata assets,
     525                 :             :     address user
     526                 :             :   ) internal view virtual returns (RewardsDataTypes.UserAssetBalance[] memory userAssetBalances);
     527                 :             : 
     528                 :             :   /// @inheritdoc IRewardsDistributor
     529                 :             :   function getAssetDecimals(address asset) external view returns (uint8) {
     530                 :           2 :     return _assets[asset].decimals;
     531                 :             :   }
     532                 :             : 
     533                 :             :   /// @inheritdoc IRewardsDistributor
     534                 :             :   function getEmissionManager() external view returns (address) {
     535                 :           5 :     return EMISSION_MANAGER;
     536                 :             :   }
     537                 :             : }
        

Generated by: LCOV version 2.1-1