Abstract Testnet

Contract Diff Checker

Contract Name:
PengoFactory

Contract Source Code:

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
/*
 * ** author  : Onchain Pengo Lab
 * ** package : @contracts/ERC721/PengoFactory.sol
 */
pragma solidity ^0.8.0;

import "../lib/base64.sol";
import "../interfaces/IPengoFactory.sol";
import "../interfaces/IPenguinOnchain.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract PengoFactory is IPengoFactory {
    using Strings for uint256;

    IPenguinOnchain public pengoContract;

    constructor() {}

    function tokenURI(
        uint256 tokenId
    ) external view override returns (string memory) {
        (
            IPenguinOnchain.Accessory[] memory accessories,
            IPenguinOnchain.Traits memory traits
        ) = pengoContract.getNFTDetails(tokenId);
        string memory baseSVG = string(
            abi.encodePacked(
                '<svg width="1000" height="1000" viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg">',
                '<rect width="100%" height="100%" fill="#2beda9"/>',
                '<rect x="140" y="100" width="40" height="15" fill="#4b4c4f"/>',
                '<rect x="135" y="110" width="50" height="35" fill="#4b4c4f"/>',
                '<rect x="125" y="140" width="70" height="15" fill="#4b4c4f"/>',
                '<rect x="115" y="150" width="90" height="15" fill="#4b4c4f"/>',
                '<rect x="105" y="160" width="110" height="20" fill="#4b4c4f"/>',
                '<rect x="115" y="170" width="90" height="30" fill="#4b4c4f"/>',
                '<rect x="125" y="195" width="70" height="30" fill="#4b4c4f"/>',
                '<rect x="150" y="150" width="20" height="15" fill="#FFFFFF"/>',
                '<rect x="140" y="160" width="40" height="15" fill="#FFFFFF"/>',
                '<rect x="130" y="170" width="60" height="25" fill="#FFFFFF"/>',
                '<rect x="140" y="190" width="40" height="20" fill="#FFFFFF"/>',
                '<rect x="145" y="115" width="10" height="10" fill="#FFFFFF"/>',
                '<rect x="165" y="115" width="10" height="10" fill="#FFFFFF"/>',
                '<rect x="148" y="118" width="4" height="4" fill="#4b4c4f"/>',
                '<rect x="168" y="118" width="4" height="4" fill="#4b4c4f"/>',
                '<rect x="155" y="130" width="10" height="10" fill="#FFA500"/>',
                '<rect x="130" y="220" width="20" height="10" fill="#FFA500"/>',
                '<rect x="170" y="220" width="20" height="10" fill="#FFA500"/>'
            )
        );

        // Menambahkan aksesori ke dalam SVG
        for (uint256 i = 0; i < accessories.length; i++) {
            baseSVG = string(abi.encodePacked(baseSVG, accessories[i].svgData));
        }

        baseSVG = string(abi.encodePacked(baseSVG, "</svg>"));

        // Membuat JSON metadata
        string memory json = Base64.encode(
            bytes(
                string(
                    abi.encodePacked(
                        "{",
                        '"name": "Pengo #',
                        tokenId.toString(),
                        '",',
                        '"description": "Pengo NFT with dynamic accessories and traits.",',
                        '"image": "data:image/svg+xml;base64,',
                        Base64.encode(bytes(baseSVG)),
                        '",',
                        '"attributes": [',
                        '{"trait_type": "Accessories", "value": "',
                        accessories.length,
                        '"},',
                        '{"trait_type": "Category", "value": "',
                        traits.category,
                        '"},',
                        '{"trait_type": "Net Worth", "value": "',
                        traits.networth,
                        '"}',
                        "]"
                        "}"
                    )
                )
            )
        );

        return string(abi.encodePacked("data:application/json;base64,", json));
    }

    function setPengoContract(address _pengoContract) external {
        pengoContract = IPenguinOnchain(_pengoContract);
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

/*
 * ** author  : Onchain Pengo Lab
 * ** package : @contracts/interfaces/IPengoFactory.sol
 */

pragma solidity ^0.8.17;

interface IPengoFactory {
    function tokenURI(
        uint256 tokenId
    ) external view returns (string memory);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

/*
 * ** author  : Onchain Pengo Lab
 * ** package : @contracts/interfaces/IPengoFactory.sol
 */

pragma solidity ^0.8.17;

interface IPenguinOnchain {
    struct Accessory {
        string accessoryType;
        string svgData;
        uint256 sellingPrice;
        uint256 lastPrice;
        address owner;
        bool forSale;
    }

    struct Traits {
        string category;
        string networth;
    }

    function getNFTDetails(uint256 tokenId) external view returns (Accessory[] memory, Traits memory);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0;

/// @title Base64
/// @author Brecht Devos - <[email protected]>
/// @notice Provides functions for encoding/decoding base64
library Base64 {
    string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    bytes  internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000"
    hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"
    hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"
    hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";

    function encode(bytes memory data) internal pure returns (string memory) {
        if (data.length == 0) return '';

        // load the table into memory
        string memory table = TABLE_ENCODE;

        // multiply by 4/3 rounded up
        uint256 encodedLen = 4 * ((data.length + 2) / 3);

        // add some extra buffer at the end required for the writing
        string memory result = new string(encodedLen + 32);

        assembly {
        // set the actual output length
            mstore(result, encodedLen)

        // prepare the lookup table
            let tablePtr := add(table, 1)

        // input ptr
            let dataPtr := data
            let endPtr := add(dataPtr, mload(data))

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

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

            // write 4 characters
                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(        input,  0x3F))))
                resultPtr := add(resultPtr, 1)
            }

        // padding with '='
            switch mod(mload(data), 3)
            case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
            case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
        }

        return result;
    }

    function decode(string memory _data) internal pure returns (bytes memory) {
        bytes memory data = bytes(_data);

        if (data.length == 0) return new bytes(0);
        require(data.length % 4 == 0, "invalid base64 decoder input");

        // load the table into memory
        bytes memory table = TABLE_DECODE;

        // every 4 characters represent 3 bytes
        uint256 decodedLen = (data.length / 4) * 3;

        // add some extra buffer at the end required for the writing
        bytes memory result = new bytes(decodedLen + 32);

        assembly {
        // padding with '='
            let lastBytes := mload(add(data, mload(data)))
            if eq(and(lastBytes, 0xFF), 0x3d) {
                decodedLen := sub(decodedLen, 1)
                if eq(and(lastBytes, 0xFFFF), 0x3d3d) {
                    decodedLen := sub(decodedLen, 1)
                }
            }

        // set the actual output length
            mstore(result, decodedLen)

        // prepare the lookup table
            let tablePtr := add(table, 1)

        // input ptr
            let dataPtr := data
            let endPtr := add(dataPtr, mload(data))

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

        // run over the input, 4 characters at a time
            for {} lt(dataPtr, endPtr) {}
            {
            // read 4 characters
                dataPtr := add(dataPtr, 4)
                let input := mload(dataPtr)

            // write 3 bytes
                let output := add(
                add(
                shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)),
                shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))),
                add(
                shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)),
                and(mload(add(tablePtr, and(        input , 0xFF))), 0xFF)
                )
                )
                mstore(resultPtr, shl(232, output))
                resultPtr := add(resultPtr, 3)
            }
        }

        return result;
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

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

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

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

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

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

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

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

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

Context size (optional):