Skip to content

Commit

Permalink
Merge pull request #39 from aave/fix/38-low-decimal-tokens
Browse files Browse the repository at this point in the history
Fix/38 low decimal tokens
  • Loading branch information
kartojal authored Dec 27, 2021
2 parents e65f365 + 8c67472 commit e61b3ca
Show file tree
Hide file tree
Showing 16 changed files with 770 additions and 307 deletions.
61 changes: 45 additions & 16 deletions contracts/incentives-v2/DistributionManagerV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pragma solidity 0.8.10;

import {IAaveDistributionManagerV2} from './interfaces/IAaveDistributionManagerV2.sol';
import {DistributionTypesV2} from './libraries/DistributionTypesV2.sol';
import {IERC20Detailed} from '@aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol';

/**
* @title DistributionManagerV2
Expand All @@ -20,13 +21,12 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
struct AssetData {
mapping(address => RewardData) rewards;
address[] availableRewards;
uint8 decimals;
}

// manager of incentives
address public immutable EMISSION_MANAGER;

uint8 public constant PRECISION = 18;

// asset => AssetData
mapping(address => AssetData) internal _assets;

Expand Down Expand Up @@ -148,6 +148,8 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
**/
function _configureAssets(DistributionTypesV2.RewardsConfigInput[] memory rewardsInput) internal {
for (uint256 i = 0; i < rewardsInput.length; i++) {
_assets[rewardsInput[i].asset].decimals = IERC20Detailed(rewardsInput[i].asset).decimals();

RewardData storage rewardConfig = _assets[rewardsInput[i].asset].rewards[
rewardsInput[i].reward
];
Expand All @@ -168,7 +170,8 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
rewardsInput[i].asset,
rewardsInput[i].reward,
rewardConfig,
rewardsInput[i].totalSupply
rewardsInput[i].totalSupply,
_assets[rewardsInput[i].asset].decimals
);

// Configure emission and distribution end of the reward per asset
Expand All @@ -189,14 +192,16 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
* @param asset The address of the asset being updated
* @param reward The address of the reward being updated
* @param rewardConfig Storage pointer to the distribution's reward config
* @param totalSupply Current total of staked _assets for this distribution
* @param totalSupply Current total of underlying assets for this distribution
* @param decimals The decimals of the underlying asset
* @return The new distribution index
**/
function _updateAssetStateInternal(
address asset,
address reward,
RewardData storage rewardConfig,
uint256 totalSupply
uint256 totalSupply,
uint8 decimals
) internal returns (uint256) {
uint256 oldIndex = rewardConfig.index;

Expand All @@ -209,7 +214,8 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
rewardConfig.emissionPerSecond,
rewardConfig.lastUpdateTimestamp,
rewardConfig.distributionEnd,
totalSupply
totalSupply,
decimals
);

if (newIndex != oldIndex) {
Expand Down Expand Up @@ -245,11 +251,17 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
uint256 userIndex = rewardData.usersIndex[user];
uint256 accruedRewards = 0;

uint256 newIndex = _updateAssetStateInternal(asset, reward, rewardData, totalSupply);
uint256 newIndex = _updateAssetStateInternal(
asset,
reward,
rewardData,
totalSupply,
_assets[asset].decimals
);

if (userIndex != newIndex) {
if (userBalance != 0) {
accruedRewards = _getRewards(userBalance, newIndex, userIndex);
accruedRewards = _getRewards(userBalance, newIndex, userIndex, _assets[asset].decimals);
}

rewardData.usersIndex[user] = newIndex;
Expand All @@ -259,6 +271,13 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
return accruedRewards;
}

/**
* @dev Iterates and updates all rewards of an asset that belongs to an user
* @param asset The address of the reference asset of the distribution
* @param user The user address
* @param userBalance The current user asset balance
* @param totalSupply Total supply of the asset
**/
function _updateUserRewardsPerAssetInternal(
address asset,
address user,
Expand Down Expand Up @@ -370,31 +389,34 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
DistributionTypesV2.UserAssetStatsInput memory stake
) internal view returns (uint256) {
RewardData storage rewardData = _assets[stake.underlyingAsset].rewards[reward];

uint8 assetDecimals = _assets[stake.underlyingAsset].decimals;
uint256 assetIndex = _getAssetIndex(
rewardData.index,
rewardData.emissionPerSecond,
rewardData.lastUpdateTimestamp,
rewardData.distributionEnd,
stake.totalSupply
stake.totalSupply,
assetDecimals
);

return _getRewards(stake.userBalance, assetIndex, rewardData.usersIndex[user]);
return _getRewards(stake.userBalance, assetIndex, rewardData.usersIndex[user], assetDecimals);
}

/**
* @dev Internal function for the calculation of user's rewards on a distribution
* @param principalUserBalance Amount staked by the user on a distribution
* @param principalUserBalance Balance of the user asset on a distribution
* @param reserveIndex Current index of the distribution
* @param userIndex Index stored for the user, representation his staking moment
* @param decimals The decimals of the underlying asset
* @return The rewards
**/
function _getRewards(
uint256 principalUserBalance,
uint256 reserveIndex,
uint256 userIndex
uint256 userIndex,
uint8 decimals
) internal pure returns (uint256) {
return (principalUserBalance * (reserveIndex - userIndex)) / 10**uint256(PRECISION);
return (principalUserBalance * (reserveIndex - userIndex)) / 10**decimals;
}

/**
Expand All @@ -403,14 +425,16 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
* @param emissionPerSecond Representing the total rewards distributed per second per asset unit, on the distribution
* @param lastUpdateTimestamp Last moment this distribution was updated
* @param totalBalance of tokens considered for the distribution
* @param decimals The decimals of the underlying asset
* @return The new index.
**/
function _getAssetIndex(
uint256 currentIndex,
uint256 emissionPerSecond,
uint128 lastUpdateTimestamp,
uint256 distributionEnd,
uint256 totalBalance
uint256 totalBalance,
uint8 decimals
) internal view returns (uint256) {
if (
emissionPerSecond == 0 ||
Expand All @@ -425,7 +449,7 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
? distributionEnd
: block.timestamp;
uint256 timeDelta = currentTimestamp - lastUpdateTimestamp;
return (emissionPerSecond * timeDelta * (10**uint256(PRECISION))) / totalBalance + currentIndex;
return (emissionPerSecond * timeDelta * (10**decimals)) / totalBalance + currentIndex;
}

/**
Expand All @@ -439,4 +463,9 @@ abstract contract DistributionManagerV2 is IAaveDistributionManagerV2 {
view
virtual
returns (DistributionTypesV2.UserAssetStatsInput[] memory userState);

/// @inheritdoc IAaveDistributionManagerV2
function getAssetDecimals(address asset) external view returns (uint8) {
return _assets[asset].decimals;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,9 @@ interface IAaveDistributionManagerV2 {
returns (address[] memory, uint256[] memory);

/**
* @dev Returns the precision to calculate the distribution delta
* @return The precision of the calculation
* @dev Returns the decimals of an asset to calculate the distribution delta
* @param asset The address to retrieve decimals saved at storage
* @return The decimals of an underlying asset
*/
function PRECISION() external view returns (uint8);
function getAssetDecimals(address asset) external view returns (uint8);
}
Loading

0 comments on commit e61b3ca

Please sign in to comment.