Polygon Sponsored slots available. Book your slot here!
Overview
POL Balance
POL Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 5 from a total of 5 transactions
Latest 5 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
49149009 | 515 days ago | Contract Creation | 0 POL | |||
49149009 | 515 days ago | Contract Creation | 0 POL | |||
49149009 | 515 days ago | Contract Creation | 0 POL | |||
49149009 | 515 days ago | Contract Creation | 0 POL | |||
49149009 | 515 days ago | Contract Creation | 0 POL |
Loading...
Loading
Contract Name:
FXBFactory
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity)
/** *Submitted for verification at polygonscan.com on 2023-10-25 */ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ============================ FXBFactory ============================ // ==================================================================== // Frax Finance: https://github.com/FraxFinance // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } } // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } } /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } } // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ========================== Timelock2Step =========================== // ==================================================================== // Frax Finance: https://github.com/FraxFinance // Primary Author // Drake Evans: https://github.com/DrakeEvans // Reviewers // Dennis: https://github.com/denett // ==================================================================== /// @title Timelock2Step /// @author Drake Evans (Frax Finance) https://github.com/drakeevans /// @dev Inspired by OpenZeppelin's Ownable2Step contract /// @notice An abstract contract which contains 2-step transfer and renounce logic for a timelock address abstract contract Timelock2Step { /// @notice The pending timelock address address public pendingTimelockAddress; /// @notice The current timelock address address public timelockAddress; constructor(address _timelockAddress) { timelockAddress = _timelockAddress; } // ============================================================================================ // Functions: External Functions // ============================================================================================ /// @notice The ```transferTimelock``` function initiates the timelock transfer /// @dev Must be called by the current timelock /// @param _newTimelock The address of the nominated (pending) timelock function transferTimelock(address _newTimelock) external virtual { _requireSenderIsTimelock(); _transferTimelock(_newTimelock); } /// @notice The ```acceptTransferTimelock``` function completes the timelock transfer /// @dev Must be called by the pending timelock function acceptTransferTimelock() external virtual { _requireSenderIsPendingTimelock(); _acceptTransferTimelock(); } /// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock /// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process function renounceTimelock() external virtual { _requireSenderIsTimelock(); _requireSenderIsPendingTimelock(); _transferTimelock(address(0)); _setTimelock(address(0)); } // ============================================================================================ // Functions: Internal Actions // ============================================================================================ /// @notice The ```_transferTimelock``` function initiates the timelock transfer /// @dev This function is to be implemented by a public function /// @param _newTimelock The address of the nominated (pending) timelock function _transferTimelock(address _newTimelock) internal { pendingTimelockAddress = _newTimelock; emit TimelockTransferStarted(timelockAddress, _newTimelock); } /// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer /// @dev This function is to be implemented by a public function function _acceptTransferTimelock() internal { pendingTimelockAddress = address(0); _setTimelock(msg.sender); } /// @notice The ```_setTimelock``` function sets the timelock address /// @dev This function is to be implemented by a public function /// @param _newTimelock The address of the new timelock function _setTimelock(address _newTimelock) internal { emit TimelockTransferred(timelockAddress, _newTimelock); timelockAddress = _newTimelock; } // ============================================================================================ // Functions: Internal Checks // ============================================================================================ /// @notice The ```_isTimelock``` function checks if _address is current timelock address /// @param _address The address to check against the timelock /// @return Whether or not msg.sender is current timelock address function _isTimelock(address _address) internal view returns (bool) { return _address == timelockAddress; } /// @notice The ```_requireIsTimelock``` function reverts if _address is not current timelock address /// @param _address The address to check against the timelock function _requireIsTimelock(address _address) internal view { if (!_isTimelock(_address)) revert AddressIsNotTimelock(timelockAddress, _address); } /// @notice The ```_requireSenderIsTimelock``` function reverts if msg.sender is not current timelock address /// @dev This function is to be implemented by a public function function _requireSenderIsTimelock() internal view { _requireIsTimelock(msg.sender); } /// @notice The ```_isPendingTimelock``` function checks if the _address is pending timelock address /// @dev This function is to be implemented by a public function /// @param _address The address to check against the pending timelock /// @return Whether or not _address is pending timelock address function _isPendingTimelock(address _address) internal view returns (bool) { return _address == pendingTimelockAddress; } /// @notice The ```_requireIsPendingTimelock``` function reverts if the _address is not pending timelock address /// @dev This function is to be implemented by a public function /// @param _address The address to check against the pending timelock function _requireIsPendingTimelock(address _address) internal view { if (!_isPendingTimelock(_address)) revert AddressIsNotPendingTimelock(pendingTimelockAddress, _address); } /// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address /// @dev This function is to be implemented by a public function function _requireSenderIsPendingTimelock() internal view { _requireIsPendingTimelock(msg.sender); } // ============================================================================================ // Functions: Events // ============================================================================================ /// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated /// @param previousTimelock The address of the previous timelock /// @param newTimelock The address of the new timelock event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock); /// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed /// @param previousTimelock The address of the previous timelock /// @param newTimelock The address of the new timelock event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock); // ============================================================================================ // Functions: Errors // ============================================================================================ /// @notice Emitted when timelock is transferred error AddressIsNotTimelock(address timelockAddress, address actualAddress); /// @notice Emitted when pending timelock is transferred error AddressIsNotPendingTimelock(address pendingTimelockAddress, address actualAddress); } // ---------------------------------------------------------------------------- // BokkyPooBah's DateTime Library v1.01 // // A gas-efficient Solidity date and time library // // https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary // // Tested date range 1970/01/01 to 2345/12/31 // // Conventions: // Unit | Range | Notes // :-------- |:-------------:|:----- // timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC // year | 1970 ... 2345 | // month | 1 ... 12 | // day | 1 ... 31 | // hour | 0 ... 23 | // minute | 0 ... 59 | // second | 0 ... 59 | // dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday // // // Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. // ---------------------------------------------------------------------------- library BokkyPooBahsDateTimeLibrary { uint256 constant SECONDS_PER_DAY = 24 * 60 * 60; uint256 constant SECONDS_PER_HOUR = 60 * 60; uint256 constant SECONDS_PER_MINUTE = 60; int256 constant OFFSET19700101 = 2_440_588; uint256 constant DOW_MON = 1; uint256 constant DOW_TUE = 2; uint256 constant DOW_WED = 3; uint256 constant DOW_THU = 4; uint256 constant DOW_FRI = 5; uint256 constant DOW_SAT = 6; uint256 constant DOW_SUN = 7; // ------------------------------------------------------------------------ // Calculate the number of days from 1970/01/01 to year/month/day using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and subtracting the offset 2440588 so that 1970/01/01 is day 0 // // days = day // - 32075 // + 1461 * (year + 4800 + (month - 14) / 12) / 4 // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 // - offset // ------------------------------------------------------------------------ function _daysFromDate(uint256 year, uint256 month, uint256 day) internal pure returns (uint256 _days) { require(year >= 1970); int256 _year = int256(year); int256 _month = int256(month); int256 _day = int256(day); int256 __days = _day - 32_075 + (1461 * (_year + 4800 + (_month - 14) / 12)) / 4 + (367 * (_month - 2 - ((_month - 14) / 12) * 12)) / 12 - (3 * ((_year + 4900 + (_month - 14) / 12) / 100)) / 4 - OFFSET19700101; _days = uint256(__days); } // ------------------------------------------------------------------------ // Calculate year/month/day from the number of days since 1970/01/01 using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and adding the offset 2440588 so that 1970/01/01 is day 0 // // int L = days + 68569 + offset // int N = 4 * L / 146097 // L = L - (146097 * N + 3) / 4 // year = 4000 * (L + 1) / 1461001 // L = L - 1461 * year / 4 + 31 // month = 80 * L / 2447 // dd = L - 2447 * month / 80 // L = month / 11 // month = month + 2 - 12 * L // year = 100 * (N - 49) + year + L // ------------------------------------------------------------------------ function _daysToDate(uint256 _days) internal pure returns (uint256 year, uint256 month, uint256 day) { int256 __days = int256(_days); int256 L = __days + 68_569 + OFFSET19700101; int256 N = (4 * L) / 146_097; L = L - (146_097 * N + 3) / 4; int256 _year = (4000 * (L + 1)) / 1_461_001; L = L - (1461 * _year) / 4 + 31; int256 _month = (80 * L) / 2447; int256 _day = L - (2447 * _month) / 80; L = _month / 11; _month = _month + 2 - 12 * L; _year = 100 * (N - 49) + _year + L; year = uint256(_year); month = uint256(_month); day = uint256(_day); } function timestampFromDate(uint256 year, uint256 month, uint256 day) internal pure returns (uint256 timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; } function timestampFromDateTime( uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second ) internal pure returns (uint256 timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; } function timestampToDate(uint256 timestamp) internal pure returns (uint256 year, uint256 month, uint256 day) { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function timestampToDateTime( uint256 timestamp ) internal pure returns (uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second) { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); uint256 secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; secs = secs % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; second = secs % SECONDS_PER_MINUTE; } function isValidDate(uint256 year, uint256 month, uint256 day) internal pure returns (bool valid) { if (year >= 1970 && month > 0 && month <= 12) { uint256 daysInMonth = _getDaysInMonth(year, month); if (day > 0 && day <= daysInMonth) { valid = true; } } } function isValidDateTime( uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second ) internal pure returns (bool valid) { if (isValidDate(year, month, day)) { if (hour < 24 && minute < 60 && second < 60) { valid = true; } } } function isLeapYear(uint256 timestamp) internal pure returns (bool leapYear) { (uint256 year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY); leapYear = _isLeapYear(year); } function _isLeapYear(uint256 year) internal pure returns (bool leapYear) { leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); } function isWeekDay(uint256 timestamp) internal pure returns (bool weekDay) { weekDay = getDayOfWeek(timestamp) <= DOW_FRI; } function isWeekEnd(uint256 timestamp) internal pure returns (bool weekEnd) { weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; } function getDaysInMonth(uint256 timestamp) internal pure returns (uint256 daysInMonth) { (uint256 year, uint256 month, ) = _daysToDate(timestamp / SECONDS_PER_DAY); daysInMonth = _getDaysInMonth(year, month); } function _getDaysInMonth(uint256 year, uint256 month) internal pure returns (uint256 daysInMonth) { if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { daysInMonth = 31; } else if (month != 2) { daysInMonth = 30; } else { daysInMonth = _isLeapYear(year) ? 29 : 28; } } // 1 = Monday, 7 = Sunday function getDayOfWeek(uint256 timestamp) internal pure returns (uint256 dayOfWeek) { uint256 _days = timestamp / SECONDS_PER_DAY; dayOfWeek = ((_days + 3) % 7) + 1; } function getYear(uint256 timestamp) internal pure returns (uint256 year) { (year, , ) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getMonth(uint256 timestamp) internal pure returns (uint256 month) { (, month, ) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getDay(uint256 timestamp) internal pure returns (uint256 day) { (, , day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getHour(uint256 timestamp) internal pure returns (uint256 hour) { uint256 secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; } function getMinute(uint256 timestamp) internal pure returns (uint256 minute) { uint256 secs = timestamp % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; } function getSecond(uint256 timestamp) internal pure returns (uint256 second) { second = timestamp % SECONDS_PER_MINUTE; } function addYears(uint256 timestamp, uint256 _years) internal pure returns (uint256 newTimestamp) { (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY); year += _years; uint256 daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY); require(newTimestamp >= timestamp); } function addMonths(uint256 timestamp, uint256 _months) internal pure returns (uint256 newTimestamp) { (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY); month += _months; year += (month - 1) / 12; month = ((month - 1) % 12) + 1; uint256 daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY); require(newTimestamp >= timestamp); } function addDays(uint256 timestamp, uint256 _days) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp + _days * SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addHours(uint256 timestamp, uint256 _hours) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; require(newTimestamp >= timestamp); } function addMinutes(uint256 timestamp, uint256 _minutes) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; require(newTimestamp >= timestamp); } function addSeconds(uint256 timestamp, uint256 _seconds) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp + _seconds; require(newTimestamp >= timestamp); } function subYears(uint256 timestamp, uint256 _years) internal pure returns (uint256 newTimestamp) { (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY); year -= _years; uint256 daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY); require(newTimestamp <= timestamp); } function subMonths(uint256 timestamp, uint256 _months) internal pure returns (uint256 newTimestamp) { (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY); uint256 yearMonth = year * 12 + (month - 1) - _months; year = yearMonth / 12; month = (yearMonth % 12) + 1; uint256 daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY); require(newTimestamp <= timestamp); } function subDays(uint256 timestamp, uint256 _days) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp - _days * SECONDS_PER_DAY; require(newTimestamp <= timestamp); } function subHours(uint256 timestamp, uint256 _hours) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; require(newTimestamp <= timestamp); } function subMinutes(uint256 timestamp, uint256 _minutes) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; require(newTimestamp <= timestamp); } function subSeconds(uint256 timestamp, uint256 _seconds) internal pure returns (uint256 newTimestamp) { newTimestamp = timestamp - _seconds; require(newTimestamp <= timestamp); } function diffYears(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _years) { require(fromTimestamp <= toTimestamp); (uint256 fromYear, , ) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); (uint256 toYear, , ) = _daysToDate(toTimestamp / SECONDS_PER_DAY); _years = toYear - fromYear; } function diffMonths(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _months) { require(fromTimestamp <= toTimestamp); (uint256 fromYear, uint256 fromMonth, ) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); (uint256 toYear, uint256 toMonth, ) = _daysToDate(toTimestamp / SECONDS_PER_DAY); _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; } function diffDays(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _days) { require(fromTimestamp <= toTimestamp); _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; } function diffHours(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _hours) { require(fromTimestamp <= toTimestamp); _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; } function diffMinutes(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _minutes) { require(fromTimestamp <= toTimestamp); _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; } function diffSeconds(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _seconds) { require(fromTimestamp <= toTimestamp); _seconds = toTimestamp - fromTimestamp; } } // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // =============================== FXB ================================ // ==================================================================== // Frax Finance: https://github.com/FraxFinance // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); } // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.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); } // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) /** * @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; } } /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} } // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC20Permit.sol) // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); } // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } } // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) // OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol) // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } } // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly assembly { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(_FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } } // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); } /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * _Available since v3.4._ * * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {EIP-5267}. * * _Available since v4.9._ */ function eip712Domain() public view virtual override returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0f", // 01111 _name.toStringWithFallback(_nameFallback), _version.toStringWithFallback(_versionFallback), block.chainid, address(this), bytes32(0), new uint256[](0) ); } } // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library Counters { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } } /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { using Counters for Counters.Counter; mapping(address => Counters.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private constant _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`. * However, to ensure consistency with the upgradeable transpiler, we will continue * to reserve a slot. * @custom:oz-renamed-from _PERMIT_TYPEHASH */ // solhint-disable-next-line var-name-mixedcase bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT; /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ constructor(string memory name) EIP712(name, "1") {} /** * @dev See {IERC20Permit-permit}. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view virtual override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } /** * @dev "Consume a nonce": return the current value and increment. * * _Available since v4.1._ */ function _useNonce(address owner) internal virtual returns (uint256 current) { Counters.Counter storage nonce = _nonces[owner]; current = nonce.current(); nonce.increment(); } } interface IFrax { function COLLATERAL_RATIO_PAUSER() external view returns (bytes32); function DEFAULT_ADMIN_ADDRESS() external view returns (address); function DEFAULT_ADMIN_ROLE() external view returns (bytes32); function addPool(address pool_address) external; function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256); function burn(uint256 amount) external; function burnFrom(address account, uint256 amount) external; function collateral_ratio_paused() external view returns (bool); function controller_address() external view returns (address); function creator_address() external view returns (address); function decimals() external view returns (uint8); function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); function eth_usd_consumer_address() external view returns (address); function eth_usd_price() external view returns (uint256); function frax_eth_oracle_address() external view returns (address); function frax_info() external view returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256); function frax_pools(address) external view returns (bool); function frax_pools_array(uint256) external view returns (address); function frax_price() external view returns (uint256); function frax_step() external view returns (uint256); function fxs_address() external view returns (address); function fxs_eth_oracle_address() external view returns (address); function fxs_price() external view returns (uint256); function genesis_supply() external view returns (uint256); function getRoleAdmin(bytes32 role) external view returns (bytes32); function getRoleMember(bytes32 role, uint256 index) external view returns (address); function getRoleMemberCount(bytes32 role) external view returns (uint256); function globalCollateralValue() external view returns (uint256); function global_collateral_ratio() external view returns (uint256); function grantRole(bytes32 role, address account) external; function hasRole(bytes32 role, address account) external view returns (bool); function increaseAllowance(address spender, uint256 addedValue) external returns (bool); function last_call_time() external view returns (uint256); function minting_fee() external view returns (uint256); function name() external view returns (string memory); function owner_address() external view returns (address); function pool_burn_from(address b_address, uint256 b_amount) external; function pool_mint(address m_address, uint256 m_amount) external; function price_band() external view returns (uint256); function price_target() external view returns (uint256); function redemption_fee() external view returns (uint256); function refreshCollateralRatio() external; function refresh_cooldown() external view returns (uint256); function removePool(address pool_address) external; function renounceRole(bytes32 role, address account) external; function revokeRole(bytes32 role, address account) external; function setController(address _controller_address) external; function setETHUSDOracle(address _eth_usd_consumer_address) external; function setFRAXEthOracle(address _frax_oracle_addr, address _weth_address) external; function setFXSAddress(address _fxs_address) external; function setFXSEthOracle(address _fxs_oracle_addr, address _weth_address) external; function setFraxStep(uint256 _new_step) external; function setMintingFee(uint256 min_fee) external; function setOwner(address _owner_address) external; function setPriceBand(uint256 _price_band) external; function setPriceTarget(uint256 _new_price_target) external; function setRedemptionFee(uint256 red_fee) external; function setRefreshCooldown(uint256 _new_cooldown) external; function setTimelock(address new_timelock) external; function symbol() external view returns (string memory); function timelock_address() external view returns (address); function toggleCollateralRatio() external; function totalSupply() external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); function weth_address() external view returns (address); } /// @title FXB /// @notice The FXB token can be redeemed for 1 FRAX at a later date. Created via a factory contract. contract FXB is ERC20, ERC20Permit { // ============================================================================================= // Storage // ============================================================================================= /// @notice Factory contract for generating FXBs FXBFactory public immutable FXB_FACTORY; /// @notice The Frax token contract IFrax public immutable FRAX; /// @notice Timestamp of bond maturity uint256 public immutable MATURITY_TIMESTAMP; /// @notice Total amount of FXB redeemed uint256 public totalFXBRedeemed; // ============================================================================================= // Structs // ============================================================================================= /// @notice Bond Information /// @param symbol The symbol of the bond /// @param name The name of the bond /// @param maturityTimestamp Timestamp the bond will mature struct BondInfo { string symbol; string name; uint256 maturityTimestamp; } // ============================================================================================= // Constructor // ============================================================================================= /// @notice Called by the factory /// @param _symbol The symbol of the bond /// @param _name The name of the bond /// @param _maturityTimestamp Timestamp the bond will mature and be redeemable constructor( address _fraxErc20, string memory _symbol, string memory _name, uint256 _maturityTimestamp ) ERC20(_symbol, _name) ERC20Permit(_symbol) { // Set the FRAX address FRAX = IFrax(_fraxErc20); // Set the factory FXB_FACTORY = FXBFactory(msg.sender); // Set the maturity timestamp MATURITY_TIMESTAMP = _maturityTimestamp; } // ============================================================================================= // View functions // ============================================================================================= /// @notice Returns summary information about the bond /// @return BondInfo Summary of the bond function bondInfo() external view returns (BondInfo memory) { return BondInfo({ symbol: symbol(), name: name(), maturityTimestamp: MATURITY_TIMESTAMP }); } /// @notice Returns a boolean representing whether a bond can be redeemed /// @return _isRedeemable If the bond is redeemable function isRedeemable() public view returns (bool _isRedeemable) { _isRedeemable = (block.timestamp >= MATURITY_TIMESTAMP); } // ============================================================================================= // Public functions // ============================================================================================= /// @notice Mints a specified amount of tokens to the account, requires caller to approve on the FRAX contract in an amount equal to the minted amount /// @param _to The account to receive minted tokens /// @param _amount The amount of the token to mint function mint(address _to, uint256 _amount) public { // NOTE: Allow minting after expiry // Effects: Give the FXB to the recipient _mint({ account: _to, amount: _amount }); // Interactions: Take 1-to-1 FRAX from the user FRAX.transferFrom({ sender: msg.sender, recipient: address(this), amount: _amount }); } /// @notice Redeems FXB 1-to-1 for FRAX /// @param _recipient Recipient of the FRAX /// @param _redeemAmount Amount to redeem function burn(address _recipient, uint256 _redeemAmount) public { // Make sure the bond has matured if (!isRedeemable()) revert BondNotRedeemable(); // Effects: Update redeem tracking totalFXBRedeemed += _redeemAmount; // Effects: Burn the FXB from the user _burn({ account: msg.sender, amount: _redeemAmount }); // Interactions: Give FRAX to the recipient FRAX.transfer({ recipient: _recipient, amount: _redeemAmount }); } // ============================================================================== // Errors // ============================================================================== /// @notice Thrown if the bond hasn't matured yet, or redeeming is paused error BondNotRedeemable(); } /// @title FXBFactory /// @notice Deploys FXB FXB ERC20 contracts contract FXBFactory is Timelock2Step { using Strings for uint256; // ============================================================================================= // Storage // ============================================================================================= // Core /// @notice The Frax token contract address public immutable FRAX; /// @notice Array of bond addresses address[] public allBonds; /// @notice Whether a given address is an FXB mapping(address _fxb => bool _isFXB) public isFXB; /// @notice Whether a given timestamp has an FXB deployed mapping(uint256 _timestamp => bool _isFXB) public isTimestampFXB; // ============================================================================================= // Constructor // ============================================================================================= /// @notice Constructor /// @param _timelockAddress The owner of this contract constructor(address _timelockAddress, address _fraxErc20) Timelock2Step(_timelockAddress) { FRAX = _fraxErc20; } //============================================================================== // Helper Functions //============================================================================== /// @notice The ```_monthNames``` function returns the 3 letter names of the months given an index /// @param _monthIndex The index of the month /// @return _monthName The name of the month function _monthNames(uint256 _monthIndex) internal pure returns (string memory _monthName) { if (_monthIndex == 1) return "JAN"; if (_monthIndex == 2) return "FEB"; if (_monthIndex == 3) return "MAR"; if (_monthIndex == 4) return "APR"; if (_monthIndex == 5) return "MAY"; if (_monthIndex == 6) return "JUN"; if (_monthIndex == 7) return "JUL"; if (_monthIndex == 8) return "AUG"; if (_monthIndex == 9) return "SEP"; if (_monthIndex == 10) return "OCT"; if (_monthIndex == 11) return "NOV"; if (_monthIndex == 12) return "DEC"; revert InvalidMonthNumber(); } // ============================================================================================= // View functions // ============================================================================================= /// @notice Returns the total number of bonds created /// @return _length uint256 Number of bonds created function allBondsLength() public view returns (uint256 _length) { return allBonds.length; } /// @notice Generates the bond symbol in the format FXB_YYYYMMDD /// @param _maturityTimestamp Date the bond will mature /// @return _bondName The name of the bond function _generateBondSymbol(uint256 _maturityTimestamp) internal pure returns (string memory _bondName) { // Maturity date uint256 _maturityMonth = BokkyPooBahsDateTimeLibrary.getMonth(_maturityTimestamp); uint256 _maturityDay = BokkyPooBahsDateTimeLibrary.getDay(_maturityTimestamp); uint256 _maturityYear = BokkyPooBahsDateTimeLibrary.getYear(_maturityTimestamp); string memory maturityMonthString; if (_maturityMonth > 9) { maturityMonthString = _maturityMonth.toString(); } else { maturityMonthString = string.concat("0", _maturityMonth.toString()); } string memory maturityDayString; if (_maturityDay > 9) { maturityDayString = _maturityDay.toString(); } else { maturityDayString = string.concat("0", _maturityDay.toString()); } // Assemble all the strings into one _bondName = string( abi.encodePacked("FXB", "_", _maturityYear.toString(), maturityMonthString, maturityDayString) ); } /// @notice Generates the bond name in the format (e.g. FXB_4_MMMDDYYYY) /// @param _bondId The id of the bond /// @param _maturityTimestamp Date the bond will mature /// @return _bondName The name of the bond function _generateBondName( uint256 _bondId, uint256 _maturityTimestamp ) internal pure returns (string memory _bondName) { // Maturity date uint256 _maturityMonth = BokkyPooBahsDateTimeLibrary.getMonth(_maturityTimestamp); uint256 _maturityDay = BokkyPooBahsDateTimeLibrary.getDay(_maturityTimestamp); uint256 _maturityYear = BokkyPooBahsDateTimeLibrary.getYear(_maturityTimestamp); string memory maturityDayString; if (_maturityDay > 9) { maturityDayString = _maturityDay.toString(); } else { maturityDayString = string(abi.encodePacked("0", _maturityDay.toString())); } // Assemble all the strings into one _bondName = string( abi.encodePacked( "FXB", "_", _bondId.toString(), "_", _monthNames(_maturityMonth), maturityDayString, _maturityYear.toString() ) ); } // ============================================================================================= // Configurations / Privileged functions // ============================================================================================= /// @notice Generates a new bond contract /// @param _maturityTimestamp Date the bond will mature and be redeemable /// @return _bondAddress The address of the new bond /// @return _bondId The id of the new bond function createBond(uint256 _maturityTimestamp) public returns (address _bondAddress, uint256 _bondId) { _requireSenderIsTimelock(); // Round the timestamp down to 00:00 UTC uint256 _coercedMaturityTimestamp = (_maturityTimestamp / 1 days) * 1 days; if (_coercedMaturityTimestamp <= block.timestamp) { revert BondMaturityTooSoon(); } // Ensure bond maturity is unique if (isTimestampFXB[_coercedMaturityTimestamp]) { revert BondMaturityAlreadyExists(); } // Set the bond id _bondId = allBondsLength(); // Get the new symbol and name string memory _bondSymbol = _generateBondSymbol({ _maturityTimestamp: _coercedMaturityTimestamp }); string memory _bondName = _generateBondName({ _bondId: _bondId, _maturityTimestamp: _coercedMaturityTimestamp }); // Create the new contract FXB fxb = new FXB({ _symbol: _bondSymbol, _name: _bondName, _maturityTimestamp: _coercedMaturityTimestamp, _fraxErc20: FRAX }); _bondAddress = address(fxb); // Add the new bond address to the array and update the map allBonds.push(_bondAddress); isFXB[_bondAddress] = true; isTimestampFXB[_coercedMaturityTimestamp] = true; emit BondCreated({ newAddress: _bondAddress, newId: _bondId, newSymbol: _bondSymbol, newName: _bondName, maturityTimestamp: _coercedMaturityTimestamp }); } // ============================================================================== // Events // ============================================================================== /// @notice The ```BondCreated``` event is emitted when a new bond is created /// @param newAddress Address of the bond /// @param newId The ID of the bond /// @param newSymbol The bond's symbol /// @param newName Name of the bond /// @param maturityTimestamp Date the bond will mature event BondCreated(address newAddress, uint256 newId, string newSymbol, string newName, uint256 maturityTimestamp); // ============================================================================== // Errors // ============================================================================== /// @notice The ```InvalidMonthNumber``` error is thrown when an invalid month number is passed error InvalidMonthNumber(); /// @notice The ```BondMaturityAlreadyExists``` error is thrown when a bond with the same maturity already exists error BondMaturityAlreadyExists(); /// @notice The ```BondMaturityTooSoon``` error is thrown when attempting to create a bond with an expiration before the current time error BondMaturityTooSoon(); }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_timelockAddress","type":"address"},{"internalType":"address","name":"_fraxErc20","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"pendingTimelockAddress","type":"address"},{"internalType":"address","name":"actualAddress","type":"address"}],"name":"AddressIsNotPendingTimelock","type":"error"},{"inputs":[{"internalType":"address","name":"timelockAddress","type":"address"},{"internalType":"address","name":"actualAddress","type":"address"}],"name":"AddressIsNotTimelock","type":"error"},{"inputs":[],"name":"BondMaturityAlreadyExists","type":"error"},{"inputs":[],"name":"BondMaturityTooSoon","type":"error"},{"inputs":[],"name":"InvalidMonthNumber","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"newId","type":"uint256"},{"indexed":false,"internalType":"string","name":"newSymbol","type":"string"},{"indexed":false,"internalType":"string","name":"newName","type":"string"},{"indexed":false,"internalType":"uint256","name":"maturityTimestamp","type":"uint256"}],"name":"BondCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockTransferred","type":"event"},{"inputs":[],"name":"FRAX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptTransferTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allBonds","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allBondsLength","outputs":[{"internalType":"uint256","name":"_length","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maturityTimestamp","type":"uint256"}],"name":"createBond","outputs":[{"internalType":"address","name":"_bondAddress","type":"address"},{"internalType":"uint256","name":"_bondId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_fxb","type":"address"}],"name":"isFXB","outputs":[{"internalType":"bool","name":"_isFXB","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"isTimestampFXB","outputs":[{"internalType":"bool","name":"_isFXB","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingTimelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newTimelock","type":"address"}],"name":"transferTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a060405234801561001057600080fd5b50604051620038473803806200384783398101604081905261003191610072565b600180546001600160a01b0319166001600160a01b03938416179055166080526100a5565b80516001600160a01b038116811461006d57600080fd5b919050565b6000806040838503121561008557600080fd5b61008e83610056565b915061009c60208401610056565b90509250929050565b60805161377f620000c8600039600081816101b7015261038a015261377f6000f3fe60806040523480156200001157600080fd5b5060043610620000d95760003560e01c8063b0e4556f116200008b578063dfea19621162000062578063dfea19621462000202578063f6ccaad41462000239578063fb5e1f5b146200024357600080fd5b8063b0e4556f14620001b1578063b4efcf4a14620001d9578063c8bf84a714620001f057600080fd5b80634bc66f3211620000c05780634bc66f3214620001425780634f8b4ae714620001635780636350e4b2146200016d57600080fd5b8063090f3f5014620000de578063450140951462000129575b600080fd5b600054620000ff9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b620001406200013a36600462001071565b62000269565b005b600154620000ff9073ffffffffffffffffffffffffffffffffffffffff1681565b6200014062000281565b620001846200017e366004620010b0565b620002af565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520162000120565b620000ff7f000000000000000000000000000000000000000000000000000000000000000081565b620000ff620001ea366004620010b0565b620004f8565b60025460405190815260200162000120565b620002286200021336600462001071565b60036020526000908152604090205460ff1681565b604051901515815260200162000120565b6200014062000530565b6200022862000254366004620010b0565b60046020526000908152604090205460ff1681565b6200027362000544565b6200027e816200054f565b50565b6200028b62000544565b62000295620005c4565b620002a160006200054f565b620002ad6000620005cf565b565b600080620002bc62000544565b6000620002cd620151808562001128565b620002dc90620151806200113f565b905042811162000318576040517f0a4dee5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205460ff161562000362576040517fe388d64f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002549150600062000374826200065d565b9050600062000384848462000764565b905060007f0000000000000000000000000000000000000000000000000000000000000000838386604051620003ba9062001063565b620003c99493929190620011cb565b604051809103906000f080158015620003e6573d6000803e3d6000fd5b506002805460018082019092557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155600090815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811686179091558984526004909252918290208054909116909217909155519096508691507f70447ad46f3971bf936af78a90dbb9f714c328506d57cf6034d96dd6c137871890620004e79083908890879087908a9062001222565b60405180910390a150505050915091565b600281815481106200050957600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6200053a620005c4565b620002ad62000833565b620002ad3362000866565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217835560015460405192939116917f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a9190a350565b620002ad33620008e4565b60015460405173ffffffffffffffffffffffffffffffffffffffff8084169216907f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc690600090a3600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b606060006200066c836200095e565b905060006200067b8462000981565b905060006200068a856200099e565b905060606009841115620006ab57620006a384620009bc565b9050620006da565b620006b684620009bc565b604051602001620006c8919062001280565b60405160208183030381529060405290505b60606009841115620006f957620006f184620009bc565b905062000728565b6200070484620009bc565b60405160200162000716919062001280565b60405160208183030381529060405290505b6200073383620009bc565b82826040516020016200074993929190620012c7565b60405160208183030381529060405295505050505050919050565b6060600062000773836200095e565b90506000620007828462000981565b9050600062000791856200099e565b905060606009831115620007b257620007aa83620009bc565b9050620007e1565b620007bd83620009bc565b604051602001620007cf919062001280565b60405160208183030381529060405290505b620007ec87620009bc565b620007f78562000a81565b826200080385620009bc565b60405160200162000818949392919062001365565b60405160208183030381529060405294505050505092915050565b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055620002ad33620005cf565b60015473ffffffffffffffffffffffffffffffffffffffff8281169116146200027e576001546040517f443dc2b400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015290821660248201526044015b60405180910390fd5b60005473ffffffffffffffffffffffffffffffffffffffff8281169116146200027e576000546040517fbe5a953700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529082166024820152604401620008db565b60006200097962000973620151808462001128565b62000dcd565b509392505050565b60006200099662000973620151808462001128565b949350505050565b6000620009b362000973620151808462001128565b50909392505050565b60606000620009cb8362000f79565b600101905060008167ffffffffffffffff811115620009ee57620009ee62001426565b6040519080825280601f01601f19166020018201604052801562000a19576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508462000a2357509392505050565b60608160010362000ac557505060408051808201909152600381527f4a414e0000000000000000000000000000000000000000000000000000000000602082015290565b8160020362000b0757505060408051808201909152600381527f4645420000000000000000000000000000000000000000000000000000000000602082015290565b8160030362000b4957505060408051808201909152600381527f4d41520000000000000000000000000000000000000000000000000000000000602082015290565b8160040362000b8b57505060408051808201909152600381527f4150520000000000000000000000000000000000000000000000000000000000602082015290565b8160050362000bcd57505060408051808201909152600381527f4d41590000000000000000000000000000000000000000000000000000000000602082015290565b8160060362000c0f57505060408051808201909152600381527f4a554e0000000000000000000000000000000000000000000000000000000000602082015290565b8160070362000c5157505060408051808201909152600381527f4a554c0000000000000000000000000000000000000000000000000000000000602082015290565b8160080362000c9357505060408051808201909152600381527f4155470000000000000000000000000000000000000000000000000000000000602082015290565b8160090362000cd557505060408051808201909152600381527f5345500000000000000000000000000000000000000000000000000000000000602082015290565b81600a0362000d1757505060408051808201909152600381527f4f43540000000000000000000000000000000000000000000000000000000000602082015290565b81600b0362000d5957505060408051808201909152600381527f4e4f560000000000000000000000000000000000000000000000000000000000602082015290565b81600c0362000d9b57505060408051808201909152600381527f4445430000000000000000000000000000000000000000000000000000000000602082015290565b6040517fc8d7e9c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080838162253d8c62000de68362010bd962001455565b62000df2919062001455565b9050600062023ab162000e0783600462001480565b62000e139190620014d2565b9050600462000e268262023ab162001480565b62000e3390600362001455565b62000e3f9190620014d2565b62000e4b908362001540565b9150600062164b0962000e6084600162001455565b62000e6e90610fa062001480565b62000e7a9190620014d2565b9050600462000e8c826105b562001480565b62000e989190620014d2565b62000ea4908462001540565b62000eb190601f62001455565b9250600061098f62000ec585605062001480565b62000ed19190620014d2565b90506000605062000ee58361098f62001480565b62000ef19190620014d2565b62000efd908662001540565b905062000f0c600b83620014d2565b945062000f1b85600c62001480565b62000f2883600262001455565b62000f34919062001540565b9150848362000f4560318762001540565b62000f5290606462001480565b62000f5e919062001455565b62000f6a919062001455565b9a919950975095505050505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831062000fc3577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef8100000000831062000ff0576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106200100f57662386f26fc10000830492506010015b6305f5e100831062001028576305f5e100830492506008015b61271083106200103d57612710830492506004015b6064831062001050576064830492506002015b600a83106200105d576001015b92915050565b6121df806200156b83390190565b6000602082840312156200108457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114620010a957600080fd5b9392505050565b600060208284031215620010c357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000826200113a576200113a620010ca565b500490565b80820281158282048414176200105d576200105d620010f9565b60005b83811015620011765781810151838201526020016200115c565b50506000910152565b600081518084526200119981602086016020860162001159565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff85168152608060208201526000620011fc60808301866200117f565b82810360408401526200121081866200117f565b91505082606083015295945050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015260a0604082015260006200125960a08301866200117f565b82810360608401526200126d81866200117f565b9150508260808301529695505050505050565b7f3000000000000000000000000000000000000000000000000000000000000000815260008251620012ba81600185016020870162001159565b9190910160010192915050565b7f465842000000000000000000000000000000000000000000000000000000000081527f5f000000000000000000000000000000000000000000000000000000000000006003820152600084516200132781600485016020890162001159565b8451908301906200134081600484016020890162001159565b84519101906200135881600484016020880162001159565b0160040195945050505050565b7f4658420000000000000000000000000000000000000000000000000000000000815260007f5f000000000000000000000000000000000000000000000000000000000000008060038401528651620013c6816004860160208b0162001159565b808401905081600482015286519150620013e8826005830160208a0162001159565b85519101906200140081600584016020890162001159565b84519101906200141881600584016020880162001159565b016005019695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8082018281126000831280158216821582161715620014785762001478620010f9565b505092915050565b808202600082127f800000000000000000000000000000000000000000000000000000000000000084141615620014bb57620014bb620010f9565b81810583148215176200105d576200105d620010f9565b600082620014e457620014e4620010ca565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156200153b576200153b620010f9565b500590565b8181036000831280158383131683831282161715620015635762001563620010f9565b509291505056fe6101c06040523480156200001257600080fd5b50604051620021df380380620021df83398101604081905262000035916200029e565b6040805180820190915260018152603160f81b60208201528390819081856003620000618382620003bf565b506004620000708282620003bf565b5062000082915083905060056200014c565b61012052620000938160066200014c565b61014052815160208084019190912060e052815190820120610100524660a0526200012160e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506001600160a01b039390931661018052505033610160526101a052620004e5565b60006020835110156200016c57620001648362000185565b90506200017f565b81620001798482620003bf565b5060ff90505b92915050565b600080829050601f81511115620001bc578260405163305a27a960e01b8152600401620001b391906200048b565b60405180910390fd5b8051620001c982620004c0565b179392505050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000204578181015183820152602001620001ea565b50506000910152565b600082601f8301126200021f57600080fd5b81516001600160401b03808211156200023c576200023c620001d1565b604051601f8301601f19908116603f01168101908282118183101715620002675762000267620001d1565b816040528381528660208588010111156200028157600080fd5b62000294846020830160208901620001e7565b9695505050505050565b60008060008060808587031215620002b557600080fd5b84516001600160a01b0381168114620002cd57600080fd5b60208601519094506001600160401b0380821115620002eb57600080fd5b620002f9888389016200020d565b945060408701519150808211156200031057600080fd5b506200031f878288016200020d565b606096909601519497939650505050565b600181811c908216806200034557607f821691505b6020821081036200036657634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003ba57600081815260208120601f850160051c81016020861015620003955750805b601f850160051c820191505b81811015620003b657828155600101620003a1565b5050505b505050565b81516001600160401b03811115620003db57620003db620001d1565b620003f381620003ec845462000330565b846200036c565b602080601f8311600181146200042b5760008415620004125750858301515b600019600386901b1c1916600185901b178555620003b6565b600085815260208120601f198616915b828110156200045c578886015182559484019460019091019084016200043b565b50858210156200047b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260008251806020840152620004ac816040850160208701620001e7565b601f01601f19169190910160400192915050565b80516020808301519190811015620003665760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a051611c5b62000584600039600081816102f101528181610356015281816106eb0152610ace0152600081816103820152818161058201526107b1015260006101970152600061066e01526000610643015260006110d5015260006110ad01526000611008015260006110320152600061105c0152611c5b6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c80637ecebe00116100e3578063a9059cbb1161008c578063d505accf11610066578063d505accf146103a4578063dd62ed3e146103b7578063f3b39b5b146103fd57600080fd5b8063a9059cbb14610341578063af92058214610354578063b0e4556f1461037d57600080fd5b806395d89b41116100bd57806395d89b41146103135780639dc29fac1461031b578063a457c2d71461032e57600080fd5b80637ecebe00146102be57806384b0196e146102d15780638e3bc0ac146102ec57600080fd5b8063313ce5671161014557806340c10f191161011f57806340c10f191461026a57806370a082311461027f57806372c381b3146102b557600080fd5b8063313ce567146102405780633644e5151461024f578063395093511461025757600080fd5b8063095ea7b311610176578063095ea7b3146101f857806318160ddd1461021b57806323b872dd1461022d57600080fd5b806306aa63751461019257806306fdde03146101e3575b600080fd5b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101eb610412565b6040516101da91906118b6565b61020b6102063660046118f9565b6104a4565b60405190151581526020016101da565b6002545b6040519081526020016101da565b61020b61023b366004611923565b6104be565b604051601281526020016101da565b61021f6104e2565b61020b6102653660046118f9565b6104f1565b61027d6102783660046118f9565b61053d565b005b61021f61028d36600461195f565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61021f60095481565b61021f6102cc36600461195f565b61060a565b6102d9610635565b6040516101da979695949392919061197a565b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b6101eb6106da565b61027d6103293660046118f9565b6106e9565b61020b61033c3660046118f9565b6107e0565b61020b61034f3660046118f9565b6108b6565b7f000000000000000000000000000000000000000000000000000000000000000042101561020b565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b61027d6103b2366004611a39565b6108c4565b61021f6103c5366004611aac565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b610405610a83565b6040516101da9190611adf565b60606003805461042190611b4d565b80601f016020809104026020016040519081016040528092919081815260200182805461044d90611b4d565b801561049a5780601f1061046f5761010080835404028352916020019161049a565b820191906000526020600020905b81548152906001019060200180831161047d57829003601f168201915b5050505050905090565b6000336104b2818585610af5565b60019150505b92915050565b6000336104cc858285610ca8565b6104d7858585610d7f565b506001949350505050565b60006104ec610fee565b905090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906104b29082908690610538908790611b9a565b610af5565b6105478282611126565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064015b6020604051808303816000875af11580156105e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106059190611bd4565b505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600760205260408120546104b8565b6000606080828080836106697f00000000000000000000000000000000000000000000000000000000000000006005611219565b6106947f00000000000000000000000000000000000000000000000000000000000000006006611219565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b60606004805461042190611b4d565b7f0000000000000000000000000000000000000000000000000000000000000000421015610743576040517f1440798b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600960008282546107559190611b9a565b90915550610765905033826112c4565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016105c2565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909190838110156108a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6104d78286868403610af5565b6000336104b2818585610d7f565b8342111561092e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016108a0565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c988888861095d8c611488565b60408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e00160405160208183030381529060405280519060200120905060006109c5826114bd565b905060006109d582878787611505565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016108a0565b610a778a8a8a610af5565b50505050505050505050565b610aa760405180606001604052806060815260200160608152602001600081525090565b6040518060600160405280610aba6106da565b8152602001610ac7610412565b81526020017f0000000000000000000000000000000000000000000000000000000000000000815250905090565b73ffffffffffffffffffffffffffffffffffffffff8316610b97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f726573730000000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff8216610c3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f737300000000000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610d795781811015610d6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016108a0565b610d798484848403610af5565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316610e22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f647265737300000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff8216610ec5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f657373000000000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610f7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e6365000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610d79565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801561105457507f000000000000000000000000000000000000000000000000000000000000000046145b1561107e57507f000000000000000000000000000000000000000000000000000000000000000090565b6104ec604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b73ffffffffffffffffffffffffffffffffffffffff82166111a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016108a0565b80600260008282546111b59190611b9a565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b606060ff83146112335761122c8361152d565b90506104b8565b81805461123f90611b4d565b80601f016020809104026020016040519081016040528092919081815260200182805461126b90611b4d565b80156112b85780601f1061128d576101008083540402835291602001916112b8565b820191906000526020600020905b81548152906001019060200180831161129b57829003601f168201915b505050505090506104b8565b73ffffffffffffffffffffffffffffffffffffffff8216611367576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f730000000000000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561141d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090208054600181018255905b50919050565b60006104b86114ca610fee565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b60008060006115168787878761156c565b915091506115238161165b565b5095945050505050565b6060600061153a83611811565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156115a35750600090506003611652565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156115f7573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661164b57600060019250925050611652565b9150600090505b94509492505050565b600081600481111561166f5761166f611bf6565b036116775750565b600181600481111561168b5761168b611bf6565b036116f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016108a0565b600281600481111561170657611706611bf6565b0361176d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016108a0565b600381600481111561178157611781611bf6565b0361180e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016108a0565b50565b600060ff8216601f8111156104b8576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000815180845260005b818110156118785760208185018101518683018201520161185c565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006118c96020830184611852565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146118f457600080fd5b919050565b6000806040838503121561190c57600080fd5b611915836118d0565b946020939093013593505050565b60008060006060848603121561193857600080fd5b611941846118d0565b925061194f602085016118d0565b9150604084013590509250925092565b60006020828403121561197157600080fd5b6118c9826118d0565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e0818401526119b660e084018a611852565b83810360408501526119c8818a611852565b6060850189905273ffffffffffffffffffffffffffffffffffffffff8816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015611a2757835183529284019291840191600101611a0b565b50909c9b505050505050505050505050565b600080600080600080600060e0888a031215611a5457600080fd5b611a5d886118d0565b9650611a6b602089016118d0565b95506040880135945060608801359350608088013560ff81168114611a8f57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611abf57600080fd5b611ac8836118d0565b9150611ad6602084016118d0565b90509250929050565b602081526000825160606020840152611afb6080840182611852565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016040850152611b368282611852565b915050604084015160608401528091505092915050565b600181811c90821680611b6157607f821691505b6020821081036114b7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b808201808211156104b8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600060208284031215611be657600080fd5b815180151581146118c957600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220c2bed37e0f8afb86bd2f823bdd44342ea1006ae5172594a0f1a25ac418151de264736f6c63430008130033a264697066735822122011879c275d8c998a2e98b56213b3a78b3006a55b77c9900ccfcc98e547f4c7c764736f6c63430008130033000000000000000000000000884de35810b085e0f15a1ac7efb86040cdb10bb700000000000000000000000045c32fa6df82ead1e2ef74d17b76547eddfaff89
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620000d95760003560e01c8063b0e4556f116200008b578063dfea19621162000062578063dfea19621462000202578063f6ccaad41462000239578063fb5e1f5b146200024357600080fd5b8063b0e4556f14620001b1578063b4efcf4a14620001d9578063c8bf84a714620001f057600080fd5b80634bc66f3211620000c05780634bc66f3214620001425780634f8b4ae714620001635780636350e4b2146200016d57600080fd5b8063090f3f5014620000de578063450140951462000129575b600080fd5b600054620000ff9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b620001406200013a36600462001071565b62000269565b005b600154620000ff9073ffffffffffffffffffffffffffffffffffffffff1681565b6200014062000281565b620001846200017e366004620010b0565b620002af565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520162000120565b620000ff7f00000000000000000000000045c32fa6df82ead1e2ef74d17b76547eddfaff8981565b620000ff620001ea366004620010b0565b620004f8565b60025460405190815260200162000120565b620002286200021336600462001071565b60036020526000908152604090205460ff1681565b604051901515815260200162000120565b6200014062000530565b6200022862000254366004620010b0565b60046020526000908152604090205460ff1681565b6200027362000544565b6200027e816200054f565b50565b6200028b62000544565b62000295620005c4565b620002a160006200054f565b620002ad6000620005cf565b565b600080620002bc62000544565b6000620002cd620151808562001128565b620002dc90620151806200113f565b905042811162000318576040517f0a4dee5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205460ff161562000362576040517fe388d64f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002549150600062000374826200065d565b9050600062000384848462000764565b905060007f00000000000000000000000045c32fa6df82ead1e2ef74d17b76547eddfaff89838386604051620003ba9062001063565b620003c99493929190620011cb565b604051809103906000f080158015620003e6573d6000803e3d6000fd5b506002805460018082019092557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155600090815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811686179091558984526004909252918290208054909116909217909155519096508691507f70447ad46f3971bf936af78a90dbb9f714c328506d57cf6034d96dd6c137871890620004e79083908890879087908a9062001222565b60405180910390a150505050915091565b600281815481106200050957600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6200053a620005c4565b620002ad62000833565b620002ad3362000866565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217835560015460405192939116917f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a9190a350565b620002ad33620008e4565b60015460405173ffffffffffffffffffffffffffffffffffffffff8084169216907f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc690600090a3600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b606060006200066c836200095e565b905060006200067b8462000981565b905060006200068a856200099e565b905060606009841115620006ab57620006a384620009bc565b9050620006da565b620006b684620009bc565b604051602001620006c8919062001280565b60405160208183030381529060405290505b60606009841115620006f957620006f184620009bc565b905062000728565b6200070484620009bc565b60405160200162000716919062001280565b60405160208183030381529060405290505b6200073383620009bc565b82826040516020016200074993929190620012c7565b60405160208183030381529060405295505050505050919050565b6060600062000773836200095e565b90506000620007828462000981565b9050600062000791856200099e565b905060606009831115620007b257620007aa83620009bc565b9050620007e1565b620007bd83620009bc565b604051602001620007cf919062001280565b60405160208183030381529060405290505b620007ec87620009bc565b620007f78562000a81565b826200080385620009bc565b60405160200162000818949392919062001365565b60405160208183030381529060405294505050505092915050565b600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055620002ad33620005cf565b60015473ffffffffffffffffffffffffffffffffffffffff8281169116146200027e576001546040517f443dc2b400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015290821660248201526044015b60405180910390fd5b60005473ffffffffffffffffffffffffffffffffffffffff8281169116146200027e576000546040517fbe5a953700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529082166024820152604401620008db565b60006200097962000973620151808462001128565b62000dcd565b509392505050565b60006200099662000973620151808462001128565b949350505050565b6000620009b362000973620151808462001128565b50909392505050565b60606000620009cb8362000f79565b600101905060008167ffffffffffffffff811115620009ee57620009ee62001426565b6040519080825280601f01601f19166020018201604052801562000a19576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508462000a2357509392505050565b60608160010362000ac557505060408051808201909152600381527f4a414e0000000000000000000000000000000000000000000000000000000000602082015290565b8160020362000b0757505060408051808201909152600381527f4645420000000000000000000000000000000000000000000000000000000000602082015290565b8160030362000b4957505060408051808201909152600381527f4d41520000000000000000000000000000000000000000000000000000000000602082015290565b8160040362000b8b57505060408051808201909152600381527f4150520000000000000000000000000000000000000000000000000000000000602082015290565b8160050362000bcd57505060408051808201909152600381527f4d41590000000000000000000000000000000000000000000000000000000000602082015290565b8160060362000c0f57505060408051808201909152600381527f4a554e0000000000000000000000000000000000000000000000000000000000602082015290565b8160070362000c5157505060408051808201909152600381527f4a554c0000000000000000000000000000000000000000000000000000000000602082015290565b8160080362000c9357505060408051808201909152600381527f4155470000000000000000000000000000000000000000000000000000000000602082015290565b8160090362000cd557505060408051808201909152600381527f5345500000000000000000000000000000000000000000000000000000000000602082015290565b81600a0362000d1757505060408051808201909152600381527f4f43540000000000000000000000000000000000000000000000000000000000602082015290565b81600b0362000d5957505060408051808201909152600381527f4e4f560000000000000000000000000000000000000000000000000000000000602082015290565b81600c0362000d9b57505060408051808201909152600381527f4445430000000000000000000000000000000000000000000000000000000000602082015290565b6040517fc8d7e9c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080838162253d8c62000de68362010bd962001455565b62000df2919062001455565b9050600062023ab162000e0783600462001480565b62000e139190620014d2565b9050600462000e268262023ab162001480565b62000e3390600362001455565b62000e3f9190620014d2565b62000e4b908362001540565b9150600062164b0962000e6084600162001455565b62000e6e90610fa062001480565b62000e7a9190620014d2565b9050600462000e8c826105b562001480565b62000e989190620014d2565b62000ea4908462001540565b62000eb190601f62001455565b9250600061098f62000ec585605062001480565b62000ed19190620014d2565b90506000605062000ee58361098f62001480565b62000ef19190620014d2565b62000efd908662001540565b905062000f0c600b83620014d2565b945062000f1b85600c62001480565b62000f2883600262001455565b62000f34919062001540565b9150848362000f4560318762001540565b62000f5290606462001480565b62000f5e919062001455565b62000f6a919062001455565b9a919950975095505050505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831062000fc3577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef8100000000831062000ff0576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106200100f57662386f26fc10000830492506010015b6305f5e100831062001028576305f5e100830492506008015b61271083106200103d57612710830492506004015b6064831062001050576064830492506002015b600a83106200105d576001015b92915050565b6121df806200156b83390190565b6000602082840312156200108457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114620010a957600080fd5b9392505050565b600060208284031215620010c357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000826200113a576200113a620010ca565b500490565b80820281158282048414176200105d576200105d620010f9565b60005b83811015620011765781810151838201526020016200115c565b50506000910152565b600081518084526200119981602086016020860162001159565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff85168152608060208201526000620011fc60808301866200117f565b82810360408401526200121081866200117f565b91505082606083015295945050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015260a0604082015260006200125960a08301866200117f565b82810360608401526200126d81866200117f565b9150508260808301529695505050505050565b7f3000000000000000000000000000000000000000000000000000000000000000815260008251620012ba81600185016020870162001159565b9190910160010192915050565b7f465842000000000000000000000000000000000000000000000000000000000081527f5f000000000000000000000000000000000000000000000000000000000000006003820152600084516200132781600485016020890162001159565b8451908301906200134081600484016020890162001159565b84519101906200135881600484016020880162001159565b0160040195945050505050565b7f4658420000000000000000000000000000000000000000000000000000000000815260007f5f000000000000000000000000000000000000000000000000000000000000008060038401528651620013c6816004860160208b0162001159565b808401905081600482015286519150620013e8826005830160208a0162001159565b85519101906200140081600584016020890162001159565b84519101906200141881600584016020880162001159565b016005019695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8082018281126000831280158216821582161715620014785762001478620010f9565b505092915050565b808202600082127f800000000000000000000000000000000000000000000000000000000000000084141615620014bb57620014bb620010f9565b81810583148215176200105d576200105d620010f9565b600082620014e457620014e4620010ca565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156200153b576200153b620010f9565b500590565b8181036000831280158383131683831282161715620015635762001563620010f9565b509291505056fe6101c06040523480156200001257600080fd5b50604051620021df380380620021df83398101604081905262000035916200029e565b6040805180820190915260018152603160f81b60208201528390819081856003620000618382620003bf565b506004620000708282620003bf565b5062000082915083905060056200014c565b61012052620000938160066200014c565b61014052815160208084019190912060e052815190820120610100524660a0526200012160e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506001600160a01b039390931661018052505033610160526101a052620004e5565b60006020835110156200016c57620001648362000185565b90506200017f565b81620001798482620003bf565b5060ff90505b92915050565b600080829050601f81511115620001bc578260405163305a27a960e01b8152600401620001b391906200048b565b60405180910390fd5b8051620001c982620004c0565b179392505050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000204578181015183820152602001620001ea565b50506000910152565b600082601f8301126200021f57600080fd5b81516001600160401b03808211156200023c576200023c620001d1565b604051601f8301601f19908116603f01168101908282118183101715620002675762000267620001d1565b816040528381528660208588010111156200028157600080fd5b62000294846020830160208901620001e7565b9695505050505050565b60008060008060808587031215620002b557600080fd5b84516001600160a01b0381168114620002cd57600080fd5b60208601519094506001600160401b0380821115620002eb57600080fd5b620002f9888389016200020d565b945060408701519150808211156200031057600080fd5b506200031f878288016200020d565b606096909601519497939650505050565b600181811c908216806200034557607f821691505b6020821081036200036657634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003ba57600081815260208120601f850160051c81016020861015620003955750805b601f850160051c820191505b81811015620003b657828155600101620003a1565b5050505b505050565b81516001600160401b03811115620003db57620003db620001d1565b620003f381620003ec845462000330565b846200036c565b602080601f8311600181146200042b5760008415620004125750858301515b600019600386901b1c1916600185901b178555620003b6565b600085815260208120601f198616915b828110156200045c578886015182559484019460019091019084016200043b565b50858210156200047b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020815260008251806020840152620004ac816040850160208701620001e7565b601f01601f19169190910160400192915050565b80516020808301519190811015620003665760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a051611c5b62000584600039600081816102f101528181610356015281816106eb0152610ace0152600081816103820152818161058201526107b1015260006101970152600061066e01526000610643015260006110d5015260006110ad01526000611008015260006110320152600061105c0152611c5b6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c80637ecebe00116100e3578063a9059cbb1161008c578063d505accf11610066578063d505accf146103a4578063dd62ed3e146103b7578063f3b39b5b146103fd57600080fd5b8063a9059cbb14610341578063af92058214610354578063b0e4556f1461037d57600080fd5b806395d89b41116100bd57806395d89b41146103135780639dc29fac1461031b578063a457c2d71461032e57600080fd5b80637ecebe00146102be57806384b0196e146102d15780638e3bc0ac146102ec57600080fd5b8063313ce5671161014557806340c10f191161011f57806340c10f191461026a57806370a082311461027f57806372c381b3146102b557600080fd5b8063313ce567146102405780633644e5151461024f578063395093511461025757600080fd5b8063095ea7b311610176578063095ea7b3146101f857806318160ddd1461021b57806323b872dd1461022d57600080fd5b806306aa63751461019257806306fdde03146101e3575b600080fd5b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101eb610412565b6040516101da91906118b6565b61020b6102063660046118f9565b6104a4565b60405190151581526020016101da565b6002545b6040519081526020016101da565b61020b61023b366004611923565b6104be565b604051601281526020016101da565b61021f6104e2565b61020b6102653660046118f9565b6104f1565b61027d6102783660046118f9565b61053d565b005b61021f61028d36600461195f565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61021f60095481565b61021f6102cc36600461195f565b61060a565b6102d9610635565b6040516101da979695949392919061197a565b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b6101eb6106da565b61027d6103293660046118f9565b6106e9565b61020b61033c3660046118f9565b6107e0565b61020b61034f3660046118f9565b6108b6565b7f000000000000000000000000000000000000000000000000000000000000000042101561020b565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b61027d6103b2366004611a39565b6108c4565b61021f6103c5366004611aac565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b610405610a83565b6040516101da9190611adf565b60606003805461042190611b4d565b80601f016020809104026020016040519081016040528092919081815260200182805461044d90611b4d565b801561049a5780601f1061046f5761010080835404028352916020019161049a565b820191906000526020600020905b81548152906001019060200180831161047d57829003601f168201915b5050505050905090565b6000336104b2818585610af5565b60019150505b92915050565b6000336104cc858285610ca8565b6104d7858585610d7f565b506001949350505050565b60006104ec610fee565b905090565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906104b29082908690610538908790611b9a565b610af5565b6105478282611126565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064015b6020604051808303816000875af11580156105e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106059190611bd4565b505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600760205260408120546104b8565b6000606080828080836106697f00000000000000000000000000000000000000000000000000000000000000006005611219565b6106947f00000000000000000000000000000000000000000000000000000000000000006006611219565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b60606004805461042190611b4d565b7f0000000000000000000000000000000000000000000000000000000000000000421015610743576040517f1440798b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600960008282546107559190611b9a565b90915550610765905033826112c4565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016105c2565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909190838110156108a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6104d78286868403610af5565b6000336104b2818585610d7f565b8342111561092e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016108a0565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c988888861095d8c611488565b60408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e00160405160208183030381529060405280519060200120905060006109c5826114bd565b905060006109d582878787611505565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016108a0565b610a778a8a8a610af5565b50505050505050505050565b610aa760405180606001604052806060815260200160608152602001600081525090565b6040518060600160405280610aba6106da565b8152602001610ac7610412565b81526020017f0000000000000000000000000000000000000000000000000000000000000000815250905090565b73ffffffffffffffffffffffffffffffffffffffff8316610b97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f726573730000000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff8216610c3a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f737300000000000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610d795781811015610d6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016108a0565b610d798484848403610af5565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316610e22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f647265737300000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff8216610ec5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f657373000000000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610f7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e6365000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610d79565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801561105457507f000000000000000000000000000000000000000000000000000000000000000046145b1561107e57507f000000000000000000000000000000000000000000000000000000000000000090565b6104ec604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b73ffffffffffffffffffffffffffffffffffffffff82166111a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016108a0565b80600260008282546111b59190611b9a565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b606060ff83146112335761122c8361152d565b90506104b8565b81805461123f90611b4d565b80601f016020809104026020016040519081016040528092919081815260200182805461126b90611b4d565b80156112b85780601f1061128d576101008083540402835291602001916112b8565b820191906000526020600020905b81548152906001019060200180831161129b57829003601f168201915b505050505090506104b8565b73ffffffffffffffffffffffffffffffffffffffff8216611367576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f730000000000000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561141d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016108a0565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090208054600181018255905b50919050565b60006104b86114ca610fee565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b60008060006115168787878761156c565b915091506115238161165b565b5095945050505050565b6060600061153a83611811565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156115a35750600090506003611652565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156115f7573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661164b57600060019250925050611652565b9150600090505b94509492505050565b600081600481111561166f5761166f611bf6565b036116775750565b600181600481111561168b5761168b611bf6565b036116f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016108a0565b600281600481111561170657611706611bf6565b0361176d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016108a0565b600381600481111561178157611781611bf6565b0361180e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016108a0565b50565b600060ff8216601f8111156104b8576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000815180845260005b818110156118785760208185018101518683018201520161185c565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006118c96020830184611852565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146118f457600080fd5b919050565b6000806040838503121561190c57600080fd5b611915836118d0565b946020939093013593505050565b60008060006060848603121561193857600080fd5b611941846118d0565b925061194f602085016118d0565b9150604084013590509250925092565b60006020828403121561197157600080fd5b6118c9826118d0565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e0818401526119b660e084018a611852565b83810360408501526119c8818a611852565b6060850189905273ffffffffffffffffffffffffffffffffffffffff8816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015611a2757835183529284019291840191600101611a0b565b50909c9b505050505050505050505050565b600080600080600080600060e0888a031215611a5457600080fd5b611a5d886118d0565b9650611a6b602089016118d0565b95506040880135945060608801359350608088013560ff81168114611a8f57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611abf57600080fd5b611ac8836118d0565b9150611ad6602084016118d0565b90509250929050565b602081526000825160606020840152611afb6080840182611852565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016040850152611b368282611852565b915050604084015160608401528091505092915050565b600181811c90821680611b6157607f821691505b6020821081036114b7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b808201808211156104b8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600060208284031215611be657600080fd5b815180151581146118c957600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220c2bed37e0f8afb86bd2f823bdd44342ea1006ae5172594a0f1a25ac418151de264736f6c63430008130033a264697066735822122011879c275d8c998a2e98b56213b3a78b3006a55b77c9900ccfcc98e547f4c7c764736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000884de35810b085e0f15a1ac7efb86040cdb10bb700000000000000000000000045c32fa6df82ead1e2ef74d17b76547eddfaff89
-----Decoded View---------------
Arg [0] : _timelockAddress (address): 0x884DE35810b085e0f15A1ac7EFb86040cdb10BB7
Arg [1] : _fraxErc20 (address): 0x45c32fA6DF82ead1e2EF74d17b76547EDdFaFF89
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000884de35810b085e0f15a1ac7efb86040cdb10bb7
Arg [1] : 00000000000000000000000045c32fa6df82ead1e2ef74d17b76547eddfaff89
Deployed Bytecode Sourcemap
99215:8742:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19242:37;;;;;;;;;;;;190:42:1;178:55;;;160:74;;148:2;133:18;19242:37:0;;;;;;;;19929:152;;;;;;:::i;:::-;;:::i;:::-;;19334:30;;;;;;;;;20624:209;;;:::i;105003:1659::-;;;;;;:::i;:::-;;:::i;:::-;;;;948:42:1;936:55;;;918:74;;1023:2;1008:18;;1001:34;;;;891:18;105003:1659:0;744:297:1;99569:29:0;;;;;99648:25;;;;;;:::i;:::-;;:::i;101813:105::-;101895:8;:15;101813:105;;1192:25:1;;;1180:2;1165:18;101813:105:0;1046:177:1;99733:49:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1393:14:1;;1386:22;1368:41;;1356:2;1341:18;99733:49:0;1228:187:1;20233:139:0;;;:::i;99854:64::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;19929:152;20005:26;:24;:26::i;:::-;20042:31;20060:12;20042:17;:31::i;:::-;19929:152;:::o;20624:209::-;20680:26;:24;:26::i;:::-;20717:33;:31;:33::i;:::-;20761:29;20787:1;20761:17;:29::i;:::-;20801:24;20822:1;20801:12;:24::i;:::-;20624:209::o;105003:1659::-;105067:20;105089:15;105117:26;:24;:26::i;:::-;105206:33;105243:27;105264:6;105243:18;:27;:::i;:::-;105242:38;;105274:6;105242:38;:::i;:::-;105206:74;;105324:15;105295:25;:44;105291:105;;105363:21;;;;;;;;;;;;;;105291:105;105455:41;;;;:14;:41;;;;;;;;105451:108;;;105520:27;;;;;;;;;;;;;;105451:108;101895:8;:15;105599:26;;105678:25;105706:70;105748:25;105706:19;:70::i;:::-;105678:98;;105787:23;105813:121;105855:7;105897:25;105813:17;:121::i;:::-;105787:147;;105983:7;106154:4;106025:11;106058:9;106102:25;105993:177;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;106290:8:0;:27;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;106328:19:0;;;:5;106290:27;106328:19;;;;;;;:26;;;;;;;;;;;106367:41;;;:14;:41;;;;;;;:48;;;;;;;;;;;106433:221;106290:27;;-1:-1:-1;106290:27:0;;-1:-1:-1;106433:221:0;;;;106290:27;;106506:7;;106539:11;;106574:9;;106367:41;;106433:221;:::i;:::-;;;;;;;;105106:1556;;;;105003:1659;;;:::o;99648:25::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;99648:25:0;:::o;20233:139::-;20295:33;:31;:33::i;:::-;20339:25;:23;:25::i;23320:99::-;23381:30;23400:10;23381:18;:30::i;21314:184::-;21383:22;:37;;;;;;;;;;;;;-1:-1:-1;21460:15:0;21436:54;;21383:37;;21460:15;;;21436:54;;21383:22;21436:54;21314:184;:::o;24534:113::-;24602:37;24628:10;24602:25;:37::i;22015:168::-;22104:15;;22084:50;;;;;;;22104:15;;22084:50;;22104:15;;22084:50;22145:15;:30;;;;;;;;;;;;;;;22015:168::o;102105:1102::-;102185:23;102247:22;102272:56;102309:18;102272:36;:56::i;:::-;102247:81;;102339:20;102362:54;102397:18;102362:34;:54::i;:::-;102339:77;;102427:21;102451:55;102487:18;102451:35;:55::i;:::-;102427:79;;102519:33;102584:1;102567:14;:18;102563:198;;;102624:25;:14;:23;:25::i;:::-;102602:47;;102563:198;;;102723:25;:14;:23;:25::i;:::-;102704:45;;;;;;;;:::i;:::-;;;;;;;;;;;;;102682:67;;102563:198;102773:31;102834:1;102819:12;:16;102815:188;;;102872:23;:12;:21;:23::i;:::-;102852:43;;102815:188;;;102967:23;:12;:21;:23::i;:::-;102948:43;;;;;;;;:::i;:::-;;;;;;;;;;;;;102928:63;;102815:188;103123:24;:13;:22;:24::i;:::-;103149:19;103170:17;103094:94;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;103061:138;;102210:997;;;;;102105:1102;;;:::o;103445:1066::-;103565:23;103627:22;103652:56;103689:18;103652:36;:56::i;:::-;103627:81;;103719:20;103742:54;103777:18;103742:34;:54::i;:::-;103719:77;;103807:21;103831:55;103867:18;103831:35;:55::i;:::-;103807:79;;103899:31;103960:1;103945:12;:16;103941:199;;;103998:23;:12;:21;:23::i;:::-;103978:43;;103941:199;;;104103:23;:12;:21;:23::i;:::-;104081:46;;;;;;;;:::i;:::-;;;;;;;;;;;;;104054:74;;103941:199;104312:18;:7;:16;:18::i;:::-;104371:27;104383:14;104371:11;:27::i;:::-;104417:17;104453:24;:13;:22;:24::i;:::-;104231:261;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;104198:305;;103590:921;;;;103445:1066;;;;:::o;21668:133::-;21756:1;21723:35;;;;;;21769:24;21782:10;21769:12;:24::i;22966:161::-;22761:15;;;22749:27;;;22761:15;;22749:27;23037:82;;23093:15;;23072:47;;;;;23093:15;;;;23072:47;;;7343:34:1;7413:15;;;7393:18;;;7386:43;7255:18;;23072:47:0;;;;;;;;24153:189;23816:4;23852:22;;23840:34;;;23852:22;;23840:34;24231:103;;24301:22;;24273:61;;;;;24301:22;;;;24273:61;;;7343:34:1;7413:15;;;7393:18;;;7386:43;7255:18;;24273:61:0;7108:327:1;34009:148:0;34069:13;34109:40;34121:27;27069:12;34121:9;:27;:::i;:::-;34109:11;:40::i;:::-;-1:-1:-1;34095:54:0;34009:148;-1:-1:-1;;;34009:148:0:o;34165:142::-;34223:11;34259:40;34271:27;27069:12;34271:9;:27;:::i;34259:40::-;34247:52;34165:142;-1:-1:-1;;;;34165:142:0:o;33856:145::-;33915:12;33953:40;33965:27;27069:12;33965:9;:27;:::i;33953:40::-;-1:-1:-1;33940:53:0;;33856:145;-1:-1:-1;;;33856:145:0:o;15514:716::-;15570:13;15621:14;15638:17;15649:5;15638:10;:17::i;:::-;15658:1;15638:21;15621:38;;15674:20;15708:6;15697:18;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;15697:18:0;-1:-1:-1;15674:41:0;-1:-1:-1;15839:28:0;;;15855:2;15839:28;15896:288;15928:5;;16070:8;16065:2;16054:14;;16049:30;15928:5;16036:44;16126:2;16117:11;;;-1:-1:-1;16147:21:0;15896:288;16147:21;-1:-1:-1;16205:6:0;15514:716;-1:-1:-1;;;15514:716:0:o;100780:680::-;100845:24;100886:11;100901:1;100886:16;100882:34;;-1:-1:-1;;100904:12:0;;;;;;;;;;;;;;;;;;100780:680::o;100882:34::-;100931:11;100946:1;100931:16;100927:34;;-1:-1:-1;;100949:12:0;;;;;;;;;;;;;;;;;;100780:680::o;100927:34::-;100976:11;100991:1;100976:16;100972:34;;-1:-1:-1;;100994:12:0;;;;;;;;;;;;;;;;;;100780:680::o;100972:34::-;101021:11;101036:1;101021:16;101017:34;;-1:-1:-1;;101039:12:0;;;;;;;;;;;;;;;;;;100780:680::o;101017:34::-;101066:11;101081:1;101066:16;101062:34;;-1:-1:-1;;101084:12:0;;;;;;;;;;;;;;;;;;100780:680::o;101062:34::-;101111:11;101126:1;101111:16;101107:34;;-1:-1:-1;;101129:12:0;;;;;;;;;;;;;;;;;;100780:680::o;101107:34::-;101156:11;101171:1;101156:16;101152:34;;-1:-1:-1;;101174:12:0;;;;;;;;;;;;;;;;;;100780:680::o;101152:34::-;101201:11;101216:1;101201:16;101197:34;;-1:-1:-1;;101219:12:0;;;;;;;;;;;;;;;;;;100780:680::o;101197:34::-;101246:11;101261:1;101246:16;101242:34;;-1:-1:-1;;101264:12:0;;;;;;;;;;;;;;;;;;100780:680::o;101242:34::-;101291:11;101306:2;101291:17;101287:35;;-1:-1:-1;;101310:12:0;;;;;;;;;;;;;;;;;;100780:680::o;101287:35::-;101337:11;101352:2;101337:17;101333:35;;-1:-1:-1;;101356:12:0;;;;;;;;;;;;;;;;;;100780:680::o;101333:35::-;101383:11;101398:2;101383:17;101379:35;;-1:-1:-1;;101402:12:0;;;;;;;;;;;;;;;;;;100780:680::o;101379:35::-;101432:20;;;;;;;;;;;;;;29543:679;29602:12;;;29678:5;29602:12;27218:9;29708:15;29678:5;29717:6;29708:15;:::i;:::-;:32;;;;:::i;:::-;29697:43;-1:-1:-1;29751:8:0;29772:7;29763:5;29697:43;29763:1;:5;:::i;:::-;29762:17;;;;:::i;:::-;29751:28;-1:-1:-1;29818:1:0;29799:11;29751:28;29799:7;:11;:::i;:::-;:15;;29813:1;29799:15;:::i;:::-;29798:21;;;;:::i;:::-;29794:25;;:1;:25;:::i;:::-;29790:29;-1:-1:-1;29830:12:0;29864:9;29854:5;29790:29;29858:1;29854:5;:::i;:::-;29846:14;;:4;:14;:::i;:::-;29845:28;;;;:::i;:::-;29830:43;-1:-1:-1;29909:1:0;29893:12;29830:43;29893:4;:12;:::i;:::-;29892:18;;;;:::i;:::-;29888:22;;:1;:22;:::i;:::-;:27;;29913:2;29888:27;:::i;:::-;29884:31;-1:-1:-1;29926:13:0;29953:4;29943:6;29884:31;29943:2;:6;:::i;:::-;29942:15;;;;:::i;:::-;29926:31;-1:-1:-1;29968:11:0;30004:2;29987:13;29926:31;29987:4;:13;:::i;:::-;29986:20;;;;:::i;:::-;29982:24;;:1;:24;:::i;:::-;29968:38;-1:-1:-1;30021:11:0;30030:2;30021:6;:11;:::i;:::-;30017:15;-1:-1:-1;30065:6:0;30017:15;30065:2;:6;:::i;:::-;30052:10;:6;30061:1;30052:10;:::i;:::-;:19;;;;:::i;:::-;30043:28;-1:-1:-1;30115:1:0;30107:5;30097:6;30101:2;30097:1;:6;:::i;:::-;30090:14;;:3;:14;:::i;:::-;:22;;;;:::i;:::-;:26;;;;:::i;:::-;30082:34;30177:6;;-1:-1:-1;30209:4:0;-1:-1:-1;29543:679:0;-1:-1:-1;;;;;;29543:679:0:o;11258:948::-;11311:7;;11398:8;11389:17;;11385:106;;11436:8;11427:17;;;-1:-1:-1;11473:2:0;11463:12;11385:106;11518:8;11509:5;:17;11505:106;;11556:8;11547:17;;;-1:-1:-1;11593:2:0;11583:12;11505:106;11638:8;11629:5;:17;11625:106;;11676:8;11667:17;;;-1:-1:-1;11713:2:0;11703:12;11625:106;11758:7;11749:5;:16;11745:103;;11795:7;11786:16;;;-1:-1:-1;11831:1:0;11821:11;11745:103;11875:7;11866:5;:16;11862:103;;11912:7;11903:16;;;-1:-1:-1;11948:1:0;11938:11;11862:103;11992:7;11983:5;:16;11979:103;;12029:7;12020:16;;;-1:-1:-1;12065:1:0;12055:11;11979:103;12109:7;12100:5;:16;12096:68;;12147:1;12137:11;12096:68;12192:6;11258:948;-1:-1:-1;;11258:948:0:o;-1:-1:-1:-;;;;;;;;:::o;245:309:1:-;304:6;357:2;345:9;336:7;332:23;328:32;325:52;;;373:1;370;363:12;325:52;412:9;399:23;462:42;455:5;451:54;444:5;441:65;431:93;;520:1;517;510:12;431:93;543:5;245:309;-1:-1:-1;;;245:309:1:o;559:180::-;618:6;671:2;659:9;650:7;646:23;642:32;639:52;;;687:1;684;677:12;639:52;-1:-1:-1;710:23:1;;559:180;-1:-1:-1;559:180:1:o;1420:184::-;1472:77;1469:1;1462:88;1569:4;1566:1;1559:15;1593:4;1590:1;1583:15;1609:184;1661:77;1658:1;1651:88;1758:4;1755:1;1748:15;1782:4;1779:1;1772:15;1798:120;1838:1;1864;1854:35;;1869:18;;:::i;:::-;-1:-1:-1;1903:9:1;;1798:120::o;1923:168::-;1996:9;;;2027;;2044:15;;;2038:22;;2024:37;2014:71;;2065:18;;:::i;2096:250::-;2181:1;2191:113;2205:6;2202:1;2199:13;2191:113;;;2281:11;;;2275:18;2262:11;;;2255:39;2227:2;2220:10;2191:113;;;-1:-1:-1;;2338:1:1;2320:16;;2313:27;2096:250::o;2351:330::-;2393:3;2431:5;2425:12;2458:6;2453:3;2446:19;2474:76;2543:6;2536:4;2531:3;2527:14;2520:4;2513:5;2509:16;2474:76;:::i;:::-;2595:2;2583:15;2600:66;2579:88;2570:98;;;;2670:4;2566:109;;2351:330;-1:-1:-1;;2351:330:1:o;2686:576::-;2951:42;2943:6;2939:55;2928:9;2921:74;3031:3;3026:2;3015:9;3011:18;3004:31;2902:4;3058:46;3099:3;3088:9;3084:19;3076:6;3058:46;:::i;:::-;3152:9;3144:6;3140:22;3135:2;3124:9;3120:18;3113:50;3180:33;3206:6;3198;3180:33;:::i;:::-;3172:41;;;3249:6;3244:2;3233:9;3229:18;3222:34;2686:576;;;;;;;:::o;3267:648::-;3560:42;3552:6;3548:55;3537:9;3530:74;3640:6;3635:2;3624:9;3620:18;3613:34;3683:3;3678:2;3667:9;3663:18;3656:31;3511:4;3710:46;3751:3;3740:9;3736:19;3728:6;3710:46;:::i;:::-;3804:9;3796:6;3792:22;3787:2;3776:9;3772:18;3765:50;3832:33;3858:6;3850;3832:33;:::i;:::-;3824:41;;;3902:6;3896:3;3885:9;3881:19;3874:35;3267:648;;;;;;;;:::o;3920:420::-;4171:3;4166;4159:16;4141:3;4204:6;4198:13;4220:74;4287:6;4283:1;4278:3;4274:11;4267:4;4259:6;4255:17;4220:74;:::i;:::-;4314:16;;;;4332:1;4310:24;;3920:420;-1:-1:-1;;3920:420:1:o;4345:979::-;4804:5;4799:3;4792:18;4839:3;4835:1;4830:3;4826:11;4819:24;4774:3;4872:6;4866:13;4888:74;4955:6;4951:1;4946:3;4942:11;4935:4;4927:6;4923:17;4888:74;:::i;:::-;5022:13;;4981:16;;;;5044:75;5022:13;5106:1;5098:10;;5091:4;5079:17;;5044:75;:::i;:::-;5180:13;;5138:17;;;5202:75;5180:13;5264:1;5256:10;;5249:4;5237:17;;5202:75;:::i;:::-;5297:17;5316:1;5293:25;;4345:979;-1:-1:-1;;;;;4345:979:1:o;5765:1338::-;6373:5;6368:3;6361:18;6343:3;6398;6430:2;6426:1;6421:3;6417:11;6410:23;6462:6;6456:13;6478:74;6545:6;6541:1;6536:3;6532:11;6525:4;6517:6;6513:17;6478:74;:::i;:::-;6580:6;6575:3;6571:16;6561:26;;6615:2;6611:1;6607:2;6603:10;6596:22;6649:6;6643:13;6627:29;;6665:75;6731:8;6727:1;6723:2;6719:10;6712:4;6704:6;6700:17;6665:75;:::i;:::-;6801:13;;6759:17;;;6823:75;6801:13;6885:1;6877:10;;6870:4;6858:17;;6823:75;:::i;:::-;6959:13;;6917:17;;;6981:75;6959:13;7043:1;7035:10;;7028:4;7016:17;;6981:75;:::i;:::-;7076:17;7095:1;7072:25;;5765:1338;-1:-1:-1;;;;;;5765:1338:1:o;7440:184::-;7492:77;7489:1;7482:88;7589:4;7586:1;7579:15;7613:4;7610:1;7603:15;7629:216;7693:9;;;7721:11;;;7668:3;7751:9;;7779:10;;7775:19;;7804:10;;7796:19;;7772:44;7769:70;;;7819:18;;:::i;:::-;7769:70;;7629:216;;;;:::o;7850:292::-;7922:9;;;7889:7;7947:9;;7964:66;7958:73;;7943:89;7940:115;;;8035:18;;:::i;:::-;8108:1;8099:7;8094:16;8091:1;8088:23;8084:1;8077:9;8074:38;8064:72;;8116:18;;:::i;8147:308::-;8186:1;8212;8202:35;;8217:18;;:::i;:::-;8334:66;8331:1;8328:73;8259:66;8256:1;8253:73;8249:153;8246:179;;;8405:18;;:::i;:::-;-1:-1:-1;8439:10:1;;8147:308::o;8460:200::-;8526:9;;;8499:4;8554:9;;8582:10;;8594:12;;;8578:29;8617:12;;;8609:21;;8575:56;8572:82;;;8634:18;;:::i;:::-;8572:82;8460:200;;;;:::o
Swarm Source
ipfs://11879c275d8c998a2e98b56213b3a78b3006a55b77c9900ccfcc98e547f4c7c7
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.