Contract Name:
CoderativeA
Contract Source Code:
File 1 of 1 : CoderativeA
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/*
11111111111 111111
11 111
11 111
11 11111111111 111
11 111
11 111
11111111111 111
CODERATIVE-1
*/
/*
* DISCLAIMER: This contract is designed to encourage users to interact with blockchain technology
* on the Sonic network, demonstrating its speed and low costs. Users are urged to thoroughly review
* the contract and understand its mechanics before interacting. By using this contract, you agree
* that you are solely responsible for any actions taken and their outcomes. Blockchain interactions
* are inherently risky, and this contract provides no guarantees.
*
* Official Website: https://coderativesonic.github.io/nft-art-generator/
* Twitter: @0xcoderative
*/
/**
* @dev Provides a set of functions to operate with Base64 strings.
*/
library Base64 {
/**
* @dev Base64 Encoding/Decoding Table
* See sections 4 and 5 of https://datatracker.ietf.org/doc/html/rfc4648
*/
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
string internal constant _TABLE_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/
function encode(bytes memory data) internal pure returns (string memory) {
return _encode(data, _TABLE, true);
}
/**
* @dev Converts a `bytes` to its Bytes64Url `string` representation.
* Output is not padded with `=` as specified in https://www.rfc-editor.org/rfc/rfc4648[rfc4648].
*/
function encodeURL(bytes memory data) internal pure returns (string memory) {
return _encode(data, _TABLE_URL, false);
}
/**
* @dev Internal table-agnostic conversion
*/
function _encode(bytes memory data, string memory table, bool withPadding) private pure returns (string memory) {
if (data.length == 0) return "";
uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3;
string memory result = new string(resultLength);
assembly ("memory-safe") {
let tablePtr := add(table, 1)
let resultPtr := add(result, 0x20)
let dataPtr := data
let endPtr := add(data, mload(data))
let afterPtr := add(endPtr, 0x20)
let afterCache := mload(afterPtr)
mstore(afterPtr, 0x00)
for {
} lt(dataPtr, endPtr) {
} {
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
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)
}
mstore(afterPtr, afterCache)
if withPadding {
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;
}
}
/**
* @title ERC721 Standard Implementation
* @notice Base implementation of ERC721 with added features for enumeration.
*/
contract ERC721 {
// Events emitted for key actions in ERC721
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
// Mapping to store the owners of tokens
mapping(uint256 => address) private _owners;
// Mapping to store balances of addresses
mapping(address => uint256) private _balances;
// Mapping for token approvals
mapping(uint256 => address) private _tokenApprovals;
// Mapping for operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
/**
* @notice Returns the balance of the given address.
* @param owner The address to query.
* @return uint256 The token balance.
*/
function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
/**
* @notice Returns the owner of the specified token ID.
* @param tokenId The token ID to query.
* @return address The owner address.
*/
function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
/**
* @notice Internal function to transfer ownership of a token.
* @param from The current owner of the token.
* @param to The new owner of the token.
* @param tokenId The token ID to transfer.
*/
function _transfer(address from, address to, uint256 tokenId) internal {
require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId);
}
/**
* @notice Internal function to mint a new token.
* @param to The address to receive the minted token.
* @param tokenId The token ID to mint.
*/
function _mint(address to, uint256 tokenId) internal {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
_afterTokenTransfer(address(0), to, tokenId);
}
/**
* @notice Checks if a token ID exists.
* @param tokenId The token ID to check.
* @return bool True if the token exists, false otherwise.
*/
function _exists(uint256 tokenId) internal view returns (bool) {
return _owners[tokenId] != address(0);
}
/**
* @dev Hook that is called before any token transfer.
*/
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual {}
/**
* @dev Hook that is called after any token transfer.
*/
function _afterTokenTransfer(address from, address to, uint256 tokenId) internal virtual {}
}
/**
* @title Ownable Contract
* @notice Basic ownership functionality for the contract.
*/
contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
_transferOwnership(initialOwner);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == msg.sender, "Ownable: caller is not the owner");
_;
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function renounceOwnership() public onlyOwner {
_transferOwnership(address(0));
}
function _transferOwnership(address newOwner) internal {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
/**
* @title ERC721Enumerable
* @notice ERC721 implementation with token enumeration functionality.
*/
contract ERC721Enumerable is ERC721 {
uint256[] private _allTokens;
mapping(uint256 => uint256) private _allTokensIndex;
mapping(address => uint256[]) private _ownedTokens;
mapping(uint256 => uint256) private _ownedTokensIndex;
function totalSupply() public view returns (uint256) {
return _allTokens.length;
}
function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
return _ownedTokens[owner][index];
}
function tokenByIndex(uint256 index) public view returns (uint256) {
require(index < _allTokens.length, "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override {
super._beforeTokenTransfer(from, to, tokenId);
if (from == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (from != to) {
_removeTokenFromOwnerEnumeration(from, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (to != from) {
_addTokenToOwnerEnumeration(to, tokenId);
}
}
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
_ownedTokens[to].push(tokenId);
_ownedTokensIndex[tokenId] = _ownedTokens[to].length - 1;
}
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
uint256 lastTokenIndex = _ownedTokens[from].length - 1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId;
_ownedTokensIndex[lastTokenId] = tokenIndex;
}
_ownedTokens[from].pop();
delete _ownedTokensIndex[tokenId];
}
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId;
_allTokensIndex[lastTokenId] = tokenIndex;
_allTokens.pop();
delete _allTokensIndex[tokenId];
}
}
/**
* @title CoderativeA
* @notice Main contract for generative art NFTs on the Sonic network.
*/
contract CoderativeA is ERC721Enumerable, Ownable {
uint256 private _tokenIds;
mapping(address => bool) private _hasMinted;
mapping(uint256 => string) public tokenData;
uint256 private constant MAX_SUPPLY = 5000;
string private _name = "Coderative-A Collection";
string private _symbol = "CAC";
event NFTMinted(address indexed minter, uint256 indexed tokenId, string data);
error AlreadyMinted();
error MaxSupplyReached();
constructor() Ownable(msg.sender) {}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function mint() external {
if (_hasMinted[msg.sender]) revert AlreadyMinted();
if (_tokenIds >= MAX_SUPPLY) revert MaxSupplyReached();
_hasMinted[msg.sender] = true;
uint256 tokenId = _tokenIds;
_tokenIds++;
string memory data = _generateArtData(msg.sender);
tokenData[tokenId] = data;
emit NFTMinted(msg.sender, tokenId, data);
_mint(msg.sender, tokenId);
}
function _generateArtData(address minter) internal view returns (string memory) {
bytes32 blockHash = blockhash(block.number - 1);
uint256 gradientAngle = uint256(keccak256(abi.encodePacked(blockHash, minter))) % 360;
uint256 noiseLevel = uint256(keccak256(abi.encodePacked(blockHash, minter, "noise"))) % 100;
uint256 colorSeed = uint256(keccak256(abi.encodePacked(blockHash, minter, "colors")));
return string(abi.encodePacked(
"{",
"\"name\":\"Coderative-A Token\",",
"\"description\":\"A generative art NFT\",",
"\"attributes\":{",
"\"angle\":", _toString(gradientAngle), ",",
"\"noise\":", _toString(noiseLevel), ",",
"\"color\":", _toString(colorSeed),
"}}"
));
}
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);
}
function tokenURI(uint256 tokenId) public view returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory data = tokenData[tokenId];
return string(abi.encodePacked("data:application/json;base64,", Base64.encode(bytes(data))));
}
}