Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Initialize | 14449820 | 1058 days ago | IN | 0 ETH | 0.00427437 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
RewardDistributorV3
Compiler Version
v0.6.12+commit.27d51765
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts-upgradeable/token/ERC20/SafeERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "./interface/IiToken.sol"; import "./interface/IRewardDistributorV3.sol"; import "./interface/IPriceOracle.sol"; import "./library/Initializable.sol"; import "./library/Ownable.sol"; import "./library/SafeRatioMath.sol"; import "./Controller.sol"; /** * @title dForce's lending reward distributor Contract * @author dForce */ contract RewardDistributorV3 is Initializable, Ownable, IRewardDistributorV3 { using SafeRatioMath for uint256; using SafeMathUpgradeable for uint256; using SafeERC20Upgradeable for IERC20Upgradeable; /// @notice the controller Controller public controller; /// @notice the global Reward distribution speed uint256 public globalDistributionSpeed; /// @notice the Reward distribution speed of each iToken mapping(address => uint256) public distributionSpeed; /// @notice the Reward distribution factor of each iToken, 1.0 by default. stored as a mantissa mapping(address => uint256) public distributionFactorMantissa; struct DistributionState { // Token's last updated index, stored as a mantissa uint256 index; // The block number the index was last updated at uint256 block; } /// @notice the Reward distribution supply state of each iToken mapping(address => DistributionState) public distributionSupplyState; /// @notice the Reward distribution borrow state of each iToken mapping(address => DistributionState) public distributionBorrowState; /// @notice the Reward distribution state of each account of each iToken mapping(address => mapping(address => uint256)) public distributionSupplierIndex; /// @notice the Reward distribution state of each account of each iToken mapping(address => mapping(address => uint256)) public distributionBorrowerIndex; /// @notice the Reward distributed into each account mapping(address => uint256) public reward; /// @notice the Reward token address address public override rewardToken; /// @notice whether the reward distribution is paused bool public paused; /// @notice the Reward distribution speed supply side of each iToken mapping(address => uint256) public distributionSupplySpeed; /// @notice the global Reward distribution speed for supply uint256 public globalDistributionSupplySpeed; /// @notice the treasury address where the reward is stored address public override treasury; /** * @dev Throws if called by any account other than the controller. */ modifier onlyController() { require( address(controller) == msg.sender, "onlyController: caller is not the controller" ); _; } /** * @notice Initializes the contract. */ function initialize(Controller _controller) external initializer { require( address(_controller) != address(0), "initialize: controller address should not be zero address!" ); __Ownable_init(); controller = _controller; paused = true; } /** * @notice set reward token address * @dev Admin function, only owner can call this * @param _newRewardToken the address of reward token */ function _setRewardToken(address _newRewardToken) external override onlyOwner { address _oldRewardToken = rewardToken; require( _newRewardToken != address(0) && _newRewardToken != _oldRewardToken, "Reward token address invalid" ); rewardToken = _newRewardToken; emit NewRewardToken(_oldRewardToken, _newRewardToken); } /** * @notice set new treasury address * @dev Admin function, only owner can call this * @param _newTreasury the address of treasury */ function _setTreasury(address _newTreasury) external override onlyOwner { address _oldTreasury = treasury; require( _newTreasury != address(0) && _newTreasury != _oldTreasury, "Treasury address invalid" ); treasury = _newTreasury; emit NewTreasury(_oldTreasury, _newTreasury); } /** * @notice Add the iToken as receipient * @dev Admin function, only controller can call this * @param _iToken the iToken to add as recipient * @param _distributionFactor the distribution factor of the recipient */ function _addRecipient(address _iToken, uint256 _distributionFactor) external override onlyController { distributionFactorMantissa[_iToken] = _distributionFactor; distributionSupplyState[_iToken] = DistributionState({ index: 0, block: block.number }); distributionBorrowState[_iToken] = DistributionState({ index: 0, block: block.number }); emit NewRecipient(_iToken, _distributionFactor); } /** * @notice Pause the reward distribution * @dev Admin function, pause will set global speed to 0 to stop the accumulation */ function _pause() external override onlyOwner { // Set the global distribution speed to 0 to stop accumulation address[] memory _iTokens = controller.getAlliTokens(); uint256 _len = _iTokens.length; for (uint256 i = 0; i < _len; i++) { _setDistributionBorrowSpeed(_iTokens[i], 0); _setDistributionSupplySpeed(_iTokens[i], 0); } _refreshGlobalDistributionSpeeds(); _setPaused(true); } /** * @notice Unpause and set distribution speeds * @dev Admin function * @param _borrowiTokens The borrow asset array * @param _borrowSpeeds The borrow speed array * @param _supplyiTokens The supply asset array * @param _supplySpeeds The supply speed array */ function _unpause( address[] calldata _borrowiTokens, uint256[] calldata _borrowSpeeds, address[] calldata _supplyiTokens, uint256[] calldata _supplySpeeds ) external override onlyOwner { _setPaused(false); _setDistributionSpeedsInternal( _borrowiTokens, _borrowSpeeds, _supplyiTokens, _supplySpeeds ); _refreshGlobalDistributionSpeeds(); } /** * @notice Pause/Unpause the reward distribution * @dev Admin function * @param _paused whether to pause/unpause the distribution */ function _setPaused(bool _paused) internal { paused = _paused; emit Paused(_paused); } /** * @notice Set distribution speeds * @dev Admin function, will fail when paused * @param _borrowiTokens The borrow asset array * @param _borrowSpeeds The borrow speed array * @param _supplyiTokens The supply asset array * @param _supplySpeeds The supply speed array */ function _setDistributionSpeeds( address[] calldata _borrowiTokens, uint256[] calldata _borrowSpeeds, address[] calldata _supplyiTokens, uint256[] calldata _supplySpeeds ) external onlyOwner { require(!paused, "Can not change speeds when paused"); _setDistributionSpeedsInternal( _borrowiTokens, _borrowSpeeds, _supplyiTokens, _supplySpeeds ); _refreshGlobalDistributionSpeeds(); } function _setDistributionSpeedsInternal( address[] memory _borrowiTokens, uint256[] memory _borrowSpeeds, address[] memory _supplyiTokens, uint256[] memory _supplySpeeds ) internal { _setDistributionBorrowSpeedsInternal(_borrowiTokens, _borrowSpeeds); _setDistributionSupplySpeedsInternal(_supplyiTokens, _supplySpeeds); } /** * @notice Set borrow distribution speeds * @dev Admin function, will fail when paused * @param _iTokens The borrow asset array * @param _borrowSpeeds The borrow speed array */ function _setDistributionBorrowSpeeds( address[] calldata _iTokens, uint256[] calldata _borrowSpeeds ) external onlyOwner { require(!paused, "Can not change borrow speeds when paused"); _setDistributionBorrowSpeedsInternal(_iTokens, _borrowSpeeds); _refreshGlobalDistributionSpeeds(); } /** * @notice Set supply distribution speeds * @dev Admin function, will fail when paused * @param _iTokens The supply asset array * @param _supplySpeeds The supply speed array */ function _setDistributionSupplySpeeds( address[] calldata _iTokens, uint256[] calldata _supplySpeeds ) external onlyOwner { require(!paused, "Can not change supply speeds when paused"); _setDistributionSupplySpeedsInternal(_iTokens, _supplySpeeds); _refreshGlobalDistributionSpeeds(); } function _refreshGlobalDistributionSpeeds() internal { address[] memory _iTokens = controller.getAlliTokens(); uint256 _len = _iTokens.length; uint256 _borrowSpeed; uint256 _supplySpeed; for (uint256 i = 0; i < _len; i++) { _borrowSpeed = _borrowSpeed.add(distributionSpeed[_iTokens[i]]); _supplySpeed = _supplySpeed.add( distributionSupplySpeed[_iTokens[i]] ); } globalDistributionSpeed = _borrowSpeed; globalDistributionSupplySpeed = _supplySpeed; emit GlobalDistributionSpeedsUpdated(_borrowSpeed, _supplySpeed); } function _setDistributionBorrowSpeedsInternal( address[] memory _iTokens, uint256[] memory _borrowSpeeds ) internal { require( _iTokens.length == _borrowSpeeds.length, "Length of _iTokens and _borrowSpeeds mismatch" ); uint256 _len = _iTokens.length; for (uint256 i = 0; i < _len; i++) { _setDistributionBorrowSpeed(_iTokens[i], _borrowSpeeds[i]); } } function _setDistributionSupplySpeedsInternal( address[] memory _iTokens, uint256[] memory _supplySpeeds ) internal { require( _iTokens.length == _supplySpeeds.length, "Length of _iTokens and _supplySpeeds mismatch" ); uint256 _len = _iTokens.length; for (uint256 i = 0; i < _len; i++) { _setDistributionSupplySpeed(_iTokens[i], _supplySpeeds[i]); } } function _setDistributionBorrowSpeed(address _iToken, uint256 _borrowSpeed) internal { // iToken must have been listed require(controller.hasiToken(_iToken), "Token has not been listed"); // Update borrow state before updating new speed _updateDistributionState(_iToken, true); distributionSpeed[_iToken] = _borrowSpeed; emit DistributionBorrowSpeedUpdated(_iToken, _borrowSpeed); } function _setDistributionSupplySpeed(address _iToken, uint256 _supplySpeed) internal { // iToken must have been listed require(controller.hasiToken(_iToken), "Token has not been listed"); // Update supply state before updating new speed _updateDistributionState(_iToken, false); distributionSupplySpeed[_iToken] = _supplySpeed; emit DistributionSupplySpeedUpdated(_iToken, _supplySpeed); } /** * @notice Update the iToken's Reward distribution state * @dev Will be called every time when the iToken's supply/borrow changes * @param _iToken The iToken to be updated * @param _isBorrow whether to update the borrow state */ function updateDistributionState(address _iToken, bool _isBorrow) external override { // Skip all updates if it is paused if (paused) { return; } _updateDistributionState(_iToken, _isBorrow); } function _updateDistributionState(address _iToken, bool _isBorrow) internal { require(controller.hasiToken(_iToken), "Token has not been listed"); DistributionState storage state = _isBorrow ? distributionBorrowState[_iToken] : distributionSupplyState[_iToken]; uint256 _speed = _isBorrow ? distributionSpeed[_iToken] : distributionSupplySpeed[_iToken]; uint256 _blockNumber = block.number; uint256 _deltaBlocks = _blockNumber.sub(state.block); if (_deltaBlocks > 0 && _speed > 0) { uint256 _totalToken = _isBorrow ? IiToken(_iToken).totalBorrows().rdiv( IiToken(_iToken).borrowIndex() ) : IERC20Upgradeable(_iToken).totalSupply(); uint256 _totalDistributed = _speed.mul(_deltaBlocks); // Reward distributed per token since last time uint256 _distributedPerToken = _totalToken > 0 ? _totalDistributed.rdiv(_totalToken) : 0; state.index = state.index.add(_distributedPerToken); } state.block = _blockNumber; } /** * @notice Update the account's Reward distribution state * @dev Will be called every time when the account's supply/borrow changes * @param _iToken The iToken to be updated * @param _account The account to be updated * @param _isBorrow whether to update the borrow state */ function updateReward( address _iToken, address _account, bool _isBorrow ) external override { _updateReward(_iToken, _account, _isBorrow); } function _updateReward( address _iToken, address _account, bool _isBorrow ) internal { require(_account != address(0), "Invalid account address!"); require(controller.hasiToken(_iToken), "Token has not been listed"); uint256 _iTokenIndex; uint256 _accountIndex; uint256 _accountBalance; if (_isBorrow) { _iTokenIndex = distributionBorrowState[_iToken].index; _accountIndex = distributionBorrowerIndex[_iToken][_account]; _accountBalance = IiToken(_iToken) .borrowBalanceStored(_account) .rdiv(IiToken(_iToken).borrowIndex()); // Update the account state to date distributionBorrowerIndex[_iToken][_account] = _iTokenIndex; } else { _iTokenIndex = distributionSupplyState[_iToken].index; _accountIndex = distributionSupplierIndex[_iToken][_account]; _accountBalance = IERC20Upgradeable(_iToken).balanceOf(_account); // Update the account state to date distributionSupplierIndex[_iToken][_account] = _iTokenIndex; } uint256 _deltaIndex = _iTokenIndex.sub(_accountIndex); uint256 _amount = _accountBalance.rmul(_deltaIndex); if (_amount > 0) { reward[_account] = reward[_account].add(_amount); emit RewardDistributed(_iToken, _account, _amount, _accountIndex); } } /** * @notice Update reward accrued in iTokens by the holders regardless of paused or not * @param _holders The account to update * @param _iTokens The _iTokens to update */ function updateRewardBatch( address[] memory _holders, address[] memory _iTokens ) public override { // Update rewards for all _iTokens for holders for (uint256 i = 0; i < _iTokens.length; i++) { address _iToken = _iTokens[i]; _updateDistributionState(_iToken, false); _updateDistributionState(_iToken, true); for (uint256 j = 0; j < _holders.length; j++) { _updateReward(_iToken, _holders[j], false); _updateReward(_iToken, _holders[j], true); } } } /** * @notice Update reward accrued in iTokens by the holders regardless of paused or not * @param _holders The account to update * @param _iTokens The _iTokens to update * @param _isBorrow whether to update the borrow state */ function _updateRewards( address[] memory _holders, address[] memory _iTokens, bool _isBorrow ) internal { // Update rewards for all _iTokens for holders for (uint256 i = 0; i < _iTokens.length; i++) { address _iToken = _iTokens[i]; _updateDistributionState(_iToken, _isBorrow); for (uint256 j = 0; j < _holders.length; j++) { _updateReward(_iToken, _holders[j], _isBorrow); } } } /** * @notice Claim reward accrued in iTokens by the holders * @param _holders The account to claim for * @param _iTokens The _iTokens to claim from */ function claimReward(address[] memory _holders, address[] memory _iTokens) public override { updateRewardBatch(_holders, _iTokens); // Withdraw all reward for all holders for (uint256 j = 0; j < _holders.length; j++) { address _account = _holders[j]; uint256 _reward = reward[_account]; if (_reward > 0) { reward[_account] = 0; IERC20Upgradeable(rewardToken).safeTransferFrom( treasury, _account, _reward ); } } } /** * @notice Claim reward accrued in iTokens by the holders * @param _holders The account to claim for * @param _suppliediTokens The _suppliediTokens to claim from * @param _borrowediTokens The _borrowediTokens to claim from */ function claimRewards( address[] memory _holders, address[] memory _suppliediTokens, address[] memory _borrowediTokens ) external override { _updateRewards(_holders, _suppliediTokens, false); _updateRewards(_holders, _borrowediTokens, true); // Withdraw all reward for all holders for (uint256 j = 0; j < _holders.length; j++) { address _account = _holders[j]; uint256 _reward = reward[_account]; if (_reward > 0) { reward[_account] = 0; IERC20Upgradeable(rewardToken).safeTransferFrom( treasury, _account, _reward ); } } } /** * @notice Claim reward accrued in all iTokens by the holders * @param _holders The account to claim for */ function claimAllReward(address[] memory _holders) external override { claimReward(_holders, controller.getAlliTokens()); } /** * @notice Rescue tokens, can only be called by treasury * @param _token The token to rescue * @param _amount The amount of token to rescue * @param _to The token to send to */ function rescueTokens( address _token, uint256 _amount, address _to ) external { require( msg.sender == treasury, "rescueTokens: can only be called by treasury" ); // transfer _to IERC20Upgradeable(_token).safeTransfer(_to, _amount); } }
//SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts-upgradeable/token/ERC20/SafeERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/EnumerableSetUpgradeable.sol"; import "./interface/IControllerInterface.sol"; import "./interface/IPriceOracle.sol"; import "./interface/IiToken.sol"; import "./interface/IRewardDistributor.sol"; import "./library/Initializable.sol"; import "./library/Ownable.sol"; import "./library/SafeRatioMath.sol"; /** * @title dForce's lending controller Contract * @author dForce */ contract Controller is Initializable, Ownable, IControllerInterface { using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; using SafeRatioMath for uint256; using SafeMathUpgradeable for uint256; using SafeERC20Upgradeable for IERC20Upgradeable; /// @dev EnumerableSet of all iTokens EnumerableSetUpgradeable.AddressSet internal iTokens; struct Market { /* * Multiplier representing the most one can borrow against their collateral in this market. * For instance, 0.9 to allow borrowing 90% of collateral value. * Must be in [0, 0.9], and stored as a mantissa. */ uint256 collateralFactorMantissa; /* * Multiplier representing the most one can borrow the asset. * For instance, 0.5 to allow borrowing this asset 50% * collateral value * collateralFactor. * When calculating equity, 0.5 with 100 borrow balance will produce 200 borrow value * Must be between (0, 1], and stored as a mantissa. */ uint256 borrowFactorMantissa; /* * The borrow capacity of the asset, will be checked in beforeBorrow() * -1 means there is no limit on the capacity * 0 means the asset can not be borrowed any more */ uint256 borrowCapacity; /* * The supply capacity of the asset, will be checked in beforeMint() * -1 means there is no limit on the capacity * 0 means the asset can not be supplied any more */ uint256 supplyCapacity; // Whether market's mint is paused bool mintPaused; // Whether market's redeem is paused bool redeemPaused; // Whether market's borrow is paused bool borrowPaused; } /// @notice Mapping of iTokens to corresponding markets mapping(address => Market) public markets; struct AccountData { // Account's collateral assets EnumerableSetUpgradeable.AddressSet collaterals; // Account's borrowed assets EnumerableSetUpgradeable.AddressSet borrowed; } /// @dev Mapping of accounts' data, including collateral and borrowed assets mapping(address => AccountData) internal accountsData; /** * @notice Oracle to query the price of a given asset */ address public priceOracle; /** * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow */ uint256 public closeFactorMantissa; // closeFactorMantissa must be strictly greater than this value uint256 internal constant closeFactorMinMantissa = 0.05e18; // 0.05 // closeFactorMantissa must not exceed this value uint256 internal constant closeFactorMaxMantissa = 0.9e18; // 0.9 /** * @notice Multiplier representing the discount on collateral that a liquidator receives */ uint256 public liquidationIncentiveMantissa; // liquidationIncentiveMantissa must be no less than this value uint256 internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0 // liquidationIncentiveMantissa must be no greater than this value uint256 internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5 // collateralFactorMantissa must not exceed this value uint256 internal constant collateralFactorMaxMantissa = 1e18; // 1.0 // borrowFactorMantissa must not exceed this value uint256 internal constant borrowFactorMaxMantissa = 1e18; // 1.0 /** * @notice Guardian who can pause mint/borrow/liquidate/transfer in case of emergency */ address public pauseGuardian; /// @notice whether global transfer is paused bool public transferPaused; /// @notice whether global seize is paused bool public seizePaused; /** * @notice the address of reward distributor */ address public override rewardDistributor; /** * @dev Check if called by owner or pauseGuardian, and only owner can unpause */ modifier checkPauser(bool _paused) { require( msg.sender == owner || (msg.sender == pauseGuardian && _paused), "Only owner and guardian can pause and only owner can unpause" ); _; } /** * @notice Initializes the contract. */ function initialize() external initializer { __Ownable_init(); } /*********************************/ /******** Security Check *********/ /*********************************/ /** * @notice Ensure this is a Controller contract. */ function isController() external view override returns (bool) { return true; } /*********************************/ /******** Admin Operations *******/ /*********************************/ /** * @notice Admin function to add iToken into supported markets * Checks if the iToken already exsits * Will `revert()` if any check fails * @param _iToken The _iToken to add * @param _collateralFactor The _collateralFactor of _iToken * @param _borrowFactor The _borrowFactor of _iToken * @param _supplyCapacity The _supplyCapacity of _iToken * @param _distributionFactor The _distributionFactor of _iToken */ function _addMarket( address _iToken, uint256 _collateralFactor, uint256 _borrowFactor, uint256 _supplyCapacity, uint256 _borrowCapacity, uint256 _distributionFactor ) external override onlyOwner { require(IiToken(_iToken).isSupported(), "Token is not supported"); // Market must recognize this controller require( IiToken(_iToken).controller() == address(this), "Token's controller is not this one" ); // Market must not have been listed, EnumerableSet.add() will return false if it exsits require(iTokens.add(_iToken), "Token has already been listed"); require( _collateralFactor <= collateralFactorMaxMantissa, "Collateral factor invalid" ); require( _borrowFactor > 0 && _borrowFactor <= borrowFactorMaxMantissa, "Borrow factor invalid" ); // Its value will be taken into account when calculate account equity // Check if the price is available for the calculation require( IPriceOracle(priceOracle).getUnderlyingPrice(_iToken) != 0, "Underlying price is unavailable" ); markets[_iToken] = Market({ collateralFactorMantissa: _collateralFactor, borrowFactorMantissa: _borrowFactor, borrowCapacity: _borrowCapacity, supplyCapacity: _supplyCapacity, mintPaused: false, redeemPaused: false, borrowPaused: false }); IRewardDistributor(rewardDistributor)._addRecipient( _iToken, _distributionFactor ); emit MarketAdded( _iToken, _collateralFactor, _borrowFactor, _supplyCapacity, _borrowCapacity, _distributionFactor ); } /** * @notice Sets price oracle * @dev Admin function to set price oracle * @param _newOracle New oracle contract */ function _setPriceOracle(address _newOracle) external override onlyOwner { address _oldOracle = priceOracle; require( _newOracle != address(0) && _newOracle != _oldOracle, "Oracle address invalid" ); priceOracle = _newOracle; emit NewPriceOracle(_oldOracle, _newOracle); } /** * @notice Sets the closeFactor used when liquidating borrows * @dev Admin function to set closeFactor * @param _newCloseFactorMantissa New close factor, scaled by 1e18 */ function _setCloseFactor(uint256 _newCloseFactorMantissa) external override onlyOwner { require( _newCloseFactorMantissa >= closeFactorMinMantissa && _newCloseFactorMantissa <= closeFactorMaxMantissa, "Close factor invalid" ); uint256 _oldCloseFactorMantissa = closeFactorMantissa; closeFactorMantissa = _newCloseFactorMantissa; emit NewCloseFactor(_oldCloseFactorMantissa, _newCloseFactorMantissa); } /** * @notice Sets liquidationIncentive * @dev Admin function to set liquidationIncentive * @param _newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 */ function _setLiquidationIncentive(uint256 _newLiquidationIncentiveMantissa) external override onlyOwner { require( _newLiquidationIncentiveMantissa >= liquidationIncentiveMinMantissa && _newLiquidationIncentiveMantissa <= liquidationIncentiveMaxMantissa, "Liquidation incentive invalid" ); uint256 _oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; liquidationIncentiveMantissa = _newLiquidationIncentiveMantissa; emit NewLiquidationIncentive( _oldLiquidationIncentiveMantissa, _newLiquidationIncentiveMantissa ); } /** * @notice Sets the collateralFactor for a iToken * @dev Admin function to set collateralFactor for a iToken * @param _iToken The token to set the factor on * @param _newCollateralFactorMantissa The new collateral factor, scaled by 1e18 */ function _setCollateralFactor( address _iToken, uint256 _newCollateralFactorMantissa ) external override onlyOwner { _checkiTokenListed(_iToken); require( _newCollateralFactorMantissa <= collateralFactorMaxMantissa, "Collateral factor invalid" ); // Its value will be taken into account when calculate account equity // Check if the price is available for the calculation require( IPriceOracle(priceOracle).getUnderlyingPrice(_iToken) != 0, "Failed to set collateral factor, underlying price is unavailable" ); Market storage _market = markets[_iToken]; uint256 _oldCollateralFactorMantissa = _market.collateralFactorMantissa; _market.collateralFactorMantissa = _newCollateralFactorMantissa; emit NewCollateralFactor( _iToken, _oldCollateralFactorMantissa, _newCollateralFactorMantissa ); } /** * @notice Sets the borrowFactor for a iToken * @dev Admin function to set borrowFactor for a iToken * @param _iToken The token to set the factor on * @param _newBorrowFactorMantissa The new borrow factor, scaled by 1e18 */ function _setBorrowFactor(address _iToken, uint256 _newBorrowFactorMantissa) external override onlyOwner { _checkiTokenListed(_iToken); require( _newBorrowFactorMantissa > 0 && _newBorrowFactorMantissa <= borrowFactorMaxMantissa, "Borrow factor invalid" ); // Its value will be taken into account when calculate account equity // Check if the price is available for the calculation require( IPriceOracle(priceOracle).getUnderlyingPrice(_iToken) != 0, "Failed to set borrow factor, underlying price is unavailable" ); Market storage _market = markets[_iToken]; uint256 _oldBorrowFactorMantissa = _market.borrowFactorMantissa; _market.borrowFactorMantissa = _newBorrowFactorMantissa; emit NewBorrowFactor( _iToken, _oldBorrowFactorMantissa, _newBorrowFactorMantissa ); } /** * @notice Sets the borrowCapacity for a iToken * @dev Admin function to set borrowCapacity for a iToken * @param _iToken The token to set the capacity on * @param _newBorrowCapacity The new borrow capacity */ function _setBorrowCapacity(address _iToken, uint256 _newBorrowCapacity) external override onlyOwner { _checkiTokenListed(_iToken); Market storage _market = markets[_iToken]; uint256 oldBorrowCapacity = _market.borrowCapacity; _market.borrowCapacity = _newBorrowCapacity; emit NewBorrowCapacity(_iToken, oldBorrowCapacity, _newBorrowCapacity); } /** * @notice Sets the supplyCapacity for a iToken * @dev Admin function to set supplyCapacity for a iToken * @param _iToken The token to set the capacity on * @param _newSupplyCapacity The new supply capacity */ function _setSupplyCapacity(address _iToken, uint256 _newSupplyCapacity) external override onlyOwner { _checkiTokenListed(_iToken); Market storage _market = markets[_iToken]; uint256 oldSupplyCapacity = _market.supplyCapacity; _market.supplyCapacity = _newSupplyCapacity; emit NewSupplyCapacity(_iToken, oldSupplyCapacity, _newSupplyCapacity); } /** * @notice Sets the pauseGuardian * @dev Admin function to set pauseGuardian * @param _newPauseGuardian The new pause guardian */ function _setPauseGuardian(address _newPauseGuardian) external override onlyOwner { address _oldPauseGuardian = pauseGuardian; require( _newPauseGuardian != address(0) && _newPauseGuardian != _oldPauseGuardian, "Pause guardian address invalid" ); pauseGuardian = _newPauseGuardian; emit NewPauseGuardian(_oldPauseGuardian, _newPauseGuardian); } /** * @notice pause/unpause mint() for all iTokens * @dev Admin function, only owner and pauseGuardian can call this * @param _paused whether to pause or unpause */ function _setAllMintPaused(bool _paused) external override checkPauser(_paused) { EnumerableSetUpgradeable.AddressSet storage _iTokens = iTokens; uint256 _len = _iTokens.length(); for (uint256 i = 0; i < _len; i++) { _setMintPausedInternal(_iTokens.at(i), _paused); } } /** * @notice pause/unpause mint() for the iToken * @dev Admin function, only owner and pauseGuardian can call this * @param _iToken The iToken to pause/unpause * @param _paused whether to pause or unpause */ function _setMintPaused(address _iToken, bool _paused) external override checkPauser(_paused) { _checkiTokenListed(_iToken); _setMintPausedInternal(_iToken, _paused); } function _setMintPausedInternal(address _iToken, bool _paused) internal { markets[_iToken].mintPaused = _paused; emit MintPaused(_iToken, _paused); } /** * @notice pause/unpause redeem() for all iTokens * @dev Admin function, only owner and pauseGuardian can call this * @param _paused whether to pause or unpause */ function _setAllRedeemPaused(bool _paused) external override checkPauser(_paused) { EnumerableSetUpgradeable.AddressSet storage _iTokens = iTokens; uint256 _len = _iTokens.length(); for (uint256 i = 0; i < _len; i++) { _setRedeemPausedInternal(_iTokens.at(i), _paused); } } /** * @notice pause/unpause redeem() for the iToken * @dev Admin function, only owner and pauseGuardian can call this * @param _iToken The iToken to pause/unpause * @param _paused whether to pause or unpause */ function _setRedeemPaused(address _iToken, bool _paused) external override checkPauser(_paused) { _checkiTokenListed(_iToken); _setRedeemPausedInternal(_iToken, _paused); } function _setRedeemPausedInternal(address _iToken, bool _paused) internal { markets[_iToken].redeemPaused = _paused; emit RedeemPaused(_iToken, _paused); } /** * @notice pause/unpause borrow() for all iTokens * @dev Admin function, only owner and pauseGuardian can call this * @param _paused whether to pause or unpause */ function _setAllBorrowPaused(bool _paused) external override checkPauser(_paused) { EnumerableSetUpgradeable.AddressSet storage _iTokens = iTokens; uint256 _len = _iTokens.length(); for (uint256 i = 0; i < _len; i++) { _setBorrowPausedInternal(_iTokens.at(i), _paused); } } /** * @notice pause/unpause borrow() for the iToken * @dev Admin function, only owner and pauseGuardian can call this * @param _iToken The iToken to pause/unpause * @param _paused whether to pause or unpause */ function _setBorrowPaused(address _iToken, bool _paused) external override checkPauser(_paused) { _checkiTokenListed(_iToken); _setBorrowPausedInternal(_iToken, _paused); } function _setBorrowPausedInternal(address _iToken, bool _paused) internal { markets[_iToken].borrowPaused = _paused; emit BorrowPaused(_iToken, _paused); } /** * @notice pause/unpause global transfer() * @dev Admin function, only owner and pauseGuardian can call this * @param _paused whether to pause or unpause */ function _setTransferPaused(bool _paused) external override checkPauser(_paused) { _setTransferPausedInternal(_paused); } function _setTransferPausedInternal(bool _paused) internal { transferPaused = _paused; emit TransferPaused(_paused); } /** * @notice pause/unpause global seize() * @dev Admin function, only owner and pauseGuardian can call this * @param _paused whether to pause or unpause */ function _setSeizePaused(bool _paused) external override checkPauser(_paused) { _setSeizePausedInternal(_paused); } function _setSeizePausedInternal(bool _paused) internal { seizePaused = _paused; emit SeizePaused(_paused); } /** * @notice pause/unpause all actions iToken, including mint/redeem/borrow * @dev Admin function, only owner and pauseGuardian can call this * @param _paused whether to pause or unpause */ function _setiTokenPaused(address _iToken, bool _paused) external override checkPauser(_paused) { _checkiTokenListed(_iToken); _setiTokenPausedInternal(_iToken, _paused); } function _setiTokenPausedInternal(address _iToken, bool _paused) internal { Market storage _market = markets[_iToken]; _market.mintPaused = _paused; emit MintPaused(_iToken, _paused); _market.redeemPaused = _paused; emit RedeemPaused(_iToken, _paused); _market.borrowPaused = _paused; emit BorrowPaused(_iToken, _paused); } /** * @notice pause/unpause entire protocol, including mint/redeem/borrow/seize/transfer * @dev Admin function, only owner and pauseGuardian can call this * @param _paused whether to pause or unpause */ function _setProtocolPaused(bool _paused) external override checkPauser(_paused) { EnumerableSetUpgradeable.AddressSet storage _iTokens = iTokens; uint256 _len = _iTokens.length(); for (uint256 i = 0; i < _len; i++) { address _iToken = _iTokens.at(i); _setiTokenPausedInternal(_iToken, _paused); } _setTransferPausedInternal(_paused); _setSeizePausedInternal(_paused); } /** * @notice Sets Reward Distributor * @dev Admin function to set reward distributor * @param _newRewardDistributor new reward distributor */ function _setRewardDistributor(address _newRewardDistributor) external override onlyOwner { address _oldRewardDistributor = rewardDistributor; require( _newRewardDistributor != address(0) && _newRewardDistributor != _oldRewardDistributor, "Reward Distributor address invalid" ); rewardDistributor = _newRewardDistributor; emit NewRewardDistributor(_oldRewardDistributor, _newRewardDistributor); } /*********************************/ /******** Policy Hooks **********/ /*********************************/ /** * @notice Hook function before iToken `mint()` * Checks if the account should be allowed to mint the given iToken * Will `revert()` if any check fails * @param _iToken The iToken to check the mint against * @param _minter The account which would get the minted tokens * @param _mintAmount The amount of underlying being minted to iToken */ function beforeMint( address _iToken, address _minter, uint256 _mintAmount ) external override { _checkiTokenListed(_iToken); Market storage _market = markets[_iToken]; require(!_market.mintPaused, "Token mint has been paused"); // Check the iToken's supply capacity, -1 means no limit uint256 _totalSupplyUnderlying = IERC20Upgradeable(_iToken).totalSupply().rmul( IiToken(_iToken).exchangeRateStored() ); require( _totalSupplyUnderlying.add(_mintAmount) <= _market.supplyCapacity, "Token supply capacity reached" ); // Update the Reward Distribution Supply state and distribute reward to suppplier IRewardDistributor(rewardDistributor).updateDistributionState( _iToken, false ); IRewardDistributor(rewardDistributor).updateReward( _iToken, _minter, false ); } /** * @notice Hook function after iToken `mint()` * Will `revert()` if any operation fails * @param _iToken The iToken being minted * @param _minter The account which would get the minted tokens * @param _mintAmount The amount of underlying being minted to iToken * @param _mintedAmount The amount of iToken being minted */ function afterMint( address _iToken, address _minter, uint256 _mintAmount, uint256 _mintedAmount ) external override { _iToken; _minter; _mintAmount; _mintedAmount; } /** * @notice Hook function before iToken `redeem()` * Checks if the account should be allowed to redeem the given iToken * Will `revert()` if any check fails * @param _iToken The iToken to check the redeem against * @param _redeemer The account which would redeem iToken * @param _redeemAmount The amount of iToken to redeem */ function beforeRedeem( address _iToken, address _redeemer, uint256 _redeemAmount ) external virtual override { // _redeemAllowed below will check whether _iToken is listed require(!markets[_iToken].redeemPaused, "Token redeem has been paused"); _redeemAllowed(_iToken, _redeemer, _redeemAmount); // Update the Reward Distribution Supply state and distribute reward to suppplier IRewardDistributor(rewardDistributor).updateDistributionState( _iToken, false ); IRewardDistributor(rewardDistributor).updateReward( _iToken, _redeemer, false ); } /** * @notice Hook function after iToken `redeem()` * Will `revert()` if any operation fails * @param _iToken The iToken being redeemed * @param _redeemer The account which redeemed iToken * @param _redeemAmount The amount of iToken being redeemed * @param _redeemedUnderlying The amount of underlying being redeemed */ function afterRedeem( address _iToken, address _redeemer, uint256 _redeemAmount, uint256 _redeemedUnderlying ) external virtual override { _iToken; _redeemer; _redeemAmount; _redeemedUnderlying; } /** * @notice Hook function before iToken `borrow()` * Checks if the account should be allowed to borrow the given iToken * Will `revert()` if any check fails * @param _iToken The iToken to check the borrow against * @param _borrower The account which would borrow iToken * @param _borrowAmount The amount of underlying to borrow */ function beforeBorrow( address _iToken, address _borrower, uint256 _borrowAmount ) external virtual override { _checkiTokenListed(_iToken); Market storage _market = markets[_iToken]; require(!_market.borrowPaused, "Token borrow has been paused"); if (!hasBorrowed(_borrower, _iToken)) { // Unlike collaterals, borrowed asset can only be added by iToken, // rather than enabled by user directly. require(msg.sender == _iToken, "sender must be iToken"); // Have checked _iToken is listed, just add it _addToBorrowed(_borrower, _iToken); } // Check borrower's equity (, uint256 _shortfall, , ) = calcAccountEquityWithEffect(_borrower, _iToken, 0, _borrowAmount); require(_shortfall == 0, "Account has some shortfall"); // Check the iToken's borrow capacity, -1 means no limit uint256 _totalBorrows = IiToken(_iToken).totalBorrows(); require( _totalBorrows.add(_borrowAmount) <= _market.borrowCapacity, "Token borrow capacity reached" ); // Update the Reward Distribution Borrow state and distribute reward to borrower IRewardDistributor(rewardDistributor).updateDistributionState( _iToken, true ); IRewardDistributor(rewardDistributor).updateReward( _iToken, _borrower, true ); } /** * @notice Hook function after iToken `borrow()` * Will `revert()` if any operation fails * @param _iToken The iToken being borrewd * @param _borrower The account which borrowed iToken * @param _borrowedAmount The amount of underlying being borrowed */ function afterBorrow( address _iToken, address _borrower, uint256 _borrowedAmount ) external virtual override { _iToken; _borrower; _borrowedAmount; } /** * @notice Hook function before iToken `repayBorrow()` * Checks if the account should be allowed to repay the given iToken * for the borrower. Will `revert()` if any check fails * @param _iToken The iToken to verify the repay against * @param _payer The account which would repay iToken * @param _borrower The account which has borrowed * @param _repayAmount The amount of underlying to repay */ function beforeRepayBorrow( address _iToken, address _payer, address _borrower, uint256 _repayAmount ) external override { _checkiTokenListed(_iToken); // Update the Reward Distribution Borrow state and distribute reward to borrower IRewardDistributor(rewardDistributor).updateDistributionState( _iToken, true ); IRewardDistributor(rewardDistributor).updateReward( _iToken, _borrower, true ); _payer; _repayAmount; } /** * @notice Hook function after iToken `repayBorrow()` * Will `revert()` if any operation fails * @param _iToken The iToken being repaid * @param _payer The account which would repay * @param _borrower The account which has borrowed * @param _repayAmount The amount of underlying being repaied */ function afterRepayBorrow( address _iToken, address _payer, address _borrower, uint256 _repayAmount ) external override { _checkiTokenListed(_iToken); // Remove _iToken from borrowed list if new borrow balance is 0 if (IiToken(_iToken).borrowBalanceStored(_borrower) == 0) { // Only allow called by iToken as we are going to remove this token from borrower's borrowed list require(msg.sender == _iToken, "sender must be iToken"); // Have checked _iToken is listed, just remove it _removeFromBorrowed(_borrower, _iToken); } _payer; _repayAmount; } /** * @notice Hook function before iToken `liquidateBorrow()` * Checks if the account should be allowed to liquidate the given iToken * for the borrower. Will `revert()` if any check fails * @param _iTokenBorrowed The iToken was borrowed * @param _iTokenCollateral The collateral iToken to be liqudate with * @param _liquidator The account which would repay the borrowed iToken * @param _borrower The account which has borrowed * @param _repayAmount The amount of underlying to repay */ function beforeLiquidateBorrow( address _iTokenBorrowed, address _iTokenCollateral, address _liquidator, address _borrower, uint256 _repayAmount ) external override { // Tokens must have been listed require( iTokens.contains(_iTokenBorrowed) && iTokens.contains(_iTokenCollateral), "Tokens have not been listed" ); (, uint256 _shortfall, , ) = calcAccountEquity(_borrower); require(_shortfall > 0, "Account does not have shortfall"); // Only allowed to repay the borrow balance's close factor uint256 _borrowBalance = IiToken(_iTokenBorrowed).borrowBalanceStored(_borrower); uint256 _maxRepay = _borrowBalance.rmul(closeFactorMantissa); require(_repayAmount <= _maxRepay, "Repay exceeds max repay allowed"); _liquidator; } /** * @notice Hook function after iToken `liquidateBorrow()` * Will `revert()` if any operation fails * @param _iTokenBorrowed The iToken was borrowed * @param _iTokenCollateral The collateral iToken to be seized * @param _liquidator The account which would repay and seize * @param _borrower The account which has borrowed * @param _repaidAmount The amount of underlying being repaied * @param _seizedAmount The amount of collateral being seized */ function afterLiquidateBorrow( address _iTokenBorrowed, address _iTokenCollateral, address _liquidator, address _borrower, uint256 _repaidAmount, uint256 _seizedAmount ) external override { _iTokenBorrowed; _iTokenCollateral; _liquidator; _borrower; _repaidAmount; _seizedAmount; // Unlike repayBorrow, liquidateBorrow does not allow to repay all borrow balance // No need to check whether should remove from borrowed asset list } /** * @notice Hook function before iToken `seize()` * Checks if the liquidator should be allowed to seize the collateral iToken * Will `revert()` if any check fails * @param _iTokenCollateral The collateral iToken to be seize * @param _iTokenBorrowed The iToken was borrowed * @param _liquidator The account which has repaid the borrowed iToken * @param _borrower The account which has borrowed * @param _seizeAmount The amount of collateral iToken to seize */ function beforeSeize( address _iTokenCollateral, address _iTokenBorrowed, address _liquidator, address _borrower, uint256 _seizeAmount ) external override { require(!seizePaused, "Seize has been paused"); // Markets must have been listed require( iTokens.contains(_iTokenBorrowed) && iTokens.contains(_iTokenCollateral), "Tokens have not been listed" ); // Sanity Check the controllers require( IiToken(_iTokenBorrowed).controller() == IiToken(_iTokenCollateral).controller(), "Controller mismatch between Borrowed and Collateral" ); // Update the Reward Distribution Supply state on collateral IRewardDistributor(rewardDistributor).updateDistributionState( _iTokenCollateral, false ); // Update reward of liquidator and borrower on collateral IRewardDistributor(rewardDistributor).updateReward( _iTokenCollateral, _liquidator, false ); IRewardDistributor(rewardDistributor).updateReward( _iTokenCollateral, _borrower, false ); _seizeAmount; } /** * @notice Hook function after iToken `seize()` * Will `revert()` if any operation fails * @param _iTokenCollateral The collateral iToken to be seized * @param _iTokenBorrowed The iToken was borrowed * @param _liquidator The account which has repaid and seized * @param _borrower The account which has borrowed * @param _seizedAmount The amount of collateral being seized */ function afterSeize( address _iTokenCollateral, address _iTokenBorrowed, address _liquidator, address _borrower, uint256 _seizedAmount ) external override { _iTokenBorrowed; _iTokenCollateral; _liquidator; _borrower; _seizedAmount; } /** * @notice Hook function before iToken `transfer()` * Checks if the transfer should be allowed * Will `revert()` if any check fails * @param _iToken The iToken to be transfered * @param _from The account to be transfered from * @param _to The account to be transfered to * @param _amount The amount to be transfered */ function beforeTransfer( address _iToken, address _from, address _to, uint256 _amount ) external override { // _redeemAllowed below will check whether _iToken is listed require(!transferPaused, "Transfer has been paused"); // Check account equity with this amount to decide whether the transfer is allowed _redeemAllowed(_iToken, _from, _amount); // Update the Reward Distribution supply state IRewardDistributor(rewardDistributor).updateDistributionState( _iToken, false ); // Update reward of from and to IRewardDistributor(rewardDistributor).updateReward( _iToken, _from, false ); IRewardDistributor(rewardDistributor).updateReward(_iToken, _to, false); } /** * @notice Hook function after iToken `transfer()` * Will `revert()` if any operation fails * @param _iToken The iToken was transfered * @param _from The account was transfer from * @param _to The account was transfer to * @param _amount The amount was transfered */ function afterTransfer( address _iToken, address _from, address _to, uint256 _amount ) external override { _iToken; _from; _to; _amount; } /** * @notice Hook function before iToken `flashloan()` * Checks if the flashloan should be allowed * Will `revert()` if any check fails * @param _iToken The iToken to be flashloaned * @param _to The account flashloaned transfer to * @param _amount The amount to be flashloaned */ function beforeFlashloan( address _iToken, address _to, uint256 _amount ) external override { // Flashloan share the same pause state with borrow require(!markets[_iToken].borrowPaused, "Token borrow has been paused"); _checkiTokenListed(_iToken); _to; _amount; // Update the Reward Distribution Borrow state IRewardDistributor(rewardDistributor).updateDistributionState( _iToken, true ); } /** * @notice Hook function after iToken `flashloan()` * Will `revert()` if any operation fails * @param _iToken The iToken was flashloaned * @param _to The account flashloan transfer to * @param _amount The amount was flashloaned */ function afterFlashloan( address _iToken, address _to, uint256 _amount ) external override { _iToken; _to; _amount; } /*********************************/ /***** Internal Functions *******/ /*********************************/ function _redeemAllowed( address _iToken, address _redeemer, uint256 _amount ) private view { _checkiTokenListed(_iToken); // No need to check liquidity if _redeemer has not used _iToken as collateral if (!accountsData[_redeemer].collaterals.contains(_iToken)) { return; } (, uint256 _shortfall, , ) = calcAccountEquityWithEffect(_redeemer, _iToken, _amount, 0); require(_shortfall == 0, "Account has some shortfall"); } /** * @dev Check if _iToken is listed */ function _checkiTokenListed(address _iToken) internal view { require(iTokens.contains(_iToken), "Token has not been listed"); } /*********************************/ /** Account equity calculation ***/ /*********************************/ /** * @notice Calculates current account equity * @param _account The account to query equity of * @return account equity, shortfall, collateral value, borrowed value. */ function calcAccountEquity(address _account) public view override returns ( uint256, uint256, uint256, uint256 ) { return calcAccountEquityWithEffect(_account, address(0), 0, 0); } /** * @dev Local vars for avoiding stack-depth limits in calculating account liquidity. * Note that `iTokenBalance` is the number of iTokens the account owns in the collateral, * whereas `borrowBalance` is the amount of underlying that the account has borrowed. */ struct AccountEquityLocalVars { uint256 sumCollateral; uint256 sumBorrowed; uint256 iTokenBalance; uint256 borrowBalance; uint256 exchangeRateMantissa; uint256 underlyingPrice; uint256 collateralValue; uint256 borrowValue; } /** * @notice Calculates current account equity plus some token and amount to effect * @param _account The account to query equity of * @param _tokenToEffect The token address to add some additional redeeem/borrow * @param _redeemAmount The additional amount to redeem * @param _borrowAmount The additional amount to borrow * @return account euqity, shortfall, collateral value, borrowed value plus the effect. */ function calcAccountEquityWithEffect( address _account, address _tokenToEffect, uint256 _redeemAmount, uint256 _borrowAmount ) internal view virtual returns ( uint256, uint256, uint256, uint256 ) { AccountEquityLocalVars memory _local; AccountData storage _accountData = accountsData[_account]; // Calculate value of all collaterals // collateralValuePerToken = underlyingPrice * exchangeRate * collateralFactor // collateralValue = balance * collateralValuePerToken // sumCollateral += collateralValue uint256 _len = _accountData.collaterals.length(); for (uint256 i = 0; i < _len; i++) { IiToken _token = IiToken(_accountData.collaterals.at(i)); _local.iTokenBalance = IERC20Upgradeable(address(_token)).balanceOf( _account ); _local.exchangeRateMantissa = _token.exchangeRateStored(); if (_tokenToEffect == address(_token) && _redeemAmount > 0) { _local.iTokenBalance = _local.iTokenBalance.sub(_redeemAmount); } _local.underlyingPrice = IPriceOracle(priceOracle) .getUnderlyingPrice(address(_token)); require( _local.underlyingPrice != 0, "Invalid price to calculate account equity" ); _local.collateralValue = _local .iTokenBalance .mul(_local.underlyingPrice) .rmul(_local.exchangeRateMantissa) .rmul(markets[address(_token)].collateralFactorMantissa); _local.sumCollateral = _local.sumCollateral.add( _local.collateralValue ); } // Calculate all borrowed value // borrowValue = underlyingPrice * underlyingBorrowed / borrowFactor // sumBorrowed += borrowValue _len = _accountData.borrowed.length(); for (uint256 i = 0; i < _len; i++) { IiToken _token = IiToken(_accountData.borrowed.at(i)); _local.borrowBalance = _token.borrowBalanceStored(_account); if (_tokenToEffect == address(_token) && _borrowAmount > 0) { _local.borrowBalance = _local.borrowBalance.add(_borrowAmount); } _local.underlyingPrice = IPriceOracle(priceOracle) .getUnderlyingPrice(address(_token)); require( _local.underlyingPrice != 0, "Invalid price to calculate account equity" ); // borrowFactorMantissa can not be set to 0 _local.borrowValue = _local .borrowBalance .mul(_local.underlyingPrice) .rdiv(markets[address(_token)].borrowFactorMantissa); _local.sumBorrowed = _local.sumBorrowed.add(_local.borrowValue); } // Should never underflow return _local.sumCollateral > _local.sumBorrowed ? ( _local.sumCollateral - _local.sumBorrowed, uint256(0), _local.sumCollateral, _local.sumBorrowed ) : ( uint256(0), _local.sumBorrowed - _local.sumCollateral, _local.sumCollateral, _local.sumBorrowed ); } /** * @notice Calculate amount of collateral iToken to seize after repaying an underlying amount * @dev Used in liquidation * @param _iTokenBorrowed The iToken was borrowed * @param _iTokenCollateral The collateral iToken to be seized * @param _actualRepayAmount The amount of underlying token liquidator has repaied * @return _seizedTokenCollateral amount of iTokenCollateral tokens to be seized */ function liquidateCalculateSeizeTokens( address _iTokenBorrowed, address _iTokenCollateral, uint256 _actualRepayAmount ) external view virtual override returns (uint256 _seizedTokenCollateral) { /* Read oracle prices for borrowed and collateral assets */ uint256 _priceBorrowed = IPriceOracle(priceOracle).getUnderlyingPrice(_iTokenBorrowed); uint256 _priceCollateral = IPriceOracle(priceOracle).getUnderlyingPrice(_iTokenCollateral); require( _priceBorrowed != 0 && _priceCollateral != 0, "Borrowed or Collateral asset price is invalid" ); uint256 _valueRepayPlusIncentive = _actualRepayAmount.mul(_priceBorrowed).rmul( liquidationIncentiveMantissa ); // Use stored value here as it is view function uint256 _exchangeRateMantissa = IiToken(_iTokenCollateral).exchangeRateStored(); // seizedTokenCollateral = valueRepayPlusIncentive / valuePerTokenCollateral // valuePerTokenCollateral = exchangeRateMantissa * priceCollateral _seizedTokenCollateral = _valueRepayPlusIncentive .rdiv(_exchangeRateMantissa) .div(_priceCollateral); } /*********************************/ /*** Account Markets Operation ***/ /*********************************/ /** * @notice Returns the markets list the account has entered * @param _account The address of the account to query * @return _accountCollaterals The markets list the account has entered */ function getEnteredMarkets(address _account) external view override returns (address[] memory _accountCollaterals) { AccountData storage _accountData = accountsData[_account]; uint256 _len = _accountData.collaterals.length(); _accountCollaterals = new address[](_len); for (uint256 i = 0; i < _len; i++) { _accountCollaterals[i] = _accountData.collaterals.at(i); } } /** * @notice Add markets to `msg.sender`'s markets list for liquidity calculations * @param _iTokens The list of addresses of the iToken markets to be entered * @return _results Success indicator for whether each corresponding market was entered */ function enterMarkets(address[] calldata _iTokens) external override returns (bool[] memory _results) { uint256 _len = _iTokens.length; _results = new bool[](_len); for (uint256 i = 0; i < _len; i++) { _results[i] = _enterMarket(_iTokens[i], msg.sender); } } /** * @notice Add the market to the account's markets list for liquidity calculations * @param _iToken The market to enter * @param _account The address of the account to modify * @return True if entered successfully, false for non-listed market or other errors */ function _enterMarket(address _iToken, address _account) internal returns (bool) { // Market not listed, skip it if (!iTokens.contains(_iToken)) { return false; } // add() will return false if iToken is in account's market list if (accountsData[_account].collaterals.add(_iToken)) { emit MarketEntered(_iToken, _account); } return true; } /** * @notice Only expect to be called by iToken contract. * @dev Add the market to the account's markets list for liquidity calculations * @param _market The market to enter * @param _account The address of the account to modify */ function enterMarketFromiToken(address _market, address _account) external override { // msg.sender must be listed iToken, typically a iMSDMiniPool _checkiTokenListed(msg.sender); require( _enterMarket(_market, _account), "enterMarketFromiToken: Only can enter a listed market!" ); } /** * @notice Returns whether the given account has entered the market * @param _account The address of the account to check * @param _iToken The iToken to check against * @return True if the account has entered the market, otherwise false. */ function hasEnteredMarket(address _account, address _iToken) external view override returns (bool) { return accountsData[_account].collaterals.contains(_iToken); } /** * @notice Remove markets from `msg.sender`'s collaterals for liquidity calculations * @param _iTokens The list of addresses of the iToken to exit * @return _results Success indicators for whether each corresponding market was exited */ function exitMarkets(address[] calldata _iTokens) external override returns (bool[] memory _results) { uint256 _len = _iTokens.length; _results = new bool[](_len); for (uint256 i = 0; i < _len; i++) { _results[i] = _exitMarket(_iTokens[i], msg.sender); } } /** * @notice Remove the market to the account's markets list for liquidity calculations * @param _iToken The market to exit * @param _account The address of the account to modify * @return True if exit successfully, false for non-listed market or other errors */ function _exitMarket(address _iToken, address _account) internal returns (bool) { // Market not listed, skip it if (!iTokens.contains(_iToken)) { return true; } // Account has not entered this market, skip it if (!accountsData[_account].collaterals.contains(_iToken)) { return true; } // Get the iToken balance uint256 _balance = IERC20Upgradeable(_iToken).balanceOf(_account); // Check account's equity if all balance are redeemed // which means iToken can be removed from collaterals _redeemAllowed(_iToken, _account, _balance); // Have checked account has entered market before accountsData[_account].collaterals.remove(_iToken); emit MarketExited(_iToken, _account); return true; } /** * @notice Returns the asset list the account has borrowed * @param _account The address of the account to query * @return _borrowedAssets The asset list the account has borrowed */ function getBorrowedAssets(address _account) external view override returns (address[] memory _borrowedAssets) { AccountData storage _accountData = accountsData[_account]; uint256 _len = _accountData.borrowed.length(); _borrowedAssets = new address[](_len); for (uint256 i = 0; i < _len; i++) { _borrowedAssets[i] = _accountData.borrowed.at(i); } } /** * @notice Add the market to the account's borrowed list for equity calculations * @param _iToken The iToken of underlying to borrow * @param _account The address of the account to modify */ function _addToBorrowed(address _account, address _iToken) internal { // add() will return false if iToken is in account's market list if (accountsData[_account].borrowed.add(_iToken)) { emit BorrowedAdded(_iToken, _account); } } /** * @notice Returns whether the given account has borrowed the given iToken * @param _account The address of the account to check * @param _iToken The iToken to check against * @return True if the account has borrowed the iToken, otherwise false. */ function hasBorrowed(address _account, address _iToken) public view override returns (bool) { return accountsData[_account].borrowed.contains(_iToken); } /** * @notice Remove the iToken from the account's borrowed list * @param _iToken The iToken to remove * @param _account The address of the account to modify */ function _removeFromBorrowed(address _account, address _iToken) internal { // remove() will return false if iToken does not exist in account's borrowed list if (accountsData[_account].borrowed.remove(_iToken)) { emit BorrowedRemoved(_iToken, _account); } } /*********************************/ /****** General Information ******/ /*********************************/ /** * @notice Return all of the iTokens * @return _alliTokens The list of iToken addresses */ function getAlliTokens() public view override returns (address[] memory _alliTokens) { EnumerableSetUpgradeable.AddressSet storage _iTokens = iTokens; uint256 _len = _iTokens.length(); _alliTokens = new address[](_len); for (uint256 i = 0; i < _len; i++) { _alliTokens[i] = _iTokens.at(i); } } /** * @notice Check whether a iToken is listed in controller * @param _iToken The iToken to check for * @return true if the iToken is listed otherwise false */ function hasiToken(address _iToken) public view override returns (bool) { return iTokens.contains(_iToken); } }
//SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "./IInterestRateModelInterface.sol"; import "./IControllerInterface.sol"; interface IiToken { function isSupported() external returns (bool); function isiToken() external returns (bool); //---------------------------------- //********* User Interface ********* //---------------------------------- function mint(address recipient, uint256 mintAmount) external; function mintForSelfAndEnterMarket(uint256 mintAmount) external; function redeem(address from, uint256 redeemTokens) external; function redeemUnderlying(address from, uint256 redeemAmount) external; function borrow(uint256 borrowAmount) external; function repayBorrow(uint256 repayAmount) external; function repayBorrowBehalf(address borrower, uint256 repayAmount) external; function liquidateBorrow( address borrower, uint256 repayAmount, address iTokenCollateral ) external; function flashloan( address recipient, uint256 loanAmount, bytes memory data ) external; function seize( address _liquidator, address _borrower, uint256 _seizeTokens ) external; function updateInterest() external returns (bool); function controller() external view returns (address); function exchangeRateCurrent() external returns (uint256); function exchangeRateStored() external view returns (uint256); function totalBorrowsCurrent() external returns (uint256); function totalBorrows() external view returns (uint256); function borrowBalanceCurrent(address _user) external returns (uint256); function borrowBalanceStored(address _user) external view returns (uint256); function borrowIndex() external view returns (uint256); function getAccountSnapshot(address _account) external view returns ( uint256, uint256, uint256 ); function borrowRatePerBlock() external view returns (uint256); function supplyRatePerBlock() external view returns (uint256); function getCash() external view returns (uint256); //---------------------------------- //********* Owner Actions ********** //---------------------------------- function _setNewReserveRatio(uint256 _newReserveRatio) external; function _setNewFlashloanFeeRatio(uint256 _newFlashloanFeeRatio) external; function _setNewProtocolFeeRatio(uint256 _newProtocolFeeRatio) external; function _setController(IControllerInterface _newController) external; function _setInterestRateModel( IInterestRateModelInterface _newInterestRateModel ) external; function _withdrawReserves(uint256 _withdrawAmount) external; }
//SPDX-License-Identifier: MIT pragma solidity 0.6.12; interface IRewardDistributorV3 { function rewardToken() external returns (address); function _setRewardToken(address newRewardToken) external; /// @notice Emitted reward token address is changed by admin event NewRewardToken(address oldRewardToken, address newRewardToken); function treasury() external returns (address); function _setTreasury(address newTreasury) external; /// @notice Emitted treasury address is changed by admin event NewTreasury(address oldTreasury, address newTreasury); function _addRecipient(address _iToken, uint256 _distributionFactor) external; event NewRecipient(address iToken, uint256 distributionFactor); /// @notice Emitted when mint is paused/unpaused by admin event Paused(bool paused); function _pause() external; function _unpause( address[] calldata _borrowiTokens, uint256[] calldata _borrowSpeeds, address[] calldata _supplyiTokens, uint256[] calldata _supplySpeeds ) external; /// @notice Emitted when Global Distribution speed for both supply and borrow are updated event GlobalDistributionSpeedsUpdated( uint256 borrowSpeed, uint256 supplySpeed ); /// @notice Emitted when iToken's Distribution borrow speed is updated event DistributionBorrowSpeedUpdated(address iToken, uint256 borrowSpeed); /// @notice Emitted when iToken's Distribution supply speed is updated event DistributionSupplySpeedUpdated(address iToken, uint256 supplySpeed); /// @notice Emitted when iToken's Distribution factor is changed by admin event NewDistributionFactor( address iToken, uint256 oldDistributionFactorMantissa, uint256 newDistributionFactorMantissa ); function updateDistributionState(address _iToken, bool _isBorrow) external; function updateReward( address _iToken, address _account, bool _isBorrow ) external; function updateRewardBatch( address[] memory _holders, address[] memory _iTokens ) external; function claimReward(address[] memory _holders, address[] memory _iTokens) external; function claimAllReward(address[] memory _holders) external; function claimRewards( address[] memory _holders, address[] memory _suppliediTokens, address[] memory _borrowediTokens ) external; /// @notice Emitted when reward of amount is distributed into account event RewardDistributed( address iToken, address account, uint256 amount, uint256 accountIndex ); }
//SPDX-License-Identifier: MIT pragma solidity 0.6.12; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {_setPendingOwner} and {_acceptOwner}. */ contract Ownable { /** * @dev Returns the address of the current owner. */ address payable public owner; /** * @dev Returns the address of the current pending owner. */ address payable public pendingOwner; event NewOwner(address indexed previousOwner, address indexed newOwner); event NewPendingOwner( address indexed oldPendingOwner, address indexed newPendingOwner ); /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner == msg.sender, "onlyOwner: caller is not the owner"); _; } /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal { owner = msg.sender; emit NewOwner(address(0), msg.sender); } /** * @notice Base on the inputing parameter `newPendingOwner` to check the exact error reason. * @dev Transfer contract control to a new owner. The newPendingOwner must call `_acceptOwner` to finish the transfer. * @param newPendingOwner New pending owner. */ function _setPendingOwner(address payable newPendingOwner) external onlyOwner { require( newPendingOwner != address(0) && newPendingOwner != pendingOwner, "_setPendingOwner: New owenr can not be zero address and owner has been set!" ); // Gets current owner. address oldPendingOwner = pendingOwner; // Sets new pending owner. pendingOwner = newPendingOwner; emit NewPendingOwner(oldPendingOwner, newPendingOwner); } /** * @dev Accepts the admin rights, but only for pendingOwenr. */ function _acceptOwner() external { require( msg.sender == pendingOwner, "_acceptOwner: Only for pending owner!" ); // Gets current values for events. address oldOwner = owner; address oldPendingOwner = pendingOwner; // Set the new contract owner. owner = pendingOwner; // Clear the pendingOwner. pendingOwner = address(0); emit NewOwner(oldOwner, owner); emit NewPendingOwner(oldPendingOwner, pendingOwner); } uint256[50] private __gap; }
//SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; library SafeRatioMath { using SafeMathUpgradeable for uint256; uint256 private constant BASE = 10**18; uint256 private constant DOUBLE = 10**36; function divup(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x.add(y.sub(1)).div(y); } function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x.mul(y).div(BASE); } function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x.mul(BASE).div(y); } function rdivup(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x.mul(BASE).add(y.sub(1)).div(y); } function tmul( uint256 x, uint256 y, uint256 z ) internal pure returns (uint256 result) { result = x.mul(y).mul(z).div(DOUBLE); } function rpow( uint256 x, uint256 n, uint256 base ) internal pure returns (uint256 z) { assembly { switch x case 0 { switch n case 0 { z := base } default { z := 0 } } default { switch mod(n, 2) case 0 { z := base } default { z := x } let half := div(base, 2) // for rounding. for { n := div(n, 2) } n { n := div(n, 2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0, 0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0, 0) } x := div(xxRound, base) if mod(n, 2) { let zx := mul(z, x) if and( iszero(iszero(x)), iszero(eq(div(zx, x), z)) ) { revert(0, 0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0, 0) } z := div(zxRound, base) } } } } } }
//SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "./IiToken.sol"; interface IPriceOracle { /** * @notice Get the underlying price of a iToken asset * @param _iToken The iToken to get the underlying price of * @return The underlying asset price mantissa (scaled by 1e18). * Zero means the price is unavailable. */ function getUnderlyingPrice(address _iToken) external view returns (uint256); /** * @notice Get the price of a underlying asset * @param _iToken The iToken to get the underlying price of * @return The underlying asset price mantissa (scaled by 1e18). * Zero means the price is unavailable and whether the price is valid. */ function getUnderlyingPriceAndStatus(address _iToken) external view returns (uint256, bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require( !_initialized, "Initializable: contract is already initialized" ); _; _initialized = true; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./IERC20Upgradeable.sol"; import "../../math/SafeMathUpgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using SafeMathUpgradeable for uint256; using AddressUpgradeable for address; function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
//SPDX-License-Identifier: MIT pragma solidity 0.6.12; interface IControllerAdminInterface { /// @notice Emitted when an admin supports a market event MarketAdded( address iToken, uint256 collateralFactor, uint256 borrowFactor, uint256 supplyCapacity, uint256 borrowCapacity, uint256 distributionFactor ); function _addMarket( address _iToken, uint256 _collateralFactor, uint256 _borrowFactor, uint256 _supplyCapacity, uint256 _borrowCapacity, uint256 _distributionFactor ) external; /// @notice Emitted when new price oracle is set event NewPriceOracle(address oldPriceOracle, address newPriceOracle); function _setPriceOracle(address newOracle) external; /// @notice Emitted when close factor is changed by admin event NewCloseFactor( uint256 oldCloseFactorMantissa, uint256 newCloseFactorMantissa ); function _setCloseFactor(uint256 newCloseFactorMantissa) external; /// @notice Emitted when liquidation incentive is changed by admin event NewLiquidationIncentive( uint256 oldLiquidationIncentiveMantissa, uint256 newLiquidationIncentiveMantissa ); function _setLiquidationIncentive(uint256 newLiquidationIncentiveMantissa) external; /// @notice Emitted when iToken's collateral factor is changed by admin event NewCollateralFactor( address iToken, uint256 oldCollateralFactorMantissa, uint256 newCollateralFactorMantissa ); function _setCollateralFactor( address iToken, uint256 newCollateralFactorMantissa ) external; /// @notice Emitted when iToken's borrow factor is changed by admin event NewBorrowFactor( address iToken, uint256 oldBorrowFactorMantissa, uint256 newBorrowFactorMantissa ); function _setBorrowFactor(address iToken, uint256 newBorrowFactorMantissa) external; /// @notice Emitted when iToken's borrow capacity is changed by admin event NewBorrowCapacity( address iToken, uint256 oldBorrowCapacity, uint256 newBorrowCapacity ); function _setBorrowCapacity(address iToken, uint256 newBorrowCapacity) external; /// @notice Emitted when iToken's supply capacity is changed by admin event NewSupplyCapacity( address iToken, uint256 oldSupplyCapacity, uint256 newSupplyCapacity ); function _setSupplyCapacity(address iToken, uint256 newSupplyCapacity) external; /// @notice Emitted when pause guardian is changed by admin event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); function _setPauseGuardian(address newPauseGuardian) external; /// @notice Emitted when mint is paused/unpaused by admin or pause guardian event MintPaused(address iToken, bool paused); function _setMintPaused(address iToken, bool paused) external; function _setAllMintPaused(bool paused) external; /// @notice Emitted when redeem is paused/unpaused by admin or pause guardian event RedeemPaused(address iToken, bool paused); function _setRedeemPaused(address iToken, bool paused) external; function _setAllRedeemPaused(bool paused) external; /// @notice Emitted when borrow is paused/unpaused by admin or pause guardian event BorrowPaused(address iToken, bool paused); function _setBorrowPaused(address iToken, bool paused) external; function _setAllBorrowPaused(bool paused) external; /// @notice Emitted when transfer is paused/unpaused by admin or pause guardian event TransferPaused(bool paused); function _setTransferPaused(bool paused) external; /// @notice Emitted when seize is paused/unpaused by admin or pause guardian event SeizePaused(bool paused); function _setSeizePaused(bool paused) external; function _setiTokenPaused(address iToken, bool paused) external; function _setProtocolPaused(bool paused) external; event NewRewardDistributor( address oldRewardDistributor, address _newRewardDistributor ); function _setRewardDistributor(address _newRewardDistributor) external; } interface IControllerPolicyInterface { function beforeMint( address iToken, address account, uint256 mintAmount ) external; function afterMint( address iToken, address minter, uint256 mintAmount, uint256 mintedAmount ) external; function beforeRedeem( address iToken, address redeemer, uint256 redeemAmount ) external; function afterRedeem( address iToken, address redeemer, uint256 redeemAmount, uint256 redeemedAmount ) external; function beforeBorrow( address iToken, address borrower, uint256 borrowAmount ) external; function afterBorrow( address iToken, address borrower, uint256 borrowedAmount ) external; function beforeRepayBorrow( address iToken, address payer, address borrower, uint256 repayAmount ) external; function afterRepayBorrow( address iToken, address payer, address borrower, uint256 repayAmount ) external; function beforeLiquidateBorrow( address iTokenBorrowed, address iTokenCollateral, address liquidator, address borrower, uint256 repayAmount ) external; function afterLiquidateBorrow( address iTokenBorrowed, address iTokenCollateral, address liquidator, address borrower, uint256 repaidAmount, uint256 seizedAmount ) external; function beforeSeize( address iTokenBorrowed, address iTokenCollateral, address liquidator, address borrower, uint256 seizeAmount ) external; function afterSeize( address iTokenBorrowed, address iTokenCollateral, address liquidator, address borrower, uint256 seizedAmount ) external; function beforeTransfer( address iToken, address from, address to, uint256 amount ) external; function afterTransfer( address iToken, address from, address to, uint256 amount ) external; function beforeFlashloan( address iToken, address to, uint256 amount ) external; function afterFlashloan( address iToken, address to, uint256 amount ) external; } interface IControllerAccountEquityInterface { function calcAccountEquity(address account) external view returns ( uint256, uint256, uint256, uint256 ); function liquidateCalculateSeizeTokens( address iTokenBorrowed, address iTokenCollateral, uint256 actualRepayAmount ) external view returns (uint256); } interface IControllerAccountInterface { function hasEnteredMarket(address account, address iToken) external view returns (bool); function getEnteredMarkets(address account) external view returns (address[] memory); /// @notice Emitted when an account enters a market event MarketEntered(address iToken, address account); function enterMarkets(address[] calldata iTokens) external returns (bool[] memory); function enterMarketFromiToken(address _market, address _account) external; /// @notice Emitted when an account exits a market event MarketExited(address iToken, address account); function exitMarkets(address[] calldata iTokens) external returns (bool[] memory); /// @notice Emitted when an account add a borrow asset event BorrowedAdded(address iToken, address account); /// @notice Emitted when an account remove a borrow asset event BorrowedRemoved(address iToken, address account); function hasBorrowed(address account, address iToken) external view returns (bool); function getBorrowedAssets(address account) external view returns (address[] memory); } interface IControllerInterface is IControllerAdminInterface, IControllerPolicyInterface, IControllerAccountEquityInterface, IControllerAccountInterface { /** * @notice Security checks when updating the comptroller of a market, always expect to return true. */ function isController() external view returns (bool); /** * @notice Return all of the iTokens * @return The list of iToken addresses */ function getAlliTokens() external view returns (address[] memory); /** * @notice Check whether a iToken is listed in controller * @param _iToken The iToken to check for * @return true if the iToken is listed otherwise false */ function hasiToken(address _iToken) external view returns (bool); /** * @return Return the distributor contract address */ function rewardDistributor() external returns (address); }
//SPDX-License-Identifier: MIT pragma solidity 0.6.12; interface IRewardDistributor { function _setRewardToken(address newRewardToken) external; /// @notice Emitted reward token address is changed by admin event NewRewardToken(address oldRewardToken, address newRewardToken); function _addRecipient(address _iToken, uint256 _distributionFactor) external; event NewRecipient(address iToken, uint256 distributionFactor); /// @notice Emitted when mint is paused/unpaused by admin event Paused(bool paused); function _pause() external; function _unpause(uint256 _borrowSpeed, uint256 _supplySpeed) external; /// @notice Emitted when Global Distribution speed for both supply and borrow are updated event GlobalDistributionSpeedsUpdated( uint256 borrowSpeed, uint256 supplySpeed ); function _setGlobalDistributionSpeeds( uint256 borrowSpeed, uint256 supplySpeed ) external; /// @notice Emitted when iToken's Distribution speed is updated event DistributionSpeedsUpdated( address iToken, uint256 borrowSpeed, uint256 supplySpeed ); function updateDistributionSpeed() external; /// @notice Emitted when iToken's Distribution factor is changed by admin event NewDistributionFactor( address iToken, uint256 oldDistributionFactorMantissa, uint256 newDistributionFactorMantissa ); function _setDistributionFactors( address[] calldata iToken, uint256[] calldata distributionFactors ) external; function updateDistributionState(address _iToken, bool _isBorrow) external; function updateReward( address _iToken, address _account, bool _isBorrow ) external; function updateRewardBatch( address[] memory _holders, address[] memory _iTokens ) external; function claimReward(address[] memory _holders, address[] memory _iTokens) external; function claimAllReward(address[] memory _holders) external; /// @notice Emitted when reward of amount is distributed into account event RewardDistributed( address iToken, address account, uint256 amount, uint256 accountIndex ); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSetUpgradeable { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(value))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(value))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(value))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint256(_at(set._inner, index))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } }
//SPDX-License-Identifier: MIT pragma solidity 0.6.12; /** * @title dForce Lending Protocol's InterestRateModel Interface. * @author dForce Team. */ interface IInterestRateModelInterface { function isInterestRateModel() external view returns (bool); /** * @dev Calculates the current borrow interest rate per block. * @param cash The total amount of cash the market has. * @param borrows The total amount of borrows the market has. * @param reserves The total amnount of reserves the market has. * @return The borrow rate per block (as a percentage, and scaled by 1e18). */ function getBorrowRate( uint256 cash, uint256 borrows, uint256 reserves ) external view returns (uint256); /** * @dev Calculates the current supply interest rate per block. * @param cash The total amount of cash the market has. * @param borrows The total amount of borrows the market has. * @param reserves The total amnount of reserves the market has. * @param reserveRatio The current reserve factor the market has. * @return The supply rate per block (as a percentage, and scaled by 1e18). */ function getSupplyRate( uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveRatio ) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when 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. */ library SafeMathUpgradeable { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ 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 Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"iToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowSpeed","type":"uint256"}],"name":"DistributionBorrowSpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"iToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"supplySpeed","type":"uint256"}],"name":"DistributionSupplySpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"borrowSpeed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supplySpeed","type":"uint256"}],"name":"GlobalDistributionSpeedsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"iToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldDistributionFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDistributionFactorMantissa","type":"uint256"}],"name":"NewDistributionFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldPendingOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newPendingOwner","type":"address"}],"name":"NewPendingOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"iToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"distributionFactor","type":"uint256"}],"name":"NewRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRewardToken","type":"address"},{"indexed":false,"internalType":"address","name":"newRewardToken","type":"address"}],"name":"NewRewardToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldTreasury","type":"address"},{"indexed":false,"internalType":"address","name":"newTreasury","type":"address"}],"name":"NewTreasury","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"iToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountIndex","type":"uint256"}],"name":"RewardDistributed","type":"event"},{"inputs":[],"name":"_acceptOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_iToken","type":"address"},{"internalType":"uint256","name":"_distributionFactor","type":"uint256"}],"name":"_addRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"_pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_iTokens","type":"address[]"},{"internalType":"uint256[]","name":"_borrowSpeeds","type":"uint256[]"}],"name":"_setDistributionBorrowSpeeds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_borrowiTokens","type":"address[]"},{"internalType":"uint256[]","name":"_borrowSpeeds","type":"uint256[]"},{"internalType":"address[]","name":"_supplyiTokens","type":"address[]"},{"internalType":"uint256[]","name":"_supplySpeeds","type":"uint256[]"}],"name":"_setDistributionSpeeds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_iTokens","type":"address[]"},{"internalType":"uint256[]","name":"_supplySpeeds","type":"uint256[]"}],"name":"_setDistributionSupplySpeeds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newPendingOwner","type":"address"}],"name":"_setPendingOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newRewardToken","type":"address"}],"name":"_setRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newTreasury","type":"address"}],"name":"_setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_borrowiTokens","type":"address[]"},{"internalType":"uint256[]","name":"_borrowSpeeds","type":"uint256[]"},{"internalType":"address[]","name":"_supplyiTokens","type":"address[]"},{"internalType":"uint256[]","name":"_supplySpeeds","type":"uint256[]"}],"name":"_unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_holders","type":"address[]"}],"name":"claimAllReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_holders","type":"address[]"},{"internalType":"address[]","name":"_iTokens","type":"address[]"}],"name":"claimReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_holders","type":"address[]"},{"internalType":"address[]","name":"_suppliediTokens","type":"address[]"},{"internalType":"address[]","name":"_borrowediTokens","type":"address[]"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract Controller","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"distributionBorrowState","outputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"block","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"distributionBorrowerIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"distributionFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"distributionSpeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"distributionSupplierIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"distributionSupplySpeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"distributionSupplyState","outputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"block","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalDistributionSpeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalDistributionSupplySpeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Controller","name":"_controller","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"rescueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"reward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_iToken","type":"address"},{"internalType":"bool","name":"_isBorrow","type":"bool"}],"name":"updateDistributionState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_iToken","type":"address"},{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_isBorrow","type":"bool"}],"name":"updateReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_holders","type":"address[]"},{"internalType":"address[]","name":"_iTokens","type":"address[]"}],"name":"updateRewardBatch","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5061342d806100206000396000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c80638de482191161011a578063caece2fe116100ad578063f7c618c11161007c578063f7c618c114610c62578063f7d6bdf214610c6a578063fc4d33f914610c90578063fca6269914610c98578063ff0427ca14610df657610206565b8063caece2fe14610bf6578063ddcbb24514610c24578063e30c397814610c52578063f77c479114610c5a57610206565b8063b37fd190116100e9578063b37fd190146109b9578063bdfa0c99146109ef578063c4d66de814610b12578063c88bf5e814610b3857610206565b80638de48219146107c0578063a1fcb8fc146107e6578063a82e84e9146107ee578063acea9d4d1461099357610206565b80635c267f6d1161019d5780636353586b1161016c5780636353586b1461070e5780636864e3ea146107345780636e96dfd71461075a5780637d3572fd146107805780638da5cb5b146107b857610206565b80635c267f6d146105a35780635c975abb146105ab5780635f1c8665146105c757806361d027b3146106ea57610206565b806338f1f57f116101d957806338f1f57f146102ba57806342e772841461041857806353889535146104b95780635658fec31461057757610206565b806320f18edd1461020b5780632a08922c1461024a578063320b2ad914610272578063340c3df81461027a575b600080fd5b6102316004803603602081101561022157600080fd5b50356001600160a01b0316610e1c565b6040805192835260208301919091528051918290030190f35b6102706004803603602081101561026057600080fd5b50356001600160a01b0316610e35565b005b610270610f63565b6102a86004803603604081101561029057600080fd5b506001600160a01b038135811691602001351661112b565b60408051918252519081900360200190f35b610270600480360360808110156102d057600080fd5b810190602081018135600160201b8111156102ea57600080fd5b8201836020820111156102fc57600080fd5b803590602001918460208302840111600160201b8311171561031d57600080fd5b919390929091602081019035600160201b81111561033a57600080fd5b82018360208201111561034c57600080fd5b803590602001918460208302840111600160201b8311171561036d57600080fd5b919390929091602081019035600160201b81111561038a57600080fd5b82018360208201111561039c57600080fd5b803590602001918460208302840111600160201b831117156103bd57600080fd5b919390929091602081019035600160201b8111156103da57600080fd5b8201836020820111156103ec57600080fd5b803590602001918460208302840111600160201b8311171561040d57600080fd5b509092509050611148565b6102706004803603602081101561042e57600080fd5b810190602081018135600160201b81111561044857600080fd5b82018360208201111561045a57600080fd5b803590602001918460208302840111600160201b8311171561047b57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506112c0945050505050565b610270600480360360408110156104cf57600080fd5b810190602081018135600160201b8111156104e957600080fd5b8201836020820111156104fb57600080fd5b803590602001918460208302840111600160201b8311171561051c57600080fd5b919390929091602081019035600160201b81111561053957600080fd5b82018360208201111561054b57600080fd5b803590602001918460208302840111600160201b8311171561056c57600080fd5b5090925090506113e1565b6102706004803603604081101561058d57600080fd5b506001600160a01b0381351690602001356114f3565b6102a86115e0565b6105b36115e6565b604080519115158252519081900360200190f35b610270600480360360408110156105dd57600080fd5b810190602081018135600160201b8111156105f757600080fd5b82018360208201111561060957600080fd5b803590602001918460208302840111600160201b8311171561062a57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561067957600080fd5b82018360208201111561068b57600080fd5b803590602001918460208302840111600160201b831117156106ac57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506115f6945050505050565b6106f2611691565b604080516001600160a01b039092168252519081900360200190f35b6102a86004803603602081101561072457600080fd5b50356001600160a01b03166116a0565b6102316004803603602081101561074a57600080fd5b50356001600160a01b03166116b2565b6102706004803603602081101561077057600080fd5b50356001600160a01b03166116cb565b6102706004803603606081101561079657600080fd5b506001600160a01b0381358116916020810135909116906040013515156117cc565b6106f26117d7565b6102a8600480360360208110156107d657600080fd5b50356001600160a01b03166117eb565b6102a86117fd565b6102706004803603606081101561080457600080fd5b810190602081018135600160201b81111561081e57600080fd5b82018360208201111561083057600080fd5b803590602001918460208302840111600160201b8311171561085157600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156108a057600080fd5b8201836020820111156108b257600080fd5b803590602001918460208302840111600160201b831117156108d357600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561092257600080fd5b82018360208201111561093457600080fd5b803590602001918460208302840111600160201b8311171561095557600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611803945050505050565b6102a8600480360360208110156109a957600080fd5b50356001600160a01b03166118a0565b610270600480360360608110156109cf57600080fd5b506001600160a01b038135811691602081013591604090910135166118b2565b61027060048036036040811015610a0557600080fd5b810190602081018135600160201b811115610a1f57600080fd5b820183602082011115610a3157600080fd5b803590602001918460208302840111600160201b83111715610a5257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610aa157600080fd5b820183602082011115610ab357600080fd5b803590602001918460208302840111600160201b83111715610ad457600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955061190f945050505050565b61027060048036036020811015610b2857600080fd5b50356001600160a01b031661199e565b61027060048036036040811015610b4e57600080fd5b810190602081018135600160201b811115610b6857600080fd5b820183602082011115610b7a57600080fd5b803590602001918460208302840111600160201b83111715610b9b57600080fd5b919390929091602081019035600160201b811115610bb857600080fd5b820183602082011115610bca57600080fd5b803590602001918460208302840111600160201b83111715610beb57600080fd5b509092509050611a70565b61027060048036036040811015610c0c57600080fd5b506001600160a01b0381351690602001351515611b74565b6102a860048036036040811015610c3a57600080fd5b506001600160a01b0381358116916020013516611b95565b6106f2611bb2565b6106f2611bc1565b6106f2611bd0565b61027060048036036020811015610c8057600080fd5b50356001600160a01b0316611bdf565b610270611d0f565b61027060048036036080811015610cae57600080fd5b810190602081018135600160201b811115610cc857600080fd5b820183602082011115610cda57600080fd5b803590602001918460208302840111600160201b83111715610cfb57600080fd5b919390929091602081019035600160201b811115610d1857600080fd5b820183602082011115610d2a57600080fd5b803590602001918460208302840111600160201b83111715610d4b57600080fd5b919390929091602081019035600160201b811115610d6857600080fd5b820183602082011115610d7a57600080fd5b803590602001918460208302840111600160201b83111715610d9b57600080fd5b919390929091602081019035600160201b811115610db857600080fd5b820183602082011115610dca57600080fd5b803590602001918460208302840111600160201b83111715610deb57600080fd5b509092509050611e06565b6102a860048036036020811015610e0c57600080fd5b50356001600160a01b0316611e5e565b6038602052600090815260409020805460019091015482565b60005461010090046001600160a01b03163314610e835760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b6040546001600160a01b0390811690821615801590610eb45750806001600160a01b0316826001600160a01b031614155b610f05576040805162461bcd60e51b815260206004820152601860248201527f5472656173757279206164647265737320696e76616c69640000000000000000604482015290519081900360640190fd5b604080546001600160a01b0319166001600160a01b03848116918217835582519084168152602081019190915281517f567657fa3f286518b318f4a29870674f433f622fdfc819691acb13105b228225929181900390910190a15050565b60005461010090046001600160a01b03163314610fb15760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b603454604080516360a8a93160e01b815290516060926001600160a01b0316916360a8a931916004808301926000929190829003018186803b158015610ff657600080fd5b505afa15801561100a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561103357600080fd5b8101908080516040519392919084600160201b82111561105257600080fd5b90830190602082018581111561106757600080fd5b82518660208202830111600160201b8211171561108357600080fd5b82525081516020918201928201910280838360005b838110156110b0578181015183820152602001611098565b50505050905001604052505050905060008151905060005b81811015611114576110ee8382815181106110df57fe5b60200260200101516000611e70565b61110c8382815181106110fd57fe5b60200260200101516000611f9a565b6001016110c8565b5061111d6120c4565b61112760016122d4565b5050565b603b60209081526000928352604080842090915290825290205481565b60005461010090046001600160a01b031633146111965760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b603d54600160a01b900460ff16156111df5760405162461bcd60e51b81526004018080602001828103825260218152602001806132b16021913960400191505060405180910390fd5b6112ae88888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a91829185019084908082843760009201919091525050604080516020808b0282810182019093528a82529093508a92508991829185019084908082843760009201919091525050604080516020808a0282810182019093528982529093508992508891829185019084908082843760009201919091525061232792505050565b6112b66120c4565b5050505050505050565b6113de81603460009054906101000a90046001600160a01b03166001600160a01b03166360a8a9316040518163ffffffff1660e01b815260040160006040518083038186803b15801561131257600080fd5b505afa158015611326573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561134f57600080fd5b8101908080516040519392919084600160201b82111561136e57600080fd5b90830190602082018581111561138357600080fd5b82518660208202830111600160201b8211171561139f57600080fd5b82525081516020918201928201910280838360005b838110156113cc5781810151838201526020016113b4565b5050505090500160405250505061190f565b50565b60005461010090046001600160a01b0316331461142f5760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b603d54600160a01b900460ff16156114785760405162461bcd60e51b81526004018080602001828103825260288152602001806132896028913960400191505060405180910390fd5b6114e58484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061233792505050565b6114ed6120c4565b50505050565b6034546001600160a01b0316331461153c5760405162461bcd60e51b815260040180806020018281038252602c81526020018061316a602c913960400191505060405180910390fd5b6001600160a01b0382166000818152603760209081526040808320859055805180820182528381524381840181815286865260388552838620925183555160019283015582518084018452858152808501918252868652603985529483902094518555519301929092558151928352820183905280517f182e1c0b34607d1b7c3312ff9a78e613c0a4c045d1460fd236374d04b5c2954f9281900390910190a15050565b603f5481565b603d54600160a01b900460ff1681565b60005b815181101561168c57600082828151811061161057fe5b602002602001015190506116258160006123bc565b6116308160016123bc565b60005b84518110156116825761165b8286838151811061164c57fe5b602002602001015160006126c8565b61167a8286838151811061166b57fe5b602002602001015160016126c8565b600101611633565b50506001016115f9565b505050565b6040546001600160a01b031681565b603c6020526000908152604090205481565b6039602052600090815260409020805460019091015482565b60005461010090046001600160a01b031633146117195760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b6001600160a01b0381161580159061173f57506001546001600160a01b03828116911614155b61177a5760405162461bcd60e51b815260040180806020018281038252604b815260200180613196604b913960600191505060405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907fb3d55174552271a4f1aaf36b72f50381e892171636b3fb5447fe00e995e7a37b90600090a35050565b61168c8383836126c8565b60005461010090046001600160a01b031681565b603e6020526000908152604090205481565b60355481565b61180f83836000612a7f565b61181b83826001612a7f565b60005b83518110156114ed57600084828151811061183557fe5b6020908102919091018101516001600160a01b0381166000908152603c9092526040909120549091508015611896576001600160a01b038083166000908152603c60205260408082209190915554603d546118969290811691168484612ae9565b505060010161181e565b60376020526000908152604090205481565b6040546001600160a01b031633146118fb5760405162461bcd60e51b815260040180806020018281038252602c81526020018061337d602c913960400191505060405180910390fd5b61168c6001600160a01b0384168284612b43565b61191982826115f6565b60005b825181101561168c57600083828151811061193357fe5b6020908102919091018101516001600160a01b0381166000908152603c9092526040909120549091508015611994576001600160a01b038083166000908152603c60205260408082209190915554603d546119949290811691168484612ae9565b505060010161191c565b60005460ff16156119e05760405162461bcd60e51b815260040180806020018281038252602e8152602001806132d2602e913960400191505060405180910390fd5b6001600160a01b038116611a255760405162461bcd60e51b815260040180806020018281038252603a815260200180613343603a913960400191505060405180910390fd5b611a2d612b95565b603480546001600160a01b039092166001600160a01b0319909216919091179055603d805460ff60a01b1916600160a01b1790556000805460ff19166001179055565b60005461010090046001600160a01b03163314611abe5760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b603d54600160a01b900460ff1615611b075760405162461bcd60e51b815260040180806020018281038252602881526020018061320e6028913960400191505060405180910390fd5b6114e584848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808802828101820190935287825290935087925086918291850190849080828437600092019190915250612bdd92505050565b603d54600160a01b900460ff1615611b8b57611127565b61112782826123bc565b603a60209081526000928352604080842090915290825290205481565b6001546001600160a01b031681565b6034546001600160a01b031681565b603d546001600160a01b031681565b60005461010090046001600160a01b03163314611c2d5760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b603d546001600160a01b0390811690821615801590611c5e5750806001600160a01b0316826001600160a01b031614155b611caf576040805162461bcd60e51b815260206004820152601c60248201527f52657761726420746f6b656e206164647265737320696e76616c696400000000604482015290519081900360640190fd5b603d80546001600160a01b0319166001600160a01b03848116918217909255604080519284168352602083019190915280517f7bdb05f6c3fc55361bbc64ceeb084448a135da92bade17eb83ea386a431aa4929281900390910190a15050565b6001546001600160a01b03163314611d585760405162461bcd60e51b81526004018080602001828103825260258152602001806133a96025913960400191505060405180910390fd5b60008054600180546001600160a01b03818116610100818102610100600160a81b03198716178088556001600160a01b031990941690945560405194849004821695909493909204169184917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a36001546040516001600160a01b03918216918316907fb3d55174552271a4f1aaf36b72f50381e892171636b3fb5447fe00e995e7a37b90600090a35050565b60005461010090046001600160a01b03163314611e545760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b6111df60006122d4565b60366020526000908152604090205481565b60345460408051632214743160e11b81526001600160a01b03858116600483015291519190921691634428e862916024808301926020929190829003018186803b158015611ebd57600080fd5b505afa158015611ed1573d6000803e3d6000fd5b505050506040513d6020811015611ee757600080fd5b5051611f36576040805162461bcd60e51b8152602060048201526019602482015278151bdad95b881a185cc81b9bdd081899595b881b1a5cdd1959603a1b604482015290519081900360640190fd5b611f418260016123bc565b6001600160a01b0382166000818152603660209081526040918290208490558151928352820183905280517f46226744ccd103a90ece5fda635bfa1900432eb5772654600cf4bcb165ed8d509281900390910190a15050565b60345460408051632214743160e11b81526001600160a01b03858116600483015291519190921691634428e862916024808301926020929190829003018186803b158015611fe757600080fd5b505afa158015611ffb573d6000803e3d6000fd5b505050506040513d602081101561201157600080fd5b5051612060576040805162461bcd60e51b8152602060048201526019602482015278151bdad95b881a185cc81b9bdd081899595b881b1a5cdd1959603a1b604482015290519081900360640190fd5b61206b8260006123bc565b6001600160a01b0382166000818152603e60209081526040918290208490558151928352820183905280517f14746676db6ada1c13245bd79a684dfbc737414c26141ccf51bec2e655aa16a39281900390910190a15050565b603454604080516360a8a93160e01b815290516060926001600160a01b0316916360a8a931916004808301926000929190829003018186803b15801561210957600080fd5b505afa15801561211d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561214657600080fd5b8101908080516040519392919084600160201b82111561216557600080fd5b90830190602082018581111561217a57600080fd5b82518660208202830111600160201b8211171561219657600080fd5b82525081516020918201928201910280838360005b838110156121c35781810151838201526020016121ab565b50505050905001604052505050905060008151905060008060005b8381101561228857612231603660008784815181106121f957fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205484612c6290919063ffffffff16565b925061227e603e600087848151811061224657fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205483612c6290919063ffffffff16565b91506001016121de565b506035829055603f819055604080518381526020810183905281517fa18693b6d74b98a33c568fa3daacae7226d03916596709a21cd5e74ba435fd83929181900390910190a150505050565b603d8054821515600160a01b810260ff60a01b199092169190911790915560408051918252517f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd29181900360200190a150565b6123318484612bdd565b6114ed82825b80518251146123775760405162461bcd60e51b815260040180806020018281038252602d8152602001806131e1602d913960400191505060405180910390fd5b815160005b818110156114ed576123b484828151811061239357fe5b60200260200101518483815181106123a757fe5b6020026020010151611f9a565b60010161237c565b60345460408051632214743160e11b81526001600160a01b03858116600483015291519190921691634428e862916024808301926020929190829003018186803b15801561240957600080fd5b505afa15801561241d573d6000803e3d6000fd5b505050506040513d602081101561243357600080fd5b5051612482576040805162461bcd60e51b8152602060048201526019602482015278151bdad95b881a185cc81b9bdd081899595b881b1a5cdd1959603a1b604482015290519081900360640190fd5b6000816124a6576001600160a01b03831660009081526038602052604090206124bf565b6001600160a01b03831660009081526039602052604090205b90506000826124e6576001600160a01b0384166000908152603e6020526040902054612500565b6001600160a01b0384166000908152603660205260409020545b60018301549091504390600090612518908390612cc5565b905060008111801561252a5750600083115b156126b9576000856125a057866001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561256f57600080fd5b505afa158015612583573d6000803e3d6000fd5b505050506040513d602081101561259957600080fd5b505161267a565b61267a876001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156125dc57600080fd5b505afa1580156125f0573d6000803e3d6000fd5b505050506040513d602081101561260657600080fd5b5051604080516308f7a6e360e31b815290516001600160a01b038b16916347bd3718916004808301926020929190829003018186803b15801561264857600080fd5b505afa15801561265c573d6000803e3d6000fd5b505050506040513d602081101561267257600080fd5b505190612d07565b905060006126888584612d25565b9050600080831161269a5760006126a4565b6126a48284612d07565b87549091506126b39082612c62565b87555050505b50600190920191909155505050565b6001600160a01b038216612723576040805162461bcd60e51b815260206004820152601860248201527f496e76616c6964206163636f756e742061646472657373210000000000000000604482015290519081900360640190fd5b60345460408051632214743160e11b81526001600160a01b03868116600483015291519190921691634428e862916024808301926020929190829003018186803b15801561277057600080fd5b505afa158015612784573d6000803e3d6000fd5b505050506040513d602081101561279a57600080fd5b50516127e9576040805162461bcd60e51b8152602060048201526019602482015278151bdad95b881a185cc81b9bdd081899595b881b1a5cdd1959603a1b604482015290519081900360640190fd5b60008060008315612903576001600160a01b03808716600081815260396020908152604080832054603b8352818420958b1684529482529182902054825163aa5af0fd60e01b8152925194975095506128d49363aa5af0fd926004808201939291829003018186803b15801561285e57600080fd5b505afa158015612872573d6000803e3d6000fd5b505050506040513d602081101561288857600080fd5b5051604080516395dd919360e01b81526001600160a01b0389811660048301529151918a16916395dd919391602480820192602092909190829003018186803b15801561264857600080fd5b6001600160a01b038088166000908152603b60209081526040808320938a1683529290522084905590506129cb565b6001600160a01b03808716600081815260386020908152604080832054603a8352818420958b16808552958352928190205481516370a0823160e01b815260048101969096529051929750955091926370a08231926024808301939192829003018186803b15801561297457600080fd5b505afa158015612988573d6000803e3d6000fd5b505050506040513d602081101561299e57600080fd5b50516001600160a01b038088166000908152603a60209081526040808320938a1683529290522084905590505b60006129d78484612cc5565b905060006129e58383612d7e565b905080156112b6576001600160a01b0387166000908152603c6020526040902054612a109082612c62565b6001600160a01b038089166000818152603c6020908152604091829020949094558051928c168352928201528082018390526060810186905290517fd53ea54cd361f7c49d3ca11bfcb71b4783448ade1b32513783ee19776f2adf319181900360800190a15050505050505050565b60005b82518110156114ed576000838281518110612a9957fe5b60200260200101519050612aad81846123bc565b60005b8551811015612adf57612ad782878381518110612ac957fe5b6020026020010151866126c8565b600101612ab0565b5050600101612a82565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526114ed908590612d96565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261168c908490612d96565b60008054610100600160a81b0319163361010081029190911782556040519091907f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b2364908290a3565b8051825114612c1d5760405162461bcd60e51b815260040180806020018281038252602d815260200180613236602d913960400191505060405180910390fd5b815160005b818110156114ed57612c5a848281518110612c3957fe5b6020026020010151848381518110612c4d57fe5b6020026020010151611e70565b600101612c22565b600082820183811015612cbc576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b6000612cbc83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612e47565b6000612cbc82612d1f85670de0b6b3a7640000612d25565b90612ee3565b600082612d3457506000612cbf565b82820282848281612d4157fe5b0414612cbc5760405162461bcd60e51b81526004018080602001828103825260218152602001806133006021913960400191505060405180910390fd5b6000612cbc670de0b6b3a7640000612d1f8585612d25565b6060612deb826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612f259092919063ffffffff16565b80519091501561168c57808060200190516020811015612e0a57600080fd5b505161168c5760405162461bcd60e51b815260040180806020018281038252602a8152602001806133ce602a913960400191505060405180910390fd5b60008184841115612ed65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612e9b578181015183820152602001612e83565b50505050905090810190601f168015612ec85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50508183035b9392505050565b6000612cbc83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612f3c565b6060612f348484600085612fa1565b949350505050565b60008183612f8b5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612e9b578181015183820152602001612e83565b506000838581612f9757fe5b0495945050505050565b606082471015612fe25760405162461bcd60e51b81526004018080602001828103825260268152602001806132636026913960400191505060405180910390fd5b612feb856130fd565b61303c576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b6020831061307b5780518252601f19909201916020918201910161305c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146130dd576040519150601f19603f3d011682016040523d82523d6000602084013e6130e2565b606091505b50915091506130f2828286613103565b979650505050505050565b3b151590565b60608315613112575081612edc565b8251156131225782518084602001fd5b60405162461bcd60e51b8152602060048201818152845160248401528451859391928392604401919085019080838360008315612e9b578181015183820152602001612e8356fe6f6e6c79436f6e74726f6c6c65723a2063616c6c6572206973206e6f742074686520636f6e74726f6c6c65725f73657450656e64696e674f776e65723a204e6577206f77656e722063616e206e6f74206265207a65726f206164647265737320616e64206f776e657220686173206265656e20736574214c656e677468206f66205f69546f6b656e7320616e64205f737570706c79537065656473206d69736d6174636843616e206e6f74206368616e676520626f72726f7720737065656473207768656e207061757365644c656e677468206f66205f69546f6b656e7320616e64205f626f72726f77537065656473206d69736d61746368416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c43616e206e6f74206368616e676520737570706c7920737065656473207768656e2070617573656443616e206e6f74206368616e676520737065656473207768656e20706175736564496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f776f6e6c794f776e65723a2063616c6c6572206973206e6f7420746865206f776e6572696e697469616c697a653a20636f6e74726f6c6c657220616464726573732073686f756c64206e6f74206265207a65726f206164647265737321726573637565546f6b656e733a2063616e206f6e6c792062652063616c6c65642062792074726561737572795f6163636570744f776e65723a204f6e6c7920666f722070656e64696e67206f776e6572215361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220729164d0dae39142e9e515ddeb7696184456c0a17fd1e6658c7bf9ab6ed9fd5264736f6c634300060c0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102065760003560e01c80638de482191161011a578063caece2fe116100ad578063f7c618c11161007c578063f7c618c114610c62578063f7d6bdf214610c6a578063fc4d33f914610c90578063fca6269914610c98578063ff0427ca14610df657610206565b8063caece2fe14610bf6578063ddcbb24514610c24578063e30c397814610c52578063f77c479114610c5a57610206565b8063b37fd190116100e9578063b37fd190146109b9578063bdfa0c99146109ef578063c4d66de814610b12578063c88bf5e814610b3857610206565b80638de48219146107c0578063a1fcb8fc146107e6578063a82e84e9146107ee578063acea9d4d1461099357610206565b80635c267f6d1161019d5780636353586b1161016c5780636353586b1461070e5780636864e3ea146107345780636e96dfd71461075a5780637d3572fd146107805780638da5cb5b146107b857610206565b80635c267f6d146105a35780635c975abb146105ab5780635f1c8665146105c757806361d027b3146106ea57610206565b806338f1f57f116101d957806338f1f57f146102ba57806342e772841461041857806353889535146104b95780635658fec31461057757610206565b806320f18edd1461020b5780632a08922c1461024a578063320b2ad914610272578063340c3df81461027a575b600080fd5b6102316004803603602081101561022157600080fd5b50356001600160a01b0316610e1c565b6040805192835260208301919091528051918290030190f35b6102706004803603602081101561026057600080fd5b50356001600160a01b0316610e35565b005b610270610f63565b6102a86004803603604081101561029057600080fd5b506001600160a01b038135811691602001351661112b565b60408051918252519081900360200190f35b610270600480360360808110156102d057600080fd5b810190602081018135600160201b8111156102ea57600080fd5b8201836020820111156102fc57600080fd5b803590602001918460208302840111600160201b8311171561031d57600080fd5b919390929091602081019035600160201b81111561033a57600080fd5b82018360208201111561034c57600080fd5b803590602001918460208302840111600160201b8311171561036d57600080fd5b919390929091602081019035600160201b81111561038a57600080fd5b82018360208201111561039c57600080fd5b803590602001918460208302840111600160201b831117156103bd57600080fd5b919390929091602081019035600160201b8111156103da57600080fd5b8201836020820111156103ec57600080fd5b803590602001918460208302840111600160201b8311171561040d57600080fd5b509092509050611148565b6102706004803603602081101561042e57600080fd5b810190602081018135600160201b81111561044857600080fd5b82018360208201111561045a57600080fd5b803590602001918460208302840111600160201b8311171561047b57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506112c0945050505050565b610270600480360360408110156104cf57600080fd5b810190602081018135600160201b8111156104e957600080fd5b8201836020820111156104fb57600080fd5b803590602001918460208302840111600160201b8311171561051c57600080fd5b919390929091602081019035600160201b81111561053957600080fd5b82018360208201111561054b57600080fd5b803590602001918460208302840111600160201b8311171561056c57600080fd5b5090925090506113e1565b6102706004803603604081101561058d57600080fd5b506001600160a01b0381351690602001356114f3565b6102a86115e0565b6105b36115e6565b604080519115158252519081900360200190f35b610270600480360360408110156105dd57600080fd5b810190602081018135600160201b8111156105f757600080fd5b82018360208201111561060957600080fd5b803590602001918460208302840111600160201b8311171561062a57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561067957600080fd5b82018360208201111561068b57600080fd5b803590602001918460208302840111600160201b831117156106ac57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506115f6945050505050565b6106f2611691565b604080516001600160a01b039092168252519081900360200190f35b6102a86004803603602081101561072457600080fd5b50356001600160a01b03166116a0565b6102316004803603602081101561074a57600080fd5b50356001600160a01b03166116b2565b6102706004803603602081101561077057600080fd5b50356001600160a01b03166116cb565b6102706004803603606081101561079657600080fd5b506001600160a01b0381358116916020810135909116906040013515156117cc565b6106f26117d7565b6102a8600480360360208110156107d657600080fd5b50356001600160a01b03166117eb565b6102a86117fd565b6102706004803603606081101561080457600080fd5b810190602081018135600160201b81111561081e57600080fd5b82018360208201111561083057600080fd5b803590602001918460208302840111600160201b8311171561085157600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156108a057600080fd5b8201836020820111156108b257600080fd5b803590602001918460208302840111600160201b831117156108d357600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561092257600080fd5b82018360208201111561093457600080fd5b803590602001918460208302840111600160201b8311171561095557600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611803945050505050565b6102a8600480360360208110156109a957600080fd5b50356001600160a01b03166118a0565b610270600480360360608110156109cf57600080fd5b506001600160a01b038135811691602081013591604090910135166118b2565b61027060048036036040811015610a0557600080fd5b810190602081018135600160201b811115610a1f57600080fd5b820183602082011115610a3157600080fd5b803590602001918460208302840111600160201b83111715610a5257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b811115610aa157600080fd5b820183602082011115610ab357600080fd5b803590602001918460208302840111600160201b83111715610ad457600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955061190f945050505050565b61027060048036036020811015610b2857600080fd5b50356001600160a01b031661199e565b61027060048036036040811015610b4e57600080fd5b810190602081018135600160201b811115610b6857600080fd5b820183602082011115610b7a57600080fd5b803590602001918460208302840111600160201b83111715610b9b57600080fd5b919390929091602081019035600160201b811115610bb857600080fd5b820183602082011115610bca57600080fd5b803590602001918460208302840111600160201b83111715610beb57600080fd5b509092509050611a70565b61027060048036036040811015610c0c57600080fd5b506001600160a01b0381351690602001351515611b74565b6102a860048036036040811015610c3a57600080fd5b506001600160a01b0381358116916020013516611b95565b6106f2611bb2565b6106f2611bc1565b6106f2611bd0565b61027060048036036020811015610c8057600080fd5b50356001600160a01b0316611bdf565b610270611d0f565b61027060048036036080811015610cae57600080fd5b810190602081018135600160201b811115610cc857600080fd5b820183602082011115610cda57600080fd5b803590602001918460208302840111600160201b83111715610cfb57600080fd5b919390929091602081019035600160201b811115610d1857600080fd5b820183602082011115610d2a57600080fd5b803590602001918460208302840111600160201b83111715610d4b57600080fd5b919390929091602081019035600160201b811115610d6857600080fd5b820183602082011115610d7a57600080fd5b803590602001918460208302840111600160201b83111715610d9b57600080fd5b919390929091602081019035600160201b811115610db857600080fd5b820183602082011115610dca57600080fd5b803590602001918460208302840111600160201b83111715610deb57600080fd5b509092509050611e06565b6102a860048036036020811015610e0c57600080fd5b50356001600160a01b0316611e5e565b6038602052600090815260409020805460019091015482565b60005461010090046001600160a01b03163314610e835760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b6040546001600160a01b0390811690821615801590610eb45750806001600160a01b0316826001600160a01b031614155b610f05576040805162461bcd60e51b815260206004820152601860248201527f5472656173757279206164647265737320696e76616c69640000000000000000604482015290519081900360640190fd5b604080546001600160a01b0319166001600160a01b03848116918217835582519084168152602081019190915281517f567657fa3f286518b318f4a29870674f433f622fdfc819691acb13105b228225929181900390910190a15050565b60005461010090046001600160a01b03163314610fb15760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b603454604080516360a8a93160e01b815290516060926001600160a01b0316916360a8a931916004808301926000929190829003018186803b158015610ff657600080fd5b505afa15801561100a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561103357600080fd5b8101908080516040519392919084600160201b82111561105257600080fd5b90830190602082018581111561106757600080fd5b82518660208202830111600160201b8211171561108357600080fd5b82525081516020918201928201910280838360005b838110156110b0578181015183820152602001611098565b50505050905001604052505050905060008151905060005b81811015611114576110ee8382815181106110df57fe5b60200260200101516000611e70565b61110c8382815181106110fd57fe5b60200260200101516000611f9a565b6001016110c8565b5061111d6120c4565b61112760016122d4565b5050565b603b60209081526000928352604080842090915290825290205481565b60005461010090046001600160a01b031633146111965760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b603d54600160a01b900460ff16156111df5760405162461bcd60e51b81526004018080602001828103825260218152602001806132b16021913960400191505060405180910390fd5b6112ae88888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a91829185019084908082843760009201919091525050604080516020808b0282810182019093528a82529093508a92508991829185019084908082843760009201919091525050604080516020808a0282810182019093528982529093508992508891829185019084908082843760009201919091525061232792505050565b6112b66120c4565b5050505050505050565b6113de81603460009054906101000a90046001600160a01b03166001600160a01b03166360a8a9316040518163ffffffff1660e01b815260040160006040518083038186803b15801561131257600080fd5b505afa158015611326573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561134f57600080fd5b8101908080516040519392919084600160201b82111561136e57600080fd5b90830190602082018581111561138357600080fd5b82518660208202830111600160201b8211171561139f57600080fd5b82525081516020918201928201910280838360005b838110156113cc5781810151838201526020016113b4565b5050505090500160405250505061190f565b50565b60005461010090046001600160a01b0316331461142f5760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b603d54600160a01b900460ff16156114785760405162461bcd60e51b81526004018080602001828103825260288152602001806132896028913960400191505060405180910390fd5b6114e58484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061233792505050565b6114ed6120c4565b50505050565b6034546001600160a01b0316331461153c5760405162461bcd60e51b815260040180806020018281038252602c81526020018061316a602c913960400191505060405180910390fd5b6001600160a01b0382166000818152603760209081526040808320859055805180820182528381524381840181815286865260388552838620925183555160019283015582518084018452858152808501918252868652603985529483902094518555519301929092558151928352820183905280517f182e1c0b34607d1b7c3312ff9a78e613c0a4c045d1460fd236374d04b5c2954f9281900390910190a15050565b603f5481565b603d54600160a01b900460ff1681565b60005b815181101561168c57600082828151811061161057fe5b602002602001015190506116258160006123bc565b6116308160016123bc565b60005b84518110156116825761165b8286838151811061164c57fe5b602002602001015160006126c8565b61167a8286838151811061166b57fe5b602002602001015160016126c8565b600101611633565b50506001016115f9565b505050565b6040546001600160a01b031681565b603c6020526000908152604090205481565b6039602052600090815260409020805460019091015482565b60005461010090046001600160a01b031633146117195760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b6001600160a01b0381161580159061173f57506001546001600160a01b03828116911614155b61177a5760405162461bcd60e51b815260040180806020018281038252604b815260200180613196604b913960600191505060405180910390fd5b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907fb3d55174552271a4f1aaf36b72f50381e892171636b3fb5447fe00e995e7a37b90600090a35050565b61168c8383836126c8565b60005461010090046001600160a01b031681565b603e6020526000908152604090205481565b60355481565b61180f83836000612a7f565b61181b83826001612a7f565b60005b83518110156114ed57600084828151811061183557fe5b6020908102919091018101516001600160a01b0381166000908152603c9092526040909120549091508015611896576001600160a01b038083166000908152603c60205260408082209190915554603d546118969290811691168484612ae9565b505060010161181e565b60376020526000908152604090205481565b6040546001600160a01b031633146118fb5760405162461bcd60e51b815260040180806020018281038252602c81526020018061337d602c913960400191505060405180910390fd5b61168c6001600160a01b0384168284612b43565b61191982826115f6565b60005b825181101561168c57600083828151811061193357fe5b6020908102919091018101516001600160a01b0381166000908152603c9092526040909120549091508015611994576001600160a01b038083166000908152603c60205260408082209190915554603d546119949290811691168484612ae9565b505060010161191c565b60005460ff16156119e05760405162461bcd60e51b815260040180806020018281038252602e8152602001806132d2602e913960400191505060405180910390fd5b6001600160a01b038116611a255760405162461bcd60e51b815260040180806020018281038252603a815260200180613343603a913960400191505060405180910390fd5b611a2d612b95565b603480546001600160a01b039092166001600160a01b0319909216919091179055603d805460ff60a01b1916600160a01b1790556000805460ff19166001179055565b60005461010090046001600160a01b03163314611abe5760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b603d54600160a01b900460ff1615611b075760405162461bcd60e51b815260040180806020018281038252602881526020018061320e6028913960400191505060405180910390fd5b6114e584848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808802828101820190935287825290935087925086918291850190849080828437600092019190915250612bdd92505050565b603d54600160a01b900460ff1615611b8b57611127565b61112782826123bc565b603a60209081526000928352604080842090915290825290205481565b6001546001600160a01b031681565b6034546001600160a01b031681565b603d546001600160a01b031681565b60005461010090046001600160a01b03163314611c2d5760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b603d546001600160a01b0390811690821615801590611c5e5750806001600160a01b0316826001600160a01b031614155b611caf576040805162461bcd60e51b815260206004820152601c60248201527f52657761726420746f6b656e206164647265737320696e76616c696400000000604482015290519081900360640190fd5b603d80546001600160a01b0319166001600160a01b03848116918217909255604080519284168352602083019190915280517f7bdb05f6c3fc55361bbc64ceeb084448a135da92bade17eb83ea386a431aa4929281900390910190a15050565b6001546001600160a01b03163314611d585760405162461bcd60e51b81526004018080602001828103825260258152602001806133a96025913960400191505060405180910390fd5b60008054600180546001600160a01b03818116610100818102610100600160a81b03198716178088556001600160a01b031990941690945560405194849004821695909493909204169184917f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b236491a36001546040516001600160a01b03918216918316907fb3d55174552271a4f1aaf36b72f50381e892171636b3fb5447fe00e995e7a37b90600090a35050565b60005461010090046001600160a01b03163314611e545760405162461bcd60e51b81526004018080602001828103825260228152602001806133216022913960400191505060405180910390fd5b6111df60006122d4565b60366020526000908152604090205481565b60345460408051632214743160e11b81526001600160a01b03858116600483015291519190921691634428e862916024808301926020929190829003018186803b158015611ebd57600080fd5b505afa158015611ed1573d6000803e3d6000fd5b505050506040513d6020811015611ee757600080fd5b5051611f36576040805162461bcd60e51b8152602060048201526019602482015278151bdad95b881a185cc81b9bdd081899595b881b1a5cdd1959603a1b604482015290519081900360640190fd5b611f418260016123bc565b6001600160a01b0382166000818152603660209081526040918290208490558151928352820183905280517f46226744ccd103a90ece5fda635bfa1900432eb5772654600cf4bcb165ed8d509281900390910190a15050565b60345460408051632214743160e11b81526001600160a01b03858116600483015291519190921691634428e862916024808301926020929190829003018186803b158015611fe757600080fd5b505afa158015611ffb573d6000803e3d6000fd5b505050506040513d602081101561201157600080fd5b5051612060576040805162461bcd60e51b8152602060048201526019602482015278151bdad95b881a185cc81b9bdd081899595b881b1a5cdd1959603a1b604482015290519081900360640190fd5b61206b8260006123bc565b6001600160a01b0382166000818152603e60209081526040918290208490558151928352820183905280517f14746676db6ada1c13245bd79a684dfbc737414c26141ccf51bec2e655aa16a39281900390910190a15050565b603454604080516360a8a93160e01b815290516060926001600160a01b0316916360a8a931916004808301926000929190829003018186803b15801561210957600080fd5b505afa15801561211d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561214657600080fd5b8101908080516040519392919084600160201b82111561216557600080fd5b90830190602082018581111561217a57600080fd5b82518660208202830111600160201b8211171561219657600080fd5b82525081516020918201928201910280838360005b838110156121c35781810151838201526020016121ab565b50505050905001604052505050905060008151905060008060005b8381101561228857612231603660008784815181106121f957fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205484612c6290919063ffffffff16565b925061227e603e600087848151811061224657fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205483612c6290919063ffffffff16565b91506001016121de565b506035829055603f819055604080518381526020810183905281517fa18693b6d74b98a33c568fa3daacae7226d03916596709a21cd5e74ba435fd83929181900390910190a150505050565b603d8054821515600160a01b810260ff60a01b199092169190911790915560408051918252517f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd29181900360200190a150565b6123318484612bdd565b6114ed82825b80518251146123775760405162461bcd60e51b815260040180806020018281038252602d8152602001806131e1602d913960400191505060405180910390fd5b815160005b818110156114ed576123b484828151811061239357fe5b60200260200101518483815181106123a757fe5b6020026020010151611f9a565b60010161237c565b60345460408051632214743160e11b81526001600160a01b03858116600483015291519190921691634428e862916024808301926020929190829003018186803b15801561240957600080fd5b505afa15801561241d573d6000803e3d6000fd5b505050506040513d602081101561243357600080fd5b5051612482576040805162461bcd60e51b8152602060048201526019602482015278151bdad95b881a185cc81b9bdd081899595b881b1a5cdd1959603a1b604482015290519081900360640190fd5b6000816124a6576001600160a01b03831660009081526038602052604090206124bf565b6001600160a01b03831660009081526039602052604090205b90506000826124e6576001600160a01b0384166000908152603e6020526040902054612500565b6001600160a01b0384166000908152603660205260409020545b60018301549091504390600090612518908390612cc5565b905060008111801561252a5750600083115b156126b9576000856125a057866001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561256f57600080fd5b505afa158015612583573d6000803e3d6000fd5b505050506040513d602081101561259957600080fd5b505161267a565b61267a876001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156125dc57600080fd5b505afa1580156125f0573d6000803e3d6000fd5b505050506040513d602081101561260657600080fd5b5051604080516308f7a6e360e31b815290516001600160a01b038b16916347bd3718916004808301926020929190829003018186803b15801561264857600080fd5b505afa15801561265c573d6000803e3d6000fd5b505050506040513d602081101561267257600080fd5b505190612d07565b905060006126888584612d25565b9050600080831161269a5760006126a4565b6126a48284612d07565b87549091506126b39082612c62565b87555050505b50600190920191909155505050565b6001600160a01b038216612723576040805162461bcd60e51b815260206004820152601860248201527f496e76616c6964206163636f756e742061646472657373210000000000000000604482015290519081900360640190fd5b60345460408051632214743160e11b81526001600160a01b03868116600483015291519190921691634428e862916024808301926020929190829003018186803b15801561277057600080fd5b505afa158015612784573d6000803e3d6000fd5b505050506040513d602081101561279a57600080fd5b50516127e9576040805162461bcd60e51b8152602060048201526019602482015278151bdad95b881a185cc81b9bdd081899595b881b1a5cdd1959603a1b604482015290519081900360640190fd5b60008060008315612903576001600160a01b03808716600081815260396020908152604080832054603b8352818420958b1684529482529182902054825163aa5af0fd60e01b8152925194975095506128d49363aa5af0fd926004808201939291829003018186803b15801561285e57600080fd5b505afa158015612872573d6000803e3d6000fd5b505050506040513d602081101561288857600080fd5b5051604080516395dd919360e01b81526001600160a01b0389811660048301529151918a16916395dd919391602480820192602092909190829003018186803b15801561264857600080fd5b6001600160a01b038088166000908152603b60209081526040808320938a1683529290522084905590506129cb565b6001600160a01b03808716600081815260386020908152604080832054603a8352818420958b16808552958352928190205481516370a0823160e01b815260048101969096529051929750955091926370a08231926024808301939192829003018186803b15801561297457600080fd5b505afa158015612988573d6000803e3d6000fd5b505050506040513d602081101561299e57600080fd5b50516001600160a01b038088166000908152603a60209081526040808320938a1683529290522084905590505b60006129d78484612cc5565b905060006129e58383612d7e565b905080156112b6576001600160a01b0387166000908152603c6020526040902054612a109082612c62565b6001600160a01b038089166000818152603c6020908152604091829020949094558051928c168352928201528082018390526060810186905290517fd53ea54cd361f7c49d3ca11bfcb71b4783448ade1b32513783ee19776f2adf319181900360800190a15050505050505050565b60005b82518110156114ed576000838281518110612a9957fe5b60200260200101519050612aad81846123bc565b60005b8551811015612adf57612ad782878381518110612ac957fe5b6020026020010151866126c8565b600101612ab0565b5050600101612a82565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526114ed908590612d96565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261168c908490612d96565b60008054610100600160a81b0319163361010081029190911782556040519091907f70aea8d848e8a90fb7661b227dc522eb6395c3dac71b63cb59edd5c9899b2364908290a3565b8051825114612c1d5760405162461bcd60e51b815260040180806020018281038252602d815260200180613236602d913960400191505060405180910390fd5b815160005b818110156114ed57612c5a848281518110612c3957fe5b6020026020010151848381518110612c4d57fe5b6020026020010151611e70565b600101612c22565b600082820183811015612cbc576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b6000612cbc83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612e47565b6000612cbc82612d1f85670de0b6b3a7640000612d25565b90612ee3565b600082612d3457506000612cbf565b82820282848281612d4157fe5b0414612cbc5760405162461bcd60e51b81526004018080602001828103825260218152602001806133006021913960400191505060405180910390fd5b6000612cbc670de0b6b3a7640000612d1f8585612d25565b6060612deb826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612f259092919063ffffffff16565b80519091501561168c57808060200190516020811015612e0a57600080fd5b505161168c5760405162461bcd60e51b815260040180806020018281038252602a8152602001806133ce602a913960400191505060405180910390fd5b60008184841115612ed65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612e9b578181015183820152602001612e83565b50505050905090810190601f168015612ec85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50508183035b9392505050565b6000612cbc83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612f3c565b6060612f348484600085612fa1565b949350505050565b60008183612f8b5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612e9b578181015183820152602001612e83565b506000838581612f9757fe5b0495945050505050565b606082471015612fe25760405162461bcd60e51b81526004018080602001828103825260268152602001806132636026913960400191505060405180910390fd5b612feb856130fd565b61303c576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b6020831061307b5780518252601f19909201916020918201910161305c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146130dd576040519150601f19603f3d011682016040523d82523d6000602084013e6130e2565b606091505b50915091506130f2828286613103565b979650505050505050565b3b151590565b60608315613112575081612edc565b8251156131225782518084602001fd5b60405162461bcd60e51b8152602060048201818152845160248401528451859391928392604401919085019080838360008315612e9b578181015183820152602001612e8356fe6f6e6c79436f6e74726f6c6c65723a2063616c6c6572206973206e6f742074686520636f6e74726f6c6c65725f73657450656e64696e674f776e65723a204e6577206f77656e722063616e206e6f74206265207a65726f206164647265737320616e64206f776e657220686173206265656e20736574214c656e677468206f66205f69546f6b656e7320616e64205f737570706c79537065656473206d69736d6174636843616e206e6f74206368616e676520626f72726f7720737065656473207768656e207061757365644c656e677468206f66205f69546f6b656e7320616e64205f626f72726f77537065656473206d69736d61746368416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c43616e206e6f74206368616e676520737570706c7920737065656473207768656e2070617573656443616e206e6f74206368616e676520737065656473207768656e20706175736564496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f776f6e6c794f776e65723a2063616c6c6572206973206e6f7420746865206f776e6572696e697469616c697a653a20636f6e74726f6c6c657220616464726573732073686f756c64206e6f74206265207a65726f206164647265737321726573637565546f6b656e733a2063616e206f6e6c792062652063616c6c65642062792074726561737572795f6163636570744f776e65723a204f6e6c7920666f722070656e64696e67206f776e6572215361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220729164d0dae39142e9e515ddeb7696184456c0a17fd1e6658c7bf9ab6ed9fd5264736f6c634300060c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.