ETH Price: $3,358.13 (+4.29%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Multicall215295392025-01-01 12:12:4730 days ago1735733567IN
0xcccbdaeA...cC9a815C0
0 ETH0.0128595114.05769216
Multicall215295362025-01-01 12:12:1130 days ago1735733531IN
0xcccbdaeA...cC9a815C0
0 ETH0.0866301213.59306085
Multicall215295342025-01-01 12:11:4730 days ago1735733507IN
0xcccbdaeA...cC9a815C0
0 ETH0.1004706615.70043591
Multicall215295322025-01-01 12:11:2330 days ago1735733483IN
0xcccbdaeA...cC9a815C0
0 ETH0.1018653616.02443863
Multicall215295182025-01-01 12:08:3530 days ago1735733315IN
0xcccbdaeA...cC9a815C0
0 ETH0.090945714.33734874
Multicall215295162025-01-01 12:08:1130 days ago1735733291IN
0xcccbdaeA...cC9a815C0
0 ETH0.0930600914.67757663
Multicall215295142025-01-01 12:07:4730 days ago1735733267IN
0xcccbdaeA...cC9a815C0
0 ETH0.0940989314.80627807
Multicall215295102025-01-01 12:06:5930 days ago1735733219IN
0xcccbdaeA...cC9a815C0
0 ETH0.0921906514.40965728
Multicall215295062025-01-01 12:06:1130 days ago1735733171IN
0xcccbdaeA...cC9a815C0
0 ETH0.0980974615.48915934
Multicall215295042025-01-01 12:05:4730 days ago1735733147IN
0xcccbdaeA...cC9a815C0
0 ETH0.1003385915.73299481
Multicall215295002025-01-01 12:04:5930 days ago1735733099IN
0xcccbdaeA...cC9a815C0
0 ETH0.1013112415.83469231
Multicall215294982025-01-01 12:04:3530 days ago1735733075IN
0xcccbdaeA...cC9a815C0
0 ETH0.1011024316.01420307
Multicall215294952025-01-01 12:03:5930 days ago1735733039IN
0xcccbdaeA...cC9a815C0
0 ETH0.1189837418.6003015
Multicall215294932025-01-01 12:03:3530 days ago1735733015IN
0xcccbdaeA...cC9a815C0
0 ETH0.1085949116.99315311
Multicall215294912025-01-01 12:03:1130 days ago1735732991IN
0xcccbdaeA...cC9a815C0
0 ETH0.0937514816.58416269
Multicall215294902025-01-01 12:02:5930 days ago1735732979IN
0xcccbdaeA...cC9a815C0
0 ETH0.1079582216.54960046
Multicall215294892025-01-01 12:02:4730 days ago1735732967IN
0xcccbdaeA...cC9a815C0
0 ETH0.0919783314.09991607
Multicall215294852025-01-01 12:01:5930 days ago1735732919IN
0xcccbdaeA...cC9a815C0
0 ETH0.095524215.02437947
Multicall215294832025-01-01 12:01:3530 days ago1735732895IN
0xcccbdaeA...cC9a815C0
0 ETH0.0928338414.13342611
Multicall215294792025-01-01 12:00:4730 days ago1735732847IN
0xcccbdaeA...cC9a815C0
0 ETH0.0924357914.61147392
Multicall215294782025-01-01 12:00:3530 days ago1735732835IN
0xcccbdaeA...cC9a815C0
0 ETH0.0909141514.29608309
Multicall215294762025-01-01 12:00:1130 days ago1735732811IN
0xcccbdaeA...cC9a815C0
0 ETH0.0893131114.12227386
Multicall215294752025-01-01 11:59:5930 days ago1735732799IN
0xcccbdaeA...cC9a815C0
0 ETH0.088545414.00024584
Multicall215294742025-01-01 11:59:4730 days ago1735732787IN
0xcccbdaeA...cC9a815C0
0 ETH0.0878091213.88443463
Multicall215294722025-01-01 11:59:2330 days ago1735732763IN
0xcccbdaeA...cC9a815C0
0 ETH0.0763065712.95250105
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
215289812025-01-01 10:20:4730 days ago1735726847  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BitmapLayers

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 1000 runs

Other Settings:
cancun EvmVersion
File 1 of 8 : BitmapLayers.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {PixelLayerResolver} from "../PixelLayerResolver.sol";

contract BitmapLayers is PixelLayerResolver {}

File 2 of 8 : PixelLayerResolver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {PaletteRegistry} from "./PaletteRegistry.sol";
import {PixelLayerRegistry} from "./PixelLayerRegistry.sol";

import {BitmapImage} from "./library/BitmapImage.sol";
import {SVGImage} from "./library/SVGImage.sol";

contract PixelLayerResolver is PaletteRegistry, PixelLayerRegistry {
    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                        CUSTOM ERRORS                        │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    error InvalidLayerIdsLength();
    error InvalidColorBitDepth();

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                          EXTERNAL                           │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    struct PaletteParam {
        string name;
        uint8 bitsPerColor;
        bytes colorData;
    }

    struct LayerAndPixelParam {
        LayerParam layer;
        RectRegion regionParam;
        uint256 bgcolorOrIndex;
        bytes pixels;
    }

    struct LayerAndPixelRefParam {
        LayerParam layer;
        RectRegion regionParam;
        uint256 bgcolorOrIndex;
        uint256 pixelRefId;
    }

    function createPaletteAndLayer(
        PaletteParam calldata palette,
        LayerAndPixelParam[] calldata param1,
        LayerAndPixelRefParam[] calldata param2
    )
        public
        returns (uint256 paletteId, uint256[] memory layerIds, uint256[] memory layerWithRefIds)
    {
        paletteId = createPalette(palette.name, palette.bitsPerColor, palette.colorData);

        {
            uint256 layerCount = param1.length;
            layerIds = new uint256[](layerCount);
            for (uint256 i = 0; i < layerCount; ++i) {
                LayerAndPixelParam calldata param = param1[i];
                layerIds[i] = createLayer(
                    param.layer, param.regionParam, param.bgcolorOrIndex, param.pixels, paletteId
                );
            }
        }

        {
            uint256 layerCount = param2.length;
            layerWithRefIds = new uint256[](layerCount);
            for (uint256 i = 0; i < layerCount; ++i) {
                LayerAndPixelRefParam calldata param = param2[i];
                layerWithRefIds[i] = createLayer(
                    param.layer,
                    param.regionParam,
                    param.bgcolorOrIndex,
                    param.pixelRefId,
                    paletteId
                );
            }
        }
    }

    function genBMPFromLayers(uint256[] memory layerIds) public view returns (bytes memory bmp) {
        (uint256 bitsPerPixel, uint256 width, uint256 height, bytes memory pixelBuffer) =
            compositeLayers(layerIds);
        return BitmapImage.generateBMP(bitsPerPixel, width, height, pixelBuffer);
    }

    function genSVGFromLayers(uint256[] memory layerIds) public view returns (bytes memory svg) {
        (uint256 bitsPerPixel, uint256 width, uint256 height, bytes memory pixelBuffer) =
            compositeLayers(layerIds);
        return bytes(SVGImage.generateSVG(bitsPerPixel, width, height, pixelBuffer));
    }

    function compositeLayers(uint256[] memory layerIds)
        public
        view
        returns (uint256 bitsPerPixel, uint256 width, uint256 height, bytes memory pixelBuffer)
    {
        uint256 layerCount = layerIds.length;
        require(layerCount > 0, InvalidLayerIdsLength());

        _sortLayersByZIndex(layerIds);

        uint256 paletteId;
        uint256 bitsPerLayerPixel;
        bytes memory pixelIdx;
        bytes memory palette;
        LayerRegionInfo memory region;

        (bitsPerLayerPixel, region, paletteId, pixelIdx) = _getLayerInner(layerIds[0]);

        width = region.layerWidth;
        height = region.layerHeight;
        (bitsPerPixel, palette) = _getPaletteColors(paletteId);

        unchecked {
            pixelBuffer = new bytes(width * height * (bitsPerPixel >> 3));

            if (region.xTL == 0 && region.yTL == 0 && region.xBR == width && region.yBR == height) {
                _compositeLayerWithPalette(
                    pixelBuffer, palette, pixelIdx, bitsPerPixel, bitsPerLayerPixel
                );
            } else {
                _compositeLayerBG(pixelBuffer, palette, bitsPerPixel, region);
                _compositeActiveRegion(
                    pixelBuffer, palette, pixelIdx, bitsPerPixel, bitsPerLayerPixel, region
                );
            }

            for (uint256 i = 1; i < layerCount; ++i) {
                uint256 tmpUint;
                (bitsPerLayerPixel, region, tmpUint, pixelIdx) = _getLayerInner(layerIds[i]);

                // Only fetch palette when it changes.
                if (tmpUint != paletteId) {
                    paletteId = tmpUint;
                    (tmpUint, palette) = _getPaletteColors(paletteId);
                    // The bits depth of new palette must be same with the first one.
                    require(tmpUint == bitsPerPixel, InvalidColorBitDepth());
                }

                if (
                    region.xTL == 0 && region.yTL == 0 && region.xBR == width
                        && region.yBR == height
                ) {
                    _compositeLayerWithPalette(
                        pixelBuffer, palette, pixelIdx, bitsPerPixel, bitsPerLayerPixel
                    );
                } else {
                    _compositeLayerBG(pixelBuffer, palette, bitsPerPixel, region);
                    _compositeActiveRegion(
                        pixelBuffer, palette, pixelIdx, bitsPerPixel, bitsPerLayerPixel, region
                    );
                }
            }
        }
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                      INTERNAL HELPERS                       │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    function _compositeLayerWithPalette(
        bytes memory pixelBuffer,
        bytes memory palette,
        bytes memory pixelIndex,
        uint256 bitsPerColor,
        uint256 bitsPerPixel
    ) internal pure {
        unchecked {
            uint256 pixelCount;
            uint256 colorMask;
            uint256 pixelIndexMask;
            assembly ("memory-safe") {
                pixelCount := div(mload(pixelBuffer), shr(3, bitsPerColor))
                pixelIndexMask := sub(shl(bitsPerPixel, 1), 1)
                colorMask := sub(shl(bitsPerColor, 1), 1)
            }

            for (uint256 i = 0; i < pixelCount; ++i) {
                // Temporary variable to store internal values, used to avoid 'stack too deep' errors.
                uint256 tmpUint;
                uint256 fgColor;

                assembly {
                    // The start bit of the `i`th index in the `pixelIndex`
                    let elemStartBit := mul(i, bitsPerPixel)
                    // shr(3, idxStartBit) => idxStartBit / 8, it is byte pos
                    let data := mload(add(add(pixelIndex, 0x20), shr(3, elemStartBit)))
                    // and(idxStartBit, 7) => idxStartBit % 8, it is bit offset
                    data := shr(sub(256, add(bitsPerPixel, and(elemStartBit, 7))), data)

                    // Read fg color from palette with `color index` decoded from pixelIndex.
                    // The start bit of the color in the `palette`.
                    elemStartBit := mul(and(data, pixelIndexMask), bitsPerColor)
                    data := mload(add(add(palette, 0x20), shr(3, elemStartBit)))
                    data := shr(sub(256, add(bitsPerColor, and(elemStartBit, 7))), data)
                    fgColor := and(data, colorMask)
                }

                uint256 alpha = fgColor & 0xFF;
                // Fully transparent, keep bgColor
                if (alpha == 0) continue;

                // Prepare bgColor offset and the word of current bgColor
                uint256 bgColorOffset;
                uint256 bgColorWordShiftCount;
                assembly {
                    // tmpUint store the `bufStartBit` which is the offset of the color in the pixelBuffer.
                    tmpUint := mul(i, bitsPerColor)
                    bgColorWordShiftCount := sub(256, add(bitsPerColor, and(tmpUint, 7)))
                    bgColorOffset := add(add(pixelBuffer, 0x20), shr(3, tmpUint))

                    // tmpUint store the whold word.
                    tmpUint := mload(bgColorOffset)
                }

                // Blend BGRA
                if (alpha < 255) {
                    // Read bgColor and blend BGRA, then update new color to fgColor
                    uint256 bgColor;
                    assembly {
                        bgColor := and(shr(bgColorWordShiftCount, tmpUint), colorMask)
                    }

                    fgColor = _blendBGRA(fgColor, bgColor, alpha);
                }

                // 1. No transparency, override with fgColor
                // 2. alpha < 255, override with blended fgColor
                assembly {
                    let mask := shl(bgColorWordShiftCount, colorMask)
                    let shifted := shl(bgColorWordShiftCount, fgColor)

                    let current := and(tmpUint, not(mask))
                    mstore(bgColorOffset, or(current, shifted))
                }
            }
        }
    }

    function _compositeActiveRegion(
        bytes memory pixelBuffer,
        bytes memory palette,
        bytes memory pixelIndex,
        uint256 bitsPerColor,
        uint256 bitsPerPixel,
        LayerRegionInfo memory region
    ) internal pure {
        unchecked {
            uint256 colorMask;
            uint256 pixelIndexMask;
            assembly ("memory-safe") {
                pixelIndexMask := sub(shl(bitsPerPixel, 1), 1)
                colorMask := sub(shl(bitsPerColor, 1), 1)

                // ! Use `0x00` to store the `pixelIndexPos`.
                mstore(0x00, 0)
            }

            while (region.yTL < region.yBR) {
                uint256 rowStart = region.yTL * region.layerWidth + region.xTL;
                uint256 rowEnd = rowStart + region.regionWidth;

                while (rowStart < rowEnd) {
                    uint256 fgColor;

                    assembly {
                        // The start bit of the `pixelIndexPos`th index in the `pixelIndex`
                        let elemStartBit := mul(mload(0x00), bitsPerPixel)
                        // shr(3, idxStartBit) => idxStartBit / 8, it is byte pos
                        let data := mload(add(add(pixelIndex, 0x20), shr(3, elemStartBit)))
                        // and(idxStartBit, 7) => idxStartBit % 8, it is bit offset
                        data := shr(sub(256, add(bitsPerPixel, and(elemStartBit, 7))), data)

                        // Read fg color from palette with `color index` decoded from pixelIndex.
                        // The start bit of the color in the `palette`.
                        elemStartBit := mul(and(data, pixelIndexMask), bitsPerColor)
                        data := mload(add(add(palette, 0x20), shr(3, elemStartBit)))
                        data := shr(sub(256, add(bitsPerColor, and(elemStartBit, 7))), data)
                        fgColor := and(data, colorMask)
                    }

                    // Fully transparent, keep bgColor
                    if ((fgColor & 0xFF) == 0) {
                        assembly {
                            mstore(0x00, add(mload(0x00), 1)) // ++pixelIndexPos
                            rowStart := add(rowStart, 1) // ++rowStart
                        }
                        continue;
                    }

                    uint256 bgShift;
                    uint256 bgOffset;
                    assembly {
                        let bufStartBit := mul(rowStart, bitsPerColor)
                        bgShift := sub(256, add(bitsPerColor, and(bufStartBit, 7)))
                        bgOffset := add(add(pixelBuffer, 0x20), shr(3, bufStartBit))
                    }

                    // Blend BGRA
                    if ((fgColor & 0xFF) < 255) {
                        // Read bgColor and blend BGRA, then update new color to fgColor
                        uint256 bgColor;
                        assembly {
                            bgColor := and(shr(bgShift, mload(bgOffset)), colorMask)
                        }

                        fgColor = _blendBGRA(fgColor, bgColor, fgColor & 0xFF);
                    }

                    // 1. No transparency, override with fgColor
                    // 2. alpha < 255, override with blended fgColor
                    assembly {
                        let mask := shl(bgShift, colorMask)
                        let current := and(mload(bgOffset), not(mask))
                        mstore(bgOffset, or(current, shl(bgShift, fgColor)))
                    }

                    assembly {
                        mstore(0x00, add(mload(0x00), 1)) // ++pixelIndexPos
                        rowStart := add(rowStart, 1) // ++rowStart
                    }
                }

                ++region.yTL;
            }
        }
    }

    function _compositeLayerBG(
        bytes memory pixelBuffer,
        bytes memory palette,
        uint256 bitsPerColor,
        LayerRegionInfo memory region
    ) internal pure {
        uint256 layerBgColor = region.inactiveBgColor;
        assembly {
            // Read fg color from palette with `color index` decoded from pixelIndex.
            // The start bit of the color in the `palette`.
            let elemStartBit := mul(layerBgColor, bitsPerColor)
            let data := mload(add(add(palette, 0x20), shr(3, elemStartBit)))
            data := shr(sub(256, add(bitsPerColor, and(elemStartBit, 7))), data)
            layerBgColor := and(data, sub(shl(bitsPerColor, 1), 1))
        }

        if (region.yTL > 0) {
            _compositeLayerRectBG(
                pixelBuffer,
                layerBgColor,
                bitsPerColor,
                LayerRegionInfo({
                    xTL: 0,
                    yTL: 0,
                    xBR: region.layerWidth,
                    yBR: region.yTL,
                    regionWidth: region.layerWidth,
                    layerWidth: region.layerWidth,
                    layerHeight: 0,
                    inactiveBgColor: 0
                })
            );
        }
        if (region.yBR < region.layerHeight) {
            _compositeLayerRectBG(
                pixelBuffer,
                layerBgColor,
                bitsPerColor,
                LayerRegionInfo({
                    xTL: 0,
                    yTL: region.yBR,
                    xBR: region.layerWidth,
                    yBR: region.layerHeight,
                    regionWidth: region.layerWidth,
                    layerWidth: region.layerWidth,
                    layerHeight: 0,
                    inactiveBgColor: 0
                })
            );
        }
        if (region.xTL > 0) {
            _compositeLayerRectBG(
                pixelBuffer,
                layerBgColor,
                bitsPerColor,
                LayerRegionInfo({
                    xTL: 0,
                    yTL: region.yTL,
                    xBR: region.xTL,
                    yBR: region.yBR,
                    regionWidth: region.xTL,
                    layerWidth: region.layerWidth,
                    layerHeight: 0,
                    inactiveBgColor: 0
                })
            );
        }
        if (region.xBR < region.layerWidth) {
            _compositeLayerRectBG(
                pixelBuffer,
                layerBgColor,
                bitsPerColor,
                LayerRegionInfo({
                    xTL: region.xBR,
                    yTL: region.yTL,
                    xBR: region.layerWidth,
                    yBR: region.yBR,
                    regionWidth: region.layerWidth - region.xBR,
                    layerWidth: region.layerWidth,
                    layerHeight: 0,
                    inactiveBgColor: 0
                })
            );
        }
    }

    function _compositeLayerRectBG(
        bytes memory pixelBuffer,
        uint256 layerBgColor,
        uint256 bitsPerColor,
        LayerRegionInfo memory region
    ) internal pure {
        unchecked {
            uint256 colorMask = (1 << bitsPerColor) - 1;

            uint256 alpha = layerBgColor & 0xFF;
            if (alpha == 0) return;

            for (uint256 y = region.yTL; y < region.yBR; ++y) {
                uint256 rowStart = y * region.layerWidth + region.xTL;
                uint256 rowEnd = rowStart + region.regionWidth;

                if (alpha == 255) {
                    while (rowStart < rowEnd) {
                        assembly {
                            let bufStartBit := mul(rowStart, bitsPerColor)
                            let shift := sub(256, add(bitsPerColor, and(bufStartBit, 7)))
                            let targetOffset := add(add(pixelBuffer, 0x20), shr(3, bufStartBit))

                            let mask := shl(shift, colorMask)
                            let current := and(mload(targetOffset), not(mask))
                            mstore(targetOffset, or(current, shl(shift, layerBgColor)))
                        }
                        ++rowStart;
                    }
                } else {
                    while (rowStart < rowEnd) {
                        uint256 bgShift;
                        uint256 bgOffset;
                        uint256 bgWord;
                        assembly {
                            let bufStartBit := mul(rowStart, bitsPerColor)
                            bgShift := sub(256, add(bitsPerColor, and(bufStartBit, 7)))
                            bgOffset := add(add(pixelBuffer, 0x20), shr(3, bufStartBit))
                            bgWord := mload(bgOffset)
                        }

                        uint256 newColor =
                            _blendBGRA(layerBgColor, (bgWord >> bgShift) & colorMask, alpha);
                        assembly {
                            let mask := shl(bgShift, colorMask)
                            let current := and(bgWord, not(mask))
                            mstore(bgOffset, or(current, shl(bgShift, newColor)))
                        }

                        ++rowStart;
                    }
                }
            }
        }
    }

    function _blendBGRA(uint256 fgColor, uint256 bgColor, uint256 fgAlpha)
        internal
        pure
        returns (uint256)
    {
        assembly ("memory-safe") {
            let w2 := sub(255, fgAlpha)

            // Approximate blended values for B, G, R channels using right shift for division by 255
            let b :=
                shr(
                    8,
                    add(mul(and(shr(24, fgColor), 0xff), fgAlpha), mul(and(shr(24, bgColor), 0xff), w2))
                )
            let g :=
                shr(
                    8,
                    add(mul(and(shr(16, fgColor), 0xff), fgAlpha), mul(and(shr(16, bgColor), 0xff), w2))
                )
            let r :=
                shr(
                    8,
                    add(mul(and(shr(8, fgColor), 0xff), fgAlpha), mul(and(shr(8, bgColor), 0xff), w2))
                )

            // Update the new fgColor
            fgColor := or(or(or(shl(24, b), shl(16, g)), shl(8, r)), fgAlpha)
        }

        return fgColor;
    }
}

File 3 of 8 : PaletteRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import {Multicallable} from "solady/utils/Multicallable.sol";

contract PaletteRegistry is Multicallable {
    using SafeCast for uint256;

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                           EVENTS                            │*/
    /*╰─────────────────────────────────────────────────────────────╯*/
    event PaletteCreated(
        uint256 indexed paletteId,
        string name,
        uint256 bitsPerColor,
        uint256 totalColors,
        uint256 colorDataSize,
        address creator
    );

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                        CUSTOM ERRORS                        │*/
    /*╰─────────────────────────────────────────────────────────────╯*/
    error InvalidColorBits();
    error InvalidColorDataLength();

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                          CONSTANTS                          │*/
    /*╰─────────────────────────────────────────────────────────────╯*/
    uint256 public constant BITS_PER_COLOR = 32;

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                           STORAGE                           │*/
    /*╰─────────────────────────────────────────────────────────────╯*/
    struct Palette {
        uint8 bitsPerColor;
        uint32 totalColors;
        string name;
        bytes colors;
    }

    struct PaletteStorage {
        uint32 lastPaletteId;
        mapping(uint32 paletteId => Palette palette) palettes;
    }

    /// @dev Returns a storage pointer for this contract.
    function _getPaletteStorage() internal pure virtual returns (PaletteStorage storage $) {
        /// @solidity memory-safe-assembly
        assembly {
            // `keccak256(abi.encode(uint256(keccak256("bmp.storage.PaletteRegistry")) - 1)) & ~bytes32(uint256(0xff))`
            $.slot := 0x3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca772633200
        }
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                          EXTERNAL                           │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    /// @param colorData It should be packed in Little-endian with order `BGRA`.
    function createPalette(string calldata name, uint8 bitsPerColor, bytes calldata colorData)
        public
        returns (uint256)
    {
        PaletteStorage storage $ = _getPaletteStorage();
        uint256 paletteId = ++$.lastPaletteId;
        Palette storage palette = $.palettes[uint32(paletteId)];

        _setPalette(palette, name, bitsPerColor, colorData);
        emit PaletteCreated(
            paletteId,
            name,
            bitsPerColor,
            (colorData.length / (bitsPerColor >> 3)),
            colorData.length,
            msg.sender
        );

        return paletteId;
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                            VIEW                             │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    function getPalettes(uint256[] calldata paletteIds)
        public
        view
        returns (Palette[] memory palettes)
    {
        uint256 length = paletteIds.length;
        palettes = new Palette[](length);

        mapping(uint32 => Palette) storage _palettes = _getPaletteStorage().palettes;

        for (uint256 i = 0; i < length; ++i) {
            palettes[i] = _palettes[uint32(paletteIds[i])];
        }
    }

    function getPalette(uint256 paletteId) public view returns (Palette memory) {
        return _getPaletteStorage().palettes[uint32(paletteId)];
    }

    function lastPaletteId() public view returns (uint256) {
        return _getPaletteStorage().lastPaletteId;
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                      INTERNAL HELPERS                       │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    function _setPalette(
        Palette storage palette,
        string calldata name,
        uint8 bitsPerColor,
        bytes calldata colorData
    ) internal {
        require(bitsPerColor == BITS_PER_COLOR, InvalidColorBits());

        uint256 perColorBytesLen = bitsPerColor >> 3;
        uint256 colorDataLength = colorData.length;
        require(
            colorDataLength > 0 && colorDataLength % perColorBytesLen == 0, InvalidColorDataLength()
        );

        if (bytes(name).length > 0) palette.name = name;
        palette.bitsPerColor = bitsPerColor;
        palette.totalColors = (colorDataLength / perColorBytesLen).toUint32();
        palette.colors = colorData;
    }

    function _getPaletteColors(uint256 paletteId)
        internal
        view
        returns (uint8 bitsPerColor, bytes memory paletteColors)
    {
        Palette storage palette = _getPaletteStorage().palettes[paletteId.toUint32()];
        bitsPerColor = palette.bitsPerColor;
        paletteColors = palette.colors;
    }
}

File 4 of 8 : PixelLayerRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import {Multicallable} from "solady/utils/Multicallable.sol";

contract PixelLayerRegistry is Multicallable {
    using SafeCast for uint256;

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                           EVENTS                            │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    event PixelLayerCreated(
        uint256 indexed layerId,
        string name,
        uint256 zIndex,
        uint256 bitsPerPixel,
        uint256 width,
        uint256 height,
        RectRegion activeRegion,
        uint256 regionPixelRefId,
        uint256 bgColor,
        uint256 paletteId,
        address creator
    );

    event PixelDataCreated(uint256 indexed pixelRefId, uint256 pixelDataLength, bytes32 pixelHash);

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                        CUSTOM ERRORS                        │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    error InvalidPaletteId();
    error InvalidPixelBits();
    error PixelLayerNotExists();
    error InvalidPixelSize();
    error InvalidLayerInactiveBgColor();
    error InvalidLayerActiveRegionConfig();

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                          CONSTANTS                          │*/
    /*╰─────────────────────────────────────────────────────────────╯*/
    uint32 public constant EMPTY_PIXEL_LAYER_ID = 0x0;
    uint256 public constant MAX_BITS_PER_PIXEL = 32;

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                           STORAGE                           │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    struct PixelData {
        bytes data;
    }

    struct Layer {
        uint8 zIndex;
        uint8 bitsPerPixel;
        uint16 width;
        uint16 height;
        /// @dev x Top Left of active region
        uint16 xTL;
        /// @dev y Top Left of active region
        uint16 yTL;
        /// @dev x Bottom Right of active region
        uint16 xBR;
        /// @dev y Bottom Right of active region
        uint16 yBR;
        uint32 pixelRefId;
        /// @dev inactive region bg color or color index when the layer is defined with an active region.
        uint32 bgColor;
        uint32 paletteId;
        string name;
    }

    struct PixelLayerStorage {
        uint32 lastLayerId;
        uint32 lastPixelRefId;
        mapping(uint32 layerId => Layer layer) layers;
        mapping(uint32 pixelRefId => PixelData pixelData) pixelDatas;
    }

    /// @dev Returns a storage pointer for this contract.
    function _getLayerStorage() internal pure virtual returns (PixelLayerStorage storage $) {
        /// @solidity memory-safe-assembly
        assembly {
            // `keccak256(abi.encode(uint256(keccak256("bmp.storage.PixelLayerStorage")) - 1)) & ~bytes32(uint256(0xff))`
            $.slot := 0x48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d400
        }
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                          EXTERNAL                           │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    struct RectRegion {
        uint256 xTL;
        uint256 yTL;
        uint256 xBR;
        uint256 yBR;
    }

    struct LayerParam {
        string name;
        uint256 zIndex;
        uint256 bitsPerPixel;
        uint256 width;
        uint256 height;
    }

    function createLayer(LayerParam calldata layerParam, bytes calldata pixels, uint256 paletteId)
        public
        returns (uint256)
    {
        return createLayer(
            layerParam, RectRegion(0, 0, layerParam.width, layerParam.height), 0, pixels, paletteId
        );
    }

    function createLayer(
        LayerParam calldata layerParam,
        RectRegion memory regionParam,
        uint256 bgcolorOrIndex,
        bytes calldata pixels,
        uint256 paletteId
    ) public returns (uint256) {
        _checkLayerRegion(
            regionParam,
            bgcolorOrIndex,
            layerParam.width,
            layerParam.height,
            layerParam.bitsPerPixel
        );
        _checkLayerData(
            layerParam.bitsPerPixel,
            regionParam.xBR - regionParam.xTL,
            regionParam.yBR - regionParam.yTL,
            pixels.length
        );
        require(paletteId > 0, InvalidPaletteId());

        PixelLayerStorage storage $ = _getLayerStorage();

        uint256 pixelRefId = _createPixelData($, pixels);

        return _createLayer(layerParam, regionParam, bgcolorOrIndex, pixelRefId, paletteId);
    }

    function createLayer(LayerParam calldata layerParam, uint256 pixelRefId, uint256 paletteId)
        public
        returns (uint256)
    {
        return createLayer(
            layerParam,
            RectRegion(0, 0, layerParam.width, layerParam.height),
            0,
            pixelRefId,
            paletteId
        );
    }

    function createLayer(
        LayerParam calldata layerParam,
        RectRegion memory regionParam,
        uint256 bgcolorOrIndex,
        uint256 pixelRefId,
        uint256 paletteId
    ) public returns (uint256) {
        _checkLayerRegion(
            regionParam,
            bgcolorOrIndex,
            layerParam.width,
            layerParam.height,
            layerParam.bitsPerPixel
        );
        _checkLayerData(
            layerParam.bitsPerPixel,
            regionParam.xBR - regionParam.xTL,
            regionParam.yBR - regionParam.yTL,
            _getPixelDataRef(_getLayerStorage(), pixelRefId.toUint32()).length
        );
        require(paletteId > 0, InvalidPaletteId());
        return _createLayer(layerParam, regionParam, bgcolorOrIndex, pixelRefId, paletteId);
    }

    function createPixelData(bytes calldata pixels) public returns (uint256 pixelRefId) {
        require(pixels.length > 0, InvalidPixelSize());
        return _createPixelData(_getLayerStorage(), pixels);
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                            VIEW                             │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    function sortLayersByZIndex(uint256[] memory layerIds) public view returns (uint256[] memory) {
        _sortLayersByZIndex(layerIds);
        return layerIds;
    }

    function getLayers(uint256[] calldata layerIds) public view returns (Layer[] memory layers) {
        uint256 length = layerIds.length;
        layers = new Layer[](length);

        mapping(uint32 => Layer) storage _layers = _getLayerStorage().layers;

        for (uint256 i = 0; i < length; ++i) {
            layers[i] = _layers[uint32(layerIds[i])];
        }
    }

    function getLayer(uint256 layerId) public view returns (Layer memory layer) {
        return _getLayerStorage().layers[uint32(layerId)];
    }

    function getPixelData(uint256 pixelRefId) public view returns (bytes memory) {
        return _getPixelDataRef(_getLayerStorage(), pixelRefId.toUint32());
    }

    function lastLayerId() public view returns (uint256) {
        return _getLayerStorage().lastLayerId;
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                      INTERNAL HELPERS                       │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    function _sortLayersByZIndex(uint256[] memory layerIds) internal view {
        mapping(uint32 => Layer) storage layers = _getLayerStorage().layers;
        unchecked {
            uint256 layerCount = _loadMemoryArray(layerIds, 0);
            if (layerCount > type(uint32).max) {
                revert SafeCast.SafeCastOverflowedUintDowncast(32, layerCount);
            }

            layerCount = layerIds.length;
            for (uint256 i = 1; i < layerCount; ++i) {
                uint32 key = _loadMemoryArray(layerIds, i).toUint32();

                require(layers[key].bitsPerPixel > 0, PixelLayerNotExists());

                uint256 keyZIndex = layers[key].zIndex;

                uint256 j = i;
                while (
                    j > 0 && layers[uint32(_loadMemoryArray(layerIds, j - 1))].zIndex > keyZIndex
                ) {
                    _storeMemoryArray(layerIds, j, _loadMemoryArray(layerIds, j - 1));

                    --j;
                }

                _storeMemoryArray(layerIds, j, key);
            }
        }
    }

    function _createLayer(
        LayerParam calldata layerParam,
        RectRegion memory regionParam,
        uint256 bgcolorOrIndex,
        uint256 pixelRefId,
        uint256 paletteId
    ) internal returns (uint256 layerId) {
        {
            PixelLayerStorage storage $ = _getLayerStorage();
            layerId = ++$.lastLayerId;
            Layer storage layer = $.layers[uint32(layerId)];

            if (bytes(layerParam.name).length > 0) {
                layer.name = layerParam.name;
            }

            layer.zIndex = layerParam.zIndex.toUint8();
            layer.bitsPerPixel = layerParam.bitsPerPixel.toUint8();
            layer.width = layerParam.width.toUint16();
            layer.height = layerParam.height.toUint16();

            layer.xTL = regionParam.xTL.toUint16();
            layer.yTL = regionParam.yTL.toUint16();
            layer.xBR = regionParam.xBR.toUint16();
            layer.yBR = regionParam.yBR.toUint16();
            layer.bgColor = bgcolorOrIndex.toUint32();

            layer.paletteId = paletteId.toUint32();
            layer.pixelRefId = pixelRefId.toUint32();
        }

        emit PixelLayerCreated(
            layerId,
            layerParam.name,
            layerParam.zIndex,
            layerParam.bitsPerPixel,
            layerParam.width,
            layerParam.height,
            regionParam,
            pixelRefId,
            bgcolorOrIndex,
            paletteId,
            msg.sender
        );
    }

    function _createPixelData(PixelLayerStorage storage $, bytes calldata pixels)
        internal
        returns (uint256 pixelRefId)
    {
        pixelRefId = ++$.lastPixelRefId;
        $.pixelDatas[uint32(pixelRefId)].data = pixels;

        emit PixelDataCreated(pixelRefId, pixels.length, keccak256(pixels));
    }

    function _getPixelDataRef(PixelLayerStorage storage $, uint32 pixelRefId)
        internal
        view
        returns (bytes storage pixelData)
    {
        return $.pixelDatas[pixelRefId].data;
    }

    function _checkLayerData(
        uint256 bitsPerPixel,
        uint256 width,
        uint256 height,
        uint256 pixelBytes
    ) internal pure {
        require(
            0 < bitsPerPixel && bitsPerPixel <= MAX_BITS_PER_PIXEL
                && _isValidBitsPerPixel(bitsPerPixel),
            InvalidPixelBits()
        );

        uint256 totalBits = width * height * bitsPerPixel;
        uint256 expectedBytes = (totalBits + 7) >> 3;

        require(pixelBytes == expectedBytes, InvalidPixelSize());
    }

    function _checkLayerRegion(
        RectRegion memory param,
        uint256 bgColorOrIndex,
        uint256 layerWidth,
        uint256 layerHeight,
        uint256 bitsPerPixel
    ) internal pure {
        require(
            param.xTL <= param.xBR && param.xBR <= layerWidth && param.yTL <= param.yBR
                && param.yBR <= layerHeight,
            InvalidLayerActiveRegionConfig()
        );
        require(bgColorOrIndex <= ((1 << bitsPerPixel) - 1), InvalidLayerInactiveBgColor());
    }

    function _isValidBitsPerPixel(uint256 bitsPerPixel) internal pure returns (bool isValid) {
        assembly ("memory-safe") {
            // Create bit mask for valid bits
            // 0x101010116 = (1 << 1) | (1 << 2) | (1 << 4) | (1 << 8) | (1 << 16) | (1 << 24) | (1 << 32)
            let validMask := 0x101010116

            // Right shift validMask by bitsPerPixel and check least significant bit
            isValid := and(shr(bitsPerPixel, validMask), 1)
        }
    }

    struct LayerRegionInfo {
        uint256 xTL;
        uint256 yTL;
        uint256 xBR;
        uint256 yBR;
        uint256 inactiveBgColor;
        uint256 regionWidth; // xBR - xTL
        uint256 layerWidth;
        uint256 layerHeight;
    }

    function _getLayerInner(uint256 layerId)
        internal
        view
        returns (
            uint256 bitsPerPixel,
            LayerRegionInfo memory region,
            uint256 paletteId,
            bytes memory pixels
        )
    {
        PixelLayerStorage storage $ = _getLayerStorage();
        Layer storage l = $.layers[uint32(layerId)];

        bitsPerPixel = l.bitsPerPixel;
        region.layerWidth = l.width;
        region.layerHeight = l.height;
        region.xTL = l.xTL;
        region.yTL = l.yTL;
        region.xBR = l.xBR;
        region.yBR = l.yBR;
        region.inactiveBgColor = l.bgColor;

        region.regionWidth = region.xBR - region.xTL;

        paletteId = l.paletteId;
        pixels = _getPixelDataRef($, l.pixelRefId);
    }

    function _loadMemoryArray(uint256[] memory arr, uint256 index)
        internal
        pure
        returns (uint256 val)
    {
        assembly {
            val := mload(add(add(arr, 0x20), shl(5, index)))
        }
    }

    function _storeMemoryArray(uint256[] memory arr, uint256 index, uint256 val) internal pure {
        assembly {
            mstore(add(add(arr, 0x20), shl(5, index)), val)
        }
    }
}

File 5 of 8 : BitmapImage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library BitmapImage {
    /// @dev BMP File Header.
    uint256 private constant BMP_FILE_HEADER_BYTE_SIZE = 14;
    /// @dev BMP V5 DIB Header.
    uint256 private constant BMP_V5_HEADER_BYTE_SIZE = 124;

    function generateBMP(uint256 bitsPerPixel, uint256 width, uint256 height, bytes memory pixels)
        internal
        pure
        returns (bytes memory bmpData)
    {
        bool isRGB = bitsPerPixel <= 24;
        uint256 imageSize = _bmpImageSize(bitsPerPixel, width, height);

        uint256 headerSize = BMP_FILE_HEADER_BYTE_SIZE + BMP_V5_HEADER_BYTE_SIZE;

        bmpData = new bytes(headerSize + imageSize);
        _writeBMPFileHeader(bmpData, bmpData.length, headerSize);
        _writeCommonDIBHeader(
            bmpData,
            BMP_V5_HEADER_BYTE_SIZE,
            imageSize,
            isRGB ? 0 : 3,
            0,
            width,
            height,
            bitsPerPixel
        );
        _writeExtraDIBHeader(bmpData);
        _writePixelData(bmpData, pixels, headerSize, width, height, bitsPerPixel >> 3);

        return bmpData;
    }

    function _bmpImageSize(uint256 bitsPerPixel, uint256 width, uint256 height)
        private
        pure
        returns (uint256)
    {
        unchecked {
            uint256 bytesPerPixel = bitsPerPixel >> 3;
            uint256 rowSize = width * bytesPerPixel;
            return (rowSize + ((4 - (rowSize & 3)) & 3)) * height;
        }
    }

    function _writeBMPFileHeader(bytes memory bmpData, uint256 fileSize, uint256 pixelOffset)
        private
        pure
    {
        // Write BMP header (14 bytes)
        assembly {
            let ptr := add(bmpData, 32)
            mstore8(ptr, 0x42) // B
            mstore8(add(ptr, 1), 0x4D) // M
        }
        _writeUint32(bmpData, 2, fileSize);
        _writeUint32(bmpData, 10, pixelOffset); // offset to pixel data
    }

    function _writeCommonDIBHeader(
        bytes memory bmpData,
        uint256 dibHeaderSize,
        uint256 imageSize,
        uint256 compressionOption,
        uint256 paletteColorCount,
        uint256 width,
        uint256 height,
        uint256 bitsPerPixel
    ) private pure {
        // Write BITMAPV4HEADER (108 bytes)
        _writeUint32(bmpData, 14, dibHeaderSize); // BITMAPV4HEADER size
        _writeUint32(bmpData, 18, width);
        _writeUint32(bmpData, 22, height);
        _writeUint16(bmpData, 26, 1); // planes must always be 1
        _writeUint16(bmpData, 28, bitsPerPixel); // bits per pixel
        _writeUint32(bmpData, 30, compressionOption); // compression; 0 - BI_RGB, 3 - BI_BITFIELDS
        _writeUint32(bmpData, 34, imageSize);
        // _writeUint32(bmpData, 38, 0); // x pixel per meter
        // _writeUint32(bmpData, 42, 0); // y pixel per meter
        _writeUint32(bmpData, 46, paletteColorCount); // color count
            // _writeUint32(bmpData, 50, 0); // important color count
    }

    function _writeExtraDIBHeader(bytes memory bmpData) private pure {
        // BITMAPV5HEADER additional fields
        _writeUint32(bmpData, 54, 0x00FF0000); // Red mask
        _writeUint32(bmpData, 58, 0x0000FF00); // Green mask
        _writeUint32(bmpData, 62, 0x000000FF); // Blue mask
        _writeUint32(bmpData, 66, 0xFF000000); // Alpha mask
        _writeUint32(bmpData, 70, 0x73524742); // Color space type (sRGB)
    }

    function _writePixelData(
        bytes memory bmpData,
        bytes memory pixelBuffer,
        uint256 pixelOffset,
        uint256 width,
        uint256 height,
        uint256 bytesPerPixel
    ) private pure {
        assembly {
            let bytesPerRow := mul(width, bytesPerPixel)
            let paddedBytesPerRow := add(bytesPerRow, and(sub(4, and(bytesPerRow, 3)), 3))

            let bmpDataPtr := add(add(bmpData, 0x20), pixelOffset)
            let pixelBufferPtr := add(pixelBuffer, 0x20)

            let heightMinus1 := sub(height, 1)

            for { let y := 0 } lt(y, height) { y := add(y, 1) } {
                mcopy(
                    add(bmpDataPtr, mul(sub(heightMinus1, y), paddedBytesPerRow)),
                    add(pixelBufferPtr, mul(y, bytesPerRow)),
                    bytesPerRow
                )
            }
        }
    }

    // Helper function to write uint32 to byte array in Little-endian
    function _writeUint32(bytes memory data, uint256 offset, uint256 value) private pure {
        assembly {
            let ptr := add(add(data, 32), offset)
            mstore8(ptr, value)
            mstore8(add(ptr, 1), shr(8, value))
            mstore8(add(ptr, 2), shr(16, value))
            mstore8(add(ptr, 3), shr(24, value))
        }
    }

    // Helper function to write uint16 to byte array in Little-endian
    function _writeUint16(bytes memory data, uint256 offset, uint256 value) private pure {
        assembly {
            let ptr := add(add(data, 32), offset)
            mstore8(ptr, value)
            mstore8(add(ptr, 1), shr(8, value))
        }
    }

    // Helper function to write bytes to byte array
    function _writeBytes(bytes memory data, uint256 offset, bytes memory value) private pure {
        assembly {
            mcopy(add(add(data, 32), offset), add(value, 32), mload(value))
        }
    }
}

File 6 of 8 : SVGImage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library SVGImage {
    function generateSVG(uint256 bitsPerPixel, uint256 width, uint256 height, bytes memory pixels)
        internal
        pure
        returns (string memory svg)
    {
        uint256 ptr;
        assembly {
            svg := mload(0x40)
            ptr := add(svg, 0x20)

            // Store "0123456789abcdef" in scratch space. Used to covert hex string.
            mstore(0x0f, 0x30313233343536373839616263646566)
        }

        ptr = _writeSVGHeader(ptr, width, height);

        unchecked {
            uint256 colorMask = (1 << bitsPerPixel) - 1;

            for (uint256 y = 0; y < height; ++y) {
                uint256 startX;
                uint256 currentColor = type(uint256).max;
                uint256 basePixelOffset = y * width;

                for (uint256 x = 0; x < width; ++x) {
                    uint256 color = _getPixel(pixels, colorMask, bitsPerPixel, basePixelOffset + x);

                    // Skip transparent pixels
                    if (uint8(color) == 0) {
                        if (currentColor < type(uint256).max) {
                            // Add path for previous segment
                            ptr = _writePath(ptr, startX, y, x - startX, currentColor);
                            currentColor = type(uint256).max;
                        }
                        startX = x + 1;
                        continue;
                    }

                    if (currentColor == type(uint256).max) {
                        currentColor = color;
                        startX = x;
                    } else if (color != currentColor) {
                        // Color changed, add path for previous segment
                        ptr = _writePath(ptr, startX, y, x - startX, currentColor);
                        currentColor = color;
                        startX = x;
                    }
                }

                // Add remaining segment at end of row
                if (currentColor < type(uint256).max && startX < width) {
                    ptr = _writePath(ptr, startX, y, width - startX, currentColor);
                }
            }
        }

        assembly {
            // '</svg>'
            mstore(ptr, 0x3c2f7376673e0000000000000000000000000000000000000000000000000000)
            ptr := add(ptr, 6)

            let length := sub(ptr, add(svg, 0x20))
            mstore(svg, length)

            let padding := and(sub(32, and(ptr, 31)), 31)
            mstore(0x40, add(ptr, padding))
        }
    }

    function _writeSVGHeader(uint256 ptr, uint256 width, uint256 height)
        private
        pure
        returns (uint256)
    {
        assembly {
            // '<svg shape-rendering="crispEdges" width="' (32 + 9 bytes)
            mstore(ptr, 0x3c7376672073686170652d72656e646572696e673d2263726973704564676573)
            ptr := add(ptr, 32)
            mstore(ptr, 0x222077696474683d220000000000000000000000000000000000000000000000)
            ptr := add(ptr, 9)
        }
        ptr = _writeUint(ptr, width);

        assembly {
            // '" height="' (10 bytes)
            mstore(ptr, 0x22206865696768743d2200000000000000000000000000000000000000000000)
            ptr := add(ptr, 10)
        }
        ptr = _writeUint(ptr, height);

        assembly {
            // '" viewBox="0 0 ' (15 bytes)
            mstore(ptr, 0x222076696577426f783d22302030200000000000000000000000000000000000)
            ptr := add(ptr, 15)
        }
        ptr = _writeUint(ptr, width);
        assembly {
            mstore8(ptr, 0x20)
            ptr := add(ptr, 1)
        }
        ptr = _writeUint(ptr, height);

        assembly {
            // '" xmlns="http://www.w3.org/2000/svg">' (33 bytes)
            mstore(ptr, 0x2220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f)
            ptr := add(ptr, 32)
            mstore(ptr, 0x737667223e000000000000000000000000000000000000000000000000000000)
            ptr := add(ptr, 5)
        }
        return ptr;
    }

    function _writePath(uint256 ptr, uint256 x, uint256 y, uint256 width, uint256 color)
        private
        pure
        returns (uint256)
    {
        assembly {
            // '<path d="M' (10 bytes)
            mstore(ptr, 0x3c7061746820643d224d00000000000000000000000000000000000000000000)
            ptr := add(ptr, 10)
        }
        ptr = _writeUint(ptr, x);

        assembly {
            mstore8(ptr, 0x20)
            ptr := add(ptr, 1)
        }

        ptr = _writeUint(ptr, y);

        assembly {
            // 'v1h' (3 bytes)
            mstore(ptr, 0x7631680000000000000000000000000000000000000000000000000000000000)
            ptr := add(ptr, 3)
        }

        ptr = _writeUint(ptr, width);

        assembly {
            // 'v-1" fill="#' (12 bytes)
            mstore(ptr, 0x762d31222066696c6c3d22230000000000000000000000000000000000000000)
            ptr := add(ptr, 12)
        }

        {
            uint256 b = uint8(color >> 24);
            uint256 g = uint8(color >> 16);
            uint256 r = uint8(color >> 8);
            uint256 a = uint8(color);
            ptr = _writeUintHex(ptr, (r << 24) | (g << 16) | (b << 8) | a, 8);
        }

        assembly {
            // '"/>' (3 bytes)
            mstore(ptr, 0x222f3e0000000000000000000000000000000000000000000000000000000000)
            ptr := add(ptr, 3)
        }

        return ptr;
    }

    function _writeUintHex(uint256 ptr, uint256 value, uint256 hexLength)
        private
        pure
        returns (uint256)
    {
        assembly {
            let end := add(ptr, hexLength)
            let result := end

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for {} 1 {} {
                result := sub(result, 2)
                mstore8(add(result, 1), mload(and(value, 15)))
                mstore8(result, mload(and(shr(4, value), 15)))
                value := shr(8, value)
                if iszero(xor(result, ptr)) { break }
            }

            ptr := end
        }

        return ptr;
    }

    function _writeUint(uint256 ptr, uint256 value) private pure returns (uint256) {
        assembly {
            let len := 1
            let v := div(value, 10)
            for {} v {} {
                len := add(len, 1)
                v := div(v, 10)
            }

            v := add(ptr, len)
            for { let end := v } 1 {} {
                end := sub(end, 1)
                // Store the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(end, add(48, mod(value, 10)))
                value := div(value, 10) // Keep dividing `value` until zero.
                if iszero(value) { break }
            }
            ptr := v
        }
        return ptr;
    }

    function _getPixel(bytes memory pixels, uint256 pixelMask, uint256 bitsPerPixel, uint256 index)
        private
        pure
        returns (uint256 result)
    {
        assembly ("memory-safe") {
            let elemStartBit := mul(index, bitsPerPixel)
            let data := mload(add(add(pixels, 0x20), shr(3, elemStartBit)))
            data := shr(sub(256, add(bitsPerPixel, and(elemStartBit, 7))), data)
            result := and(data, pixelMask)
        }
    }
}

File 7 of 8 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }

    /**
     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
     */
    function toUint(bool b) internal pure returns (uint256 u) {
        assembly ("memory-safe") {
            u := iszero(iszero(b))
        }
    }
}

File 8 of 8 : Multicallable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Contract that enables a single call to call multiple methods on itself.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Multicallable.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Multicallable.sol)
///
/// WARNING:
/// This implementation is NOT to be used with ERC2771 out-of-the-box.
/// https://blog.openzeppelin.com/arbitrary-address-spoofing-vulnerability-erc2771context-multicall-public-disclosure
/// This also applies to potentially other ERCs / patterns appending to the back of calldata.
///
/// We do NOT have a check for ERC2771, as we do not inherit from OpenZeppelin's context.
/// Moreover, it is infeasible and inefficient for us to add checks and mitigations
/// for all possible ERC / patterns appending to the back of calldata.
///
/// We would highly recommend using an alternative pattern such as
/// https://github.com/Vectorized/multicaller
/// which is more flexible, futureproof, and safer by default.
abstract contract Multicallable {
    /// @dev Apply `delegatecall` with the current contract to each calldata in `data`,
    /// and store the `abi.encode` formatted results of each `delegatecall` into `results`.
    /// If any of the `delegatecall`s reverts, the entire context is reverted,
    /// and the error is bubbled up.
    ///
    /// By default, this function directly returns the results and terminates the call context.
    /// If you need to add before and after actions to the multicall, please override this function.
    function multicall(bytes[] calldata data) public payable virtual returns (bytes[] memory) {
        // Revert if `msg.value` is non-zero by default to guard against double-spending.
        // (See: https://www.paradigm.xyz/2021/08/two-rights-might-make-a-wrong)
        //
        // If you really need to pass in a `msg.value`, then you will have to
        // override this function and add in any relevant before and after checks.
        if (msg.value != 0) revert();
        // `_multicallDirectReturn` returns the results directly and terminates the call context.
        _multicallDirectReturn(_multicall(data));
    }

    /// @dev The inner logic of `multicall`.
    /// This function is included so that you can override `multicall`
    /// to add before and after actions, and use the `_multicallDirectReturn` function.
    function _multicall(bytes[] calldata data) internal virtual returns (bytes32 results) {
        /// @solidity memory-safe-assembly
        assembly {
            results := mload(0x40)
            mstore(results, 0x20)
            mstore(add(0x20, results), data.length)
            let c := add(0x40, results)
            let s := c
            let end := shl(5, data.length)
            calldatacopy(c, data.offset, end)
            end := add(c, end)
            let m := end
            if data.length {
                for {} 1 {} {
                    let o := add(data.offset, mload(c))
                    calldatacopy(m, add(o, 0x20), calldataload(o))
                    // forgefmt: disable-next-item
                    if iszero(delegatecall(gas(), address(), m, calldataload(o), codesize(), 0x00)) {
                        // Bubble up the revert if the delegatecall reverts.
                        returndatacopy(results, 0x00, returndatasize())
                        revert(results, returndatasize())
                    }
                    mstore(c, sub(m, s))
                    c := add(0x20, c)
                    // Append the `returndatasize()`, and the return data.
                    mstore(m, returndatasize())
                    let b := add(m, 0x20)
                    returndatacopy(b, 0x00, returndatasize())
                    // Advance `m` by `returndatasize() + 0x20`,
                    // rounded up to the next multiple of 32.
                    m := and(add(add(b, returndatasize()), 0x1f), 0xffffffffffffffe0)
                    mstore(add(b, returndatasize()), 0) // Zeroize the slot after the returndata.
                    if iszero(lt(c, end)) { break }
                }
            }
            mstore(0x40, m) // Allocate memory.
            results := or(shl(64, m), results) // Pack the bytes length into `results`.
        }
    }

    /// @dev Decodes the `results` into an array of bytes.
    /// This can be useful if you need to access the results or re-encode it.
    function _multicallResultsToBytesArray(bytes32 results)
        internal
        pure
        virtual
        returns (bytes[] memory decoded)
    {
        /// @solidity memory-safe-assembly
        assembly {
            decoded := mload(0x40)
            let c := and(0xffffffffffffffff, results) // Extract the offset.
            mstore(decoded, mload(add(c, 0x20))) // Store the length.
            let o := add(decoded, 0x20) // Start of elements in `decoded`.
            let end := add(o, shl(5, mload(decoded)))
            mstore(0x40, end) // Allocate memory.
            let s := add(c, 0x40) // Start of elements in `results`.
            let d := sub(s, o) // Difference between input and output pointers.
            for {} iszero(eq(o, end)) { o := add(o, 0x20) } { mstore(o, add(mload(add(d, o)), s)) }
        }
    }

    /// @dev Directly returns the `results` and terminates the current call context.
    /// `results` must be from `_multicall`, else behavior is undefined.
    function _multicallDirectReturn(bytes32 results) internal pure virtual {
        /// @solidity memory-safe-assembly
        assembly {
            return(and(0xffffffffffffffff, results), shr(64, results))
        }
    }
}

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "solady/=lib/solady/src/",
    "@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "@openzeppelin/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
    "solady/=lib/solady/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"InvalidColorBitDepth","type":"error"},{"inputs":[],"name":"InvalidColorBits","type":"error"},{"inputs":[],"name":"InvalidColorDataLength","type":"error"},{"inputs":[],"name":"InvalidLayerActiveRegionConfig","type":"error"},{"inputs":[],"name":"InvalidLayerIdsLength","type":"error"},{"inputs":[],"name":"InvalidLayerInactiveBgColor","type":"error"},{"inputs":[],"name":"InvalidPaletteId","type":"error"},{"inputs":[],"name":"InvalidPixelBits","type":"error"},{"inputs":[],"name":"InvalidPixelSize","type":"error"},{"inputs":[],"name":"PixelLayerNotExists","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"paletteId","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"uint256","name":"bitsPerColor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalColors","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"colorDataSize","type":"uint256"},{"indexed":false,"internalType":"address","name":"creator","type":"address"}],"name":"PaletteCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pixelRefId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pixelDataLength","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"pixelHash","type":"bytes32"}],"name":"PixelDataCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"layerId","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"uint256","name":"zIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"width","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"height","type":"uint256"},{"components":[{"internalType":"uint256","name":"xTL","type":"uint256"},{"internalType":"uint256","name":"yTL","type":"uint256"},{"internalType":"uint256","name":"xBR","type":"uint256"},{"internalType":"uint256","name":"yBR","type":"uint256"}],"indexed":false,"internalType":"struct PixelLayerRegistry.RectRegion","name":"activeRegion","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"regionPixelRefId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bgColor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paletteId","type":"uint256"},{"indexed":false,"internalType":"address","name":"creator","type":"address"}],"name":"PixelLayerCreated","type":"event"},{"inputs":[],"name":"BITS_PER_COLOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMPTY_PIXEL_LAYER_ID","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BITS_PER_PIXEL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"}],"name":"compositeLayers","outputs":[{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"},{"internalType":"bytes","name":"pixelBuffer","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layerParam","type":"tuple"},{"internalType":"bytes","name":"pixels","type":"bytes"},{"internalType":"uint256","name":"paletteId","type":"uint256"}],"name":"createLayer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layerParam","type":"tuple"},{"components":[{"internalType":"uint256","name":"xTL","type":"uint256"},{"internalType":"uint256","name":"yTL","type":"uint256"},{"internalType":"uint256","name":"xBR","type":"uint256"},{"internalType":"uint256","name":"yBR","type":"uint256"}],"internalType":"struct PixelLayerRegistry.RectRegion","name":"regionParam","type":"tuple"},{"internalType":"uint256","name":"bgcolorOrIndex","type":"uint256"},{"internalType":"uint256","name":"pixelRefId","type":"uint256"},{"internalType":"uint256","name":"paletteId","type":"uint256"}],"name":"createLayer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layerParam","type":"tuple"},{"components":[{"internalType":"uint256","name":"xTL","type":"uint256"},{"internalType":"uint256","name":"yTL","type":"uint256"},{"internalType":"uint256","name":"xBR","type":"uint256"},{"internalType":"uint256","name":"yBR","type":"uint256"}],"internalType":"struct PixelLayerRegistry.RectRegion","name":"regionParam","type":"tuple"},{"internalType":"uint256","name":"bgcolorOrIndex","type":"uint256"},{"internalType":"bytes","name":"pixels","type":"bytes"},{"internalType":"uint256","name":"paletteId","type":"uint256"}],"name":"createLayer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layerParam","type":"tuple"},{"internalType":"uint256","name":"pixelRefId","type":"uint256"},{"internalType":"uint256","name":"paletteId","type":"uint256"}],"name":"createLayer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint8","name":"bitsPerColor","type":"uint8"},{"internalType":"bytes","name":"colorData","type":"bytes"}],"name":"createPalette","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint8","name":"bitsPerColor","type":"uint8"},{"internalType":"bytes","name":"colorData","type":"bytes"}],"internalType":"struct PixelLayerResolver.PaletteParam","name":"palette","type":"tuple"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layer","type":"tuple"},{"components":[{"internalType":"uint256","name":"xTL","type":"uint256"},{"internalType":"uint256","name":"yTL","type":"uint256"},{"internalType":"uint256","name":"xBR","type":"uint256"},{"internalType":"uint256","name":"yBR","type":"uint256"}],"internalType":"struct PixelLayerRegistry.RectRegion","name":"regionParam","type":"tuple"},{"internalType":"uint256","name":"bgcolorOrIndex","type":"uint256"},{"internalType":"bytes","name":"pixels","type":"bytes"}],"internalType":"struct PixelLayerResolver.LayerAndPixelParam[]","name":"param1","type":"tuple[]"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layer","type":"tuple"},{"components":[{"internalType":"uint256","name":"xTL","type":"uint256"},{"internalType":"uint256","name":"yTL","type":"uint256"},{"internalType":"uint256","name":"xBR","type":"uint256"},{"internalType":"uint256","name":"yBR","type":"uint256"}],"internalType":"struct PixelLayerRegistry.RectRegion","name":"regionParam","type":"tuple"},{"internalType":"uint256","name":"bgcolorOrIndex","type":"uint256"},{"internalType":"uint256","name":"pixelRefId","type":"uint256"}],"internalType":"struct PixelLayerResolver.LayerAndPixelRefParam[]","name":"param2","type":"tuple[]"}],"name":"createPaletteAndLayer","outputs":[{"internalType":"uint256","name":"paletteId","type":"uint256"},{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"},{"internalType":"uint256[]","name":"layerWithRefIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"pixels","type":"bytes"}],"name":"createPixelData","outputs":[{"internalType":"uint256","name":"pixelRefId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"}],"name":"genBMPFromLayers","outputs":[{"internalType":"bytes","name":"bmp","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"}],"name":"genSVGFromLayers","outputs":[{"internalType":"bytes","name":"svg","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"layerId","type":"uint256"}],"name":"getLayer","outputs":[{"components":[{"internalType":"uint8","name":"zIndex","type":"uint8"},{"internalType":"uint8","name":"bitsPerPixel","type":"uint8"},{"internalType":"uint16","name":"width","type":"uint16"},{"internalType":"uint16","name":"height","type":"uint16"},{"internalType":"uint16","name":"xTL","type":"uint16"},{"internalType":"uint16","name":"yTL","type":"uint16"},{"internalType":"uint16","name":"xBR","type":"uint16"},{"internalType":"uint16","name":"yBR","type":"uint16"},{"internalType":"uint32","name":"pixelRefId","type":"uint32"},{"internalType":"uint32","name":"bgColor","type":"uint32"},{"internalType":"uint32","name":"paletteId","type":"uint32"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct PixelLayerRegistry.Layer","name":"layer","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"}],"name":"getLayers","outputs":[{"components":[{"internalType":"uint8","name":"zIndex","type":"uint8"},{"internalType":"uint8","name":"bitsPerPixel","type":"uint8"},{"internalType":"uint16","name":"width","type":"uint16"},{"internalType":"uint16","name":"height","type":"uint16"},{"internalType":"uint16","name":"xTL","type":"uint16"},{"internalType":"uint16","name":"yTL","type":"uint16"},{"internalType":"uint16","name":"xBR","type":"uint16"},{"internalType":"uint16","name":"yBR","type":"uint16"},{"internalType":"uint32","name":"pixelRefId","type":"uint32"},{"internalType":"uint32","name":"bgColor","type":"uint32"},{"internalType":"uint32","name":"paletteId","type":"uint32"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct PixelLayerRegistry.Layer[]","name":"layers","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"paletteId","type":"uint256"}],"name":"getPalette","outputs":[{"components":[{"internalType":"uint8","name":"bitsPerColor","type":"uint8"},{"internalType":"uint32","name":"totalColors","type":"uint32"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes","name":"colors","type":"bytes"}],"internalType":"struct PaletteRegistry.Palette","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"paletteIds","type":"uint256[]"}],"name":"getPalettes","outputs":[{"components":[{"internalType":"uint8","name":"bitsPerColor","type":"uint8"},{"internalType":"uint32","name":"totalColors","type":"uint32"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes","name":"colors","type":"bytes"}],"internalType":"struct PaletteRegistry.Palette[]","name":"palettes","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pixelRefId","type":"uint256"}],"name":"getPixelData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastLayerId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPaletteId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"}],"name":"sortLayersByZIndex","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"}]

6080604052348015600e575f5ffd5b506139df8061001c5f395ff3fe60806040526004361061016d575f3560e01c8063837ab668116100c6578063ac9650d81161007c578063df0c783811610057578063df0c783814610316578063dfdaf5281461040d578063f781e3ae14610439575f5ffd5b8063ac9650d8146103ba578063c278dba3146103da578063ccbe1ed2146103f9575f5ffd5b806394ac753e116100ac57806394ac753e14610368578063a21abed81461037c578063a26327ff1461039b575f5ffd5b8063837ab6681461032a57806390c302e714610349575f5ffd5b8063505e570a1161012657806360ff37bc1161010157806360ff37bc146102cb5780636abf7826146102f75780637b7e260514610316575f5ffd5b8063505e570a1461024b57806351c39604146102775780635840b0f81461029f575f5ffd5b80632cc4dcb6116101565780632cc4dcb6146101cf57806347d02b81146101ee57806349f83b1f1461021c575f5ffd5b80630d499331146101715780631adb75ac146101a3575b5f5ffd5b34801561017c575f5ffd5b5061019061018b366004612d98565b610465565b6040519081526020015b60405180910390f35b3480156101ae575f5ffd5b506101c26101bd366004612e49565b6104a5565b60405161019a9190612fc2565b3480156101da575f5ffd5b506101906101e93660046130cb565b610731565b3480156101f9575f5ffd5b5061020d610208366004613130565b61080a565b60405161019a93929190613208565b348015610227575f5ffd5b5061023b610236366004613232565b6109ea565b60405161019a94939291906132de565b348015610256575f5ffd5b5061026a610265366004613302565b610c72565b60405161019a9190613363565b348015610282575f5ffd5b5061028a5f81565b60405163ffffffff909116815260200161019a565b3480156102aa575f5ffd5b506102be6102b9366004613302565b610e10565b60405161019a9190613375565b3480156102d6575f5ffd5b506102ea6102e5366004613232565b610ecd565b60405161019a9190613387565b348015610302575f5ffd5b506102be610311366004613232565b610edc565b348015610321575f5ffd5b50610190602081565b348015610335575f5ffd5b50610190610344366004613399565b610eff565b348015610354575f5ffd5b50610190610363366004613427565b610fb7565b348015610373575f5ffd5b50610190610ff5565b348015610387575f5ffd5b506102be610396366004613232565b611024565b3480156103a6575f5ffd5b506101906103b5366004613486565b611047565b6103cd6103c8366004612e49565b61111c565b60405161019a91906134f6565b3480156103e5575f5ffd5b506101906103f436600461354d565b611140565b348015610404575f5ffd5b50610190611191565b348015610418575f5ffd5b5061042c610427366004612e49565b6111b8565b60405161019a9190613580565b348015610444575f5ffd5b50610458610453366004613302565b6113f4565b60405161019a91906135d7565b5f61049c8560405180608001604052805f81526020015f81526020018860600135815260200188608001358152505f878787610eff565b95945050505050565b6060818067ffffffffffffffff8111156104c1576104c1613025565b60405190808252806020026020018201604052801561055057816020015b60408051610180810182525f808252602080830182905292820181905260608083018290526080830182905260a0830182905260c0830182905260e083018290526101008301829052610120830182905261014083019190915261016082015282525f199092019101816104df5790505b5091507f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d4015f5b8281101561072857815f878784818110610592576105926135e9565b63ffffffff6020918202939093013583168452838101949094525060409182015f20825161018081018452815460ff80821683526101008083049091169683019690965261ffff6201000082048116958301959095526401000000008104851660608301526601000000000000810485166080830152680100000000000000008104851660a08301526a01000000000000000000008104851660c0830152600160601b810490941660e0820152600160701b8404831694810194909452600160901b83048216610120850152600160b01b9092041661014083015260018101805461016084019190610683906135fd565b80601f01602080910402602001604051908101604052809291908181526020018280546106af906135fd565b80156106fa5780601f106106d1576101008083540402835291602001916106fa565b820191905f5260205f20905b8154815290600101906020018083116106dd57829003601f168201915b505050505081525050848281518110610715576107156135e9565b6020908102919091010152600101610576565b50505092915050565b5f61074b8585886060013589608001358a60400135611566565b6107d38660400135865f015187604001516107669190613643565b8760200151886060015161077a9190613643565b6107c17f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d4006107a789611626565b63ffffffff165f9081526002919091016020526040902090565b80546107cc906135fd565b905061165b565b5f82116107f357604051632b4582a560e01b815260040160405180910390fd5b6108008686868686611706565b9695505050505050565b5f60608061083861081b8980613656565b61082b60408c0160208d01613699565b6103b560408d018d613656565b9250858067ffffffffffffffff81111561085457610854613025565b60405190808252806020026020018201604052801561087d578160200160208202803683370190505b5092505f5b8181101561090e573689898381811061089d5761089d6135e9565b90506020028101906108af91906136b2565b90506108e86108be82806136d0565b6108d0368490038401602085016136e4565b60a08401356108e260c0860186613656565b8b610eff565b8583815181106108fa576108fa6135e9565b602090810291909101015250600101610882565b508490508067ffffffffffffffff81111561092b5761092b613025565b604051908082528060200260200182016040528015610954578160200160208202803683370190505b5091505f5b818110156109dd5736878783818110610974576109746135e9565b905060200281019061098691906136b2565b90506109b761099582806136d0565b6109a7368490038401602085016136e4565b8360a001358460c001358a610731565b8483815181106109c9576109c96135e9565b602090810291909101015250600101610959565b5050955095509592505050565b5f5f5f60605f855190505f8111610a2d576040517f21fa0dc700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a3686611a29565b5f5f606080610a7b6040518061010001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b610a9d8b5f81518110610a9057610a906135e9565b6020026020010151611bac565b60c083015160e0840151909d509b509097509195509093509050610ac085611d9c565b8160ff169150809350819b50505060038a901c888a020267ffffffffffffffff811115610aef57610aef613025565b6040519080825280601f01601f191660200182016040528015610b19576020820181803683370190505b508151909750158015610b2e57506020810151155b8015610b3d5750888160400151145b8015610b4c5750878160600151145b15610b6357610b5e8783858d88611e7f565b610b7d565b610b6f87838c84611fb1565b610b7d8783858d888661217e565b60015b86811015610c64575f610b9e8d8381518110610a9057610a906135e9565b92985091965093509050868114610bfb57809650610bbb87611d9c565b945060ff1690508b8114610bfb576040517f23f838ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251158015610c0c57506020830151155b8015610c1b57508a8360400151145b8015610c2a5750898360600151145b15610c4157610c3c8985878f8a611e7f565b610c5b565b610c4d89858e86611fb1565b610c5b8985878f8a8861217e565b50600101610b80565b505050505050509193509193565b60408051608080820183525f808352602080840182905260608486018190528085015263ffffffff86811683527f3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca77263320182529185902085519384018652805460ff81168552610100900490921690830152600181018054939492939192840191610cf9906135fd565b80601f0160208091040260200160405190810160405280929190818152602001828054610d25906135fd565b8015610d705780601f10610d4757610100808354040283529160200191610d70565b820191905f5260205f20905b815481529060010190602001808311610d5357829003601f168201915b50505050508152602001600282018054610d89906135fd565b80601f0160208091040260200160405190810160405280929190818152602001828054610db5906135fd565b8015610e005780601f10610dd757610100808354040283529160200191610e00565b820191905f5260205f20905b815481529060010190602001808311610de357829003601f168201915b5050505050815250509050919050565b6060610e3f7f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d4006107a784611626565b8054610e4a906135fd565b80601f0160208091040260200160405190810160405280929190818152602001828054610e76906135fd565b8015610ec15780601f10610e9857610100808354040283529160200191610ec1565b820191905f5260205f20905b815481529060010190602001808311610ea457829003601f168201915b50505050509050919050565b6060610ed882611a29565b5090565b60605f5f5f5f610eeb866109ea565b9350935093509350610800848484846122fb565b5f610f19868689606001358a608001358b60400135611566565b610f4e8760400135875f01518860400151610f349190613643565b88602001518960600151610f489190613643565b8661165b565b5f8211610f6e57604051632b4582a560e01b815260040160405180910390fd5b7f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d4005f610f9b8287876123c6565b9050610faa8989898488611706565b9998505050505050505050565b5f610fed8460405180608001604052805f81526020015f81526020018760600135815260200187608001358152505f8686610731565b949350505050565b5f7f3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca7726332005b5463ffffffff16919050565b60605f5f5f5f611033866109ea565b93509350935093506108008484848461247f565b7f3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca77263320080545f91908290829082906110829063ffffffff166136fe565b825463ffffffff9182166101009390930a83810292021916179091555f81815260018401602052604090209091506110be818a8a8a8a8a6125d9565b817f73b05f94061684c43b9361fa65b5b965397451ddaa3035fce829f4fdc43997168a8a8a6110f4601f600383901c168b613736565b60405161110894939291908c903390613771565b60405180910390a250979650505050505050565b60603415611128575f5ffd5b61113a61113584846126c7565b612753565b92915050565b5f8161115f576040516306e5cf7960e21b815260040160405180910390fd5b61118a7f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d40084846123c6565b9392505050565b5f7f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d400611018565b6060818067ffffffffffffffff8111156111d4576111d4613025565b60405190808252806020026020018201604052801561122757816020015b604080516080810182525f80825260208201526060918101829052818101919091528152602001906001900390816111f25790505b5091507f3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca7726332015f5b8281101561072857815f878784818110611269576112696135e9565b63ffffffff6020918202939093013583168452838101949094525060409182015f208251608081018452815460ff811682526101009004909216938201939093526001830180549193928401916112bf906135fd565b80601f01602080910402602001604051908101604052809291908181526020018280546112eb906135fd565b80156113365780601f1061130d57610100808354040283529160200191611336565b820191905f5260205f20905b81548152906001019060200180831161131957829003601f168201915b5050505050815260200160028201805461134f906135fd565b80601f016020809104026020016040519081016040528092919081815260200182805461137b906135fd565b80156113c65780601f1061139d576101008083540402835291602001916113c6565b820191905f5260205f20905b8154815290600101906020018083116113a957829003601f168201915b5050505050815250508482815181106113e1576113e16135e9565b602090810291909101015260010161124d565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201929092526101608101919091527f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d40063ffffffff8084165f90815260019283016020908152604091829020825161018081018452815460ff80821683526101008083049091169483019490945261ffff6201000082048116958301959095526401000000008104851660608301526601000000000000810485166080830152680100000000000000008104851660a08301526a01000000000000000000008104851660c0830152600160601b810490941660e0820152600160701b8404851692810192909252600160901b83048416610120830152600160b01b909204909216610140830152918201805491929161016084019190610d89906135fd565b604085015185511180159061157f575082856040015111155b801561159357508460600151856020015111155b80156115a3575081856060015111155b6115d9576040517f45e4a28400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115e6600180831b613643565b84111561161f576040517f24aad79700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b5f63ffffffff821115610ed8576040516306dfcc6560e41b815260206004820152602481018390526044015b60405180910390fd5b835f10801561166b575060208411155b801561167e57506001640101010116851c165b6116b4576040517f10c88af100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f846116c084866137c2565b6116ca91906137c2565b90505f60036116da8360076137d9565b901c90508083146116fe576040516306e5cf7960e21b815260040160405180910390fd5b505050505050565b7f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d40080545f91908190839061173f9063ffffffff166136fe565b825463ffffffff9182166101009390930a83810292021916179091555f81815260018301602052604081209193506117778980613656565b9050111561179b576117898880613656565b6001830191611799919083613830565b505b6117a88860200135612764565b815460ff191660ff919091161781556117c46040890135612764565b815460ff919091166101000261ff00199091161781556117e76060890135612791565b815461ffff91909116620100000263ffff00001990911617815561180e6080890135612791565b815461ffff919091166401000000000265ffff0000000019909116178155865161183790612791565b815461ffff9190911666010000000000000267ffff00000000000019909116178155602087015161186790612791565b815461ffff91909116680100000000000000000269ffff000000000000000019909116178155604087015161189b90612791565b815461ffff919091166a0100000000000000000000026bffff000000000000000000001990911617815560608701516118d390612791565b815461ffff91909116600160601b026dffff0000000000000000000000001990911617815561190186611626565b815463ffffffff91909116600160901b027fffffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffff90911617815561194284611626565b815463ffffffff91909116600160b01b027fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff90911617815561198385611626565b815463ffffffff91909116600160701b027fffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffff90911617905550807f354260e53682a8b55f8da011fb4d880b47efb2d44dd4c2502511508e3cd59d276119e88880613656565b89602001358a604001358b606001358c608001358c8b8d8c33604051611a189b9a999897969594939291906138ea565b60405180910390a295945050505050565b60208101517f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d4019063ffffffff811115611a7f576040516306dfcc6560e41b81526020600482015260248101829052604401611652565b50815160015b81811015611ba6575f611aa6611aa1868460051b016020015190565b611626565b63ffffffff81165f90815260208690526040902054909150610100900460ff16611afc576040517f2eb8a6de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff81165f9081526020859052604090205460ff16825b5f81118015611b51575081865f611b368a6001860360051b016020015190565b63ffffffff16815260208101919091526040015f205460ff16115b15611b8657611b7e8782611b6e8a6001860360051b016020015190565b808260051b602085010152505050565b5f1901611b16565b63ffffffff8316600582901b880160200152505050806001019050611a85565b50505050565b5f611bed6040518061010001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b63ffffffff8381165f9081527f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d40160209081526040808320805461ffff620100008204811660c08901526401000000008204811660e08901526601000000000000820481168089526801000000000000000083048216958901959095526a010000000000000000000082048116938801849052600160601b820416606088810191909152600160901b8204909616608088015260ff6101009091041696509293927f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d400929091611cdb9190613643565b60a0860152805463ffffffff600160701b820481165f9081526002850160205260409020600160b01b9092041694508054611d15906135fd565b80601f0160208091040260200160405190810160405280929190818152602001828054611d41906135fd565b8015611d8c5780601f10611d6357610100808354040283529160200191611d8c565b820191905f5260205f20905b815481529060010190602001808311611d6f57829003601f168201915b5050505050925050509193509193565b5f6060817f3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca77263320181611dcb86611626565b63ffffffff16815260208101919091526040015f20805460028201805460ff9092169550919250611dfb906135fd565b80601f0160208091040260200160405190810160405280929190818152602001828054611e27906135fd565b8015611e725780601f10611e4957610100808354040283529160200191611e72565b820191905f5260205f20905b815481529060010190602001808311611e5557829003601f168201915b5050505050915050915091565b8451600383901c9004600180841b5f1990810191841b015f5b83811015611fa6576020858202600381811c8a01830151600792831689016101009081039190911c86168a029182901c8c01909301515f9391909216890190031c841660ff8116808303611eee57505050611f9e565b838902600381901c8d0160200180519450906007168a016101000360ff831015611f895784811c8816611f858582865f8160ff038060ff8560181c16028360ff8760181c16020160081c8160ff8660101c16028460ff8860101c16020160081c8260ff8760081c16028560ff8960081c16020160081c9250848360081b8260101b8460181b17171796505050508390509392505050565b9450505b87811b19949094169290931b91909117909152505b600101611e98565b505050505050505050565b60808101516020908302600381901c85018201519183015160079091168401610100039190911c6001841b5f190116901561203b5761203b8582856040518061010001604052805f81526020015f81526020018760c001518152602001876020015181526020015f81526020018760c0015181526020018760c0015181526020015f8152506127bf565b8160e00151826060015110156120a4576120a48582856040518061010001604052805f8152602001876060015181526020018760c0015181526020018760e0015181526020015f81526020018760c0015181526020018760c0015181526020015f8152506127bf565b815115612102576121028582856040518061010001604052805f815260200187602001518152602001875f01518152602001876060015181526020015f8152602001875f015181526020018760c0015181526020015f8152506127bf565b8160c001518260400151101561161f5761161f85828560405180610100016040528087604001518152602001876020015181526020018760c001518152602001876060015181526020015f815260200187604001518860c001516121669190613643565b81526020018760c0015181526020015f8152506127bf565b5f8052600180841b5f1990810191841b015b8260600151836020015110156122f157825160c0840151602085015160a086015191029091019081015b808210156122df575f80516020908802600381811c8c0183015160079283168b016101009081039190911c88168c029182901c8e019093015191168a019091031c85169060ff8216900361221b5760015f51015f52600183019250506121ba565b60078389029081168901610100039060031c8c0160200160ff83811610156122b8578051821c87166122b4848260ff82165f8160ff038060ff8560181c16028360ff8760181c16020160081c8160ff8660101c16028460ff8860101c16020160081c8260ff8760081c16028560ff8960081c16020160081c9250848360081b8260101b8460181b17171796505050508390509392505050565b9350505b86821b8019825116905083831b811782525060015f51015f526001850194505050506121ba565b50506020830180516001019052612190565b5050505050505050565b60606018851115600386811c86028082166004039091160184025f612322607c600e6137d9565b905061232e82826137d9565b67ffffffffffffffff81111561234657612346613025565b6040519080825280601f01601f191660200182016040528015612370576020820181803683370190505b50935061237f84855183612913565b6123a084607c8486612392576003612394565b5f5b60ff165f8c8c8f612940565b6123a9846129a1565b6123bb8486838a8a60038e901c6129ee565b505050949350505050565b82545f9084906004906123e690640100000000900463ffffffff166136fe565b825463ffffffff9182166101009390930a83810292021916179091555f818152600286016020526040902090915061241f838583613830565b50807f346bf82ec5020791c432a36ed3f70a81bfba0a2321f643108f8ee31a0e0a4a1b848490508585604051612456929190613987565b604051908190038120612470928252602082015260400190565b60405180910390a29392505050565b6040516f30313233343536373839616263646566600f52602081016124a5818686612a38565b90505f196001871b015f5b8581101561258e575f5f19828902825b8a811015612559578082018c02600381901c8a01602001515f916007168e01610100031c871690508060ff165f0361251d575f198410156125115761250a88868888860388612b60565b97505f1993505b81600101945050612551565b5f1984036125305780935081945061254f565b83811461254f5761254688868888860388612b60565b97508093508194505b505b6001016124c0565b505f198210801561256957508983105b156125805761257d868486868e0386612b60565b95505b5050508060010190506124b0565b50507f3c2f7376673e000000000000000000000000000000000000000000000000000081528181036019190182526006808201601f9081166020031690910101604052949350505050565b60208360ff1614612616576040517ff7765fcc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601f600384901c1681801580159061263557506126338282613996565b155b61266b576040517f9b95bcaa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85156126825760018801612680878983613830565b505b875460ff191660ff861617885561269c611aa18383613736565b885463ffffffff919091166101000264ffffffff001990911617885560028801611fa6848683613830565b5f60405190506020815281816020015280604001808360051b808684378201808515612741575b8351870180356020820183375f38823584305af461270e573d5f873e3d86fd5b5082810384523d815260209384019381013d5f823e5f3d8201523d01601f0167ffffffffffffffe01690508184106126ee575b60408181521b90931795945050505050565b8060401c8167ffffffffffffffff16f35b5f60ff821115610ed8576040516306dfcc6560e41b81526008600482015260248101839052604401611652565b5f61ffff821115610ed8576040516306dfcc6560e41b81526010600482015260248101839052604401611652565b5f196001831b0160ff84165f8190036127d9575050611ba6565b60208301515b836060015181101561290a57835160c085015160a086015190830290910190810160ff84900361284e575b8082101561284957868202600781168801610100038160031c60208c0101915086811b801983511690508a821b8117835250505081600101915061280a565b612900565b8082101561290057818702600381901c8a0160200180516007909216890161010003915f6128e48c83861c8b168a5f8160ff038060ff8560181c16028360ff8760181c16020160081c8160ff8660101c16028460ff8860101c16020160081c8260ff8760081c16028560ff8960081c16020160081c9250848360081b8260101b8460181b17171796505050508390509392505050565b89851b19929092169190931b179052506001919091019061284e565b50506001016127df565b50505050505050565b6020830160428153604d60018201535061292f83600284612c81565b61293b83600a83612c81565b505050565b61294c88600e89612c81565b61295888601285612c81565b61296488601684612c81565b61297188601a6001612cab565b61297d88601c83612cab565b61298988601e87612c81565b61299588602288612c81565b6122f188602e86612c81565b6129b081603662ff0000612c81565b6129be81603a61ff00612c81565b6129cb81603e60ff612c81565b6129db81604263ff000000612c81565b6129eb8160466373524742612c81565b50565b808302600380821660040316810185602089010160208801600186035f5b87811015612a2a57858682028401868385030286015e600101612a0c565b505050505050505050505050565b7f3c7376672073686170652d72656e646572696e673d226372697370456467657383527f222077696474683d22000000000000000000000000000000000000000000000060208401526029909201915f612a928484612cc3565b7f22206865696768743d22000000000000000000000000000000000000000000008152600a019350612ac48483612cc3565b7f222076696577426f783d223020302000000000000000000000000000000000008152600f019350612af68484612cc3565b935060208453600184019350612b0c8483612cc3565b7f2220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f81527f737667223e0000000000000000000000000000000000000000000000000000006020820152602501949350505050565b5f7f3c7061746820643d224d000000000000000000000000000000000000000000008652600a86019550612b948686612cc3565b955060208653600186019550612baa8685612cc3565b7f763168000000000000000000000000000000000000000000000000000000000081526003019550612bdc8684612cc3565b95507f762d31222066696c6c3d222300000000000000000000000000000000000000008652600c860195505f601883901c60ff1690505f601084901c60ff1690505f600885901c60ff1690505f8560ff169050612c4d8a82600887901b601087901b601887901b1717176008612d08565b7f222f3e000000000000000000000000000000000000000000000000000000000081526003019a9950505050505050505050565b8160208401018181538160081c60018201538160101c60028201538160181c600382015350505050565b8160208401018181538160081c600182015350505050565b5f6001600a83045b8015612ce15760019190910190600a9004612ccb565b508301805b600182039150600a84066030018253600a8404935083612ce657949350505050565b5f818401805b600f8516516001198201915f190153600f8560041c165181538460081c9450858118612d0e5750949350505050565b5f60a08284031215612d4d575f5ffd5b50919050565b5f5f83601f840112612d63575f5ffd5b50813567ffffffffffffffff811115612d7a575f5ffd5b602083019150836020828501011115612d91575f5ffd5b9250929050565b5f5f5f5f60608587031215612dab575f5ffd5b843567ffffffffffffffff811115612dc1575f5ffd5b612dcd87828801612d3d565b945050602085013567ffffffffffffffff811115612de9575f5ffd5b612df587828801612d53565b9598909750949560400135949350505050565b5f5f83601f840112612e18575f5ffd5b50813567ffffffffffffffff811115612e2f575f5ffd5b6020830191508360208260051b8501011115612d91575f5ffd5b5f5f60208385031215612e5a575f5ffd5b823567ffffffffffffffff811115612e70575f5ffd5b612e7c85828601612e08565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b805160ff1682525f6020820151612ed2602085018260ff169052565b506040820151612ee8604085018261ffff169052565b506060820151612efe606085018261ffff169052565b506080820151612f14608085018261ffff169052565b5060a0820151612f2a60a085018261ffff169052565b5060c0820151612f4060c085018261ffff169052565b5060e0820151612f5660e085018261ffff169052565b50610100820151612f7061010085018263ffffffff169052565b50610120820151612f8a61012085018263ffffffff169052565b50610140820151612fa461014085018263ffffffff169052565b50610160820151610180610160850152610fed610180850182612e88565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561301957603f19878603018452613004858351612eb6565b94506020938401939190910190600101612fe8565b50929695505050505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561306257613062613025565b604052919050565b5f6080828403121561307a575f5ffd5b6040516080810167ffffffffffffffff8111828210171561309d5761309d613025565b6040908152833582526020808501359083015283810135908201526060928301359281019290925250919050565b5f5f5f5f5f61010086880312156130e0575f5ffd5b853567ffffffffffffffff8111156130f6575f5ffd5b61310288828901612d3d565b955050613112876020880161306a565b949794965050505060a08301359260c08101359260e0909101359150565b5f5f5f5f5f60608688031215613144575f5ffd5b853567ffffffffffffffff81111561315a575f5ffd5b86016060818903121561316b575f5ffd5b9450602086013567ffffffffffffffff811115613186575f5ffd5b61319288828901612e08565b909550935050604086013567ffffffffffffffff8111156131b1575f5ffd5b6131bd88828901612e08565b969995985093965092949392505050565b5f8151808452602084019350602083015f5b828110156131fe5781518652602095860195909101906001016131e0565b5093949350505050565b838152606060208201525f61322060608301856131ce565b828103604084015261080081856131ce565b5f60208284031215613242575f5ffd5b813567ffffffffffffffff811115613258575f5ffd5b8201601f81018413613268575f5ffd5b803567ffffffffffffffff81111561328257613282613025565b8060051b61329260208201613039565b918252602081840181019290810190878411156132ad575f5ffd5b6020850194505b838510156132d3578435808352602095860195909350909101906132b4565b979650505050505050565b848152836020820152826040820152608060608201525f6108006080830184612e88565b5f60208284031215613312575f5ffd5b5035919050565b60ff815116825263ffffffff60208201511660208301525f60408201516080604085015261334a6080850182612e88565b90506060830151848203606086015261049c8282612e88565b602081525f61118a6020830184613319565b602081525f61118a6020830184612e88565b602081525f61118a60208301846131ce565b5f5f5f5f5f5f61010087890312156133af575f5ffd5b863567ffffffffffffffff8111156133c5575f5ffd5b6133d189828a01612d3d565b9650506133e1886020890161306a565b945060a0870135935060c087013567ffffffffffffffff811115613403575f5ffd5b61340f89828a01612d53565b979a969950949794969560e090950135949350505050565b5f5f5f60608486031215613439575f5ffd5b833567ffffffffffffffff81111561344f575f5ffd5b61345b86828701612d3d565b9660208601359650604090950135949350505050565b803560ff81168114613481575f5ffd5b919050565b5f5f5f5f5f6060868803121561349a575f5ffd5b853567ffffffffffffffff8111156134b0575f5ffd5b6134bc88828901612d53565b90965094506134cf905060208701613471565b9250604086013567ffffffffffffffff8111156134ea575f5ffd5b6131bd88828901612d53565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561301957603f19878603018452613538858351612e88565b9450602093840193919091019060010161351c565b5f5f6020838503121561355e575f5ffd5b823567ffffffffffffffff811115613574575f5ffd5b612e7c85828601612d53565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561301957603f198786030184526135c2858351613319565b945060209384019391909101906001016135a6565b602081525f61118a6020830184612eb6565b634e487b7160e01b5f52603260045260245ffd5b600181811c9082168061361157607f821691505b602082108103612d4d57634e487b7160e01b5f52602260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8181038181111561113a5761113a61362f565b5f5f8335601e1984360301811261366b575f5ffd5b83018035915067ffffffffffffffff821115613685575f5ffd5b602001915036819003821315612d91575f5ffd5b5f602082840312156136a9575f5ffd5b61118a82613471565b5f823560de198336030181126136c6575f5ffd5b9190910192915050565b5f8235609e198336030181126136c6575f5ffd5b5f608082840312156136f4575f5ffd5b61118a838361306a565b5f63ffffffff821663ffffffff81036137195761371961362f565b60010192915050565b634e487b7160e01b5f52601260045260245ffd5b5f8261374457613744613722565b500490565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60a081525f61378460a08301888a613749565b905060ff8616602083015284604083015283606083015273ffffffffffffffffffffffffffffffffffffffff83166080830152979650505050505050565b808202811582820484141761113a5761113a61362f565b8082018082111561113a5761113a61362f565b601f82111561293b57805f5260205f20601f840160051c810160208510156138115750805b601f840160051c820191505b8181101561161f575f815560010161381d565b67ffffffffffffffff83111561384857613848613025565b61385c8361385683546135fd565b836137ec565b5f601f84116001811461388d575f85156138765750838201355b5f19600387901b1c1916600186901b17835561161f565b5f83815260208120601f198716915b828110156138bc578685013582556020948501946001909201910161389c565b50868210156138d8575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6101a081525f6138ff6101a083018d8f613749565b90508a6020830152896040830152886060830152876080830152865160a0830152602087015160c0830152604087015160e0830152606087015161010083015285610120830152846101408301528361016083015261397761018083018473ffffffffffffffffffffffffffffffffffffffff169052565b9c9b505050505050505050505050565b818382375f9101908152919050565b5f826139a4576139a4613722565b50069056fea264697066735822122077e89be32244d9ce82ae1ea1924731e0e0932d6723068d44b818e677ab9d501064736f6c634300081c0033

Deployed Bytecode

0x60806040526004361061016d575f3560e01c8063837ab668116100c6578063ac9650d81161007c578063df0c783811610057578063df0c783814610316578063dfdaf5281461040d578063f781e3ae14610439575f5ffd5b8063ac9650d8146103ba578063c278dba3146103da578063ccbe1ed2146103f9575f5ffd5b806394ac753e116100ac57806394ac753e14610368578063a21abed81461037c578063a26327ff1461039b575f5ffd5b8063837ab6681461032a57806390c302e714610349575f5ffd5b8063505e570a1161012657806360ff37bc1161010157806360ff37bc146102cb5780636abf7826146102f75780637b7e260514610316575f5ffd5b8063505e570a1461024b57806351c39604146102775780635840b0f81461029f575f5ffd5b80632cc4dcb6116101565780632cc4dcb6146101cf57806347d02b81146101ee57806349f83b1f1461021c575f5ffd5b80630d499331146101715780631adb75ac146101a3575b5f5ffd5b34801561017c575f5ffd5b5061019061018b366004612d98565b610465565b6040519081526020015b60405180910390f35b3480156101ae575f5ffd5b506101c26101bd366004612e49565b6104a5565b60405161019a9190612fc2565b3480156101da575f5ffd5b506101906101e93660046130cb565b610731565b3480156101f9575f5ffd5b5061020d610208366004613130565b61080a565b60405161019a93929190613208565b348015610227575f5ffd5b5061023b610236366004613232565b6109ea565b60405161019a94939291906132de565b348015610256575f5ffd5b5061026a610265366004613302565b610c72565b60405161019a9190613363565b348015610282575f5ffd5b5061028a5f81565b60405163ffffffff909116815260200161019a565b3480156102aa575f5ffd5b506102be6102b9366004613302565b610e10565b60405161019a9190613375565b3480156102d6575f5ffd5b506102ea6102e5366004613232565b610ecd565b60405161019a9190613387565b348015610302575f5ffd5b506102be610311366004613232565b610edc565b348015610321575f5ffd5b50610190602081565b348015610335575f5ffd5b50610190610344366004613399565b610eff565b348015610354575f5ffd5b50610190610363366004613427565b610fb7565b348015610373575f5ffd5b50610190610ff5565b348015610387575f5ffd5b506102be610396366004613232565b611024565b3480156103a6575f5ffd5b506101906103b5366004613486565b611047565b6103cd6103c8366004612e49565b61111c565b60405161019a91906134f6565b3480156103e5575f5ffd5b506101906103f436600461354d565b611140565b348015610404575f5ffd5b50610190611191565b348015610418575f5ffd5b5061042c610427366004612e49565b6111b8565b60405161019a9190613580565b348015610444575f5ffd5b50610458610453366004613302565b6113f4565b60405161019a91906135d7565b5f61049c8560405180608001604052805f81526020015f81526020018860600135815260200188608001358152505f878787610eff565b95945050505050565b6060818067ffffffffffffffff8111156104c1576104c1613025565b60405190808252806020026020018201604052801561055057816020015b60408051610180810182525f808252602080830182905292820181905260608083018290526080830182905260a0830182905260c0830182905260e083018290526101008301829052610120830182905261014083019190915261016082015282525f199092019101816104df5790505b5091507f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d4015f5b8281101561072857815f878784818110610592576105926135e9565b63ffffffff6020918202939093013583168452838101949094525060409182015f20825161018081018452815460ff80821683526101008083049091169683019690965261ffff6201000082048116958301959095526401000000008104851660608301526601000000000000810485166080830152680100000000000000008104851660a08301526a01000000000000000000008104851660c0830152600160601b810490941660e0820152600160701b8404831694810194909452600160901b83048216610120850152600160b01b9092041661014083015260018101805461016084019190610683906135fd565b80601f01602080910402602001604051908101604052809291908181526020018280546106af906135fd565b80156106fa5780601f106106d1576101008083540402835291602001916106fa565b820191905f5260205f20905b8154815290600101906020018083116106dd57829003601f168201915b505050505081525050848281518110610715576107156135e9565b6020908102919091010152600101610576565b50505092915050565b5f61074b8585886060013589608001358a60400135611566565b6107d38660400135865f015187604001516107669190613643565b8760200151886060015161077a9190613643565b6107c17f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d4006107a789611626565b63ffffffff165f9081526002919091016020526040902090565b80546107cc906135fd565b905061165b565b5f82116107f357604051632b4582a560e01b815260040160405180910390fd5b6108008686868686611706565b9695505050505050565b5f60608061083861081b8980613656565b61082b60408c0160208d01613699565b6103b560408d018d613656565b9250858067ffffffffffffffff81111561085457610854613025565b60405190808252806020026020018201604052801561087d578160200160208202803683370190505b5092505f5b8181101561090e573689898381811061089d5761089d6135e9565b90506020028101906108af91906136b2565b90506108e86108be82806136d0565b6108d0368490038401602085016136e4565b60a08401356108e260c0860186613656565b8b610eff565b8583815181106108fa576108fa6135e9565b602090810291909101015250600101610882565b508490508067ffffffffffffffff81111561092b5761092b613025565b604051908082528060200260200182016040528015610954578160200160208202803683370190505b5091505f5b818110156109dd5736878783818110610974576109746135e9565b905060200281019061098691906136b2565b90506109b761099582806136d0565b6109a7368490038401602085016136e4565b8360a001358460c001358a610731565b8483815181106109c9576109c96135e9565b602090810291909101015250600101610959565b5050955095509592505050565b5f5f5f60605f855190505f8111610a2d576040517f21fa0dc700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a3686611a29565b5f5f606080610a7b6040518061010001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b610a9d8b5f81518110610a9057610a906135e9565b6020026020010151611bac565b60c083015160e0840151909d509b509097509195509093509050610ac085611d9c565b8160ff169150809350819b50505060038a901c888a020267ffffffffffffffff811115610aef57610aef613025565b6040519080825280601f01601f191660200182016040528015610b19576020820181803683370190505b508151909750158015610b2e57506020810151155b8015610b3d5750888160400151145b8015610b4c5750878160600151145b15610b6357610b5e8783858d88611e7f565b610b7d565b610b6f87838c84611fb1565b610b7d8783858d888661217e565b60015b86811015610c64575f610b9e8d8381518110610a9057610a906135e9565b92985091965093509050868114610bfb57809650610bbb87611d9c565b945060ff1690508b8114610bfb576040517f23f838ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251158015610c0c57506020830151155b8015610c1b57508a8360400151145b8015610c2a5750898360600151145b15610c4157610c3c8985878f8a611e7f565b610c5b565b610c4d89858e86611fb1565b610c5b8985878f8a8861217e565b50600101610b80565b505050505050509193509193565b60408051608080820183525f808352602080840182905260608486018190528085015263ffffffff86811683527f3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca77263320182529185902085519384018652805460ff81168552610100900490921690830152600181018054939492939192840191610cf9906135fd565b80601f0160208091040260200160405190810160405280929190818152602001828054610d25906135fd565b8015610d705780601f10610d4757610100808354040283529160200191610d70565b820191905f5260205f20905b815481529060010190602001808311610d5357829003601f168201915b50505050508152602001600282018054610d89906135fd565b80601f0160208091040260200160405190810160405280929190818152602001828054610db5906135fd565b8015610e005780601f10610dd757610100808354040283529160200191610e00565b820191905f5260205f20905b815481529060010190602001808311610de357829003601f168201915b5050505050815250509050919050565b6060610e3f7f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d4006107a784611626565b8054610e4a906135fd565b80601f0160208091040260200160405190810160405280929190818152602001828054610e76906135fd565b8015610ec15780601f10610e9857610100808354040283529160200191610ec1565b820191905f5260205f20905b815481529060010190602001808311610ea457829003601f168201915b50505050509050919050565b6060610ed882611a29565b5090565b60605f5f5f5f610eeb866109ea565b9350935093509350610800848484846122fb565b5f610f19868689606001358a608001358b60400135611566565b610f4e8760400135875f01518860400151610f349190613643565b88602001518960600151610f489190613643565b8661165b565b5f8211610f6e57604051632b4582a560e01b815260040160405180910390fd5b7f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d4005f610f9b8287876123c6565b9050610faa8989898488611706565b9998505050505050505050565b5f610fed8460405180608001604052805f81526020015f81526020018760600135815260200187608001358152505f8686610731565b949350505050565b5f7f3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca7726332005b5463ffffffff16919050565b60605f5f5f5f611033866109ea565b93509350935093506108008484848461247f565b7f3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca77263320080545f91908290829082906110829063ffffffff166136fe565b825463ffffffff9182166101009390930a83810292021916179091555f81815260018401602052604090209091506110be818a8a8a8a8a6125d9565b817f73b05f94061684c43b9361fa65b5b965397451ddaa3035fce829f4fdc43997168a8a8a6110f4601f600383901c168b613736565b60405161110894939291908c903390613771565b60405180910390a250979650505050505050565b60603415611128575f5ffd5b61113a61113584846126c7565b612753565b92915050565b5f8161115f576040516306e5cf7960e21b815260040160405180910390fd5b61118a7f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d40084846123c6565b9392505050565b5f7f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d400611018565b6060818067ffffffffffffffff8111156111d4576111d4613025565b60405190808252806020026020018201604052801561122757816020015b604080516080810182525f80825260208201526060918101829052818101919091528152602001906001900390816111f25790505b5091507f3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca7726332015f5b8281101561072857815f878784818110611269576112696135e9565b63ffffffff6020918202939093013583168452838101949094525060409182015f208251608081018452815460ff811682526101009004909216938201939093526001830180549193928401916112bf906135fd565b80601f01602080910402602001604051908101604052809291908181526020018280546112eb906135fd565b80156113365780601f1061130d57610100808354040283529160200191611336565b820191905f5260205f20905b81548152906001019060200180831161131957829003601f168201915b5050505050815260200160028201805461134f906135fd565b80601f016020809104026020016040519081016040528092919081815260200182805461137b906135fd565b80156113c65780601f1061139d576101008083540402835291602001916113c6565b820191905f5260205f20905b8154815290600101906020018083116113a957829003601f168201915b5050505050815250508482815181106113e1576113e16135e9565b602090810291909101015260010161124d565b60408051610180810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201929092526101608101919091527f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d40063ffffffff8084165f90815260019283016020908152604091829020825161018081018452815460ff80821683526101008083049091169483019490945261ffff6201000082048116958301959095526401000000008104851660608301526601000000000000810485166080830152680100000000000000008104851660a08301526a01000000000000000000008104851660c0830152600160601b810490941660e0820152600160701b8404851692810192909252600160901b83048416610120830152600160b01b909204909216610140830152918201805491929161016084019190610d89906135fd565b604085015185511180159061157f575082856040015111155b801561159357508460600151856020015111155b80156115a3575081856060015111155b6115d9576040517f45e4a28400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115e6600180831b613643565b84111561161f576040517f24aad79700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b5f63ffffffff821115610ed8576040516306dfcc6560e41b815260206004820152602481018390526044015b60405180910390fd5b835f10801561166b575060208411155b801561167e57506001640101010116851c165b6116b4576040517f10c88af100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f846116c084866137c2565b6116ca91906137c2565b90505f60036116da8360076137d9565b901c90508083146116fe576040516306e5cf7960e21b815260040160405180910390fd5b505050505050565b7f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d40080545f91908190839061173f9063ffffffff166136fe565b825463ffffffff9182166101009390930a83810292021916179091555f81815260018301602052604081209193506117778980613656565b9050111561179b576117898880613656565b6001830191611799919083613830565b505b6117a88860200135612764565b815460ff191660ff919091161781556117c46040890135612764565b815460ff919091166101000261ff00199091161781556117e76060890135612791565b815461ffff91909116620100000263ffff00001990911617815561180e6080890135612791565b815461ffff919091166401000000000265ffff0000000019909116178155865161183790612791565b815461ffff9190911666010000000000000267ffff00000000000019909116178155602087015161186790612791565b815461ffff91909116680100000000000000000269ffff000000000000000019909116178155604087015161189b90612791565b815461ffff919091166a0100000000000000000000026bffff000000000000000000001990911617815560608701516118d390612791565b815461ffff91909116600160601b026dffff0000000000000000000000001990911617815561190186611626565b815463ffffffff91909116600160901b027fffffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffff90911617815561194284611626565b815463ffffffff91909116600160b01b027fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff90911617815561198385611626565b815463ffffffff91909116600160701b027fffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffff90911617905550807f354260e53682a8b55f8da011fb4d880b47efb2d44dd4c2502511508e3cd59d276119e88880613656565b89602001358a604001358b606001358c608001358c8b8d8c33604051611a189b9a999897969594939291906138ea565b60405180910390a295945050505050565b60208101517f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d4019063ffffffff811115611a7f576040516306dfcc6560e41b81526020600482015260248101829052604401611652565b50815160015b81811015611ba6575f611aa6611aa1868460051b016020015190565b611626565b63ffffffff81165f90815260208690526040902054909150610100900460ff16611afc576040517f2eb8a6de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff81165f9081526020859052604090205460ff16825b5f81118015611b51575081865f611b368a6001860360051b016020015190565b63ffffffff16815260208101919091526040015f205460ff16115b15611b8657611b7e8782611b6e8a6001860360051b016020015190565b808260051b602085010152505050565b5f1901611b16565b63ffffffff8316600582901b880160200152505050806001019050611a85565b50505050565b5f611bed6040518061010001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b63ffffffff8381165f9081527f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d40160209081526040808320805461ffff620100008204811660c08901526401000000008204811660e08901526601000000000000820481168089526801000000000000000083048216958901959095526a010000000000000000000082048116938801849052600160601b820416606088810191909152600160901b8204909616608088015260ff6101009091041696509293927f48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d400929091611cdb9190613643565b60a0860152805463ffffffff600160701b820481165f9081526002850160205260409020600160b01b9092041694508054611d15906135fd565b80601f0160208091040260200160405190810160405280929190818152602001828054611d41906135fd565b8015611d8c5780601f10611d6357610100808354040283529160200191611d8c565b820191905f5260205f20905b815481529060010190602001808311611d6f57829003601f168201915b5050505050925050509193509193565b5f6060817f3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca77263320181611dcb86611626565b63ffffffff16815260208101919091526040015f20805460028201805460ff9092169550919250611dfb906135fd565b80601f0160208091040260200160405190810160405280929190818152602001828054611e27906135fd565b8015611e725780601f10611e4957610100808354040283529160200191611e72565b820191905f5260205f20905b815481529060010190602001808311611e5557829003601f168201915b5050505050915050915091565b8451600383901c9004600180841b5f1990810191841b015f5b83811015611fa6576020858202600381811c8a01830151600792831689016101009081039190911c86168a029182901c8c01909301515f9391909216890190031c841660ff8116808303611eee57505050611f9e565b838902600381901c8d0160200180519450906007168a016101000360ff831015611f895784811c8816611f858582865f8160ff038060ff8560181c16028360ff8760181c16020160081c8160ff8660101c16028460ff8860101c16020160081c8260ff8760081c16028560ff8960081c16020160081c9250848360081b8260101b8460181b17171796505050508390509392505050565b9450505b87811b19949094169290931b91909117909152505b600101611e98565b505050505050505050565b60808101516020908302600381901c85018201519183015160079091168401610100039190911c6001841b5f190116901561203b5761203b8582856040518061010001604052805f81526020015f81526020018760c001518152602001876020015181526020015f81526020018760c0015181526020018760c0015181526020015f8152506127bf565b8160e00151826060015110156120a4576120a48582856040518061010001604052805f8152602001876060015181526020018760c0015181526020018760e0015181526020015f81526020018760c0015181526020018760c0015181526020015f8152506127bf565b815115612102576121028582856040518061010001604052805f815260200187602001518152602001875f01518152602001876060015181526020015f8152602001875f015181526020018760c0015181526020015f8152506127bf565b8160c001518260400151101561161f5761161f85828560405180610100016040528087604001518152602001876020015181526020018760c001518152602001876060015181526020015f815260200187604001518860c001516121669190613643565b81526020018760c0015181526020015f8152506127bf565b5f8052600180841b5f1990810191841b015b8260600151836020015110156122f157825160c0840151602085015160a086015191029091019081015b808210156122df575f80516020908802600381811c8c0183015160079283168b016101009081039190911c88168c029182901c8e019093015191168a019091031c85169060ff8216900361221b5760015f51015f52600183019250506121ba565b60078389029081168901610100039060031c8c0160200160ff83811610156122b8578051821c87166122b4848260ff82165f8160ff038060ff8560181c16028360ff8760181c16020160081c8160ff8660101c16028460ff8860101c16020160081c8260ff8760081c16028560ff8960081c16020160081c9250848360081b8260101b8460181b17171796505050508390509392505050565b9350505b86821b8019825116905083831b811782525060015f51015f526001850194505050506121ba565b50506020830180516001019052612190565b5050505050505050565b60606018851115600386811c86028082166004039091160184025f612322607c600e6137d9565b905061232e82826137d9565b67ffffffffffffffff81111561234657612346613025565b6040519080825280601f01601f191660200182016040528015612370576020820181803683370190505b50935061237f84855183612913565b6123a084607c8486612392576003612394565b5f5b60ff165f8c8c8f612940565b6123a9846129a1565b6123bb8486838a8a60038e901c6129ee565b505050949350505050565b82545f9084906004906123e690640100000000900463ffffffff166136fe565b825463ffffffff9182166101009390930a83810292021916179091555f818152600286016020526040902090915061241f838583613830565b50807f346bf82ec5020791c432a36ed3f70a81bfba0a2321f643108f8ee31a0e0a4a1b848490508585604051612456929190613987565b604051908190038120612470928252602082015260400190565b60405180910390a29392505050565b6040516f30313233343536373839616263646566600f52602081016124a5818686612a38565b90505f196001871b015f5b8581101561258e575f5f19828902825b8a811015612559578082018c02600381901c8a01602001515f916007168e01610100031c871690508060ff165f0361251d575f198410156125115761250a88868888860388612b60565b97505f1993505b81600101945050612551565b5f1984036125305780935081945061254f565b83811461254f5761254688868888860388612b60565b97508093508194505b505b6001016124c0565b505f198210801561256957508983105b156125805761257d868486868e0386612b60565b95505b5050508060010190506124b0565b50507f3c2f7376673e000000000000000000000000000000000000000000000000000081528181036019190182526006808201601f9081166020031690910101604052949350505050565b60208360ff1614612616576040517ff7765fcc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601f600384901c1681801580159061263557506126338282613996565b155b61266b576040517f9b95bcaa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85156126825760018801612680878983613830565b505b875460ff191660ff861617885561269c611aa18383613736565b885463ffffffff919091166101000264ffffffff001990911617885560028801611fa6848683613830565b5f60405190506020815281816020015280604001808360051b808684378201808515612741575b8351870180356020820183375f38823584305af461270e573d5f873e3d86fd5b5082810384523d815260209384019381013d5f823e5f3d8201523d01601f0167ffffffffffffffe01690508184106126ee575b60408181521b90931795945050505050565b8060401c8167ffffffffffffffff16f35b5f60ff821115610ed8576040516306dfcc6560e41b81526008600482015260248101839052604401611652565b5f61ffff821115610ed8576040516306dfcc6560e41b81526010600482015260248101839052604401611652565b5f196001831b0160ff84165f8190036127d9575050611ba6565b60208301515b836060015181101561290a57835160c085015160a086015190830290910190810160ff84900361284e575b8082101561284957868202600781168801610100038160031c60208c0101915086811b801983511690508a821b8117835250505081600101915061280a565b612900565b8082101561290057818702600381901c8a0160200180516007909216890161010003915f6128e48c83861c8b168a5f8160ff038060ff8560181c16028360ff8760181c16020160081c8160ff8660101c16028460ff8860101c16020160081c8260ff8760081c16028560ff8960081c16020160081c9250848360081b8260101b8460181b17171796505050508390509392505050565b89851b19929092169190931b179052506001919091019061284e565b50506001016127df565b50505050505050565b6020830160428153604d60018201535061292f83600284612c81565b61293b83600a83612c81565b505050565b61294c88600e89612c81565b61295888601285612c81565b61296488601684612c81565b61297188601a6001612cab565b61297d88601c83612cab565b61298988601e87612c81565b61299588602288612c81565b6122f188602e86612c81565b6129b081603662ff0000612c81565b6129be81603a61ff00612c81565b6129cb81603e60ff612c81565b6129db81604263ff000000612c81565b6129eb8160466373524742612c81565b50565b808302600380821660040316810185602089010160208801600186035f5b87811015612a2a57858682028401868385030286015e600101612a0c565b505050505050505050505050565b7f3c7376672073686170652d72656e646572696e673d226372697370456467657383527f222077696474683d22000000000000000000000000000000000000000000000060208401526029909201915f612a928484612cc3565b7f22206865696768743d22000000000000000000000000000000000000000000008152600a019350612ac48483612cc3565b7f222076696577426f783d223020302000000000000000000000000000000000008152600f019350612af68484612cc3565b935060208453600184019350612b0c8483612cc3565b7f2220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f81527f737667223e0000000000000000000000000000000000000000000000000000006020820152602501949350505050565b5f7f3c7061746820643d224d000000000000000000000000000000000000000000008652600a86019550612b948686612cc3565b955060208653600186019550612baa8685612cc3565b7f763168000000000000000000000000000000000000000000000000000000000081526003019550612bdc8684612cc3565b95507f762d31222066696c6c3d222300000000000000000000000000000000000000008652600c860195505f601883901c60ff1690505f601084901c60ff1690505f600885901c60ff1690505f8560ff169050612c4d8a82600887901b601087901b601887901b1717176008612d08565b7f222f3e000000000000000000000000000000000000000000000000000000000081526003019a9950505050505050505050565b8160208401018181538160081c60018201538160101c60028201538160181c600382015350505050565b8160208401018181538160081c600182015350505050565b5f6001600a83045b8015612ce15760019190910190600a9004612ccb565b508301805b600182039150600a84066030018253600a8404935083612ce657949350505050565b5f818401805b600f8516516001198201915f190153600f8560041c165181538460081c9450858118612d0e5750949350505050565b5f60a08284031215612d4d575f5ffd5b50919050565b5f5f83601f840112612d63575f5ffd5b50813567ffffffffffffffff811115612d7a575f5ffd5b602083019150836020828501011115612d91575f5ffd5b9250929050565b5f5f5f5f60608587031215612dab575f5ffd5b843567ffffffffffffffff811115612dc1575f5ffd5b612dcd87828801612d3d565b945050602085013567ffffffffffffffff811115612de9575f5ffd5b612df587828801612d53565b9598909750949560400135949350505050565b5f5f83601f840112612e18575f5ffd5b50813567ffffffffffffffff811115612e2f575f5ffd5b6020830191508360208260051b8501011115612d91575f5ffd5b5f5f60208385031215612e5a575f5ffd5b823567ffffffffffffffff811115612e70575f5ffd5b612e7c85828601612e08565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b805160ff1682525f6020820151612ed2602085018260ff169052565b506040820151612ee8604085018261ffff169052565b506060820151612efe606085018261ffff169052565b506080820151612f14608085018261ffff169052565b5060a0820151612f2a60a085018261ffff169052565b5060c0820151612f4060c085018261ffff169052565b5060e0820151612f5660e085018261ffff169052565b50610100820151612f7061010085018263ffffffff169052565b50610120820151612f8a61012085018263ffffffff169052565b50610140820151612fa461014085018263ffffffff169052565b50610160820151610180610160850152610fed610180850182612e88565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561301957603f19878603018452613004858351612eb6565b94506020938401939190910190600101612fe8565b50929695505050505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561306257613062613025565b604052919050565b5f6080828403121561307a575f5ffd5b6040516080810167ffffffffffffffff8111828210171561309d5761309d613025565b6040908152833582526020808501359083015283810135908201526060928301359281019290925250919050565b5f5f5f5f5f61010086880312156130e0575f5ffd5b853567ffffffffffffffff8111156130f6575f5ffd5b61310288828901612d3d565b955050613112876020880161306a565b949794965050505060a08301359260c08101359260e0909101359150565b5f5f5f5f5f60608688031215613144575f5ffd5b853567ffffffffffffffff81111561315a575f5ffd5b86016060818903121561316b575f5ffd5b9450602086013567ffffffffffffffff811115613186575f5ffd5b61319288828901612e08565b909550935050604086013567ffffffffffffffff8111156131b1575f5ffd5b6131bd88828901612e08565b969995985093965092949392505050565b5f8151808452602084019350602083015f5b828110156131fe5781518652602095860195909101906001016131e0565b5093949350505050565b838152606060208201525f61322060608301856131ce565b828103604084015261080081856131ce565b5f60208284031215613242575f5ffd5b813567ffffffffffffffff811115613258575f5ffd5b8201601f81018413613268575f5ffd5b803567ffffffffffffffff81111561328257613282613025565b8060051b61329260208201613039565b918252602081840181019290810190878411156132ad575f5ffd5b6020850194505b838510156132d3578435808352602095860195909350909101906132b4565b979650505050505050565b848152836020820152826040820152608060608201525f6108006080830184612e88565b5f60208284031215613312575f5ffd5b5035919050565b60ff815116825263ffffffff60208201511660208301525f60408201516080604085015261334a6080850182612e88565b90506060830151848203606086015261049c8282612e88565b602081525f61118a6020830184613319565b602081525f61118a6020830184612e88565b602081525f61118a60208301846131ce565b5f5f5f5f5f5f61010087890312156133af575f5ffd5b863567ffffffffffffffff8111156133c5575f5ffd5b6133d189828a01612d3d565b9650506133e1886020890161306a565b945060a0870135935060c087013567ffffffffffffffff811115613403575f5ffd5b61340f89828a01612d53565b979a969950949794969560e090950135949350505050565b5f5f5f60608486031215613439575f5ffd5b833567ffffffffffffffff81111561344f575f5ffd5b61345b86828701612d3d565b9660208601359650604090950135949350505050565b803560ff81168114613481575f5ffd5b919050565b5f5f5f5f5f6060868803121561349a575f5ffd5b853567ffffffffffffffff8111156134b0575f5ffd5b6134bc88828901612d53565b90965094506134cf905060208701613471565b9250604086013567ffffffffffffffff8111156134ea575f5ffd5b6131bd88828901612d53565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561301957603f19878603018452613538858351612e88565b9450602093840193919091019060010161351c565b5f5f6020838503121561355e575f5ffd5b823567ffffffffffffffff811115613574575f5ffd5b612e7c85828601612d53565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561301957603f198786030184526135c2858351613319565b945060209384019391909101906001016135a6565b602081525f61118a6020830184612eb6565b634e487b7160e01b5f52603260045260245ffd5b600181811c9082168061361157607f821691505b602082108103612d4d57634e487b7160e01b5f52602260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8181038181111561113a5761113a61362f565b5f5f8335601e1984360301811261366b575f5ffd5b83018035915067ffffffffffffffff821115613685575f5ffd5b602001915036819003821315612d91575f5ffd5b5f602082840312156136a9575f5ffd5b61118a82613471565b5f823560de198336030181126136c6575f5ffd5b9190910192915050565b5f8235609e198336030181126136c6575f5ffd5b5f608082840312156136f4575f5ffd5b61118a838361306a565b5f63ffffffff821663ffffffff81036137195761371961362f565b60010192915050565b634e487b7160e01b5f52601260045260245ffd5b5f8261374457613744613722565b500490565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60a081525f61378460a08301888a613749565b905060ff8616602083015284604083015283606083015273ffffffffffffffffffffffffffffffffffffffff83166080830152979650505050505050565b808202811582820484141761113a5761113a61362f565b8082018082111561113a5761113a61362f565b601f82111561293b57805f5260205f20601f840160051c810160208510156138115750805b601f840160051c820191505b8181101561161f575f815560010161381d565b67ffffffffffffffff83111561384857613848613025565b61385c8361385683546135fd565b836137ec565b5f601f84116001811461388d575f85156138765750838201355b5f19600387901b1c1916600186901b17835561161f565b5f83815260208120601f198716915b828110156138bc578685013582556020948501946001909201910161389c565b50868210156138d8575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6101a081525f6138ff6101a083018d8f613749565b90508a6020830152896040830152886060830152876080830152865160a0830152602087015160c0830152604087015160e0830152606087015161010083015285610120830152846101408301528361016083015261397761018083018473ffffffffffffffffffffffffffffffffffffffff169052565b9c9b505050505050505050505050565b818382375f9101908152919050565b5f826139a4576139a4613722565b50069056fea264697066735822122077e89be32244d9ce82ae1ea1924731e0e0932d6723068d44b818e677ab9d501064736f6c634300081c0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.