APE Price: $0.71 (-5.88%)

Contract Diff Checker

Contract Name:
GoobalooData

Contract Source Code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/**
 * @title GobsDataSource
 * @notice Stores SVGs for traits and generates SVGs for on-chain Goblin images.
 */
contract GoobalooData {
    address payable internal deployer;
    bool private contractSealed = false;
    mapping(string => mapping(string => string)) private traitSVGs; // traitType => value => SVG
    mapping(uint256 => Trait[]) private gobTraits; // Simplified storage for traits
    string private hoodieOverlaySVG;

    struct Trait {
        string traitType;
        string value;
    }

    modifier onlyDeployer() {
        require(msg.sender == deployer, "Only deployer.");
        _;
    }

    modifier unsealed() {
        require(!contractSealed, "Contract is sealed.");
        _;
    }

    constructor() {
        deployer = payable(msg.sender);
    }

    /**
     * @notice Seal the contract to prevent further modifications.
     */
    function sealContract() external onlyDeployer unsealed {
        contractSealed = true;
    }

    /**
     * @notice Store SVG data for a trait value
     * @param traitType The type of trait (e.g., "Background", "Head", etc.)
     * @param value The trait value (e.g., "Red", "Blue", etc.)
     * @param svg The SVG string for this trait
     */
    function storeTraitSVG(
        string memory traitType,
        string memory value,
        string memory svg
    ) external onlyDeployer unsealed {
        traitSVGs[traitType][value] = svg;
    }

    /**
     * @notice Store multiple trait SVGs at once
     */
    function batchStoreTraitSVGs(
        string[] memory traitTypes,
        string[] memory values,
        string[] memory svgs
    ) external onlyDeployer unsealed {
        require(
            traitTypes.length == values.length && values.length == svgs.length,
            "Mismatched arrays"
        );

        for (uint256 i = 0; i < traitTypes.length; i++) {
            traitSVGs[traitTypes[i]][values[i]] = svgs[i];
        }
    }

    /**
     * @notice Store traits for a token
     * @param tokenId The token ID to store traits for
     * @param traitTypes Array of trait types
     * @param values Array of values corresponding to trait types
     */
    function storeTraits(
        uint256 tokenId,
        string[] memory traitTypes,
        string[] memory values
    ) external onlyDeployer unsealed {
        require(tokenId < 2222, "Invalid token ID");
        require(traitTypes.length > 0, "No traits provided");
        require(
            traitTypes.length == values.length,
            string.concat(
                "Length mismatch: traitTypes(",
                toString(traitTypes.length),
                ") != values(",
                toString(values.length),
                ")"
            )
        );

        // Clear existing traits
        delete gobTraits[tokenId];

        // Store new traits
        for (uint256 i = 0; i < traitTypes.length; i++) {
            require(bytes(traitTypes[i]).length > 0, "Empty trait type");
            require(bytes(values[i]).length > 0, "Empty trait value");

            gobTraits[tokenId].push(
                Trait({traitType: traitTypes[i], value: values[i]})
            );
        }
    }

    /**
     * @notice Retrieve traits for a token
     * @param tokenId The ID of the token
     * @return The traits for the token
     */
    function getTraits(uint256 tokenId) external view returns (string memory) {
        require(gobTraits[tokenId].length > 0, "Traits not set");

        string memory jsonTraits = "[";

        for (uint256 i = 0; i < gobTraits[tokenId].length; i++) {
            jsonTraits = string.concat(
                jsonTraits,
                '{"trait_type": "',
                gobTraits[tokenId][i].traitType,
                '", "value": "',
                gobTraits[tokenId][i].value,
                '"}'
            );

            if (i < gobTraits[tokenId].length - 1) {
                jsonTraits = string.concat(jsonTraits, ",");
            }
        }

        jsonTraits = string.concat(jsonTraits, "]");
        return jsonTraits;
    }

    /**
     * @notice Retrieve SVG for a Goblin
     * @param tokenId The ID of the Goblin
     * @return The SVG for the Goblin
     */
    function getGoobalooSVG(
        uint256 tokenId
    ) external view returns (string memory) {
        require(tokenId < 2222, "Invalid tokenId");
        require(gobTraits[tokenId].length > 0, "Traits not set");

        string memory svg = "";
        bool hasHoodie = false;

        for (uint256 i = 0; i < gobTraits[tokenId].length; i++) {
            string memory traitType = gobTraits[tokenId][i].traitType;
            string memory value = gobTraits[tokenId][i].value;

            // Check if this goblin has hoodie
            if (
                keccak256(abi.encodePacked(traitType)) ==
                keccak256(abi.encodePacked("clothes")) &&
                keccak256(abi.encodePacked(value)) ==
                keccak256(abi.encodePacked("hoodie"))
            ) {
                hasHoodie = true;
            }

            string memory traitSVG = traitSVGs[traitType][value];
            require(bytes(traitSVG).length > 0, "SVG not found for trait");

            svg = string.concat(svg, "<g>", traitSVG, "</g>");
        }

        // Add hoodie overlay at the end if this goblin has hoodie
        if (hasHoodie) {
            require(
                bytes(hoodieOverlaySVG).length > 0,
                "Hoodie overlay not set"
            );
            svg = string.concat(svg, "<g>", hoodieOverlaySVG, "</g>");
        }

        return svg;
    }

    /**
     * @notice Store the hoodie overlay SVG that goes on top of other traits
     */
    function storeHoodieOverlay(
        string memory svg
    ) external onlyDeployer unsealed {
        hoodieOverlaySVG = svg;
    }

    /**
     * @notice Store traits for multiple Goblins in batch
     * @param tokenIds Array of token IDs
     * @param traitTypes Array of trait types for each trait
     * @param values Array of values for each trait
     */
    function batchStoreTraits(
        uint256[] memory tokenIds,
        string[] memory traitTypes,
        string[] memory values
    ) external onlyDeployer unsealed {
        require(
            traitTypes.length == values.length,
            "Length mismatch: traitTypes and values arrays"
        );
        require(tokenIds.length > 0, "Empty arrays provided");
        require(
            tokenIds.length == traitTypes.length,
            string.concat(
                "Length mismatch: tokenIds(",
                toString(tokenIds.length),
                ") != traitTypes(",
                toString(traitTypes.length),
                ")"
            )
        );
        require(
            tokenIds[0] < 2222,
            string.concat("Invalid token ID: ", toString(tokenIds[0]))
        );

        uint256 currentTokenId = tokenIds[0];
        delete gobTraits[currentTokenId];

        for (uint256 i = 0; i < tokenIds.length; i++) {
            require(
                tokenIds[i] < 2222,
                string.concat(
                    "Invalid token ID at index ",
                    toString(i),
                    ": ",
                    toString(tokenIds[i])
                )
            );
            require(
                bytes(traitTypes[i]).length > 0,
                string.concat("Empty trait type at index ", toString(i))
            );
            require(
                bytes(values[i]).length > 0,
                string.concat("Empty trait value at index ", toString(i))
            );

            if (currentTokenId != tokenIds[i]) {
                currentTokenId = tokenIds[i];
                delete gobTraits[currentTokenId];
            }

            Trait memory trait = Trait({
                traitType: traitTypes[i],
                value: values[i]
            });
            gobTraits[tokenIds[i]].push(trait);
        }
    }

    // Helper function to convert uint to string
    function toString(uint256 value) internal pure returns (string memory) {
        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);
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):