OnChainRobin
0xf197be206258f6b5c702cacaef0dccd252a400c8
Verification
Verified
0.8.24+commit.e11b9ed9
Type
Contract
10,221 bytes
ABI entries
73
20 read · 15 write
License
none
Contract information
- Address
- 0xf197be206258f6b5c702cacaef0dccd252a400c8
- Chain
- Robinhood Chain (4663)
- Compiler
- 0.8.24+commit.e11b9ed9
- Optimization
- Enabled
- Creator
- 0x04106c7260…fF55a72929
- Creation tx
- 0xf467385219…8d4a33020f
Token
- Name
- onChainRobin
- Symbol
- OCR
- Decimals
- —
- Holders
- 1,200
- Market
- View token page →
Read contract (20)
MAX_PUBLIC_MINT() → uint256
MAX_SUPPLY() → uint256
MAX_TREASURY_MINT() → uint256
amountMinted(address) → uint256
balanceOf(address) → uint256
baseURI() → string
contractURI() → string
contractURIString() → string
getApproved(uint256) → address
isApprovedForAll(address, address) → bool
mintPrice() → uint256
name() → string
owner() → address
ownerOf(uint256) → address
publicMintEnabled() → bool
royaltyInfo(uint256, uint256) → address, uint256
supportsInterface(bytes4) → bool
symbol() → string
tokenURI(uint256) → string
totalSupply() → uint256
Events (11)
ApprovalApprovalForAllBaseURIUpdatedConsecutiveTransferContractURIUpdatedOwnershipTransferredPriceUpdatedPublicMintStateChangedTransferTreasuryMintedWithdrawn
ABI
[
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "ApprovalCallerNotOwnerNorApproved",
"type": "error"
},
{
"inputs": [],
"name": "ApprovalQueryForNonexistentToken",
"type": "error"
},
{
"inputs": [],
"name": "BalanceQueryForZeroAddress",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "numerator",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "denominator",
"type": "uint256"
}
],
"name": "ERC2981InvalidDefaultRoyalty",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
}
],
"name": "ERC2981InvalidDefaultRoyaltyReceiver",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "numerator",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "denominator",
"type": "uint256"
}
],
"name": "ERC2981InvalidTokenRoyalty",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "address",
"name": "receiver",
"type": "address"
}
],
"name": "ERC2981InvalidTokenRoyaltyReceiver",
"type": "error"
},
{
"inputs": [],
"name": "MintERC2309QuantityExceedsLimit",
"type": "error"
},
{
"inputs": [],
"name": "MintToZeroAddress",
"type": "error"
},
{
"inputs": [],
"name": "MintZeroQuantity",
"type": "error"
},
{
"inputs": [],
"name": "NotCompatibleWithSpotMints",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OwnableInvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "OwnableUnauthorizedAccount",
"type": "error"
},
{
"inputs": [],
"name": "OwnerQueryForNonexistentToken",
"type": "error"
},
{
"inputs": [],
"name": "OwnershipNotInitializedForExtraData",
"type": "error"
},
{
"inputs": [],
"name": "ReentrancyGuardReentrantCall",
"type": "error"
},
{
"inputs": [],
"name": "SequentialMintExceedsLimit",
"type": "error"
},
{
"inputs": [],
"name": "SequentialUpToTooSmall",
"type": "error"
},
{
"inputs": [],
"name": "SpotMintTokenIdTooSmall",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "length",
"type": "uint256"
}
],
"name": "StringsInsufficientHexLength",
"type": "error"
},
{
"inputs": [],
"name": "TokenAlreadyExists",
"type": "error"
},
{
"inputs": [],
"name": "TransferCallerNotOwnerNorApproved",
"type": "error"
},
{
"inputs": [],
"name": "TransferFromIncorrectOwner",
"type": "error"
},
{
"inputs": [],
"name": "TransferToNonERC721ReceiverImplementer",
"type": "error"
},
{
"inputs": [],
"name": "TransferToZeroAddress",
"type": "error"
},
{
"inputs": [],
"name": "URIQueryForNonexistentToken",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "approved",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"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": false,
"internalType": "string",
"name": "newBaseURI",
"type": "string"
}
],
"name": "BaseURIUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "fromTokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "toTokenId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
}
],
"name": "ConsecutiveTransfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "string",
"name": "newContractURI",
"type": "string"
}
],
"name": "ContractURIUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "newPrice",
"type": "uint256"
}
],
"name": "PriceUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "bool",
"name": "isEnabled",
"type": "bool"
}
],
"name": "PublicMintStateChanged",
"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": "tokenId",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "TreasuryMinted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Withdrawn",
"type": "event"
},
{
"inputs": [],
"name": "MAX_PUBLIC_MINT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_SUPPLY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_TREASURY_MINT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "amountMinted",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "approve",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "baseURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "contractURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "contractURIString",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "getApproved",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "isApprovedForAll",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "mintPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"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": "tokenId",
"type": "uint256"
}
],
"name": "ownerOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "publicMint",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "publicMintEnabled",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "salePrice",
"type": "uint256"
}
],
"name": "royaltyInfo",
"outputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "_newBaseURI",
"type": "string"
}
],
"name": "setBaseURI",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "_newContractURI",
"type": "string"
}
],
"name": "setContractURI",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"internalType": "uint96",
"name": "feeNumerator",
"type": "uint96"
}
],
"name": "setDefaultRoyalty",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_newPrice",
"type": "uint256"
}
],
"name": "setMintPrice",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bool",
"name": "_state",
"type": "bool"
}
],
"name": "setPublicMintState",
"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": "tokenId",
"type": "uint256"
}
],
"name": "tokenURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "result",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "treasuryMint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "withdraw",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "erc721a/contracts/ERC721A.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
/**
* @title OnChainRobin (OCR)
* @notice Fully On-Chain NFT Collection for Robinhood Chain.
* @dev Implements ERC721A, ERC2981 (Royalties), and fully on-chain deterministic SVG generation.
*/
contract OnChainRobin is ERC721A, ERC2981, Ownable, ReentrancyGuard {
using Strings for uint256;
// --- State Variables ---
uint256 public constant MAX_SUPPLY = 5999;
uint256 public constant MAX_PUBLIC_MINT = 5;
uint256 public constant MAX_TREASURY_MINT = 99;
uint256 public mintPrice = 0.001 ether;
bool public publicMintEnabled = false;
// Optional URIs if external fallback is ever required
string public baseURI;
string public contractURIString;
mapping(address => uint256) public amountMinted;
// --- Events ---
event TreasuryMinted(address indexed to, uint256 amount);
event PublicMintStateChanged(bool isEnabled);
event PriceUpdated(uint256 newPrice);
event Withdrawn(address indexed owner, uint256 amount);
event BaseURIUpdated(string newBaseURI);
event ContractURIUpdated(string newContractURI);
// --- Constructor ---
constructor() ERC721A("onChainRobin", "OCR") Ownable(msg.sender) {
// Set default royalty to 3% (300 basis points)
_setDefaultRoyalty(msg.sender, 300);
}
// --- Minting Functions ---
/**
* @notice Treasury mint for the owner (Max 99 per tx).
* @param amount Number of NFTs to mint.
*/
function treasuryMint(uint256 amount) external onlyOwner {
require(amount > 0, "Amount must be greater than 0");
require(amount <= MAX_TREASURY_MINT, "Exceeds max treasury mint per tx");
require(_totalMinted() + amount <= MAX_SUPPLY, "Exceeds max supply");
_mint(msg.sender, amount);
emit TreasuryMinted(msg.sender, amount);
}
/**
* @notice Public mint function.
* @param amount Number of NFTs to mint.
*/
function publicMint(uint256 amount) external payable nonReentrant {
require(publicMintEnabled, "Public mint is disabled");
require(amount > 0, "Amount must be greater than 0");
require(amountMinted[msg.sender] + amount <= MAX_PUBLIC_MINT, "Exceeds wallet limit");
require(_totalMinted() + amount <= MAX_SUPPLY, "Exceeds max supply");
require(msg.value == mintPrice * amount, "Incorrect ETH payment");
amountMinted[msg.sender] += amount;
_mint(msg.sender, amount);
}
// --- Admin Functions ---
/**
* @notice Enables or disables the public mint.
* @param _state True to enable, false to disable.
*/
function setPublicMintState(bool _state) external onlyOwner {
publicMintEnabled = _state;
emit PublicMintStateChanged(_state);
}
/**
* @notice Updates the public mint price.
* @param _newPrice New price in wei.
*/
function setMintPrice(uint256 _newPrice) external onlyOwner {
mintPrice = _newPrice;
emit PriceUpdated(_newPrice);
}
/**
* @notice Updates the ERC2981 royalty configuration.
* @param receiver Address to receive royalties.
* @param feeNumerator Royalty percentage in basis points (e.g., 300 = 3%).
*/
function setDefaultRoyalty(address receiver, uint96 feeNumerator) external onlyOwner {
_setDefaultRoyalty(receiver, feeNumerator);
}
/**
* @notice Sets a fallback base URI.
* @param _newBaseURI New base URI string.
*/
function setBaseURI(string calldata _newBaseURI) external onlyOwner {
baseURI = _newBaseURI;
emit BaseURIUpdated(_newBaseURI);
}
/**
* @notice Sets the contract-level metadata URI.
* @param _newContractURI New contract URI string.
*/
function setContractURI(string calldata _newContractURI) external onlyOwner {
contractURIString = _newContractURI;
emit ContractURIUpdated(_newContractURI);
}
/**
* @notice Safely withdraws the entire ETH balance of the contract.
* Uses the recommended call pattern and ReentrancyGuard.
*/
function withdraw() external onlyOwner nonReentrant {
uint256 balance = address(this).balance;
require(balance > 0, "No ETH to withdraw");
(bool success, ) = msg.sender.call{value: balance}("");
require(success, "Withdraw failed");
emit Withdrawn(msg.sender, balance);
}
// --- On-Chain SVG & Metadata Generation ---
/**
* @notice Generates deterministic symmetric pixel art SVG based on Token ID.
* @param tokenId The token ID to generate art for.
* @return Base64 encoded SVG string.
*/
function generateSVG(uint256 tokenId) internal pure returns (string memory) {
// Derive a deterministic seed solely from the Token ID
uint256 seed = uint256(keccak256(abi.encodePacked("OCR_SEED", tokenId)));
string memory svg = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' shape-rendering='crispEdges'><rect width='16' height='16' fill='#DFFF00'/>";
// Generate an 8x16 grid and mirror it horizontally to create 16x16 symmetric pixel art
for (uint8 y = 0; y < 16; y++) {
for (uint8 x = 0; x < 8; x++) {
uint256 bitIndex = y * 8 + x;
if ((seed >> bitIndex) & 1 == 1) {
string memory yStr = uint256(y).toString();
// Left side pixel
svg = string.concat(
svg,
"<rect x='", uint256(x).toString(), "' y='", yStr, "' width='1' height='1' fill='#000'/>"
);
// Right side mirrored pixel
svg = string.concat(
svg,
"<rect x='", uint256(15 - x).toString(), "' y='", yStr, "' width='1' height='1' fill='#000'/>"
);
}
}
}
svg = string.concat(svg, "</svg>");
return svg;
}
/**
* @notice Returns the fully on-chain generated metadata for a given token.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
// If a base URI is set, it overrides the on-chain metadata
if (bytes(baseURI).length > 0) {
return string.concat(baseURI, tokenId.toString());
}
string memory svg = generateSVG(tokenId);
uint256 seed = uint256(keccak256(abi.encodePacked("OCR_SEED", tokenId)));
string memory json = Base64.encode(
bytes(
string.concat(
'{"name": "onChainRobin #', tokenId.toString(), '", ',
'"description": "100% Fully On-Chain Deterministic Pixel Art on the Robinhood Chain.", ',
'"attributes": [',
'{"trait_type": "Background", "value": "Electric Lime"}, ',
'{"trait_type": "Pixel Style", "value": "Symmetric"}, ',
'{"trait_type": "Seed", "value": "0x', Strings.toHexString(uint160(seed >> 96)), '"}, ',
'{"trait_type": "Renderer", "value": "On-Chain SVG"}',
'], ',
'"image": "data:image/svg+xml;base64,', Base64.encode(bytes(svg)), '"}'
)
)
);
return string.concat("data:application/json;base64,", json);
}
/**
* @notice Contract-level metadata for marketplaces (e.g., OpenSea).
*/
function contractURI() external view returns (string memory) {
return contractURIString;
}
// --- Overrides ---
/**
* @dev Resolves override conflict between ERC721A and ERC2981.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, ERC2981) returns (bool) {
return super.supportsInterface(interfaceId);
}
/**
* @dev Start token IDs at 1.
*/
function _startTokenId() internal view virtual override returns (uint256) {
return 1;
}
}Chain explorer2144msChain node84ms