Sepolia Testnet

Contract

0x800De4d33015FeB4e344951aCe8eA2f4F33aE529

Overview

ETH Balance

0.574968157411760027 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Fetch Virtual Ac...66550882024-09-08 12:13:123 days ago1725797592IN
0x800De4d3...4F33aE529
0 ETH0.00011284.65422238
Fetch Virtual Ac...66550582024-09-08 12:05:483 days ago1725797148IN
0x800De4d3...4F33aE529
0 ETH0.000114654.73045462
Fetch Virtual Ac...66550332024-09-08 11:59:123 days ago1725796752IN
0x800De4d3...4F33aE529
0 ETH0.000094073.88110276
Fetch Virtual Ac...66549992024-09-08 11:50:243 days ago1725796224IN
0x800De4d3...4F33aE529
0 ETH0.000085933.54537913
Fetch Virtual Ac...66549912024-09-08 11:48:363 days ago1725796116IN
0x800De4d3...4F33aE529
0 ETH0.000086133.55356596
Fetch Virtual Ac...66549792024-09-08 11:46:003 days ago1725795960IN
0x800De4d3...4F33aE529
0 ETH0.003732133.72146039
Fetch Virtual Ac...66418342024-09-06 7:02:125 days ago1725606132IN
0x800De4d3...4F33aE529
0 ETH0.00010994.53457025
Fetch Virtual Ac...66418292024-09-06 7:00:365 days ago1725606036IN
0x800De4d3...4F33aE529
0 ETH0.004216554.20449729
Fetch Virtual Ac...66308922024-09-04 10:55:127 days ago1725447312IN
0x800De4d3...4F33aE529
0 ETH0.0007115329.37055593
Fetch Virtual Ac...66308782024-09-04 10:52:127 days ago1725447132IN
0x800De4d3...4F33aE529
0 ETH0.0009026537.25980164
Fetch Virtual Ac...66308002024-09-04 10:33:487 days ago1725446028IN
0x800De4d3...4F33aE529
0 ETH0.0015762665.06497095
Fetch Virtual Ac...66307732024-09-04 10:26:487 days ago1725445608IN
0x800De4d3...4F33aE529
0 ETH0.0011685148.23382835
Fetch Virtual Ac...66307502024-09-04 10:21:367 days ago1725445296IN
0x800De4d3...4F33aE529
0 ETH0.064042163.85972133
Fetch Virtual Ac...66251002024-09-03 12:11:248 days ago1725365484IN
0x800De4d3...4F33aE529
0 ETH0.0005296721.85304891
Fetch Virtual Ac...66249722024-09-03 11:42:248 days ago1725363744IN
0x800De4d3...4F33aE529
0 ETH0.0006629127.35042325
Fetch Virtual Ac...66249582024-09-03 11:39:128 days ago1725363552IN
0x800De4d3...4F33aE529
0 ETH0.0224388822.37471568
Fetch Virtual Ac...66207782024-09-02 19:45:488 days ago1725306348IN
0x800De4d3...4F33aE529
0 ETH0.000061872.55261945
Fetch Virtual Ac...66207572024-09-02 19:41:008 days ago1725306060IN
0x800De4d3...4F33aE529
0 ETH0.000063362.61434442
Fetch Virtual Ac...66207362024-09-02 19:36:248 days ago1725305784IN
0x800De4d3...4F33aE529
0 ETH0.002552642.54534475
Fetch Virtual Ac...66186922024-09-02 11:54:489 days ago1725278088IN
0x800De4d3...4F33aE529
0 ETH0.0007548331.14245803
Fetch Virtual Ac...66186862024-09-02 11:52:369 days ago1725277956IN
0x800De4d3...4F33aE529
0 ETH0.000605324.97358421
Fetch Virtual Ac...66186772024-09-02 11:50:489 days ago1725277848IN
0x800De4d3...4F33aE529
0 ETH0.0007113929.35056784
Fetch Virtual Ac...66186712024-09-02 11:49:369 days ago1725277776IN
0x800De4d3...4F33aE529
0 ETH0.0008580235.40006757
Fetch Virtual Ac...66186662024-09-02 11:48:369 days ago1725277716IN
0x800De4d3...4F33aE529
0 ETH0.000961539.66920003
Fetch Virtual Ac...66186542024-09-02 11:46:129 days ago1725277572IN
0x800De4d3...4F33aE529
0 ETH0.0401305240.01576118
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
66549792024-09-08 11:46:003 days ago1725795960
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66418292024-09-06 7:00:365 days ago1725606036
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66307502024-09-04 10:21:367 days ago1725445296
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66264482024-09-03 17:21:008 days ago1725384060
0x800De4d3...4F33aE529
0.01 ETH
66249582024-09-03 11:39:128 days ago1725363552
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66207362024-09-02 19:36:248 days ago1725305784
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66186542024-09-02 11:46:129 days ago1725277572
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66158452024-09-02 1:08:009 days ago1725239280
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66132962024-09-01 15:25:3610 days ago1725204336
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66132942024-09-01 15:25:0010 days ago1725204300
0x800De4d3...4F33aE529
0.01 ETH
66132942024-09-01 15:25:0010 days ago1725204300
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66117192024-09-01 9:29:2410 days ago1725182964
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66112322024-09-01 7:44:0010 days ago1725176640
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66109192024-09-01 6:32:4810 days ago1725172368
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66102032024-09-01 3:41:3610 days ago1725162096
0x800De4d3...4F33aE529
 Contract Creation0 ETH
66100132024-09-01 2:53:4810 days ago1725159228
0x800De4d3...4F33aE529
 Contract Creation0 ETH
65994132024-08-30 9:49:3612 days ago1725011376
0x800De4d3...4F33aE529
 Contract Creation0 ETH
65914282024-08-29 3:31:1213 days ago1724902272
0x800De4d3...4F33aE529
 Contract Creation0 ETH
65850262024-08-28 2:44:2414 days ago1724813064
0x800De4d3...4F33aE529
 Contract Creation0 ETH
65829062024-08-27 18:46:2414 days ago1724784384
0x800De4d3...4F33aE529
 Contract Creation0 ETH
65815522024-08-27 13:42:4815 days ago1724766168
0x800De4d3...4F33aE529
 Contract Creation0 ETH
65791362024-08-27 4:33:0015 days ago1724733180
0x800De4d3...4F33aE529
 Contract Creation0 ETH
65571552024-08-23 17:17:0019 days ago1724433420
0x800De4d3...4F33aE529
 Contract Creation0 ETH
65570752024-08-23 16:56:4819 days ago1724432208
0x800De4d3...4F33aE529
 Contract Creation0 ETH
65556792024-08-23 11:46:3619 days ago1724413596
0x800De4d3...4F33aE529
 Contract Creation0 ETH
View All Internal Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xF1A889f8...B86B9E9ac
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
RootPort

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion
File 1 of 25 : RootPort.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {Ownable} from "lib/solady/src/auth/Ownable.sol";
import {SafeTransferLib} from "lib/solady/src/utils/SafeTransferLib.sol";

import {ReentrancyGuard} from "lib/solmate/src/utils/ReentrancyGuard.sol";

import {ICoreRootRouter, GasParams} from "./interfaces/ICoreRootRouter.sol";
import {IERC20hTokenRootFactory} from "./interfaces/IERC20hTokenRootFactory.sol";
import {IRootBridgeAgent as IBridgeAgent} from "./interfaces/IRootBridgeAgent.sol";
import {IRootPort, VirtualAccount} from "./interfaces/IRootPort.sol";

import {ERC20hToken} from "./token/ERC20hToken.sol";

/// @title Root Port - Omnichain Token Management Contract
/// @author MaiaDAO
contract RootPort is Ownable, ReentrancyGuard, IRootPort {
    using SafeTransferLib for address;

    /*///////////////////////////////////////////////////////////////
                            SETUP STATE
    ///////////////////////////////////////////////////////////////*/

    /// @notice True if setup is still ongoing, false otherwise.
    bool internal _setup;

    /// @notice True if core setup is still ongoing, false otherwise.
    bool internal _setupCore;

    /*///////////////////////////////////////////////////////////////
                          ROOT PORT STATE
    ///////////////////////////////////////////////////////////////*/

    /// @notice Local Chain Id
    uint256 public immutable localChainId;

    /// @notice The address of local branch port responsible for handling local transactions.
    address public localBranchPortAddress;

    /// @notice The address of the core router in charge of adding new tokens to the system.
    address public coreRootRouterAddress;

    /// @notice The address of the core router in charge of adding new tokens to the system.
    address public coreRootBridgeAgentAddress;

    /*///////////////////////////////////////////////////////////////
                            VIRTUAL ACCOUNT
    ///////////////////////////////////////////////////////////////*/

    /// @notice Mapping from user address to Virtual Account.
    mapping(address user => VirtualAccount account) public getUserAccount;

    /// @notice Holds the mapping from Virtual account to router address => bool.
    /// @notice Stores whether a router is approved to spend a virtual account.
    mapping(VirtualAccount acount => mapping(address router => bool allowed)) public isRouterApproved;

    /*///////////////////////////////////////////////////////////////
                            BRIDGE AGENTS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Mapping from address to Bridge Agent.
    mapping(uint256 chainId => bool isActive) public isChainId;

    /// @notice Mapping from address to isBridgeAgent (bool).
    mapping(address bridgeAgent => bool isActive) public isBridgeAgent;

    /// @notice Bridge Agents deployed in root chain.
    address[] public bridgeAgents;

    /// @notice Mapping address Bridge Agent => address Bridge Agent Manager
    mapping(address bridgeAgent => address bridgeAgentManager) public getBridgeAgentManager;

    /*///////////////////////////////////////////////////////////////
                        BRIDGE AGENT FACTORIES
    ///////////////////////////////////////////////////////////////*/

    /// @notice Mapping from Underlying Address to isUnderlying (bool).
    mapping(address bridgeAgentFactory => bool isActive) public isBridgeAgentFactory;

    /// @notice Bridge Agents deployed in root chain.
    address[] public bridgeAgentFactories;

    /*///////////////////////////////////////////////////////////////
                                hTOKENS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Mapping with all global hTokens deployed in the system.
    mapping(address token => bool isGlobalToken) public isGlobalAddress;

    /// @notice Local Address -> ChainId -> Global Address
    mapping(address localAddress => mapping(uint256 chainId => address globalAddress)) public getGlobalTokenFromLocal;

    /// @notice Global Address -> ChainId -> Local Address
    mapping(address globalAddress => mapping(uint256 chainId => address localAddress)) public getLocalTokenFromGlobal;

    /// @notice Underlying Address -> ChainId -> Local Address
    mapping(address underlyingAddress => mapping(uint256 chainId => address localAddress)) public
        getLocalTokenFromUnderlying;

    /// @notice Mapping from Local Address to Underlying Address.
    mapping(address localAddress => mapping(uint256 chainId => address underlyingAddress)) public
        getUnderlyingTokenFromLocal;

    /*///////////////////////////////////////////////////////////////
                            hTOKEN ACCOUNTING
    ///////////////////////////////////////////////////////////////*/

    /// @notice Mapping from global address to total hToken supply allocated to branches.
    mapping(address globalAddress => uint256 totalSupplyBranches) public getTotalSupplyBranches;

    /// @notice Mapping from global address to chainId to current hToken balance allocated to chain.
    mapping(address globalAddress => mapping(uint256 chainId => uint256 balance)) public getBalanceOfBranch;

    /*///////////////////////////////////////////////////////////////
                                CONSTRUCTOR
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Constructor for Root Port.
     * @param _localChainId layer zero chain id of the local chain.
     */
    constructor(uint256 _localChainId) {
        localChainId = _localChainId;
        isChainId[_localChainId] = true;

        _initializeOwner(msg.sender);
        _setup = true;
        _setupCore = true;
    }

    /*///////////////////////////////////////////////////////////////
                        FALLBACK FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    receive() external payable {}

    /*///////////////////////////////////////////////////////////////
                    INITIALIZATION FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     *  @notice Function to initialize the Root Port.
     *   @param _bridgeAgentFactory The address of the Bridge Agent Factory.
     *   @param _coreRootRouter The address of the Core Root Router.
     */
    function initialize(address _bridgeAgentFactory, address _coreRootRouter) external onlyOwner {
        if (_bridgeAgentFactory == address(0)) revert InvalidRootBridgeAgentFactory();
        if (_coreRootRouter == address(0)) revert InvalidCoreRootRouter();
        if (!_setup) revert SetUpEnded();

        // End setup
        _setup = false;

        // Add Bridge Agent Factory
        isBridgeAgentFactory[_bridgeAgentFactory] = true;
        bridgeAgentFactories.push(_bridgeAgentFactory);

        // Add Core Root Router
        coreRootRouterAddress = _coreRootRouter;
    }

    /**
     *  @notice Function to initialize the Root Chain Core Contracts in Port Storage.
     *   @param _coreRootBridgeAgent The address of the Core Root Bridge Agent.
     *   @param _coreLocalBranchBridgeAgent The address of the Core Arbitrum Branch Bridge Agent.
     *   @param _localBranchPortAddress The address of the Arbitrum Branch Port.
     */
    function initializeCore(
        address _coreRootBridgeAgent,
        address _coreLocalBranchBridgeAgent,
        address _localBranchPortAddress
    ) external onlyOwner {
        if (_coreRootBridgeAgent == address(0)) revert InvalidCoreRootBridgeAgent();
        if (_coreLocalBranchBridgeAgent == address(0)) revert InvalidCoreBranchRouter();
        if (_localBranchPortAddress == address(0)) revert InvalidBranchPort();
        if (!isBridgeAgent[_coreRootBridgeAgent]) revert UnrecognizedCoreRootBridgeAgent();
        if (!_setupCore) revert SetUpCoreEnded();

        // End core setup
        _setupCore = false;

        // Set Core Arbitrum Branch Port Address
        localBranchPortAddress = _localBranchPortAddress;

        // Set Core Root Bridge Agent
        coreRootBridgeAgentAddress = _coreRootBridgeAgent;

        // Set Core Root Bridge Agent Manager
        getBridgeAgentManager[_coreRootBridgeAgent] = owner();

        // Sync Core Arbitrum Branch Bridge Agent with Core Root Bridge Agent
        IBridgeAgent(_coreRootBridgeAgent).syncBranchBridgeAgent(_coreLocalBranchBridgeAgent, localChainId);

        //Emit Core Root Set Event
        emit CoreRootSet(coreRootRouterAddress, _coreRootBridgeAgent);
    }

    /// @notice Function being overridden to prevent mistakenly renouncing ownership.
    function renounceOwnership() public payable override onlyOwner {
        revert RenounceOwnershipNotAllowed();
    }

    /*///////////////////////////////////////////////////////////////
                        EXTERNAL VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IRootPort
    function getLocalToken(address _localAddress, uint256 _srcChainId, uint256 _dstChainId)
        external
        view
        override
        returns (address)
    {
        return _getLocalToken(_localAddress, _srcChainId, _dstChainId);
    }

    /**
     * @notice View Function returns Local Token's Local Address on another chain.
     * @param _localAddress The address of the token in the local chain.
     * @param _srcChainId The chainId of the chain where the token is deployed.
     * @param _dstChainId The chainId of the chain for which the token address is requested.
     */
    function _getLocalToken(address _localAddress, uint256 _srcChainId, uint256 _dstChainId)
        internal
        view
        returns (address)
    {
        address globalAddress = getGlobalTokenFromLocal[_localAddress][_srcChainId];
        return getLocalTokenFromGlobal[globalAddress][_dstChainId];
    }

    /// @inheritdoc IRootPort
    function getUnderlyingTokenFromGlobal(address _globalAddress, uint256 _srcChainId)
        external
        view
        override
        returns (address)
    {
        address localAddress = getLocalTokenFromGlobal[_globalAddress][_srcChainId];
        return getUnderlyingTokenFromLocal[localAddress][_srcChainId];
    }

    /// @inheritdoc IRootPort
    function isGlobalToken(address _globalAddress, uint256 _srcChainId) external view override returns (bool) {
        return getLocalTokenFromGlobal[_globalAddress][_srcChainId] != address(0);
    }

    /// @inheritdoc IRootPort
    function isLocalToken(address _localAddress, uint256 _srcChainId) external view override returns (bool) {
        return getGlobalTokenFromLocal[_localAddress][_srcChainId] != address(0);
    }

    /// @inheritdoc IRootPort
    function isLocalToken(address _localAddress, uint256 _srcChainId, uint256 _dstChainId)
        external
        view
        returns (bool)
    {
        return _getLocalToken(_localAddress, _srcChainId, _dstChainId) != address(0);
    }

    /// @inheritdoc IRootPort
    function isUnderlyingToken(address _underlyingToken, uint256 _srcChainId) external view override returns (bool) {
        return getLocalTokenFromUnderlying[_underlyingToken][_srcChainId] != address(0);
    }

    /*///////////////////////////////////////////////////////////////
                        hTOKEN MANAGEMENT FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IRootPort
    function setAddresses(
        address _globalAddress,
        address _localAddress,
        address _underlyingAddress,
        uint256 _srcChainId
    ) external override requiresCoreRootRouter {
        // Verify addresses are valid
        if (_globalAddress == address(0)) revert InvalidGlobalAddress();
        if (_localAddress == address(0)) revert InvalidLocalAddress();
        if (_underlyingAddress == address(0)) revert InvalidUnderlyingAddress();

        // Update Token State
        isGlobalAddress[_globalAddress] = true;
        getGlobalTokenFromLocal[_localAddress][_srcChainId] = _globalAddress;
        getLocalTokenFromGlobal[_globalAddress][_srcChainId] = _localAddress;
        getLocalTokenFromUnderlying[_underlyingAddress][_srcChainId] = _localAddress;
        getUnderlyingTokenFromLocal[_localAddress][_srcChainId] = _underlyingAddress;

        emit LocalTokenAdded(_underlyingAddress, _localAddress, _globalAddress, _srcChainId);
    }

    /// @inheritdoc IRootPort
    function setLocalAddress(address _globalAddress, address _localAddress, uint256 _srcChainId)
        external
        override
        requiresCoreRootRouter
    {
        if (_localAddress == address(0)) revert InvalidLocalAddress();

        getGlobalTokenFromLocal[_localAddress][_srcChainId] = _globalAddress;
        getLocalTokenFromGlobal[_globalAddress][_srcChainId] = _localAddress;

        emit GlobalTokenAdded(_localAddress, _globalAddress, _srcChainId);
    }

    /*///////////////////////////////////////////////////////////////
                        hTOKEN ACCOUNTING FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IRootPort
    function bridgeToRoot(address _to, address _hToken, uint256 _amount, uint256 _deposit, uint256 _srcChainId)
        external
        override
        nonReentrant
        requiresBridgeAgent
        requiresGlobalAddress(_hToken)
    {
        if (_amount - _deposit > 0) {
            unchecked {
                // Decrement balance of hToken in srcChainId
                _decrementBranchBalance(_hToken, _amount - _deposit, _srcChainId);
                // Transfer hToken to root contract recipient
                _hToken.safeTransfer(_to, _amount - _deposit);
            }
        }

        if (_deposit > 0) ERC20hToken(_hToken).mint(_to, _deposit);
    }

    /**
     * @notice Function to decrement the balance of a hToken in a branch.
     * @param _hToken The address of the hToken.
     * @param _amount The amount to decrement the balance by.
     * @param _srcChainId The chainId of the chain where the hToken is being bridged from.
     */
    function _decrementBranchBalance(address _hToken, uint256 _amount, uint256 _srcChainId) internal {
        // Check if srcChainId is localChainId
        if (_srcChainId == localChainId) {
            // Revert if exceeds total balance available in root
            if (ERC20hToken(_hToken).balanceOf(address(this)) < getTotalSupplyBranches[_hToken] + _amount) {
                revert InsufficientBalance();
            }
        } else {
            // Decrement balance of hToken in srcChainId
            getBalanceOfBranch[_hToken][_srcChainId] -= _amount;
            // Decrement totalSupplyBranches of hToken
            getTotalSupplyBranches[_hToken] -= _amount;
        }
    }

    /// @inheritdoc IRootPort
    function bridgeToBranch(address _from, address _hToken, uint256 _amount, uint256 _deposit, uint256 _dstChainId)
        external
        nonReentrant
        requiresBridgeAgent
        requiresGlobalAddress(_hToken)
    {
        if (_amount - _deposit > 0) {
            unchecked {
                // Increment balance of hToken in dstChainId
                _incrementBranchBalance(_hToken, _amount - _deposit, _dstChainId);
                // Transfer hToken to root port
                _hToken.safeTransferFrom(_from, address(this), _amount - _deposit);
            }
        }

        if (_deposit > 0) ERC20hToken(_hToken).burn(_from, _deposit);
    }

    /**
     * @notice Function to increment the balance of a hToken in a branch.
     * @param _hToken The address of the hToken.
     * @param _amount The amount to increment the balance by.
     * @param _dstChainId The chainId of the chain where the hToken is being bridged to.
     */
    function _incrementBranchBalance(address _hToken, uint256 _amount, uint256 _dstChainId) internal {
        // Check if srcChainId is localChainId
        if (_dstChainId == localChainId) return;

        unchecked {
            // Increment balance of hToken in srcChainId
            getBalanceOfBranch[_hToken][_dstChainId] += _amount;
            // Increment totalSupplyBranches of hToken
            getTotalSupplyBranches[_hToken] += _amount;
        }
    }

    /*///////////////////////////////////////////////////////////////
                hTOKEN ACCOUNTING FUNCTIONS (ARB BRANCH)
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IRootPort
    function bridgeToRootFromLocalBranch(address _from, address _hToken, uint256 _amount)
        external
        override
        nonReentrant
        requiresLocalBranchPort
        requiresGlobalAddress(_hToken)
    {
        _hToken.safeTransferFrom(_from, address(this), _amount);
    }

    function bridgeToLocalBranchFromRoot(address _to, address _hToken, uint256 _amount)
        external
        override
        nonReentrant
        requiresLocalBranchPort
        requiresGlobalAddress(_hToken)
    {
        // Revert if exceeds total balance available in root
        if (ERC20hToken(_hToken).balanceOf(address(this)) < getTotalSupplyBranches[_hToken] + _amount) {
            revert InsufficientBalance();
        }

        _hToken.safeTransfer(_to, _amount);
    }

    /// @inheritdoc IRootPort
    function burnFromLocalBranch(address _from, address _hToken, uint256 _amount)
        external
        override
        nonReentrant
        requiresLocalBranchPort
        requiresGlobalAddress(_hToken)
    {
        ERC20hToken(_hToken).burn(_from, _amount);
    }

    /// @inheritdoc IRootPort
    function mintToLocalBranch(address _to, address _hToken, uint256 _amount)
        external
        override
        nonReentrant
        requiresLocalBranchPort
        requiresGlobalAddress(_hToken)
    {
        ERC20hToken(_hToken).mint(_to, _amount);
    }

    /*///////////////////////////////////////////////////////////////
                    VIRTUAL ACCOUNT MANAGEMENT FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IRootPort
    function fetchVirtualAccount(address _user) external override returns (VirtualAccount account) {
        account = getUserAccount[_user];
        if (address(account) == address(0)) account = _addVirtualAccount(_user);
    }

    /**
     * @notice Creates a new virtual account for a user.
     * @param _user address of the user to associate a virtual account with.
     * @return newAccount the newly created virtual account.
     */
    function _addVirtualAccount(address _user) internal returns (VirtualAccount newAccount) {
        if (_user == address(0)) revert InvalidUserAddress();

        newAccount = new VirtualAccount{salt: bytes32(bytes20(_user))}(_user);
        getUserAccount[_user] = newAccount;

        emit VirtualAccountCreated(_user, address(newAccount));
    }

    /// @inheritdoc IRootPort
    function toggleVirtualAccountApproved(VirtualAccount _userAccount, address _router)
        external
        override
        requiresBridgeAgent
    {
        isRouterApproved[_userAccount][_router] = !isRouterApproved[_userAccount][_router];
    }

    /*///////////////////////////////////////////////////////////////
                    BRIDGE AGENT MANAGEMENT FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IRootPort
    function addBridgeAgent(address _manager, address _bridgeAgent) external override requiresBridgeAgentFactory {
        if (isBridgeAgent[_bridgeAgent]) revert AlreadyAddedBridgeAgent();

        bridgeAgents.push(_bridgeAgent);
        getBridgeAgentManager[_bridgeAgent] = _manager;
        isBridgeAgent[_bridgeAgent] = true;
    }

    /// @inheritdoc IRootPort
    function syncBranchBridgeAgentWithRoot(
        address _newBranchBridgeAgent,
        address _rootBridgeAgent,
        uint256 _branchChainId
    ) external override requiresCoreRootRouter {
        // Check if root bridge agent already has a branch bridge agent for this chain.
        if (IBridgeAgent(_rootBridgeAgent).getBranchBridgeAgent(_branchChainId) != address(0)) {
            revert AlreadyAddedBridgeAgent();
        }
        // Check if chain is allowed for bridge agent addition.
        if (!IBridgeAgent(_rootBridgeAgent).isBranchBridgeAgentAllowed(_branchChainId)) {
            revert BridgeAgentNotAllowed();
        }

        // Update Root Bridge Agent getBranchBridgeAgent mapping
        IBridgeAgent(_rootBridgeAgent).syncBranchBridgeAgent(_newBranchBridgeAgent, _branchChainId);

        emit BridgeAgentSynced(_newBranchBridgeAgent, _rootBridgeAgent, _branchChainId);
    }

    /*///////////////////////////////////////////////////////////////
                        BRIDGE AGENT MANAGER FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IRootPort
    function setBridgeAgentManager(address _newManager) external override requiresBridgeAgent {
        getBridgeAgentManager[msg.sender] = _newManager;

        emit BridgeAgentManagerSet(msg.sender, _newManager);
    }

    /*///////////////////////////////////////////////////////////////
                            ADMIN FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IRootPort
    function toggleBridgeAgentFactory(address _bridgeAgentFactory) external override onlyOwner {
        isBridgeAgentFactory[_bridgeAgentFactory] = !isBridgeAgentFactory[_bridgeAgentFactory];

        emit BridgeAgentFactoryToggled(_bridgeAgentFactory);
    }

    /// @inheritdoc IRootPort
    function addNewChain(
        address _coreBranchBridgeAgentAddress,
        uint256 _chainId,
        string memory _wrappedGasTokenName,
        string memory _wrappedGasTokenSymbol,
        uint8 _wrappedGasTokenDecimals,
        address _newLocalBranchWrappedNativeTokenAddress,
        address _newUnderlyingBranchWrappedNativeTokenAddress
    ) external override onlyOwner {
        // Check if chain already added
        if (isChainId[_chainId]) revert AlreadyAddedChain();

        // Create new global token for new chain's wrapped native token
        address newGlobalToken = address(
            IERC20hTokenRootFactory(ICoreRootRouter(coreRootRouterAddress).hTokenFactoryAddress()).createToken(
                _wrappedGasTokenName, _wrappedGasTokenSymbol, _wrappedGasTokenDecimals
            )
        );

        // Sync new branch bridge agent with root core bridge agent
        IBridgeAgent(ICoreRootRouter(coreRootRouterAddress).bridgeAgentAddress()).syncBranchBridgeAgent(
            _coreBranchBridgeAgentAddress, _chainId
        );

        // Update State

        // 1. Add new chain to chainId mapping
        isChainId[_chainId] = true;
        // 2. Add new chain to global address mapping
        isGlobalAddress[newGlobalToken] = true;
        // 3. Add new branch local token to global token address mapping
        getGlobalTokenFromLocal[_newLocalBranchWrappedNativeTokenAddress][_chainId] = newGlobalToken;
        // 4. Add new global token to branch local token address mapping
        getLocalTokenFromGlobal[newGlobalToken][_chainId] = _newLocalBranchWrappedNativeTokenAddress;
        // 5. Add new branch underlying token to branch local token address mapping
        getLocalTokenFromUnderlying[_newUnderlyingBranchWrappedNativeTokenAddress][_chainId] =
            _newLocalBranchWrappedNativeTokenAddress;
        // 6. Add new branch local token to branch underlying token address mapping
        getUnderlyingTokenFromLocal[_newLocalBranchWrappedNativeTokenAddress][_chainId] =
            _newUnderlyingBranchWrappedNativeTokenAddress;

        emit NewChainAdded(_chainId);
    }

    /// @inheritdoc IRootPort
    function addEcosystemToken(address _ecoTokenGlobalAddress) external override onlyOwner {
        // Check if token already added as ecosystem token
        if (isGlobalAddress[_ecoTokenGlobalAddress]) revert AlreadyAddedEcosystemToken();

        // Check if token is an hToken
        if (getUnderlyingTokenFromLocal[_ecoTokenGlobalAddress][localChainId] != address(0)) {
            revert AlreadyAddedEcosystemToken();
        }

        // Check if token already added as underlying token
        address localTokenAddress = getLocalTokenFromUnderlying[_ecoTokenGlobalAddress][localChainId];
        if (localTokenAddress != address(0)) {
            // If there is a deposit of the underlying token, revert
            if (ERC20hToken(localTokenAddress).totalSupply() > 0) {
                revert AlreadyAddedEcosystemToken();
            } else {
                getUnderlyingTokenFromLocal[localTokenAddress][localChainId] = address(0);
                getLocalTokenFromUnderlying[_ecoTokenGlobalAddress][localChainId] = address(0);
            }
        }

        // Update State
        // 1. Add new global token to global address mapping
        isGlobalAddress[_ecoTokenGlobalAddress] = true;
        // 2. Add new branch local token address to global token mapping
        getGlobalTokenFromLocal[_ecoTokenGlobalAddress][localChainId] = _ecoTokenGlobalAddress;
        // 3. Add new global token to branch local token address mapping
        getLocalTokenFromGlobal[_ecoTokenGlobalAddress][localChainId] = _ecoTokenGlobalAddress;

        emit EcosystemTokenAdded(_ecoTokenGlobalAddress);
    }

    /// @inheritdoc IRootPort
    function setCoreRootRouter(address _coreRootRouter, address _coreRootBridgeAgent) external override onlyOwner {
        if (_coreRootRouter == address(0)) revert InvalidCoreRootRouter();
        if (_coreRootBridgeAgent == address(0)) revert InvalidCoreRootBridgeAgent();

        coreRootRouterAddress = _coreRootRouter;
        coreRootBridgeAgentAddress = _coreRootBridgeAgent;
        getBridgeAgentManager[_coreRootBridgeAgent] = owner();

        emit CoreRootSet(_coreRootRouter, _coreRootBridgeAgent);
    }

    /// @inheritdoc IRootPort
    function setCoreBranchRouter(
        address _refundee,
        address _coreBranchRouter,
        address _coreBranchBridgeAgent,
        uint16 _dstChainId,
        GasParams calldata _gParams
    ) external payable override onlyOwner {
        if (_coreBranchRouter == address(0)) revert InvalidCoreBranchRouter();
        if (_coreBranchBridgeAgent == address(0)) revert InvalidCoreBrancBridgeAgent();

        ICoreRootRouter(coreRootRouterAddress).setCoreBranch{value: msg.value}(
            _refundee, _coreBranchRouter, _coreBranchBridgeAgent, _dstChainId, _gParams
        );

        emit CoreBranchSet(_coreBranchRouter, _coreBranchBridgeAgent, _dstChainId);
    }

    /// @inheritdoc IRootPort
    function syncNewCoreBranchRouter(address _coreBranchRouter, address _coreBranchBridgeAgent, uint16 _dstChainId)
        external
        override
        onlyOwner
    {
        if (_coreBranchRouter == address(0)) revert InvalidCoreBranchRouter();
        if (_coreBranchBridgeAgent == address(0)) revert InvalidCoreBrancBridgeAgent();

        IBridgeAgent(coreRootBridgeAgentAddress).syncBranchBridgeAgent(_coreBranchBridgeAgent, _dstChainId);

        emit CoreBranchSynced(_coreBranchRouter, _coreBranchBridgeAgent, _dstChainId);
    }

    /// @inheritdoc IRootPort
    function sweep(address _recipient) external override onlyOwner {
        // Check if recipient is not zero address
        if (_recipient == address(0)) revert InvalidRecipientAddress();
        // Safe Transfer All ETH
        _recipient.safeTransferAllETH();
    }
    /*///////////////////////////////////////////////////////////////
                                MODIFIERS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Modifier that verifies global address is valid.
    modifier requiresGlobalAddress(address _globalAddress) {
        if (!isGlobalAddress[_globalAddress]) revert InvalidGlobalAddress();
        _;
    }

    /// @notice Modifier that verifies msg sender is an active Bridge Agent Factory.
    modifier requiresBridgeAgentFactory() {
        if (!isBridgeAgentFactory[msg.sender]) revert UnrecognizedBridgeAgentFactory();
        _;
    }

    /// @notice Modifier that verifies msg sender is an active Bridge Agent.
    modifier requiresBridgeAgent() {
        if (!isBridgeAgent[msg.sender]) revert UnrecognizedBridgeAgent();
        _;
    }

    /// @notice Modifier that verifies msg sender is the Root Chain's Core Router.
    modifier requiresCoreRootRouter() {
        if (msg.sender != coreRootRouterAddress) revert UnrecognizedCoreRootRouter();
        _;
    }

    /// @notice Modifier that verifies msg sender is the Root Chain's Local Branch Port.
    modifier requiresLocalBranchPort() {
        if (msg.sender != localBranchPortAddress) revert UnrecognizedLocalBranchPort();
        _;
    }
}

File 2 of 25 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 3 of 25 : ERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../IERC1155Receiver.sol";
import "../../../utils/introspection/ERC165.sol";

/**
 * @dev _Available since v3.1._
 */
abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
    }
}

File 4 of 25 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 5 of 25 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 6 of 25 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 7 of 25 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /// @dev Cannot double-initialize.
    error AlreadyInitialized();

    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    /// @dev The owner slot is given by:
    /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    bytes32 internal constant _OWNER_SLOT =
        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                if sload(ownerSlot) {
                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
                    revert(0x1c, 0x04)
                }
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(_OWNER_SLOT, newOwner)
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, newOwner)
            }
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(_OWNER_SLOT))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_OWNER_SLOT)
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                         MODIFIERS                          */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}

File 8 of 25 : LibZip.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for compressing and decompressing bytes.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibZip.sol)
/// @author Calldata compression by clabby (https://github.com/clabby/op-kompressor)
/// @author FastLZ by ariya (https://github.com/ariya/FastLZ)
///
/// @dev Note:
/// The accompanying solady.js library includes implementations of
/// FastLZ and calldata operations for convenience.
library LibZip {
    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                     FAST LZ OPERATIONS                     */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    // LZ77 implementation based on FastLZ.
    // Equivalent to level 1 compression and decompression at the following commit:
    // https://github.com/ariya/FastLZ/commit/344eb4025f9ae866ebf7a2ec48850f7113a97a42
    // Decompression is backwards compatible.

    /// @dev Returns the compressed `data`.
    function flzCompress(bytes memory data) internal pure returns (bytes memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            function ms8(d_, v_) -> _d {
                mstore8(d_, v_)
                _d := add(d_, 1)
            }
            function u24(p_) -> _u {
                let w := mload(p_)
                _u := or(shl(16, byte(2, w)), or(shl(8, byte(1, w)), byte(0, w)))
            }
            function cmp(p_, q_, e_) -> _l {
                for { e_ := sub(e_, q_) } lt(_l, e_) { _l := add(_l, 1) } {
                    e_ := mul(iszero(byte(0, xor(mload(add(p_, _l)), mload(add(q_, _l))))), e_)
                }
            }
            function literals(runs_, src_, dest_) -> _o {
                for { _o := dest_ } iszero(lt(runs_, 0x20)) { runs_ := sub(runs_, 0x20) } {
                    mstore(ms8(_o, 31), mload(src_))
                    _o := add(_o, 0x21)
                    src_ := add(src_, 0x20)
                }
                if iszero(runs_) { leave }
                mstore(ms8(_o, sub(runs_, 1)), mload(src_))
                _o := add(1, add(_o, runs_))
            }
            function match(l_, d_, o_) -> _o {
                for { d_ := sub(d_, 1) } iszero(lt(l_, 263)) { l_ := sub(l_, 262) } {
                    o_ := ms8(ms8(ms8(o_, add(224, shr(8, d_))), 253), and(0xff, d_))
                }
                if iszero(lt(l_, 7)) {
                    _o := ms8(ms8(ms8(o_, add(224, shr(8, d_))), sub(l_, 7)), and(0xff, d_))
                    leave
                }
                _o := ms8(ms8(o_, add(shl(5, l_), shr(8, d_))), and(0xff, d_))
            }
            function setHash(i_, v_) {
                let p := add(mload(0x40), shl(2, i_))
                mstore(p, xor(mload(p), shl(224, xor(shr(224, mload(p)), v_))))
            }
            function getHash(i_) -> _h {
                _h := shr(224, mload(add(mload(0x40), shl(2, i_))))
            }
            function hash(v_) -> _r {
                _r := and(shr(19, mul(2654435769, v_)), 0x1fff)
            }
            function setNextHash(ip_, ipStart_) -> _ip {
                setHash(hash(u24(ip_)), sub(ip_, ipStart_))
                _ip := add(ip_, 1)
            }
            codecopy(mload(0x40), codesize(), 0x8000) // Zeroize the hashmap.
            let op := add(mload(0x40), 0x8000)
            let a := add(data, 0x20)
            let ipStart := a
            let ipLimit := sub(add(ipStart, mload(data)), 13)
            for { let ip := add(2, a) } lt(ip, ipLimit) {} {
                let r := 0
                let d := 0
                for {} 1 {} {
                    let s := u24(ip)
                    let h := hash(s)
                    r := add(ipStart, getHash(h))
                    setHash(h, sub(ip, ipStart))
                    d := sub(ip, r)
                    if iszero(lt(ip, ipLimit)) { break }
                    ip := add(ip, 1)
                    if iszero(gt(d, 0x1fff)) { if eq(s, u24(r)) { break } }
                }
                if iszero(lt(ip, ipLimit)) { break }
                ip := sub(ip, 1)
                if gt(ip, a) { op := literals(sub(ip, a), a, op) }
                let l := cmp(add(r, 3), add(ip, 3), add(ipLimit, 9))
                op := match(l, d, op)
                ip := setNextHash(setNextHash(add(ip, l), ipStart), ipStart)
                a := ip
            }
            op := literals(sub(add(ipStart, mload(data)), a), a, op)
            result := mload(0x40)
            let t := add(result, 0x8000)
            let n := sub(op, t)
            mstore(result, n) // Store the length.
            // Copy the result to compact the memory, overwriting the hashmap.
            let o := add(result, 0x20)
            for { let i } lt(i, n) { i := add(i, 0x20) } { mstore(add(o, i), mload(add(t, i))) }
            mstore(add(o, n), 0) // Zeroize the slot after the string.
            mstore(0x40, add(add(o, n), 0x20)) // Allocate the memory.
        }
    }

    /// @dev Returns the decompressed `data`.
    function flzDecompress(bytes memory data) internal pure returns (bytes memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            let end := add(add(data, 0x20), mload(data))
            result := mload(0x40)
            let op := add(result, 0x20)
            for { data := add(data, 0x20) } lt(data, end) {} {
                let w := mload(data)
                let c := byte(0, w)
                let t := shr(5, c)
                if iszero(t) {
                    mstore(op, mload(add(data, 1)))
                    data := add(data, add(2, c))
                    op := add(op, add(1, c))
                    continue
                }
                let g := eq(t, 7)
                let l := add(2, xor(t, mul(g, xor(t, add(7, byte(1, w)))))) // M
                for {
                    let s := add(add(shl(8, and(0x1f, c)), byte(add(1, g), w)), 1) // R
                    let r := sub(op, s)
                    let f := xor(s, mul(gt(s, 0x20), xor(s, 0x20)))
                    let j := 0
                } 1 {} {
                    mstore(add(op, j), mload(add(r, j)))
                    j := add(j, f)
                    if iszero(lt(j, l)) { break }
                }
                data := add(data, add(2, g))
                op := add(op, l)
            }
            mstore(result, sub(op, add(result, 0x20))) // Store the length.
            mstore(op, 0) // Zeroize the slot after the string.
            mstore(0x40, add(op, 0x20)) // Allocate the memory.
        }
    }

    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                    CALLDATA OPERATIONS                     */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    // Calldata compression and decompression using selective run length encoding:
    // - Sequences of 0x00 (up to 128 consecutive).
    // - Sequences of 0xff (up to 32 consecutive).
    //
    // A run length encoded block consists of two bytes:
    // (0) 0x00
    // (1) A control byte with the following bit layout:
    //     - [7]     `0: 0x00, 1: 0xff`.
    //     - [0..6]  `runLength - 1`.
    //
    // The first 4 bytes are bitwise negated so that the compressed calldata
    // can be dispatched into the `fallback` and `receive` functions.

    /// @dev Returns the compressed `data`.
    function cdCompress(bytes memory data) internal pure returns (bytes memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            function rle(v_, o_, d_) -> _o, _d {
                mstore(o_, shl(240, or(and(0xff, add(d_, 0xff)), and(0x80, v_))))
                _o := add(o_, 2)
            }
            result := mload(0x40)
            let o := add(result, 0x20)
            let z := 0 // Number of consecutive 0x00.
            let y := 0 // Number of consecutive 0xff.
            for { let end := add(data, mload(data)) } iszero(eq(data, end)) {} {
                data := add(data, 1)
                let c := byte(31, mload(data))
                if iszero(c) {
                    if y { o, y := rle(0xff, o, y) }
                    z := add(z, 1)
                    if eq(z, 0x80) { o, z := rle(0x00, o, 0x80) }
                    continue
                }
                if eq(c, 0xff) {
                    if z { o, z := rle(0x00, o, z) }
                    y := add(y, 1)
                    if eq(y, 0x20) { o, y := rle(0xff, o, 0x20) }
                    continue
                }
                if y { o, y := rle(0xff, o, y) }
                if z { o, z := rle(0x00, o, z) }
                mstore8(o, c)
                o := add(o, 1)
            }
            if y { o, y := rle(0xff, o, y) }
            if z { o, z := rle(0x00, o, z) }
            // Bitwise negate the first 4 bytes.
            mstore(add(result, 4), not(mload(add(result, 4))))
            mstore(result, sub(o, add(result, 0x20))) // Store the length.
            mstore(o, 0) // Zeroize the slot after the string.
            mstore(0x40, add(o, 0x20)) // Allocate the memory.
        }
    }

    /// @dev Returns the decompressed `data`.
    function cdDecompress(bytes memory data) internal pure returns (bytes memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            if mload(data) {
                result := mload(0x40)
                let o := add(result, 0x20)
                let s := add(data, 4)
                let v := mload(s)
                let end := add(data, mload(data))
                mstore(s, not(v)) // Bitwise negate the first 4 bytes.
                for {} lt(data, end) {} {
                    data := add(data, 1)
                    let c := byte(31, mload(data))
                    if iszero(c) {
                        data := add(data, 1)
                        let d := byte(31, mload(data))
                        // Fill with either 0xff or 0x00.
                        mstore(o, not(0))
                        if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) }
                        o := add(o, add(and(d, 0x7f), 1))
                        continue
                    }
                    mstore8(o, c)
                    o := add(o, 1)
                }
                mstore(s, v) // Restore the first 4 bytes.
                mstore(result, sub(o, add(result, 0x20))) // Store the length.
                mstore(o, 0) // Zeroize the slot after the string.
                mstore(0x40, add(o, 0x20)) // Allocate the memory.
            }
        }
    }

    /// @dev To be called in the `fallback` function.
    /// ```
    ///     fallback() external payable { LibZip.cdFallback(); }
    ///     receive() external payable {} // Silence compiler warning to add a `receive` function.
    /// ```
    /// For efficiency, this function will directly return the results, terminating the context.
    /// If called internally, it must be called at the end of the function.
    function cdFallback() internal {
        assembly {
            if iszero(calldatasize()) { return(calldatasize(), calldatasize()) }
            let o := 0
            let f := not(3) // For negating the first 4 bytes.
            for { let i := 0 } lt(i, calldatasize()) {} {
                let c := byte(0, xor(add(i, f), calldataload(i)))
                i := add(i, 1)
                if iszero(c) {
                    let d := byte(0, xor(add(i, f), calldataload(i)))
                    i := add(i, 1)
                    // Fill with either 0xff or 0x00.
                    mstore(o, not(0))
                    if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) }
                    o := add(o, add(and(d, 0x7f), 1))
                    continue
                }
                mstore8(o, c)
                o := add(o, 1)
            }
            let success := delegatecall(gas(), address(), 0x00, o, codesize(), 0x00)
            returndatacopy(0x00, 0x00, returndatasize())
            if iszero(success) { revert(0x00, returndatasize()) }
            return(0x00, returndatasize())
        }
    }
}

File 9 of 25 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for
    /// the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                mstore(0x34, amount) // Store back the original `amount`.
                // Retry the approval, reverting upon failure.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul(
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }
}

File 10 of 25 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 11 of 25 : ERC721.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    event Approval(address indexed owner, address indexed spender, uint256 indexed id);

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /*//////////////////////////////////////////////////////////////
                         METADATA STORAGE/LOGIC
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*//////////////////////////////////////////////////////////////
                      ERC721 BALANCE/OWNER STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) internal _ownerOf;

    mapping(address => uint256) internal _balanceOf;

    function ownerOf(uint256 id) public view virtual returns (address owner) {
        require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
    }

    function balanceOf(address owner) public view virtual returns (uint256) {
        require(owner != address(0), "ZERO_ADDRESS");

        return _balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                         ERC721 APPROVAL STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*//////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = _ownerOf[id];

        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(from == _ownerOf[id], "WRONG_FROM");

        require(to != address(0), "INVALID_RECIPIENT");

        require(
            msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
            "NOT_AUTHORIZED"
        );

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            _balanceOf[from]--;

            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes calldata data
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(_ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        emit Transfer(address(0), to, id);
    }

    function _burn(uint256 id) internal virtual {
        address owner = _ownerOf[id];

        require(owner != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            _balanceOf[owner]--;
        }

        delete _ownerOf[id];

        delete getApproved[id];

        emit Transfer(owner, address(0), id);
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }
}

/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC721TokenReceiver.onERC721Received.selector;
    }
}

File 12 of 25 : ReentrancyGuard.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    uint256 private locked = 1;

    modifier nonReentrant() virtual {
        require(locked == 1, "REENTRANCY");

        locked = 2;

        _;

        locked = 1;
    }
}

File 13 of 25 : BridgeAgentStructs.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/*///////////////////////////////////////////////////////////////
                            STRUCTS
//////////////////////////////////////////////////////////////*/

/// @notice Struct for storing the gas parameters for a cross-chain call.
/// @param gasLimit gas units allocated for a cross-chain call execution.
/// @param remoteBranchExecutionGas native token amount to request for destiantion branch usage.
struct GasParams {
    uint256 gasLimit;
    uint256 remoteBranchExecutionGas;
}

/// @notice Struct for storing information about a deposit in a Branch Bridge Agent's state.
/// @param status status of the deposit. Has 3 states - ready, done, retrieve.
/// @param isSigned indicates if the deposit has been signed allowing Virtual Account usage.
/// @param owner owner of the deposit.
/// @param hTokens array of local hTokens addresses.
/// @param tokens array of underlying token addresses.
/// @param amounts array of total deposited amounts.
/// @param deposits array of underlying token deposited amounts.
struct Deposit {
    uint8 status;
    uint88 isSigned;
    address owner;
    address[] hTokens;
    address[] tokens;
    uint256[] amounts;
    uint256[] deposits;
}

/// @notice Struct for inputting deposit information into a Branch Bridge Agent.
/// @param hToken local hToken address.
/// @param token underlying token address.
/// @param amount total amount to deposit.
/// @param deposit underlying token amount to deposit.
struct DepositInput {
    address hToken;
    address token;
    uint256 amount;
    uint256 deposit;
}

/// @notice Struct for inputting multiple asset deposit information into a Branch Bridge Agent.
/// @param hTokens array of local hTokens addresses.
/// @param tokens array of underlying token addresses.
/// @param amounts array of total amounts to deposit.
/// @param deposits array of underlying token amounts to deposit.
struct DepositMultipleInput {
    address[] hTokens;
    address[] tokens;
    uint256[] amounts;
    uint256[] deposits;
}

/// @notice Struct for encoding deposit information in a cross-chain message.
/// @param depositNonce deposit nonce.
/// @param hToken local hToken address.
/// @param token underlying token address.
/// @param amount total amount to deposit.
/// @param deposit underlying token amount to deposit.
struct DepositParams {
    uint32 depositNonce;
    address hToken;
    address token;
    uint256 amount;
    uint256 deposit;
}

/// @notice Struct for encoding multiple asset deposit information in a cross-chain message.
/// @param numberOfAssets number of assets to deposit.
/// @param depositNonce deposit nonce.
/// @param hTokens array of local hTokens addresses.
/// @param tokens array of underlying token addresses.
/// @param amounts array of total amounts to deposit.
/// @param deposits array of underlying token amounts to deposit.
struct DepositMultipleParams {
    uint8 numberOfAssets;
    uint32 depositNonce;
    address[] hTokens;
    address[] tokens;
    uint256[] amounts;
    uint256[] deposits;
}

/// @notice Struct for storing information about a settlement in a Root Bridge Agent's state.
/// @param dstChainId destination chain for interaction.
/// @param status status of the settlement.
/// @param owner owner of the settlement.
/// @param recipient recipient of the settlement.
/// @param hTokens array of global hTokens addresses.
/// @param tokens array of underlying token addresses.
/// @param amounts array of total settled amounts.
/// @param deposits array of underlying token settled amounts.
struct Settlement {
    uint16 dstChainId;
    uint80 status;
    address owner;
    address recipient;
    address[] hTokens;
    address[] tokens;
    uint256[] amounts;
    uint256[] deposits;
}

/// @notice Struct for inputting token settlement information into a Root Bridge Agent.
/// @param globalAddress global hToken address.
/// @param amount total amount to settle.
/// @param deposit underlying token amount to settle.
struct SettlementInput {
    address globalAddress;
    uint256 amount;
    uint256 deposit;
}

/// @notice Struct for inputting multiple asset settlement information into a Root Bridge Agent.
/// @param globalAddresses array of global hTokens addresses.
/// @param amounts array of total amounts to settle.
/// @param deposits array of underlying token amounts to settle.

struct SettlementMultipleInput {
    address[] globalAddresses;
    uint256[] amounts;
    uint256[] deposits;
}

/// @notice Struct for encoding settlement information in a cross-chain message.
/// @param settlementNonce settlement nonce.
/// @param recipient recipient of the settlement.
/// @param hToken destination local hToken address.
/// @param token destination underlying token address.
/// @param amount total amount to settle.
/// @param deposit underlying token amount to settle.
struct SettlementParams {
    uint32 settlementNonce;
    address recipient;
    address hToken;
    address token;
    uint256 amount;
    uint256 deposit;
}

/// @notice Struct for encoding multiple asset settlement information in a cross-chain message.
/// @param numberOfAssets number of assets to settle.
/// @param recipient recipient of the settlement.
/// @param settlementNonce settlement nonce.
/// @param hTokens array of destination local hTokens addresses.
/// @param tokens array of destination underlying token addresses.
/// @param amounts array of total amounts to settle.
/// @param deposits array of underlying token amounts to settle.
struct SettlementMultipleParams {
    uint8 numberOfAssets;
    address recipient;
    uint32 settlementNonce;
    address[] hTokens;
    address[] tokens;
    uint256[] amounts;
    uint256[] deposits;
}

File 14 of 25 : IBranchBridgeAgent.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {
    GasParams,
    Deposit,
    DepositInput,
    DepositMultipleInput,
    DepositParams,
    DepositMultipleParams,
    SettlementParams,
    SettlementMultipleParams
} from "./BridgeAgentStructs.sol";
import {ILayerZeroReceiver} from "./ILayerZeroReceiver.sol";

/**
 * @title  Branch Bridge Agent Contract
 * @author MaiaDAO
 * @notice Contract for deployment in Branch Chains of Omnichain System, responsible for interfacing with
 *         Users and Routers acting as a middleman to access LayerZero cross-chain messaging and requesting/depositing
 *         assets in the Branch Chain's Ports.
 * @dev    Bridge Agents allow for the encapsulation of business logic as well as standardize cross-chain communication,
 *         allowing for the creation of custom Routers to perform actions in response to local / remote user requests.
 *         This contract is designed for deployment in the Branch Chains of the Ulysses Omnichain Liquidity System.
 *         The Branch Bridge Agent is responsible for sending/receiving requests to/from the LayerZero Messaging Layer
 *         for execution, as well as requests tokens clearances and tx execution to the `BranchBridgeAgentExecutor`.
 *         Remote execution is "sandboxed" within 2 different layers/nestings:
 *         - 1: Upon receiving a request from LayerZero Messaging Layer to avoid blocking future requests due to
 *              execution reversion, ensuring our app is Non-Blocking.
 *              (See https://github.com/LayerZero-Labs/solidity-examples/blob/8e62ebc886407aafc89dbd2a778e61b7c0a25ca0/contracts/lzApp/NonblockingLzApp.sol)
 *         - 2: The call to `BranchBridgeAgentExecutor` is in charge of requesting token deposits for each remote
 *              interaction as well as performing the Router calls, if any of the calls initiated by the Router lead
 *              to an invalid state change both the token deposit clearances as well as the external interactions
 *              will be reverted and caught by the `BranchBridgeAgent`.
 *
 *         **BRANCH BRIDGE AGENT SETTLEMENT FLAGs** Func IDs for calling these functions through the messaging layer
 *
 *         | ID   | DESCRIPTION                                                                                       |
 *         | ---- | ------------------------------------------------------------------------------------------------- |
 *         | 0x01 | Call to Branch without Settlement.                                                                |
 *         | 0x02 | Call to Branch with Settlement.                                                                   |
 *         | 0x03 | Call to Branch with Settlement of Multiple Tokens.                                                |
 *         | 0x04 | Call to `retrieveSettlement()`. (trigger `_fallback` for a settlement that has not been executed) |
 *         | 0x05 | Call to `_fallback()`. (reopens a deposit for asset redemption)                                   |
 *
 *         Encoding Scheme for different Root Bridge Agent Deposit Flags:
 *
 *           - ht = hToken
 *           - t = Token
 *           - A = Amount
 *           - D = Deposit
 *           - b = bytes
 *           - n = number of assets
 *
 *         | Flag   | Deposit Info                | Token Info              | DATA |
 *         | ------ | --------------------------- | ----------------------- | ---- |
 *         | 1 byte | 4-25 bytes                  | 104 or (128 * n) bytes  |      |
 *         |        |                             | hT - t - A - D          | ...  |
 *         | 0x1    | 20b(recipient) + 4b(nonce)  |          ---            | ...  |
 *         | 0x2    | 20b(recipient) + 4b(nonce)  | 20b + 20b + 32b + 32b   | ...  |
 *         | 0x3    | 1b(n) + 20b(recipient) + 4b | 32b + 32b + 32b + 32b   | ...  |
 *
 *         **Generic Contract Interaction Flow:**
 *         BridgeAgent.lzReceive() -> BridgeAgentExecutor.execute() -> Router.execute()
 *
 */
interface IBranchBridgeAgent is ILayerZeroReceiver {
    /*///////////////////////////////////////////////////////////////
                        VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice External function to return the Branch Chain's Local Port Address.
     * @return address of the Branch Chain's Local Port.
     */
    function localPortAddress() external view returns (address);

    /**
     * @notice External function to return the Branch Bridge Agent Executor Address.
     * @return address of the Branch Bridge Agent Executor.
     */
    function bridgeAgentExecutorAddress() external view returns (address);

    /**
     * @notice External function that returns a given deposit entry.
     *  @param depositNonce Identifier for user deposit.
     */
    function getDepositEntry(uint32 depositNonce) external view returns (Deposit memory);

    /*///////////////////////////////////////////////////////////////
                    USER AND BRANCH ROUTER FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Function to perform a call to the Root Omnichain Router without token deposit.
     *  @param gasRefundee Address to return excess gas deposited in `msg.value` to.
     *  @param params enconded parameters to execute on the root chain router.
     *  @param gasParams gas parameters for the cross-chain call.
     *  @dev DEPOSIT ID: 1 (Call without deposit)
     */
    function callOut(address payable gasRefundee, bytes calldata params, GasParams calldata gasParams)
        external
        payable;

    /**
     * @notice Function to perform a call to the Root Omnichain Router while depositing a single asset.
     *  @param depositOwnerAndGasRefundee Deposit owner and address to return excess gas deposited in `msg.value` to.
     *  @param params enconded parameters to execute on the root chain router.
     *  @param depositParams additional token deposit parameters.
     *  @param gasParams gas parameters for the cross-chain call.
     *  @dev DEPOSIT ID: 2 (Call with single deposit)
     */
    function callOutAndBridge(
        address payable depositOwnerAndGasRefundee,
        bytes calldata params,
        DepositInput memory depositParams,
        GasParams calldata gasParams
    ) external payable;

    /**
     * @notice Function to perform a call to the Root Omnichain Router while depositing two or more assets.
     *  @param depositOwnerAndGasRefundee Deposit owner and address to return excess gas deposited in `msg.value` to.
     *  @param params enconded parameters to execute on the root chain router.
     *  @param depositParams additional token deposit parameters.
     *  @param gasParams gas parameters for the cross-chain call.
     *  @dev DEPOSIT ID: 3 (Call with multiple deposit)
     */
    function callOutAndBridgeMultiple(
        address payable depositOwnerAndGasRefundee,
        bytes calldata params,
        DepositMultipleInput memory depositParams,
        GasParams calldata gasParams
    ) external payable;

    /**
     * @notice Perform a call to the Root Omnichain Router without token deposit with msg.sender information.
     *  @dev msg.sender is gasRefundee in signed calls.
     *  @param params enconded parameters to execute on the root chain router.
     *  @param gasParams gas parameters for the cross-chain call.
     *  @dev DEPOSIT ID: 4 (Call without deposit and verified sender)
     */
    function callOutSigned(bytes calldata params, GasParams calldata gasParams) external payable;

    /**
     * @notice Function to perform a call to the Root Omnichain Router while depositing a single asset msg.sender.
     *  @dev msg.sender is depositOwnerAndGasRefundee in signed calls.
     *  @param params enconded parameters to execute on the root chain router.
     *  @param depositParams additional token deposit parameters.
     *  @param gasParams gas parameters for the cross-chain call.
     *  @param hasFallbackToggled flag to indicate if the fallback function was toggled.
     *  @dev DEPOSIT ID: 5 (Call with single deposit and verified sender)
     */
    function callOutSignedAndBridge(
        bytes calldata params,
        DepositInput memory depositParams,
        GasParams calldata gasParams,
        bool hasFallbackToggled
    ) external payable;

    /**
     * @notice Function to perform a call to the Root Omnichain Router while
     *         depositing two or more assets with msg.sender.
     *  @dev msg.sender is depositOwnerAndGasRefundee in signed calls.
     *  @param params enconded parameters to execute on the root chain router.
     *  @param depositParams additional token deposit parameters.
     *  @param gasParams gas parameters for the cross-chain call.
     *  @param hasFallbackToggled flag to indicate if the fallback function was toggled.
     *  @dev DEPOSIT ID: 6 (Call with multiple deposit and verified sender)
     */
    function callOutSignedAndBridgeMultiple(
        bytes calldata params,
        DepositMultipleInput memory depositParams,
        GasParams calldata gasParams,
        bool hasFallbackToggled
    ) external payable;

    /*///////////////////////////////////////////////////////////////
                    DEPOSIT EXTERNAL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Function to perform a call to the Root Omnichain Environment
     *         retrying a failed non-signed deposit that hasn't been executed yet.
     *  @param owner address of the deposit owner.
     *  @param depositNonce Identifier for user deposit.
     *  @param params parameters to execute on the root chain router.
     *  @param gasParams gas parameters for the cross-chain call.
     */
    function retryDeposit(address owner, uint32 depositNonce, bytes calldata params, GasParams calldata gasParams)
        external
        payable;

    /**
     * @notice Function to perform a call to the Root Omnichain Environment
     *         retrying a failed signed deposit that hasn't been executed yet.
     *  @param depositNonce Identifier for user deposit.
     *  @param params parameters to execute on the root chain router.
     *  @param gasParams gas parameters for the cross-chain call.
     *  @param hasFallbackToggled flag to indicate if the fallback function was toggled.
     */
    function retryDepositSigned(
        uint32 depositNonce,
        bytes calldata params,
        GasParams calldata gasParams,
        bool hasFallbackToggled
    ) external payable;

    /**
     * @notice External function to request tokens back to branch chain after failing omnichain environment interaction.
     *  @param depositNonce Identifier for user deposit to retrieve.
     *  @param gasParams gas parameters for the cross-chain call.
     *  @dev DEPOSIT ID: 8
     */
    function retrieveDeposit(uint32 depositNonce, GasParams calldata gasParams) external payable;

    /**
     * @notice External function to retry a failed Deposit entry on this branch chain.
     *  @param depositNonce Identifier for user deposit.
     *  @param recipient address to receive the redeemed tokens.
     */
    function redeemDeposit(uint32 depositNonce, address recipient) external;

    /**
     * @notice External function to retry a failed Deposit entry on this branch chain.
     *  @param depositNonce Identifier for user deposit.
     *  @param recipient address to receive the redeemed tokens.
     *  @param localTokenAddress address of the local token to redeem.
     */
    function redeemDeposit(uint32 depositNonce, address recipient, address localTokenAddress) external;

    /*///////////////////////////////////////////////////////////////
                    SETTLEMENT EXTERNAL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice External function to retry a failed Settlement entry on the root chain.
     *  @param settlementNonce Identifier for user settlement.
     *  @param params parameters to execute on the root chain router.
     *  @param gasParams gas parameters for the cross-chain call to root chain and for the settlement to branch.
     *  @param hasFallbackToggled flag to indicate if the fallback function should be toggled.
     *  @dev DEPOSIT ID: 7
     */
    function retrySettlement(
        uint32 settlementNonce,
        bytes calldata params,
        GasParams[2] calldata gasParams,
        bool hasFallbackToggled
    ) external payable;

    /*///////////////////////////////////////////////////////////////
                    TOKEN MANAGEMENT EXTERNAL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Function to request balance clearance from a Port to a given user.
     *  @param recipient token receiver.
     *  @param hToken  local hToken addresse to clear balance for.
     *  @param token  native / underlying token addresse to clear balance for.
     *  @param amount amounts of token to clear balance for.
     *  @param deposit amount of native / underlying tokens to clear balance for.
     */
    function bridgeIn(address recipient, address hToken, address token, uint256 amount, uint256 deposit) external;

    /**
     * @notice Function to request balance clearance from a Port to a given address.
     *  @param recipient token receiver.
     *  @param sParams encode packed multiple settlement info.
     */
    function bridgeInMultiple(address recipient, SettlementMultipleParams calldata sParams) external;

    /*///////////////////////////////////////////////////////////////
                                EVENTS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Event emitted when a deposit is successfully and fully redeemed.
    /// @param depositNonce Identifier for user deposit.
    /// @param recipient address to receive the redeemed tokens.
    event RedeemDeposit(uint256 indexed depositNonce, address indexed recipient);

    /// @notice Event emitted when a single token is redeemed from a deposit and there are other tokens left to redeem.
    /// @param depositNonce Identifier for user deposit.
    /// @param recipient address to receive the redeemed tokens.
    /// @param localTokenAddress address of the local token to redeem.
    event RedeemDeposit(uint256 indexed depositNonce, address indexed recipient, address indexed localTokenAddress);

    /// @notice Event emitted when a settlement nonce is executed successfully.
    /// @param nonce Identifier for user settlement.
    event LogExecute(uint256 indexed nonce);

    /// @notice Event emitted when fallback is received for a failed deposit nonce.
    /// @param nonce Identifier for user deposit.
    event LogFallback(uint256 indexed nonce);

    /// @notice Event emitted after a message is sent to the Layer Zero Endpoint.
    /// @param gasLimit gas limit for the cross-chain call.
    /// @param remoteBranchExecutionGas native gas tokens to be sent to the remote branch.
    event LogGasParams(uint256 indexed gasLimit, uint256 indexed remoteBranchExecutionGas);

    /*///////////////////////////////////////////////////////////////
                                ERRORS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Error emitted when the provided Root Bridge Agent Address is invalid.
    error InvalidRootBridgeAgentAddress();
    /// @notice Error emitted when the provided Branch Port Address is invalid.
    error InvalidBranchPortAddress();
    /// @notice Error emitted when the provided Layer Zero Endpoint Address is invalid.
    error InvalidEndpointAddress();

    /// @notice Error emitted when the Branch Bridge Agent does not recognize the action flag.
    error UnknownFlag();
    /// @notice Error emitted when a settlement nonce fails to execute and does not have fallback enabled.
    error ExecutionFailure();

    /// @notice Error emitted when a Layer Zero remote caller in not recognized as the Root Bridge Agent.
    error LayerZeroUnauthorizedCaller();
    /// @notice Error emitted when the caller is not the local Layer Zero Endpoint contract.
    error LayerZeroUnauthorizedEndpoint();

    /// @notice Error emitted when the settlement nonce has already been executed.
    error AlreadyExecutedTransaction();

    /// @notice Error emitted when the local hToken address is zero.
    error InvalidLocalAddress();
    /// @notice Error emitted when the deposit information is not valid.
    error InvalidInput();

    /// @notice Error emitted when the the wrong retryDeposit function for a deposit type (Signed or Unsigned).
    error WrongDepositType();
    /// @notice Error emitted when caller is not the deposit owner.
    error NotDepositOwner();
    /// @notice Error emitted when the action of deposit nonce is not retryabable.
    error DepositRetryUnavailableUseCallout();
    /// @notice Error emitted when the deposit nonce is not in a redeemable state.
    error DepositRedeemUnavailable();
    /// @notice Error emitted when the deposit nonce is not in a retryable state.
    error DepositAlreadyRetrieved();

    /// @notice Error emitted when the caller is not the Branch Bridge Agent's Router
    error UnrecognizedRouter();
    /// @notice Error emitted when the caller is not the Branch Bridge Agent's Executors
    error UnrecognizedBridgeAgentExecutor();
}

File 15 of 25 : ICoreRootRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {GasParams} from "./IBranchBridgeAgent.sol";

import {IRootRouter} from "./IRootRouter.sol";

/**
 * @title  Core Root Router Contract
 * @author MaiaDAO
 * @notice Core Root Router implementation for deployment in the Root Chain.
 *         This contract is allows users to permissionlessly add new tokens
 *         or Bridge Agents to the system. As well as executes key governance
 *         enabled system functions (i.e. `addBridgeAgentFactory`).
 * @dev    Func IDs for calling these functions through messaging layer:
 *
 *         **CROSS-CHAIN MESSAGING FUNCIDs**
 *
 *         | FUNC ID | FUNC NAME                      |
 *         | ------- | ------------------------------ |
 *         | 0x01    | addGlobalToken                 |
 *         | 0x02    | addLocalToken                  |
 *         | 0x03    | setLocalToken                  |
 *         | 0x04    | syncBranchBridgeAgent          |
 */
interface ICoreRootRouter is IRootRouter {
    /*///////////////////////////////////////////////////////////////
                              VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Root Chain Layer Zero Identifier.
    function rootChainId() external view returns (uint256);

    /// @notice Address for Local Port Address where funds deposited from this chain are kept
    ///         managed and supplied to different Port Strategies.
    function rootPortAddress() external view returns (address);

    /// @notice Bridge Agent to manage remote execution and cross-chain assets.
    function bridgeAgentAddress() external view returns (address payable);

    /// @notice Bridge Agent Executor Address.
    function bridgeAgentExecutorAddress() external view returns (address);

    /// @notice ERC20 hToken Root Factory Address.
    function hTokenFactoryAddress() external view returns (address);

    /*///////////////////////////////////////////////////////////////
                    BRIDGE AGENT MANAGEMENT FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Add a new Chain (Branch Bridge Agent and respective Router) to a Root Bridge Agent.
     * @param _branchBridgeAgentFactory Address of the branch Bridge Agent Factory.
     * @param _newBranchRouter Address of the new branch router.
     * @param _refundee Address of the excess gas receiver.
     * @param _dstChainId Chain Id of the branch chain where the new Bridge Agent will be deployed.
     * @param _gParams Gas parameters for remote execution.
     */
    function addBranchToBridgeAgent(
        address _rootBridgeAgent,
        address _branchBridgeAgentFactory,
        address _newBranchRouter,
        address _refundee,
        uint16 _dstChainId,
        GasParams[2] calldata _gParams
    ) external payable;

    /*///////////////////////////////////////////////////////////////
                GOVERNANCE / ADMIN EXTERNAL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Add or Remove a Branch Bridge Agent Factory.
     * @param _rootBridgeAgentFactory Address of the root Bridge Agent Factory.
     * @param _branchBridgeAgentFactory Address of the branch Bridge Agent Factory.
     * @param _refundee Receiver of any leftover execution gas upon reaching the destination network.
     * @param _dstChainId Chain Id of the branch chain where the new Bridge Agent will be deployed.
     * @param _gParams Gas parameters for remote execution.
     */
    function toggleBranchBridgeAgentFactory(
        address _rootBridgeAgentFactory,
        address _branchBridgeAgentFactory,
        address _refundee,
        uint16 _dstChainId,
        GasParams calldata _gParams
    ) external payable;

    /**
     * @notice Add or Remove a Strategy Token.
     * @param _underlyingToken Address of the underlying token to be added for use in Branch strategies.
     * @param _minimumReservesRatio Minimum Branch Port reserves ratio for the underlying token.
     * @dev Must be between 7000 and 9999 (70% and 99.99%). Can be any value if the token is being de-activated.
     * @param _refundee Receiver of any leftover execution gas upon reaching destination network.
     * @param _dstChainId Chain Id of the branch chain where the new Bridge Agent will be deployed.
     * @param _gParams Gas parameters for remote execution.
     */
    function toggleStrategyToken(
        address _underlyingToken,
        uint256 _minimumReservesRatio,
        address _refundee,
        uint16 _dstChainId,
        GasParams calldata _gParams
    ) external payable;

    /**
     * @notice Update an active Strategy Token's minimum reserves ratio.
     * @param _underlyingToken Address of the underlying token to be added for use in Branch strategies.
     * @param _minimumReservesRatio Minimum Branch Port reserves ratio for the underlying token.
     * @param _refundee Receiver of any leftover execution gas upon reaching destination network.
     * @param _dstChainId Chain Id of the branch chain where the new Bridge Agent will be deployed.
     * @param _gParams Gas parameters for remote execution.
     */
    function updateStrategyToken(
        address _underlyingToken,
        uint256 _minimumReservesRatio,
        address _refundee,
        uint16 _dstChainId,
        GasParams calldata _gParams
    ) external payable;

    /**
     * @notice Add or Remove a Port Strategy.
     * @param _portStrategy Address of the Port Strategy to be added for use in Branch strategies.
     * @param _underlyingToken Address of the underlying token to be added for use in Branch strategies.
     * @param _dailyManagementLimit Daily management limit of the given token for the Port Strategy.
     * @param _reserveRatioManagementLimit Total reserves management limit of the given token for the Port Strategy.
     * @param _refundee Receiver of any leftover execution gas upon reaching destination network.
     * @param _dstChainId Chain Id of the branch chain where the new Bridge Agent will be deployed.
     * @param _gParams Gas parameters for remote execution.
     */
    function togglePortStrategy(
        address _portStrategy,
        address _underlyingToken,
        uint256 _dailyManagementLimit,
        uint256 _reserveRatioManagementLimit,
        address _refundee,
        uint16 _dstChainId,
        GasParams calldata _gParams
    ) external payable;

    /**
     * @notice Update a Port Strategy.
     * @param _portStrategy Address of the Port Strategy to be added for use in Branch strategies.
     * @param _underlyingToken Address of the underlying token to be added for use in Branch strategies.
     * @param _dailyManagementLimit Daily management limit of the given token for the Port Strategy.
     * @param _reserveRatioManagementLimit Total reserves management limit of the given token for the Port Strategy.
     * @param _refundee Receiver of any leftover execution gas upon reaching destination network.
     * @param _dstChainId Chain Id of the branch chain where the new Bridge Agent will be deployed.
     * @param _gParams Gas parameters for remote execution.
     */
    function updatePortStrategy(
        address _portStrategy,
        address _underlyingToken,
        uint256 _dailyManagementLimit,
        uint256 _reserveRatioManagementLimit,
        address _refundee,
        uint16 _dstChainId,
        GasParams calldata _gParams
    ) external payable;

    /**
     * @notice Set the Core Branch Router and Bridge Agent.
     * @param _refundee Receiver of any leftover execution gas upon reaching destination network.
     * @param _coreBranchRouter Address of the Core Branch Router.
     * @param _coreBranchBridgeAgent Address of the Core Branch Bridge Agent.
     * @param _dstChainId Chain Id of the branch chain where the new Bridge Agent will be deployed.
     * @param _gParams Gas parameters for remote execution.
     */
    function setCoreBranch(
        address _refundee,
        address _coreBranchRouter,
        address _coreBranchBridgeAgent,
        uint16 _dstChainId,
        GasParams calldata _gParams
    ) external payable;

    /**
     * @notice Allows governance to claim any native tokens accumulated from failed transactions.
     *  @param _refundee Receiver of any excess msg.value sent to Layer Zero on source chain.
     *  @param _recipient address to transfer ETH to on destination chain.
     *  @param _gParams gasParameters for remote execution
     */
    function sweep(address _refundee, address _recipient, uint16 _dstChainId, GasParams calldata _gParams)
        external
        payable;

    /*///////////////////////////////////////////////////////////////
                                ERRORS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Error emitted when an invalid chain id is provided.
    error InvalidChainId();

    /// @notice Error emitted when a chain id not approved by the Bridge Agent Manager is provided for chain addition.
    error UnauthorizedChainId();

    /// @notice Error emitted when the caller is not the Bridge Agent Manager.
    error UnauthorizedCallerNotManager();

    /// @notice Error emitted when the global token has already been added to a given chain.
    error TokenAlreadyAdded();

    /// @notice Error emitted when the provided token is not recognized as a global token.
    error UnrecognizedGlobalToken();

    /// @notice Error emitted when the caller is not the Bridge Agent Factory.
    error UnrecognizedBridgeAgentFactory();
}

File 16 of 25 : IERC20hToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title  ERC20 hToken Branch Contract
 * @author MaiaDAO.
 * @notice ERC20 hToken contract deployed with the Ulysses Omnichain Liquidity System.
 *         ERC20 representation of a token deposited in a  Branch Chain's Port.
 * @dev    If this is a root hToken, this asset is minted / burned in reflection of it's origin Branch Port balance.
 *         Should not be burned being stored in Root Port instead if Branch hToken mint is requested.
 */
interface IERC20hToken {
    /*///////////////////////////////////////////////////////////////
                                ERC20 LOGIC
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Function to mint tokens.
     * @param account Address of the account to receive the tokens.
     * @param amount Amount of tokens to be minted.
     */
    function mint(address account, uint256 amount) external;

    /**
     * @notice Function to burn tokens.
     * @param account Address of the account to burn the tokens from.
     * @param amount Amount of tokens to be burned.
     */
    function burn(address account, uint256 amount) external;

    /*///////////////////////////////////////////////////////////////
                                  ERRORS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Error thrown when the Port Address is the zero address.
    error InvalidPortAddress();
}

File 17 of 25 : IERC20hTokenRootFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {ERC20hToken} from "../token/ERC20hToken.sol";

/**
 * @title  Factory Contract for Root hTokens
 * @author MaiaDAO
 * @notice Factory contract allowing for permissionless deployment of new Root hTokens in the
 *  	   Root Chain of Ulysses Omnichain Liquidity Protocol.
 * @dev    This contract is called by the chain's Core Root Router.
 */
interface IERC20hTokenRootFactory {
    /*///////////////////////////////////////////////////////////////
                            hTOKEN FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Function to create a new hToken.
     * @param _name Name of the Token.
     * @param _symbol Symbol of the Token.
     * @param _decimals Decimals of the Token.
     */
    function createToken(string memory _name, string memory _symbol, uint8 _decimals)
        external
        returns (ERC20hToken newToken);

    /*///////////////////////////////////////////////////////////////
                                ERRORS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Error emitted when caller is not the Core Root Router nor the Root Port.
    error UnrecognizedCoreRouterOrPort();
}

File 18 of 25 : ILayerZeroReceiver.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

interface ILayerZeroReceiver {
    /*///////////////////////////////////////////////////////////////
                            LAYER ZERO FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice LayerZero endpoint will invoke this function to deliver the message on the destination
     *  @param _srcChainId the source endpoint identifier
     *  @param _srcAddress the source sending contract address from the source chain
     *  @param _nonce the ordered message nonce
     *  @param _payload the signed payload is the UA bytes has encoded to be sent
     */
    function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload)
        external
        payable
        returns (bool);

    /**
     * @notice External function to receive cross-chain messages from LayerZero Endpoint Contract without blocking.
     *  @param _endpoint address of the LayerZero Endpoint Contract.
     *  @param _srcAddress address path of the recipient + sender.
     *  @param _payload Calldata for function call.
     */
    function lzReceiveNonBlocking(
        address _endpoint,
        uint16 _srcChainId,
        bytes calldata _srcAddress,
        bytes calldata _payload
    ) external payable;

    /**
     * @notice Only when the BridgeAgent needs to resume the message flow in blocking mode and clear the stored payload.
     *  @param _srcChainId the chainId of the source chain
     *  @param _srcAddress the contract address of the source contract at the source chain
     */
    function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}

File 19 of 25 : IRootBridgeAgent.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {
    GasParams,
    DepositParams,
    DepositMultipleParams,
    Settlement,
    SettlementInput,
    SettlementMultipleInput,
    SettlementParams
} from "./BridgeAgentStructs.sol";

import {ILayerZeroReceiver} from "./ILayerZeroReceiver.sol";

/*///////////////////////////////////////////////////////////////
                            ENUMS
//////////////////////////////////////////////////////////////*/

/**
 * @title  Root Bridge Agent Contract
 * @author MaiaDAO
 * @notice Contract responsible for interfacing with Users and Routers acting as a middleman to
 *         access LayerZero cross-chain messaging and Port communication for asset management.
 * @dev    Bridge Agents allow for the encapsulation of business logic as well as the standardized
 *         cross-chain communication, allowing for the creation of custom Routers to perform
 *         actions as a response to remote user requests. This contract is for deployment in the Root
 *         Chain Omnichain Environment based on Arbitrum.
 *         The Root Bridge Agent is responsible for sending/receiving requests to/from the LayerZero Messaging Layer for
 *         execution, as well as requests tokens clearances and tx execution from the `RootBridgeAgentExecutor`.
 *         Remote execution is "sandboxed" within 2 different layers/nestings:
 *         - 1: Upon receiving a request from LayerZero Messaging Layer to avoid blocking future requests due
 *              to execution reversion, ensuring our app is Non-Blocking.
 *              (See https://github.com/LayerZero-Labs/solidity-examples/blob/8e62ebc886407aafc89dbd2a778e61b7c0a25ca0/contracts/lzApp/NonblockingLzApp.sol)
 *         - 2: The call to `RootBridgeAgentExecutor` is in charge of requesting token deposits for each
 *              remote interaction as well as performing the Router calls if any of the calls initiated
 *              by the Router led to an invalid state change in both the token deposit clearances as well as
 *              the external interactions will be reverted and caught by the `RootBridgeAgent`.
 *
 *         **ROOT BRIDGE AGENT DEPOSIT FLAGS** Func IDs for calling these  functions through the messaging layer
 *
 *         | ID   | DESCRIPTION                                                                                           |
 *         |------|-------------------------------------------------------------------------------------------------------|
 *         | 0x01 | Call to Root Router without Deposit.                                                                  |
 *         | 0x02 | Call to Root Router with Deposit.                                                                     |
 *         | 0x03 | Call to Root Router with Deposit of Multiple Tokens.                                                  |
 *         | 0x04 | Call to Root Router without Deposit + signed message.                                                 |
 *         | 0x05 | Call to Root Router with Deposit + signed message.                                                    |
 *         | 0x06 | Call to Root Router with Deposit of Multiple Tokens + signed message.                                 |
 *         | 0x07 | Call to `retrySettlement()`. (retries sending a settlement w/ new calldata for execution + new gas)   |
 *         | 0x08 | Call to `retrieveDeposit()`. (clears a deposit that has not been executed yet triggering `_fallback`) |
 *         | 0x09 | Call to `_fallback()`. (reopens a settlement for asset redemption)                                    |
 *
 *
 *            Encoding Scheme for different Root Bridge Agent Deposit Flags:
 *
 *             - ht = hToken
 *             - t = Token
 *             - A = Amount
 *             - D = Deposit
 *             - b = bytes
 *             - n = number of assets
 *
 *         |            Flag               |        Deposit Info        |             Token Info             |   DATA   |
 *         |-------------------------------|----------------------------|------------------------------------|----------|
 *         |           1 byte              |         4-25 bytes         |       104 or (128 * n) bytes       |   ...	|
 *         |                               |                            |           hT - t - A - D           |          |
 *         | callOut = 0x01                |                 4b(nonce)  |                 ---                |   ...	|
 *         | callOutSingle = 0x02          |                 4b(nonce)  |        20b + 20b + 32b + 32b       |   ...	|
 *         | callOutMulti = 0x03           |         1b(n) + 4b(nonce)  |   	  32b + 32b + 32b + 32b      |   ...	|
 *         | callOutSigned = 0x04          |    20b(recip) + 4b(nonce)  |   	          ---                |   ...    |
 *         | callOutSignedSingle = 0x05    |           20b + 4b(nonce)  |        20b + 20b + 32b + 32b       |   ...	|
 *         | callOutSignedMultiple = 0x06  |   20b + 1b(n) + 4b(nonce)  |        32b + 32b + 32b + 32b       |   ...	|
 *
 *         **Generic Contract Interaction Flow:**
 *         BridgeAgent.lzReceive() -> BridgeAgentExecutor.execute() -> Router.execute()
 *
 */
interface IRootBridgeAgent is ILayerZeroReceiver {
    /*///////////////////////////////////////////////////////////////
                            VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Function that returns the current settlement nonce.
     *  @return nonce bridge agent's current settlement nonce
     *
     */
    function settlementNonce() external view returns (uint32 nonce);

    /**
     * @notice External function that returns a given settlement entry.
     *  @param _settlementNonce Identifier for token settlement.
     *
     */
    function getSettlementEntry(uint32 _settlementNonce) external view returns (Settlement memory);

    /**
     * @notice External function to get the Bridge Agent Executor Address.
     * @return address Bridge Agent Executor Address.
     */
    function bridgeAgentExecutorAddress() external view returns (address);

    /**
     * @notice External function to get the Root Bridge Agent's Factory Address.
     *  @return address Root Bridge Agent's Factory Address.
     */
    function factoryAddress() external view returns (address);

    /**
     * @notice External function to get the attached Branch Bridge Agent for a given chain.
     *  @param _chainId Chain ID of the Branch Bridge Agent.
     *  @return address Branch Bridge Agent Address.
     */
    function getBranchBridgeAgent(uint256 _chainId) external view returns (address);

    /**
     * @notice External function to verify a given chain has been allowed by the Root Bridge Agent's Manager
     *         for new Branch Bridge Agent creation.
     *  @param _chainId Chain ID of the Branch Bridge Agent.
     *  @return bool True if the chain has been allowed for new Branch Bridge Agent creation.
     */
    function isBranchBridgeAgentAllowed(uint256 _chainId) external view returns (bool);

    /*///////////////////////////////////////////////////////////////
                        ROOT ROUTER CALL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice External function performs call to LayerZero Endpoint Contract for cross-chain messaging.
     *  @param _gasRefundee Address to return excess gas deposited in `msg.value` to.
     *  @param _recipient address to receive any outstanding gas on the destination chain.
     *  @param _dstChainId Chain to bridge to.
     *  @param _params Calldata for function call.
     *  @param _gParams Gas Parameters for cross-chain message.
     *  @dev Internal function performs call to LayerZero Endpoint Contract for cross-chain messaging.
     */
    function callOut(
        address payable _gasRefundee,
        address _recipient,
        uint16 _dstChainId,
        bytes memory _params,
        GasParams calldata _gParams
    ) external payable;

    /**
     * @notice External function to move assets from root chain to branch omnichain environment.
     *  @param _settlementOwnerAndGasRefundee the effective owner of the settlement this address receives
     *                    excess gas deposited on source chain for a cross-chain call and is allowed to redeeming
     *                    assets after a failed settlement fallback. This address' Virtual Account is also allowed.
     *  @param _recipient recipient of bridged tokens and any outstanding gas on the destination chain.
     *  @param _dstChainId chain to bridge to.
     *  @param _params parameters for function call on branch chain.
     *  @param _sParams settlement parameters for asset bridging to branch chains.
     *  @param _gParams Gas Parameters for cross-chain message.
     *  @param _hasFallbackToggled Flag to toggle fallback function.
     *
     */
    function callOutAndBridge(
        address payable _settlementOwnerAndGasRefundee,
        address _recipient,
        uint16 _dstChainId,
        bytes calldata _params,
        SettlementInput calldata _sParams,
        GasParams calldata _gParams,
        bool _hasFallbackToggled
    ) external payable;

    /**
     * @notice External function to move assets from branch chain to root omnichain environment.
     *  @param _settlementOwnerAndGasRefundee the effective owner of the settlement this address receives
     *                    excess gas deposited on source chain for a cross-chain call and is allowed to redeeming
     *                    assets after a failed settlement fallback. This address' Virtual Account is also allowed.
     *  @param _recipient recipient of bridged tokens.
     *  @param _dstChainId chain to bridge to.
     *  @param _params parameters for function call on branch chain.
     *  @param _sParams settlement parameters for asset bridging to branch chains.
     *  @param _gParams Gas Parameters for cross-chain message.
     *  @param _hasFallbackToggled Flag to toggle fallback function.
     *
     *
     */
    function callOutAndBridgeMultiple(
        address payable _settlementOwnerAndGasRefundee,
        address _recipient,
        uint16 _dstChainId,
        bytes calldata _params,
        SettlementMultipleInput calldata _sParams,
        GasParams calldata _gParams,
        bool _hasFallbackToggled
    ) external payable;

    /*///////////////////////////////////////////////////////////////
                        SETTLEMENT FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Function to retry a user's Settlement balance.
     *  @param _settlementOwnerAndGasRefundee owner of the settlement and gas refundee.
     *  @param _settlementNonce Identifier for token settlement.
     *  @param _recipient recipient of bridged tokens and any outstanding gas on the destination chain.
     *  @param _params Calldata for function call in branch chain.
     *  @param _gParams Gas Parameters for cross-chain message.
     *  @param _hasFallbackToggled Flag to toggle fallback function.
     */
    function retrySettlement(
        address _settlementOwnerAndGasRefundee,
        uint32 _settlementNonce,
        address _recipient,
        bytes calldata _params,
        GasParams calldata _gParams,
        bool _hasFallbackToggled
    ) external payable;

    /**
     * @notice Function that allows retrieval of failed Settlement's foricng fallback to be triggered.
     *  @param _settlementNonce Identifier for token settlement.
     *  @param _gParams Gas Parameters for cross-chain message.
     *
     */
    function retrieveSettlement(uint32 _settlementNonce, GasParams calldata _gParams) external payable;

    /**
     * @notice Function that allows redemption of failed Settlement's global tokens.
     *  @param _depositNonce Identifier for token deposit.
     *  @param _recipient recipient of redeemed root/global tokens.
     *
     */
    function redeemSettlement(uint32 _depositNonce, address _recipient) external;

    /*///////////////////////////////////////////////////////////////
                    TOKEN MANAGEMENT FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Function to move assets from branch chain to root omnichain environment.
     * @dev Called in response to Bridge Agent Executor.
     *  @param _recipient recipient of bridged token.
     *  @param _dParams Cross-Chain Deposit of Multiple Tokens Params.
     *  @param _srcChainId chain to bridge from.
     *
     */
    function bridgeIn(address _recipient, DepositParams memory _dParams, uint256 _srcChainId) external;

    /**
     * @notice Function to move assets from branch chain to root omnichain environment.
     * @dev Called in response to Bridge Agent Executor.
     *  @param _recipient recipient of bridged tokens.
     *  @param _dParams Cross-Chain Deposit of Multiple Tokens Params.
     *  @param _srcChainId chain to bridge from.
     *  @dev Since the input data is encodePacked we need to parse it:
     *     1. First byte is the number of assets to be bridged in. Equals length of all arrays.
     *     2. Next 4 bytes are the nonce of the deposit.
     *     3. Last 32 bytes after the token related information are the chain to bridge to.
     *     4. Token related information starts at index PARAMS_TKN_START is encoded as follows:
     *         1. N * 32 bytes for the hToken address.
     *         2. N * 32 bytes for the underlying token address.
     *         3. N * 32 bytes for the amount of hTokens to be bridged in.
     *         4. N * 32 bytes for the amount of underlying tokens to be bridged in.
     *     5. Each of the 4 token related arrays are of length N and start at the following indexes:
     *         1. PARAMS_TKN_START [hToken address has no offset from token information start].
     *         2. PARAMS_TKN_START + (PARAMS_ADDRESS_SIZE * N)
     *         3. PARAMS_TKN_START + (PARAMS_AMT_OFFSET * N)
     *         4. PARAMS_TKN_START + (PARAMS_DEPOSIT_OFFSET * N)
     *
     */
    function bridgeInMultiple(address _recipient, DepositMultipleParams calldata _dParams, uint256 _srcChainId)
        external;

    /*///////////////////////////////////////////////////////////////
                            ADMIN FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Adds a new branch bridge agent to a given branch chainId
     *  @param _branchChainId chainId of the branch chain
     */
    function approveBranchBridgeAgent(uint256 _branchChainId) external;

    /**
     * @notice Updates the address of the branch bridge agent
     *  @param _newBranchBridgeAgent address of the new branch bridge agent
     *  @param _branchChainId chainId of the branch chain
     */
    function syncBranchBridgeAgent(address _newBranchBridgeAgent, uint256 _branchChainId) external;

    /**
     * @notice Allows current bridge agent manager to allowlist a successor address.
     *  @param _newManager address of the new bridge agent manager.
     */
    function transferManagementRole(address _newManager) external;

    /**
     * @notice Used by the new bridge agent manager to accept the management role.
     */
    function acceptManagementRole() external;

    /*///////////////////////////////////////////////////////////////
                             EVENTS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Event emitted when a settlement is successfully and fully redeemed.
    /// @param settlementNonce Identifier for user settlement.
    /// @param recipient recipient of redeemed root/global tokens.
    event RedeemSettlement(uint256 indexed settlementNonce, address indexed recipient);

    /// @notice Event emitted when fallback is received for a failed deposit nonce.
    /// @param depositNonce Identifier for user deposit.
    /// @param srcChainId Chain ID of the source chain.
    event LogExecute(uint256 indexed depositNonce, uint256 indexed srcChainId);

    /// @notice Event emitted when a settlement nonce is executed successfully.
    /// @param settlementNonce Identifier for user settlement.
    /// @param dstChainId Chain ID of the destination chain.
    event LogFallback(uint256 indexed settlementNonce, uint256 indexed dstChainId);

    /// @notice Event emitted after a message is sent to the Layer Zero Endpoint.
    /// @param gasLimit gas limit for the cross-chain call.
    /// @param remoteBranchExecutionGas native gas tokens to be sent to the remote branch.
    event LogGasParams(uint256 indexed gasLimit, uint256 indexed remoteBranchExecutionGas);

    /*///////////////////////////////////////////////////////////////
                            ERRORS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Error emitted when the provided Root Router Address is invalid.
    error InvalidRootRouterAddress();
    /// @notice Error emitted when the provided Branch Port Address is invalid.
    error InvalidRootPortAddress();
    /// @notice Error emitted when the provided Layer Zero Endpoint Address is invalid.
    error InvalidEndpointAddress();

    /// @notice Error emitted execution of a transaction fails.
    error ExecutionFailure();
    /// @notice Error emitted when the provided deposit nonce has already been executed.
    error AlreadyExecutedTransaction();

    /// @notice Error emitted when the Bridge Agent does not recognize the provided action flag.
    error UnknownFlag();

    /// @notice Error emitted when caller is not the DAO address.
    error NotDao();

    /// @notice Error emitted when caller is not the Layer Zero Endpoint.
    error LayerZeroUnauthorizedEndpoint();
    /// @notice Error emitted when remote caller is not the chain's connected Branch Bridge Agent.
    error LayerZeroUnauthorizedCaller();

    /// @notice Error emitted when the Root Bridge Agent already has a Branch Bridge Agent for a given chain.
    error AlreadyAddedBridgeAgent();

    /// @notice Error emitted when the caller is not the connected Root Bridge Agent Executor.
    error UnrecognizedExecutor();
    /// @notice Error emitted when the caller is not the Root Port.
    error UnrecognizedPort();
    /// @notice Error emitted when the caller is not the connected Root Bridge Agent.
    error UnrecognizedBridgeAgent();
    /// @notice Error emitted when the caller is not the connected Arbitrum Branch Bridge Agent.
    error UnrecognizedLocalBridgeAgent();
    /// @notice Error emitted when the caller is not the Root Bridge Agent's Manager.
    error UnrecognizedBridgeAgentManager();
    /// @notice Error emitted when the caller is not the connected Root Router.
    error UnrecognizedRouter();

    /// @notice Error emitted when the requested token does not have an underlying address is the destiantion chain.
    error UnrecognizedUnderlyingAddress();
    /// @notice Error emitted when the requested token is not recognized in the destination chain.
    error UnrecognizedLocalAddress();

    /// @notice Error emitted when the settlement is not available for retry.
    error SettlementRetryUnavailable();
    /// @notice Error emitted when the settlement action flag is no retryable.
    error SettlementRetryUnavailableUseCallout();
    /// @notice Error emitted when the settlement is not available for redemption.
    error SettlementRedeemUnavailable();
    /// @notice Error emitted when the settlement is not available for retrieval.
    error SettlementRetrieveUnavailable();

    /// @notice Error emitted when caller is not the settlement owner.
    error NotSettlementOwner();

    /// @notice Error emitted when Virtual Account caller is not the owner or the approved router.
    error ContractsVirtualAccountNotAllowed();

    /// @notice Error emitted when there is not enough balance to serve a request, meaning request is invalid.
    error InsufficientBalanceForSettlement();

    /// @notice Error emitted when the token info is invalid.
    error InvalidInputParams();
    /// @notice Error emitted when the token info are not of the same length.
    error InvalidInputParamsLength();
}

File 20 of 25 : IRootPort.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {GasParams} from "../interfaces/IRootBridgeAgent.sol";

import {VirtualAccount} from "../VirtualAccount.sol";

/**
 * @title  Root Port - Omnichain Token Management Contract
 * @author MaiaDAO
 * @notice Ulysses `RootPort` implementation for Root Omnichain Environment deployment.
 *         This contract is used to manage the deposit and withdrawal of assets
 *         between the Root Omnichain Environment and every Branch Chain in response to
 *         Root Bridge Agents requests. Manages Bridge Agents and their factories as well as
 *         key governance enabled actions such as adding new chains and bridge agent factories.
 */
interface IRootPort {
    /*///////////////////////////////////////////////////////////////
                        VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/
    /**
     * @notice View Function returns True if the chain Id has been added to the system.
     *  @param _chainId The Layer Zero chainId of the chain.
     * @return bool True if the chain Id has been added to the system.
     */
    function isChainId(uint256 _chainId) external view returns (bool);

    /**
     * @notice View Function returns True if the bridge agent factory has been added to the system.
     *  @param _bridgeAgentFactory The address of the bridge agent factory.
     * @return bool True if the bridge agent factory has been added to the system.
     */
    function isBridgeAgentFactory(address _bridgeAgentFactory) external view returns (bool);

    /**
     * @notice View Function returns True if the address corresponds to a global token.
     *  @param _globalAddress The address of the token in the global chain.
     * @return bool True if the address corresponds to a global token.
     */
    function isGlobalAddress(address _globalAddress) external view returns (bool);

    /**
     * @notice View Function returns Token's Global Address from it's local address.
     *  @param _localAddress The address of the token in the local chain.
     *  @param _srcChainId The chainId of the chain where the token is deployed.
     * @return address The address of the global token.
     */
    function getGlobalTokenFromLocal(address _localAddress, uint256 _srcChainId) external view returns (address);

    /**
     * @notice View Function returns Token's Local Address from it's global address.
     *  @param _globalAddress The address of the token in the global chain.
     *  @param _srcChainId The chainId of the chain where the token is deployed.
     * @return address The address of the local token.
     */
    function getLocalTokenFromGlobal(address _globalAddress, uint256 _srcChainId) external view returns (address);

    /**
     * @notice View Function that returns the local token address from the underlying token address.
     *  @param _underlyingAddress The address of the underlying token.
     *  @param _srcChainId The chainId of the chain where the token is deployed.
     * @return address The address of the local token.
     */
    function getLocalTokenFromUnderlying(address _underlyingAddress, uint256 _srcChainId)
        external
        view
        returns (address);

    /**
     * @notice Function that returns Local Token's Local Address on another chain.
     *  @param _localAddress The address of the token in the local chain.
     *  @param _srcChainId The chainId of the chain where the token is deployed.
     *  @param _dstChainId The chainId of the chain where the token is deployed.
     * @return address The address of the local token in the destination chain.
     */
    function getLocalToken(address _localAddress, uint256 _srcChainId, uint256 _dstChainId)
        external
        view
        returns (address);

    /**
     * @notice View Function returns a underlying token address from it's local address.
     *  @param _localAddress The address of the token in the local chain.
     *  @param _srcChainId The chainId of the chain where the token is deployed.
     * @return address The address of the underlying token.
     */
    function getUnderlyingTokenFromLocal(address _localAddress, uint256 _srcChainId) external view returns (address);

    /**
     * @notice Returns the underlying token address given it's global address.
     *  @param _globalAddress The address of the token in the global chain.
     *  @param _srcChainId The chainId of the chain where the token is deployed.
     * @return address The address of the underlying token.
     */
    function getUnderlyingTokenFromGlobal(address _globalAddress, uint256 _srcChainId)
        external
        view
        returns (address);

    /**
     * @notice View Function returns True if Global Token is already added in current chain, false otherwise.
     *  @param _globalAddress The address of the token in the global chain.
     *  @param _srcChainId The chainId of the chain where the token is deployed.
     * @return bool True if Global Token is already added in current chain, false otherwise.
     */
    function isGlobalToken(address _globalAddress, uint256 _srcChainId) external view returns (bool);

    /**
     * @notice View Function returns True if Local Token is already added in current chain, false otherwise.
     *  @param _localAddress The address of the token in the local chain.
     *  @param _srcChainId The chainId of the chain where the token is deployed.
     * @return bool True if Local Token is already added in current chain, false otherwise.
     */
    function isLocalToken(address _localAddress, uint256 _srcChainId) external view returns (bool);

    /**
     * @notice View Function returns True if Local Token is already added in destination chain, false otherwise.
     *  @param _localAddress The address of the token in the local chain.
     *  @param _srcChainId The chainId of the chain where the token is deployed.
     *  @param _dstChainId The chainId of the chain where the token is deployed.
     * @return bool True if Local Token is already added in current chain, false otherwise.
     */
    function isLocalToken(address _localAddress, uint256 _srcChainId, uint256 _dstChainId)
        external
        view
        returns (bool);

    /**
     * @notice View Function returns True if the underlying Token is already added in given chain, false otherwise.
     *  @param _underlyingToken The address of the underlying token.
     *  @param _srcChainId The chainId of the chain where the token is deployed.
     * @return bool True if the underlying Token is already added in given chain, false otherwise.
     */
    function isUnderlyingToken(address _underlyingToken, uint256 _srcChainId) external view returns (bool);

    /**
     * @notice View Function returns True if the router is approved by user request to use their virtual account.
     *  @param _userAccount The virtual account of the user.
     *  @param _router The address of the router.
     * @return bool True if the router is approved by user request to use their virtual account.
     */
    function isRouterApproved(VirtualAccount _userAccount, address _router) external returns (bool);

    /**
     * @notice View Function returns Virtual Account of a given user.
     *  @param _user The address of the user.
     * @return VirtualAccount user virtual account.
     */
    function getUserAccount(address _user) external view returns (VirtualAccount);

    /**
     * @notice View Function returns bridge agent manager for a given root bridge agent.
     *  @param _rootBridgeAgent address of the root bridge agent.
     * @return address address of the bridge agent manager.
     */
    function getBridgeAgentManager(address _rootBridgeAgent) external view returns (address);

    /*///////////////////////////////////////////////////////////////
                        BRIDGE AGENT MANAGER FUNCTIONS
    ///////////////////////////////////////////////////////////////*/
    /**
     * @notice Allows a root bridge agent to update it's bridge agent manager address.
     *  @param _newManager address of the new bridge agent manager.
     */
    function setBridgeAgentManager(address _newManager) external;

    /*///////////////////////////////////////////////////////////////
                        hTOKEN ACCOUTING FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Updates root port state to match a new deposit.
     *   @param _to recipient of bridged tokens.
     *   @param _hToken address of the hToken to bridge.
     *   @param _amount total amount of tokens to bridge.
     *   @param _deposit amount of underlying tokens to deposit.
     *   @param _srcChainId chainId of the chain where the tokens are being bridged from.
     */
    function bridgeToRoot(address _to, address _hToken, uint256 _amount, uint256 _deposit, uint256 _srcChainId)
        external;

    /**
     * @notice Updates root port state to match hTokens being bridged to branch.
     *   @param _from depositor of the hTokens to bridge.
     *   @param _hToken address of the hToken to bridge.
     *   @param _amount total amount of tokens to bridge.
     *   @param _deposit amount of underlying tokens to deposit.
     *   @param _dstChainId chainId of the chain where the tokens are being bridged to.
     */
    function bridgeToBranch(address _from, address _hToken, uint256 _amount, uint256 _deposit, uint256 _dstChainId)
        external;

    /**
     * @notice Bridges hTokens from the local arbitrum branch for usage in the root port.
     *   @param _from sender of the hTokens to bridge.
     *   @param _hToken address of the hToken to bridge.
     *   @param _amount amount of hTokens to bridge.
     */
    function bridgeToRootFromLocalBranch(address _from, address _hToken, uint256 _amount) external;

    /**
     * @notice Bridges hTokens from the root port to the local arbitrum branch.
     *   @param _to recipient of the bridged tokens.
     *   @param _hToken address of the hToken to bridge.
     *   @param _amount amount of hTokens to bridge.
     */
    function bridgeToLocalBranchFromRoot(address _to, address _hToken, uint256 _amount) external;

    /**
     * @notice Burns tokens from the Arbitrum Branch Port withdrawer address.
     *   @param _from sender of the tokens to burn.
     *   @param _hToken address of the hToken to burn.
     *   @param _amount amount of tokens to burn.
     */
    function burnFromLocalBranch(address _from, address _hToken, uint256 _amount) external;

    /**
     * @notice Mints new root hTokens to the recipient address in reflection of Artbitrum Branch Port deposit.
     *   @param _to recipient of the newly minted tokens.
     *   @param _hToken address of the hToken to mint.
     *   @param _amount amount of tokens to mint.
     */
    function mintToLocalBranch(address _to, address _hToken, uint256 _amount) external;

    /*///////////////////////////////////////////////////////////////
                        hTOKEN MANAGEMENT FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Setter function to add a new underlying token to the system. Includes the creation of a new local hToken
     *         and global hToken.
     *   @param _globalAddress new root hToken address to set.
     *   @param _localAddress new origin chain local hToken address to set.
     *   @param _underlyingAddress new underlying/native token address to set.
     *   @param _srcChainId chainId of the chain where the token is deployed.
     *
     */
    function setAddresses(
        address _globalAddress,
        address _localAddress,
        address _underlyingAddress,
        uint256 _srcChainId
    ) external;

    /**
     * @notice Setter function to update a Global hToken's Local hToken Address.
     *   @param _globalAddress new hToken address to update.
     *   @param _localAddress new underlying/native token address to set.
     *
     */
    function setLocalAddress(address _globalAddress, address _localAddress, uint256 _srcChainId) external;

    /*///////////////////////////////////////////////////////////////
                    VIRTUAL ACCOUNT MANAGEMENT FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Gets the virtual account given a user address. Creates a new virtual account if one does not exist.
     * @param _user address of the user to get the virtual account for.
     */
    function fetchVirtualAccount(address _user) external returns (VirtualAccount account);

    /**
     * @notice Toggles the approval of a router for virtual account usage.
     * @dev Allows for a router to interact/spend from a user's virtual account.
     * @param _userAccount virtual account to toggle the approval for.
     * @param _router router to toggle the approval for.
     */
    function toggleVirtualAccountApproved(VirtualAccount _userAccount, address _router) external;

    /*///////////////////////////////////////////////////////////////
                    BRIDGE AGENT MANAGEMENT FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Adds a new bridge agent to the system.
     * @param _manager address of the manager of the bridge agent.
     * @param _bridgeAgent address of the bridge agent to add.
     */
    function addBridgeAgent(address _manager, address _bridgeAgent) external;

    /**
     * @notice Sets the address of the branch bridge agent connected to a root bridge agent for a given chain.
     * @param _newBranchBridgeAgent address of the new branch bridge agent.
     * @param _rootBridgeAgent address of the root bridge agent.
     * @param _srcChainId chainId of the chain to set the bridge agent for.
     */
    function syncBranchBridgeAgentWithRoot(address _newBranchBridgeAgent, address _rootBridgeAgent, uint256 _srcChainId)
        external;

    /*///////////////////////////////////////////////////////////////
                            ADMIN FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Toggles the status of a bridge agent factory.
     * @param _bridgeAgentFactory address of the bridge agent factory to toggle.
     */
    function toggleBridgeAgentFactory(address _bridgeAgentFactory) external;

    /**
     * @notice Adds a new chain to the root port lists of chains and adds core branch contracts to system.
     * @param _coreBranchBridgeAgentAddress address of the core branch bridge agent
     * @param _chainId chainId of the new chain
     * @param _wrappedGasTokenName gas token name of the new chain
     * @param _wrappedGasTokenSymbol gas token symbol of the new chain
     * @param _wrappedGasTokenDecimals gas token decimals of the new chain
     * @param _newLocalBranchWrappedNativeTokenAddress address of the wrapped native local hToken of the new chain
     * @param _newUnderlyingBranchWrappedNativeTokenAddress new branch address of the underlying wrapped native token
     */
    function addNewChain(
        address _coreBranchBridgeAgentAddress,
        uint256 _chainId,
        string memory _wrappedGasTokenName,
        string memory _wrappedGasTokenSymbol,
        uint8 _wrappedGasTokenDecimals,
        address _newLocalBranchWrappedNativeTokenAddress,
        address _newUnderlyingBranchWrappedNativeTokenAddress
    ) external;

    /**
     * @notice Adds an ecosystem hToken to a branch chain
     * @param ecoTokenGlobalAddress ecosystem token global address
     */
    function addEcosystemToken(address ecoTokenGlobalAddress) external;

    /**
     * @notice Sets the core root router and bridge agent
     * @param _coreRootRouter address of the core root router
     * @param _coreRootBridgeAgent address of the core root bridge agent
     */
    function setCoreRootRouter(address _coreRootRouter, address _coreRootBridgeAgent) external;

    /**
     * @notice Sets the core branch router and bridge agent
     * @param _refundee address of the refundee
     * @param _coreBranchRouter address of the core branch router
     * @param _coreBranchBridgeAgent address of the core branch bridge agent
     * @param _dstChainId chainId of the destination chain
     * @param _gParams gas params for the transaction
     */
    function setCoreBranchRouter(
        address _refundee,
        address _coreBranchRouter,
        address _coreBranchBridgeAgent,
        uint16 _dstChainId,
        GasParams calldata _gParams
    ) external payable;

    /**
     * @notice Syncs a new core branch router and bridge agent.
     * @param _coreBranchRouter address of the core branch router
     * @param _coreBranchBridgeAgent address of the core branch bridge agent
     * @param _dstChainId chainId of the destination chain
     */
    function syncNewCoreBranchRouter(address _coreBranchRouter, address _coreBranchBridgeAgent, uint16 _dstChainId)
        external;

    /**
     * @notice Allows governance to withdraw any native tokens accumulated from failed transactions.
     *  @param _to address to transfer ETH to.
     */
    function sweep(address _to) external;

    /*///////////////////////////////////////////////////////////////
                            EVENTS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Emitted when a new chain is added to the system.
    event NewChainAdded(uint256 indexed chainId);

    /// @notice Emitted when a new bridge agent manager is set for a Root Bridge Agent.
    event BridgeAgentManagerSet(address indexed bridgeAgent, address indexed manager);

    /// @notice Emitted when a new bridge agent factory is added or removed.
    event BridgeAgentFactoryToggled(address indexed bridgeAgentFactory);
    /// @notice Emitted when a new bridge agent is added or removed.
    event BridgeAgentToggled(address indexed bridgeAgent);
    /// @notice Emitted when a new branch bridge agent is added to a root bridge agent.
    event BridgeAgentSynced(address indexed bridgeAgent, address indexed rootBridgeAgent, uint256 indexed srcChainId);

    /// @notice Emitted when a new Virtual Account is created.
    event VirtualAccountCreated(address indexed user, address indexed account);

    /// @notice Emitted when a new local token is added to the system.
    event LocalTokenAdded(
        address indexed underlyingAddress, address indexed localAddress, address indexed globalAddress, uint256 chainId
    );
    /// @notice Emitted when a new global token is added to the system.
    event GlobalTokenAdded(address indexed localAddress, address indexed globalAddress, uint256 indexed chainId);
    /// @notice Emitted when a new Ecosystem Token is added to the system.
    event EcosystemTokenAdded(address indexed ecoTokenGlobalAddress);

    /// @notice Emitted when the Core Root Router and Bridge Agent are set.
    event CoreRootSet(address indexed coreRootRouter, address indexed coreRootBridgeAgent);
    /// @notice Emitted when a new Core Branch Router and Bridge Agent are set.
    event CoreBranchSet(
        address indexed coreBranchRouter, address indexed coreBranchBridgeAgent, uint16 indexed dstChainId
    );
    /// @notice Emitted when a new Core Branch Router and Bridge Agent are synced with the root environment.
    event CoreBranchSynced(
        address indexed coreBranchRouter, address indexed coreBranchBridgeAgent, uint16 indexed dstChainId
    );

    /*///////////////////////////////////////////////////////////////
                            ERRORS  
    ///////////////////////////////////////////////////////////////*/

    /// @notice Error emitted when the owner tries to renounce ownership.
    error RenounceOwnershipNotAllowed();

    /// @notice Error emitted when Set Up period is over.
    error SetUpEnded();
    /// @notice Error emitted when Core Set Up period is over.
    error SetUpCoreEnded();

    /// @notice Error emitted when hToken minting fails.
    error UnableToMint();
    /// @notice Error emitted when hToken bridging fails due to insufficient balance.
    error InsufficientBalance();

    /// @notice Error emitted when an invalid global token address is provided.
    error InvalidGlobalAddress();
    /// @notice Error emitted when an invalid local token address is provided.
    error InvalidLocalAddress();
    /// @notice Error emitted when an invalid underlying token address is provided.
    error InvalidUnderlyingAddress();
    /// @notice Error emitted when zero address is provided for Virtual Account creation.
    error InvalidUserAddress();
    /// @notice Error emitted when zero address is provided for sweep recipient.
    error InvalidRecipientAddress();
    /// @notice Error emitted when zero address is provided for CoreRootRouter.
    error InvalidCoreRootRouter();
    /// @notice Error emitted when zero address is provided for CoreRootBridgeAgent.
    error InvalidCoreRootBridgeAgent();
    /// @notice Error emitted when zero address is provided for CoreBranchRouter.
    error InvalidCoreBranchRouter();
    /// @notice Error emitted when zero address is provided for CoreBranchBridgeAgent.
    error InvalidCoreBrancBridgeAgent();
    /// @notice Error emitted when zero address is provided for RootBridgeAgentFactory.
    error InvalidRootBridgeAgentFactory();
    /// @notice Error emitted when zero address is provided for Branch Port.
    error InvalidBranchPort();

    /// @notice Error emitted when caller is not a Bridge Agent Factory.
    error UnrecognizedBridgeAgentFactory();
    /// @notice Error emitted when caller is not a Bridge Agent.
    error UnrecognizedBridgeAgent();
    /// @notice Error emitted when caller is not the Core Root Router.
    error UnrecognizedCoreRootRouter();
    /// @notice Error emitted when caller is not the Arbitrum Branch
    error UnrecognizedLocalBranchPort();
    /// @notice Error emitted when Core Root Bridge Agent being added isn't added as Bridge Agent yet.
    error UnrecognizedCoreRootBridgeAgent();

    /// @notice Error emitted when trying to add a chain that already exists.
    error AlreadyAddedChain();
    /// @notice Error emitted when trying to add a token that already exists as an Ecosystem Token.
    error AlreadyAddedEcosystemToken();

    /// @notice Error emitted when trying to add a Bridge Agent that already exists.
    error AlreadyAddedBridgeAgent();
    /// @notice Error emitted when trying to add a Bridge Agent Factory that already exists.
    error AlreadyAddedBridgeAgentFactory();

    /// @notice Error emitted when trying to add a chain to a Root Bridge Agent without a Bridge Agent Manager allowing.
    error BridgeAgentNotAllowed();
}

File 21 of 25 : IRootRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {DepositParams, DepositMultipleParams, GasParams} from "../interfaces/IRootBridgeAgent.sol";

/**
 * @title  Root Router Contract
 * @author MaiaDAO
 * @notice Base Root Contract for interfacing with Root Bridge Agents.
 *         This contract for deployment in the Root Chain of the Ulysses Omnichain System,
 *         additional logic can be implemented to perform actions before sending cross-chain
 *         requests to Branch Chains, as well as in response to remote requests.
 */
interface IRootRouter {
    /*///////////////////////////////////////////////////////////////
                            Router Functions
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Function to execute Branch Bridge Agent initiated requests to retry a settlement.
     * @param _settlementNonce settlement nonce.
     * @param _recipient recipient address.
     * @param _params data received from messaging layer.
     * @param _gParams gas parameters.
     * @param _hasFallbackToggled flag to indicate if fallback has been toggled.
     */
    function retrySettlement(
        uint32 _settlementNonce,
        address _recipient,
        bytes calldata _params,
        GasParams calldata _gParams,
        bool _hasFallbackToggled
    ) external payable;

    /*///////////////////////////////////////////////////////////////
                        LAYERZERO FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Function to execute Branch Bridge Agent initiated requests to retry a settlement.
     * @param _owner user account address.
     * @param _settlementNonce settlement nonce.
     * @param _recipient recipient address.
     * @param _params data received from messaging layer.
     * @param _gParams gas parameters.
     * @param _hasFallbackToggled flag to indicate if fallback has been toggled.
     * @param _srcChainId chain where the request originated from.
     */
    function executeRetrySettlement(
        address _owner,
        uint32 _settlementNonce,
        address _recipient,
        bytes calldata _params,
        GasParams calldata _gParams,
        bool _hasFallbackToggled,
        uint16 _srcChainId
    ) external payable;

    /**
     *   @notice Function responsible of executing a crosschain request without any deposit.
     *   @param params data received from messaging layer.
     *   @param srcChainId chain where the request originated from.
     *
     */
    function execute(bytes memory params, uint16 srcChainId) external payable;

    /**
     *   @notice Function responsible of executing a crosschain request which contains cross-chain deposit information attached.
     *   @param params execution data received from messaging layer.
     *   @param dParams cross-chain deposit information.
     *   @param srcChainId chain where the request originated from.
     *
     */
    function executeDepositSingle(bytes memory params, DepositParams memory dParams, uint16 srcChainId)
        external
        payable;

    /**
     *   @notice Function responsible of executing a crosschain request which contains cross-chain deposit information for multiple assets attached.
     *   @param params execution data received from messaging layer.
     *   @param dParams cross-chain multiple deposit information.
     *   @param srcChainId chain where the request originated from.
     *
     */
    function executeDepositMultiple(bytes memory params, DepositMultipleParams memory dParams, uint16 srcChainId)
        external
        payable;

    /**
     * @notice Function responsible of executing a crosschain request with msg.sender without any deposit.
     * @param params execution data received from messaging layer.
     * @param userAccount user account address.
     * @param srcChainId chain where the request originated from.
     */
    function executeSigned(bytes memory params, address userAccount, uint16 srcChainId) external payable;

    /**
     * @notice Function responsible of executing a crosschain request which contains cross-chain deposit information and msg.sender attached.
     * @param params execution data received from messaging layer.
     * @param dParams cross-chain deposit information.
     * @param userAccount user account address.
     * @param srcChainId chain where the request originated from.
     */
    function executeSignedDepositSingle(
        bytes memory params,
        DepositParams memory dParams,
        address userAccount,
        uint16 srcChainId
    ) external payable;

    /**
     * @notice Function responsible of executing a crosschain request which contains cross-chain deposit information for multiple assets and msg.sender attached.
     * @param params execution data received from messaging layer.
     * @param dParams cross-chain multiple deposit information.
     * @param userAccount user account address.
     * @param srcChainId chain where the request originated from.
     */
    function executeSignedDepositMultiple(
        bytes memory params,
        DepositMultipleParams memory dParams,
        address userAccount,
        uint16 srcChainId
    ) external payable;

    /*///////////////////////////////////////////////////////////////
                             ERRORS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Error emitted when function ID is not recognized by the router.
    error UnrecognizedFunctionId();
    /// @notice Error emitted when the caller is not the connected Root Bridge Agent.
    error UnrecognizedBridgeAgent();
    /// @notice Error emitted when the caller is not the connected Root Bridge Agent Executor.
    error UnrecognizedBridgeAgentExecutor();
}

File 22 of 25 : IVirtualAccount.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC721Receiver} from "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol";

/// @notice Call structure based off `Multicall2` contract for aggregating calls.
struct Call {
    address target;
    bytes callData;
}

/// @notice Payable call structure based off `Multicall3` contract for aggreagating calls with `msg.value`.
struct PayableCall {
    address target;
    bytes callData;
    uint256 value;
}

/**
 * @title  Virtual Account Contract
 * @author MaiaDAO
 * @notice A Virtual Account allows users to manage assets and perform interactions remotely while
 *         allowing dApps to keep encapsulated user balance for accounting purposes.
 * @dev    This contract is based off `Multicall2` and `Multicall3` contract, executes a set of `Call` or `PayableCall`
 *         objects if any of the performed calls is invalid the whole batch should revert.
 */
interface IVirtualAccount is IERC721Receiver {
    /*///////////////////////////////////////////////////////////////
                                VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Returns the address of the user that owns the VirtualAccount.
     * @return The address of the user that owns the VirtualAccount.
     */
    function userAddress() external view returns (address);

    /**
     * @notice Returns the address of the local port.
     * @return The address of the local port.
     */
    function localPortAddress() external view returns (address);

    /*///////////////////////////////////////////////////////////////
                            WITHDRAW FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Withdraws native tokens from the VirtualAccount.
     * @param _amount The amount of tokens to withdraw.
     */
    function withdrawNative(uint256 _amount) external;

    /**
     * @notice Withdraws ERC20 tokens from the VirtualAccount.
     * @param _token The address of the ERC20 token to withdraw.
     * @param _amount The amount of tokens to withdraw.
     */
    function withdrawERC20(address _token, uint256 _amount) external;

    /**
     * @notice Withdraws ERC721 tokens from the VirtualAccount.
     * @param _token The address of the ERC721 token to withdraw.
     * @param _tokenId The id of the token to withdraw.
     */
    function withdrawERC721(address _token, uint256 _tokenId) external;

    /*///////////////////////////////////////////////////////////////
                              CALL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Aggregate calls ensuring each call is successful. Inspired by `Multicall2` contract.
     * @param callInput The call to make.
     * @return The return data of the call.
     */
    function call(Call[] calldata callInput) external returns (bytes[] memory);

    /**
     * @notice Aggregate calls with a msg value ensuring each call is successful. Inspired by `Multicall3` contract.
     * @param calls The calls to make.
     * @return The return data of the calls.
     * @dev Reverts if msg.value is less than the sum of the call values.
     */
    function payableCall(PayableCall[] calldata calls) external payable returns (bytes[] memory);

    /*///////////////////////////////////////////////////////////////
                                ERRORS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Error thrown when a call is not successfull.
    error CallFailed(bytes returnData);

    /// @notice Error thrown when caller is not an approved Virtual Account caller.
    error UnauthorizedCaller();
}

File 23 of 25 : AddressCodeSize.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title  Address Code Size Library
 * @notice Library for checking the size of a contract's code.
 * @dev    Used for checking if an address is a contract or an EOA.
 */
library AddressCodeSize {
    /*///////////////////////////////////////////////////////////////
                   PAYLOAD DECODING POSITIONAL CONSTANTS
    ///////////////////////////////////////////////////////////////*/

    function isContract(address addr) internal view returns (bool) {
        uint256 size;
        assembly ("memory-safe") {
            size := extcodesize(addr)
        }
        return size > 0;
    }

    function isEOA(address addr) internal view returns (bool) {
        uint256 size;
        assembly ("memory-safe") {
            size := extcodesize(addr)
        }
        return size == 0;
    }
}

File 24 of 25 : ERC20hToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Ownable} from "lib/solady/src/auth/Ownable.sol";

import {ERC20} from "lib/solmate/src/tokens/ERC20.sol";

import {IERC20hToken} from "../interfaces/IERC20hToken.sol";

/// @title ERC20 hToken Contract
/// @author MaiaDAO
contract ERC20hToken is ERC20, Ownable, IERC20hToken {
    /**
     * @notice Constructor for the ERC20hToken branch or root Contract.
     *   @param _localPortAddress Address of the local Branch or Root Port Contract.
     *   @param _name Name of the Token.
     *   @param _symbol Symbol of the Token.
     *   @param _decimals Decimals of the Token.
     */
    constructor(address _localPortAddress, string memory _name, string memory _symbol, uint8 _decimals)
        ERC20(_name, _symbol, _decimals)
    {
        if (_localPortAddress == address(0)) revert InvalidPortAddress();
        _initializeOwner(_localPortAddress);
    }

    /*///////////////////////////////////////////////////////////////
                        ERC20 LOGIC
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IERC20hToken
    function mint(address account, uint256 amount) external override onlyOwner {
        _mint(account, amount);
    }

    /// @inheritdoc IERC20hToken
    function burn(address account, uint256 amount) public override onlyOwner {
        _burn(account, amount);
    }
}

File 25 of 25 : VirtualAccount.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {LibZip} from "lib/solady/src/utils/LibZip.sol";
import {SafeTransferLib} from "lib/solady/src/utils/SafeTransferLib.sol";

import {ERC721} from "lib/solmate/src/tokens/ERC721.sol";

import {ERC1155Receiver} from "lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Receiver.sol";
import {IERC1155Receiver} from "lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol";
import {IERC721Receiver} from "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol";

import {IVirtualAccount, Call, PayableCall} from "./interfaces/IVirtualAccount.sol";
import {IRootPort} from "./interfaces/IRootPort.sol";

import {AddressCodeSize} from "./lib/AddressCodeSize.sol";

/// @title VirtualAccount - Contract for managing a virtual user account on the Root Chain
contract VirtualAccount is IVirtualAccount, ERC1155Receiver {
    using SafeTransferLib for address;
    using AddressCodeSize for address;

    /// @inheritdoc IVirtualAccount
    address public immutable override userAddress;

    /// @inheritdoc IVirtualAccount
    address public immutable override localPortAddress;

    /*//////////////////////////////////////////////////////////////
                            CONSTRUCTOR
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Constructor for Virtual Account.
     * @param _userAddress Address of the user/owner.
     */
    constructor(address _userAddress) {
        localPortAddress = msg.sender;
        userAddress = _userAddress;
    }

    /*//////////////////////////////////////////////////////////////
                            FALLBACK FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    fallback() external payable {
        LibZip.cdFallback();
    }

    receive() external payable {}

    /*//////////////////////////////////////////////////////////////
                            EXTERNAL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IVirtualAccount
    function withdrawNative(uint256 _amount) external override requiresApprovedCaller {
        msg.sender.safeTransferETH(_amount);
    }

    /// @inheritdoc IVirtualAccount
    function withdrawERC20(address _token, uint256 _amount) external override requiresApprovedCaller {
        _token.safeTransfer(msg.sender, _amount);
    }

    /// @inheritdoc IVirtualAccount
    function withdrawERC721(address _token, uint256 _tokenId) external override requiresApprovedCaller {
        ERC721(_token).transferFrom(address(this), msg.sender, _tokenId);
    }

    /// @inheritdoc IVirtualAccount
    function call(Call[] calldata calls) external override requiresApprovedCaller returns (bytes[] memory returnData) {
        uint256 length = calls.length;
        returnData = new bytes[](length);

        for (uint256 i = 0; i < length;) {
            bool success;
            Call calldata _call = calls[i];

            if (_call.target.isContract()) (success, returnData[i]) = _call.target.call(_call.callData);

            if (!success) revert CallFailed(returnData[i]);

            unchecked {
                ++i;
            }
        }
    }

    /// @inheritdoc IVirtualAccount
    function payableCall(PayableCall[] calldata calls)
        public
        payable
        override
        requiresApprovedCaller
        returns (bytes[] memory returnData)
    {
        uint256 valAccumulator;
        uint256 length = calls.length;
        returnData = new bytes[](length);
        PayableCall calldata _call;
        for (uint256 i = 0; i < length;) {
            _call = calls[i];
            uint256 val = _call.value;
            // Humanity will be a Type V Kardashev Civilization before this overflows - andreas
            // ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256
            unchecked {
                valAccumulator += val;
            }

            bool success;

            if (_call.target.isContract()) (success, returnData[i]) = _call.target.call{value: val}(_call.callData);

            if (!success) revert CallFailed(returnData[i]);

            unchecked {
                ++i;
            }
        }

        // Finally, make sure the msg.value = SUM(call[0...i].value) if not throw error with 'IncorrectEtherPaid()'
        if (msg.value != valAccumulator) revert CallFailed(hex"5c63102a");
    }

    /*//////////////////////////////////////////////////////////////
                            EXTERNAL HOOKS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IERC721Receiver
    function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {
        return this.onERC721Received.selector;
    }

    /// @inheritdoc IERC1155Receiver
    function onERC1155Received(address, address, uint256, uint256, bytes calldata)
        external
        pure
        override
        returns (bytes4)
    {
        return this.onERC1155Received.selector;
    }

    /// @inheritdoc IERC1155Receiver
    function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata)
        external
        pure
        override
        returns (bytes4)
    {
        return this.onERC1155BatchReceived.selector;
    }

    /*///////////////////////////////////////////////////////////////
                                MODIFIERS
    ///////////////////////////////////////////////////////////////*/

    /// @notice Modifier that verifies msg sender is the approved to use the virtual account. Either the owner or an approved router.
    modifier requiresApprovedCaller() {
        if (!IRootPort(localPortAddress).isRouterApproved(this, msg.sender)) {
            if (msg.sender != userAddress) {
                revert UnauthorizedCaller();
            }
        }
        _;
    }
}

Settings
{
  "viaIR": true,
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "bytecodeHash": "none"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"_localChainId","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyAddedBridgeAgent","type":"error"},{"inputs":[],"name":"AlreadyAddedBridgeAgentFactory","type":"error"},{"inputs":[],"name":"AlreadyAddedChain","type":"error"},{"inputs":[],"name":"AlreadyAddedEcosystemToken","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BridgeAgentNotAllowed","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidBranchPort","type":"error"},{"inputs":[],"name":"InvalidCoreBrancBridgeAgent","type":"error"},{"inputs":[],"name":"InvalidCoreBranchRouter","type":"error"},{"inputs":[],"name":"InvalidCoreRootBridgeAgent","type":"error"},{"inputs":[],"name":"InvalidCoreRootRouter","type":"error"},{"inputs":[],"name":"InvalidGlobalAddress","type":"error"},{"inputs":[],"name":"InvalidLocalAddress","type":"error"},{"inputs":[],"name":"InvalidRecipientAddress","type":"error"},{"inputs":[],"name":"InvalidRootBridgeAgentFactory","type":"error"},{"inputs":[],"name":"InvalidUnderlyingAddress","type":"error"},{"inputs":[],"name":"InvalidUserAddress","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"RenounceOwnershipNotAllowed","type":"error"},{"inputs":[],"name":"SetUpCoreEnded","type":"error"},{"inputs":[],"name":"SetUpEnded","type":"error"},{"inputs":[],"name":"UnableToMint","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnrecognizedBridgeAgent","type":"error"},{"inputs":[],"name":"UnrecognizedBridgeAgentFactory","type":"error"},{"inputs":[],"name":"UnrecognizedCoreRootBridgeAgent","type":"error"},{"inputs":[],"name":"UnrecognizedCoreRootRouter","type":"error"},{"inputs":[],"name":"UnrecognizedLocalBranchPort","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bridgeAgentFactory","type":"address"}],"name":"BridgeAgentFactoryToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bridgeAgent","type":"address"},{"indexed":true,"internalType":"address","name":"manager","type":"address"}],"name":"BridgeAgentManagerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bridgeAgent","type":"address"},{"indexed":true,"internalType":"address","name":"rootBridgeAgent","type":"address"},{"indexed":true,"internalType":"uint256","name":"srcChainId","type":"uint256"}],"name":"BridgeAgentSynced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bridgeAgent","type":"address"}],"name":"BridgeAgentToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"coreBranchRouter","type":"address"},{"indexed":true,"internalType":"address","name":"coreBranchBridgeAgent","type":"address"},{"indexed":true,"internalType":"uint16","name":"dstChainId","type":"uint16"}],"name":"CoreBranchSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"coreBranchRouter","type":"address"},{"indexed":true,"internalType":"address","name":"coreBranchBridgeAgent","type":"address"},{"indexed":true,"internalType":"uint16","name":"dstChainId","type":"uint16"}],"name":"CoreBranchSynced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"coreRootRouter","type":"address"},{"indexed":true,"internalType":"address","name":"coreRootBridgeAgent","type":"address"}],"name":"CoreRootSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"ecoTokenGlobalAddress","type":"address"}],"name":"EcosystemTokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"localAddress","type":"address"},{"indexed":true,"internalType":"address","name":"globalAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"GlobalTokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlyingAddress","type":"address"},{"indexed":true,"internalType":"address","name":"localAddress","type":"address"},{"indexed":true,"internalType":"address","name":"globalAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"LocalTokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"NewChainAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"VirtualAccountCreated","type":"event"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"},{"internalType":"address","name":"_bridgeAgent","type":"address"}],"name":"addBridgeAgent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ecoTokenGlobalAddress","type":"address"}],"name":"addEcosystemToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_coreBranchBridgeAgentAddress","type":"address"},{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"string","name":"_wrappedGasTokenName","type":"string"},{"internalType":"string","name":"_wrappedGasTokenSymbol","type":"string"},{"internalType":"uint8","name":"_wrappedGasTokenDecimals","type":"uint8"},{"internalType":"address","name":"_newLocalBranchWrappedNativeTokenAddress","type":"address"},{"internalType":"address","name":"_newUnderlyingBranchWrappedNativeTokenAddress","type":"address"}],"name":"addNewChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"bridgeAgentFactories","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"bridgeAgents","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_deposit","type":"uint256"},{"internalType":"uint256","name":"_dstChainId","type":"uint256"}],"name":"bridgeToBranch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"bridgeToLocalBranchFromRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_deposit","type":"uint256"},{"internalType":"uint256","name":"_srcChainId","type":"uint256"}],"name":"bridgeToRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"bridgeToRootFromLocalBranch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burnFromLocalBranch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"coreRootBridgeAgentAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"coreRootRouterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"fetchVirtualAccount","outputs":[{"internalType":"contract VirtualAccount","name":"account","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"globalAddress","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getBalanceOfBranch","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bridgeAgent","type":"address"}],"name":"getBridgeAgentManager","outputs":[{"internalType":"address","name":"bridgeAgentManager","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localAddress","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getGlobalTokenFromLocal","outputs":[{"internalType":"address","name":"globalAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_localAddress","type":"address"},{"internalType":"uint256","name":"_srcChainId","type":"uint256"},{"internalType":"uint256","name":"_dstChainId","type":"uint256"}],"name":"getLocalToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"globalAddress","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getLocalTokenFromGlobal","outputs":[{"internalType":"address","name":"localAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingAddress","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getLocalTokenFromUnderlying","outputs":[{"internalType":"address","name":"localAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"globalAddress","type":"address"}],"name":"getTotalSupplyBranches","outputs":[{"internalType":"uint256","name":"totalSupplyBranches","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_globalAddress","type":"address"},{"internalType":"uint256","name":"_srcChainId","type":"uint256"}],"name":"getUnderlyingTokenFromGlobal","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localAddress","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getUnderlyingTokenFromLocal","outputs":[{"internalType":"address","name":"underlyingAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserAccount","outputs":[{"internalType":"contract VirtualAccount","name":"account","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bridgeAgentFactory","type":"address"},{"internalType":"address","name":"_coreRootRouter","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_coreRootBridgeAgent","type":"address"},{"internalType":"address","name":"_coreLocalBranchBridgeAgent","type":"address"},{"internalType":"address","name":"_localBranchPortAddress","type":"address"}],"name":"initializeCore","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"bridgeAgent","type":"address"}],"name":"isBridgeAgent","outputs":[{"internalType":"bool","name":"isActive","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bridgeAgentFactory","type":"address"}],"name":"isBridgeAgentFactory","outputs":[{"internalType":"bool","name":"isActive","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"isChainId","outputs":[{"internalType":"bool","name":"isActive","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isGlobalAddress","outputs":[{"internalType":"bool","name":"isGlobalToken","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_globalAddress","type":"address"},{"internalType":"uint256","name":"_srcChainId","type":"uint256"}],"name":"isGlobalToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_localAddress","type":"address"},{"internalType":"uint256","name":"_srcChainId","type":"uint256"}],"name":"isLocalToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_localAddress","type":"address"},{"internalType":"uint256","name":"_srcChainId","type":"uint256"},{"internalType":"uint256","name":"_dstChainId","type":"uint256"}],"name":"isLocalToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract VirtualAccount","name":"acount","type":"address"},{"internalType":"address","name":"router","type":"address"}],"name":"isRouterApproved","outputs":[{"internalType":"bool","name":"allowed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingToken","type":"address"},{"internalType":"uint256","name":"_srcChainId","type":"uint256"}],"name":"isUnderlyingToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"localBranchPortAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"localChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"address","name":"_hToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintToLocalBranch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_globalAddress","type":"address"},{"internalType":"address","name":"_localAddress","type":"address"},{"internalType":"address","name":"_underlyingAddress","type":"address"},{"internalType":"uint256","name":"_srcChainId","type":"uint256"}],"name":"setAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newManager","type":"address"}],"name":"setBridgeAgentManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_refundee","type":"address"},{"internalType":"address","name":"_coreBranchRouter","type":"address"},{"internalType":"address","name":"_coreBranchBridgeAgent","type":"address"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"remoteBranchExecutionGas","type":"uint256"}],"internalType":"struct GasParams","name":"_gParams","type":"tuple"}],"name":"setCoreBranchRouter","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_coreRootRouter","type":"address"},{"internalType":"address","name":"_coreRootBridgeAgent","type":"address"}],"name":"setCoreRootRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_globalAddress","type":"address"},{"internalType":"address","name":"_localAddress","type":"address"},{"internalType":"uint256","name":"_srcChainId","type":"uint256"}],"name":"setLocalAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newBranchBridgeAgent","type":"address"},{"internalType":"address","name":"_rootBridgeAgent","type":"address"},{"internalType":"uint256","name":"_branchChainId","type":"uint256"}],"name":"syncBranchBridgeAgentWithRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_coreBranchRouter","type":"address"},{"internalType":"address","name":"_coreBranchBridgeAgent","type":"address"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"}],"name":"syncNewCoreBranchRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridgeAgentFactory","type":"address"}],"name":"toggleBridgeAgentFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract VirtualAccount","name":"_userAccount","type":"address"},{"internalType":"address","name":"_router","type":"address"}],"name":"toggleVirtualAccountApproved","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

Deployed Bytecode

0x6040608081526004908136101562000022575b505036156200002057600080fd5b005b600091823560e01c90816301681a621462003604578163065b904114620035b857816311d9a45014620032ce578163165897f91462003137578163193c603d146200304857816319e6f19d1462002e235781631ef6dc421462002db157816321b4156d1462002d15578163256929621462002cab57816325fa1fdc1462002c4057816326d120cd1462002bcc5781633363581d1462002b5a578163375c0f0a1462002b0d578163485cc95514620028f657816354d1f13d146200289157816356a43fde14620027cc5781635961913414620026225781635b056da514620025c757816363a82db21462002427578163644c181514620023105781636781e22114620022bb578163715018a6146200225e57816381beb20214620022095781638da5cb5b14620021955781638f4920c71462001f2d57816391ed2f5f1462001e5e57816393d18a9b1462001d0c5781639777a4eb1462001c83578163a4b449be14620019a7578163b83e3f3214620018ce578163bb8b5f73146200185a578163bd4adce314620017fb578163c14135c0146200178c578163c28e38f9146200171a578163c8c1ae5414620015a3578163cba5a775146200153a578163cd288574146200123b578163d0ea9dc01462001084578163d3fbcc2e1462001019578163d561b1511462000fb3578163e688eeba1462000f2b578163ec385b0b1462000d9b578163ecf0a1b914620008f0578163ee486b3a1462000867578163ee93258a146200080a578163f04e283e146200073a578163f2fde38b146200067f578163f521c8f4146200060d578163f9cd96e514620005b5578163faaf7ee11462000541578163fb47e01614620004da578163fb6f948d146200046f578163fd4f332e146200030b575063fee81cf403620000125734620003075760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200030757602091620002f1620036b2565b9063389a75e1600c525281600c20549051908152f35b5080fd5b919050346200046b57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b5762000348620036b2565b9062000353620036d6565b916200035e620039a2565b73ffffffffffffffffffffffffffffffffffffffff809116928315620004435781169384156200041c57507fffffffffffffffffffffffff00000000000000000000000000000000000000009083826002541617600255848260035416176003557fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275492858752600960205286209216908254161790557fe314f264b06c99244ff9fa39359a00a3572bbd67762bbd853634b17e5eeccf468380a380f35b82517f481ddcbe000000000000000000000000000000000000000000000000000000008152fd5b8483517f1aeaf725000000000000000000000000000000000000000000000000000000008152fd5b8280fd5b505034620003075760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003075760ff8160209373ffffffffffffffffffffffffffffffffffffffff620004c7620036b2565b1681526007855220541690519015158152f35b9050346200046b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b578160209373ffffffffffffffffffffffffffffffffffffffff928362000532620036b2565b16825285522054169051908152f35b5050346200030757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307576020918173ffffffffffffffffffffffffffffffffffffffff918262000598620036b2565b168152600e85528181206024358252855220541615159051908152f35b5050346200030757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003075760209073ffffffffffffffffffffffffffffffffffffffff60015460101c169051908152f35b5050346200030757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307576020918173ffffffffffffffffffffffffffffffffffffffff918262000664620036b2565b16815260108552818120602435825285522054169051908152f35b839060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200030757620006b6620036b2565b90620006c1620039a2565b8160601b156200072f575073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a35580f35b637448fbae8352601cfd5b8360207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620008075762000770620036b2565b6200077a620039a2565b63389a75e1600c528082526020600c209283544211620007fc57508173ffffffffffffffffffffffffffffffffffffffff929355167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a35580f35b636f5e88188352601cfd5b80fd5b50503462000307576020918162000821366200384b565b73ffffffffffffffffffffffffffffffffffffffff9283168552600d87528385209185529086528284205482168452600e86528284209084528552912054915191168152f35b9050346200046b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b573591600b5483101562000807575073ffffffffffffffffffffffffffffffffffffffff602092600b6000527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90154169051908152f35b919050346200046b577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60e08136011262000c82576200092f620036b2565b916024359360443567ffffffffffffffff9081811162000d975762000958903690840162003928565b9060643590811162000d975762000973903690840162003928565b916084359560ff871680970362000d935760a4359273ffffffffffffffffffffffffffffffffffffffff9788851680950362000d8e5760c4359789891680990362000d8e578b96620009c4620039a2565b8b885260ff8960209960068b5220541662000d66579185949392918d9692898d600254168c51958680927f448c8a200000000000000000000000000000000000000000000000000000000082525afa93841562000d5c578d8862000a7697958e958e98958d95869762000d1c575b509062000a869160609798519b8c9a8b998a977fe8a0aed3000000000000000000000000000000000000000000000000000000008952880152606487019062003bd3565b9185830301602486015262003bd3565b9060448301520393165af190811562000d1257908991859162000cd1575b501697828682600254168951928380927f24e731590000000000000000000000000000000000000000000000000000000082525afa90811562000cc757859162000c86575b501691823b1562000c825762000b54928492838c938a51968795869485937f6522a3cf00000000000000000000000000000000000000000000000000000000855284016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1801562000c785762000c5c575b50869052600682528287207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090600182825416179055858852600c8352600184892091825416179055808752600d82528287208688528252828720947fffffffffffffffffffffffff00000000000000000000000000000000000000009581878254161790558752600e825282872086885282528287208186825416179055838752600f82528287208688528252828720818682541617905586526010815281862090858752528420918254161790557fb096a54dc09108ad4542be48bacab0f8e7663d7e1adbdd8a516e7fafd1aa5f4f8280a280f35b62000c6790620038a2565b62000c7457863862000b65565b8680fd5b85513d84823e3d90fd5b8380fd5b90508681813d831162000cbf575b62000ca08183620038e6565b8101031262000cbb5751818116810362000cbb573862000ae9565b8480fd5b503d62000c94565b88513d87823e3d90fd5b809250878092503d831162000d0a575b62000ced8183620038e6565b8101031262000c825751888116810362000c825788903862000aa4565b503d62000ce1565b87513d86823e3d90fd5b606097509062000d4a62000a8693928c8d3d1062000d54575b62000d418183620038e6565b81019062003ba5565b9750909162000a32565b503d62000d35565b8b513d8a823e3d90fd5b8589517f35b66c9d000000000000000000000000000000000000000000000000000000008152fd5b600080fd5b8880fd5b8780fd5b838334620003075762000dae36620037e8565b9262000dbe6001865414620039db565b6002855573ffffffffffffffffffffffffffffffffffffffff8060015460101c16330362000f035782168086526020600c815260ff83882054161562000edb578251907f70a0823100000000000000000000000000000000000000000000000000000000825230898301528082602481865afa91821562000ed157889262000e9b575b506011919288525262000e58858388205462003ac8565b1162000e73575062000e6c93945062003a7e565b6001815580f35b8590517ff4d678b8000000000000000000000000000000000000000000000000000000008152fd5b91508082813d831162000ec9575b62000eb58183620038e6565b8101031262000d8e57601191519162000e41565b503d62000ea9565b84513d8a823e3d90fd5b8783517fd890f8ca000000000000000000000000000000000000000000000000000000008152fd5b8682517f7268a71b000000000000000000000000000000000000000000000000000000008152fd5b5050346200030757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307576020918162000f6b620036b2565b9160243573ffffffffffffffffffffffffffffffffffffffff8094168252600e8652828220818352865283838320541682526010865282822090825285522054169051908152f35b505034620003075760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307578060209273ffffffffffffffffffffffffffffffffffffffff62001009620036b2565b1681526011845220549051908152f35b505034620003075760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003075760ff8160209373ffffffffffffffffffffffffffffffffffffffff62001071620036b2565b168152600a855220541690519015158152f35b83915034620003075762001098366200377d565b96939492620010ae6001889493945414620039db565b60028755338752600760205260ff858820541615620012135773ffffffffffffffffffffffffffffffffffffffff811691828852600c60205260ff868920541615620011eb579783918962001105848b9c62003a41565b620011c4575b5050506200111c575b856001815580f35b803b15620011c05762001182948680948651978895869485937f9dc29fac00000000000000000000000000000000000000000000000000000000855284016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1908115620011b757506200119f575b8080808062001114565b620011aa90620038a2565b6200080757808262001195565b513d84823e3d90fd5b8580fd5b620011e193620011d8910392838362003b30565b87309162003ad6565b818880806200110b565b8486517fd890f8ca000000000000000000000000000000000000000000000000000000008152fd5b8385517f541ba3f8000000000000000000000000000000000000000000000000000000008152fd5b9050346200046b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b5762001278620036b2565b9062001283620036d6565b926200128e620036fa565b9362001299620039a2565b73ffffffffffffffffffffffffffffffffffffffff809416948515620015125784821615620014ea5784811615620014c257858752600760205260ff8388205416156200149a576001549060ff8260081c16156200147157907fffffffffffffffffffff000000000000000000000000000000000000000000ff75ffffffffffffffffffffffffffffffffffffffff0000899695949360101b169116176001557fffffffffffffffffffffffff0000000000000000000000000000000000000000868160035416176003557fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275490878652600960205286848720921690825416179055853b1562000c825781517f6522a3cf00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169281019283527f00000000000000000000000000000000000000000000000000000000000027b1602084015291839083908190604001038183895af1908115620011b7575062001459575b5050600254167fe314f264b06c99244ff9fa39359a00a3572bbd67762bbd853634b17e5eeccf468380a380f35b6200146490620038a2565b6200046b5782386200142c565b505050517f35bcc231000000000000000000000000000000000000000000000000000000008152fd5b5050517f02354282000000000000000000000000000000000000000000000000000000008152fd5b5050517f818a956e000000000000000000000000000000000000000000000000000000008152fd5b5050517fb35bd61f000000000000000000000000000000000000000000000000000000008152fd5b5050517f481ddcbe000000000000000000000000000000000000000000000000000000008152fd5b505034620003075760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307576020918173ffffffffffffffffffffffffffffffffffffffff918262001592620036b2565b168152600985522054169051908152f35b9050346200046b5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b57620015e0620036b2565b90620015eb620036d6565b906044359361ffff851680950362000d8e5762001607620039a2565b73ffffffffffffffffffffffffffffffffffffffff809416928315620016f3578416938415620016cc57908692916003541691823b1562000c8257856044859283855196879485937f6522a3cf0000000000000000000000000000000000000000000000000000000085528401528b60248401525af1908115620011b75750620016b4575b50807f66a2079bcf76283338bf4e376ca0594b08c2a52440685de3c967ca3e09f9935c91a480f35b620016bf90620038a2565b62000c825783386200168c565b50517f7e0b63cc000000000000000000000000000000000000000000000000000000008152fd5b50517fb35bd61f000000000000000000000000000000000000000000000000000000008152fd5b5050346200030757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307576020918173ffffffffffffffffffffffffffffffffffffffff918262001771620036b2565b168152600e8552818120602435825285522054169051908152f35b5050346200030757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307578060209273ffffffffffffffffffffffffffffffffffffffff620017e1620036b2565b168152601284528181206024358252845220549051908152f35b50503462000307576020918162001812366200384b565b73ffffffffffffffffffffffffffffffffffffffff9283168552600d87528385209185529086528284205482168452600e865282842090845285529120549151911615158152f35b5050346200030757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307576020918173ffffffffffffffffffffffffffffffffffffffff9182620018b1620036b2565b168152600d85528181206024358252855220541615159051908152f35b8383346200030757620018e1366200371e565b919091338452600760205260ff8285205416156200197f576200197c93945073ffffffffffffffffffffffffffffffffffffffff8093169283865260056020528286209116908160005260205260ff826000205416159285526005602052818520906000526020526000209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b80f35b8482517f541ba3f8000000000000000000000000000000000000000000000000000000008152fd5b919050346200046b57602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000c8257620019e7620036b2565b620019f1620039a2565b73ffffffffffffffffffffffffffffffffffffffff80911693848652600c845260ff838720541662001c5c5784865260108452828620917f00000000000000000000000000000000000000000000000000000000000027b192838852855280848820541662001c3457858752600f8552838720838852855283872054168062001b25575b5050908391828652600c845281862060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055600d84528186208187528452818620937fffffffffffffffffffffffff0000000000000000000000000000000000000000948486825416179055838752600e8152828720918752528420918254161790557f37953ae118bff6822588ee911e863a3b03c444c17d26c48abcfce3b5307b77be8280a280f35b8395939694929196517f18160ddd00000000000000000000000000000000000000000000000000000000815283818981855afa90811562001c2a57869162001bf7575b501562001b97578686517f125ae064000000000000000000000000000000000000000000000000000000008152fd5b84849693959750526010845281862081875284528186207fffffffffffffffffffffffff000000000000000000000000000000000000000090818154169055838752600f8552828720828852855282872090815416905590913862001a75565b90508381813d831162001c22575b62001c118183620038e6565b8101031262000d8e57513862001b68565b503d62001c05565b87513d88823e3d90fd5b5082517f125ae064000000000000000000000000000000000000000000000000000000008152fd5b82517f125ae064000000000000000000000000000000000000000000000000000000008152fd5b9050346200046b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b57359160085483101562000807575073ffffffffffffffffffffffffffffffffffffffff60209260086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30154169051908152f35b83915034620003075762001d2036620037e8565b9491929062001d336001865414620039db565b6002855573ffffffffffffffffffffffffffffffffffffffff908160015460101c16330362001e36571694858552600c60205260ff83862054161562001e0e578585963b15620011c05762001ddb948680948651978895869485937f9dc29fac00000000000000000000000000000000000000000000000000000000855284016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1908115620011b7575062001df6575b506001905580f35b62001e0190620038a2565b6200080757808262001dee565b5090517fd890f8ca000000000000000000000000000000000000000000000000000000008152fd5b8284517f7268a71b000000000000000000000000000000000000000000000000000000008152fd5b83915034620003075762001e7236620037e8565b9491929062001e856001865414620039db565b6002855573ffffffffffffffffffffffffffffffffffffffff908160015460101c16330362001e36571694858552600c60205260ff83862054161562001e0e578585963b15620011c05762001ddb948680948651978895869485937f40c10f1900000000000000000000000000000000000000000000000000000000855284016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b919050346200046b5762001f4136620037e8565b9373ffffffffffffffffffffffffffffffffffffffff9291836002541633036200216d5783169380517f59b6da27000000000000000000000000000000000000000000000000000000008152868382015260209081816024818a5afa9081156200211a579086918a916200214b575b5016620021245781517f8edd8a48000000000000000000000000000000000000000000000000000000008152878482015281816024818a5afa9182156200211a578992620020dc575b505015620020b657908691853b156200046b5780517f6522a3cf00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851692810192835260208301889052918390839081906040010381838a5af1908115620011b757506200209e575b5050167f357f705c8af6ca487328955747302f0015edfc0b4a256c565a105a9fba7804e88480a480f35b620020a990620038a2565b62000cbb57843862002074565b517f809fb713000000000000000000000000000000000000000000000000000000008152fd5b90809250813d831162002112575b620020f68183620038e6565b8101031262000d975751801515810362000d9757388062001ff9565b503d620020ea565b83513d8b823e3d90fd5b50517f7c8e4f64000000000000000000000000000000000000000000000000000000008152fd5b620021669150833d851162000d545762000d418183620038e6565b3862001fb0565b5083517f32efe22e000000000000000000000000000000000000000000000000000000008152fd5b5050346200030757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003075760209073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754915191168152f35b5050346200030757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003075760209073ffffffffffffffffffffffffffffffffffffffff600254169051908152f35b8284807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000807575062002295620039a2565b517f96c553eb000000000000000000000000000000000000000000000000000000008152fd5b5050346200030757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003075760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b919050346200046b576200232436620037e8565b93919073ffffffffffffffffffffffffffffffffffffffff9081600254163303620023ff578116928315620023d857508290818752600d6020528487208688526020528487209216937fffffffffffffffffffffffff0000000000000000000000000000000000000000928584825416179055848752600e6020528087208688526020528620918254161790557f32349a8e01b326bbb6f9eb4434cbe9f467008ed3c20c9e277587e2c5f9eb3b9f8480a480f35b84517fc221614a000000000000000000000000000000000000000000000000000000008152fd5b8385517f32efe22e000000000000000000000000000000000000000000000000000000008152fd5b905060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b576200245e620036b2565b9162002469620036d6565b9162002474620036fa565b916064359461ffff861680960362000d8e57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c36011262000c7457620024ba620039a2565b73ffffffffffffffffffffffffffffffffffffffff809516938415620014ea5785169485156200259f5790818894939260025416803b15620011c057859260c491855196879485937fd6ee592200000000000000000000000000000000000000000000000000000000855216908301528860248301528960448301528a6064830152608435608483015260a43560a483015234905af1908115620011b7575062002587575b50807f9e2cb2f08e6d85ab3b2b790a831fb69435dc0e0b4cc036fdfe8d0b125a6c294191a480f35b6200259290620038a2565b62000c825783386200255f565b5050517f7e0b63cc000000000000000000000000000000000000000000000000000000008152fd5b5050346200030757817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200030757602090517f00000000000000000000000000000000000000000000000000000000000027b18152f35b828434620008075760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000807576200265f620036b2565b9173ffffffffffffffffffffffffffffffffffffffff9182841690818152856020528383822054169485156200269c575b60208686865191168152f35b90918093955015620027a45784516112d7918282019282841067ffffffffffffffff85111762002778577fffffffffffffffffffffffffffffffffffffffff000000000000000000000000602092849262003c34843987865260601b169303019083f59182156200276c5760209581835286527f4a5206d82707a242e1001c0051c5db7a10a623044ac3d34d2b0f42f20b895ea08583209285851693847fffffffffffffffffffffffff000000000000000000000000000000000000000082541617905580a39184808062002690565b508351903d90823e3d90fd5b60248560418b7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b8585517f702b3d90000000000000000000000000000000000000000000000000000000008152fd5b505034620003075760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307576200286a73ffffffffffffffffffffffffffffffffffffffff62002822620036b2565b6200282c620039a2565b16808452600a602052918320805460ff81811615167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116179055565b7fa64bc674084fdd52a9cdb6aca0e184c83739450e349016391528abafd6097c038280a280f35b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620008075763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b9050346200046b57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b5762002932620036b2565b906200293d620036d6565b9162002948620039a2565b73ffffffffffffffffffffffffffffffffffffffff80911692831562002ae5571692831562002abf576001549060ff82161562002a97576001907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008093168255848752600a602052862091825416179055600b54906801000000000000000082101562002a69576001820180600b5582101562002a3b5750600b6000527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9017fffffffffffffffffffffffff00000000000000000000000000000000000000009182825416179055600254161760025580f35b6032907f4e487b71000000000000000000000000000000000000000000000000000000006000525260246000fd5b6041907f4e487b71000000000000000000000000000000000000000000000000000000006000525260246000fd5b9050517f86112245000000000000000000000000000000000000000000000000000000008152fd5b517f1aeaf725000000000000000000000000000000000000000000000000000000008152fd5b8285517f9596f8b5000000000000000000000000000000000000000000000000000000008152fd5b9050346200046b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b578160209360ff923581526006855220541690519015158152f35b5050346200030757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307576020918173ffffffffffffffffffffffffffffffffffffffff918262002bb1620036b2565b168152600f8552818120602435825285522054169051908152f35b5050346200030757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307576020918173ffffffffffffffffffffffffffffffffffffffff918262002c23620036b2565b168152600f85528181206024358252855220541615159051908152f35b505034620003075760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003075760ff8160209373ffffffffffffffffffffffffffffffffffffffff62002c98620036b2565b168152600c855220541690519015158152f35b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620008075763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b838334620003075762002d2836620037e8565b9262002d3b6001869493945414620039db565b6002855573ffffffffffffffffffffffffffffffffffffffff8060015460101c16330362000f035783168552600c60205260ff81862054161562002d89575062000e6c939450309162003ad6565b8590517fd890f8ca000000000000000000000000000000000000000000000000000000008152fd5b5050346200030757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011262000307576020918173ffffffffffffffffffffffffffffffffffffffff918262002e08620036b2565b168152600d8552818120602435825285522054169051908152f35b9050346200046b5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b5762002e60620036b2565b9062002e6b620036d6565b9262002e76620036fa565b926064359073ffffffffffffffffffffffffffffffffffffffff90816002541633036200301f57811695861562002ff657811694851562002fcd571692831562002fa65750907fbc68f8c6bc7725cd153211b66209e3c2bc0706ec10427059be524f96db68247c91858752602091600c835280882060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055858852600d835280882082895283528088207fffffffffffffffffffffffff0000000000000000000000000000000000000000908882825416179055878952600e8452818920838a5284528189208782825416179055858952600f8452818920838a528452818920878282541617905586895260108452818920838a52845285828a209182541617905551908152a480f35b82517fe9a1cca5000000000000000000000000000000000000000000000000000000008152fd5b505050517fc221614a000000000000000000000000000000000000000000000000000000008152fd5b505050517fd890f8ca000000000000000000000000000000000000000000000000000000008152fd5b505050517f32efe22e000000000000000000000000000000000000000000000000000000008152fd5b919050346200046b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b5762003086620036b2565b91338452600760205260ff82852054161562003110575073ffffffffffffffffffffffffffffffffffffffff9033845260096020528320911690817fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055337f6a4acad6c0a510d922a080fd743bba1ac0a9fa6f560526c18819e351bb8e04b78380a380f35b90517f541ba3f8000000000000000000000000000000000000000000000000000000008152fd5b9050346200046b57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b5762003173620036b2565b906200317e620036d6565b338552600a60205260ff848620541615620032a65773ffffffffffffffffffffffffffffffffffffffff80911691828652600760205260ff85872054166200327f57600854906801000000000000000082101562002a6957600182018060085582101562002a3b575060086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee301917fffffffffffffffffffffffff0000000000000000000000000000000000000000928184825416179055855260096020528385209216908254161790556007602052812060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905580f35b84517f7c8e4f64000000000000000000000000000000000000000000000000000000008152fd5b5082517fdbf8f2a1000000000000000000000000000000000000000000000000000000008152fd5b839150346200030757620032e2366200377d565b620032f76001889996939594995414620039db565b600287553387526020926007845260ff868920541615620035905773ffffffffffffffffffffffffffffffffffffffff811693848952600c815260ff878a2054161562003568578962003350878b9c9b999a9b62003a41565b620033fd575b505050508262003369575b836001815580f35b813b1562000c825783620033cd968651978895869485937f40c10f1900000000000000000000000000000000000000000000000000000000855284016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1908115620011b75750620033eb575b808281808062003361565b620033f690620038a2565b81620033e0565b95809791929394959603937f00000000000000000000000000000000000000000000000000000000000027b181146000146200351c5750508651907f70a0823100000000000000000000000000000000000000000000000000000000825230898301528082602481895afa91821562003512578a92620034d8575b50601190868b52526200348f83888b205462003ac8565b11620034b057829188959493620034a69262003a7e565b8780808062003356565b8686517ff4d678b8000000000000000000000000000000000000000000000000000000008152fd5b9080925081813d83116200350a575b620034f38183620038e6565b8101031262003506575190601162003478565b8980fd5b503d620034e7565b88513d8c823e3d90fd5b926011869593620034a69589859b9a999552601282528b8b20908b5281528a8a206200354a86825462003a41565b9055878a52528888206200356084825462003a41565b905562003a7e565b8787517fd890f8ca000000000000000000000000000000000000000000000000000000008152fd5b8686517f541ba3f8000000000000000000000000000000000000000000000000000000008152fd5b505034620003075760ff81602093620035d1366200371e565b73ffffffffffffffffffffffffffffffffffffffff91821683526005875283832091168252855220549151911615158152f35b919050346200046b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126200046b5762003642620036b2565b906200364d620039a2565b73ffffffffffffffffffffffffffffffffffffffff8216156200368a575082908180389247905af1156200367f575080f35b63b12d13eb8252601cfd5b9050517f44d99fea000000000000000000000000000000000000000000000000000000008152fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820362000d8e57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820362000d8e57565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820362000d8e57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc604091011262000d8e5773ffffffffffffffffffffffffffffffffffffffff90600435828116810362000d8e5791602435908116810362000d8e5790565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a091011262000d8e5773ffffffffffffffffffffffffffffffffffffffff90600435828116810362000d8e5791602435908116810362000d8e5790604435906064359060843590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc606091011262000d8e5773ffffffffffffffffffffffffffffffffffffffff90600435828116810362000d8e5791602435908116810362000d8e579060443590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc606091011262000d8e5760043573ffffffffffffffffffffffffffffffffffffffff8116810362000d8e57906024359060443590565b67ffffffffffffffff8111620038b757604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117620038b757604052565b81601f8201121562000d8e5780359067ffffffffffffffff8211620038b757604051926200397f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601160185620038e6565b8284526020838301011162000d8e57816000926020809301838601378301015290565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543303620039cd57565b6382b429006000526004601cfd5b15620039e357565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152fd5b9190820391821162003a4f57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60109260209260145260345260446000938480936fa9059cbb00000000000000000000000082525af13d15600183511417161562003abb57603452565b6390b8ec1890526004601cfd5b9190820180921162003a4f57565b601c600060649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d1560016000511417161562003b22576000606052604052565b637939f4246000526004601cfd5b90917f00000000000000000000000000000000000000000000000000000000000027b1811462003ba05773ffffffffffffffffffffffffffffffffffffffff6040921660009181835260126020528383209083526020528282208481540190558152601160205220908154019055565b505050565b9081602091031262000d8e575173ffffffffffffffffffffffffffffffffffffffff8116810362000d8e5790565b919082519283825260005b84811062003c1e5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b60208183018101518483018201520162003bde56fe60c0346100bd57601f6112d738819003918201601f19168301916001600160401b038311848410176100c2578084926020946040528339810103126100bd57516001600160a01b03811681036100bd573360a0526080526040516111fe90816100d982396080518181816104e7015281816106390152818161072e0152818161084c015281816109a80152610b31015260a0518181816102b10152818161048f015281816105f1015281816106e6015281816108050152610aea0152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040526004361015610015575b36610b7b57005b60003560e01c806301ffc9a7146100c5578063150b7a02146100c05780635abfaf6c146100bb57806362ffbaa2146100b657806384276d81146100b157806393f29694146100ac578063a1db9782146100a7578063bc197c81146100a2578063e4128fb31461009d578063f23a6e61146100985763f3e414f80361000e57610a5d565b6109cc565b61095d565b610896565b610778565b610683565b610570565b610431565b610266565b6101d5565b346101845760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610184576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361018457807f4e2312e0000000000000000000000000000000000000000000000000000000006020921490811561015a575b506040519015158152f35b7f01ffc9a7000000000000000000000000000000000000000000000000000000009150143861014f565b600080fd5b73ffffffffffffffffffffffffffffffffffffffff81160361018457565b9181601f840112156101845782359167ffffffffffffffff8311610184576020838186019501011161018457565b346101845760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101845761020f600435610189565b61021a602435610189565b60643567ffffffffffffffff81116101845761023a9036906004016101a7565b505060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b346101845760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261018457602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b9181601f840112156101845782359167ffffffffffffffff8311610184576020808501948460051b01011161018457565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610184576004359067ffffffffffffffff82116101845761034f916004016102d5565b9091565b919082519283825260005b84811061039d5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b60208183018101518483018201520161035e565b602080820190808352835180925260408301928160408460051b8301019501936000915b8483106103e55750505050505090565b9091929394958480610421837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a51610353565b98019301930191949392906103d5565b61043a36610306565b6040517f065b904100000000000000000000000000000000000000000000000000000000815230600482015233602482015290919073ffffffffffffffffffffffffffffffffffffffff9060208160448160007f000000000000000000000000000000000000000000000000000000000000000087165af190811561056b5760009161053d575b50156104e5575b6104e16104d584846110b0565b604051918291826103b1565b0390f35b7f000000000000000000000000000000000000000000000000000000000000000016330361051357386104c8565b60046040517f5c427cd9000000000000000000000000000000000000000000000000000000008152fd5b61055e915060203d8111610564575b6105568183610c6e565b810190610cb4565b386104c1565b503d61054c565b610ccc565b346101845760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610184576040517f065b904100000000000000000000000000000000000000000000000000000000815230600482015233602482015273ffffffffffffffffffffffffffffffffffffffff9060208160448160007f000000000000000000000000000000000000000000000000000000000000000087165af190811561056b57600091610665575b5015610637575b610635600435610cd8565b005b7f0000000000000000000000000000000000000000000000000000000000000000163303610513573861062a565b61067d915060203d8111610564576105568183610c6e565b38610623565b346101845761069136610306565b6040517f065b904100000000000000000000000000000000000000000000000000000000815230600482015233602482015290919073ffffffffffffffffffffffffffffffffffffffff9060208160448160007f000000000000000000000000000000000000000000000000000000000000000087165af190811561056b5760009161075a575b501561072c575b6104e16104d58484610f67565b7f0000000000000000000000000000000000000000000000000000000000000000163303610513573861071f565b610772915060203d8111610564576105568183610c6e565b38610718565b346101845760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610184576004356107b381610189565b6040517f065b904100000000000000000000000000000000000000000000000000000000815230600482015233602482015273ffffffffffffffffffffffffffffffffffffffff9060208160448160007f000000000000000000000000000000000000000000000000000000000000000087165af190811561056b57600091610878575b501561084a575b61063560243583610cf7565b7f0000000000000000000000000000000000000000000000000000000000000000163303610513573861083e565b610890915060203d8111610564576105568183610c6e565b38610837565b346101845760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610184576108d0600435610189565b6108db602435610189565b67ffffffffffffffff604435818111610184576108fc9036906004016102d5565b5050606435818111610184576109169036906004016102d5565b5050608435908111610184576109309036906004016101a7565b50506040517fbc197c81000000000000000000000000000000000000000000000000000000008152602090f35b346101845760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261018457602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101845760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261018457610a06600435610189565b610a11602435610189565b60843567ffffffffffffffff811161018457610a319036906004016101a7565b505060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b346101845760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261018457600435610a9881610189565b6040517f065b904100000000000000000000000000000000000000000000000000000000815230600482015233602482015273ffffffffffffffffffffffffffffffffffffffff9060208160448160007f000000000000000000000000000000000000000000000000000000000000000087165af190811561056b57600091610b5d575b5015610b2f575b61063560243583610d41565b7f00000000000000000000000000000000000000000000000000000000000000001633036105135738610b23565b610b75915060203d8111610564576105568183610c6e565b38610b1c565b3615610c3b576000805b368110610ba8576000388382305af43d6000803e15610ba3573d6000f35b3d6000fd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9181358383011860001a600180809401948215610bec5750508153015b90610b85565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff845290850194607f9250803591011860001a81811115610c30575b160101610be6565b838101388439610c28565b3636f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610caf57604052565b610c3f565b90816020910312610184575180151581036101845790565b6040513d6000823e3d90fd5b60009081803892335af115610ce957565b63b12d13eb6000526004601cfd5b6020906010923360145260345260446000938480936fa9059cbb00000000000000000000000082525af13d156001835114171615610d3457603452565b6390b8ec1890526004601cfd5b73ffffffffffffffffffffffffffffffffffffffff1690813b15610184576000916064839260405194859384927f23b872dd00000000000000000000000000000000000000000000000000000000845230600485015233602485015260448401525af1801561056b57610db15750565b67ffffffffffffffff8111610caf57604052565b67ffffffffffffffff8111610caf5760051b60200190565b90610de782610dc5565b610df46040519182610c6e565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610e228294610dc5565b019060005b828110610e3357505050565b806060602080938501015201610e27565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b35610e7d81610189565b90565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610184570180359067ffffffffffffffff82116101845760200191813603831361018457565b908092918237016000815290565b3d15610f38573d9067ffffffffffffffff8211610caf5760405191610f2c60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610c6e565b82523d6000602084013e565b606090565b8051821015610f515760209160051b010190565b610e44565b906020610e7d928181520190610353565b9190610f7281610ddd565b9260005b828110610f8257505050565b60008160051b8301357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18436030181121561106c5781908401610fcd610fc782610e73565b3b151590565b611025575b505015610fe157600101610f76565b610fee6110219186610f3d565b516040519182917fa5fa8d2b00000000000000000000000000000000000000000000000000000000835260048301610f56565b0390fd5b8161103d61103283610e73565b926020810190610e80565b919061104e60405180948193610ed1565b03925af161105a610edf565b6110648388610f3d565b528038610fd2565b5080fd5b9190811015610f515760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa181360301821215610184570190565b9190916000906110bf84610ddd565b93825b81811061113a5750505034036110d457565b6040517fa5fa8d2b000000000000000000000000000000000000000000000000000000008152806110216004820160609060208152600460208201527f5c63102a0000000000000000000000000000000000000000000000000000000060408201520190565b611145818385611070565b60409081810135809601956000918291611161610fc783610e73565b6111b6575b5050501561117757506001016110c2565b6111846110219288610f3d565b5190519182917fa5fa8d2b00000000000000000000000000000000000000000000000000000000835260048301610f56565b6111c261103283610e73565b91906111d2875180948193610ed1565b03925af16111de610edf565b6111e8848a610f3d565b5280388061116656fea164736f6c6343000813000aa164736f6c6343000813000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.