Blockchain / Global / Address

Contract

0x839934166b2ECd942bE97Da7f4DF051530eD0601

Balance
0 SOMI
Transactions sent
1
Type
Contract · 18,627 bytes of code

RewardsController Verified

Compiler
solc 0.8.20+commit.a1b79de6
Language
Solidity
Optimization
Yes, 100000 runs
EVM version
paris
License
—
Verified
2026-10-12

@aave/periphery-v3/contracts/rewards/RewardsController.sol

and 11 more files

Solidity
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.10;

import {VersionedInitializable} from '@aave/core-v3/contracts/protocol/libraries/aave-upgradeability/VersionedInitializable.sol';
import {SafeCast} from '@aave/core-v3/contracts/dependencies/openzeppelin/contracts/SafeCast.sol';
import {IScaledBalanceToken} from '@aave/core-v3/contracts/interfaces/IScaledBalanceToken.sol';
import {RewardsDistributor} from './RewardsDistributor.sol';
import {IRewardsController} from './interfaces/IRewardsController.sol';
import {ITransferStrategyBase} from './interfaces/ITransferStrategyBase.sol';
import {RewardsDataTypes} from './libraries/RewardsDataTypes.sol';
import {IEACAggregatorProxy} from '../misc/interfaces/IEACAggregatorProxy.sol';

/**
 * @title RewardsController
 * @notice Abstract contract template to build Distributors contracts for ERC20 rewards to protocol participants
 * @author Aave
 **/
contract RewardsController is RewardsDistributor, VersionedInitializable, IRewardsController {
  using SafeCast for uint256;

  uint256 public constant REVISION = 1;

  // 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
  mapping(address => address) internal _authorizedClaimers;

  // reward => transfer strategy implementation contract
  // The TransferStrategy contract abstracts the logic regarding
  // the source of the reward and how to transfer it to the user.
  mapping(address => ITransferStrategyBase) internal _transferStrategy;

  // This mapping contains the price oracle per reward.
  // A price oracle is enforced for integrators to be able to show incentives at
  // the current Aave UI without the need to setup an external price registry
  // At the moment of reward configuration, the Incentives Controller performs
  // a check to see if the provided reward oracle contains `latestAnswer`.
  mapping(address => IEACAggregatorProxy) internal _rewardOracle;

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

  constructor(address emissionManager) RewardsDistributor(emissionManager) {}

  /**
   * @dev Initialize for RewardsController
   * @dev It expects an address as argument since its initialized via PoolAddressesProvider._updateImpl()
   **/
  function initialize(address) external initializer {}

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

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

  /// @inheritdoc IRewardsController
  function getRewardOracle(address reward) external view override returns (address) {
    return address(_rewardOracle[reward]);
  }

  /// @inheritdoc IRewardsController
  function getTransferStrategy(address reward) external view override returns (address) {
    return address(_transferStrategy[reward]);
  }

  /// @inheritdoc IRewardsController
  function configureAssets(
    RewardsDataTypes.RewardsConfigInput[] memory config
  ) external override onlyEmissionManager {
    for (uint256 i = 0; i < config.length; i++) {
      // Get the current Scaled Total Supply of AToken or Debt token
      config[i].totalSupply = IScaledBalanceToken(config[i].asset).scaledTotalSupply();

      // Install TransferStrategy logic at IncentivesController
      _installTransferStrategy(config[i].reward, config[i].transferStrategy);

      // Set reward oracle, enforces input oracle to have latestPrice function
      _setRewardOracle(config[i].reward, config[i].rewardOracle);
    }
    _configureAssets(config);
  }

  /// @inheritdoc IRewardsController
  function setTransferStrategy(
    address reward,
    ITransferStrategyBase transferStrategy
  ) external onlyEmissionManager {
    _installTransferStrategy(reward, transferStrategy);
  }

  /// @inheritdoc IRewardsController
  function setRewardOracle(
    address reward,
    IEACAggregatorProxy rewardOracle
  ) external onlyEmissionManager {
    _setRewardOracle(reward, rewardOracle);
  }

  /// @inheritdoc IRewardsController
  function handleAction(address user, uint256 totalSupply, uint256 userBalance) external override {
    _updateData(msg.sender, user, userBalance, totalSupply);
  }

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

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

  /// @inheritdoc IRewardsController
  function claimRewardsToSelf(
    address[] calldata assets,
    uint256 amount,
    address reward
  ) external override returns (uint256) {
    return _claimRewards(assets, amount, msg.sender, msg.sender, msg.sender, reward);
  }

  /// @inheritdoc IRewardsController
  function claimAllRewards(
    address[] calldata assets,
    address to
  ) external override returns (address[] memory rewardsList, uint256[] memory claimedAmounts) {
    require(to != address(0), 'INVALID_TO_ADDRESS');
    return _claimAllRewards(assets, msg.sender, msg.sender, to);
  }

  /// @inheritdoc IRewardsController
  function claimAllRewardsOnBehalf(
    address[] calldata assets,
    address user,
    address to
  )
    external
    override
    onlyAuthorizedClaimers(msg.sender, user)
    returns (address[] memory rewardsList, uint256[] memory claimedAmounts)
  {
    require(user != address(0), 'INVALID_USER_ADDRESS');
    require(to != address(0), 'INVALID_TO_ADDRESS');
    return _claimAllRewards(assets, msg.sender, user, to);
  }

  /// @inheritdoc IRewardsController
  function claimAllRewardsToSelf(
    address[] calldata assets
  ) external override returns (address[] memory rewardsList, uint256[] memory claimedAmounts) {
    return _claimAllRewards(assets, msg.sender, msg.sender, msg.sender);
  }

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

  /**
   * @dev Get user balances and total supply of all the assets specified by the assets parameter
   * @param assets List of assets to retrieve user balance and total supply
   * @param user Address of the user
   * @return userAssetBalances contains a list of structs with user balance and total supply of the given assets
   */
  function _getUserAssetBalances(
    address[] calldata assets,
    address user
  ) internal view override returns (RewardsDataTypes.UserAssetBalance[] memory userAssetBalances) {
    userAssetBalances = new RewardsDataTypes.UserAssetBalance[](assets.length);
    for (uint256 i = 0; i < assets.length; i++) {
      userAssetBalances[i].asset = assets[i];
      (userAssetBalances[i].userBalance, userAssetBalances[i].totalSupply) = IScaledBalanceToken(
        assets[i]
      ).getScaledUserBalanceAndSupply(user);
    }
    return userAssetBalances;
  }

  /**
   * @dev Claims one type of reward for a user on behalf, on all the assets of the pool, accumulating the pending rewards.
   * @param assets List of assets to check eligible distributions before claiming rewards
   * @param amount Amount of rewards to claim
   * @param claimer Address of the claimer who claims rewards on behalf of user
   * @param user Address to check and claim rewards
   * @param to Address that will be receiving the rewards
   * @param reward Address of the reward token
   * @return Rewards claimed
   **/
  function _claimRewards(
    address[] calldata assets,
    uint256 amount,
    address claimer,
    address user,
    address to,
    address reward
  ) internal returns (uint256) {
    if (amount == 0) {
      return 0;
    }
    uint256 totalRewards;

    _updateDataMultiple(user, _getUserAssetBalances(assets, user));
    for (uint256 i = 0; i < assets.length; i++) {
      address asset = assets[i];
      totalRewards += _assets[asset].rewards[reward].usersData[user].accrued;

      if (totalRewards <= amount) {
        _assets[asset].rewards[reward].usersData[user].accrued = 0;
      } else {
        uint256 difference = totalRewards - amount;
        totalRewards -= difference;
        _assets[asset].rewards[reward].usersData[user].accrued = difference.toUint128();
        break;
      }
    }

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

    _transferRewards(to, reward, totalRewards);
    emit RewardsClaimed(user, reward, to, claimer, totalRewards);

    return totalRewards;
  }

  /**
   * @dev Claims one type of reward for a user on behalf, on all the assets of the pool, accumulating the pending rewards.
   * @param assets List of assets to check eligible distributions before claiming rewards
   * @param claimer Address of the claimer on behalf of user
   * @param user Address to check and claim rewards
   * @param to Address that will be receiving the rewards
   * @return
   *   rewardsList List of reward addresses
   *   claimedAmount List of claimed amounts, follows "rewardsList" items order
   **/
  function _claimAllRewards(
    address[] calldata assets,
    address claimer,
    address user,
    address to
  ) internal returns (address[] memory rewardsList, uint256[] memory claimedAmounts) {
    uint256 rewardsListLength = _rewardsList.length;
    rewardsList = new address[](rewardsListLength);
    claimedAmounts = new uint256[](rewardsListLength);

    _updateDataMultiple(user, _getUserAssetBalances(assets, user));

    for (uint256 i = 0; i < assets.length; i++) {
      address asset = assets[i];
      for (uint256 j = 0; j < rewardsListLength; j++) {
        if (rewardsList[j] == address(0)) {
          rewardsList[j] = _rewardsList[j];
        }
        uint256 rewardAmount = _assets[asset].rewards[rewardsList[j]].usersData[user].accrued;
        if (rewardAmount != 0) {
          claimedAmounts[j] += rewardAmount;
          _assets[asset].rewards[rewardsList[j]].usersData[user].accrued = 0;
        }
      }
    }
    for (uint256 i = 0; i < rewardsListLength; i++) {
      _transferRewards(to, rewardsList[i], claimedAmounts[i]);
      emit RewardsClaimed(user, rewardsList[i], to, claimer, claimedAmounts[i]);
    }
    return (rewardsList, claimedAmounts);
  }

  /**
   * @dev Function to transfer rewards to the desired account using delegatecall and
   * @param to Account address to send the rewards
   * @param reward Address of the reward token
   * @param amount Amount of rewards to transfer
   */
  function _transferRewards(address to, address reward, uint256 amount) internal {
    ITransferStrategyBase transferStrategy = _transferStrategy[reward];

    bool success = transferStrategy.performTransfer(to, reward, amount);

    require(success == true, 'TRANSFER_ERROR');
  }

  /**
   * @dev Returns true if `account` is a contract.
   * @param account The address of the account
   * @return bool, true if contract, false otherwise
   */
  function _isContract(address account) internal view returns (bool) {
    // This method relies on extcodesize, which returns 0 for contracts in
    // construction, since the code is only stored at the end of the
    // constructor execution.

    uint256 size;
    // solhint-disable-next-line no-inline-assembly
    assembly {
      size := extcodesize(account)
    }
    return size > 0;
  }

  /**
   * @dev Internal function to call the optional install hook at the TransferStrategy
   * @param reward The address of the reward token
   * @param transferStrategy The address of the reward TransferStrategy
   */
  function _installTransferStrategy(
    address reward,
    ITransferStrategyBase transferStrategy
  ) internal {
    require(address(transferStrategy) != address(0), 'STRATEGY_CAN_NOT_BE_ZERO');
    require(_isContract(address(transferStrategy)) == true, 'STRATEGY_MUST_BE_CONTRACT');

    _transferStrategy[reward] = transferStrategy;

    emit TransferStrategyInstalled(reward, address(transferStrategy));
  }

  /**
   * @dev Update the Price Oracle of a reward token. The Price Oracle must follow Chainlink IEACAggregatorProxy interface.
   * @notice The Price Oracle of a reward is used for displaying correct data about the incentives at the UI frontend.
   * @param reward The address of the reward token
   * @param rewardOracle The address of the price oracle
   */

  function _setRewardOracle(address reward, IEACAggregatorProxy rewardOracle) internal {
    require(rewardOracle.latestAnswer() > 0, 'ORACLE_MUST_RETURN_PRICE');
    _rewardOracle[reward] = rewardOracle;
    emit RewardOracleUpdated(reward, address(rewardOracle));
  }
}

Other files

  • @aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20.sol
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity ^0.8.0;
    
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
      /**
       * @dev Returns the amount of tokens in existence.
       */
      function totalSupply() external view returns (uint256);
    
      /**
       * @dev Returns the amount of tokens owned by `account`.
       */
      function balanceOf(address account) external view returns (uint256);
    
      /**
       * @dev Moves `amount` tokens from the caller's account to `recipient`.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * Emits a {Transfer} event.
       */
      function transfer(address recipient, uint256 amount) external returns (bool);
    
      /**
       * @dev Returns the remaining number of tokens that `spender` will be
       * allowed to spend on behalf of `owner` through {transferFrom}. This is
       * zero by default.
       *
       * This value changes when {approve} or {transferFrom} are called.
       */
      function allowance(address owner, address spender) external view returns (uint256);
    
      /**
       * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * IMPORTANT: Beware that changing an allowance with this method brings the risk
       * that someone may use both the old and the new allowance by unfortunate
       * transaction ordering. One possible solution to mitigate this race
       * condition is to first reduce the spender's allowance to 0 and set the
       * desired value afterwards:
       * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
       *
       * Emits an {Approval} event.
       */
      function approve(address spender, uint256 amount) external returns (bool);
    
      /**
       * @dev Moves `amount` tokens from `sender` to `recipient` using the
       * allowance mechanism. `amount` is then deducted from the caller's
       * allowance.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * Emits a {Transfer} event.
       */
      function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
      /**
       * @dev Emitted when `value` tokens are moved from one account (`from`) to
       * another (`to`).
       *
       * Note that `value` may be zero.
       */
      event Transfer(address indexed from, address indexed to, uint256 value);
    
      /**
       * @dev Emitted when the allowance of a `spender` for an `owner` is set by
       * a call to {approve}. `value` is the new allowance.
       */
      event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
  • @aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity ^0.8.0;
    
    import {IERC20} from './IERC20.sol';
    
    interface IERC20Detailed is IERC20 {
      function name() external view returns (string memory);
    
      function symbol() external view returns (string memory);
    
      function decimals() external view returns (uint8);
    }
    
  • @aave/core-v3/contracts/dependencies/openzeppelin/contracts/SafeCast.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)
    pragma solidity ^0.8.0;
    
    /**
     * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
     * checks.
     *
     * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
     * easily result in undesired exploitation or bugs, since developers usually
     * assume that overflows raise errors. `SafeCast` restores this intuition by
     * reverting the transaction when such an operation overflows.
     *
     * Using this library instead of the unchecked operations eliminates an entire
     * class of bugs, so it's recommended to use it always.
     *
     * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
     * all math on `uint256` and `int256` and then downcasting.
     */
    library SafeCast {
      /**
       * @dev Returns the downcasted uint224 from uint256, reverting on
       * overflow (when the input is greater than largest uint224).
       *
       * Counterpart to Solidity's `uint224` operator.
       *
       * Requirements:
       *
       * - input must fit into 224 bits
       */
      function toUint224(uint256 value) internal pure returns (uint224) {
        require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
        return uint224(value);
      }
    
      /**
       * @dev Returns the downcasted uint128 from uint256, reverting on
       * overflow (when the input is greater than largest uint128).
       *
       * Counterpart to Solidity's `uint128` operator.
       *
       * Requirements:
       *
       * - input must fit into 128 bits
       */
      function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
      }
    
      /**
       * @dev Returns the downcasted uint96 from uint256, reverting on
       * overflow (when the input is greater than largest uint96).
       *
       * Counterpart to Solidity's `uint96` operator.
       *
       * Requirements:
       *
       * - input must fit into 96 bits
       */
      function toUint96(uint256 value) internal pure returns (uint96) {
        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
        return uint96(value);
      }
    
      /**
       * @dev Returns the downcasted uint64 from uint256, reverting on
       * overflow (when the input is greater than largest uint64).
       *
       * Counterpart to Solidity's `uint64` operator.
       *
       * Requirements:
       *
       * - input must fit into 64 bits
       */
      function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
      }
    
      /**
       * @dev Returns the downcasted uint32 from uint256, reverting on
       * overflow (when the input is greater than largest uint32).
       *
       * Counterpart to Solidity's `uint32` operator.
       *
       * Requirements:
       *
       * - input must fit into 32 bits
       */
      function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
      }
    
      /**
       * @dev Returns the downcasted uint16 from uint256, reverting on
       * overflow (when the input is greater than largest uint16).
       *
       * Counterpart to Solidity's `uint16` operator.
       *
       * Requirements:
       *
       * - input must fit into 16 bits
       */
      function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
      }
    
      /**
       * @dev Returns the downcasted uint8 from uint256, reverting on
       * overflow (when the input is greater than largest uint8).
       *
       * Counterpart to Solidity's `uint8` operator.
       *
       * Requirements:
       *
       * - input must fit into 8 bits.
       */
      function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
      }
    
      /**
       * @dev Converts a signed int256 into an unsigned uint256.
       *
       * Requirements:
       *
       * - input must be greater than or equal to 0.
       */
      function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, 'SafeCast: value must be positive');
        return uint256(value);
      }
    
      /**
       * @dev Returns the downcasted int128 from int256, reverting on
       * overflow (when the input is less than smallest int128 or
       * greater than largest int128).
       *
       * Counterpart to Solidity's `int128` operator.
       *
       * Requirements:
       *
       * - input must fit into 128 bits
       *
       * _Available since v3.1._
       */
      function toInt128(int256 value) internal pure returns (int128) {
        require(
          value >= type(int128).min && value <= type(int128).max,
          "SafeCast: value doesn't fit in 128 bits"
        );
        return int128(value);
      }
    
      /**
       * @dev Returns the downcasted int64 from int256, reverting on
       * overflow (when the input is less than smallest int64 or
       * greater than largest int64).
       *
       * Counterpart to Solidity's `int64` operator.
       *
       * Requirements:
       *
       * - input must fit into 64 bits
       *
       * _Available since v3.1._
       */
      function toInt64(int256 value) internal pure returns (int64) {
        require(
          value >= type(int64).min && value <= type(int64).max,
          "SafeCast: value doesn't fit in 64 bits"
        );
        return int64(value);
      }
    
      /**
       * @dev Returns the downcasted int32 from int256, reverting on
       * overflow (when the input is less than smallest int32 or
       * greater than largest int32).
       *
       * Counterpart to Solidity's `int32` operator.
       *
       * Requirements:
       *
       * - input must fit into 32 bits
       *
       * _Available since v3.1._
       */
      function toInt32(int256 value) internal pure returns (int32) {
        require(
          value >= type(int32).min && value <= type(int32).max,
          "SafeCast: value doesn't fit in 32 bits"
        );
        return int32(value);
      }
    
      /**
       * @dev Returns the downcasted int16 from int256, reverting on
       * overflow (when the input is less than smallest int16 or
       * greater than largest int16).
       *
       * Counterpart to Solidity's `int16` operator.
       *
       * Requirements:
       *
       * - input must fit into 16 bits
       *
       * _Available since v3.1._
       */
      function toInt16(int256 value) internal pure returns (int16) {
        require(
          value >= type(int16).min && value <= type(int16).max,
          "SafeCast: value doesn't fit in 16 bits"
        );
        return int16(value);
      }
    
      /**
       * @dev Returns the downcasted int8 from int256, reverting on
       * overflow (when the input is less than smallest int8 or
       * greater than largest int8).
       *
       * Counterpart to Solidity's `int8` operator.
       *
       * Requirements:
       *
       * - input must fit into 8 bits.
       *
       * _Available since v3.1._
       */
      function toInt8(int256 value) internal pure returns (int8) {
        require(
          value >= type(int8).min && value <= type(int8).max,
          "SafeCast: value doesn't fit in 8 bits"
        );
        return int8(value);
      }
    
      /**
       * @dev Converts an unsigned uint256 into a signed int256.
       *
       * Requirements:
       *
       * - input must be less than or equal to maxInt256.
       */
      function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        return int256(value);
      }
    }
    
  • @aave/core-v3/contracts/interfaces/IScaledBalanceToken.sol
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity ^0.8.0;
    
    /**
     * @title IScaledBalanceToken
     * @author Aave
     * @notice Defines the basic interface for a scaled-balance token.
     */
    interface IScaledBalanceToken {
      /**
       * @dev Emitted after the mint action
       * @param caller The address performing the mint
       * @param onBehalfOf The address of the user that will receive the minted tokens
       * @param value The scaled-up amount being minted (based on user entered amount and balance increase from interest)
       * @param balanceIncrease The increase in scaled-up balance since the last action of 'onBehalfOf'
       * @param index The next liquidity index of the reserve
       */
      event Mint(
        address indexed caller,
        address indexed onBehalfOf,
        uint256 value,
        uint256 balanceIncrease,
        uint256 index
      );
    
      /**
       * @dev Emitted after the burn action
       * @dev If the burn function does not involve a transfer of the underlying asset, the target defaults to zero address
       * @param from The address from which the tokens will be burned
       * @param target The address that will receive the underlying, if any
       * @param value The scaled-up amount being burned (user entered amount - balance increase from interest)
       * @param balanceIncrease The increase in scaled-up balance since the last action of 'from'
       * @param index The next liquidity index of the reserve
       */
      event Burn(
        address indexed from,
        address indexed target,
        uint256 value,
        uint256 balanceIncrease,
        uint256 index
      );
    
      /**
       * @notice Returns the scaled balance of the user.
       * @dev The scaled balance is the sum of all the updated stored balance divided by the reserve's liquidity index
       * at the moment of the update
       * @param user The user whose balance is calculated
       * @return The scaled balance of the user
       */
      function scaledBalanceOf(address user) external view returns (uint256);
    
      /**
       * @notice Returns the scaled balance of the user and the scaled total supply.
       * @param user The address of the user
       * @return The scaled balance of the user
       * @return The scaled total supply
       */
      function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
    
      /**
       * @notice Returns the scaled total supply of the scaled balance token. Represents sum(debt/index)
       * @return The scaled total supply
       */
      function scaledTotalSupply() external view returns (uint256);
    
      /**
       * @notice Returns last index interest was accrued to the user's balance
       * @param user The address of the user
       * @return The last index interest was accrued to the user's balance, expressed in ray
       */
      function getPreviousIndex(address user) external view returns (uint256);
    }
    
  • @aave/core-v3/contracts/protocol/libraries/aave-upgradeability/VersionedInitializable.sol
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity ^0.8.0;
    
    /**
     * @title VersionedInitializable
     * @author Aave, inspired by the OpenZeppelin Initializable contract
     * @notice Helper contract to implement initializer functions. To use it, replace
     * the constructor with a function that has the `initializer` modifier.
     * @dev WARNING: Unlike constructors, initializer functions must be manually
     * invoked. This applies both to deploying an Initializable contract, as well
     * as extending an Initializable contract via inheritance.
     * WARNING: When used with inheritance, manual care must be taken to not invoke
     * a parent initializer twice, or ensure that all initializers are idempotent,
     * because this is not dealt with automatically as with constructors.
     */
    abstract contract VersionedInitializable {
      /**
       * @dev Indicates that the contract has been initialized.
       */
      uint256 private lastInitializedRevision = 0;
    
      /**
       * @dev Indicates that the contract is in the process of being initialized.
       */
      bool private initializing;
    
      /**
       * @dev Modifier to use in the initializer function of a contract.
       */
      modifier initializer() {
        uint256 revision = getRevision();
        require(
          initializing || isConstructor() || revision > lastInitializedRevision,
          'Contract instance has already been initialized'
        );
    
        bool isTopLevelCall = !initializing;
        if (isTopLevelCall) {
          initializing = true;
          lastInitializedRevision = revision;
        }
    
        _;
    
        if (isTopLevelCall) {
          initializing = false;
        }
      }
    
      /**
       * @notice Returns the revision number of the contract
       * @dev Needs to be defined in the inherited class as a constant.
       * @return The revision number
       */
      function getRevision() internal pure virtual returns (uint256);
    
      /**
       * @notice Returns true if and only if the function is running in the constructor
       * @return True if the function is running in the constructor
       */
      function isConstructor() private view returns (bool) {
        // extcodesize checks the size of the code stored in an address, and
        // address returns the current address. Since the code is still not
        // deployed when running a constructor, any checks on its code size will
        // yield zero, making it an effective way to detect if a contract is
        // under construction or not.
        uint256 cs;
        //solium-disable-next-line
        assembly {
          cs := extcodesize(address())
        }
        return cs == 0;
      }
    
      // Reserved storage space to allow for layout changes in the future.
      uint256[50] private ______gap;
    }
    
  • @aave/periphery-v3/contracts/misc/interfaces/IEACAggregatorProxy.sol
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity ^0.8.10;
    
    interface IEACAggregatorProxy {
      function decimals() external view returns (uint8);
    
      function latestAnswer() external view returns (int256);
    
      function latestTimestamp() external view returns (uint256);
    
      function latestRound() external view returns (uint256);
    
      function getAnswer(uint256 roundId) external view returns (int256);
    
      function getTimestamp(uint256 roundId) external view returns (uint256);
    
      event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);
      event NewRound(uint256 indexed roundId, address indexed startedBy);
    }
    
  • @aave/periphery-v3/contracts/rewards/RewardsDistributor.sol
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity ^0.8.10;
    
    import {IScaledBalanceToken} from '@aave/core-v3/contracts/interfaces/IScaledBalanceToken.sol';
    import {IERC20Detailed} from '@aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol';
    import {SafeCast} from '@aave/core-v3/contracts/dependencies/openzeppelin/contracts/SafeCast.sol';
    import {IRewardsDistributor} from './interfaces/IRewardsDistributor.sol';
    import {RewardsDataTypes} from './libraries/RewardsDataTypes.sol';
    
    /**
     * @title RewardsDistributor
     * @notice Accounting contract to manage multiple staking distributions with multiple rewards
     * @author Aave
     **/
    abstract contract RewardsDistributor is IRewardsDistributor {
      using SafeCast for uint256;
    
      // Manager of incentives
      address public immutable EMISSION_MANAGER;
      // Deprecated: This storage slot is kept for backwards compatibility purposes.
      address internal _emissionManager;
    
      // Map of rewarded asset addresses and their data (assetAddress => assetData)
      mapping(address => RewardsDataTypes.AssetData) internal _assets;
    
      // Map of reward assets (rewardAddress => enabled)
      mapping(address => bool) internal _isRewardEnabled;
    
      // Rewards list
      address[] internal _rewardsList;
    
      // Assets list
      address[] internal _assetsList;
    
      modifier onlyEmissionManager() {
        require(msg.sender == EMISSION_MANAGER, 'ONLY_EMISSION_MANAGER');
        _;
      }
    
      constructor(address emissionManager) {
        EMISSION_MANAGER = emissionManager;
      }
    
      /// @inheritdoc IRewardsDistributor
      function getRewardsData(
        address asset,
        address reward
      ) public view override returns (uint256, uint256, uint256, uint256) {
        return (
          _assets[asset].rewards[reward].index,
          _assets[asset].rewards[reward].emissionPerSecond,
          _assets[asset].rewards[reward].lastUpdateTimestamp,
          _assets[asset].rewards[reward].distributionEnd
        );
      }
    
      /// @inheritdoc IRewardsDistributor
      function getAssetIndex(
        address asset,
        address reward
      ) external view override returns (uint256, uint256) {
        RewardsDataTypes.RewardData storage rewardData = _assets[asset].rewards[reward];
        return
          _getAssetIndex(
            rewardData,
            IScaledBalanceToken(asset).scaledTotalSupply(),
            10 ** _assets[asset].decimals
          );
      }
    
      /// @inheritdoc IRewardsDistributor
      function getDistributionEnd(
        address asset,
        address reward
      ) external view override returns (uint256) {
        return _assets[asset].rewards[reward].distributionEnd;
      }
    
      /// @inheritdoc IRewardsDistributor
      function getRewardsByAsset(address asset) external view override returns (address[] memory) {
        uint128 rewardsCount = _assets[asset].availableRewardsCount;
        address[] memory availableRewards = new address[](rewardsCount);
    
        for (uint128 i = 0; i < rewardsCount; i++) {
          availableRewards[i] = _assets[asset].availableRewards[i];
        }
        return availableRewards;
      }
    
      /// @inheritdoc IRewardsDistributor
      function getRewardsList() external view override returns (address[] memory) {
        return _rewardsList;
      }
    
      /// @inheritdoc IRewardsDistributor
      function getUserAssetIndex(
        address user,
        address asset,
        address reward
      ) public view override returns (uint256) {
        return _assets[asset].rewards[reward].usersData[user].index;
      }
    
      /// @inheritdoc IRewardsDistributor
      function getUserAccruedRewards(
        address user,
        address reward
      ) external view override returns (uint256) {
        uint256 totalAccrued;
        for (uint256 i = 0; i < _assetsList.length; i++) {
          totalAccrued += _assets[_assetsList[i]].rewards[reward].usersData[user].accrued;
        }
    
        return totalAccrued;
      }
    
      /// @inheritdoc IRewardsDistributor
      function getUserRewards(
        address[] calldata assets,
        address user,
        address reward
      ) external view override returns (uint256) {
        return _getUserReward(user, reward, _getUserAssetBalances(assets, user));
      }
    
      /// @inheritdoc IRewardsDistributor
      function getAllUserRewards(
        address[] calldata assets,
        address user
      )
        external
        view
        override
        returns (address[] memory rewardsList, uint256[] memory unclaimedAmounts)
      {
        RewardsDataTypes.UserAssetBalance[] memory userAssetBalances = _getUserAssetBalances(
          assets,
          user
        );
        rewardsList = new address[](_rewardsList.length);
        unclaimedAmounts = new uint256[](rewardsList.length);
    
        // Add unrealized rewards from user to unclaimedRewards
        for (uint256 i = 0; i < userAssetBalances.length; i++) {
          for (uint256 r = 0; r < rewardsList.length; r++) {
            rewardsList[r] = _rewardsList[r];
            unclaimedAmounts[r] += _assets[userAssetBalances[i].asset]
              .rewards[rewardsList[r]]
              .usersData[user]
              .accrued;
    
            if (userAssetBalances[i].userBalance == 0) {
              continue;
            }
            unclaimedAmounts[r] += _getPendingRewards(user, rewardsList[r], userAssetBalances[i]);
          }
        }
        return (rewardsList, unclaimedAmounts);
      }
    
      /// @inheritdoc IRewardsDistributor
      function setDistributionEnd(
        address asset,
        address reward,
        uint32 newDistributionEnd
      ) external override onlyEmissionManager {
        uint256 oldDistributionEnd = _assets[asset].rewards[reward].distributionEnd;
        _assets[asset].rewards[reward].distributionEnd = newDistributionEnd;
    
        emit AssetConfigUpdated(
          asset,
          reward,
          _assets[asset].rewards[reward].emissionPerSecond,
          _assets[asset].rewards[reward].emissionPerSecond,
          oldDistributionEnd,
          newDistributionEnd,
          _assets[asset].rewards[reward].index
        );
      }
    
      /// @inheritdoc IRewardsDistributor
      function setEmissionPerSecond(
        address asset,
        address[] calldata rewards,
        uint88[] calldata newEmissionsPerSecond
      ) external override onlyEmissionManager {
        require(rewards.length == newEmissionsPerSecond.length, 'INVALID_INPUT');
        for (uint256 i = 0; i < rewards.length; i++) {
          RewardsDataTypes.AssetData storage assetConfig = _assets[asset];
          RewardsDataTypes.RewardData storage rewardConfig = _assets[asset].rewards[rewards[i]];
          uint256 decimals = assetConfig.decimals;
          require(
            decimals != 0 && rewardConfig.lastUpdateTimestamp != 0,
            'DISTRIBUTION_DOES_NOT_EXIST'
          );
    
          (uint256 newIndex, ) = _updateRewardData(
            rewardConfig,
            IScaledBalanceToken(asset).scaledTotalSupply(),
            10 ** decimals
          );
    
          uint256 oldEmissionPerSecond = rewardConfig.emissionPerSecond;
          rewardConfig.emissionPerSecond = newEmissionsPerSecond[i];
    
          emit AssetConfigUpdated(
            asset,
            rewards[i],
            oldEmissionPerSecond,
            newEmissionsPerSecond[i],
            rewardConfig.distributionEnd,
            rewardConfig.distributionEnd,
            newIndex
          );
        }
      }
    
      /**
       * @dev Configure the _assets for a specific emission
       * @param rewardsInput The array of each asset configuration
       **/
      function _configureAssets(RewardsDataTypes.RewardsConfigInput[] memory rewardsInput) internal {
        for (uint256 i = 0; i < rewardsInput.length; i++) {
          if (_assets[rewardsInput[i].asset].decimals == 0) {
            //never initialized before, adding to the list of assets
            _assetsList.push(rewardsInput[i].asset);
          }
    
          uint256 decimals = _assets[rewardsInput[i].asset].decimals = IERC20Detailed(
            rewardsInput[i].asset
          ).decimals();
    
          RewardsDataTypes.RewardData storage rewardConfig = _assets[rewardsInput[i].asset].rewards[
            rewardsInput[i].reward
          ];
    
          // Add reward address to asset available rewards if latestUpdateTimestamp is zero
          if (rewardConfig.lastUpdateTimestamp == 0) {
            _assets[rewardsInput[i].asset].availableRewards[
              _assets[rewardsInput[i].asset].availableRewardsCount
            ] = rewardsInput[i].reward;
            _assets[rewardsInput[i].asset].availableRewardsCount++;
          }
    
          // Add reward address to global rewards list if still not enabled
          if (_isRewardEnabled[rewardsInput[i].reward] == false) {
            _isRewardEnabled[rewardsInput[i].reward] = true;
            _rewardsList.push(rewardsInput[i].reward);
          }
    
          // Due emissions is still zero, updates only latestUpdateTimestamp
          (uint256 newIndex, ) = _updateRewardData(
            rewardConfig,
            rewardsInput[i].totalSupply,
            10 ** decimals
          );
    
          // Configure emission and distribution end of the reward per asset
          uint88 oldEmissionsPerSecond = rewardConfig.emissionPerSecond;
          uint32 oldDistributionEnd = rewardConfig.distributionEnd;
          rewardConfig.emissionPerSecond = rewardsInput[i].emissionPerSecond;
          rewardConfig.distributionEnd = rewardsInput[i].distributionEnd;
    
          emit AssetConfigUpdated(
            rewardsInput[i].asset,
            rewardsInput[i].reward,
            oldEmissionsPerSecond,
            rewardsInput[i].emissionPerSecond,
            oldDistributionEnd,
            rewardsInput[i].distributionEnd,
            newIndex
          );
        }
      }
    
      /**
       * @dev Updates the state of the distribution for the specified reward
       * @param rewardData Storage pointer to the distribution reward config
       * @param totalSupply Current total of underlying assets for this distribution
       * @param assetUnit One unit of asset (10**decimals)
       * @return The new distribution index
       * @return True if the index was updated, false otherwise
       **/
      function _updateRewardData(
        RewardsDataTypes.RewardData storage rewardData,
        uint256 totalSupply,
        uint256 assetUnit
      ) internal returns (uint256, bool) {
        (uint256 oldIndex, uint256 newIndex) = _getAssetIndex(rewardData, totalSupply, assetUnit);
        bool indexUpdated;
        if (newIndex != oldIndex) {
          require(newIndex <= type(uint104).max, 'INDEX_OVERFLOW');
          indexUpdated = true;
    
          //optimization: storing one after another saves one SSTORE
          rewardData.index = uint104(newIndex);
          rewardData.lastUpdateTimestamp = block.timestamp.toUint32();
        } else {
          rewardData.lastUpdateTimestamp = block.timestamp.toUint32();
        }
    
        return (newIndex, indexUpdated);
      }
    
      /**
       * @dev Updates the state of the distribution for the specific user
       * @param rewardData Storage pointer to the distribution reward config
       * @param user The address of the user
       * @param userBalance The user balance of the asset
       * @param newAssetIndex The new index of the asset distribution
       * @param assetUnit One unit of asset (10**decimals)
       * @return The rewards accrued since the last update
       **/
      function _updateUserData(
        RewardsDataTypes.RewardData storage rewardData,
        address user,
        uint256 userBalance,
        uint256 newAssetIndex,
        uint256 assetUnit
      ) internal returns (uint256, bool) {
        uint256 userIndex = rewardData.usersData[user].index;
        uint256 rewardsAccrued;
        bool dataUpdated;
        if ((dataUpdated = userIndex != newAssetIndex)) {
          // already checked for overflow in _updateRewardData
          rewardData.usersData[user].index = uint104(newAssetIndex);
          if (userBalance != 0) {
            rewardsAccrued = _getRewards(userBalance, newAssetIndex, userIndex, assetUnit);
    
            rewardData.usersData[user].accrued += rewardsAccrued.toUint128();
          }
        }
        return (rewardsAccrued, dataUpdated);
      }
    
      /**
       * @dev Iterates and accrues all the rewards for asset of the specific 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 _updateData(
        address asset,
        address user,
        uint256 userBalance,
        uint256 totalSupply
      ) internal {
        uint256 assetUnit;
        uint256 numAvailableRewards = _assets[asset].availableRewardsCount;
        unchecked {
          assetUnit = 10 ** _assets[asset].decimals;
        }
    
        if (numAvailableRewards == 0) {
          return;
        }
        unchecked {
          for (uint128 r = 0; r < numAvailableRewards; r++) {
            address reward = _assets[asset].availableRewards[r];
            RewardsDataTypes.RewardData storage rewardData = _assets[asset].rewards[reward];
    
            (uint256 newAssetIndex, bool rewardDataUpdated) = _updateRewardData(
              rewardData,
              totalSupply,
              assetUnit
            );
    
            (uint256 rewardsAccrued, bool userDataUpdated) = _updateUserData(
              rewardData,
              user,
              userBalance,
              newAssetIndex,
              assetUnit
            );
    
            if (rewardDataUpdated || userDataUpdated) {
              emit Accrued(asset, reward, user, newAssetIndex, newAssetIndex, rewardsAccrued);
            }
          }
        }
      }
    
      /**
       * @dev Accrues all the rewards of the assets specified in the userAssetBalances list
       * @param user The address of the user
       * @param userAssetBalances List of structs with the user balance and total supply of a set of assets
       **/
      function _updateDataMultiple(
        address user,
        RewardsDataTypes.UserAssetBalance[] memory userAssetBalances
      ) internal {
        for (uint256 i = 0; i < userAssetBalances.length; i++) {
          _updateData(
            userAssetBalances[i].asset,
            user,
            userAssetBalances[i].userBalance,
            userAssetBalances[i].totalSupply
          );
        }
      }
    
      /**
       * @dev Return the accrued unclaimed amount of a reward from a user over a list of distribution
       * @param user The address of the user
       * @param reward The address of the reward token
       * @param userAssetBalances List of structs with the user balance and total supply of a set of assets
       * @return unclaimedRewards The accrued rewards for the user until the moment
       **/
      function _getUserReward(
        address user,
        address reward,
        RewardsDataTypes.UserAssetBalance[] memory userAssetBalances
      ) internal view returns (uint256 unclaimedRewards) {
        // Add unrealized rewards
        for (uint256 i = 0; i < userAssetBalances.length; i++) {
          if (userAssetBalances[i].userBalance == 0) {
            unclaimedRewards += _assets[userAssetBalances[i].asset]
              .rewards[reward]
              .usersData[user]
              .accrued;
          } else {
            unclaimedRewards +=
              _getPendingRewards(user, reward, userAssetBalances[i]) +
              _assets[userAssetBalances[i].asset].rewards[reward].usersData[user].accrued;
          }
        }
    
        return unclaimedRewards;
      }
    
      /**
       * @dev Calculates the pending (not yet accrued) rewards since the last user action
       * @param user The address of the user
       * @param reward The address of the reward token
       * @param userAssetBalance struct with the user balance and total supply of the incentivized asset
       * @return The pending rewards for the user since the last user action
       **/
      function _getPendingRewards(
        address user,
        address reward,
        RewardsDataTypes.UserAssetBalance memory userAssetBalance
      ) internal view returns (uint256) {
        RewardsDataTypes.RewardData storage rewardData = _assets[userAssetBalance.asset].rewards[
          reward
        ];
        uint256 assetUnit = 10 ** _assets[userAssetBalance.asset].decimals;
        (, uint256 nextIndex) = _getAssetIndex(rewardData, userAssetBalance.totalSupply, assetUnit);
    
        return
          _getRewards(
            userAssetBalance.userBalance,
            nextIndex,
            rewardData.usersData[user].index,
            assetUnit
          );
      }
    
      /**
       * @dev Internal function for the calculation of user's rewards on a distribution
       * @param userBalance 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 assetUnit One unit of asset (10**decimals)
       * @return The rewards
       **/
      function _getRewards(
        uint256 userBalance,
        uint256 reserveIndex,
        uint256 userIndex,
        uint256 assetUnit
      ) internal pure returns (uint256) {
        uint256 result = userBalance * (reserveIndex - userIndex);
        assembly {
          result := div(result, assetUnit)
        }
        return result;
      }
    
      /**
       * @dev Calculates the next value of an specific distribution index, with validations
       * @param rewardData Storage pointer to the distribution reward config
       * @param totalSupply of the asset being rewarded
       * @param assetUnit One unit of asset (10**decimals)
       * @return The new index.
       **/
      function _getAssetIndex(
        RewardsDataTypes.RewardData storage rewardData,
        uint256 totalSupply,
        uint256 assetUnit
      ) internal view returns (uint256, uint256) {
        uint256 oldIndex = rewardData.index;
        uint256 distributionEnd = rewardData.distributionEnd;
        uint256 emissionPerSecond = rewardData.emissionPerSecond;
        uint256 lastUpdateTimestamp = rewardData.lastUpdateTimestamp;
    
        if (
          emissionPerSecond == 0 ||
          totalSupply == 0 ||
          lastUpdateTimestamp == block.timestamp ||
          lastUpdateTimestamp >= distributionEnd
        ) {
          return (oldIndex, oldIndex);
        }
    
        uint256 currentTimestamp = block.timestamp > distributionEnd
          ? distributionEnd
          : block.timestamp;
        uint256 timeDelta = currentTimestamp - lastUpdateTimestamp;
        uint256 firstTerm = emissionPerSecond * timeDelta * assetUnit;
        assembly {
          firstTerm := div(firstTerm, totalSupply)
        }
        return (oldIndex, (firstTerm + oldIndex));
      }
    
      /**
       * @dev Get user balances and total supply of all the assets specified by the assets parameter
       * @param assets List of assets to retrieve user balance and total supply
       * @param user Address of the user
       * @return userAssetBalances contains a list of structs with user balance and total supply of the given assets
       */
      function _getUserAssetBalances(
        address[] calldata assets,
        address user
      ) internal view virtual returns (RewardsDataTypes.UserAssetBalance[] memory userAssetBalances);
    
      /// @inheritdoc IRewardsDistributor
      function getAssetDecimals(address asset) external view returns (uint8) {
        return _assets[asset].decimals;
      }
    
      /// @inheritdoc IRewardsDistributor
      function getEmissionManager() external view returns (address) {
        return EMISSION_MANAGER;
      }
    }
    
  • @aave/periphery-v3/contracts/rewards/interfaces/IRewardsController.sol
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity ^0.8.10;
    
    import {IRewardsDistributor} from './IRewardsDistributor.sol';
    import {ITransferStrategyBase} from './ITransferStrategyBase.sol';
    import {IEACAggregatorProxy} from '../../misc/interfaces/IEACAggregatorProxy.sol';
    import {RewardsDataTypes} from '../libraries/RewardsDataTypes.sol';
    
    /**
     * @title IRewardsController
     * @author Aave
     * @notice Defines the basic interface for a Rewards Controller.
     */
    interface IRewardsController is IRewardsDistributor {
      /**
       * @dev Emitted when a new address is whitelisted as claimer of rewards on behalf of a user
       * @param user The address of the user
       * @param claimer The address of the claimer
       */
      event ClaimerSet(address indexed user, address indexed claimer);
    
      /**
       * @dev Emitted when rewards are claimed
       * @param user The address of the user rewards has been claimed on behalf of
       * @param reward The address of the token reward is claimed
       * @param to The address of the receiver of the rewards
       * @param claimer The address of the claimer
       * @param amount The amount of rewards claimed
       */
      event RewardsClaimed(
        address indexed user,
        address indexed reward,
        address indexed to,
        address claimer,
        uint256 amount
      );
    
      /**
       * @dev Emitted when a transfer strategy is installed for the reward distribution
       * @param reward The address of the token reward
       * @param transferStrategy The address of TransferStrategy contract
       */
      event TransferStrategyInstalled(address indexed reward, address indexed transferStrategy);
    
      /**
       * @dev Emitted when the reward oracle is updated
       * @param reward The address of the token reward
       * @param rewardOracle The address of oracle
       */
      event RewardOracleUpdated(address indexed reward, address indexed rewardOracle);
    
      /**
       * @dev Whitelists an address to claim the rewards on behalf of another address
       * @param user The address of the user
       * @param claimer The address of the claimer
       */
      function setClaimer(address user, address claimer) external;
    
      /**
       * @dev Sets a TransferStrategy logic contract that determines the logic of the rewards transfer
       * @param reward The address of the reward token
       * @param transferStrategy The address of the TransferStrategy logic contract
       */
      function setTransferStrategy(address reward, ITransferStrategyBase transferStrategy) external;
    
      /**
       * @dev Sets an Aave Oracle contract to enforce rewards with a source of value.
       * @notice At the moment of reward configuration, the Incentives Controller performs
       * a check to see if the reward asset oracle is compatible with IEACAggregator proxy.
       * This check is enforced for integrators to be able to show incentives at
       * the current Aave UI without the need to setup an external price registry
       * @param reward The address of the reward to set the price aggregator
       * @param rewardOracle The address of price aggregator that follows IEACAggregatorProxy interface
       */
      function setRewardOracle(address reward, IEACAggregatorProxy rewardOracle) external;
    
      /**
       * @dev Get the price aggregator oracle address
       * @param reward The address of the reward
       * @return The price oracle of the reward
       */
      function getRewardOracle(address reward) external view returns (address);
    
      /**
       * @dev Returns the whitelisted claimer for a certain address (0x0 if not set)
       * @param user The address of the user
       * @return The claimer address
       */
      function getClaimer(address user) external view returns (address);
    
      /**
       * @dev Returns the Transfer Strategy implementation contract address being used for a reward address
       * @param reward The address of the reward
       * @return The address of the TransferStrategy contract
       */
      function getTransferStrategy(address reward) external view returns (address);
    
      /**
       * @dev Configure assets to incentivize with an emission of rewards per second until the end of distribution.
       * @param config The assets configuration input, the list of structs contains the following fields:
       *   uint104 emissionPerSecond: The emission per second following rewards unit decimals.
       *   uint256 totalSupply: The total supply of the asset to incentivize
       *   uint40 distributionEnd: The end of the distribution of the incentives for an asset
       *   address asset: The asset address to incentivize
       *   address reward: The reward token address
       *   ITransferStrategy transferStrategy: The TransferStrategy address with the install hook and claim logic.
       *   IEACAggregatorProxy rewardOracle: The Price Oracle of a reward to visualize the incentives at the UI Frontend.
       *                                     Must follow Chainlink Aggregator IEACAggregatorProxy interface to be compatible.
       */
      function configureAssets(RewardsDataTypes.RewardsConfigInput[] memory config) external;
    
      /**
       * @dev Called by the corresponding asset on transfer hook in order to update the rewards distribution.
       * @dev The units of `totalSupply` and `userBalance` should be the same.
       * @param user The address of the user whose asset balance has changed
       * @param totalSupply The total supply of the asset prior to user balance change
       * @param userBalance The previous user balance prior to balance change
       **/
      function handleAction(address user, uint256 totalSupply, uint256 userBalance) external;
    
      /**
       * @dev Claims reward for a user to the desired address, on all the assets of the pool, accumulating the pending rewards
       * @param assets List of assets to check eligible distributions before claiming rewards
       * @param amount The amount of rewards to claim
       * @param to The address that will be receiving the rewards
       * @param reward The address of the reward token
       * @return The amount of rewards claimed
       **/
      function claimRewards(
        address[] calldata assets,
        uint256 amount,
        address to,
        address reward
      ) external returns (uint256);
    
      /**
       * @dev Claims reward for a user on behalf, on all the assets of the pool, accumulating the pending rewards. The
       * caller must be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
       * @param assets The list of assets to check eligible distributions before claiming rewards
       * @param amount The amount of rewards to claim
       * @param user The address to check and claim rewards
       * @param to The address that will be receiving the rewards
       * @param reward The address of the reward token
       * @return The amount of rewards claimed
       **/
      function claimRewardsOnBehalf(
        address[] calldata assets,
        uint256 amount,
        address user,
        address to,
        address reward
      ) external returns (uint256);
    
      /**
       * @dev Claims reward for msg.sender, on all the assets of the pool, accumulating the pending rewards
       * @param assets The list of assets to check eligible distributions before claiming rewards
       * @param amount The amount of rewards to claim
       * @param reward The address of the reward token
       * @return The amount of rewards claimed
       **/
      function claimRewardsToSelf(
        address[] calldata assets,
        uint256 amount,
        address reward
      ) external returns (uint256);
    
      /**
       * @dev Claims all rewards for a user to the desired address, on all the assets of the pool, accumulating the pending rewards
       * @param assets The list of assets to check eligible distributions before claiming rewards
       * @param to The address that will be receiving the rewards
       * @return rewardsList List of addresses of the reward tokens
       * @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardList"
       **/
      function claimAllRewards(
        address[] calldata assets,
        address to
      ) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
    
      /**
       * @dev Claims all rewards for a user on behalf, on all the assets of the pool, accumulating the pending rewards. The caller must
       * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
       * @param assets The list of assets to check eligible distributions before claiming rewards
       * @param user The address to check and claim rewards
       * @param to The address that will be receiving the rewards
       * @return rewardsList List of addresses of the reward tokens
       * @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardsList"
       **/
      function claimAllRewardsOnBehalf(
        address[] calldata assets,
        address user,
        address to
      ) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
    
      /**
       * @dev Claims all reward for msg.sender, on all the assets of the pool, accumulating the pending rewards
       * @param assets The list of assets to check eligible distributions before claiming rewards
       * @return rewardsList List of addresses of the reward tokens
       * @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardsList"
       **/
      function claimAllRewardsToSelf(
        address[] calldata assets
      ) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
    }
    
  • @aave/periphery-v3/contracts/rewards/interfaces/IRewardsDistributor.sol
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity ^0.8.10;
    
    /**
     * @title IRewardsDistributor
     * @author Aave
     * @notice Defines the basic interface for a Rewards Distributor.
     */
    interface IRewardsDistributor {
      /**
       * @dev Emitted when the configuration of the rewards of an asset is updated.
       * @param asset The address of the incentivized asset
       * @param reward The address of the reward token
       * @param oldEmission The old emissions per second value of the reward distribution
       * @param newEmission The new emissions per second value of the reward distribution
       * @param oldDistributionEnd The old end timestamp of the reward distribution
       * @param newDistributionEnd The new end timestamp of the reward distribution
       * @param assetIndex The index of the asset distribution
       */
      event AssetConfigUpdated(
        address indexed asset,
        address indexed reward,
        uint256 oldEmission,
        uint256 newEmission,
        uint256 oldDistributionEnd,
        uint256 newDistributionEnd,
        uint256 assetIndex
      );
    
      /**
       * @dev Emitted when rewards of an asset are accrued on behalf of a user.
       * @param asset The address of the incentivized asset
       * @param reward The address of the reward token
       * @param user The address of the user that rewards are accrued on behalf of
       * @param assetIndex The index of the asset distribution
       * @param userIndex The index of the asset distribution on behalf of the user
       * @param rewardsAccrued The amount of rewards accrued
       */
      event Accrued(
        address indexed asset,
        address indexed reward,
        address indexed user,
        uint256 assetIndex,
        uint256 userIndex,
        uint256 rewardsAccrued
      );
    
      /**
       * @dev Sets the end date for the distribution
       * @param asset The asset to incentivize
       * @param reward The reward token that incentives the asset
       * @param newDistributionEnd The end date of the incentivization, in unix time format
       **/
      function setDistributionEnd(address asset, address reward, uint32 newDistributionEnd) external;
    
      /**
       * @dev Sets the emission per second of a set of reward distributions
       * @param asset The asset is being incentivized
       * @param rewards List of reward addresses are being distributed
       * @param newEmissionsPerSecond List of new reward emissions per second
       */
      function setEmissionPerSecond(
        address asset,
        address[] calldata rewards,
        uint88[] calldata newEmissionsPerSecond
      ) external;
    
      /**
       * @dev Gets the end date for the distribution
       * @param asset The incentivized asset
       * @param reward The reward token of the incentivized asset
       * @return The timestamp with the end of the distribution, in unix time format
       **/
      function getDistributionEnd(address asset, address reward) external view returns (uint256);
    
      /**
       * @dev Returns the index of a user on a reward distribution
       * @param user Address of the user
       * @param asset The incentivized asset
       * @param reward The reward token of the incentivized asset
       * @return The current user asset index, not including new distributions
       **/
      function getUserAssetIndex(
        address user,
        address asset,
        address reward
      ) external view returns (uint256);
    
      /**
       * @dev Returns the configuration of the distribution reward for a certain asset
       * @param asset The incentivized asset
       * @param reward The reward token of the incentivized asset
       * @return The index of the asset distribution
       * @return The emission per second of the reward distribution
       * @return The timestamp of the last update of the index
       * @return The timestamp of the distribution end
       **/
      function getRewardsData(
        address asset,
        address reward
      ) external view returns (uint256, uint256, uint256, uint256);
    
      /**
       * @dev Calculates the next value of an specific distribution index, with validations.
       * @param asset The incentivized asset
       * @param reward The reward token of the incentivized asset
       * @return The old index of the asset distribution
       * @return The new index of the asset distribution
       **/
      function getAssetIndex(address asset, address reward) external view returns (uint256, uint256);
    
      /**
       * @dev Returns the list of available reward token addresses of an incentivized asset
       * @param asset The incentivized asset
       * @return List of rewards addresses of the input asset
       **/
      function getRewardsByAsset(address asset) external view returns (address[] memory);
    
      /**
       * @dev Returns the list of available reward addresses
       * @return List of rewards supported in this contract
       **/
      function getRewardsList() external view returns (address[] memory);
    
      /**
       * @dev Returns the accrued rewards balance of a user, not including virtually accrued rewards since last distribution.
       * @param user The address of the user
       * @param reward The address of the reward token
       * @return Unclaimed rewards, not including new distributions
       **/
      function getUserAccruedRewards(address user, address reward) external view returns (uint256);
    
      /**
       * @dev Returns a single rewards balance of a user, including virtually accrued and unrealized claimable rewards.
       * @param assets List of incentivized assets to check eligible distributions
       * @param user The address of the user
       * @param reward The address of the reward token
       * @return The rewards amount
       **/
      function getUserRewards(
        address[] calldata assets,
        address user,
        address reward
      ) external view returns (uint256);
    
      /**
       * @dev Returns a list all rewards of a user, including already accrued and unrealized claimable rewards
       * @param assets List of incentivized assets to check eligible distributions
       * @param user The address of the user
       * @return The list of reward addresses
       * @return The list of unclaimed amount of rewards
       **/
      function getAllUserRewards(
        address[] calldata assets,
        address user
      ) external view returns (address[] memory, uint256[] memory);
    
      /**
       * @dev Returns the decimals of an asset to calculate the distribution delta
       * @param asset The address to retrieve decimals
       * @return The decimals of an underlying asset
       */
      function getAssetDecimals(address asset) external view returns (uint8);
    
      /**
       * @dev Returns the address of the emission manager
       * @return The address of the EmissionManager
       */
      function EMISSION_MANAGER() external view returns (address);
    
      /**
       * @dev Returns the address of the emission manager.
       * Deprecated: This getter is maintained for compatibility purposes. Use the `EMISSION_MANAGER()` function instead.
       * @return The address of the EmissionManager
       */
      function getEmissionManager() external view returns (address);
    }
    
  • @aave/periphery-v3/contracts/rewards/interfaces/ITransferStrategyBase.sol
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity ^0.8.10;
    
    interface ITransferStrategyBase {
      event EmergencyWithdrawal(
        address indexed caller,
        address indexed token,
        address indexed to,
        uint256 amount
      );
    
      /**
       * @dev Perform custom transfer logic via delegate call from source contract to a TransferStrategy implementation
       * @param to Account to transfer rewards
       * @param reward Address of the reward token
       * @param amount Amount to transfer to the "to" address parameter
       * @return Returns true bool if transfer logic succeeds
       */
      function performTransfer(address to, address reward, uint256 amount) external returns (bool);
    
      /**
       * @return Returns the address of the Incentives Controller
       */
      function getIncentivesController() external view returns (address);
    
      /**
       * @return Returns the address of the Rewards admin
       */
      function getRewardsAdmin() external view returns (address);
    
      /**
       * @dev Perform an emergency token withdrawal only callable by the Rewards admin
       * @param token Address of the token to withdraw funds from this contract
       * @param to Address of the recipient of the withdrawal
       * @param amount Amount of the withdrawal
       */
      function emergencyWithdrawal(address token, address to, uint256 amount) external;
    }
    
  • @aave/periphery-v3/contracts/rewards/libraries/RewardsDataTypes.sol
    // SPDX-License-Identifier: AGPL-3.0
    pragma solidity ^0.8.10;
    
    import {ITransferStrategyBase} from '../interfaces/ITransferStrategyBase.sol';
    import {IEACAggregatorProxy} from '../../misc/interfaces/IEACAggregatorProxy.sol';
    
    library RewardsDataTypes {
      struct RewardsConfigInput {
        uint88 emissionPerSecond;
        uint256 totalSupply;
        uint32 distributionEnd;
        address asset;
        address reward;
        ITransferStrategyBase transferStrategy;
        IEACAggregatorProxy rewardOracle;
      }
    
      struct UserAssetBalance {
        address asset;
        uint256 userBalance;
        uint256 totalSupply;
      }
    
      struct UserData {
        // Liquidity index of the reward distribution for the user
        uint104 index;
        // Amount of accrued rewards for the user since last user index update
        uint128 accrued;
      }
    
      struct RewardData {
        // Liquidity index of the reward distribution
        uint104 index;
        // Amount of reward tokens distributed per second
        uint88 emissionPerSecond;
        // Timestamp of the last reward index update
        uint32 lastUpdateTimestamp;
        // The end of the distribution of rewards (in seconds)
        uint32 distributionEnd;
        // Map of user addresses and their rewards data (userAddress => userData)
        mapping(address => UserData) usersData;
      }
    
      struct AssetData {
        // Map of reward token addresses and their data (rewardTokenAddress => rewardData)
        mapping(address => RewardData) rewards;
        // List of reward token addresses for the asset
        mapping(uint128 => address) availableRewards;
        // Count of reward tokens for the asset
        uint128 availableRewardsCount;
        // Number of decimals of the asset
        uint8 decimals;
      }
    }
    
ABI · 37 entries
json
[
  {
    "type": "constructor",
    "inputs": [
      {
        "name": "emissionManager",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "Accrued",
    "type": "event",
    "inputs": [
      {
        "name": "asset",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "user",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "assetIndex",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "userIndex",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "rewardsAccrued",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "AssetConfigUpdated",
    "type": "event",
    "inputs": [
      {
        "name": "asset",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "oldEmission",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "newEmission",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "oldDistributionEnd",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "newDistributionEnd",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "assetIndex",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "ClaimerSet",
    "type": "event",
    "inputs": [
      {
        "name": "user",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "claimer",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "RewardOracleUpdated",
    "type": "event",
    "inputs": [
      {
        "name": "reward",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "rewardOracle",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "RewardsClaimed",
    "type": "event",
    "inputs": [
      {
        "name": "user",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "to",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "claimer",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "amount",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "TransferStrategyInstalled",
    "type": "event",
    "inputs": [
      {
        "name": "reward",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "transferStrategy",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "EMISSION_MANAGER",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "REVISION",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "claimAllRewards",
    "type": "function",
    "inputs": [
      {
        "name": "assets",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "to",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "rewardsList",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "claimedAmounts",
        "type": "uint256[]",
        "internalType": "uint256[]"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "claimAllRewardsOnBehalf",
    "type": "function",
    "inputs": [
      {
        "name": "assets",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "user",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "to",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "rewardsList",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "claimedAmounts",
        "type": "uint256[]",
        "internalType": "uint256[]"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "claimAllRewardsToSelf",
    "type": "function",
    "inputs": [
      {
        "name": "assets",
        "type": "address[]",
        "internalType": "address[]"
      }
    ],
    "outputs": [
      {
        "name": "rewardsList",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "claimedAmounts",
        "type": "uint256[]",
        "internalType": "uint256[]"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "claimRewards",
    "type": "function",
    "inputs": [
      {
        "name": "assets",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "amount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "to",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "claimRewardsOnBehalf",
    "type": "function",
    "inputs": [
      {
        "name": "assets",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "amount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "user",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "to",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "claimRewardsToSelf",
    "type": "function",
    "inputs": [
      {
        "name": "assets",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "amount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "configureAssets",
    "type": "function",
    "inputs": [
      {
        "name": "config",
        "type": "tuple[]",
        "components": [
          {
            "name": "emissionPerSecond",
            "type": "uint88",
            "internalType": "uint88"
          },
          {
            "name": "totalSupply",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "distributionEnd",
            "type": "uint32",
            "internalType": "uint32"
          },
          {
            "name": "asset",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "reward",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "transferStrategy",
            "type": "address",
            "internalType": "contract ITransferStrategyBase"
          },
          {
            "name": "rewardOracle",
            "type": "address",
            "internalType": "contract IEACAggregatorProxy"
          }
        ],
        "internalType": "struct RewardsDataTypes.RewardsConfigInput[]"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "getAllUserRewards",
    "type": "function",
    "inputs": [
      {
        "name": "assets",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "user",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "rewardsList",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "unclaimedAmounts",
        "type": "uint256[]",
        "internalType": "uint256[]"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getAssetDecimals",
    "type": "function",
    "inputs": [
      {
        "name": "asset",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint8",
        "internalType": "uint8"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getAssetIndex",
    "type": "function",
    "inputs": [
      {
        "name": "asset",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getClaimer",
    "type": "function",
    "inputs": [
      {
        "name": "user",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getDistributionEnd",
    "type": "function",
    "inputs": [
      {
        "name": "asset",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getEmissionManager",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getRewardOracle",
    "type": "function",
    "inputs": [
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getRewardsByAsset",
    "type": "function",
    "inputs": [
      {
        "name": "asset",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "address[]",
        "internalType": "address[]"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getRewardsData",
    "type": "function",
    "inputs": [
      {
        "name": "asset",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getRewardsList",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address[]",
        "internalType": "address[]"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getTransferStrategy",
    "type": "function",
    "inputs": [
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getUserAccruedRewards",
    "type": "function",
    "inputs": [
      {
        "name": "user",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getUserAssetIndex",
    "type": "function",
    "inputs": [
      {
        "name": "user",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "asset",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getUserRewards",
    "type": "function",
    "inputs": [
      {
        "name": "assets",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "user",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "handleAction",
    "type": "function",
    "inputs": [
      {
        "name": "user",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "totalSupply",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "userBalance",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "initialize",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setClaimer",
    "type": "function",
    "inputs": [
      {
        "name": "user",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "caller",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setDistributionEnd",
    "type": "function",
    "inputs": [
      {
        "name": "asset",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "newDistributionEnd",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setEmissionPerSecond",
    "type": "function",
    "inputs": [
      {
        "name": "asset",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "rewards",
        "type": "address[]",
        "internalType": "address[]"
      },
      {
        "name": "newEmissionsPerSecond",
        "type": "uint88[]",
        "internalType": "uint88[]"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setRewardOracle",
    "type": "function",
    "inputs": [
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "rewardOracle",
        "type": "address",
        "internalType": "contract IEACAggregatorProxy"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setTransferStrategy",
    "type": "function",
    "inputs": [
      {
        "name": "reward",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "transferStrategy",
        "type": "address",
        "internalType": "contract ITransferStrategyBase"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  }
]