CrossChainToken
0xc6911796042b15d7fa4f6cde69e245ddcd3d9c31
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
9,593 bytes
ABI entries
67
22 read · 17 write
License
none
Contract information
- Address
- 0xc6911796042b15d7fa4f6cde69e245ddcd3d9c31
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0xe4a0015B4c…0Bc539D88F
- Creation tx
- 0xc43a8dba6d…bc124ad40a
Token
- Name
- Virtuals Protocol
- Symbol
- VIRTUAL
- Decimals
- 18
- Holders
- 10,009
- Market
- View token page →
Read contract (22)
BURNER_ROLE() → bytes32
BURN_MINT_ADMIN_ROLE() → bytes32
DEFAULT_ADMIN_ROLE() → bytes32
MINTER_ROLE() → bytes32
allowance(address, address) → uint256
balanceOf(address) → uint256
decimals() → uint8
defaultAdmin() → address
defaultAdminDelay() → uint48
defaultAdminDelayIncreaseWait() → uint48
getCCIPAdmin() → address
getRoleAdmin(bytes32) → bytes32
hasRole(bytes32, address) → bool
maxSupply() → uint256
name() → string
owner() → address
pendingDefaultAdmin() → address, uint48
pendingDefaultAdminDelay() → uint48, uint48
supportsInterface(bytes4) → bool
symbol() → string
totalSupply() → uint256
typeAndVersion() → string
Events (10)
ApprovalCCIPAdminTransferredDefaultAdminDelayChangeCanceledDefaultAdminDelayChangeScheduledDefaultAdminTransferCanceledDefaultAdminTransferScheduledRoleAdminChangedRoleGrantedRoleRevokedTransfer
ABI
[
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "uint256",
"name": "maxSupply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "preMint",
"type": "uint256"
},
{
"internalType": "address",
"name": "preMintRecipient",
"type": "address"
},
{
"internalType": "uint8",
"name": "decimals",
"type": "uint8"
},
{
"internalType": "address",
"name": "ccipAdmin",
"type": "address"
}
],
"internalType": "struct BaseERC20.ConstructorParams",
"name": "args",
"type": "tuple"
},
{
"internalType": "address",
"name": "burnMintRoleAdmin",
"type": "address"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AccessControlBadConfirmation",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint48",
"name": "schedule",
"type": "uint48"
}
],
"name": "AccessControlEnforcedDefaultAdminDelay",
"type": "error"
},
{
"inputs": [],
"name": "AccessControlEnforcedDefaultAdminRules",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "defaultAdmin",
"type": "address"
}
],
"name": "AccessControlInvalidDefaultAdmin",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "bytes32",
"name": "neededRole",
"type": "bytes32"
}
],
"name": "AccessControlUnauthorizedAccount",
"type": "error"
},
{
"inputs": [],
"name": "CannotRenounceCCIPAdmin",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "allowance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "needed",
"type": "uint256"
}
],
"name": "ERC20InsufficientAllowance",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "needed",
"type": "uint256"
}
],
"name": "ERC20InsufficientBalance",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "approver",
"type": "address"
}
],
"name": "ERC20InvalidApprover",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
}
],
"name": "ERC20InvalidReceiver",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "ERC20InvalidSender",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
}
],
"name": "ERC20InvalidSpender",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "supplyAfterMint",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxSupply",
"type": "uint256"
}
],
"name": "MaxSupplyExceeded",
"type": "error"
},
{
"inputs": [],
"name": "OnlyCCIPAdmin",
"type": "error"
},
{
"inputs": [],
"name": "PreMintAddressNotSet",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "preMintRecipient",
"type": "address"
}
],
"name": "PreMintRecipientSetWithZeroPreMint",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "bits",
"type": "uint8"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "SafeCastOverflowedUintDowncast",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousAdmin",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newAdmin",
"type": "address"
}
],
"name": "CCIPAdminTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [],
"name": "DefaultAdminDelayChangeCanceled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint48",
"name": "newDelay",
"type": "uint48"
},
{
"indexed": false,
"internalType": "uint48",
"name": "effectSchedule",
"type": "uint48"
}
],
"name": "DefaultAdminDelayChangeScheduled",
"type": "event"
},
{
"anonymous": false,
"inputs": [],
"name": "DefaultAdminTransferCanceled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "newAdmin",
"type": "address"
},
{
"indexed": false,
"internalType": "uint48",
"name": "acceptSchedule",
"type": "uint48"
}
],
"name": "DefaultAdminTransferScheduled",
"type": "event"
},
{
"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": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [],
"name": "BURNER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "BURN_MINT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "DEFAULT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MINTER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "acceptDefaultAdminTransfer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newAdmin",
"type": "address"
}
],
"name": "beginDefaultAdminTransfer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "burnFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "cancelDefaultAdminTransfer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint48",
"name": "newDelay",
"type": "uint48"
}
],
"name": "changeDefaultAdminDelay",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "_decimals",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "defaultAdmin",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "defaultAdminDelay",
"outputs": [
{
"internalType": "uint48",
"name": "",
"type": "uint48"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "defaultAdminDelayIncreaseWait",
"outputs": [
{
"internalType": "uint48",
"name": "",
"type": "uint48"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getCCIPAdmin",
"outputs": [
{
"internalType": "address",
"name": "ccipAdmin",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "burnAndMinter",
"type": "address"
}
],
"name": "grantMintAndBurnRoles",
"outputs": [],
"stateMutability": "nonpayable",
"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": [],
"name": "maxSupply",
"outputs": [
{
"internalType": "uint256",
"name": "_maxSupply",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"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": [],
"name": "pendingDefaultAdmin",
"outputs": [
{
"internalType": "address",
"name": "newAdmin",
"type": "address"
},
{
"internalType": "uint48",
"name": "schedule",
"type": "uint48"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pendingDefaultAdminDelay",
"outputs": [
{
"internalType": "uint48",
"name": "newDelay",
"type": "uint48"
},
{
"internalType": "uint48",
"name": "schedule",
"type": "uint48"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"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": [],
"name": "rollbackDefaultAdminDelay",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newAdmin",
"type": "address"
}
],
"name": "setCCIPAdmin",
"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": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "typeAndVersion",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "pure",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {BaseERC20} from "./BaseERC20.sol";
import {IBurnMintERC20} from "../interfaces/IBurnMintERC20.sol";
import {
AccessControlDefaultAdminRules
} from "@openzeppelin/contracts@5.3.0/access/extensions/AccessControlDefaultAdminRules.sol";
import {IERC165} from "@openzeppelin/contracts@5.3.0/utils/introspection/IERC165.sol";
/// @notice A basic ERC20 compatible token contract with burn and minting roles.
/// @dev The total supply can be limited during deployment.
/// @dev This contract inherits its access control from AccessControlDefaultAdminRules, meaning it relies on OZ
/// AccessControl with 2-step ownership transfers. There's also a separate `ccipAdmin` role which can be used to
/// register with the CCIP token admin registry but has no other special powers, and can only be transferred by the
/// DEFAULT_ADMIN_ROLE. The DEFAULT_ADMIN_ROLE holder can also be used to register the token in the token admin registry.
contract CrossChainToken is BaseERC20, AccessControlDefaultAdminRules, IBurnMintERC20 {
function typeAndVersion() external pure virtual override returns (string memory) {
return "CrossChainToken 2.0.0";
}
/// @notice The holder of this role can mint tokens.
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
/// @notice The holder of this role can burn tokens.
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
/// @notice The holder of this role can grant/revoke both the MINTER_ROLE and the BURNER_ROLE.
bytes32 public constant BURN_MINT_ADMIN_ROLE = keccak256("BURN_MINT_ADMIN_ROLE");
/// @param args The parameters for the ERC20 token, including name, symbol, decimals, max supply, and pre-mint amount.
/// @param burnMintRoleAdmin The address to grant the BURN_MINT_ADMIN_ROLE. If set to address(0), no address will be
/// granted the role.
/// @param owner The address to set as the owner of the contract, which has the default admin role. If set to
/// address(0), the deployer will be set as the owner.
constructor(
ConstructorParams memory args,
address burnMintRoleAdmin,
address owner
) BaseERC20(args) AccessControlDefaultAdminRules(0, owner == address(0) ? msg.sender : owner) {
if (burnMintRoleAdmin != address(0)) {
_grantRole(BURN_MINT_ADMIN_ROLE, burnMintRoleAdmin);
}
_setRoleAdmin(MINTER_ROLE, BURN_MINT_ADMIN_ROLE);
_setRoleAdmin(BURNER_ROLE, BURN_MINT_ADMIN_ROLE);
}
/// @inheritdoc IERC165
function supportsInterface(
bytes4 interfaceId
) public view virtual override(AccessControlDefaultAdminRules, BaseERC20) returns (bool) {
return AccessControlDefaultAdminRules.supportsInterface(interfaceId) || BaseERC20.supportsInterface(interfaceId)
|| interfaceId == type(IBurnMintERC20).interfaceId;
}
// ================================================================
// │ Burning & minting │
// ================================================================
/// @inheritdoc IBurnMintERC20
/// @dev Uses OZ ERC20 _burn to disallow burning from address(0).
function burn(
uint256 amount
) public virtual override onlyRole(BURNER_ROLE) {
_burn(_msgSender(), amount);
}
/// @inheritdoc IBurnMintERC20
/// @dev Alias for BurnFrom for compatibility with the older naming convention.
/// @dev Uses burnFrom for all validation & logic.
function burn(
address account,
uint256 amount
) public virtual override {
burnFrom(account, amount);
}
/// @inheritdoc IBurnMintERC20
/// @dev Uses OZ ERC20 _burn to disallow burning from address(0).
function burnFrom(
address account,
uint256 amount
) public virtual override onlyRole(BURNER_ROLE) {
_spendAllowance(account, _msgSender(), amount);
_burn(account, amount);
}
/// @inheritdoc IBurnMintERC20
/// @dev Uses OZ ERC20 _mint to disallow minting to address(0), and BaseERC20 to disallow minting to address(this).
/// @dev Uses BaseERC20's max supply logic.
function mint(
address account,
uint256 amount
) public virtual override onlyRole(MINTER_ROLE) {
_mint(account, amount);
}
// ================================================================
// │ Roles │
// ================================================================
/// @notice grants both mint and burn roles to `burnAndMinter`.
/// @param burnAndMinter The address to be granted both the MINTER_ROLE and BURNER_ROLE.
/// @dev calls public functions so this function does not require
/// access controls. This is handled in the inner functions.
function grantMintAndBurnRoles(
address burnAndMinter
) public virtual {
grantRole(MINTER_ROLE, burnAndMinter);
grantRole(BURNER_ROLE, burnAndMinter);
}
/// @notice Sets the CCIP admin role to `newAdmin`.
/// @dev Overrides the default CCIP admin role setter to require the caller to have the DEFAULT_ADMIN_ROLE.
/// @param newAdmin The address of the new CCIP admin.
function setCCIPAdmin(
address newAdmin
) external virtual override onlyRole(DEFAULT_ADMIN_ROLE) {
_setCCIPAdmin(newAdmin);
}
}
Chain explorer3739msChain node87ms