Contract 0xaad324f7e4dd50c6b105820f8a877ee2dcbfa789 4

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x3d7771d7c344aed38957d8d6f158526f00318f4c741b1d1231d87341d1b1bb14Initialize79399512022-03-15 14:04:30202 days 9 hrs agoAave: Deployer IN 0xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH0.000129193288 ETH
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x1057f25e3db0e4f23365cd24e3037eb17c85d9f8779f69aeafe3368b664be8ec282339332022-10-03 23:27:062 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x49242ed67700e6b9211624726a18f379d3540dbe5dfe04a15f68f0a5d9662dc9282328002022-10-03 23:15:1114 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x316f5519cfa84ef1d9a93648c11f8d04ecca21227f4883463ed9b324325bc372282327352022-10-03 23:14:0715 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x2d1e5dce60bbcfafd0090812999b05ef22892c771fcafe4d21193b9e69f3f9ed282324852022-10-03 23:11:0018 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x17df781de232eabe6e5b7586fccf8983db72ef20f5f507da7a1ac45cf621f6f9282319722022-10-03 23:04:1225 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x17df781de232eabe6e5b7586fccf8983db72ef20f5f507da7a1ac45cf621f6f9282319722022-10-03 23:04:1225 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x17df781de232eabe6e5b7586fccf8983db72ef20f5f507da7a1ac45cf621f6f9282319722022-10-03 23:04:1225 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x17df781de232eabe6e5b7586fccf8983db72ef20f5f507da7a1ac45cf621f6f9282319722022-10-03 23:04:1225 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x3bd19c024bb3cff92b926e5b5378408385af5c44a9fa45f568a8091ba7e50dca282317162022-10-03 23:01:1228 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x7af12220fae4395ea5d3f709836dce19d8d757641bdc49867e10458fa5dc46de282316222022-10-03 23:00:1129 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x20f6e85cf6fd07362a003379ca1d13d9a9cf9cac9e6ec5e25aa3ffad301b824d282315822022-10-03 22:59:4130 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x1c4679e4fb2167ba3f0e407e5c54dfb23946458e46fae01e8d20b8499bcd166e282314432022-10-03 22:57:4132 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x51546a214315a3e573ba7da8969c871b8c5053df8442088ba230b0c7edec25e1282313822022-10-03 22:57:0132 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0xc021e03214175f5b5ed59c520aff53d51a3c14f7a127437872cc2d4f6474f2b3282313572022-10-03 22:56:4233 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x05125ce27f5eb5af43fa1804f3d36a0aeab55ae64591b055247a4306aecfdc27282313382022-10-03 22:56:2633 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x05125ce27f5eb5af43fa1804f3d36a0aeab55ae64591b055247a4306aecfdc27282313382022-10-03 22:56:2633 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x05125ce27f5eb5af43fa1804f3d36a0aeab55ae64591b055247a4306aecfdc27282313382022-10-03 22:56:2633 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0xa3b583b2d0ff18ecb2bcec6ca5760d50e77356d954039dbe94b839209d4b0e19282313352022-10-03 22:56:2533 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x5f5f44cd7d7007a151f622f27dc9139f096d3dcbd7b9e4b34b2a61832f5a16f6282312522022-10-03 22:55:1934 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x3e20b61bbbc1de107e70795602ebdda8d15aed70ac1bbfd8e9b911c71e15c6f4282311822022-10-03 22:54:3035 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0xdb137975b22e69836d84582b44a948bd535b13642e82db95331fd91c0588b8b6282311292022-10-03 22:53:5236 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x9b2ecb81789d2b2c2bb3219d88cd6b6960c4e833e1d9d0e9462d3eb22923d7fe282309272022-10-03 22:50:3939 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0xf836dbddfcbb44388a738c22af71e9ba66c821ad1f24a7d1b6eb66d74cfcc535282308242022-10-03 22:48:5840 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0x63a3fda96ff007e6f3bdba77c3d8867eda39e25e3d4a9daca8f8bfb48136f72c282307472022-10-03 22:47:4342 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
0xeb86894274ce070278bfb6dc0813d325e50d88c07273a1f275ed86f2e8a1a2f7282307132022-10-03 22:47:0342 mins ago Aave: Incentives V30xaad324f7e4dd50c6b105820f8a877ee2dcbfa7890 ETH
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RewardsController

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 100000 runs

Other Settings:
default evmVersion, BSL 1.1 license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 12 : IERC20.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.10;

/**
 * @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);
}

File 2 of 12 : IERC20Detailed.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.10;

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);
}

File 3 of 12 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)
pragma solidity 0.8.10;

/**
 * @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);
  }
}

File 4 of 12 : IScaledBalanceToken.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.10;

/**
 * @title IScaledBalanceToken
 * @author Aave
 * @notice Defines the basic interface for a scaledbalance 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 scaled balance tokens
   * @param value The amount being minted (user entered amount + balance increase from interest)
   * @param balanceIncrease The increase in balance since the last action of the user
   * @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 scaled balance tokens are burned
   * @param from The address from which the scaled tokens will be burned
   * @param target The address that will receive the underlying, if any
   * @param value The amount being burned (user entered amount - balance increase from interest)
   * @param balanceIncrease The increase in balance since the last action of the user
   * @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);
}

File 5 of 12 : VersionedInitializable.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.10;

/**
 * @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;
}

File 6 of 12 : 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);
}

File 7 of 12 : RewardsController.sol
// 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
   * @param emissionManager address of the EmissionManager
   **/
  function initialize(address emissionManager) external initializer {
    _setEmissionManager(emissionManager);
  }

  /// @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));
  }
}

File 8 of 12 : RewardsDistributor.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.10;

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 internal _emissionManager;

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

  // reward => enabled
  mapping(address => bool) internal _isRewardEnabled;

  // global rewards list
  address[] internal _rewardsList;

  //global assets list
  address[] internal _assetsList;

  modifier onlyEmissionManager() {
    require(msg.sender == _emissionManager, 'ONLY_EMISSION_MANAGER');
    _;
  }

  constructor(address emissionManager) {
    _setEmissionManager(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 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,
        IERC20Detailed(asset).totalSupply(),
        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) {
        continue;
      }
      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 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 _emissionManager;
  }

  /// @inheritdoc IRewardsDistributor
  function setEmissionManager(address emissionManager) external onlyEmissionManager {
    _setEmissionManager(emissionManager);
  }

  /**
   * @dev Updates the address of the emission manager
   * @param emissionManager The address of the new EmissionManager
   */
  function _setEmissionManager(address emissionManager) internal {
    address previousEmissionManager = _emissionManager;
    _emissionManager = emissionManager;
    emit EmissionManagerUpdated(previousEmissionManager, emissionManager);
  }
}

File 9 of 12 : 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 any update that affects the rewards distribution
   * @param user The address of the user
   * @param userBalance The user balance of the asset
   * @param totalSupply The total supply of the asset
   **/
  function handleAction(
    address user,
    uint256 userBalance,
    uint256 totalSupply
  ) 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);
}

File 10 of 12 : 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 Emitted when the emission manager address is updated.
   * @param oldEmissionManager The address of the old emission manager
   * @param newEmissionManager The address of the new emission manager
   */
  event EmissionManagerUpdated(
    address indexed oldEmissionManager,
    address indexed newEmissionManager
  );

  /**
   * @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 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 getEmissionManager() external view returns (address);

  /**
   * @dev Updates the address of the emission manager
   * @param emissionManager The address of the new EmissionManager
   */
  function setEmissionManager(address emissionManager) external;
}

File 11 of 12 : 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;
}

File 12 of 12 : 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 {
    uint104 index; // matches reward index
    uint128 accrued;
  }

  struct RewardData {
    uint104 index;
    uint88 emissionPerSecond;
    uint32 lastUpdateTimestamp;
    uint32 distributionEnd;
    mapping(address => UserData) usersData;
  }

  struct AssetData {
    mapping(address => RewardData) rewards;
    mapping(uint128 => address) availableRewards;
    uint128 availableRewardsCount;
    uint8 decimals;
  }
}

Settings
{
  "evmVersion": "berlin",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 100000
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"emissionManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"reward","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardsAccrued","type":"uint256"}],"name":"Accrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"reward","type":"address"},{"indexed":false,"internalType":"uint256","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"}],"name":"AssetConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"claimer","type":"address"}],"name":"ClaimerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldEmissionManager","type":"address"},{"indexed":true,"internalType":"address","name":"newEmissionManager","type":"address"}],"name":"EmissionManagerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"reward","type":"address"},{"indexed":true,"internalType":"address","name":"rewardOracle","type":"address"}],"name":"RewardOracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"reward","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"reward","type":"address"},{"indexed":true,"internalType":"address","name":"transferStrategy","type":"address"}],"name":"TransferStrategyInstalled","type":"event"},{"inputs":[],"name":"REVISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"claimAllRewards","outputs":[{"internalType":"address[]","name":"rewardsList","type":"address[]"},{"internalType":"uint256[]","name":"claimedAmounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"claimAllRewardsOnBehalf","outputs":[{"internalType":"address[]","name":"rewardsList","type":"address[]"},{"internalType":"uint256[]","name":"claimedAmounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"}],"name":"claimAllRewardsToSelf","outputs":[{"internalType":"address[]","name":"rewardsList","type":"address[]"},{"internalType":"uint256[]","name":"claimedAmounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"reward","type":"address"}],"name":"claimRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"reward","type":"address"}],"name":"claimRewardsOnBehalf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"reward","type":"address"}],"name":"claimRewardsToSelf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint88","name":"emissionPerSecond","type":"uint88"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint32","name":"distributionEnd","type":"uint32"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"reward","type":"address"},{"internalType":"contract ITransferStrategyBase","name":"transferStrategy","type":"address"},{"internalType":"contract IEACAggregatorProxy","name":"rewardOracle","type":"address"}],"internalType":"struct RewardsDataTypes.RewardsConfigInput[]","name":"config","type":"tuple[]"}],"name":"configureAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"address","name":"user","type":"address"}],"name":"getAllUserRewards","outputs":[{"internalType":"address[]","name":"rewardsList","type":"address[]"},{"internalType":"uint256[]","name":"unclaimedAmounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getAssetDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getClaimer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"reward","type":"address"}],"name":"getDistributionEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEmissionManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"reward","type":"address"}],"name":"getRewardOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getRewardsByAsset","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"reward","type":"address"}],"name":"getRewardsData","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardsList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"reward","type":"address"}],"name":"getTransferStrategy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"reward","type":"address"}],"name":"getUserAccruedRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"reward","type":"address"}],"name":"getUserAssetIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"reward","type":"address"}],"name":"getUserRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"userBalance","type":"uint256"}],"name":"handleAction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"emissionManager","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"caller","type":"address"}],"name":"setClaimer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"reward","type":"address"},{"internalType":"uint32","name":"newDistributionEnd","type":"uint32"}],"name":"setDistributionEnd","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"emissionManager","type":"address"}],"name":"setEmissionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address[]","name":"rewards","type":"address[]"},{"internalType":"uint88[]","name":"newEmissionsPerSecond","type":"uint88[]"}],"name":"setEmissionPerSecond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"reward","type":"address"},{"internalType":"contract IEACAggregatorProxy","name":"rewardOracle","type":"address"}],"name":"setRewardOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"reward","type":"address"},{"internalType":"contract ITransferStrategyBase","name":"transferStrategy","type":"address"}],"name":"setTransferStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405260006005553480156200001657600080fd5b50604051620048153803806200481583398101604081905262000039916200009d565b8062000045816200004d565b5050620000cf565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f53271355c244f99d37f622c90fe574eb7c35c7b3548ea276cf9b5b11c601605e9190a35050565b600060208284031215620000b057600080fd5b81516001600160a01b0381168114620000c857600080fd5b9392505050565b61473680620000df6000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c80637eff4ba811610104578063bb492bf5116100a2578063dde43cba11610071578063dde43cba146105df578063e15ac623146105e7578063f5cf673b146105fa578063f996868b1461060d57600080fd5b8063bb492bf514610593578063bf90f63a146105a6578063c4d66de8146105b9578063c5a7b538146105cc57600080fd5b80639efd6f72116100de5780639efd6f72146105035780639ff55db914610565578063b022418c14610578578063b45ac1a91461058b57600080fd5b80637eff4ba8146103f657806392074b08146104d2578063955c2ad7146104f057600080fd5b8063533f542a116101715780635f130b241161014b5780635f130b24146103515780636657732f1461038a57806370674ab9146103aa57806374d945ec146103bd57600080fd5b8063533f542a146102c75780635453ba101461032b57806357b898831461033e57600080fd5b806331873e2e116101ad57806331873e2e1461026b57806333028b99146102805780634c0369c3146102935780634f7459d5146102b457600080fd5b80631b839c77146101d4578063236300dc146101fa5780632a17bf601461020d575b600080fd5b6101e76101e2366004613cce565b610620565b6040519081526020015b60405180910390f35b6101e7610208366004613d4c565b610680565b61024661021b366004613dc0565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152603b60205260409020541690565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f1565b61027e610279366004613de4565b61071d565b005b6101e761028e366004613e19565b61072e565b6102a66102a1366004613e9e565b6108da565b6040516101f1929190613f46565b61027e6102c2366004613dc0565b610c30565b6101e76102d5366004613f9d565b73ffffffffffffffffffffffffffffffffffffffff808316600090815260016020818152604080842086861685528252808420948816845293909101905220546cffffffffffffffffffffffffff169392505050565b61027e610339366004613cce565b610cbd565b6101e761034c366004613fdd565b610d4c565b61024661035f366004613dc0565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152603a60205260409020541690565b61039d610398366004613dc0565b610d66565b6040516101f1919061403c565b6101e76103b836600461404f565b610eb8565b6102466103cb366004613dc0565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152603960205260409020541690565b6104b2610404366004613cce565b73ffffffffffffffffffffffffffffffffffffffff91821660009081526001602090815260408083209390941682529190915220546cffffffffffffffffffffffffff8116916affffffffffffffffffffff6d01000000000000000000000000008304169163ffffffff780100000000000000000000000000000000000000000000000082048116927c01000000000000000000000000000000000000000000000000000000009092041690565b6040805194855260208501939093529183015260608201526080016101f1565b60005473ffffffffffffffffffffffffffffffffffffffff16610246565b61027e6104fe366004614187565b610ecf565b610553610511366004613dc0565b73ffffffffffffffffffffffffffffffffffffffff16600090815260016020526040902060020154700100000000000000000000000000000000900460ff1690565b60405160ff90911681526020016101f1565b6102a661057336600461404f565b6110ae565b6101e7610586366004613cce565b61125d565b61039d611316565b6102a66105a1366004613e9e565b611385565b6102a66105b43660046142b5565b61141e565b61027e6105c7366004613dc0565b61143a565b61027e6105da3660046142f7565b61155f565b6101e7600181565b61027e6105f5366004613cce565b6116f7565b61027e610608366004613cce565b611782565b61027e61061b36600461433e565b61187f565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600160209081526040808320938516835292905220547c0100000000000000000000000000000000000000000000000000000000900463ffffffff165b92915050565b600073ffffffffffffffffffffffffffffffffffffffff8316610704576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f494e56414c49445f544f5f41444452455353000000000000000000000000000060448201526064015b60405180910390fd5b61071386868633338888611cd5565b9695505050505050565b61072933848385611f66565b505050565b73ffffffffffffffffffffffffffffffffffffffff8084166000908152603960205260408120549091339186911682146107c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f434c41494d45525f554e415554484f52495a454400000000000000000000000060448201526064016106fb565b73ffffffffffffffffffffffffffffffffffffffff8616610841576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f494e56414c49445f555345525f4144445245535300000000000000000000000060448201526064016106fb565b73ffffffffffffffffffffffffffffffffffffffff85166108be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f494e56414c49445f544f5f41444452455353000000000000000000000000000060448201526064016106fb565b6108cd898989338a8a8a611cd5565b9998505050505050505050565b60608060006108ea868686612119565b60035490915067ffffffffffffffff811115610908576109086140ac565b604051908082528060200260200182016040528015610931578160200160208202803683370190505b509250825167ffffffffffffffff81111561094e5761094e6140ac565b604051908082528060200260200182016040528015610977578160200160208202803683370190505b50915060005b8151811015610c255760005b8451811015610c1257600381815481106109a5576109a56143c1565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168582815181106109e2576109e26143c1565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060016000848481518110610a3257610a326143c1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016000868381518110610a8f57610a8f6143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600d9054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16848281518110610b5557610b556143c1565b60200260200101818151610b69919061441f565b9052508251839083908110610b8057610b806143c1565b60200260200101516020015160001415610b9957610c00565b610bd686868381518110610baf57610baf6143c1565b6020026020010151858581518110610bc957610bc96143c1565b6020026020010151612317565b848281518110610be857610be86143c1565b60200260200101818151610bfc919061441f565b9052505b80610c0a81614437565b915050610989565b5080610c1d81614437565b91505061097d565b50505b935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610cb1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f4e4c595f454d495353494f4e5f4d414e41474552000000000000000000000060448201526064016106fb565b610cba816123e5565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f4e4c595f454d495353494f4e5f4d414e41474552000000000000000000000060448201526064016106fb565b610d48828261245a565b5050565b6000610d5d85858533333388611cd5565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600160205260408120600201546060916fffffffffffffffffffffffffffffffff909116908167ffffffffffffffff811115610dc057610dc06140ac565b604051908082528060200260200182016040528015610de9578160200160208202803683370190505b50905060005b826fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff161015610eb05773ffffffffffffffffffffffffffffffffffffffff80861660009081526001602081815260408084206fffffffffffffffffffffffffffffffff871680865293019091529091205484519216918491908110610e7957610e796143c1565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015280610ea881614470565b915050610def565b509392505050565b6000610d5d8383610eca888888612119565b6125ae565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f4e4c595f454d495353494f4e5f4d414e41474552000000000000000000000060448201526064016106fb565b60005b81518110156110a457818181518110610f6e57610f6e6143c1565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1663b1bf962d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe891906144a0565b828281518110610ffa57610ffa6143c1565b6020026020010151602001818152505061104e82828151811061101f5761101f6143c1565b60200260200101516080015183838151811061103d5761103d6143c1565b602002602001015160a001516126b7565b611092828281518110611063576110636143c1565b602002602001015160800151838381518110611081576110816143c1565b602002602001015160c0015161245a565b8061109c81614437565b915050610f53565b50610cba8161281d565b73ffffffffffffffffffffffffffffffffffffffff808316600090815260396020526040902054606091829133918691168214611147576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f434c41494d45525f554e415554484f52495a454400000000000000000000000060448201526064016106fb565b73ffffffffffffffffffffffffffffffffffffffff86166111c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f494e56414c49445f555345525f4144445245535300000000000000000000000060448201526064016106fb565b73ffffffffffffffffffffffffffffffffffffffff8516611241576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f494e56414c49445f544f5f41444452455353000000000000000000000000000060448201526064016106fb565b61124e88883389896130be565b93509350505094509492505050565b60008060005b600454811015610eb0576001600060048381548110611284576112846143c1565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff908116845283820194909452604092830182208885168352815282822093891682526001909301909252902054611302906d010000000000000000000000000090046fffffffffffffffffffffffffffffffff168361441f565b91508061130e81614437565b915050611263565b6060600380548060200260200160405190810160405280929190818152602001828054801561137b57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611350575b5050505050905090565b60608073ffffffffffffffffffffffffffffffffffffffff8316611405576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f494e56414c49445f544f5f41444452455353000000000000000000000000000060448201526064016106fb565b61141285853333876130be565b91509150935093915050565b60608061142e84843333336130be565b915091505b9250929050565b60065460019060ff168061144d5750303b155b80611459575060055481115b6114e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560448201527f656e20696e697469616c697a656400000000000000000000000000000000000060648201526084016106fb565b60065460ff1615801561152357600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560058290555b61152c836123e5565b801561072957600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146115e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f4e4c595f454d495353494f4e5f4d414e41474552000000000000000000000060448201526064016106fb565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902080547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81167c010000000000000000000000000000000000000000000000000000000063ffffffff8981168281029384179586905587516d01000000000000000000000000009096046affffffffffffffffffffff16808752968601969096529083041694830185905260608301939093526cffffffffffffffffffffffffff9081169216919091176080820152909291907fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc59060a00160405180910390a350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611778576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f4e4c595f454d495353494f4e5f4d414e41474552000000000000000000000060448201526064016106fb565b610d4882826126b7565b60005473ffffffffffffffffffffffffffffffffffffffff163314611803576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f4e4c595f454d495353494f4e5f4d414e41474552000000000000000000000060448201526064016106fb565b73ffffffffffffffffffffffffffffffffffffffff82811660008181526039602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f4925eafc82d0c4d67889898eeed64b18488ab19811e61620f387026dec126a289190a35050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611900576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f4e4c595f454d495353494f4e5f4d414e41474552000000000000000000000060448201526064016106fb565b828114611969576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f494e56414c49445f494e5055540000000000000000000000000000000000000060448201526064016106fb565b60005b83811015611ccd5773ffffffffffffffffffffffffffffffffffffffff861660009081526001602052604081209081818888868181106119ae576119ae6143c1565b90506020020160208101906119c39190613dc0565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000206002830154909150700100000000000000000000000000000000900460ff168015801590611a39575081547801000000000000000000000000000000000000000000000000900463ffffffff1615155b611a9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f444953545249425554494f4e5f444f45535f4e4f545f4558495354000000000060448201526064016106fb565b6000611b24838b73ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1491906144a0565b611b1f85600a6145d9565b6135a6565b5083549091506d010000000000000000000000000090046affffffffffffffffffffff16878787818110611b5a57611b5a6143c1565b9050602002016020810190611b6f91906145e5565b84546affffffffffffffffffffff919091166d0100000000000000000000000000027fffffffffffffffff0000000000000000000000ffffffffffffffffffffffffff909116178455898987818110611bca57611bca6143c1565b9050602002016020810190611bdf9190613dc0565b73ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff167fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc5838b8b8b818110611c4057611c406143c1565b9050602002016020810190611c5591906145e5565b8854604080519384526affffffffffffffffffffff90921660208401527c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690820181905260608201526080810186905260a00160405180910390a350505050508080611cc590614437565b91505061196c565b505050505050565b600085611ce457506000611f5b565b6000611cfa85611cf58b8b89612119565b613734565b60005b88811015611ee15760008a8a83818110611d1957611d196143c1565b9050602002016020810190611d2e9190613dc0565b73ffffffffffffffffffffffffffffffffffffffff81811660009081526001602081815260408084208b861685528252808420948d1684529390910190522054909150611d9e906d010000000000000000000000000090046fffffffffffffffffffffffffffffffff168461441f565b9250888311611e115773ffffffffffffffffffffffffffffffffffffffff80821660009081526001602081815260408084208a861685528252808420948c1684529390910190522080547fffffff00000000000000000000000000000000ffffffffffffffffffffffffff169055611ece565b6000611e1d8a85614600565b9050611e298185614600565b9350611e34816137b5565b73ffffffffffffffffffffffffffffffffffffffff92831660009081526001602081815260408084208b881685528252808420968d1684529590910190529290922080546fffffffffffffffffffffffffffffffff939093166d0100000000000000000000000000027fffffff00000000000000000000000000000000ffffffffffffffffffffffffff9093169290921790915550611ee1565b5080611ed981614437565b915050611cfd565b5080611ef1576000915050611f5b565b611efc84848361385b565b6040805173ffffffffffffffffffffffffffffffffffffffff8881168252602082018490528087169286821692918916917fc052130bc4ef84580db505783484b067ea8b71b3bca78a7e12db7aea8658f004910160405180910390a490505b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff841660009081526001602052604090206002015460ff700100000000000000000000000000000000820416600a0a906fffffffffffffffffffffffffffffffff1680611fc8575050612113565b60005b81816fffffffffffffffffffffffffffffffff16101561210f5773ffffffffffffffffffffffffffffffffffffffff80881660009081526001602081815260408084206fffffffffffffffffffffffffffffffff8716855292830182528084205490941680845291905291812090806120458389896135a6565b91509150600080612059858d8d878d613987565b9150915082806120665750805b156120fd578b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff167f3303facd24627943a92e9dc87cfbb34b15c49b726eec3ad3487c16be9ab8efe88788876040516120f4939291909283526020830191909152604082015260600190565b60405180910390a45b505060019094019350611fcb92505050565b5050505b50505050565b60608267ffffffffffffffff811115612134576121346140ac565b60405190808252806020026020018201604052801561219f57816020015b61218c6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b8152602001906001900390816121525790505b50905060005b83811015610eb0578484828181106121bf576121bf6143c1565b90506020020160208101906121d49190613dc0565b8282815181106121e6576121e66143c1565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff909116905284848281811061221d5761221d6143c1565b90506020020160208101906122329190613dc0565b6040517f0afbcdc900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301529190911690630afbcdc9906024016040805180830381865afa15801561229f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c39190614617565b8383815181106122d5576122d56143c1565b60200260200101516020018484815181106122f2576122f26143c1565b602090810291909101015160400191909152528061230f81614437565b9150506121a5565b805173ffffffffffffffffffffffffffffffffffffffff90811660009081526001602081815260408084208786168552825280842086519095168452919052812060020154909190829061238390700100000000000000000000000000000000900460ff16600a61463b565b9050600061239683866040015184613ae6565b60208088015173ffffffffffffffffffffffffffffffffffffffff8b16600090815260018801909252604090912054919350611f5b92509083906cffffffffffffffffffffffffff1685613bf2565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f53271355c244f99d37f622c90fe574eb7c35c7b3548ea276cf9b5b11c601605e9190a35050565b60008173ffffffffffffffffffffffffffffffffffffffff166350d25bcd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cb91906144a0565b13612532576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4f5241434c455f4d5553545f52455455524e5f5052494345000000000000000060448201526064016106fb565b73ffffffffffffffffffffffffffffffffffffffff8281166000818152603b602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f1a1cd5483e52e60b9ff7f3b9d1db3bbd9e9d21c6324ad3a8c79dba9b75e62f4d9190a35050565b6000805b8251811015610eb0578281815181106125cd576125cd6143c1565b602002602001015160200151600014156125e6576126a5565b600160008483815181106125fc576125fc6143c1565b6020908102919091018101515173ffffffffffffffffffffffffffffffffffffffff908116835282820193909352604091820160009081208885168252825282812093891681526001909301905290205483516d01000000000000000000000000009091046fffffffffffffffffffffffffffffffff169061268e9087908790879086908110610bc957610bc96143c1565b612698919061441f565b6126a2908361441f565b91505b806126af81614437565b9150506125b2565b73ffffffffffffffffffffffffffffffffffffffff8116612734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f53545241544547595f43414e5f4e4f545f42455f5a45524f000000000000000060448201526064016106fb565b6001813b1515146127a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f53545241544547595f4d5553545f42455f434f4e54524143540000000000000060448201526064016106fb565b73ffffffffffffffffffffffffffffffffffffffff8281166000818152603a602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055517f8ca1d928f1d72493a6b78c4f74aabde976bc37ffe2570f2a1ce5a8abd3dde0aa9190a35050565b60005b8151811015610d48576001600083838151811061283f5761283f6143c1565b6020908102919091018101516060015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002060020154700100000000000000000000000000000000900460ff1661290b5760048282815181106128a6576128a66143c1565b6020908102919091018101516060015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790555b600082828151811061291f5761291f6143c1565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612975573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612999919061464a565b600160008585815181106129af576129af6143c1565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160106101000a81548160ff021916908360ff160217905560ff169050600060016000858581518110612a2c57612a2c6143c1565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000016000858581518110612a8957612a896143c1565b6020908102919091018101516080015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080549091507801000000000000000000000000000000000000000000000000900463ffffffff16612cf857838381518110612afa57612afa6143c1565b60200260200101516080015160016000868681518110612b1c57612b1c6143c1565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101600060016000888881518110612b7d57612b7d6143c1565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016000858581518110612c6957612c696143c1565b6020908102919091018101516060015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600090812060020180546fffffffffffffffffffffffffffffffff1691612cc083614470565b91906101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550505b60026000858581518110612d0e57612d0e6143c1565b6020908102919091018101516080015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff16612e3857600160026000868681518110612d6257612d626143c1565b60200260200101516080015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506003848481518110612dd357612dd36143c1565b6020908102919091018101516080015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790555b6000612e6982868681518110612e5057612e506143c1565b60200260200101516020015185600a611b1f91906145d9565b50825486519192506d010000000000000000000000000081046affffffffffffffffffffff16917c010000000000000000000000000000000000000000000000000000000090910463ffffffff1690879087908110612eca57612eca6143c1565b60209081029190910101515184546affffffffffffffffffffff9091166d0100000000000000000000000000027fffffffffffffffff0000000000000000000000ffffffffffffffffffffffffff9091161784558651879087908110612f3257612f326143c1565b602090810291909101015160400151845463ffffffff9091167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091161784558651879087908110612fa157612fa16143c1565b60200260200101516080015173ffffffffffffffffffffffffffffffffffffffff16878781518110612fd557612fd56143c1565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff167fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc5848a8a8151811061302b5761302b6143c1565b602002602001015160000151858c8c8151811061304a5761304a6143c1565b6020026020010151604001518960405161309e9594939291906affffffffffffffffffffff958616815293909416602084015263ffffffff9182166040840152166060820152608081019190915260a00190565b60405180910390a3505050505080806130b690614437565b915050612820565b60035460609081908067ffffffffffffffff8111156130df576130df6140ac565b604051908082528060200260200182016040528015613108578160200160208202803683370190505b5092508067ffffffffffffffff811115613124576131246140ac565b60405190808252806020026020018201604052801561314d578160200160208202803683370190505b50915061315f85611cf58a8a89612119565b60005b8781101561346e57600089898381811061317e5761317e6143c1565b90506020020160208101906131939190613dc0565b905060005b8381101561345957600073ffffffffffffffffffffffffffffffffffffffff168682815181106131ca576131ca6143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614156132795760038181548110613201576132016143c1565b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1686828151811061323e5761323e6143c1565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260408120875182908990859081106132b4576132b46143c1565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff90811683528282019390935260409182016000908120938d168152600190930190529020546d010000000000000000000000000090046fffffffffffffffffffffffffffffffff16905080156134465780868381518110613338576133386143c1565b6020026020010181815161334c919061441f565b90525073ffffffffffffffffffffffffffffffffffffffff83166000908152600160205260408120885182908a908690811061338a5761338a6143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600d6101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505b508061345181614437565b915050613198565b5050808061346690614437565b915050613162565b5060005b8181101561359a576134b785858381518110613490576134906143c1565b60200260200101518584815181106134aa576134aa6143c1565b602002602001015161385b565b8473ffffffffffffffffffffffffffffffffffffffff168482815181106134e0576134e06143c1565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fc052130bc4ef84580db505783484b067ea8b71b3bca78a7e12db7aea8658f0048a878681518110613549576135496143c1565b602002602001015160405161358092919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a48061359281614437565b915050613472565b50509550959350505050565b6000806000806135b7878787613ae6565b9150915060008282146136d0576cffffffffffffffffffffffffff82111561363b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e4445585f4f564552464c4f5700000000000000000000000000000000000060448201526064016106fb565b5086547fffffffffffffffffffffffffffffffffffffff00000000000000000000000000166cffffffffffffffffffffffffff8216178755600161367e42613c16565b885463ffffffff919091167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff909116178855613727565b6136d942613c16565b885463ffffffff919091167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9091161788555b9097909650945050505050565b60005b8151811015610729576137a3828281518110613755576137556143c1565b60200260200101516000015184848481518110613774576137746143c1565b602002602001015160200151858581518110613792576137926143c1565b602002602001015160400151611f66565b806137ad81614437565b915050613737565b60006fffffffffffffffffffffffffffffffff821115613857576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201527f323820626974730000000000000000000000000000000000000000000000000060648201526084016106fb565b5090565b73ffffffffffffffffffffffffffffffffffffffff8281166000818152603a60205260408082205490517f16beb9820000000000000000000000000000000000000000000000000000000081528785166004820152602481019390935260448301859052909216919082906316beb982906064016020604051808303816000875af11580156138ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613912919061466d565b9050600181151514613980576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f5452414e534645525f4552524f5200000000000000000000000000000000000060448201526064016106fb565b5050505050565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260018601602052604081205481906cffffffffffffffffffffffffff1681858214801590613ad75773ffffffffffffffffffffffffffffffffffffffff8916600090815260018b016020526040902080547fffffffffffffffffffffffffffffffffffffff00000000000000000000000000166cffffffffffffffffffffffffff89161790558715613ad757613a3b88888589613bf2565b9150613a46826137b5565b73ffffffffffffffffffffffffffffffffffffffff8a16600090815260018c01602052604090208054600d90613aa09084906d010000000000000000000000000090046fffffffffffffffffffffffffffffffff1661468f565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505b90999098509650505050505050565b825460009081906cffffffffffffffffffffffffff81169063ffffffff7c010000000000000000000000000000000000000000000000000000000082048116916affffffffffffffffffffff6d010000000000000000000000000082041691780100000000000000000000000000000000000000000000000090910416811580613b6e575087155b80613b7857504281145b80613b835750828110155b15613b975783849550955050505050610c28565b6000834211613ba65742613ba8565b835b90506000613bb68383614600565b9050600089613bc583876146c3565b613bcf91906146c3565b8b9004905086613bdf818361441f565b9850985050505050505050935093915050565b600080613bff8486614600565b613c0990876146c3565b9290920495945050505050565b600063ffffffff821115613857576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201527f322062697473000000000000000000000000000000000000000000000000000060648201526084016106fb565b73ffffffffffffffffffffffffffffffffffffffff81168114610cba57600080fd5b60008060408385031215613ce157600080fd5b8235613cec81613cac565b91506020830135613cfc81613cac565b809150509250929050565b60008083601f840112613d1957600080fd5b50813567ffffffffffffffff811115613d3157600080fd5b6020830191508360208260051b850101111561143357600080fd5b600080600080600060808688031215613d6457600080fd5b853567ffffffffffffffff811115613d7b57600080fd5b613d8788828901613d07565b909650945050602086013592506040860135613da281613cac565b91506060860135613db281613cac565b809150509295509295909350565b600060208284031215613dd257600080fd5b8135613ddd81613cac565b9392505050565b600080600060608486031215613df957600080fd5b8335613e0481613cac565b95602085013595506040909401359392505050565b60008060008060008060a08789031215613e3257600080fd5b863567ffffffffffffffff811115613e4957600080fd5b613e5589828a01613d07565b909750955050602087013593506040870135613e7081613cac565b92506060870135613e8081613cac565b91506080870135613e9081613cac565b809150509295509295509295565b600080600060408486031215613eb357600080fd5b833567ffffffffffffffff811115613eca57600080fd5b613ed686828701613d07565b9094509250506020840135613eea81613cac565b809150509250925092565b600081518084526020808501945080840160005b83811015613f3b57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613f09565b509495945050505050565b604081526000613f596040830185613ef5565b82810360208481019190915284518083528582019282019060005b81811015613f9057845183529383019391830191600101613f74565b5090979650505050505050565b600080600060608486031215613fb257600080fd5b8335613fbd81613cac565b92506020840135613fcd81613cac565b91506040840135613eea81613cac565b60008060008060608587031215613ff357600080fd5b843567ffffffffffffffff81111561400a57600080fd5b61401687828801613d07565b90955093505060208501359150604085013561403181613cac565b939692955090935050565b602081526000613ddd6020830184613ef5565b6000806000806060858703121561406557600080fd5b843567ffffffffffffffff81111561407c57600080fd5b61408887828801613d07565b909550935050602085013561409c81613cac565b9150604085013561403181613cac565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff811182821017156140fe576140fe6140ac565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561414b5761414b6140ac565b604052919050565b80356affffffffffffffffffffff8116811461416e57600080fd5b919050565b803563ffffffff8116811461416e57600080fd5b6000602080838503121561419a57600080fd5b823567ffffffffffffffff808211156141b257600080fd5b818501915085601f8301126141c657600080fd5b8135818111156141d8576141d86140ac565b6141e6848260051b01614104565b818152848101925060e091820284018501918883111561420557600080fd5b938501935b828510156142a95780858a0312156142225760008081fd5b61422a6140db565b61423386614153565b81528686013587820152604061424a818801614173565b9082015260608681013561425d81613cac565b9082015260808681013561427081613cac565b9082015260a08681013561428381613cac565b9082015260c08681013561429681613cac565b908201528452938401939285019261420a565b50979650505050505050565b600080602083850312156142c857600080fd5b823567ffffffffffffffff8111156142df57600080fd5b6142eb85828601613d07565b90969095509350505050565b60008060006060848603121561430c57600080fd5b833561431781613cac565b9250602084013561432781613cac565b915061433560408501614173565b90509250925092565b60008060008060006060868803121561435657600080fd5b853561436181613cac565b9450602086013567ffffffffffffffff8082111561437e57600080fd5b61438a89838a01613d07565b909650945060408801359150808211156143a357600080fd5b506143b088828901613d07565b969995985093965092949392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115614432576144326143f0565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614469576144696143f0565b5060010190565b60006fffffffffffffffffffffffffffffffff80831681811415614496576144966143f0565b6001019392505050565b6000602082840312156144b257600080fd5b5051919050565b600181815b8085111561451257817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156144f8576144f86143f0565b8085161561450557918102915b93841c93908002906144be565b509250929050565b6000826145295750600161067a565b816145365750600061067a565b816001811461454c576002811461455657614572565b600191505061067a565b60ff841115614567576145676143f0565b50506001821b61067a565b5060208310610133831016604e8410600b8410161715614595575081810a61067a565b61459f83836144b9565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156145d1576145d16143f0565b029392505050565b6000613ddd838361451a565b6000602082840312156145f757600080fd5b613ddd82614153565b600082821015614612576146126143f0565b500390565b6000806040838503121561462a57600080fd5b505080516020909101519092909150565b6000613ddd60ff84168361451a565b60006020828403121561465c57600080fd5b815160ff81168114613ddd57600080fd5b60006020828403121561467f57600080fd5b81518015158114613ddd57600080fd5b60006fffffffffffffffffffffffffffffffff8083168185168083038211156146ba576146ba6143f0565b01949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156146fb576146fb6143f0565b50029056fea2646970667358221220c796703301646937034c3b2aa298423ad3ca1a227451675a0e2359d6ba27e96564736f6c634300080a00330000000000000000000000004365f8e70cf38c6ca67de41448508f2da8825500

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000004365f8e70cf38c6ca67de41448508f2da8825500

-----Decoded View---------------
Arg [0] : emissionManager (address): 0x4365f8e70cf38c6ca67de41448508f2da8825500

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004365f8e70cf38c6ca67de41448508f2da8825500


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.