LaunchTemplateRegistry
0x1c781892dbe4dbaf2637259e4963b3cc41eb46a0
Verification
Verified
v0.8.24+commit.e11b9ed9
Type
Contract
4,589 bytes
ABI entries
31
13 read · 5 write
License
none
Contract information
- Address
- 0x1c781892dbe4dbaf2637259e4963b3cc41eb46a0
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.24+commit.e11b9ed9
- Optimization
- Enabled
- Creator
- 0xd03543d97B…F446Cd1418
- Creation tx
- 0x46d4da66c5…7172f34b15
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (13)
DEFAULT_ADMIN_ROLE() → bytes32
MAX_CREATOR_FEE_BPS() → uint16
MAX_LAUNCH_FEE_WEI() → uint256
MAX_TOKEN_DECIMALS() → uint8
MAX_TOKEN_SUPPLY() → uint256
MIN_TOKEN_DECIMALS() → uint8
REGISTRY_VERSION() → uint32
TEMPLATE_MANAGER_ROLE() → bytes32
getRoleAdmin(bytes32) → bytes32
getTemplate(bytes32, uint32) → tuple
hasRole(bytes32, address) → bool
latestVersion(bytes32) → uint32
supportsInterface(bytes4) → bool
Events (5)
RoleAdminChangedRoleGrantedRoleRevokedTemplateAvailabilityUpdatedTemplateVersionAdded
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "admin",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AccessControlBadConfirmation",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "bytes32",
"name": "neededRole",
"type": "bytes32"
}
],
"name": "AccessControlUnauthorizedAccount",
"type": "error"
},
{
"inputs": [],
"name": "InvalidAddress",
"type": "error"
},
{
"inputs": [],
"name": "InvalidTemplate",
"type": "error"
},
{
"inputs": [],
"name": "InvalidVersion",
"type": "error"
},
{
"inputs": [],
"name": "TemplateAlreadyExists",
"type": "error"
},
{
"inputs": [],
"name": "TemplateNotFound",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "previousAdminRole",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newAdminRole",
"type": "bytes32"
}
],
"name": "RoleAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleGranted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleRevoked",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "templateKey",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "uint32",
"name": "version",
"type": "uint32"
},
{
"indexed": false,
"internalType": "bool",
"name": "enabled",
"type": "bool"
}
],
"name": "TemplateAvailabilityUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "templateKey",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "uint32",
"name": "version",
"type": "uint32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "configurationHash",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "bool",
"name": "enabled",
"type": "bool"
}
],
"name": "TemplateVersionAdded",
"type": "event"
},
{
"inputs": [],
"name": "DEFAULT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_CREATOR_FEE_BPS",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_LAUNCH_FEE_WEI",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_TOKEN_DECIMALS",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_TOKEN_SUPPLY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MIN_TOKEN_DECIMALS",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "REGISTRY_VERSION",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TEMPLATE_MANAGER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "templateKey",
"type": "bytes32"
},
{
"internalType": "uint32",
"name": "version",
"type": "uint32"
},
{
"components": [
{
"internalType": "uint256",
"name": "tokenSupply",
"type": "uint256"
},
{
"internalType": "uint8",
"name": "tokenDecimals",
"type": "uint8"
},
{
"internalType": "bool",
"name": "burnable",
"type": "bool"
},
{
"internalType": "uint256",
"name": "launchFeeWei",
"type": "uint256"
},
{
"internalType": "uint16",
"name": "creatorFeeBps",
"type": "uint16"
},
{
"internalType": "uint256",
"name": "stakeRequirement",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "curveConfigHash",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "fairLaunchConfigHash",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "isGenesis",
"type": "bool"
},
{
"internalType": "bool",
"name": "isOfficial",
"type": "bool"
}
],
"internalType": "struct LaunchTemplateRegistry.TemplateConfig",
"name": "config",
"type": "tuple"
},
{
"internalType": "bool",
"name": "enabled",
"type": "bool"
}
],
"name": "addTemplateVersion",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "templateKey",
"type": "bytes32"
},
{
"internalType": "uint32",
"name": "version",
"type": "uint32"
}
],
"name": "getTemplate",
"outputs": [
{
"components": [
{
"internalType": "bool",
"name": "exists",
"type": "bool"
},
{
"internalType": "bool",
"name": "enabled",
"type": "bool"
},
{
"internalType": "uint32",
"name": "version",
"type": "uint32"
},
{
"internalType": "uint256",
"name": "tokenSupply",
"type": "uint256"
},
{
"internalType": "uint8",
"name": "tokenDecimals",
"type": "uint8"
},
{
"internalType": "bool",
"name": "burnable",
"type": "bool"
},
{
"internalType": "uint256",
"name": "launchFeeWei",
"type": "uint256"
},
{
"internalType": "uint16",
"name": "creatorFeeBps",
"type": "uint16"
},
{
"internalType": "uint256",
"name": "stakeRequirement",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "curveConfigHash",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "fairLaunchConfigHash",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "isGenesis",
"type": "bool"
},
{
"internalType": "bool",
"name": "isOfficial",
"type": "bool"
}
],
"internalType": "struct LaunchTemplateRegistry.StandardTokenTemplate",
"name": "template",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "grantRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "hasRole",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "templateKey",
"type": "bytes32"
}
],
"name": "latestVersion",
"outputs": [
{
"internalType": "uint32",
"name": "version",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "callerConfirmation",
"type": "address"
}
],
"name": "renounceRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "revokeRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "templateKey",
"type": "bytes32"
},
{
"internalType": "uint32",
"name": "version",
"type": "uint32"
},
{
"internalType": "bool",
"name": "enabled",
"type": "bool"
}
],
"name": "setTemplateEnabled",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
/// @title Equifold Launch Template Registry
/// @author Equifold
/// @notice Append-only standard-token templates with explicit versions and bounded parameters.
contract LaunchTemplateRegistry is AccessControl {
error InvalidAddress();
error InvalidTemplate();
error InvalidVersion();
error TemplateAlreadyExists();
error TemplateNotFound();
uint16 public constant MAX_CREATOR_FEE_BPS = 1000;
uint256 public constant MAX_LAUNCH_FEE_WEI = 10 ether;
uint256 public constant MAX_TOKEN_SUPPLY = 1e36;
uint8 public constant MIN_TOKEN_DECIMALS = 6;
uint8 public constant MAX_TOKEN_DECIMALS = 18;
uint32 public constant REGISTRY_VERSION = 1;
bytes32 public constant TEMPLATE_MANAGER_ROLE = keccak256("TEMPLATE_MANAGER_ROLE");
struct TemplateConfig {
uint256 tokenSupply;
uint8 tokenDecimals;
bool burnable;
uint256 launchFeeWei;
uint16 creatorFeeBps;
uint256 stakeRequirement;
bytes32 curveConfigHash;
bytes32 fairLaunchConfigHash;
bool isGenesis;
bool isOfficial;
}
struct StandardTokenTemplate {
bool exists;
bool enabled;
uint32 version;
uint256 tokenSupply;
uint8 tokenDecimals;
bool burnable;
uint256 launchFeeWei;
uint16 creatorFeeBps;
uint256 stakeRequirement;
bytes32 curveConfigHash;
bytes32 fairLaunchConfigHash;
bool isGenesis;
bool isOfficial;
}
mapping(bytes32 templateKey => uint32 version) public latestVersion;
mapping(bytes32 templateKey => mapping(uint32 version => StandardTokenTemplate template))
private _templates;
event TemplateVersionAdded(
bytes32 indexed templateKey,
uint32 indexed version,
bytes32 indexed configurationHash,
bool enabled
);
event TemplateAvailabilityUpdated(
bytes32 indexed templateKey, uint32 indexed version, bool enabled
);
constructor(
address admin
) {
if (admin == address(0)) revert InvalidAddress();
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(TEMPLATE_MANAGER_ROLE, admin);
}
/// @notice Adds the next immutable version of a launch template.
function addTemplateVersion(
bytes32 templateKey,
uint32 version,
TemplateConfig calldata config,
bool enabled
) external onlyRole(TEMPLATE_MANAGER_ROLE) {
if (templateKey == bytes32(0)) revert InvalidTemplate();
if (version == 0 || version != latestVersion[templateKey] + 1) revert InvalidVersion();
if (_templates[templateKey][version].exists) revert TemplateAlreadyExists();
if (
config.tokenSupply == 0 || config.tokenSupply > MAX_TOKEN_SUPPLY
|| config.tokenDecimals < MIN_TOKEN_DECIMALS
|| config.tokenDecimals > MAX_TOKEN_DECIMALS
|| config.launchFeeWei > MAX_LAUNCH_FEE_WEI
|| config.creatorFeeBps > MAX_CREATOR_FEE_BPS
|| config.curveConfigHash == bytes32(0) || config.fairLaunchConfigHash == bytes32(0)
|| (config.isGenesis && !config.isOfficial)
) revert InvalidTemplate();
_templates[templateKey][version] = StandardTokenTemplate({
exists: true,
enabled: enabled,
version: version,
tokenSupply: config.tokenSupply,
tokenDecimals: config.tokenDecimals,
burnable: config.burnable,
launchFeeWei: config.launchFeeWei,
creatorFeeBps: config.creatorFeeBps,
stakeRequirement: config.stakeRequirement,
curveConfigHash: config.curveConfigHash,
fairLaunchConfigHash: config.fairLaunchConfigHash,
isGenesis: config.isGenesis,
isOfficial: config.isOfficial
});
latestVersion[templateKey] = version;
emit TemplateVersionAdded(templateKey, version, keccak256(abi.encode(config)), enabled);
}
/// @notice Enables or disables new launches without mutating the template configuration.
function setTemplateEnabled(
bytes32 templateKey,
uint32 version,
bool enabled
) external onlyRole(TEMPLATE_MANAGER_ROLE) {
StandardTokenTemplate storage template = _templates[templateKey][version];
if (!template.exists) revert TemplateNotFound();
template.enabled = enabled;
emit TemplateAvailabilityUpdated(templateKey, version, enabled);
}
function getTemplate(
bytes32 templateKey,
uint32 version
) external view returns (StandardTokenTemplate memory template) {
template = _templates[templateKey][version];
if (!template.exists) revert TemplateNotFound();
}
}
Chain explorer4871msChain node72ms