Contract 0xbfd6ef07df5c5da0327c7988accf0ba100cf682b

Txn Hash Method
Block
From
To
Value [Txn Fee]
0x0f05aa27987704d5a048c9b675fc21df1ec42575860b53cf9c577e04db3a0f640x6153566158009202022-11-30 13:42:0469 days 7 hrs ago0x902a3f17114f815573cb1d87e16a027d52e2a158 IN  Create: NFTDescriptor0 CRO22.705074022758 4,868.192383723
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NFTDescriptor

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 6 : Base64.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides a set of functions to operate with Base64 strings.
 *
 * _Available since v4.5._
 */
library Base64 {
    /**
     * @dev Base64 Encoding/Decoding Table
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /**
     * @dev Converts a `bytes` to its Bytes64 `string` representation.
     */
    function encode(bytes memory data) internal pure returns (string memory) {
        /**
         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
         */
        if (data.length == 0) return "";

        // Loads the table into memory
        string memory table = _TABLE;

        // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
        // and split into 4 numbers of 6 bits.
        // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
        // - `data.length + 2`  -> Round up
        // - `/ 3`              -> Number of 3-bytes chunks
        // - `4 *`              -> 4 characters for each chunk
        string memory result = new string(4 * ((data.length + 2) / 3));

        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the lookup table (skip the first "length" byte)
            let tablePtr := add(table, 1)

            // Prepare result pointer, jump over length
            let resultPtr := add(result, 32)

            // Run over the input, 3 bytes at a time
            for {
                let dataPtr := data
                let endPtr := add(data, mload(data))
            } lt(dataPtr, endPtr) {

            } {
                // Advance 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // To write each character, shift the 3 bytes (18 bits) chunk
                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                // and apply logical AND with 0x3F which is the number of
                // the previous character in the ASCII table prior to the Base64 Table
                // The result is then added to the table to get the character to write,
                // and finally write it in the result pointer but with a left shift
                // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits

                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance
            }

            // When data `bytes` is not exactly 3 bytes long
            // it is padded with `=` characters at the end
            switch mod(mload(data), 3)
            case 1 {
                mstore8(sub(resultPtr, 1), 0x3d)
                mstore8(sub(resultPtr, 2), 0x3d)
            }
            case 2 {
                mstore8(sub(resultPtr, 1), 0x3d)
            }
        }

        return result;
    }
}

File 2 of 6 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_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) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @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);
    }
}

File 3 of 6 : DateTime.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// ----------------------------------------------------------------------------
// DateTime Library v2.0
//
// 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 DateTime {
    uint256 constant SECONDS_PER_DAY = 24 * 60 * 60;
    uint256 constant SECONDS_PER_HOUR = 60 * 60;
    uint256 constant SECONDS_PER_MINUTE = 60;
    int256 constant OFFSET19700101 = 2440588;

    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 - 32075 + (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) {
        unchecked {
            int256 __days = int256(_days);

            int256 L = __days + 68569 + OFFSET19700101;
            int256 N = (4 * L) / 146097;
            L = L - (146097 * N + 3) / 4;
            int256 _year = (4000 * (L + 1)) / 1461001;
            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) {
        unchecked {
            (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)
    {
        unchecked {
            (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;
    }
}

File 4 of 6 : DecimalString.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

/*
    Library taken from https://gist.github.com/wilsoncusack/d2e680e0f961e36393d1bf0b6faafba7 and
    https://github.com/Uniswap/v3-periphery/blob/main/contracts/libraries/NFTDescriptor.sol
*/
library DecimalString {
    function decimalString(
        uint256 number,
        uint8 decimals,
        bool isPercent
    ) internal pure returns (Result memory) {
        uint8 percentBufferOffset = isPercent ? 1 : 0;
        uint256 tenPowDecimals = 10**decimals;

        uint256 temp = number;
        uint8 digits;
        uint8 numSigfigs;
        while (temp != 0) {
            if (numSigfigs > 0) {
                // count all digits preceding least significant figure
                numSigfigs++;
            } else if (temp % 10 != 0) {
                numSigfigs++;
            }
            digits++;
            temp /= 10;
        }

        DecimalStringParams memory params;
        params.isPercent = isPercent;
        if ((digits - numSigfigs) >= decimals) {
            // no decimals, ensure we preserve all trailing zeros
            params.sigfigs = number / tenPowDecimals;
            params.sigfigIndex = digits - decimals;
            params.bufferLength = params.sigfigIndex + percentBufferOffset;
        } else {
            // chop all trailing zeros for numbers with decimals
            params.sigfigs = number / (10**(digits - numSigfigs));
            if (tenPowDecimals > number) {
                // number is less tahn one
                // in this case, there may be leading zeros after the decimal place
                // that need to be added

                // offset leading zeros by two to account for leading '0.'
                params.zerosStartIndex = 2;
                params.zerosEndIndex = decimals - digits + 2;
                params.sigfigIndex = numSigfigs + params.zerosEndIndex;
                params.bufferLength = params.sigfigIndex + percentBufferOffset;
                params.isLessThanOne = true;
            } else {
                // In this case, there are digits before and
                // after the decimal place
                params.sigfigIndex = numSigfigs + 1;
                params.decimalIndex = digits - decimals + 1;
            }
        }
        params.bufferLength = params.sigfigIndex + percentBufferOffset;

        Result memory result = Result({result: generateDecimalString(params), length: params.bufferLength});
        return result;
    }

    struct Result {
        string result;
        uint8 length;
    }

    // With modifications, the below taken
    // from https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/libraries/NFTDescriptor.sol#L189-L231

    struct DecimalStringParams {
        // significant figures of decimal
        uint256 sigfigs;
        // length of decimal string
        uint8 bufferLength;
        // ending index for significant figures (funtion works backwards when copying sigfigs)
        uint8 sigfigIndex;
        // index of decimal place (0 if no decimal)
        uint8 decimalIndex;
        // start index for trailing/leading 0's for very small/large numbers
        uint8 zerosStartIndex;
        // end index for trailing/leading 0's for very small/large numbers
        uint8 zerosEndIndex;
        // true if decimal number is less than one
        bool isLessThanOne;
        // true if string should include "%"
        bool isPercent;
    }

    function generateDecimalString(DecimalStringParams memory params) private pure returns (string memory) {
        bytes memory buffer = new bytes(params.bufferLength);
        if (params.isPercent) {
            buffer[buffer.length - 1] = "%";
        }
        if (params.isLessThanOne) {
            buffer[0] = "0";
            buffer[1] = ".";
        }

        // add leading/trailing 0's
        for (
            uint256 zerosCursor = params.zerosStartIndex;
            zerosCursor < params.zerosEndIndex;
            zerosCursor++
        ) {
            buffer[zerosCursor] = bytes1(uint8(48));
        }
        // add sigfigs
        while (params.sigfigs > 0) {
            if (params.decimalIndex > 0 && params.sigfigIndex == params.decimalIndex) {
                buffer[--params.sigfigIndex] = ".";
            }
            buffer[--params.sigfigIndex] = bytes1(uint8(uint256(48) + (params.sigfigs % 10)));
            params.sigfigs /= 10;
        }
        return string(buffer);
    }
}

File 5 of 6 : NFTDescriptor.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "./NFTSVG.sol";

library NFTDescriptor {
    using Strings for uint256;

    struct ConstructTokenURIParams {
        uint256 tokenId;
        address owner;
        uint128 unlockStartTime;
        uint128 unlockEndTime;
        // total liquidCro amount pending unlock
        uint256 liquidCroAmount;
        // liquidCro to cro rate - this can decrease in the event of slashing, require divide by 1e18
        uint256 liquidCro2CroExchangeRate;
        uint8 exchangeRateDecimal;
    }

    function generateNFTParams(ConstructTokenURIParams memory params)
        private
        pure
        returns (NFTSVG.SVGParams memory)
    {
        uint256 croAmount = getCroAmount(
            params.liquidCroAmount,
            params.liquidCro2CroExchangeRate,
            params.exchangeRateDecimal
        );
        uint256 liquidCroAmount = getLiquidCroAmount(params.liquidCroAmount);

        string memory exchangeRate = DecimalString
            .decimalString(params.liquidCro2CroExchangeRate, params.exchangeRateDecimal, false)
            .result;

        NFTSVG.SVGParams memory params = NFTSVG.SVGParams({
            tokenId: params.tokenId,
            owner: addressToString(params.owner),
            unlockStartTime: getTimeInFormat(params.unlockStartTime),
            unlockEndTime: getTimeInFormat(params.unlockEndTime),
            liquidCroAmount: liquidCroAmount,
            croAmount: croAmount,
            exchangeRate: exchangeRate
        });

        return params;
    }

    function constructTokenURI(ConstructTokenURIParams memory params) public pure returns (string memory) {
        NFTSVG.SVGParams memory svgParams = generateNFTParams(params);

        DecimalString.Result memory croAmountString = DecimalString.decimalString(
            svgParams.croAmount,
            18,
            false
        );

        string memory name = string(
            abi.encodePacked(
                "Veno Finance - Claim ",
                croAmountString.result,
                " CRO @ ",
                svgParams.unlockEndTime
            )
        );

        DecimalString.Result memory liquidCroAmountString = DecimalString.decimalString(
            svgParams.liquidCroAmount,
            18,
            false
        );

        string memory descriptionPart1 = generateDescriptionPart1(
            croAmountString.result,
            svgParams.unlockEndTime,
            svgParams.owner
        );
        // To bypass compilation error, variable length is too long have to separate to two variables.
        string memory descriptionPart2 = generateDescriptionPart2(
            croAmountString.result,
            liquidCroAmountString.result,
            svgParams.unlockEndTime,
            svgParams.tokenId
        );

        string memory image = Base64.encode(bytes(generateSVGImage(svgParams)));

        return
            string(
                abi.encodePacked(
                    "data:application/json;base64,",
                    Base64.encode(
                        bytes(
                            abi.encodePacked(
                                '{"name":"',
                                name,
                                '", "description":"',
                                descriptionPart1,
                                descriptionPart2,
                                '", "image": "',
                                "data:image/svg+xml;base64,",
                                image,
                                '"}'
                            )
                        )
                    )
                )
            );
    }

    function generateSVGImage(NFTSVG.SVGParams memory params) internal pure returns (string memory) {
        return NFTSVG.generateSVGImage(params);
    }

    function generateDescriptionPart1(
        string memory croAmount,
        string memory unlockEndTime,
        string memory owner
    ) internal pure returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "This NFT represents a claim to ",
                    croAmount,
                    " CRO that will be available after ",
                    unlockEndTime,
                    "\\n",
                    "LCRO Address: ",
                    owner,
                    "\\n"
                )
            );
    }

    function generateDescriptionPart2(
        string memory croAmount,
        string memory liquidCroAmount,
        string memory unlockEndTime,
        uint256 tokenId
    ) private pure returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "LCRO burned: ",
                    liquidCroAmount,
                    "\\n",
                    "CRO to claim: ",
                    croAmount,
                    "\\n",
                    "Est. unbound date: ",
                    unlockEndTime,
                    "\\n",
                    "TokenId: ",
                    tokenId.toString()
                )
            );
    }

    function getTimeInFormat(uint256 time) private pure returns (string memory) {
        (uint256 year, uint256 month, uint256 day) = DateTime.timestampToDate(time);

        return string(abi.encodePacked(year.toString(), "/", month.toString(), "/", day.toString()));
    }

    function getCroAmount(
        uint256 liquidCroAmount,
        uint256 liquidCro2CroExchangeRate,
        uint8 exchangeRateDecimal
    ) private pure returns (uint256) {
        uint256 croAmount = (liquidCroAmount * liquidCro2CroExchangeRate) / 10**exchangeRateDecimal;

        // round down croAmount to the nearest 2 decimal place
        uint256 croAmountRounded = croAmount - (croAmount % 1e16);
        return croAmountRounded;
    }

    function getLiquidCroAmount(uint256 liquidCroAmount) private pure returns (uint256) {
        // round down croAmount to the nearest 2 decimal place
        uint256 liquidCroAmountRounded = liquidCroAmount - (liquidCroAmount % 1e16);

        return liquidCroAmountRounded;
    }

    function addressToString(address addr) private pure returns (string memory) {
        return (uint256(uint160(addr))).toHexString(20);
    }
}

File 6 of 6 : NFTSVG.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import "@openzeppelin/contracts/utils/Strings.sol";
import "solidity-datetime/contracts/DateTime.sol";
import "./DecimalString.sol";
import "./NFTDescriptor.sol";

library NFTSVG {
    using Strings for uint256;

    struct SVGParams {
        uint256 tokenId;
        string owner;
        string unlockStartTime;
        string unlockEndTime;
        uint256 liquidCroAmount;
        uint256 croAmount;
        string exchangeRate;
    }

    function generateSVGImage(SVGParams memory params) internal pure returns (string memory) {
        return
            string(
                abi.encodePacked(
                    generateSVGDefs(),
                    generateCroAmountText(params),
                    generateUnlockStartTime(params),
                    generateUnlockEndTime(params),
                    generateExchangeRateText(params),
                    generateLiquidCroAmount(params),
                    generateNFTOwnerInfo(params),
                    "</svg>"
                )
            );
    }

    function generateSVGDefs() private pure returns (string memory svg) {
        svg = string(
            abi.encodePacked(
                '<svg width="290" height="500" viewBox="0 0 290 500" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_28_340)"><rect width="290" height="500" fill="white"/><rect x="0.5" y="0.5" width="289" height="499" rx="14.5" fill="white" stroke="url(#paint0_linear_28_340)"/><g filter="url(#filter0_f_28_340)"><path d="M170.578 245.941C174.788 234.091 176.638 219.221 174.118 201.101C178.308 166.091 184.448 120.551 151.458 104.421C140.718 99.6806 132.278 90.2006 121.538 87.3506C113.868 84.5006 110.028 99.6806 113.098 109.171C116.938 119.611 124.608 129.091 123.838 141.431C122.308 153.761 111.558 153.761 104.578 158.081C61.0383 173.231 57.7683 243.321 87.3383 270.371C93.2783 275.801 100.278 279.271 107.598 281.151C108.648 299.251 112.628 316.351 117.928 333.941C125.358 361.341 83.9083 409.241 101.598 411.821C133.818 418.461 165.278 386.201 196.258 368.391C241.258 333.331 222.168 248.731 170.578 245.951V245.941Z" fill="url(#paint1_linear_28_340)"/></g><path d="M0.178894 298.063C6.07889 292.413 12.3589 287.123 17.4489 281.703C61.0889 235.223 26.3989 236.693 0.178894 211.143V217.243C25.7589 240.383 58.6789 238.403 3.72889 288.623C-0.741106 292.703 0.178894 290.673 0.178894 298.063V298.063ZM194.739 144.923C201.249 114.503 178.689 87.2932 184.289 58.1432C189.649 30.2732 227.009 13.7232 249.339 0.133205C244.319 0.133205 247.349 -0.876795 236.649 5.19321C214.909 17.5432 187.029 33.3532 182.329 57.7632C176.629 87.4332 199.139 114.823 192.789 144.493C186.369 174.503 162.319 188.143 123.349 168.423C61.6989 137.253 16.8989 76.0632 4.34889 4.77321C3.73889 5.41321 3.17889 6.09321 2.68889 6.83321C24.4189 136.353 175.719 233.823 194.739 144.923ZM154.169 93.0432C165.219 59.7132 126.629 36.5232 180.669 0.133205H173.649C125.089 35.1232 160.079 62.5132 150.379 91.7832C144.049 110.893 128.739 118.853 102.239 104.533C62.8989 83.3332 34.0989 44.7632 23.1389 0.133205C18.1189 0.133205 18.5189 -1.31679 20.4589 5.74321C42.2189 84.6632 134.409 152.683 154.169 93.0432ZM0.178894 240.363V265.943C5.96889 257.063 7.73889 247.803 0.178894 240.363ZM174.469 118.943C185.039 78.2832 135.829 48.7232 204.419 6.20321C216.719 -1.43679 216.659 0.133205 208.629 0.133205C129.609 47.5132 182.189 77.3532 171.569 118.183C153.969 185.843 44.4089 111.963 17.2989 17.4132C12.3389 0.103205 14.6589 -0.536795 10.2789 0.973205C31.3389 109.613 154.949 193.993 174.469 118.943ZM133.799 67.3032C143.869 45.2332 122.089 25.1932 149.729 0.143205H142.559C118.869 24.8832 137.729 46.6332 129.249 65.2332C122.949 79.0532 111.919 84.1532 91.7189 72.6132C64.6489 57.2032 43.8689 31.0832 33.7489 0.133205H28.4889C44.3889 50.7532 112.109 114.873 133.799 67.2932V67.3032ZM281.799 1.69321C281.699 1.64321 280.759 1.15321 280.659 1.21321C212.569 42.0432 182.939 48.2432 205.739 119.363C210.999 135.763 217.259 152.923 214.019 170.783C196.349 267.953 35.6589 171.433 0.178894 31.7332C0.178894 48.5832 35.5689 154.343 132.789 202.093C178.789 224.693 209.179 207.873 215.729 171.883C219.019 153.773 213.569 136.483 208.279 119.963C185.369 48.5232 214.739 41.9132 281.799 1.69321V1.69321ZM29.6889 125.513C21.3089 107.863 13.4589 88.6932 0.178894 75.2432C0.178894 80.6532 3.92889 73.2232 22.5889 115.363C40.0189 154.703 60.8189 182.813 112.089 209.633C153.559 231.333 132.899 262.213 97.0589 292.303C38.6789 341.323 18.6389 351.843 31.8489 410.313C39.1989 442.873 47.3389 480.713 37.3989 500.133H38.4989C50.9689 474.673 32.2989 419.853 29.3389 387.333C23.6889 325.273 121.889 297.293 135.119 246.473C146.999 200.813 71.7889 214.193 29.6889 125.503V125.513ZM0.178894 433.433C8.74889 421.313 5.02889 399.083 1.09889 375.553C-0.131106 368.173 0.178894 363.953 0.178894 390.963C4.37889 420.093 0.178894 418.383 0.178894 433.443V433.433ZM102.879 247.163C110.859 209.173 48.3689 220.383 12.7389 145.803C8.55889 137.063 4.83889 127.723 0.178894 119.033C0.178894 125.493 -0.851106 120.953 6.24889 136.813C47.1189 228.133 110.199 208.713 100.469 248.003C95.8589 266.563 72.6689 286.233 53.0789 302.643C4.6689 343.203 8.01889 355.983 16.0089 399.293C22.7489 435.813 29.5189 472.133 0.848894 476.063C-0.0411059 476.183 0.178894 475.663 0.178894 478.303C36.0589 474.873 22.5489 424.083 16.2789 388.693C12.3889 366.763 10.0789 351.763 26.2989 331.263C46.9789 305.113 96.4589 277.783 102.879 247.153V247.163ZM70.2689 249.413C76.2989 218.943 30.4789 225.913 0.178894 171.683V178.243C11.9489 197.193 28.4189 212.063 52.1289 225.393C101.189 252.993 18.2289 293.623 0.178894 326.163C0.178894 340.883 -1.92111 333.023 8.26889 320.043C24.7589 298.993 65.2989 274.813 70.2689 249.403V249.413Z" fill="url(#paint2_radial_28_340)"/><path d="M140.943 271.632C166.373 219.822 188.972 232.432 211.582 217.042L180.573 186.023C160.543 165.993 128.053 165.993 108.023 186.023C87.9925 206.053 87.9925 238.543 108.023 258.573L133.882 284.433C136.312 280.513 138.682 276.262 140.952 271.632H140.943Z" fill="white"/><path d="M225.69 446.76C220.89 429.13 209.2 418.11 178.67 395.9C163.57 384.92 140.25 376.06 119.67 368.25C77.12 352.09 69.15 348.8 98.56 324.92C158.21 276.48 135.95 244.55 189.57 227.62C273.38 201.16 210.19 107.88 210.01 81.1C209.77 46.73 245.21 18.48 278.7 12.74C307.48 7.80999 260.92 8.04 230.65 35.04C215.84 48.25 207.75 64.44 207.86 80.64C207.93 90.57 211.18 98.31 215.31 108.11C231.29 146.1 243.44 194.39 209.15 217.25C186.81 232.14 163.98 220.74 138.6 272.44C114.2 322.14 78.53 328.3 79.54 347.63C80.2 360.41 146.87 374 178.1 396.72C208.42 418.77 220.03 429.69 224.75 447.03C229.34 463.91 232.72 474.57 240.87 480.36C252.51 488.64 288.21 486.53 288.21 484.31C237.59 489.04 234.4 478.65 225.72 446.77L225.69 446.76ZM288.18 79.53V76.43C269.28 85.45 253.42 102.37 253.02 122.85C252.66 140.9 290.03 202.74 252.69 229.33C235.93 241.27 218.54 233.33 199.33 273.46C181.01 311.42 154.2 316.3 155.09 332.22C156.02 347.98 248.5 357.96 267.29 415.98C272.08 430.76 276.51 437.18 288.18 439.13V436.46C278.54 434.65 274.38 428.91 269.91 415.14C250.89 356.48 158.58 344.7 157.84 332.06C157.08 318.41 183.62 312.35 201.81 274.65C220.01 236.63 237.7 243.39 254.28 231.57C293.68 203.5 255.41 140.31 255.76 122.9C256.13 104.4 270.55 88.39 288.17 79.53H288.18ZM248.81 434.55C243.5 417.23 243.12 410.75 205.1 382.78C178.65 363.29 119.72 349.7 119.18 339.81C118.32 323.79 149.41 317.35 170.65 273.76C192.54 228.67 212.03 238.83 231.92 225.16C277.38 194.02 232.25 121.67 232.31 101.76C232.5 73.43 260.64 50.59 288.18 43.93V42C259.47 48.77 230.63 72.49 230.43 101.75C230.35 126.79 285.3 208.05 213.16 231.49C164.67 247.25 183.68 273.88 132.36 318.36C104.17 342.79 117.63 346.2 152.88 359.9C170.73 366.83 190.96 374.69 203.99 384.3C230.57 403.85 240.78 413.51 245.16 428.77C252.54 454.52 256.62 463.01 282.88 463.01C288.92 463.01 288.19 463.45 288.19 461.02C260.05 461.89 255.28 455.85 248.82 434.56L248.81 434.55ZM257.99 356.56C239.48 342.35 196.91 330.9 196.51 324.3C195.82 313.04 217.97 307.33 232.99 275.54C252.71 233.8 275.29 252.06 288.19 224.12C292.48 214.82 293 202.86 290.08 186.9C288.82 180.02 288.35 175.35 288.2 179.49C288.2 178.99 288.2 178.5 288.2 177.98C283.48 158.3 270.66 143.35 288.2 122.33V116.85C272.8 132.52 273.93 146.98 279.79 163.3C285.21 178.4 287.38 192.7 288.16 198.72C288.16 201.46 288.18 204.51 288.18 207.9C287.2 226.3 277.9 235.15 262.05 241.47C227.56 255.24 239.08 274.93 204.23 306.95C183.08 326.38 192.75 330 219.93 341.3C232.46 346.51 246.66 352.42 255.8 359.44C284.67 381.44 283.52 385.87 288.2 398.55C288.2 387.1 291.8 382.31 258 356.56H257.99ZM243.24 304.49C272.33 276.42 261.39 263.03 288.18 250.63C288.18 244.65 288.78 245.4 286.39 246.5C278.01 250.38 269.35 254.39 260.07 274.51C248.04 300.62 229.85 304.49 230.67 316.82C231.34 326.93 263.48 331.68 288.18 352.26V346.44C278.3 338.43 272.71 335.62 255.26 327.94C231.9 317.66 230.2 317.07 243.24 304.49V304.49ZM275.95 295.58C261.23 310.92 269.25 314.34 288.18 323.42V317.46C264.22 305.96 273.87 309.18 288.18 289.65C288.18 272.71 291.35 279.55 275.95 295.59V295.58Z" fill="url(#paint3_radial_28_340)"/><rect width="290" height="500" rx="15" fill="url(#paint4_linear_28_340)"/><path d="M25.75 336.75H249C257.422 336.75 264.25 343.578 264.25 352C264.25 360.422 257.422 367.25 249 367.25H25.75V336.75ZM25.75 373.75H249C257.422 373.75 264.25 380.578 264.25 389C264.25 397.422 257.422 404.25 249 404.25H25.75V373.75ZM25.75 441.25V410.75H249C257.422 410.75 264.25 417.578 264.25 426C264.25 434.422 257.422 441.25 249 441.25H25.75ZM25.75 447.75H249C257.422 447.75 264.25 454.578 264.25 463C264.25 471.422 257.422 478.25 249 478.25H25.75V447.75Z" fill="white" stroke="url(#paint5_linear_28_340)" stroke-width="1.5"/><path d="M0 15C0 6.71571 6.71573 0 15 0H30V500H15C6.71573 500 0 493.284 0 485V15Z" fill="#D9D9D9"/><path d="M0 15C0 6.71571 6.71573 0 15 0H30V500H15C6.71573 500 0 493.284 0 485V15Z" fill="url(#paint6_linear_28_340)"/><rect x="1" y="1" width="288" height="498" rx="14" stroke="url(#paint7_linear_28_340)" stroke-width="2"/></g>',
                "<defs>",
                '<filter id="filter0_f_28_340" x="18" y="37" width="253.538" height="425.707" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur stdDeviation="25" result="effect1_foregroundBlur_28_340"/></filter>',
                '<linearGradient id="paint0_linear_28_340" x1="4.50011" y1="499.5" x2="4.50021" y2="0.999959" gradientUnits="userSpaceOnUse"><stop stop-color="#6666FF"/><stop offset="1" stop-color="#FF66AD"/></linearGradient>',
                '<linearGradient id="paint1_linear_28_340" x1="129.498" y1="199.351" x2="152.328" y2="319.221" gradientUnits="userSpaceOnUse"><stop stop-color="#FFD2E7"/><stop offset="1" stop-color="#D2F2FF"/></linearGradient>'
                '<radialGradient id="paint2_radial_28_340" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(74.7589 10.4432) scale(251.05)"><stop stop-color="#FF66AD"/><stop offset="1" stop-color="#C9C9FF"/></radialGradient><radialGradient id="paint3_radial_28_340" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(324.54 347.11) scale(220.66 220.66)"><stop stop-color="#C9C9FF"/><stop offset="1" stop-color="#6666FF"/></radialGradient>',
                '<linearGradient id="paint4_linear_28_340" x1="145" y1="0" x2="145" y2="500" gradientUnits="userSpaceOnUse"><stop offset="0.125" stop-color="white"/><stop offset="0.479167" stop-color="white" stop-opacity="0"/><stop offset="0.479267" stop-color="white" stop-opacity="0"/><stop offset="0.90625" stop-color="white"/></linearGradient>',
                '<linearGradient id="paint5_linear_28_340" x1="23.9171" y1="463" x2="265.958" y2="463" gradientUnits="userSpaceOnUse"><stop stop-color="#6666FF"/><stop offset="1" stop-color="#FF66AD"/></linearGradient>',
                '<linearGradient id="paint6_linear_28_340" x1="0" y1="500" x2="0" y2="0" gradientUnits="userSpaceOnUse"><stop stop-color="#6666FF"/><stop offset="1" stop-color="#FF66AD"/></linearGradient>',
                '<linearGradient id="paint7_linear_28_340" x1="4.50011" y1="499.5" x2="4.50021" y2="0.999959" gradientUnits="userSpaceOnUse"><stop stop-color="#6666FF"/><stop offset="1" stop-color="#FF66AD"/></linearGradient>',
                '<clipPath id="clip0_28_340"><rect width="290" height="500" fill="white"/></clipPath>',
                "</defs>"
            )
        );
    }

    function generateCroAmountText(SVGParams memory params) internal pure returns (string memory svg) {
        uint256 fontSize = 20;

        // round down croAmount to the nearest 2 decimal place
        uint256 croAmountRounded = params.croAmount - (params.croAmount % 1e16);

        DecimalString.Result memory decimalString = DecimalString.decimalString(croAmountRounded, 18, false);

        if (decimalString.length < 12) {
            fontSize = 36;
        } else if (decimalString.length < 18) {
            fontSize = 25;
        }

        svg = string(
            abi.encodePacked(
                '<text y="50px" x="45px" fill="#1D0063" font-family="Arial" font-weight="800" font-size="36px" font-style="italic">CRO </text>',
                '<text y="90px" x="45px" fill="#1D0063" font-family="Arial" font-weight="800" font-size="',
                fontSize.toString(),
                'px" font-style="italic">',
                decimalString.result,
                "</text>"
            )
        );
    }

    function generateLiquidCroAmount(SVGParams memory params) internal pure returns (string memory svg) {
        uint256 fontSize = 10;

        // round down croAmount to the nearest 2 decimal place
        uint256 liquidCroAmountRounded = params.liquidCroAmount - (params.liquidCroAmount % 1e16);

        DecimalString.Result memory decimalString = DecimalString.decimalString(
            liquidCroAmountRounded,
            18,
            false
        );

        if (decimalString.length < 20) {
            fontSize = 12;
        } else if (decimalString.length < 22) {
            fontSize = 11;
        }

        svg = string(
            abi.encodePacked(
                '<text y="468px" x="45px" fill="black" font-family="Arial" font-weight="800" font-size="12px">LCRO amount:</text>',
                '<text y="468px" x="135px" fill="black" font-family="Arial" font-size="',
                fontSize.toString(),
                'px">',
                decimalString.result,
                "</text>"
            )
        );
    }

    function generateExchangeRateText(SVGParams memory params) internal pure returns (string memory svg) {
        svg = string(
            abi.encodePacked(
                '<text y="430px" x="45px" fill="black" font-family="Arial" font-weight="800" font-size="12px">Exchange rate:</text>',
                '<text y="430px" x="135px" fill="black" font-family="Arial" font-size="12px">',
                params.exchangeRate,
                " CRO",
                "</text>"
            )
        );
    }

    function generateNFTOwnerInfo(SVGParams memory params) internal pure returns (string memory svg) {
        svg = string(
            abi.encodePacked(
                '<text word-spacing="6px" x="75px" y="-10px" fill="#FFFFFF" font-family="Arial" transform="rotate(90)" font-size="13px" font-weight="700">',
                params.owner,
                " LCRO",
                "</text>"
            )
        );
    }

    function generateUnlockStartTime(SVGParams memory params) internal pure returns (string memory svg) {
        svg = string(
            abi.encodePacked(
                '<text y="355px" x="45px" fill="black" font-family="Arial" font-weight="800" font-size="12px">Mint date:</text>',
                '<text y="355px" x="105px" fill="black" font-family="Arial" font-size="12px">',
                params.unlockStartTime,
                "</text>"
            )
        );
    }

    function generateUnlockEndTime(SVGParams memory params) internal pure returns (string memory svg) {
        svg = string(
            abi.encodePacked(
                '<text y="393px" x="45px" fill="black" font-family="Arial" font-weight="800" font-size="12px">Unlock date:</text>',
                '<text y="393" x="120px" fill="black" font-family="Arial" font-size="12px">',
                params.unlockEndTime,
                "</text>"
            )
        );
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solidity-datetime/=lib/solidity-datetime/",
    "solidity-datetime/contracts/=lib/solidity-datetime/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {
    "src/libraries/NFTDescriptor.sol": {
      "NFTDescriptor": "0xbfd6ef07df5c5da0327c7988accf0ba100cf682b"
    }
  }
}

Contract ABI

[{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint128","name":"unlockStartTime","type":"uint128"},{"internalType":"uint128","name":"unlockEndTime","type":"uint128"},{"internalType":"uint256","name":"liquidCroAmount","type":"uint256"},{"internalType":"uint256","name":"liquidCro2CroExchangeRate","type":"uint256"},{"internalType":"uint8","name":"exchangeRateDecimal","type":"uint8"}],"internalType":"struct NFTDescriptor.ConstructTokenURIParams","name":"params","type":"tuple"}],"name":"constructTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]

61535661003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063c49917d71461003a575b600080fd5b61004d610048366004610f59565b610063565b60405161005a9190611032565b60405180910390f35b6060600061007083610175565b905060006100858260a0015160126000610276565b90506000816000015183606001516040516020016100a4929190611065565b604051602081830303815290604052905060006100c8846080015160126000610276565b905060006100e38460000151866060015187602001516104a2565b9050600061010385600001518460000151886060015189600001516104d1565b905060006101186101138861050b565b61051c565b90506101488584848460405160200161013494939291906110c8565b60405160208183030381529060405261051c565b60405160200161015891906111a6565b604051602081830303815290604052975050505050505050919050565b6101b56040518060e00160405280600081526020016060815260200160608152602001606081526020016000815260200160008152602001606081525090565b60006101ce83608001518460a001518560c0015161066f565b905060006101df84608001516106ba565b905060006101f78560a001518660c001516000610276565b60000151905060006040518060e001604052808760000151815260200161022188602001516106df565b815260200161023c88604001516001600160801b03166106f5565b815260200161025788606001516001600160801b03166106f5565b8152602081019490945260408401949094525060609091015292915050565b60408051808201909152606081526000602082015260008261029957600061029c565b60015b905060006102ab85600a6112e5565b9050856000805b82156103115760ff8116156102d357806102cb816112f4565b9150506102f1565b6102de600a84611329565b156102f157806102ed816112f4565b9150505b816102fb816112f4565b925061030a9050600a8461133d565b92506102b2565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915287151560e082015260ff89166103618385611351565b60ff16106103a157610373858b61133d565b815261037f8984611351565b60ff1660408201819052610394908790611374565b60ff166020820152610454565b6103ab8284611351565b6103b690600a6112e5565b6103c0908b61133d565b81528985111561042357600260808201526103db838a611351565b6103e6906002611374565b60ff1660a082018190526103fa9083611374565b60ff166040820181905261040f908790611374565b60ff166020820152600160c0820152610454565b61042e826001611374565b60ff1660408201526104408984611351565b61044b906001611374565b60ff1660608201525b8581604001516104649190611374565b60ff166020820152604080518082019091526000908061048384610751565b815260209384015160ff16930192909252509998505050505050505050565b60608383836040516020016104b993929190611399565b60405160208183030381529060405290509392505050565b60608385846104df85610994565b6040516020016104f29493929190611469565b6040516020818303038152906040529050949350505050565b606061051682610a9d565b92915050565b6060815160000361053b57505060408051602081019091526000815290565b60006040518060600160405280604081526020016152c1604091399050600060038451600261056a9190611540565b610574919061133d565b61057f906004611558565b67ffffffffffffffff81111561059757610597610eff565b6040519080825280601f01601f1916602001820160405280156105c1576020820181803683370190505b509050600182016020820185865187015b8082101561062d576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f81168501518453506001830192506105d2565b5050600386510660018114610649576002811461065c57610664565b603d6001830353603d6002830353610664565b603d60018303535b509195945050505050565b60008061067d83600a6112e5565b6106878587611558565b610691919061133d565b905060006106a6662386f26fc1000083611329565b6106b09083611577565b9695505050505050565b6000806106ce662386f26fc1000084611329565b6106d89084611577565b9392505050565b60606105166001600160a01b0383166014610b09565b6060600080600061070585610ca9565b92509250925061071483610994565b61071d83610994565b61072683610994565b6040516020016107389392919061158e565b6040516020818303038152906040529350505050919050565b60606000826020015160ff1667ffffffffffffffff81111561077557610775610eff565b6040519080825280601f01601f19166020018201604052801561079f576020820181803683370190505b5090508260e00151156107e857602560f81b81600183516107c09190611577565b815181106107d0576107d06115e8565b60200101906001600160f81b031916908160001a9053505b8260c001511561085157600360fc1b8160008151811061080a5761080a6115e8565b60200101906001600160f81b031916908160001a905350601760f91b81600181518110610839576108396115e8565b60200101906001600160f81b031916908160001a9053505b608083015160ff165b8360a0015160ff168110156108a957603060f81b828281518110610880576108806115e8565b60200101906001600160f81b031916908160001a905350806108a1816115fe565b91505061085a565b505b825115610516576000836060015160ff161180156108d65750826060015160ff16836040015160ff16145b1561091f57601760f91b818460400180516108f090611617565b60ff169081905281518110610907576109076115e8565b60200101906001600160f81b031916908160001a9053505b825161092d90600a90611329565b610938906030611540565b60f81b8184604001805161094b90611617565b60ff169081905281518110610962576109626115e8565b60200101906001600160f81b031916908160001a905350600a8360000181815161098c919061133d565b9052506108ab565b6060816000036109bb5750506040805180820190915260018152600360fc1b602082015290565b8160005b81156109e557806109cf816115fe565b91506109de9050600a8361133d565b91506109bf565b60008167ffffffffffffffff811115610a0057610a00610eff565b6040519080825280601f01601f191660200182016040528015610a2a576020820181803683370190505b5090505b8415610a9557610a3f600183611577565b9150610a4c600a86611329565b610a57906030611540565b60f81b818381518110610a6c57610a6c6115e8565b60200101906001600160f81b031916908160001a905350610a8e600a8661133d565b9450610a2e565b949350505050565b6060610aa7610cc8565b610ab083610ced565b610ab984610d7a565b610ac285610d91565b610acb86610da8565b610ad487610dbf565b610add88610e4c565b604051602001610af39796959493929190611634565b6040516020818303038152906040529050919050565b60606000610b18836002611558565b610b23906002611540565b67ffffffffffffffff811115610b3b57610b3b610eff565b6040519080825280601f01601f191660200182016040528015610b65576020820181803683370190505b509050600360fc1b81600081518110610b8057610b806115e8565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110610baf57610baf6115e8565b60200101906001600160f81b031916908160001a9053506000610bd3846002611558565b610bde906001611540565b90505b6001811115610c56576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110610c1257610c126115e8565b1a60f81b828281518110610c2857610c286115e8565b60200101906001600160f81b031916908160001a90535060049490941c93610c4f816116d4565b9050610be1565b5083156106d85760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640160405180910390fd5b60008080610cbb620151808504610e63565b9196909550909350915050565b6060604051602001610cd9906116eb565b604051602081830303815290604052905090565b60606000601490506000662386f26fc100008460a00151610d0e9190611329565b8460a00151610d1d9190611577565b90506000610d2e8260126000610276565b9050600c816020015160ff161015610d495760249250610d5e565b6012816020015160ff161015610d5e57601992505b610d6783610994565b8151604051610738929190602001614c48565b60608160400151604051602001610af39190614da3565b60608160600151604051602001610af39190614eab565b60608160c00151604051602001610af39190614f95565b60606000600a90506000662386f26fc100008460800151610de09190611329565b8460800151610def9190611577565b90506000610e008260126000610276565b90506014816020015160ff161015610e1b57600c9250610e30565b6016816020015160ff161015610e3057600b92505b610e3983610994565b81516040516107389291906020016150ae565b60608160200151604051602001610af391906151d8565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281610ec057610ec0611313565b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b634e487b7160e01b600052604160045260246000fd5b80356001600160a01b0381168114610f2c57600080fd5b919050565b80356001600160801b0381168114610f2c57600080fd5b803560ff81168114610f2c57600080fd5b600060e08284031215610f6b57600080fd5b60405160e0810181811067ffffffffffffffff82111715610f9c57634e487b7160e01b600052604160045260246000fd5b60405282358152610faf60208401610f15565b6020820152610fc060408401610f31565b6040820152610fd160608401610f31565b60608201526080830135608082015260a083013560a0820152610ff660c08401610f48565b60c08201529392505050565b60005b8381101561101d578181015183820152602001611005565b8381111561102c576000848401525b50505050565b6020815260008251806020840152611051816040850160208701611002565b601f01601f19169190910160400192915050565b7402b32b737902334b730b731b290169021b630b4b69605d1b815260008351611095816015850160208801611002565b6601021a9279020160cd1b60159184019182015283516110bc81601c840160208801611002565b01601c01949350505050565b683d913730b6b2911d1160b91b815284516000906110ed816009850160208a01611002565b71111610113232b9b1b934b83a34b7b7111d1160711b600991840191820152855161111f81601b840160208a01611002565b855191019061113581601b840160208901611002565b6c1116101134b6b0b3b2911d101160991b601b92909101918201527f646174613a696d6167652f7376672b786d6c3b6261736536342c00000000000060288201528351611189816042840160208801611002565b61227d60f01b604292909101918201526044019695505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516111de81601d850160208701611002565b91909101601d0192915050565b634e487b7160e01b600052601160045260246000fd5b600181815b8085111561123c578160001904821115611222576112226111eb565b8085161561122f57918102915b93841c9390800290611206565b509250929050565b60008261125357506001610516565b8161126057506000610516565b816001811461127657600281146112805761129c565b6001915050610516565b60ff841115611291576112916111eb565b50506001821b610516565b5060208310610133831016604e8410600b84101617156112bf575081810a610516565b6112c98383611201565b80600019048211156112dd576112dd6111eb565b029392505050565b60006106d860ff841683611244565b600060ff821660ff810361130a5761130a6111eb565b60010192915050565b634e487b7160e01b600052601260045260246000fd5b60008261133857611338611313565b500690565b60008261134c5761134c611313565b500490565b600060ff821660ff84168082101561136b5761136b6111eb565b90039392505050565b600060ff821660ff84168060ff03821115611391576113916111eb565b019392505050565b7f54686973204e465420726570726573656e7473206120636c61696d20746f20008152600084516113d181601f850160208901611002565b7f2043524f20746861742077696c6c20626520617661696c61626c652061667465601f9184019182015261039160f51b603f8201528451611419816041840160208901611002565b808201915050612e3760f11b8060418301526d02621a9279020b2323932b9b99d160951b60438301528451611455816051850160208901611002565b605192019182015260530195945050505050565b6c02621a92790313ab93732b21d1609d1b81526000855161149181600d850160208a01611002565b8083019050612e3760f11b80600d8301526d021a927903a379031b630b4b69d160951b600f83015286516114cc81601d850160208b01611002565b601d920191820181905272022b9ba17103ab73137bab732103230ba329d1606d1b601f8301528551611505816032850160208a01611002565b60329201918201526802a37b5b2b724b21d160bd1b6034820152835161153281603d840160208801611002565b01603d019695505050505050565b60008219821115611553576115536111eb565b500190565b6000816000190483118215151615611572576115726111eb565b500290565b600082821015611589576115896111eb565b500390565b600084516115a0818460208901611002565b8083019050602f60f81b80825285516115c0816001850160208a01611002565b600192019182015283516115db816002840160208801611002565b0160020195945050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201611610576116106111eb565b5060010190565b600060ff82168061162a5761162a6111eb565b6000190192915050565b6000885160206116478285838e01611002565b89519184019161165a8184848e01611002565b895192019161166c8184848d01611002565b885192019161167e8184848c01611002565b87519201916116908184848b01611002565b86519201916116a28184848a01611002565b85519201916116b48184848901611002565b651e17b9bb339f60d11b9201918252506006019998505050505050505050565b6000816116e3576116e36111eb565b506000190190565b7f3c7376672077696474683d2232393022206865696768743d223530302220766981527f6577426f783d223020302032393020353030222066696c6c3d226e6f6e65222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f67223e3c6720636c69702d706174683d2275726c2823636c6970305f32385f3360608201527f343029223e3c726563742077696474683d2232393022206865696768743d223560808201527f3030222066696c6c3d227768697465222f3e3c7265637420783d22302e35222060a08201527f793d22302e35222077696474683d2232383922206865696768743d223439392260c08201527f2072783d2231342e35222066696c6c3d22776869746522207374726f6b653d2260e08201527f75726c28237061696e74305f6c696e6561725f32385f33343029222f3e3c67206101008201527f66696c7465723d2275726c282366696c746572305f665f32385f33343029223e6101208201527f3c7061746820643d224d3137302e353738203234352e393431433137342e37386101408201527f38203233342e303931203137362e363338203231392e323231203137342e31316101608201527f38203230312e313031433137382e333038203136362e303931203138342e34346101808201527f38203132302e353531203135312e343538203130342e343231433134302e37316101a08201527f382039392e36383036203133322e3237382039302e32303036203132312e35336101c08201527f382038372e33353036433131332e3836382038342e35303036203131302e30326101e08201527f382039392e36383036203131332e303938203130392e313731433131362e39336102008201527f38203131392e363131203132342e363038203132392e303931203132332e38336102208201527f38203134312e343331433132322e333038203135332e373631203131312e35356102408201527f38203135332e373631203130342e353738203135382e3038314336312e3033386102608201527f33203137332e3233312035372e37363833203234332e3332312038372e3333386102808201527f33203237302e3337314339332e32373833203237352e383031203130302e32376102a08201527f38203237392e323731203130372e353938203238312e313531433130382e36346102c08201527f38203239392e323531203131322e363238203331362e333531203131372e39326102e08201527f38203333332e393431433132352e333538203336312e3334312038332e3930386103008201527f33203430392e323431203130312e353938203431312e383231433133332e38316103208201527f38203431382e343631203136352e323738203338362e323031203139362e32356103408201527f38203336382e333931433234312e323538203333332e333331203232322e31366103608201527f38203234382e373331203137302e353738203234352e393531563234352e39346103808201527f315a222066696c6c3d2275726c28237061696e74315f6c696e6561725f32385f6103a08201527f33343029222f3e3c2f673e3c7061746820643d224d302e3137383839342032396103c08201527f382e30363343362e3037383839203239322e3431332031322e333538392032386103e08201527f372e3132332031372e34343839203238312e3730334336312e303838392032336104008201527f352e3232332032362e33393839203233362e36393320302e31373838393420326104208201527f31312e313433563231372e3234334332352e37353839203234302e33383320356104408201527f382e36373839203233382e34303320332e3732383839203238382e363233432d6104608201527f302e373431313036203239322e37303320302e313738383934203239302e36376104808201527f3320302e313738383934203239382e303633563239382e3036335a4d3139342e6104a08201527f373339203134342e393233433230312e323439203131342e353033203137382e6104c08201527f3638392038372e32393332203138342e3238392035382e31343332433138392e6104e08201527f3634392033302e32373332203232372e3030392031332e37323332203234392e6105008201527f33333920302e313333323035433234342e33313920302e3133333230352032346105208201527f372e333439202d302e383736373935203233362e36343920352e3139333231436105408201527f3231342e3930392031372e35343332203138372e3032392033332e33353332206105608201527f3138322e3332392035372e37363332433137362e3632392038372e34333332206105808201527f3139392e313339203131342e383233203139322e373839203134342e343933436105a08201527f3138362e333639203137342e353033203136322e333139203138382e313433206105c08201527f3132332e333439203136382e3432334336312e36393839203133372e323533206105e08201527f31362e383938392037362e3036333220342e333438383920342e3737333231436106008201527f332e373338383920352e343133323120332e313738383920362e3039333231206106208201527f322e363838383920362e38333332314332342e34313839203133362e333533206106408201527f3137352e373139203233332e383233203139342e373339203134342e3932335a6106608201527f4d3135342e3136392039332e30343332433136352e3231392035392e373133326106808201527f203132362e3632392033362e35323332203138302e36363920302e31333332306106a08201527f35483137332e363439433132352e3038392033352e31323332203136302e30376106c08201527f392036322e35313332203135302e3337392039312e37383332433134342e30346106e08201527f39203131302e383933203132382e373339203131382e383533203130322e32336107008201527f39203130342e3533334336322e383938392038332e333333322033342e3039386107208201527f392034342e373633322032332e3133383920302e3133333230354331382e31316107408201527f383920302e3133333230352031382e35313839202d312e33313637392032302e6107608201527f3435383920352e37343332314334322e323138392038342e36363332203133346107808201527f2e343039203135322e363833203135342e3136392039332e303433325a4d302e6107a08201527f313738383934203234302e333633563236352e39343343352e393638383920326107c08201527f35372e30363320372e3733383839203234372e38303320302e313738383934206107e08201527f3234302e3336335a4d3137342e343639203131382e393433433138352e3033396108008201527f2037382e32383332203133352e3832392034382e37323332203230342e3431396108208201527f20362e3230333231433231362e373139202d312e3433363739203231362e36356108408201527f3920302e313333323035203230382e36323920302e313333323035433132392e6108608201527f3630392034372e35313332203138322e3138392037372e33353332203137312e6108808201527f353639203131382e313833433135332e393639203138352e3834332034342e346108a08201527f303839203131312e3936332031372e323938392031372e343133324331322e336108c08201527f33383920302e3130333230352031342e36353839202d302e35333637393520316108e08201527f302e3237383920302e3937333230354333312e33333839203130392e363133206109008201527f3135342e393439203139332e393933203137342e343639203131382e3934335a6109208201527f4d3133332e3739392036372e33303332433134332e3836392034352e323333326109408201527f203132322e3038392032352e31393332203134392e37323920302e31343332306109608201527f35483134322e353539433131382e3836392032342e38383332203133372e37326109808201527f392034362e36333332203132392e3234392036352e32333332433132322e39346109a08201527f392037392e30353332203131312e3931392038342e313533322039312e3731386109c08201527f392037322e363133324336342e363438392035372e323033322034332e3836386109e08201527f392033312e303833322033332e3734383920302e3133333230354832382e3438610a008201527f38394334342e333838392035302e37353332203131322e313039203131342e38610a208201527f3733203133332e3739392036372e323933325636372e333033325a4d3238312e610a408201527f37393920312e3639333231433238312e36393920312e3634333231203238302e610a608201527f37353920312e3135333231203238302e36353920312e3231333231433231322e610a808201527f3536392034322e30343332203138322e3933392034382e32343332203230352e610aa08201527f373339203131392e333633433231302e393939203133352e373633203231372e610ac08201527f323539203135322e393233203231342e303139203137302e373833433139362e610ae08201527f333439203236372e3935332033352e36353839203137312e34333320302e3137610b008201527f383839342033312e3733333243302e3137383839342034382e35383332203335610b208201527f2e35363839203135342e333433203133322e373839203230322e303933433137610b408201527f382e373839203232342e363933203230392e313739203230372e383733203231610b608201527f352e373239203137312e383833433231392e303139203135332e373733203231610b808201527f332e353639203133362e343833203230382e323739203131392e393633433138610ba08201527f352e3336392034382e35323332203231342e3733392034312e39313332203238610bc08201527f312e37393920312e363933323156312e36393332315a4d32392e363838392031610be08201527f32352e3531334332312e33303839203130372e3836332031332e343538392038610c008201527f382e3639333220302e3137383839342037352e3234333243302e313738383934610c208201527f2038302e3635333220332e39323838392037332e323233322032322e35383839610c408201527f203131352e3336334334302e30313839203135342e3730332036302e38313839610c608201527f203138322e383133203131322e303839203230392e363333433135332e353539610c808201527f203233312e333333203133322e383939203236322e3231332039372e30353839610ca08201527f203239322e3330334333382e36373839203334312e3332332031382e36333839610cc08201527f203335312e3834332033312e38343839203431302e3331334333392e31393839610ce08201527f203434322e3837332034372e33333839203438302e3731332033372e33393839610d008201527f203530302e3133334833382e343938394335302e39363839203437342e363733610d208201527f2033322e32393839203431392e3835332032392e33333839203338372e333333610d408201527f4332332e36383839203332352e323733203132312e383839203239372e323933610d608201527f203133352e313139203234362e343733433134362e393939203230302e383133610d808201527f2037312e37383839203231342e3139332032392e36383839203132352e353033610da08201527f563132352e3531335a4d302e313738383934203433332e34333343382e373438610dc08201527f3839203432312e33313320352e3032383839203339392e30383320312e303938610de08201527f3839203337352e353533432d302e313331313036203336382e31373320302e31610e008201527f3738383934203336332e39353320302e313738383934203339302e3936334334610e208201527f2e3337383839203432302e30393320302e313738383934203431382e33383320610e408201527f302e313738383934203433332e343433563433332e3433335a4d3130322e3837610e608201527f39203234372e313633433131302e383539203230392e3137332034382e333638610e808201527f39203232302e3338332031322e37333839203134352e38303343382e35353838610ea08201527f39203133372e30363320342e3833383839203132372e37323320302e31373838610ec08201527f3934203131392e30333343302e313738383934203132352e343933202d302e38610ee08201527f3531313036203132302e39353320362e3234383839203133362e383133433437610f008201527f2e31313839203232382e313333203131302e313939203230382e373133203130610f208201527f302e343639203234382e3030334339352e38353839203236362e353633203732610f408201527f2e36363839203238362e3233332035332e30373839203330322e36343343342e610f608201527f36363839203334332e32303320382e3031383839203335352e3938332031362e610f808201527f30303839203339392e3239334332322e37343839203433352e3831332032392e610fa08201527f35313839203437322e31333320302e383438383934203437362e303633432d30610fc08201527f2e30343131303539203437362e31383320302e313738383934203437352e3636610fe08201527f3320302e313738383934203437382e3330334333362e30353839203437342e386110008201527f37332032322e35343839203432342e3038332031362e32373839203338382e366110208201527f39334331322e33383839203336362e3736332031302e30373839203335312e376110408201527f36332032362e32393839203333312e3236334334362e39373839203330352e316110608201527f31332039362e34353839203237372e373833203130322e383739203234372e316110808201527f3533563234372e3136335a4d37302e32363839203234392e3431334337362e326110a08201527f393839203231382e3934332033302e34373839203232352e39313320302e31376110c08201527f38383934203137312e363833563137382e3234334331312e39343839203139376110e08201527f2e3139332032382e34313839203231322e3036332035322e31323839203232356111008201527f2e333933433130312e313839203235322e3939332031382e32323839203239336111208201527f2e36323320302e313738383934203332362e31363343302e31373838393420336111408201527f34302e383833202d312e3932313131203333332e30323320382e3236383839206111608201527f3332302e3034334332342e37353839203239382e3939332036352e32393839206111808201527f3237342e3831332037302e32363839203234392e343033563234392e3431335a6111a08201527f222066696c6c3d2275726c28237061696e74325f72616469616c5f32385f33346111c08201527f3029222f3e3c7061746820643d224d3134302e393433203237312e36333243316111e08201527f36362e333733203231392e383232203138382e393732203233322e34333220326112008201527f31312e353832203231372e3034324c3138302e353733203138362e30323343316112208201527f36302e353433203136352e393933203132382e303533203136352e39393320316112408201527f30382e303233203138362e3032334338372e39393235203230362e30353320386112608201527f372e39393235203233382e353433203130382e303233203235382e3537334c316112808201527f33332e383832203238342e343333433133362e333132203238302e35313320316112a08201527f33382e363832203237362e323632203134302e393532203237312e36333248316112c08201527f34302e3934335a222066696c6c3d227768697465222f3e3c7061746820643d226112e08201527f4d3232352e3639203434362e3736433232302e3839203432392e3133203230396113008201527f2e32203431382e3131203137382e3637203339352e39433136332e35372033386113208201527f342e3932203134302e3235203337362e3036203131392e3637203336382e32356113408201527f4337372e3132203335322e30392036392e3135203334382e382039382e3536206113608201527f3332342e3932433135382e3231203237362e3438203133352e3935203234342e6113808201527f3535203138392e3537203232372e3632433237332e3338203230312e313620326113a08201527f31302e3139203130372e3838203231302e30312038312e31433230392e3737206113c08201527f34362e3733203234352e32312031382e3438203237382e372031322e373443336113e08201527f30372e343820372e3830393939203236302e393220382e3034203233302e36356114008201527f2033352e3034433231352e38342034382e3235203230372e37352036342e34346114208201527f203230372e38362038302e3634433230372e39332039302e3537203231312e316114408201527f382039382e3331203231352e3331203130382e3131433233312e3239203134366114608201527f2e31203234332e3434203139342e3339203230392e3135203231372e323543316114808201527f38362e3831203233322e3134203136332e3938203232302e3734203133382e366114a08201527f203237322e3434433131342e32203332322e31342037382e3533203332382e336114c08201527f2037392e3534203334372e36334338302e32203336302e3431203134362e38376114e08201527f20333734203137382e31203339362e3732433230382e3432203431382e3737206115008201527f3232302e3033203432392e3639203232342e3735203434372e3033433232392e6115208201527f3334203436332e3931203233322e3732203437342e3537203234302e383720346115408201527f38302e3336433235322e3531203438382e3634203238382e3231203438362e356115608201527f33203238382e3231203438342e3331433233372e3539203438392e30342032336115808201527f342e34203437382e3635203232352e3732203434362e37374c3232352e3639206115a08201527f3434362e37365a4d3238382e31382037392e35335637362e3433433236392e326115c08201527f382038352e3435203235332e3432203130322e3337203235332e3032203132326115e08201527f2e3835433235322e3636203134302e39203239302e3033203230322e373420326116008201527f35322e3639203232392e3333433233352e3933203234312e3237203231382e356116208201527f34203233332e3333203139392e3333203237332e3436433138312e30312033316116408201527f312e3432203135342e32203331362e33203135352e3039203333322e323243316116608201527f35362e3032203334372e3938203234382e35203335372e3936203236372e32396116808201527f203431352e3938433237322e3038203433302e3736203237362e3531203433376116a08201527f2e3138203238382e3138203433392e3133563433362e3436433237382e3534206116c08201527f3433342e3635203237342e3338203432382e3931203236392e3931203431352e6116e08201527f3134433235302e3839203335362e3438203135382e3538203334342e372031356117008201527f372e3834203333322e3036433135372e3038203331382e3431203138332e36326117208201527f203331322e3335203230312e3831203237342e3635433232302e3031203233366117408201527f2e3633203233372e37203234332e3339203235342e3238203233312e353743326117608201527f39332e3638203230332e35203235352e3431203134302e3331203235352e37366117808201527f203132322e39433235362e3133203130342e34203237302e35352038382e33396117a08201527f203238382e31372037392e3533483238382e31385a4d3234382e3831203433346117c08201527f2e3535433234332e35203431372e3233203234332e3132203431302e373520326117e08201527f30352e31203338322e3738433137382e3635203336332e3239203131392e37326118008201527f203334392e37203131392e3138203333392e3831433131382e3332203332332e6118208201527f3739203134392e3431203331372e3335203137302e3635203237332e373643316118408201527f39322e3534203232382e3637203231322e3033203233382e3833203233312e396118608201527f32203232352e3136433237372e3338203139342e3032203233322e32352031326118808201527f312e3637203233322e3331203130312e3736433233322e352037332e343320326118a08201527f36302e36342035302e3539203238382e31382034332e3933563432433235392e6118c08201527f34372034382e3737203233302e36332037322e3439203233302e3433203130316118e08201527f2e3735433233302e3335203132362e3739203238352e33203230382e303520326119008201527f31332e3136203233312e3439433136342e3637203234372e3235203138332e366119208201527f38203237332e3838203133322e3336203331382e3336433130342e31372033346119408201527f322e3739203131372e3633203334362e32203135322e3838203335392e3943316119608201527f37302e3733203336362e3833203139302e3936203337342e3639203230332e396119808201527f39203338342e33433233302e3537203430332e3835203234302e3738203431336119a08201527f2e3531203234352e3136203432382e3737433235322e3534203435342e3532206119c08201527f3235362e3632203436332e3031203238322e3838203436332e3031433238382e6119e08201527f3932203436332e3031203238382e3139203436332e3435203238382e31392034611a008201527f36312e3032433236302e3035203436312e3839203235352e3238203435352e38611a208201527f35203234382e3832203433342e35364c3234382e3831203433342e35355a4d32611a408201527f35372e3939203335362e3536433233392e3438203334322e3335203139362e39611a608201527f31203333302e39203139362e3531203332342e33433139352e3832203331332e611a808201527f3034203231372e3937203330372e3333203233322e3939203237352e35344332611aa08201527f35322e3731203233332e38203237352e3239203235322e3036203238382e3139611ac08201527f203232342e3132433239322e3438203231342e383220323933203230322e3836611ae08201527f203239302e3038203138362e39433238382e3832203138302e3032203238382e611b008201527f3335203137352e3335203238382e32203137392e3439433238382e3220313738611b208201527f2e3939203238382e32203137382e35203238382e32203137372e393843323833611b408201527f2e3438203135382e33203237302e3636203134332e3335203238382e32203132611b608201527f322e3333563131362e3835433237322e38203133322e3532203237332e393320611b808201527f3134362e3938203237392e3739203136332e33433238352e3231203137382e34611ba08201527f203238372e3338203139322e37203238382e3136203139382e3732433238382e611bc08201527f3136203230312e3436203238382e3138203230342e3531203238382e31382032611be08201527f30372e39433238372e32203232362e33203237372e39203233352e3135203236611c008201527f322e3035203234312e3437433232372e3536203235352e3234203233392e3038611c208201527f203237342e3933203230342e3233203330362e3935433138332e303820333236611c408201527f2e3338203139322e373520333330203231392e3933203334312e33433233322e611c608201527f3436203334362e3531203234362e3636203335322e3432203235352e38203335611c808201527f392e3434433238342e3637203338312e3434203238332e3532203338352e3837611ca08201527f203238382e32203339382e3535433238382e32203338372e31203239312e3820611cc08201527f3338322e333120323538203335362e3536483235372e39395a4d3234332e3234611ce08201527f203330342e3439433237322e3333203237362e3432203236312e333920323633611d008201527f2e3033203238382e3138203235302e3633433238382e3138203234342e363520611d208201527f3238382e3738203234352e34203238362e3339203234362e35433237382e3031611d408201527f203235302e3338203236392e3335203235342e3339203236302e303720323734611d608201527f2e3531433234382e3034203330302e3632203232392e3835203330342e343920611d808201527f3233302e3637203331362e3832433233312e3334203332362e3933203236332e611da08201527f3438203333312e3638203238382e3138203335322e3236563334362e34344332611dc08201527f37382e33203333382e3433203237322e3731203333352e3632203235352e3236611de08201527f203332372e3934433233312e39203331372e3636203233302e32203331372e30611e008201527f37203234332e3234203330342e3439563330342e34395a4d3237352e39352032611e208201527f39352e3538433236312e3233203331302e3932203236392e3235203331342e33611e408201527f34203238382e3138203332332e3432563331372e3436433236342e3232203330611e608201527f352e3936203237332e3837203330392e3138203238382e3138203238392e3635611e808201527f433238382e3138203237322e3731203239312e3335203237392e353520323735611ea08201527f2e3935203239352e3539563239352e35385a222066696c6c3d2275726c282370611ec08201527f61696e74335f72616469616c5f32385f33343029222f3e3c7265637420776964611ee08201527f74683d2232393022206865696768743d22353030222072783d22313522206669611f008201527f6c6c3d2275726c28237061696e74345f6c696e6561725f32385f33343029222f611f208201527f3e3c7061746820643d224d32352e3735203333362e373548323439433235372e611f408201527f343232203333362e3735203236342e3235203334332e353738203236342e3235611f608201527f20333532433236342e3235203336302e343232203235372e343232203336372e611f808201527f323520323439203336372e32354832352e3735563333362e37355a4d32352e37611fa08201527f35203337332e373548323439433235372e343232203337332e3735203236342e611fc08201527f3235203338302e353738203236342e323520333839433236342e323520333937611fe08201527f2e343232203235372e343232203430342e323520323439203430342e323548326120008201527f352e3735563337332e37355a4d32352e3735203434312e3235563431302e37356120208201527f48323439433235372e343232203431302e3735203236342e3235203431372e356120408201527f3738203236342e323520343236433236342e3235203433342e343232203235376120608201527f2e343232203434312e323520323439203434312e32354832352e37355a4d32356120808201527f2e3735203434372e373548323439433235372e343232203434372e37352032366120a08201527f342e3235203435342e353738203236342e323520343633433236342e323520346120c08201527f37312e343232203235372e343232203437382e323520323439203437382e32356120e08201527f4832352e3735563434372e37355a222066696c6c3d22776869746522207374726121008201527f6f6b653d2275726c28237061696e74355f6c696e6561725f32385f33343029226121208201527f207374726f6b652d77696474683d22312e35222f3e3c7061746820643d224d306121408201527f203135433020362e373135373120362e373135373320302031352030483330566121608201527f35303048313543362e3731353733203530302030203439332e323834203020346121808201527f38355631355a222066696c6c3d2223443944394439222f3e3c7061746820643d6121a08201527f224d30203135433020362e373135373120362e373135373320302031352030486121c08201527f33305635303048313543362e3731353733203530302030203439332e323834206121e08201527f30203438355631355a222066696c6c3d2275726c28237061696e74365f6c696e6122008201527f6561725f32385f33343029222f3e3c7265637420783d22312220793d223122206122208201527f77696474683d2232383822206865696768743d22343938222072783d223134226122408201527f207374726f6b653d2275726c28237061696e74375f6c696e6561725f32385f336122608201527f34302922207374726f6b652d77696474683d2232222f3e3c2f673e0000000000612280820152651e3232b3399f60d11b61229b8201527f3c66696c7465722069643d2266696c746572305f665f32385f3334302220783d6122a18201527f2231382220793d223337222077696474683d223235332e3533382220686569676122c18201527f68743d223432352e373037222066696c746572556e6974733d227573657253706122e18201527f6163654f6e5573652220636f6c6f722d696e746572706f6c6174696f6e2d66696123018201527f6c746572733d2273524742223e3c6665466c6f6f6420666c6f6f642d6f7061636123218201527f6974793d22302220726573756c743d224261636b67726f756e64496d616765466123418201527f6978222f3e3c6665426c656e64206d6f64653d226e6f726d616c2220696e3d226123618201527f536f75726365477261706869632220696e323d224261636b67726f756e64496d6123818201527f6167654669782220726573756c743d227368617065222f3e3c666547617573736123a18201527f69616e426c757220737464446576696174696f6e3d2232352220726573756c746123c18201527f3d22656666656374315f666f726567726f756e64426c75725f32385f333430226123e18201526a179f1e17b334b63a32b91f60a91b6124018201527f3c6c696e6561724772616469656e742069643d227061696e74305f6c696e656161240c8201527f725f32385f333430222078313d22342e3530303131222079313d223439392e3561242c8201527f222078323d22342e3530303231222079323d22302e393939393539222067726161244c8201527f6469656e74556e6974733d227573657253706163654f6e557365223e3c73746f61246c8201527f702073746f702d636f6c6f723d2223363636364646222f3e3c73746f70206f6661248c8201527f667365743d2231222073746f702d636f6c6f723d2223464636364144222f3e3c6124ac8201526f17b634b732b0b923b930b234b2b73a1f60811b6124cc8201527f3c6c696e6561724772616469656e742069643d227061696e74315f6c696e65616124dc8201527f725f32385f333430222078313d223132392e343938222079313d223139392e336124fc8201527f3531222078323d223135322e333238222079323d223331392e3232312220677261251c8201527f616469656e74556e6974733d227573657253706163654f6e557365223e3c737461253c8201527f6f702073746f702d636f6c6f723d2223464644324537222f3e3c73746f70206f61255c8201527f66667365743d2231222073746f702d636f6c6f723d2223443246324646222f3e61257c8201527f3c2f6c696e6561724772616469656e743e3c72616469616c4772616469656e7461259c8201527f2069643d227061696e74325f72616469616c5f32385f333430222063783d22306125bc8201527f222063793d22302220723d223122206772616469656e74556e6974733d2275736125dc8201527f657253706163654f6e55736522206772616469656e745472616e73666f726d3d6125fc8201527f227472616e736c6174652837342e373538392031302e3434333229207363616c61261c8201527f65283235312e303529223e3c73746f702073746f702d636f6c6f723d2223464661263c8201527f36364144222f3e3c73746f70206f66667365743d2231222073746f702d636f6c61265c8201527f6f723d2223433943394646222f3e3c2f72616469616c4772616469656e743e3c61267c8201527f72616469616c4772616469656e742069643d227061696e74335f72616469616c61269c8201527f5f32385f333430222063783d2230222063793d22302220723d223122206772616126bc8201527f6469656e74556e6974733d227573657253706163654f6e5573652220677261646126dc8201527f69656e745472616e73666f726d3d227472616e736c617465283332342e3534206126fc8201527f3334372e313129207363616c65283232302e3636203232302e363629223e3c7361271c8201527f746f702073746f702d636f6c6f723d2223433943394646222f3e3c73746f702061273c8201527f6f66667365743d2231222073746f702d636f6c6f723d2223363636364646222f61275c820152711f1e17b930b234b0b623b930b234b2b73a1f60711b61277c8201527f3c6c696e6561724772616469656e742069643d227061696e74345f6c696e656161278e8201527f725f32385f333430222078313d22313435222079313d2230222078323d2231346127ae8201527f35222079323d2235303022206772616469656e74556e6974733d2275736572536127ce8201527f706163654f6e557365223e3c73746f70206f66667365743d22302e31323522206127ee8201527f73746f702d636f6c6f723d227768697465222f3e3c73746f70206f666673657461280e8201527f3d22302e343739313637222073746f702d636f6c6f723d22776869746522207361282e8201527f746f702d6f7061636974793d2230222f3e3c73746f70206f66667365743d223061284e8201527f2e343739323637222073746f702d636f6c6f723d227768697465222073746f7061286e8201527f2d6f7061636974793d2230222f3e3c73746f70206f66667365743d22302e393061288e8201527f363235222073746f702d636f6c6f723d227768697465222f3e3c2f6c696e65616128ae820152693923b930b234b2b73a1f60b11b6128ce8201527f3c6c696e6561724772616469656e742069643d227061696e74355f6c696e65616128d88201527f725f32385f333430222078313d2232332e39313731222079313d2234363322206128f88201527f78323d223236352e393538222079323d2234363322206772616469656e74556e6129188201527f6974733d227573657253706163654f6e557365223e3c73746f702073746f702d6129388201527f636f6c6f723d2223363636364646222f3e3c73746f70206f66667365743d22316129588201527f222073746f702d636f6c6f723d2223464636364144222f3e3c2f6c696e6561726129788201526823b930b234b2b73a1f60b91b6129988201527f3c6c696e6561724772616469656e742069643d227061696e74365f6c696e65616129a18201527f725f32385f333430222078313d2230222079313d22353030222078323d2230226129c18201527f2079323d223022206772616469656e74556e6974733d227573657253706163656129e18201527f4f6e557365223e3c73746f702073746f702d636f6c6f723d2223363636364646612a018201527f222f3e3c73746f70206f66667365743d2231222073746f702d636f6c6f723d22612a218201527f23464636364144222f3e3c2f6c696e6561724772616469656e743e0000000000612a418201526000610516614c35614bc9612a5c85017f3c6c696e6561724772616469656e742069643d227061696e74375f6c696e656181527f725f32385f333430222078313d22342e3530303131222079313d223439392e3560208201527f222078323d22342e3530303231222079323d22302e393939393539222067726160408201527f6469656e74556e6974733d227573657253706163654f6e557365223e3c73746f60608201527f702073746f702d636f6c6f723d2223363636364646222f3e3c73746f70206f6660808201527f667365743d2231222073746f702d636f6c6f723d2223464636364144222f3e3c60a08201526f17b634b732b0b923b930b234b2b73a1f60811b60c082015260d00190565b7f3c636c6970506174682069643d22636c6970305f32385f333430223e3c72656381527f742077696474683d2232393022206865696768743d22353030222066696c6c3d602082015273113bb434ba3291179f1e17b1b634b82830ba341f60611b604082015260540190565b661e17b232b3399f60c91b815260070190565b7f3c7465787420793d22353070782220783d2234357078222066696c6c3d222331815260007f44303036332220666f6e742d66616d696c793d22417269616c2220666f6e742d8060208401527f7765696768743d223830302220666f6e742d73697a653d22333670782220666f60408401527f6e742d7374796c653d226974616c6963223e43524f203c2f746578743e00000060608401527f3c7465787420793d22393070782220783d2234357078222066696c6c3d222331607d84015280609d840152507f7765696768743d223830302220666f6e742d73697a653d22000000000000000060bd8301528351614d468160d5850160208801611002565b7f70782220666f6e742d7374796c653d226974616c6963223e000000000000000060d5918401918201528351614d838160ed840160208801611002565b661e17ba32bc3a1f60c91b60ed929091019182015260f401949350505050565b7f3c7465787420793d2233353570782220783d2234357078222066696c6c3d2262815260008051602061530183398151915260208201527f65696768743d223830302220666f6e742d73697a653d2231327078223e4d696e60408201526d3a103230ba329d1e17ba32bc3a1f60911b60608201527f3c7465787420793d2233353570782220783d223130357078222066696c6c3d22606e8201527f626c61636b2220666f6e742d66616d696c793d22417269616c2220666f6e742d608e8201526b39b4bd329e911899383c111f60a11b60ae82015260008251614e8d8160ba850160208701611002565b661e17ba32bc3a1f60c91b60ba93909101928301525060c101919050565b7f3c7465787420793d2233393370782220783d2234357078222066696c6c3d2262815260008051602061530183398151915260208201527f65696768743d223830302220666f6e742d73697a653d2231327078223e556e6c60408201526f37b1b5903230ba329d1e17ba32bc3a1f60811b60608201527f3c7465787420793d223339332220783d223132307078222066696c6c3d22626c60708201527f61636b2220666f6e742d66616d696c793d22417269616c2220666f6e742d73696090820152693d329e911899383c111f60b11b60b082015260008251614e8d8160ba850160208701611002565b7f3c7465787420793d2234333070782220783d2234357078222066696c6c3d2262815260008051602061530183398151915260208201527f65696768743d223830302220666f6e742d73697a653d2231327078223e4578636040820152713430b733b2903930ba329d1e17ba32bc3a1f60711b60608201527f3c7465787420793d2234333070782220783d223133357078222066696c6c3d2260728201527f626c61636b2220666f6e742d66616d696c793d22417269616c2220666f6e742d60928201526b39b4bd329e911899383c111f60a11b60b2820152600082516150838160be850160208701611002565b632043524f60e01b60be939091019283015250661e17ba32bc3a1f60c91b60c282015260c901919050565b7f3c7465787420793d2234363870782220783d2234357078222066696c6c3d2262815260008051602061530183398151915260208201527f65696768743d223830302220666f6e742d73697a653d2231327078223e4c435260408201526f279030b6b7bab73a1d1e17ba32bc3a1f60811b60608201527f3c7465787420793d2234363870782220783d223133357078222066696c6c3d2260708201527f626c61636b2220666f6e742d66616d696c793d22417269616c2220666f6e742d60908201526539b4bd329e9160d11b60b0820152600083516151948160b6850160208801611002565b63383c111f60e11b60b69184019182015283516151b88160ba840160208801611002565b661e17ba32bc3a1f60c91b60ba929091019182015260c101949350505050565b7f3c7465787420776f72642d73706163696e673d223670782220783d223735707881527f2220793d222d31307078222066696c6c3d22234646464646462220666f6e742d60208201527f66616d696c793d22417269616c22207472616e73666f726d3d22726f7461746560408201527f283930292220666f6e742d73697a653d22313370782220666f6e742d77656967606082015268343a1e911b9818111f60b91b608082015260008251615294816089850160208701611002565b64204c43524f60d81b6089939091019283015250661e17ba32bc3a1f60c91b608e82015260950191905056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6c61636b2220666f6e742d66616d696c793d22417269616c2220666f6e742d77a2646970667358221220d4a2a354a11173635d72bdd12b14675f0c5bce0aa2ebe5e3683fb822e21d9af264736f6c634300080f0033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.