Overview
POL Balance
0 POL
POL Value
$0.00More Info
Private Name Tags
ContractCreator
Sponsored
Latest 25 from a total of 41 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
_pause Control P... | 44446651 | 463 days ago | IN | 0 POL | 0.00484283 | ||||
Deploy H Token | 44434943 | 464 days ago | IN | 0 POL | 0.89736149 | ||||
_set Collateral ... | 44434889 | 464 days ago | IN | 0 POL | 0.01247299 | ||||
_pause Control P... | 44434860 | 464 days ago | IN | 0 POL | 0.00510984 | ||||
_pause Control P... | 43021038 | 500 days ago | IN | 0 POL | 0.00580827 | ||||
Deploy H Token | 43020867 | 500 days ago | IN | 0 POL | 0.97427446 | ||||
Deploy H Token | 43020827 | 500 days ago | IN | 0 POL | 0.96342763 | ||||
Deploy H Token | 43020771 | 500 days ago | IN | 0 POL | 0.87678839 | ||||
Deploy H Token | 43020715 | 500 days ago | IN | 0 POL | 0.87446443 | ||||
Deploy H Token | 43020531 | 500 days ago | IN | 0 POL | 0.79551413 | ||||
_set Underlying ... | 43020274 | 500 days ago | IN | 0 POL | 0.00509317 | ||||
_set Collateral ... | 43020261 | 500 days ago | IN | 0 POL | 0.01476772 | ||||
_set Collateral ... | 43020255 | 500 days ago | IN | 0 POL | 0.01582051 | ||||
_set Collateral ... | 43020249 | 500 days ago | IN | 0 POL | 0.018368 | ||||
_set Collateral ... | 43020242 | 500 days ago | IN | 0 POL | 0.01366928 | ||||
_set Collateral ... | 43020239 | 500 days ago | IN | 0 POL | 0.01279722 | ||||
_pause Control P... | 43020233 | 500 days ago | IN | 0 POL | 0.00533041 | ||||
_pause Control P... | 41051703 | 551 days ago | IN | 0 POL | 0.00292875 | ||||
Deploy H Token | 41051575 | 551 days ago | IN | 0 POL | 0.58075357 | ||||
_set Underlying ... | 41051520 | 551 days ago | IN | 0 POL | 0.00705192 | ||||
_set Collateral ... | 41051508 | 551 days ago | IN | 0 POL | 0.00705724 | ||||
Deploy H Token | 40875187 | 555 days ago | IN | 0 POL | 0.59932906 | ||||
_set Collateral ... | 40875105 | 555 days ago | IN | 0 POL | 0.00780793 | ||||
Set Price Oracle | 40874977 | 555 days ago | IN | 0 POL | 0.00608907 | ||||
_set Oracle Stat... | 40874969 | 555 days ago | IN | 0 POL | 0.01110143 |
Loading...
Loading
Contract Name:
ControlPanel
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 300 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.15; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "../interfaces/InterestRateModelI.sol"; import "../interfaces/PermissionlessOracleI.sol"; import "../interfaces/ControllerI.sol"; import "../interfaces/LiquidatorI.sol"; import "../interfaces/HTokenI.sol"; import "../interfaces/HTokenFactoryI.sol"; import "../interfaces/InterestRateModelI.sol"; import "../interfaces/ControlPanelI.sol"; import "../utils/ErrorReporter.sol"; /** * @title Honey Finance Control Panel * @notice Permissionlessly deploy and administer HTokens in the Honey Finance protocol * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle */ contract ControlPanel is ControlPanelI, AccessControl, Pausable { // ----- Imports ----- using EnumerableSet for EnumerableSet.AddressSet; using SafeERC20 for IERC20; // ---------- HToken Role Constants ---------- /// @notice keccak256 0xd1ae8bbdabd60d63e418b84f5ad6f9cba90092c9816d7724d85f0d4e4bea2c60 bytes32 internal constant SUPPLIER_ROLE = keccak256("SUPPLIER_ROLE"); /// @notice keccak256 0x3fb0aaa9e8051cfc6c234a5d843bed33910f70c647055f27247c10144c7552e1 bytes32 internal constant MARKET_ADMIN_ROLE = keccak256("MARKET_ADMIN_ROLE"); /// @notice keccak256 0x5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c16 bytes32 internal constant LIQUIDATOR_ROLE = keccak256("LIQUIDATOR_ROLE"); // ---------- Versioning ---------- /// @notice this corresponds to 1.0.0 uint256 public constant version = 1_000_000; // ---------- Honey-controlled parameters ---------- /// @notice Controller address new HTokens will be deployed with ControllerI public controller; /// @notice Liquidator address new HTokens will be deployed with LiquidatorI public liquidator; /// @notice Marketplace address new HTokens will be deployed with address public marketplace; /// @notice Hive fee receiver address new HTokens will be deployed with address public protocolCommisionReceiver; /// @notice Treasury address new HTokens will be deployed with address public dao; /// @notice Ops multisig address new HTokens will be deployed with address public ops; /// @notice Default borrow fee new HTokens will be deployed with uint256 public defaultBorrowFeeMantissa = 0.02e18; // 2% /// @notice Default referred borrow fee new HTokens will be deployed with uint256 public defaultReferredBorrowFeeMantissa = 0.02e18; // 2% /// @notice Default protocol commission new HTokens will be deployed with uint256 public defaultProtocolCommissionMantissa = 0.02e18; // 2% /// @notice Default reserve factor new HTokens will be deployed with uint256 public defaultReserveFactorMantissa = 0.02e18; // 2% /// @notice Default initial exchange rate new HTokens will be deployed with uint256 public defaultInitialExchangeRateMantissa = 0.5e18; // 50% uint256 internal constant maxFeeMantissa = 0.05e18; // 5% // ---------- Whitelisted Addresses ---------- EnumerableSet.AddressSet internal registeredUnderlyings; EnumerableSet.AddressSet internal registeredCollaterals; EnumerableSet.AddressSet internal registeredOracles; // ---------- State Variables ---------- EnumerableSet.AddressSet internal deployedHTokens; /// @notice Mapps the owner to the owned htokens mapping(address => EnumerableSet.AddressSet) internal ownedHTokens; /// @notice Factory which will deploy new HTokens HTokenFactoryI public factory; // ---------- Construction ---------- constructor() { _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); } // ---------- Deploy ---------- /** * @notice Deploy an HToken and set it up in the Honey protocol * @param _underlyingToken Address of the underlying ERC-20 liquid asset * @param _collateralToken Address of the underlying ERC-721 collateral asset * @param _interestRateModel Address of the interest rate model * @param _adminCommissionReceiver Address that receives admin fees * @param _oracle Address of the collateral price oracle * @param _maxLTVFactorMantissa Max LTV factor in mantissa format * @param _collateralFactorMantissa Collateral factor in mantissa format */ function deployHToken( address _underlyingToken, address _collateralToken, address _interestRateModel, address _adminCommissionReceiver, address _oracle, uint256 _maxLTVFactorMantissa, uint256 _collateralFactorMantissa ) external override { if (paused()) revert PausedAction(); if (!registeredUnderlyings.contains(_underlyingToken)) revert ControlPanelError(Error.FACTORY_INVALID_UNDERLYING); if (!registeredCollaterals.contains(_collateralToken)) revert ControlPanelError(Error.FACTORY_INVALID_COLLATERAL); if (!registeredOracles.contains(_oracle)) revert ControlPanelError(Error.FACTORY_INVALID_ORACLE); if ( _interestRateModel == address(0) || !InterestRateModelI(_interestRateModel).supportsInterface(type(InterestRateModelI).interfaceId) ) revert ControlPanelError(Error.FACTORY_INVALID_INTEREST_RATE_MODEL); if (IERC20Metadata(_underlyingToken).decimals() != 18) revert ControlPanelError(Error.FACTORY_INVALID_UNDERLYING_DECIMALS); string memory name = string.concat( "Honey ", IERC20Metadata(_underlyingToken).symbol(), " ", IERC721Metadata(_collateralToken).symbol() ); string memory symbol = string.concat( "h", IERC20Metadata(_underlyingToken).symbol(), IERC721Metadata(_collateralToken).symbol() ); address hToken = factory.deployHToken( _underlyingToken, _collateralToken, address(controller), _interestRateModel, address(liquidator), defaultInitialExchangeRateMantissa, _adminCommissionReceiver, protocolCommisionReceiver, name, symbol ); if (hToken == address(0)) revert HTokenFactoryError(Error.FACTORY_DEPLOYMENT_FAILED); deployedHTokens.add(hToken); ownedHTokens[msg.sender].add(hToken); // Configure parameters HTokenI(hToken)._setProtocolFees(defaultProtocolCommissionMantissa, defaultReserveFactorMantissa); // Configure the roles HTokenI(hToken).grantRole(DEFAULT_ADMIN_ROLE, ops); HTokenI(hToken).grantRole(MARKET_ADMIN_ROLE, address(this)); HTokenI(hToken).grantRole(SUPPLIER_ROLE, address(this)); HTokenI(hToken).grantRole(LIQUIDATOR_ROLE, marketplace); HTokenI(hToken).renounceRole(DEFAULT_ADMIN_ROLE, address(this)); // Set up the new market controller._supportMarket(HTokenI(hToken)); controller._setPriceOracle(HTokenI(hToken), PermissionlessOracleI(_oracle)); controller._setFactors(HTokenI(hToken), _maxLTVFactorMantissa, _collateralFactorMantissa); controller._setBorrowFeePerMarket(HTokenI(hToken), defaultBorrowFeeMantissa, defaultReferredBorrowFeeMantissa); // Set up liquidator liquidator._initializeHToken(HTokenI(hToken)); emit HTokenDeployed( msg.sender, hToken, _underlyingToken, _collateralToken, controller, liquidator, defaultInitialExchangeRateMantissa, protocolCommisionReceiver, name, symbol ); } // ---------- Administer ---------- /** * @notice Sets a new price oracle for an HToken * @param _hToken HToken to set the oracle for * @param _newOracle New oracle address */ function setPriceOracle(address _hToken, address _newOracle) external { if (paused()) revert PausedAction(); if (!registeredOracles.contains(_newOracle)) revert ControlPanelError(Error.FACTORY_INVALID_ORACLE); if (!ownedHTokens[msg.sender].contains(_hToken)) revert Unauthorized(); controller._setPriceOracle(HTokenI(_hToken), PermissionlessOracleI(_newOracle)); } /** * @notice Sets the maxLTVFactor and collateral factor for an HToken * @param _hToken HToken to set the factors for * @param _newMaxLTVFactorMantissa New close factor in mantissa format * @param _newCollateralFactorMantissa New collateral factor in mantissa format */ function setFactors( address _hToken, uint256 _newMaxLTVFactorMantissa, uint256 _newCollateralFactorMantissa ) external { if (paused()) revert PausedAction(); if (!ownedHTokens[msg.sender].contains(_hToken)) revert Unauthorized(); controller._setFactors(HTokenI(_hToken), _newMaxLTVFactorMantissa, _newCollateralFactorMantissa); } /** * @notice Set new admin fee mantissa * @param _hToken HToken to set the admin fee for * @param _newAdminCommissionMantissa New admin fee mantissa */ function setAdminCommission(address _hToken, uint256 _newAdminCommissionMantissa) external { if (paused()) revert PausedAction(); if (!ownedHTokens[msg.sender].contains(_hToken)) revert Unauthorized(); HTokenI(_hToken)._setAdminCommission(_newAdminCommissionMantissa); } /** * @notice Sets a new protocol address parameter * @dev Target of 3 is reserved by convention for admin fee receiver * @dev Target of 5 is reserved by convention for interest rate model * @param _hToken HToken to set the parameter for * @param _newAddress Address of the new contract * @param _target Target ID of the address to be set */ function setAddressMarketAdmin( address _hToken, address _newAddress, uint256 _target ) external { if (paused()) revert PausedAction(); if (!ownedHTokens[msg.sender].contains(_hToken)) revert Unauthorized(); HTokenI(_hToken)._setAddressMarketAdmin(_newAddress, _target); } /** * @notice Pause an action for a particular HToken * @param _hToken HToken to pause * @param _state True for paused, false for unpaused * @param _target Target ID of the component to pause */ function pauseComponent( address _hToken, bool _state, uint256 _target ) external { if (paused()) revert PausedAction(); if (!ownedHTokens[msg.sender].contains(_hToken)) revert Unauthorized(); controller._pauseComponent(HTokenI(_hToken), _state, _target); } /** * @notice Add to or take away from reserves * @dev Accrues interest * @param _hToken HToken to modify reserves of * @param _amount Quantity of underlying ERC-20 token to change the reserves by * @param _add True to add reserves, false to remove reserves */ function modifyReserves( address _hToken, uint256 _amount, bool _add ) external { if (paused()) revert PausedAction(); if (!ownedHTokens[msg.sender].contains(_hToken)) revert Unauthorized(); if (_add) { IERC20 underlying = HTokenI(_hToken).underlyingToken(); underlying.safeTransferFrom(msg.sender, address(this), _amount); underlying.safeApprove(_hToken, _amount); HTokenI(_hToken)._modifyReserves(_amount, true); } else { HTokenI(_hToken)._modifyReserves(_amount, false); IERC20(HTokenI(_hToken).underlyingToken()).safeTransfer(msg.sender, _amount); } } /** * @notice Transfer the ability to administer an HToken to another address * @dev This function does not have a zero address check, to permit users to renounce ownership * @param _hToken HToken to transfer * @param _newOwner Address of the new owner */ function transferOwnership(address _hToken, address _newOwner) external { if (paused()) revert PausedAction(); if (!ownedHTokens[msg.sender].contains(_hToken)) revert Unauthorized(); ownedHTokens[msg.sender].remove(_hToken); ownedHTokens[_newOwner].add(_hToken); emit OwnershipTransferred(_hToken, msg.sender, _newOwner); } // ---------- View Functions ---------- /** * @notice Get the address of an HToken in the enumerable set * @param _index Index of the HToken to retrieve * @return HToken address */ function getDeployedHToken(uint256 _index) external view returns (address) { return deployedHTokens.at(_index); } /** * @notice Get the number of HTokens deployed * @return Number of HTokens deployed */ function getDeployedHTokenCount() external view returns (uint256) { return deployedHTokens.length(); } /** * @notice Get whether an HToken was deployed by the control panel * @param _hToken Address of the HToken * @return True if deployed */ function isDeployedHToken(address _hToken) external view returns (bool) { return deployedHTokens.contains(_hToken); } /** * @notice Get the address of an underlying token in the enumerable set * @param _index Index of the underlying token to retrieve * @return Underlying token address */ function getUnderlying(uint256 _index) external view returns (address) { return registeredUnderlyings.at(_index); } /** * @notice Get the number of underlying tokens * @return Number of underlying tokens */ function getUnderlyingCount() external view returns (uint256) { return registeredUnderlyings.length(); } /** * @notice Get whether an underlying token is registered in the control panel * @param _underlying Address of the underlying token * @return True if registered */ function isRegisteredUnderlying(address _underlying) external view returns (bool) { return registeredUnderlyings.contains(_underlying); } /** * @notice Get the address of a collateral token in the enumerable set * @param _index Index of the collateral token to retrieve * @return Collateral token address */ function getCollateral(uint256 _index) external view returns (address) { return registeredCollaterals.at(_index); } /** * @notice Get the number of collateral tokens * @return Number of collateral tokens */ function getCollateralCount() external view returns (uint256) { return registeredCollaterals.length(); } /** * @notice Get whether a collateral is registered in the control panel * @param _collateral Address of the collateral token * @return True if registered */ function isRegisteredCollateral(address _collateral) external view returns (bool) { return registeredCollaterals.contains(_collateral); } /** * @notice Get the address of an oracle in the enumerable set * @param _index Index of the oracle to retrieve * @return Oracle address */ function getOracle(uint256 _index) external view returns (address) { return registeredOracles.at(_index); } /** * @notice Get the number of oracles * @return Number of oracles */ function getOracleCount() external view returns (uint256) { return registeredOracles.length(); } /** * @notice Get whether an oracle is registered in the control panel * @param _oracle Address of the oracle * @return True if registered */ function isRegisteredOracle(address _oracle) external view returns (bool) { return registeredOracles.contains(_oracle); } /** * @notice Get the address of an HToken in the enumerable set of HTokens owned by a user * @param _user Address of the user to query * @param _index Index of the HToken to retrieve * @return HToken address */ function getOwnedHToken(address _user, uint256 _index) external view returns (address) { return ownedHTokens[_user].at(_index); } /** * @notice Get the number of HTokens in the enumerable set of HTokens owned by a user * @return Number of HTokens */ function getOwnedHTokenCount(address _user) external view returns (uint256) { return ownedHTokens[_user].length(); } /** * @notice Get whether a user owns a particular HToken * @param _hToken Address of the HToken * @return True if owned */ function isOwnedHToken(address _user, address _hToken) external view returns (bool) { return ownedHTokens[_user].contains(_hToken); } // ---------- Permissioned Functions ---------- /** * @notice Add or remove an address from the whitelist of underlying tokens * @param _underlying Address of the underlying token * @param _status True to add, false to remove */ function _setUnderlyingStatus(address _underlying, bool _status) external { if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert Unauthorized(); if (_status) { registeredUnderlyings.add(_underlying); } else { registeredUnderlyings.remove(_underlying); } emit UnderlyingStatusSet(_underlying, _status); } /** * @notice Add or remove an address from the whitelist of collateral tokens * @param _collateral Address of the collateral token * @param _status True to add, false to remove */ function _setCollateralStatus(address _collateral, bool _status) external { if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert Unauthorized(); if (_status) { registeredCollaterals.add(_collateral); } else { registeredCollaterals.remove(_collateral); } emit CollateralStatusSet(_collateral, _status); } /** * @notice Add or remove an address from the whitelist of oracles * @param _oracle Address of the oracle * @param _status True to add, false to remove */ function _setOracleStatus(address _oracle, bool _status) external { if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert Unauthorized(); if (_status) { registeredOracles.add(_oracle); } else { registeredOracles.remove(_oracle); } emit OracleStatusSet(_oracle, _status); } /** * @notice Set the numerical default values used in HToken deployments * @param _defaultBorrowFeeMantissa Borrow fee in mantissa format * @param _defaultReferredBorrowFeeMantissa Referred borrow fee in mantissa format * @param _defaultProtocolCommissionMantissa Hive fee in mantissa format * @param _defaultReserveFactorMantissa Reserve factor in mantissa format * @param _defaultInitialExchangeRateMantissa Initial exchange rate in mantissa format */ function _setDefaults( uint256 _defaultBorrowFeeMantissa, uint256 _defaultReferredBorrowFeeMantissa, uint256 _defaultProtocolCommissionMantissa, uint256 _defaultReserveFactorMantissa, uint256 _defaultInitialExchangeRateMantissa ) external { if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert Unauthorized(); if ( _defaultBorrowFeeMantissa > maxFeeMantissa || _defaultReferredBorrowFeeMantissa > maxFeeMantissa || _defaultInitialExchangeRateMantissa == 0 ) revert ControlPanelError(Error.BAD_INPUT); defaultBorrowFeeMantissa = _defaultBorrowFeeMantissa; defaultReferredBorrowFeeMantissa = _defaultReferredBorrowFeeMantissa; defaultProtocolCommissionMantissa = _defaultProtocolCommissionMantissa; defaultReserveFactorMantissa = _defaultReserveFactorMantissa; defaultInitialExchangeRateMantissa = _defaultInitialExchangeRateMantissa; emit DefaultsSet( _defaultBorrowFeeMantissa, _defaultReferredBorrowFeeMantissa, _defaultProtocolCommissionMantissa, _defaultReserveFactorMantissa, _defaultInitialExchangeRateMantissa ); } /** * @notice Sets a new protocol address parameter * @dev WARNING when changing ops or marketplace as the roles will remain in place for the old address * @param _newAddress Address of the new contract * @param _target Target ID of the address to be set */ function _setAddress(address _newAddress, uint256 _target) external { if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert Unauthorized(); address oldAddress; if (_target == 0) { oldAddress = address(liquidator); liquidator = LiquidatorI(_newAddress); } else if (_target == 1) { oldAddress = address(controller); controller = ControllerI(_newAddress); } else if (_target == 2) { oldAddress = protocolCommisionReceiver; protocolCommisionReceiver = _newAddress; } else if (_target == 3) { oldAddress = dao; dao = _newAddress; } else if (_target == 4) { oldAddress = address(factory); factory = HTokenFactoryI(_newAddress); } else if (_target == 5) { oldAddress = ops; ops = _newAddress; } else if (_target == 6) { oldAddress = marketplace; marketplace = _newAddress; } else { revert WrongParams(); } emit AddressUpdated(_newAddress, oldAddress, _target); } /** * @notice Pauses the control panel * @param _state True to pause, false to unpause */ function _pauseControlPanel(bool _state) external { if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert Unauthorized(); if (_state) _pause(); else _unpause(); emit ControllerPaused(_state); } // ---------- Events ---------- event UnderlyingStatusSet(address indexed _underlying, bool _status); event CollateralStatusSet(address indexed _collateral, bool _status); event OracleStatusSet(address indexed _oracle, bool _status); event DefaultsSet( uint256 _defaultBorrowFeeMantissa, uint256 _defaultReferredBorrowFeeMantissa, uint256 _defaultProtocolCommissionMantissa, uint256 _defaultReserveFactorMantissa, uint256 _defaultInitialExchangeRateMantissa ); event AddressUpdated(address indexed _oldAddress, address indexed _newAddress, uint256 _target); event HTokenDeployed( address _deployer, address indexed _hToken, address indexed _underlying, address indexed _collateral, ControllerI _controller, LiquidatorI _liquidator, uint256 _exchangeRateMantissa, address _hiveFeeReceiver, string _name, string _symbol ); event OwnershipTransferred(address indexed _hToken, address indexed _oldOwner, address indexed _newOwner); event ControllerPaused(bool _state); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol) pragma solidity ^0.8.0; import "./IERC1155.sol"; import "./IERC1155Receiver.sol"; import "./extensions/IERC1155MetadataURI.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of the basic standard multi-token. * See https://eips.ethereum.org/EIPS/eip-1155 * Originally based on code by Enjin: https://github.com/enjin/erc-1155 * * _Available since v3.1._ */ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { using Address for address; // Mapping from token ID to account balances mapping(uint256 => mapping(address => uint256)) private _balances; // Mapping from account to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json string private _uri; /** * @dev See {_setURI}. */ constructor(string memory uri_) { _setURI(uri_); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155).interfaceId || interfaceId == type(IERC1155MetadataURI).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC1155MetadataURI-uri}. * * This implementation returns the same URI for *all* token types. It relies * on the token type ID substitution mechanism * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. * * Clients calling this function must replace the `\{id\}` substring with the * actual token type ID. */ function uri(uint256) public view virtual override returns (string memory) { return _uri; } /** * @dev See {IERC1155-balanceOf}. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { require(account != address(0), "ERC1155: address zero is not a valid owner"); return _balances[id][account]; } /** * @dev See {IERC1155-balanceOfBatch}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] memory accounts, uint256[] memory ids) public view virtual override returns (uint256[] memory) { require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); uint256[] memory batchBalances = new uint256[](accounts.length); for (uint256 i = 0; i < accounts.length; ++i) { batchBalances[i] = balanceOf(accounts[i], ids[i]); } return batchBalances; } /** * @dev See {IERC1155-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC1155-isApprovedForAll}. */ function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { return _operatorApprovals[account][operator]; } /** * @dev See {IERC1155-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes memory data ) public virtual override { require( from == _msgSender() || isApprovedForAll(from, _msgSender()), "ERC1155: caller is not token owner or approved" ); _safeTransferFrom(from, to, id, amount, data); } /** * @dev See {IERC1155-safeBatchTransferFrom}. */ function safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) public virtual override { require( from == _msgSender() || isApprovedForAll(from, _msgSender()), "ERC1155: caller is not token owner or approved" ); _safeBatchTransferFrom(from, to, ids, amounts, data); } /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function _safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { require(to != address(0), "ERC1155: transfer to the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, from, to, ids, amounts, data); uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); unchecked { _balances[id][from] = fromBalance - amount; } _balances[id][to] += amount; emit TransferSingle(operator, from, to, id, amount); _afterTokenTransfer(operator, from, to, ids, amounts, data); _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); } /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function _safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); require(to != address(0), "ERC1155: transfer to the zero address"); address operator = _msgSender(); _beforeTokenTransfer(operator, from, to, ids, amounts, data); for (uint256 i = 0; i < ids.length; ++i) { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); unchecked { _balances[id][from] = fromBalance - amount; } _balances[id][to] += amount; } emit TransferBatch(operator, from, to, ids, amounts); _afterTokenTransfer(operator, from, to, ids, amounts, data); _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); } /** * @dev Sets a new URI for all token types, by relying on the token type ID * substitution mechanism * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. * * By this mechanism, any occurrence of the `\{id\}` substring in either the * URI or any of the amounts in the JSON file at said URI will be replaced by * clients with the token type ID. * * For example, the `https://token-cdn-domain/\{id\}.json` URI would be * interpreted by clients as * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` * for token type ID 0x4cce0. * * See {uri}. * * Because these URIs cannot be meaningfully represented by the {URI} event, * this function emits no events. */ function _setURI(string memory newuri) internal virtual { _uri = newuri; } /** * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function _mint( address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { require(to != address(0), "ERC1155: mint to the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); _balances[id][to] += amount; emit TransferSingle(operator, address(0), to, id, amount); _afterTokenTransfer(operator, address(0), to, ids, amounts, data); _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); } /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function _mintBatch( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { require(to != address(0), "ERC1155: mint to the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); address operator = _msgSender(); _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); for (uint256 i = 0; i < ids.length; i++) { _balances[ids[i]][to] += amounts[i]; } emit TransferBatch(operator, address(0), to, ids, amounts); _afterTokenTransfer(operator, address(0), to, ids, amounts, data); _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); } /** * @dev Destroys `amount` tokens of token type `id` from `from` * * Emits a {TransferSingle} event. * * Requirements: * * - `from` cannot be the zero address. * - `from` must have at least `amount` tokens of token type `id`. */ function _burn( address from, uint256 id, uint256 amount ) internal virtual { require(from != address(0), "ERC1155: burn from the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); unchecked { _balances[id][from] = fromBalance - amount; } emit TransferSingle(operator, from, address(0), id, amount); _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); } /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. */ function _burnBatch( address from, uint256[] memory ids, uint256[] memory amounts ) internal virtual { require(from != address(0), "ERC1155: burn from the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); address operator = _msgSender(); _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); for (uint256 i = 0; i < ids.length; i++) { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); unchecked { _balances[id][from] = fromBalance - amount; } } emit TransferBatch(operator, from, address(0), ids, amounts); _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC1155: setting approval status for self"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Hook that is called before any token transfer. This includes minting * and burning, as well as batched variants. * * The same hook is called on both single and batched variants. For single * transfers, the length of the `ids` and `amounts` arrays will be 1. * * Calling conditions (for each `id` and `amount` pair): * * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens * of token type `id` will be transferred to `to`. * - When `from` is zero, `amount` tokens of token type `id` will be minted * for `to`. * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` * will be burned. * - `from` and `to` are never both zero. * - `ids` and `amounts` have the same, non-zero length. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} /** * @dev Hook that is called after any token transfer. This includes minting * and burning, as well as batched variants. * * The same hook is called on both single and batched variants. For single * transfers, the length of the `id` and `amount` arrays will be 1. * * Calling conditions (for each `id` and `amount` pair): * * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens * of token type `id` will be transferred to `to`. * - When `from` is zero, `amount` tokens of token type `id` will be minted * for `to`. * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` * will be burned. * - `from` and `to` are never both zero. * - `ids` and `amounts` have the same, non-zero length. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual {} function _doSafeTransferAcceptanceCheck( address operator, address from, address to, uint256 id, uint256 amount, bytes memory data ) private { if (to.isContract()) { try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { if (response != IERC1155Receiver.onERC1155Received.selector) { revert("ERC1155: ERC1155Receiver rejected tokens"); } } catch Error(string memory reason) { revert(reason); } catch { revert("ERC1155: transfer to non-ERC1155Receiver implementer"); } } } function _doSafeBatchTransferAcceptanceCheck( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) private { if (to.isContract()) { try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( bytes4 response ) { if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { revert("ERC1155: ERC1155Receiver rejected tokens"); } } catch Error(string memory reason) { revert(reason); } catch { revert("ERC1155: transfer to non-ERC1155Receiver implementer"); } } } function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { uint256[] memory array = new uint256[](1); array[0] = element; return array; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol) pragma solidity ^0.8.0; import "../IERC1155.sol"; /** * @dev Interface of the optional ERC1155MetadataExtension interface, as defined * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. * * _Available since v3.1._ */ interface IERC1155MetadataURI is IERC1155 { /** * @dev Returns the URI for token type `id`. * * If the `\{id\}` substring is present in the URI, it must be replaced by * clients with the actual token type ID. */ function uri(uint256 id) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev _Available since v3.1._ */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.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 SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 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( IERC20 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' 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( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @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(IERC20 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 require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 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"); (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 functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // 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 /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^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. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // 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; if (lastIndex != toDeleteIndex) { 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] = valueIndex; // Replace lastValue's index to valueIndex } // 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) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // 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); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // 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(uint160(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(uint160(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(uint160(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(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // 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 in 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)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.15; import "./HTokenInternal.sol"; /** * @title Honey Finance's HToken contract * @notice ERC-1155 contract which wraps an ERC-20 underlying liquid asset and an ERC-721 underlying collateral asset * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle * @custom:coauthor m4rio */ contract HToken is HTokenInternal { using SafeERC20 for IERC20; /// @notice Version of the contract. 1_000_000 corresponds to 1.0.0 uint256 public constant version = 1_000_000; // Reentrancy parameters and event uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; error Reentrant(); /** * @notice Initialize the market * @param _underlyingToken address of the underlying ERC-20 liquid asset * @param _collateralToken address of the underlying ERC-721 collateral asset * @param _controller address of the controller * @param _interestRateModel address of the interest rate model * @param _liquidator address of the liquidator * @param _initialExchangeRateMantissa initial exchange rate, mantissa formatted * @param _adminCommissionReceiver address that receives admin commission * @param _protocolCommissionReceiver address that receives protocol commission * @param _roleReceiver address to recieve DEFAULT_ADMIN_ROLE * @param _name name of the token * @param _symbol symbol of the token */ constructor( address _underlyingToken, address _collateralToken, address _controller, address _interestRateModel, address _liquidator, uint256 _initialExchangeRateMantissa, address _adminCommissionReceiver, address _protocolCommissionReceiver, address _roleReceiver, string memory _name, string memory _symbol ) HTokenInternal( _underlyingToken, _collateralToken, _controller, _interestRateModel, _liquidator, _initialExchangeRateMantissa, _adminCommissionReceiver, _protocolCommissionReceiver, _roleReceiver, _name, _symbol ) {} // ----- Lend side functions ----- /** * @notice Deposit underlying ERC-20 asset and mint hTokens * @dev Pull pattern, user must approve the contract before calling. If _to is address(0) then it becomes msg.sender * @param _amount Quantity of underlying ERC-20 to transfer in * @param _to Target address to mint hTokens to */ function depositUnderlying(uint256 _amount, address _to) external { checkReentrant(); if (_to == address(0)) _to = msg.sender; depositUnderlyingInternal(_amount, _to); _status = _NOT_ENTERED; } /** * @notice Redeem a specified amount of hTokens for their underlying ERC-20 asset * @param _amount Quantity of hTokens to redeem for underlying ERC-20 */ function redeem(uint256 _amount) external { checkReentrant(); redeemInternal(_amount); _status = _NOT_ENTERED; } /** * @notice Withdraws the specified amount of underlying ERC-20 asset, consuming the minimum amount of hTokens necessary * @param _amount Quantity of underlying ERC-20 tokens to withdraw */ function withdraw(uint256 _amount) external { checkReentrant(); withdrawInternal(_amount); _status = _NOT_ENTERED; } /** * @notice Deposit multiple specified tokens of the underlying ERC-721 asset and mint ERC-1155 deposit coupon NFTs * @dev Pull pattern, user must approve the contract before calling. * @param _collateralIds Token IDs of underlying ERC-721 to be transferred in */ function depositCollateral(uint256[] calldata _collateralIds) external { checkReentrant(); uint256 len = _collateralIds.length; for (uint256 i; i < len; ) { depositCollateralInternal(_collateralIds[i]); unchecked { ++i; } } _status = _NOT_ENTERED; } /** * @notice Sender borrows assets from the protocol against the specified collateral asset, without a referral code * @dev Collateral must be deposited first. * @param _borrowAmount Amount of underlying ERC-20 to borrow * @param _collateralId Token ID of underlying ERC-721 to be borrowed against */ function borrow(uint256 _borrowAmount, uint256 _collateralId) external { checkReentrant(); borrowInternal(_borrowAmount, _collateralId, "", new bytes(0)); _status = _NOT_ENTERED; } /** * @notice Sender borrows assets from the protocol against the specified collateral asset, using a referral code * @param _borrowAmount Amount of underlying ERC-20 to borrow * @param _collateralId Token ID of underlying ERC-721 to be borrowed against * @param _referral Referral code as a plain string * @param _signature Signed message authorizing the referral, provided by Honey Labs */ function borrowReferred( uint256 _borrowAmount, uint256 _collateralId, string calldata _referral, bytes calldata _signature ) external { checkReentrant(); borrowInternal(_borrowAmount, _collateralId, _referral, _signature); _status = _NOT_ENTERED; } /** * @notice Sender repays a borrow taken against the specified collateral asset * @dev Pull pattern, user must approve the contract before calling. * @param _repayAmount Amount of underlying ERC-20 to repay * @param _collateralId Token ID of underlying ERC-721 to be repaid against * @param _owner Owner of the coupon ID associated with this collateral */ function repayBorrow( uint256 _repayAmount, uint256 _collateralId, address _owner ) external { checkReentrant(); if (_owner == address(0)) _owner = msg.sender; repayBorrowInternal(_owner, _repayAmount, _collateralId, false); _status = _NOT_ENTERED; } /** * @notice Burn deposit coupon NFTs and withdraw the associated underlying ERC-721 NFTs * @param _collateralIds Token IDs of underlying ERC-721 to be withdrawn */ function withdrawCollateral(uint256[] calldata _collateralIds) external { checkReentrant(); uint256 len = _collateralIds.length; for (uint256 i; i < len; ) { withdrawCollateralInternal(_collateralIds[i]); unchecked { ++i; } } _status = _NOT_ENTERED; } /** * @notice Trigger transfer of an NFT to the liquidation contract * @param _collateralId Token ID of underlying ERC-721 to be liquidated */ function liquidateBorrow(uint256 _collateralId) external { checkReentrant(); liquidateBorrowInternal(_collateralId); _status = _NOT_ENTERED; } /** * @notice Pay off the entirety of a liquidated debt position and burn the coupon * @dev May only be called by the liquidator * @param _borrower Owner of the debt position * @param _collateralId Token ID of underlying ERC-721 to be closed out */ function closeoutLiquidation(address _borrower, uint256 _collateralId) external { checkReentrant(); if (!hasRole(LIQUIDATOR_ROLE, msg.sender)) revert Unauthorized(); closeoutLiquidationInternal(_borrower, _collateralId); _status = _NOT_ENTERED; } /** * @notice Accrues all interest due to the protocol * @dev Call this before performing calculations using 'totalBorrows' or other contract-wide quantities */ function accrueInterest() external { checkReentrant(); accrueInterestInternal(); _status = _NOT_ENTERED; } // ----- Utility functions ----- /** * @notice Sweep accidental ERC-20 transfers to this contract. * @dev Tokens are sent to the DAO for later distribution * @param _token The address of the ERC-20 token to sweep */ function sweepToken(IERC20 _token) external { if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender) || _token == underlyingToken) revert Unauthorized(); uint256 balance = _token.balanceOf(address(this)); if (balance > 0) { _token.safeTransfer(dao, balance); } } function checkReentrant() private { if (_status == _ENTERED) revert Reentrant(); _status = _ENTERED; } }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.15; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import ".././interfaces/ControllerI.sol"; import ".././interfaces/HTokenHelperI.sol"; import ".././interfaces/HTokenI.sol"; import ".././interfaces/InterestRateModelI.sol"; import ".././utils/ErrorReporter.sol"; /** * @title Honey Finance's HToken Internal structure contract implemented by HToken * @notice ERC-1155 contract which wraps an ERC-20 underlying liquid asset and an ERC-721 underlying collateral asset * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle * @custom:coauthor m4rio */ contract HTokenInternal is ERC1155, IERC721Receiver, AccessControl { // ----- Imports ----- using SafeERC20 for IERC20Metadata; // ----- Access Control ----- bytes32 public constant SUPPLIER_ROLE = keccak256("SUPPLIER_ROLE"); bytes32 public constant MARKET_ADMIN_ROLE = keccak256("MARKET_ADMIN_ROLE"); bytes32 public constant LIQUIDATOR_ROLE = keccak256("LIQUIDATOR_ROLE"); // ----- Parameters ----- /// @notice The mantissa-formatted maximum borrow rate which can ever be applied (.0005% / block) uint256 private constant borrowRateMaxMantissa = 0.0005e16; /// @notice The mantissa-formatted exchange rate used when hToken totalSupply = 0 uint256 private immutable initialExchangeRateMantissa; /// @notice The mantissa-formatted fraction of interest set aside for reserves uint256 private reserveFactorMantissa; /// @notice The mantissa-formatted fraction of interest accrued to the hToken admin uint256 private adminComissionMantissa; /// @notice The mantissa-formatted fraction of interest accrued to the protocol uint256 private protocolComissionMantissa; /// @notice The mantissa-formatted maximum fraction of interest which can be ever be accrued to reserves or fees uint256 private constant reserveFactorPlusFeesMaxMantissa = 0.5e18; // 50% - TODO: change later /// @notice the name of the token string public name; /// @notice the symbol of the token string public symbol; /// @notice decimals of the ERC-20 underlying token uint8 public immutable decimals; // ----- Addresses ----- /// @notice Receiver of admin fees address private adminCommisionReceiver; /// @notice Receiver of hive fees address private protocolCommisionReceiver; /// @notice DAO address where swept tokens will be transmitted address internal dao; /// @notice Liquidation handler contract address private liquidator; /// @notice Referrer Pool where the referral program fees are collected address private referralPool; /// @notice Contract which oversees inter-hToken operations ControllerI private controller; /// @notice Model which tells what the current interest rate should be InterestRateModelI private interestRateModel; /// @notice Helper contract which handles URI HTokenHelperI private hTokenHelper; /// @notice Underlying ERC-20 borrowable/lendable token IERC20Metadata public immutable underlyingToken; /// @notice Underlying ERC-721 collateral token IERC721 public immutable collateralToken; // ----- State Variables ----- // Bookkeeping uint256 public totalBorrows; uint256 public totalShares; uint256 public totalReserves; uint256 public totalSupply; uint256 public totalProtocolCommission; uint256 public totalAdminCommission; uint256 public totalBorrowFees; uint256 public totalReferredBorrowFees; /// @notice Block number that interest was last accrued at uint256 public accrualBlockNumber; /// @notice Interest that will be earned for each unit of borrow principal uint256 public interestIndexStored; /* a coupon can be in 3 states: when never created is COUPON_UNINITIALIZED, if it is active then COUPON_ACTIVE, if deleted then COUPON_INACTIVE */ uint8 private constant COUPON_UNINITIALIZED = 0; uint8 private constant COUPON_INACTIVE = 1; uint8 private constant COUPON_ACTIVE = 2; uint8 private constant COUPON_LIQUIDATED = 3; uint256 public idCounter; /// @notice Mapping of collateralId => Coupon struct mapping(uint256 => Coupon) public borrowCoupons; /// @notice Mapping of couponId => Collateral struct mapping(uint256 => Collateral) public collateralPerBorrowCouponId; /// @notice Stores how many coupons a user has mapping(address => uint256) public userToCoupons; /// @notice Stores the sharesBalancePerUser so we don't iterate through the coupons to calculate it mapping(address => uint256) public sharesBalancePerUser; struct Coupon { uint32 id; //Coupon's token ID uint8 active; // Coupon activity status address owner; // Who is the current owner of this coupon uint256 collateralId; // tokenId of the collateral collection that is borrowed against uint256 borrowAmount; // Principal borrow balance, denominated in underlying ERC20 token. uint256 debtShares; // Debt shares, keeps the shares of total debt by the protocol } struct Collateral { uint256 collateralId; // TokenId of the collateral bool active; // Collateral activity status } constructor( address _underlyingToken, address _collateralToken, address _controllerAddress, address _interestRateModel, address _liquidator, uint256 _initialExchangeRateMantissa, address _adminCommissionReceiver, address _protocolCommissionReceiver, address _roleReceiver, string memory _name, string memory _symbol ) ERC1155("") { if ( _liquidator == address(0) || _adminCommissionReceiver == address(0) || _protocolCommissionReceiver == address(0) || _underlyingToken == address(0) || _collateralToken == address(0) ) revert WrongParams(); // Set initial exchange rate if (_initialExchangeRateMantissa == 0) revert HTokenError(Error.INITIAL_EXCHANGE_MANTISSA); initialExchangeRateMantissa = _initialExchangeRateMantissa; // Setup the collateral NFT collection if (!IERC721(_collateralToken).supportsInterface(type(IERC721).interfaceId)) revert WrongParams(); collateralToken = IERC721(_collateralToken); // Setting roles _grantRole(DEFAULT_ADMIN_ROLE, _roleReceiver); _grantRole(LIQUIDATOR_ROLE, _liquidator); // Setup underlying token underlyingToken = IERC20Metadata(_underlyingToken); // Setup decimals decimals = IERC20Metadata(_underlyingToken).decimals(); // Set liquidator contract liquidator = _liquidator; // Increment to reserve id 0 for hTokens ++idCounter; // Setup controller controller = ControllerI(_controllerAddress); // Initialize block number accrualBlockNumber = block.number; // Setup interest rate interestRateModel = InterestRateModelI(_interestRateModel); // Set fee receivers adminCommisionReceiver = _adminCommissionReceiver; protocolCommisionReceiver = _protocolCommissionReceiver; name = _name; symbol = _symbol; } // ---------- Lending functions ---------- /** * @dev Deposit underlying tokens and receive hTokens as proof of deposit * @dev Must be approved to transfer amount of underlying tokens. Accrues interest and updates exchange rate. * @param _amount Quantity of underlying ERC-20 to transfer in * @param _to Target address to mint hTokens to */ function depositUnderlyingInternal(uint256 _amount, address _to) internal { controller.depositUnderlyingAllowed(HTokenI(address(this)), _to, _amount); accrueInterestInternal(); uint256 tokensToMint = (_amount * 1e18) / exchangeRateStored(); doUnderlyingTransferIn(msg.sender, _amount); totalSupply += tokensToMint; _mint(_to, 0, tokensToMint, ""); emit UnderlyingDeposited(msg.sender, _to, _amount, tokensToMint, totalSupply); } /** * @dev Redeem a specified amount of hTokens for the corresponding amount of the underlying ERC-20 asset * @dev Accrues interest and updates exchange rate. * @param _amount Quantity of hTokens to redeem for underlying ERC-20 */ function redeemInternal(uint256 _amount) internal { controller.redeemAllowed(HTokenI(address(this)), msg.sender, _amount); accrueInterestInternal(); uint256 underlyingToWithdraw = (_amount * exchangeRateStored()) / 1e18; totalSupply -= _amount; _burn(msg.sender, 0, _amount); doUnderlyingTransferOut(msg.sender, underlyingToWithdraw); emit Redeem(msg.sender, _amount, underlyingToWithdraw, totalSupply); } /** * @dev Withdraw a specified quantity of the underlying ERC-20 asset, redeeming any amount of hTokens necessary * @dev Accrues interest and updates exchange rate. * @param _amount Amount of ERC-20 underlying to be withdrawn */ function withdrawInternal(uint256 _amount) internal { accrueInterestInternal(); uint256 tokensToRedeem = (_amount * 1e18) / exchangeRateStored(); controller.redeemAllowed(HTokenI(address(this)), msg.sender, tokensToRedeem); totalSupply -= tokensToRedeem; _burn(msg.sender, 0, tokensToRedeem); doUnderlyingTransferOut(msg.sender, _amount); emit Withdraw(msg.sender, tokensToRedeem, _amount, totalSupply); } /** * @dev Transfers the ERC-20 underlying token from the contract to the recipient * @param _to Destination address * @param _amount Amount to withdraw */ function doUnderlyingTransferOut(address _to, uint256 _amount) internal { underlyingToken.safeTransfer(_to, _amount); } /** * @dev Transfers the ERC-20 underlying token to the contract * @dev `_from` needs to approve before hand * @param _from Source of the funds * @param _amount Amount to transfer */ function doUnderlyingTransferIn(address _from, uint256 _amount) internal { underlyingToken.safeTransferFrom(_from, address(this), _amount); } // ---------- Borrowing functions ---------- /** * @dev Deposit an ERC-721 collateral NFt * @param _collateralId Token ID of underlying ERC-721 to be transferred in */ function depositCollateralInternal(uint256 _collateralId) internal { controller.depositCollateralAllowed(HTokenI(address(this)), msg.sender, _collateralId); collateralToken.safeTransferFrom(msg.sender, address(this), _collateralId); uint256 couponId = mintCoupon(msg.sender, _collateralId); emit CollateralDeposited(msg.sender, _collateralId, couponId); } /** * @dev Borrow an amount against a specific collateral and accrue it to the coupon * @param _borrowAmount Amount of underlying ERC-20 to borrow * @param _collateralId Token ID of underlying ERC-721 to be borrowed against * @param _referral Referral code as a plain string * @param _signature Signed message authorizing the referral, provided by Honey Labs */ function borrowInternal( uint256 _borrowAmount, uint256 _collateralId, string memory _referral, bytes memory _signature ) internal { Coupon storage coupon = borrowCoupons[_collateralId]; // Coupon must exist if (coupon.active == COUPON_UNINITIALIZED) revert HTokenError(Error.COUPON_LOOKUP); // Sanity check to make sure the coupon was found correctly if (coupon.collateralId != _collateralId) revert WrongParams(); // Only the owner may borrow against a collateral address couponOwner = coupon.owner; if (couponOwner != msg.sender) revert NotOwner(); // The contract must own the relevant tokenId if (collateralToken.ownerOf(_collateralId) != address(this)) revert HTokenError(Error.TOKEN_NOT_PRESENT); accrueInterestInternal(); (uint256 borrowFeeMantissa, bool referred) = controller.getBorrowFeePerMarket( HTokenI(address(this)), _referral, _signature ); uint256 borrowFee = (_borrowAmount * borrowFeeMantissa) / 1e18; uint256 borrowIncurred = _borrowAmount + borrowFee; // Check for borrow allowed controller.borrowAllowed(HTokenI(address(this)), msg.sender, _collateralId, borrowIncurred); uint256 shares = (totalBorrows == 0) ? borrowIncurred : (totalShares * borrowIncurred) / totalBorrows; totalShares += shares; coupon.debtShares += shares; sharesBalancePerUser[couponOwner] += shares; // Add the borrow amount to the token coupon.borrowAmount += borrowIncurred; // Update accounting variables totalBorrows += borrowIncurred; if (referred) { uint256 balanceToReferralPool = (borrowFee * borrowFeeMantissa) / 1e18; totalReferredBorrowFees += balanceToReferralPool; borrowFee -= balanceToReferralPool; emit BorrowReferred(msg.sender, _referral, _borrowAmount, balanceToReferralPool); } totalBorrowFees += borrowFee; // Transfer the funds to borrower doUnderlyingTransferOut(msg.sender, _borrowAmount); emit Borrow(msg.sender, _borrowAmount, _collateralId, borrowIncurred); } /** * @dev Repay a borrow for a given collateral * @param _repayAmount Amount to repay * @param _collateralId Token ID of the ERC-721 collateral asset being repaid against */ function repayBorrowInternal( address _borrower, uint256 _repayAmount, uint256 _collateralId, bool _repayAgainstLiquidated ) internal { // Can't repay 0 amount if (_repayAmount == 0) revert HTokenError(Error.AMOUNT_ZERO); // Accrue interest accrueInterestInternal(); // Controller check for repayBorrow controller.repayBorrowAllowed(HTokenI(address(this)), _repayAmount, _collateralId); // Find the user's coupon Coupon storage coupon = borrowCoupons[_collateralId]; address couponOwner = coupon.owner; if (couponOwner != _borrower) revert Unauthorized(); // Sanity check to make sure the coupon was found correctly if (coupon.collateralId != _collateralId) revert WrongParams(); if (_repayAgainstLiquidated) { if (coupon.active != COUPON_LIQUIDATED) revert HTokenError(Error.REPAY_NOT_ALLOWED); } else { if (coupon.active == COUPON_LIQUIDATED) revert HTokenError(Error.REPAY_NOT_ALLOWED); } // Get outstanding debt uint256 debt = getDebtForCollateral(_collateralId); if (debt == 0) revert HTokenError(Error.NO_DEBT); // Set amount to repay uint256 payment = (_repayAmount > debt) ? debt : _repayAmount; doUnderlyingTransferIn(msg.sender, payment); uint256 interest = debt - coupon.borrowAmount; uint256 borrowAmount = coupon.borrowAmount; unchecked { // If paid amount is > interest, we update borrow amount with the difference, we first pay interest // then we pay the borrowed amount if (interest < payment) { uint256 paidBorrow = payment - interest; borrowAmount = borrowAmount < paidBorrow ? 0 : borrowAmount - paidBorrow; } } // If fully repaid, wipe the whole shares to avoid rounding dust uint256 shares = borrowAmount == 0 ? coupon.debtShares : (totalShares * payment) / totalBorrows; // Decrease balances uint256 newTotalBorrows = totalBorrows - payment; totalBorrows = newTotalBorrows; totalShares -= shares; coupon.debtShares -= shares; coupon.borrowAmount = borrowAmount; sharesBalancePerUser[couponOwner] -= shares; emit RepayBorrow(msg.sender, couponOwner, payment, debt, newTotalBorrows, _collateralId); } /** * @dev Withdraw collateral * @param _collateralId Token ID of the ERC-721 collateral asset to withdraw */ function withdrawCollateralInternal(uint256 _collateralId) internal { Coupon storage activeCoupon = borrowCoupons[_collateralId]; if (activeCoupon.owner != msg.sender) revert Unauthorized(); // checks if withdrawal is allowed, if not will fail controller.withdrawCollateralAllowed(HTokenI(address(this)), _collateralId); uint256 _activeCollateralId = activeCoupon.collateralId; burnAndDelete(msg.sender, _activeCollateralId, activeCoupon.id); collateralToken.safeTransferFrom(address(this), msg.sender, _activeCollateralId); emit CollateralWithdrawn(msg.sender, _collateralId); } /** * @dev Mint a borrow coupon NFT on collateral deposit * @dev Reuses old coupon IDs if they have been previously minted and burned * @param _to Recipient of the coupon * @param _collateralId Token ID of the ERC-721 collateral asset being deposited */ function mintCoupon(address _to, uint256 _collateralId) internal returns (uint256) { uint256 currentId = idCounter; Coupon storage coupon = borrowCoupons[_collateralId]; if (coupon.active > COUPON_UNINITIALIZED) { currentId = coupon.id; } else { ++idCounter; coupon.id = uint32(currentId); } // Construct a coupon coupon.collateralId = _collateralId; coupon.borrowAmount = 0; coupon.active = COUPON_ACTIVE; coupon.debtShares = 0; coupon.owner = _to; collateralPerBorrowCouponId[currentId] = Collateral(_collateralId, true); // Mint NFT _mint(_to, currentId, 1, ""); return currentId; } // ---------- Liquidation functions ---------- /** * @dev Liquidate a borrow and send the collateral to the liquidator contract * @param _collateralId Token ID of the ERC-721 collateral asset to liquidate */ function liquidateBorrowInternal(uint256 _collateralId) internal { Coupon storage activeCoupon = borrowCoupons[_collateralId]; if (activeCoupon.active != COUPON_ACTIVE) revert HTokenError(Error.LIQUIDATION_NOT_ALLOWED); accrueInterestInternal(); //checks if liquidation is allowed, e.g. debt > collateral factor controller.liquidationAllowed(HTokenI(address(this)), _collateralId); activeCoupon.active = COUPON_LIQUIDATED; bytes memory data = abi.encode(address(this)); address cachedLiquidator = liquidator; collateralToken.safeTransferFrom(address(this), cachedLiquidator, _collateralId, data); emit BorrowLiquidated(msg.sender, cachedLiquidator, activeCoupon.owner, _collateralId); } /** * @notice Pay off the entirety of a borrow position and burn the coupon * @dev May only be called by the liquidator * @param _borrower Owner of the debt position * @param _collateralId Token ID of underlying ERC-721 to be closed out */ function closeoutLiquidationInternal(address _borrower, uint256 _collateralId) internal { accrueInterestInternal(); Coupon storage coupon = borrowCoupons[_collateralId]; if (coupon.owner != _borrower) revert Unauthorized(); // Repay borrow uint256 cachedBorrowAmount = getDebtForCollateral(_collateralId); repayBorrowInternal(_borrower, cachedBorrowAmount, _collateralId, true); // Burn the NFT coupon burnAndDelete(_borrower, coupon.collateralId, coupon.id); emit LiquidationClosed(msg.sender, _borrower, _collateralId, cachedBorrowAmount); } /** * @dev Burns a coupon and deletes it from the data structure * @param _account User to burn from * @param _collateralId Collateral associated with this coupon * @param _couponId Coupon ID to burn */ function burnAndDelete( address _account, uint256 _collateralId, uint256 _couponId ) internal { // makes coupon inactive and deletes it from user coupons _burn(_account, _couponId, 1); Coupon storage borrowCoupon = borrowCoupons[_collateralId]; borrowCoupon.active = COUPON_INACTIVE; borrowCoupon.owner = address(0); borrowCoupon.borrowAmount = 0; borrowCoupon.debtShares = 0; collateralPerBorrowCouponId[_couponId].active = false; } // ---------- Exchange rate functions ---------- /** * @notice Calculates the exchange rate from the ERC-20 underlying to the HToken * @dev This function does not accrue interest before calculating the exchange rate. * @dev Call accrueInterest first to get an accurate quantity. * @return Calculated exchange rate scaled by 1e18 */ function exchangeRateStored() public view returns (uint256) { uint256 cachedTotalSupply = totalSupply; if (cachedTotalSupply == 0) { // If there are no tokens minted: exchangeRate = initialExchangeRate return initialExchangeRateMantissa; } else { /* * Otherwise: * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply */ uint256 cashPlusBorrowsMinusReserves = getCashPrior() + totalBorrows - totalReserves; uint256 exchangeRate = (cashPlusBorrowsMinusReserves * 1e18) / cachedTotalSupply; return exchangeRate; } } // ---------- View Helper functions ---------- /** * @notice Get the outstanding debt of a collateral * @dev Simulates accrual of interest * @param _collateralId Token ID of underlying ERC-721 * @return Outstanding debt in units of underlying ERC-20 */ function getDebtForCollateral(uint256 _collateralId) public view returns (uint256) { Coupon storage borrowCoupon = borrowCoupons[_collateralId]; return totalShares == 0 ? 0 : (getDebt() * borrowCoupon.debtShares) / totalShares; } /** * @notice Returns the current per-block borrow interest rate for this hToken * @return The borrow interest rate per block, scaled by 1e18 */ function borrowRatePerBlock() external view returns (uint256) { return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves); } /** * @notice Get the outstanding debt of a coupon * @dev Simulates accrual of interest * @param _couponId ID of the coupon * @return Outstanding debt in units of underlying ERC-20 */ function getDebtForCoupon(uint256 _couponId) external view returns (uint256) { uint256 collateralId = collateralPerBorrowCouponId[_couponId].collateralId; return getDebtForCollateral(collateralId); } /** * @notice Gets balance of this contract in terms of the underlying excluding the fees * @dev This excludes the value of the current message, if any * @return The quantity of underlying ERC-20 tokens owned by this contract */ function getCashPrior() public view returns (uint256) { uint256 totalFees = totalAdminCommission + totalProtocolCommission + totalBorrowFees + totalReferredBorrowFees; uint256 balance = underlyingToken.balanceOf(address(this)); unchecked { if (totalFees > balance) return 0; else return balance - totalFees; } } /** * @notice Get a snapshot of the account's balances, and the cached exchange rate * @dev This is used by controller to more efficiently perform liquidity checks. * @dev Does not accrue interest before calculation. * @param _account Address of the account to snapshot * @return (hToken balance, borrow balance, exchange rate mantissa) */ function getAccountSnapshot(address _account) external view returns ( uint256, uint256, uint256 ) { uint256 userDebt; if (totalShares > 0) userDebt = (sharesBalancePerUser[_account] * totalBorrows) / totalShares; return (balanceOf(_account, 0), userDebt, exchangeRateStored()); } /** * @notice Get the outstanding debt of the protocol * @return Protocol debt */ function getDebt() public view returns (uint256) { uint256 cachedDecimals = decimals; if (decimals < 18) cachedDecimals = 18 - decimals; return totalBorrows + ((totalBorrows * (interestIndex() - interestIndexStored)) / 10**cachedDecimals); } /** * @notice Returns protocol fees * @return Reserve factor mantissa * @return Admin fee mantissa * @return Hive fee mantissa * @return Initial exchange rate mantissa * @return Maximum borrow rate mantissa */ function getProtocolFees() external view returns ( uint256, uint256, uint256, uint256, uint256 ) { return ( reserveFactorMantissa, adminComissionMantissa, protocolComissionMantissa, initialExchangeRateMantissa, borrowRateMaxMantissa ); } /** * @notice Returns different addresses of the protocol * @return Liquidator address * @return HTokenHelper address * @return Controller address * @return Admin Fee Receiver address * @return Hive Fee Receiver address * @return Interest Model address * @return Referral Pool address * @return DAO address */ function getAddresses() external view returns ( address, address, address, address, address, address, address, address ) { return ( address(liquidator), address(hTokenHelper), address(controller), adminCommisionReceiver, protocolCommisionReceiver, address(interestRateModel), referralPool, dao ); } /** * @notice Get the coupon for a specific collateral NFT * @param _collateralId Token ID of underlying ERC-721 * @return Coupon */ function getSpecificCouponByCollateralId(uint256 _collateralId) external view returns (Coupon memory) { return borrowCoupons[_collateralId]; } // ---------- Interest functions ---------- /** * @notice Calculate the prevailing interest due per token of debt principal * @return Mantissa formatted interest rate per token of debt */ function interestIndex() public view returns (uint256) { // Calculate the number of blocks elapsed since the last accrual uint256 blockDelta = block.number - accrualBlockNumber; // Short-circuit if no protocol debt or no blocks elapsed since last calculation uint256 borrowsPrior = totalBorrows; if (borrowsPrior == 0 || blockDelta == 0) { return interestIndexStored; } // Calculate and validate the current borrow interest rate uint256 borrowRateMantissa = interestRateModel.getBorrowRate(getCashPrior(), borrowsPrior, totalReserves); if (borrowRateMantissa > borrowRateMaxMantissa) revert AccrueInterestError(Error.BORROW_RATE_TOO_BIG); uint256 simpleInterestFactor = borrowRateMantissa * blockDelta; return interestIndexStored + (simpleInterestFactor); } /** * @notice Accrues all interest due to the protocol * @dev Call this before performing calculations using 'totalBorrows' or other contract-wide quantities */ function accrueInterestInternal() internal { /* * Calculate the interest accumulated into borrows, fees, and reserves: * interestAccumulated = SUM(individual coupon interest accumulated) * totalBorrows = interestAccumulated + totalBorrows * totalReserves = interestAccumulated * reserveFactor + totalReserves * totalProtocolCommission = interestAccumulated * hiveFee + totalProtocolCommission * totalAdminCommission = interestAccumulated * adminFee + totalAdminCommission */ // We cache the old index uint256 interestIndexStoredCached = interestIndexStored; // Only update if they have not already been updated. if (block.number > accrualBlockNumber) { interestIndexStored = interestIndex(); accrualBlockNumber = block.number; } uint256 cachedDecimals = decimals; if (decimals < 18) { unchecked { cachedDecimals = 18 - decimals; } } // update interest accumulated uint256 interestAccumulated = ((totalBorrows * (interestIndexStored - interestIndexStoredCached)) / 10**cachedDecimals); totalBorrows += interestAccumulated; totalReserves += (reserveFactorMantissa * interestAccumulated) / 1e18; totalProtocolCommission += (protocolComissionMantissa * interestAccumulated) / 1e18; totalAdminCommission += (adminComissionMantissa * interestAccumulated) / 1e18; emit InterestAccrued(interestAccumulated, interestIndexStored, totalBorrows); } /** * @notice Checks if the last accrue interest was called within the same block */ function verifyFreshnessInternal() internal view { if (accrualBlockNumber != block.number) { revert AdminError(Error.MARKET_NOT_FRESH); } } // ---------- Admin Functions ---------- /** * @notice Add to or take away from reserves * @dev Accrues interest * @param _amount Quantity of underlying ERC-20 token to change the reserves by * @param _add True to add reserves, false to remove reserves */ function _modifyReserves(uint256 _amount, bool _add) external { _checkRole(SUPPLIER_ROLE, msg.sender); accrueInterestInternal(); verifyFreshnessInternal(); if (_add) { doUnderlyingTransferIn(msg.sender, _amount); uint256 totalReservesNew = totalReserves + _amount; totalReserves = totalReservesNew; emit ReservesAdded(msg.sender, _amount, totalReservesNew); } else { if (getCashPrior() + totalReserves < _amount) { revert AdminError(Error.TOKEN_INSUFFICIENT_CASH); } if (_amount > totalReserves) { revert AdminError(Error.BAD_INPUT); } unchecked { totalReserves -= _amount; } doUnderlyingTransferOut(msg.sender, _amount); emit ReservesReduced(msg.sender, _amount, totalReserves); } } /** * @notice Set new protocol fee and reserve factor mantissas * @dev Accrues interest * @param _newProtocolCommissionMantissa New protocol fee mantissa * @param _newReserveFactorMantissa New reserve factor mantissa */ function _setProtocolFees(uint256 _newProtocolCommissionMantissa, uint256 _newReserveFactorMantissa) external { _checkRole(DEFAULT_ADMIN_ROLE, msg.sender); accrueInterestInternal(); uint256 cachedAdminCommissionMantissa = adminComissionMantissa; if ( _newReserveFactorMantissa + cachedAdminCommissionMantissa + _newProtocolCommissionMantissa > reserveFactorPlusFeesMaxMantissa ) { revert AdminError(Error.BAD_INPUT); } emit ProtocolFeesUpdated( protocolComissionMantissa, _newProtocolCommissionMantissa, cachedAdminCommissionMantissa, cachedAdminCommissionMantissa, reserveFactorMantissa, _newReserveFactorMantissa ); protocolComissionMantissa = _newProtocolCommissionMantissa; reserveFactorMantissa = _newReserveFactorMantissa; } /** * @notice Set new admin fee mantissa * @dev Accrues interest * @param _newAdminCommissionMantissa New admin fee mantissa */ function _setAdminCommission(uint256 _newAdminCommissionMantissa) external { _checkRole(MARKET_ADMIN_ROLE, msg.sender); accrueInterestInternal(); uint256 cachedProtocolCommissionMantissa = protocolComissionMantissa; uint256 cachedReserveFactorMantissa = reserveFactorMantissa; if ( cachedReserveFactorMantissa + _newAdminCommissionMantissa + cachedProtocolCommissionMantissa > reserveFactorPlusFeesMaxMantissa ) { revert AdminError(Error.BAD_INPUT); } emit ProtocolFeesUpdated( cachedProtocolCommissionMantissa, cachedProtocolCommissionMantissa, adminComissionMantissa, _newAdminCommissionMantissa, cachedReserveFactorMantissa, cachedReserveFactorMantissa ); adminComissionMantissa = _newAdminCommissionMantissa; } /** * @notice Withdraw admin fees * @param _amount Quantity of underlying ERC-20 token to withdraw */ function _withdrawAdminCommissions(uint256 _amount) external { _checkRole(MARKET_ADMIN_ROLE, msg.sender); accrueInterestInternal(); verifyFreshnessInternal(); uint256 cachedTotalAdminCommissions = totalAdminCommission; if (cachedTotalAdminCommissions < _amount) { revert AdminError(Error.AMOUNT_TOO_BIG); } unchecked { totalAdminCommission = cachedTotalAdminCommissions - _amount; } doUnderlyingTransferOut(adminCommisionReceiver, _amount); emit AdminCommissionsWithdrawn(_amount); } /** * @notice Withdraw hive fees * @param _amount Quantity of underlying ERC-20 token to withdraw */ function _withdrawProtocolCommissions(uint256 _amount) external { _checkRole(DEFAULT_ADMIN_ROLE, msg.sender); accrueInterestInternal(); verifyFreshnessInternal(); uint256 cachedTotalProtocolCommissions = totalProtocolCommission; if (cachedTotalProtocolCommissions < _amount) { revert AdminError(Error.AMOUNT_TOO_BIG); } unchecked { totalProtocolCommission = cachedTotalProtocolCommissions - _amount; } doUnderlyingTransferOut(protocolCommisionReceiver, _amount); emit ProtocolCommissionsWithdrawn(_amount); } /** * @notice Withdraw protocol fees * @param _amount Quantity of underlying ERC-20 token to withdraw * @param _referralFees True to withdraw referral fees, false to withdraw borrow fees */ function _withdrawBorrowFees(uint256 _amount, bool _referralFees) external { _checkRole(DEFAULT_ADMIN_ROLE, msg.sender); accrueInterestInternal(); verifyFreshnessInternal(); if (_amount == 0) revert WrongParams(); if ((!_referralFees && totalBorrowFees < _amount) || (_referralFees && totalReferredBorrowFees < _amount)) { revert AdminError(Error.AMOUNT_TOO_BIG); } if (_referralFees) { totalReferredBorrowFees -= _amount; doUnderlyingTransferOut(referralPool, _amount); } else { totalBorrowFees -= _amount; doUnderlyingTransferOut(dao, _amount); } emit BorrowFeesWithdrawn(_amount, _referralFees); } /** * @notice Sets a new protocol address parameter * @dev Callable only by MARKET_ADMIN_ROLE * @dev Target of 3 is reserved by convention for admin fee receiver * @dev Target of 5 is reserved by convention for interest rate model * @param _newAddress Address of the new contract * @param _target Target ID of the address to be set */ function _setAddressMarketAdmin(address _newAddress, uint256 _target) external { if (_newAddress == address(0)) revert WrongParams(); _checkRole(MARKET_ADMIN_ROLE, msg.sender); address oldAddress; if (_target == 3) { oldAddress = adminCommisionReceiver; adminCommisionReceiver = _newAddress; } else if (_target == 5) { oldAddress = address(interestRateModel); interestRateModel = InterestRateModelI(_newAddress); } else revert WrongParams(); emit AddressUpdated(_newAddress, oldAddress, _target); } /** * @notice Sets a new protocol address parameter * @dev Callable only by DEFAULT_ADMIN_ROLE * @dev Target of 3 is reserved by convention for admin fee receiver * @dev Target of 5 is reserved by convention for interest rate model * @param _newAddress Address of the new contract * @param _target Target ID of the address to be set */ function _setAddress(address _newAddress, uint256 _target) external { if (_newAddress == address(0)) revert WrongParams(); _checkRole(DEFAULT_ADMIN_ROLE, msg.sender); address oldAddress; if (_target == 0) { oldAddress = address(liquidator); liquidator = _newAddress; } else if (_target == 1) { oldAddress = address(hTokenHelper); hTokenHelper = HTokenHelperI(_newAddress); } else if (_target == 2) { oldAddress = address(controller); controller = ControllerI(_newAddress); } else if (_target == 4) { oldAddress = protocolCommisionReceiver; protocolCommisionReceiver = _newAddress; } else if (_target == 5) { oldAddress = address(interestRateModel); interestRateModel = InterestRateModelI(_newAddress); } else if (_target == 6) { oldAddress = referralPool; referralPool = _newAddress; } else if (_target == 7) { oldAddress = dao; dao = _newAddress; } else revert WrongParams(); emit AddressUpdated(_newAddress, oldAddress, _target); } // ---------- Overrides ---------- /** * @notice Returns the URI by calling the hTokenHelper * @param _id ID of the token to fetch the URI for */ function uri(uint256 _id) public view virtual override returns (string memory) { return hTokenHelper.uri(_id, address(this)); } /** * @dev See {IERC165-supportsInterface}. * @inheritdoc IERC165 */ function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC1155, AccessControl) returns (bool) { return _interfaceId == type(IERC1155).interfaceId || _interfaceId == type(AccessControl).interfaceId || _interfaceId == type(IERC721Receiver).interfaceId || _interfaceId == type(HTokenI).interfaceId; } /** * @inheritdoc IERC721Receiver */ function onERC721Received( address, address, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC721Received.selector; } function _beforeTokenTransfer( address _operator, address _from, address _to, uint256[] memory _ids, uint256[] memory _amounts, bytes memory _data ) internal virtual override(ERC1155) { if (_from == _to) { super._beforeTokenTransfer(_operator, _from, _to, _ids, _amounts, _data); return; } uint256 len = _ids.length; uint256 lengthToModify; for (uint256 i; i < len; ) { // HTokens don't require coupon management if (_ids[i] > 0) { Collateral storage collateral = collateralPerBorrowCouponId[_ids[i]]; if (!collateral.active) { unchecked { ++i; } continue; } Coupon storage coupon = borrowCoupons[collateral.collateralId]; coupon.owner = _to; uint256 _shares = coupon.debtShares; sharesBalancePerUser[_from] -= _shares; sharesBalancePerUser[_to] += _shares; unchecked { ++lengthToModify; } } unchecked { ++i; } } controller.transferAllowed(HTokenI(address(this))); if (_from != address(0)) { userToCoupons[_from] -= lengthToModify; } if (_to != address(0)) { userToCoupons[_to] += lengthToModify; } super._beforeTokenTransfer(_operator, _from, _to, _ids, _amounts, _data); } // ---------- Events ---------- // ---------- Market Events ---------- event InterestAccrued(uint256 _interestAccumulated, uint256 _interestIndex, uint256 _totalBorrows); event Redeem(address indexed _initiator, uint256 _redeemAmount, uint256 _tokensWithdrawn, uint256 _totalHTokenSupply); event Withdraw( address indexed _initiator, uint256 _redeemAmount, uint256 _tokensWithdrawn, uint256 _totalHTokenSupply ); event UnderlyingDeposited( address indexed _initiator, address indexed _to, uint256 _amount, uint256 _tokensToMint, uint256 _totalhTokenSupply ); event Borrow(address indexed _borrower, uint256 _borrowAmount, uint256 _tokenId, uint256 _totalBorrows); event BorrowReferred(address indexed _initiator, string _referrer, uint256 _amount, uint256 _fee); event RepayBorrow( address indexed _payer, address indexed _borrower, uint256 _repayAmount, uint256 _accountBorrows, uint256 _totalBorrows, uint256 _collateralId ); event CollateralDeposited(address indexed _initiator, uint256 _collateralId, uint256 _couponId); event CollateralWithdrawn(address indexed _initiator, uint256 _collateralId); event BorrowLiquidated( address indexed _initiator, address indexed _liquidator, address _owner, uint256 _collateralId ); event LiquidationClosed( address indexed _initiator, address indexed _borrower, uint256 _collateralId, uint256 _borrowAmount ); // ---------- Admin Events ---------- event AddressUpdated(address indexed _oldAddress, address indexed _newAddress, uint256 _target); event ReservesAdded(address indexed _supplier, uint256 _addAmount, uint256 _newTotalReserves); event ReservesReduced(address indexed _supplier, uint256 _reduceAmount, uint256 _newTotalReserves); event AdminCommissionsWithdrawn(uint256 _amount); event ProtocolCommissionsWithdrawn(uint256 _amount); event BorrowFeesWithdrawn(uint256 _amount, bool _referralFees); event ProtocolFeesUpdated( uint256 _oldProtocolCommission, uint256 _newProtocolCommission, uint256 _oldAdminCommission, uint256 _newAdminCommission, uint256 _oldReserveFactor, uint256 _newReserveFactor ); }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; import "./HTokenI.sol"; import "./PermissionlessOracleI.sol"; /** * @title Interface of Controller * @author Honey Labs Inc. * @custom:coauthor m4rio * @custom:contributor BowTiedPickle */ interface ControllerI { /** * @notice returns the oracle per market */ function oracle(HTokenI _hToken) external view returns (PermissionlessOracleI); /** * @notice Add assets to be included in account liquidity calculation * @param _hTokens The list of addresses of the hToken markets to be enabled */ function enterMarkets(HTokenI[] calldata _hTokens) external; /** * @notice Removes asset from sender's account liquidity calculation * @dev Sender must not have an outstanding borrow balance in the asset, * or be providing necessary collateral for an outstanding borrow. * @param _hToken The address of the asset to be removed */ function exitMarket(HTokenI _hToken) external; /** * @notice Checks if the account should be allowed to deposit underlying in the market * @param _hToken The market to verify the redeem against * @param _depositor The account which that wants to deposit * @param _amount The number of underlying it wants to deposit */ function depositUnderlyingAllowed( HTokenI _hToken, address _depositor, uint256 _amount ) external; /** * @notice Checks if the account should be allowed to borrow the underlying asset of the given market * @param _hToken The market to verify the borrow against * @param _borrower The account which would borrow the asset * @param _collateralId collateral Id, aka the NFT token Id * @param _borrowAmount The amount of underlying the account would borrow */ function borrowAllowed( HTokenI _hToken, address _borrower, uint256 _collateralId, uint256 _borrowAmount ) external; /** * @notice Checks if the account should be allowed to deposit a collateral * @param _hToken The market to verify the deposit of the collateral * @param _depositor The account which deposits the collateral * @param _collateralId The collateral token id */ function depositCollateralAllowed( HTokenI _hToken, address _depositor, uint256 _collateralId ) external; /** * @notice Checks if the account should be allowed to redeem tokens in the given market * @param _hToken The market to verify the redeem against * @param _redeemer The account which would redeem the tokens * @param _redeemTokens The number of hTokens to exchange for the underlying asset in the market */ function redeemAllowed( HTokenI _hToken, address _redeemer, uint256 _redeemTokens ) external view; /** * @notice Checks if the collateral is at risk of being liquidated * @param _hToken The market to verify the liquidation * @param _collateralId collateral Id, aka the NFT token Id */ function liquidationAllowed(HTokenI _hToken, uint256 _collateralId) external view; /** * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed * @param _hToken The market to hypothetically redeem/borrow in * @param _account The account to determine liquidity for * @param _redeemTokens The number of tokens to hypothetically redeem * @param _borrowAmount The amount of underlying to hypothetically borrow * @param _collateralId collateral Id, aka the NFT token Id * @return liquidity - hypothetical account liquidity in excess of collateral requirements * @return shortfall - hypothetical account shortfall below collateral requirements * @return ltvShortfall - Loan to value shortfall, this is the max a user can borrow */ function getHypotheticalAccountLiquidity( HTokenI _hToken, address _account, uint256 _collateralId, uint256 _redeemTokens, uint256 _borrowAmount ) external view returns ( uint256 liquidity, uint256 shortfall, uint256 ltvShortfall ); /** * @notice Returns whether the given account is entered in the given asset * @param _hToken The hToken to check * @param _account The address of the account to check * @return True if the account is in the asset, otherwise false. */ function checkMembership(HTokenI _hToken, address _account) external view returns (bool); /** * @notice Checks if the account should be allowed to transfer tokens in the given market * @param _hToken The market to verify the transfer against */ function transferAllowed(HTokenI _hToken) external; /** * @notice Checks if the account should be allowed to repay a borrow in the given market * @param _hToken The market to verify the repay against * @param _repayAmount The amount of the underlying asset the account would repay * @param _collateralId collateral Id, aka the NFT token Id */ function repayBorrowAllowed( HTokenI _hToken, uint256 _repayAmount, uint256 _collateralId ) external view; /** * @notice checks if withdrawal are allowed for this token id * @param _hToken The market to verify the withdrawal from * @param _collateralId what to pay for */ function withdrawCollateralAllowed(HTokenI _hToken, uint256 _collateralId) external view; /** * @notice checks if a market exists and it's listed * @param _hToken the market we check to see if it exists * @return bool true or false */ function marketExists(HTokenI _hToken) external view returns (bool); /** * @notice Returns market data for a specific market * @param _hToken the market we want to retrieved Controller data * @return bool If the market is listed * @return uint256 MAX Factor Mantissa * @return uint256 Collateral Factor Mantissa */ function getMarketData(HTokenI _hToken) external view returns ( bool, uint256, uint256 ); /** * @notice checks if an underlying exists in the market * @param _underlying the underlying to check if exists * @return bool true or false */ function underlyingExistsInMarkets(address _underlying) external view returns (bool); /** * @notice checks if a collateral exists in the market * @param _collateral the collateral to check if exists * @return bool true or false */ function collateralExistsInMarkets(address _collateral) external view returns (bool); /** * @notice Checks if a certain action is paused within a market * @param _hToken The market we want to check if an action is paused * @param _target The action we want to check if it's paused * @return bool true or false */ function isActionPaused(HTokenI _hToken, uint256 _target) external view returns (bool); /** * @notice returns the borrow fee per market, accounts for referral * @param _hToken the market we want the borrow fee for * @param _referral referral code for Referral program of Honey Labs * @param _signature signed message provided by Honey Labs */ function getBorrowFeePerMarket( HTokenI _hToken, string calldata _referral, bytes calldata _signature ) external view returns (uint256, bool); /** * @notice returns the borrow fee per market if provided a referral code, accounts for referral * @param _hToken the market we want the borrow fee for */ function getReferralBorrowFeePerMarket(HTokenI _hToken) external view returns (uint256); // ---------- Permissioned Functions ---------- function _supportMarket(HTokenI _hToken) external; function _setPriceOracle(HTokenI _hToken, PermissionlessOracleI _newOracle) external; function _setFactors( HTokenI _hToken, uint256 _newMaxLTVFactorMantissa, uint256 _newCollateralFactorMantissa ) external; function _setBorrowFeePerMarket( HTokenI _market, uint256 _fee, uint256 _referralFee ) external; function _pauseComponent( HTokenI _hToken, bool _state, uint256 _target ) external; }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; import "./ControllerI.sol"; import "./HTokenInternalI.sol"; /** * @title Interface of Control Panel * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle */ interface ControlPanelI { function deployHToken( address _underlyingToken, address _collateralToken, address _interestRateModel, address _adminFeeReceiver, address _oracle, uint256 _collateralFactorMantissa, uint256 _maxLTVFactorMantissa ) external; }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; import "../htoken/HToken.sol"; /** * @title Honey Finance Factory * @notice Factory that deploys a new HToken * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle * @custom:coauthor m4rio */ interface HTokenFactoryI { function deployHToken( address _underlyingToken, address _collateralToken, address _controllerAddress, address _interestRateModel, address _liquidator, uint256 _initialExchangeRateMantissa, address _adminFeeReceiver, address _hiveFeeReceiver, string memory _name, string memory _symbol ) external returns (address); }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; import ".././interfaces/HTokenI.sol"; import ".././interfaces/PriceOracleI.sol"; import ".././interfaces/ControllerI.sol"; /** * @title Interface for HTokenHelper * @author Honey Labs Inc. * @custom:coauthor m4rio * @custom:contributor BowTiedPickle */ interface HTokenHelperI { /** * @notice Get cash balance of this hToken in the underlying asset * @return The quantity of underlying asset owned by this contract */ function getCash(HTokenI _hToken) external view returns (uint256); /** * @notice Get underlying balance that is available for withdrawal or borrow * @return The quantity of underlying not tied up */ function getAvailableUnderlying(HTokenI _hToken) external view returns (uint256); /** * @notice Get underlying balance for an account * @param _account the account to check the balance for * @return The quantity of underlying asset owned by this account */ function getAvailableUnderlyingForUser(HTokenI _hToken, address _account) external view returns (uint256); /** * @notice Get underlying balance that is available to be withdrawn * @return The quantity of underlying that can be borrowed */ function getAvailableUnderlyingToBorrow(HTokenI _hToken) external view returns (uint256); /** * @notice returns different assets per a hToken, helper method to reduce frontend calls * @param _hToken the hToken to get the assets for * @return total borrows * @return total reserves * @return total underlying balance * @return active coupons */ function getAssets(HTokenI _hToken) external view returns ( uint256, uint256, uint256, HTokenI.Coupon[] memory ); /** * @notice Get all a user's coupons * @param _hToken The HToken we want to get the user's coupons from * @param _user The user to search for * @return Array of all coupons belonging to the user */ function getUserCoupons(HTokenI _hToken, address _user) external view returns (HTokenI.Coupon[] memory); /** * @notice Get the number of coupons deposited aka active * @param _hToken The HToken we want to get the active User Coupons * @param _hasDebt if the coupon has debt or not * @return Array of all active coupons */ function getActiveCoupons(HTokenI _hToken, bool _hasDebt) external view returns (HTokenI.Coupon[] memory); /** * @notice Get tokenIds of all a user's coupons * @param _hToken The HToken we want to get the User Coupon Indices * @param _user The user to search for * @return Array of indices of all coupons belonging to the user */ function getUserCouponIndices(HTokenI _hToken, address _user) external view returns (uint256[] memory); /** * @notice returns prices for a market to reduce frontend calls * @param _hToken the hToken to get the prices for * @return collection floor price in underlying value * @return underlying price in usd */ function getMarketOraclePrices(HTokenI _hToken) external view returns (uint256, uint256); /** * @notice Returns the borrow fee for a market, it can also return the discounted fee for referred borrow * @param _hToken The market we want to get the borrow fee for * @param _referred Flag that needs to be true in case we want to get the referred borrow fee * @return fee - The borrow fee mantissa denominated in 1e18 */ function getMarketBorrowFee(HTokenI _hToken, bool _referred) external view returns (uint256 fee); /** * @notice returns the collection price floor in usd * @param _hToken the hToken to get the price for * @return collection floor price in usd */ function getFloorPriceInUSD(HTokenI _hToken) external view returns (uint256); /** * @notice returns the collection price floor in underlying value * @param _hToken the hToken to get the price for * @return collection floor price in underlying */ function getFloorPriceInUnderlying(HTokenI _hToken) external view returns (uint256); /** * @notice get the underlying price in usd for a hToken * @param _hToken the hToken to get the price for * @return underlying price in usd */ function getUnderlyingPriceInUSD(HTokenI _hToken) external view returns (uint256); /** * @notice get the max borrowable amount for a market * @notice it computes the floor price in usd and take the % of collateral factor that can be max borrowed * then it divides it by the underlying price in usd. * @param _hToken the hToken to get the price for * @param _hivemind the controller used to get the collateral factor * @return underlying price in underlying */ function getMaxBorrowableAmountInUnderlying(HTokenI _hToken, ControllerI _hivemind) external view returns (uint256); /** * @notice get the max borrowable amount for a market * @notice it computes the floor price in usd and take the % of collateral factor that can be max borrowed * @param _hToken the hToken to get the price for * @param _hivemind the controller used to get the collateral factor * @return underlying price in usd */ function getMaxBorrowableAmountInUSD(HTokenI _hToken, ControllerI _hivemind) external view returns (uint256); /** * @notice get's all the coupons that have deposited collateral * @param _hToken market to get the collateral from * @param _startTokenId start token id of the collateral collection, as we don't know how big the collection will be we have * to do pagination * @param _endTokenId end of token id we want to get. * @return coupons list of coupons that are active */ function getAllCollateralPerHToken( HTokenI _hToken, uint256 _startTokenId, uint256 _endTokenId ) external view returns (HTokenI.Coupon[] memory coupons); /** * @notice Gets data about a market for frontend display * @param _hToken the market we want the data for * @return interest rate of the market * @return total underlying supplied in a market * @return total underlying available to be borrowed */ function getFrontendMarketData(HTokenI _hToken) external view returns ( uint256, uint256, uint256 ); /** * @notice Gets data about a coupon for frontend display * @param _hToken The market we want the coupon for * @param _couponId The coupon id we want to get the data for * @return debt of this coupon * @return allowance - how much liquidity can borrow till hitting LTV * @return nft floor price */ function getFrontendCouponData(HTokenI _hToken, uint256 _couponId) external view returns ( uint256, uint256, uint256 ); /** * @notice Gets Liquidation data for a market, for frontend purposes * @param _hToken the market we want the data for * @return Liquidation threshold of a market (collateral factor) * @return Total debt of the market * @return TVL of a market which consists of the total coupons that have debt */ function getFrontendLiquidationData(HTokenI _hToken) external view returns ( uint256, uint256, uint256 ); /** * @notice uri function called from the HToken that returns the uri metadata for a coupon * @param _id id of the hToken * @param _hTokenAddress address of the hToken */ function uri(uint256 _id, address _hTokenAddress) external view returns (string memory); }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; import "./HTokenInternalI.sol"; /** * @title Interface of HToken * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle * @custom:coauthor m4rio */ interface HTokenI is HTokenInternalI { /** * @notice Deposit underlying ERC-20 asset and mint hTokens * @dev Pull pattern, user must approve the contract before calling. If _to is address(0) then it becomes msg.sender * @param _amount Quantity of underlying ERC-20 to transfer in * @param _to Target address to mint hTokens to */ function depositUnderlying(uint256 _amount, address _to) external; /** * @notice Redeem a specified amount of hTokens for their underlying ERC-20 asset * @param _amount Quantity of hTokens to redeem for underlying ERC-20 */ function redeem(uint256 _amount) external; /** * @notice Withdraws the specified amount of underlying ERC-20 asset, consuming the minimum amount of hTokens necessary * @param _amount Quantity of underlying ERC-20 tokens to withdraw */ function withdraw(uint256 _amount) external; /** * @notice Deposit multiple specified tokens of the underlying ERC-721 asset and mint ERC-1155 deposit coupon NFTs * @dev Pull pattern, user must approve the contract before calling. * @param _collateralIds Token IDs of underlying ERC-721 to be transferred in */ function depositCollateral(uint256[] calldata _collateralIds) external; /** * @notice Sender borrows assets from the protocol against the specified collateral asset, without a referral code * @dev Collateral must be deposited first. * @param _borrowAmount Amount of underlying ERC-20 to borrow * @param _collateralId Token ID of underlying ERC-721 to be borrowed against */ function borrow(uint256 _borrowAmount, uint256 _collateralId) external; /** * @notice Sender borrows assets from the protocol against the specified collateral asset, using a referral code * @param _borrowAmount Amount of underlying ERC-20 to borrow * @param _collateralId Token ID of underlying ERC-721 to be borrowed against * @param _referral Referral code as a plain string * @param _signature Signed message authorizing the referral, provided by Honey Labs */ function borrowReferred( uint256 _borrowAmount, uint256 _collateralId, string calldata _referral, bytes calldata _signature ) external; /** * @notice Sender repays a borrow taken against the specified collateral asset * @dev Pull pattern, user must approve the contract before calling. * @param _repayAmount Amount of underlying ERC-20 to repay * @param _collateralId Token ID of underlying ERC-721 to be repaid against */ function repayBorrow( uint256 _repayAmount, uint256 _collateralId, address _to ) external; /** * @notice Burn deposit coupon NFTs and withdraw the associated underlying ERC-721 NFTs * @param _collateralIds Token IDs of underlying ERC-721 to be withdrawn */ function withdrawCollateral(uint256[] calldata _collateralIds) external; /** * @notice Trigger transfer of an NFT to the liquidation contract * @param _collateralId Token ID of underlying ERC-721 to be liquidated */ function liquidateBorrow(uint256 _collateralId) external; /** * @notice Pay off the entirety of a liquidated debt position and burn the coupon * @dev May only be called by the liquidator * @param _borrower Owner of the debt position * @param _collateralId Token ID of underlying ERC-721 to be closed out */ function closeoutLiquidation(address _borrower, uint256 _collateralId) external; /** * @notice Accrues all interest due to the protocol * @dev Call this before performing calculations using 'totalBorrows' or other contract-wide quantities */ function accrueInterest() external; // ----- Utility functions ----- /** * @notice Sweep accidental ERC-20 transfers to this contract. * @dev Tokens are sent to the DAO for later distribution * @param _token The address of the ERC-20 token to sweep */ function sweepToken(IERC20 _token) external; }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import "@openzeppelin/contracts/access/IAccessControl.sol"; /** * @title Interface of HToken Internal * @author Honey Labs Inc. * @custom:coauthor m4rio * @custom:coauthor BowTiedPickle */ interface HTokenInternalI is IERC1155, IAccessControl { struct Coupon { uint32 id; //Coupon's id uint8 active; // Coupon activity status address owner; // Who is the current owner of this coupon uint256 collateralId; // tokenId of the collateral collection that is borrowed against uint256 borrowAmount; // Principal borrow balance, denominated in underlying ERC20 token. uint256 debtShares; // Debt shares, keeps the shares of total debt by the protocol } struct Collateral { uint256 collateralId; // TokenId of the collateral bool active; // Collateral activity status } // ----- Informational ----- function decimals() external view returns (uint8); function name() external view returns (string memory); function symbol() external view returns (string memory); // ----- Addresses ----- function collateralToken() external view returns (IERC721); function underlyingToken() external view returns (IERC20); // ----- Protocol Accounting ----- function totalBorrows() external view returns (uint256); function totalReserves() external view returns (uint256); function totalSupply() external view returns (uint256); function totalFuseFees() external view returns (uint256); function totalAdminCommission() external view returns (uint256); function accrualBlockNumber() external view returns (uint256); function interestIndexStored() external view returns (uint256); function totalProtocolCommissions() external view returns (uint256); function userToCoupons(address _user) external view returns (uint256); function collateralPerBorrowCouponId(uint256 _couponId) external view returns (Collateral memory); function borrowCoupons(uint256 _collateralId) external view returns (Coupon memory); // ----- Views ----- /** * @notice Get the outstanding debt of a collateral * @dev Simulates accrual of interest * @param _collateralId Token ID of underlying ERC-721 * @return Outstanding debt in units of underlying ERC-20 */ function getDebtForCollateral(uint256 _collateralId) external view returns (uint256); /** * @notice Returns the current per-block borrow interest rate for this hToken * @return The borrow interest rate per block, scaled by 1e18 */ function borrowRatePerBlock() external view returns (uint256); /** * @notice Get the outstanding debt of a coupon * @dev Simulates accrual of interest * @param _couponId ID of the coupon * @return Outstanding debt in units of underlying ERC-20 */ function getDebtForCoupon(uint256 _couponId) external view returns (uint256); /** * @notice Gets balance of this contract in terms of the underlying excluding the fees * @dev This excludes the value of the current message, if any * @return The quantity of underlying ERC-20 tokens owned by this contract */ function getCashPrior() external view returns (uint256); /** * @notice Get a snapshot of the account's balances, and the cached exchange rate * @dev This is used by controller to more efficiently perform liquidity checks. * @param _account Address of the account to snapshot * @return (token balance, borrow balance, exchange rate mantissa) */ function getAccountSnapshot(address _account) external view returns ( uint256, uint256, uint256 ); /** * @notice Get the outstanding debt of the protocol * @return Protocol debt */ function getDebt() external view returns (uint256); /** * @notice Returns protocol fees * @return Reserve factor mantissa * @return Admin fee mantissa * @return Hive fee mantissa * @return Initial exchange rate mantissa * @return Maximum borrow rate mantissa */ function getProtocolFees() external view returns ( uint256, uint256, uint256, uint256, uint256 ); /** * @notice Returns different addresses of the protocol * @return Liquidator address * @return HTokenHelper address * @return Controller address * @return Admin Fee Receiver address * @return Hive Fee Receiver address * @return Interest Model address * @return Referral Pool address * @return DAO address */ function getAddresses() external view returns ( address, address, address, address, address, address, address, address ); /** * @notice Get the last minted coupon ID * @return The last minted coupon ID */ function idCounter() external view returns (uint256); /** * @notice Get the coupon for a specific collateral NFT * @param _collateralId Token ID of underlying ERC-721 * @return Coupon */ function getSpecificCouponByCollateralId(uint256 _collateralId) external view returns (Coupon memory); /** * @notice Calculate the prevailing interest due per token of debt principal * @return Mantissa formatted interest rate per token of debt */ function interestIndex() external view returns (uint256); /** * @notice Accrue interest then return the up-to-date exchange rate from the ERC-20 underlying to the HToken * @return Calculated exchange rate scaled by 1e18 */ function exchangeRateCurrent() external returns (uint256); /** * @notice Calculates the exchange rate from the ERC-20 underlying to the HToken * @dev This function does not accrue interest before calculating the exchange rate * @return Calculated exchange rate scaled by 1e18 */ function exchangeRateStored() external view returns (uint256); /** * @notice Add to or take away from reserves * @dev Accrues interest * @param _amount Quantity of underlying ERC-20 token to change the reserves by */ function _modifyReserves(uint256 _amount, bool _add) external; /** * @notice Set new admin fee mantissas * @dev Accrues interest * @param _newAdminCommissionMantissa New admin fee mantissa */ function _setAdminCommission(uint256 _newAdminCommissionMantissa) external; /** * @notice Set new protocol commission and reserve factor mantissas * @dev Accrues interest * @param _newProtocolCommissionMantissa New protocol commission mantissa * @param _newReserveFactorMantissa New reserve factor mantissa */ function _setProtocolFees(uint256 _newProtocolCommissionMantissa, uint256 _newReserveFactorMantissa) external; /** * @notice Sets a new admin fee receiver * @param _newAddress Address of the new admin fee receiver * @param _target Target ID of the address to be set */ function _setAddressMarketAdmin(address _newAddress, uint256 _target) external; }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; /** * @title Modified Compound's InterestRateModel Interface * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle * @custom:contributor m4rio */ interface InterestRateModelI { /** * @notice Calculates the current borrow rate per block * @param _cash The amount of cash in the market * @param _borrows The amount of borrows in the market * @param _reserves The amount of reserves in the market * @return The borrow rate percentage per block as a mantissa (scaled by 1e18) */ function getBorrowRate( uint256 _cash, uint256 _borrows, uint256 _reserves ) external view returns (uint256); /** * @notice Calculates the current supply rate per block * @param _cash The amount of cash in the market * @param _borrows The amount of borrows in the market * @param _reserves The amount of reserves in the market * @param _reserveFactorMantissa The current reserve factor for the market * @return The supply rate percentage per block as a mantissa (scaled by 1e18) */ function getSupplyRate( uint256 _cash, uint256 _borrows, uint256 _reserves, uint256 _reserveFactorMantissa ) external view returns (uint256); /** * @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)` * @param _cash The amount of cash in the market * @param _borrows The amount of borrows in the market * @param _reserves The amount of reserves in the market * @return The utilization rate as a mantissa between [0, 1e18] */ function utilizationRate( uint256 _cash, uint256 _borrows, uint256 _reserves ) external pure returns (uint256); /** * * @param _interfaceId The interface identifier, as specified in ERC-165 */ function supportsInterface(bytes4 _interfaceId) external view returns (bool); }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import "../interfaces/HTokenI.sol"; /** * @title Interface of Liquidator * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle * @custom:contributor m4rio */ interface LiquidatorI is IERC721Receiver { function isRegisteredUnderlying(address _token) external view returns (bool); function isRegisteredHToken(address _hToken) external view returns (bool); function _initializeHToken(HTokenI _hToken) external; }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; import "./HTokenI.sol"; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; /** * @title PermissionlessOracleI interface for the Permissionless oracle * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle * @custom:coauthor m4rio */ interface PermissionlessOracleI { /** * @notice returns the price (in eth) for the floor of a collection * @param _collection address of the collection * @param _decimals adjust decimals of the returned price */ function getFloorPrice(address _collection, uint256 _decimals) external view returns (uint128, uint128); /** * @notice returns the latest price for a given pair * @param _erc20 the erc20 we want to get the price for in USD * @param _decimals decimals to denote the result in */ function getUnderlyingPriceInUSD(IERC20 _erc20, uint256 _decimals) external view returns (uint256); /** * @notice get price of eth * @param _decimals adjust decimals of the returned price */ function getEthPrice(uint256 _decimals) external view returns (uint256); /** * @notice get price feeds for a token * @return returns the Chainlink Aggregator interface */ function priceFeeds(IERC20 _token) external view returns (AggregatorV3Interface); /** * @notice returns the update threshold for a specific _collection */ function updateThreshold(address _collection) external view returns (uint256); /** * @notice returns the number of floors for a specific _collection * @param _address address of the collection * */ function getNoOfFloors(address _address) external view returns (uint256); /** * @notice returns the last updated timestamp for a specific _collection * @param _collection address of the collection * */ function getLastUpdated(address _collection) external view returns (uint256); }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.8.4; import "./HTokenI.sol"; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; /** * @title PriceOracle interface for Chainlink oracles * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle * @custom:coauthor m4rio */ interface PriceOracleI { /** * @notice returns the underlying price for the floor of a collection * @param _collection address of the collection * @param _decimals adjust decimals of the returned price */ function getFloorPrice(address _collection, uint256 _decimals) external view returns (uint128, uint128); /** * @notice returns the underlying price for an individual token id * @param _collection address of the collection * @param _tokenId token id within this collection * @param _decimals adjust decimals of the returned price */ function getUnderlyingIndividualNFTPrice( address _collection, uint256 _tokenId, uint256 _decimals ) external view returns (uint256); /** * @notice returns the latest price for a given pair * @param _erc20 the erc20 we want to get the price for in USD * @param _decimals decimals to denote the result in */ function getUnderlyingPriceInUSD(IERC20 _erc20, uint256 _decimals) external view returns (uint256); /** * @notice get price of eth * @param _decimals adjust decimals of the returned price */ function getEthPrice(uint256 _decimals) external view returns (uint256); /** * @notice get price feeds for a token * @return returns the Chainlink Aggregator interface */ function priceFeeds(IERC20 _token) external view returns (AggregatorV3Interface); /** * @notice returns the update threshold */ function updateThreshold() external view returns (uint256); }
//SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.15; error Unauthorized(); error AccrueInterestError(Error error); error WrongParams(); error Unexpected(string error); error InvalidCoupon(); error ControllerError(Error error); error AdminError(Error error); error MarketError(Error error); error HTokenError(Error error); error LiquidatorError(Error error); error ControlPanelError(Error error); error HTokenFactoryError(Error error); error PausedAction(); error NotOwner(); error ExternalFailure(string error); error Initialized(); error Uninitialized(); error OracleNotUpdated(); error TransferError(); error StalePrice(); /** * @title Errors reported across Honey Labs Inc. contracts * @author Honey Labs Inc. * @custom:coauthor BowTiedPickle * @custom:coauthor m4rio */ enum Error { UNAUTHORIZED, //0 INSUFFICIENT_LIQUIDITY, INVALID_COLLATERAL_FACTOR, MAX_MARKETS_IN, MARKET_NOT_LISTED, MARKET_ALREADY_LISTED, //5 MARKET_CAP_BORROW_REACHED, MARKET_NOT_FRESH, PRICE_ERROR, BAD_INPUT, AMOUNT_ZERO, //10 NO_DEBT, LIQUIDATION_NOT_ALLOWED, WITHDRAW_NOT_ALLOWED, INITIAL_EXCHANGE_MANTISSA, TRANSFER_ERROR, //15 COUPON_LOOKUP, TOKEN_INSUFFICIENT_CASH, BORROW_RATE_TOO_BIG, NONZERO_BORROW_BALANCE, AMOUNT_TOO_BIG, //20 AUCTION_NOT_ACTIVE, AUCTION_FINISHED, AUCTION_NOT_FINISHED, AUCTION_BID_TOO_LOW, AUCTION_NO_BIDS, //25 CLAWBACK_WINDOW_EXPIRED, CLAWBACK_WINDOW_NOT_EXPIRED, REFUND_NOT_OWED, TOKEN_LOOKUP_ERROR, INSUFFICIENT_WINNING_BID, //30 TOKEN_DEBT_NONEXISTENT, AUCTION_SETTLE_FORBIDDEN, NFT20_PAIR_NOT_FOUND, NFTX_PAIR_NOT_FOUND, TOKEN_NOT_PRESENT, //35 CANCEL_TOO_SOON, AUCTION_USER_NOT_FOUND, NOT_FOUND, INVALID_MAX_LTV_FACTOR, BALANCE_INSUFFICIENT, //40 ORACLE_NOT_SET, MARKET_INVALID, FACTORY_INVALID_COLLATERAL, FACTORY_INVALID_UNDERLYING, FACTORY_INVALID_ORACLE, //45 FACTORY_DEPLOYMENT_FAILED, REPAY_NOT_ALLOWED, NONZERO_UNDERLYING_BALANCE, INVALID_ACTION, ORACLE_IS_PRESENT, //50 FACTORY_INVALID_UNDERLYING_DECIMALS, FACTORY_INVALID_INTEREST_RATE_MODEL }
{ "optimizer": { "enabled": true, "runs": 300 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"enum Error","name":"error","type":"uint8"}],"name":"ControlPanelError","type":"error"},{"inputs":[{"internalType":"enum Error","name":"error","type":"uint8"}],"name":"HTokenFactoryError","type":"error"},{"inputs":[],"name":"PausedAction","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"WrongParams","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oldAddress","type":"address"},{"indexed":true,"internalType":"address","name":"_newAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_target","type":"uint256"}],"name":"AddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_collateral","type":"address"},{"indexed":false,"internalType":"bool","name":"_status","type":"bool"}],"name":"CollateralStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_state","type":"bool"}],"name":"ControllerPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_defaultBorrowFeeMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_defaultReferredBorrowFeeMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_defaultProtocolCommissionMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_defaultReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_defaultInitialExchangeRateMantissa","type":"uint256"}],"name":"DefaultsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_deployer","type":"address"},{"indexed":true,"internalType":"address","name":"_hToken","type":"address"},{"indexed":true,"internalType":"address","name":"_underlying","type":"address"},{"indexed":true,"internalType":"address","name":"_collateral","type":"address"},{"indexed":false,"internalType":"contract ControllerI","name":"_controller","type":"address"},{"indexed":false,"internalType":"contract LiquidatorI","name":"_liquidator","type":"address"},{"indexed":false,"internalType":"uint256","name":"_exchangeRateMantissa","type":"uint256"},{"indexed":false,"internalType":"address","name":"_hiveFeeReceiver","type":"address"},{"indexed":false,"internalType":"string","name":"_name","type":"string"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"}],"name":"HTokenDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oracle","type":"address"},{"indexed":false,"internalType":"bool","name":"_status","type":"bool"}],"name":"OracleStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_hToken","type":"address"},{"indexed":true,"internalType":"address","name":"_oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_underlying","type":"address"},{"indexed":false,"internalType":"bool","name":"_status","type":"bool"}],"name":"UnderlyingStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_state","type":"bool"}],"name":"_pauseControlPanel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newAddress","type":"address"},{"internalType":"uint256","name":"_target","type":"uint256"}],"name":"_setAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"_setCollateralStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_defaultBorrowFeeMantissa","type":"uint256"},{"internalType":"uint256","name":"_defaultReferredBorrowFeeMantissa","type":"uint256"},{"internalType":"uint256","name":"_defaultProtocolCommissionMantissa","type":"uint256"},{"internalType":"uint256","name":"_defaultReserveFactorMantissa","type":"uint256"},{"internalType":"uint256","name":"_defaultInitialExchangeRateMantissa","type":"uint256"}],"name":"_setDefaults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"_setOracleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"_setUnderlyingStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract ControllerI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dao","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultBorrowFeeMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultInitialExchangeRateMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultProtocolCommissionMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultReferredBorrowFeeMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultReserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingToken","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_interestRateModel","type":"address"},{"internalType":"address","name":"_adminCommissionReceiver","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"uint256","name":"_maxLTVFactorMantissa","type":"uint256"},{"internalType":"uint256","name":"_collateralFactorMantissa","type":"uint256"}],"name":"deployHToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract HTokenFactoryI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getCollateral","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCollateralCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getDeployedHToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDeployedHTokenCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOracleCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getOwnedHToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getOwnedHTokenCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getUnderlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyingCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_hToken","type":"address"}],"name":"isDeployedHToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_hToken","type":"address"}],"name":"isOwnedHToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_collateral","type":"address"}],"name":"isRegisteredCollateral","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_oracle","type":"address"}],"name":"isRegisteredOracle","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_underlying","type":"address"}],"name":"isRegisteredUnderlying","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidator","outputs":[{"internalType":"contract LiquidatorI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketplace","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_add","type":"bool"}],"name":"modifyReserves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ops","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"bool","name":"_state","type":"bool"},{"internalType":"uint256","name":"_target","type":"uint256"}],"name":"pauseComponent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolCommisionReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"address","name":"_newAddress","type":"address"},{"internalType":"uint256","name":"_target","type":"uint256"}],"name":"setAddressMarketAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"uint256","name":"_newAdminCommissionMantissa","type":"uint256"}],"name":"setAdminCommission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"uint256","name":"_newMaxLTVFactorMantissa","type":"uint256"},{"internalType":"uint256","name":"_newCollateralFactorMantissa","type":"uint256"}],"name":"setFactors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"address","name":"_newOracle","type":"address"}],"name":"setPriceOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405266470de4df82000060075566470de4df82000060085566470de4df82000060095566470de4df820000600a556706f05b59d3b20000600b553480156200004957600080fd5b506001805460ff191690556200006160003362000067565b62000108565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000104576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620000c33390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b61306580620001186000396000f3fe608060405234801561001057600080fd5b50600436106103365760003560e01c80636a06fd48116101b2578063a2448add116100f9578063d264ea69116100a2578063e70abe921161007c578063e70abe9214610678578063e71d541e1461068b578063f77c47911461069e578063ffca3cdc146106b657600080fd5b8063d264ea6914610649578063d547741f14610652578063e1084f8a1461066557600080fd5b8063b6807dd0116100d3578063b6807dd014610610578063b9c514e914610623578063c45a01551461063657600080fd5b8063a2448add146105d7578063abc8c7af146105ea578063b0c97e24146105fd57600080fd5b8063846d04141161015b5780639d4d0a6c116101355780639d4d0a6c146105bf578063a04b1a45146105c7578063a217fddf146105cf57600080fd5b8063846d04141461059057806391d14854146105995780639adcdc5d146105ac57600080fd5b80636dad54ae1161018c5780636dad54ae146105615780636eb5e41a1461056a578063777963cf1461057d57600080fd5b80636a06fd48146105325780636bfecd31146105455780636d4354211461054e57600080fd5b8063343142e41161028157806341ef48981161022a5780635c975abb116102045780635c975abb146104ee57806360a4cf89146104f95780636327c5701461050c57806367a74ddc1461051f57600080fd5b806341ef4898146104be5780634d97aab1146104d157806354fd4d50146104e457600080fd5b80633f4e42511161025b5780633f4e4251146104905780634046ebae146104985780634162169f146104ab57600080fd5b8063343142e41461045757806336568abe1461046a5780633ea815171461047d57600080fd5b8063254d8f8b116102e35780632a62a490116102bd5780632a62a4901461041e5780632b60ace3146104315780632f2ff15d1461044457600080fd5b8063254d8f8b146103e35780632911eb21146103f857806329dd273e1461040b57600080fd5b80631aa410ab116103145780631aa410ab146103a45780631f1ee6b9146103ad578063248a9ca3146103c057600080fd5b806301ffc9a71461033b57806310a9de60146103635780631473fce01461038e575b600080fd5b61034e6103493660046128c7565b6106c9565b60405190151581526020015b60405180910390f35b6103766103713660046128f1565b610700565b6040516001600160a01b03909116815260200161035a565b61039661070d565b60405190815260200161035a565b61039660085481565b600454610376906001600160a01b031681565b6103966103ce3660046128f1565b60009081526020819052604090206001015490565b6103f66103f136600461292d565b61071e565b005b61034e61040636600461296f565b610950565b6103766104193660046128f1565b61095d565b61037661042c3660046128f1565b61096a565b6103f661043f36600461298c565b610977565b6103f66104523660046129c5565b610a0b565b61034e61046536600461296f565b610a30565b6103f66104783660046129c5565b610a3d565b6103f661048b3660046129ea565b610ac0565b610396610b9b565b600254610376906001600160a01b031681565b600554610376906001600160a01b031681565b6103f66104cc366004612a25565b610ba7565b6103766104df366004612a25565b610c5f565b610396620f424081565b60015460ff1661034e565b61034e610507366004612a51565b610c88565b6103f661051a366004612a7f565b610caa565b6103f661052d366004612a51565b610d24565b61034e61054036600461296f565b610de8565b61039660075481565b6103f661055c366004612a51565b610df5565b610396600b5481565b6103f6610578366004612a9c565b610ec9565b6103f661058b366004612b1f565b61191f565b61039660095481565b61034e6105a73660046129c5565b6119f1565b6103f66105ba36600461298c565b611a1a565b610396611aa2565b610396611aae565b610396600081565b6103966105e536600461296f565b611aba565b600354610376906001600160a01b031681565b6103f661060b366004612a25565b611adb565b61034e61061e36600461296f565b611cc1565b6103f6610631366004612b54565b611cce565b601554610376906001600160a01b031681565b610396600a5481565b6103f66106603660046129c5565b611d6e565b6103f6610673366004612b95565b611d93565b600654610376906001600160a01b031681565b6103766106993660046128f1565b611e21565b6001546103769061010090046001600160a01b031681565b6103f66106c436600461298c565b611e2e565b60006001600160e01b03198216637965db0b60e01b14806106fa57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006106fa601083611eb6565b6000610719600e611ec2565b905090565b60015460ff16156107425760405163a59392f560e01b815260040160405180910390fd5b33600090815260146020526040902061075b9084611ecc565b610777576040516282b42960e81b815260040160405180910390fd5b8015610873576000836001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e19190612bc5565b90506107f86001600160a01b038216333086611eee565b61080c6001600160a01b0382168585611f5f565b6040516340df1bb760e11b815260048101849052600160248201526001600160a01b038516906381be376e90604401600060405180830381600087803b15801561085557600080fd5b505af1158015610869573d6000803e3d6000fd5b5050505050505050565b6040516340df1bb760e11b815260048101839052600060248201526001600160a01b038416906381be376e90604401600060405180830381600087803b1580156108bc57600080fd5b505af11580156108d0573d6000803e3d6000fd5b5050505061094b3383856001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015610917573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093b9190612bc5565b6001600160a01b0316919061207b565b505050565b60006106fa601083611ecc565b60006106fa601283611eb6565b60006106fa600e83611eb6565b6109826000336119f1565b61099e576040516282b42960e81b815260040160405180910390fd5b80156109b5576109af600e836120ab565b506109c2565b6109c0600e836120c0565b505b816001600160a01b03167f5245173d03ce5943dbb7a3b2e128500e5bc5ddedd2bf9280fb5b3f742a8dd92e826040516109ff911515815260200190565b60405180910390a25050565b600082815260208190526040902060010154610a26816120d5565b61094b83836120e2565b60006106fa601283611ecc565b6001600160a01b0381163314610ab25760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610abc8282612166565b5050565b610acb6000336119f1565b610ae7576040516282b42960e81b815260040160405180910390fd5b66b1a2bc2ec50000851180610b02575066b1a2bc2ec5000084115b80610b0b575080155b15610b2c5760096040516359e3112360e11b8152600401610aa99190612be2565b600785905560088490556009839055600a829055600b819055604080518681526020810186905290810184905260608101839052608081018290527f1037cb9915c5982bc5bc540a4cb0bb86a964b60fa87ad2f870cd27e5d340da9d9060a00160405180910390a15050505050565b60006107196010611ec2565b60015460ff1615610bcb5760405163a59392f560e01b815260040160405180910390fd5b336000908152601460205260409020610be49083611ecc565b610c00576040516282b42960e81b815260040160405180910390fd5b60405163844f7c5760e01b8152600481018290526001600160a01b0383169063844f7c57906024015b600060405180830381600087803b158015610c4357600080fd5b505af1158015610c57573d6000803e3d6000fd5b505050505050565b6001600160a01b0382166000908152601460205260408120610c819083611eb6565b9392505050565b6001600160a01b0382166000908152601460205260408120610c819083611ecc565b610cb56000336119f1565b610cd1576040516282b42960e81b815260040160405180910390fd5b8015610ce457610cdf6121cb565b610cec565b610cec61221f565b60405181151581527f39567b785870bed9653807a175b95d7b0d9143f81efd6442752171db25032fe59060200160405180910390a150565b60015460ff1615610d485760405163a59392f560e01b815260040160405180910390fd5b610d53601082611ecc565b610d7357602d6040516359e3112360e11b8152600401610aa99190612be2565b336000908152601460205260409020610d8c9083611ecc565b610da8576040516282b42960e81b815260040160405180910390fd5b6001546040516370d064d160e01b81526001600160a01b0384811660048301528381166024830152610100909204909116906370d064d190604401610c29565b60006106fa600c83611ecc565b60015460ff1615610e195760405163a59392f560e01b815260040160405180910390fd5b336000908152601460205260409020610e329083611ecc565b610e4e576040516282b42960e81b815260040160405180910390fd5b336000908152601460205260409020610e6790836120c0565b506001600160a01b0381166000908152601460205260409020610e8a90836120ab565b506040516001600160a01b038083169133918516907fc8894f26f396ce8c004245c8b7cd1b92103a6e4302fcbab883987149ac01b7ec90600090a45050565b60015460ff1615610eed5760405163a59392f560e01b815260040160405180910390fd5b610ef8600c88611ecc565b610f1857602c6040516359e3112360e11b8152600401610aa99190612be2565b610f23600e87611ecc565b610f4357602b6040516359e3112360e11b8152600401610aa99190612be2565b610f4e601084611ecc565b610f6e57602d6040516359e3112360e11b8152600401610aa99190612be2565b6001600160a01b0385161580610ff057506040516301ffc9a760e01b8152636135719d60e11b60048201526001600160a01b038616906301ffc9a790602401602060405180830381865afa158015610fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee9190612c0a565b155b156110115760346040516359e3112360e11b8152600401610aa99190612be2565b866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561104f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110739190612c27565b60ff166012146110995760336040516359e3112360e11b8152600401610aa99190612be2565b6000876001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156110d9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111019190810190612c8c565b876001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561113f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111679190810190612c8c565b604051602001611178929190612d2e565b60405160208183030381529060405290506000886001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156111c9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111f19190810190612c8c565b886001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561122f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112579190810190612c8c565b604051602001611268929190612d7c565b60405160208183030381529060405290506000601560009054906101000a90046001600160a01b03166001600160a01b031663e1d007458b8b60018054906101000a90046001600160a01b03168c600260009054906101000a90046001600160a01b0316600b548e600460009054906101000a90046001600160a01b03168c8c6040518b63ffffffff1660e01b815260040161130d9a99989796959493929190612de7565b6020604051808303816000875af115801561132c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113509190612bc5565b90506001600160a01b03811661137c57602e604051631b31a7b960e01b8152600401610aa99190612be2565b6113876012826120ab565b503360009081526014602052604090206113a190826120ab565b50600954600a54604051635f98f48f60e01b81526001600160a01b03841692635f98f48f926113db92600401918252602082015260400190565b600060405180830381600087803b1580156113f557600080fd5b505af1158015611409573d6000803e3d6000fd5b5050600654604051632f2ff15d60e01b8152600060048201526001600160a01b0391821660248201529084169250632f2ff15d9150604401600060405180830381600087803b15801561145b57600080fd5b505af115801561146f573d6000803e3d6000fd5b5050604051632f2ff15d60e01b81527f3fb0aaa9e8051cfc6c234a5d843bed33910f70c647055f27247c10144c7552e160048201523060248201526001600160a01b0384169250632f2ff15d9150604401600060405180830381600087803b1580156114da57600080fd5b505af11580156114ee573d6000803e3d6000fd5b5050604051632f2ff15d60e01b81527fd1ae8bbdabd60d63e418b84f5ad6f9cba90092c9816d7724d85f0d4e4bea2c6060048201523060248201526001600160a01b0384169250632f2ff15d9150604401600060405180830381600087803b15801561155957600080fd5b505af115801561156d573d6000803e3d6000fd5b5050600354604051632f2ff15d60e01b81527f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c1660048201526001600160a01b0391821660248201529084169250632f2ff15d9150604401600060405180830381600087803b1580156115de57600080fd5b505af11580156115f2573d6000803e3d6000fd5b5050604051631b2b455f60e11b8152600060048201523060248201526001600160a01b03841692506336568abe9150604401600060405180830381600087803b15801561163e57600080fd5b505af1158015611652573d6000803e3d6000fd5b50506001546040516353b59fed60e11b81526001600160a01b038581166004830152610100909204909116925063a76b3fda9150602401600060405180830381600087803b1580156116a357600080fd5b505af11580156116b7573d6000803e3d6000fd5b50506001546040516370d064d160e01b81526001600160a01b0385811660048301528a8116602483015261010090920490911692506370d064d19150604401600060405180830381600087803b15801561171057600080fd5b505af1158015611724573d6000803e3d6000fd5b505060015460405163cf82661560e01b81526001600160a01b038581166004830152602482018a905260448201899052610100909204909116925063cf8266159150606401600060405180830381600087803b15801561178357600080fd5b505af1158015611797573d6000803e3d6000fd5b5050600154600754600854604051636688f38560e11b81526001600160a01b0387811660048301526024820193909352604481019190915261010090920416925063cd11e70a9150606401600060405180830381600087803b1580156117fc57600080fd5b505af1158015611810573d6000803e3d6000fd5b505060025460405163071cc68760e51b81526001600160a01b038581166004830152909116925063e398d0e09150602401600060405180830381600087803b15801561185b57600080fd5b505af115801561186f573d6000803e3d6000fd5b50505050886001600160a01b03168a6001600160a01b0316826001600160a01b03167f13e733547c407f7d7f9aa23a3f3a6faa2bdf1ccbd74c95371037d7c31599a77c3360018054906101000a90046001600160a01b0316600260009054906101000a90046001600160a01b0316600b54600460009054906101000a90046001600160a01b03168b8b60405161190b9796959493929190612e69565b60405180910390a450505050505050505050565b60015460ff16156119435760405163a59392f560e01b815260040160405180910390fd5b33600090815260146020526040902061195c9084611ecc565b611978576040516282b42960e81b815260040160405180910390fd5b60015460405163cf82661560e01b81526001600160a01b03858116600483015260248201859052604482018490526101009092049091169063cf826615906064015b600060405180830381600087803b1580156119d457600080fd5b505af11580156119e8573d6000803e3d6000fd5b50505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b611a256000336119f1565b611a41576040516282b42960e81b815260040160405180910390fd5b8015611a5857611a526010836120ab565b50611a65565b611a636010836120c0565b505b816001600160a01b03167f3f1d225da75a416ad0ce50b55c7b417802b43a72e61a108f4b84742e7e158f26826040516109ff911515815260200190565b60006107196012611ec2565b6000610719600c611ec2565b6001600160a01b03811660009081526014602052604081206106fa90611ec2565b611ae66000336119f1565b611b02576040516282b42960e81b815260040160405180910390fd5b600081600003611b315750600280546001600160a01b038481166001600160a01b031983161790925516611c6f565b81600103611b755750600180546001600160a01b0384811661010090810274ffffffffffffffffffffffffffffffffffffffff001984161790935591900416611c6f565b81600203611ba25750600480546001600160a01b038481166001600160a01b031983161790925516611c6f565b81600303611bcf5750600580546001600160a01b038481166001600160a01b031983161790925516611c6f565b81600403611bfc5750601580546001600160a01b038481166001600160a01b031983161790925516611c6f565b81600503611c295750600680546001600160a01b038481166001600160a01b031983161790925516611c6f565b81600603611c565750600380546001600160a01b038481166001600160a01b031983161790925516611c6f565b604051635863f78960e01b815260040160405180910390fd5b806001600160a01b0316836001600160a01b03167f4e5960f91526bead4911fd7dc9b52ede9bca2120886a0852a6259873a3367dcf84604051611cb491815260200190565b60405180910390a3505050565b60006106fa600e83611ecc565b60015460ff1615611cf25760405163a59392f560e01b815260040160405180910390fd5b336000908152601460205260409020611d0b9084611ecc565b611d27576040516282b42960e81b815260040160405180910390fd5b6001546040516302ddde9f60e21b81526001600160a01b03858116600483015284151560248301526044820184905261010090920490911690630b777a7c906064016119ba565b600082815260208190526040902060010154611d89816120d5565b61094b8383612166565b60015460ff1615611db75760405163a59392f560e01b815260040160405180910390fd5b336000908152601460205260409020611dd09084611ecc565b611dec576040516282b42960e81b815260040160405180910390fd5b60405163c6be718560e01b81526001600160a01b0383811660048301526024820183905284169063c6be7185906044016119ba565b60006106fa600c83611eb6565b611e396000336119f1565b611e55576040516282b42960e81b815260040160405180910390fd5b8015611e6c57611e66600c836120ab565b50611e79565b611e77600c836120c0565b505b816001600160a01b03167f9f6bdb98829005317cbe87817978b7d89e7077ea2bb3ffb834129e2f63ec0a19826040516109ff911515815260200190565b6000610c818383612258565b60006106fa825490565b6001600160a01b03811660009081526001830160205260408120541515610c81565b6040516001600160a01b0380851660248301528316604482015260648101829052611f599085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612282565b50505050565b801580611fd95750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611fb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd79190612ecb565b155b61204b5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610aa9565b6040516001600160a01b03831660248201526044810182905261094b90849063095ea7b360e01b90606401611f22565b6040516001600160a01b03831660248201526044810182905261094b90849063a9059cbb60e01b90606401611f22565b6000610c81836001600160a01b038416612354565b6000610c81836001600160a01b0384166123a3565b6120df8133612496565b50565b6120ec82826119f1565b610abc576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556121223390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b61217082826119f1565b15610abc576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6121d36124ef565b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a1565b612227612537565b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612202565b600082600001828154811061226f5761226f612ee4565b9060005260206000200154905092915050565b60006122d7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166125899092919063ffffffff16565b80519091501561094b57808060200190518101906122f59190612c0a565b61094b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610aa9565b600081815260018301602052604081205461239b575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106fa565b5060006106fa565b6000818152600183016020526040812054801561248c5760006123c7600183612f10565b85549091506000906123db90600190612f10565b90508181146124405760008660000182815481106123fb576123fb612ee4565b906000526020600020015490508087600001848154811061241e5761241e612ee4565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061245157612451612f27565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106fa565b60009150506106fa565b6124a082826119f1565b610abc576124ad816125a0565b6124b88360206125b2565b6040516020016124c9929190612f3d565b60408051601f198184030181529082905262461bcd60e51b8252610aa991600401612fb2565b60015460ff16156125355760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610aa9565b565b60015460ff166125355760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610aa9565b6060612598848460008561274e565b949350505050565b60606106fa6001600160a01b03831660145b606060006125c1836002612fc5565b6125cc906002612fe4565b67ffffffffffffffff8111156125e4576125e4612c4a565b6040519080825280601f01601f19166020018201604052801561260e576020820181803683370190505b509050600360fc1b8160008151811061262957612629612ee4565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061265857612658612ee4565b60200101906001600160f81b031916908160001a905350600061267c846002612fc5565b612687906001612fe4565b90505b60018111156126ff576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106126bb576126bb612ee4565b1a60f81b8282815181106126d1576126d1612ee4565b60200101906001600160f81b031916908160001a90535060049490941c936126f881612ffc565b905061268a565b508315610c815760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610aa9565b6060824710156127af5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610aa9565b600080866001600160a01b031685876040516127cb9190613013565b60006040518083038185875af1925050503d8060008114612808576040519150601f19603f3d011682016040523d82523d6000602084013e61280d565b606091505b509150915061281e87838387612829565b979650505050505050565b60608315612898578251600003612891576001600160a01b0385163b6128915760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aa9565b5081612598565b61259883838151156128ad5781518083602001fd5b8060405162461bcd60e51b8152600401610aa99190612fb2565b6000602082840312156128d957600080fd5b81356001600160e01b031981168114610c8157600080fd5b60006020828403121561290357600080fd5b5035919050565b6001600160a01b03811681146120df57600080fd5b80151581146120df57600080fd5b60008060006060848603121561294257600080fd5b833561294d8161290a565b92506020840135915060408401356129648161291f565b809150509250925092565b60006020828403121561298157600080fd5b8135610c818161290a565b6000806040838503121561299f57600080fd5b82356129aa8161290a565b915060208301356129ba8161291f565b809150509250929050565b600080604083850312156129d857600080fd5b8235915060208301356129ba8161290a565b600080600080600060a08688031215612a0257600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60008060408385031215612a3857600080fd5b8235612a438161290a565b946020939093013593505050565b60008060408385031215612a6457600080fd5b8235612a6f8161290a565b915060208301356129ba8161290a565b600060208284031215612a9157600080fd5b8135610c818161291f565b600080600080600080600060e0888a031215612ab757600080fd5b8735612ac28161290a565b96506020880135612ad28161290a565b95506040880135612ae28161290a565b94506060880135612af28161290a565b93506080880135612b028161290a565b9699959850939692959460a0840135945060c09093013592915050565b600080600060608486031215612b3457600080fd5b8335612b3f8161290a565b95602085013595506040909401359392505050565b600080600060608486031215612b6957600080fd5b8335612b748161290a565b92506020840135612b848161291f565b929592945050506040919091013590565b600080600060608486031215612baa57600080fd5b8335612bb58161290a565b92506020840135612b848161290a565b600060208284031215612bd757600080fd5b8151610c818161290a565b6020810160358310612c0457634e487b7160e01b600052602160045260246000fd5b91905290565b600060208284031215612c1c57600080fd5b8151610c818161291f565b600060208284031215612c3957600080fd5b815160ff81168114610c8157600080fd5b634e487b7160e01b600052604160045260246000fd5b60005b83811015612c7b578181015183820152602001612c63565b83811115611f595750506000910152565b600060208284031215612c9e57600080fd5b815167ffffffffffffffff80821115612cb657600080fd5b818401915084601f830112612cca57600080fd5b815181811115612cdc57612cdc612c4a565b604051601f8201601f19908116603f01168101908382118183101715612d0457612d04612c4a565b81604052828152876020848701011115612d1d57600080fd5b61281e836020830160208801612c60565b6502437b732bc960d51b815260008351612d4f816006850160208801612c60565b600160fd1b6006918401918201528351612d70816007840160208801612c60565b01600701949350505050565b600d60fb1b815260008351612d98816001850160208801612c60565b835190830190612daf816001840160208801612c60565b01600101949350505050565b60008151808452612dd3816020860160208601612c60565b601f01601f19169290920160200192915050565b60006101406001600160a01b03808e168452808d166020850152808c166040850152808b166060850152808a1660808501528860a085015280881660c085015280871660e08501525080610100840152612e4381840186612dbb565b9050828103610120840152612e588185612dbb565b9d9c50505050505050505050505050565b60006001600160a01b03808a1683528089166020840152808816604084015286606084015280861660808401525060e060a0830152612eab60e0830185612dbb565b82810360c0840152612ebd8185612dbb565b9a9950505050505050505050565b600060208284031215612edd57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082821015612f2257612f22612efa565b500390565b634e487b7160e01b600052603160045260246000fd5b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612f75816017850160208801612c60565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351612fa6816028840160208801612c60565b01602801949350505050565b602081526000610c816020830184612dbb565b6000816000190483118215151615612fdf57612fdf612efa565b500290565b60008219821115612ff757612ff7612efa565b500190565b60008161300b5761300b612efa565b506000190190565b60008251613025818460208701612c60565b919091019291505056fea2646970667358221220011a7a6d7ce486b3d7b642a5ea5858ee1284d12dce9206e229a6d428c3d9089064736f6c634300080f0033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103365760003560e01c80636a06fd48116101b2578063a2448add116100f9578063d264ea69116100a2578063e70abe921161007c578063e70abe9214610678578063e71d541e1461068b578063f77c47911461069e578063ffca3cdc146106b657600080fd5b8063d264ea6914610649578063d547741f14610652578063e1084f8a1461066557600080fd5b8063b6807dd0116100d3578063b6807dd014610610578063b9c514e914610623578063c45a01551461063657600080fd5b8063a2448add146105d7578063abc8c7af146105ea578063b0c97e24146105fd57600080fd5b8063846d04141161015b5780639d4d0a6c116101355780639d4d0a6c146105bf578063a04b1a45146105c7578063a217fddf146105cf57600080fd5b8063846d04141461059057806391d14854146105995780639adcdc5d146105ac57600080fd5b80636dad54ae1161018c5780636dad54ae146105615780636eb5e41a1461056a578063777963cf1461057d57600080fd5b80636a06fd48146105325780636bfecd31146105455780636d4354211461054e57600080fd5b8063343142e41161028157806341ef48981161022a5780635c975abb116102045780635c975abb146104ee57806360a4cf89146104f95780636327c5701461050c57806367a74ddc1461051f57600080fd5b806341ef4898146104be5780634d97aab1146104d157806354fd4d50146104e457600080fd5b80633f4e42511161025b5780633f4e4251146104905780634046ebae146104985780634162169f146104ab57600080fd5b8063343142e41461045757806336568abe1461046a5780633ea815171461047d57600080fd5b8063254d8f8b116102e35780632a62a490116102bd5780632a62a4901461041e5780632b60ace3146104315780632f2ff15d1461044457600080fd5b8063254d8f8b146103e35780632911eb21146103f857806329dd273e1461040b57600080fd5b80631aa410ab116103145780631aa410ab146103a45780631f1ee6b9146103ad578063248a9ca3146103c057600080fd5b806301ffc9a71461033b57806310a9de60146103635780631473fce01461038e575b600080fd5b61034e6103493660046128c7565b6106c9565b60405190151581526020015b60405180910390f35b6103766103713660046128f1565b610700565b6040516001600160a01b03909116815260200161035a565b61039661070d565b60405190815260200161035a565b61039660085481565b600454610376906001600160a01b031681565b6103966103ce3660046128f1565b60009081526020819052604090206001015490565b6103f66103f136600461292d565b61071e565b005b61034e61040636600461296f565b610950565b6103766104193660046128f1565b61095d565b61037661042c3660046128f1565b61096a565b6103f661043f36600461298c565b610977565b6103f66104523660046129c5565b610a0b565b61034e61046536600461296f565b610a30565b6103f66104783660046129c5565b610a3d565b6103f661048b3660046129ea565b610ac0565b610396610b9b565b600254610376906001600160a01b031681565b600554610376906001600160a01b031681565b6103f66104cc366004612a25565b610ba7565b6103766104df366004612a25565b610c5f565b610396620f424081565b60015460ff1661034e565b61034e610507366004612a51565b610c88565b6103f661051a366004612a7f565b610caa565b6103f661052d366004612a51565b610d24565b61034e61054036600461296f565b610de8565b61039660075481565b6103f661055c366004612a51565b610df5565b610396600b5481565b6103f6610578366004612a9c565b610ec9565b6103f661058b366004612b1f565b61191f565b61039660095481565b61034e6105a73660046129c5565b6119f1565b6103f66105ba36600461298c565b611a1a565b610396611aa2565b610396611aae565b610396600081565b6103966105e536600461296f565b611aba565b600354610376906001600160a01b031681565b6103f661060b366004612a25565b611adb565b61034e61061e36600461296f565b611cc1565b6103f6610631366004612b54565b611cce565b601554610376906001600160a01b031681565b610396600a5481565b6103f66106603660046129c5565b611d6e565b6103f6610673366004612b95565b611d93565b600654610376906001600160a01b031681565b6103766106993660046128f1565b611e21565b6001546103769061010090046001600160a01b031681565b6103f66106c436600461298c565b611e2e565b60006001600160e01b03198216637965db0b60e01b14806106fa57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006106fa601083611eb6565b6000610719600e611ec2565b905090565b60015460ff16156107425760405163a59392f560e01b815260040160405180910390fd5b33600090815260146020526040902061075b9084611ecc565b610777576040516282b42960e81b815260040160405180910390fd5b8015610873576000836001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e19190612bc5565b90506107f86001600160a01b038216333086611eee565b61080c6001600160a01b0382168585611f5f565b6040516340df1bb760e11b815260048101849052600160248201526001600160a01b038516906381be376e90604401600060405180830381600087803b15801561085557600080fd5b505af1158015610869573d6000803e3d6000fd5b5050505050505050565b6040516340df1bb760e11b815260048101839052600060248201526001600160a01b038416906381be376e90604401600060405180830381600087803b1580156108bc57600080fd5b505af11580156108d0573d6000803e3d6000fd5b5050505061094b3383856001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015610917573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093b9190612bc5565b6001600160a01b0316919061207b565b505050565b60006106fa601083611ecc565b60006106fa601283611eb6565b60006106fa600e83611eb6565b6109826000336119f1565b61099e576040516282b42960e81b815260040160405180910390fd5b80156109b5576109af600e836120ab565b506109c2565b6109c0600e836120c0565b505b816001600160a01b03167f5245173d03ce5943dbb7a3b2e128500e5bc5ddedd2bf9280fb5b3f742a8dd92e826040516109ff911515815260200190565b60405180910390a25050565b600082815260208190526040902060010154610a26816120d5565b61094b83836120e2565b60006106fa601283611ecc565b6001600160a01b0381163314610ab25760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610abc8282612166565b5050565b610acb6000336119f1565b610ae7576040516282b42960e81b815260040160405180910390fd5b66b1a2bc2ec50000851180610b02575066b1a2bc2ec5000084115b80610b0b575080155b15610b2c5760096040516359e3112360e11b8152600401610aa99190612be2565b600785905560088490556009839055600a829055600b819055604080518681526020810186905290810184905260608101839052608081018290527f1037cb9915c5982bc5bc540a4cb0bb86a964b60fa87ad2f870cd27e5d340da9d9060a00160405180910390a15050505050565b60006107196010611ec2565b60015460ff1615610bcb5760405163a59392f560e01b815260040160405180910390fd5b336000908152601460205260409020610be49083611ecc565b610c00576040516282b42960e81b815260040160405180910390fd5b60405163844f7c5760e01b8152600481018290526001600160a01b0383169063844f7c57906024015b600060405180830381600087803b158015610c4357600080fd5b505af1158015610c57573d6000803e3d6000fd5b505050505050565b6001600160a01b0382166000908152601460205260408120610c819083611eb6565b9392505050565b6001600160a01b0382166000908152601460205260408120610c819083611ecc565b610cb56000336119f1565b610cd1576040516282b42960e81b815260040160405180910390fd5b8015610ce457610cdf6121cb565b610cec565b610cec61221f565b60405181151581527f39567b785870bed9653807a175b95d7b0d9143f81efd6442752171db25032fe59060200160405180910390a150565b60015460ff1615610d485760405163a59392f560e01b815260040160405180910390fd5b610d53601082611ecc565b610d7357602d6040516359e3112360e11b8152600401610aa99190612be2565b336000908152601460205260409020610d8c9083611ecc565b610da8576040516282b42960e81b815260040160405180910390fd5b6001546040516370d064d160e01b81526001600160a01b0384811660048301528381166024830152610100909204909116906370d064d190604401610c29565b60006106fa600c83611ecc565b60015460ff1615610e195760405163a59392f560e01b815260040160405180910390fd5b336000908152601460205260409020610e329083611ecc565b610e4e576040516282b42960e81b815260040160405180910390fd5b336000908152601460205260409020610e6790836120c0565b506001600160a01b0381166000908152601460205260409020610e8a90836120ab565b506040516001600160a01b038083169133918516907fc8894f26f396ce8c004245c8b7cd1b92103a6e4302fcbab883987149ac01b7ec90600090a45050565b60015460ff1615610eed5760405163a59392f560e01b815260040160405180910390fd5b610ef8600c88611ecc565b610f1857602c6040516359e3112360e11b8152600401610aa99190612be2565b610f23600e87611ecc565b610f4357602b6040516359e3112360e11b8152600401610aa99190612be2565b610f4e601084611ecc565b610f6e57602d6040516359e3112360e11b8152600401610aa99190612be2565b6001600160a01b0385161580610ff057506040516301ffc9a760e01b8152636135719d60e11b60048201526001600160a01b038616906301ffc9a790602401602060405180830381865afa158015610fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee9190612c0a565b155b156110115760346040516359e3112360e11b8152600401610aa99190612be2565b866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561104f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110739190612c27565b60ff166012146110995760336040516359e3112360e11b8152600401610aa99190612be2565b6000876001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156110d9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111019190810190612c8c565b876001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561113f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111679190810190612c8c565b604051602001611178929190612d2e565b60405160208183030381529060405290506000886001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156111c9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111f19190810190612c8c565b886001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561122f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112579190810190612c8c565b604051602001611268929190612d7c565b60405160208183030381529060405290506000601560009054906101000a90046001600160a01b03166001600160a01b031663e1d007458b8b60018054906101000a90046001600160a01b03168c600260009054906101000a90046001600160a01b0316600b548e600460009054906101000a90046001600160a01b03168c8c6040518b63ffffffff1660e01b815260040161130d9a99989796959493929190612de7565b6020604051808303816000875af115801561132c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113509190612bc5565b90506001600160a01b03811661137c57602e604051631b31a7b960e01b8152600401610aa99190612be2565b6113876012826120ab565b503360009081526014602052604090206113a190826120ab565b50600954600a54604051635f98f48f60e01b81526001600160a01b03841692635f98f48f926113db92600401918252602082015260400190565b600060405180830381600087803b1580156113f557600080fd5b505af1158015611409573d6000803e3d6000fd5b5050600654604051632f2ff15d60e01b8152600060048201526001600160a01b0391821660248201529084169250632f2ff15d9150604401600060405180830381600087803b15801561145b57600080fd5b505af115801561146f573d6000803e3d6000fd5b5050604051632f2ff15d60e01b81527f3fb0aaa9e8051cfc6c234a5d843bed33910f70c647055f27247c10144c7552e160048201523060248201526001600160a01b0384169250632f2ff15d9150604401600060405180830381600087803b1580156114da57600080fd5b505af11580156114ee573d6000803e3d6000fd5b5050604051632f2ff15d60e01b81527fd1ae8bbdabd60d63e418b84f5ad6f9cba90092c9816d7724d85f0d4e4bea2c6060048201523060248201526001600160a01b0384169250632f2ff15d9150604401600060405180830381600087803b15801561155957600080fd5b505af115801561156d573d6000803e3d6000fd5b5050600354604051632f2ff15d60e01b81527f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c1660048201526001600160a01b0391821660248201529084169250632f2ff15d9150604401600060405180830381600087803b1580156115de57600080fd5b505af11580156115f2573d6000803e3d6000fd5b5050604051631b2b455f60e11b8152600060048201523060248201526001600160a01b03841692506336568abe9150604401600060405180830381600087803b15801561163e57600080fd5b505af1158015611652573d6000803e3d6000fd5b50506001546040516353b59fed60e11b81526001600160a01b038581166004830152610100909204909116925063a76b3fda9150602401600060405180830381600087803b1580156116a357600080fd5b505af11580156116b7573d6000803e3d6000fd5b50506001546040516370d064d160e01b81526001600160a01b0385811660048301528a8116602483015261010090920490911692506370d064d19150604401600060405180830381600087803b15801561171057600080fd5b505af1158015611724573d6000803e3d6000fd5b505060015460405163cf82661560e01b81526001600160a01b038581166004830152602482018a905260448201899052610100909204909116925063cf8266159150606401600060405180830381600087803b15801561178357600080fd5b505af1158015611797573d6000803e3d6000fd5b5050600154600754600854604051636688f38560e11b81526001600160a01b0387811660048301526024820193909352604481019190915261010090920416925063cd11e70a9150606401600060405180830381600087803b1580156117fc57600080fd5b505af1158015611810573d6000803e3d6000fd5b505060025460405163071cc68760e51b81526001600160a01b038581166004830152909116925063e398d0e09150602401600060405180830381600087803b15801561185b57600080fd5b505af115801561186f573d6000803e3d6000fd5b50505050886001600160a01b03168a6001600160a01b0316826001600160a01b03167f13e733547c407f7d7f9aa23a3f3a6faa2bdf1ccbd74c95371037d7c31599a77c3360018054906101000a90046001600160a01b0316600260009054906101000a90046001600160a01b0316600b54600460009054906101000a90046001600160a01b03168b8b60405161190b9796959493929190612e69565b60405180910390a450505050505050505050565b60015460ff16156119435760405163a59392f560e01b815260040160405180910390fd5b33600090815260146020526040902061195c9084611ecc565b611978576040516282b42960e81b815260040160405180910390fd5b60015460405163cf82661560e01b81526001600160a01b03858116600483015260248201859052604482018490526101009092049091169063cf826615906064015b600060405180830381600087803b1580156119d457600080fd5b505af11580156119e8573d6000803e3d6000fd5b50505050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b611a256000336119f1565b611a41576040516282b42960e81b815260040160405180910390fd5b8015611a5857611a526010836120ab565b50611a65565b611a636010836120c0565b505b816001600160a01b03167f3f1d225da75a416ad0ce50b55c7b417802b43a72e61a108f4b84742e7e158f26826040516109ff911515815260200190565b60006107196012611ec2565b6000610719600c611ec2565b6001600160a01b03811660009081526014602052604081206106fa90611ec2565b611ae66000336119f1565b611b02576040516282b42960e81b815260040160405180910390fd5b600081600003611b315750600280546001600160a01b038481166001600160a01b031983161790925516611c6f565b81600103611b755750600180546001600160a01b0384811661010090810274ffffffffffffffffffffffffffffffffffffffff001984161790935591900416611c6f565b81600203611ba25750600480546001600160a01b038481166001600160a01b031983161790925516611c6f565b81600303611bcf5750600580546001600160a01b038481166001600160a01b031983161790925516611c6f565b81600403611bfc5750601580546001600160a01b038481166001600160a01b031983161790925516611c6f565b81600503611c295750600680546001600160a01b038481166001600160a01b031983161790925516611c6f565b81600603611c565750600380546001600160a01b038481166001600160a01b031983161790925516611c6f565b604051635863f78960e01b815260040160405180910390fd5b806001600160a01b0316836001600160a01b03167f4e5960f91526bead4911fd7dc9b52ede9bca2120886a0852a6259873a3367dcf84604051611cb491815260200190565b60405180910390a3505050565b60006106fa600e83611ecc565b60015460ff1615611cf25760405163a59392f560e01b815260040160405180910390fd5b336000908152601460205260409020611d0b9084611ecc565b611d27576040516282b42960e81b815260040160405180910390fd5b6001546040516302ddde9f60e21b81526001600160a01b03858116600483015284151560248301526044820184905261010090920490911690630b777a7c906064016119ba565b600082815260208190526040902060010154611d89816120d5565b61094b8383612166565b60015460ff1615611db75760405163a59392f560e01b815260040160405180910390fd5b336000908152601460205260409020611dd09084611ecc565b611dec576040516282b42960e81b815260040160405180910390fd5b60405163c6be718560e01b81526001600160a01b0383811660048301526024820183905284169063c6be7185906044016119ba565b60006106fa600c83611eb6565b611e396000336119f1565b611e55576040516282b42960e81b815260040160405180910390fd5b8015611e6c57611e66600c836120ab565b50611e79565b611e77600c836120c0565b505b816001600160a01b03167f9f6bdb98829005317cbe87817978b7d89e7077ea2bb3ffb834129e2f63ec0a19826040516109ff911515815260200190565b6000610c818383612258565b60006106fa825490565b6001600160a01b03811660009081526001830160205260408120541515610c81565b6040516001600160a01b0380851660248301528316604482015260648101829052611f599085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612282565b50505050565b801580611fd95750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611fb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd79190612ecb565b155b61204b5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610aa9565b6040516001600160a01b03831660248201526044810182905261094b90849063095ea7b360e01b90606401611f22565b6040516001600160a01b03831660248201526044810182905261094b90849063a9059cbb60e01b90606401611f22565b6000610c81836001600160a01b038416612354565b6000610c81836001600160a01b0384166123a3565b6120df8133612496565b50565b6120ec82826119f1565b610abc576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556121223390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b61217082826119f1565b15610abc576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6121d36124ef565b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a1565b612227612537565b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612202565b600082600001828154811061226f5761226f612ee4565b9060005260206000200154905092915050565b60006122d7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166125899092919063ffffffff16565b80519091501561094b57808060200190518101906122f59190612c0a565b61094b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610aa9565b600081815260018301602052604081205461239b575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106fa565b5060006106fa565b6000818152600183016020526040812054801561248c5760006123c7600183612f10565b85549091506000906123db90600190612f10565b90508181146124405760008660000182815481106123fb576123fb612ee4565b906000526020600020015490508087600001848154811061241e5761241e612ee4565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061245157612451612f27565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106fa565b60009150506106fa565b6124a082826119f1565b610abc576124ad816125a0565b6124b88360206125b2565b6040516020016124c9929190612f3d565b60408051601f198184030181529082905262461bcd60e51b8252610aa991600401612fb2565b60015460ff16156125355760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610aa9565b565b60015460ff166125355760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610aa9565b6060612598848460008561274e565b949350505050565b60606106fa6001600160a01b03831660145b606060006125c1836002612fc5565b6125cc906002612fe4565b67ffffffffffffffff8111156125e4576125e4612c4a565b6040519080825280601f01601f19166020018201604052801561260e576020820181803683370190505b509050600360fc1b8160008151811061262957612629612ee4565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061265857612658612ee4565b60200101906001600160f81b031916908160001a905350600061267c846002612fc5565b612687906001612fe4565b90505b60018111156126ff576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106126bb576126bb612ee4565b1a60f81b8282815181106126d1576126d1612ee4565b60200101906001600160f81b031916908160001a90535060049490941c936126f881612ffc565b905061268a565b508315610c815760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610aa9565b6060824710156127af5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610aa9565b600080866001600160a01b031685876040516127cb9190613013565b60006040518083038185875af1925050503d8060008114612808576040519150601f19603f3d011682016040523d82523d6000602084013e61280d565b606091505b509150915061281e87838387612829565b979650505050505050565b60608315612898578251600003612891576001600160a01b0385163b6128915760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aa9565b5081612598565b61259883838151156128ad5781518083602001fd5b8060405162461bcd60e51b8152600401610aa99190612fb2565b6000602082840312156128d957600080fd5b81356001600160e01b031981168114610c8157600080fd5b60006020828403121561290357600080fd5b5035919050565b6001600160a01b03811681146120df57600080fd5b80151581146120df57600080fd5b60008060006060848603121561294257600080fd5b833561294d8161290a565b92506020840135915060408401356129648161291f565b809150509250925092565b60006020828403121561298157600080fd5b8135610c818161290a565b6000806040838503121561299f57600080fd5b82356129aa8161290a565b915060208301356129ba8161291f565b809150509250929050565b600080604083850312156129d857600080fd5b8235915060208301356129ba8161290a565b600080600080600060a08688031215612a0257600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60008060408385031215612a3857600080fd5b8235612a438161290a565b946020939093013593505050565b60008060408385031215612a6457600080fd5b8235612a6f8161290a565b915060208301356129ba8161290a565b600060208284031215612a9157600080fd5b8135610c818161291f565b600080600080600080600060e0888a031215612ab757600080fd5b8735612ac28161290a565b96506020880135612ad28161290a565b95506040880135612ae28161290a565b94506060880135612af28161290a565b93506080880135612b028161290a565b9699959850939692959460a0840135945060c09093013592915050565b600080600060608486031215612b3457600080fd5b8335612b3f8161290a565b95602085013595506040909401359392505050565b600080600060608486031215612b6957600080fd5b8335612b748161290a565b92506020840135612b848161291f565b929592945050506040919091013590565b600080600060608486031215612baa57600080fd5b8335612bb58161290a565b92506020840135612b848161290a565b600060208284031215612bd757600080fd5b8151610c818161290a565b6020810160358310612c0457634e487b7160e01b600052602160045260246000fd5b91905290565b600060208284031215612c1c57600080fd5b8151610c818161291f565b600060208284031215612c3957600080fd5b815160ff81168114610c8157600080fd5b634e487b7160e01b600052604160045260246000fd5b60005b83811015612c7b578181015183820152602001612c63565b83811115611f595750506000910152565b600060208284031215612c9e57600080fd5b815167ffffffffffffffff80821115612cb657600080fd5b818401915084601f830112612cca57600080fd5b815181811115612cdc57612cdc612c4a565b604051601f8201601f19908116603f01168101908382118183101715612d0457612d04612c4a565b81604052828152876020848701011115612d1d57600080fd5b61281e836020830160208801612c60565b6502437b732bc960d51b815260008351612d4f816006850160208801612c60565b600160fd1b6006918401918201528351612d70816007840160208801612c60565b01600701949350505050565b600d60fb1b815260008351612d98816001850160208801612c60565b835190830190612daf816001840160208801612c60565b01600101949350505050565b60008151808452612dd3816020860160208601612c60565b601f01601f19169290920160200192915050565b60006101406001600160a01b03808e168452808d166020850152808c166040850152808b166060850152808a1660808501528860a085015280881660c085015280871660e08501525080610100840152612e4381840186612dbb565b9050828103610120840152612e588185612dbb565b9d9c50505050505050505050505050565b60006001600160a01b03808a1683528089166020840152808816604084015286606084015280861660808401525060e060a0830152612eab60e0830185612dbb565b82810360c0840152612ebd8185612dbb565b9a9950505050505050505050565b600060208284031215612edd57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082821015612f2257612f22612efa565b500390565b634e487b7160e01b600052603160045260246000fd5b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612f75816017850160208801612c60565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351612fa6816028840160208801612c60565b01602801949350505050565b602081526000610c816020830184612dbb565b6000816000190483118215151615612fdf57612fdf612efa565b500290565b60008219821115612ff757612ff7612efa565b500190565b60008161300b5761300b612efa565b506000190190565b60008251613025818460208701612c60565b919091019291505056fea2646970667358221220011a7a6d7ce486b3d7b642a5ea5858ee1284d12dce9206e229a6d428c3d9089064736f6c634300080f0033
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.