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);
}
}