Agents
0x967f96ed9aecb0b9ef3f34532d931702f39cf24b
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
7,685 bytes
ABI entries
66
19 read · 11 write
License
none
Contract information
- Address
- 0x967f96ed9aecb0b9ef3f34532d931702f39cf24b
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x290A12d965…4bE69A27Cb
- Creation tx
- 0x6ce53e9fc1…dbfcc3d21c
Token
- Name
- Agents
- Symbol
- AGT
- Decimals
- —
- Holders
- 7
- Market
- View token page →
Read contract (19)
balanceOf(address) → uint256
cidUsed(bytes32) → bool
domainSeparator() → bytes32
eip712Domain() → bytes1, string, string, uint256, address, bytes32, uint256[]
factory() → address
getApproved(uint256) → address
isApprovedForAll(address, address) → bool
name() → string
nextTokenId() → uint256
owner() → address
ownerOf(uint256) → address
royaltyInfo(uint256, uint256) → address, uint256
signer() → address
supportsInterface(bytes4) → bool
symbol() → string
tokenByIndex(uint256) → uint256
tokenOfOwnerByIndex(address, uint256) → uint256
tokenURI(uint256) → string
totalSupply() → uint256
Events (9)
ApprovalApprovalForAllEIP712DomainChangedFactoryUpdatedMintedOwnershipTransferredRoyaltyUpdatedSignerUpdatedTransfer
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "initialOwner",
"type": "address"
},
{
"internalType": "address",
"name": "initialSigner",
"type": "address"
},
{
"internalType": "address",
"name": "royaltyReceiver",
"type": "address"
},
{
"internalType": "uint96",
"name": "royaltyBps",
"type": "uint96"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "CidAlreadyUsed",
"type": "error"
},
{
"inputs": [],
"name": "ECDSAInvalidSignature",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "length",
"type": "uint256"
}
],
"name": "ECDSAInvalidSignatureLength",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"name": "ECDSAInvalidSignatureS",
"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": "ERC721EnumerableForbiddenBatchMint",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "ERC721IncorrectOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "ERC721InsufficientApproval",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "approver",
"type": "address"
}
],
"name": "ERC721InvalidApprover",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "ERC721InvalidOperator",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "ERC721InvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
}
],
"name": "ERC721InvalidReceiver",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "ERC721InvalidSender",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "ERC721NonexistentToken",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "ERC721OutOfBoundsIndex",
"type": "error"
},
{
"inputs": [],
"name": "EmptyCID",
"type": "error"
},
{
"inputs": [],
"name": "InvalidShortString",
"type": "error"
},
{
"inputs": [],
"name": "InvalidSignature",
"type": "error"
},
{
"inputs": [],
"name": "OnlyFactory",
"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": [
{
"internalType": "string",
"name": "str",
"type": "string"
}
],
"name": "StringTooLong",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"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": [],
"name": "EIP712DomainChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "oldFactory",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newFactory",
"type": "address"
}
],
"name": "FactoryUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "string",
"name": "cid",
"type": "string"
}
],
"name": "Minted",
"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": "address",
"name": "receiver",
"type": "address"
},
{
"indexed": false,
"internalType": "uint96",
"name": "feeNumerator",
"type": "uint96"
}
],
"name": "RoyaltyUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "oldSigner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newSigner",
"type": "address"
}
],
"name": "SignerUpdated",
"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"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "approve",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"name": "cidUsed",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "domainSeparator",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "eip712Domain",
"outputs": [
{
"internalType": "bytes1",
"name": "fields",
"type": "bytes1"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "version",
"type": "string"
},
{
"internalType": "uint256",
"name": "chainId",
"type": "uint256"
},
{
"internalType": "address",
"name": "verifyingContract",
"type": "address"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "uint256[]",
"name": "extensions",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "factory",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"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": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "string",
"name": "cid",
"type": "string"
},
{
"internalType": "bytes",
"name": "signature",
"type": "bytes"
}
],
"name": "mintFromFactory",
"outputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "nextTokenId",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"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": [],
"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": "nonpayable",
"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": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newFactory",
"type": "address"
}
],
"name": "setFactory",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"internalType": "uint96",
"name": "feeNumerator",
"type": "uint96"
}
],
"name": "setRoyalty",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newSigner",
"type": "address"
}
],
"name": "setSigner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "signer",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"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": "index",
"type": "uint256"
}
],
"name": "tokenByIndex",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "tokenOfOwnerByIndex",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"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": "",
"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": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import {ERC2981} from "@openzeppelin/contracts/token/common/ERC2981.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title Agents
* @notice ERC-721 NFT minted exclusively by PrimePadFactory during a project launch.
*
* Mint flow:
* 1. Admin uploads agent metadata to IPFS, gets a CID
* 2. Admin's server signs an EIP-712 voucher: MintVoucher(bytes32 cidHash)
* where cidHash = keccak256(bytes(cid))
* 3. Project creator calls PrimePadFactory.deploy(...) passing the cid + signature
* 4. Factory calls Agents.mintFromFactory(creator, cid, signature)
* 5. Contract verifies the signature and mints to `creator` with the next sequential tokenId
*
* Each CID can only be used once. tokenIds are auto-assigned, never re-used.
*
* Standards: ERC-721, ERC-2981 (royalties), EIP-712 (signed vouchers).
*/
contract Agents is ERC721Enumerable, ERC2981, EIP712, Ownable {
using ECDSA for bytes32;
bytes32 private constant MINT_VOUCHER_TYPEHASH = keccak256(
"MintVoucher(bytes32 cidHash)"
);
/// Authorized signer for mint vouchers (the admin server's key).
address public signer;
/// PrimePadFactory address — only contract permitted to call mintFromFactory.
address public factory;
/// Per-token metadata CID (without "ipfs://" prefix).
mapping(uint256 => string) private _tokenCIDs;
/// Track which CID hashes have been used (prevents duplicate mints of the same content).
mapping(bytes32 => bool) public cidUsed;
/// Next tokenId to mint. Auto-incremented on every mint.
uint256 public nextTokenId = 1;
event Minted(address indexed to, uint256 indexed tokenId, string cid);
event SignerUpdated(address indexed oldSigner, address indexed newSigner);
event FactoryUpdated(address indexed oldFactory, address indexed newFactory);
event RoyaltyUpdated(address receiver, uint96 feeNumerator);
error CidAlreadyUsed();
error InvalidSignature();
error ZeroAddress();
error EmptyCID();
error OnlyFactory();
/**
* @param initialOwner Admin address (controls signer + royalties + factory wiring)
* @param initialSigner Address whose signatures authorize mints
* @param royaltyReceiver Royalty recipient for ERC-2981
* @param royaltyBps Royalty in basis points (e.g. 500 = 5%)
*/
constructor(
address initialOwner,
address initialSigner,
address royaltyReceiver,
uint96 royaltyBps
)
ERC721("Agents", "AGT")
EIP712("Agents", "1")
Ownable(initialOwner)
{
if (initialSigner == address(0)) revert ZeroAddress();
signer = initialSigner;
if (royaltyReceiver != address(0) && royaltyBps > 0) {
_setDefaultRoyalty(royaltyReceiver, royaltyBps);
}
}
/**
* @notice Mint an agent NFT. Callable only by the configured factory.
* The factory passes the project creator as `to`.
*
* @param to Recipient (the project creator).
* @param cid Plaintext IPFS CID (signed off-chain as keccak256(cid)).
* @param signature EIP-712 signature from `signer`.
* @return tokenId The auto-assigned tokenId of the minted NFT.
*/
function mintFromFactory(
address to,
string calldata cid,
bytes calldata signature
) external returns (uint256 tokenId) {
if (msg.sender != factory) revert OnlyFactory();
if (bytes(cid).length == 0) revert EmptyCID();
if (to == address(0)) revert ZeroAddress();
bytes32 cidHash = keccak256(bytes(cid));
if (cidUsed[cidHash]) revert CidAlreadyUsed();
bytes32 structHash = keccak256(abi.encode(MINT_VOUCHER_TYPEHASH, cidHash));
bytes32 digest = _hashTypedDataV4(structHash);
if (digest.recover(signature) != signer) revert InvalidSignature();
cidUsed[cidHash] = true;
tokenId = nextTokenId++;
_tokenCIDs[tokenId] = cid;
_safeMint(to, tokenId);
emit Minted(to, tokenId, cid);
}
/**
* Returns "ipfs://<CID>". Marketplaces resolve this to the metadata JSON.
*/
function tokenURI(uint256 tokenId) public view override returns (string memory) {
_requireOwned(tokenId);
return string(abi.encodePacked("ipfs://", _tokenCIDs[tokenId]));
}
/// EIP-712 domain separator (handy for off-chain signing libs).
function domainSeparator() external view returns (bytes32) {
return _domainSeparatorV4();
}
/* ── Admin ─────────────────────────────────────────────────── */
function setSigner(address newSigner) external onlyOwner {
if (newSigner == address(0)) revert ZeroAddress();
emit SignerUpdated(signer, newSigner);
signer = newSigner;
}
function setFactory(address newFactory) external onlyOwner {
if (newFactory == address(0)) revert ZeroAddress();
emit FactoryUpdated(factory, newFactory);
factory = newFactory;
}
function setRoyalty(address receiver, uint96 feeNumerator) external onlyOwner {
_setDefaultRoyalty(receiver, feeNumerator);
emit RoyaltyUpdated(receiver, feeNumerator);
}
/* ── ERC-165 (combine parents) ─────────────────────────────── */
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721Enumerable, ERC2981)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
function _update(address to, uint256 tokenId, address auth)
internal
override(ERC721Enumerable)
returns (address)
{
return super._update(to, tokenId, auth);
}
function _increaseBalance(address account, uint128 value)
internal
override(ERC721Enumerable)
{
super._increaseBalance(account, value);
}
}
Chain explorer1505msChain node95ms