Contract Overview
Balance:
0 MATIC
MATIC Value:
$0.00
My Name Tag:
Not Available, login to update
Txn Hash |
Method
|
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0x9b786ea0fdb5356dfd5813773937c5f2b7196a76c69873b5ca6aac211acb178d | 0x60806040 | 40788167 | 64 days 6 hrs ago | 0xe820cc557279acc115d61b7c450f47ff000b4ef6 | IN | Create: HTokenFactory | 0 MATIC | 0.42829896 |
[ Download CSV Export ]
Latest 8 internal transactions
[ Download CSV Export ]
Contract Name:
HTokenFactory
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: 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.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 (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: BUSL-1.1 pragma solidity ^0.8.15; 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 */ contract HTokenFactory { address private controlPanel; constructor(address _controlPanel) { controlPanel = _controlPanel; } function deployHToken( address _underlyingToken, address _collateralToken, address _controllerAddress, address _interestRateModel, address _liquidator, uint256 _initialExchangeRateMantissa, address _adminCommissionReceiver, address _protocolCommissionReceiver, string memory _name, string memory _symbol ) external returns (address) { if (msg.sender != controlPanel) { revert WrongCaller(); } HToken hToken = new HToken( _underlyingToken, _collateralToken, _controllerAddress, _interestRateModel, _liquidator, _initialExchangeRateMantissa, _adminCommissionReceiver, _protocolCommissionReceiver, msg.sender, _name, _symbol ); return address(hToken); } error WrongCaller(); }
//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 ".././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 "./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":[{"internalType":"address","name":"_controlPanel","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WrongCaller","type":"error"},{"inputs":[{"internalType":"address","name":"_underlyingToken","type":"address"},{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"address","name":"_controllerAddress","type":"address"},{"internalType":"address","name":"_interestRateModel","type":"address"},{"internalType":"address","name":"_liquidator","type":"address"},{"internalType":"uint256","name":"_initialExchangeRateMantissa","type":"uint256"},{"internalType":"address","name":"_adminCommissionReceiver","type":"address"},{"internalType":"address","name":"_protocolCommissionReceiver","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"deployHToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5060405161602a38038061602a83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b615f97806100936000396000f3fe60806040523480156200001157600080fd5b50600436106200002e5760003560e01c8063e1d007451462000033575b600080fd5b6200004a62000044366004620001c8565b62000066565b6040516001600160a01b03909116815260200160405180910390f35b600080546001600160a01b03163314620000935760405163068690bf60e11b815260040160405180910390fd5b60008b8b8b8b8b8b8b8b338c8c604051620000ae90620000f2565b620000c49b9a9998979695949392919062000311565b604051809103906000f080158015620000e1573d6000803e3d6000fd5b509c9b505050505050505050505050565b615bc080620003a283390190565b80356001600160a01b03811681146200011857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200014557600080fd5b813567ffffffffffffffff808211156200016357620001636200011d565b604051601f8301601f19908116603f011681019082821181831017156200018e576200018e6200011d565b81604052838152866020858801011115620001a857600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806000806000806000806000806101408b8d031215620001e957600080fd5b620001f48b62000100565b99506200020460208c0162000100565b98506200021460408c0162000100565b97506200022460608c0162000100565b96506200023460808c0162000100565b955060a08b013594506200024b60c08c0162000100565b93506200025b60e08c0162000100565b92506101008b013567ffffffffffffffff808211156200027a57600080fd5b620002888e838f0162000133565b93506101208d0135915080821115620002a057600080fd5b50620002af8d828e0162000133565b9150509295989b9194979a5092959850565b6000815180845260005b81811015620002e957602081850181015186830182015201620002cb565b81811115620002fc576000602083870101525b50601f01601f19169290920160200192915050565b60006101606001600160a01b03808f168452808e166020850152808d166040850152808c166060850152808b1660808501528960a085015280891660c085015280881660e085015280871661010085015250806101208401526200037881840186620002c1565b90508281036101408401526200038f8185620002c1565b9e9d505050505050505050505050505056fe6101006040523480156200001257600080fd5b5060405162005bc038038062005bc08339810160408190526200003591620004b3565b8a8a8a8a8a8a8a8a8a8a8a6040518060200160405280600081525062000061816200031360201b60201c565b506001600160a01b03871615806200008057506001600160a01b038516155b806200009357506001600160a01b038416155b80620000a657506001600160a01b038b16155b80620000b957506001600160a01b038a16155b15620000d857604051635863f78960e01b815260040160405180910390fd5b856000036200010857600e60405163076cbf6360e11b8152600401620000ff9190620005c6565b60405180910390fd5b60808690526040516301ffc9a760e01b81526380ac58cd60e01b60048201526001600160a01b038b16906301ffc9a790602401602060405180830381865afa15801562000159573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200017f9190620005ef565b6200019d57604051635863f78960e01b815260040160405180910390fd5b6001600160a01b038a1660e052620001b760008462000325565b620001e37f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c168862000325565b6001600160a01b038b1660c08190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa1580156200022e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200025491906200061a565b60ff1660a052600c80546001600160a01b0319166001600160a01b038916179055601b805460009062000287906200063f565b90915550600e80546001600160a01b03808c166001600160a01b03199283161790925543601955600f80548b841690831617905560098054888416908316179055600a8054928716929091169190911790556007620002e78382620006f6565b506008620002f68282620006f6565b5050505050505050505050505050505050505050505050620007c2565b6002620003218282620006f6565b5050565b60008281526003602090815260408083206001600160a01b038516845290915290205460ff16620003215760008281526003602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620003853390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b80516001600160a01b0381168114620003e157600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200040e57600080fd5b81516001600160401b03808211156200042b576200042b620003e6565b604051601f8301601f19908116603f01168101908282118183101715620004565762000456620003e6565b816040528381526020925086838588010111156200047357600080fd5b600091505b8382101562000497578582018301518183018401529082019062000478565b83821115620004a95760008385830101525b9695505050505050565b60008060008060008060008060008060006101608c8e031215620004d657600080fd5b620004e18c620003c9565b9a50620004f160208d01620003c9565b99506200050160408d01620003c9565b98506200051160608d01620003c9565b97506200052160808d01620003c9565b965060a08c015195506200053860c08d01620003c9565b94506200054860e08d01620003c9565b9350620005596101008d01620003c9565b6101208d01519093506001600160401b038111156200057757600080fd5b620005858e828f01620003fc565b6101408e015190935090506001600160401b03811115620005a557600080fd5b620005b38e828f01620003fc565b9150509295989b509295989b9093969950565b6020810160358310620005e957634e487b7160e01b600052602160045260246000fd5b91905290565b6000602082840312156200060257600080fd5b815180151581146200061357600080fd5b9392505050565b6000602082840312156200062d57600080fd5b815160ff811681146200061357600080fd5b6000600182016200066057634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200067c57607f821691505b6020821081036200069d57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620006f157600081815260208120601f850160051c81016020861015620006cc5750805b601f850160051c820191505b81811015620006ed57828155600101620006d8565b5050505b505050565b81516001600160401b03811115620007125762000712620003e6565b6200072a8162000723845462000667565b84620006a3565b602080601f831160018114620007625760008415620007495750858301515b600019600386901b1c1916600185901b178555620006ed565b600085815260208120601f198616915b82811015620007935788860151825594840194600190910190840162000772565b5085821015620007b25787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516153696200085760003960008181610a110152818161218d01528181612c5301528181612e5e0152612f860152600081816105f10152818161100401528181611e85015281816127ad015261304001526000818161067c01528181610ec201528181610ef0015281816125ea0152612618015260008181610b0e0152610f8601526153696000f3fe608060405234801561001057600080fd5b50600436106104115760003560e01c8063844f7c5711610220578063c6be718511610130578063e45bcfcc116100b8578063ee778c5911610087578063ee778c5914610bcb578063ef3f6df114610bde578063f242432a14610be7578063f42c2b0414610bfa578063f8f9da2814610c1a57600080fd5b8063e45bcfcc14610b6a578063e985e9c514610b73578063eb08ab2814610baf578063eb10931f14610bb857600080fd5b8063d6f0d39f116100ff578063d6f0d39f14610ac9578063d8dfcea014610af0578063db006a7514610b46578063dd5a612c14610b59578063e404728714610b6157600080fd5b8063c6be718514610a87578063c79c0cd914610a9a578063c8229b6c14610aa3578063d547741f14610ab657600080fd5b8063a376f2b8116101b3578063b0c97e2411610182578063b0c97e24146109f9578063b2016bd414610a0c578063b6e35da014610a33578063c37f68e214610a46578063c588618d14610a7457600080fd5b8063a376f2b81461096a578063a39fac121461097d578063a6afed95146109e8578063ade35dad146109f057600080fd5b806395d89b41116101ef57806395d89b4114610920578063a217fddf14610928578063a22cb46514610930578063a29508fc1461094357600080fd5b8063844f7c57146108d1578063855bb602146108e45780638f840ddd1461090457806391d148541461090d57600080fd5b80632eb2c2d61161032657806347bd3718116102ae57806354fd4d501161027d57806354fd4d50146108905780635f98f48f1461089a57806362314245146108ad5780636c540baf146108b557806381be376e146108be57600080fd5b806347bd3718146107445780634d3a968b1461074d5780634e1273f4146107605780634f38d2351461078057600080fd5b806333483f8f116102f557806333483f8f146106c357806334613dab1461070257806336568abe146107155780633a98ef39146107285780633e48f0331461073157600080fd5b80632eb2c2d6146106515780632f2ff15d14610664578063313ce56714610677578063330c8010146106b057600080fd5b806316d8887a116103a95780631fb99762116103785780631fb997621461052e578063248a9ca3146105c95780632495a599146105ec57806327a1ec0a1461062b5780632e1a7d4d1461063e57600080fd5b806316d8887a146104e357806318160ddd1461050a578063182df0f5146105135780631be195601461051b57600080fd5b80630ecbcdab116103e55780630ecbcdab1461048757806312377b0c1461049c57806314a6bf0f146104af578063150b7a02146104b757600080fd5b8062fdd58e1461041657806301ffc9a71461043c57806306fdde031461045f5780630e89341c14610474575b600080fd5b6104296104243660046144db565b610c22565b6040519081526020015b60405180910390f35b61044f61044a36600461451d565b610cbb565b6040519015158152602001610433565b610467610d27565b6040516104339190614592565b6104676104823660046145a5565b610db5565b61049a6104953660046145be565b610e2d565b005b6104296104aa3660046145a5565b610e9d565b610429610ebc565b6104ca6104c53660046146a7565b610f66565b6040516001600160e01b03199091168152602001610433565b6104297f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c1681565b61042960145481565b610429610f77565b61049a610529366004614713565b610ff0565b61058561053c3660046145a5565b601c60205260009081526040902080546001820154600283015460039093015463ffffffff831693640100000000840460ff1693600160281b90046001600160a01b0316929186565b6040805163ffffffff909716875260ff90951660208701526001600160a01b03909316938501939093526060840152608083019190915260a082015260c001610433565b6104296105d73660046145a5565b60009081526003602052604090206001015490565b6106137f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610433565b61049a61063936600461473e565b6110e6565b61049a61064c3660046145a5565b61120a565b61049a61065f366004614803565b611223565b61049a6106723660046148b1565b61126f565b61069e7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610433565b61049a6106be3660046145a5565b611299565b6106ed6106d13660046145a5565b601d602052600090815260409020805460019091015460ff1682565b60408051928352901515602083015201610433565b61049a6107103660046145a5565b611327565b61049a6107233660046148b1565b611338565b61042960125481565b61049a61073f3660046148d6565b6113b2565b61042960115481565b61049a61075b3660046148d6565b6113fa565b61077361076e36600461494b565b611437565b6040516104339190614a53565b61083261078e3660046145a5565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506000908152601c6020908152604091829020825160c081018452815463ffffffff81168252640100000000810460ff1693820193909352600160281b9092046001600160a01b031692820192909252600182015460608201526002820154608082015260039091015460a082015290565b6040516104339190600060c08201905063ffffffff835116825260ff60208401511660208301526001600160a01b036040840151166040830152606083015160608301526080830151608083015260a083015160a083015292915050565b610429620f424081565b61049a6108a83660046145be565b611561565b61042961161c565b61042960195481565b61049a6108cc36600461473e565b611729565b61049a6108df3660046145a5565b611884565b6104296108f2366004614713565b601f6020526000908152604090205481565b61042960135481565b61044f61091b3660046148b1565b61195b565b610467611986565b610429600081565b61049a61093e366004614a66565b611993565b6104297fd1ae8bbdabd60d63e418b84f5ad6f9cba90092c9816d7724d85f0d4e4bea2c6081565b61049a610978366004614add565b61199e565b600c54601054600e54600954600a54600f54600d54600b54604080516001600160a01b03998a16815297891660208901529588169587019590955292861660608601529085166080850152841660a0840152831660c08301529190911660e082015261010001610433565b61049a611a28565b61042960185481565b61049a610a073660046144db565b611a3f565b6106137f000000000000000000000000000000000000000000000000000000000000000081565b610429610a413660046145a5565b611c19565b610a59610a54366004614713565b611c61565b60408051938452602084019290925290820152606001610433565b61049a610a82366004614b60565b611cca565b61049a610a953660046144db565b611cfa565b61042960175481565b61049a610ab13660046144db565b611da7565b61049a610ac43660046148b1565b611dff565b6104297f3fb0aaa9e8051cfc6c234a5d843bed33910f70c647055f27247c10144c7552e181565b600454600554600654604080519384526020840192909252908201527f0000000000000000000000000000000000000000000000000000000000000000606082015265048c27395000608082015260a001610433565b61049a610b543660046145a5565b611e24565b610429611e35565b610429601a5481565b61042960155481565b61044f610b81366004614b99565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b610429601b5481565b61049a610bc63660046145a5565b611f09565b61049a610bd93660046148b1565b611fb6565b61042960165481565b61049a610bf5366004614bc7565b611fd9565b610429610c08366004614713565b601e6020526000908152604090205481565b61042961201e565b60006001600160a01b038316610c925760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b506000818152602081815260408083206001600160a01b03861684529091529020545b92915050565b60006001600160e01b03198216636cdb3d1360e11b1480610cec57506001600160e01b0319821663da8def7360e01b145b80610d0757506001600160e01b03198216630a85bd0160e11b145b80610cb557506001600160e01b031982166341277d7560e01b1492915050565b60078054610d3490614c30565b80601f0160208091040260200160405190810160405280929190818152602001828054610d6090614c30565b8015610dad5780601f10610d8257610100808354040283529160200191610dad565b820191906000526020600020905b815481529060010190602001808311610d9057829003601f168201915b505050505081565b6010546040516353a3d1f560e11b8152600481018390523060248201526060916001600160a01b03169063a747a3ea90604401600060405180830381865afa158015610e05573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cb59190810190614c6a565b610e356120b2565b610e94828260405180602001604052806000815250600067ffffffffffffffff811115610e6457610e646145e0565b6040519080825280601f01601f191660200182016040528015610e8e576020820181803683370190505b506120dc565b50506001602055565b6000818152601d6020526040812054610eb581611c19565b9392505050565b600060ff7f0000000000000000000000000000000000000000000000000000000000000000166012811015610f1c57610f167f00000000000000000000000000000000000000000000000000000000000000006012614d02565b60ff1690505b610f2781600a614e09565b601a54610f3261161c565b610f3c9190614e15565b601154610f499190614e2c565b610f539190614e4b565b601154610f609190614e6d565b91505090565b630a85bd0160e11b5b949350505050565b601454600090808203610fab577f000000000000000000000000000000000000000000000000000000000000000091505090565b6000601354601154610fbb611e35565b610fc59190614e6d565b610fcf9190614e15565b9050600082610fe683670de0b6b3a7640000614e2c565b610f6f9190614e4b565b610ffb60003361195b565b158061103857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316145b15611055576040516282b42960e81b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa15801561109c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c09190614e85565b905080156110e257600b546110e2906001600160a01b0384811691168361250d565b5050565b6110f1600033612570565b6110f96125c9565b611101612779565b8160000361112257604051635863f78960e01b815260040160405180910390fd5b80158015611131575081601754105b806111455750808015611145575081601854105b156111665760146040516342a8a55b60e01b8152600401610c899190614e9e565b801561119e57816018600082825461117e9190614e15565b9091555050600d54611199906001600160a01b0316836127a0565b6111cb565b81601760008282546111b09190614e15565b9091555050600b546111cb906001600160a01b0316836127a0565b6040805183815282151560208201527f0dad1ab35923e15f45fcab4b7501c2e87ac99e23901e63d505573f74287cc99991015b60405180910390a15050565b6112126120b2565b61121b816127d4565b506001602055565b6001600160a01b03851633148061123f575061123f8533610b81565b61125b5760405162461bcd60e51b8152600401610c8990614ec6565b61126885858585856128dd565b5050505050565b60008281526003602052604090206001015461128a81612ac8565b6112948383612ad5565b505050565b6112a4600033612570565b6112ac6125c9565b6112b4612779565b601554818110156112db5760146040516342a8a55b60e01b8152600401610c899190614e9e565b818103601555600a546112f7906001600160a01b0316836127a0565b6040518281527f8370bb0803f69d6ea194886767fc70fa8314f53265077aa340b353c4a0a60312906020016111fe565b61132f6120b2565b61121b81612b5b565b6001600160a01b03811633146113a85760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610c89565b6110e28282612d1b565b6113ba6120b2565b8060005b818110156113ef576113e78484838181106113db576113db614f14565b90506020020135612d82565b6001016113be565b505060016020555050565b6114026120b2565b8060005b818110156113ef5761142f84848381811061142357611423614f14565b90506020020135612efc565b600101611406565b6060815183511461149c5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608401610c89565b6000835167ffffffffffffffff8111156114b8576114b86145e0565b6040519080825280602002602001820160405280156114e1578160200160208202803683370190505b50905060005b84518110156115595761152c85828151811061150557611505614f14565b602002602001015185838151811061151f5761151f614f14565b6020026020010151610c22565b82828151811061153e5761153e614f14565b602090810291909101015261155281614f2a565b90506114e7565b509392505050565b61156c600033612570565b6115746125c9565b6005546706f05b59d3b200008361158b8385614e6d565b6115959190614e6d565b11156115b75760096040516342a8a55b60e01b8152600401610c899190614e9e565b6006546004546040805192835260208301869052820183905260608201839052608082015260a081018390527f540cc59835c43e083d684e30cfdd7b6e73e9cb966e3e50b66e885336ad8e57349060c00160405180910390a150600691909155600455565b6000806019544361162d9190614e15565b60115490915080158061163e575081155b1561164d57601a549250505090565b600f546000906001600160a01b03166315f24053611669611e35565b6013546040516001600160e01b031960e085901b1681526004810192909252602482018690526044820152606401602060405180830381865afa1580156116b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d89190614e85565b905065048c27395000811115611704576012604051635890300f60e01b8152600401610c899190614e9e565b60006117108483614e2c565b905080601a546117209190614e6d565b94505050505090565b6117537fd1ae8bbdabd60d63e418b84f5ad6f9cba90092c9816d7724d85f0d4e4bea2c6033612570565b61175b6125c9565b611763612779565b80156117cb576117733383613033565b6000826013546117839190614e6d565b6013819055604080518581526020810183905291925033917fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc5910160405180910390a2505050565b816013546117d7611e35565b6117e19190614e6d565b10156118035760116040516342a8a55b60e01b8152600401610c899190614e9e565b6013548211156118295760096040516342a8a55b60e01b8152600401610c899190614e9e565b60138054839003905561183c33836127a0565b60135460405133917f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e9161187891868252602082015260400190565b60405180910390a25050565b6118ae7f3fb0aaa9e8051cfc6c234a5d843bed33910f70c647055f27247c10144c7552e133612570565b6118b66125c9565b6006546004546706f05b59d3b20000826118d08584614e6d565b6118da9190614e6d565b11156118fc5760096040516342a8a55b60e01b8152600401610c899190614e9e565b600554604080518481526020810185905280820192909252606082018590526080820183905260a08201839052517f540cc59835c43e083d684e30cfdd7b6e73e9cb966e3e50b66e885336ad8e57349181900360c00190a15050600555565b60009182526003602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60088054610d3490614c30565b6110e2338383613068565b6119a66120b2565b611a1b868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a0181900481028201810190925288815292508891508790819084018382808284376000920191909152506120dc92505050565b5050600160205550505050565b611a306120b2565b611a386125c9565b6001602055565b6001600160a01b038216611a6657604051635863f78960e01b815260040160405180910390fd5b611a71600033612570565b600081600003611aa05750600c80546001600160a01b038481166001600160a01b031983161790925516611bc7565b81600103611acd5750601080546001600160a01b038481166001600160a01b031983161790925516611bc7565b81600203611afa5750600e80546001600160a01b038481166001600160a01b031983161790925516611bc7565b81600403611b275750600a80546001600160a01b038481166001600160a01b031983161790925516611bc7565b81600503611b545750600f80546001600160a01b038481166001600160a01b031983161790925516611bc7565b81600603611b815750600d80546001600160a01b038481166001600160a01b031983161790925516611bc7565b81600703611bae5750600b80546001600160a01b038481166001600160a01b031983161790925516611bc7565b604051635863f78960e01b815260040160405180910390fd5b806001600160a01b0316836001600160a01b03167f4e5960f91526bead4911fd7dc9b52ede9bca2120886a0852a6259873a3367dcf84604051611c0c91815260200190565b60405180910390a3505050565b6000818152601c6020526040812060125415611c58576012548160030154611c3f610ebc565b611c499190614e2c565b611c539190614e4b565b610eb5565b60009392505050565b60008060008060006012541115611ca8576012546011546001600160a01b0387166000908152601f6020526040902054611c9b9190614e2c565b611ca59190614e4b565b90505b611cb3856000610c22565b81611cbc610f77565b935093509350509193909250565b611cd26120b2565b6001600160a01b038116611ce35750335b611cf08184846000613140565b5050600160205550565b6001600160a01b038216611d2157604051635863f78960e01b815260040160405180910390fd5b611d4b7f3fb0aaa9e8051cfc6c234a5d843bed33910f70c647055f27247c10144c7552e133612570565b600081600303611d7a5750600980546001600160a01b038481166001600160a01b031983161790925516611bc7565b81600503611bae5750600f80546001600160a01b038481166001600160a01b031983161790925516611bc7565b611daf6120b2565b611dd97f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c163361195b565b611df5576040516282b42960e81b815260040160405180910390fd5b610e948282613446565b600082815260036020526040902060010154611e1a81612ac8565b6112948383612d1b565b611e2c6120b2565b61121b81613504565b600080601854601754601554601654611e4e9190614e6d565b611e589190614e6d565b611e629190614e6d565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611ecc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef09190614e85565b905080821115611f035760009250505090565b03919050565b611f337f3fb0aaa9e8051cfc6c234a5d843bed33910f70c647055f27247c10144c7552e133612570565b611f3b6125c9565b611f43612779565b60165481811015611f6a5760146040516342a8a55b60e01b8152600401610c899190614e9e565b818103601655600954611f86906001600160a01b0316836127a0565b6040518281527faa20b5f6821c93f428851c86ba5cf4c815c7f9e46c6bfc13c58a9dbdb42d6663906020016111fe565b611fbe6120b2565b6001600160a01b038116611fcf5750335b610e94828261360f565b6001600160a01b038516331480611ff55750611ff58533610b81565b6120115760405162461bcd60e51b8152600401610c8990614ec6565b6112688585858585613739565b600f546000906001600160a01b03166315f2405361203a611e35565b6011546013546040516001600160e01b031960e086901b168152600481019390935260248301919091526044820152606401602060405180830381865afa158015612089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ad9190614e85565b905090565b6002602054036120d55760405163769dd35360e11b815260040160405180910390fd5b6002602055565b6000838152601c602052604090208054640100000000900460ff1661211757601060405163076cbf6360e11b8152600401610c899190614e9e565b8381600101541461213b57604051635863f78960e01b815260040160405180910390fd5b8054600160281b90046001600160a01b031633811461216d576040516330cd747160e01b815260040160405180910390fd5b6040516331a9108f60e11b81526004810186905230906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa1580156121d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f89190614f43565b6001600160a01b03161461222257602360405163076cbf6360e11b8152600401610c899190614e9e565b61222a6125c9565b600e5460405163edf04a7d60e01b815260009182916001600160a01b039091169063edf04a7d906122639030908a908a90600401614f60565b6040805180830381865afa15801561227f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122a39190614f94565b90925090506000670de0b6b3a76400006122bd848b614e2c565b6122c79190614e4b565b905060006122d5828b614e6d565b600e5460405162b3500160e31b8152306004820152336024820152604481018c9052606481018390529192506001600160a01b03169063059a800890608401600060405180830381600087803b15801561232e57600080fd5b505af1158015612342573d6000803e3d6000fd5b50505050600060115460001461237257601154826012546123639190614e2c565b61236d9190614e4b565b612374565b815b905080601260008282546123889190614e6d565b92505081905550808760030160008282546123a39190614e6d565b90915550506001600160a01b0386166000908152601f6020526040812080548392906123d0908490614e6d565b92505081905550818760020160008282546123eb9190614e6d565b9250508190555081601160008282546124049190614e6d565b9091555050831561249b576000670de0b6b3a76400006124248786614e2c565b61242e9190614e4b565b905080601860008282546124429190614e6d565b9091555061245290508185614e15565b9350336001600160a01b03167f26bc1d75fa909bd75138988e83f4f268a02ad20f16414838a13b0dca9f8afa4b8b8e8460405161249193929190614fb9565b60405180910390a2505b82601760008282546124ad9190614e6d565b909155506124bd9050338c6127a0565b604080518c8152602081018c905290810183905233907f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab809060600160405180910390a25050505050505050505050565b6040516001600160a01b03831660248201526044810182905261129490849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613871565b61257a828261195b565b6110e25761258781613943565b612592836020613955565b6040516020016125a3929190614fde565b60408051601f198184030181529082905262461bcd60e51b8252610c8991600401614592565b601a546019544311156125e6576125de61161c565b601a55436019555b60ff7f000000000000000000000000000000000000000000000000000000000000000016601281101561263c575060ff7f0000000000000000000000000000000000000000000000000000000000000000601203165b600061264982600a614e09565b83601a546126579190614e15565b6011546126649190614e2c565b61266e9190614e4b565b905080601160008282546126829190614e6d565b9091555050600454670de0b6b3a76400009061269f908390614e2c565b6126a99190614e4b565b601360008282546126ba9190614e6d565b9091555050600654670de0b6b3a7640000906126d7908390614e2c565b6126e19190614e4b565b601560008282546126f29190614e6d565b9091555050600554670de0b6b3a76400009061270f908390614e2c565b6127199190614e4b565b6016600082825461272a9190614e6d565b9091555050601a546011546040805184815260208101939093528201527fe9d95e658b0c714da9de2e12fbed253a24a632058a074dc7c90b8b6618675c7c9060600160405180910390a1505050565b436019541461279e5760076040516342a8a55b60e01b8152600401610c899190614e9e565b565b6110e26001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016838361250d565b6127dc6125c9565b60006127e6610f77565b6127f883670de0b6b3a7640000614e2c565b6128029190614e4b565b600e5460405163eabe7d9160e01b8152306004820152336024820152604481018390529192506001600160a01b03169063eabe7d919060640160006040518083038186803b15801561285357600080fd5b505afa158015612867573d6000803e3d6000fd5b50505050806014600082825461287d9190614e15565b9091555061288f905033600083613af1565b61289933836127a0565b60145460408051838152602081018590529081019190915233907f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca9490606001611878565b815183511461293f5760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608401610c89565b6001600160a01b0384166129655760405162461bcd60e51b8152600401610c8990615053565b33612974818787878787613c86565b60005b8451811015612a5a57600085828151811061299457612994614f14565b6020026020010151905060008583815181106129b2576129b2614f14565b602090810291909101810151600084815280835260408082206001600160a01b038e168352909352919091205490915081811015612a025760405162461bcd60e51b8152600401610c8990615098565b6000838152602081815260408083206001600160a01b038e8116855292528083208585039055908b16825281208054849290612a3f908490614e6d565b9250508190555050505080612a5390614f2a565b9050612977565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051612aaa9291906150e2565b60405180910390a4612ac0818787878787613eb2565b505050505050565b612ad28133612570565b50565b612adf828261195b565b6110e25760008281526003602090815260408083206001600160a01b03851684529091529020805460ff19166001179055612b173390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000818152601c602052604090208054640100000000900460ff16600214612b9957600c60405163076cbf6360e11b8152600401610c899190614e9e565b612ba16125c9565b600e54604051636e37944560e01b8152306004820152602481018490526001600160a01b0390911690636e3794459060440160006040518083038186803b158015612beb57600080fd5b505afa158015612bff573d6000803e3d6000fd5b5050825464ff0000000019166403000000001783555050604080513060208201526000910160408051601f1981840301815290829052600c54635c46a7ef60e11b83529092506001600160a01b03908116917f00000000000000000000000000000000000000000000000000000000000000009091169063b88d4fde90612c90903090859089908890600401615110565b600060405180830381600087803b158015612caa57600080fd5b505af1158015612cbe573d6000803e3d6000fd5b5050845460408051600160281b9092046001600160a01b03908116835260208301899052851693503392507f3dc74f0af87eb89117556974b0649590ed68e65a9aef1fdf861dc8760528c36691015b60405180910390a350505050565b612d25828261195b565b156110e25760008281526003602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000818152601c602052604090208054600160281b90046001600160a01b03163314612dc0576040516282b42960e81b815260040160405180910390fd5b600e5460405163b3623f3160e01b8152306004820152602481018490526001600160a01b039091169063b3623f319060440160006040518083038186803b158015612e0a57600080fd5b505afa158015612e1e573d6000803e3d6000fd5b5050505060018101548154612e3c903390839063ffffffff16614016565b604051632142170760e11b8152306004820152336024820152604481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342842e0e90606401600060405180830381600087803b158015612eaa57600080fd5b505af1158015612ebe573d6000803e3d6000fd5b50506040518581523392507fc30fcfbcaac9e0deffa719714eaa82396ff506a0d0d0eebe170830177288715d915060200160405180910390a2505050565b600e5460405163e124075f60e01b8152306004820152336024820152604481018390526001600160a01b039091169063e124075f90606401600060405180830381600087803b158015612f4e57600080fd5b505af1158015612f62573d6000803e3d6000fd5b5050604051632142170760e11b8152336004820152306024820152604481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692506342842e0e9150606401600060405180830381600087803b158015612fd457600080fd5b505af1158015612fe8573d6000803e3d6000fd5b505050506000612ff83383614070565b604080518481526020810183905291925033917ff4d587c98d234ca4d147061e6b5167e7f41ee17f11562a9f0b49570abece859e9101611878565b6110e26001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001683308461415f565b816001600160a01b0316836001600160a01b0316036130db5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610c89565b6001600160a01b03838116600081815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319101611c0c565b8260000361316457600a60405163076cbf6360e11b8152600401610c899190614e9e565b61316c6125c9565b600e54604051638438811560e01b815230600482015260248101859052604481018490526001600160a01b039091169063843881159060640160006040518083038186803b1580156131bd57600080fd5b505afa1580156131d1573d6000803e3d6000fd5b5050506000838152601c6020526040902080549091506001600160a01b03600160281b9091048116908616811461321a576040516282b42960e81b815260040160405180910390fd5b8382600101541461323e57604051635863f78960e01b815260040160405180910390fd5b8215613279578154640100000000900460ff1660031461327457602f60405163076cbf6360e11b8152600401610c899190614e9e565b6132ab565b815460021964010000000090910460ff16016132ab57602f60405163076cbf6360e11b8152600401610c899190614e9e565b60006132b685611c19565b9050806000036132dc57600b60405163076cbf6360e11b8152600401610c899190614e9e565b60008187116132eb57866132ed565b815b90506132f93382613033565b600084600201548361330b9190614e15565b6002860154909150828210156133345781830380821061332d57808203613330565b60005b9150505b6000811561335c576011548460125461334d9190614e2c565b6133579190614e4b565b613362565b86600301545b90506000846011546133749190614e15565b905080601181905550816012600082825461338f9190614e15565b92505081905550818860030160008282546133aa9190614e15565b9091555050600288018390556001600160a01b0387166000908152601f6020526040812080548492906133de908490614e15565b90915550506040805186815260208101889052908101829052606081018b90526001600160a01b0388169033907f6fadbf7329d21f278e724fa0d4511001a158f2a97ee35c5bc4cf8b64417399ef9060800160405180910390a3505050505050505050505050565b61344e6125c9565b6000818152601c6020526040902080546001600160a01b03848116600160281b909204161461348f576040516282b42960e81b815260040160405180910390fd5b600061349a83611c19565b90506134a98482856001613140565b600182015482546134c191869163ffffffff16614016565b60408051848152602081018390526001600160a01b0386169133917fa1c59fc0134cdbb1d2f4594588a96756a132881fc9a40185857684b06bec4b149101612d0d565b600e5460405163eabe7d9160e01b8152306004820152336024820152604481018390526001600160a01b039091169063eabe7d919060640160006040518083038186803b15801561355457600080fd5b505afa158015613568573d6000803e3d6000fd5b505050506135746125c9565b6000670de0b6b3a7640000613587610f77565b6135919084614e2c565b61359b9190614e4b565b905081601460008282546135af9190614e15565b909155506135c1905033600084613af1565b6135cb33826127a0565b60145460408051848152602081018490529081019190915233907fbd5034ffbd47e4e72a94baa2cdb74c6fad73cb3bcdc13036b72ec8306f5a764690606001611878565b600e5460405163a9ab107f60e01b81523060048201526001600160a01b038381166024830152604482018590529091169063a9ab107f90606401600060405180830381600087803b15801561366357600080fd5b505af1158015613677573d6000803e3d6000fd5b505050506136836125c9565b600061368d610f77565b61369f84670de0b6b3a7640000614e2c565b6136a99190614e4b565b90506136b53384613033565b80601460008282546136c79190614e6d565b925050819055506136ea826000836040518060200160405280600081525061419d565b6014546040805185815260208101849052908101919091526001600160a01b0383169033907f5a2a8f243cc739487a182d9a7b0b5b83373fa28dade3004fded99d332d3ddf1090606001611c0c565b6001600160a01b03841661375f5760405162461bcd60e51b8152600401610c8990615053565b33600061376b856142b7565b90506000613778856142b7565b9050613788838989858589613c86565b6000868152602081815260408083206001600160a01b038c168452909152902054858110156137c95760405162461bcd60e51b8152600401610c8990615098565b6000878152602081815260408083206001600160a01b038d8116855292528083208985039055908a16825281208054889290613806908490614e6d565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4613866848a8a8a8a8a614302565b505050505050505050565b60006138c6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166143bd9092919063ffffffff16565b80519091501561129457808060200190518101906138e49190615142565b6112945760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c89565b6060610cb56001600160a01b03831660145b60606000613964836002614e2c565b61396f906002614e6d565b67ffffffffffffffff811115613987576139876145e0565b6040519080825280601f01601f1916602001820160405280156139b1576020820181803683370190505b509050600360fc1b816000815181106139cc576139cc614f14565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106139fb576139fb614f14565b60200101906001600160f81b031916908160001a9053506000613a1f846002614e2c565b613a2a906001614e6d565b90505b6001811115613aa2576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110613a5e57613a5e614f14565b1a60f81b828281518110613a7457613a74614f14565b60200101906001600160f81b031916908160001a90535060049490941c93613a9b8161515f565b9050613a2d565b508315610eb55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610c89565b6001600160a01b038316613b535760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610c89565b336000613b5f846142b7565b90506000613b6c846142b7565b9050613b8c83876000858560405180602001604052806000815250613c86565b6000858152602081815260408083206001600160a01b038a16845290915290205484811015613c095760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608401610c89565b6000868152602081815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46040805160208101909152600090525b50505050505050565b836001600160a01b0316856001600160a01b03160315612ac05782516000805b82811015613dd0576000868281518110613cc257613cc2614f14565b60200260200101511115613dc8576000601d6000888481518110613ce857613ce8614f14565b6020026020010151815260200190815260200160002090508060010160009054906101000a900460ff16613d1f5750600101613ca6565b80546000908152601c6020908152604080832080546001600160a01b03808e16600160281b0278ffffffffffffffffffffffffffffffffffffffff0000000000199092169190911782556003820154908e168552601f909352908320805491938392613d8c908490614e15565b90915550506001600160a01b038a166000908152601f602052604081208054839290613db9908490614e6d565b90915550506001909401935050505b600101613ca6565b50600e5460405163151eeb5560e01b81523060048201526001600160a01b039091169063151eeb5590602401600060405180830381600087803b158015613e1657600080fd5b505af1158015613e2a573d6000803e3d6000fd5b505050506001600160a01b03871615613e6b576001600160a01b0387166000908152601e602052604081208054839290613e65908490614e15565b90915550505b6001600160a01b03861615613ea8576001600160a01b0386166000908152601e602052604081208054839290613ea2908490614e6d565b90915550505b5050505050505050565b6001600160a01b0384163b15612ac05760405163bc197c8160e01b81526001600160a01b0385169063bc197c8190613ef69089908990889088908890600401615176565b6020604051808303816000875af1925050508015613f31575060408051601f3d908101601f19168201909252613f2e918101906151d4565b60015b613fe657613f3d6151f1565b806308c379a003613f765750613f5161520d565b80613f5c5750613f78565b8060405162461bcd60e51b8152600401610c899190614592565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d4552433131353560448201527f526563656976657220696d706c656d656e7465720000000000000000000000006064820152608401610c89565b6001600160e01b0319811663bc197c8160e01b14613c7d5760405162461bcd60e51b8152600401610c8990615297565b61402283826001613af1565b6000918252601c602090815260408084208054640100000000600160c81b03191664010000000017815560028101859055600301849055918352601d90529020600101805460ff1916905550565b601b546000828152601c602052604081208054919291640100000000900460ff16156140a557805463ffffffff1691506140cc565b601b600081546140b490614f2a565b90915550805463ffffffff191663ffffffff83161781555b6001818101859055600060028301819055825460038401829055640200000000640100000000600160c81b0319909116600160281b6001600160a01b038a1602171783556040805180820182528781526020808201858152878552601d82528385209251835551918501805460ff191692151592909217909155815190810190915290815261155991879185919061419d565b6040516001600160a01b03808516602483015283166044820152606481018290526141979085906323b872dd60e01b90608401612539565b50505050565b6001600160a01b0384166141fd5760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610c89565b336000614209856142b7565b90506000614216856142b7565b905061422783600089858589613c86565b6000868152602081815260408083206001600160a01b038b16845290915281208054879290614257908490614e6d565b909155505060408051878152602081018790526001600160a01b03808a1692600092918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4613c7d83600089898989614302565b604080516001808252818301909252606091600091906020808301908036833701905050905082816000815181106142f1576142f1614f14565b602090810291909101015292915050565b6001600160a01b0384163b15612ac05760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e619061434690899089908890889088906004016152df565b6020604051808303816000875af1925050508015614381575060408051601f3d908101601f1916820190925261437e918101906151d4565b60015b61438d57613f3d6151f1565b6001600160e01b0319811663f23a6e6160e01b14613c7d5760405162461bcd60e51b8152600401610c8990615297565b6060610f6f848460008585600080866001600160a01b031685876040516143e49190615317565b60006040518083038185875af1925050503d8060008114614421576040519150601f19603f3d011682016040523d82523d6000602084013e614426565b606091505b509150915061443787838387614442565b979650505050505050565b606083156144b15782516000036144aa576001600160a01b0385163b6144aa5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c89565b5081610f6f565b610f6f8383815115613f5c5781518083602001fd5b6001600160a01b0381168114612ad257600080fd5b600080604083850312156144ee57600080fd5b82356144f9816144c6565b946020939093013593505050565b6001600160e01b031981168114612ad257600080fd5b60006020828403121561452f57600080fd5b8135610eb581614507565b60005b8381101561455557818101518382015260200161453d565b838111156141975750506000910152565b6000815180845261457e81602086016020860161453a565b601f01601f19169290920160200192915050565b602081526000610eb56020830184614566565b6000602082840312156145b757600080fd5b5035919050565b600080604083850312156145d157600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff8111828210171561461c5761461c6145e0565b6040525050565b600067ffffffffffffffff82111561463d5761463d6145e0565b50601f01601f191660200190565b600082601f83011261465c57600080fd5b813561466781614623565b60405161467482826145f6565b82815285602084870101111561468957600080fd5b82602086016020830137600092810160200192909252509392505050565b600080600080608085870312156146bd57600080fd5b84356146c8816144c6565b935060208501356146d8816144c6565b925060408501359150606085013567ffffffffffffffff8111156146fb57600080fd5b6147078782880161464b565b91505092959194509250565b60006020828403121561472557600080fd5b8135610eb5816144c6565b8015158114612ad257600080fd5b6000806040838503121561475157600080fd5b82359150602083013561476381614730565b809150509250929050565b600067ffffffffffffffff821115614788576147886145e0565b5060051b60200190565b600082601f8301126147a357600080fd5b813560206147b08261476e565b6040516147bd82826145f6565b83815260059390931b85018201928281019150868411156147dd57600080fd5b8286015b848110156147f857803583529183019183016147e1565b509695505050505050565b600080600080600060a0868803121561481b57600080fd5b8535614826816144c6565b94506020860135614836816144c6565b9350604086013567ffffffffffffffff8082111561485357600080fd5b61485f89838a01614792565b9450606088013591508082111561487557600080fd5b61488189838a01614792565b9350608088013591508082111561489757600080fd5b506148a48882890161464b565b9150509295509295909350565b600080604083850312156148c457600080fd5b823591506020830135614763816144c6565b600080602083850312156148e957600080fd5b823567ffffffffffffffff8082111561490157600080fd5b818501915085601f83011261491557600080fd5b81358181111561492457600080fd5b8660208260051b850101111561493957600080fd5b60209290920196919550909350505050565b6000806040838503121561495e57600080fd5b823567ffffffffffffffff8082111561497657600080fd5b818501915085601f83011261498a57600080fd5b813560206149978261476e565b6040516149a482826145f6565b83815260059390931b85018201928281019150898411156149c457600080fd5b948201945b838610156149eb5785356149dc816144c6565b825294820194908201906149c9565b96505086013592505080821115614a0157600080fd5b50614a0e85828601614792565b9150509250929050565b600081518084526020808501945080840160005b83811015614a4857815187529582019590820190600101614a2c565b509495945050505050565b602081526000610eb56020830184614a18565b60008060408385031215614a7957600080fd5b8235614a84816144c6565b9150602083013561476381614730565b60008083601f840112614aa657600080fd5b50813567ffffffffffffffff811115614abe57600080fd5b602083019150836020828501011115614ad657600080fd5b9250929050565b60008060008060008060808789031215614af657600080fd5b8635955060208701359450604087013567ffffffffffffffff80821115614b1c57600080fd5b614b288a838b01614a94565b90965094506060890135915080821115614b4157600080fd5b50614b4e89828a01614a94565b979a9699509497509295939492505050565b600080600060608486031215614b7557600080fd5b83359250602084013591506040840135614b8e816144c6565b809150509250925092565b60008060408385031215614bac57600080fd5b8235614bb7816144c6565b91506020830135614763816144c6565b600080600080600060a08688031215614bdf57600080fd5b8535614bea816144c6565b94506020860135614bfa816144c6565b93506040860135925060608601359150608086013567ffffffffffffffff811115614c2457600080fd5b6148a48882890161464b565b600181811c90821680614c4457607f821691505b602082108103614c6457634e487b7160e01b600052602260045260246000fd5b50919050565b600060208284031215614c7c57600080fd5b815167ffffffffffffffff811115614c9357600080fd5b8201601f81018413614ca457600080fd5b8051614caf81614623565b604051614cbc82826145f6565b828152866020848601011115614cd157600080fd5b614ce283602083016020870161453a565b9695505050505050565b634e487b7160e01b600052601160045260246000fd5b600060ff821660ff841680821015614d1c57614d1c614cec565b90039392505050565b600181815b80851115614d60578160001904821115614d4657614d46614cec565b80851615614d5357918102915b93841c9390800290614d2a565b509250929050565b600082614d7757506001610cb5565b81614d8457506000610cb5565b8160018114614d9a5760028114614da457614dc0565b6001915050610cb5565b60ff841115614db557614db5614cec565b50506001821b610cb5565b5060208310610133831016604e8410600b8410161715614de3575081810a610cb5565b614ded8383614d25565b8060001904821115614e0157614e01614cec565b029392505050565b6000610eb58383614d68565b600082821015614e2757614e27614cec565b500390565b6000816000190483118215151615614e4657614e46614cec565b500290565b600082614e6857634e487b7160e01b600052601260045260246000fd5b500490565b60008219821115614e8057614e80614cec565b500190565b600060208284031215614e9757600080fd5b5051919050565b6020810160358310614ec057634e487b7160e01b600052602160045260246000fd5b91905290565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060018201614f3c57614f3c614cec565b5060010190565b600060208284031215614f5557600080fd5b8151610eb5816144c6565b6001600160a01b0384168152606060208201526000614f826060830185614566565b8281036040840152614ce28185614566565b60008060408385031215614fa757600080fd5b82519150602083015161476381614730565b606081526000614fcc6060830186614566565b60208301949094525060400152919050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161501681601785016020880161453a565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161504781602884016020880161453a565b01602801949350505050565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b6040815260006150f56040830185614a18565b82810360208401526151078185614a18565b95945050505050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152614ce26080830184614566565b60006020828403121561515457600080fd5b8151610eb581614730565b60008161516e5761516e614cec565b506000190190565b60006001600160a01b03808816835280871660208401525060a060408301526151a260a0830186614a18565b82810360608401526151b48186614a18565b905082810360808401526151c88185614566565b98975050505050505050565b6000602082840312156151e657600080fd5b8151610eb581614507565b600060033d111561520a5760046000803e5060005160e01c5b90565b600060443d101561521b5790565b6040516003193d81016004833e81513d67ffffffffffffffff816024840111818411171561524b57505050505090565b82850191508151818111156152635750505050505090565b843d870101602082850101111561527d5750505050505090565b61528c602082860101876145f6565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b60006001600160a01b03808816835280871660208401525084604083015283606083015260a0608083015261443760a0830184614566565b6000825161532981846020870161453a565b919091019291505056fea2646970667358221220abc551e89912bb24f13ef14cc367eb87a2fa0579ece3f16403085461b3f7dccd64736f6c634300080f0033a2646970667358221220ee2f31ac490558404dfc38f0449e3f9324ac07bb80f3df10ebb21c6cb2cb8d9e64736f6c634300080f00330000000000000000000000003c681140690b7dfe0dcb2c8d44d5713afaf67bcd
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003c681140690b7dfe0dcb2c8d44d5713afaf67bcd
-----Decoded View---------------
Arg [0] : _controlPanel (address): 0x3c681140690b7dfe0dcb2c8d44d5713afaf67bcd
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000003c681140690b7dfe0dcb2c8d44d5713afaf67bcd
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.