ETH Price: $3,428.60 (+2.47%)

Token

ghoulBalls (🎊)
 

Overview

Max Total Supply

0 🎊

Holders

126

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A

Other Info

Balance
2 🎊
0xdaf6f334d49abf1065e6d1dbf5ea04f563d424c2
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
ghoulBalls

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 6 : ghoulBalls.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

import {ERC721} from "solmate/tokens/ERC721.sol";
import {Owned} from "solmate/auth/Owned.sol";
import {libImg} from "../src/libImg.sol";
import {png} from "../src/png.sol";
import {json} from "../src/JSON.sol";

interface IBasedGhouls {
    function ownerOf(uint256 id) external view returns (address owner);
}

contract ghoulBalls is ERC721, Owned(msg.sender) {

    uint32 constant WIDTH_AND_HEIGHT = 128;
    int256 constant CIRCLE_RADIUS = 69;

    IBasedGhouls ghouls = IBasedGhouls(0xeF1a89cbfAbE59397FfdA11Fc5DF293E9bC5Db90);

    mapping(uint256 => bytes) internal colours;

    function _hash(bytes memory SAUCE) internal pure returns(bytes memory) {
        return abi.encodePacked(keccak256(SAUCE));
    }

    function toUint256(bytes memory _bytes) internal pure returns (uint256) {
        require(_bytes.length >= 32, "toUint256_outOfBounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(_bytes, 0x20))
        }

        return tempUint;
    }

    // Each RGB is 3 bytes, determine number of balls that will be in the PNG then generate the colours
    function _generateColour(uint256 id) internal view returns(bytes memory) {
        uint256 randomish = toUint256(_hash(abi.encodePacked(id, msg.sender, block.timestamp)));

        if((randomish % 69) > 60) {
            return abi.encodePacked((uint144(randomish))); //6
        } else if((randomish % 69) > 50) {
            return abi.encodePacked((uint96(randomish))); //4
        } else if((randomish % 69) > 40) {
            return abi.encodePacked((uint48(randomish))); //2
        } else {
            return abi.encodePacked((uint24(randomish))); //1
        }
        
    }

    function mint_the_ball(uint256 id) public {
        require(id < 10000, "invalid ball.");
        if (id<6666) {
            require(ghouls.ownerOf(id) == msg.sender, "not your ghoul.");
        }
        require(_ownerOf[id] == address(0), "someone else got this ghoulBall.");

        colours[id] = _generateColour(id);

        _mint(msg.sender, id);
    }

    function click_for_utility(uint256 id) public {
        _burn(id);
    }

    function getPalette(uint256 id) internal view returns (bytes3[] memory) {
        bytes memory _coloursArr = colours[id];

        bytes3[] memory palette = new bytes3[](_coloursArr.length/3);

        for(uint256 i = 0; i<palette.length; i++) {
            palette[i] = 
                bytes3(
                    bytes.concat(
                        _coloursArr[i*3],
                        _coloursArr[i*3+1],
                        _coloursArr[i*3+2]
                    )
                );
        }

        return palette;
    }

    function tokenPNG(uint256 id) public view returns (string memory) {
        bytes3[] memory _palette = getPalette(id);

        libImg.IMAGE memory imgPixels = libImg.IMAGE(
            WIDTH_AND_HEIGHT,
            WIDTH_AND_HEIGHT,
            new bytes(WIDTH_AND_HEIGHT*WIDTH_AND_HEIGHT+1)
        );
        
        return png.encodedPNG(WIDTH_AND_HEIGHT, WIDTH_AND_HEIGHT, _palette, libImg.drawImage(imgPixels, _palette.length), true);

    }

    function tokenAttributes(uint256 id) internal view returns (string memory) {
        bytes memory plte = colours[id];

        string memory palettes;
        bool last;

        for (uint256 i = 0; i<plte.length/3; i++) {
            last = (i == (plte.length/3-1)) ? true : false;

            palettes = string.concat(
                palettes,
                json._attr(
                    string.concat('ball ', json.toString(i+1)),
                    string.concat(
                        json.toString(uint8(plte[i*3])),
                        ', ',
                        json.toString(uint8(plte[i*3+1])),
                        ', ',
                        json.toString(uint8(plte[i*3+2]))
                    ),
                    last
                )
            );
        }

        // we attach the number of balls, and colour palette to the ERC721 JSON
        return string.concat(
            json._attr('ball count', json.toString(plte.length/3)),
            palettes
        );

    }

    function tokenURI(uint256 id) public view override returns (string memory) {
        return json.formattedMetadata(
            'ghoulBalls',
            "ghoulBalls are fully onchain PNGs that evolve with every block, absolutely rugging the right-click savers after everyblock. No roadmap, no development, no utility, no marketing, and nothing more. They promise nothing and deliver even less. They're just PNGs.",
            tokenPNG(id),
            tokenAttributes(id)
        );
    }

    //never know if they'll rug us again with a v3
    function updateGhoulAddr(address ghoulAddr) public onlyOwner {
        ghouls = IBasedGhouls(ghoulAddr);
    }
    
    constructor() ERC721("ghoulBalls", unicode"🎊"){}

}

File 2 of 6 : ERC721.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    event Approval(address indexed owner, address indexed spender, uint256 indexed id);

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /*//////////////////////////////////////////////////////////////
                         METADATA STORAGE/LOGIC
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*//////////////////////////////////////////////////////////////
                      ERC721 BALANCE/OWNER STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) internal _ownerOf;

    mapping(address => uint256) internal _balanceOf;

    function ownerOf(uint256 id) public view virtual returns (address owner) {
        require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
    }

    function balanceOf(address owner) public view virtual returns (uint256) {
        require(owner != address(0), "ZERO_ADDRESS");

        return _balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                         ERC721 APPROVAL STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*//////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = _ownerOf[id];

        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(from == _ownerOf[id], "WRONG_FROM");

        require(to != address(0), "INVALID_RECIPIENT");

        require(
            msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
            "NOT_AUTHORIZED"
        );

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            _balanceOf[from]--;

            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes calldata data
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(_ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        emit Transfer(address(0), to, id);
    }

    function _burn(uint256 id) internal virtual {
        address owner = _ownerOf[id];

        require(owner != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            _balanceOf[owner]--;
        }

        delete _ownerOf[id];

        delete getApproved[id];

        emit Transfer(owner, address(0), id);
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }
}

/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC721TokenReceiver.onERC721Received.selector;
    }
}

File 3 of 6 : Owned.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnerUpdated(address indexed user, address indexed newOwner);

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

        emit OwnerUpdated(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function setOwner(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnerUpdated(msg.sender, newOwner);
    }
}

File 4 of 6 : libImg.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;

library libImg {

    struct IMAGE{
        uint256 width;
        uint256 height;
        bytes pixels;
    }

    function toIndex(int256 _x, int256 _y, uint256 _width) internal pure returns (uint256 index){
        unchecked{
            index = uint256(_y) * (_width +1) + uint256(_x) + 1;
        }
        
    }

    function assignMidPoint(uint256 seed, uint256 width, uint256 height) internal pure returns (int256 x, int256 y) {

        x = int256(
                (
                    ((seed >> 2*8) % width) +
                    (width / 2)
                ) /2
            );

        y = int256(
                (
                    ((seed) % height) +
                    (height / 2)

                ) /2
            );


    }

    function rasterFilledCircle(IMAGE memory img, int256 xMid, int256 yMid, int256 r, bytes1 idxColour) internal pure returns (IMAGE memory) {

        int256 xSym;
        int256 ySym;
        int256 x = 0;
        int256 y = int(r);

        unchecked {
            for (x = xMid - r ; x <= xMid; x++) {
                for (y = yMid - r ; y <= yMid; y++) {
                    if ((x - xMid)*(x - xMid) + (y - yMid)*(y - yMid) <= r*r) 
                    {
                        xSym = xMid - (x - xMid);
                        ySym = yMid - (y - yMid);
                        // (x, y), (x, ySym), (xSym , y), (xSym, ySym) are in the circle
                        if (x >= 0 && y >= 0) {
                            img.pixels[toIndex(x, y,img.width)] = idxColour;
                        }
                        if (x >= 0 && ySym >= 0) {
                            img.pixels[toIndex(x, ySym,img.width)] = idxColour;
                        }
                        if (xSym >= 0 && y >= 0) {
                            img.pixels[toIndex(xSym, y,img.width)] = idxColour;
                        }
                        if (xSym >= 0 && ySym >= 0) {
                            img.pixels[toIndex(xSym, ySym,img.width)] = idxColour;
                        }
                    }
                }
            }
        }
        return img;
    }

    function drawImage(IMAGE memory img, uint256 circleCount) internal view returns (bytes memory){

        IMAGE memory tempImg;
        int256 xMid;
        int256 yMid;
        uint256 randoSeed;

        for (uint8 i = 0; i<circleCount; i++) {
            randoSeed = uint256(keccak256(abi.encodePacked(block.timestamp, i)));
            (xMid, yMid) = assignMidPoint(randoSeed, img.width, img.height);

            tempImg = rasterFilledCircle(img, xMid, yMid, int256(18), bytes1(i+1));
        }
        
        return tempImg.pixels;

    }

}

File 5 of 6 : png.sol
// SPDX-License-Identifier: Unlicense
/*
 * @title Onchain PNGs
 * @author Colin Platt <[email protected]>
 *
 * @dev PNG encoding tools written in Solidity for producing read-only onchain PNG files.
 */

pragma solidity =0.8.13;

library png {
    
    struct RGBA {
        bytes1 red;
        bytes1 green;
        bytes1 blue;
    }

    function rgbToPalette(bytes1 red, bytes1 green, bytes1 blue) internal pure returns (bytes3) {
        return bytes3(abi.encodePacked(red, green, blue));
    }

    function rgbToPalette(RGBA memory _rgb) internal pure returns (bytes3) {
        return bytes3(abi.encodePacked(_rgb.red, _rgb.green, _rgb.blue));
    }

    function calculateBitDepth(uint256 _length) internal pure returns (uint256) {
        if (_length < 3) {
            return 2;
        } else if(_length < 5) {
            return 4;
        } else if(_length < 17) {
            return 16;
        } else {
            return 256;
        }
    }

    function formatPalette(bytes3[] memory _palette, bool _8bit) internal pure returns (bytes memory) {
        require(_palette.length <= 256, "PNG: Palette too large.");

        uint256 depth = _8bit? uint256(256) : calculateBitDepth(_palette.length);
        bytes memory paletteObj;

        for (uint i = 0; i<_palette.length; i++) {
            paletteObj = abi.encodePacked(paletteObj, _palette[i]);
        }

        for (uint i = _palette.length; i<depth-1; i++) {
            paletteObj = abi.encodePacked(paletteObj, bytes3(0x000000));
        }

        return abi.encodePacked(
            uint32(depth*3),
            'PLTE',
            bytes3(0x000000),
            paletteObj
        );
    }

    function _tRNS(uint256 _bitDepth, uint256 _palette) internal pure returns (bytes memory) {

        bytes memory tRNSObj = abi.encodePacked(bytes1(0x00));

        for (uint i = 0; i<_palette; i++) {
            tRNSObj = abi.encodePacked(tRNSObj, bytes1(0xFF));
        }

        for (uint i = _palette; i<_bitDepth-1; i++) {
            tRNSObj = abi.encodePacked(tRNSObj, bytes1(0x00));
        }

        return abi.encodePacked(
            uint32(_bitDepth),
            'tRNS',
            tRNSObj
        );
    }

    function rawPNG(uint32 width, uint32 height, bytes3[] memory palette, bytes memory pixels, bool force8bit) internal pure returns (bytes memory) {

        uint256[256] memory crcTable = calcCrcTable();

        // Write PLTE
        bytes memory plte = formatPalette(palette, force8bit);

        // Write tRNS
        bytes memory tRNS = png._tRNS(
            force8bit ? 256 : calculateBitDepth(palette.length),
            palette.length
            );

        // Write IHDR
        bytes21 header = bytes21(abi.encodePacked(
                uint32(13),
                'IHDR',
                width,
                height,
                bytes5(0x0803000000)
            )
        );

        bytes7 deflate = bytes7(
            abi.encodePacked(
                bytes2(0x78DA),
                pixels.length > 65535 ? bytes1(0x00) :  bytes1(0x01),
                png.byte2lsb(uint16(pixels.length)),
                ~png.byte2lsb(uint16(pixels.length))
            )
        );

        bytes memory zlib = abi.encodePacked('IDAT', deflate, pixels, _adler32(pixels));

        return abi.encodePacked(
            bytes8(0x89504E470D0A1A0A),
            header, 
            _CRC(crcTable, abi.encodePacked(header),4),
            plte, 
            _CRC(crcTable, abi.encodePacked(plte),4),
            tRNS, 
            _CRC(crcTable, abi.encodePacked(tRNS),4),
            uint32(zlib.length-4),
            zlib,
            _CRC(crcTable, abi.encodePacked(zlib), 0), 
            bytes12(0x0000000049454E44AE426082)
        );

    }

    function encodedPNG(uint32 width, uint32 height, bytes3[] memory palette, bytes memory pixels, bool force8bit) internal pure returns (string memory) {
        return string.concat('data:image/png;base64,', base64encode(rawPNG(width, height, palette, pixels, force8bit)));
    }






    // @dev Does not check out of bounds
    function coordinatesToIndex(uint256 _x, uint256 _y, uint256 _width) internal pure returns (uint256 index) {
            index = _y * (_width + 1) + _x + 1;
	}

    

    








    /////////////////////////// 
    /// Checksums

    // need to check faster ways to do this
    function calcCrcTable() internal pure returns (uint256[256] memory crcTable) {
        uint256 c;

        unchecked{
            for(uint256 n = 0; n < 256; n++) {
                c = n;
                for (uint256 k = 0; k < 8; k++) {
                    if(c & 1 == 1) {
                        c = 0xedb88320 ^ (c >>1);
                    } else {
                        c = c >> 1;
                    }
                }
                crcTable[n] = c;
            }
        }
    }

    function _CRC(uint256[256] memory crcTable, bytes memory chunk, uint256 offset) internal pure returns (bytes4) {

        uint256 len = chunk.length;

        uint32 c = uint32(0xffffffff);
        unchecked{
            for(uint256 n = offset; n < len; n++) {
                c = uint32(crcTable[(c^uint8(chunk[n])) & 0xff] ^ (c >> 8));
            }
        }
        return bytes4(c)^0xffffffff;

    }

    
    function _adler32(bytes memory _data) internal pure returns (bytes4) {
        uint32 a = 1;
        uint32 b = 0;

        uint256 _len = _data.length;

        unchecked {
            for (uint256 i = 0; i < _len; i++) {
                a = (a + uint8(_data[i])) % 65521; //may need to convert to uint32
                b = (b + a) % 65521;
            }
        }

        return bytes4((b << 16) | a);

    }

    /////////////////////////// 
    /// Utilities

    function byte2lsb(uint16 _input) internal pure returns (bytes2) {

        return byte2lsb(bytes2(_input));

    }

    function byte2lsb(bytes2 _input) internal pure returns (bytes2) {

        return bytes2(abi.encodePacked(bytes1(_input << 8), bytes1(_input)));

    }

    function _toBuffer(bytes memory _bytes) internal pure returns (bytes1[] memory) {

        uint256 _length = _bytes.length;

        bytes1[] memory byteArray = new bytes1[](_length);
        bytes memory tempBytes;

        unchecked{
            for (uint256 i = 0; i<_length; i++) {
                assembly {
                    // Get a location of some free memory and store it in tempBytes as
                    // Solidity does for memory variables.
                    tempBytes := mload(0x40)

                    // The first word of the slice result is potentially a partial
                    // word read from the original array. To read it, we calculate
                    // the length of that partial word and start copying that many
                    // bytes into the array. The first word we copy will start with
                    // data we don't care about, but the last `lengthmod` bytes will
                    // land at the beginning of the contents of the new array. When
                    // we're done copying, we overwrite the full first word with
                    // the actual length of the slice.
                    let lengthmod := and(1, 31)

                    // The multiplication in the next line is necessary
                    // because when slicing multiples of 32 bytes (lengthmod == 0)
                    // the following copy loop was copying the origin's length
                    // and then ending prematurely not copying everything it should.
                    let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                    let end := add(mc, 1)

                    for {
                        // The multiplication in the next line has the same exact purpose
                        // as the one above.
                        let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), i)
                    } lt(mc, end) {
                        mc := add(mc, 0x20)
                        cc := add(cc, 0x20)
                    } {
                        mstore(mc, mload(cc))
                    }

                    mstore(tempBytes, 1)

                    //update free-memory pointer
                    //allocating the array padded to 32 bytes like the compiler does now
                    mstore(0x40, and(add(mc, 31), not(31)))
                }

                byteArray[i] = bytes1(tempBytes);

            }
        }
        
        return byteArray;
    }

    /**
     * @dev Base64 Encoding/Decoding Table
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

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

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

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

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

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

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

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

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

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

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

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

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

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

        return result;
    }



}

File 6 of 6 : JSON.sol
//SPDX-License-Identifier: Unlicense
/*
 * @title ERC721 JSON metadata
 * @author Colin Platt <[email protected]>
 *
 * @dev JSON utilities for base64 encoded ERC721 JSON metadata schema
 */
pragma solidity ^0.8.12;

library json {
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// @dev JSON requires that double quotes be escaped or JSONs will not build correctly
    /// string.concat also requires an escape, use \\" or the constant DOUBLE_QUOTES to represent " in JSON
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////

    string constant DOUBLE_QUOTES = '\\"';

    function formattedMetadata(
        string memory name,
        string memory description,
        string memory pngImg,
        string memory attributes
    )   internal
        pure
        returns (string memory)
    {
        return string.concat(
            'data:application/json;base64,',
            encode(
                bytes(
                    string.concat(
                    '{',
                    _prop('name', name),
                    _prop('description', description),
                    _xmlImage(pngImg),
                    _objectSq('attributes', attributes),
                    '}'
                    )
                )
            )
        );
    }
    
    function _xmlImage(string memory _pngImg)
        internal
        pure
        returns (string memory) 
    {
        return _prop(
                        'image',
                        string.concat(
                            'data:image/svg+xml;base64,',
                            encode(
                                bytes(string.concat(
                                    '<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  <image x="0" y="0" width="128" height="128" preserveAspectRatio="xMidYMid" xlink:href="',
                                    _pngImg,
                                    '"/></svg>'
                                ))
                            )
                        ),
                        false
        );
    }

    function _prop(string memory _key, string memory _val)
        internal
        pure
        returns (string memory)
    {
        return string.concat('"', _key, '": ', '"', _val, '", ');
    }

    function _prop(string memory _key, string memory _val, bool last)
        internal
        pure
        returns (string memory)
    {
        if(last) {
            return string.concat('"', _key, '": ', '"', _val, '"');
        } else {
            return string.concat('"', _key, '": ', '"', _val, '", ');
        }
        
    }

    function _object(string memory _key, string memory _val)
        internal
        pure
        returns (string memory)
    {
        return string.concat('"', _key, '": ', '{', _val, '}');
    }

    function _objectSq(string memory _key, string memory _val)
        internal
        pure
        returns (string memory)
    {
        return string.concat('"', _key, '": ', '[', _val, ']');
    }

    function _attr(string memory _trait_type, string memory _value)
        internal
        pure
        returns (string memory)
    {
        return string.concat('{"trait_type": "', _trait_type, '", ', '"value" : "', _value, '"}, ');
    }

    function _attr(string memory _trait_type, string memory _value, bool last)
        internal
        pure
        returns (string memory)
    {
        if (last) {
            return string.concat('{"trait_type": "', _trait_type, '", ', '"value" : "', _value, '"}');
        } else {
            return string.concat('{"trait_type": "', _trait_type, '", ', '"value" : "', _value, '"}, ');
        }
        
    }

     
     /**
     * taken from Openzeppelin
     * @dev Base64 Encoding/Decoding Table
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

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

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

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

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

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

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

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

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

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

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

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

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

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

        return result;
    }

    /**
     * taken from Openzeppelin
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

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

}

Settings
{
  "remappings": [
    "ds-test/=lib/solmate/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solidity-trigonometry/=lib/solidity-trigonometry/src/",
    "solmate/=lib/solmate/src/",
    "src/=src/",
    "test/=test/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"click_for_utility","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"mint_the_ball","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenPNG","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"ghoulAddr","type":"address"}],"name":"updateGhoulAddr","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052600780546001600160a01b03191673ef1a89cbfabe59397ffda11fc5df293e9bc5db901790553480156200003757600080fd5b50604080518082018252600a81526967686f756c42616c6c7360b01b602080830191825283518085019094526004845263784fc74560e11b908401528151339391620000879160009190620000f2565b5080516200009d906001906020840190620000f2565b5050600680546001600160a01b0319166001600160a01b0384169081179091556040519091506000907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a350620001d4565b828054620001009062000198565b90600052602060002090601f0160209004810192826200012457600085556200016f565b82601f106200013f57805160ff19168380011785556200016f565b828001600101855582156200016f579182015b828111156200016f57825182559160200191906001019062000152565b506200017d92915062000181565b5090565b5b808211156200017d576000815560010162000182565b600181811c90821680620001ad57607f821691505b602082108103620001ce57634e487b7160e01b600052602260045260246000fd5b50919050565b61328580620001e46000396000f3fe608060405234801561001057600080fd5b50600436106101205760003560e01c80636352211e116100ad578063a8ce53a011610071578063a8ce53a014610279578063b88d4fde1461028c578063c87b56dd1461029f578063d79d93d4146102b2578063e985e9c5146102c557600080fd5b80636352211e1461021757806370a082311461022a5780638da5cb5b1461024b57806395d89b411461025e578063a22cb4651461026657600080fd5b8063095ea7b3116100f4578063095ea7b3146101b857806313af4035146101cb57806323b872dd146101de57806335842845146101f157806342842e0e1461020457600080fd5b806223a12e1461012557806301ffc9a71461013a57806306fdde0314610162578063081812fc14610177575b600080fd5b610138610133366004612422565b6102f3565b005b61014d610148366004612455565b610363565b60405190151581526020015b60405180910390f35b61016a6103b5565b60405161015991906124a2565b6101a06101853660046124d5565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610159565b6101386101c63660046124ee565b610443565b6101386101d9366004612422565b610525565b6101386101ec36600461251a565b6105ba565b61016a6101ff3660046124d5565b610781565b61013861021236600461251a565b61083e565b6101a06102253660046124d5565b610936565b61023d610238366004612422565b61098d565b604051908152602001610159565b6006546101a0906001600160a01b031681565b61016a6109f0565b61013861027436600461255b565b6109fd565b6101386102873660046124d5565b610a69565b61013861029a366004612599565b610a75565b61016a6102ad3660046124d5565b610b5d565b6101386102c03660046124d5565b610bb8565b61014d6102d3366004612638565b600560209081526000928352604080842090915290825290205460ff1681565b6006546001600160a01b031633146103415760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b60006301ffc9a760e01b6001600160e01b03198316148061039457506380ac58cd60e01b6001600160e01b03198316145b806103af5750635b5e139f60e01b6001600160e01b03198316145b92915050565b600080546103c290612666565b80601f01602080910402602001604051908101604052809291908181526020018280546103ee90612666565b801561043b5780601f106104105761010080835404028352916020019161043b565b820191906000526020600020905b81548152906001019060200180831161041e57829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b03163381148061048c57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b6104c95760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610338565b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6006546001600160a01b0316331461056e5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401610338565b600680546001600160a01b0319166001600160a01b03831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b6000818152600260205260409020546001600160a01b038481169116146106105760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610338565b6001600160a01b03821661065a5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610338565b336001600160a01b038416148061069457506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b806106b557506000818152600460205260409020546001600160a01b031633145b6106f25760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610338565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6060600061078e83610d54565b905060006040518060600160405280608063ffffffff168152602001608063ffffffff1681526020016080806107c491906126b0565b6107cf9060016126dc565b63ffffffff1667ffffffffffffffff8111156107ed576107ed612704565b6040519080825280601f01601f191660200182016040528015610817576020820181803683370190505b5081525090506108366080808461082f858751610f66565b600161102c565b949350505050565b6108498383836105ba565b6001600160a01b0382163b15806108f25750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156108c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e6919061271a565b6001600160e01b031916145b6109315760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610338565b505050565b6000818152600260205260409020546001600160a01b0316806109885760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610338565b919050565b60006001600160a01b0382166109d45760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610338565b506001600160a01b031660009081526003602052604090205490565b600180546103c290612666565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b610a728161106d565b50565b610a808585856105ba565b6001600160a01b0384163b1580610b175750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a0290610ac89033908a90899089908990600401612737565b6020604051808303816000875af1158015610ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0b919061271a565b6001600160e01b031916145b610b565760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610338565b5050505050565b60606103af6040518060400160405280600a81526020016967686f756c42616c6c7360b01b815250604051806101400160405280610102815260200161310e6101029139610baa85610781565b610bb38661113a565b61137e565b6127108110610bf95760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b2103130b6361760991b6044820152606401610338565b611a0a811015610cb8576007546040516331a9108f60e11b81526004810183905233916001600160a01b031690636352211e90602401602060405180830381865afa158015610c4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c70919061278b565b6001600160a01b031614610cb85760405162461bcd60e51b815260206004820152600f60248201526e3737ba103cb7bab91033b437bab61760891b6044820152606401610338565b6000818152600260205260409020546001600160a01b031615610d1d5760405162461bcd60e51b815260206004820181905260248201527f736f6d656f6e6520656c736520676f7420746869732067686f756c42616c6c2e6044820152606401610338565b610d268161145b565b60008281526008602090815260409091208251610d499391929190910190612354565b50610a72338261158d565b600081815260086020526040812080546060929190610d7290612666565b80601f0160208091040260200160405190810160405280929190818152602001828054610d9e90612666565b8015610deb5780601f10610dc057610100808354040283529160200191610deb565b820191906000526020600020905b815481529060010190602001808311610dce57829003601f168201915b50505050509050600060038251610e0291906127be565b67ffffffffffffffff811115610e1a57610e1a612704565b604051908082528060200260200182016040528015610e43578160200160208202803683370190505b50905060005b8151811015610f5e5782610e5e8260036127d2565b81518110610e6e57610e6e6127f1565b01602001516001600160f81b03191683610e898360036127d2565b610e94906001612807565b81518110610ea457610ea46127f1565b01602001516001600160f81b03191684610ebf8460036127d2565b610eca906002612807565b81518110610eda57610eda6127f1565b016020908101516040516001600160f81b031994851692810192909252918316602182015291166022820152602301604051602081830303815290604052610f219061281f565b828281518110610f3357610f336127f1565b6001600160e81b03199092166020928302919091019091015280610f5681612856565b915050610e49565b509392505050565b60408051606081810183526000808352602083015291810182905260008080805b868160ff16101561101d574281604051602001610fbb92919091825260f81b6001600160f81b031916602082015260210190565b6040516020818303038152906040528051906020012060001c9150610fe98289600001518a60200151611698565b9094509250611009888585601261100186600161286f565b60f81b6116ff565b94508061101581612894565b915050610f87565b50505050604001519392505050565b606061104361103e87878787876118cc565b611b1a565b60405160200161105391906128cf565b604051602081830303815290604052905095945050505050565b6000818152600260205260409020546001600160a01b0316806110bf5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610338565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b031990811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b60008181526008602052604081208054606092919061115890612666565b80601f016020809104026020016040519081016040528092919081815260200182805461118490612666565b80156111d15780601f106111a6576101008083540402835291602001916111d1565b820191906000526020600020905b8154815290600101906020018083116111b457829003601f168201915b505050505090506060600080600090505b600384516111f091906127be565b8110156113165760016003855161120791906127be565b611211919061290d565b811461121e576000611221565b60015b9150826112e161123a611235846001612807565b611c6d565b60405160200161124a9190612924565b60408051601f19818403018152919052611286876112698660036127d2565b81518110611279576112796127f1565b016020015160f81c611c6d565b6112a0886112958760036127d2565b611269906001612807565b6112ba896112af8860036127d2565b611269906002612807565b6040516020016112cc93929190612951565b60405160208183030381529060405285611d6e565b6040516020016112f29291906129ac565b6040516020818303038152906040529250808061130e90612856565b9150506111e2565b506113536040518060400160405280600a81526020016918985b1b0818dbdd5b9d60b21b81525061134e6003865161123591906127be565b611db9565b826040516020016113659291906129ac565b6040516020818303038152906040529350505050919050565b60606114326113a9604051806040016040528060048152602001636e616d6560e01b81525087611de5565b6113d66040518060400160405280600b81526020016a3232b9b1b934b83a34b7b760a91b81525087611de5565b6113df86611dfa565b61140b6040518060400160405280600a8152602001696174747269627574657360b01b81525087611e57565b60405160200161141e94939291906129d2565b604051602081830303815290604052611b1a565b6040516020016114429190612a48565b6040516020818303038152906040529050949350505050565b606060006114b66114b184334260405160200161149d9392919092835260609190911b6bffffffffffffffffffffffff19166020830152603482015260540190565b604051602081830303815290604052611e6c565b611e9e565b9050603c6114c5604583612a8d565b1115611504576040516dffffffffffffffffffffffffffff19607083901b1660208201526032015b604051602081830303815290604052915050919050565b6032611511604583612a8d565b1115611536576040516001600160a01b031960a083901b166020820152602c016114ed565b6028611543604583612a8d565b1115611568576040516001600160d01b031960d083901b1660208201526026016114ed565b6040516001600160e81b031960e883901b1660208201526023016114ed565b50919050565b6001600160a01b0382166115d75760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610338565b6000818152600260205260409020546001600160a01b03161561162d5760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610338565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60008060026116a781866127be565b6116b586601089901c612a8d565b6116bf9190612807565b6116c991906127be565b915060026116d781856127be565b6116e18588612a8d565b6116eb9190612807565b6116f591906127be565b9050935093915050565b61172360405180606001604052806000815260200160008152602001606081525090565b600080848703855b8882136118be57508587035b8781136118b3578680028983038002898303800201136118ab57888203890393508781038803925060008212158015611771575060008112155b156117b25760408a01518a51879190600190810184028501018151811061179a5761179a6127f1565b60200101906001600160f81b031916908160001a9053505b600082121580156117c4575060008312155b156118055760408a01518a5187919060019081018602850101815181106117ed576117ed6127f1565b60200101906001600160f81b031916908160001a9053505b60008412158015611817575060008112155b156118585760408a01518a518791906001908101840287010181518110611840576118406127f1565b60200101906001600160f81b031916908160001a9053505b6000841215801561186a575060008312155b156118ab5760408a01518a518791906001908101860287010181518110611893576118936127f1565b60200101906001600160f81b031916908160001a9053505b600101611737565b60019091019061172b565b509798975050505050505050565b606060006118d8611ef2565b905060006118e68685611f6b565b9050600061190c85611901576118fc88516120c2565b611905565b6101005b8851612100565b604051600d60e01b60208201526324a4222960e11b60248201526001600160e01b031960e08c811b821660288401528b901b16602c82015261080360f01b603082015290915060009060350160405160208183030381529060405261197090612aa1565b905060006178da60f01b61ffff89511161198e57600160f81b611991565b60005b61199b8a516121e6565b6119a58b516121e6565b6040516001600160f01b031994851660208201526001600160f81b031990931660228401529083166023830152199190911660258201526027016040516020818303038152906040526119f790612ad8565b905060008189611a068b6121f4565b604051602001611a1893929190612b0b565b60408051601f19818403018152908290526affffffffffffffffffffff198516602083015291506744a8272386850d0560c11b908490611a6e9089906035015b604051602081830303815290604052600461226c565b87611a848a8a604051602001611a589190612b5e565b88611a9a8c8b604051602001611a589190612b5e565b60048851611aa8919061290d565b88611ad48f8b604051602001611abe9190612b5e565b604051602081830303815290604052600061226c565b604051611afa9a999897969594939291906724a2a7225721304160a11b90602001612b7a565b604051602081830303815290604052965050505050505095945050505050565b60608151600003611b3957505060408051602081019091526000815290565b60006040518060600160405280604081526020016132106040913990506000600384516002611b689190612807565b611b7291906127be565b611b7d9060046127d2565b67ffffffffffffffff811115611b9557611b95612704565b6040519080825280601f01601f191660200182016040528015611bbf576020820181803683370190505b509050600182016020820185865187015b80821015611c2b576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250611bd0565b5050600386510660018114611c475760028114611c5a57611c62565b603d6001830353603d6002830353611c62565b603d60018303535b509195945050505050565b606081600003611c945750506040805180820190915260018152600360fc1b602082015290565b8160005b8115611cbe5780611ca881612856565b9150611cb79050600a836127be565b9150611c98565b60008167ffffffffffffffff811115611cd957611cd9612704565b6040519080825280601f01601f191660200182016040528015611d03576020820181803683370190505b5090505b841561083657611d1860018361290d565b9150611d25600a86612a8d565b611d30906030612807565b60f81b818381518110611d4557611d456127f1565b60200101906001600160f81b031916908160001a905350611d67600a866127be565b9450611d07565b60608115611d9f578383604051602001611d89929190612c4f565b6040516020818303038152906040529050611db2565b8383604051602001611d89929190612ccd565b9392505050565b60608282604051602001611dce929190612ccd565b604051602081830303815290604052905092915050565b60608282604051602001611dce929190612d4d565b60606103af60405180604001604052806005815260200164696d61676560d81b815250611e318460405160200161141e9190612db2565b604051602001611e419190612ee6565b60405160208183030381529060405260006122e9565b60608282604051602001611dce929190612f2b565b60608180519060200120604051602001611e8891815260200190565b6040516020818303038152906040529050919050565b6000602082511015611eea5760405162461bcd60e51b8152602060048201526015602482015274746f55696e743235365f6f75744f66426f756e647360581b6044820152606401610338565b506020015190565b611efa6123d8565b6000805b610100811015611f665780915060005b6008811015611f445782600116600103611f3457600183901c63edb88320189250611f3c565b600183901c92505b600101611f0e565b508183826101008110611f5957611f596127f1565b6020020152600101611efe565b505090565b606061010083511115611fc05760405162461bcd60e51b815260206004820152601760248201527f504e473a2050616c6574746520746f6f206c617267652e0000000000000000006044820152606401610338565b600082611fd657611fd184516120c2565b611fda565b6101005b9050606060005b855181101561203a5781868281518110611ffd57611ffd6127f1565b6020026020010151604051602001612016929190612f8f565b6040516020818303038152906040529150808061203290612856565b915050611fe1565b5084515b61204960018461290d565b81101561208857604051612064908390600090602001612f8f565b6040516020818303038152906040529150808061208090612856565b91505061203e565b506120948260036127d2565b6040516120a991906000908490602001612fbe565b6040516020818303038152906040529250505092915050565b600060038210156120d557506002919050565b60058210156120e657506004919050565b60118210156120f757506010919050565b50610100919050565b604051600060208201819052606091602101604051602081830303815290604052905060005b8381101561216d576040516121499083906001600160f81b031990602001613011565b6040516020818303038152906040529150808061216590612856565b915050612126565b50825b61217b60018661290d565b8110156121ba57604051612196908390600090602001613011565b604051602081830303815290604052915080806121b290612856565b915050612170565b5083816040516020016121ce929190613040565b60405160208183030381529060405291505092915050565b60006103af8260f01b612317565b80516000906001908290815b818110156122555761fff186828151811061221d5761221d6127f1565b60209101015160f81c850163ffffffff168161223b5761223b6127a8565b06935061fff163ffffffff84860116069250600101612200565b505060101b65ffffffff0000161760e01b92915050565b815160009063ffffffff835b828110156122d25760088263ffffffff16901c63ffffffff16878783815181106122a4576122a46127f1565b016020015160f81c841860ff1661010081106122c2576122c26127f1565b6020020151189150600101612278565b5060e01b6001600160e01b03191895945050505050565b60608115612304578383604051602001611d8992919061307f565b8383604051602001611d89929190612d4d565b6040516001600160f81b0319600883901b81166020830152821660218201526000906022016040516020818303038152906040526103af906130da565b82805461236090612666565b90600052602060002090601f01602090048101928261238257600085556123c8565b82601f1061239b57805160ff19168380011785556123c8565b828001600101855582156123c8579182015b828111156123c85782518255916020019190600101906123ad565b506123d49291506123f8565b5090565b604051806120000160405280610100906020820280368337509192915050565b5b808211156123d457600081556001016123f9565b6001600160a01b0381168114610a7257600080fd5b60006020828403121561243457600080fd5b8135611db28161240d565b6001600160e01b031981168114610a7257600080fd5b60006020828403121561246757600080fd5b8135611db28161243f565b60005b8381101561248d578181015183820152602001612475565b8381111561249c576000848401525b50505050565b60208152600082518060208401526124c1816040850160208701612472565b601f01601f19169190910160400192915050565b6000602082840312156124e757600080fd5b5035919050565b6000806040838503121561250157600080fd5b823561250c8161240d565b946020939093013593505050565b60008060006060848603121561252f57600080fd5b833561253a8161240d565b9250602084013561254a8161240d565b929592945050506040919091013590565b6000806040838503121561256e57600080fd5b82356125798161240d565b91506020830135801515811461258e57600080fd5b809150509250929050565b6000806000806000608086880312156125b157600080fd5b85356125bc8161240d565b945060208601356125cc8161240d565b935060408601359250606086013567ffffffffffffffff808211156125f057600080fd5b818801915088601f83011261260457600080fd5b81358181111561261357600080fd5b89602082850101111561262557600080fd5b9699959850939650602001949392505050565b6000806040838503121561264b57600080fd5b82356126568161240d565b9150602083013561258e8161240d565b600181811c9082168061267a57607f821691505b60208210810361158757634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600063ffffffff808316818516818304811182151516156126d3576126d361269a565b02949350505050565b600063ffffffff8083168185168083038211156126fb576126fb61269a565b01949350505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561272c57600080fd5b8151611db28161243f565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b60006020828403121561279d57600080fd5b8151611db28161240d565b634e487b7160e01b600052601260045260246000fd5b6000826127cd576127cd6127a8565b500490565b60008160001904831182151516156127ec576127ec61269a565b500290565b634e487b7160e01b600052603260045260246000fd5b6000821982111561281a5761281a61269a565b500190565b805160208201516001600160e81b0319808216929190600383101561284e5780818460030360031b1b83161693505b505050919050565b6000600182016128685761286861269a565b5060010190565b600060ff821660ff84168060ff0382111561288c5761288c61269a565b019392505050565b600060ff821660ff81036128aa576128aa61269a565b60010192915050565b600081516128c5818560208601612472565b9290920192915050565b7519185d184e9a5b5859d94bdc1b99ced8985cd94d8d0b60521b815260008251612900816016850160208701612472565b9190910160160192915050565b60008282101561291f5761291f61269a565b500390565b6403130b636160dd1b815260008251612944816005850160208701612472565b9190910160050192915050565b60008451612963818460208901612472565b808301905061016160f51b8082528551612984816002850160208a01612472565b6002920191820152835161299f816004840160208801612472565b0160040195945050505050565b600083516129be818460208801612472565b8351908301906126fb818360208801612472565b607b60f81b8152600085516129ee816001850160208a01612472565b855190830190612a05816001840160208a01612472565b8551910190612a1b816001840160208901612472565b8451910160010190612a31818360208801612472565b607d60f81b91019081526001019695505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612a8081601d850160208701612472565b91909101601d0192915050565b600082612a9c57612a9c6127a8565b500690565b805160208201516affffffffffffffffffffff19808216929190601583101561284e5760159290920360031b82901b161692915050565b805160208201516001600160c81b0319808216929190600783101561284e5760079290920360031b82901b161692915050565b631251105560e21b81526001600160c81b0319841660048201528251600090612b3b81600b850160208801612472565b6001600160e01b03199390931691909201600b810191909152600f019392505050565b60008251612b70818460208701612472565b9190910192915050565b6001600160c01b03198c1681526affffffffffffffffffffff198b1660088201526001600160e01b03198a8116601d830152895160009190612bc3816021860160208f01612472565b8a82166021918501918201528951612be2816025840160208e01612472565b89831660259290910191820152612c08602982018960e01b6001600160e01b0319169052565b612c15602d8201886128b3565b915050612c2b81866001600160e01b0319169052565b6001600160a01b0319841660048201526010019d9c50505050505050505050505050565b6f3d913a3930b4ba2fba3cb832911d101160811b81528251600090612c7b816010850160208801612472565b6201116160ed1b6010918401918201526a113b30b63ab291101d101160a91b60138201528351612cb281601e840160208801612472565b61227d60f01b601e9290910191820152602001949350505050565b6f3d913a3930b4ba2fba3cb832911d101160811b81528251600090612cf9816010850160208801612472565b6201116160ed1b6010918401918201526a113b30b63ab291101d101160a91b60138201528351612d3081601e840160208801612472565b630113e96160e51b601e9290910191820152602201949350505050565b6000601160f91b8083528451612d6a816001860160208901612472565b620111d160ed1b6001918501918201526004810191909152835190612d96826005830160208801612472565b6201116160ed1b91016005810191909152600801949350505050565b7f3c7376672077696474683d223130302522206865696768743d2231303025222081527f76657273696f6e3d22312e312220786d6c6e733d22687474703a2f2f7777772e60208201527f77332e6f72672f323030302f7376672220786d6c6e733a786c696e6b3d22687460408201527f74703a2f2f7777772e77332e6f72672f313939392f786c696e6b223e20203c6960608201527f6d61676520783d22302220793d2230222077696474683d22313238222068656960808201527f6768743d2231323822207072657365727665417370656374526174696f3d227860a08201527426b4b22ca6b4b211103c3634b7359d343932b31e9160591b60c082015260008251612ec68160d5850160208701612472565b6811179f1e17b9bb339f60b91b60d593909101928301525060de01919050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000815260008251612f1e81601a850160208701612472565b91909101601a0192915050565b601160f91b81528251600090612f48816001850160208801612472565b620111d160ed1b600191840191820152605b60f81b60048201528351612f75816005840160208801612472565b605d60f81b60059290910191820152600601949350505050565b60008351612fa1818460208801612472565b6001600160e81b0319939093169190920190815260030192915050565b60e084901b6001600160e01b031916815263504c544560e01b60048201526001600160e81b031983166008820152815160009061300281600b850160208701612472565b91909101600b01949350505050565b60008351613023818460208801612472565b6001600160f81b0319939093169190920190815260010192915050565b63ffffffff60e01b8360e01b1681526374524e5360e01b600482015260008251613071816008850160208701612472565b919091016008019392505050565b6000601160f91b808352845161309c816001860160208901612472565b620111d160ed1b6001918501918201526004810182905284516130c6816005840160208901612472565b016005810191909152600601949350505050565b805160208201516001600160f01b0319808216929190600283101561284e5760029290920360031b82901b16169291505056fe67686f756c42616c6c73206172652066756c6c79206f6e636861696e20504e477320746861742065766f6c7665207769746820657665727920626c6f636b2c206162736f6c7574656c792072756767696e67207468652072696768742d636c69636b20736176657273206166746572206576657279626c6f636b2e204e6f20726f61646d61702c206e6f20646576656c6f706d656e742c206e6f207574696c6974792c206e6f206d61726b6574696e672c20616e64206e6f7468696e67206d6f72652e20546865792070726f6d697365206e6f7468696e6720616e642064656c69766572206576656e206c6573732e2054686579277265206a75737420504e47732e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122029efa5ef6f32d59491e214790b5c34e578eb26a758ca0d692398a0399c6cf39e64736f6c634300080d0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101205760003560e01c80636352211e116100ad578063a8ce53a011610071578063a8ce53a014610279578063b88d4fde1461028c578063c87b56dd1461029f578063d79d93d4146102b2578063e985e9c5146102c557600080fd5b80636352211e1461021757806370a082311461022a5780638da5cb5b1461024b57806395d89b411461025e578063a22cb4651461026657600080fd5b8063095ea7b3116100f4578063095ea7b3146101b857806313af4035146101cb57806323b872dd146101de57806335842845146101f157806342842e0e1461020457600080fd5b806223a12e1461012557806301ffc9a71461013a57806306fdde0314610162578063081812fc14610177575b600080fd5b610138610133366004612422565b6102f3565b005b61014d610148366004612455565b610363565b60405190151581526020015b60405180910390f35b61016a6103b5565b60405161015991906124a2565b6101a06101853660046124d5565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610159565b6101386101c63660046124ee565b610443565b6101386101d9366004612422565b610525565b6101386101ec36600461251a565b6105ba565b61016a6101ff3660046124d5565b610781565b61013861021236600461251a565b61083e565b6101a06102253660046124d5565b610936565b61023d610238366004612422565b61098d565b604051908152602001610159565b6006546101a0906001600160a01b031681565b61016a6109f0565b61013861027436600461255b565b6109fd565b6101386102873660046124d5565b610a69565b61013861029a366004612599565b610a75565b61016a6102ad3660046124d5565b610b5d565b6101386102c03660046124d5565b610bb8565b61014d6102d3366004612638565b600560209081526000928352604080842090915290825290205460ff1681565b6006546001600160a01b031633146103415760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b600780546001600160a01b0319166001600160a01b0392909216919091179055565b60006301ffc9a760e01b6001600160e01b03198316148061039457506380ac58cd60e01b6001600160e01b03198316145b806103af5750635b5e139f60e01b6001600160e01b03198316145b92915050565b600080546103c290612666565b80601f01602080910402602001604051908101604052809291908181526020018280546103ee90612666565b801561043b5780601f106104105761010080835404028352916020019161043b565b820191906000526020600020905b81548152906001019060200180831161041e57829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b03163381148061048c57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b6104c95760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610338565b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6006546001600160a01b0316331461056e5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401610338565b600680546001600160a01b0319166001600160a01b03831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b6000818152600260205260409020546001600160a01b038481169116146106105760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610338565b6001600160a01b03821661065a5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610338565b336001600160a01b038416148061069457506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b806106b557506000818152600460205260409020546001600160a01b031633145b6106f25760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610338565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6060600061078e83610d54565b905060006040518060600160405280608063ffffffff168152602001608063ffffffff1681526020016080806107c491906126b0565b6107cf9060016126dc565b63ffffffff1667ffffffffffffffff8111156107ed576107ed612704565b6040519080825280601f01601f191660200182016040528015610817576020820181803683370190505b5081525090506108366080808461082f858751610f66565b600161102c565b949350505050565b6108498383836105ba565b6001600160a01b0382163b15806108f25750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156108c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e6919061271a565b6001600160e01b031916145b6109315760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610338565b505050565b6000818152600260205260409020546001600160a01b0316806109885760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610338565b919050565b60006001600160a01b0382166109d45760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610338565b506001600160a01b031660009081526003602052604090205490565b600180546103c290612666565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b610a728161106d565b50565b610a808585856105ba565b6001600160a01b0384163b1580610b175750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a0290610ac89033908a90899089908990600401612737565b6020604051808303816000875af1158015610ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0b919061271a565b6001600160e01b031916145b610b565760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610338565b5050505050565b60606103af6040518060400160405280600a81526020016967686f756c42616c6c7360b01b815250604051806101400160405280610102815260200161310e6101029139610baa85610781565b610bb38661113a565b61137e565b6127108110610bf95760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b2103130b6361760991b6044820152606401610338565b611a0a811015610cb8576007546040516331a9108f60e11b81526004810183905233916001600160a01b031690636352211e90602401602060405180830381865afa158015610c4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c70919061278b565b6001600160a01b031614610cb85760405162461bcd60e51b815260206004820152600f60248201526e3737ba103cb7bab91033b437bab61760891b6044820152606401610338565b6000818152600260205260409020546001600160a01b031615610d1d5760405162461bcd60e51b815260206004820181905260248201527f736f6d656f6e6520656c736520676f7420746869732067686f756c42616c6c2e6044820152606401610338565b610d268161145b565b60008281526008602090815260409091208251610d499391929190910190612354565b50610a72338261158d565b600081815260086020526040812080546060929190610d7290612666565b80601f0160208091040260200160405190810160405280929190818152602001828054610d9e90612666565b8015610deb5780601f10610dc057610100808354040283529160200191610deb565b820191906000526020600020905b815481529060010190602001808311610dce57829003601f168201915b50505050509050600060038251610e0291906127be565b67ffffffffffffffff811115610e1a57610e1a612704565b604051908082528060200260200182016040528015610e43578160200160208202803683370190505b50905060005b8151811015610f5e5782610e5e8260036127d2565b81518110610e6e57610e6e6127f1565b01602001516001600160f81b03191683610e898360036127d2565b610e94906001612807565b81518110610ea457610ea46127f1565b01602001516001600160f81b03191684610ebf8460036127d2565b610eca906002612807565b81518110610eda57610eda6127f1565b016020908101516040516001600160f81b031994851692810192909252918316602182015291166022820152602301604051602081830303815290604052610f219061281f565b828281518110610f3357610f336127f1565b6001600160e81b03199092166020928302919091019091015280610f5681612856565b915050610e49565b509392505050565b60408051606081810183526000808352602083015291810182905260008080805b868160ff16101561101d574281604051602001610fbb92919091825260f81b6001600160f81b031916602082015260210190565b6040516020818303038152906040528051906020012060001c9150610fe98289600001518a60200151611698565b9094509250611009888585601261100186600161286f565b60f81b6116ff565b94508061101581612894565b915050610f87565b50505050604001519392505050565b606061104361103e87878787876118cc565b611b1a565b60405160200161105391906128cf565b604051602081830303815290604052905095945050505050565b6000818152600260205260409020546001600160a01b0316806110bf5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610338565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b031990811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b60008181526008602052604081208054606092919061115890612666565b80601f016020809104026020016040519081016040528092919081815260200182805461118490612666565b80156111d15780601f106111a6576101008083540402835291602001916111d1565b820191906000526020600020905b8154815290600101906020018083116111b457829003601f168201915b505050505090506060600080600090505b600384516111f091906127be565b8110156113165760016003855161120791906127be565b611211919061290d565b811461121e576000611221565b60015b9150826112e161123a611235846001612807565b611c6d565b60405160200161124a9190612924565b60408051601f19818403018152919052611286876112698660036127d2565b81518110611279576112796127f1565b016020015160f81c611c6d565b6112a0886112958760036127d2565b611269906001612807565b6112ba896112af8860036127d2565b611269906002612807565b6040516020016112cc93929190612951565b60405160208183030381529060405285611d6e565b6040516020016112f29291906129ac565b6040516020818303038152906040529250808061130e90612856565b9150506111e2565b506113536040518060400160405280600a81526020016918985b1b0818dbdd5b9d60b21b81525061134e6003865161123591906127be565b611db9565b826040516020016113659291906129ac565b6040516020818303038152906040529350505050919050565b60606114326113a9604051806040016040528060048152602001636e616d6560e01b81525087611de5565b6113d66040518060400160405280600b81526020016a3232b9b1b934b83a34b7b760a91b81525087611de5565b6113df86611dfa565b61140b6040518060400160405280600a8152602001696174747269627574657360b01b81525087611e57565b60405160200161141e94939291906129d2565b604051602081830303815290604052611b1a565b6040516020016114429190612a48565b6040516020818303038152906040529050949350505050565b606060006114b66114b184334260405160200161149d9392919092835260609190911b6bffffffffffffffffffffffff19166020830152603482015260540190565b604051602081830303815290604052611e6c565b611e9e565b9050603c6114c5604583612a8d565b1115611504576040516dffffffffffffffffffffffffffff19607083901b1660208201526032015b604051602081830303815290604052915050919050565b6032611511604583612a8d565b1115611536576040516001600160a01b031960a083901b166020820152602c016114ed565b6028611543604583612a8d565b1115611568576040516001600160d01b031960d083901b1660208201526026016114ed565b6040516001600160e81b031960e883901b1660208201526023016114ed565b50919050565b6001600160a01b0382166115d75760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610338565b6000818152600260205260409020546001600160a01b03161561162d5760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610338565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60008060026116a781866127be565b6116b586601089901c612a8d565b6116bf9190612807565b6116c991906127be565b915060026116d781856127be565b6116e18588612a8d565b6116eb9190612807565b6116f591906127be565b9050935093915050565b61172360405180606001604052806000815260200160008152602001606081525090565b600080848703855b8882136118be57508587035b8781136118b3578680028983038002898303800201136118ab57888203890393508781038803925060008212158015611771575060008112155b156117b25760408a01518a51879190600190810184028501018151811061179a5761179a6127f1565b60200101906001600160f81b031916908160001a9053505b600082121580156117c4575060008312155b156118055760408a01518a5187919060019081018602850101815181106117ed576117ed6127f1565b60200101906001600160f81b031916908160001a9053505b60008412158015611817575060008112155b156118585760408a01518a518791906001908101840287010181518110611840576118406127f1565b60200101906001600160f81b031916908160001a9053505b6000841215801561186a575060008312155b156118ab5760408a01518a518791906001908101860287010181518110611893576118936127f1565b60200101906001600160f81b031916908160001a9053505b600101611737565b60019091019061172b565b509798975050505050505050565b606060006118d8611ef2565b905060006118e68685611f6b565b9050600061190c85611901576118fc88516120c2565b611905565b6101005b8851612100565b604051600d60e01b60208201526324a4222960e11b60248201526001600160e01b031960e08c811b821660288401528b901b16602c82015261080360f01b603082015290915060009060350160405160208183030381529060405261197090612aa1565b905060006178da60f01b61ffff89511161198e57600160f81b611991565b60005b61199b8a516121e6565b6119a58b516121e6565b6040516001600160f01b031994851660208201526001600160f81b031990931660228401529083166023830152199190911660258201526027016040516020818303038152906040526119f790612ad8565b905060008189611a068b6121f4565b604051602001611a1893929190612b0b565b60408051601f19818403018152908290526affffffffffffffffffffff198516602083015291506744a8272386850d0560c11b908490611a6e9089906035015b604051602081830303815290604052600461226c565b87611a848a8a604051602001611a589190612b5e565b88611a9a8c8b604051602001611a589190612b5e565b60048851611aa8919061290d565b88611ad48f8b604051602001611abe9190612b5e565b604051602081830303815290604052600061226c565b604051611afa9a999897969594939291906724a2a7225721304160a11b90602001612b7a565b604051602081830303815290604052965050505050505095945050505050565b60608151600003611b3957505060408051602081019091526000815290565b60006040518060600160405280604081526020016132106040913990506000600384516002611b689190612807565b611b7291906127be565b611b7d9060046127d2565b67ffffffffffffffff811115611b9557611b95612704565b6040519080825280601f01601f191660200182016040528015611bbf576020820181803683370190505b509050600182016020820185865187015b80821015611c2b576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250611bd0565b5050600386510660018114611c475760028114611c5a57611c62565b603d6001830353603d6002830353611c62565b603d60018303535b509195945050505050565b606081600003611c945750506040805180820190915260018152600360fc1b602082015290565b8160005b8115611cbe5780611ca881612856565b9150611cb79050600a836127be565b9150611c98565b60008167ffffffffffffffff811115611cd957611cd9612704565b6040519080825280601f01601f191660200182016040528015611d03576020820181803683370190505b5090505b841561083657611d1860018361290d565b9150611d25600a86612a8d565b611d30906030612807565b60f81b818381518110611d4557611d456127f1565b60200101906001600160f81b031916908160001a905350611d67600a866127be565b9450611d07565b60608115611d9f578383604051602001611d89929190612c4f565b6040516020818303038152906040529050611db2565b8383604051602001611d89929190612ccd565b9392505050565b60608282604051602001611dce929190612ccd565b604051602081830303815290604052905092915050565b60608282604051602001611dce929190612d4d565b60606103af60405180604001604052806005815260200164696d61676560d81b815250611e318460405160200161141e9190612db2565b604051602001611e419190612ee6565b60405160208183030381529060405260006122e9565b60608282604051602001611dce929190612f2b565b60608180519060200120604051602001611e8891815260200190565b6040516020818303038152906040529050919050565b6000602082511015611eea5760405162461bcd60e51b8152602060048201526015602482015274746f55696e743235365f6f75744f66426f756e647360581b6044820152606401610338565b506020015190565b611efa6123d8565b6000805b610100811015611f665780915060005b6008811015611f445782600116600103611f3457600183901c63edb88320189250611f3c565b600183901c92505b600101611f0e565b508183826101008110611f5957611f596127f1565b6020020152600101611efe565b505090565b606061010083511115611fc05760405162461bcd60e51b815260206004820152601760248201527f504e473a2050616c6574746520746f6f206c617267652e0000000000000000006044820152606401610338565b600082611fd657611fd184516120c2565b611fda565b6101005b9050606060005b855181101561203a5781868281518110611ffd57611ffd6127f1565b6020026020010151604051602001612016929190612f8f565b6040516020818303038152906040529150808061203290612856565b915050611fe1565b5084515b61204960018461290d565b81101561208857604051612064908390600090602001612f8f565b6040516020818303038152906040529150808061208090612856565b91505061203e565b506120948260036127d2565b6040516120a991906000908490602001612fbe565b6040516020818303038152906040529250505092915050565b600060038210156120d557506002919050565b60058210156120e657506004919050565b60118210156120f757506010919050565b50610100919050565b604051600060208201819052606091602101604051602081830303815290604052905060005b8381101561216d576040516121499083906001600160f81b031990602001613011565b6040516020818303038152906040529150808061216590612856565b915050612126565b50825b61217b60018661290d565b8110156121ba57604051612196908390600090602001613011565b604051602081830303815290604052915080806121b290612856565b915050612170565b5083816040516020016121ce929190613040565b60405160208183030381529060405291505092915050565b60006103af8260f01b612317565b80516000906001908290815b818110156122555761fff186828151811061221d5761221d6127f1565b60209101015160f81c850163ffffffff168161223b5761223b6127a8565b06935061fff163ffffffff84860116069250600101612200565b505060101b65ffffffff0000161760e01b92915050565b815160009063ffffffff835b828110156122d25760088263ffffffff16901c63ffffffff16878783815181106122a4576122a46127f1565b016020015160f81c841860ff1661010081106122c2576122c26127f1565b6020020151189150600101612278565b5060e01b6001600160e01b03191895945050505050565b60608115612304578383604051602001611d8992919061307f565b8383604051602001611d89929190612d4d565b6040516001600160f81b0319600883901b81166020830152821660218201526000906022016040516020818303038152906040526103af906130da565b82805461236090612666565b90600052602060002090601f01602090048101928261238257600085556123c8565b82601f1061239b57805160ff19168380011785556123c8565b828001600101855582156123c8579182015b828111156123c85782518255916020019190600101906123ad565b506123d49291506123f8565b5090565b604051806120000160405280610100906020820280368337509192915050565b5b808211156123d457600081556001016123f9565b6001600160a01b0381168114610a7257600080fd5b60006020828403121561243457600080fd5b8135611db28161240d565b6001600160e01b031981168114610a7257600080fd5b60006020828403121561246757600080fd5b8135611db28161243f565b60005b8381101561248d578181015183820152602001612475565b8381111561249c576000848401525b50505050565b60208152600082518060208401526124c1816040850160208701612472565b601f01601f19169190910160400192915050565b6000602082840312156124e757600080fd5b5035919050565b6000806040838503121561250157600080fd5b823561250c8161240d565b946020939093013593505050565b60008060006060848603121561252f57600080fd5b833561253a8161240d565b9250602084013561254a8161240d565b929592945050506040919091013590565b6000806040838503121561256e57600080fd5b82356125798161240d565b91506020830135801515811461258e57600080fd5b809150509250929050565b6000806000806000608086880312156125b157600080fd5b85356125bc8161240d565b945060208601356125cc8161240d565b935060408601359250606086013567ffffffffffffffff808211156125f057600080fd5b818801915088601f83011261260457600080fd5b81358181111561261357600080fd5b89602082850101111561262557600080fd5b9699959850939650602001949392505050565b6000806040838503121561264b57600080fd5b82356126568161240d565b9150602083013561258e8161240d565b600181811c9082168061267a57607f821691505b60208210810361158757634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600063ffffffff808316818516818304811182151516156126d3576126d361269a565b02949350505050565b600063ffffffff8083168185168083038211156126fb576126fb61269a565b01949350505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561272c57600080fd5b8151611db28161243f565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b60006020828403121561279d57600080fd5b8151611db28161240d565b634e487b7160e01b600052601260045260246000fd5b6000826127cd576127cd6127a8565b500490565b60008160001904831182151516156127ec576127ec61269a565b500290565b634e487b7160e01b600052603260045260246000fd5b6000821982111561281a5761281a61269a565b500190565b805160208201516001600160e81b0319808216929190600383101561284e5780818460030360031b1b83161693505b505050919050565b6000600182016128685761286861269a565b5060010190565b600060ff821660ff84168060ff0382111561288c5761288c61269a565b019392505050565b600060ff821660ff81036128aa576128aa61269a565b60010192915050565b600081516128c5818560208601612472565b9290920192915050565b7519185d184e9a5b5859d94bdc1b99ced8985cd94d8d0b60521b815260008251612900816016850160208701612472565b9190910160160192915050565b60008282101561291f5761291f61269a565b500390565b6403130b636160dd1b815260008251612944816005850160208701612472565b9190910160050192915050565b60008451612963818460208901612472565b808301905061016160f51b8082528551612984816002850160208a01612472565b6002920191820152835161299f816004840160208801612472565b0160040195945050505050565b600083516129be818460208801612472565b8351908301906126fb818360208801612472565b607b60f81b8152600085516129ee816001850160208a01612472565b855190830190612a05816001840160208a01612472565b8551910190612a1b816001840160208901612472565b8451910160010190612a31818360208801612472565b607d60f81b91019081526001019695505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612a8081601d850160208701612472565b91909101601d0192915050565b600082612a9c57612a9c6127a8565b500690565b805160208201516affffffffffffffffffffff19808216929190601583101561284e5760159290920360031b82901b161692915050565b805160208201516001600160c81b0319808216929190600783101561284e5760079290920360031b82901b161692915050565b631251105560e21b81526001600160c81b0319841660048201528251600090612b3b81600b850160208801612472565b6001600160e01b03199390931691909201600b810191909152600f019392505050565b60008251612b70818460208701612472565b9190910192915050565b6001600160c01b03198c1681526affffffffffffffffffffff198b1660088201526001600160e01b03198a8116601d830152895160009190612bc3816021860160208f01612472565b8a82166021918501918201528951612be2816025840160208e01612472565b89831660259290910191820152612c08602982018960e01b6001600160e01b0319169052565b612c15602d8201886128b3565b915050612c2b81866001600160e01b0319169052565b6001600160a01b0319841660048201526010019d9c50505050505050505050505050565b6f3d913a3930b4ba2fba3cb832911d101160811b81528251600090612c7b816010850160208801612472565b6201116160ed1b6010918401918201526a113b30b63ab291101d101160a91b60138201528351612cb281601e840160208801612472565b61227d60f01b601e9290910191820152602001949350505050565b6f3d913a3930b4ba2fba3cb832911d101160811b81528251600090612cf9816010850160208801612472565b6201116160ed1b6010918401918201526a113b30b63ab291101d101160a91b60138201528351612d3081601e840160208801612472565b630113e96160e51b601e9290910191820152602201949350505050565b6000601160f91b8083528451612d6a816001860160208901612472565b620111d160ed1b6001918501918201526004810191909152835190612d96826005830160208801612472565b6201116160ed1b91016005810191909152600801949350505050565b7f3c7376672077696474683d223130302522206865696768743d2231303025222081527f76657273696f6e3d22312e312220786d6c6e733d22687474703a2f2f7777772e60208201527f77332e6f72672f323030302f7376672220786d6c6e733a786c696e6b3d22687460408201527f74703a2f2f7777772e77332e6f72672f313939392f786c696e6b223e20203c6960608201527f6d61676520783d22302220793d2230222077696474683d22313238222068656960808201527f6768743d2231323822207072657365727665417370656374526174696f3d227860a08201527426b4b22ca6b4b211103c3634b7359d343932b31e9160591b60c082015260008251612ec68160d5850160208701612472565b6811179f1e17b9bb339f60b91b60d593909101928301525060de01919050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000815260008251612f1e81601a850160208701612472565b91909101601a0192915050565b601160f91b81528251600090612f48816001850160208801612472565b620111d160ed1b600191840191820152605b60f81b60048201528351612f75816005840160208801612472565b605d60f81b60059290910191820152600601949350505050565b60008351612fa1818460208801612472565b6001600160e81b0319939093169190920190815260030192915050565b60e084901b6001600160e01b031916815263504c544560e01b60048201526001600160e81b031983166008820152815160009061300281600b850160208701612472565b91909101600b01949350505050565b60008351613023818460208801612472565b6001600160f81b0319939093169190920190815260010192915050565b63ffffffff60e01b8360e01b1681526374524e5360e01b600482015260008251613071816008850160208701612472565b919091016008019392505050565b6000601160f91b808352845161309c816001860160208901612472565b620111d160ed1b6001918501918201526004810182905284516130c6816005840160208901612472565b016005810191909152600601949350505050565b805160208201516001600160f01b0319808216929190600283101561284e5760029290920360031b82901b16169291505056fe67686f756c42616c6c73206172652066756c6c79206f6e636861696e20504e477320746861742065766f6c7665207769746820657665727920626c6f636b2c206162736f6c7574656c792072756767696e67207468652072696768742d636c69636b20736176657273206166746572206576657279626c6f636b2e204e6f20726f61646d61702c206e6f20646576656c6f706d656e742c206e6f207574696c6974792c206e6f206d61726b6574696e672c20616e64206e6f7468696e67206d6f72652e20546865792070726f6d697365206e6f7468696e6720616e642064656c69766572206576656e206c6573732e2054686579277265206a75737420504e47732e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122029efa5ef6f32d59491e214790b5c34e578eb26a758ca0d692398a0399c6cf39e64736f6c634300080d0033

Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.