Address Contract Verified
Address
0x099f52b74DFe2435a93b74872DD695EAE80E57E2
Balance
0.000300000 ETH
Nonce
1
Code Size
547 bytes
Creator
Create2 Deployer at tx 0xec1c58b4...7bb183
Indexed Transactions
0
Contract Bytecode
547 bytes
0x60806040526004361015610015575b3661014557005b5f3560e01c80638da5cb5b146101005763907be21a0361000e57346100fc5760203660031901126100fc576004356001600160a01b038116908190036100fc57335f9081527f246d4897788137da0dfee54983711d7cec9a265cfb0821648ff88be774e373ce602052604090205460ff16156100e5576bffffffffffffffffffffffff60a01b7f5de96d96f7bd5b0df20e0957dfe48c1f2abf0fa75147ae539b8d798edd281caf5416177f5de96d96f7bd5b0df20e0957dfe48c1f2abf0fa75147ae539b8d798edd281caf555f80f35b63e2517d3f60e01b5f52336004525f60245260445ffd5b5f80fd5b346100fc575f3660031901126100fc577f5de96d96f7bd5b0df20e0957dfe48c1f2abf0fa75147ae539b8d798edd281caf546001600160a01b03166080908152602090f35b5f80356001600160e01b03191681527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c60205260409020546001600160a01b031680156101a9575f8091368280378136915af43d5f803e156101a5573d5ff35b3d5ffd5b606460405162461bcd60e51b815260206004820152602060248201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f742065786973746044820152fdfea2646970667358221220de83cdd4c5779591495e69db1ffb3d009d06834d030d5bba56293c14a54672ab64736f6c634300081c0033
Verified Source Code Full Match
Compiler: v0.8.28+commit.7893614a
EVM: prague
Optimization: Yes (200 runs)
AccessControlInternal.sol 104 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {AccessControlStorage} from "./AccessControlStorage.sol";
contract AccessControlInternal is IAccessControl {
bytes32 constant DEFAULT_ADMIN_ROLE = 0x00; // Default admin role
bytes32 constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); // Pauser role
bytes32 constant CCIP_OPERATOR_ROLE = keccak256("CCIP_OPERATOR_ROLE"); // CCIP operator role
bytes32 constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); // Proposer role
bytes32 constant MULTISIG_ROLE = keccak256("MULTISIG_ROLE"); // Multisig role
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `msg.sender`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view {
_checkRole(role, msg.sender);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function _hasRole(bytes32 role, address account) internal view returns (bool) {
return AccessControlStorage._getAccessControlStorage()._roles[role].hasRole[account];
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function _getRoleAdmin(bytes32 role) internal view returns (bytes32) {
return AccessControlStorage._getAccessControlStorage()._roles[role].adminRole;
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view {
if (!_hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal {
bytes32 previousAdminRole = _getRoleAdmin(role);
AccessControlStorage._getAccessControlStorage()._roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal returns (bool) {
if (!_hasRole(role, account)) {
AccessControlStorage._getAccessControlStorage()._roles[role].hasRole[account] = true;
emit RoleGranted(role, account, msg.sender);
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal returns (bool) {
if (_hasRole(role, account)) {
AccessControlStorage._getAccessControlStorage()._roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, msg.sender);
return true;
} else {
return false;
}
}
}
AccessControlStorage.sol 30 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
library AccessControlStorage {
bytes32 constant ACL_STORAGE_POSITION = keccak256("openzeppelin.accesscontrol.storage");
/// @title RoleData
/// @notice Data structure for role management
struct RoleData {
mapping(address account => bool) hasRole; // Mapping of accounts to roles
bytes32 adminRole; // Admin role for this role
}
/// @title AccessControlStorageStruct
/// @notice Storage structure for access control
struct AccessControlStorageStruct {
address deployerAdmin;
mapping(bytes32 role => RoleData) _roles; // Mapping of roles to role data
}
/// @notice Retrieves the AccessControl storage instance
/// @return $ The AccessControl storage instance
function _getAccessControlStorage() internal pure returns (AccessControlStorageStruct storage $) {
bytes32 position = ACL_STORAGE_POSITION;
assembly {
$.slot := position
}
}
}
IAccessControl.sol 44 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title IAccessControl
/// @notice Interface defining role-based access control methods
/// @dev Specifies core methods for managing roles and access permissions
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @notice Event emitted when a role is granted to an account
* @param role Bytes32 identifier of the role
* @param account Address receiving the role
* @param sender Address that granted the role
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @notice Event emitted when a role is revoked from an account
* @param role Bytes32 identifier of the role
* @param account Address losing the role
* @param sender Address that revoked the role
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @notice Event emitted when a role's admin is changed
* @param role Bytes32 identifier of the role
* @param previousAdminRole Previous admin role
* @param newAdminRole New admin role
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
}
BridgeStorage.sol 35 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {BridgeLibrary} from "../../../Libraries/BridgeLibrary.sol";
/// @title BridgeStorage
/// @notice Storage structure for bridge operations
library BridgeStorage {
bytes32 constant BRIDGE_STORAGE_POSITION = keccak256("diamond.bridge.storage");
struct BridgeStorageStruct {
address bridgeFlatFeeReceiver; // Address to receive protocol fees
address bridgePercentageFeeReceiver;
bool erc20Paused; // Indicates if ERC20 bridging is paused
uint256 bridgeFlatFee; // Flat Fee for bridging operations
uint256 bridgeTotalFlatFeeCollected;
uint256 bridgeFlatFeeThreshold;
uint256 bridgePercentageFee; // Percentage Fee for bridging operations (basis points)
mapping(address => uint256) bridgeTotalPercentageFeeCollected;
mapping(address => uint256) deployerNonce; // Nonce for deployers
mapping(address => mapping(uint64 => bool)) isDeployedOnDestinationChain; // Mapping of deployed tokens on destination chains
mapping(address => BridgeLibrary.IncomingTokenDetails) incomingTokenDetails; // Mapping of incoming token details
mapping(address => address) outgoingDeployedTokenAddress;
mapping(address => bool) isExemptFromFees;
}
/// @notice Retrieves the Bridge storage instance
/// @return $ The Bridge storage instance
function _getBridgeStorage() internal pure returns (BridgeStorageStruct storage $) {
bytes32 position = BRIDGE_STORAGE_POSITION;
assembly {
$.slot := position
}
}
}
Diamond.sol 95 lines
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 * * Implementation of a diamond. /******************************************************************************/ // Storage Imports import {BridgeStorage} from "../Bases/Bridge/ERC20/BridgeStorage.sol"; import {LibDiamond} from "./LibDiamond.sol"; import {IDiamondCut} from "./IDiamondCut.sol"; import {AccessControlStorage, AccessControlInternal} from "../Bases/AccessControl/AccessControlInternal.sol"; /// @title Diamond /// @notice Implements the diamond standard for contract composition contract Diamond is AccessControlInternal { struct Initialization { address initContract; ///< Address of the contract to initialize bytes initData; ///< Initialization data } /// @notice Initializes the diamond /// @param _contractOwner The owner of the contract /// @param _diamondCut The list of facets to add /// @param _initializations The list of initialization pairs to execute constructor( address _contractOwner, IDiamondCut.FacetCut[] memory _diamondCut, Initialization[] memory _initializations ) payable { if (_contractOwner != address(0)) { _grantRole(DEFAULT_ADMIN_ROLE, _contractOwner); _grantRole(PROPOSER_ROLE, _contractOwner); _grantRole(CCIP_OPERATOR_ROLE, _contractOwner); _grantRole(PAUSER_ROLE, _contractOwner); _grantRole(MULTISIG_ROLE, _contractOwner); } AccessControlStorage._getAccessControlStorage().deployerAdmin = _contractOwner; LibDiamond.diamondCut(_diamondCut, address(0), ""); for (uint256 i = 0; i < _initializations.length; i++) { LibDiamond.initializeDiamondCut(_initializations[i].initContract, _initializations[i].initData); } } /// @notice Returns the owner of the diamond /// @return The owner of the diamond function owner() external view returns (address) { return AccessControlStorage._getAccessControlStorage().deployerAdmin; } function transferDeployerAdmin(address newDeployerAdmin) external onlyRole(DEFAULT_ADMIN_ROLE) { AccessControlStorage._getAccessControlStorage().deployerAdmin = newDeployerAdmin; } // Find facet for function that is called and execute the // function if a facet is found and return any value. fallback() external payable { LibDiamond.DiamondStorage storage ds; bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; // get diamond storage assembly { ds.slot := position } // get facet from function selector address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress; require(facet != address(0), "Diamond: Function does not exist"); // Execute external function from facet using delegatecall and return any value. assembly { // copy function selector and any arguments calldatacopy(0, 0, calldatasize()) // execute function call using the facet let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) // get any return value returndatacopy(0, 0, returndatasize()) // return any return value or error back to the caller switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /// @notice Receives ETH receive() external payable {} }
IDiamondCut.sol 32 lines
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ /// @title IDiamondCut /// @notice Interface defining the diamond cut operations. interface IDiamondCut { enum FacetCutAction { Add, // Add a facet Replace, // Replace a facet Remove // Remove a facet } // Add=0, Replace=1, Remove=2 struct FacetCut { address facetAddress; // Address of the facet FacetCutAction action; // Action to perform bytes4[] functionSelectors; // Function selectors to add, replace, or remove } /// @notice Add/replace/remove any number of functions and optionally execute /// a function with delegatecall /// @param _diamondCut Contains the facet addresses and function selectors /// @param _init The address of the contract or facet to execute _calldata /// @param _calldata A function call, including function selector and arguments /// _calldata is executed with delegatecall on _init function diamondCut(FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata) external; }
LibDiamond.sol 228 lines
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ import {IDiamondCut} from "./IDiamondCut.sol"; /// @title LibDiamond /// @notice Library for managing diamond storage and facets. library LibDiamond { bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage"); /// @title FacetAddressAndPosition /// @notice Struct for storing the address of a facet and its position in the facetFunctionSelectors array struct FacetAddressAndPosition { address facetAddress; uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array } /// @title FacetFunctionSelectors /// @notice Struct for storing the function selectors for a facet struct FacetFunctionSelectors { bytes4[] functionSelectors; uint256 facetAddressPosition; // position of facetAddress in facetAddresses array } /// @title DiamondStorage /// @notice Struct for storing the diamond storage struct DiamondStorage { // maps function selector to the facet address and // the position of the selector in the facetFunctionSelectors.selectors array mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition; // maps facet addresses to function selectors mapping(address => FacetFunctionSelectors) facetFunctionSelectors; // facet addresses address[] facetAddresses; // Used to query if a contract implements an interface. // Used to implement ERC-165. mapping(bytes4 => bool) supportedInterfaces; } /// @notice Gets the diamond storage /// @return ds The diamond storage function diamondStorage() internal pure returns (DiamondStorage storage ds) { bytes32 position = DIAMOND_STORAGE_POSITION; assembly { ds.slot := position } } /// @notice Event emitted when the diamond cut event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata); /// @notice Internal function version of diamondCut /// @param _diamondCut The diamond cut /// @param _init The init address /// @param _calldata The calldata function diamondCut(IDiamondCut.FacetCut[] memory _diamondCut, address _init, bytes memory _calldata) internal { for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) { IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action; if (action == IDiamondCut.FacetCutAction.Add) { addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else if (action == IDiamondCut.FacetCutAction.Replace) { replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else if (action == IDiamondCut.FacetCutAction.Remove) { removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else { revert("LibDiamondCut: Incorrect FacetCutAction"); } } emit DiamondCut(_diamondCut, _init, _calldata); initializeDiamondCut(_init, _calldata); } /// @notice Adds functions to the diamond /// @param _facetAddress The address of the facet /// @param _functionSelectors The function selectors function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)"); uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length); // add new facet address if it does not exist if (selectorPosition == 0) { addFacet(ds, _facetAddress); } for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists"); addFunction(ds, selector, selectorPosition, _facetAddress); selectorPosition++; } } /// @notice Replaces functions in the diamond /// @param _facetAddress The address of the facet /// @param _functionSelectors The function selectors function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)"); uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length); // add new facet address if it does not exist if (selectorPosition == 0) { addFacet(ds, _facetAddress); } for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function"); removeFunction(ds, oldFacetAddress, selector); addFunction(ds, selector, selectorPosition, _facetAddress); selectorPosition++; } } /// @notice Removes functions from the diamond /// @param _facetAddress The address of the facet /// @param _functionSelectors The function selectors function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); // if function does not exist then do nothing and return require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)"); for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; removeFunction(ds, oldFacetAddress, selector); } } /// @notice Adds a facet to the diamond /// @param _facetAddress The address of the facet function addFacet(DiamondStorage storage ds, address _facetAddress) internal { enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code"); ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds.facetAddresses.length; ds.facetAddresses.push(_facetAddress); } /// @notice Adds a function to the diamond /// @param _selector The selector /// @param _selectorPosition The selector position /// @param _facetAddress The address of the facet function addFunction( DiamondStorage storage ds, bytes4 _selector, uint96 _selectorPosition, address _facetAddress ) internal { ds.selectorToFacetAndPosition[_selector].functionSelectorPosition = _selectorPosition; ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(_selector); ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress; } /// @notice Removes a function from the diamond /// @param _facetAddress The address of the facet /// @param _selector The selector function removeFunction(DiamondStorage storage ds, address _facetAddress, bytes4 _selector) internal { require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist"); // an immutable function is a function defined directly in a diamond require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function"); // replace selector with last selector, then delete last selector uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition; uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1; // if not the same then replace _selector with lastSelector if (selectorPosition != lastSelectorPosition) { bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition]; ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector; ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint96(selectorPosition); } // delete the last selector ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop(); delete ds.selectorToFacetAndPosition[_selector]; // if no more selectors for facet address then delete the facet address if (lastSelectorPosition == 0) { // replace facet address with last facet address and delete last facet address uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1; uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition; if (facetAddressPosition != lastFacetAddressPosition) { address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition]; ds.facetAddresses[facetAddressPosition] = lastFacetAddress; ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = facetAddressPosition; } ds.facetAddresses.pop(); delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition; } } /// @notice Initializes the diamond cut /// @param _init The init address /// @param _calldata The calldata function initializeDiamondCut(address _init, bytes memory _calldata) internal { if (_init == address(0)) { require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty"); } else { require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)"); if (_init != address(this)) { enforceHasContractCode(_init, "LibDiamondCut: _init address has no code"); } (bool success, bytes memory error) = _init.delegatecall(_calldata); if (!success) { if (error.length > 0) { // bubble up the error revert(string(error)); } else { revert("LibDiamondCut: _init function reverted"); } } } } /// @notice Enforces that a contract has code /// @param _contract The contract /// @param _errorMessage The error message function enforceHasContractCode(address _contract, string memory _errorMessage) internal view { uint256 contractSize; assembly { contractSize := extcodesize(_contract) } require(contractSize > 0, _errorMessage); } }
BridgeLibrary.sol 39 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {TokenMetadataLibrary} from "./TokenMetadataLibrary.sol";
/// @title BridgeLibrary
/// @notice Library for bridge-related operations.
library BridgeLibrary {
error TokenDeploymentFailed();
/// @notice Struct for incoming token details
struct IncomingTokenDetails {
address originToken; ///< Original token address
address deployedToken; ///< Locally deployed token address
TokenMetadataLibrary.TokenMetadata tokenMetadata; ///< Metadata of the transferred token
uint64 originChainSelector; ///< Identifier of the source blockchain
bool hasBurnMintAuthority; ///< Indicates if the token has burn/mint authority
}
/// @notice Struct for bridging token details
struct BridgingTokenDetails {
address owner; ///< Owner of the token
address originToken; ///< Original token address
address deployedToken; ///< Deployed token address
TokenMetadataLibrary.TokenMetadata tokenMetadata; ///< Token metadata
uint256 tokenAmount; ///< Amount of tokens being transferred
uint64 originChainSelector; ///< Identifier of the origin blockchain
uint64 sourceChainSelector; ///< Identifier of the source blockchain
bool hasBurnMintAuthority; ///< Indicates if the token has burn/mint authority
bool isExemptFromFees; ///< Indicates if the token is exempt from fees
}
/// @notice Struct for standard token details
struct StandardTokenStruct {
address owner; ///< Initial token owner
address ccip_admin; ///< CCIP admin address
TokenMetadataLibrary.TokenMetadata tokenMetadata; ///< Token metadata
}
}
TokenMetadataLibrary.sol 14 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @title TokenMetadataLibrary
/// @notice Library for managing token metadata.
library TokenMetadataLibrary {
/// @notice Struct for token metadata
struct TokenMetadata {
string name; ///< Token name
string symbol; ///< Token symbol
uint8 decimals; ///< Number of decimal places
uint256 maxSupply; ///< Maximum possible token supply
}
}
Read Contract
owner 0x8da5cb5b → address
Write Contract 1 functions
These functions modify contract state and require a wallet transaction to execute.
transferDeployerAdmin 0x907be21a
address newDeployerAdmin
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address