Avalanche Fuji Testnet

Contract

0xB9826Bbf0deB10cC3924449B93F418db6b16be36
Source Code Source Code

Overview

AVAX Balance

Avalanche C-Chain LogoAvalanche C-Chain LogoAvalanche C-Chain Logo0 AVAX

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Amount
Register L1441605712025-07-31 15:42:24170 days ago1753976544IN
0xB9826Bbf...b6b16be36
0.01 AVAX00
Set L1Middleware438982922025-07-25 15:54:18176 days ago1753458858IN
0xB9826Bbf...b6b16be36
0 AVAX00.00000082
Register L1409080852025-05-25 8:04:36238 days ago1748160276IN
0xB9826Bbf...b6b16be36
0.01 AVAX00
Set L1Middleware408982572025-05-24 23:56:24238 days ago1748130984IN
0xB9826Bbf...b6b16be36
0 AVAX00
Register L1408969972025-05-24 22:35:37238 days ago1748126137IN
0xB9826Bbf...b6b16be36
0.01 AVAX00
Set L1Middleware406293412025-05-16 13:07:12247 days ago1747400832IN
0xB9826Bbf...b6b16be36
0 AVAX00
Register L1403721542025-05-09 16:46:21253 days ago1746809181IN
0xB9826Bbf...b6b16be36
0.01 AVAX00

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To Amount
441605712025-07-31 15:42:24170 days ago1753976544
0xB9826Bbf...b6b16be36
0.01 AVAX
441605712025-07-31 15:42:24170 days ago1753976544
0xB9826Bbf...b6b16be36
0 AVAX
441180302025-07-30 16:15:38171 days ago1753892138
0xB9826Bbf...b6b16be36
0 AVAX
441168892025-07-30 15:40:26171 days ago1753890026
0xB9826Bbf...b6b16be36
0 AVAX
438983342025-07-25 15:55:42176 days ago1753458942
0xB9826Bbf...b6b16be36
0 AVAX
438983342025-07-25 15:55:42176 days ago1753458942
0xB9826Bbf...b6b16be36
0 AVAX
438983342025-07-25 15:55:42176 days ago1753458942
0xB9826Bbf...b6b16be36
0 AVAX
438982922025-07-25 15:54:18176 days ago1753458858
0xB9826Bbf...b6b16be36
0 AVAX
413227812025-06-04 16:00:25227 days ago1749052825
0xB9826Bbf...b6b16be36
0 AVAX
413227812025-06-04 16:00:25227 days ago1749052825
0xB9826Bbf...b6b16be36
0 AVAX
413227812025-06-04 16:00:25227 days ago1749052825
0xB9826Bbf...b6b16be36
0 AVAX
413227622025-06-04 15:59:46227 days ago1749052786
0xB9826Bbf...b6b16be36
0 AVAX
413227622025-06-04 15:59:46227 days ago1749052786
0xB9826Bbf...b6b16be36
0 AVAX
413227622025-06-04 15:59:46227 days ago1749052786
0xB9826Bbf...b6b16be36
0 AVAX
413226562025-06-04 15:56:12227 days ago1749052572
0xB9826Bbf...b6b16be36
0 AVAX
413226562025-06-04 15:56:12227 days ago1749052572
0xB9826Bbf...b6b16be36
0 AVAX
413226562025-06-04 15:56:12227 days ago1749052572
0xB9826Bbf...b6b16be36
0 AVAX
409985192025-05-27 22:35:20235 days ago1748385320
0xB9826Bbf...b6b16be36
0 AVAX
409985192025-05-27 22:35:20235 days ago1748385320
0xB9826Bbf...b6b16be36
0 AVAX
409985192025-05-27 22:35:20235 days ago1748385320
0xB9826Bbf...b6b16be36
0 AVAX
409979972025-05-27 22:08:27235 days ago1748383707
0xB9826Bbf...b6b16be36
0 AVAX
409979972025-05-27 22:08:27235 days ago1748383707
0xB9826Bbf...b6b16be36
0 AVAX
409979972025-05-27 22:08:27235 days ago1748383707
0xB9826Bbf...b6b16be36
0 AVAX
409977342025-05-27 21:53:53235 days ago1748382833
0xB9826Bbf...b6b16be36
0 AVAX
409977342025-05-27 21:53:53235 days ago1748382833
0xB9826Bbf...b6b16be36
0 AVAX
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
L1Registry

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: BUSL-1.1
// SPDX-FileCopyrightText: Copyright 2024 ADDPHO

pragma solidity 0.8.25;

import {IL1Registry} from "../interfaces/IL1Registry.sol";
import {IAvalancheL1Middleware} from "../interfaces/middleware/IAvalancheL1Middleware.sol";

import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

contract L1Registry is IL1Registry, Ownable {
    using EnumerableSet for EnumerableSet.AddressSet;

    EnumerableSet.AddressSet private l1s;

    /// @notice The l1Middleware for each L1
    mapping(address => address) public l1Middleware;

    /// @notice The metadata URL for each L1
    mapping(address => string) public l1MetadataURL;

    /// @notice The fee collector address (can be changed later).
    address payable public feeCollector;

    /// @notice The adjustable fee (in wei) for registerL1.
    uint256 public registerFee;

    /// @notice MAX_FEE is the maximum fee that can be set by the owner.
    uint256 immutable MAX_FEE;

    /// @notice Tracks the total unclaimed fees in the contract
    uint256 public unclaimedFees;

    modifier onlyValidatorManagerOwner(
        address l1
    ) {
        // Ensure caller owns the validator manager
        address vmOwner = Ownable(l1).owner();
        if (vmOwner != msg.sender) {
            revert L1Registry__NotValidatorManagerOwner(msg.sender, vmOwner);
        }
        _;
    }

    modifier isRegisteredL1(
        address l1
    ) {
        if (!isRegistered(l1)) {
            revert L1Registry__L1NotRegistered();
        }
        _;
    }

    modifier notZeroAddress(
        address l1
    ) {
        if (l1 == address(0)) {
            revert L1Registry__InvalidValidatorManager(l1);
        }
        _;
    }

    constructor(address payable feeCollector_, uint256 registerFee_, uint256 MAX_FEE_, address owner) Ownable(owner) {
        if (feeCollector_ == address(0)) {
            revert L1Registry__ZeroAddress("feeCollector");
        }
        feeCollector = feeCollector_;
        registerFee = registerFee_;
        MAX_FEE = MAX_FEE_;
    }

    /// @inheritdoc IL1Registry
    function registerL1(
        address l1,
        address l1Middleware_,
        string calldata metadataURL
    ) external payable notZeroAddress(l1) onlyValidatorManagerOwner(l1) {
        // Only require fee if it's set to non-zero
        if (registerFee > 0) {
            if (msg.value < registerFee) {
                revert L1Registry__InsufficientFee();
            }

            // Transfer fee to collector (feeCollector is guaranteed to be non-zero)
            (bool success,) = feeCollector.call{value: msg.value}("");
            if (!success) {
                unclaimedFees += msg.value;
            }
        }

        bool registered = l1s.add(l1);
        if (!registered) {
            revert L1Registry__L1AlreadyRegistered();
        }
        l1Middleware[l1] = l1Middleware_;
        l1MetadataURL[l1] = metadataURL;

        emit RegisterL1(l1);
        emit SetL1Middleware(l1, l1Middleware_);
        emit SetMetadataURL(l1, metadataURL);
    }

    /// @inheritdoc IL1Registry
    function setL1Middleware(
        address l1,
        address l1Middleware_
    ) external notZeroAddress(l1Middleware_) isRegisteredL1(l1) onlyValidatorManagerOwner(l1) {
        l1Middleware[l1] = l1Middleware_;

        emit SetL1Middleware(l1, l1Middleware_);
    }

    /// @inheritdoc IL1Registry
    function setMetadataURL(
        address l1,
        string calldata metadataURL
    ) external isRegisteredL1(l1) onlyValidatorManagerOwner(l1) {
        // TODO: check that msg.sender is a SecurityModule of the ValidatorManager

        l1MetadataURL[l1] = metadataURL;

        emit SetMetadataURL(l1, metadataURL);
    }

    /// @inheritdoc IL1Registry
    function isRegistered(
        address l1
    ) public view returns (bool) {
        return l1s.contains(l1);
    }

    // @inheritdoc IL1Registry
    function isRegisteredWithMiddleware(address l1, address vaultManager_) external view returns (bool) {
        if (!isRegistered(l1)) {
            return false;
        }

        address middleware = l1Middleware[l1];
        if (middleware == address(0)) {
            return false;
        }

        address actualVaultManager = IAvalancheL1Middleware(middleware).getVaultManager();

        if (actualVaultManager != vaultManager_) {
            revert L1Registry__InvalidL1Middleware();
        }

        return true;
    }

    /// @inheritdoc IL1Registry
    function getL1At(
        uint256 index
    ) public view returns (address, address, string memory) {
        address l1 = l1s.at(index);
        return (l1, l1Middleware[l1], l1MetadataURL[l1]);
    }

    /// @inheritdoc IL1Registry
    function totalL1s() public view returns (uint256) {
        return l1s.length();
    }

    /// @inheritdoc IL1Registry
    function getAllL1s() public view returns (address[] memory, address[] memory, string[] memory) {
        address[] memory l1sList = l1s.values();
        address[] memory l1Middlewares = new address[](l1sList.length);
        string[] memory metadataURLs = new string[](l1sList.length);
        for (uint256 i = 0; i < l1sList.length; i++) {
            l1Middlewares[i] = l1Middleware[l1sList[i]];
            metadataURLs[i] = l1MetadataURL[l1sList[i]];
        }
        return (l1sList, l1Middlewares, metadataURLs);
    }

    /// @notice Adjust fee collector. Only owner can change it.
    /// @param newFeeCollector The new fee collector address
    function setFeeCollector(
        address payable newFeeCollector
    ) external onlyOwner {
        if (newFeeCollector == address(0)) {
            revert L1Registry__ZeroAddress("feeCollector");
        }
        
        // Try to disburse any accumulated fees to the new collector
        uint256 feesToSend = unclaimedFees;
        if (feesToSend > 0) {
            // Reset unclaimed fees before transfer to prevent reentrancy issues
            unclaimedFees = 0;
            
            (bool success,) = newFeeCollector.call{value: feesToSend}("");
            if (!success) {
                // If transfer fails, restore the unclaimed fees amount
                // but continue execution so that feeCollector is still updated
                unclaimedFees = feesToSend;
            }
        }
        
        feeCollector = newFeeCollector;
    }

    /// @notice Adjust fee. Only owner can change it.
    function setRegisterFee(
        uint256 newFee
    ) external onlyOwner {
        if (newFee > MAX_FEE) {
            revert L1Registry__FeeExceedsMaximum(newFee, MAX_FEE);
        }
        registerFee = newFee;
    }

    /// @notice Allows the fee collector to withdraw accumulated fees
    function withdrawFees() external {
        if (msg.sender != feeCollector) {
            revert L1Registry__NotFeeCollector(msg.sender);
        }
        
        uint256 feesToSend = unclaimedFees;
        if (feesToSend == 0) {
            revert L1Registry__NoFeesToWithdraw();
        }
        
        // Reset unclaimed fees before transfer to prevent reentrancy issues
        unclaimedFees = 0;
        
        (bool success,) = feeCollector.call{value: feesToSend}("");
        if (!success) {
            // If transfer fails, restore the unclaimed fees amount
            unclaimedFees = feesToSend;
            revert L1Registry__FeeTransferFailed();
        }
    }

    receive() external payable {}
}

// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright 2024 ADDPHO

pragma solidity ^0.8.0;

interface IL1Registry {
    event RegisterL1(address indexed l1);
    event SetL1Middleware(address indexed l1, address indexed l1Middleware);
    event SetMetadataURL(address indexed l1, string metadataURL);

    error L1Registry__L1AlreadyRegistered();
    error L1Registry__L1NotRegistered();
    error L1Registry__InvalidValidatorManager(address l1);
    error L1Registry__InvalidL1Middleware();
    error L1Registry__NotValidatorManagerOwner(address caller, address expectedOwner);
    error L1Registry__InsufficientFee();
    error L1Registry__FeeTransferFailed();
    error L1Registry__FeeExceedsMaximum(uint256 newFee, uint256 maxFee);
    error L1Registry__ZeroAddress(string name);
    error L1Registry__NotFeeCollector(address caller);
    error L1Registry__NoFeesToWithdraw();

    /**
     * @notice Register an Avalanche L1
     * @dev l1 must be the manager of the Avalanche L1
     * @dev msg.sender must be a SecurityModule of the l1
     * @dev l1Middleware must be a SecurityModule of the Avalanche L1
     * @param l1 The Avalanche L1. Should be The ValidatorManager.
     * @param l1Middleware The l1Middleware of the Avalanche L1
     * @param metadataURL The metadata URL of the Avalanche L1
     */
    function registerL1(
        address l1,
        address l1Middleware,
        string calldata metadataURL
    )
        /*, uint32 messageIndex, SubnetConversionData subnetConversionData*/
        external
        payable;

    /**
     * @notice Check if an address is registered as an L1
     * @param l1 The Avalanche L1. Should be The ValidatorManager.
     * @return True if the address is registered as an L1, false otherwise
     */
    function isRegistered(
        address l1
    ) external view returns (bool);

    /**
     * @notice Check if an address is registered as an L1 and if the Middleware is correct
     * @param l1 The Avalanche L1. Should be The ValidatorManager.
     * @param l1middleware_ The l1Middleware to check
     * @return True if the address is registered as an L1 and the middleware is correct, false otherwise
     */
    function isRegisteredWithMiddleware(address l1, address l1middleware_) external view returns (bool);

    /**
     * @notice Get the L1 at a specific index
     * @param index The index of the L1 to get
     * @return The address of the L1 at the specified index
     * @return The l1Middleware of the L1 at the specified index
     * @return The metadata URL of the L1 at the specified index
     */
    function getL1At(
        uint256 index
    ) external view returns (address, address, string memory);

    /**
     * @notice Get the total number of L1s
     * @return Total number of L1s
     */
    function totalL1s() external view returns (uint256);

    /**
     * @notice Get all L1s
     * @return Array of all L1s
     * @return Array of all L1s' l1Middlewares
     * @return Array of all L1s' metadata URLs
     */
    function getAllL1s() external view returns (address[] memory, address[] memory, string[] memory);

    /**
     * @notice Set the l1Middleware of an L1
     * @param l1 The Avalanche L1. Should be The ValidatorManager.
     * @param l1Middleware_ The new l1Middleware
     */
    function setL1Middleware(address l1, address l1Middleware_) external;

    /**
     * @notice Set the metadata URL of an L1
     * @param l1 The Avalanche L1. Should be The ValidatorManager.
     * @param metadataURL The new metadata URL
     */
    function setMetadataURL(address l1, string calldata metadataURL) external;
}

// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright 2024 ADDPHO

pragma solidity 0.8.25;

import {
    IValidatorManager,
    Validator,
    ValidatorStatus,
    ValidatorRegistrationInput,
    PChainOwner
} from "@avalabs/teleporter/validator-manager/interfaces/IValidatorManager.sol";

/**
 * @title IAvalancheL1Middleware
 * @notice Manages operator registration, asset classes, stake accounting, and slashing for Avalanche L1
 */
interface IAvalancheL1Middleware {
    // Errors
    error AvalancheL1Middleware__ActiveSecondaryAssetCLass(uint256 assetClassId);
    error AvalancheL1Middleware__AssetClassNotActive(uint256 assetClassId);
    error AvalancheL1Middleware__AssetStillInUse(uint256 assetClassId);
    error AvalancheL1Middleware__AlreadyRebalanced(address operator, uint48 epoch);
    error AvalancheL1Middleware__WeightUpdateNotPending(bytes32 validationId);
    error AvalancheL1Middleware__CollateralNotInAssetClass(address collateral, uint96 assetClassId);
    error AvalancheL1Middleware__EpochError(uint48 epochStartTs);
    error AvalancheL1Middleware__MaxL1LimitZero();
    error AvalancheL1Middleware__NoSlasher();
    error AvalancheL1Middleware__NotEnoughFreeStakeSecondaryAssetClasses();
    error AvalancheL1Middleware__NodeNotActive();
    error AvalancheL1Middleware__NotEnoughFreeStake(uint256 newStake);
    error AvalancheL1Middleware__StakeTooHigh(uint256 newStake, uint256 maxStake);
    error AvalancheL1Middleware__StakeTooLow(uint256 newStake, uint256 minStake);
    error AvalancheL1Middleware__OperatorGracePeriodNotPassed(uint48 disabledTime, uint48 slashingWindow);
    error AvalancheL1Middleware__OperatorAlreadyRegistered(address operator);
    error AvalancheL1Middleware__OperatorNotOptedIn(address operator, address l1ValidatorManager);
    error AvalancheL1Middleware__OperatorNotRegistered(address operator);
    error AvalancheL1Middleware__SlashingWindowTooShort(uint48 slashingWindow, uint48 epochDuration);
    error AvalancheL1Middleware__TooBigSlashAmount();
    error AvalancheL1Middleware__NodeNotFound(bytes32 nodeId);
    error AvalancheL1Middleware__SecurityModuleCapacityNotEnough(uint256 securityModuleCapacity, uint256 minStake);
    error AvalancheL1Middleware__WeightUpdatePending(bytes32 validationID);
    error AvalancheL1Middleware__NodeStateNotUpdated(bytes32 validationID);
    error AvalancheL1Middleware__NotEpochUpdatePeriod(uint48 timeNow, uint48 epochUpdatePeriod);
    error AvalancheL1Middleware__NotImplemented();
    error AvalancheL1Middleware__NodePendingRemoval(bytes32 nodeId);
    error AvalancheL1Middleware__NodePendingUpdate(bytes32 nodeId);
    error AvalancheL1Middleware__ZeroAddress(string name);
    error AvalancheL1Middleware__InvalidScaleFactor();

    // Events
    /**
     * @notice Emitted when a node is added
     * @param operator The operator who added the node
     * @param nodeId The ID of the node
     * @param stake The stake assigned to the node
     * @param validationID The validation identifier from BalancerValidatorManager
     */
    event NodeAdded(address indexed operator, bytes32 indexed nodeId, uint256 stake, bytes32 indexed validationID);

    /**
     * @notice Emitted when a node is removed
     * @param operator The operator who removed the node
     * @param nodeId The ID of the node
     * @param validationID The validation identifier from BalancerValidatorManager
     */
    event NodeRemoved(address indexed operator, bytes32 indexed nodeId, bytes32 indexed validationID);

    /**
     * @notice Emitted when a single node's stake is updated
     * @param operator The operator who owns the node
     * @param nodeId The ID of the node
     * @param newStake The new stake of the node
     * @param validationID The validation identifier from BalancerValidatorManager
     */
    event NodeStakeUpdated(
        address indexed operator, bytes32 indexed nodeId, uint256 newStake, bytes32 indexed validationID
    );

    /**
     * @notice Emitted when the operator has leftover stake after rebalancing
     * @param operator The operator who has leftover stake
     * @param leftoverStake The amount of leftover stake
     */
    event OperatorHasLeftoverStake(address indexed operator, uint256 leftoverStake);

    /**
     * @notice Emitted when all node stakes are updated for an operator
     * @param operator The operator
     * @param newStake The total new stake for the operator
     */
    event AllNodeStakesUpdated(address indexed operator, uint256 newStake);

    /**
     * @notice Emitted when the Vault Manager is updated
     * @param oldVaultManager The old Vault Manager address
     * @param newVaultManager The new Vault Manager address
     */
    event VaultManagerUpdated(address indexed oldVaultManager, address indexed newVaultManager);

    /**
     * @dev Simple struct to return operator stake and key.
     */
    struct OperatorData {
        uint256 stake;
        bytes32 key;
    }
    // External functions
    /**
     * @notice Activates a secondary asset class
     * @param assetClassId The asset class ID to activate
     */

    function activateSecondaryAssetClass(
        uint256 assetClassId
    ) external;

    /**
     * @notice Deactivates a secondary asset class
     * @param assetClassId The asset class ID to deactivate
     */
    function deactivateSecondaryAssetClass(
        uint256 assetClassId
    ) external;

    /**
     * @notice Registers a new operator and enables it
     * @param operator The operator address
     */
    function registerOperator(
        address operator
    ) external;

    /**
     * @notice Disables an operator
     * @param operator The operator address
     */
    function disableOperator(
        address operator
    ) external;

    /**
     * @notice Enables an operator
     * @param operator The operator address
     */
    function enableOperator(
        address operator
    ) external;

    /**
     * @notice Removes an operator if grace period has passed
     * @param operator The operator address
     */
    function removeOperator(
        address operator
    ) external;

    /**
     * @notice Add a new node => create a new validator.
     * Check the new node stake also ensure security module capacity.
     * @param nodeId The node ID
     * @param blsKey The BLS key
     * @param registrationExpiry The Unix timestamp after which the reigistration is no longer valid on the P-Chain
     * @param remainingBalanceOwner The owner of a validator's remaining balance
     * @param disableOwner The owner of a validator's disable owner on the P-Chain
     * @param stakeAmount The initial stake of the node to be added(optional)
     */
    function addNode(
        bytes32 nodeId,
        bytes calldata blsKey,
        uint64 registrationExpiry,
        PChainOwner calldata remainingBalanceOwner,
        PChainOwner calldata disableOwner,
        uint256 stakeAmount
    ) external;

    /**
     * @notice Remove a node => remove a validator.
     * @param nodeId The node ID
     */
    function removeNode(
        bytes32 nodeId
    ) external;

    /**
     * @notice Rebalance node stakes once per epoch for an operator.
     * @param operator The operator address
     * @param limitStake The maximum stake adjustment (add or remove) allowed per node per call.
     */
    function forceUpdateNodes(address operator, uint256 limitStake) external;

    /**
     * @notice Update the stake of a validator.
     * @param nodeId The node ID.
     * @param stakeAmount The new stake.
     */
    function initializeValidatorStakeUpdate(bytes32 nodeId, uint256 stakeAmount) external;

    /**
     * @notice Finalize a pending validator registration
     * @param operator The operator address
     * @param nodeId The node ID
     * @param messageIndex The message index
     */
    function completeValidatorRegistration(address operator, bytes32 nodeId, uint32 messageIndex) external;

    /**
     * @notice Finalize a pending stake update
     * @param nodeId The node ID
     * @param messageIndex The message index
     */
    function completeStakeUpdate(bytes32 nodeId, uint32 messageIndex) external;

    /**
     * @notice Finalize a pending validator removal
     * @param messageIndex The message index
     */
    function completeValidatorRemoval(
        uint32 messageIndex
    ) external;

    /**
     * @notice Slashes an operator's stake
     * @param epoch The epoch of the slash
     * @param operator The operator being slashed
     * @param amount The slash amount
     * @param assetClassId The asset class ID
     */
    function slash(uint48 epoch, address operator, uint256 amount, uint96 assetClassId) external;

    /**
     * @notice Calculates and caches total stake for an epoch
     * @param epoch The epoch number
     * @param assetClassId The asset class ID
     * @return totalStake The total stake calculated and cached
     */
    function calcAndCacheStakes(uint48 epoch, uint96 assetClassId) external returns (uint256);

    /**
     * @notice Calculates and caches node stakes for all operators retroactively for all epochs
     */
    function calcAndCacheNodeStakeForAllOperators() external;

    /**
     * @notice Fetches the primary and secondary asset classes
     * @return primary The primary asset class
     * @return secondaries An array of secondary asset classes
     */
    function getActiveAssetClasses() external view returns (uint256 primary, uint256[] memory secondaries);

    /**
     * @notice Checks if the classId is active
     * @param assetClassId The asset class ID
     * @return bool True if active
     */
    function isActiveAssetClass(
        uint96 assetClassId
    ) external view returns (bool);

    /**
     * @notice Gets the start timestamp for a given epoch
     * @param epoch The epoch number
     * @return timestamp The start time of that epoch
     */
    function getEpochStartTs(
        uint48 epoch
    ) external view returns (uint48);

    /**
     * @notice Gets the epoch number at a given timestamp
     * @param timestamp The timestamp
     * @return epoch The epoch at that time
     */
    function getEpochAtTs(
        uint48 timestamp
    ) external view returns (uint48);

    /**
     * @notice Gets the current epoch based on the current block time
     * @return epoch The current epoch
     */
    function getCurrentEpoch() external view returns (uint48);

    /**
     * @notice Returns an operator's stake at a given epoch for a specific asset class
     * @param operator The operator address
     * @param epoch The epoch number
     * @param assetClassId The asset class ID
     * @return stake The operator's stake
     */
    function getOperatorStake(address operator, uint48 epoch, uint96 assetClassId) external view returns (uint256);

    /**
     * @notice Returns total stake across all operators in a specific epoch
     * @param epoch The epoch number
     * @param assetClassId The asset class ID
     * @return The total stake in that epoch
     */
    function getTotalStake(uint48 epoch, uint96 assetClassId) external view returns (uint256);

    /**
     * @notice Returns all operators
     */
    function getAllOperators() external view returns (address[] memory);

    /**
     * @notice Returns the cached stake for a given node in the specified epoch, based on its Validation ID.
     * @param epoch The target Not enough free stake to add nodeepoch.
     * @param validationId The node ID.
     * @return The node stake from the cache.
     */
    function getNodeStake(uint48 epoch, bytes32 validationId) external view returns (uint256);

    /**
     * @notice Returns the current epoch number
     * @param operator The operator address
     * @param epoch The epoch number
     * @return activeNodeIds The list of nodes
     */
    function getActiveNodesForEpoch(address operator, uint48 epoch) external view returns (bytes32[] memory);

    /**
     * @notice Returns the available stake for an operator
     * @param operator The operator address
     * @return The available stake
     */
    function getOperatorAvailableStake(
        address operator
    ) external view returns (uint256);

    /**
     * @notice Summation of node stakes from the nodeStakeCache.
     * @param operator The operator address.
     * @return registeredStake The sum of node stakes.
     */
    function getOperatorUsedStakeCached(
        address operator
    ) external view returns (uint256);

    /**
     * @notice Returns the Vault Manager address associated to this middleware
     * @return Address Vault Manager
     */
    function getVaultManager() external view returns (address);

    /**
     * @notice Returns the true active stake for an operator in a given epoch and asset class
     * @param epoch The epoch number
     * @param operator The operator address
     * @param assetClass The asset class ID
     * @return The true active stake
     */
    function getOperatorUsedStakeCachedPerEpoch(
        uint48 epoch,
        address operator,
        uint96 assetClass
    ) external view returns (uint256);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// (c) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

// SPDX-License-Identifier: Ecosystem

pragma solidity 0.8.25;

/**
 * @dev Validator status
 */
enum ValidatorStatus {
    Unknown,
    PendingAdded,
    Active,
    PendingRemoved,
    Completed,
    Invalidated
}

/**
 * @dev Specifies the owner of a validator's remaining balance or disable owner on the P-Chain.
 * P-Chain addresses are also 20-bytes, so we use the address type to represent them.
 */
struct PChainOwner {
    uint32 threshold;
    address[] addresses;
}

/**
 * @dev Contains the active state of a Validator
 */
struct Validator {
    ValidatorStatus status;
    bytes nodeID;
    uint64 startingWeight;
    uint64 messageNonce;
    uint64 weight;
    uint64 startedAt;
    uint64 endedAt;
}

/**
 * @dev Describes the current churn period
 */
struct ValidatorChurnPeriod {
    uint256 startedAt;
    uint64 initialWeight;
    uint64 totalWeight;
    uint64 churnAmount;
}

/**
 * @notice Validator Manager settings, used to initialize the Validator Manager
 * @notice The l1ID is the ID of the L1 that the Validator Manager is managing
 * @notice The churnPeriodSeconds is the duration of the churn period in seconds
 * @notice The maximumChurnPercentage is the maximum percentage of the total weight that can be added or removed in a single churn period
 */
struct ValidatorManagerSettings {
    bytes32 l1ID;
    uint64 churnPeriodSeconds;
    uint8 maximumChurnPercentage;
}

/**
 * @dev Description of the conversion data used to convert
 * a subnet to an L1 on the P-Chain.
 * This data is the pre-image of a hash that is authenticated by the P-Chain
 * and verified by the Validator Manager.
 */
struct ConversionData {
    bytes32 l1ID;
    bytes32 validatorManagerBlockchainID;
    address validatorManagerAddress;
    InitialValidator[] initialValidators;
}

/**
 * @dev Specifies an initial validator, used in the conversion data.
 */
struct InitialValidator {
    bytes nodeID;
    bytes blsPublicKey;
    uint64 weight;
}

/**
 * @dev Specifies a validator to register.
 */
struct ValidatorRegistrationInput {
    bytes nodeID;
    bytes blsPublicKey;
    uint64 registrationExpiry;
    PChainOwner remainingBalanceOwner;
    PChainOwner disableOwner;
}

/**
 * @notice Interface for Validator Manager contracts that implement Subnet-only Validator management.
 */
interface IValidatorManager {
    /**
     * @notice Emitted when a new validation period is created by locking stake in the manager contract.
     * Note: This event does not mean that the validation period has been successfully registered on the P-Chain,
     * and rewards for this validation period will not begin accruing until the {ValidationPeriodRegistered} event is
     * emitted.
     * @param validationID The ID of the validation period being created.
     * @param nodeID The node ID of the validator being registered.
     * @param registerValidationMessageID The ID of the ICM message that will be sent to the P-Chain to register the
     * validation period.
     * @param weight The weight of the validator being registered.
     * @param registrationExpiry The Unix timestamp after which the reigistration is no longer valid on the P-Chain.
     */
    event ValidationPeriodCreated(
        bytes32 indexed validationID,
        bytes indexed nodeID,
        bytes32 indexed registerValidationMessageID,
        uint64 weight,
        uint64 registrationExpiry
    );

    event InitialValidatorCreated(
        bytes32 indexed validationID, bytes indexed nodeID, uint64 weight
    );

    /**
     * @notice Emitted when the staking manager learns that the validation period has been successfully registered
     * on the P-Chain. Rewards for this validation period will begin accruing when this event is emitted.
     * @param validationID The ID of the validation period being registered.
     * @param weight The weight of the validator being registered.
     * @param timestamp The time at which the validation period was registered with the contract.
     */
    event ValidationPeriodRegistered(
        bytes32 indexed validationID, uint64 weight, uint256 timestamp
    );

    /**
     * @notice Emitted when the process of ending a registered validation period is started by calling
     * {initializeEndValidation}.
     * Note: The stake for this validation period remains locked until a {ValidationPeriodRemoved} event is emitted.
     * @param validationID The ID of the validation period being removed.
     * @param setWeightMessageID The ID of the ICM message that updates the validator's weight on the P-Chain.
     * @param weight The weight of the validator being removed.
     * @param endTime The time at which the removal was initiated.
     */
    event ValidatorRemovalInitialized(
        bytes32 indexed validationID,
        bytes32 indexed setWeightMessageID,
        uint64 weight,
        uint256 endTime
    );

    /**
     * @notice Emitted when the stake for a validation period is unlocked and returned to the staker.
     * This is done by calling {completeEndValidation}, which provides proof from the P-Chain that the
     * validation period is not active and will never be active in the future.
     * @param validationID The ID of the validation period being removed.
     */
    event ValidationPeriodEnded(bytes32 indexed validationID, ValidatorStatus indexed status);

    /**
     * @notice Event emitted when validator weight is updated.
     * @param validationID The ID of the validation period being updated
     * @param nonce The message nonce used to update the validator weight
     * @param weight The updated validator weight that is sent to the P-Chain
     * @param setWeightMessageID The ID of the ICM message that updates the validator's weight on the P-Chain
     */
    event ValidatorWeightUpdate(
        bytes32 indexed validationID,
        uint64 indexed nonce,
        uint64 weight,
        bytes32 setWeightMessageID
    );

    /**
     * @notice Verifies and sets the initial validator set for the chain through a P-Chain SubnetToL1ConversionMessage.
     * @param conversionData The subnet conversion message data used to recompute and verify against the conversionID.
     * @param messsageIndex The index that contains the SubnetToL1ConversionMessage ICM message containing the conversionID to be verified against the provided {ConversionData}
     */
    function initializeValidatorSet(
        ConversionData calldata conversionData,
        uint32 messsageIndex
    ) external;

    /**
     * @notice Resubmits a validator registration message to be sent to the P-Chain.
     * Only necessary if the original message can't be delivered due to validator churn.
     * @param validationID The ID of the validation period being registered.
     */
    function resendRegisterValidatorMessage(bytes32 validationID) external;

    /**
     * @notice Completes the validator registration process by returning an acknowledgement of the registration of a
     * validationID from the P-Chain.
     * @param messageIndex The index of the ICM message to be received providing the acknowledgement.
     */
    function completeValidatorRegistration(uint32 messageIndex) external;

    /**
     * @notice Resubmits a validator end message to be sent to the P-Chain.
     * Only necessary if the original message can't be delivered due to validator churn.
     * @param validationID The ID of the validation period being ended.
     */
    function resendEndValidatorMessage(bytes32 validationID) external;

    /**
     * @notice Completes the process of ending a validation period by receiving an acknowledgement from the P-Chain
     * that the validation ID is not active and will never be active in the future. Returns the the stake associated
     * with the validation.
     * Note: This function can be used for successful validation periods that have been explicitly ended by calling
     * {initializeEndValidation} or for validation periods that never began on the P-Chain due to the {registrationExpiry} being reached.
     * @param messageIndex The index of the ICM message to be received providing the proof the validation is not active
     * and never will be active on the P-Chain.
     */
    function completeEndValidation(uint32 messageIndex) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

Settings
{
  "remappings": [
    "@suzaku/collateral/=lib/collateral/src/",
    "@suzaku/core/=lib/suzaku-core/",
    "@suzaku/contracts-lib/=lib/suzaku-contracts-library/",
    "@suzaku/contracts-library/=lib/suzaku-contracts-library/src/",
    "@avalabs/teleporter/=lib/suzaku-contracts-library/lib/icm-contracts/contracts/",
    "@avalabs/icm-contracts/=lib/suzaku-contracts-library/lib/icm-contracts/contracts/",
    "@avalabs/subnet-evm-contracts/=lib/suzaku-core/lib/suzaku-contracts-library/lib/icm-contracts/lib/subnet-evm/contracts/contracts/",
    "@avalabs/[email protected]/=lib/suzaku-contracts-library/lib/icm-contracts/lib/subnet-evm/contracts/",
    "@forge-std/=lib/suzaku-contracts-library/lib/icm-contracts/lib/forge-std/src/",
    "@mocks/=lib/suzaku-contracts-library/lib/icm-contracts/contracts/mocks/",
    "@openzeppelin/contracts-upgradeable/=lib/collateral/lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/[email protected]/=lib/suzaku-contracts-library/lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/collateral/lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/[email protected]/=lib/suzaku-contracts-library/lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/foundry-upgrades/=lib/suzaku-core/lib/openzeppelin-foundry-upgrades/src/",
    "@symbiotic/core/=lib/suzaku-core/lib/core/src/",
    "@teleporter/=lib/suzaku-contracts-library/lib/icm-contracts/contracts/teleporter/",
    "@utilities/=lib/suzaku-contracts-library/lib/icm-contracts/contracts/utilities/",
    "collateral/=lib/collateral/",
    "core/=lib/suzaku-core/lib/core/",
    "ds-test/=lib/collateral/lib/permit2/lib/solmate/lib/ds-test/src/",
    "erc4626-tests/=lib/collateral/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-gas-snapshot/=lib/collateral/lib/permit2/lib/forge-gas-snapshot/src/",
    "forge-std/=lib/forge-std/src/",
    "icm-contracts/=lib/suzaku-contracts-library/lib/icm-contracts/contracts/",
    "openzeppelin-contracts-upgradeable/=lib/collateral/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/collateral/lib/openzeppelin-contracts/",
    "openzeppelin-foundry-upgrades/=lib/suzaku-core/lib/openzeppelin-foundry-upgrades/src/",
    "permit2/=lib/collateral/lib/permit2/",
    "solidity-stringutils/=lib/suzaku-core/lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/",
    "solmate/=lib/collateral/lib/permit2/lib/solmate/",
    "subnet-evm/=lib/suzaku-contracts-library/lib/icm-contracts/lib/subnet-evm/",
    "suzaku-contracts-library/=lib/suzaku-contracts-library/",
    "suzaku-core/=lib/suzaku-core/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "libraries": {}
}

Contract ABI

API
[{"inputs":[{"internalType":"address payable","name":"feeCollector_","type":"address"},{"internalType":"uint256","name":"registerFee_","type":"uint256"},{"internalType":"uint256","name":"MAX_FEE_","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"newFee","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"}],"name":"L1Registry__FeeExceedsMaximum","type":"error"},{"inputs":[],"name":"L1Registry__FeeTransferFailed","type":"error"},{"inputs":[],"name":"L1Registry__InsufficientFee","type":"error"},{"inputs":[],"name":"L1Registry__InvalidL1Middleware","type":"error"},{"inputs":[{"internalType":"address","name":"l1","type":"address"}],"name":"L1Registry__InvalidValidatorManager","type":"error"},{"inputs":[],"name":"L1Registry__L1AlreadyRegistered","type":"error"},{"inputs":[],"name":"L1Registry__L1NotRegistered","type":"error"},{"inputs":[],"name":"L1Registry__NoFeesToWithdraw","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"L1Registry__NotFeeCollector","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"expectedOwner","type":"address"}],"name":"L1Registry__NotValidatorManagerOwner","type":"error"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"L1Registry__ZeroAddress","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"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":true,"internalType":"address","name":"l1","type":"address"}],"name":"RegisterL1","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"l1","type":"address"},{"indexed":true,"internalType":"address","name":"l1Middleware","type":"address"}],"name":"SetL1Middleware","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"l1","type":"address"},{"indexed":false,"internalType":"string","name":"metadataURL","type":"string"}],"name":"SetMetadataURL","type":"event"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllL1s","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getL1At","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"l1","type":"address"}],"name":"isRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"l1","type":"address"},{"internalType":"address","name":"vaultManager_","type":"address"}],"name":"isRegisteredWithMiddleware","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"l1MetadataURL","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"l1Middleware","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registerFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"l1","type":"address"},{"internalType":"address","name":"l1Middleware_","type":"address"},{"internalType":"string","name":"metadataURL","type":"string"}],"name":"registerL1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newFeeCollector","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"l1","type":"address"},{"internalType":"address","name":"l1Middleware_","type":"address"}],"name":"setL1Middleware","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"l1","type":"address"},{"internalType":"string","name":"metadataURL","type":"string"}],"name":"setMetadataURL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"setRegisterFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalL1s","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unclaimedFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a03461012757601f6113b838819003918201601f19168301916001600160401b0383118484101761012b578084926080946040528339810103126101275780516001600160a01b039081811690819003610127576020830151916060604085015194015181811680910361012757801561010f575f549060018060a01b03199281848416175f5560405192167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a382156100dd5750600554161760055560065560805260405161127890816101408239608051816108dc0152f35b635a0bc64760e01b815260206004820152600c60248201526b3332b2a1b7b63632b1ba37b960a11b6044820152606490fd5b604051631e4fbdf760e01b81525f6004820152602490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe608060409080825260049081361015610022575b5050503615610020575f80fd5b005b5f3560e01c90816303f187ea14610e295750806334ebec3014610df05780633a98187b14610cb35780634049596a14610c86578063476343ee14610c08578063715018a614610bb1578063720057c4146109b4578063734d8287146109965780638c36aa1c1461094b5780638da5cb5b1461092457806392be2ab8146108bd5780639ec60b41146105ae578063a42dce8014610502578063bffcb7e814610461578063c3c5a5471461041e578063c40e2880146101cf578063c415b95c146101a7578063d96f3599146101895763f2fde38b146100ff5780610013565b3461018557602036600319011261018557610118610e43565b90610121611181565b6001600160a01b0391821692831561016f5750505f54826001600160601b0360a01b8216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b905f6024925191631e4fbdf760e01b8352820152fd5b5f80fd5b8234610185575f366003190112610185576020906001549051908152f35b8234610185575f3660031901126101855760055490516001600160a01b039091168152602090f35b50346101855781600319360112610185576101e8610e43565b67ffffffffffffffff90602435828111610185576102099036908501610fdf565b92909160018060a01b038091169461022c865f52600260205260405f2054151590565b15610410578651638da5cb5b60e01b8152602092838284818b5afa918215610406575f926103d7575b5033908216036103aa5750855f52808252865f20928511610397575061027b8254610ecf565b601f8111610354575b505f90601f85116001146102dd5750946102cd91845f8051602061122383398151915296975f916102d2575b508560011b905f198760031b1c19161790555b519283928361115a565b0390a2005b90508401355f6102b0565b90601f198516835f52825f20925f905b82821061033c575050916102cd9391865f8051602061122383398151915298999410610323575b5050600185811b0190556102c3565b8501355f19600388901b60f8161c191690555f80610314565b80600185968294968a013581550195019301906102ed565b825f52815f20601f860160051c81019183871061038d575b601f0160051c01905b8181106103825750610284565b5f8155600101610375565b909150819061036c565b604190634e487b7160e01b5f525260245ffd5b8751630f42d82560e21b8152339281019283526001600160a01b0390911660208301529081906040010390fd5b6103f8919250843d86116103ff575b6103f08183610f07565b81019061100d565b905f610255565b503d6103e6565b89513d5f823e3d90fd5b86516332814c1960e01b8152fd5b8234610185576020366003190112610185576020906104586001600160a01b03610446610e43565b165f52600260205260405f2054151590565b90519015158152f35b509034610185576020366003190112610185578135906001548210156104ef576104eb9060018060a01b0380937fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf601541692835f526003602052815f2054169360205260606104d1825f20610f3d565b918051958695865260208601528401526060830190610eab565b0390f35b603283634e487b7160e01b5f525260245ffd5b50346101855760203660031901126101855780356001600160a01b038116929083900361018557610531611181565b821561057b578260075480610559575b506001600160601b0360a01b60055416176005555f80f35b5f6007555f80808084865af161056d6110db565b506105415760075581610541565b9060206064925191635a0bc64760e01b8352820152600c60248201526b3332b2a1b7b63632b1ba37b960a11b6044820152fd5b506060366003190112610185576105c3610e43565b6105cb610e59565b67ffffffffffffffff93604435858111610185576105ec9036908601610fdf565b956001600160a01b03948516959194909186156108a6578351638da5cb5b60e01b815260209290838184818c5afa90811561089c575f9161087f575b5033828216036108525750600654806107f4575b50610646886111ac565b156107e557875f5260038352845f20951694856001600160601b0360a01b825416179055808252835f2092881161039757506106828254610ecf565b601f81116107a2575b505f90601f881160011461072a57509186915f8051602061122383398151915296976102cd945f9161071f575b508360011b905f198560031b1c19161790555b51938493877fec03e7641f2ddabb96aad9433e5ecdce879559cf693804cc5891626950fd006a5f80a2877fc4bfddda2d4796aa99cbc1d81e2732dcbb467734f776699113fb7bafbff8d56f5f80a38361115a565b90508601355f6106b8565b90601f198816835f52825f20925f905b82821061078a575050918893915f8051602061122383398151915298996102cd969410610771575b5050600183811b0190556106cb565b8701355f19600386901b60f8161c191690555f80610762565b80600185968294968c0135815501950193019061073a565b825f52815f20601f890160051c810191838a106107db575b601f0160051c01905b8181106107d0575061068b565b5f81556001016107c3565b90915081906107ba565b50835163030fa68760e51b8152fd5b3410610843575f8080803485600554165af161080e6110db565b501561081b575b5f61063c565b60075434810180911161083057600755610815565b601183634e487b7160e01b5f525260245ffd5b508351631fab2c7d60e01b8152fd5b8551630f42d82560e21b8152338185019081526001600160a01b0390921660208301529081906040010390fd5b6108969150843d86116103ff576103f08183610f07565b5f610628565b86513d5f823e3d90fd5b8351632f286dff60e01b8152908101879052602490fd5b5034610185576020366003190112610185578035916108da611181565b7f00000000000000000000000000000000000000000000000000000000000000009081841161090a576006849055005b926044935192633fb535d560e11b84528301526024820152fd5b8234610185575f366003190112610185575f5490516001600160a01b039091168152602090f35b509034610185576020366003190112610185576104eb916001600160a01b03610972610e43565b165f52602052610983815f20610f3d565b9051918291602083526020830190610eab565b8234610185575f366003190112610185576020906007549051908152f35b509034610185575f36600319011261018557805190816001918254808352602080930190845f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6905f5b818110610b9e5750505084610a15910385610f07565b835191610a39610a248461111a565b93610a3184519586610f07565b80855261111a565b601f1993908401368383013785519684610a6a610a558a61111a565b99610a6287519b8c610f07565b808b5261111a565b015f5b818110610b8f575050855f905b610b02575b5050610aa690610a99845197606089526060890190610e6f565b9087820384890152610e6f565b918583039086015285519182815281810182808560051b8401019801945f925b858410610ad357888a0389f35b909192939495968580610aef8c8686869f030188528b51610eab565b9b99019796959190910193019190610ac6565b9086989691889694959651811015610b825782906001600160a01b0380610b29838d611132565b51165f526003885280895f205416610b418388611132565b52610b4c828c611132565b51165f52828752610b5e885f20610f3d565b610b68828b611132565b52610b73818a611132565b50019091969895949395610a7a565b5097959794939294610a7f565b60608a82018601528401610a6d565b82548452928501929186019186016109ff565b34610185575f36600319011261018557610bc9611181565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b509034610185575f366003190112610185576005546001600160a01b031633819003610c7057600754908115610c61575f8080938193826007555af1610c4c6110db565b5015610c5457005b5163eaa7352f60e01b8152fd5b50505163134b502360e01b8152fd5b815163e548a2dd60e01b81523381850152602490fd5b8234610185578060031936011261018557602090610458610ca5610e43565b610cad610e59565b9061102c565b5034610185578160031936011261018557610ccc610e43565b916001600160a01b0380610cde610e59565b16938415610dd957811692610cfe845f52600260205260405f2054151590565b15610dcb578251638da5cb5b60e01b8152916020838381885afa928315610dc1575f93610da0575b503390831603610d74575050815f5260036020525f20826001600160601b0360a01b8254161790557fc4bfddda2d4796aa99cbc1d81e2732dcbb467734f776699113fb7bafbff8d56f5f80a3005b8251630f42d82560e21b8152339181019182526001600160a01b03909216602082015281906040010390fd5b610dba91935060203d6020116103ff576103f08183610f07565b915f610d26565b84513d5f823e3d90fd5b82516332814c1960e01b8152fd5b8251632f286dff60e01b8152808501869052602490fd5b8234610185576020366003190112610185576020906001600160a01b0380610e16610e43565b165f5260038352815f2054169051908152f35b34610185575f366003190112610185576020906006548152f35b600435906001600160a01b038216820361018557565b602435906001600160a01b038216820361018557565b9081518082526020808093019301915f5b828110610e8e575050505090565b83516001600160a01b031685529381019392810192600101610e80565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b90600182811c92168015610efd575b6020831014610ee957565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ede565b90601f8019910116810190811067ffffffffffffffff821117610f2957604052565b634e487b7160e01b5f52604160045260245ffd5b9060405191825f8254610f4f81610ecf565b908184526020946001916001811690815f14610fbd5750600114610f7f575b505050610f7d92500383610f07565b565b5f90815285812095935091905b818310610fa5575050610f7d93508201015f8080610f6e565b85548884018501529485019487945091830191610f8c565b92505050610f7d94925060ff191682840152151560051b8201015f8080610f6e565b9181601f840112156101855782359167ffffffffffffffff8311610185576020838186019501011161018557565b9081602091031261018557516001600160a01b03811681036101855790565b6001600160a01b039081165f81815260026020526040902054156110d4575f5260036020528060405f2054169182156110d45760206004936040519485809263b9bbb6f560e01b82525afa9283156110c9575f936110a6575b50811691160361109457600190565b604051631363c09760e31b8152600490fd5b829193506110c29060203d6020116103ff576103f08183610f07565b9290611085565b6040513d5f823e3d90fd5b5050505f90565b3d15611115573d9067ffffffffffffffff8211610f29576040519161110a601f8201601f191660200184610f07565b82523d5f602084013e565b606090565b67ffffffffffffffff8111610f295760051b60200190565b80518210156111465760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b90918060409360208452816020850152848401375f828201840152601f01601f1916010190565b5f546001600160a01b0316330361119457565b60405163118cdaa760e01b8152336004820152602490fd5b805f52600260205260405f2054155f1461121d5760015468010000000000000000811015610f295760018101806001558110156111465781907fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60155600154905f52600260205260405f2055600190565b505f9056fef8dac27f20d622a0759394313683066cb713a406633a3a7dde8799654015ea64a264697066735822122037e9b2d1d530821a921e7af3795e0509281a80561f2352bf3ef1ca77ce6876cd64736f6c634300081900330000000000000000000000002811086bd8962c536264e711470f7ef9a783a5eb000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000002811086bd8962c536264e711470f7ef9a783a5eb

Deployed Bytecode

0x608060409080825260049081361015610022575b5050503615610020575f80fd5b005b5f3560e01c90816303f187ea14610e295750806334ebec3014610df05780633a98187b14610cb35780634049596a14610c86578063476343ee14610c08578063715018a614610bb1578063720057c4146109b4578063734d8287146109965780638c36aa1c1461094b5780638da5cb5b1461092457806392be2ab8146108bd5780639ec60b41146105ae578063a42dce8014610502578063bffcb7e814610461578063c3c5a5471461041e578063c40e2880146101cf578063c415b95c146101a7578063d96f3599146101895763f2fde38b146100ff5780610013565b3461018557602036600319011261018557610118610e43565b90610121611181565b6001600160a01b0391821692831561016f5750505f54826001600160601b0360a01b8216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b905f6024925191631e4fbdf760e01b8352820152fd5b5f80fd5b8234610185575f366003190112610185576020906001549051908152f35b8234610185575f3660031901126101855760055490516001600160a01b039091168152602090f35b50346101855781600319360112610185576101e8610e43565b67ffffffffffffffff90602435828111610185576102099036908501610fdf565b92909160018060a01b038091169461022c865f52600260205260405f2054151590565b15610410578651638da5cb5b60e01b8152602092838284818b5afa918215610406575f926103d7575b5033908216036103aa5750855f52808252865f20928511610397575061027b8254610ecf565b601f8111610354575b505f90601f85116001146102dd5750946102cd91845f8051602061122383398151915296975f916102d2575b508560011b905f198760031b1c19161790555b519283928361115a565b0390a2005b90508401355f6102b0565b90601f198516835f52825f20925f905b82821061033c575050916102cd9391865f8051602061122383398151915298999410610323575b5050600185811b0190556102c3565b8501355f19600388901b60f8161c191690555f80610314565b80600185968294968a013581550195019301906102ed565b825f52815f20601f860160051c81019183871061038d575b601f0160051c01905b8181106103825750610284565b5f8155600101610375565b909150819061036c565b604190634e487b7160e01b5f525260245ffd5b8751630f42d82560e21b8152339281019283526001600160a01b0390911660208301529081906040010390fd5b6103f8919250843d86116103ff575b6103f08183610f07565b81019061100d565b905f610255565b503d6103e6565b89513d5f823e3d90fd5b86516332814c1960e01b8152fd5b8234610185576020366003190112610185576020906104586001600160a01b03610446610e43565b165f52600260205260405f2054151590565b90519015158152f35b509034610185576020366003190112610185578135906001548210156104ef576104eb9060018060a01b0380937fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf601541692835f526003602052815f2054169360205260606104d1825f20610f3d565b918051958695865260208601528401526060830190610eab565b0390f35b603283634e487b7160e01b5f525260245ffd5b50346101855760203660031901126101855780356001600160a01b038116929083900361018557610531611181565b821561057b578260075480610559575b506001600160601b0360a01b60055416176005555f80f35b5f6007555f80808084865af161056d6110db565b506105415760075581610541565b9060206064925191635a0bc64760e01b8352820152600c60248201526b3332b2a1b7b63632b1ba37b960a11b6044820152fd5b506060366003190112610185576105c3610e43565b6105cb610e59565b67ffffffffffffffff93604435858111610185576105ec9036908601610fdf565b956001600160a01b03948516959194909186156108a6578351638da5cb5b60e01b815260209290838184818c5afa90811561089c575f9161087f575b5033828216036108525750600654806107f4575b50610646886111ac565b156107e557875f5260038352845f20951694856001600160601b0360a01b825416179055808252835f2092881161039757506106828254610ecf565b601f81116107a2575b505f90601f881160011461072a57509186915f8051602061122383398151915296976102cd945f9161071f575b508360011b905f198560031b1c19161790555b51938493877fec03e7641f2ddabb96aad9433e5ecdce879559cf693804cc5891626950fd006a5f80a2877fc4bfddda2d4796aa99cbc1d81e2732dcbb467734f776699113fb7bafbff8d56f5f80a38361115a565b90508601355f6106b8565b90601f198816835f52825f20925f905b82821061078a575050918893915f8051602061122383398151915298996102cd969410610771575b5050600183811b0190556106cb565b8701355f19600386901b60f8161c191690555f80610762565b80600185968294968c0135815501950193019061073a565b825f52815f20601f890160051c810191838a106107db575b601f0160051c01905b8181106107d0575061068b565b5f81556001016107c3565b90915081906107ba565b50835163030fa68760e51b8152fd5b3410610843575f8080803485600554165af161080e6110db565b501561081b575b5f61063c565b60075434810180911161083057600755610815565b601183634e487b7160e01b5f525260245ffd5b508351631fab2c7d60e01b8152fd5b8551630f42d82560e21b8152338185019081526001600160a01b0390921660208301529081906040010390fd5b6108969150843d86116103ff576103f08183610f07565b5f610628565b86513d5f823e3d90fd5b8351632f286dff60e01b8152908101879052602490fd5b5034610185576020366003190112610185578035916108da611181565b7f0000000000000000000000000000000000000000000000000de0b6b3a76400009081841161090a576006849055005b926044935192633fb535d560e11b84528301526024820152fd5b8234610185575f366003190112610185575f5490516001600160a01b039091168152602090f35b509034610185576020366003190112610185576104eb916001600160a01b03610972610e43565b165f52602052610983815f20610f3d565b9051918291602083526020830190610eab565b8234610185575f366003190112610185576020906007549051908152f35b509034610185575f36600319011261018557805190816001918254808352602080930190845f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6905f5b818110610b9e5750505084610a15910385610f07565b835191610a39610a248461111a565b93610a3184519586610f07565b80855261111a565b601f1993908401368383013785519684610a6a610a558a61111a565b99610a6287519b8c610f07565b808b5261111a565b015f5b818110610b8f575050855f905b610b02575b5050610aa690610a99845197606089526060890190610e6f565b9087820384890152610e6f565b918583039086015285519182815281810182808560051b8401019801945f925b858410610ad357888a0389f35b909192939495968580610aef8c8686869f030188528b51610eab565b9b99019796959190910193019190610ac6565b9086989691889694959651811015610b825782906001600160a01b0380610b29838d611132565b51165f526003885280895f205416610b418388611132565b52610b4c828c611132565b51165f52828752610b5e885f20610f3d565b610b68828b611132565b52610b73818a611132565b50019091969895949395610a7a565b5097959794939294610a7f565b60608a82018601528401610a6d565b82548452928501929186019186016109ff565b34610185575f36600319011261018557610bc9611181565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b509034610185575f366003190112610185576005546001600160a01b031633819003610c7057600754908115610c61575f8080938193826007555af1610c4c6110db565b5015610c5457005b5163eaa7352f60e01b8152fd5b50505163134b502360e01b8152fd5b815163e548a2dd60e01b81523381850152602490fd5b8234610185578060031936011261018557602090610458610ca5610e43565b610cad610e59565b9061102c565b5034610185578160031936011261018557610ccc610e43565b916001600160a01b0380610cde610e59565b16938415610dd957811692610cfe845f52600260205260405f2054151590565b15610dcb578251638da5cb5b60e01b8152916020838381885afa928315610dc1575f93610da0575b503390831603610d74575050815f5260036020525f20826001600160601b0360a01b8254161790557fc4bfddda2d4796aa99cbc1d81e2732dcbb467734f776699113fb7bafbff8d56f5f80a3005b8251630f42d82560e21b8152339181019182526001600160a01b03909216602082015281906040010390fd5b610dba91935060203d6020116103ff576103f08183610f07565b915f610d26565b84513d5f823e3d90fd5b82516332814c1960e01b8152fd5b8251632f286dff60e01b8152808501869052602490fd5b8234610185576020366003190112610185576020906001600160a01b0380610e16610e43565b165f5260038352815f2054169051908152f35b34610185575f366003190112610185576020906006548152f35b600435906001600160a01b038216820361018557565b602435906001600160a01b038216820361018557565b9081518082526020808093019301915f5b828110610e8e575050505090565b83516001600160a01b031685529381019392810192600101610e80565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b90600182811c92168015610efd575b6020831014610ee957565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ede565b90601f8019910116810190811067ffffffffffffffff821117610f2957604052565b634e487b7160e01b5f52604160045260245ffd5b9060405191825f8254610f4f81610ecf565b908184526020946001916001811690815f14610fbd5750600114610f7f575b505050610f7d92500383610f07565b565b5f90815285812095935091905b818310610fa5575050610f7d93508201015f8080610f6e565b85548884018501529485019487945091830191610f8c565b92505050610f7d94925060ff191682840152151560051b8201015f8080610f6e565b9181601f840112156101855782359167ffffffffffffffff8311610185576020838186019501011161018557565b9081602091031261018557516001600160a01b03811681036101855790565b6001600160a01b039081165f81815260026020526040902054156110d4575f5260036020528060405f2054169182156110d45760206004936040519485809263b9bbb6f560e01b82525afa9283156110c9575f936110a6575b50811691160361109457600190565b604051631363c09760e31b8152600490fd5b829193506110c29060203d6020116103ff576103f08183610f07565b9290611085565b6040513d5f823e3d90fd5b5050505f90565b3d15611115573d9067ffffffffffffffff8211610f29576040519161110a601f8201601f191660200184610f07565b82523d5f602084013e565b606090565b67ffffffffffffffff8111610f295760051b60200190565b80518210156111465760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b90918060409360208452816020850152848401375f828201840152601f01601f1916010190565b5f546001600160a01b0316330361119457565b60405163118cdaa760e01b8152336004820152602490fd5b805f52600260205260405f2054155f1461121d5760015468010000000000000000811015610f295760018101806001558110156111465781907fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60155600154905f52600260205260405f2055600190565b505f9056fef8dac27f20d622a0759394313683066cb713a406633a3a7dde8799654015ea64a264697066735822122037e9b2d1d530821a921e7af3795e0509281a80561f2352bf3ef1ca77ce6876cd64736f6c63430008190033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000002811086bd8962c536264e711470f7ef9a783a5eb000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000002811086bd8962c536264e711470f7ef9a783a5eb

-----Decoded View---------------
Arg [0] : feeCollector_ (address): 0x2811086Bd8962C536264e711470f7ef9A783a5eB
Arg [1] : registerFee_ (uint256): 10000000000000000
Arg [2] : MAX_FEE_ (uint256): 1000000000000000000
Arg [3] : owner (address): 0x2811086Bd8962C536264e711470f7ef9A783a5eB

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000002811086bd8962c536264e711470f7ef9a783a5eb
Arg [1] : 000000000000000000000000000000000000000000000000002386f26fc10000
Arg [2] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [3] : 0000000000000000000000002811086bd8962c536264e711470f7ef9a783a5eb


Block Transaction Gas Used Reward
view all blocks ##produced##

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
0xB9826Bbf0deB10cC3924449B93F418db6b16be36
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.