StakedToken vs ERC20

Created Diff never expires
28 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
219 lines
11 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
202 lines
// SPDX-License-Identifier: agpl-3.0
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.7.5;
pragma solidity 0.7.5;
pragma experimental ABIEncoderV2;
pragma experimental ABIEncoderV2;


import {SafeERC20} from '@aave/aave-stake/contracts/lib/SafeERC20.sol';
import {SafeERC20} from '@aave/aave-stake/contracts/lib/SafeERC20.sol';
import {SafeMath} from '../lib/SafeMath.sol';
import {SafeMath} from '../lib/SafeMath.sol';
import {DistributionTypes} from '../lib/DistributionTypes.sol';
import {DistributionTypes} from '../lib/DistributionTypes.sol';
import {VersionedInitializable} from '@aave/aave-stake/contracts/utils/VersionedInitializable.sol';
import {VersionedInitializable} from '@aave/aave-stake/contracts/utils/VersionedInitializable.sol';
import {DistributionManager} from './DistributionManager.sol';
import {DistributionManager} from './DistributionManager.sol';
import {IStakedTokenWithConfig} from '../interfaces/IStakedTokenWithConfig.sol';
import {IERC20} from '@aave/aave-stake/contracts/interfaces/IERC20.sol';
import {IERC20} from '@aave/aave-stake/contracts/interfaces/IERC20.sol';
import {IScaledBalanceToken} from '../interfaces/IScaledBalanceToken.sol';
import {IScaledBalanceToken} from '../interfaces/IScaledBalanceToken.sol';
import {IAaveIncentivesController} from '../interfaces/IAaveIncentivesController.sol';
import {IAaveIncentivesController} from '../interfaces/IAaveIncentivesController.sol';


/**
/**
* @title StakedTokenIncentivesController
* @title ERC20TokenIncentivesController
* @notice Distributor contract for rewards to the Aave protocol, using a staked token as rewards asset.
* @notice Distributor contract for rewards to the Aave protocol, using a regular ERC20 token as rewards asset.
* The contract stakes the rewards before redistributing them to the Aave protocol participants.
* @author Aave, Joey Santoro
* The reference staked token implementation is at https://github.com/aave/aave-stake-v2
* @author Aave
**/
**/
contract StakedTokenIncentivesController is
contract ERC20TokenIncentivesController is
IAaveIncentivesController,
IAaveIncentivesController,
VersionedInitializable,
VersionedInitializable,
DistributionManager
DistributionManager
{
{
using SafeMath for uint256;
using SafeMath for uint256;
using SafeERC20 for IERC20;
using SafeERC20 for IERC20;


uint256 public constant REVISION = 1;
uint256 public constant REVISION = 1;


IStakedTokenWithConfig public immutable STAKE_TOKEN;
/// @inheritdoc IAaveIncentivesController
address public immutable override REWARD_TOKEN;


mapping(address => uint256) internal _usersUnclaimedRewards;
mapping(address => uint256) internal _usersUnclaimedRewards;


// this mapping allows whitelisted addresses to claim on behalf of others
// this mapping allows whitelisted addresses to claim on behalf of others
// useful for contracts that hold tokens to be rewarded but don't have any native logic to claim Liquidity Mining rewards
// useful for contracts that hold tokens to be rewarded but don't have any native logic to claim Liquidity Mining rewards
mapping(address => address) internal _authorizedClaimers;
mapping(address => address) internal _authorizedClaimers;


modifier onlyAuthorizedClaimers(address claimer, address user) {
modifier onlyAuthorizedClaimers(address claimer, address user) {
require(_authorizedClaimers[user] == claimer, 'CLAIMER_UNAUTHORIZED');
require(_authorizedClaimers[user] == claimer, 'CLAIMER_UNAUTHORIZED');
_;
_;
}
}


constructor(IStakedTokenWithConfig stakeToken, address emissionManager)
constructor(address rewardToken, address emissionManager)
DistributionManager(emissionManager)
DistributionManager(emissionManager)
{
{
STAKE_TOKEN = stakeToken;
REWARD_TOKEN = rewardToken;
}

/**
* @dev Initialize IStakedTokenIncentivesController
* @param addressesProvider the address of the corresponding addresses provider
**/
function initialize(address addressesProvider) external initializer {
//approves the safety module to allow staking
IERC20(STAKE_TOKEN.STAKED_TOKEN()).safeApprove(address(STAKE_TOKEN), type(uint256).max);
}
}


/// @inheritdoc IAaveIncentivesController
/// @inheritdoc IAaveIncentivesController
function configureAssets(address[] calldata assets, uint256[] calldata emissionsPerSecond)
function configureAssets(address[] calldata assets, uint256[] calldata emissionsPerSecond)
external
external
override
override
onlyEmissionManager
onlyEmissionManager
{
{
require(assets.length == emissionsPerSecond.length, 'INVALID_CONFIGURATION');
require(assets.length == emissionsPerSecond.length, 'INVALID_CONFIGURATION');


DistributionTypes.AssetConfigInput[] memory assetsConfig =
DistributionTypes.AssetConfigInput[] memory assetsConfig =
new DistributionTypes.AssetConfigInput[](assets.length);
new DistributionTypes.AssetConfigInput[](assets.length);


for (uint256 i = 0; i < assets.length; i++) {
for (uint256 i = 0; i < assets.length; i++) {
assetsConfig[i].underlyingAsset = assets[i];
assetsConfig[i].underlyingAsset = assets[i];
assetsConfig[i].emissionPerSecond = uint104(emissionsPerSecond[i]);
assetsConfig[i].emissionPerSecond = uint104(emissionsPerSecond[i]);


require(assetsConfig[i].emissionPerSecond == emissionsPerSecond[i], 'INVALID_CONFIGURATION');
require(assetsConfig[i].emissionPerSecond == emissionsPerSecond[i], 'INVALID_CONFIGURATION');


assetsConfig[i].totalStaked = IScaledBalanceToken(assets[i]).scaledTotalSupply();
assetsConfig[i].totalStaked = IScaledBalanceToken(assets[i]).scaledTotalSupply();
}
}
_configureAssets(assetsConfig);
_configureAssets(assetsConfig);
}
}


/// @inheritdoc IAaveIncentivesController
/// @inheritdoc IAaveIncentivesController
function handleAction(
function handleAction(
address user,
address user,
uint256 totalSupply,
uint256 totalSupply,
uint256 userBalance
uint256 userBalance
) external override {
) external override {
uint256 accruedRewards = _updateUserAssetInternal(user, msg.sender, userBalance, totalSupply);
uint256 accruedRewards = _updateUserAssetInternal(user, msg.sender, userBalance, totalSupply);
if (accruedRewards != 0) {
if (accruedRewards != 0) {
_usersUnclaimedRewards[user] = _usersUnclaimedRewards[user].add(accruedRewards);
_usersUnclaimedRewards[user] = _usersUnclaimedRewards[user].add(accruedRewards);
emit RewardsAccrued(user, accruedRewards);
emit RewardsAccrued(user, accruedRewards);
}
}
}
}


/// @inheritdoc IAaveIncentivesController
/// @inheritdoc IAaveIncentivesController
function getRewardsBalance(address[] calldata assets, address user)
function getRewardsBalance(address[] calldata assets, address user)
external
external
view
view
override
override
returns (uint256)
returns (uint256)
{
{
uint256 unclaimedRewards = _usersUnclaimedRewards[user];
uint256 unclaimedRewards = _usersUnclaimedRewards[user];


DistributionTypes.UserStakeInput[] memory userState =
DistributionTypes.UserStakeInput[] memory userState =
new DistributionTypes.UserStakeInput[](assets.length);
new DistributionTypes.UserStakeInput[](assets.length);
for (uint256 i = 0; i < assets.length; i++) {
for (uint256 i = 0; i < assets.length; i++) {
userState[i].underlyingAsset = assets[i];
userState[i].underlyingAsset = assets[i];
(userState[i].stakedByUser, userState[i].totalStaked) = IScaledBalanceToken(assets[i])
(userState[i].stakedByUser, userState[i].totalStaked) = IScaledBalanceToken(assets[i])
.getScaledUserBalanceAndSupply(user);
.getScaledUserBalanceAndSupply(user);
}
}
unclaimedRewards = unclaimedRewards.add(_getUnclaimedRewards(user, userState));
unclaimedRewards = unclaimedRewards.add(_getUnclaimedRewards(user, userState));
return unclaimedRewards;
return unclaimedRewards;
}
}


/// @inheritdoc IAaveIncentivesController
/// @inheritdoc IAaveIncentivesController
function claimRewards(
function claimRewards(
address[] calldata assets,
address[] calldata assets,
uint256 amount,
uint256 amount,
address to
address to
) external override returns (uint256) {
) external override returns (uint256) {
require(to != address(0), 'INVALID_TO_ADDRESS');
require(to != address(0), 'INVALID_TO_ADDRESS');
return _claimRewards(assets, amount, msg.sender, msg.sender, to);
return _claimRewards(assets, amount, msg.sender, msg.sender, to);
}
}


/// @inheritdoc IAaveIncentivesController
/// @inheritdoc IAaveIncentivesController
function claimRewardsOnBehalf(
function claimRewardsOnBehalf(
address[] calldata assets,
address[] calldata assets,
uint256 amount,
uint256 amount,
address user,
address user,
address to
address to
) external override onlyAuthorizedClaimers(msg.sender, user) returns (uint256) {
) external override onlyAuthorizedClaimers(msg.sender, user) returns (uint256) {
require(user != address(0), 'INVALID_USER_ADDRESS');
require(user != address(0), 'INVALID_USER_ADDRESS');
require(to != address(0), 'INVALID_TO_ADDRESS');
require(to != address(0), 'INVALID_TO_ADDRESS');
return _claimRewards(assets, amount, msg.sender, user, to);
return _claimRewards(assets, amount, msg.sender, user, to);
}
}


/**
/**
* @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards.
* @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards.
* @param amount Amount of rewards to claim
* @param amount Amount of rewards to claim
* @param user Address to check and claim rewards
* @param user Address to check and claim rewards
* @param to Address that will be receiving the rewards
* @param to Address that will be receiving the rewards
* @return Rewards claimed
* @return Rewards claimed
**/
**/


/// @inheritdoc IAaveIncentivesController
/// @inheritdoc IAaveIncentivesController
function setClaimer(address user, address caller) external override onlyEmissionManager {
function setClaimer(address user, address caller) external override onlyEmissionManager {
_authorizedClaimers[user] = caller;
_authorizedClaimers[user] = caller;
emit ClaimerSet(user, caller);
emit ClaimerSet(user, caller);
}
}


/// @inheritdoc IAaveIncentivesController
/// @inheritdoc IAaveIncentivesController
function getClaimer(address user) external view override returns (address) {
function getClaimer(address user) external view override returns (address) {
return _authorizedClaimers[user];
return _authorizedClaimers[user];
}
}


/// @inheritdoc IAaveIncentivesController
/// @inheritdoc IAaveIncentivesController
function getUserUnclaimedRewards(address _user) external view override returns (uint256) {
function getUserUnclaimedRewards(address _user) external view override returns (uint256) {
return _usersUnclaimedRewards[_user];
return _usersUnclaimedRewards[_user];
}
}


/// @inheritdoc IAaveIncentivesController
function REWARD_TOKEN() external view override returns (address) {
return address(STAKE_TOKEN);
}

/**
/**
* @dev returns the revision of the implementation contract
* @dev returns the revision of the implementation contract
*/
*/
function getRevision() internal pure override returns (uint256) {
function getRevision() internal pure override returns (uint256) {
return REVISION;
return REVISION;
}
}


/**
/**
* @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards.
* @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards.
* @param amount Amount of rewards to claim
* @param amount Amount of rewards to claim
* @param user Address to check and claim rewards
* @param user Address to check and claim rewards
* @param to Address that will be receiving the rewards
* @param to Address that will be receiving the rewards
* @return Rewards claimed
* @return Rewards claimed
**/
**/
function _claimRewards(
function _claimRewards(
address[] calldata assets,
address[] calldata assets,
uint256 amount,
uint256 amount,
address claimer,
address claimer,
address user,
address user,
address to
address to
) internal returns (uint256) {
) internal returns (uint256) {
if (amount == 0) {
if (amount == 0) {
return 0;
return 0;
}
}
uint256 unclaimedRewards = _usersUnclaimedRewards[user];
uint256 unclaimedRewards = _usersUnclaimedRewards[user];


DistributionTypes.UserStakeInput[] memory userState =
DistributionTypes.UserStakeInput[] memory userState =
new DistributionTypes.UserStakeInput[](assets.length);
new DistributionTypes.UserStakeInput[](assets.length);
for (uint256 i = 0; i < assets.length; i++) {
for (uint256 i = 0; i < assets.length; i++) {
userState[i].underlyingAsset = assets[i];
userState[i].underlyingAsset = assets[i];
(userState[i].stakedByUser, userState[i].totalStaked) = IScaledBalanceToken(assets[i])
(userState[i].stakedByUser, userState[i].totalStaked) = IScaledBalanceToken(assets[i])
.getScaledUserBalanceAndSupply(user);
.getScaledUserBalanceAndSupply(user);
}
}


uint256 accruedRewards = _claimRewards(user, userState);
uint256 accruedRewards = _claimRewards(user, userState);
if (accruedRewards != 0) {
if (accruedRewards != 0) {
unclaimedRewards = unclaimedRewards.add(accruedRewards);
unclaimedRewards = unclaimedRewards.add(accruedRewards);
emit RewardsAccrued(user, accruedRewards);
emit RewardsAccrued(user, accruedRewards);
}
}


if (unclaimedRewards == 0) {
if (unclaimedRewards == 0) {
return 0;
return 0;
}
}


uint256 amountToClaim = amount > unclaimedRewards ? unclaimedRewards : amount;
uint256 amountToClaim = amount > unclaimedRewards ? unclaimedRewards : amount;
_usersUnclaimedRewards[user] = unclaimedRewards - amountToClaim; // Safe due to the previous line
_usersUnclaimedRewards[user] = unclaimedRewards - amountToClaim; // Safe due to the previous line


STAKE_TOKEN.stake(to, amountToClaim);
IERC20(REWARD_TOKEN).transfer(to, amountToClaim);
emit RewardsClaimed(user, to, claimer, amountToClaim);
emit RewardsClaimed(user, to, claimer, amountToClaim);


return amountToClaim;
return amountToClaim;
}
}
}
}