Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 12 from a total of 12 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Collateral P... | 15048345 | 881 days ago | IN | 0 ETH | 0.00211967 | ||||
Set Collateral P... | 15048337 | 881 days ago | IN | 0 ETH | 0.00266925 | ||||
Set Collateral P... | 15048325 | 881 days ago | IN | 0 ETH | 0.00297671 | ||||
Set Collateral P... | 14998794 | 890 days ago | IN | 0 ETH | 0.00602371 | ||||
Set Collateral P... | 14962473 | 896 days ago | IN | 0 ETH | 0.00954491 | ||||
Set Collateral P... | 14962467 | 896 days ago | IN | 0 ETH | 0.01085666 | ||||
Set Collateral P... | 14878417 | 911 days ago | IN | 0 ETH | 0.00455501 | ||||
Set Collateral P... | 14878295 | 911 days ago | IN | 0 ETH | 0.00412188 | ||||
Set Utilization ... | 14878256 | 911 days ago | IN | 0 ETH | 0.00260815 | ||||
Grant Role | 14878216 | 911 days ago | IN | 0 ETH | 0.00127079 | ||||
Set Minimum Loan... | 14878215 | 911 days ago | IN | 0 ETH | 0.00104171 | ||||
0x60806040 | 14878197 | 911 days ago | IN | 0 ETH | 0.03348848 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
LoanPriceOracle
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.9; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "prb-math/contracts/PRBMathUD60x18.sol"; import "./interfaces/ICollateralOracle.sol"; import "./interfaces/ILoanPriceOracle.sol"; /** * @title Loan Price Oracle */ contract LoanPriceOracle is AccessControl, ILoanPriceOracle { using EnumerableSet for EnumerableSet.AddressSet; /**************************************************************************/ /* Constants */ /**************************************************************************/ /** * @notice Implementation version */ string public constant IMPLEMENTATION_VERSION = "1.0"; /** * @notice One in UD60x18 */ uint256 private constant ONE_UD60X18 = 1e18; /**************************************************************************/ /* Access Control Roles */ /**************************************************************************/ /** * @notice Parameter admin role */ bytes32 public constant PARAMETER_ADMIN_ROLE = keccak256("PARAMETER_ADMIN"); /**************************************************************************/ /* Errors */ /**************************************************************************/ /** * @notice Unsupported token decimals */ error UnsupportedTokenDecimals(); /** * @notice Invalid address (e.g. zero address) */ error InvalidAddress(); /**************************************************************************/ /* Events */ /**************************************************************************/ /** * @notice Emitted when minimum loan duration is updated * @param duration New minimum loan duration in seconds */ event MinimumLoanDurationUpdated(uint256 duration); /** * @notice Emitted when utilization parameters are updated */ event UtilizationParametersUpdated(); /** * @notice Emitted when collateral parameters are updated * @param collateralToken Address of collateral token */ event CollateralParametersUpdated(address indexed collateralToken); /** * @notice Emitted when collateral oracle is updated * @param collateralOracle Address of collateral oracle */ event CollateralOracleUpdated(address collateralOracle); /**************************************************************************/ /* State */ /**************************************************************************/ /** * @notice Piecewise linear model parameters * @param offset Output value offset in UD4x18 * @param slope1 Slope before kink in UD4x18 * @param slope2 Slope after kink in UD4x18 * @param target Input value of kink in UD11x18 * @param max Max input value in UD11x18 */ struct PiecewiseLinearModel { uint72 offset; uint72 slope1; uint72 slope2; uint96 target; uint96 max; } /** * @notice Collateral parameters * @param active Collateral is supported * @param loanToValueRateComponent Rate component model for loan to value * @param durationRateComponent Rate component model for duration * @param rateComponentWeights Weights for rate components, each 0 to 10000 */ struct CollateralParameters { bool active; PiecewiseLinearModel loanToValueRateComponent; PiecewiseLinearModel durationRateComponent; uint16[3] rateComponentWeights; /* 0-10000 */ } /** * @dev Rate component model for utilization */ PiecewiseLinearModel private _utilizationParameters; /** * @dev Mapping of collateral token contract to collateral parameters */ mapping(address => CollateralParameters) private _parameters; /** * @dev Set of supported collateral tokens */ EnumerableSet.AddressSet private _collateralTokens; /** * @dev Collateral oracle */ ICollateralOracle public collateralOracle; /** * @notice Minimum loan duration in seconds */ uint256 public minimumLoanDuration; /**************************************************************************/ /* Constructor */ /**************************************************************************/ /** * @notice LoanPriceOracle constructor * @param collateralOracle_ Collateral oracle */ constructor(ICollateralOracle collateralOracle_) { if (IERC20Metadata(address(collateralOracle_.currencyToken())).decimals() != 18) revert UnsupportedTokenDecimals(); collateralOracle = collateralOracle_; _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); _grantRole(PARAMETER_ADMIN_ROLE, msg.sender); } /**************************************************************************/ /* Internal Helper Functions */ /**************************************************************************/ /** * @dev Compute the output of the specified piecewise linear model with * input x * @param model Piecewise linear model to compute * @param x Input value in UD60x18 * @param index Parameter index (for error reporting) * @return Result in UD60x18 */ function _computeRateComponent( PiecewiseLinearModel storage model, uint256 x, uint256 index ) internal view returns (uint256) { if (x > uint256(model.max)) { revert ParameterOutOfBounds(index); } return (x <= uint256(model.target)) ? uint256(model.offset) + PRBMathUD60x18.mul(x, uint256(model.slope1)) : uint256(model.offset) + PRBMathUD60x18.mul(uint256(model.target), uint256(model.slope1)) + PRBMathUD60x18.mul(x - uint256(model.target), uint256(model.slope2)); } /** * @dev Compute the weighted rate * @param weights Weights to apply, each 0 to 10000 * @param components Components to weight, each UD60x18 * @return Weighted rate in UD60x18 */ function _computeWeightedRate(uint16[3] storage weights, uint256[3] memory components) internal view returns (uint256) { return PRBMathUD60x18.div( PRBMathUD60x18.mul(components[0], PRBMathUD60x18.fromUint(weights[0])) + PRBMathUD60x18.mul(components[1], PRBMathUD60x18.fromUint(weights[1])) + PRBMathUD60x18.mul(components[2], PRBMathUD60x18.fromUint(weights[2])), PRBMathUD60x18.fromUint(10000) ); } /**************************************************************************/ /* Primary API */ /**************************************************************************/ /** * @inheritdoc ILoanPriceOracle */ function priceLoan( address collateralToken, uint256 collateralTokenId, uint256 principal, uint256 repayment, uint256 duration, uint256 maturity, uint256 utilization ) external view returns (uint256) { /* Unused variables */ duration; /* Validate minimum loan duration */ if (block.timestamp > maturity - minimumLoanDuration) { revert InsufficientTimeRemaining(); } /* Look up collateral parameters */ CollateralParameters storage collateralParameters = _parameters[collateralToken]; if (!collateralParameters.active) { revert UnsupportedCollateral(); } /* Look up collateral value */ uint256 collateralValue = collateralOracle.collateralValue(collateralToken, collateralTokenId); /* Calculate loan time remaining */ uint256 loanTimeRemaining = PRBMathUD60x18.fromUint(maturity - block.timestamp); /* Calculate loan to value */ uint256 loanToValue = PRBMathUD60x18.div(principal, collateralValue); /* Compute discount rate components for utilization, loan-to-value, and duration */ uint256[3] memory rateComponents = [ _computeRateComponent(_utilizationParameters, utilization, 0), _computeRateComponent(collateralParameters.loanToValueRateComponent, loanToValue, 1), _computeRateComponent(collateralParameters.durationRateComponent, loanTimeRemaining, 2) ]; /* Calculate discount rate from components */ uint256 discountRate = _computeWeightedRate(collateralParameters.rateComponentWeights, rateComponents); /* Calculate purchase price */ /* Purchase Price = Loan Repayment Value / (1 + Discount Rate * t) */ uint256 purchasePrice = PRBMathUD60x18.div( repayment, ONE_UD60X18 + PRBMathUD60x18.mul(discountRate, loanTimeRemaining) ); return purchasePrice; } /**************************************************************************/ /* Getters */ /**************************************************************************/ /** * @inheritdoc ILoanPriceOracle */ function currencyToken() external view returns (IERC20) { return collateralOracle.currencyToken(); } /** * @notice Get utilization parameters * @return Utilization rate component model */ function getUtilizationParameters() external view returns (PiecewiseLinearModel memory) { return _utilizationParameters; } /** * @notice Get collateral parameters for token contract * @param collateralToken Collateral token contract * @return Collateral parameters */ function getCollateralParameters(address collateralToken) external view returns (CollateralParameters memory) { return _parameters[collateralToken]; } /** * @notice Get list of supported collateral tokens * @return List of collateral token addresses */ function supportedCollateralTokens() external view returns (address[] memory) { return _collateralTokens.values(); } /**************************************************************************/ /* Setters */ /**************************************************************************/ /** * @notice Set minimum loan duration * * Emits a {MinimumLoanDurationUpdated} event. * * @param duration Minimum loan duration in seconds */ function setMinimumLoanDuration(uint256 duration) external onlyRole(PARAMETER_ADMIN_ROLE) { minimumLoanDuration = duration; emit MinimumLoanDurationUpdated(duration); } /** * @notice Set utilization parameters * * Emits a {UtilizationParametersUpdated} event. * * @param packedUtilizationParameters Utilization rate component model, ABI-encoded */ function setUtilizationParameters(bytes calldata packedUtilizationParameters) external onlyRole(PARAMETER_ADMIN_ROLE) { _utilizationParameters = abi.decode(packedUtilizationParameters, (PiecewiseLinearModel)); emit UtilizationParametersUpdated(); } /** * @notice Set collateral parameters * * Emits a {CollateralParametersUpdated} event. * * @param collateralToken Collateral token contract * @param packedCollateralParameters Collateral parameters, ABI-encoded */ function setCollateralParameters(address collateralToken, bytes calldata packedCollateralParameters) external onlyRole(PARAMETER_ADMIN_ROLE) { if (collateralToken == address(0)) revert InvalidAddress(); _parameters[collateralToken] = abi.decode(packedCollateralParameters, (CollateralParameters)); /* Validate rate component weights sum to 10000 */ if ( _parameters[collateralToken].rateComponentWeights[0] + _parameters[collateralToken].rateComponentWeights[1] + _parameters[collateralToken].rateComponentWeights[2] != 10000 ) revert ParameterOutOfBounds(4); if (_parameters[collateralToken].active) { _collateralTokens.add(collateralToken); } else { _collateralTokens.remove(collateralToken); } emit CollateralParametersUpdated(collateralToken); } /** * @notice Set collateral collateral oracle * * Emits a {CollateralOracleUpdated} event. * * @param collateralOracle_ Collateral oracle contract */ function setCollateralOracle(address collateralOracle_) external onlyRole(DEFAULT_ADMIN_ROLE) { if (IERC20Metadata(address(ICollateralOracle(collateralOracle_).currencyToken())).decimals() != 18) revert UnsupportedTokenDecimals(); collateralOracle = ICollateralOracle(collateralOracle_); emit CollateralOracleUpdated(collateralOracle_); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.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, _msgSender()); _; } /** * @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 `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(uint160(account), 20), " 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. */ 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. */ 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`. */ 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. * * [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. */ 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. */ 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 (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 v4.4.1 (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; assembly { result := store } return result; } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; import "./PRBMath.sol"; /// @title PRBMathUD60x18 /// @author Paul Razvan Berg /// @notice Smart contract library for advanced fixed-point math that works with uint256 numbers considered to have 18 /// trailing decimals. We call this number representation unsigned 60.18-decimal fixed-point, since there can be up to 60 /// digits in the integer part and up to 18 decimals in the fractional part. The numbers are bound by the minimum and the /// maximum values permitted by the Solidity type uint256. library PRBMathUD60x18 { /// @dev Half the SCALE number. uint256 internal constant HALF_SCALE = 5e17; /// @dev log2(e) as an unsigned 60.18-decimal fixed-point number. uint256 internal constant LOG2_E = 1_442695040888963407; /// @dev The maximum value an unsigned 60.18-decimal fixed-point number can have. uint256 internal constant MAX_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_584007913129639935; /// @dev The maximum whole value an unsigned 60.18-decimal fixed-point number can have. uint256 internal constant MAX_WHOLE_UD60x18 = 115792089237316195423570985008687907853269984665640564039457_000000000000000000; /// @dev How many trailing decimals can be represented. uint256 internal constant SCALE = 1e18; /// @notice Calculates the arithmetic average of x and y, rounding down. /// @param x The first operand as an unsigned 60.18-decimal fixed-point number. /// @param y The second operand as an unsigned 60.18-decimal fixed-point number. /// @return result The arithmetic average as an unsigned 60.18-decimal fixed-point number. function avg(uint256 x, uint256 y) internal pure returns (uint256 result) { // The operations can never overflow. unchecked { // The last operand checks if both x and y are odd and if that is the case, we add 1 to the result. We need // to do this because if both numbers are odd, the 0.5 remainder gets truncated twice. result = (x >> 1) + (y >> 1) + (x & y & 1); } } /// @notice Yields the least unsigned 60.18 decimal fixed-point number greater than or equal to x. /// /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// /// Requirements: /// - x must be less than or equal to MAX_WHOLE_UD60x18. /// /// @param x The unsigned 60.18-decimal fixed-point number to ceil. /// @param result The least integer greater than or equal to x, as an unsigned 60.18-decimal fixed-point number. function ceil(uint256 x) internal pure returns (uint256 result) { if (x > MAX_WHOLE_UD60x18) { revert PRBMathUD60x18__CeilOverflow(x); } assembly { // Equivalent to "x % SCALE" but faster. let remainder := mod(x, SCALE) // Equivalent to "SCALE - remainder" but faster. let delta := sub(SCALE, remainder) // Equivalent to "x + delta * (remainder > 0 ? 1 : 0)" but faster. result := add(x, mul(delta, gt(remainder, 0))) } } /// @notice Divides two unsigned 60.18-decimal fixed-point numbers, returning a new unsigned 60.18-decimal fixed-point number. /// /// @dev Uses mulDiv to enable overflow-safe multiplication and division. /// /// Requirements: /// - The denominator cannot be zero. /// /// @param x The numerator as an unsigned 60.18-decimal fixed-point number. /// @param y The denominator as an unsigned 60.18-decimal fixed-point number. /// @param result The quotient as an unsigned 60.18-decimal fixed-point number. function div(uint256 x, uint256 y) internal pure returns (uint256 result) { result = PRBMath.mulDiv(x, SCALE, y); } /// @notice Returns Euler's number as an unsigned 60.18-decimal fixed-point number. /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant). function e() internal pure returns (uint256 result) { result = 2_718281828459045235; } /// @notice Calculates the natural exponent of x. /// /// @dev Based on the insight that e^x = 2^(x * log2(e)). /// /// Requirements: /// - All from "log2". /// - x must be less than 133.084258667509499441. /// /// @param x The exponent as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp(uint256 x) internal pure returns (uint256 result) { // Without this check, the value passed to "exp2" would be greater than 192. if (x >= 133_084258667509499441) { revert PRBMathUD60x18__ExpInputTooBig(x); } // Do the fixed-point multiplication inline to save gas. unchecked { uint256 doubleScaleProduct = x * LOG2_E; result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE); } } /// @notice Calculates the binary exponent of x using the binary fraction method. /// /// @dev See https://ethereum.stackexchange.com/q/79903/24693. /// /// Requirements: /// - x must be 192 or less. /// - The result must fit within MAX_UD60x18. /// /// @param x The exponent as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp2(uint256 x) internal pure returns (uint256 result) { // 2^192 doesn't fit within the 192.64-bit format used internally in this function. if (x >= 192e18) { revert PRBMathUD60x18__Exp2InputTooBig(x); } unchecked { // Convert x to the 192.64-bit fixed-point format. uint256 x192x64 = (x << 64) / SCALE; // Pass x to the PRBMath.exp2 function, which uses the 192.64-bit fixed-point number representation. result = PRBMath.exp2(x192x64); } } /// @notice Yields the greatest unsigned 60.18 decimal fixed-point number less than or equal to x. /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts. /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions. /// @param x The unsigned 60.18-decimal fixed-point number to floor. /// @param result The greatest integer less than or equal to x, as an unsigned 60.18-decimal fixed-point number. function floor(uint256 x) internal pure returns (uint256 result) { assembly { // Equivalent to "x % SCALE" but faster. let remainder := mod(x, SCALE) // Equivalent to "x - remainder * (remainder > 0 ? 1 : 0)" but faster. result := sub(x, mul(remainder, gt(remainder, 0))) } } /// @notice Yields the excess beyond the floor of x. /// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part. /// @param x The unsigned 60.18-decimal fixed-point number to get the fractional part of. /// @param result The fractional part of x as an unsigned 60.18-decimal fixed-point number. function frac(uint256 x) internal pure returns (uint256 result) { assembly { result := mod(x, SCALE) } } /// @notice Converts a number from basic integer form to unsigned 60.18-decimal fixed-point representation. /// /// @dev Requirements: /// - x must be less than or equal to MAX_UD60x18 divided by SCALE. /// /// @param x The basic integer to convert. /// @param result The same number in unsigned 60.18-decimal fixed-point representation. function fromUint(uint256 x) internal pure returns (uint256 result) { unchecked { if (x > MAX_UD60x18 / SCALE) { revert PRBMathUD60x18__FromUintOverflow(x); } result = x * SCALE; } } /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down. /// /// @dev Requirements: /// - x * y must fit within MAX_UD60x18, lest it overflows. /// /// @param x The first operand as an unsigned 60.18-decimal fixed-point number. /// @param y The second operand as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function gm(uint256 x, uint256 y) internal pure returns (uint256 result) { if (x == 0) { return 0; } unchecked { // Checking for overflow this way is faster than letting Solidity do it. uint256 xy = x * y; if (xy / x != y) { revert PRBMathUD60x18__GmOverflow(x, y); } // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE // during multiplication. See the comments within the "sqrt" function. result = PRBMath.sqrt(xy); } } /// @notice Calculates 1 / x, rounding toward zero. /// /// @dev Requirements: /// - x cannot be zero. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the inverse. /// @return result The inverse as an unsigned 60.18-decimal fixed-point number. function inv(uint256 x) internal pure returns (uint256 result) { unchecked { // 1e36 is SCALE * SCALE. result = 1e36 / x; } } /// @notice Calculates the natural logarithm of x. /// /// @dev Based on the insight that ln(x) = log2(x) / log2(e). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// - This doesn't return exactly 1 for 2.718281828459045235, for that we would need more fine-grained precision. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the natural logarithm. /// @return result The natural logarithm as an unsigned 60.18-decimal fixed-point number. function ln(uint256 x) internal pure returns (uint256 result) { // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x) // can return is 196205294292027477728. unchecked { result = (log2(x) * SCALE) / LOG2_E; } } /// @notice Calculates the common logarithm of x. /// /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common /// logarithm based on the insight that log10(x) = log2(x) / log2(10). /// /// Requirements: /// - All from "log2". /// /// Caveats: /// - All from "log2". /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the common logarithm. /// @return result The common logarithm as an unsigned 60.18-decimal fixed-point number. function log10(uint256 x) internal pure returns (uint256 result) { if (x < SCALE) { revert PRBMathUD60x18__LogInputTooSmall(x); } // Note that the "mul" in this block is the assembly multiplication operation, not the "mul" function defined // in this contract. // prettier-ignore assembly { switch x case 1 { result := mul(SCALE, sub(0, 18)) } case 10 { result := mul(SCALE, sub(1, 18)) } case 100 { result := mul(SCALE, sub(2, 18)) } case 1000 { result := mul(SCALE, sub(3, 18)) } case 10000 { result := mul(SCALE, sub(4, 18)) } case 100000 { result := mul(SCALE, sub(5, 18)) } case 1000000 { result := mul(SCALE, sub(6, 18)) } case 10000000 { result := mul(SCALE, sub(7, 18)) } case 100000000 { result := mul(SCALE, sub(8, 18)) } case 1000000000 { result := mul(SCALE, sub(9, 18)) } case 10000000000 { result := mul(SCALE, sub(10, 18)) } case 100000000000 { result := mul(SCALE, sub(11, 18)) } case 1000000000000 { result := mul(SCALE, sub(12, 18)) } case 10000000000000 { result := mul(SCALE, sub(13, 18)) } case 100000000000000 { result := mul(SCALE, sub(14, 18)) } case 1000000000000000 { result := mul(SCALE, sub(15, 18)) } case 10000000000000000 { result := mul(SCALE, sub(16, 18)) } case 100000000000000000 { result := mul(SCALE, sub(17, 18)) } case 1000000000000000000 { result := 0 } case 10000000000000000000 { result := SCALE } case 100000000000000000000 { result := mul(SCALE, 2) } case 1000000000000000000000 { result := mul(SCALE, 3) } case 10000000000000000000000 { result := mul(SCALE, 4) } case 100000000000000000000000 { result := mul(SCALE, 5) } case 1000000000000000000000000 { result := mul(SCALE, 6) } case 10000000000000000000000000 { result := mul(SCALE, 7) } case 100000000000000000000000000 { result := mul(SCALE, 8) } case 1000000000000000000000000000 { result := mul(SCALE, 9) } case 10000000000000000000000000000 { result := mul(SCALE, 10) } case 100000000000000000000000000000 { result := mul(SCALE, 11) } case 1000000000000000000000000000000 { result := mul(SCALE, 12) } case 10000000000000000000000000000000 { result := mul(SCALE, 13) } case 100000000000000000000000000000000 { result := mul(SCALE, 14) } case 1000000000000000000000000000000000 { result := mul(SCALE, 15) } case 10000000000000000000000000000000000 { result := mul(SCALE, 16) } case 100000000000000000000000000000000000 { result := mul(SCALE, 17) } case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) } case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) } case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) } case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) } case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) } case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) } case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) } case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) } case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) } case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) } case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) } case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) } case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) } case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) } case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) } case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) } case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) } case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) } case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) } case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) } case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) } case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) } case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) } case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) } case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) } case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) } case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) } case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) } case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) } case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) } case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) } case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) } case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) } case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) } case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) } case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) } case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) } case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) } case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) } case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) } case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) } case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) } default { result := MAX_UD60x18 } } if (result == MAX_UD60x18) { // Do the fixed-point division inline to save gas. The denominator is log2(10). unchecked { result = (log2(x) * SCALE) / 3_321928094887362347; } } } /// @notice Calculates the binary logarithm of x. /// /// @dev Based on the iterative approximation algorithm. /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation /// /// Requirements: /// - x must be greater than or equal to SCALE, otherwise the result would be negative. /// /// Caveats: /// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the binary logarithm. /// @return result The binary logarithm as an unsigned 60.18-decimal fixed-point number. function log2(uint256 x) internal pure returns (uint256 result) { if (x < SCALE) { revert PRBMathUD60x18__LogInputTooSmall(x); } unchecked { // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n). uint256 n = PRBMath.mostSignificantBit(x / SCALE); // The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow // because n is maximum 255 and SCALE is 1e18. result = n * SCALE; // This is y = x * 2^(-n). uint256 y = x >> n; // If y = 1, the fractional part is zero. if (y == SCALE) { return result; } // Calculate the fractional part via the iterative approximation. // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster. for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) { y = (y * y) / SCALE; // Is y^2 > 2 and so in the range [2,4)? if (y >= 2 * SCALE) { // Add the 2^(-m) factor to the logarithm. result += delta; // Corresponds to z/2 on Wikipedia. y >>= 1; } } } } /// @notice Multiplies two unsigned 60.18-decimal fixed-point numbers together, returning a new unsigned 60.18-decimal /// fixed-point number. /// @dev See the documentation for the "PRBMath.mulDivFixedPoint" function. /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The product as an unsigned 60.18-decimal fixed-point number. function mul(uint256 x, uint256 y) internal pure returns (uint256 result) { result = PRBMath.mulDivFixedPoint(x, y); } /// @notice Returns PI as an unsigned 60.18-decimal fixed-point number. function pi() internal pure returns (uint256 result) { result = 3_141592653589793238; } /// @notice Raises x to the power of y. /// /// @dev Based on the insight that x^y = 2^(log2(x) * y). /// /// Requirements: /// - All from "exp2", "log2" and "mul". /// /// Caveats: /// - All from "exp2", "log2" and "mul". /// - Assumes 0^0 is 1. /// /// @param x Number to raise to given power y, as an unsigned 60.18-decimal fixed-point number. /// @param y Exponent to raise x to, as an unsigned 60.18-decimal fixed-point number. /// @return result x raised to power y, as an unsigned 60.18-decimal fixed-point number. function pow(uint256 x, uint256 y) internal pure returns (uint256 result) { if (x == 0) { result = y == 0 ? SCALE : uint256(0); } else { result = exp2(mul(log2(x), y)); } } /// @notice Raises x (unsigned 60.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the /// famous algorithm "exponentiation by squaring". /// /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// Requirements: /// - The result must fit within MAX_UD60x18. /// /// Caveats: /// - All from "mul". /// - Assumes 0^0 is 1. /// /// @param x The base as an unsigned 60.18-decimal fixed-point number. /// @param y The exponent as an uint256. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function powu(uint256 x, uint256 y) internal pure returns (uint256 result) { // Calculate the first iteration of the loop in advance. result = y & 1 > 0 ? x : SCALE; // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster. for (y >>= 1; y > 0; y >>= 1) { x = PRBMath.mulDivFixedPoint(x, x); // Equivalent to "y % 2 == 1" but faster. if (y & 1 > 0) { result = PRBMath.mulDivFixedPoint(result, x); } } } /// @notice Returns 1 as an unsigned 60.18-decimal fixed-point number. function scale() internal pure returns (uint256 result) { result = SCALE; } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Requirements: /// - x must be less than MAX_UD60x18 / SCALE. /// /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the square root. /// @return result The result as an unsigned 60.18-decimal fixed-point . function sqrt(uint256 x) internal pure returns (uint256 result) { unchecked { if (x > MAX_UD60x18 / SCALE) { revert PRBMathUD60x18__SqrtOverflow(x); } // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two unsigned // 60.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root). result = PRBMath.sqrt(x * SCALE); } } /// @notice Converts a unsigned 60.18-decimal fixed-point number to basic integer form, rounding down in the process. /// @param x The unsigned 60.18-decimal fixed-point number to convert. /// @return result The same number in basic integer form. function toUint(uint256 x) internal pure returns (uint256 result) { unchecked { result = x / SCALE; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title Interface to a Collateral Oracle */ interface ICollateralOracle { /**************************************************************************/ /* Error codes */ /**************************************************************************/ /** * @notice Unsupported collateral token */ error UnsupportedCollateral(); /**************************************************************************/ /* Getters */ /**************************************************************************/ /** * @notice Get currency token used for pricing * @return Currency token contract */ function currencyToken() external view returns (IERC20); /** * @notice Get collateral value * @param collateralToken Collateral token contract * @param collateralTokenId Collateral token ID * @return Collateral value */ function collateralValue(address collateralToken, uint256 collateralTokenId) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title Interface to a LoanPriceOracle */ interface ILoanPriceOracle { /**************************************************************************/ /* Error codes */ /**************************************************************************/ /** * @notice Unsupported collateral token contract */ error UnsupportedCollateral(); /** * @notice Insufficient time remaining for loan */ error InsufficientTimeRemaining(); /** * @notice Loan parameter out of bounds * @param index Index of out of bound parameter */ error ParameterOutOfBounds(uint256 index); /**************************************************************************/ /* Getters */ /**************************************************************************/ /** * @notice Get currency token used for pricing * @return Currency token contract */ function currencyToken() external view returns (IERC20); /**************************************************************************/ /* Primary API */ /**************************************************************************/ /** * @notice Price a loan collateralized by the specified token contract and * token id * @param collateralToken Collateral token contract * @param collateralTokenId Collateral token ID * @param principal Principal value of loan, in UD60x18 * @param repayment Repayment value of loan, in UD60x18 * @param duration Duration of loan, in seconds * @param maturity Maturity of loan, in seconds since Unix epoch * @param utilization Vault fund utilization, in UD60x18 * @return Price of loan, in UD60x18 */ function priceLoan( address collateralToken, uint256 collateralTokenId, uint256 principal, uint256 repayment, uint256 duration, uint256 maturity, uint256 utilization ) external view returns (uint256); }
// 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 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/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @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] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// 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.5.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `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); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivFixedPointOverflow(uint256 prod1); /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator); /// @notice Emitted when one of the inputs is type(int256).min. error PRBMath__MulDivSignedInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows int256. error PRBMath__MulDivSignedOverflow(uint256 rAbs); /// @notice Emitted when the input is MIN_SD59x18. error PRBMathSD59x18__AbsInputTooSmall(); /// @notice Emitted when ceiling a number overflows SD59x18. error PRBMathSD59x18__CeilOverflow(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__DivInputTooSmall(); /// @notice Emitted when one of the intermediary unsigned results overflows SD59x18. error PRBMathSD59x18__DivOverflow(uint256 rAbs); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathSD59x18__ExpInputTooBig(int256 x); /// @notice Emitted when the input is greater than 192. error PRBMathSD59x18__Exp2InputTooBig(int256 x); /// @notice Emitted when flooring a number underflows SD59x18. error PRBMathSD59x18__FloorUnderflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18. error PRBMathSD59x18__FromIntOverflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18. error PRBMathSD59x18__FromIntUnderflow(int256 x); /// @notice Emitted when the product of the inputs is negative. error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y); /// @notice Emitted when multiplying the inputs overflows SD59x18. error PRBMathSD59x18__GmOverflow(int256 x, int256 y); /// @notice Emitted when the input is less than or equal to zero. error PRBMathSD59x18__LogInputTooSmall(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__MulInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__MulOverflow(uint256 rAbs); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__PowuOverflow(uint256 rAbs); /// @notice Emitted when the input is negative. error PRBMathSD59x18__SqrtNegativeInput(int256 x); /// @notice Emitted when the calculating the square root overflows SD59x18. error PRBMathSD59x18__SqrtOverflow(int256 x); /// @notice Emitted when addition overflows UD60x18. error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y); /// @notice Emitted when ceiling a number overflows UD60x18. error PRBMathUD60x18__CeilOverflow(uint256 x); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathUD60x18__ExpInputTooBig(uint256 x); /// @notice Emitted when the input is greater than 192. error PRBMathUD60x18__Exp2InputTooBig(uint256 x); /// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18. error PRBMathUD60x18__FromUintOverflow(uint256 x); /// @notice Emitted when multiplying the inputs overflows UD60x18. error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y); /// @notice Emitted when the input is less than 1. error PRBMathUD60x18__LogInputTooSmall(uint256 x); /// @notice Emitted when the calculating the square root overflows UD60x18. error PRBMathUD60x18__SqrtOverflow(uint256 x); /// @notice Emitted when subtraction underflows UD60x18. error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y); /// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library /// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point /// representation. When it does not, it is explicitly mentioned in the NatSpec documentation. library PRBMath { /// STRUCTS /// struct SD59x18 { int256 value; } struct UD60x18 { uint256 value; } /// STORAGE /// /// @dev How many trailing decimals can be represented. uint256 internal constant SCALE = 1e18; /// @dev Largest power of two divisor of SCALE. uint256 internal constant SCALE_LPOTD = 262144; /// @dev SCALE inverted mod 2^256. uint256 internal constant SCALE_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /// FUNCTIONS /// /// @notice Calculates the binary exponent of x using the binary fraction method. /// @dev Has to use 192.64-bit fixed-point numbers. /// See https://ethereum.stackexchange.com/a/96594/24693. /// @param x The exponent as an unsigned 192.64-bit fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp2(uint256 x) internal pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows // because the initial result is 2^191 and all magic factors are less than 2^65. if (x & 0x8000000000000000 > 0) { result = (result * 0x16A09E667F3BCC909) >> 64; } if (x & 0x4000000000000000 > 0) { result = (result * 0x1306FE0A31B7152DF) >> 64; } if (x & 0x2000000000000000 > 0) { result = (result * 0x1172B83C7D517ADCE) >> 64; } if (x & 0x1000000000000000 > 0) { result = (result * 0x10B5586CF9890F62A) >> 64; } if (x & 0x800000000000000 > 0) { result = (result * 0x1059B0D31585743AE) >> 64; } if (x & 0x400000000000000 > 0) { result = (result * 0x102C9A3E778060EE7) >> 64; } if (x & 0x200000000000000 > 0) { result = (result * 0x10163DA9FB33356D8) >> 64; } if (x & 0x100000000000000 > 0) { result = (result * 0x100B1AFA5ABCBED61) >> 64; } if (x & 0x80000000000000 > 0) { result = (result * 0x10058C86DA1C09EA2) >> 64; } if (x & 0x40000000000000 > 0) { result = (result * 0x1002C605E2E8CEC50) >> 64; } if (x & 0x20000000000000 > 0) { result = (result * 0x100162F3904051FA1) >> 64; } if (x & 0x10000000000000 > 0) { result = (result * 0x1000B175EFFDC76BA) >> 64; } if (x & 0x8000000000000 > 0) { result = (result * 0x100058BA01FB9F96D) >> 64; } if (x & 0x4000000000000 > 0) { result = (result * 0x10002C5CC37DA9492) >> 64; } if (x & 0x2000000000000 > 0) { result = (result * 0x1000162E525EE0547) >> 64; } if (x & 0x1000000000000 > 0) { result = (result * 0x10000B17255775C04) >> 64; } if (x & 0x800000000000 > 0) { result = (result * 0x1000058B91B5BC9AE) >> 64; } if (x & 0x400000000000 > 0) { result = (result * 0x100002C5C89D5EC6D) >> 64; } if (x & 0x200000000000 > 0) { result = (result * 0x10000162E43F4F831) >> 64; } if (x & 0x100000000000 > 0) { result = (result * 0x100000B1721BCFC9A) >> 64; } if (x & 0x80000000000 > 0) { result = (result * 0x10000058B90CF1E6E) >> 64; } if (x & 0x40000000000 > 0) { result = (result * 0x1000002C5C863B73F) >> 64; } if (x & 0x20000000000 > 0) { result = (result * 0x100000162E430E5A2) >> 64; } if (x & 0x10000000000 > 0) { result = (result * 0x1000000B172183551) >> 64; } if (x & 0x8000000000 > 0) { result = (result * 0x100000058B90C0B49) >> 64; } if (x & 0x4000000000 > 0) { result = (result * 0x10000002C5C8601CC) >> 64; } if (x & 0x2000000000 > 0) { result = (result * 0x1000000162E42FFF0) >> 64; } if (x & 0x1000000000 > 0) { result = (result * 0x10000000B17217FBB) >> 64; } if (x & 0x800000000 > 0) { result = (result * 0x1000000058B90BFCE) >> 64; } if (x & 0x400000000 > 0) { result = (result * 0x100000002C5C85FE3) >> 64; } if (x & 0x200000000 > 0) { result = (result * 0x10000000162E42FF1) >> 64; } if (x & 0x100000000 > 0) { result = (result * 0x100000000B17217F8) >> 64; } if (x & 0x80000000 > 0) { result = (result * 0x10000000058B90BFC) >> 64; } if (x & 0x40000000 > 0) { result = (result * 0x1000000002C5C85FE) >> 64; } if (x & 0x20000000 > 0) { result = (result * 0x100000000162E42FF) >> 64; } if (x & 0x10000000 > 0) { result = (result * 0x1000000000B17217F) >> 64; } if (x & 0x8000000 > 0) { result = (result * 0x100000000058B90C0) >> 64; } if (x & 0x4000000 > 0) { result = (result * 0x10000000002C5C860) >> 64; } if (x & 0x2000000 > 0) { result = (result * 0x1000000000162E430) >> 64; } if (x & 0x1000000 > 0) { result = (result * 0x10000000000B17218) >> 64; } if (x & 0x800000 > 0) { result = (result * 0x1000000000058B90C) >> 64; } if (x & 0x400000 > 0) { result = (result * 0x100000000002C5C86) >> 64; } if (x & 0x200000 > 0) { result = (result * 0x10000000000162E43) >> 64; } if (x & 0x100000 > 0) { result = (result * 0x100000000000B1721) >> 64; } if (x & 0x80000 > 0) { result = (result * 0x10000000000058B91) >> 64; } if (x & 0x40000 > 0) { result = (result * 0x1000000000002C5C8) >> 64; } if (x & 0x20000 > 0) { result = (result * 0x100000000000162E4) >> 64; } if (x & 0x10000 > 0) { result = (result * 0x1000000000000B172) >> 64; } if (x & 0x8000 > 0) { result = (result * 0x100000000000058B9) >> 64; } if (x & 0x4000 > 0) { result = (result * 0x10000000000002C5D) >> 64; } if (x & 0x2000 > 0) { result = (result * 0x1000000000000162E) >> 64; } if (x & 0x1000 > 0) { result = (result * 0x10000000000000B17) >> 64; } if (x & 0x800 > 0) { result = (result * 0x1000000000000058C) >> 64; } if (x & 0x400 > 0) { result = (result * 0x100000000000002C6) >> 64; } if (x & 0x200 > 0) { result = (result * 0x10000000000000163) >> 64; } if (x & 0x100 > 0) { result = (result * 0x100000000000000B1) >> 64; } if (x & 0x80 > 0) { result = (result * 0x10000000000000059) >> 64; } if (x & 0x40 > 0) { result = (result * 0x1000000000000002C) >> 64; } if (x & 0x20 > 0) { result = (result * 0x10000000000000016) >> 64; } if (x & 0x10 > 0) { result = (result * 0x1000000000000000B) >> 64; } if (x & 0x8 > 0) { result = (result * 0x10000000000000006) >> 64; } if (x & 0x4 > 0) { result = (result * 0x10000000000000003) >> 64; } if (x & 0x2 > 0) { result = (result * 0x10000000000000001) >> 64; } if (x & 0x1 > 0) { result = (result * 0x10000000000000001) >> 64; } // We're doing two things at the same time: // // 1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191 // rather than 192. // 2. Convert the result to the unsigned 60.18-decimal fixed-point format. // // This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n". result *= SCALE; result >>= (191 - (x >> 64)); } } /// @notice Finds the zero-based index of the first one in the binary representation of x. /// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set /// @param x The uint256 number for which to find the index of the most significant bit. /// @return msb The index of the most significant bit as an uint256. function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) { if (x >= 2**128) { x >>= 128; msb += 128; } if (x >= 2**64) { x >>= 64; msb += 64; } if (x >= 2**32) { x >>= 32; msb += 32; } if (x >= 2**16) { x >>= 16; msb += 16; } if (x >= 2**8) { x >>= 8; msb += 8; } if (x >= 2**4) { x >>= 4; msb += 4; } if (x >= 2**2) { x >>= 2; msb += 2; } if (x >= 2**1) { // No need to shift x any more. msb += 1; } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Requirements: /// - The denominator cannot be zero. /// - The result must fit within uint256. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The multiplicand as an uint256. /// @param y The multiplier as an uint256. /// @param denominator The divisor as an uint256. /// @return result The result as an uint256. function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { // 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) { unchecked { result = prod0 / denominator; } return result; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (prod1 >= denominator) { revert PRBMath__MulDivOverflow(prod1, denominator); } /////////////////////////////////////////////// // 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. unchecked { // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 lpotdod = denominator & (~denominator + 1); assembly { // Divide denominator by lpotdod. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one. lpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * lpotdod; // 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 floor(x*y÷1e18) with full precision. /// /// @dev Variant of "mulDiv" with constant folding, i.e. in which the denominator is always 1e18. Before returning the /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of /// being rounded to 1e-18. See "Listing 6" and text above it at https://accu.org/index.php/journals/1717. /// /// Requirements: /// - The result must fit within uint256. /// /// Caveats: /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works. /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations: /// 1. x * y = type(uint256).max * SCALE /// 2. (x * y) % SCALE >= SCALE / 2 /// /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) { uint256 prod0; uint256 prod1; assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } if (prod1 >= SCALE) { revert PRBMath__MulDivFixedPointOverflow(prod1); } uint256 remainder; uint256 roundUpUnit; assembly { remainder := mulmod(x, y, SCALE) roundUpUnit := gt(remainder, 499999999999999999) } if (prod1 == 0) { unchecked { result = (prod0 / SCALE) + roundUpUnit; return result; } } assembly { result := add( mul( or( div(sub(prod0, remainder), SCALE_LPOTD), mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1)) ), SCALE_INVERSE ), roundUpUnit ) } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev An extension of "mulDiv" for signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - None of the inputs can be type(int256).min. /// - The result must fit within int256. /// /// @param x The multiplicand as an int256. /// @param y The multiplier as an int256. /// @param denominator The divisor as an int256. /// @return result The result as an int256. function mulDivSigned( int256 x, int256 y, int256 denominator ) internal pure returns (int256 result) { if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) { revert PRBMath__MulDivSignedInputTooSmall(); } // Get hold of the absolute values of x, y and the denominator. uint256 ax; uint256 ay; uint256 ad; unchecked { ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); ad = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of (x*y)÷denominator. The result must fit within int256. uint256 rAbs = mulDiv(ax, ay, ad); if (rAbs > uint256(type(int256).max)) { revert PRBMath__MulDivSignedOverflow(rAbs); } // Get the signs of x, y and the denominator. uint256 sx; uint256 sy; uint256 sd; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) sd := sgt(denominator, sub(0, 1)) } // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs. // If yes, the result should be negative. result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs); } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as an uint256. function sqrt(uint256 x) internal pure returns (uint256 result) { if (x == 0) { return 0; } // Set the initial guess to the least power of two that is greater than or equal to sqrt(x). uint256 xAux = uint256(x); result = 1; if (xAux >= 0x100000000000000000000000000000000) { xAux >>= 128; result <<= 64; } if (xAux >= 0x10000000000000000) { xAux >>= 64; result <<= 32; } if (xAux >= 0x100000000) { xAux >>= 32; result <<= 16; } if (xAux >= 0x10000) { xAux >>= 16; result <<= 8; } if (xAux >= 0x100) { xAux >>= 8; result <<= 4; } if (xAux >= 0x10) { xAux >>= 4; result <<= 2; } if (xAux >= 0x8) { result <<= 1; } // The operations can never overflow because the result is max 2^127 when it enters this block. unchecked { result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // Seven iterations should be enough uint256 roundedDownResult = x / result; return result >= roundedDownResult ? roundedDownResult : result; } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract ICollateralOracle","name":"collateralOracle_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InsufficientTimeRemaining","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"PRBMathUD60x18__FromUintOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"}],"name":"PRBMath__MulDivFixedPointOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath__MulDivOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"ParameterOutOfBounds","type":"error"},{"inputs":[],"name":"UnsupportedCollateral","type":"error"},{"inputs":[],"name":"UnsupportedTokenDecimals","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"collateralOracle","type":"address"}],"name":"CollateralOracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collateralToken","type":"address"}],"name":"CollateralParametersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"MinimumLoanDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[],"name":"UtilizationParametersUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IMPLEMENTATION_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PARAMETER_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralOracle","outputs":[{"internalType":"contract ICollateralOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currencyToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collateralToken","type":"address"}],"name":"getCollateralParameters","outputs":[{"components":[{"internalType":"bool","name":"active","type":"bool"},{"components":[{"internalType":"uint72","name":"offset","type":"uint72"},{"internalType":"uint72","name":"slope1","type":"uint72"},{"internalType":"uint72","name":"slope2","type":"uint72"},{"internalType":"uint96","name":"target","type":"uint96"},{"internalType":"uint96","name":"max","type":"uint96"}],"internalType":"struct LoanPriceOracle.PiecewiseLinearModel","name":"loanToValueRateComponent","type":"tuple"},{"components":[{"internalType":"uint72","name":"offset","type":"uint72"},{"internalType":"uint72","name":"slope1","type":"uint72"},{"internalType":"uint72","name":"slope2","type":"uint72"},{"internalType":"uint96","name":"target","type":"uint96"},{"internalType":"uint96","name":"max","type":"uint96"}],"internalType":"struct LoanPriceOracle.PiecewiseLinearModel","name":"durationRateComponent","type":"tuple"},{"internalType":"uint16[3]","name":"rateComponentWeights","type":"uint16[3]"}],"internalType":"struct LoanPriceOracle.CollateralParameters","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUtilizationParameters","outputs":[{"components":[{"internalType":"uint72","name":"offset","type":"uint72"},{"internalType":"uint72","name":"slope1","type":"uint72"},{"internalType":"uint72","name":"slope2","type":"uint72"},{"internalType":"uint96","name":"target","type":"uint96"},{"internalType":"uint96","name":"max","type":"uint96"}],"internalType":"struct LoanPriceOracle.PiecewiseLinearModel","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumLoanDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"uint256","name":"collateralTokenId","type":"uint256"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"repayment","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint256","name":"utilization","type":"uint256"}],"name":"priceLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collateralOracle_","type":"address"}],"name":"setCollateralOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"bytes","name":"packedCollateralParameters","type":"bytes"}],"name":"setCollateralParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setMinimumLoanDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"packedUtilizationParameters","type":"bytes"}],"name":"setUtilizationParameters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supportedCollateralTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620021db380380620021db833981016040819052620000349162000256565b806001600160a01b0316636b2fa3746040518163ffffffff1660e01b815260040160206040518083038186803b1580156200006e57600080fd5b505afa15801562000083573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000a9919062000256565b6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015620000e257600080fd5b505afa158015620000f7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200011d91906200027d565b60ff16601214620001415760405163455de91560e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b038316179055620001696000336200019c565b620001957ff0b50f04623eeaacfa1f202e062a3001c925a35c6b75d6903e67b43f44bbf152336200019c565b50620002a2565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000239576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001f83390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6001600160a01b03811681146200025357600080fd5b50565b6000602082840312156200026957600080fd5b815162000276816200023d565b9392505050565b6000602082840312156200029057600080fd5b815160ff811681146200027657600080fd5b611f2980620002b26000396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c80639f24f55a116100ad578063d547741f11610071578063d547741f1461031e578063db9f73b714610331578063e21aa11514610346578063e301c8ab14610359578063e8b966621461036c57600080fd5b80639f24f55a146102d2578063a217d5ce146102db578063a217fddf146102ee578063b626de1b146102f6578063d3e4d5fd1461030b57600080fd5b8063518f2e23116100f4578063518f2e23146101c55780636b2fa3741461025d578063754b377c1461027d57806386df6667146102ac57806391d14854146102bf57600080fd5b806301ffc9a714610131578063157907d014610159578063248a9ca31461016e5780632f2ff15d1461019f57806336568abe146101b2575b600080fd5b61014461013f3660046117d1565b61038c565b60405190151581526020015b60405180910390f35b61016c610167366004611813565b6103c3565b005b61019161017c366004611830565b60009081526020819052604090206001015490565b604051908152602001610150565b61016c6101ad366004611849565b610529565b61016c6101c0366004611849565b610554565b6102506040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506040805160a0810182526001546001600160481b038082168352600160481b820481166020840152600160901b90910416918101919091526002546001600160601b038082166060840152600160601b90910416608082015290565b60405161015091906118c7565b6102656105d7565b6040516001600160a01b039091168152602001610150565b61029f604051806040016040528060038152602001620312e360ec1b81525081565b6040516101509190611905565b61016c6102ba366004611830565b610659565b6101446102cd366004611849565b6106a7565b61019160075481565b600654610265906001600160a01b031681565b610191600081565b610191600080516020611ed483398151915281565b610191610319366004611938565b6106d0565b61016c61032c366004611849565b610876565b61033961089c565b604051610150919061198d565b61016c610354366004611a23565b6108a8565b61016c610367366004611a78565b610c12565b61037f61037a366004611813565b610cfc565b6040516101509190611aba565b60006001600160e01b03198216637965db0b60e01b14806103bd57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006103cf8133610e3e565b816001600160a01b0316636b2fa3746040518163ffffffff1660e01b815260040160206040518083038186803b15801561040857600080fd5b505afa15801561041c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104409190611b25565b6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561047857600080fd5b505afa15801561048c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b09190611b42565b60ff166012146104d35760405163455de91560e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0384169081179091556040519081527f4d04733e8b24e47241141064bcff3dea45b26c907b14e305e4fc8d5f08162ab2906020015b60405180910390a15050565b6000828152602081905260409020600101546105458133610e3e565b61054f8383610ea2565b505050565b6001600160a01b03811633146105c95760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105d38282610f26565b5050565b60065460408051631acbe8dd60e21b815290516000926001600160a01b031691636b2fa374916004808301926020929190829003018186803b15801561061c57600080fd5b505afa158015610630573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106549190611b25565b905090565b600080516020611ed48339815191526106728133610e3e565b60078290556040518281527f4622ec290be91a4b7e65972861047b775daafc1d30b8ccd320a32a94828d08c99060200161051d565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6000600754836106e09190611b7b565b421115610700576040516304a8207d60e11b815260040160405180910390fd5b6001600160a01b0388166000908152600360205260409020805460ff1661073a5760405163621a135560e01b815260040160405180910390fd5b60065460405163d4e04df160e01b81526001600160a01b038b81166004830152602482018b9052600092169063d4e04df19060440160206040518083038186803b15801561078757600080fd5b505afa15801561079b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bf9190611b92565b905060006107d56107d04288611b7b565b610f8b565b905060006107e38a84610fd8565b9050600060405180606001604052806107ff60018a6000610ff4565b815260200161081387600101856001610ff4565b815260200161082787600301866002610ff4565b90529050600061083a60058701836110ff565b905060006108638c61084c8488611182565b61085e90670de0b6b3a7640000611bab565b610fd8565b9f9e505050505050505050505050505050565b6000828152602081905260409020600101546108928133610e3e565b61054f8383610f26565b6060610654600461118e565b600080516020611ed48339815191526108c18133610e3e565b6001600160a01b0384166108e85760405163e6c4247b60e01b815260040160405180910390fd5b6108f482840184611ce9565b60036000866001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160010160008201518160000160006101000a8154816001600160481b0302191690836001600160481b0316021790555060208201518160000160096101000a8154816001600160481b0302191690836001600160481b0316021790555060408201518160000160126101000a8154816001600160481b0302191690836001600160481b0316021790555060608201518160010160006101000a8154816001600160601b0302191690836001600160601b03160217905550608082015181600101600c6101000a8154816001600160601b0302191690836001600160601b03160217905550505060408201518160030160008201518160000160006101000a8154816001600160481b0302191690836001600160481b0316021790555060208201518160000160096101000a8154816001600160481b0302191690836001600160481b0316021790555060408201518160000160126101000a8154816001600160481b0302191690836001600160481b0316021790555060608201518160010160006101000a8154816001600160601b0302191690836001600160601b03160217905550608082015181600101600c6101000a8154816001600160601b0302191690836001600160601b031602179055505050606082015181600501906003610b2892919061168f565b5050506001600160a01b03841660009081526003602052604090206005015461ffff6401000000008204811691610b689162010000820481169116611dba565b610b729190611dba565b61ffff1661271014610b99576040516388b9529f60e01b81526004818101526024016105c0565b6001600160a01b03841660009081526003602052604090205460ff1615610bcb57610bc560048561119b565b50610bd8565b610bd66004856111b0565b505b6040516001600160a01b038516907f289e465e7319143e641ed75dbed25f4933159b29b1f59bd0aac54819a50c530290600090a250505050565b600080516020611ed4833981519152610c2b8133610e3e565b610c3782840184611de0565b80516001805460208401516040808601516001600160481b03908116600160901b0268ffffffffffffffffff60901b19938216600160481b0271ffffffffffffffffffffffffffffffffffff19909516919096161792909217169290921790556060820151600280546080909401516001600160601b03908116600160601b026001600160c01b031990951692169190911792909217909155517f6e74446ffaa623f3b6298a74d5db3ba805d731b88222b3c3fb0ce2d46c60b7d990600090a1505050565b610d04611725565b6001600160a01b0382166000908152600360208181526040808420815160808082018452825460ff1615158252835160a0808201865260018501546001600160481b038082168452600160481b8083048216858b0152600160901b928390048216858a015260028801546001600160601b03808216606080890191909152600160601b928390048216888a0152898d01979097528a519586018b52898d0154808516875292830484169b86019b909b5292900416828801526004860154808916838501520490961691860191909152818401949094528251808501938490529095919493860193909260058601928390855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610df65790505050505050815250509050919050565b610e4882826106a7565b6105d357610e60816001600160a01b031660146111c5565b610e6b8360206111c5565b604051602001610e7c929190611dfc565b60408051601f198184030181529082905262461bcd60e51b82526105c091600401611905565b610eac82826106a7565b6105d3576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610ee23390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610f3082826106a7565b156105d3576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60007812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f21821115610fca57604051633492ffd960e01b8152600481018390526024016105c0565b50670de0b6b3a76400000290565b6000610fed83670de0b6b3a764000084611361565b9392505050565b6001830154600090600160601b90046001600160601b031683111561102f576040516388b9529f60e01b8152600481018390526024016105c0565b60018401546001600160601b03168311156110c557600184015461107790611060906001600160601b031685611b7b565b8554600160901b90046001600160481b0316611182565b600185015485546110a1916001600160601b031690600160481b90046001600160481b0316611182565b85546110b691906001600160481b0316611bab565b6110c09190611bab565b6110f7565b83546110e2908490600160481b90046001600160481b0316611182565b84546110f791906001600160481b0316611bab565b949350505050565b6000610fed61113e83600260200201516111398660025b601091828204019190066002029054906101000a900461ffff1661ffff16610f8b565b611182565b602084015161115290611139876001611116565b845161116390611139886000611116565b61116d9190611bab565b6111779190611bab565b61085e612710610f8b565b6000610fed838361142f565b60606000610fed836114f1565b6000610fed836001600160a01b03841661154d565b6000610fed836001600160a01b03841661159c565b606060006111d4836002611e87565b6111df906002611bab565b67ffffffffffffffff8111156111f7576111f7611bc3565b6040519080825280601f01601f191660200182016040528015611221576020820181803683370190505b509050600360fc1b8160008151811061123c5761123c611da4565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061126b5761126b611da4565b60200101906001600160f81b031916908160001a905350600061128f846002611e87565b61129a906001611bab565b90505b6001811115611312576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106112ce576112ce611da4565b1a60f81b8282815181106112e4576112e4611da4565b60200101906001600160f81b031916908160001a90535060049490941c9361130b81611ea6565b905061129d565b508315610fed5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105c0565b60008080600019858709858702925082811083820303915050806000141561139c5783828161139257611392611e71565b0492505050610fed565b8381106113c657604051631dcf306360e21b815260048101829052602481018590526044016105c0565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008080600019848609848602925082811083820303915050670de0b6b3a764000081106114735760405163698d9a0160e11b8152600481018290526024016105c0565b600080670de0b6b3a76400008688099150506706f05b59d3b1ffff8111826114ad5780670de0b6b3a76400008504019450505050506103bd565b620400008285030493909111909103600160ee1b02919091177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106690201905092915050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561154157602002820191906000526020600020905b81548152602001906001019080831161152d575b50505050509050919050565b6000818152600183016020526040812054611594575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556103bd565b5060006103bd565b600081815260018301602052604081205480156116855760006115c0600183611b7b565b85549091506000906115d490600190611b7b565b90508181146116395760008660000182815481106115f4576115f4611da4565b906000526020600020015490508087600001848154811061161757611617611da4565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061164a5761164a611ebd565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506103bd565b60009150506103bd565b6001830191839082156117155791602002820160005b838211156116e557835183826101000a81548161ffff021916908361ffff16021790555092602001926002016020816001010492830192600103026116a5565b80156117135782816101000a81549061ffff02191690556002016020816001010492830192600103026116e5565b505b5061172192915061179e565b5090565b60408051608080820183526000808352835160a08101855281815260208181018390529481018290526060810182905291820152909182019081526040805160a0810182526000808252602082810182905292820181905260608201819052608082015291019081526020016117996117b3565b905290565b5b80821115611721576000815560010161179f565b60405180606001604052806003906020820280368337509192915050565b6000602082840312156117e357600080fd5b81356001600160e01b031981168114610fed57600080fd5b6001600160a01b038116811461181057600080fd5b50565b60006020828403121561182557600080fd5b8135610fed816117fb565b60006020828403121561184257600080fd5b5035919050565b6000806040838503121561185c57600080fd5b82359150602083013561186e816117fb565b809150509250929050565b6001600160481b038082511683528060208301511660208401528060408301511660408401525060608101516001600160601b03808216606085015280608084015116608085015250505050565b60a081016103bd8284611879565b60005b838110156118f05781810151838201526020016118d8565b838111156118ff576000848401525b50505050565b60208152600082518060208401526119248160408501602087016118d5565b601f01601f19169190910160400192915050565b600080600080600080600060e0888a03121561195357600080fd5b873561195e816117fb565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b6020808252825182820181905260009190848201906040850190845b818110156119ce5783516001600160a01b0316835292840192918401916001016119a9565b50909695505050505050565b60008083601f8401126119ec57600080fd5b50813567ffffffffffffffff811115611a0457600080fd5b602083019150836020828501011115611a1c57600080fd5b9250929050565b600080600060408486031215611a3857600080fd5b8335611a43816117fb565b9250602084013567ffffffffffffffff811115611a5f57600080fd5b611a6b868287016119da565b9497909650939450505050565b60008060208385031215611a8b57600080fd5b823567ffffffffffffffff811115611aa257600080fd5b611aae858286016119da565b90969095509350505050565b8151151581526020808301516101c083019190611ad982850182611879565b506040840151611aec60c0850182611879565b506060840151610160840160005b6003811015611b1b57825161ffff1682529183019190830190600101611afa565b5050505092915050565b600060208284031215611b3757600080fd5b8151610fed816117fb565b600060208284031215611b5457600080fd5b815160ff81168114610fed57600080fd5b634e487b7160e01b600052601160045260246000fd5b600082821015611b8d57611b8d611b65565b500390565b600060208284031215611ba457600080fd5b5051919050565b60008219821115611bbe57611bbe611b65565b500190565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715611bfc57611bfc611bc3565b60405290565b6040516060810167ffffffffffffffff81118282101715611bfc57611bfc611bc3565b80356001600160481b0381168114611c3c57600080fd5b919050565b80356001600160601b0381168114611c3c57600080fd5b600060a08284031215611c6a57600080fd5b60405160a0810181811067ffffffffffffffff82111715611c8d57611c8d611bc3565b604052905080611c9c83611c25565b8152611caa60208401611c25565b6020820152611cbb60408401611c25565b6040820152611ccc60608401611c41565b6060820152611cdd60808401611c41565b60808201525092915050565b60006101c0808385031215611cfd57600080fd5b611d05611bd9565b83358015158114611d1557600080fd5b81526020611d2586868301611c58565b81830152611d368660c08701611c58565b60408301528561017f860112611d4b57600080fd5b611d53611c02565b928501928087851115611d6557600080fd5b61016087015b85811015611d9357803561ffff81168114611d865760008081fd5b8352918301918301611d6b565b506060840152509095945050505050565b634e487b7160e01b600052603260045260246000fd5b600061ffff808316818516808303821115611dd757611dd7611b65565b01949350505050565b600060a08284031215611df257600080fd5b610fed8383611c58565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611e348160178501602088016118d5565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351611e658160288401602088016118d5565b01602801949350505050565b634e487b7160e01b600052601260045260246000fd5b6000816000190483118215151615611ea157611ea1611b65565b500290565b600081611eb557611eb5611b65565b506000190190565b634e487b7160e01b600052603160045260246000fdfef0b50f04623eeaacfa1f202e062a3001c925a35c6b75d6903e67b43f44bbf152a2646970667358221220320896166f40409ca168588b4899f46176ff657fe39f7e84059058f84b8d089e64736f6c63430008090033000000000000000000000000fcfe283b64be414ef0ae65e863c07607a2b4a442
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061012c5760003560e01c80639f24f55a116100ad578063d547741f11610071578063d547741f1461031e578063db9f73b714610331578063e21aa11514610346578063e301c8ab14610359578063e8b966621461036c57600080fd5b80639f24f55a146102d2578063a217d5ce146102db578063a217fddf146102ee578063b626de1b146102f6578063d3e4d5fd1461030b57600080fd5b8063518f2e23116100f4578063518f2e23146101c55780636b2fa3741461025d578063754b377c1461027d57806386df6667146102ac57806391d14854146102bf57600080fd5b806301ffc9a714610131578063157907d014610159578063248a9ca31461016e5780632f2ff15d1461019f57806336568abe146101b2575b600080fd5b61014461013f3660046117d1565b61038c565b60405190151581526020015b60405180910390f35b61016c610167366004611813565b6103c3565b005b61019161017c366004611830565b60009081526020819052604090206001015490565b604051908152602001610150565b61016c6101ad366004611849565b610529565b61016c6101c0366004611849565b610554565b6102506040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506040805160a0810182526001546001600160481b038082168352600160481b820481166020840152600160901b90910416918101919091526002546001600160601b038082166060840152600160601b90910416608082015290565b60405161015091906118c7565b6102656105d7565b6040516001600160a01b039091168152602001610150565b61029f604051806040016040528060038152602001620312e360ec1b81525081565b6040516101509190611905565b61016c6102ba366004611830565b610659565b6101446102cd366004611849565b6106a7565b61019160075481565b600654610265906001600160a01b031681565b610191600081565b610191600080516020611ed483398151915281565b610191610319366004611938565b6106d0565b61016c61032c366004611849565b610876565b61033961089c565b604051610150919061198d565b61016c610354366004611a23565b6108a8565b61016c610367366004611a78565b610c12565b61037f61037a366004611813565b610cfc565b6040516101509190611aba565b60006001600160e01b03198216637965db0b60e01b14806103bd57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006103cf8133610e3e565b816001600160a01b0316636b2fa3746040518163ffffffff1660e01b815260040160206040518083038186803b15801561040857600080fd5b505afa15801561041c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104409190611b25565b6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561047857600080fd5b505afa15801561048c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b09190611b42565b60ff166012146104d35760405163455de91560e01b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0384169081179091556040519081527f4d04733e8b24e47241141064bcff3dea45b26c907b14e305e4fc8d5f08162ab2906020015b60405180910390a15050565b6000828152602081905260409020600101546105458133610e3e565b61054f8383610ea2565b505050565b6001600160a01b03811633146105c95760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6105d38282610f26565b5050565b60065460408051631acbe8dd60e21b815290516000926001600160a01b031691636b2fa374916004808301926020929190829003018186803b15801561061c57600080fd5b505afa158015610630573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106549190611b25565b905090565b600080516020611ed48339815191526106728133610e3e565b60078290556040518281527f4622ec290be91a4b7e65972861047b775daafc1d30b8ccd320a32a94828d08c99060200161051d565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6000600754836106e09190611b7b565b421115610700576040516304a8207d60e11b815260040160405180910390fd5b6001600160a01b0388166000908152600360205260409020805460ff1661073a5760405163621a135560e01b815260040160405180910390fd5b60065460405163d4e04df160e01b81526001600160a01b038b81166004830152602482018b9052600092169063d4e04df19060440160206040518083038186803b15801561078757600080fd5b505afa15801561079b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bf9190611b92565b905060006107d56107d04288611b7b565b610f8b565b905060006107e38a84610fd8565b9050600060405180606001604052806107ff60018a6000610ff4565b815260200161081387600101856001610ff4565b815260200161082787600301866002610ff4565b90529050600061083a60058701836110ff565b905060006108638c61084c8488611182565b61085e90670de0b6b3a7640000611bab565b610fd8565b9f9e505050505050505050505050505050565b6000828152602081905260409020600101546108928133610e3e565b61054f8383610f26565b6060610654600461118e565b600080516020611ed48339815191526108c18133610e3e565b6001600160a01b0384166108e85760405163e6c4247b60e01b815260040160405180910390fd5b6108f482840184611ce9565b60036000866001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160010160008201518160000160006101000a8154816001600160481b0302191690836001600160481b0316021790555060208201518160000160096101000a8154816001600160481b0302191690836001600160481b0316021790555060408201518160000160126101000a8154816001600160481b0302191690836001600160481b0316021790555060608201518160010160006101000a8154816001600160601b0302191690836001600160601b03160217905550608082015181600101600c6101000a8154816001600160601b0302191690836001600160601b03160217905550505060408201518160030160008201518160000160006101000a8154816001600160481b0302191690836001600160481b0316021790555060208201518160000160096101000a8154816001600160481b0302191690836001600160481b0316021790555060408201518160000160126101000a8154816001600160481b0302191690836001600160481b0316021790555060608201518160010160006101000a8154816001600160601b0302191690836001600160601b03160217905550608082015181600101600c6101000a8154816001600160601b0302191690836001600160601b031602179055505050606082015181600501906003610b2892919061168f565b5050506001600160a01b03841660009081526003602052604090206005015461ffff6401000000008204811691610b689162010000820481169116611dba565b610b729190611dba565b61ffff1661271014610b99576040516388b9529f60e01b81526004818101526024016105c0565b6001600160a01b03841660009081526003602052604090205460ff1615610bcb57610bc560048561119b565b50610bd8565b610bd66004856111b0565b505b6040516001600160a01b038516907f289e465e7319143e641ed75dbed25f4933159b29b1f59bd0aac54819a50c530290600090a250505050565b600080516020611ed4833981519152610c2b8133610e3e565b610c3782840184611de0565b80516001805460208401516040808601516001600160481b03908116600160901b0268ffffffffffffffffff60901b19938216600160481b0271ffffffffffffffffffffffffffffffffffff19909516919096161792909217169290921790556060820151600280546080909401516001600160601b03908116600160601b026001600160c01b031990951692169190911792909217909155517f6e74446ffaa623f3b6298a74d5db3ba805d731b88222b3c3fb0ce2d46c60b7d990600090a1505050565b610d04611725565b6001600160a01b0382166000908152600360208181526040808420815160808082018452825460ff1615158252835160a0808201865260018501546001600160481b038082168452600160481b8083048216858b0152600160901b928390048216858a015260028801546001600160601b03808216606080890191909152600160601b928390048216888a0152898d01979097528a519586018b52898d0154808516875292830484169b86019b909b5292900416828801526004860154808916838501520490961691860191909152818401949094528251808501938490529095919493860193909260058601928390855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610df65790505050505050815250509050919050565b610e4882826106a7565b6105d357610e60816001600160a01b031660146111c5565b610e6b8360206111c5565b604051602001610e7c929190611dfc565b60408051601f198184030181529082905262461bcd60e51b82526105c091600401611905565b610eac82826106a7565b6105d3576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055610ee23390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b610f3082826106a7565b156105d3576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60007812725dd1d243aba0e75fe645cc4873f9e65afe688c928e1f21821115610fca57604051633492ffd960e01b8152600481018390526024016105c0565b50670de0b6b3a76400000290565b6000610fed83670de0b6b3a764000084611361565b9392505050565b6001830154600090600160601b90046001600160601b031683111561102f576040516388b9529f60e01b8152600481018390526024016105c0565b60018401546001600160601b03168311156110c557600184015461107790611060906001600160601b031685611b7b565b8554600160901b90046001600160481b0316611182565b600185015485546110a1916001600160601b031690600160481b90046001600160481b0316611182565b85546110b691906001600160481b0316611bab565b6110c09190611bab565b6110f7565b83546110e2908490600160481b90046001600160481b0316611182565b84546110f791906001600160481b0316611bab565b949350505050565b6000610fed61113e83600260200201516111398660025b601091828204019190066002029054906101000a900461ffff1661ffff16610f8b565b611182565b602084015161115290611139876001611116565b845161116390611139886000611116565b61116d9190611bab565b6111779190611bab565b61085e612710610f8b565b6000610fed838361142f565b60606000610fed836114f1565b6000610fed836001600160a01b03841661154d565b6000610fed836001600160a01b03841661159c565b606060006111d4836002611e87565b6111df906002611bab565b67ffffffffffffffff8111156111f7576111f7611bc3565b6040519080825280601f01601f191660200182016040528015611221576020820181803683370190505b509050600360fc1b8160008151811061123c5761123c611da4565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061126b5761126b611da4565b60200101906001600160f81b031916908160001a905350600061128f846002611e87565b61129a906001611bab565b90505b6001811115611312576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106112ce576112ce611da4565b1a60f81b8282815181106112e4576112e4611da4565b60200101906001600160f81b031916908160001a90535060049490941c9361130b81611ea6565b905061129d565b508315610fed5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105c0565b60008080600019858709858702925082811083820303915050806000141561139c5783828161139257611392611e71565b0492505050610fed565b8381106113c657604051631dcf306360e21b815260048101829052602481018590526044016105c0565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008080600019848609848602925082811083820303915050670de0b6b3a764000081106114735760405163698d9a0160e11b8152600481018290526024016105c0565b600080670de0b6b3a76400008688099150506706f05b59d3b1ffff8111826114ad5780670de0b6b3a76400008504019450505050506103bd565b620400008285030493909111909103600160ee1b02919091177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106690201905092915050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561154157602002820191906000526020600020905b81548152602001906001019080831161152d575b50505050509050919050565b6000818152600183016020526040812054611594575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556103bd565b5060006103bd565b600081815260018301602052604081205480156116855760006115c0600183611b7b565b85549091506000906115d490600190611b7b565b90508181146116395760008660000182815481106115f4576115f4611da4565b906000526020600020015490508087600001848154811061161757611617611da4565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061164a5761164a611ebd565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506103bd565b60009150506103bd565b6001830191839082156117155791602002820160005b838211156116e557835183826101000a81548161ffff021916908361ffff16021790555092602001926002016020816001010492830192600103026116a5565b80156117135782816101000a81549061ffff02191690556002016020816001010492830192600103026116e5565b505b5061172192915061179e565b5090565b60408051608080820183526000808352835160a08101855281815260208181018390529481018290526060810182905291820152909182019081526040805160a0810182526000808252602082810182905292820181905260608201819052608082015291019081526020016117996117b3565b905290565b5b80821115611721576000815560010161179f565b60405180606001604052806003906020820280368337509192915050565b6000602082840312156117e357600080fd5b81356001600160e01b031981168114610fed57600080fd5b6001600160a01b038116811461181057600080fd5b50565b60006020828403121561182557600080fd5b8135610fed816117fb565b60006020828403121561184257600080fd5b5035919050565b6000806040838503121561185c57600080fd5b82359150602083013561186e816117fb565b809150509250929050565b6001600160481b038082511683528060208301511660208401528060408301511660408401525060608101516001600160601b03808216606085015280608084015116608085015250505050565b60a081016103bd8284611879565b60005b838110156118f05781810151838201526020016118d8565b838111156118ff576000848401525b50505050565b60208152600082518060208401526119248160408501602087016118d5565b601f01601f19169190910160400192915050565b600080600080600080600060e0888a03121561195357600080fd5b873561195e816117fb565b9960208901359950604089013598606081013598506080810135975060a0810135965060c00135945092505050565b6020808252825182820181905260009190848201906040850190845b818110156119ce5783516001600160a01b0316835292840192918401916001016119a9565b50909695505050505050565b60008083601f8401126119ec57600080fd5b50813567ffffffffffffffff811115611a0457600080fd5b602083019150836020828501011115611a1c57600080fd5b9250929050565b600080600060408486031215611a3857600080fd5b8335611a43816117fb565b9250602084013567ffffffffffffffff811115611a5f57600080fd5b611a6b868287016119da565b9497909650939450505050565b60008060208385031215611a8b57600080fd5b823567ffffffffffffffff811115611aa257600080fd5b611aae858286016119da565b90969095509350505050565b8151151581526020808301516101c083019190611ad982850182611879565b506040840151611aec60c0850182611879565b506060840151610160840160005b6003811015611b1b57825161ffff1682529183019190830190600101611afa565b5050505092915050565b600060208284031215611b3757600080fd5b8151610fed816117fb565b600060208284031215611b5457600080fd5b815160ff81168114610fed57600080fd5b634e487b7160e01b600052601160045260246000fd5b600082821015611b8d57611b8d611b65565b500390565b600060208284031215611ba457600080fd5b5051919050565b60008219821115611bbe57611bbe611b65565b500190565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715611bfc57611bfc611bc3565b60405290565b6040516060810167ffffffffffffffff81118282101715611bfc57611bfc611bc3565b80356001600160481b0381168114611c3c57600080fd5b919050565b80356001600160601b0381168114611c3c57600080fd5b600060a08284031215611c6a57600080fd5b60405160a0810181811067ffffffffffffffff82111715611c8d57611c8d611bc3565b604052905080611c9c83611c25565b8152611caa60208401611c25565b6020820152611cbb60408401611c25565b6040820152611ccc60608401611c41565b6060820152611cdd60808401611c41565b60808201525092915050565b60006101c0808385031215611cfd57600080fd5b611d05611bd9565b83358015158114611d1557600080fd5b81526020611d2586868301611c58565b81830152611d368660c08701611c58565b60408301528561017f860112611d4b57600080fd5b611d53611c02565b928501928087851115611d6557600080fd5b61016087015b85811015611d9357803561ffff81168114611d865760008081fd5b8352918301918301611d6b565b506060840152509095945050505050565b634e487b7160e01b600052603260045260246000fd5b600061ffff808316818516808303821115611dd757611dd7611b65565b01949350505050565b600060a08284031215611df257600080fd5b610fed8383611c58565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351611e348160178501602088016118d5565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351611e658160288401602088016118d5565b01602801949350505050565b634e487b7160e01b600052601260045260246000fd5b6000816000190483118215151615611ea157611ea1611b65565b500290565b600081611eb557611eb5611b65565b506000190190565b634e487b7160e01b600052603160045260246000fdfef0b50f04623eeaacfa1f202e062a3001c925a35c6b75d6903e67b43f44bbf152a2646970667358221220320896166f40409ca168588b4899f46176ff657fe39f7e84059058f84b8d089e64736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000fcfe283b64be414ef0ae65e863c07607a2b4a442
-----Decoded View---------------
Arg [0] : collateralOracle_ (address): 0xFCFe283B64be414eF0aE65e863c07607a2b4A442
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000fcfe283b64be414ef0ae65e863c07607a2b4a442
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.