ScanHoodNFTFactory
0x08418af2299d4ec3a2598dbce5f6dcfb1e64a733
Verification
Verified
v0.8.30+commit.73712a01
Type
Contract
15,630 bytes
ABI entries
30
8 read · 7 write
License
mit
Contract information
- Address
- 0x08418af2299d4ec3a2598dbce5f6dcfb1e64a733
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.30+commit.73712a01
- Optimization
- Enabled
- Creator
- 0xB13670445A…7FFA63e89C
- Creation tx
- 0xe4c90a7943…deca476da3
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (8)
allCollections(uint256) → address
collectionsCount() → uint256
feeWallet() → address
isScanHoodCollection(address) → bool
launchFee() → uint256
owner() → address
pendingOwner() → address
platformFeeBps() → uint16
Events (6)
CollectionLaunchedFeeWalletUpdatedLaunchFeeUpdatedOwnershipTransferStartedOwnershipTransferredPlatformFeeBpsUpdated
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "initialOwner",
"type": "address"
},
{
"internalType": "address",
"name": "feeWallet_",
"type": "address"
},
{
"internalType": "uint256",
"name": "initialLaunchFee",
"type": "uint256"
},
{
"internalType": "uint16",
"name": "initialPlatformFeeBps",
"type": "uint16"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "InvalidBasisPoints",
"type": "error"
},
{
"inputs": [],
"name": "InvalidMaxSupply",
"type": "error"
},
{
"inputs": [],
"name": "InvalidRoyaltyBasisPoints",
"type": "error"
},
{
"inputs": [],
"name": "LaunchFeeNotPaid",
"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": "ReentrancyGuardReentrantCall",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "collection",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "string",
"name": "name",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"indexed": false,
"internalType": "uint256",
"name": "maxSupply",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "mintPrice",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "mintStart",
"type": "uint256"
}
],
"name": "CollectionLaunched",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "feeWallet",
"type": "address"
}
],
"name": "FeeWalletUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "launchFee",
"type": "uint256"
}
],
"name": "LaunchFeeUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferStarted",
"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": "uint16",
"name": "platformFeeBps",
"type": "uint16"
}
],
"name": "PlatformFeeBpsUpdated",
"type": "event"
},
{
"inputs": [],
"name": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "allCollections",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "collectionsCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "feeWallet",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "collection",
"type": "address"
}
],
"name": "isScanHoodCollection",
"outputs": [
{
"internalType": "bool",
"name": "isOurs",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "string",
"name": "baseURI",
"type": "string"
},
{
"internalType": "string",
"name": "logo",
"type": "string"
},
{
"internalType": "string",
"name": "description",
"type": "string"
},
{
"components": [
{
"internalType": "string",
"name": "twitter",
"type": "string"
},
{
"internalType": "string",
"name": "telegram",
"type": "string"
},
{
"internalType": "string",
"name": "discord",
"type": "string"
},
{
"internalType": "string",
"name": "website",
"type": "string"
},
{
"internalType": "string",
"name": "farcaster",
"type": "string"
}
],
"internalType": "struct ScanHoodNFTCollection.Socials",
"name": "socials",
"type": "tuple"
},
{
"internalType": "uint256",
"name": "maxSupply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "reserveSupply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "mintPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "walletLimit",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "mintStart",
"type": "uint256"
},
{
"internalType": "uint96",
"name": "royaltyBps",
"type": "uint96"
}
],
"internalType": "struct ScanHoodNFTFactory.CollectionParams",
"name": "params",
"type": "tuple"
}
],
"name": "launchCollection",
"outputs": [
{
"internalType": "address",
"name": "collection",
"type": "address"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "launchFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pendingOwner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "platformFeeBps",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newFeeWallet",
"type": "address"
}
],
"name": "setFeeWallet",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "newLaunchFee",
"type": "uint256"
}
],
"name": "setLaunchFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "newPlatformFeeBps",
"type": "uint16"
}
],
"name": "setPlatformFeeBps",
"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.30;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {ScanHoodNFTCollection} from "./ScanHoodNFTCollection.sol";
/**
* @title ScanHoodNFTFactory
* @notice Deploys ScanHoodNFTCollection contracts (fixed-supply ERC-721, locked
* royalty, capped mint) for a flat native-token launch fee. Mirrors the posture
* of the token launchpad: fork audited primitives (OpenZeppelin ERC-721/2981),
* add only the orchestration and no-rug guarantees on top. No marketplace or
* escrow here — trading happens on OpenSea; this only handles fair launch.
*/
contract ScanHoodNFTFactory is Ownable2Step, ReentrancyGuard {
error LaunchFeeNotPaid();
error ZeroAddress();
error InvalidMaxSupply();
error InvalidBasisPoints();
error InvalidRoyaltyBasisPoints();
event CollectionLaunched(
address indexed collection,
address indexed creator,
string name,
string symbol,
uint256 maxSupply,
uint256 mintPrice,
uint256 mintStart
);
event LaunchFeeUpdated(uint256 launchFee);
event FeeWalletUpdated(address feeWallet);
event PlatformFeeBpsUpdated(uint16 platformFeeBps);
uint256 private constant BASIS_POINTS = 10_000;
uint96 private constant MAX_ROYALTY_BPS = 1_000; // 10% cap, matches OpenSea/EIP-2981 marketplace norms
uint256 public launchFee;
address public feeWallet;
uint16 public platformFeeBps;
address[] public allCollections;
mapping(address collection => bool isOurs) public isScanHoodCollection;
struct CollectionParams {
string name;
string symbol;
string baseURI;
string logo;
string description;
ScanHoodNFTCollection.Socials socials;
uint256 maxSupply;
uint256 reserveSupply;
uint256 mintPrice;
uint256 walletLimit;
uint256 mintStart;
uint96 royaltyBps;
}
constructor(address initialOwner, address feeWallet_, uint256 initialLaunchFee, uint16 initialPlatformFeeBps)
Ownable(initialOwner)
{
if (feeWallet_ == address(0)) revert ZeroAddress();
if (initialPlatformFeeBps > BASIS_POINTS) revert InvalidBasisPoints();
feeWallet = feeWallet_;
launchFee = initialLaunchFee;
platformFeeBps = initialPlatformFeeBps;
}
/// @notice Deploys and returns a new fixed-supply collection owned by the caller.
function launchCollection(CollectionParams calldata params)
external
payable
nonReentrant
returns (address collection)
{
if (msg.value < launchFee) revert LaunchFeeNotPaid();
if (params.maxSupply == 0) revert InvalidMaxSupply();
if (params.royaltyBps > MAX_ROYALTY_BPS) revert InvalidRoyaltyBasisPoints();
collection = address(
new ScanHoodNFTCollection(
params.name,
params.symbol,
params.baseURI,
params.logo,
params.description,
params.socials,
msg.sender,
feeWallet,
platformFeeBps,
params.maxSupply,
params.reserveSupply,
params.mintPrice,
params.walletLimit,
params.mintStart,
params.royaltyBps
)
);
allCollections.push(collection);
isScanHoodCollection[collection] = true;
emit CollectionLaunched(
collection, msg.sender, params.name, params.symbol, params.maxSupply, params.mintPrice, params.mintStart
);
if (launchFee > 0) {
(bool sent,) = payable(feeWallet).call{value: launchFee}("");
if (!sent) revert LaunchFeeNotPaid();
}
uint256 refund = msg.value - launchFee;
if (refund > 0) {
(bool sentRefund,) = payable(msg.sender).call{value: refund}("");
if (!sentRefund) revert LaunchFeeNotPaid();
}
}
function collectionsCount() external view returns (uint256) {
return allCollections.length;
}
function setLaunchFee(uint256 newLaunchFee) external onlyOwner {
launchFee = newLaunchFee;
emit LaunchFeeUpdated(newLaunchFee);
}
function setFeeWallet(address newFeeWallet) external onlyOwner {
if (newFeeWallet == address(0)) revert ZeroAddress();
feeWallet = newFeeWallet;
emit FeeWalletUpdated(newFeeWallet);
}
function setPlatformFeeBps(uint16 newPlatformFeeBps) external onlyOwner {
if (newPlatformFeeBps > BASIS_POINTS) revert InvalidBasisPoints();
platformFeeBps = newPlatformFeeBps;
emit PlatformFeeBpsUpdated(newPlatformFeeBps);
}
}
Chain explorer4203msChain node82ms