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 | 1059 days ago | IN | 0 ETH | 0.00427437 |
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers. Name tag integration is not available in advanced view.
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
||||
---|---|---|---|---|---|---|---|
21199778 | 91 days ago | 0 ETH | |||||
21199778 | 91 days ago | 0 ETH | |||||
21199769 | 91 days ago | 0 ETH | |||||
21199769 | 91 days ago | 0 ETH | |||||
21199769 | 91 days ago | 0 ETH | |||||
21199769 | 91 days ago | 0 ETH | |||||
21199769 | 91 days ago | 0 ETH | |||||
21003736 | 118 days ago | 0 ETH | |||||
20999326 | 119 days ago | 0 ETH | |||||
20999326 | 119 days ago | 0 ETH | |||||
20999320 | 119 days ago | 0 ETH | |||||
20999320 | 119 days ago | 0 ETH | |||||
20999314 | 119 days ago | 0 ETH | |||||
20999314 | 119 days ago | 0 ETH | |||||
20999309 | 119 days ago | 0 ETH | |||||
20999309 | 119 days ago | 0 ETH | |||||
20999303 | 119 days ago | 0 ETH | |||||
20999303 | 119 days ago | 0 ETH | |||||
20999270 | 119 days ago | 0 ETH | |||||
20999270 | 119 days ago | 0 ETH | |||||
20999263 | 119 days ago | 0 ETH | |||||
20999263 | 119 days ago | 0 ETH | |||||
20999257 | 119 days ago | 0 ETH | |||||
20999257 | 119 days ago | 0 ETH | |||||
20999252 | 119 days ago | 0 ETH |
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.