Overview
HYPE Balance
HYPE Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 779363 | 323 days ago | Contract Creation | 0 HYPE |
Cross-Chain Transactions
Loading...
Loading
This contract contains unverified libraries: BorrowLogic, BridgeLogic, ConfiguratorLogic, EModeLogic, FlashLoanLogic, LiquidationLogic, PoolLogic, SupplyLogic
Contract Name:
RewardsController
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.10;
import {VersionedInitializable} from 'contracts/protocol/libraries/aave-upgradeability/VersionedInitializable.sol';
import {SafeCast} from 'contracts/dependencies/openzeppelin/contracts/SafeCast.sol';
import {IScaledBalanceToken} from 'contracts/interfaces/IScaledBalanceToken.sol';
import {RewardsDistributor} from './RewardsDistributor.sol';
import {IRewardsController} from './interfaces/IRewardsController.sol';
import {ITransferStrategyBase} from './interfaces/ITransferStrategyBase.sol';
import {RewardsDataTypes} from './libraries/RewardsDataTypes.sol';
import {IEACAggregatorProxy} from '../misc/interfaces/IEACAggregatorProxy.sol';
/**
* @title RewardsController
* @notice Abstract contract template to build Distributors contracts for ERC20 rewards to protocol participants
* @author Aave
**/
contract RewardsController is RewardsDistributor, VersionedInitializable, IRewardsController {
using SafeCast for uint256;
uint256 public constant REVISION = 1;
// This mapping allows whitelisted addresses to claim on behalf of others
// useful for contracts that hold tokens to be rewarded but don't have any native logic to claim Liquidity Mining rewards
mapping(address => address) internal _authorizedClaimers;
// reward => transfer strategy implementation contract
// The TransferStrategy contract abstracts the logic regarding
// the source of the reward and how to transfer it to the user.
mapping(address => ITransferStrategyBase) internal _transferStrategy;
// This mapping contains the price oracle per reward.
// A price oracle is enforced for integrators to be able to show incentives at
// the current Aave UI without the need to setup an external price registry
// At the moment of reward configuration, the Incentives Controller performs
// a check to see if the provided reward oracle contains `latestAnswer`.
mapping(address => IEACAggregatorProxy) internal _rewardOracle;
modifier onlyAuthorizedClaimers(address claimer, address user) {
require(_authorizedClaimers[user] == claimer, 'CLAIMER_UNAUTHORIZED');
_;
}
constructor(address emissionManager) RewardsDistributor(emissionManager) {}
/**
* @dev Initialize for RewardsController
* @dev It expects an address as argument since its initialized via PoolAddressesProvider._updateImpl()
**/
function initialize(address) external initializer {}
/// @inheritdoc IRewardsController
function getClaimer(address user) external view override returns (address) {
return _authorizedClaimers[user];
}
/**
* @dev Returns the revision of the implementation contract
* @return uint256, current revision version
*/
function getRevision() internal pure override returns (uint256) {
return REVISION;
}
/// @inheritdoc IRewardsController
function getRewardOracle(address reward) external view override returns (address) {
return address(_rewardOracle[reward]);
}
/// @inheritdoc IRewardsController
function getTransferStrategy(address reward) external view override returns (address) {
return address(_transferStrategy[reward]);
}
/// @inheritdoc IRewardsController
function configureAssets(
RewardsDataTypes.RewardsConfigInput[] memory config
) external override onlyEmissionManager {
for (uint256 i = 0; i < config.length; i++) {
// Get the current Scaled Total Supply of AToken or Debt token
config[i].totalSupply = IScaledBalanceToken(config[i].asset).scaledTotalSupply();
// Install TransferStrategy logic at IncentivesController
_installTransferStrategy(config[i].reward, config[i].transferStrategy);
// Set reward oracle, enforces input oracle to have latestPrice function
_setRewardOracle(config[i].reward, config[i].rewardOracle);
}
_configureAssets(config);
}
/// @inheritdoc IRewardsController
function setTransferStrategy(
address reward,
ITransferStrategyBase transferStrategy
) external onlyEmissionManager {
_installTransferStrategy(reward, transferStrategy);
}
/// @inheritdoc IRewardsController
function setRewardOracle(
address reward,
IEACAggregatorProxy rewardOracle
) external onlyEmissionManager {
_setRewardOracle(reward, rewardOracle);
}
/// @inheritdoc IRewardsController
function handleAction(address user, uint256 totalSupply, uint256 userBalance) external override {
_updateData(msg.sender, user, userBalance, totalSupply);
}
/// @inheritdoc IRewardsController
function claimRewards(
address[] calldata assets,
uint256 amount,
address to,
address reward
) external override returns (uint256) {
require(to != address(0), 'INVALID_TO_ADDRESS');
return _claimRewards(assets, amount, msg.sender, msg.sender, to, reward);
}
/// @inheritdoc IRewardsController
function claimRewardsOnBehalf(
address[] calldata assets,
uint256 amount,
address user,
address to,
address reward
) external override onlyAuthorizedClaimers(msg.sender, user) returns (uint256) {
require(user != address(0), 'INVALID_USER_ADDRESS');
require(to != address(0), 'INVALID_TO_ADDRESS');
return _claimRewards(assets, amount, msg.sender, user, to, reward);
}
/// @inheritdoc IRewardsController
function claimRewardsToSelf(
address[] calldata assets,
uint256 amount,
address reward
) external override returns (uint256) {
return _claimRewards(assets, amount, msg.sender, msg.sender, msg.sender, reward);
}
/// @inheritdoc IRewardsController
function claimAllRewards(
address[] calldata assets,
address to
) external override returns (address[] memory rewardsList, uint256[] memory claimedAmounts) {
require(to != address(0), 'INVALID_TO_ADDRESS');
return _claimAllRewards(assets, msg.sender, msg.sender, to);
}
/// @inheritdoc IRewardsController
function claimAllRewardsOnBehalf(
address[] calldata assets,
address user,
address to
)
external
override
onlyAuthorizedClaimers(msg.sender, user)
returns (address[] memory rewardsList, uint256[] memory claimedAmounts)
{
require(user != address(0), 'INVALID_USER_ADDRESS');
require(to != address(0), 'INVALID_TO_ADDRESS');
return _claimAllRewards(assets, msg.sender, user, to);
}
/// @inheritdoc IRewardsController
function claimAllRewardsToSelf(
address[] calldata assets
) external override returns (address[] memory rewardsList, uint256[] memory claimedAmounts) {
return _claimAllRewards(assets, msg.sender, msg.sender, msg.sender);
}
/// @inheritdoc IRewardsController
function setClaimer(address user, address caller) external override onlyEmissionManager {
_authorizedClaimers[user] = caller;
emit ClaimerSet(user, caller);
}
/**
* @dev Get user balances and total supply of all the assets specified by the assets parameter
* @param assets List of assets to retrieve user balance and total supply
* @param user Address of the user
* @return userAssetBalances contains a list of structs with user balance and total supply of the given assets
*/
function _getUserAssetBalances(
address[] calldata assets,
address user
) internal view override returns (RewardsDataTypes.UserAssetBalance[] memory userAssetBalances) {
userAssetBalances = new RewardsDataTypes.UserAssetBalance[](assets.length);
for (uint256 i = 0; i < assets.length; i++) {
userAssetBalances[i].asset = assets[i];
(userAssetBalances[i].userBalance, userAssetBalances[i].totalSupply) = IScaledBalanceToken(
assets[i]
).getScaledUserBalanceAndSupply(user);
}
return userAssetBalances;
}
/**
* @dev Claims one type of reward for a user on behalf, on all the assets of the pool, accumulating the pending rewards.
* @param assets List of assets to check eligible distributions before claiming rewards
* @param amount Amount of rewards to claim
* @param claimer Address of the claimer who claims rewards on behalf of user
* @param user Address to check and claim rewards
* @param to Address that will be receiving the rewards
* @param reward Address of the reward token
* @return Rewards claimed
**/
function _claimRewards(
address[] calldata assets,
uint256 amount,
address claimer,
address user,
address to,
address reward
) internal returns (uint256) {
if (amount == 0) {
return 0;
}
uint256 totalRewards;
_updateDataMultiple(user, _getUserAssetBalances(assets, user));
for (uint256 i = 0; i < assets.length; i++) {
address asset = assets[i];
totalRewards += _assets[asset].rewards[reward].usersData[user].accrued;
if (totalRewards <= amount) {
_assets[asset].rewards[reward].usersData[user].accrued = 0;
} else {
uint256 difference = totalRewards - amount;
totalRewards -= difference;
_assets[asset].rewards[reward].usersData[user].accrued = difference.toUint128();
break;
}
}
if (totalRewards == 0) {
return 0;
}
_transferRewards(to, reward, totalRewards);
emit RewardsClaimed(user, reward, to, claimer, totalRewards);
return totalRewards;
}
/**
* @dev Claims one type of reward for a user on behalf, on all the assets of the pool, accumulating the pending rewards.
* @param assets List of assets to check eligible distributions before claiming rewards
* @param claimer Address of the claimer on behalf of user
* @param user Address to check and claim rewards
* @param to Address that will be receiving the rewards
* @return
* rewardsList List of reward addresses
* claimedAmount List of claimed amounts, follows "rewardsList" items order
**/
function _claimAllRewards(
address[] calldata assets,
address claimer,
address user,
address to
) internal returns (address[] memory rewardsList, uint256[] memory claimedAmounts) {
uint256 rewardsListLength = _rewardsList.length;
rewardsList = new address[](rewardsListLength);
claimedAmounts = new uint256[](rewardsListLength);
_updateDataMultiple(user, _getUserAssetBalances(assets, user));
for (uint256 i = 0; i < assets.length; i++) {
address asset = assets[i];
for (uint256 j = 0; j < rewardsListLength; j++) {
if (rewardsList[j] == address(0)) {
rewardsList[j] = _rewardsList[j];
}
uint256 rewardAmount = _assets[asset].rewards[rewardsList[j]].usersData[user].accrued;
if (rewardAmount != 0) {
claimedAmounts[j] += rewardAmount;
_assets[asset].rewards[rewardsList[j]].usersData[user].accrued = 0;
}
}
}
for (uint256 i = 0; i < rewardsListLength; i++) {
_transferRewards(to, rewardsList[i], claimedAmounts[i]);
emit RewardsClaimed(user, rewardsList[i], to, claimer, claimedAmounts[i]);
}
return (rewardsList, claimedAmounts);
}
/**
* @dev Function to transfer rewards to the desired account using delegatecall and
* @param to Account address to send the rewards
* @param reward Address of the reward token
* @param amount Amount of rewards to transfer
*/
function _transferRewards(address to, address reward, uint256 amount) internal {
ITransferStrategyBase transferStrategy = _transferStrategy[reward];
bool success = transferStrategy.performTransfer(to, reward, amount);
require(success == true, 'TRANSFER_ERROR');
}
/**
* @dev Returns true if `account` is a contract.
* @param account The address of the account
* @return bool, true if contract, false otherwise
*/
function _isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Internal function to call the optional install hook at the TransferStrategy
* @param reward The address of the reward token
* @param transferStrategy The address of the reward TransferStrategy
*/
function _installTransferStrategy(
address reward,
ITransferStrategyBase transferStrategy
) internal {
require(address(transferStrategy) != address(0), 'STRATEGY_CAN_NOT_BE_ZERO');
require(_isContract(address(transferStrategy)) == true, 'STRATEGY_MUST_BE_CONTRACT');
_transferStrategy[reward] = transferStrategy;
emit TransferStrategyInstalled(reward, address(transferStrategy));
}
/**
* @dev Update the Price Oracle of a reward token. The Price Oracle must follow Chainlink IEACAggregatorProxy interface.
* @notice The Price Oracle of a reward is used for displaying correct data about the incentives at the UI frontend.
* @param reward The address of the reward token
* @param rewardOracle The address of the price oracle
*/
function _setRewardOracle(address reward, IEACAggregatorProxy rewardOracle) internal {
require(rewardOracle.latestAnswer() > 0, 'ORACLE_MUST_RETURN_PRICE');
_rewardOracle[reward] = rewardOracle;
emit RewardOracleUpdated(reward, address(rewardOracle));
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.0;
import {IERC20} from './IERC20.sol';
interface IERC20Detailed is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, 'SafeCast: value must be positive');
return uint256(value);
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128) {
require(
value >= type(int128).min && value <= type(int128).max,
"SafeCast: value doesn't fit in 128 bits"
);
return int128(value);
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64) {
require(
value >= type(int64).min && value <= type(int64).max,
"SafeCast: value doesn't fit in 64 bits"
);
return int64(value);
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32) {
require(
value >= type(int32).min && value <= type(int32).max,
"SafeCast: value doesn't fit in 32 bits"
);
return int32(value);
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16) {
require(
value >= type(int16).min && value <= type(int16).max,
"SafeCast: value doesn't fit in 16 bits"
);
return int16(value);
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8) {
require(
value >= type(int8).min && value <= type(int8).max,
"SafeCast: value doesn't fit in 8 bits"
);
return int8(value);
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.0;
/**
* @title IScaledBalanceToken
* @author Aave
* @notice Defines the basic interface for a scaled-balance token.
*/
interface IScaledBalanceToken {
/**
* @dev Emitted after the mint action
* @param caller The address performing the mint
* @param onBehalfOf The address of the user that will receive the minted tokens
* @param value The scaled-up amount being minted (based on user entered amount and balance increase from interest)
* @param balanceIncrease The increase in scaled-up balance since the last action of 'onBehalfOf'
* @param index The next liquidity index of the reserve
*/
event Mint(
address indexed caller,
address indexed onBehalfOf,
uint256 value,
uint256 balanceIncrease,
uint256 index
);
/**
* @dev Emitted after the burn action
* @dev If the burn function does not involve a transfer of the underlying asset, the target defaults to zero address
* @param from The address from which the tokens will be burned
* @param target The address that will receive the underlying, if any
* @param value The scaled-up amount being burned (user entered amount - balance increase from interest)
* @param balanceIncrease The increase in scaled-up balance since the last action of 'from'
* @param index The next liquidity index of the reserve
*/
event Burn(
address indexed from,
address indexed target,
uint256 value,
uint256 balanceIncrease,
uint256 index
);
/**
* @notice Returns the scaled balance of the user.
* @dev The scaled balance is the sum of all the updated stored balance divided by the reserve's liquidity index
* at the moment of the update
* @param user The user whose balance is calculated
* @return The scaled balance of the user
*/
function scaledBalanceOf(address user) external view returns (uint256);
/**
* @notice Returns the scaled balance of the user and the scaled total supply.
* @param user The address of the user
* @return The scaled balance of the user
* @return The scaled total supply
*/
function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
/**
* @notice Returns the scaled total supply of the scaled balance token. Represents sum(debt/index)
* @return The scaled total supply
*/
function scaledTotalSupply() external view returns (uint256);
/**
* @notice Returns last index interest was accrued to the user's balance
* @param user The address of the user
* @return The last index interest was accrued to the user's balance, expressed in ray
*/
function getPreviousIndex(address user) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
interface IEACAggregatorProxy {
function decimals() external view returns (uint8);
function latestAnswer() external view returns (int256);
function latestTimestamp() external view returns (uint256);
function latestRound() external view returns (uint256);
function getAnswer(uint256 roundId) external view returns (int256);
function getTimestamp(uint256 roundId) external view returns (uint256);
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp);
event NewRound(uint256 indexed roundId, address indexed startedBy);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.10;
import {IScaledBalanceToken} from 'contracts/interfaces/IScaledBalanceToken.sol';
import {IERC20Detailed} from 'contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol';
import {SafeCast} from 'contracts/dependencies/openzeppelin/contracts/SafeCast.sol';
import {IRewardsDistributor} from './interfaces/IRewardsDistributor.sol';
import {RewardsDataTypes} from './libraries/RewardsDataTypes.sol';
/**
* @title RewardsDistributor
* @notice Accounting contract to manage multiple staking distributions with multiple rewards
* @author Aave
**/
abstract contract RewardsDistributor is IRewardsDistributor {
using SafeCast for uint256;
// Manager of incentives
address public immutable EMISSION_MANAGER;
// Deprecated: This storage slot is kept for backwards compatibility purposes.
address internal _emissionManager;
// Map of rewarded asset addresses and their data (assetAddress => assetData)
mapping(address => RewardsDataTypes.AssetData) internal _assets;
// Map of reward assets (rewardAddress => enabled)
mapping(address => bool) internal _isRewardEnabled;
// Rewards list
address[] internal _rewardsList;
// Assets list
address[] internal _assetsList;
modifier onlyEmissionManager() {
require(msg.sender == EMISSION_MANAGER, 'ONLY_EMISSION_MANAGER');
_;
}
constructor(address emissionManager) {
EMISSION_MANAGER = emissionManager;
}
/// @inheritdoc IRewardsDistributor
function getRewardsData(
address asset,
address reward
) 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 {IEACAggregatorProxy} from '../../misc/interfaces/IEACAggregatorProxy.sol';
import {RewardsDataTypes} from '../libraries/RewardsDataTypes.sol';
/**
* @title IRewardsController
* @author Aave
* @notice Defines the basic interface for a Rewards Controller.
*/
interface IRewardsController is IRewardsDistributor {
/**
* @dev Emitted when a new address is whitelisted as claimer of rewards on behalf of a user
* @param user The address of the user
* @param claimer The address of the claimer
*/
event ClaimerSet(address indexed user, address indexed claimer);
/**
* @dev Emitted when rewards are claimed
* @param user The address of the user rewards has been claimed on behalf of
* @param reward The address of the token reward is claimed
* @param to The address of the receiver of the rewards
* @param claimer The address of the claimer
* @param amount The amount of rewards claimed
*/
event RewardsClaimed(
address indexed user,
address indexed reward,
address indexed to,
address claimer,
uint256 amount
);
/**
* @dev Emitted when a transfer strategy is installed for the reward distribution
* @param reward The address of the token reward
* @param transferStrategy The address of TransferStrategy contract
*/
event TransferStrategyInstalled(address indexed reward, address indexed transferStrategy);
/**
* @dev Emitted when the reward oracle is updated
* @param reward The address of the token reward
* @param rewardOracle The address of oracle
*/
event RewardOracleUpdated(address indexed reward, address indexed rewardOracle);
/**
* @dev Whitelists an address to claim the rewards on behalf of another address
* @param user The address of the user
* @param claimer The address of the claimer
*/
function setClaimer(address user, address claimer) external;
/**
* @dev Sets a TransferStrategy logic contract that determines the logic of the rewards transfer
* @param reward The address of the reward token
* @param transferStrategy The address of the TransferStrategy logic contract
*/
function setTransferStrategy(address reward, ITransferStrategyBase transferStrategy) external;
/**
* @dev Sets an Aave Oracle contract to enforce rewards with a source of value.
* @notice At the moment of reward configuration, the Incentives Controller performs
* a check to see if the reward asset oracle is compatible with IEACAggregator proxy.
* This check is enforced for integrators to be able to show incentives at
* the current Aave UI without the need to setup an external price registry
* @param reward The address of the reward to set the price aggregator
* @param rewardOracle The address of price aggregator that follows IEACAggregatorProxy interface
*/
function setRewardOracle(address reward, IEACAggregatorProxy rewardOracle) external;
/**
* @dev Get the price aggregator oracle address
* @param reward The address of the reward
* @return The price oracle of the reward
*/
function getRewardOracle(address reward) external view returns (address);
/**
* @dev Returns the whitelisted claimer for a certain address (0x0 if not set)
* @param user The address of the user
* @return The claimer address
*/
function getClaimer(address user) external view returns (address);
/**
* @dev Returns the Transfer Strategy implementation contract address being used for a reward address
* @param reward The address of the reward
* @return The address of the TransferStrategy contract
*/
function getTransferStrategy(address reward) external view returns (address);
/**
* @dev Configure assets to incentivize with an emission of rewards per second until the end of distribution.
* @param config The assets configuration input, the list of structs contains the following fields:
* uint104 emissionPerSecond: The emission per second following rewards unit decimals.
* uint256 totalSupply: The total supply of the asset to incentivize
* uint40 distributionEnd: The end of the distribution of the incentives for an asset
* address asset: The asset address to incentivize
* address reward: The reward token address
* ITransferStrategy transferStrategy: The TransferStrategy address with the install hook and claim logic.
* IEACAggregatorProxy rewardOracle: The Price Oracle of a reward to visualize the incentives at the UI Frontend.
* Must follow Chainlink Aggregator IEACAggregatorProxy interface to be compatible.
*/
function configureAssets(RewardsDataTypes.RewardsConfigInput[] memory config) external;
/**
* @dev Called by the corresponding asset on transfer hook in order to update the rewards distribution.
* @dev The units of `totalSupply` and `userBalance` should be the same.
* @param user The address of the user whose asset balance has changed
* @param totalSupply The total supply of the asset prior to user balance change
* @param userBalance The previous user balance prior to balance change
**/
function handleAction(address user, uint256 totalSupply, uint256 userBalance) external;
/**
* @dev Claims reward for a user to the desired address, on all the assets of the pool, accumulating the pending rewards
* @param assets List of assets to check eligible distributions before claiming rewards
* @param amount The amount of rewards to claim
* @param to The address that will be receiving the rewards
* @param reward The address of the reward token
* @return The amount of rewards claimed
**/
function claimRewards(
address[] calldata assets,
uint256 amount,
address to,
address reward
) external returns (uint256);
/**
* @dev Claims reward for a user on behalf, on all the assets of the pool, accumulating the pending rewards. The
* caller must be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
* @param assets The list of assets to check eligible distributions before claiming rewards
* @param amount The amount of rewards to claim
* @param user The address to check and claim rewards
* @param to The address that will be receiving the rewards
* @param reward The address of the reward token
* @return The amount of rewards claimed
**/
function claimRewardsOnBehalf(
address[] calldata assets,
uint256 amount,
address user,
address to,
address reward
) external returns (uint256);
/**
* @dev Claims reward for msg.sender, on all the assets of the pool, accumulating the pending rewards
* @param assets The list of assets to check eligible distributions before claiming rewards
* @param amount The amount of rewards to claim
* @param reward The address of the reward token
* @return The amount of rewards claimed
**/
function claimRewardsToSelf(
address[] calldata assets,
uint256 amount,
address reward
) external returns (uint256);
/**
* @dev Claims all rewards for a user to the desired address, on all the assets of the pool, accumulating the pending rewards
* @param assets The list of assets to check eligible distributions before claiming rewards
* @param to The address that will be receiving the rewards
* @return rewardsList List of addresses of the reward tokens
* @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardList"
**/
function claimAllRewards(
address[] calldata assets,
address to
) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
/**
* @dev Claims all rewards for a user on behalf, on all the assets of the pool, accumulating the pending rewards. The caller must
* be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
* @param assets The list of assets to check eligible distributions before claiming rewards
* @param user The address to check and claim rewards
* @param to The address that will be receiving the rewards
* @return rewardsList List of addresses of the reward tokens
* @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardsList"
**/
function claimAllRewardsOnBehalf(
address[] calldata assets,
address user,
address to
) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
/**
* @dev Claims all reward for msg.sender, on all the assets of the pool, accumulating the pending rewards
* @param assets The list of assets to check eligible distributions before claiming rewards
* @return rewardsList List of addresses of the reward tokens
* @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardsList"
**/
function claimAllRewardsToSelf(
address[] calldata assets
) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
}// 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 {IEACAggregatorProxy} from '../../misc/interfaces/IEACAggregatorProxy.sol';
library RewardsDataTypes {
struct RewardsConfigInput {
uint88 emissionPerSecond;
uint256 totalSupply;
uint32 distributionEnd;
address asset;
address reward;
ITransferStrategyBase transferStrategy;
IEACAggregatorProxy rewardOracle;
}
struct UserAssetBalance {
address asset;
uint256 userBalance;
uint256 totalSupply;
}
struct UserData {
// Liquidity index of the reward distribution for the user
uint104 index;
// Amount of accrued rewards for the user since last user index update
uint128 accrued;
}
struct RewardData {
// Liquidity index of the reward distribution
uint104 index;
// Amount of reward tokens distributed per second
uint88 emissionPerSecond;
// Timestamp of the last reward index update
uint32 lastUpdateTimestamp;
// The end of the distribution of rewards (in seconds)
uint32 distributionEnd;
// Map of user addresses and their rewards data (userAddress => userData)
mapping(address => UserData) usersData;
}
struct AssetData {
// Map of reward token addresses and their data (rewardTokenAddress => rewardData)
mapping(address => RewardData) rewards;
// List of reward token addresses for the asset
mapping(uint128 => address) availableRewards;
// Count of reward tokens for the asset
uint128 availableRewardsCount;
// Number of decimals of the asset
uint8 decimals;
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.0;
/**
* @title VersionedInitializable
* @author Aave, inspired by the OpenZeppelin Initializable contract
* @notice Helper contract to implement initializer functions. To use it, replace
* the constructor with a function that has the `initializer` modifier.
* @dev WARNING: Unlike constructors, initializer functions must be manually
* invoked. This applies both to deploying an Initializable contract, as well
* as extending an Initializable contract via inheritance.
* WARNING: When used with inheritance, manual care must be taken to not invoke
* a parent initializer twice, or ensure that all initializers are idempotent,
* because this is not dealt with automatically as with constructors.
*/
abstract contract VersionedInitializable {
/**
* @dev Indicates that the contract has been initialized.
*/
uint256 private lastInitializedRevision = 0;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private initializing;
/**
* @dev Modifier to use in the initializer function of a contract.
*/
modifier initializer() {
uint256 revision = getRevision();
require(
initializing || isConstructor() || revision > lastInitializedRevision,
'Contract instance has already been initialized'
);
bool isTopLevelCall = !initializing;
if (isTopLevelCall) {
initializing = true;
lastInitializedRevision = revision;
}
_;
if (isTopLevelCall) {
initializing = false;
}
}
/**
* @notice Returns the revision number of the contract
* @dev Needs to be defined in the inherited class as a constant.
* @return The revision number
*/
function getRevision() internal pure virtual returns (uint256);
/**
* @notice Returns true if and only if the function is running in the constructor
* @return True if the function is running in the constructor
*/
function isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
uint256 cs;
//solium-disable-next-line
assembly {
cs := extcodesize(address())
}
return cs == 0;
}
// Reserved storage space to allow for layout changes in the future.
uint256[50] private ______gap;
}{
"evmVersion": "shanghai",
"libraries": {
"contracts/protocol/libraries/logic/BorrowLogic.sol": {
"BorrowLogic": "0x732872409e5d98b37E89814763cf97fE438603b4"
},
"contracts/protocol/libraries/logic/BridgeLogic.sol": {
"BridgeLogic": "0xAB33b3A13563E65d737AeA88773ea675e073Fa2f"
},
"contracts/protocol/libraries/logic/ConfiguratorLogic.sol": {
"ConfiguratorLogic": "0xf16019f295d3A99c2dDBcDd6a220D496036C2E22"
},
"contracts/protocol/libraries/logic/EModeLogic.sol": {
"EModeLogic": "0xB9bc838F9BAD6cF18AcbBb8Df84b0c442bc55400"
},
"contracts/protocol/libraries/logic/FlashLoanLogic.sol": {
"FlashLoanLogic": "0x372EA9A547F26d3730B21a54A04fB7D79E5f8612"
},
"contracts/protocol/libraries/logic/LiquidationLogic.sol": {
"LiquidationLogic": "0x6C772b50D1Db1981D8329Cf6F9DDf3EdB2a576d7"
},
"contracts/protocol/libraries/logic/PoolLogic.sol": {
"PoolLogic": "0x93b4B177AF0282616A98a065f33C44C170383e41"
},
"contracts/protocol/libraries/logic/SupplyLogic.sol": {
"SupplyLogic": "0x787819f4700a2e2E6bF08A1CA5D4eb6a7A5193E5"
}
},
"metadata": {
"appendCBOR": true,
"bytecodeHash": "none",
"useLiteralContent": false
},
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"solidity-utils/=lib/solidity-utils/src/",
"forge-std/=lib/forge-std/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"@openzeppelin/contacts/=lib/openzeppelin-contracts/contracts/",
"@uniswap/v3-periphery/=lib/v3-periphery/",
"@uniswap/v3-core/=lib/v3-core/",
"@layerzerolabs/solidity-examples/=lib/endpoint-v1-solidity-examples/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"v3-core/=lib/v3-core/",
"v3-periphery/=lib/v3-periphery/contracts/"
],
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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 IEACAggregatorProxy","name":"rewardOracle","type":"address"}],"internalType":"struct RewardsDataTypes.RewardsConfigInput[]","name":"config","type":"tuple[]"}],"name":"configureAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"address","name":"user","type":"address"}],"name":"getAllUserRewards","outputs":[{"internalType":"address[]","name":"rewardsList","type":"address[]"},{"internalType":"uint256[]","name":"unclaimedAmounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getAssetDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"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 IEACAggregatorProxy","name":"rewardOracle","type":"address"}],"name":"setRewardOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"reward","type":"address"},{"internalType":"contract ITransferStrategyBase","name":"transferStrategy","type":"address"}],"name":"setTransferStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a06040525f60055534801562000014575f80fd5b506040516200385438038062003854833981016040819052620000379162000049565b6001600160a01b031660805262000078565b5f602082840312156200005a575f80fd5b81516001600160a01b038116811462000071575f80fd5b9392505050565b608051613792620000c25f395f818161044f0152818161054c015281816109f901528181610c4c015281816110e5015281816111f40152818161124601526112e401526137925ff3fe608060405234801561000f575f80fd5b50600436106101d1575f3560e01c806392074b08116100fe578063bf90f63a1161009e578063dde43cba1161006e578063dde43cba1461056e578063e15ac62314610576578063f5cf673b14610589578063f996868b1461059c575f80fd5b8063bf90f63a1461050e578063c4d66de814610521578063c5a7b53814610534578063cbcbb50714610547575f80fd5b80639ff55db9116100d95780639ff55db9146104cd578063b022418c146104e0578063b45ac1a9146104f3578063bb492bf5146104fb575f80fd5b806392074b081461044d578063955c2ad7146104735780639efd6f7214610486575f80fd5b80635453ba101161017457806370674ab91161014457806370674ab91461035b57806374d945ec1461036e5780637eff4ba814610399578063886fe70b14610425575f80fd5b80635453ba10146102ea57806357b89883146102fd5780635f130b24146103105780636657732f1461033b575f80fd5b806331873e2e116101af57806331873e2e1461025157806333028b99146102665780634c0369c314610279578063533f542a1461029a575f80fd5b80631b839c77146101d5578063236300dc146101fb5780632a17bf601461020e575b5f80fd5b6101e86101e3366004612e76565b6105af565b6040519081526020015b60405180910390f35b6101e8610209366004612eed565b6105e8565b61023961021c366004612f5b565b6001600160a01b039081165f908152603b60205260409020541690565b6040516001600160a01b0390911681526020016101f2565b61026461025f366004612f7d565b610631565b005b6101e8610274366004612faf565b610642565b61028c61028736600461302e565b610736565b6040516101f29291906130c2565b6101e86102a8366004613117565b6001600160a01b038083165f90815260016020818152604080842086861685528252808420948816845293909101905220546001600160681b03169392505050565b6102646102f8366004612e76565b6109ee565b6101e861030b366004613154565b610a44565b61023961031e366004612f5b565b6001600160a01b039081165f908152603a60205260409020541690565b61034e610349366004612f5b565b610a5d565b6040516101f291906131ae565b6101e86103693660046131c0565b610b60565b61023961037c366004612f5b565b6001600160a01b039081165f908152603960205260409020541690565b6104056103a7366004612e76565b6001600160a01b039182165f9081526001602090815260408083209390941682529190915220546001600160681b038116916001600160581b03600160681b8304169163ffffffff600160c01b8204811692600160e01b9092041690565b6040805194855260208501939093529183015260608201526080016101f2565b610438610433366004612e76565b610b76565b604080519283526020830191909152016101f2565b7f0000000000000000000000000000000000000000000000000000000000000000610239565b6102646104813660046132b2565b610c41565b6104bb610494366004612f5b565b6001600160a01b03165f90815260016020526040902060020154600160801b900460ff1690565b60405160ff90911681526020016101f2565b61028c6104db3660046131c0565b610dda565b6101e86104ee366004612e76565b610ed1565b61034e610f66565b61028c61050936600461302e565b610fc6565b61028c61051c3660046133d9565b611008565b61026461052f366004612f5b565b611023565b610264610542366004613417565b6110da565b6102397f000000000000000000000000000000000000000000000000000000000000000081565b6101e8600181565b610264610584366004612e76565b6111e9565b610264610597366004612e76565b61123b565b6102646105aa36600461345b565b6112d9565b6001600160a01b038281165f90815260016020908152604080832093851683529290522054600160e01b900463ffffffff165b92915050565b5f6001600160a01b0383166106185760405162461bcd60e51b815260040161060f906134d7565b60405180910390fd5b610627868686333388886115ff565b9695505050505050565b61063d33848385611806565b505050565b6001600160a01b038084165f908152603960205260408120549091339186911682146106a75760405162461bcd60e51b815260206004820152601460248201527310d3105253515497d5539055551213d49256915160621b604482015260640161060f565b6001600160a01b0386166106f45760405162461bcd60e51b8152602060048201526014602482015273494e56414c49445f555345525f4144445245535360601b604482015260640161060f565b6001600160a01b03851661071a5760405162461bcd60e51b815260040161060f906134d7565b610729898989338a8a8a6115ff565b9998505050505050505050565b6060805f610745868686611951565b6003549091506001600160401b0381111561076257610762613218565b60405190808252806020026020018201604052801561078b578160200160208202803683370190505b50925082516001600160401b038111156107a7576107a7613218565b6040519080825280602002602001820160405280156107d0578160200160208202803683370190505b5091505f5b81518110156109e3575f5b84518110156109d057600381815481106107fc576107fc613503565b905f5260205f20015f9054906101000a90046001600160a01b031685828151811061082957610829613503565b60200260200101906001600160a01b031690816001600160a01b03168152505060015f84848151811061085e5761085e613503565b60200260200101515f01516001600160a01b03166001600160a01b031681526020019081526020015f205f015f86838151811061089d5761089d613503565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206001015f876001600160a01b03166001600160a01b031681526020019081526020015f205f01600d9054906101000a90046001600160801b03166001600160801b031684828151811061091957610919613503565b6020026020010181815161092d919061352b565b905250825183908390811061094457610944613503565b6020026020010151602001515f03156109be576109948686838151811061096d5761096d613503565b602002602001015185858151811061098757610987613503565b6020026020010151611b08565b8482815181106109a6576109a6613503565b602002602001018181516109ba919061352b565b9052505b806109c88161353e565b9150506107e0565b50806109db8161353e565b9150506107d5565b50505b935093915050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a365760405162461bcd60e51b815260040161060f90613556565b610a408282611ba6565b5050565b5f610a54858585333333886115ff565b95945050505050565b6001600160a01b0381165f908152600160205260408120600201546060916001600160801b0390911690816001600160401b03811115610a9f57610a9f613218565b604051908082528060200260200182016040528015610ac8578160200160208202803683370190505b5090505f5b826001600160801b0316816001600160801b03161015610b58576001600160a01b038086165f9081526001602081815260408084206001600160801b03871680865293019091529091205484519216918491908110610b2e57610b2e613503565b6001600160a01b039092166020928302919091019091015280610b5081613585565b915050610acd565b509392505050565b5f610a548383610b71888888611951565b611caa565b6001600160a01b038083165f8181526001602090815260408083209486168352938152838220845163b1bf962d60e01b81529451929485949193610c349385939263b1bf962d92600480830193928290030181865afa158015610bdb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bff91906135aa565b6001600160a01b0388165f90815260016020526040902060020154610c2f90600160801b900460ff16600a6136a1565b611e02565b92509250505b9250929050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c895760405162461bcd60e51b815260040161060f90613556565b5f5b8151811015610dcd57818181518110610ca657610ca6613503565b6020026020010151606001516001600160a01b031663b1bf962d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ced573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1191906135aa565b828281518110610d2357610d23613503565b60200260200101516020018181525050610d77828281518110610d4857610d48613503565b602002602001015160800151838381518110610d6657610d66613503565b602002602001015160a00151611ec8565b610dbb828281518110610d8c57610d8c613503565b602002602001015160800151838381518110610daa57610daa613503565b602002602001015160c00151611ba6565b80610dc58161353e565b915050610c8b565b50610dd781611fc7565b50565b6001600160a01b038083165f90815260396020526040902054606091829133918691168214610e425760405162461bcd60e51b815260206004820152601460248201527310d3105253515497d5539055551213d49256915160621b604482015260640161060f565b6001600160a01b038616610e8f5760405162461bcd60e51b8152602060048201526014602482015273494e56414c49445f555345525f4144445245535360601b604482015260640161060f565b6001600160a01b038516610eb55760405162461bcd60e51b815260040161060f906134d7565b610ec2888833898961265a565b93509350505094509492505050565b5f805f5b600454811015610b585760015f60048381548110610ef557610ef5613503565b5f918252602080832091909101546001600160a01b03908116845283820194909452604092830182208885168352815282822093891682526001909301909252902054610f5290600160681b90046001600160801b03168361352b565b915080610f5e8161353e565b915050610ed5565b60606003805480602002602001604051908101604052809291908181526020018280548015610fbc57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610f9e575b5050505050905090565b6060806001600160a01b038316610fef5760405162461bcd60e51b815260040161060f906134d7565b610ffc858533338761265a565b91509150935093915050565b606080611018848433333361265a565b915091509250929050565b60065460019060ff16806110365750303b155b80611042575060055481115b6110a55760405162461bcd60e51b815260206004820152602e60248201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560448201526d195b881a5b9a5d1a585b1a5e995960921b606482015260840161060f565b60065460ff161580156110c5576006805460ff1916600117905560058290555b801561063d576006805460ff19169055505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111225760405162461bcd60e51b815260040161060f90613556565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902080546001600160e01b038116600160e01b63ffffffff898116828102938417958690558751600160681b9096046001600160581b0316808752968601969096529083041694830185905260608301939093526001600160681b039081169216919091176080820152909291907fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc59060a00160405180910390a350505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146112315760405162461bcd60e51b815260040161060f90613556565b610a408282611ec8565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146112835760405162461bcd60e51b815260040161060f90613556565b6001600160a01b038281165f8181526039602052604080822080546001600160a01b0319169486169485179055517f4925eafc82d0c4d67889898eeed64b18488ab19811e61620f387026dec126a289190a35050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146113215760405162461bcd60e51b815260040161060f90613556565b8281146113605760405162461bcd60e51b815260206004820152600d60248201526c1253959053125117d253941555609a1b604482015260640161060f565b5f5b838110156115f7576001600160a01b0386165f90815260016020526040812090818188888681811061139657611396613503565b90506020020160208101906113ab9190612f5b565b6001600160a01b0316815260208101919091526040015f206002830154909150600160801b900460ff1680158015906113f157508154600160c01b900463ffffffff1615155b61143d5760405162461bcd60e51b815260206004820152601b60248201527f444953545249425554494f4e5f444f45535f4e4f545f45584953540000000000604482015260640161060f565b5f6114b2838b6001600160a01b031663b1bf962d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561147e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114a291906135aa565b6114ad85600a6136af565b612a3b565b508354909150600160681b90046001600160581b03168787878181106114da576114da613503565b90506020020160208101906114ef91906136ba565b84546001600160581b0391909116600160681b026affffffffffffffffffffff60681b1990911617845589898781811061152b5761152b613503565b90506020020160208101906115409190612f5b565b6001600160a01b03168b6001600160a01b03167fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc5838b8b8b81811061158757611587613503565b905060200201602081019061159c91906136ba565b8854604080519384526001600160581b039092166020840152600160e01b900463ffffffff1690820181905260608201526080810186905260a00160405180910390a3505050505080806115ef9061353e565b915050611362565b505050505050565b5f855f0361160e57505f6117fb565b5f6116238561161e8b8b89611951565b612b25565b5f5b8881101561178d575f8a8a8381811061164057611640613503565b90506020020160208101906116559190612f5b565b6001600160a01b038181165f9081526001602081815260408084208b861685528252808420948d16845293909101905220549091506116a490600160681b90046001600160801b03168461352b565b92508883116116f4576001600160a01b038082165f9081526001602081815260408084208a861685528252808420948c168452939091019052208054600160681b600160e81b031916905561177a565b5f6116ff8a856136d3565b905061170b81856136d3565b935061171681612ba4565b6001600160a01b039283165f9081526001602081815260408084208b881685528252808420968d1684529590910190529290922080546001600160801b0393909316600160681b02600160681b600160e81b0319909316929092179091555061178d565b50806117858161353e565b915050611625565b50805f0361179e575f9150506117fb565b6117a9848483612c10565b604080516001600160a01b038881168252602082018490528087169286821692918916917fc052130bc4ef84580db505783484b067ea8b71b3bca78a7e12db7aea8658f004910160405180910390a490505b979650505050505050565b6001600160a01b0384165f9081526001602052604081206002015460ff600160801b820416600a0a916001600160801b039091169081900361184957505061194b565b5f5b81816001600160801b03161015611947576001600160a01b038088165f9081526001602081815260408084206001600160801b038716855292830182528084205490941680845291905291812090806118a5838989612a3b565b915091505f806118b8858d8d878d612ce9565b9150915082806118c55750805b15611935578b6001600160a01b0316866001600160a01b03168e6001600160a01b03167f3303facd24627943a92e9dc87cfbb34b15c49b726eec3ad3487c16be9ab8efe887888760405161192c939291909283526020830191909152604082015260600190565b60405180910390a45b50506001909401935061184b92505050565b5050505b50505050565b6060826001600160401b0381111561196b5761196b613218565b6040519080825280602002602001820160405280156119c657816020015b6119b360405180606001604052805f6001600160a01b031681526020015f81526020015f81525090565b8152602001906001900390816119895790505b5090505f5b83811015610b58578484828181106119e5576119e5613503565b90506020020160208101906119fa9190612f5b565b828281518110611a0c57611a0c613503565b60209081029190910101516001600160a01b039091169052848482818110611a3657611a36613503565b9050602002016020810190611a4b9190612f5b565b604051630afbcdc960e01b81526001600160a01b0385811660048301529190911690630afbcdc9906024016040805180830381865afa158015611a90573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ab491906136e6565b838381518110611ac657611ac6613503565b6020026020010151602001848481518110611ae357611ae3613503565b6020908102919091010151604001919091525280611b008161353e565b9150506119cb565b80516001600160a01b039081165f90815260016020818152604080842087861685528252808420865190951684529190528120600201549091908290611b5990600160801b900460ff16600a6136a1565b90505f611b6b83866040015184611e02565b6020808801516001600160a01b038b165f908152600188019092526040909120549193506117fb92509083906001600160681b031685612ddb565b5f816001600160a01b03166350d25bcd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611be3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c0791906135aa565b13611c545760405162461bcd60e51b815260206004820152601860248201527f4f5241434c455f4d5553545f52455455524e5f50524943450000000000000000604482015260640161060f565b6001600160a01b038281165f818152603b602052604080822080546001600160a01b0319169486169485179055517f1a1cd5483e52e60b9ff7f3b9d1db3bbd9e9d21c6324ad3a8c79dba9b75e62f4d9190a35050565b5f805b8251811015610b5857828181518110611cc857611cc8613503565b6020026020010151602001515f03611d535760015f848381518110611cef57611cef613503565b602090810291909101810151516001600160a01b0390811683528282019390935260409182015f90812088851682528252828120938916815260019093019052902054611d4c90600160681b90046001600160801b03168361352b565b9150611df0565b60015f848381518110611d6857611d68613503565b602090810291909101810151516001600160a01b0390811683528282019390935260409182015f908120888516825282528281209389168152600190930190529020548351600160681b9091046001600160801b031690611dd9908790879087908690811061098757610987613503565b611de3919061352b565b611ded908361352b565b91505b80611dfa8161353e565b915050611cad565b82545f9081906001600160681b0381169063ffffffff600160e01b82048116916001600160581b03600160681b82041691600160c01b90910416811580611e47575087155b80611e5157504281145b80611e5c5750828110155b15611e7057838495509550505050506109e6565b5f834211611e7e5742611e80565b835b90505f611e8d83836136d3565b90505f89611e9b8387613708565b611ea59190613708565b8b9004905086611eb5818361352b565b9850985050505050505050935093915050565b6001600160a01b038116611f1e5760405162461bcd60e51b815260206004820152601860248201527f53545241544547595f43414e5f4e4f545f42455f5a45524f0000000000000000604482015260640161060f565b6001813b151514611f715760405162461bcd60e51b815260206004820152601960248201527f53545241544547595f4d5553545f42455f434f4e545241435400000000000000604482015260640161060f565b6001600160a01b038281165f818152603a602052604080822080546001600160a01b0319169486169485179055517f8ca1d928f1d72493a6b78c4f74aabde976bc37ffe2570f2a1ce5a8abd3dde0aa9190a35050565b5f5b8151811015610a405760015f838381518110611fe757611fe7613503565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f2060020160109054906101000a900460ff1660ff165f0361207f57600482828151811061204057612040613503565b6020908102919091018101516060015182546001810184555f938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b5f82828151811061209257612092613503565b6020026020010151606001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120d9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120fd919061371f565b60015f85858151811061211257612112613503565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f2060020160106101000a81548160ff021916908360ff160217905560ff1690505f60015f85858151811061217257612172613503565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f205f015f8585815181106121b2576121b2613503565b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020015f209050805f0160189054906101000a900463ffffffff1663ffffffff165f036123745783838151811061221157612211613503565b60200260200101516080015160015f86868151811061223257612232613503565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f206001015f60015f88888151811061227657612276613503565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f206002015f9054906101000a90046001600160801b03166001600160801b03166001600160801b031681526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060015f85858151811061230e5761230e613503565b602090810291909101810151606001516001600160a01b031682528101919091526040015f90812060020180546001600160801b03169161234e83613585565b91906101000a8154816001600160801b0302191690836001600160801b03160217905550505b60025f85858151811061238957612389613503565b602090810291909101810151608001516001600160a01b031682528101919091526040015f9081205460ff161515900361246857600160025f8686815181106123d4576123d4613503565b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff021916908315150217905550600384848151811061242957612429613503565b6020908102919091018101516080015182546001810184555f938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b5f6124988286868151811061247f5761247f613503565b60200260200101516020015185600a6114ad91906136af565b5082548651919250600160681b81046001600160581b031691600160e01b90910463ffffffff16908790879081106124d2576124d2613503565b60209081029190910101515184546001600160581b03909116600160681b026affffffffffffffffffffff60681b19909116178455865187908790811061251b5761251b613503565b602090810291909101015160400151845463ffffffff909116600160e01b026001600160e01b03909116178455865187908790811061255c5761255c613503565b6020026020010151608001516001600160a01b031687878151811061258357612583613503565b6020026020010151606001516001600160a01b03167fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc5848a8a815181106125cc576125cc613503565b60200260200101515f0151858c8c815181106125ea576125ea613503565b6020026020010151604001518960405161263a9594939291906001600160581b03958616815293909416602084015263ffffffff9182166040840152166060820152608081019190915260a00190565b60405180910390a3505050505080806126529061353e565b915050611fc9565b6003546060908190806001600160401b0381111561267a5761267a613218565b6040519080825280602002602001820160405280156126a3578160200160208202803683370190505b509250806001600160401b038111156126be576126be613218565b6040519080825280602002602001820160405280156126e7578160200160208202803683370190505b5091506126f98561161e8a8a89611951565b5f5b87811015612938575f89898381811061271657612716613503565b905060200201602081019061272b9190612f5b565b90505f5b83811015612923575f6001600160a01b031686828151811061275357612753613503565b60200260200101516001600160a01b0316036127ca576003818154811061277c5761277c613503565b905f5260205f20015f9054906101000a90046001600160a01b03168682815181106127a9576127a9613503565b60200260200101906001600160a01b031690816001600160a01b0316815250505b6001600160a01b0382165f908152600160205260408120875182908990859081106127f7576127f7613503565b6020908102919091018101516001600160a01b0390811683528282019390935260409182015f908120938d16815260019093019052902054600160681b90046001600160801b031690508015612910578086838151811061285a5761285a613503565b6020026020010181815161286e919061352b565b9052506001600160a01b0383165f908152600160205260408120885182908a908690811061289e5761289e613503565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206001015f8b6001600160a01b03166001600160a01b031681526020019081526020015f205f01600d6101000a8154816001600160801b0302191690836001600160801b031602179055505b508061291b8161353e565b91505061272f565b505080806129309061353e565b9150506126fb565b505f5b81811015612a2f576129808585838151811061295957612959613503565b602002602001015185848151811061297357612973613503565b6020026020010151612c10565b846001600160a01b031684828151811061299c5761299c613503565b60200260200101516001600160a01b0316876001600160a01b03167fc052130bc4ef84580db505783484b067ea8b71b3bca78a7e12db7aea8658f0048a8786815181106129eb576129eb613503565b6020026020010151604051612a159291906001600160a01b03929092168252602082015260400190565b60405180910390a480612a278161353e565b91505061293b565b50509550959350505050565b5f805f80612a4a878787611e02565b915091505f828214612aee576001600160681b03821115612a9e5760405162461bcd60e51b815260206004820152600e60248201526d494e4445585f4f564552464c4f5760901b604482015260640161060f565b5086546cffffffffffffffffffffffffff19166001600160681b0382161787556001612ac942612dfe565b885463ffffffff91909116600160c01b0263ffffffff60c01b19909116178855612b18565b612af742612dfe565b885463ffffffff91909116600160c01b0263ffffffff60c01b199091161788555b9097909650945050505050565b5f5b815181101561063d57612b92828281518110612b4557612b45613503565b60200260200101515f015184848481518110612b6357612b63613503565b602002602001015160200151858581518110612b8157612b81613503565b602002602001015160400151611806565b80612b9c8161353e565b915050612b27565b5f6001600160801b03821115612c0c5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b606482015260840161060f565b5090565b6001600160a01b038281165f818152603a6020526040808220549051630b5f5cc160e11b81528785166004820152602481019390935260448301859052909216919082906316beb982906064016020604051808303815f875af1158015612c79573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c9d919061373f565b9050600181151514612ce25760405162461bcd60e51b815260206004820152600e60248201526d2a2920a729a322a92fa2a92927a960911b604482015260640161060f565b5050505050565b6001600160a01b0384165f90815260018601602052604081205481906001600160681b031681858214801590612dcc576001600160a01b0389165f90815260018b016020526040902080546cffffffffffffffffffffffffff19166001600160681b0389161790558715612dcc57612d6388888589612ddb565b9150612d6e82612ba4565b6001600160a01b038a165f90815260018c01602052604090208054600d90612da7908490600160681b90046001600160801b031661375e565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b90999098509650505050505050565b5f80612de784866136d3565b612df19087613708565b9290920495945050505050565b5f63ffffffff821115612c0c5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b606482015260840161060f565b6001600160a01b0381168114610dd7575f80fd5b5f8060408385031215612e87575f80fd5b8235612e9281612e62565b91506020830135612ea281612e62565b809150509250929050565b5f8083601f840112612ebd575f80fd5b5081356001600160401b03811115612ed3575f80fd5b6020830191508360208260051b8501011115610c3a575f80fd5b5f805f805f60808688031215612f01575f80fd5b85356001600160401b03811115612f16575f80fd5b612f2288828901612ead565b909650945050602086013592506040860135612f3d81612e62565b91506060860135612f4d81612e62565b809150509295509295909350565b5f60208284031215612f6b575f80fd5b8135612f7681612e62565b9392505050565b5f805f60608486031215612f8f575f80fd5b8335612f9a81612e62565b95602085013595506040909401359392505050565b5f805f805f8060a08789031215612fc4575f80fd5b86356001600160401b03811115612fd9575f80fd5b612fe589828a01612ead565b90975095505060208701359350604087013561300081612e62565b9250606087013561301081612e62565b9150608087013561302081612e62565b809150509295509295509295565b5f805f60408486031215613040575f80fd5b83356001600160401b03811115613055575f80fd5b61306186828701612ead565b909450925050602084013561307581612e62565b809150509250925092565b5f8151808452602080850194508084015f5b838110156130b75781516001600160a01b031687529582019590820190600101613092565b509495945050505050565b604081525f6130d46040830185613080565b8281036020848101919091528451808352858201928201905f5b8181101561310a578451835293830193918301916001016130ee565b5090979650505050505050565b5f805f60608486031215613129575f80fd5b833561313481612e62565b9250602084013561314481612e62565b9150604084013561307581612e62565b5f805f8060608587031215613167575f80fd5b84356001600160401b0381111561317c575f80fd5b61318887828801612ead565b9095509350506020850135915060408501356131a381612e62565b939692955090935050565b602081525f612f766020830184613080565b5f805f80606085870312156131d3575f80fd5b84356001600160401b038111156131e8575f80fd5b6131f487828801612ead565b909550935050602085013561320881612e62565b915060408501356131a381612e62565b634e487b7160e01b5f52604160045260245ffd5b60405160e081016001600160401b038111828210171561324e5761324e613218565b60405290565b604051601f8201601f191681016001600160401b038111828210171561327c5761327c613218565b604052919050565b80356001600160581b038116811461329a575f80fd5b919050565b803563ffffffff8116811461329a575f80fd5b5f60208083850312156132c3575f80fd5b82356001600160401b03808211156132d9575f80fd5b818501915085601f8301126132ec575f80fd5b8135818111156132fe576132fe613218565b61330c848260051b01613254565b818152848101925060e091820284018501918883111561332a575f80fd5b938501935b828510156133cd5780858a031215613346575f8081fd5b61334e61322c565b61335786613284565b81528686013587820152604061336e81880161329f565b9082015260608681013561338181612e62565b9082015260808681013561339481612e62565b9082015260a0868101356133a781612e62565b9082015260c0868101356133ba81612e62565b908201528452938401939285019261332f565b50979650505050505050565b5f80602083850312156133ea575f80fd5b82356001600160401b038111156133ff575f80fd5b61340b85828601612ead565b90969095509350505050565b5f805f60608486031215613429575f80fd5b833561343481612e62565b9250602084013561344481612e62565b91506134526040850161329f565b90509250925092565b5f805f805f6060868803121561346f575f80fd5b853561347a81612e62565b945060208601356001600160401b0380821115613495575f80fd5b6134a189838a01612ead565b909650945060408801359150808211156134b9575f80fd5b506134c688828901612ead565b969995985093965092949392505050565b602080825260129082015271494e56414c49445f544f5f4144445245535360701b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b808201808211156105e2576105e2613517565b5f6001820161354f5761354f613517565b5060010190565b60208082526015908201527427a7262cafa2a6a4a9a9a4a7a72fa6a0a720a3a2a960591b604082015260600190565b5f6001600160801b038083168181036135a0576135a0613517565b6001019392505050565b5f602082840312156135ba575f80fd5b5051919050565b600181815b808511156135fb57815f19048211156135e1576135e1613517565b808516156135ee57918102915b93841c93908002906135c6565b509250929050565b5f82613611575060016105e2565b8161361d57505f6105e2565b8160018114613633576002811461363d57613659565b60019150506105e2565b60ff84111561364e5761364e613517565b50506001821b6105e2565b5060208310610133831016604e8410600b841016171561367c575081810a6105e2565b61368683836135c1565b805f190482111561369957613699613517565b029392505050565b5f612f7660ff841683613603565b5f612f768383613603565b5f602082840312156136ca575f80fd5b612f7682613284565b818103818111156105e2576105e2613517565b5f80604083850312156136f7575f80fd5b505080516020909101519092909150565b80820281158282048414176105e2576105e2613517565b5f6020828403121561372f575f80fd5b815160ff81168114612f76575f80fd5b5f6020828403121561374f575f80fd5b81518015158114612f76575f80fd5b6001600160801b0381811683821601908082111561377e5761377e613517565b509291505056fea164736f6c6343000814000a000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b3
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106101d1575f3560e01c806392074b08116100fe578063bf90f63a1161009e578063dde43cba1161006e578063dde43cba1461056e578063e15ac62314610576578063f5cf673b14610589578063f996868b1461059c575f80fd5b8063bf90f63a1461050e578063c4d66de814610521578063c5a7b53814610534578063cbcbb50714610547575f80fd5b80639ff55db9116100d95780639ff55db9146104cd578063b022418c146104e0578063b45ac1a9146104f3578063bb492bf5146104fb575f80fd5b806392074b081461044d578063955c2ad7146104735780639efd6f7214610486575f80fd5b80635453ba101161017457806370674ab91161014457806370674ab91461035b57806374d945ec1461036e5780637eff4ba814610399578063886fe70b14610425575f80fd5b80635453ba10146102ea57806357b89883146102fd5780635f130b24146103105780636657732f1461033b575f80fd5b806331873e2e116101af57806331873e2e1461025157806333028b99146102665780634c0369c314610279578063533f542a1461029a575f80fd5b80631b839c77146101d5578063236300dc146101fb5780632a17bf601461020e575b5f80fd5b6101e86101e3366004612e76565b6105af565b6040519081526020015b60405180910390f35b6101e8610209366004612eed565b6105e8565b61023961021c366004612f5b565b6001600160a01b039081165f908152603b60205260409020541690565b6040516001600160a01b0390911681526020016101f2565b61026461025f366004612f7d565b610631565b005b6101e8610274366004612faf565b610642565b61028c61028736600461302e565b610736565b6040516101f29291906130c2565b6101e86102a8366004613117565b6001600160a01b038083165f90815260016020818152604080842086861685528252808420948816845293909101905220546001600160681b03169392505050565b6102646102f8366004612e76565b6109ee565b6101e861030b366004613154565b610a44565b61023961031e366004612f5b565b6001600160a01b039081165f908152603a60205260409020541690565b61034e610349366004612f5b565b610a5d565b6040516101f291906131ae565b6101e86103693660046131c0565b610b60565b61023961037c366004612f5b565b6001600160a01b039081165f908152603960205260409020541690565b6104056103a7366004612e76565b6001600160a01b039182165f9081526001602090815260408083209390941682529190915220546001600160681b038116916001600160581b03600160681b8304169163ffffffff600160c01b8204811692600160e01b9092041690565b6040805194855260208501939093529183015260608201526080016101f2565b610438610433366004612e76565b610b76565b604080519283526020830191909152016101f2565b7f000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b3610239565b6102646104813660046132b2565b610c41565b6104bb610494366004612f5b565b6001600160a01b03165f90815260016020526040902060020154600160801b900460ff1690565b60405160ff90911681526020016101f2565b61028c6104db3660046131c0565b610dda565b6101e86104ee366004612e76565b610ed1565b61034e610f66565b61028c61050936600461302e565b610fc6565b61028c61051c3660046133d9565b611008565b61026461052f366004612f5b565b611023565b610264610542366004613417565b6110da565b6102397f000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b381565b6101e8600181565b610264610584366004612e76565b6111e9565b610264610597366004612e76565b61123b565b6102646105aa36600461345b565b6112d9565b6001600160a01b038281165f90815260016020908152604080832093851683529290522054600160e01b900463ffffffff165b92915050565b5f6001600160a01b0383166106185760405162461bcd60e51b815260040161060f906134d7565b60405180910390fd5b610627868686333388886115ff565b9695505050505050565b61063d33848385611806565b505050565b6001600160a01b038084165f908152603960205260408120549091339186911682146106a75760405162461bcd60e51b815260206004820152601460248201527310d3105253515497d5539055551213d49256915160621b604482015260640161060f565b6001600160a01b0386166106f45760405162461bcd60e51b8152602060048201526014602482015273494e56414c49445f555345525f4144445245535360601b604482015260640161060f565b6001600160a01b03851661071a5760405162461bcd60e51b815260040161060f906134d7565b610729898989338a8a8a6115ff565b9998505050505050505050565b6060805f610745868686611951565b6003549091506001600160401b0381111561076257610762613218565b60405190808252806020026020018201604052801561078b578160200160208202803683370190505b50925082516001600160401b038111156107a7576107a7613218565b6040519080825280602002602001820160405280156107d0578160200160208202803683370190505b5091505f5b81518110156109e3575f5b84518110156109d057600381815481106107fc576107fc613503565b905f5260205f20015f9054906101000a90046001600160a01b031685828151811061082957610829613503565b60200260200101906001600160a01b031690816001600160a01b03168152505060015f84848151811061085e5761085e613503565b60200260200101515f01516001600160a01b03166001600160a01b031681526020019081526020015f205f015f86838151811061089d5761089d613503565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206001015f876001600160a01b03166001600160a01b031681526020019081526020015f205f01600d9054906101000a90046001600160801b03166001600160801b031684828151811061091957610919613503565b6020026020010181815161092d919061352b565b905250825183908390811061094457610944613503565b6020026020010151602001515f03156109be576109948686838151811061096d5761096d613503565b602002602001015185858151811061098757610987613503565b6020026020010151611b08565b8482815181106109a6576109a6613503565b602002602001018181516109ba919061352b565b9052505b806109c88161353e565b9150506107e0565b50806109db8161353e565b9150506107d5565b50505b935093915050565b336001600160a01b037f000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b31614610a365760405162461bcd60e51b815260040161060f90613556565b610a408282611ba6565b5050565b5f610a54858585333333886115ff565b95945050505050565b6001600160a01b0381165f908152600160205260408120600201546060916001600160801b0390911690816001600160401b03811115610a9f57610a9f613218565b604051908082528060200260200182016040528015610ac8578160200160208202803683370190505b5090505f5b826001600160801b0316816001600160801b03161015610b58576001600160a01b038086165f9081526001602081815260408084206001600160801b03871680865293019091529091205484519216918491908110610b2e57610b2e613503565b6001600160a01b039092166020928302919091019091015280610b5081613585565b915050610acd565b509392505050565b5f610a548383610b71888888611951565b611caa565b6001600160a01b038083165f8181526001602090815260408083209486168352938152838220845163b1bf962d60e01b81529451929485949193610c349385939263b1bf962d92600480830193928290030181865afa158015610bdb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bff91906135aa565b6001600160a01b0388165f90815260016020526040902060020154610c2f90600160801b900460ff16600a6136a1565b611e02565b92509250505b9250929050565b336001600160a01b037f000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b31614610c895760405162461bcd60e51b815260040161060f90613556565b5f5b8151811015610dcd57818181518110610ca657610ca6613503565b6020026020010151606001516001600160a01b031663b1bf962d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ced573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1191906135aa565b828281518110610d2357610d23613503565b60200260200101516020018181525050610d77828281518110610d4857610d48613503565b602002602001015160800151838381518110610d6657610d66613503565b602002602001015160a00151611ec8565b610dbb828281518110610d8c57610d8c613503565b602002602001015160800151838381518110610daa57610daa613503565b602002602001015160c00151611ba6565b80610dc58161353e565b915050610c8b565b50610dd781611fc7565b50565b6001600160a01b038083165f90815260396020526040902054606091829133918691168214610e425760405162461bcd60e51b815260206004820152601460248201527310d3105253515497d5539055551213d49256915160621b604482015260640161060f565b6001600160a01b038616610e8f5760405162461bcd60e51b8152602060048201526014602482015273494e56414c49445f555345525f4144445245535360601b604482015260640161060f565b6001600160a01b038516610eb55760405162461bcd60e51b815260040161060f906134d7565b610ec2888833898961265a565b93509350505094509492505050565b5f805f5b600454811015610b585760015f60048381548110610ef557610ef5613503565b5f918252602080832091909101546001600160a01b03908116845283820194909452604092830182208885168352815282822093891682526001909301909252902054610f5290600160681b90046001600160801b03168361352b565b915080610f5e8161353e565b915050610ed5565b60606003805480602002602001604051908101604052809291908181526020018280548015610fbc57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610f9e575b5050505050905090565b6060806001600160a01b038316610fef5760405162461bcd60e51b815260040161060f906134d7565b610ffc858533338761265a565b91509150935093915050565b606080611018848433333361265a565b915091509250929050565b60065460019060ff16806110365750303b155b80611042575060055481115b6110a55760405162461bcd60e51b815260206004820152602e60248201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560448201526d195b881a5b9a5d1a585b1a5e995960921b606482015260840161060f565b60065460ff161580156110c5576006805460ff1916600117905560058290555b801561063d576006805460ff19169055505050565b336001600160a01b037f000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b316146111225760405162461bcd60e51b815260040161060f90613556565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902080546001600160e01b038116600160e01b63ffffffff898116828102938417958690558751600160681b9096046001600160581b0316808752968601969096529083041694830185905260608301939093526001600160681b039081169216919091176080820152909291907fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc59060a00160405180910390a350505050565b336001600160a01b037f000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b316146112315760405162461bcd60e51b815260040161060f90613556565b610a408282611ec8565b336001600160a01b037f000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b316146112835760405162461bcd60e51b815260040161060f90613556565b6001600160a01b038281165f8181526039602052604080822080546001600160a01b0319169486169485179055517f4925eafc82d0c4d67889898eeed64b18488ab19811e61620f387026dec126a289190a35050565b336001600160a01b037f000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b316146113215760405162461bcd60e51b815260040161060f90613556565b8281146113605760405162461bcd60e51b815260206004820152600d60248201526c1253959053125117d253941555609a1b604482015260640161060f565b5f5b838110156115f7576001600160a01b0386165f90815260016020526040812090818188888681811061139657611396613503565b90506020020160208101906113ab9190612f5b565b6001600160a01b0316815260208101919091526040015f206002830154909150600160801b900460ff1680158015906113f157508154600160c01b900463ffffffff1615155b61143d5760405162461bcd60e51b815260206004820152601b60248201527f444953545249425554494f4e5f444f45535f4e4f545f45584953540000000000604482015260640161060f565b5f6114b2838b6001600160a01b031663b1bf962d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561147e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114a291906135aa565b6114ad85600a6136af565b612a3b565b508354909150600160681b90046001600160581b03168787878181106114da576114da613503565b90506020020160208101906114ef91906136ba565b84546001600160581b0391909116600160681b026affffffffffffffffffffff60681b1990911617845589898781811061152b5761152b613503565b90506020020160208101906115409190612f5b565b6001600160a01b03168b6001600160a01b03167fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc5838b8b8b81811061158757611587613503565b905060200201602081019061159c91906136ba565b8854604080519384526001600160581b039092166020840152600160e01b900463ffffffff1690820181905260608201526080810186905260a00160405180910390a3505050505080806115ef9061353e565b915050611362565b505050505050565b5f855f0361160e57505f6117fb565b5f6116238561161e8b8b89611951565b612b25565b5f5b8881101561178d575f8a8a8381811061164057611640613503565b90506020020160208101906116559190612f5b565b6001600160a01b038181165f9081526001602081815260408084208b861685528252808420948d16845293909101905220549091506116a490600160681b90046001600160801b03168461352b565b92508883116116f4576001600160a01b038082165f9081526001602081815260408084208a861685528252808420948c168452939091019052208054600160681b600160e81b031916905561177a565b5f6116ff8a856136d3565b905061170b81856136d3565b935061171681612ba4565b6001600160a01b039283165f9081526001602081815260408084208b881685528252808420968d1684529590910190529290922080546001600160801b0393909316600160681b02600160681b600160e81b0319909316929092179091555061178d565b50806117858161353e565b915050611625565b50805f0361179e575f9150506117fb565b6117a9848483612c10565b604080516001600160a01b038881168252602082018490528087169286821692918916917fc052130bc4ef84580db505783484b067ea8b71b3bca78a7e12db7aea8658f004910160405180910390a490505b979650505050505050565b6001600160a01b0384165f9081526001602052604081206002015460ff600160801b820416600a0a916001600160801b039091169081900361184957505061194b565b5f5b81816001600160801b03161015611947576001600160a01b038088165f9081526001602081815260408084206001600160801b038716855292830182528084205490941680845291905291812090806118a5838989612a3b565b915091505f806118b8858d8d878d612ce9565b9150915082806118c55750805b15611935578b6001600160a01b0316866001600160a01b03168e6001600160a01b03167f3303facd24627943a92e9dc87cfbb34b15c49b726eec3ad3487c16be9ab8efe887888760405161192c939291909283526020830191909152604082015260600190565b60405180910390a45b50506001909401935061184b92505050565b5050505b50505050565b6060826001600160401b0381111561196b5761196b613218565b6040519080825280602002602001820160405280156119c657816020015b6119b360405180606001604052805f6001600160a01b031681526020015f81526020015f81525090565b8152602001906001900390816119895790505b5090505f5b83811015610b58578484828181106119e5576119e5613503565b90506020020160208101906119fa9190612f5b565b828281518110611a0c57611a0c613503565b60209081029190910101516001600160a01b039091169052848482818110611a3657611a36613503565b9050602002016020810190611a4b9190612f5b565b604051630afbcdc960e01b81526001600160a01b0385811660048301529190911690630afbcdc9906024016040805180830381865afa158015611a90573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ab491906136e6565b838381518110611ac657611ac6613503565b6020026020010151602001848481518110611ae357611ae3613503565b6020908102919091010151604001919091525280611b008161353e565b9150506119cb565b80516001600160a01b039081165f90815260016020818152604080842087861685528252808420865190951684529190528120600201549091908290611b5990600160801b900460ff16600a6136a1565b90505f611b6b83866040015184611e02565b6020808801516001600160a01b038b165f908152600188019092526040909120549193506117fb92509083906001600160681b031685612ddb565b5f816001600160a01b03166350d25bcd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611be3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c0791906135aa565b13611c545760405162461bcd60e51b815260206004820152601860248201527f4f5241434c455f4d5553545f52455455524e5f50524943450000000000000000604482015260640161060f565b6001600160a01b038281165f818152603b602052604080822080546001600160a01b0319169486169485179055517f1a1cd5483e52e60b9ff7f3b9d1db3bbd9e9d21c6324ad3a8c79dba9b75e62f4d9190a35050565b5f805b8251811015610b5857828181518110611cc857611cc8613503565b6020026020010151602001515f03611d535760015f848381518110611cef57611cef613503565b602090810291909101810151516001600160a01b0390811683528282019390935260409182015f90812088851682528252828120938916815260019093019052902054611d4c90600160681b90046001600160801b03168361352b565b9150611df0565b60015f848381518110611d6857611d68613503565b602090810291909101810151516001600160a01b0390811683528282019390935260409182015f908120888516825282528281209389168152600190930190529020548351600160681b9091046001600160801b031690611dd9908790879087908690811061098757610987613503565b611de3919061352b565b611ded908361352b565b91505b80611dfa8161353e565b915050611cad565b82545f9081906001600160681b0381169063ffffffff600160e01b82048116916001600160581b03600160681b82041691600160c01b90910416811580611e47575087155b80611e5157504281145b80611e5c5750828110155b15611e7057838495509550505050506109e6565b5f834211611e7e5742611e80565b835b90505f611e8d83836136d3565b90505f89611e9b8387613708565b611ea59190613708565b8b9004905086611eb5818361352b565b9850985050505050505050935093915050565b6001600160a01b038116611f1e5760405162461bcd60e51b815260206004820152601860248201527f53545241544547595f43414e5f4e4f545f42455f5a45524f0000000000000000604482015260640161060f565b6001813b151514611f715760405162461bcd60e51b815260206004820152601960248201527f53545241544547595f4d5553545f42455f434f4e545241435400000000000000604482015260640161060f565b6001600160a01b038281165f818152603a602052604080822080546001600160a01b0319169486169485179055517f8ca1d928f1d72493a6b78c4f74aabde976bc37ffe2570f2a1ce5a8abd3dde0aa9190a35050565b5f5b8151811015610a405760015f838381518110611fe757611fe7613503565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f2060020160109054906101000a900460ff1660ff165f0361207f57600482828151811061204057612040613503565b6020908102919091018101516060015182546001810184555f938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b5f82828151811061209257612092613503565b6020026020010151606001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120d9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120fd919061371f565b60015f85858151811061211257612112613503565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f2060020160106101000a81548160ff021916908360ff160217905560ff1690505f60015f85858151811061217257612172613503565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f205f015f8585815181106121b2576121b2613503565b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020015f209050805f0160189054906101000a900463ffffffff1663ffffffff165f036123745783838151811061221157612211613503565b60200260200101516080015160015f86868151811061223257612232613503565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f206001015f60015f88888151811061227657612276613503565b6020026020010151606001516001600160a01b03166001600160a01b031681526020019081526020015f206002015f9054906101000a90046001600160801b03166001600160801b03166001600160801b031681526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060015f85858151811061230e5761230e613503565b602090810291909101810151606001516001600160a01b031682528101919091526040015f90812060020180546001600160801b03169161234e83613585565b91906101000a8154816001600160801b0302191690836001600160801b03160217905550505b60025f85858151811061238957612389613503565b602090810291909101810151608001516001600160a01b031682528101919091526040015f9081205460ff161515900361246857600160025f8686815181106123d4576123d4613503565b6020026020010151608001516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff021916908315150217905550600384848151811061242957612429613503565b6020908102919091018101516080015182546001810184555f938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b5f6124988286868151811061247f5761247f613503565b60200260200101516020015185600a6114ad91906136af565b5082548651919250600160681b81046001600160581b031691600160e01b90910463ffffffff16908790879081106124d2576124d2613503565b60209081029190910101515184546001600160581b03909116600160681b026affffffffffffffffffffff60681b19909116178455865187908790811061251b5761251b613503565b602090810291909101015160400151845463ffffffff909116600160e01b026001600160e01b03909116178455865187908790811061255c5761255c613503565b6020026020010151608001516001600160a01b031687878151811061258357612583613503565b6020026020010151606001516001600160a01b03167fac1777479f07f3e7c34da8402139d54027a6a260caaae168bdee825ca5580dc5848a8a815181106125cc576125cc613503565b60200260200101515f0151858c8c815181106125ea576125ea613503565b6020026020010151604001518960405161263a9594939291906001600160581b03958616815293909416602084015263ffffffff9182166040840152166060820152608081019190915260a00190565b60405180910390a3505050505080806126529061353e565b915050611fc9565b6003546060908190806001600160401b0381111561267a5761267a613218565b6040519080825280602002602001820160405280156126a3578160200160208202803683370190505b509250806001600160401b038111156126be576126be613218565b6040519080825280602002602001820160405280156126e7578160200160208202803683370190505b5091506126f98561161e8a8a89611951565b5f5b87811015612938575f89898381811061271657612716613503565b905060200201602081019061272b9190612f5b565b90505f5b83811015612923575f6001600160a01b031686828151811061275357612753613503565b60200260200101516001600160a01b0316036127ca576003818154811061277c5761277c613503565b905f5260205f20015f9054906101000a90046001600160a01b03168682815181106127a9576127a9613503565b60200260200101906001600160a01b031690816001600160a01b0316815250505b6001600160a01b0382165f908152600160205260408120875182908990859081106127f7576127f7613503565b6020908102919091018101516001600160a01b0390811683528282019390935260409182015f908120938d16815260019093019052902054600160681b90046001600160801b031690508015612910578086838151811061285a5761285a613503565b6020026020010181815161286e919061352b565b9052506001600160a01b0383165f908152600160205260408120885182908a908690811061289e5761289e613503565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206001015f8b6001600160a01b03166001600160a01b031681526020019081526020015f205f01600d6101000a8154816001600160801b0302191690836001600160801b031602179055505b508061291b8161353e565b91505061272f565b505080806129309061353e565b9150506126fb565b505f5b81811015612a2f576129808585838151811061295957612959613503565b602002602001015185848151811061297357612973613503565b6020026020010151612c10565b846001600160a01b031684828151811061299c5761299c613503565b60200260200101516001600160a01b0316876001600160a01b03167fc052130bc4ef84580db505783484b067ea8b71b3bca78a7e12db7aea8658f0048a8786815181106129eb576129eb613503565b6020026020010151604051612a159291906001600160a01b03929092168252602082015260400190565b60405180910390a480612a278161353e565b91505061293b565b50509550959350505050565b5f805f80612a4a878787611e02565b915091505f828214612aee576001600160681b03821115612a9e5760405162461bcd60e51b815260206004820152600e60248201526d494e4445585f4f564552464c4f5760901b604482015260640161060f565b5086546cffffffffffffffffffffffffff19166001600160681b0382161787556001612ac942612dfe565b885463ffffffff91909116600160c01b0263ffffffff60c01b19909116178855612b18565b612af742612dfe565b885463ffffffff91909116600160c01b0263ffffffff60c01b199091161788555b9097909650945050505050565b5f5b815181101561063d57612b92828281518110612b4557612b45613503565b60200260200101515f015184848481518110612b6357612b63613503565b602002602001015160200151858581518110612b8157612b81613503565b602002602001015160400151611806565b80612b9c8161353e565b915050612b27565b5f6001600160801b03821115612c0c5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b606482015260840161060f565b5090565b6001600160a01b038281165f818152603a6020526040808220549051630b5f5cc160e11b81528785166004820152602481019390935260448301859052909216919082906316beb982906064016020604051808303815f875af1158015612c79573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c9d919061373f565b9050600181151514612ce25760405162461bcd60e51b815260206004820152600e60248201526d2a2920a729a322a92fa2a92927a960911b604482015260640161060f565b5050505050565b6001600160a01b0384165f90815260018601602052604081205481906001600160681b031681858214801590612dcc576001600160a01b0389165f90815260018b016020526040902080546cffffffffffffffffffffffffff19166001600160681b0389161790558715612dcc57612d6388888589612ddb565b9150612d6e82612ba4565b6001600160a01b038a165f90815260018c01602052604090208054600d90612da7908490600160681b90046001600160801b031661375e565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b90999098509650505050505050565b5f80612de784866136d3565b612df19087613708565b9290920495945050505050565b5f63ffffffff821115612c0c5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b606482015260840161060f565b6001600160a01b0381168114610dd7575f80fd5b5f8060408385031215612e87575f80fd5b8235612e9281612e62565b91506020830135612ea281612e62565b809150509250929050565b5f8083601f840112612ebd575f80fd5b5081356001600160401b03811115612ed3575f80fd5b6020830191508360208260051b8501011115610c3a575f80fd5b5f805f805f60808688031215612f01575f80fd5b85356001600160401b03811115612f16575f80fd5b612f2288828901612ead565b909650945050602086013592506040860135612f3d81612e62565b91506060860135612f4d81612e62565b809150509295509295909350565b5f60208284031215612f6b575f80fd5b8135612f7681612e62565b9392505050565b5f805f60608486031215612f8f575f80fd5b8335612f9a81612e62565b95602085013595506040909401359392505050565b5f805f805f8060a08789031215612fc4575f80fd5b86356001600160401b03811115612fd9575f80fd5b612fe589828a01612ead565b90975095505060208701359350604087013561300081612e62565b9250606087013561301081612e62565b9150608087013561302081612e62565b809150509295509295509295565b5f805f60408486031215613040575f80fd5b83356001600160401b03811115613055575f80fd5b61306186828701612ead565b909450925050602084013561307581612e62565b809150509250925092565b5f8151808452602080850194508084015f5b838110156130b75781516001600160a01b031687529582019590820190600101613092565b509495945050505050565b604081525f6130d46040830185613080565b8281036020848101919091528451808352858201928201905f5b8181101561310a578451835293830193918301916001016130ee565b5090979650505050505050565b5f805f60608486031215613129575f80fd5b833561313481612e62565b9250602084013561314481612e62565b9150604084013561307581612e62565b5f805f8060608587031215613167575f80fd5b84356001600160401b0381111561317c575f80fd5b61318887828801612ead565b9095509350506020850135915060408501356131a381612e62565b939692955090935050565b602081525f612f766020830184613080565b5f805f80606085870312156131d3575f80fd5b84356001600160401b038111156131e8575f80fd5b6131f487828801612ead565b909550935050602085013561320881612e62565b915060408501356131a381612e62565b634e487b7160e01b5f52604160045260245ffd5b60405160e081016001600160401b038111828210171561324e5761324e613218565b60405290565b604051601f8201601f191681016001600160401b038111828210171561327c5761327c613218565b604052919050565b80356001600160581b038116811461329a575f80fd5b919050565b803563ffffffff8116811461329a575f80fd5b5f60208083850312156132c3575f80fd5b82356001600160401b03808211156132d9575f80fd5b818501915085601f8301126132ec575f80fd5b8135818111156132fe576132fe613218565b61330c848260051b01613254565b818152848101925060e091820284018501918883111561332a575f80fd5b938501935b828510156133cd5780858a031215613346575f8081fd5b61334e61322c565b61335786613284565b81528686013587820152604061336e81880161329f565b9082015260608681013561338181612e62565b9082015260808681013561339481612e62565b9082015260a0868101356133a781612e62565b9082015260c0868101356133ba81612e62565b908201528452938401939285019261332f565b50979650505050505050565b5f80602083850312156133ea575f80fd5b82356001600160401b038111156133ff575f80fd5b61340b85828601612ead565b90969095509350505050565b5f805f60608486031215613429575f80fd5b833561343481612e62565b9250602084013561344481612e62565b91506134526040850161329f565b90509250925092565b5f805f805f6060868803121561346f575f80fd5b853561347a81612e62565b945060208601356001600160401b0380821115613495575f80fd5b6134a189838a01612ead565b909650945060408801359150808211156134b9575f80fd5b506134c688828901612ead565b969995985093965092949392505050565b602080825260129082015271494e56414c49445f544f5f4144445245535360701b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b808201808211156105e2576105e2613517565b5f6001820161354f5761354f613517565b5060010190565b60208082526015908201527427a7262cafa2a6a4a9a9a4a7a72fa6a0a720a3a2a960591b604082015260600190565b5f6001600160801b038083168181036135a0576135a0613517565b6001019392505050565b5f602082840312156135ba575f80fd5b5051919050565b600181815b808511156135fb57815f19048211156135e1576135e1613517565b808516156135ee57918102915b93841c93908002906135c6565b509250929050565b5f82613611575060016105e2565b8161361d57505f6105e2565b8160018114613633576002811461363d57613659565b60019150506105e2565b60ff84111561364e5761364e613517565b50506001821b6105e2565b5060208310610133831016604e8410600b841016171561367c575081810a6105e2565b61368683836135c1565b805f190482111561369957613699613517565b029392505050565b5f612f7660ff841683613603565b5f612f768383613603565b5f602082840312156136ca575f80fd5b612f7682613284565b818103818111156105e2576105e2613517565b5f80604083850312156136f7575f80fd5b505080516020909101519092909150565b80820281158282048414176105e2576105e2613517565b5f6020828403121561372f575f80fd5b815160ff81168114612f76575f80fd5b5f6020828403121561374f575f80fd5b81518015158114612f76575f80fd5b6001600160801b0381811683821601908082111561377e5761377e613517565b509291505056fea164736f6c6343000814000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b3
-----Decoded View---------------
Arg [0] : emissionManager (address): 0xF8f60F84a43D05316ccff66407fC466b50c3c2B3
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000f8f60f84a43d05316ccff66407fc466b50c3c2b3
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in HYPE
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.