S Price: $0.509981 (+0.54%)

Contract

0xa465E96470f0919B2fb91b2f88D57DeAfB1D766a

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Call Out And Bri...109592442025-03-01 10:53:316 days ago1740826411IN
0xa465E964...AfB1D766a
30 S0.0449670751.5
Call Out And Bri...109565842025-03-01 10:35:576 days ago1740825357IN
0xa465E964...AfB1D766a
10 S0.0441827751.5
Call Out And Bri...109534032025-03-01 10:15:436 days ago1740824143IN
0xa465E964...AfB1D766a
10 S0.0441839151.5
Call Out And Bri...109508462025-03-01 9:59:376 days ago1740823177IN
0xa465E964...AfB1D766a
10 S0.0441811251.5
Call Out And Bri...109502932025-03-01 9:56:046 days ago1740822964IN
0xa465E964...AfB1D766a
10 S0.0457662951.5
Retry Deposit109501622025-03-01 9:55:176 days ago1740822917IN
0xa465E964...AfB1D766a
10 S0.0277995451.5
Initialize34725022025-01-11 23:18:0755 days ago1736637487IN
0xa465E964...AfB1D766a
0 S0.000520175.5

Latest 6 internal transactions

Parent Transaction Hash Block From To
109592442025-03-01 10:53:316 days ago1740826411
0xa465E964...AfB1D766a
30 S
109565842025-03-01 10:35:576 days ago1740825357
0xa465E964...AfB1D766a
10 S
109534032025-03-01 10:15:436 days ago1740824143
0xa465E964...AfB1D766a
10 S
109508462025-03-01 9:59:376 days ago1740823177
0xa465E964...AfB1D766a
10 S
109502932025-03-01 9:56:046 days ago1740822964
0xa465E964...AfB1D766a
10 S
109501622025-03-01 9:55:176 days ago1740822917
0xa465E964...AfB1D766a
10 S
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BaseBranchRouter

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion
File 1 of 9 : BaseBranchRouter.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 {ERC20} from "lib/solmate/src/tokens/ERC20.sol";
import {ReentrancyGuard} from "lib/solmate/src/utils/ReentrancyGuard.sol";

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

import {
    IBranchBridgeAgent as IBridgeAgent,
    GasParams,
    Deposit,
    DepositInput,
    DepositParams,
    DepositMultipleInput,
    DepositMultipleParams,
    SettlementParams,
    SettlementMultipleParams
} from "./interfaces/IBranchBridgeAgent.sol";

/// @title Base Branch Router Contract
/// @author MaiaDAO
contract BaseBranchRouter is IBranchRouter, ReentrancyGuard, Ownable {
    using SafeTransferLib for address;

    /*///////////////////////////////////////////////////////////////
                    BASE BRANCH ROUTER STATE
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IBranchRouter
    address public localPortAddress;

    /// @inheritdoc IBranchRouter
    address public override localBridgeAgentAddress;

    /// @inheritdoc IBranchRouter
    address public override bridgeAgentExecutorAddress;

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

    /// @notice Constructor for Base Branch Router.
    constructor() {
        _initializeOwner(msg.sender);
    }

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

    /**
     * @notice Initializes the Base Branch Router.
     * @param _localBridgeAgentAddress The address of the local Bridge Agent.
     */
    function initialize(address _localBridgeAgentAddress) public virtual onlyOwner {
        require(_localBridgeAgentAddress != address(0), "Bridge Agent address cannot be 0");
        renounceOwnership();

        localBridgeAgentAddress = _localBridgeAgentAddress;
        localPortAddress = IBridgeAgent(_localBridgeAgentAddress).localPortAddress();
        bridgeAgentExecutorAddress = IBridgeAgent(_localBridgeAgentAddress).bridgeAgentExecutorAddress();
    }

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

    /// @inheritdoc IBranchRouter
    function getDepositEntry(uint32 _depositNonce) external view override returns (Deposit memory) {
        return IBridgeAgent(localBridgeAgentAddress).getDepositEntry(_depositNonce);
    }

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

    /// @inheritdoc IBranchRouter
    function callOut(bytes calldata _params, GasParams calldata _gParams)
        external
        payable
        virtual
        override
        nonReentrant
    {
        IBridgeAgent(localBridgeAgentAddress).callOut{value: msg.value}(payable(msg.sender), _params, _gParams);
    }

    /// @inheritdoc IBranchRouter
    function callOutAndBridge(bytes calldata _params, DepositInput calldata _dParams, GasParams calldata _gParams)
        external
        payable
        virtual
        override
        nonReentrant
    {
        //Transfer tokens to this contract.
        _transferAndApproveToken(_dParams.hToken, _dParams.token, _dParams.amount, _dParams.deposit);

        //Perform call to bridge agent.
        IBridgeAgent(localBridgeAgentAddress).callOutAndBridge{value: msg.value}(
            payable(msg.sender), _params, _dParams, _gParams
        );
    }

    /// @inheritdoc IBranchRouter
    function callOutAndBridgeMultiple(
        bytes calldata _params,
        DepositMultipleInput calldata _dParams,
        GasParams calldata _gParams
    ) external payable virtual override nonReentrant {
        //Transfer tokens to this contract.
        _transferAndApproveMultipleTokens(_dParams);

        //Perform call to bridge agent.
        IBridgeAgent(localBridgeAgentAddress).callOutAndBridgeMultiple{value: msg.value}(
            payable(msg.sender), _params, _dParams, _gParams
        );
    }

    /// @inheritdoc IBranchRouter
    function retryDeposit(uint32 _depositNonce, bytes calldata _params, GasParams calldata _gParams)
        external
        payable
        virtual
        override
    {
        // Perform call to bridge agent.
        IBridgeAgent(localBridgeAgentAddress).retryDeposit{value: msg.value}(
            msg.sender, _depositNonce, _params, _gParams
        );
    }

    /*///////////////////////////////////////////////////////////////
                 BRIDGE AGENT EXECUTOR EXTERNAL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IBranchRouter
    function executeNoSettlement(bytes calldata) external payable virtual override {
        revert UnrecognizedFunctionId();
    }

    /// @inheritdoc IBranchRouter
    function executeSettlement(bytes calldata, SettlementParams memory) external payable virtual override {
        revert UnrecognizedFunctionId();
    }

    /// @inheritdoc IBranchRouter
    function executeSettlementMultiple(bytes calldata, SettlementMultipleParams memory)
        external
        payable
        virtual
        override
    {
        revert UnrecognizedFunctionId();
    }

    /*///////////////////////////////////////////////////////////////
                           INTERNAL FUNCTIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Internal function to transfer token into a contract.
     *   @param _hToken The address of the hToken.
     *   @param _token The address of the token.
     *   @param _amount The amount of the hToken.
     *   @param _deposit The amount of the token.
     */
    function _transferAndApproveToken(address _hToken, address _token, uint256 _amount, uint256 _deposit)
        internal
        virtual
    {
        // Check if the local branch tokens are being spent
        if (_amount - _deposit > 0) {
            unchecked {
                _hToken.safeTransferFrom(msg.sender, address(this), _amount - _deposit);
            }
        }

        // Check if the underlying tokens are being spent
        if (_deposit > 0) {
            _token.safeTransferFrom(msg.sender, address(this), _deposit);
            _token.safeApprove(localPortAddress, _deposit);
        }
    }

    /**
     * @notice Internal function to transfer multiple tokens into a contract.
     *   @param _dParams The DepositMultipleInput struct
     */
    function _transferAndApproveMultipleTokens(DepositMultipleInput calldata _dParams) internal {
        uint256 len = _dParams.hTokens.length;
        for (uint256 i = 0; i < len;) {
            _transferAndApproveToken(_dParams.hTokens[i], _dParams.tokens[i], _dParams.amounts[i], _dParams.deposits[i]);

            unchecked {
                ++i;
            }
        }
    }

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

    /// @notice Modifier that verifies msg sender is the Bridge Agent Executor.
    modifier requiresAgentExecutor() {
        if (msg.sender != bridgeAgentExecutorAddress) revert UnrecognizedBridgeAgentExecutor();
        _;
    }
}

File 2 of 9 : 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 3 of 9 : 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)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.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();

    /// @dev The Permit2 operation has failed.
    error Permit2Failed();

    /// @dev The Permit2 amount must be less than `2**160 - 1`.
    error Permit2AmountOverflow();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         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;

    /// @dev The unique EIP-712 domain domain separator for the DAI token contract.
    bytes32 internal constant DAI_DOMAIN_SEPARATOR =
        0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;

    /// @dev The address for the WETH9 contract on Ethereum mainnet.
    address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    /// @dev The canonical Permit2 address.
    /// [Github](https://github.com/Uniswap/permit2)
    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
    address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       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 `amount` of ERC20 `token` from `from` to `to`.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function trySafeTransferFrom(address token, address from, address to, uint256 amount)
        internal
        returns (bool success)
    {
        /// @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)`.
            success :=
                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(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( // The arguments of `mul` are evaluated from right to left.
                    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)
                    )
                )
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// If the initial attempt fails, try to use Permit2 to transfer the token.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
        if (!trySafeTransferFrom(token, from, to, amount)) {
            permit2TransferFrom(token, from, to, amount);
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.
    /// Reverts upon failure.
    function permit2TransferFrom(address token, address from, address to, uint256 amount)
        internal
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(add(m, 0x74), shr(96, shl(96, token)))
            mstore(add(m, 0x54), amount)
            mstore(add(m, 0x34), to)
            mstore(add(m, 0x20), shl(96, from))
            // `transferFrom(address,address,uint160,address)`.
            mstore(m, 0x36c78516000000000000000000000000)
            let p := PERMIT2
            let exists := eq(chainid(), 1)
            if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
            if iszero(and(call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00), exists)) {
                mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
            }
        }
    }

    /// @dev Permit a user to spend a given amount of
    /// another user's tokens via native EIP-2612 permit if possible, falling
    /// back to Permit2 if native permit fails or is not implemented on the token.
    function permit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        bool success;
        /// @solidity memory-safe-assembly
        assembly {
            for {} shl(96, xor(token, WETH9)) {} {
                mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.
                if iszero(
                    and( // The arguments of `and` are evaluated from right to left.
                        lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.
                        // Gas stipend to limit gas burn for tokens that don't refund gas when
                        // an non-existing function is called. 5K should be enough for a SLOAD.
                        staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
                    )
                ) { break }
                // After here, we can be sure that token is a contract.
                let m := mload(0x40)
                mstore(add(m, 0x34), spender)
                mstore(add(m, 0x20), shl(96, owner))
                mstore(add(m, 0x74), deadline)
                if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
                    mstore(0x14, owner)
                    mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.
                    mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
                    mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
                    // `nonces` is already at `add(m, 0x54)`.
                    // `1` is already stored at `add(m, 0x94)`.
                    mstore(add(m, 0xb4), and(0xff, v))
                    mstore(add(m, 0xd4), r)
                    mstore(add(m, 0xf4), s)
                    success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
                    break
                }
                mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.
                mstore(add(m, 0x54), amount)
                mstore(add(m, 0x94), and(0xff, v))
                mstore(add(m, 0xb4), r)
                mstore(add(m, 0xd4), s)
                success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
                break
            }
        }
        if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
    }

    /// @dev Simple permit on the Permit2 contract.
    function simplePermit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, 0x927da105) // `allowance(address,address,address)`.
            {
                let addressMask := shr(96, not(0))
                mstore(add(m, 0x20), and(addressMask, owner))
                mstore(add(m, 0x40), and(addressMask, token))
                mstore(add(m, 0x60), and(addressMask, spender))
                mstore(add(m, 0xc0), and(addressMask, spender))
            }
            let p := mul(PERMIT2, iszero(shr(160, amount)))
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.
                    staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
                )
            ) {
                mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(p))), 0x04)
            }
            mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).
            // `owner` is already `add(m, 0x20)`.
            // `token` is already at `add(m, 0x40)`.
            mstore(add(m, 0x60), amount)
            mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.
            // `nonce` is already at `add(m, 0xa0)`.
            // `spender` is already at `add(m, 0xc0)`.
            mstore(add(m, 0xe0), deadline)
            mstore(add(m, 0x100), 0x100) // `signature` offset.
            mstore(add(m, 0x120), 0x41) // `signature` length.
            mstore(add(m, 0x140), r)
            mstore(add(m, 0x160), s)
            mstore(add(m, 0x180), shl(248, v))
            if iszero(call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00)) {
                mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

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

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

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

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

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

    string public name;

    string public symbol;

    uint8 public immutable decimals;

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

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

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

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

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

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

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

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

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

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

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

        return true;
    }

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

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

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

        return true;
    }

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

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

        balanceOf[from] -= amount;

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

        emit Transfer(from, to, amount);

        return true;
    }

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

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

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

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

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

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

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

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

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

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

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

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

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

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

File 5 of 9 : 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 6 of 9 : 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 7 of 9 : IBranchBridgeAgent.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 8 of 9 : IBranchRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {
    GasParams,
    Deposit,
    DepositInput,
    DepositMultipleInput,
    SettlementParams,
    SettlementMultipleParams
} from "./IBranchBridgeAgent.sol";

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

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

    /// @notice Address for local Branch Bridge Agent who processes requests and interacts with local port.
    function localBridgeAgentAddress() external view returns (address);

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

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

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

    /**
     * @notice Function to perform a call to the Root Omnichain Router without token deposit.
     *   @param params enconded parameters to execute on the root chain.
     *   @param gParams gas parameters for the cross-chain call.
     *   @dev ACTION ID: 1 (Call without deposit)
     *
     */
    function callOut(bytes calldata params, GasParams calldata gParams) external payable;

    /**
     * @notice Function to perform a call to the Root Omnichain Router while depositing a single asset.
     *   @param params encoded parameters to execute on the root chain.
     *   @param dParams additional token deposit parameters.
     *   @param gParams gas parameters for the cross-chain call.
     *   @dev ACTION ID: 2 (Call with single deposit)
     *
     */
    function callOutAndBridge(bytes calldata params, DepositInput calldata dParams, GasParams calldata gParams)
        external
        payable;

    /**
     * @notice Function to perform a call to the Root Omnichain Router while depositing two or more assets.
     *   @param params encoded parameters to execute on the root chain.
     *   @param dParams additional token deposit parameters.
     *   @param gParams gas parameters for the cross-chain call.
     *   @dev ACTION ID: 3 (Call with multiple deposit)
     *
     */
    function callOutAndBridgeMultiple(
        bytes calldata params,
        DepositMultipleInput calldata dParams,
        GasParams calldata gParams
    ) external payable;

    /**
     * @notice Function to retry a deposit that has failed.
     *   @param _depositNonce Identifier for user deposit.
     *   @param _params encoded router parameters to execute on the root chain.
     *   @param _gParams gas parameters for the cross-chain call.
     */
    function retryDeposit(uint32 _depositNonce, bytes calldata _params, GasParams calldata _gParams) external payable;

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

    /**
     * @notice Function responsible of executing a branch router response.
     *   @param params data received from messaging layer.
     */
    function executeNoSettlement(bytes calldata params) external payable;

    /**
     * @dev Function responsible of executing a crosschain request without any deposit.
     *   @param params data received from messaging layer.
     *   @param sParams SettlementParams struct.
     */
    function executeSettlement(bytes calldata params, SettlementParams calldata sParams) external payable;

    /**
     * @dev Function responsible of executing a crosschain request which contains
     *      cross-chain deposit information attached.
     *   @param params data received from messaging layer.
     *   @param sParams SettlementParams struct containing deposit information.
     *
     */
    function executeSettlementMultiple(bytes calldata params, SettlementMultipleParams calldata sParams)
        external
        payable;

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

    /// @notice Error emitted when the Branch Router does not recognize the function ID.
    error UnrecognizedFunctionId();

    /// @notice Error emitted when caller is not the Branch Bridge Agent Executor.
    error UnrecognizedBridgeAgentExecutor();
}

File 9 of 9 : 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;
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[],"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":"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":"bridgeAgentExecutorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_params","type":"bytes"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"remoteBranchExecutionGas","type":"uint256"}],"internalType":"struct GasParams","name":"_gParams","type":"tuple"}],"name":"callOut","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_params","type":"bytes"},{"components":[{"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 DepositInput","name":"_dParams","type":"tuple"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"remoteBranchExecutionGas","type":"uint256"}],"internalType":"struct GasParams","name":"_gParams","type":"tuple"}],"name":"callOutAndBridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_params","type":"bytes"},{"components":[{"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 DepositMultipleInput","name":"_dParams","type":"tuple"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"remoteBranchExecutionGas","type":"uint256"}],"internalType":"struct GasParams","name":"_gParams","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":"","type":"bytes"}],"name":"executeNoSettlement","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"},{"components":[{"internalType":"uint32","name":"settlementNonce","type":"uint32"},{"internalType":"address","name":"recipient","type":"address"},{"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 SettlementParams","name":"","type":"tuple"}],"name":"executeSettlement","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"},{"components":[{"internalType":"uint8","name":"numberOfAssets","type":"uint8"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint32","name":"settlementNonce","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 SettlementMultipleParams","name":"","type":"tuple"}],"name":"executeSettlementMultiple","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_depositNonce","type":"uint32"}],"name":"getDepositEntry","outputs":[{"components":[{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"uint88","name":"isSigned","type":"uint88"},{"internalType":"address","name":"owner","type":"address"},{"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 Deposit","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_localBridgeAgentAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"localBridgeAgentAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"localPortAddress","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":"_depositNonce","type":"uint32"},{"internalType":"bytes","name":"_params","type":"bytes"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"remoteBranchExecutionGas","type":"uint256"}],"internalType":"struct GasParams","name":"_gParams","type":"tuple"}],"name":"retryDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"}]

6080806040523461004a57600160005533638b78c6d819553360007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3611b4b90816100508239f35b600080fdfe6040608081526004908136101561001557600080fd5b60009160e0908335821c918263158599501461127b5782631e2bcb1a1461101b5782632569296214610fb257826346fcff1814610f3d57826351e372b014610def578263546af93114610d9b57826354d1f13d14610d375782635abfaf6c14610ce3578263715018a614610c6357826383dd527d146109b75784836384cb82b614610885575082638da5cb5b14610812578263c4d66de8146105b5578263cd9f603114610561578263f04e283e14610499578263f2fde38b146103e457848363f4f79eb51461029c57508263fa536bec1461014f57505063fee81cf4146100fb57600080fd5b3461014b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5760209161013561150b565b9063389a75e1600c525281600c20549051908152f35b5080fd5b8484917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102995767ffffffffffffffff90833582811161014b5761019a903690860161141a565b505060c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc360112610299575081519060c082019081118282101761026b57825260243563ffffffff811681036102665781526101f56114e8565b602082015273ffffffffffffffffffffffffffffffffffffffff60643581811681036102665783830152608435908116810361026657606082015260a435608082015260a060c435910152517f48d3a3f7000000000000000000000000000000000000000000000000000000008152fd5b600080fd5b6041847f4e487b71000000000000000000000000000000000000000000000000000000006000525260246000fd5b80fd5b80838660607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e057813567ffffffffffffffff81116103db576102e7903690840161141a565b9290827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103d75761031f60018654146117d9565b6002855573ffffffffffffffffffffffffffffffffffffffff60025416803b156103d35761038b9486938551968794859384937f114357cb000000000000000000000000000000000000000000000000000000008552339085015260806024850152608484019161183e565b60243560448301526044356064830152039134905af19081156103ca57506103b6575b506001905580f35b6103bf90611448565b6102995780826103ae565b513d84823e3d90fd5b8580fd5b8480fd5b505050fd5b5050fd5b848260207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5761041861150b565b906104216116bc565b8160601b1561048e575073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a35580f35b637448fbae8352601cfd5b508360207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610299576104cd61150b565b6104d56116bc565b63389a75e1600c528082526020600c20928354421161055657508173ffffffffffffffffffffffffffffffffffffffff929355167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a35580f35b636f5e88188352601cfd5b5050503461014b57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5760209073ffffffffffffffffffffffffffffffffffffffff600254169051908152f35b5090503461080e57602091827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261075a576105f161150b565b916105fa6116bc565b73ffffffffffffffffffffffffffffffffffffffff8093169384156107b5576106216116bc565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3557fffffffffffffffffffffffff0000000000000000000000000000000000000000948086600254161760025583517f5abfaf6c00000000000000000000000000000000000000000000000000000000815282818581855afa9081156107ab5783929187918a9161076e575b50168760015416176001558451938480927f546af9310000000000000000000000000000000000000000000000000000000082525afa9283156107655750859261072b575b50501690600354161760035580f35b90809250813d831161075e575b61074281836114a7565b8101031261075a57610753906116f4565b388061071c565b8380fd5b503d610738565b513d87823e3d90fd5b938092508491503d83116107a4575b61078781836114a7565b810103126107a0578561079a84936116f4565b386106d7565b8780fd5b503d61077d565b85513d8a823e3d90fd5b8060649351927f08c379a000000000000000000000000000000000000000000000000000000000845283015260248201527f427269646765204167656e7420616464726573732063616e6e6f7420626520306044820152fd5b8280fd5b5050503461014b57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5760209073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754915191168152f35b80838660807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e0576108ba61154f565b9160243567ffffffffffffffff81116103d7576108da903690830161141a565b93837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc3601126103d35773ffffffffffffffffffffffffffffffffffffffff6002541690813b156109b357869361097863ffffffff948751988996879586957f5515a133000000000000000000000000000000000000000000000000000000008752339087015216602485015260a0604485015260a484019161183e565b61098e6064830160443581526020606435910152565b039134905af19081156103ca57506109a35750f35b6109ac90611448565b6102995780f35b8680fd5b9150923461029957602092837ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b579060c0916109f761154f565b918151610a038161148b565b81815281878201528183820152606094818680809401528260808201528260a082015201528063ffffffff602473ffffffffffffffffffffffffffffffffffffffff95866002541686519b8c9485937f83dd527d00000000000000000000000000000000000000000000000000000000855216908301525afa968715610c57578197610b3f575b6affffffffffffffffffffff87610b3b8a89610ad78a8a8a805198888a998a5260ff885116818b01528701511681890152850151168187015283015182608087015261010086019061163e565b9060c0610b2a610b176080860151947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868a83030160a08b015261163e565b60a08601518589830301848a0152611688565b930151918584030190850152611688565b0390f35b909196503d8083833e610b5281836114a7565b810190868183031261080e57805167ffffffffffffffff918282116103d75701868184031261075a57885193610b878561148b565b815160ff8116810361014b578552888201516affffffffffffffffffffff8116810361014b5789860152610bbc8a83016116f4565b8a8601528682015183811161014b5784610bd7918401611715565b87860152608082015183811161014b5784610bf3918401611715565b608086015260a082015183811161014b5784610c1091840161177b565b60a086015260c0820151928311610299575092610c456affffffffffffffffffffff999693610b3b989693610ad7960161177b565b60c08201529750929481949250610a8a565b509051903d90823e3d90fd5b84807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261029957610c956116bc565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b5050503461014b57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5760209073ffffffffffffffffffffffffffffffffffffffff600154169051908152f35b84807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102995763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b5050503461014b57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b8484917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc90838236011261080e5767ffffffffffffffff9085358281116103d757610e3d903690880161141a565b5050602435928284116103d757833603011261080e57835192610e5f8461148b565b8286013560ff8116810361014b578452610e7b6024840161152e565b6020850152604483013563ffffffff811681036102665785850152606483013582811161014b57610eb19087369186010161157a565b6060850152608483013582811161014b57610ed19087369186010161157a565b608085015260a483013582811161014b57610ef1908736918601016115e0565b60a085015260c4830135918211610299575060c09185610f1492369201016115e0565b910152517f48d3a3f7000000000000000000000000000000000000000000000000000000008152fd5b50828460207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102995782359067ffffffffffffffff82116102995750610f8a903690840161141a565b5050517f48d3a3f7000000000000000000000000000000000000000000000000000000008152fd5b84807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102995763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b5083837ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60808136011261080e5767ffffffffffffffff9184358381116103d757611069903690870161141a565b93906024359182116103d35781870160808584360301126109b357837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc3601126109b3576001979497956110bf878954146117d9565b600288556110cd8280611aab565b9690508899602486019760646044880197019b5b818110611219575050899a73ffffffffffffffffffffffffffffffffffffffff60029b9a9b541694853b15611215578a9789519a8b98899788977f6dfb0dd800000000000000000000000000000000000000000000000000000000895233908901526024880160a0905260a48801906111599261183e565b9486860301604487015261116d838061189e565b60808752608087019061117f926118f1565b9061118a908461189e565b868303602088015261119c92916118f1565b906111a7908361189e565b8583038c8701526111b89291611944565b916111c29161189e565b909280830390606001526111d592611944565b606482016111ec9060443581526020606435910152565b039134905af19081156103ca575061120357505580f35b61120c90611448565b61014b57815580f35b8a80fd5b806112758b8f8b8f958061124e8d946112678361124e6112606112548361124e61125961125461126e9c8f8061124e91611aab565b90611aff565b61187d565b9d8d611aab565b9789611aab565b3595611aab565b3592611981565b016110e1565b909291507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261080e5782823567ffffffffffffffff811161014b576112c6903690850161141a565b60807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261080e57837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5c36011261080e5761132660018454146117d9565b600283556024359073ffffffffffffffffffffffffffffffffffffffff958683168084036103d35760443588811681036109b35761136d6064359586608435938492611981565b886002541694853b156107a0576113c29989519a8b98899788977fa507c5430000000000000000000000000000000000000000000000000000000089523390890152610100602489015261010488019161183e565b9360448601526113d06114e8565b166064850152608484015260a483015260a43560c483015260c43560e4830152039134905af19081156103ca575061140b575b506001815580f35b61141490611448565b38611403565b9181601f840112156102665782359167ffffffffffffffff8311610266576020838186019501011161026657565b67ffffffffffffffff811161145c57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60e0810190811067ffffffffffffffff82111761145c57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761145c57604052565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361026657565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361026657565b359073ffffffffffffffffffffffffffffffffffffffff8216820361026657565b6004359063ffffffff8216820361026657565b67ffffffffffffffff811161145c5760051b60200190565b81601f820112156102665780359161159183611562565b9261159f60405194856114a7565b808452602092838086019260051b820101928311610266578301905b8282106115c9575050505090565b8380916115d58461152e565b8152019101906115bb565b81601f82011215610266578035916115f783611562565b9261160560405194856114a7565b808452602092838086019260051b820101928311610266578301905b82821061162f575050505090565b81358152908301908301611621565b90815180825260208080930193019160005b82811061165e575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101611650565b90815180825260208080930193019160005b8281106116a8575050505090565b83518552938101939281019260010161169a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275433036116e657565b6382b429006000526004601cfd5b519073ffffffffffffffffffffffffffffffffffffffff8216820361026657565b81601f820112156102665780519161172c83611562565b9261173a60405194856114a7565b808452602092838086019260051b820101928311610266578301905b828210611764575050505090565b838091611770846116f4565b815201910190611756565b81601f820112156102665780519161179283611562565b926117a060405194856114a7565b808452602092838086019260051b820101928311610266578301905b8282106117ca575050505090565b815181529083019083016117bc565b156117e057565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152fd5b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b3573ffffffffffffffffffffffffffffffffffffffff811681036102665790565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561026657016020813591019167ffffffffffffffff8211610266578160051b3603831361026657565b91908082526020809201929160005b82811061190e575050505090565b90919293828060019273ffffffffffffffffffffffffffffffffffffffff6119358961152e565b16815201950193929101611900565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116102665760209260051b809284830137010190565b90929182810390808211611a23578303611a0f575b5050806119a1575050565b601091816119b3602093303385611a52565b73ffffffffffffffffffffffffffffffffffffffff6001541660145260345260446000938480936f095ea7b300000000000000000000000082525af13d156001835114171615611a0257603452565b633e3f8f7390526004601cfd5b611a1c9130903390611a52565b3880611996565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b601c600060649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d15600160005114171615611a9d576000606052604052565b637939f4246000526004601cfd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610266570180359067ffffffffffffffff821161026657602001918160051b3603831361026657565b9190811015611b0f5760051b0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c6343000813000a

Deployed Bytecode

0x6040608081526004908136101561001557600080fd5b60009160e0908335821c918263158599501461127b5782631e2bcb1a1461101b5782632569296214610fb257826346fcff1814610f3d57826351e372b014610def578263546af93114610d9b57826354d1f13d14610d375782635abfaf6c14610ce3578263715018a614610c6357826383dd527d146109b75784836384cb82b614610885575082638da5cb5b14610812578263c4d66de8146105b5578263cd9f603114610561578263f04e283e14610499578263f2fde38b146103e457848363f4f79eb51461029c57508263fa536bec1461014f57505063fee81cf4146100fb57600080fd5b3461014b5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5760209161013561150b565b9063389a75e1600c525281600c20549051908152f35b5080fd5b8484917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102995767ffffffffffffffff90833582811161014b5761019a903690860161141a565b505060c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc360112610299575081519060c082019081118282101761026b57825260243563ffffffff811681036102665781526101f56114e8565b602082015273ffffffffffffffffffffffffffffffffffffffff60643581811681036102665783830152608435908116810361026657606082015260a435608082015260a060c435910152517f48d3a3f7000000000000000000000000000000000000000000000000000000008152fd5b600080fd5b6041847f4e487b71000000000000000000000000000000000000000000000000000000006000525260246000fd5b80fd5b80838660607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e057813567ffffffffffffffff81116103db576102e7903690840161141a565b9290827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103d75761031f60018654146117d9565b6002855573ffffffffffffffffffffffffffffffffffffffff60025416803b156103d35761038b9486938551968794859384937f114357cb000000000000000000000000000000000000000000000000000000008552339085015260806024850152608484019161183e565b60243560448301526044356064830152039134905af19081156103ca57506103b6575b506001905580f35b6103bf90611448565b6102995780826103ae565b513d84823e3d90fd5b8580fd5b8480fd5b505050fd5b5050fd5b848260207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5761041861150b565b906104216116bc565b8160601b1561048e575073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a35580f35b637448fbae8352601cfd5b508360207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610299576104cd61150b565b6104d56116bc565b63389a75e1600c528082526020600c20928354421161055657508173ffffffffffffffffffffffffffffffffffffffff929355167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a35580f35b636f5e88188352601cfd5b5050503461014b57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5760209073ffffffffffffffffffffffffffffffffffffffff600254169051908152f35b5090503461080e57602091827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261075a576105f161150b565b916105fa6116bc565b73ffffffffffffffffffffffffffffffffffffffff8093169384156107b5576106216116bc565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3557fffffffffffffffffffffffff0000000000000000000000000000000000000000948086600254161760025583517f5abfaf6c00000000000000000000000000000000000000000000000000000000815282818581855afa9081156107ab5783929187918a9161076e575b50168760015416176001558451938480927f546af9310000000000000000000000000000000000000000000000000000000082525afa9283156107655750859261072b575b50501690600354161760035580f35b90809250813d831161075e575b61074281836114a7565b8101031261075a57610753906116f4565b388061071c565b8380fd5b503d610738565b513d87823e3d90fd5b938092508491503d83116107a4575b61078781836114a7565b810103126107a0578561079a84936116f4565b386106d7565b8780fd5b503d61077d565b85513d8a823e3d90fd5b8060649351927f08c379a000000000000000000000000000000000000000000000000000000000845283015260248201527f427269646765204167656e7420616464726573732063616e6e6f7420626520306044820152fd5b8280fd5b5050503461014b57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5760209073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754915191168152f35b80838660807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103e0576108ba61154f565b9160243567ffffffffffffffff81116103d7576108da903690830161141a565b93837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc3601126103d35773ffffffffffffffffffffffffffffffffffffffff6002541690813b156109b357869361097863ffffffff948751988996879586957f5515a133000000000000000000000000000000000000000000000000000000008752339087015216602485015260a0604485015260a484019161183e565b61098e6064830160443581526020606435910152565b039134905af19081156103ca57506109a35750f35b6109ac90611448565b6102995780f35b8680fd5b9150923461029957602092837ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b579060c0916109f761154f565b918151610a038161148b565b81815281878201528183820152606094818680809401528260808201528260a082015201528063ffffffff602473ffffffffffffffffffffffffffffffffffffffff95866002541686519b8c9485937f83dd527d00000000000000000000000000000000000000000000000000000000855216908301525afa968715610c57578197610b3f575b6affffffffffffffffffffff87610b3b8a89610ad78a8a8a805198888a998a5260ff885116818b01528701511681890152850151168187015283015182608087015261010086019061163e565b9060c0610b2a610b176080860151947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868a83030160a08b015261163e565b60a08601518589830301848a0152611688565b930151918584030190850152611688565b0390f35b909196503d8083833e610b5281836114a7565b810190868183031261080e57805167ffffffffffffffff918282116103d75701868184031261075a57885193610b878561148b565b815160ff8116810361014b578552888201516affffffffffffffffffffff8116810361014b5789860152610bbc8a83016116f4565b8a8601528682015183811161014b5784610bd7918401611715565b87860152608082015183811161014b5784610bf3918401611715565b608086015260a082015183811161014b5784610c1091840161177b565b60a086015260c0820151928311610299575092610c456affffffffffffffffffffff999693610b3b989693610ad7960161177b565b60c08201529750929481949250610a8a565b509051903d90823e3d90fd5b84807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261029957610c956116bc565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b5050503461014b57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5760209073ffffffffffffffffffffffffffffffffffffffff600154169051908152f35b84807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102995763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b5050503461014b57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014b5760209073ffffffffffffffffffffffffffffffffffffffff600354169051908152f35b8484917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc90838236011261080e5767ffffffffffffffff9085358281116103d757610e3d903690880161141a565b5050602435928284116103d757833603011261080e57835192610e5f8461148b565b8286013560ff8116810361014b578452610e7b6024840161152e565b6020850152604483013563ffffffff811681036102665785850152606483013582811161014b57610eb19087369186010161157a565b6060850152608483013582811161014b57610ed19087369186010161157a565b608085015260a483013582811161014b57610ef1908736918601016115e0565b60a085015260c4830135918211610299575060c09185610f1492369201016115e0565b910152517f48d3a3f7000000000000000000000000000000000000000000000000000000008152fd5b50828460207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102995782359067ffffffffffffffff82116102995750610f8a903690840161141a565b5050517f48d3a3f7000000000000000000000000000000000000000000000000000000008152fd5b84807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102995763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b5083837ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60808136011261080e5767ffffffffffffffff9184358381116103d757611069903690870161141a565b93906024359182116103d35781870160808584360301126109b357837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc3601126109b3576001979497956110bf878954146117d9565b600288556110cd8280611aab565b9690508899602486019760646044880197019b5b818110611219575050899a73ffffffffffffffffffffffffffffffffffffffff60029b9a9b541694853b15611215578a9789519a8b98899788977f6dfb0dd800000000000000000000000000000000000000000000000000000000895233908901526024880160a0905260a48801906111599261183e565b9486860301604487015261116d838061189e565b60808752608087019061117f926118f1565b9061118a908461189e565b868303602088015261119c92916118f1565b906111a7908361189e565b8583038c8701526111b89291611944565b916111c29161189e565b909280830390606001526111d592611944565b606482016111ec9060443581526020606435910152565b039134905af19081156103ca575061120357505580f35b61120c90611448565b61014b57815580f35b8a80fd5b806112758b8f8b8f958061124e8d946112678361124e6112606112548361124e61125961125461126e9c8f8061124e91611aab565b90611aff565b61187d565b9d8d611aab565b9789611aab565b3595611aab565b3592611981565b016110e1565b909291507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261080e5782823567ffffffffffffffff811161014b576112c6903690850161141a565b60807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc36011261080e57837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5c36011261080e5761132660018454146117d9565b600283556024359073ffffffffffffffffffffffffffffffffffffffff958683168084036103d35760443588811681036109b35761136d6064359586608435938492611981565b886002541694853b156107a0576113c29989519a8b98899788977fa507c5430000000000000000000000000000000000000000000000000000000089523390890152610100602489015261010488019161183e565b9360448601526113d06114e8565b166064850152608484015260a483015260a43560c483015260c43560e4830152039134905af19081156103ca575061140b575b506001815580f35b61141490611448565b38611403565b9181601f840112156102665782359167ffffffffffffffff8311610266576020838186019501011161026657565b67ffffffffffffffff811161145c57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60e0810190811067ffffffffffffffff82111761145c57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761145c57604052565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361026657565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361026657565b359073ffffffffffffffffffffffffffffffffffffffff8216820361026657565b6004359063ffffffff8216820361026657565b67ffffffffffffffff811161145c5760051b60200190565b81601f820112156102665780359161159183611562565b9261159f60405194856114a7565b808452602092838086019260051b820101928311610266578301905b8282106115c9575050505090565b8380916115d58461152e565b8152019101906115bb565b81601f82011215610266578035916115f783611562565b9261160560405194856114a7565b808452602092838086019260051b820101928311610266578301905b82821061162f575050505090565b81358152908301908301611621565b90815180825260208080930193019160005b82811061165e575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101611650565b90815180825260208080930193019160005b8281106116a8575050505090565b83518552938101939281019260010161169a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275433036116e657565b6382b429006000526004601cfd5b519073ffffffffffffffffffffffffffffffffffffffff8216820361026657565b81601f820112156102665780519161172c83611562565b9261173a60405194856114a7565b808452602092838086019260051b820101928311610266578301905b828210611764575050505090565b838091611770846116f4565b815201910190611756565b81601f820112156102665780519161179283611562565b926117a060405194856114a7565b808452602092838086019260051b820101928311610266578301905b8282106117ca575050505090565b815181529083019083016117bc565b156117e057565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e4359000000000000000000000000000000000000000000006044820152fd5b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b3573ffffffffffffffffffffffffffffffffffffffff811681036102665790565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561026657016020813591019167ffffffffffffffff8211610266578160051b3603831361026657565b91908082526020809201929160005b82811061190e575050505090565b90919293828060019273ffffffffffffffffffffffffffffffffffffffff6119358961152e565b16815201950193929101611900565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116102665760209260051b809284830137010190565b90929182810390808211611a23578303611a0f575b5050806119a1575050565b601091816119b3602093303385611a52565b73ffffffffffffffffffffffffffffffffffffffff6001541660145260345260446000938480936f095ea7b300000000000000000000000082525af13d156001835114171615611a0257603452565b633e3f8f7390526004601cfd5b611a1c9130903390611a52565b3880611996565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b601c600060649281946020966040519860605260405260601b602c526f23b872dd000000000000000000000000600c525af13d15600160005114171615611a9d576000606052604052565b637939f4246000526004601cfd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610266570180359067ffffffffffffffff821161026657602001918160051b3603831361026657565b9190811015611b0f5760051b0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c6343000813000a

Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

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