Sepolia Testnet

Contract

0x0887db9b1df886bA926EA7853f012B26Cf589e47

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Initialize63683412024-07-24 15:46:12137 days ago1721835972IN
0x0887db9b...6Cf589e47
0 ETH0.0025835236.05303116

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
69369672024-10-24 16:23:3644 days ago1729787016
0x0887db9b...6Cf589e47
0.01 ETH
69369672024-10-24 16:23:3644 days ago1729787016
0x0887db9b...6Cf589e47
0.01 ETH
66650672024-09-10 5:56:2489 days ago1725947784
0x0887db9b...6Cf589e47
0.01 ETH
66650672024-09-10 5:56:2489 days ago1725947784
0x0887db9b...6Cf589e47
0.01 ETH
66308902024-09-04 10:54:4895 days ago1725447288
0x0887db9b...6Cf589e47
0.01 ETH
66308902024-09-04 10:54:4895 days ago1725447288
0x0887db9b...6Cf589e47
0.01 ETH
66264482024-09-03 17:21:0095 days ago1725384060
0x0887db9b...6Cf589e47
0.01 ETH
66250462024-09-03 11:59:0096 days ago1725364740
0x0887db9b...6Cf589e47
0.01 ETH
66250462024-09-03 11:59:0096 days ago1725364740
0x0887db9b...6Cf589e47
0.01 ETH
66168512024-09-02 4:58:3697 days ago1725253116
0x0887db9b...6Cf589e47
0.01 ETH
66168512024-09-02 4:58:3697 days ago1725253116
0x0887db9b...6Cf589e47
0.01 ETH
66132962024-09-01 15:25:3698 days ago1725204336
0x0887db9b...6Cf589e47
0.01 ETH
66132962024-09-01 15:25:3698 days ago1725204336
0x0887db9b...6Cf589e47
0.01 ETH
66132942024-09-01 15:25:0098 days ago1725204300
0x0887db9b...6Cf589e47
0.01 ETH
65535902024-08-23 3:52:48107 days ago1724385168
0x0887db9b...6Cf589e47
0.01 ETH
65535902024-08-23 3:52:48107 days ago1724385168
0x0887db9b...6Cf589e47
0.01 ETH
65480522024-08-22 7:04:48108 days ago1724310288
0x0887db9b...6Cf589e47
0.01 ETH
65480522024-08-22 7:04:48108 days ago1724310288
0x0887db9b...6Cf589e47
0.01 ETH
65437632024-08-21 14:50:36109 days ago1724251836
0x0887db9b...6Cf589e47
0.00018008 ETH
65437632024-08-21 14:50:36109 days ago1724251836
0x0887db9b...6Cf589e47
0.00018008 ETH
65437632024-08-21 14:50:36109 days ago1724251836
0x0887db9b...6Cf589e47
0.00018094 ETH
65437632024-08-21 14:50:36109 days ago1724251836
0x0887db9b...6Cf589e47
0.00018094 ETH
65419132024-08-21 7:52:36109 days ago1724226756
0x0887db9b...6Cf589e47
0.01 ETH
65419132024-08-21 7:52:36109 days ago1724226756
0x0887db9b...6Cf589e47
0.01 ETH
65418642024-08-21 7:41:36109 days ago1724226096
0x0887db9b...6Cf589e47
0.01 ETH
View All Internal Transactions
Loading...
Loading

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

Contract Name:
MulticallRootRouterLibZip

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

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

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

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

/**
 * @title  Multicall Root Router LibZip Contract
 * @author MaiaDAO
 * @notice Root Router implementation for interfacing with third-party dApps present in the Root Omnichain Environment.
 * @dev    Func IDs for calling these  functions through the messaging layer:
 *
 *         CROSS-CHAIN MESSAGING FUNCIDs
 *         -----------------------------
 *         FUNC ID      | FUNC NAME
 *         -------------+---------------
 *         0x01         | multicallNoOutput
 *         0x02         | multicallSingleOutput
 *         0x03         | multicallMultipleOutput
 */
contract MulticallRootRouterLibZip is MulticallRootRouter {
    using LibZip for bytes;

    /**
     * @notice Constructor for Multicall Root Router.
     * @param _localChainId The local chain id.
     * @param _localPortAddress The local port address.
     * @param _multicallAddress The address of the Multicall contract.
     */
    constructor(uint256 _localChainId, address _localPortAddress, address _multicallAddress)
        MulticallRootRouter(_localChainId, _localPortAddress, _multicallAddress)
    {}

    /*///////////////////////////////////////////////////////////////
                            DECODING FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     *  @notice Function hook to decode bytes data.
     *  @param data to be decoded.
     *  @return decoded data.
     */
    function _decode(bytes calldata data) internal pure override returns (bytes memory) {
        return data.cdDecompress();
    }
}

File 2 of 13 : 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 3 of 13 : 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 4 of 13 : 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 5 of 13 : 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 6 of 13 : 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 7 of 13 : 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 8 of 13 : 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 9 of 13 : IMulticall2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Multicall2 - Aggregate results from multiple read-only function calls
/// @author Michael Elliot <[email protected]>
/// @author Joshua Levine <[email protected]>
/// @author Nick Johnson <[email protected]>

interface IMulticall2 {
    struct Call {
        address target;
        bytes callData;
    }

    struct Result {
        bool success;
        bytes returnData;
    }

    function aggregate(Call[] memory calls) external returns (uint256 blockNumber, bytes[] memory returnData);
}

File 10 of 13 : 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(uint32 indexed _settlementNonce, address _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 11 of 13 : 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 12 of 13 : 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();

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

File 13 of 13 : MulticallRootRouter.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 {IMulticall2 as IMulticall} from "./interfaces/IMulticall2.sol";
import {
    GasParams,
    IRootBridgeAgent as IBridgeAgent,
    SettlementInput,
    SettlementMultipleInput
} from "./interfaces/IRootBridgeAgent.sol";
import {IRootRouter, DepositParams, DepositMultipleParams} from "./interfaces/IRootRouter.sol";
import {IVirtualAccount, Call} from "./interfaces/IVirtualAccount.sol";

/// @notice Multicall Root Router parameters with token output information.
/// @param settlementOwner settlement owner and excess gas receiver, can retry/retrieve/redeem.
/// @param recipient Address to receive the output assets in the destination chain.
/// @param outputToken Address of the output hToken.
/// @param amountOut Amount of output hTokens to send to destination.
/// @param depositOut Amount of underlying tokens to clear in destination.
struct OutputParams {
    address settlementOwner;
    address recipient;
    address outputToken;
    uint256 amountOut;
    uint256 depositOut;
}

/// @notice Multicall Root Router parameters with multiple token output information.
/// @param settlementOwner settlement owner and excess gas receiver, can retry/retrieve/redeem.
/// @param recipient Address to receive the output assets in the destination chain.
/// @param outputTokens Addresses of the output hTokens.
/// @param amountsOut Total amount of tokens to send to destination.
/// @param depositsOut Amounts of underlying tokens to clear in destination.
struct OutputMultipleParams {
    address settlementOwner;
    address recipient;
    address[] outputTokens;
    uint256[] amountsOut;
    uint256[] depositsOut;
}

/**
 * @title  Multicall Root Router Contract
 * @author MaiaDAO
 * @notice Root Router implementation for interfacing with third-party dApps present in the Root Omnichain Environment.
 * @dev    Func IDs for calling these  functions through the messaging layer:
 *
 *         CROSS-CHAIN MESSAGING FUNCIDs
 *         -----------------------------
 *         FUNC ID      | FUNC NAME
 *         -------------+---------------
 *         0x01         | multicallNoOutput
 *         0x02         | multicallSingleOutput
 *         0x03         | multicallMultipleOutput
 */
contract MulticallRootRouter is Ownable, ReentrancyGuard, IRootRouter {
    using SafeTransferLib for address;

    /*///////////////////////////////////////////////////////////////
                            CONSTANTS
    ///////////////////////////////////////////////////////////////*/

    /// @dev Used for identifying cases when this contract's balance of a token is to be used as an input
    /// This value is equivalent to 1<<255, i.e. a singular 1 in the most significant bit.
    uint256 internal constant CONTRACT_BALANCE = 0x8000000000000000000000000000000000000000000000000000000000000000;

    /*///////////////////////////////////////////////////////////////
                    MULTICALL ROOT ROUTER STATE
    ///////////////////////////////////////////////////////////////*/

    /// @notice Root Chain Layer Zero Identifier.
    uint256 public immutable localChainId;

    /// @notice Address for Local Port Address where assets are stored and managed.
    address public immutable localPortAddress;

    /// @notice Root Chain Multicall Address.
    address public immutable multicallAddress;

    /// @notice Bridge Agent to manage communications and cross-chain assets.
    address payable public bridgeAgentAddress;

    /// @notice Bridge Agent Executor Address.
    address public bridgeAgentExecutorAddress;

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

    /**
     * @notice Constructor for Multicall Root Router.
     * @param _localChainId local layer zero chain id.
     * @param _localPortAddress address of the root Port.
     * @param _multicallAddress address of the Multicall contract.
     */
    constructor(uint256 _localChainId, address _localPortAddress, address _multicallAddress) {
        require(_localPortAddress != address(0), "Local Port Address cannot be 0");
        require(_multicallAddress != address(0), "Multicall Address cannot be 0");

        localChainId = _localChainId;
        localPortAddress = _localPortAddress;
        multicallAddress = _multicallAddress;
        _initializeOwner(msg.sender);
    }

    /*///////////////////////////////////////////////////////////////
                        INITIALIZATION FUNCTIONS
    ///////////////////////////////////////////////////////////////*/
    /**
     * @notice Initializes the Multicall Root Router.
     * @param _bridgeAgentAddress The address of the Bridge Agent.
     */
    function initialize(address _bridgeAgentAddress) external onlyOwner {
        require(_bridgeAgentAddress != address(0), "Bridge Agent Address cannot be 0");
        renounceOwnership();

        bridgeAgentAddress = payable(_bridgeAgentAddress);
        bridgeAgentExecutorAddress = IBridgeAgent(_bridgeAgentAddress).bridgeAgentExecutorAddress();
    }

    /*///////////////////////////////////////////////////////////////
                            USER FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     *  @notice Function to call 'callOutAndBridge' on RootBridgeAgent.
     *  @param settlementOwner settlement owner and excess gas receiver.
     *  @param recipient Address to receive the output assets.
     *  @param outputToken Address of the output hToken.
     *  @param amountOut Amount of output hTokens to send.
     *  @param depositOut Amount of output hTokens to deposit.
     *  @param dstChainId Chain Id of the destination chain.
     *  @param gasParams Amounts of tokens to withdraw from the destination port.
     */
    function callOutAndBridge(
        address settlementOwner,
        address recipient,
        address outputToken,
        uint256 amountOut,
        uint256 depositOut,
        uint16 dstChainId,
        GasParams memory gasParams
    ) external payable virtual {
        outputToken.safeTransferFrom(msg.sender, address(this), amountOut);

        _approveAndCallOut(settlementOwner, recipient, outputToken, amountOut, depositOut, dstChainId, gasParams);
    }

    /**
     *  @notice Function to call 'callOutAndBridgeMultiple' on RootBridgeAgent.
     *  @param settlementOwner settlement owner and excess gas receiver.
     *  @param recipient Address to receive the output assets.
     *  @param outputTokens Addresses of the output hTokens.
     *  @param amountsOut Total amount of tokens to send.
     *  @param depositsOut Amounts of tokens to withdraw from the destination port.
     *  @param gasParams Amounts of tokens to withdraw from the destination port.
     */
    function callOutAndBridgeMultiple(
        address settlementOwner,
        address recipient,
        address[] memory outputTokens,
        uint256[] memory amountsOut,
        uint256[] memory depositsOut,
        uint16 dstChainId,
        GasParams memory gasParams
    ) external payable virtual {
        for (uint256 i = 0; i < outputTokens.length;) {
            outputTokens[i].safeTransferFrom(msg.sender, address(this), amountsOut[i]);

            unchecked {
                ++i;
            }
        }

        _approveMultipleAndCallOut(
            settlementOwner, recipient, outputTokens, amountsOut, depositsOut, dstChainId, gasParams
        );
    }

    /// @inheritdoc IRootRouter
    function retrySettlement(
        uint32 _settlementNonce,
        address _recipient,
        bytes calldata,
        GasParams calldata _gParams,
        bool _hasFallbackToggled
    ) external payable override {
        /// @dev Payload is empty because the current BranchRouter does not support receiving a payload.
        // Perform call to bridge agent.
        IBridgeAgent(bridgeAgentAddress).retrySettlement{value: msg.value}(
            msg.sender, _settlementNonce, _recipient, "", _gParams, _hasFallbackToggled
        );
    }

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

    /// @inheritdoc IRootRouter
    function executeRetrySettlement(
        address _owner,
        uint32 _settlementNonce,
        address _recipient,
        bytes calldata,
        GasParams calldata _gParams,
        bool _hasFallbackToggled,
        uint16
    ) public payable override requiresBridgeAgent {
        /// @dev Payload is empty because the current BranchRouter does not support receiving a payload.
        // Perform call to bridge agent.
        IBridgeAgent(bridgeAgentAddress).retrySettlement{value: msg.value}(
            _owner, _settlementNonce, _recipient, "", _gParams, _hasFallbackToggled
        );
    }

    /**
     *  @inheritdoc IRootRouter
     *  @dev FuncIDs
     *
     *  FUNC ID      | FUNC NAME
     *  0x01         |  multicallNoOutput
     *  0x02         |  multicallSingleOutput
     *  0x03         |  multicallMultipleOutput
     *
     */
    function execute(bytes calldata encodedData, uint16) external payable override nonReentrant requiresExecutor {
        // Parse funcId
        bytes1 funcId = encodedData[0];

        /// FUNC ID: 1 (multicallNoOutput)
        if (funcId == 0x01) {
            // Decode Params
            (IMulticall.Call[] memory callData) = abi.decode(_decode(encodedData[1:]), (IMulticall.Call[]));

            // Perform Calls
            _multicall(callData);

            // If there was any ETH sent in this call, send it to the Root Port.
            if (msg.value > 0) localPortAddress.safeTransferETH(msg.value);

            /// FUNC ID: 2 (multicallSingleOutput)
        } else if (funcId == 0x02) {
            // Decode Params
            (
                IMulticall.Call[] memory callData,
                OutputParams memory outputParams,
                uint16 dstChainId,
                GasParams memory gasParams
            ) = abi.decode(_decode(encodedData[1:]), (IMulticall.Call[], OutputParams, uint16, GasParams));

            // Perform Calls
            _multicall(callData);

            // Bridge Out assets
            _approveAndCallOut(
                outputParams.settlementOwner,
                outputParams.recipient,
                outputParams.outputToken,
                outputParams.amountOut,
                outputParams.depositOut,
                dstChainId,
                gasParams
            );

            /// FUNC ID: 3 (multicallMultipleOutput)
        } else if (funcId == 0x03) {
            // Decode Params
            (
                IMulticall.Call[] memory callData,
                OutputMultipleParams memory outputParams,
                uint16 dstChainId,
                GasParams memory gasParams
            ) = abi.decode(_decode(encodedData[1:]), (IMulticall.Call[], OutputMultipleParams, uint16, GasParams));

            // Perform Calls
            _multicall(callData);

            // Bridge Out assets
            _approveMultipleAndCallOut(
                outputParams.settlementOwner,
                outputParams.recipient,
                outputParams.outputTokens,
                outputParams.amountsOut,
                outputParams.depositsOut,
                dstChainId,
                gasParams
            );
            /// UNRECOGNIZED FUNC ID
        } else {
            revert UnrecognizedFunctionId();
        }
    }

    ///@inheritdoc IRootRouter
    function executeDepositSingle(bytes calldata, DepositParams calldata, uint16) external payable override {
        revert();
    }

    ///@inheritdoc IRootRouter
    function executeDepositMultiple(bytes calldata, DepositMultipleParams calldata, uint16) external payable {
        revert();
    }

    ///  @inheritdoc IRootRouter
    function executeSigned(bytes calldata encodedData, address userAccount, uint16)
        external
        payable
        override
        nonReentrant
        requiresExecutor
    {
        _executeSigned(encodedData, userAccount);
    }

    ///  @inheritdoc IRootRouter
    function executeSignedDepositSingle(bytes calldata encodedData, DepositParams calldata, address userAccount, uint16)
        external
        payable
        override
        requiresExecutor
        nonReentrant
    {
        _executeSigned(encodedData, userAccount);
    }

    ///  @inheritdoc IRootRouter
    function executeSignedDepositMultiple(
        bytes calldata encodedData,
        DepositMultipleParams calldata,
        address userAccount,
        uint16
    ) external payable override requiresExecutor nonReentrant {
        _executeSigned(encodedData, userAccount);
    }

    /**
     *  @dev FuncIDs
     *
     *  FUNC ID      | FUNC NAME
     *  0x01         |  multicallNoOutput
     *  0x02         |  multicallSingleOutput
     *  0x03         |  multicallMultipleOutput
     */
    function _executeSigned(bytes calldata encodedData, address userAccount) internal {
        // Parse funcId
        bytes1 funcId = encodedData[0];

        /// FUNC ID: 1 (multicallNoOutput)
        if (funcId == 0x01) {
            // Decode Params
            Call[] memory calls = abi.decode(_decode(encodedData[1:]), (Call[]));

            // Make requested calls
            IVirtualAccount(userAccount).call(calls);

            // If there was any ETH sent in this call, send it to the virtual account owner.
            if (msg.value > 0) IVirtualAccount(userAccount).userAddress().safeTransferETH(msg.value);

            /// FUNC ID: 2 (multicallSingleOutput)
        } else if (funcId == 0x02) {
            // Decode Params
            (Call[] memory calls, OutputParams memory outputParams, uint16 dstChainId, GasParams memory gasParams) =
                abi.decode(_decode(encodedData[1:]), (Call[], OutputParams, uint16, GasParams));

            // Make requested calls
            IVirtualAccount(userAccount).call(calls);

            // use amountOut == CONTRACT_BALANCE as a flag to swap the entire balance of the contract
            if (outputParams.amountOut == CONTRACT_BALANCE) {
                uint256 virtualBalance = outputParams.outputToken.balanceOf(userAccount);
                outputParams.depositOut = virtualBalance;
                outputParams.amountOut = virtualBalance;
            }

            // Withdraw assets from Virtual Account
            IVirtualAccount(userAccount).withdrawERC20(outputParams.outputToken, outputParams.amountOut);

            // Bridge Out assets
            _approveAndCallOut(
                outputParams.settlementOwner,
                outputParams.recipient,
                outputParams.outputToken,
                outputParams.amountOut,
                outputParams.depositOut,
                dstChainId,
                gasParams
            );

            /// FUNC ID: 3 (multicallMultipleOutput)
        } else if (funcId == 0x03) {
            // Decode Params
            (
                Call[] memory calls,
                OutputMultipleParams memory outputParams,
                uint16 dstChainId,
                GasParams memory gasParams
            ) = abi.decode(_decode(encodedData[1:]), (Call[], OutputMultipleParams, uint16, GasParams));

            // Make requested calls
            IVirtualAccount(userAccount).call(calls);

            // Withdraw assets from Virtual Account
            for (uint256 i = 0; i < outputParams.outputTokens.length;) {
                // use amountOut == CONTRACT_BALANCE as a flag to swap the entire balance of the contract
                if (outputParams.amountsOut[i] == CONTRACT_BALANCE) {
                    uint256 virtualBalance = outputParams.outputTokens[i].balanceOf(userAccount);
                    outputParams.depositsOut[i] = virtualBalance;
                    outputParams.amountsOut[i] = virtualBalance;
                }

                IVirtualAccount(userAccount).withdrawERC20(outputParams.outputTokens[i], outputParams.amountsOut[i]);

                unchecked {
                    ++i;
                }
            }

            // Bridge Out assets
            _approveMultipleAndCallOut(
                outputParams.settlementOwner,
                outputParams.recipient,
                outputParams.outputTokens,
                outputParams.amountsOut,
                outputParams.depositsOut,
                dstChainId,
                gasParams
            );
            /// UNRECOGNIZED FUNC ID
        } else {
            revert UnrecognizedFunctionId();
        }
    }

    /*///////////////////////////////////////////////////////////////
                          MULTICALL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     *  @notice Function to perform a set of actions on the omnichain environment without using the user's Virtual Acccount.
     *  @param calls to be executed.
     */
    function _multicall(IMulticall.Call[] memory calls)
        internal
        returns (uint256 blockNumber, bytes[] memory returnData)
    {
        // Make requested calls
        (blockNumber, returnData) = IMulticall(multicallAddress).aggregate(calls);
    }

    /*///////////////////////////////////////////////////////////////
                              INTERNAL HOOKS
    ///////////////////////////////////////////////////////////////*/

    /**
     *  @notice Function to approve token spend before Bridge Agent interaction to Bridge Out of omnichain environment.
     *  @param settlementOwner settlement owner and excess gas receiver.
     *  @param recipient Address to receive the output assets.
     *  @param outputToken Address of the output hToken.
     *  @param amountOut Amount of output hTokens to send.
     *  @param depositOut Amount of output hTokens to deposit.
     *  @param dstChainId Chain Id of the destination chain.
     */
    function _approveAndCallOut(
        address settlementOwner,
        address recipient,
        address outputToken,
        uint256 amountOut,
        uint256 depositOut,
        uint16 dstChainId,
        GasParams memory gasParams
    ) internal virtual {
        if (amountOut - depositOut > 0) {
            // Approve Root Port to spend/send output hTokens.
            outputToken.safeApprove(localPortAddress, amountOut - depositOut);
        }

        //Move output hTokens from Root to Branch and call 'clearToken'.
        IBridgeAgent(bridgeAgentAddress).callOutAndBridge{value: msg.value}(
            payable(settlementOwner),
            recipient,
            dstChainId,
            "",
            SettlementInput(outputToken, amountOut, depositOut),
            gasParams,
            false
        );
    }

    /**
     *  @notice Function to approve multiple token spend before Bridge Agent interaction to Bridge Out of omnichain environment.
     *  @param settlementOwner settlement owner and excess gas receiver.
     *  @param recipient Address to receive the output assets.
     *  @param outputTokens Addresses of the output hTokens.
     *  @param amountsOut Total amount of tokens to send.
     *  @param depositsOut Amounts of tokens to withdraw from the destination port.
     *
     */
    function _approveMultipleAndCallOut(
        address settlementOwner,
        address recipient,
        address[] memory outputTokens,
        uint256[] memory amountsOut,
        uint256[] memory depositsOut,
        uint16 dstChainId,
        GasParams memory gasParams
    ) internal virtual {
        // For each output token
        for (uint256 i = 0; i < outputTokens.length;) {
            if (amountsOut[i] - depositsOut[i] > 0) {
                // Approve Root Port to spend output hTokens.
                outputTokens[i].safeApprove(localPortAddress, amountsOut[i] - depositsOut[i]);
            }

            unchecked {
                ++i;
            }
        }

        //Move output hTokens from Root to Branch and call 'clearTokens'.
        IBridgeAgent(bridgeAgentAddress).callOutAndBridgeMultiple{value: msg.value}(
            payable(settlementOwner),
            recipient,
            dstChainId,
            "",
            SettlementMultipleInput(outputTokens, amountsOut, depositsOut),
            gasParams,
            false
        );
    }

    /*///////////////////////////////////////////////////////////////
                            DECODING FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     *  @notice Function hook to decode bytes data.
     *  @param data to be decoded.
     *  @return decoded data.
     */
    function _decode(bytes calldata data) internal pure virtual returns (bytes memory) {
        return data;
    }

    /// @notice Verifies the caller is the Bridge Agent Executor.
    modifier requiresExecutor() {
        if (msg.sender != bridgeAgentExecutorAddress) revert UnrecognizedBridgeAgentExecutor();
        _;
    }

    /// @notice Verifies the caller is the Bridge Agent Executor.
    modifier requiresBridgeAgent() {
        if (msg.sender != bridgeAgentAddress) revert UnrecognizedBridgeAgent();
        _;
    }
}

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"},{"internalType":"address","name":"_localPortAddress","type":"address"},{"internalType":"address","name":"_multicallAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnrecognizedBridgeAgent","type":"error"},{"inputs":[],"name":"UnrecognizedBridgeAgentExecutor","type":"error"},{"inputs":[],"name":"UnrecognizedFunctionId","type":"error"},{"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"},{"inputs":[],"name":"bridgeAgentAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridgeAgentExecutorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"settlementOwner","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"depositOut","type":"uint256"},{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"remoteBranchExecutionGas","type":"uint256"}],"internalType":"struct GasParams","name":"gasParams","type":"tuple"}],"name":"callOutAndBridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"settlementOwner","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address[]","name":"outputTokens","type":"address[]"},{"internalType":"uint256[]","name":"amountsOut","type":"uint256[]"},{"internalType":"uint256[]","name":"depositsOut","type":"uint256[]"},{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"remoteBranchExecutionGas","type":"uint256"}],"internalType":"struct GasParams","name":"gasParams","type":"tuple"}],"name":"callOutAndBridgeMultiple","outputs":[],"stateMutability":"payable","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":[{"internalType":"bytes","name":"encodedData","type":"bytes"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"},{"components":[{"internalType":"uint8","name":"numberOfAssets","type":"uint8"},{"internalType":"uint32","name":"depositNonce","type":"uint32"},{"internalType":"address[]","name":"hTokens","type":"address[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"deposits","type":"uint256[]"}],"internalType":"struct DepositMultipleParams","name":"","type":"tuple"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"executeDepositMultiple","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"},{"components":[{"internalType":"uint32","name":"depositNonce","type":"uint32"},{"internalType":"address","name":"hToken","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deposit","type":"uint256"}],"internalType":"struct DepositParams","name":"","type":"tuple"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"executeDepositSingle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint32","name":"_settlementNonce","type":"uint32"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"bytes","name":"","type":"bytes"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"remoteBranchExecutionGas","type":"uint256"}],"internalType":"struct GasParams","name":"_gParams","type":"tuple"},{"internalType":"bool","name":"_hasFallbackToggled","type":"bool"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"executeRetrySettlement","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedData","type":"bytes"},{"internalType":"address","name":"userAccount","type":"address"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"executeSigned","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedData","type":"bytes"},{"components":[{"internalType":"uint8","name":"numberOfAssets","type":"uint8"},{"internalType":"uint32","name":"depositNonce","type":"uint32"},{"internalType":"address[]","name":"hTokens","type":"address[]"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"deposits","type":"uint256[]"}],"internalType":"struct DepositMultipleParams","name":"","type":"tuple"},{"internalType":"address","name":"userAccount","type":"address"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"executeSignedDepositMultiple","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedData","type":"bytes"},{"components":[{"internalType":"uint32","name":"depositNonce","type":"uint32"},{"internalType":"address","name":"hToken","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deposit","type":"uint256"}],"internalType":"struct DepositParams","name":"","type":"tuple"},{"internalType":"address","name":"userAccount","type":"address"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"executeSignedDepositSingle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridgeAgentAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"localChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"localPortAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multicallAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"uint32","name":"_settlementNonce","type":"uint32"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"bytes","name":"","type":"bytes"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"remoteBranchExecutionGas","type":"uint256"}],"internalType":"struct GasParams","name":"_gParams","type":"tuple"},{"internalType":"bool","name":"_hasFallbackToggled","type":"bool"}],"name":"retrySettlement","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"}]

Deployed Bytecode

0x608060408181526004918236101561001657600080fd5b600092833560e01c91826301510d37146113745750816308178604146113055781631f74bed3146111c657816324e7315914611173578163256929621461110a5781633779da4f1461109657816337dcb53014610fdf5781634a6a99d914610e72578163546af93114610e1f57816354d1f13d14610dbb5781635abfaf6c14610d4c5781635b056da514610cf3578163617ef5b714610c88578163715018a614610c085781637d0cfac814610b825781638c252780146107a15781638da5cb5b1461072f578163a094139e14610667578163c4d66de81461049b578163e6901932146102f5578163f04e283e1461022b578163f2fde38b14610176575063fee81cf41461012257600080fd5b346101725760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101725760209161015c6114b5565b9063389a75e1600c525281600c20549051908152f35b5080fd5b839060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610172576101aa6114b5565b906101b361169f565b8160601b15610220575073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a35580f35b637448fbae8352601cfd5b8360207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f25761025e6114b5565b61026661169f565b63389a75e1600c528082526020600c2092835442116102e757508173ffffffffffffffffffffffffffffffffffffffff929355167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a35580f35b636f5e88188352601cfd5b80fd5b8391506101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101725761032b6114b5565b9260243563ffffffff811680910361048e5761034561146f565b9460643567ffffffffffffffff8111610497576103659036908601611441565b5050827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c3601126104935760c4359586151580970361048e576103a66114e9565b5073ffffffffffffffffffffffffffffffffffffffff918260015416803303610466578798813b156104625784610104948a9789519a8b9889977f795454910000000000000000000000000000000000000000000000000000000089521690870152602486015216604484015260e06064840152600060e4840152608435608484015260a43560a484015260c483015234905af190811561045957506104495750f35b6104529061150b565b6102f25780f35b513d84823e3d90fd5b8880fd5b8686517f541ba3f8000000000000000000000000000000000000000000000000000000008152fd5b600080fd5b8480fd5b8580fd5b90503461066357602091827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105f6576104d66114b5565b916104df61169f565b73ffffffffffffffffffffffffffffffffffffffff80931693841561060a5761050661169f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a355807fffffffffffffffffffffffff000000000000000000000000000000000000000095808760015416176001558451938480927f546af9310000000000000000000000000000000000000000000000000000000082525afa928315610601575085926105c7575b50501690600254161760025580f35b90809250813d83116105fa575b6105de81836115a2565b810103126105f6576105ef906116d7565b38806105b8565b8380fd5b503d6105d4565b513d87823e3d90fd5b8060649351927f08c379a000000000000000000000000000000000000000000000000000000000845283015260248201527f427269646765204167656e7420416464726573732063616e6e6f7420626520306044820152fd5b8280fd5b838360607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017257823567ffffffffffffffff8111610663576106b19036908501611441565b906106ba611492565b926106c36114fa565b506106d16001865414611794565b6002855573ffffffffffffffffffffffffffffffffffffffff6002541633036107075750610700939450611d2e565b6001815580f35b8590517ffeb51801000000000000000000000000000000000000000000000000000000008152fd5b50503461017257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101725760209073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754915191168152f35b918091507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106635767ffffffffffffffff908235828111610493576107ed9036908501611441565b909160243561ffff81160361048e5760019461080b86885414611794565b6002875573ffffffffffffffffffffffffffffffffffffffff9081600254163303610b5b578315610b2f5784357fff00000000000000000000000000000000000000000000000000000000000000167f0100000000000000000000000000000000000000000000000000000000000000810361092f5750505050808411610493576108c391847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108be93019101612a21565b612a57565b9081518201916020818403126104935760208101519182116104935760206108f392816108f8950192010161189b565b6124b8565b505034610905575b815580f35b610900347f000000000000000000000000800de4d33015feb4e344951ace8ea2f4f33ae529611b58565b9294919391927f02000000000000000000000000000000000000000000000000000000000000008103610a21575050808611610a1d5761099791867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108be93019101612a21565b90815182016101208360208301920312610a1d576020830151948511610a1d576109c98160206109009786010161189b565b936109f96109f36109dc84848801611afd565b936101006109ec60e08901611ac6565b9701611ad5565b956124b8565b50508282511692806020840151169183015116906080606084015193015193612649565b8680fd5b7f030000000000000000000000000000000000000000000000000000000000000003610b085750808611610a1d57610a8191867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108be93019101612a21565b908151820160a08360208301920312610a1d576020830151858111610b0457816020610aaf9286010161189b565b9380840151958611610b0457610ae26109f3610ad38460206109009a8901016119d3565b9360806109ec60608901611ac6565b50508282511692602083015116908201519060806060840151930151936127f9565b8780fd5b84517f48d3a3f7000000000000000000000000000000000000000000000000000000008152fd5b8760326024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b82517ffeb51801000000000000000000000000000000000000000000000000000000008152fd5b839060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101725780359067ffffffffffffffff821161066357610bcc91369101611441565b505060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126102f25760c43561ffff81160361048e5780fd5b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f257610c3a61169f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b83907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60608136011261066357813567ffffffffffffffff9283821161049357610cd491369101611441565b50506024359182116106635760c091360301126102f2576101726114fa565b50503461017257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017257602090517f00000000000000000000000000000000000000000000000000000000000027b18152f35b50503461017257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610172576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000800de4d33015feb4e344951ace8ea2f4f33ae529168152f35b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f25763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b50503461017257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101725760209073ffffffffffffffffffffffffffffffffffffffff600254169051908152f35b8391506101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017257610ea86114b5565b91610eb1611492565b67ffffffffffffffff926044358481116105f657366023820112156105f6578082013590610eea610ee183611629565b985198896115a2565b8188526020916024838a019160051b83010191368311610a1d57602401905b828210610fb357505050506064358481116105f657610f2b9036908301611641565b936084359081116105f657610f4291369101611641565b610f4a6114d8565b90610f54366115e3565b92845b8851811015610fa25780610f9c73ffffffffffffffffffffffffffffffffffffffff610f856001948d611751565b5116610f91838b611751565b5190309033906116f8565b01610f57565b509487610fb09596886127f9565b80f35b813573ffffffffffffffffffffffffffffffffffffffff8116810361048e578152908301908301610f09565b83836101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261017257823567ffffffffffffffff81116106635761102a9036908501611441565b9060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126105f65760c4359273ffffffffffffffffffffffffffffffffffffffff808516850361048e5761107f6114e9565b506002541633036107075750610fb0939450611b76565b836101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f257610fb06110cd6114b5565b6110d5611492565b906110de61146f565b906064356110ea6114d8565b926110f4366115e3565b94611101833033856116f8565b60843593612649565b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102f25763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b50503461017257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101725760209073ffffffffffffffffffffffffffffffffffffffff600154169051908152f35b91905060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106635782823563ffffffff81168091036101725761120c611492565b9360443567ffffffffffffffff81116105f65761122c9036908301611441565b5050837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c3601126106635760a435908115158092036105f65773ffffffffffffffffffffffffffffffffffffffff91826001541690813b156104975761010493875198899687957f795454910000000000000000000000000000000000000000000000000000000087523390870152602486015216604484015260e060648401528560e4840152606435608484015260843560a484015260c483015234905af190811561045957506112fc575080f35b610fb09061150b565b50503461017257817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610172576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ca11bde05977b3631167028862be2a173976ca11168152f35b84907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6080813601126106635767ffffffffffffffff8435818111610493576113c09036908701611441565b929091602435908111610497579060c091360301126105f6576113e161146f565b9260643561ffff8116036104935773ffffffffffffffffffffffffffffffffffffffff60025416330361141a5750610fb0939450611b76565b807ffeb5180100000000000000000000000000000000000000000000000000000000879252fd5b9181601f8401121561048e5782359167ffffffffffffffff831161048e576020838186019501011161048e57565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361048e57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361048e57565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361048e57565b60a4359061ffff8216820361048e57565b60e4359061ffff8216820361048e57565b6044359061ffff8216820361048e57565b67ffffffffffffffff811161151f57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff82111761151f57604052565b60a0810190811067ffffffffffffffff82111761151f57604052565b6060810190811067ffffffffffffffff82111761151f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761151f57604052565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c604091011261048e576040519061161a8261154e565b60c435825260e4356020830152565b67ffffffffffffffff811161151f5760051b60200190565b81601f8201121561048e5780359161165883611629565b9261166660405194856115a2565b808452602092838086019260051b82010192831161048e578301905b828210611690575050505090565b81358152908301908301611682565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275433036116c957565b6382b429006000526004601cfd5b519073ffffffffffffffffffffffffffffffffffffffff8216820361048e57565b601c600060649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d15600160005114171615611743576000606052604052565b637939f4246000526004601cfd5b80518210156117655760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b1561179b57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152fd5b67ffffffffffffffff811161151f57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b8381106118465750506000910152565b8181015183820152602001611836565b81601f8201121561048e57805161186c816117f9565b9261187a60405194856115a2565b8184526020828401011161048e576118989160208085019101611833565b90565b81601f8201121561048e578051906118b282611629565b926040926118c2845195866115a2565b808552602093848087019260051b8501019383851161048e57858101925b8584106118f1575050505050505090565b835167ffffffffffffffff9081811161048e57830191847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848903011261048e57845161193d8161154e565b6119488a85016116d7565b81528584015192831161048e57611966888b80969581960101611856565b838201528152019301926118e0565b81601f8201121561048e5780519161198c83611629565b9261199a60405194856115a2565b808452602092838086019260051b82010192831161048e578301905b8282106119c4575050505090565b815181529083019083016119b6565b919060a08382031261048e57604051906119ec8261156a565b81936119f7816116d7565b8352602091611a078383016116d7565b8385015260408201519267ffffffffffffffff9384811161048e5783019082601f8301121561048e57815191611a3c83611629565b92611a4a60405194856115a2565b808452828085019160051b8301019185831161048e578301905b828210611aaf57505050506040850152606082015183811161048e5781611a8c918401611975565b6060850152608082015192831161048e57608092611aaa9201611975565b910152565b838091611abb846116d7565b815201910190611a64565b519061ffff8216820361048e57565b919082604091031261048e57604051611aed8161154e565b6020808294805184520151910152565b91908260a091031261048e57604051611b158161156a565b6080808294611b23816116d7565b8452611b31602082016116d7565b6020850152611b42604082016116d7565b6040850152606081015160608501520151910152565b600080809338935af115611b6857565b63b12d13eb6000526004601cfd5b90611b949291611b8a600160005414611794565b6002600055611d2e565b6001600055565b9080601f8301121561048e57815190611bb382611629565b92611bc160405194856115a2565b828452602092838086019160051b8301019280841161048e57848301915b848310611bef5750505050505090565b825167ffffffffffffffff811161048e578691611c1184848094890101611856565b815201920191611bdf565b9060208282031261048e57815167ffffffffffffffff811161048e576118989201611b9b565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602060609473ffffffffffffffffffffffffffffffffffffffff8151168552015160406020850152611ca78151809281604088015260208888019101611833565b0116010190565b602080820190808352835180925260408301928160408460051b8301019501936000915b848310611ce25750505050505090565b9091929394958480611d1e837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528a51611c42565b9801930193019194939290611cd2565b9080156117655781357fff00000000000000000000000000000000000000000000000000000000000000167f01000000000000000000000000000000000000000000000000000000000000008103611f2957508060011161048e57611dbc9160017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108be93019101612a21565b8051810190602091828282031261048e578282015167ffffffffffffffff811161048e57611e439284611e09928173ffffffffffffffffffffffffffffffffffffffff950192010161189b565b931692604051907f93f296940000000000000000000000000000000000000000000000000000000082528180600094859360048301611cae565b038183885af18015611f1e57611efc575b5034611e61575b5050505b565b81600493604051948580927fe4128fb30000000000000000000000000000000000000000000000000000000082525afa918215611eef578192611eb5575b5050611ead91503490611b58565b388080611e5b565b90915082813d8311611ee8575b611ecc81836115a2565b810103126102f25750611ee1611ead916116d7565b3880611e9f565b503d611ec2565b50604051903d90823e3d90fd5b611f17903d8084833e611f0f81836115a2565b810190611c1c565b5038611e54565b6040513d84823e3d90fd5b9293927f0200000000000000000000000000000000000000000000000000000000000000810361217a57508060011161048e57611f8f9160017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108be93019101612a21565b918251830192610120816020860195031261048e5760208101519367ffffffffffffffff851161048e57611fcb8160206120469785010161189b565b90604093611ff5611fde83878701611afd565b92610100611fee60e08801611ac6565b9601611ad5565b9473ffffffffffffffffffffffffffffffffffffffff93848316908251907f93f29694000000000000000000000000000000000000000000000000000000008252818060009c8d9360048301611cae565b038183865af1801561217057612156575b5060608401927f8000000000000000000000000000000000000000000000000000000000000000845114612139575b5081840191898684511692855190803b156106635783517fa1db978200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff95909516600486015260248501919091528390604490829084905af19081156121305750611e5f989950612121575b506080848451169480602086015116925116925193015193612649565b61212a9061150b565b38612104565b513d8b823e3d90fd5b61214890868487015116612489565b806080860152835238612086565b612169903d808c833e611f0f81836115a2565b5038612057565b83513d8c823e3d90fd5b909391907f03000000000000000000000000000000000000000000000000000000000000000361245f5760019380851161048e576121e091857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6108be93019101612a21565b90815182019060a0836020840193031261048e5760208301519067ffffffffffffffff9182811161048e5783602061221a9287010161189b565b956040928386015190811161048e57846020612238928801016119d3565b9161225361224860608801611ac6565b956080809801611ad5565b9573ffffffffffffffffffffffffffffffffffffffff948583169080519a7f93f29694000000000000000000000000000000000000000000000000000000008c5260008c8181819f6122a9600496878301611cae565b038183895af18015612455579088959493929161243a575b5092909192958389019660608a01985b6122fa575b505050505050611e5f979850848451169460208501511691519251930151936127f9565b875151811015612435578e878b8d848c878f612338847f80000000000000000000000000000000000000000000000000000000000000009251611751565b51146123fa575b509091935061234f925051611751565b51169061235d838c51611751565b51853b156101725787517fa1db978200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909316878401908152602081019190915282908190604001038183885af180156123ed57918796959493929187926123de575b500190919293946122d1565b6123e79061150b565b386123d2565b508f8651903d90823e3d90fd5b61241d9361240c846124139451611751565b5116612489565b9384930151611751565b52612429838c51611751565b52878b8d848c8761233f565b6122d6565b61244d913d8091833e611f0f81836115a2565b508c386122c1565b84513d84823e3d90fd5b60046040517f48d3a3f7000000000000000000000000000000000000000000000000000000008152fd5b602460106020939284936014526f70a082310000000000000000000000006000525afa601f3d11166020510290565b604051907f252dba42000000000000000000000000000000000000000000000000000000008252602482019082602092836004830152825180915260448201908460448260051b8501019401916000905b868383106125c55750505050508060009203818373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ca11bde05977b3631167028862be2a173976ca11165af19081156125b957600092839261256d575b50509091565b9091509291923d8085833e61258281836115a2565b810190604081830312610493578051928101519067ffffffffffffffff8211610497576125b29394955001611b9b565b3880612567565b6040513d6000823e3d90fd5b6125fe877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc83949698600196989a030186528851611c42565b96019201920186939192612509565b9190820391821161261a57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9593929194909461265a848461260d565b612743575b73ffffffffffffffffffffffffffffffffffffffff91826001541696836040519361268985611586565b1683526020830194855260408301958652873b1561048e578390816040519a7ffe2beab9000000000000000000000000000000000000000000000000000000008c521660048b015216602489015261ffff166044880152606487016101409052610144870160009052511660848601525160a48501525160c4840152805160e484015260200151610104830152610124820160009052813491815a9361016492600095f180156125b95761273a5750565b611e5f9061150b565b612777612750858561260d565b7f000000000000000000000000800de4d33015feb4e344951ace8ea2f4f33ae5298361277c565b61265f565b60109260209260145260345260446000938480936f095ea7b300000000000000000000000082525af13d1560018351141716156127b857603452565b633e3f8f7390526004601cfd5b90815180825260208080930193019160005b8281106127e5575050505090565b8351855293810193928101926001016127d7565b9590919496929660005b86518110156128ab5780878a8261283161281f60019684611751565b5161282a838d611751565b519061260d565b61283f575b50505001612803565b6128708173ffffffffffffffffffffffffffffffffffffffff61286861287b946128a397611751565b511693611751565b5161282a858c611751565b907f000000000000000000000000800de4d33015feb4e344951ace8ea2f4f33ae5299061277c565b878a82612836565b50929695909391949573ffffffffffffffffffffffffffffffffffffffff966001908882541697604051916128df83611586565b825260209687830194855260408301968752893b1561048e5761ffff908b80937ffec7336a000000000000000000000000000000000000000000000000000000009b999795969c9a989d6040519e8f9d8e521660048d01521660248b0152166044890152610100606489015260006101048901526101206084890152610184880192519260606101248a01528351809152856101a48a019401916000905b828210612a075750505050600097508694928594926129cd6129df9351917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedc9283898303016101448a01526127c5565b915190868303016101648701526127c5565b91805160a4850152015160c48301528560e4830152039134905af180156125b95761273a5750565b8351811686528c9a509487019492870192908b019061297d565b90612a2b816117f9565b91612a3960405193846115a2565b818352368282011161048e5781600092602092838601378301015290565b90606091805180612a66575050565b91925060405160208101936004830193845190840193811986525b809685821015612aff5760018092019760ff808a5116918215612aac575050815301945b9495612a81565b60020180517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8552909a50607f9250908490821683811115612af4575b505016010194612aa5565b013884398338612ae9565b93965050909360209350527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848203018452600081520160405256fea164736f6c6343000813000a

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.