Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
7408285 | 11 days ago | Contract Creation | 0 S |
Loading...
Loading
Contract Name:
RewardsController
Compiler Version
v0.8.22+commit.4fc1097e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.10; import {VersionedInitializable} from '../misc/aave-upgradeability/VersionedInitializable.sol'; import {SafeCast} from '../dependencies/openzeppelin/contracts/SafeCast.sol'; import {IScaledBalanceToken} from '../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 {AggregatorInterface} from '../dependencies/chainlink/AggregatorInterface.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 => AggregatorInterface) internal _rewardOracle; modifier onlyAuthorizedClaimers(address claimer, address user) { require(_authorizedClaimers[user] == claimer, 'CLAIMER_UNAUTHORIZED'); _; } constructor(address emissionManager) RewardsDistributor(emissionManager) {} /** * @dev Initialize for RewardsController * @dev It expects an address as argument since its initialized via PoolAddressesProvider._updateImpl() **/ function initialize(address) external initializer {} /// @inheritdoc IRewardsController function getClaimer(address user) external view override returns (address) { return _authorizedClaimers[user]; } /** * @dev Returns the revision of the implementation contract * @return uint256, current revision version */ function getRevision() internal pure override returns (uint256) { return REVISION; } /// @inheritdoc IRewardsController function getRewardOracle(address reward) external view override returns (address) { return address(_rewardOracle[reward]); } /// @inheritdoc IRewardsController function getTransferStrategy(address reward) external view override returns (address) { return address(_transferStrategy[reward]); } /// @inheritdoc IRewardsController function configureAssets( RewardsDataTypes.RewardsConfigInput[] memory config ) external override onlyEmissionManager { for (uint256 i = 0; i < config.length; i++) { // Get the current Scaled Total Supply of AToken or Debt token config[i].totalSupply = IScaledBalanceToken(config[i].asset).scaledTotalSupply(); // Install TransferStrategy logic at IncentivesController _installTransferStrategy(config[i].reward, config[i].transferStrategy); // Set reward oracle, enforces input oracle to have latestPrice function _setRewardOracle(config[i].reward, config[i].rewardOracle); } _configureAssets(config); } /// @inheritdoc IRewardsController function setTransferStrategy( address reward, ITransferStrategyBase transferStrategy ) external onlyEmissionManager { _installTransferStrategy(reward, transferStrategy); } /// @inheritdoc IRewardsController function setRewardOracle( address reward, AggregatorInterface 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 AggregatorInterface 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, AggregatorInterface rewardOracle) internal { require(rewardOracle.latestAnswer() > 0, 'ORACLE_MUST_RETURN_PRICE'); _rewardOracle[reward] = rewardOracle; emit RewardOracleUpdated(reward, address(rewardOracle)); } }
// SPDX-License-Identifier: MIT // Chainlink Contracts v0.8 pragma solidity ^0.8.0; interface AggregatorInterface { function decimals() external view returns (uint8); function description() external view returns (string memory); function getRoundData( uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); 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 updatedAt); event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT 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); }
// 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); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IScaledBalanceToken * @author Aave * @notice Defines the basic interface for a scaled-balance token. */ interface IScaledBalanceToken { /** * @dev Emitted after the mint action * @param caller The address performing the mint * @param onBehalfOf The address of the user that will receive the minted tokens * @param value The scaled-up amount being minted (based on user entered amount and balance increase from interest) * @param balanceIncrease The increase in scaled-up balance since the last action of 'onBehalfOf' * @param index The next liquidity index of the reserve */ event Mint( address indexed caller, address indexed onBehalfOf, uint256 value, uint256 balanceIncrease, uint256 index ); /** * @dev Emitted after the burn action * @dev If the burn function does not involve a transfer of the underlying asset, the target defaults to zero address * @param from The address from which the tokens will be burned * @param target The address that will receive the underlying, if any * @param value The scaled-up amount being burned (user entered amount - balance increase from interest) * @param balanceIncrease The increase in scaled-up balance since the last action of 'from' * @param index The next liquidity index of the reserve */ event Burn( address indexed from, address indexed target, uint256 value, uint256 balanceIncrease, uint256 index ); /** * @notice Returns the scaled balance of the user. * @dev The scaled balance is the sum of all the updated stored balance divided by the reserve's liquidity index * at the moment of the update * @param user The user whose balance is calculated * @return The scaled balance of the user */ function scaledBalanceOf(address user) external view returns (uint256); /** * @notice Returns the scaled balance of the user and the scaled total supply. * @param user The address of the user * @return The scaled balance of the user * @return The scaled total supply */ function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256); /** * @notice Returns the scaled total supply of the scaled balance token. Represents sum(debt/index) * @return The scaled total supply */ function scaledTotalSupply() external view returns (uint256); /** * @notice Returns last index interest was accrued to the user's balance * @param user The address of the user * @return The last index interest was accrued to the user's balance, expressed in ray */ function getPreviousIndex(address user) external view returns (uint256); }
// SPDX-License-Identifier: MIT 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; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.10; import {IScaledBalanceToken} from '../interfaces/IScaledBalanceToken.sol'; import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol'; import {SafeCast} from '../dependencies/openzeppelin/contracts/SafeCast.sol'; import {IRewardsDistributor} from './interfaces/IRewardsDistributor.sol'; import {RewardsDataTypes} from './libraries/RewardsDataTypes.sol'; /** * @title RewardsDistributor * @notice Accounting contract to manage multiple staking distributions with multiple rewards * @author Aave **/ abstract contract RewardsDistributor is IRewardsDistributor { using SafeCast for uint256; // Manager of incentives address public immutable EMISSION_MANAGER; // Deprecated: This storage slot is kept for backwards compatibility purposes. address internal _emissionManager; // Map of rewarded asset addresses and their data (assetAddress => assetData) mapping(address => RewardsDataTypes.AssetData) internal _assets; // Map of reward assets (rewardAddress => enabled) mapping(address => bool) internal _isRewardEnabled; // Rewards list address[] internal _rewardsList; // Assets list address[] internal _assetsList; modifier onlyEmissionManager() { require(msg.sender == EMISSION_MANAGER, 'ONLY_EMISSION_MANAGER'); _; } constructor(address emissionManager) { EMISSION_MANAGER = emissionManager; } /// @inheritdoc IRewardsDistributor function getRewardsData( address asset, address reward ) external view override returns (uint256, uint256, uint256, uint256) { return ( _assets[asset].rewards[reward].index, _assets[asset].rewards[reward].emissionPerSecond, _assets[asset].rewards[reward].lastUpdateTimestamp, _assets[asset].rewards[reward].distributionEnd ); } /// @inheritdoc IRewardsDistributor function getAssetIndex( address asset, address reward ) external view override returns (uint256, uint256) { RewardsDataTypes.RewardData storage rewardData = _assets[asset].rewards[reward]; return _getAssetIndex( rewardData, IScaledBalanceToken(asset).scaledTotalSupply(), 10 ** _assets[asset].decimals ); } /// @inheritdoc IRewardsDistributor function getDistributionEnd( address asset, address reward ) external view override returns (uint256) { return _assets[asset].rewards[reward].distributionEnd; } /// @inheritdoc IRewardsDistributor function getRewardsByAsset(address asset) external view override returns (address[] memory) { uint128 rewardsCount = _assets[asset].availableRewardsCount; address[] memory availableRewards = new address[](rewardsCount); for (uint128 i = 0; i < rewardsCount; i++) { availableRewards[i] = _assets[asset].availableRewards[i]; } return availableRewards; } /// @inheritdoc IRewardsDistributor function getRewardsList() external view override returns (address[] memory) { return _rewardsList; } /// @inheritdoc IRewardsDistributor function getUserAssetIndex( address user, address asset, address reward ) external view override returns (uint256) { return _assets[asset].rewards[reward].usersData[user].index; } /// @inheritdoc IRewardsDistributor function getUserAccruedRewards( address user, address reward ) external view override returns (uint256) { uint256 totalAccrued; for (uint256 i = 0; i < _assetsList.length; i++) { totalAccrued += _assets[_assetsList[i]].rewards[reward].usersData[user].accrued; } return totalAccrued; } /// @inheritdoc IRewardsDistributor function getUserRewards( address[] calldata assets, address user, address reward ) external view override returns (uint256) { return _getUserReward(user, reward, _getUserAssetBalances(assets, user)); } /// @inheritdoc IRewardsDistributor function getAllUserRewards( address[] calldata assets, address user ) external view override returns (address[] memory rewardsList, uint256[] memory unclaimedAmounts) { RewardsDataTypes.UserAssetBalance[] memory userAssetBalances = _getUserAssetBalances( assets, user ); rewardsList = new address[](_rewardsList.length); unclaimedAmounts = new uint256[](rewardsList.length); // Add unrealized rewards from user to unclaimedRewards for (uint256 i = 0; i < userAssetBalances.length; i++) { for (uint256 r = 0; r < rewardsList.length; r++) { rewardsList[r] = _rewardsList[r]; unclaimedAmounts[r] += _assets[userAssetBalances[i].asset] .rewards[rewardsList[r]] .usersData[user] .accrued; if (userAssetBalances[i].userBalance == 0) { continue; } unclaimedAmounts[r] += _getPendingRewards(user, rewardsList[r], userAssetBalances[i]); } } return (rewardsList, unclaimedAmounts); } /// @inheritdoc IRewardsDistributor function setDistributionEnd( address asset, address reward, uint32 newDistributionEnd ) external override onlyEmissionManager { uint256 oldDistributionEnd = _assets[asset].rewards[reward].distributionEnd; _assets[asset].rewards[reward].distributionEnd = newDistributionEnd; emit AssetConfigUpdated( asset, reward, _assets[asset].rewards[reward].emissionPerSecond, _assets[asset].rewards[reward].emissionPerSecond, oldDistributionEnd, newDistributionEnd, _assets[asset].rewards[reward].index ); } /// @inheritdoc IRewardsDistributor function setEmissionPerSecond( address asset, address[] calldata rewards, uint88[] calldata newEmissionsPerSecond ) external override onlyEmissionManager { require(rewards.length == newEmissionsPerSecond.length, 'INVALID_INPUT'); for (uint256 i = 0; i < rewards.length; i++) { RewardsDataTypes.AssetData storage assetConfig = _assets[asset]; RewardsDataTypes.RewardData storage rewardConfig = _assets[asset].rewards[rewards[i]]; uint256 decimals = assetConfig.decimals; require( decimals != 0 && rewardConfig.lastUpdateTimestamp != 0, 'DISTRIBUTION_DOES_NOT_EXIST' ); (uint256 newIndex, ) = _updateRewardData( rewardConfig, IScaledBalanceToken(asset).scaledTotalSupply(), 10 ** decimals ); uint256 oldEmissionPerSecond = rewardConfig.emissionPerSecond; rewardConfig.emissionPerSecond = newEmissionsPerSecond[i]; emit AssetConfigUpdated( asset, rewards[i], oldEmissionPerSecond, newEmissionsPerSecond[i], rewardConfig.distributionEnd, rewardConfig.distributionEnd, newIndex ); } } /** * @dev Configure the _assets for a specific emission * @param rewardsInput The array of each asset configuration **/ function _configureAssets(RewardsDataTypes.RewardsConfigInput[] memory rewardsInput) internal { for (uint256 i = 0; i < rewardsInput.length; i++) { if (_assets[rewardsInput[i].asset].decimals == 0) { //never initialized before, adding to the list of assets _assetsList.push(rewardsInput[i].asset); } uint256 decimals = _assets[rewardsInput[i].asset].decimals = IERC20Detailed( rewardsInput[i].asset ).decimals(); RewardsDataTypes.RewardData storage rewardConfig = _assets[rewardsInput[i].asset].rewards[ rewardsInput[i].reward ]; // Add reward address to asset available rewards if latestUpdateTimestamp is zero if (rewardConfig.lastUpdateTimestamp == 0) { _assets[rewardsInput[i].asset].availableRewards[ _assets[rewardsInput[i].asset].availableRewardsCount ] = rewardsInput[i].reward; _assets[rewardsInput[i].asset].availableRewardsCount++; } // Add reward address to global rewards list if still not enabled if (_isRewardEnabled[rewardsInput[i].reward] == false) { _isRewardEnabled[rewardsInput[i].reward] = true; _rewardsList.push(rewardsInput[i].reward); } // Due emissions is still zero, updates only latestUpdateTimestamp (uint256 newIndex, ) = _updateRewardData( rewardConfig, rewardsInput[i].totalSupply, 10 ** decimals ); // Configure emission and distribution end of the reward per asset uint88 oldEmissionsPerSecond = rewardConfig.emissionPerSecond; uint32 oldDistributionEnd = rewardConfig.distributionEnd; rewardConfig.emissionPerSecond = rewardsInput[i].emissionPerSecond; rewardConfig.distributionEnd = rewardsInput[i].distributionEnd; emit AssetConfigUpdated( rewardsInput[i].asset, rewardsInput[i].reward, oldEmissionsPerSecond, rewardsInput[i].emissionPerSecond, oldDistributionEnd, rewardsInput[i].distributionEnd, newIndex ); } } /** * @dev Updates the state of the distribution for the specified reward * @param rewardData Storage pointer to the distribution reward config * @param totalSupply Current total of underlying assets for this distribution * @param assetUnit One unit of asset (10**decimals) * @return The new distribution index * @return True if the index was updated, false otherwise **/ function _updateRewardData( RewardsDataTypes.RewardData storage rewardData, uint256 totalSupply, uint256 assetUnit ) internal returns (uint256, bool) { (uint256 oldIndex, uint256 newIndex) = _getAssetIndex(rewardData, totalSupply, assetUnit); bool indexUpdated; if (newIndex != oldIndex) { require(newIndex <= type(uint104).max, 'INDEX_OVERFLOW'); indexUpdated = true; //optimization: storing one after another saves one SSTORE rewardData.index = uint104(newIndex); rewardData.lastUpdateTimestamp = block.timestamp.toUint32(); } else { rewardData.lastUpdateTimestamp = block.timestamp.toUint32(); } return (newIndex, indexUpdated); } /** * @dev Updates the state of the distribution for the specific user * @param rewardData Storage pointer to the distribution reward config * @param user The address of the user * @param userBalance The user balance of the asset * @param newAssetIndex The new index of the asset distribution * @param assetUnit One unit of asset (10**decimals) * @return The rewards accrued since the last update **/ function _updateUserData( RewardsDataTypes.RewardData storage rewardData, address user, uint256 userBalance, uint256 newAssetIndex, uint256 assetUnit ) internal returns (uint256, bool) { uint256 userIndex = rewardData.usersData[user].index; uint256 rewardsAccrued; bool dataUpdated; if ((dataUpdated = userIndex != newAssetIndex)) { // already checked for overflow in _updateRewardData rewardData.usersData[user].index = uint104(newAssetIndex); if (userBalance != 0) { rewardsAccrued = _getRewards(userBalance, newAssetIndex, userIndex, assetUnit); rewardData.usersData[user].accrued += rewardsAccrued.toUint128(); } } return (rewardsAccrued, dataUpdated); } /** * @dev Iterates and accrues all the rewards for asset of the specific user * @param asset The address of the reference asset of the distribution * @param user The user address * @param userBalance The current user asset balance * @param totalSupply Total supply of the asset **/ function _updateData( address asset, address user, uint256 userBalance, uint256 totalSupply ) internal { uint256 assetUnit; uint256 numAvailableRewards = _assets[asset].availableRewardsCount; unchecked { assetUnit = 10 ** _assets[asset].decimals; } if (numAvailableRewards == 0) { return; } unchecked { for (uint128 r = 0; r < numAvailableRewards; r++) { address reward = _assets[asset].availableRewards[r]; RewardsDataTypes.RewardData storage rewardData = _assets[asset].rewards[reward]; (uint256 newAssetIndex, bool rewardDataUpdated) = _updateRewardData( rewardData, totalSupply, assetUnit ); (uint256 rewardsAccrued, bool userDataUpdated) = _updateUserData( rewardData, user, userBalance, newAssetIndex, assetUnit ); if (rewardDataUpdated || userDataUpdated) { emit Accrued(asset, reward, user, newAssetIndex, newAssetIndex, rewardsAccrued); } } } } /** * @dev Accrues all the rewards of the assets specified in the userAssetBalances list * @param user The address of the user * @param userAssetBalances List of structs with the user balance and total supply of a set of assets **/ function _updateDataMultiple( address user, RewardsDataTypes.UserAssetBalance[] memory userAssetBalances ) internal { for (uint256 i = 0; i < userAssetBalances.length; i++) { _updateData( userAssetBalances[i].asset, user, userAssetBalances[i].userBalance, userAssetBalances[i].totalSupply ); } } /** * @dev Return the accrued unclaimed amount of a reward from a user over a list of distribution * @param user The address of the user * @param reward The address of the reward token * @param userAssetBalances List of structs with the user balance and total supply of a set of assets * @return unclaimedRewards The accrued rewards for the user until the moment **/ function _getUserReward( address user, address reward, RewardsDataTypes.UserAssetBalance[] memory userAssetBalances ) internal view returns (uint256 unclaimedRewards) { // Add unrealized rewards for (uint256 i = 0; i < userAssetBalances.length; i++) { if (userAssetBalances[i].userBalance == 0) { unclaimedRewards += _assets[userAssetBalances[i].asset] .rewards[reward] .usersData[user] .accrued; } else { unclaimedRewards += _getPendingRewards(user, reward, userAssetBalances[i]) + _assets[userAssetBalances[i].asset].rewards[reward].usersData[user].accrued; } } return unclaimedRewards; } /** * @dev Calculates the pending (not yet accrued) rewards since the last user action * @param user The address of the user * @param reward The address of the reward token * @param userAssetBalance struct with the user balance and total supply of the incentivized asset * @return The pending rewards for the user since the last user action **/ function _getPendingRewards( address user, address reward, RewardsDataTypes.UserAssetBalance memory userAssetBalance ) internal view returns (uint256) { RewardsDataTypes.RewardData storage rewardData = _assets[userAssetBalance.asset].rewards[ reward ]; uint256 assetUnit = 10 ** _assets[userAssetBalance.asset].decimals; (, uint256 nextIndex) = _getAssetIndex(rewardData, userAssetBalance.totalSupply, assetUnit); return _getRewards( userAssetBalance.userBalance, nextIndex, rewardData.usersData[user].index, assetUnit ); } /** * @dev Internal function for the calculation of user's rewards on a distribution * @param userBalance Balance of the user asset on a distribution * @param reserveIndex Current index of the distribution * @param userIndex Index stored for the user, representation his staking moment * @param assetUnit One unit of asset (10**decimals) * @return The rewards **/ function _getRewards( uint256 userBalance, uint256 reserveIndex, uint256 userIndex, uint256 assetUnit ) internal pure returns (uint256) { uint256 result = userBalance * (reserveIndex - userIndex); assembly { result := div(result, assetUnit) } return result; } /** * @dev Calculates the next value of an specific distribution index, with validations * @param rewardData Storage pointer to the distribution reward config * @param totalSupply of the asset being rewarded * @param assetUnit One unit of asset (10**decimals) * @return The new index. **/ function _getAssetIndex( RewardsDataTypes.RewardData storage rewardData, uint256 totalSupply, uint256 assetUnit ) internal view returns (uint256, uint256) { uint256 oldIndex = rewardData.index; uint256 distributionEnd = rewardData.distributionEnd; uint256 emissionPerSecond = rewardData.emissionPerSecond; uint256 lastUpdateTimestamp = rewardData.lastUpdateTimestamp; if ( emissionPerSecond == 0 || totalSupply == 0 || lastUpdateTimestamp == block.timestamp || lastUpdateTimestamp >= distributionEnd ) { return (oldIndex, oldIndex); } uint256 currentTimestamp = block.timestamp > distributionEnd ? distributionEnd : block.timestamp; uint256 timeDelta = currentTimestamp - lastUpdateTimestamp; uint256 firstTerm = emissionPerSecond * timeDelta * assetUnit; assembly { firstTerm := div(firstTerm, totalSupply) } return (oldIndex, (firstTerm + oldIndex)); } /** * @dev Get user balances and total supply of all the assets specified by the assets parameter * @param assets List of assets to retrieve user balance and total supply * @param user Address of the user * @return userAssetBalances contains a list of structs with user balance and total supply of the given assets */ function _getUserAssetBalances( address[] calldata assets, address user ) internal view virtual returns (RewardsDataTypes.UserAssetBalance[] memory userAssetBalances); /// @inheritdoc IRewardsDistributor function getAssetDecimals(address asset) external view returns (uint8) { return _assets[asset].decimals; } /// @inheritdoc IRewardsDistributor function getEmissionManager() external view returns (address) { return EMISSION_MANAGER; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {IRewardsDistributor} from './IRewardsDistributor.sol'; import {ITransferStrategyBase} from './ITransferStrategyBase.sol'; import {AggregatorInterface} from '../../dependencies/chainlink/AggregatorInterface.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 AggregatorInterface interface */ function setRewardOracle(address reward, AggregatorInterface 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. * AggregatorInterface rewardOracle: The Price Oracle of a reward to visualize the incentives at the UI Frontend. * Must follow Chainlink Aggregator AggregatorInterface interface to be compatible. */ function configureAssets(RewardsDataTypes.RewardsConfigInput[] memory config) external; /** * @dev Called by the corresponding asset on transfer hook in order to update the rewards distribution. * @dev The units of `totalSupply` and `userBalance` should be the same. * @param user The address of the user whose asset balance has changed * @param totalSupply The total supply of the asset prior to user balance change * @param userBalance The previous user balance prior to balance change **/ function handleAction(address user, uint256 totalSupply, uint256 userBalance) external; /** * @dev Claims reward for a user to the desired address, on all the assets of the pool, accumulating the pending rewards * @param assets List of assets to check eligible distributions before claiming rewards * @param amount The amount of rewards to claim * @param to The address that will be receiving the rewards * @param reward The address of the reward token * @return The amount of rewards claimed **/ function claimRewards( address[] calldata assets, uint256 amount, address to, address reward ) external returns (uint256); /** * @dev Claims reward for a user on behalf, on all the assets of the pool, accumulating the pending rewards. The * caller must be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager * @param assets The list of assets to check eligible distributions before claiming rewards * @param amount The amount of rewards to claim * @param user The address to check and claim rewards * @param to The address that will be receiving the rewards * @param reward The address of the reward token * @return The amount of rewards claimed **/ function claimRewardsOnBehalf( address[] calldata assets, uint256 amount, address user, address to, address reward ) external returns (uint256); /** * @dev Claims reward for msg.sender, on all the assets of the pool, accumulating the pending rewards * @param assets The list of assets to check eligible distributions before claiming rewards * @param amount The amount of rewards to claim * @param reward The address of the reward token * @return The amount of rewards claimed **/ function claimRewardsToSelf( address[] calldata assets, uint256 amount, address reward ) external returns (uint256); /** * @dev Claims all rewards for a user to the desired address, on all the assets of the pool, accumulating the pending rewards * @param assets The list of assets to check eligible distributions before claiming rewards * @param to The address that will be receiving the rewards * @return rewardsList List of addresses of the reward tokens * @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardList" **/ function claimAllRewards( address[] calldata assets, address to ) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts); /** * @dev Claims all rewards for a user on behalf, on all the assets of the pool, accumulating the pending rewards. The caller must * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager * @param assets The list of assets to check eligible distributions before claiming rewards * @param user The address to check and claim rewards * @param to The address that will be receiving the rewards * @return rewardsList List of addresses of the reward tokens * @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardsList" **/ function claimAllRewardsOnBehalf( address[] calldata assets, address user, address to ) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts); /** * @dev Claims all reward for msg.sender, on all the assets of the pool, accumulating the pending rewards * @param assets The list of assets to check eligible distributions before claiming rewards * @return rewardsList List of addresses of the reward tokens * @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardsList" **/ function claimAllRewardsToSelf( address[] calldata assets ) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /** * @title IRewardsDistributor * @author Aave * @notice Defines the basic interface for a Rewards Distributor. */ interface IRewardsDistributor { /** * @dev Emitted when the configuration of the rewards of an asset is updated. * @param asset The address of the incentivized asset * @param reward The address of the reward token * @param oldEmission The old emissions per second value of the reward distribution * @param newEmission The new emissions per second value of the reward distribution * @param oldDistributionEnd The old end timestamp of the reward distribution * @param newDistributionEnd The new end timestamp of the reward distribution * @param assetIndex The index of the asset distribution */ event AssetConfigUpdated( address indexed asset, address indexed reward, uint256 oldEmission, uint256 newEmission, uint256 oldDistributionEnd, uint256 newDistributionEnd, uint256 assetIndex ); /** * @dev Emitted when rewards of an asset are accrued on behalf of a user. * @param asset The address of the incentivized asset * @param reward The address of the reward token * @param user The address of the user that rewards are accrued on behalf of * @param assetIndex The index of the asset distribution * @param userIndex The index of the asset distribution on behalf of the user * @param rewardsAccrued The amount of rewards accrued */ event Accrued( address indexed asset, address indexed reward, address indexed user, uint256 assetIndex, uint256 userIndex, uint256 rewardsAccrued ); /** * @dev Sets the end date for the distribution * @param asset The asset to incentivize * @param reward The reward token that incentives the asset * @param newDistributionEnd The end date of the incentivization, in unix time format **/ function setDistributionEnd(address asset, address reward, uint32 newDistributionEnd) external; /** * @dev Sets the emission per second of a set of reward distributions * @param asset The asset is being incentivized * @param rewards List of reward addresses are being distributed * @param newEmissionsPerSecond List of new reward emissions per second */ function setEmissionPerSecond( address asset, address[] calldata rewards, uint88[] calldata newEmissionsPerSecond ) external; /** * @dev Gets the end date for the distribution * @param asset The incentivized asset * @param reward The reward token of the incentivized asset * @return The timestamp with the end of the distribution, in unix time format **/ function getDistributionEnd(address asset, address reward) external view returns (uint256); /** * @dev Returns the index of a user on a reward distribution * @param user Address of the user * @param asset The incentivized asset * @param reward The reward token of the incentivized asset * @return The current user asset index, not including new distributions **/ function getUserAssetIndex( address user, address asset, address reward ) external view returns (uint256); /** * @dev Returns the configuration of the distribution reward for a certain asset * @param asset The incentivized asset * @param reward The reward token of the incentivized asset * @return The index of the asset distribution * @return The emission per second of the reward distribution * @return The timestamp of the last update of the index * @return The timestamp of the distribution end **/ function getRewardsData( address asset, address reward ) external view returns (uint256, uint256, uint256, uint256); /** * @dev Calculates the next value of an specific distribution index, with validations. * @param asset The incentivized asset * @param reward The reward token of the incentivized asset * @return The old index of the asset distribution * @return The new index of the asset distribution **/ function getAssetIndex(address asset, address reward) external view returns (uint256, uint256); /** * @dev Returns the list of available reward token addresses of an incentivized asset * @param asset The incentivized asset * @return List of rewards addresses of the input asset **/ function getRewardsByAsset(address asset) external view returns (address[] memory); /** * @dev Returns the list of available reward addresses * @return List of rewards supported in this contract **/ function getRewardsList() external view returns (address[] memory); /** * @dev Returns the accrued rewards balance of a user, not including virtually accrued rewards since last distribution. * @param user The address of the user * @param reward The address of the reward token * @return Unclaimed rewards, not including new distributions **/ function getUserAccruedRewards(address user, address reward) external view returns (uint256); /** * @dev Returns a single rewards balance of a user, including virtually accrued and unrealized claimable rewards. * @param assets List of incentivized assets to check eligible distributions * @param user The address of the user * @param reward The address of the reward token * @return The rewards amount **/ function getUserRewards( address[] calldata assets, address user, address reward ) external view returns (uint256); /** * @dev Returns a list all rewards of a user, including already accrued and unrealized claimable rewards * @param assets List of incentivized assets to check eligible distributions * @param user The address of the user * @return The list of reward addresses * @return The list of unclaimed amount of rewards **/ function getAllUserRewards( address[] calldata assets, address user ) external view returns (address[] memory, uint256[] memory); /** * @dev Returns the decimals of an asset to calculate the distribution delta * @param asset The address to retrieve decimals * @return The decimals of an underlying asset */ function getAssetDecimals(address asset) external view returns (uint8); /** * @dev Returns the address of the emission manager * @return The address of the EmissionManager */ function EMISSION_MANAGER() external view returns (address); /** * @dev Returns the address of the emission manager. * Deprecated: This getter is maintained for compatibility purposes. Use the `EMISSION_MANAGER()` function instead. * @return The address of the EmissionManager */ function getEmissionManager() external view returns (address); }
// SPDX-License-Identifier: MIT 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; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import {ITransferStrategyBase} from '../interfaces/ITransferStrategyBase.sol'; import {AggregatorInterface} from '../../dependencies/chainlink/AggregatorInterface.sol'; library RewardsDataTypes { struct RewardsConfigInput { uint88 emissionPerSecond; uint256 totalSupply; uint32 distributionEnd; address asset; address reward; ITransferStrategyBase transferStrategy; AggregatorInterface rewardOracle; } struct UserAssetBalance { address asset; uint256 userBalance; uint256 totalSupply; } struct UserData { // Liquidity index of the reward distribution for the user uint104 index; // Amount of accrued rewards for the user since last user index update uint128 accrued; } struct RewardData { // Liquidity index of the reward distribution uint104 index; // Amount of reward tokens distributed per second uint88 emissionPerSecond; // Timestamp of the last reward index update uint32 lastUpdateTimestamp; // The end of the distribution of rewards (in seconds) uint32 distributionEnd; // Map of user addresses and their rewards data (userAddress => userData) mapping(address => UserData) usersData; } struct AssetData { // Map of reward token addresses and their data (rewardTokenAddress => rewardData) mapping(address => RewardData) rewards; // List of reward token addresses for the asset mapping(uint128 => address) availableRewards; // Count of reward tokens for the asset uint128 availableRewardsCount; // Number of decimals of the asset uint8 decimals; } }
{ "remappings": [ "solidity-utils/=lib/solidity-utils/src/", "forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "openzeppelin-contracts-upgradeable/=lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/", "@openzeppelin/contracts-upgradeable/=lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/", "erc4626-tests/=lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "halmos-cheatcodes/=lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "shanghai", "viaIR": false, "libraries": { "src/contracts/protocol/libraries/logic/BorrowLogic.sol": { "BorrowLogic": "0x62325c94E1c49dcDb5937726aB5D8A4c37bCAd36" }, "src/contracts/protocol/libraries/logic/BridgeLogic.sol": { "BridgeLogic": "0x621Ef86D8A5C693a06295BC288B95C12D4CE4994" }, "src/contracts/protocol/libraries/logic/ConfiguratorLogic.sol": { "ConfiguratorLogic": "0x09e88e877B39D883BAFd46b65E7B06CC56963041" }, "src/contracts/protocol/libraries/logic/EModeLogic.sol": { "EModeLogic": "0xC31d2362fAeD85dF79d0bec99693D0EB0Abd3f74" }, "src/contracts/protocol/libraries/logic/FlashLoanLogic.sol": { "FlashLoanLogic": "0x34039100cc9584Ae5D741d322e16d0d18CEE8770" }, "src/contracts/protocol/libraries/logic/LiquidationLogic.sol": { "LiquidationLogic": "0x4731bF01583F991278692E8727d0700a00A1fBBf" }, "src/contracts/protocol/libraries/logic/PoolLogic.sol": { "PoolLogic": "0xf8C97539934ee66a67C26010e8e027D77E821B0C" }, "src/contracts/protocol/libraries/logic/SupplyLogic.sol": { "SupplyLogic": "0x185477906B46D9b8DE0DEB73A1bBfb87b5b51BC3" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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":"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":"EMISSION_MANAGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"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 AggregatorInterface","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":"asset","type":"address"},{"internalType":"address","name":"reward","type":"address"}],"name":"getAssetIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"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":"","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":"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 AggregatorInterface","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"}]
Contract Creation Code
60a06040525f60055534801562000014575f80fd5b50604051620037b5380380620037b5833981016040819052620000379162000049565b6001600160a01b031660805262000078565b5f602082840312156200005a575f80fd5b81516001600160a01b038116811462000071575f80fd5b9392505050565b6080516136f3620000c25f395f818161044f0152818161054c015281816109e501528181610c2e015281816110b3015281816111c20152818161121401526112b201526136f35ff3fe608060405234801561000f575f80fd5b50600436106101d1575f3560e01c806392074b08116100fe578063bf90f63a1161009e578063dde43cba1161006e578063dde43cba1461056e578063e15ac62314610576578063f5cf673b14610589578063f996868b1461059c575f80fd5b8063bf90f63a1461050e578063c4d66de814610521578063c5a7b53814610534578063cbcbb50714610547575f80fd5b80639ff55db9116100d95780639ff55db9146104cd578063b022418c146104e0578063b45ac1a9146104f3578063bb492bf5146104fb575f80fd5b806392074b081461044d578063955c2ad7146104735780639efd6f7214610486575f80fd5b80635453ba101161017457806370674ab91161014457806370674ab91461035b57806374d945ec1461036e5780637eff4ba814610399578063886fe70b14610425575f80fd5b80635453ba10146102ea57806357b89883146102fd5780635f130b24146103105780636657732f1461033b575f80fd5b806331873e2e116101af57806331873e2e1461025157806333028b99146102665780634c0369c314610279578063533f542a1461029a575f80fd5b80631b839c77146101d5578063236300dc146101fb5780632a17bf601461020e575b5f80fd5b6101e86101e3366004612def565b6105af565b6040519081526020015b60405180910390f35b6101e8610209366004612e66565b6105e8565b61023961021c366004612ed4565b6001600160a01b039081165f908152603b60205260409020541690565b6040516001600160a01b0390911681526020016101f2565b61026461025f366004612ef6565b610631565b005b6101e8610274366004612f28565b610642565b61028c610287366004612fa7565b610736565b6040516101f292919061303c565b6101e86102a8366004613091565b6001600160a01b038083165f90815260016020818152604080842086861685528252808420948816845293909101905220546001600160681b03169392505050565b6102646102f8366004612def565b6109da565b6101e861030b3660046130ce565b610a30565b61023961031e366004612ed4565b6001600160a01b039081165f908152603a60205260409020541690565b61034e610349366004612ed4565b610a49565b6040516101f29190613128565b6101e861036936600461313a565b610b42565b61023961037c366004612ed4565b6001600160a01b039081165f908152603960205260409020541690565b6104056103a7366004612def565b6001600160a01b039182165f9081526001602090815260408083209390941682529190915220546001600160681b038116916001600160581b03600160681b8304169163ffffffff600160c01b8204811692600160e01b9092041690565b6040805194855260208501939093529183015260608201526080016101f2565b610438610433366004612def565b610b58565b604080519283526020830191909152016101f2565b7f0000000000000000000000000000000000000000000000000000000000000000610239565b61026461048136600461322c565b610c23565b6104bb610494366004612ed4565b6001600160a01b03165f90815260016020526040902060020154600160801b900460ff1690565b60405160ff90911681526020016101f2565b61028c6104db36600461313a565b610db2565b6101e86104ee366004612def565b610ea9565b61034e610f34565b61028c610509366004612fa7565b610f94565b61028c61051c366004613352565b610fd6565b61026461052f366004612ed4565b610ff1565b610264610542366004613390565b6110a8565b6102397f000000000000000000000000000000000000000000000000000000000000000081565b6101e8600181565b610264610584366004612def565b6111b7565b610264610597366004612def565b611209565b6102646105aa3660046133d4565b6112a7565b6001600160a01b038281165f90815260016020908152604080832093851683529290522054600160e01b900463ffffffff165b92915050565b5f6001600160a01b0383166106185760405162461bcd60e51b815260040161060f90613450565b60405180910390fd5b610627868686333388886115c6565b9695505050505050565b61063d338483856117c3565b505050565b6001600160a01b038084165f908152603960205260408120549091339186911682146106a75760405162461bcd60e51b815260206004820152601460248201527310d3105253515497d5539055551213d49256915160621b604482015260640161060f565b6001600160a01b0386166106f45760405162461bcd60e51b8152602060048201526014602482015273494e56414c49445f555345525f4144445245535360601b604482015260640161060f565b6001600160a01b03851661071a5760405162461bcd60e51b815260040161060f90613450565b610729898989338a8a8a6115c6565b9998505050505050505050565b6060805f61074586868661190e565b6003549091506001600160401b0381111561076257610762613192565b60405190808252806020026020018201604052801561078b578160200160208202803683370190505b50925082516001600160401b038111156107a7576107a7613192565b6040519080825280602002602001820160405280156107d0578160200160208202803683370190505b5091505f5b81518110156109cf575f5b84518110156109c657600381815481106107fc576107fc61347c565b905f5260205f20015f9054906101000a90046001600160a01b03168582815181106108295761082961347c565b60200260200101906001600160a01b031690816001600160a01b03168152505060015f84848151811061085e5761085e61347c565b60200260200101515f01516001600160a01b03166001600160a01b031681526020019081526020015f205f015f86838151811061089d5761089d61347c565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206001015f876001600160a01b03166001600160a01b031681526020019081526020015f205f01600d9054906101000a90046001600160801b03166001600160801b03168482815181106109195761091961347c565b6020026020010181815161092d91906134a4565b90525082518390839081106109445761094461347c565b6020026020010151602001515f03156109be576109948686838151811061096d5761096d61347c565b60200260200101518585815181106109875761098761347c565b6020026020010151611abb565b8482815181106109a6576109a661347c565b602002602001018181516109ba91906134a4565b9052505b6001016107e0565b506001016107d5565b50505b935093915050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a225760405162461bcd60e51b815260040161060f906134b7565b610a2c8282611b59565b5050565b5f610a40858585333333886115c6565b95945050505050565b6001600160a01b0381165f908152600160205260408120600201546060916001600160801b0390911690816001600160401b03811115610a8b57610a8b613192565b604051908082528060200260200182016040528015610ab4578160200160208202803683370190505b5090505f5b826001600160801b0316816001600160801b03161015610b3a576001600160a01b038086165f9081526001602081815260408084206001600160801b03871680865293019091529091205484519216918491908110610b1a57610b1a61347c565b6001600160a01b0390921660209283029190910190910152600101610ab9565b509392505050565b5f610a408383610b5388888861190e565b611c5d565b6001600160a01b038083165f8181526001602090815260408083209486168352938152838220845163b1bf962d60e01b81529451929485949193610c169385939263b1bf962d92600480830193928290030181865afa158015610bbd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610be191906134e6565b6001600160a01b0388165f90815260016020526040902060020154610c1190600160801b900460ff16600a6135dd565b611dab565b92509250505b9250929050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c6b5760405162461bcd60e51b815260040161060f906134b7565b5f5b8151811015610da557818181518110610c8857610c8861347c565b6020026020010151606001516001600160a01b031663b1bf962d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ccf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf391906134e6565b828281518110610d0557610d0561347c565b60200260200101516020018181525050610d59828281518110610d2a57610d2a61347c565b602002602001015160800151838381518110610d4857610d4861347c565b602002602001015160a00151611e71565b610d9d828281518110610d6e57610d6e61347c565b602002602001015160800151838381518110610d8c57610d8c61347c565b602002602001015160c00151611b59565b600101610c6d565b50610daf81611f70565b50565b6001600160a01b038083165f90815260396020526040902054606091829133918691168214610e1a5760405162461bcd60e51b815260206004820152601460248201527310d3105253515497d5539055551213d49256915160621b604482015260640161060f565b6001600160a01b038616610e675760405162461bcd60e51b8152602060048201526014602482015273494e56414c49445f555345525f4144445245535360601b604482015260640161060f565b6001600160a01b038516610e8d5760405162461bcd60e51b815260040161060f90613450565b610e9a88883389896125fc565b93509350505094509492505050565b5f805f5b600454811015610b3a5760015f60048381548110610ecd57610ecd61347c565b5f918252602080832091909101546001600160a01b03908116845283820194909452604092830182208885168352815282822093891682526001909301909252902054610f2a90600160681b90046001600160801b0316836134a4565b9150600101610ead565b60606003805480602002602001604051908101604052809291908181526020018280548015610f8a57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610f6c575b5050505050905090565b6060806001600160a01b038316610fbd5760405162461bcd60e51b815260040161060f90613450565b610fca85853333876125fc565b91509150935093915050565b606080610fe684843333336125fc565b915091509250929050565b60065460019060ff16806110045750303b155b80611010575060055481115b6110735760405162461bcd60e51b815260206004820152602e60248201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560448201526d195b881a5b9a5d1a585b1a5e995960921b606482015260840161060f565b60065460ff16158015611093576006805460ff1916600117905560058290555b801561063d576006805460ff19169055505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146110f05760405162461bcd60e51b815260040161060f906134b7565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902080546001600160e01b038116600160e01b63ffffffff898116828102938417958690558751600160681b9096046001600160581b0316808752968601969096529083041694830185905260608301939093526001600160681b039081169216919091176080820152909291907fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc59060a00160405180910390a350505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111ff5760405162461bcd60e51b815260040161060f906134b7565b610a2c8282611e71565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146112515760405162461bcd60e51b815260040161060f906134b7565b6001600160a01b038281165f8181526039602052604080822080546001600160a01b0319169486169485179055517f4925eafc82d0c4d67889898eeed64b18488ab19811e61620f387026dec126a289190a35050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146112ef5760405162461bcd60e51b815260040161060f906134b7565b82811461132e5760405162461bcd60e51b815260206004820152600d60248201526c1253959053125117d253941555609a1b604482015260640161060f565b5f5b838110156115be576001600160a01b0386165f9081526001602052604081209081818888868181106113645761136461347c565b90506020020160208101906113799190612ed4565b6001600160a01b0316815260208101919091526040015f206002830154909150600160801b900460ff1680158015906113bf57508154600160c01b900463ffffffff1615155b61140b5760405162461bcd60e51b815260206004820152601b60248201527f444953545249425554494f4e5f444f45535f4e4f545f45584953540000000000604482015260640161060f565b5f611480838b6001600160a01b031663b1bf962d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561144c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061147091906134e6565b61147b85600a6135eb565b6129be565b508354909150600160681b90046001600160581b03168787878181106114a8576114a861347c565b90506020020160208101906114bd91906135f6565b84546001600160581b0391909116600160681b026affffffffffffffffffffff60681b199091161784558989878181106114f9576114f961347c565b905060200201602081019061150e9190612ed4565b6001600160a01b03168b6001600160a01b03167fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc5838b8b8b8181106115555761155561347c565b905060200201602081019061156a91906135f6565b8854604080519384526001600160581b039092166020840152600160e01b900463ffffffff1690820181905260608201526080810186905260a00160405180910390a3505060019093019250611330915050565b505050505050565b5f855f036115d557505f6117b8565b5f6115ea856115e58b8b8961190e565b612aa8565b5f5b8881101561174a575f8a8a838181106116075761160761347c565b905060200201602081019061161c9190612ed4565b6001600160a01b038181165f9081526001602081815260408084208b861685528252808420948d168452939091019052205490915061166b90600160681b90046001600160801b0316846134a4565b92508883116116bb576001600160a01b038082165f9081526001602081815260408084208a861685528252808420948c168452939091019052208054600160681b600160e81b0319169055611741565b5f6116c68a8561360f565b90506116d2818561360f565b93506116dd81612b1d565b6001600160a01b039283165f9081526001602081815260408084208b881685528252808420968d1684529590910190529290922080546001600160801b0393909316600160681b02600160681b600160e81b0319909316929092179091555061174a565b506001016115ec565b50805f0361175b575f9150506117b8565b611766848483612b89565b604080516001600160a01b038881168252602082018490528087169286821692918916917fc052130bc4ef84580db505783484b067ea8b71b3bca78a7e12db7aea8658f004910160405180910390a490505b979650505050505050565b6001600160a01b0384165f9081526001602052604081206002015460ff600160801b820416600a0a916001600160801b0390911690819003611806575050611908565b5f5b81816001600160801b03161015611904576001600160a01b038088165f9081526001602081815260408084206001600160801b038716855292830182528084205490941680845291905291812090806118628389896129be565b915091505f80611875858d8d878d612c62565b9150915082806118825750805b156118f2578b6001600160a01b0316866001600160a01b03168e6001600160a01b03167f3303facd24627943a92e9dc87cfbb34b15c49b726eec3ad3487c16be9ab8efe88788876040516118e9939291909283526020830191909152604082015260600190565b60405180910390a45b50506001909401935061180892505050565b5050505b50505050565b6060826001600160401b0381111561192857611928613192565b60405190808252806020026020018201604052801561198357816020015b61197060405180606001604052805f6001600160a01b031681526020015f81526020015f81525090565b8152602001906001900390816119465790505b5090505f5b83811015610b3a578484828181106119a2576119a261347c565b90506020020160208101906119b79190612ed4565b8282815181106119c9576119c961347c565b60209081029190910101516001600160a01b0390911690528484828181106119f3576119f361347c565b9050602002016020810190611a089190612ed4565b604051630afbcdc960e01b81526001600160a01b0385811660048301529190911690630afbcdc9906024016040805180830381865afa158015611a4d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a719190613622565b838381518110611a8357611a8361347c565b6020026020010151602001848481518110611aa057611aa061347c565b60209081029190910101516040019190915252600101611988565b80516001600160a01b039081165f90815260016020818152604080842087861685528252808420865190951684529190528120600201549091908290611b0c90600160801b900460ff16600a6135dd565b90505f611b1e83866040015184611dab565b6020808801516001600160a01b038b165f908152600188019092526040909120549193506117b892509083906001600160681b031685612d54565b5f816001600160a01b03166350d25bcd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bba91906134e6565b13611c075760405162461bcd60e51b815260206004820152601860248201527f4f5241434c455f4d5553545f52455455524e5f50524943450000000000000000604482015260640161060f565b6001600160a01b038281165f818152603b602052604080822080546001600160a01b0319169486169485179055517f1a1cd5483e52e60b9ff7f3b9d1db3bbd9e9d21c6324ad3a8c79dba9b75e62f4d9190a35050565b5f805b8251811015610b3a57828181518110611c7b57611c7b61347c565b6020026020010151602001515f03611d065760015f848381518110611ca257611ca261347c565b602090810291909101810151516001600160a01b0390811683528282019390935260409182015f90812088851682528252828120938916815260019093019052902054611cff90600160681b90046001600160801b0316836134a4565b9150611da3565b60015f848381518110611d1b57611d1b61347c565b602090810291909101810151516001600160a01b0390811683528282019390935260409182015f908120888516825282528281209389168152600190930190529020548351600160681b9091046001600160801b031690611d8c90879087908790869081106109875761098761347c565b611d9691906134a4565b611da090836134a4565b91505b600101611c60565b82545f9081906001600160681b0381169063ffffffff600160e01b82048116916001600160581b03600160681b82041691600160c01b90910416811580611df0575087155b80611dfa57504281145b80611e055750828110155b15611e1957838495509550505050506109d2565b5f834211611e275742611e29565b835b90505f611e36838361360f565b90505f89611e448387613644565b611e4e9190613644565b8b9004905086611e5e81836134a4565b9850985050505050505050935093915050565b6001600160a01b038116611ec75760405162461bcd60e51b815260206004820152601860248201527f53545241544547595f43414e5f4e4f545f42455f5a45524f0000000000000000604482015260640161060f565b6001813b151514611f1a5760405162461bcd60e51b815260206004820152601960248201527f53545241544547595f4d5553545f42455f434f4e545241435400000000000000604482015260640161060f565b6001600160a01b038281165f818152603a602052604080822080546001600160a01b0319169486169485179055517f8ca1d928f1d72493a6b78c4f74aabde976bc37ffe2570f2a1ce5a8abd3dde0aa9190a35050565b5f5b8151811015610a2c5760015f838381518110611f9057611f9061347c565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f2060020160109054906101000a900460ff1660ff165f03612028576004828281518110611fe957611fe961347c565b6020908102919091018101516060015182546001810184555f938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b5f82828151811061203b5761203b61347c565b6020026020010151606001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612082573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120a6919061365b565b60015f8585815181106120bb576120bb61347c565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f2060020160106101000a81548160ff021916908360ff160217905560ff1690505f60015f85858151811061211b5761211b61347c565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f205f015f85858151811061215b5761215b61347c565b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020015f209050805f0160189054906101000a900463ffffffff1663ffffffff165f0361231d578383815181106121ba576121ba61347c565b60200260200101516080015160015f8686815181106121db576121db61347c565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f206001015f60015f88888151811061221f5761221f61347c565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f206002015f9054906101000a90046001600160801b03166001600160801b03166001600160801b031681526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060015f8585815181106122b7576122b761347c565b602090810291909101810151606001516001600160a01b031682528101919091526040015f90812060020180546001600160801b0316916122f78361367b565b91906101000a8154816001600160801b0302191690836001600160801b03160217905550505b60025f8585815181106123325761233261347c565b602090810291909101810151608001516001600160a01b031682528101919091526040015f9081205460ff161515900361241157600160025f86868151811061237d5761237d61347c565b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff02191690831515021790555060038484815181106123d2576123d261347c565b6020908102919091018101516080015182546001810184555f938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b5f612441828686815181106124285761242861347c565b60200260200101516020015185600a61147b91906135eb565b5082548651919250600160681b81046001600160581b031691600160e01b90910463ffffffff169087908790811061247b5761247b61347c565b60209081029190910101515184546001600160581b03909116600160681b026affffffffffffffffffffff60681b1990911617845586518790879081106124c4576124c461347c565b602090810291909101015160400151845463ffffffff909116600160e01b026001600160e01b0390911617845586518790879081106125055761250561347c565b6020026020010151608001516001600160a01b031687878151811061252c5761252c61347c565b6020026020010151606001516001600160a01b03167fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc5848a8a815181106125755761257561347c565b60200260200101515f0151858c8c815181106125935761259361347c565b602002602001015160400151896040516125e39594939291906001600160581b03958616815293909416602084015263ffffffff9182166040840152166060820152608081019190915260a00190565b60405180910390a3505060019093019250611f72915050565b6003546060908190806001600160401b0381111561261c5761261c613192565b604051908082528060200260200182016040528015612645578160200160208202803683370190505b509250806001600160401b0381111561266057612660613192565b604051908082528060200260200182016040528015612689578160200160208202803683370190505b50915061269b856115e58a8a8961190e565b5f5b878110156128c5575f8989838181106126b8576126b861347c565b90506020020160208101906126cd9190612ed4565b90505f5b838110156128bb575f6001600160a01b03168682815181106126f5576126f561347c565b60200260200101516001600160a01b03160361276c576003818154811061271e5761271e61347c565b905f5260205f20015f9054906101000a90046001600160a01b031686828151811061274b5761274b61347c565b60200260200101906001600160a01b031690816001600160a01b0316815250505b6001600160a01b0382165f908152600160205260408120875182908990859081106127995761279961347c565b6020908102919091018101516001600160a01b0390811683528282019390935260409182015f908120938d16815260019093019052902054600160681b90046001600160801b0316905080156128b257808683815181106127fc576127fc61347c565b6020026020010181815161281091906134a4565b9052506001600160a01b0383165f908152600160205260408120885182908a90869081106128405761284061347c565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206001015f8b6001600160a01b03166001600160a01b031681526020019081526020015f205f01600d6101000a8154816001600160801b0302191690836001600160801b031602179055505b506001016126d1565b505060010161269d565b505f5b818110156129b25761290d858583815181106128e6576128e661347c565b60200260200101518584815181106129005761290061347c565b6020026020010151612b89565b846001600160a01b03168482815181106129295761292961347c565b60200260200101516001600160a01b0316876001600160a01b03167fc052130bc4ef84580db505783484b067ea8b71b3bca78a7e12db7aea8658f0048a8786815181106129785761297861347c565b60200260200101516040516129a29291906001600160a01b03929092168252602082015260400190565b60405180910390a46001016128c8565b50509550959350505050565b5f805f806129cd878787611dab565b915091505f828214612a71576001600160681b03821115612a215760405162461bcd60e51b815260206004820152600e60248201526d494e4445585f4f564552464c4f5760901b604482015260640161060f565b5086546cffffffffffffffffffffffffff19166001600160681b0382161787556001612a4c42612d77565b885463ffffffff91909116600160c01b0263ffffffff60c01b19909116178855612a9b565b612a7a42612d77565b885463ffffffff91909116600160c01b0263ffffffff60c01b199091161788555b9097909650945050505050565b5f5b815181101561063d57612b15828281518110612ac857612ac861347c565b60200260200101515f015184848481518110612ae657612ae661347c565b602002602001015160200151858581518110612b0457612b0461347c565b6020026020010151604001516117c3565b600101612aaa565b5f6001600160801b03821115612b855760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b606482015260840161060f565b5090565b6001600160a01b038281165f818152603a6020526040808220549051630b5f5cc160e11b81528785166004820152602481019390935260448301859052909216919082906316beb982906064016020604051808303815f875af1158015612bf2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c1691906136a0565b9050600181151514612c5b5760405162461bcd60e51b815260206004820152600e60248201526d2a2920a729a322a92fa2a92927a960911b604482015260640161060f565b5050505050565b6001600160a01b0384165f90815260018601602052604081205481906001600160681b031681858214801590612d45576001600160a01b0389165f90815260018b016020526040902080546cffffffffffffffffffffffffff19166001600160681b0389161790558715612d4557612cdc88888589612d54565b9150612ce782612b1d565b6001600160a01b038a165f90815260018c01602052604090208054600d90612d20908490600160681b90046001600160801b03166136bf565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b90999098509650505050505050565b5f80612d60848661360f565b612d6a9087613644565b9290920495945050505050565b5f63ffffffff821115612b855760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b606482015260840161060f565b6001600160a01b0381168114610daf575f80fd5b5f8060408385031215612e00575f80fd5b8235612e0b81612ddb565b91506020830135612e1b81612ddb565b809150509250929050565b5f8083601f840112612e36575f80fd5b5081356001600160401b03811115612e4c575f80fd5b6020830191508360208260051b8501011115610c1c575f80fd5b5f805f805f60808688031215612e7a575f80fd5b85356001600160401b03811115612e8f575f80fd5b612e9b88828901612e26565b909650945050602086013592506040860135612eb681612ddb565b91506060860135612ec681612ddb565b809150509295509295909350565b5f60208284031215612ee4575f80fd5b8135612eef81612ddb565b9392505050565b5f805f60608486031215612f08575f80fd5b8335612f1381612ddb565b95602085013595506040909401359392505050565b5f805f805f8060a08789031215612f3d575f80fd5b86356001600160401b03811115612f52575f80fd5b612f5e89828a01612e26565b909750955050602087013593506040870135612f7981612ddb565b92506060870135612f8981612ddb565b91506080870135612f9981612ddb565b809150509295509295509295565b5f805f60408486031215612fb9575f80fd5b83356001600160401b03811115612fce575f80fd5b612fda86828701612e26565b9094509250506020840135612fee81612ddb565b809150509250925092565b5f815180845260208085019450602084015f5b838110156130315781516001600160a01b03168752958201959082019060010161300c565b509495945050505050565b604081525f61304e6040830185612ff9565b8281036020848101919091528451808352858201928201905f5b8181101561308457845183529383019391830191600101613068565b5090979650505050505050565b5f805f606084860312156130a3575f80fd5b83356130ae81612ddb565b925060208401356130be81612ddb565b91506040840135612fee81612ddb565b5f805f80606085870312156130e1575f80fd5b84356001600160401b038111156130f6575f80fd5b61310287828801612e26565b90955093505060208501359150604085013561311d81612ddb565b939692955090935050565b602081525f612eef6020830184612ff9565b5f805f806060858703121561314d575f80fd5b84356001600160401b03811115613162575f80fd5b61316e87828801612e26565b909550935050602085013561318281612ddb565b9150604085013561311d81612ddb565b634e487b7160e01b5f52604160045260245ffd5b60405160e081016001600160401b03811182821017156131c8576131c8613192565b60405290565b604051601f8201601f191681016001600160401b03811182821017156131f6576131f6613192565b604052919050565b80356001600160581b0381168114613214575f80fd5b919050565b803563ffffffff81168114613214575f80fd5b5f602080838503121561323d575f80fd5b82356001600160401b0380821115613253575f80fd5b818501915085601f830112613266575f80fd5b81358181111561327857613278613192565b613286848260051b016131ce565b818152848101925060e09182028401850191888311156132a4575f80fd5b938501935b828510156133465780858a0312156132bf575f80fd5b6132c76131a6565b6132d0866131fe565b8152868601358782015260406132e7818801613219565b908201526060868101356132fa81612ddb565b9082015260808681013561330d81612ddb565b9082015260a08681013561332081612ddb565b9082015260c08681013561333381612ddb565b90820152845293840193928501926132a9565b50979650505050505050565b5f8060208385031215613363575f80fd5b82356001600160401b03811115613378575f80fd5b61338485828601612e26565b90969095509350505050565b5f805f606084860312156133a2575f80fd5b83356133ad81612ddb565b925060208401356133bd81612ddb565b91506133cb60408501613219565b90509250925092565b5f805f805f606086880312156133e8575f80fd5b85356133f381612ddb565b945060208601356001600160401b038082111561340e575f80fd5b61341a89838a01612e26565b90965094506040880135915080821115613432575f80fd5b5061343f88828901612e26565b969995985093965092949392505050565b602080825260129082015271494e56414c49445f544f5f4144445245535360701b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b808201808211156105e2576105e2613490565b60208082526015908201527427a7262cafa2a6a4a9a9a4a7a72fa6a0a720a3a2a960591b604082015260600190565b5f602082840312156134f6575f80fd5b5051919050565b600181815b8085111561353757815f190482111561351d5761351d613490565b8085161561352a57918102915b93841c9390800290613502565b509250929050565b5f8261354d575060016105e2565b8161355957505f6105e2565b816001811461356f576002811461357957613595565b60019150506105e2565b60ff84111561358a5761358a613490565b50506001821b6105e2565b5060208310610133831016604e8410600b84101617156135b8575081810a6105e2565b6135c283836134fd565b805f19048211156135d5576135d5613490565b029392505050565b5f612eef60ff84168361353f565b5f612eef838361353f565b5f60208284031215613606575f80fd5b612eef826131fe565b818103818111156105e2576105e2613490565b5f8060408385031215613633575f80fd5b505080516020909101519092909150565b80820281158282048414176105e2576105e2613490565b5f6020828403121561366b575f80fd5b815160ff81168114612eef575f80fd5b5f6001600160801b0380831681810361369657613696613490565b6001019392505050565b5f602082840312156136b0575f80fd5b81518015158114612eef575f80fd5b6001600160801b038181168382160190808211156136df576136df613490565b509291505056fea164736f6c6343000816000a0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c1
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106101d1575f3560e01c806392074b08116100fe578063bf90f63a1161009e578063dde43cba1161006e578063dde43cba1461056e578063e15ac62314610576578063f5cf673b14610589578063f996868b1461059c575f80fd5b8063bf90f63a1461050e578063c4d66de814610521578063c5a7b53814610534578063cbcbb50714610547575f80fd5b80639ff55db9116100d95780639ff55db9146104cd578063b022418c146104e0578063b45ac1a9146104f3578063bb492bf5146104fb575f80fd5b806392074b081461044d578063955c2ad7146104735780639efd6f7214610486575f80fd5b80635453ba101161017457806370674ab91161014457806370674ab91461035b57806374d945ec1461036e5780637eff4ba814610399578063886fe70b14610425575f80fd5b80635453ba10146102ea57806357b89883146102fd5780635f130b24146103105780636657732f1461033b575f80fd5b806331873e2e116101af57806331873e2e1461025157806333028b99146102665780634c0369c314610279578063533f542a1461029a575f80fd5b80631b839c77146101d5578063236300dc146101fb5780632a17bf601461020e575b5f80fd5b6101e86101e3366004612def565b6105af565b6040519081526020015b60405180910390f35b6101e8610209366004612e66565b6105e8565b61023961021c366004612ed4565b6001600160a01b039081165f908152603b60205260409020541690565b6040516001600160a01b0390911681526020016101f2565b61026461025f366004612ef6565b610631565b005b6101e8610274366004612f28565b610642565b61028c610287366004612fa7565b610736565b6040516101f292919061303c565b6101e86102a8366004613091565b6001600160a01b038083165f90815260016020818152604080842086861685528252808420948816845293909101905220546001600160681b03169392505050565b6102646102f8366004612def565b6109da565b6101e861030b3660046130ce565b610a30565b61023961031e366004612ed4565b6001600160a01b039081165f908152603a60205260409020541690565b61034e610349366004612ed4565b610a49565b6040516101f29190613128565b6101e861036936600461313a565b610b42565b61023961037c366004612ed4565b6001600160a01b039081165f908152603960205260409020541690565b6104056103a7366004612def565b6001600160a01b039182165f9081526001602090815260408083209390941682529190915220546001600160681b038116916001600160581b03600160681b8304169163ffffffff600160c01b8204811692600160e01b9092041690565b6040805194855260208501939093529183015260608201526080016101f2565b610438610433366004612def565b610b58565b604080519283526020830191909152016101f2565b7f0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c1610239565b61026461048136600461322c565b610c23565b6104bb610494366004612ed4565b6001600160a01b03165f90815260016020526040902060020154600160801b900460ff1690565b60405160ff90911681526020016101f2565b61028c6104db36600461313a565b610db2565b6101e86104ee366004612def565b610ea9565b61034e610f34565b61028c610509366004612fa7565b610f94565b61028c61051c366004613352565b610fd6565b61026461052f366004612ed4565b610ff1565b610264610542366004613390565b6110a8565b6102397f0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c181565b6101e8600181565b610264610584366004612def565b6111b7565b610264610597366004612def565b611209565b6102646105aa3660046133d4565b6112a7565b6001600160a01b038281165f90815260016020908152604080832093851683529290522054600160e01b900463ffffffff165b92915050565b5f6001600160a01b0383166106185760405162461bcd60e51b815260040161060f90613450565b60405180910390fd5b610627868686333388886115c6565b9695505050505050565b61063d338483856117c3565b505050565b6001600160a01b038084165f908152603960205260408120549091339186911682146106a75760405162461bcd60e51b815260206004820152601460248201527310d3105253515497d5539055551213d49256915160621b604482015260640161060f565b6001600160a01b0386166106f45760405162461bcd60e51b8152602060048201526014602482015273494e56414c49445f555345525f4144445245535360601b604482015260640161060f565b6001600160a01b03851661071a5760405162461bcd60e51b815260040161060f90613450565b610729898989338a8a8a6115c6565b9998505050505050505050565b6060805f61074586868661190e565b6003549091506001600160401b0381111561076257610762613192565b60405190808252806020026020018201604052801561078b578160200160208202803683370190505b50925082516001600160401b038111156107a7576107a7613192565b6040519080825280602002602001820160405280156107d0578160200160208202803683370190505b5091505f5b81518110156109cf575f5b84518110156109c657600381815481106107fc576107fc61347c565b905f5260205f20015f9054906101000a90046001600160a01b03168582815181106108295761082961347c565b60200260200101906001600160a01b031690816001600160a01b03168152505060015f84848151811061085e5761085e61347c565b60200260200101515f01516001600160a01b03166001600160a01b031681526020019081526020015f205f015f86838151811061089d5761089d61347c565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206001015f876001600160a01b03166001600160a01b031681526020019081526020015f205f01600d9054906101000a90046001600160801b03166001600160801b03168482815181106109195761091961347c565b6020026020010181815161092d91906134a4565b90525082518390839081106109445761094461347c565b6020026020010151602001515f03156109be576109948686838151811061096d5761096d61347c565b60200260200101518585815181106109875761098761347c565b6020026020010151611abb565b8482815181106109a6576109a661347c565b602002602001018181516109ba91906134a4565b9052505b6001016107e0565b506001016107d5565b50505b935093915050565b336001600160a01b037f0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c11614610a225760405162461bcd60e51b815260040161060f906134b7565b610a2c8282611b59565b5050565b5f610a40858585333333886115c6565b95945050505050565b6001600160a01b0381165f908152600160205260408120600201546060916001600160801b0390911690816001600160401b03811115610a8b57610a8b613192565b604051908082528060200260200182016040528015610ab4578160200160208202803683370190505b5090505f5b826001600160801b0316816001600160801b03161015610b3a576001600160a01b038086165f9081526001602081815260408084206001600160801b03871680865293019091529091205484519216918491908110610b1a57610b1a61347c565b6001600160a01b0390921660209283029190910190910152600101610ab9565b509392505050565b5f610a408383610b5388888861190e565b611c5d565b6001600160a01b038083165f8181526001602090815260408083209486168352938152838220845163b1bf962d60e01b81529451929485949193610c169385939263b1bf962d92600480830193928290030181865afa158015610bbd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610be191906134e6565b6001600160a01b0388165f90815260016020526040902060020154610c1190600160801b900460ff16600a6135dd565b611dab565b92509250505b9250929050565b336001600160a01b037f0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c11614610c6b5760405162461bcd60e51b815260040161060f906134b7565b5f5b8151811015610da557818181518110610c8857610c8861347c565b6020026020010151606001516001600160a01b031663b1bf962d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ccf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf391906134e6565b828281518110610d0557610d0561347c565b60200260200101516020018181525050610d59828281518110610d2a57610d2a61347c565b602002602001015160800151838381518110610d4857610d4861347c565b602002602001015160a00151611e71565b610d9d828281518110610d6e57610d6e61347c565b602002602001015160800151838381518110610d8c57610d8c61347c565b602002602001015160c00151611b59565b600101610c6d565b50610daf81611f70565b50565b6001600160a01b038083165f90815260396020526040902054606091829133918691168214610e1a5760405162461bcd60e51b815260206004820152601460248201527310d3105253515497d5539055551213d49256915160621b604482015260640161060f565b6001600160a01b038616610e675760405162461bcd60e51b8152602060048201526014602482015273494e56414c49445f555345525f4144445245535360601b604482015260640161060f565b6001600160a01b038516610e8d5760405162461bcd60e51b815260040161060f90613450565b610e9a88883389896125fc565b93509350505094509492505050565b5f805f5b600454811015610b3a5760015f60048381548110610ecd57610ecd61347c565b5f918252602080832091909101546001600160a01b03908116845283820194909452604092830182208885168352815282822093891682526001909301909252902054610f2a90600160681b90046001600160801b0316836134a4565b9150600101610ead565b60606003805480602002602001604051908101604052809291908181526020018280548015610f8a57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610f6c575b5050505050905090565b6060806001600160a01b038316610fbd5760405162461bcd60e51b815260040161060f90613450565b610fca85853333876125fc565b91509150935093915050565b606080610fe684843333336125fc565b915091509250929050565b60065460019060ff16806110045750303b155b80611010575060055481115b6110735760405162461bcd60e51b815260206004820152602e60248201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560448201526d195b881a5b9a5d1a585b1a5e995960921b606482015260840161060f565b60065460ff16158015611093576006805460ff1916600117905560058290555b801561063d576006805460ff19169055505050565b336001600160a01b037f0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c116146110f05760405162461bcd60e51b815260040161060f906134b7565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902080546001600160e01b038116600160e01b63ffffffff898116828102938417958690558751600160681b9096046001600160581b0316808752968601969096529083041694830185905260608301939093526001600160681b039081169216919091176080820152909291907fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc59060a00160405180910390a350505050565b336001600160a01b037f0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c116146111ff5760405162461bcd60e51b815260040161060f906134b7565b610a2c8282611e71565b336001600160a01b037f0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c116146112515760405162461bcd60e51b815260040161060f906134b7565b6001600160a01b038281165f8181526039602052604080822080546001600160a01b0319169486169485179055517f4925eafc82d0c4d67889898eeed64b18488ab19811e61620f387026dec126a289190a35050565b336001600160a01b037f0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c116146112ef5760405162461bcd60e51b815260040161060f906134b7565b82811461132e5760405162461bcd60e51b815260206004820152600d60248201526c1253959053125117d253941555609a1b604482015260640161060f565b5f5b838110156115be576001600160a01b0386165f9081526001602052604081209081818888868181106113645761136461347c565b90506020020160208101906113799190612ed4565b6001600160a01b0316815260208101919091526040015f206002830154909150600160801b900460ff1680158015906113bf57508154600160c01b900463ffffffff1615155b61140b5760405162461bcd60e51b815260206004820152601b60248201527f444953545249425554494f4e5f444f45535f4e4f545f45584953540000000000604482015260640161060f565b5f611480838b6001600160a01b031663b1bf962d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561144c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061147091906134e6565b61147b85600a6135eb565b6129be565b508354909150600160681b90046001600160581b03168787878181106114a8576114a861347c565b90506020020160208101906114bd91906135f6565b84546001600160581b0391909116600160681b026affffffffffffffffffffff60681b199091161784558989878181106114f9576114f961347c565b905060200201602081019061150e9190612ed4565b6001600160a01b03168b6001600160a01b03167fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc5838b8b8b8181106115555761155561347c565b905060200201602081019061156a91906135f6565b8854604080519384526001600160581b039092166020840152600160e01b900463ffffffff1690820181905260608201526080810186905260a00160405180910390a3505060019093019250611330915050565b505050505050565b5f855f036115d557505f6117b8565b5f6115ea856115e58b8b8961190e565b612aa8565b5f5b8881101561174a575f8a8a838181106116075761160761347c565b905060200201602081019061161c9190612ed4565b6001600160a01b038181165f9081526001602081815260408084208b861685528252808420948d168452939091019052205490915061166b90600160681b90046001600160801b0316846134a4565b92508883116116bb576001600160a01b038082165f9081526001602081815260408084208a861685528252808420948c168452939091019052208054600160681b600160e81b0319169055611741565b5f6116c68a8561360f565b90506116d2818561360f565b93506116dd81612b1d565b6001600160a01b039283165f9081526001602081815260408084208b881685528252808420968d1684529590910190529290922080546001600160801b0393909316600160681b02600160681b600160e81b0319909316929092179091555061174a565b506001016115ec565b50805f0361175b575f9150506117b8565b611766848483612b89565b604080516001600160a01b038881168252602082018490528087169286821692918916917fc052130bc4ef84580db505783484b067ea8b71b3bca78a7e12db7aea8658f004910160405180910390a490505b979650505050505050565b6001600160a01b0384165f9081526001602052604081206002015460ff600160801b820416600a0a916001600160801b0390911690819003611806575050611908565b5f5b81816001600160801b03161015611904576001600160a01b038088165f9081526001602081815260408084206001600160801b038716855292830182528084205490941680845291905291812090806118628389896129be565b915091505f80611875858d8d878d612c62565b9150915082806118825750805b156118f2578b6001600160a01b0316866001600160a01b03168e6001600160a01b03167f3303facd24627943a92e9dc87cfbb34b15c49b726eec3ad3487c16be9ab8efe88788876040516118e9939291909283526020830191909152604082015260600190565b60405180910390a45b50506001909401935061180892505050565b5050505b50505050565b6060826001600160401b0381111561192857611928613192565b60405190808252806020026020018201604052801561198357816020015b61197060405180606001604052805f6001600160a01b031681526020015f81526020015f81525090565b8152602001906001900390816119465790505b5090505f5b83811015610b3a578484828181106119a2576119a261347c565b90506020020160208101906119b79190612ed4565b8282815181106119c9576119c961347c565b60209081029190910101516001600160a01b0390911690528484828181106119f3576119f361347c565b9050602002016020810190611a089190612ed4565b604051630afbcdc960e01b81526001600160a01b0385811660048301529190911690630afbcdc9906024016040805180830381865afa158015611a4d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a719190613622565b838381518110611a8357611a8361347c565b6020026020010151602001848481518110611aa057611aa061347c565b60209081029190910101516040019190915252600101611988565b80516001600160a01b039081165f90815260016020818152604080842087861685528252808420865190951684529190528120600201549091908290611b0c90600160801b900460ff16600a6135dd565b90505f611b1e83866040015184611dab565b6020808801516001600160a01b038b165f908152600188019092526040909120549193506117b892509083906001600160681b031685612d54565b5f816001600160a01b03166350d25bcd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bba91906134e6565b13611c075760405162461bcd60e51b815260206004820152601860248201527f4f5241434c455f4d5553545f52455455524e5f50524943450000000000000000604482015260640161060f565b6001600160a01b038281165f818152603b602052604080822080546001600160a01b0319169486169485179055517f1a1cd5483e52e60b9ff7f3b9d1db3bbd9e9d21c6324ad3a8c79dba9b75e62f4d9190a35050565b5f805b8251811015610b3a57828181518110611c7b57611c7b61347c565b6020026020010151602001515f03611d065760015f848381518110611ca257611ca261347c565b602090810291909101810151516001600160a01b0390811683528282019390935260409182015f90812088851682528252828120938916815260019093019052902054611cff90600160681b90046001600160801b0316836134a4565b9150611da3565b60015f848381518110611d1b57611d1b61347c565b602090810291909101810151516001600160a01b0390811683528282019390935260409182015f908120888516825282528281209389168152600190930190529020548351600160681b9091046001600160801b031690611d8c90879087908790869081106109875761098761347c565b611d9691906134a4565b611da090836134a4565b91505b600101611c60565b82545f9081906001600160681b0381169063ffffffff600160e01b82048116916001600160581b03600160681b82041691600160c01b90910416811580611df0575087155b80611dfa57504281145b80611e055750828110155b15611e1957838495509550505050506109d2565b5f834211611e275742611e29565b835b90505f611e36838361360f565b90505f89611e448387613644565b611e4e9190613644565b8b9004905086611e5e81836134a4565b9850985050505050505050935093915050565b6001600160a01b038116611ec75760405162461bcd60e51b815260206004820152601860248201527f53545241544547595f43414e5f4e4f545f42455f5a45524f0000000000000000604482015260640161060f565b6001813b151514611f1a5760405162461bcd60e51b815260206004820152601960248201527f53545241544547595f4d5553545f42455f434f4e545241435400000000000000604482015260640161060f565b6001600160a01b038281165f818152603a602052604080822080546001600160a01b0319169486169485179055517f8ca1d928f1d72493a6b78c4f74aabde976bc37ffe2570f2a1ce5a8abd3dde0aa9190a35050565b5f5b8151811015610a2c5760015f838381518110611f9057611f9061347c565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f2060020160109054906101000a900460ff1660ff165f03612028576004828281518110611fe957611fe961347c565b6020908102919091018101516060015182546001810184555f938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b5f82828151811061203b5761203b61347c565b6020026020010151606001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612082573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120a6919061365b565b60015f8585815181106120bb576120bb61347c565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f2060020160106101000a81548160ff021916908360ff160217905560ff1690505f60015f85858151811061211b5761211b61347c565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f205f015f85858151811061215b5761215b61347c565b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020015f209050805f0160189054906101000a900463ffffffff1663ffffffff165f0361231d578383815181106121ba576121ba61347c565b60200260200101516080015160015f8686815181106121db576121db61347c565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f206001015f60015f88888151811061221f5761221f61347c565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f206002015f9054906101000a90046001600160801b03166001600160801b03166001600160801b031681526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060015f8585815181106122b7576122b761347c565b602090810291909101810151606001516001600160a01b031682528101919091526040015f90812060020180546001600160801b0316916122f78361367b565b91906101000a8154816001600160801b0302191690836001600160801b03160217905550505b60025f8585815181106123325761233261347c565b602090810291909101810151608001516001600160a01b031682528101919091526040015f9081205460ff161515900361241157600160025f86868151811061237d5761237d61347c565b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff02191690831515021790555060038484815181106123d2576123d261347c565b6020908102919091018101516080015182546001810184555f938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b5f612441828686815181106124285761242861347c565b60200260200101516020015185600a61147b91906135eb565b5082548651919250600160681b81046001600160581b031691600160e01b90910463ffffffff169087908790811061247b5761247b61347c565b60209081029190910101515184546001600160581b03909116600160681b026affffffffffffffffffffff60681b1990911617845586518790879081106124c4576124c461347c565b602090810291909101015160400151845463ffffffff909116600160e01b026001600160e01b0390911617845586518790879081106125055761250561347c565b6020026020010151608001516001600160a01b031687878151811061252c5761252c61347c565b6020026020010151606001516001600160a01b03167fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc5848a8a815181106125755761257561347c565b60200260200101515f0151858c8c815181106125935761259361347c565b602002602001015160400151896040516125e39594939291906001600160581b03958616815293909416602084015263ffffffff9182166040840152166060820152608081019190915260a00190565b60405180910390a3505060019093019250611f72915050565b6003546060908190806001600160401b0381111561261c5761261c613192565b604051908082528060200260200182016040528015612645578160200160208202803683370190505b509250806001600160401b0381111561266057612660613192565b604051908082528060200260200182016040528015612689578160200160208202803683370190505b50915061269b856115e58a8a8961190e565b5f5b878110156128c5575f8989838181106126b8576126b861347c565b90506020020160208101906126cd9190612ed4565b90505f5b838110156128bb575f6001600160a01b03168682815181106126f5576126f561347c565b60200260200101516001600160a01b03160361276c576003818154811061271e5761271e61347c565b905f5260205f20015f9054906101000a90046001600160a01b031686828151811061274b5761274b61347c565b60200260200101906001600160a01b031690816001600160a01b0316815250505b6001600160a01b0382165f908152600160205260408120875182908990859081106127995761279961347c565b6020908102919091018101516001600160a01b0390811683528282019390935260409182015f908120938d16815260019093019052902054600160681b90046001600160801b0316905080156128b257808683815181106127fc576127fc61347c565b6020026020010181815161281091906134a4565b9052506001600160a01b0383165f908152600160205260408120885182908a90869081106128405761284061347c565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206001015f8b6001600160a01b03166001600160a01b031681526020019081526020015f205f01600d6101000a8154816001600160801b0302191690836001600160801b031602179055505b506001016126d1565b505060010161269d565b505f5b818110156129b25761290d858583815181106128e6576128e661347c565b60200260200101518584815181106129005761290061347c565b6020026020010151612b89565b846001600160a01b03168482815181106129295761292961347c565b60200260200101516001600160a01b0316876001600160a01b03167fc052130bc4ef84580db505783484b067ea8b71b3bca78a7e12db7aea8658f0048a8786815181106129785761297861347c565b60200260200101516040516129a29291906001600160a01b03929092168252602082015260400190565b60405180910390a46001016128c8565b50509550959350505050565b5f805f806129cd878787611dab565b915091505f828214612a71576001600160681b03821115612a215760405162461bcd60e51b815260206004820152600e60248201526d494e4445585f4f564552464c4f5760901b604482015260640161060f565b5086546cffffffffffffffffffffffffff19166001600160681b0382161787556001612a4c42612d77565b885463ffffffff91909116600160c01b0263ffffffff60c01b19909116178855612a9b565b612a7a42612d77565b885463ffffffff91909116600160c01b0263ffffffff60c01b199091161788555b9097909650945050505050565b5f5b815181101561063d57612b15828281518110612ac857612ac861347c565b60200260200101515f015184848481518110612ae657612ae661347c565b602002602001015160200151858581518110612b0457612b0461347c565b6020026020010151604001516117c3565b600101612aaa565b5f6001600160801b03821115612b855760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b606482015260840161060f565b5090565b6001600160a01b038281165f818152603a6020526040808220549051630b5f5cc160e11b81528785166004820152602481019390935260448301859052909216919082906316beb982906064016020604051808303815f875af1158015612bf2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c1691906136a0565b9050600181151514612c5b5760405162461bcd60e51b815260206004820152600e60248201526d2a2920a729a322a92fa2a92927a960911b604482015260640161060f565b5050505050565b6001600160a01b0384165f90815260018601602052604081205481906001600160681b031681858214801590612d45576001600160a01b0389165f90815260018b016020526040902080546cffffffffffffffffffffffffff19166001600160681b0389161790558715612d4557612cdc88888589612d54565b9150612ce782612b1d565b6001600160a01b038a165f90815260018c01602052604090208054600d90612d20908490600160681b90046001600160801b03166136bf565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b90999098509650505050505050565b5f80612d60848661360f565b612d6a9087613644565b9290920495945050505050565b5f63ffffffff821115612b855760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b606482015260840161060f565b6001600160a01b0381168114610daf575f80fd5b5f8060408385031215612e00575f80fd5b8235612e0b81612ddb565b91506020830135612e1b81612ddb565b809150509250929050565b5f8083601f840112612e36575f80fd5b5081356001600160401b03811115612e4c575f80fd5b6020830191508360208260051b8501011115610c1c575f80fd5b5f805f805f60808688031215612e7a575f80fd5b85356001600160401b03811115612e8f575f80fd5b612e9b88828901612e26565b909650945050602086013592506040860135612eb681612ddb565b91506060860135612ec681612ddb565b809150509295509295909350565b5f60208284031215612ee4575f80fd5b8135612eef81612ddb565b9392505050565b5f805f60608486031215612f08575f80fd5b8335612f1381612ddb565b95602085013595506040909401359392505050565b5f805f805f8060a08789031215612f3d575f80fd5b86356001600160401b03811115612f52575f80fd5b612f5e89828a01612e26565b909750955050602087013593506040870135612f7981612ddb565b92506060870135612f8981612ddb565b91506080870135612f9981612ddb565b809150509295509295509295565b5f805f60408486031215612fb9575f80fd5b83356001600160401b03811115612fce575f80fd5b612fda86828701612e26565b9094509250506020840135612fee81612ddb565b809150509250925092565b5f815180845260208085019450602084015f5b838110156130315781516001600160a01b03168752958201959082019060010161300c565b509495945050505050565b604081525f61304e6040830185612ff9565b8281036020848101919091528451808352858201928201905f5b8181101561308457845183529383019391830191600101613068565b5090979650505050505050565b5f805f606084860312156130a3575f80fd5b83356130ae81612ddb565b925060208401356130be81612ddb565b91506040840135612fee81612ddb565b5f805f80606085870312156130e1575f80fd5b84356001600160401b038111156130f6575f80fd5b61310287828801612e26565b90955093505060208501359150604085013561311d81612ddb565b939692955090935050565b602081525f612eef6020830184612ff9565b5f805f806060858703121561314d575f80fd5b84356001600160401b03811115613162575f80fd5b61316e87828801612e26565b909550935050602085013561318281612ddb565b9150604085013561311d81612ddb565b634e487b7160e01b5f52604160045260245ffd5b60405160e081016001600160401b03811182821017156131c8576131c8613192565b60405290565b604051601f8201601f191681016001600160401b03811182821017156131f6576131f6613192565b604052919050565b80356001600160581b0381168114613214575f80fd5b919050565b803563ffffffff81168114613214575f80fd5b5f602080838503121561323d575f80fd5b82356001600160401b0380821115613253575f80fd5b818501915085601f830112613266575f80fd5b81358181111561327857613278613192565b613286848260051b016131ce565b818152848101925060e09182028401850191888311156132a4575f80fd5b938501935b828510156133465780858a0312156132bf575f80fd5b6132c76131a6565b6132d0866131fe565b8152868601358782015260406132e7818801613219565b908201526060868101356132fa81612ddb565b9082015260808681013561330d81612ddb565b9082015260a08681013561332081612ddb565b9082015260c08681013561333381612ddb565b90820152845293840193928501926132a9565b50979650505050505050565b5f8060208385031215613363575f80fd5b82356001600160401b03811115613378575f80fd5b61338485828601612e26565b90969095509350505050565b5f805f606084860312156133a2575f80fd5b83356133ad81612ddb565b925060208401356133bd81612ddb565b91506133cb60408501613219565b90509250925092565b5f805f805f606086880312156133e8575f80fd5b85356133f381612ddb565b945060208601356001600160401b038082111561340e575f80fd5b61341a89838a01612e26565b90965094506040880135915080821115613432575f80fd5b5061343f88828901612e26565b969995985093965092949392505050565b602080825260129082015271494e56414c49445f544f5f4144445245535360701b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b808201808211156105e2576105e2613490565b60208082526015908201527427a7262cafa2a6a4a9a9a4a7a72fa6a0a720a3a2a960591b604082015260600190565b5f602082840312156134f6575f80fd5b5051919050565b600181815b8085111561353757815f190482111561351d5761351d613490565b8085161561352a57918102915b93841c9390800290613502565b509250929050565b5f8261354d575060016105e2565b8161355957505f6105e2565b816001811461356f576002811461357957613595565b60019150506105e2565b60ff84111561358a5761358a613490565b50506001821b6105e2565b5060208310610133831016604e8410600b84101617156135b8575081810a6105e2565b6135c283836134fd565b805f19048211156135d5576135d5613490565b029392505050565b5f612eef60ff84168361353f565b5f612eef838361353f565b5f60208284031215613606575f80fd5b612eef826131fe565b818103818111156105e2576105e2613490565b5f8060408385031215613633575f80fd5b505080516020909101519092909150565b80820281158282048414176105e2576105e2613490565b5f6020828403121561366b575f80fd5b815160ff81168114612eef575f80fd5b5f6001600160801b0380831681810361369657613696613490565b6001019392505050565b5f602082840312156136b0575f80fd5b81518015158114612eef575f80fd5b6001600160801b038181168382160190808211156136df576136df613490565b509291505056fea164736f6c6343000816000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c1
-----Decoded View---------------
Arg [0] : emissionManager (address): 0x4F6f44325828D2A40724A0a966F33d75cD1DF7c1
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004f6f44325828d2a40724a0a966f33d75cd1df7c1
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.