ETH Price: $3,160.44 (+0.31%)
Gas: 0.08 Gwei

Contract

0x0736bdc975aF0675B9A045384Efed91360d25479
 

More Info

Private Name Tags

ContractCreator

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Fill238115652025-11-16 11:51:352 mins ago1763293895IN
0x0736bdc9...360d25479
0 ETH0.000031310.11506506
Deposit238115632025-11-16 11:51:112 mins ago1763293871IN
0x0736bdc9...360d25479
0 ETH0.000028320.11597881
Deposit Native238115192025-11-16 11:42:2311 mins ago1763293343IN
0x0736bdc9...360d25479
0.002 ETH0.000418732.09988257
Fill238115172025-11-16 11:41:5911 mins ago1763293319IN
0x0736bdc9...360d25479
0 ETH0.000025470.17773186
Fill238114802025-11-16 11:34:3519 mins ago1763292875IN
0x0736bdc9...360d25479
0 ETH0.000052290.13077068
Deposit Native238114762025-11-16 11:33:4719 mins ago1763292827IN
0x0736bdc9...360d25479
0.0011 ETH0.000018480.09268717
Deposit Native238114462025-11-16 11:27:4725 mins ago1763292467IN
0x0736bdc9...360d25479
0.0012 ETH0.000025690.12881992
Fill238114462025-11-16 11:27:4725 mins ago1763292467IN
0x0736bdc9...360d25479
0 ETH0.000055990.17727814
Deposit Native238114382025-11-16 11:26:1127 mins ago1763292371IN
0x0736bdc9...360d25479
0.01 ETH0.000026090.1308235
Deposit238114382025-11-16 11:26:1127 mins ago1763292371IN
0x0736bdc9...360d25479
0 ETH0.000108620.44479731
Deposit238114212025-11-16 11:22:4730 mins ago1763292167IN
0x0736bdc9...360d25479
0 ETH0.000047450.19431119
Deposit238113972025-11-16 11:17:5935 mins ago1763291879IN
0x0736bdc9...360d25479
0 ETH0.000048240.19756195
Fill238113552025-11-16 11:09:3544 mins ago1763291375IN
0x0736bdc9...360d25479
0 ETH0.000011660.08141903
Fill238113532025-11-16 11:09:1144 mins ago1763291351IN
0x0736bdc9...360d25479
0 ETH0.000025010.10125815
Fill238113372025-11-16 11:05:5947 mins ago1763291159IN
0x0736bdc9...360d25479
0 ETH0.000026550.10746344
Fill238113282025-11-16 11:04:1149 mins ago1763291051IN
0x0736bdc9...360d25479
0 ETH0.000024450.09897833
Fill238113242025-11-16 11:03:2350 mins ago1763291003IN
0x0736bdc9...360d25479
0 ETH0.00002640.10038206
Fill238112992025-11-16 10:58:2355 mins ago1763290703IN
0x0736bdc9...360d25479
0 ETH0.000035310.09030653
Fill238112902025-11-16 10:56:3557 mins ago1763290595IN
0x0736bdc9...360d25479
0 ETH0.000043760.17716169
Fill238112612025-11-16 10:50:471 hr ago1763290247IN
0x0736bdc9...360d25479
0 ETH0.000021420.08673433
Fill238112532025-11-16 10:49:111 hr ago1763290151IN
0x0736bdc9...360d25479
0 ETH0.000017870.12475301
Fill238112422025-11-16 10:46:591 hr ago1763290019IN
0x0736bdc9...360d25479
0 ETH0.000016790.06796026
Fill238112392025-11-16 10:46:231 hr ago1763289983IN
0x0736bdc9...360d25479
0 ETH0.000020070.08125023
Fill238112112025-11-16 10:40:471 hr ago1763289647IN
0x0736bdc9...360d25479
0 ETH0.000026040.10539923
Fill238112082025-11-16 10:40:111 hr ago1763289611IN
0x0736bdc9...360d25479
0 ETH0.000015460.11166707
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer238115652025-11-16 11:51:352 mins ago1763293895
0x0736bdc9...360d25479
0.00017613 ETH
Transfer238115652025-11-16 11:51:352 mins ago1763293895
0x0736bdc9...360d25479
0.07974102 ETH
Transfer238115652025-11-16 11:51:352 mins ago1763293895
0x0736bdc9...360d25479
0.07991716 ETH
Transfer238114802025-11-16 11:34:3519 mins ago1763292875
0x0736bdc9...360d25479
0.00000277 ETH
Transfer238114802025-11-16 11:34:3519 mins ago1763292875
0x0736bdc9...360d25479
0.0274822 ETH
Transfer238114802025-11-16 11:34:3519 mins ago1763292875
0x0736bdc9...360d25479
0.02748497 ETH
Transfer238114512025-11-16 11:28:4724 mins ago1763292527
0x0736bdc9...360d25479
0.0012 ETH
Transfer238114462025-11-16 11:27:4725 mins ago1763292467
0x0736bdc9...360d25479
0.00104816 ETH
Transfer238114462025-11-16 11:27:4725 mins ago1763292467
0x0736bdc9...360d25479
0.29823344 ETH
Transfer238114462025-11-16 11:27:4725 mins ago1763292467
0x0736bdc9...360d25479
0.29928161 ETH
Transfer238113532025-11-16 11:09:1144 mins ago1763291351
0x0736bdc9...360d25479
0.00006548 ETH
Transfer238113532025-11-16 11:09:1144 mins ago1763291351
0x0736bdc9...360d25479
0.09134601 ETH
Transfer238113532025-11-16 11:09:1144 mins ago1763291351
0x0736bdc9...360d25479
0.09141149 ETH
Transfer238113372025-11-16 11:05:5947 mins ago1763291159
0x0736bdc9...360d25479
0.00006611 ETH
Transfer238113372025-11-16 11:05:5947 mins ago1763291159
0x0736bdc9...360d25479
0.0676441 ETH
Transfer238113372025-11-16 11:05:5947 mins ago1763291159
0x0736bdc9...360d25479
0.06771022 ETH
Transfer238113282025-11-16 11:04:1149 mins ago1763291051
0x0736bdc9...360d25479
0.00000209 ETH
Transfer238113282025-11-16 11:04:1149 mins ago1763291051
0x0736bdc9...360d25479
0.00284105 ETH
Transfer238113282025-11-16 11:04:1149 mins ago1763291051
0x0736bdc9...360d25479
0.00284314 ETH
Transfer238113242025-11-16 11:03:2350 mins ago1763291003
0x0736bdc9...360d25479
0.0000935 ETH
Transfer238113242025-11-16 11:03:2350 mins ago1763291003
0x0736bdc9...360d25479
0.08210186 ETH
Transfer238113242025-11-16 11:03:2350 mins ago1763291003
0x0736bdc9...360d25479
0.08219536 ETH
Transfer238112992025-11-16 10:58:2355 mins ago1763290703
0x0736bdc9...360d25479
0.00000059 ETH
Transfer238112992025-11-16 10:58:2355 mins ago1763290703
0x0736bdc9...360d25479
0.00245645 ETH
Transfer238112992025-11-16 10:58:2355 mins ago1763290703
0x0736bdc9...360d25479
0.00245705 ETH
View All Internal Transactions
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Aori

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 100 runs

Other Settings:
paris EvmVersion, MIT license
File 1 of 28 : Aori.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import { OApp, Origin, MessagingFee, MessagingReceipt } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Pausable } from "@openzeppelin/contracts/utils/Pausable.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { EIP712 } from "solady/src/utils/EIP712.sol";
import { ECDSA } from "solady/src/utils/ECDSA.sol";
import { IAori } from "./IAori.sol";
import "./AoriUtils.sol";

/**                            @@@@@@@@@@@@                                              
                             @@         @@@@@@                     @@@@@                  
                             @@           @@@@@                    @@@@@                  
                             @@@                                                          
                               @@@@                                                       
                                 @@@@@                                                   
                                     @@@@@                                                
       @@@@@@@@@    @@@@          @@@@@@@@@@    @@@@@@    @@@@@@@  @@@@@                  
     @@@@      @@   @@@@      @@@@       @@@@@@@   @@@@ @@    @@@   @@@@                  
    @@@@         @ @@@@     @@@@          @@@@@@   @@@@        @@   @@@@                  
   @@@@@         @@@@@@   @@@@@            @@@@@@  @@@@         @   @@@@                  
   @@@@@          @@@@    @@@@@   @    @    @@@@@  @@@@             @@@@                  
   @@@@@          @@@@   @@@@@@   @@@@@@    @@@@@  @@@@             @@@@                  
   @@@@@         @@@@@   @@@@@@   @    @    @@@@@  @@@@             @@@@                  
   @@@@@         @@@@     @@@@@             @@@@   @@@@             @@@@                  
    @@@@        @@@@@@    @@@@@@           @@@@    @@@@             @@@@                  
     @@@@      @@@@  @@@@@@ @@@@@         @@@      @@@@             @@@@   @@             
       @@@@@@@@@     @@@@@     @@@@@@@@@@@         @@@@               @@@@@
 */
/**
 * @title Aori  
 * @dev version 0.3.1 
 * @notice Aori is a trust-minimized omnichain intent settlement protocol.
 * Connecting users and solvers from any chain to any chain,
 * facilitating peer to peer exchange from any token to any token.
 */

contract Aori is IAori, OApp, ReentrancyGuard, Pausable, EIP712 {
    using PayloadPackUtils for bytes32[];
    using PayloadUnpackUtils for bytes;
    using PayloadSizeUtils for uint8;
    using HookUtils for SrcHook;
    using HookUtils for DstHook;
    using SafeERC20 for IERC20;
    using BalanceUtils for Balance;
    using ValidationUtils for IAori.Order;
    using NativeTokenUtils for address;
    
    constructor(
        address _endpoint, // LayerZero endpoint address
        address _owner, // Contract owner address
        uint32 _eid, // Endpoint ID for this chain
        uint16 _maxFillsPerSettle // Maximum number of fills per settlement
    ) OApp(_endpoint, _owner) Ownable(_owner) EIP712() {
        ENDPOINT_ID = _eid;
        MAX_FILLS_PER_SETTLE = _maxFillsPerSettle;
        require(_owner != address(0), "Set owner");
        isSupportedChain[_eid] = true;
    }

    /**
     * @notice Allows the contract to receive native tokens
     * @dev Required for native token operations including hook interactions
     */
    receive() external payable {
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         SRC STATE                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Unique identifier for this endpoint in the LayerZero network
    uint32 public immutable ENDPOINT_ID;

    // Tracks locked and unlocked balances for each user and token
    mapping(address => mapping(address => Balance)) private balances;

    // Stores orders by their unique hash
    mapping(bytes32 => Order) public orders;
    
    // Tracks supported chains by their endpoint IDs
    mapping(uint32 => bool) public isSupportedChain;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         DST STATE                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Maximum number of fills that can be included in a single settlement
    uint16 public immutable MAX_FILLS_PER_SETTLE;

    // Tracks the current status of each order
    mapping(bytes32 => IAori.OrderStatus) public orderStatus;

    // Tracks whitelisted hook addresses for token conversion
    mapping(address => bool) public isAllowedHook;

    // Tracks whitelisted solver addresses
    mapping(address => bool) public isAllowedSolver;

    // Maps source endpoint and maker to an array of order hashes filled by a filler
    mapping(uint32 => mapping(address => bytes32[])) public srcEidToFillerFills;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      OWNER FUNCTIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @notice Pauses all contract operations
     * @dev Only callable by the contract owner
    */
    function pause() external onlyOwner {
        _pause();
    }

    /**
     * @notice Unpauses all contract operations
     * @dev Only callable by the contract owner
     */
    function unpause() external onlyOwner {
        _unpause();
    }

    /**
     * @notice Adds a hook address to the whitelist
     * @param hook The address of the hook to whitelist
     * @dev Only callable by the contract owner
     */
    function addAllowedHook(address hook) external onlyOwner {
        isAllowedHook[hook] = true;
    }

    /**
     * @notice Removes a hook address from the whitelist
     * @param hook The address of the hook to remove
     * @dev Only callable by the contract owner
     */
    function removeAllowedHook(address hook) external onlyOwner {
        isAllowedHook[hook] = false;
    }

    /**
     * @notice Adds a solver address to the whitelist
     * @param solver The address of the solver to whitelist
     * @dev Only callable by the contract owner
     */
    function addAllowedSolver(address solver) external onlyOwner {
        isAllowedSolver[solver] = true;
    }

    /**
     * @notice Removes a solver address from the whitelist
     * @param solver The address of the solver to remove
     * @dev Only callable by the contract owner
     */
    function removeAllowedSolver(address solver) external onlyOwner {
        isAllowedSolver[solver] = false;
    }

    /**
    * @notice Adds a single chain to the supported chains list
    * @param eid The endpoint ID of the chain to add
    * @dev Only callable by the contract owner
    */
    function addSupportedChain(uint32 eid) external onlyOwner {
        isSupportedChain[eid] = true;
        emit ChainSupported(eid);
    }

    /**
    * @notice Adds multiple chains to the supported chains list
    * @param eids Array of endpoint IDs of the chains to add
    * @return results Array of booleans indicating which EIDs were successfully added
    * @dev Only callable by the contract owner
    */
    function addSupportedChains(uint32[] calldata eids) external onlyOwner returns (bool[] memory results) {
        uint256 length = eids.length;
        results = new bool[](length);
        
        for (uint256 i = 0; i < length; i++) {
            isSupportedChain[eids[i]] = true;
            emit ChainSupported(eids[i]);
            results[i] = true;
        }
        return results;
    }

    /**
     * @notice Removes a supported chain by its endpoint ID
     * @param eid The endpoint ID of the chain to remove
     * @dev Only callable by the contract owner
     */
    function removeSupportedChain(uint32 eid) external onlyOwner {
        isSupportedChain[eid] = false;
        emit ChainRemoved(eid);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    EMERGENCY FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
    * @notice Emergency function to cancel an order, bypassing normal restrictions
    * @dev Only callable by the contract owner. Always transfers tokens to maintain accounting consistency.
    *      WARNING: This bypasses normal validation and should only be used in emergency situations.
    * @param orderId The hash of the order to cancel
    * @param recipient The address to send tokens to (can be different from offerer)
    */
    function emergencyCancel(bytes32 orderId, address recipient) external onlyOwner {
        require(orderStatus[orderId] == IAori.OrderStatus.Active, "Can only cancel active orders");
        require(recipient != address(0), "Invalid recipient address");
        
        Order memory order = orders[orderId];
        require(order.srcEid == ENDPOINT_ID, "Emergency cancel only allowed on source chain");
        
        address tokenAddress = order.inputToken;
        uint128 amountToReturn = order.inputAmount;
        
        // Validate sufficient balance
        tokenAddress.validateSufficientBalance(amountToReturn);
        
        orderStatus[orderId] = IAori.OrderStatus.Cancelled;
        bool success = balances[order.offerer][tokenAddress].decreaseLockedNoRevert(amountToReturn);
        require(success, "Failed to decrease locked balance");
        
        // Transfer tokens to recipient
        tokenAddress.safeTransfer(recipient, amountToReturn);
        
        emit Cancel(orderId);
        emit Withdraw(recipient, tokenAddress, amountToReturn);
    }
 
    /**
     * @notice Emergency function to extract tokens or ether from the contract
     * @dev Only callable by the contract owner. Does not update user balances - use for direct contract withdrawals.
     * @param token The token address to withdraw
     * @param amount The amount of tokens to withdraw
     */
    function emergencyWithdraw(address token, uint256 amount) external onlyOwner {
        uint256 etherBalance = address(this).balance;
        if (etherBalance > 0) {
            (bool success, ) = payable(owner()).call{ value: etherBalance }("");
            require(success, "Ether withdrawal failed");
        }
        if (amount > 0) {
            token.safeTransfer(owner(), amount);
        }
    }

    /**
     * @notice Emergency function to extract tokens from a specific user's balance while maintaining accounting consistency
     * @dev Only callable by the contract owner. Updates user balances to maintain internal accounting state.
     * @param token The token address to withdraw
     * @param amount The amount of tokens to withdraw
     * @param user The user address whose balance to withdraw from
     * @param isLocked Whether to withdraw from locked (true) or unlocked (false) balance
     * @param recipient The address to send the withdrawn tokens to
     */
    function emergencyWithdraw(
        address token, 
        uint256 amount, 
        address user, 
        bool isLocked,
        address recipient
    ) external onlyOwner {
        require(amount > 0, "Amount must be greater than zero");
        require(user != address(0), "Invalid user address");
        require(recipient != address(0), "Invalid recipient address");
        
        if (isLocked) {
            bool success = balances[user][token].decreaseLockedNoRevert(uint128(amount));
            require(success, "Failed to decrease locked balance");
        } else {
            uint256 unlockedBalance = balances[user][token].unlocked;
            require(unlockedBalance >= amount, "Insufficient unlocked balance");
            balances[user][token].unlocked = uint128(unlockedBalance - amount);
        }
        
        // Validate sufficient balance and transfer
        token.validateSufficientBalance(amount);
        token.safeTransfer(recipient, amount);
        
        emit Withdraw(user, token, amount);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         MODIFIERS                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @notice Modifier to ensure the caller is a whitelisted solver
     * @dev Only allows whitelisted solvers to proceed
     */
    modifier onlySolver() {
        require(isAllowedSolver[msg.sender], "Invalid solver");
        _;
    }

    /**
     * @notice Modifier to ensure the caller is a whitelisted hook address
     * @dev Only allows whitelisted hook addresses to proceed
     * @param hookAddress The address of the hook to check
     */
    modifier allowedHookAddress(address hookAddress) {
        require(isAllowedHook[hookAddress], "Invalid hook address");
        _;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          DEPOSIT                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @notice Deposits tokens to the contract without a hook call
     * @dev Takes tokens from offerer (not the caller) via transferFrom after signature verification
     * @param order The order details
     * @param signature The user's EIP712 signature over the order
     */
    function deposit(
        Order calldata order,
        bytes calldata signature
    ) external nonReentrant whenNotPaused onlySolver {
        require(!order.inputToken.isNativeToken(), "Use depositNative for native tokens");
        
        bytes32 orderId = order.validateDeposit(
            signature,
            _hashOrder712(order),
            ENDPOINT_ID,
            this.orderStatus,
            this.isSupportedChain
        );
        
        IERC20(order.inputToken).safeTransferFrom(order.offerer, address(this), order.inputAmount);
        _postDeposit(order.inputToken, order.inputAmount, order, orderId);
    }

    /**
     * @notice Deposits tokens to the contract with a hook call for token conversion
     * @dev Executes a hook call for token conversion before deposit processing.
     *      For single-chain swaps, immediately settles and transfers tokens to recipient.
     *      For cross-chain swaps, locks converted tokens for later settlement.
     * @param order The order details
     * @param signature The user's EIP712 signature over the order
     * @param hook The pre-hook configuration for token conversion
     */
    function deposit(
        Order calldata order,
        bytes calldata signature,
        SrcHook calldata hook
    ) external nonReentrant whenNotPaused onlySolver {
        require(!order.inputToken.isNativeToken(), "Use depositNative for native tokens");
        require(hook.isSome(), "Missing hook");
        bytes32 orderId = order.validateDeposit(
            signature,
            _hashOrder712(order),
            ENDPOINT_ID,
            this.orderStatus,
            this.isSupportedChain
        );

        // Execute hook to convert input tokens to preferred/output tokens
        (uint256 amountReceived, address tokenReceived) = 
            _executeSrcHook(order, hook);
        
        emit SrcHookExecuted(orderId, tokenReceived, amountReceived);
        
        if (order.isSingleChainSwap()) {
            // Single-chain: immediate settlement (tokens already transferred to recipient)
            orders[orderId] = order;
            orderStatus[orderId] = IAori.OrderStatus.Settled;
            emit Settle(orderId);
        } else {
            // Cross-chain: lock converted tokens for later settlement
            _postDeposit(tokenReceived, amountReceived, order, orderId);
        }
    }

    /**
     * @notice Executes a source hook to convert input tokens and handle distribution
     * @dev Sends input tokens to hook, executes conversion, and handles token distribution.
     *      For single-chain swaps: converts to output token and immediately distributes.
     *      For cross-chain swaps: converts to preferred token for later cross-chain transfer.
     * @param order The order details
     * @param hook The source hook configuration
     * @return amountReceived The amount of tokens received from the hook
     * @return tokenReceived The token address that was received
     */
    function _executeSrcHook(
        Order calldata order,
        SrcHook calldata hook
    ) internal allowedHookAddress(hook.hookAddress) returns (
        uint256 amountReceived,
        address tokenReceived
    ) {
        // Send input tokens to hook for conversion
        IERC20(order.inputToken).safeTransferFrom(
            order.offerer,
            hook.hookAddress,
            order.inputAmount
        );
        
        if (order.isSingleChainSwap()) {
            // Single-chain: convert to final output token and distribute immediately
            amountReceived = ExecutionUtils.observeBalChg(
                hook.hookAddress,
                hook.instructions,
                order.outputToken
            );
            
            require(amountReceived >= order.outputAmount, "Insufficient output from hook");
            tokenReceived = order.outputToken;
            
            // Distribute tokens: exact amount to recipient, surplus to solver
            order.outputToken.safeTransfer(order.recipient, order.outputAmount);
            
            uint256 surplus = amountReceived - order.outputAmount;
            if (surplus > 0) {
                order.outputToken.safeTransfer(msg.sender, surplus);
            }
        } else {
            // Cross-chain: convert to preferred token for cross-chain transfer
            amountReceived = ExecutionUtils.observeBalChg(
                hook.hookAddress,
                hook.instructions,
                hook.preferredToken
            );
            
            require(amountReceived >= hook.minPreferedTokenAmountOut, "Insufficient output from hook");
            tokenReceived = hook.preferredToken;
        }
    }

    /**
     * @notice Posts a deposit and updates the order status
     * @param depositToken The token address to deposit
     * @param depositAmount The amount of tokens to deposit
     * @param order The order details
     * @param orderId The unique identifier for the order
     */
    function _postDeposit(
        address depositToken,
        uint256 depositAmount,
        Order calldata order,
        bytes32 orderId
    ) internal {
        balances[order.offerer][depositToken].lock(SafeCast.toUint128(depositAmount));
        orderStatus[orderId] = IAori.OrderStatus.Active;
        orders[orderId] = order;
        orders[orderId].inputToken = depositToken;
        orders[orderId].inputAmount = SafeCast.toUint128(depositAmount);

        emit Deposit(orderId, order);
    }

    /**
     * @notice Deposits native tokens to the contract without a hook call
     * @dev User calls this directly and sends their own ETH via msg.value.
     * @param order The order details (must specify NATIVE_TOKEN as inputToken)
     */
    function depositNative(
        Order calldata order
    ) external payable nonReentrant whenNotPaused {
        require(order.inputToken.isNativeToken(), "Order must specify native token");
        require(msg.value == order.inputAmount, "Incorrect native amount");
        require(msg.sender == order.offerer, "Only offerer can deposit native tokens");
        
        // Calculate order ID and validate uniqueness
        bytes32 orderId = hash(order);
        require(orderStatus[orderId] == IAori.OrderStatus.Unknown, "Order already exists");
        require(isSupportedChain[order.dstEid], "Destination chain not supported");
        require(order.srcEid == ENDPOINT_ID, "Chain mismatch");
        
        // Use validation utility for common order parameter checks
        ValidationUtils.validateCommonOrderParams(order);
        
        _postDeposit(order.inputToken, order.inputAmount, order, orderId);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                             FILL                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @notice Fills an order by transferring output tokens from the filler to recipient
     * @dev For single-chain orders: settles immediately with internal balance transfers.
     *      For cross-chain orders: marks as filled and queues for later settlement.
     * @param order The order details to fill
     */
    function fill(Order calldata order) external payable nonReentrant whenNotPaused onlySolver {
        bytes32 orderId = order.validateFill(
            ENDPOINT_ID,
            this.orderStatus
        );
        
        // Validate payment method matches output token type
        if (order.outputToken.isNativeToken()) {
            require(msg.value == order.outputAmount, "Incorrect native amount sent");
        } else {
            require(msg.value == 0, "No native tokens should be sent for ERC20 fills");
        }

        // Update contract state
        if (order.isSingleChainSwap()) {
            _settleSingleChainSwap(orderId, order, msg.sender);
        } else {
            _postFill(orderId, order);
        }

        // Transfer tokens to recipient
        if (order.outputToken.isNativeToken()) {
            order.outputToken.safeTransfer(order.recipient, order.outputAmount);
        } else {
            IERC20(order.outputToken).safeTransferFrom(msg.sender, order.recipient, order.outputAmount);
        }
    }

    /**
     * @notice Fills an order by converting preferred tokens to output tokens via hook
     * @dev Uses a hook contract to convert solver's preferred tokens into the required output tokens.
     *      Any surplus from the conversion is returned to the solver.
     * @param order The order details to fill
     * @param hook The hook configuration for token conversion
     */
    function fill(
        Order calldata order,
        IAori.DstHook calldata hook
    ) external payable nonReentrant whenNotPaused onlySolver {

        bytes32 orderId = order.validateFill(
            ENDPOINT_ID,
            this.orderStatus
        );
        
        // Execute hook to convert preferred tokens to output tokens
        uint256 amountReceived = _executeDstHook(order, hook);
        emit DstHookExecuted(orderId, hook.preferredToken, amountReceived);

        uint256 surplus = amountReceived - order.outputAmount;

        // Update contract state
        if (order.isSingleChainSwap()) {
            _settleSingleChainSwap(orderId, order, msg.sender);
        } else {
            _postFill(orderId, order);
        }

        // Transfer tokens: exact amount to recipient, surplus to solver
        order.outputToken.safeTransfer(order.recipient, order.outputAmount);
        if (surplus > 0) {
            order.outputToken.safeTransfer(msg.sender, surplus);
        }
    }

    /**
     * @notice Executes a destination hook and handles token conversion
     * @param order The order details
     * @param hook The destination hook configuration
     * @return balChg The balance change observed from the hook execution
     */
    function _executeDstHook(
        Order calldata order,
        IAori.DstHook calldata hook
    ) internal allowedHookAddress(hook.hookAddress) returns (uint256 balChg) {
        if (hook.preferedDstInputAmount > 0) {
            if (hook.preferredToken.isNativeToken()) {
                require(msg.value == hook.preferedDstInputAmount, "Incorrect native amount for preferred token");
                (bool success, ) = payable(hook.hookAddress).call{value: hook.preferedDstInputAmount}("");
                require(success, "Native transfer to hook failed");
            } else {
                // ERC20 token input - no native tokens should be sent
                require(msg.value == 0, "No native tokens should be sent for ERC20 preferred token");
                IERC20(hook.preferredToken).safeTransferFrom(
                    msg.sender,
                    hook.hookAddress,
                    hook.preferedDstInputAmount
                );
            }
        } else {
            // Hook expects no input tokens - ensure no ETH was mistakenly sent
            require(msg.value == 0, "No native tokens expected");
        }

        balChg = ExecutionUtils.observeBalChg(
            hook.hookAddress,
            hook.instructions,
            order.outputToken
        );
        require(balChg >= order.outputAmount, "Hook must provide at least the expected output amount");
    }

    /**
     * @notice Processes an order after successful filling
     * @param orderId The unique identifier for the order
     * @param order The order details that were filled
     */
    function _postFill(bytes32 orderId, Order calldata order) internal {
        orderStatus[orderId] = IAori.OrderStatus.Filled;
        srcEidToFillerFills[order.srcEid][msg.sender].push(orderId);
        emit Fill(orderId, order);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                            SETTLE                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @notice Settles filled orders by batching order hashes into a payload and sending through LayerZero
     * @dev Requires ETH to be sent for LayerZero fees
     * @param srcEid The source endpoint ID
     * @param filler The filler address
     * @param extraOptions Additional LayerZero options
     */
    function settle(
        uint32 srcEid,
        address filler,
        bytes calldata extraOptions
    ) external payable nonReentrant whenNotPaused onlySolver {
        bytes32[] storage arr = srcEidToFillerFills[srcEid][filler];
        uint256 arrLength = arr.length;
        require(arrLength > 0, "No orders provided");

        uint16 fillCount = uint16(
            arrLength < MAX_FILLS_PER_SETTLE ? arrLength : MAX_FILLS_PER_SETTLE
        );
        bytes memory payload = arr.packSettlement(filler, fillCount);

        MessagingReceipt memory receipt = _lzSend(srcEid, payload, extraOptions, MessagingFee(msg.value, 0), payable(msg.sender));
        emit SettleSent(srcEid, filler, payload, receipt.guid, receipt.nonce, receipt.fee.nativeFee);
    }

    /**
     * @notice Settles a single order by transferring tokens from offerer to filler
     * @dev Moves tokens from offerer's locked balance to filler's unlocked balance.
     *      Uses cache-and-restore pattern to ensure true atomicity - if any step fails, 
     *      all balance changes are reverted to prevent accounting inconsistencies.
     * @param orderId The hash of the order to settle
     * @param filler The filler address who will receive the tokens
     */
    function _settleOrder(bytes32 orderId, address filler) internal {
        if (orderStatus[orderId] != IAori.OrderStatus.Active) {
            return; // Skip non-active orders
        }
        
        Order memory order = orders[orderId];
        
        // Cache original balances for potential rollback
        Balance memory offererBalanceCache = balances[order.offerer][order.inputToken];
        Balance memory fillerBalanceCache = balances[filler][order.inputToken];
        
        // Attempt atomic balance transfer
        bool successLock = balances[order.offerer][order.inputToken].decreaseLockedNoRevert(
            order.inputAmount
        );
        bool successUnlock = balances[filler][order.inputToken].increaseUnlockedNoRevert(
            order.inputAmount
        );

        // If either operation failed, restore original balances to maintain atomicity
        if (!successLock || !successUnlock) {
            balances[order.offerer][order.inputToken] = offererBalanceCache;
            balances[filler][order.inputToken] = fillerBalanceCache;
            return; // Exit with no state changes
        }
        
        orderStatus[orderId] = IAori.OrderStatus.Settled;
        emit Settle(orderId);
    }

    /**
     * @notice Handles settlement of filled orders
     * @param payload The settlement payload containing order hashes and filler information
     * @param senderEid The source endpoint ID
     * @dev Skips orders that were filled on the wrong chain and emits an event
     */
    function _handleSettlement(bytes calldata payload, uint32 senderEid) internal {
        payload.validateSettlementLen();
        (address filler, uint16 fillCount) = payload.unpackSettlementHeader();
        payload.validateSettlementLen(fillCount);

        for (uint256 i = 0; i < fillCount; ++i) {
            bytes32 orderId = payload.unpackSettlementBodyAt(i);
            Order memory order = orders[orderId];
            
            if (order.dstEid != senderEid) {
                emit settlementFailed(
                    orderId, 
                    order.dstEid, 
                    senderEid, 
                    "Eid mismatch"
                );
                continue; 
            }
            
            _settleOrder(orderId, filler);
        }
    }

    /**
     * @notice Handles settlement of same-chain swaps with immediate token transfer
     * @dev Performs atomic settlement within the same transaction for same-chain orders.
     *      Moves tokens from offerer's locked balance to solver's unlocked balance.
     *      Includes comprehensive validation to ensure balance consistency.
     * @param orderId The unique identifier for the order
     * @param order The order details
     * @param solver The address of the solver who filled the order
     */
    function _settleSingleChainSwap(
        bytes32 orderId,
        Order memory order,
        address solver
    ) internal {
        // Capture initial state for validation
        uint128 initialOffererLocked = balances[order.offerer][order.inputToken].locked;
        uint128 initialSolverUnlocked = balances[solver][order.inputToken].unlocked;
        
        // Atomic balance transfer: locked → unlocked
        if (balances[order.offerer][order.inputToken].locked >= order.inputAmount) {
            bool successLock = balances[order.offerer][order.inputToken].decreaseLockedNoRevert(
                order.inputAmount
            );
            
            bool successUnlock = balances[solver][order.inputToken].increaseUnlockedNoRevert(
                order.inputAmount
            );
            
            require(successLock && successUnlock, "Balance operation failed");
        }
        
        // Verify the transfer was executed correctly
        uint128 finalOffererLocked = balances[order.offerer][order.inputToken].locked;
        uint128 finalSolverUnlocked = balances[solver][order.inputToken].unlocked;

        balances[order.offerer][order.inputToken].validateBalanceTransferOrRevert(
            initialOffererLocked,
            finalOffererLocked,
            initialSolverUnlocked,
            finalSolverUnlocked,
            order.inputAmount
        );

        orderStatus[orderId] = IAori.OrderStatus.Settled;
        emit Settle(orderId);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                            CANCEL                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @notice Allows cancellation of single-chain orders from the source chain
     * @dev Cross-chain orders must be cancelled from the destination chain to prevent race conditions.
     * Cancellation is permitted for:
     *      1. Whitelisted solvers (for any active single-chain order)
     *      2. Order offerers (for their own expired single-chain orders)
     * @param orderId The hash of the order to cancel
     */
    function cancel(bytes32 orderId) external nonReentrant whenNotPaused {
        Order memory order = orders[orderId];
        
        order.validateSourceChainCancel(
            orderId,
            ENDPOINT_ID,
            this.orderStatus,
            msg.sender,
            this.isAllowedSolver
        );
        
        _cancel(orderId);
    }

    /**
     * @notice Cancels a cross-chain order from the destination chain by sending a cancellation message to the source chain
     * @dev This is the required method for cancelling cross-chain orders to prevent race conditions with settlement.
     * Requires ETH to be sent for LayerZero fees. Cancellation is permitted for:
     *      1. Whitelisted solvers (anytime before settlement)
     *      2. Order offerers (after expiry)
     *      3. Order recipients (after expiry)
     * @param orderId The hash of the order to cancel
     * @param orderToCancel The order details to cancel
     * @param extraOptions Additional LayerZero options
     */
    function cancel(
        bytes32 orderId,
        Order calldata orderToCancel,
        bytes calldata extraOptions
    ) external payable nonReentrant whenNotPaused {
        require(hash(orderToCancel) == orderId, "Submitted order data doesn't match orderId");
        
        orderToCancel.validateCancel(
            orderId,
            ENDPOINT_ID,
            this.orderStatus,
            msg.sender,
            this.isAllowedSolver
        );
        
        orderStatus[orderId] = IAori.OrderStatus.Cancelled;
        
        bytes memory payload = PayloadPackUtils.packCancellation(orderId);
        MessagingReceipt memory receipt = __lzSend(orderToCancel.srcEid, payload, extraOptions);
        emit CancelSent(orderId, receipt.guid, receipt.nonce, receipt.fee.nativeFee);
    }

    /**
     * @notice Internal function to cancel an order and return tokens to offerer
     * @dev Updates order status, decreases locked balance, and transfers tokens back.
     * @param orderId The hash of the order to cancel
     */
    function _cancel(bytes32 orderId) internal {
        require(orderStatus[orderId] == IAori.OrderStatus.Active, "Can only cancel active orders");
        
        Order memory order = orders[orderId];
        uint128 amountToReturn = order.inputAmount;
        address tokenAddress = order.inputToken;
        address recipient = order.offerer;
        
        // Validate contract has sufficient tokens
        tokenAddress.validateSufficientBalance(amountToReturn);
        
        // Update state first
        orderStatus[orderId] = IAori.OrderStatus.Cancelled;
        bool success = balances[recipient][tokenAddress].decreaseLockedNoRevert(amountToReturn);
        require(success, "Failed to decrease locked balance");
        
        // Transfer tokens back to offerer 
        tokenAddress.safeTransfer(recipient, amountToReturn);
        emit Cancel(orderId);
    }

    /**
     * @notice Handles cancellation payload from source chain
     * @param payload The cancellation payload containing the order hash
     */
    function _handleCancellation(bytes calldata payload) internal {
        payload.validateCancellationLen();
        bytes32 orderId = payload.unpackCancellation();
        _cancel(orderId);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          WITHDRAW                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @notice Allows users to withdraw their unlocked token balances
     * @dev Only unlocked balances can be withdrawn. Locked balances are reserved for active orders.
     * @param token The token address to withdraw
     * @param amount The amount to withdraw (use 0 to withdraw full balance)
     */
    function withdraw(address token, uint256 amount) external nonReentrant whenNotPaused {
        address holder = msg.sender;
        uint256 unlockedBalance = balances[holder][token].unlocked;
        require(unlockedBalance > 0, "Non-zero balance required");
        
        // Default to full balance if amount is 0
        if (amount == 0) {
            amount = unlockedBalance;
        } else {
            require(unlockedBalance >= amount, "Insufficient unlocked balance");
        }
        
        token.validateSufficientBalance(amount);
        
        // Update balance
        balances[holder][token].unlocked = uint128(unlockedBalance - amount);
        
        // Transfer tokens to user
        token.safeTransfer(holder, amount);
        emit Withdraw(holder, token, amount);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   LAYERZERO FUNCTIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @notice Sends a message through LayerZero
     * @dev Captures and returns the MessagingReceipt for event emission
     * @param eId The destination endpoint ID
     * @param payload The message payload
     * @param extraOptions Additional options
     * @return receipt The messaging receipt containing transaction details (guid, nonce, fee)
     */
    function __lzSend(
        uint32 eId, 
        bytes memory payload, 
        bytes calldata extraOptions
    ) internal returns (MessagingReceipt memory receipt) {
        return _lzSend(eId, payload, extraOptions, MessagingFee(msg.value, 0), payable(msg.sender));
    }

    /**
     * @notice Handles incoming LayerZero messages for order settlement and cancellation
     * @dev Processes settlement and cancellation payloads
     * @param payload The message payload containing order hashes and filler information
     */
    function _lzReceive(
        Origin calldata origin,
        bytes32,
        bytes calldata payload,
        address,
        bytes calldata
    ) internal override whenNotPaused {
        require(payload.length > 0, "Empty payload");
        
        // Pass the sender chain's endpoint ID
        _recvPayload(payload, origin.srcEid);
    }

    /**
     * @notice Processes incoming LayerZero messages based on the payload type
     * @param payload The message payload containing order hashes and filler information
     */
    function _recvPayload(bytes calldata payload, uint32 srcEid) internal {
        PayloadType msgType = payload.getType();
        if (msgType == PayloadType.Cancellation) {
            _handleCancellation(payload);
        } else if (msgType == PayloadType.Settlement) {
            _handleSettlement(payload, srcEid);
        } else {
            revert("Unsupported payload type");
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               EIP-712/HASHING HELPER FUNCTIONS             */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @dev Returns the domain name and version for EIP712.
     */
    function _domainNameAndVersion()
        internal
        pure
        override
        returns (string memory name, string memory version)
    {
        return ("Aori", "0.3.1");
    }

    /**
     * @dev EIP712 typehash for order struct
     */
    bytes32 private constant _ORDER_TYPEHASH =
        keccak256(
            "Order(uint128 inputAmount,uint128 outputAmount,address inputToken,address outputToken,uint32 startTime,uint32 endTime,uint32 srcEid,uint32 dstEid,address offerer,address recipient)"
        );

    /**
     * @dev Returns the EIP712 digest for the given order
     * @param order The order details
     * @return The computed digest
     */
    function _hashOrder712(Order calldata order) internal view returns (bytes32) {
        return
            _hashTypedDataSansChainId(
                keccak256(
                    abi.encode(
                        _ORDER_TYPEHASH,
                        order.inputAmount,
                        order.outputAmount,
                        order.inputToken,
                        order.outputToken,
                        order.startTime,
                        order.endTime,
                        order.srcEid,
                        order.dstEid,
                        order.offerer,
                        order.recipient
                    )
                )
            );
    }

    /**
     * @notice Computes the hash of an order
     * @param order The order to hash
     * @return The computed hash
     */
    function hash(IAori.Order calldata order) public pure returns (bytes32) {
        return keccak256(abi.encode(order));
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       VIEW FUNCTIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @notice Returns the locked balance for a user and token
     * @param offerer The user address
     * @param token The token address
     * @return The locked balance amount
     */
    function getLockedBalances(address offerer, address token) external view returns (uint256) {
        return balances[offerer][token].locked;
    }

    /**
     * @notice Returns the unlocked balance for a user and token
     * @param offerer The user address
     * @param token The token address
     * @return The unlocked balance amount
     */
    function getUnlockedBalances(address offerer, address token) external view returns (uint256) {
        return balances[offerer][token].unlocked;
    }

    /**
     * @notice Returns a fee quote for sending a message through LayerZero
     * @param _dstEid Destination endpoint ID
     * @param _msgType Message type (0 for settlement, 1 for cancellation)
     * @param _options Execution options
     * @param _payInLzToken Whether to pay fee in LayerZero token
     * @param _srcEid Source endpoint ID (for settle operations)
     * @param _filler Filler address (for settle operations)
     * @return fee The messaging fee in native currency
     */
    function quote(
        uint32 _dstEid,
        uint8 _msgType,
        bytes calldata _options,
        bool _payInLzToken,
        uint32 _srcEid,
        address _filler
    ) public view returns (uint256 fee) {
        // Calculate payload size using the library function
        uint256 fillsLength = srcEidToFillerFills[_srcEid][_filler].length;
        uint256 payloadSize = PayloadSizeUtils.calculatePayloadSize(
            _msgType,
            fillsLength,
            MAX_FILLS_PER_SETTLE
        );

    // Get the quote from LayerZero
    MessagingFee memory messagingFee = _quote(
            _dstEid,
            new bytes(payloadSize),
            _options,
            _payInLzToken
        );

        return messagingFee.nativeFee;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

import { IMessageLibManager } from "./IMessageLibManager.sol";
import { IMessagingComposer } from "./IMessagingComposer.sol";
import { IMessagingChannel } from "./IMessagingChannel.sol";
import { IMessagingContext } from "./IMessagingContext.sol";

struct MessagingParams {
    uint32 dstEid;
    bytes32 receiver;
    bytes message;
    bytes options;
    bool payInLzToken;
}

struct MessagingReceipt {
    bytes32 guid;
    uint64 nonce;
    MessagingFee fee;
}

struct MessagingFee {
    uint256 nativeFee;
    uint256 lzTokenFee;
}

struct Origin {
    uint32 srcEid;
    bytes32 sender;
    uint64 nonce;
}

interface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext {
    event PacketSent(bytes encodedPayload, bytes options, address sendLibrary);

    event PacketVerified(Origin origin, address receiver, bytes32 payloadHash);

    event PacketDelivered(Origin origin, address receiver);

    event LzReceiveAlert(
        address indexed receiver,
        address indexed executor,
        Origin origin,
        bytes32 guid,
        uint256 gas,
        uint256 value,
        bytes message,
        bytes extraData,
        bytes reason
    );

    event LzTokenSet(address token);

    event DelegateSet(address sender, address delegate);

    function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory);

    function send(
        MessagingParams calldata _params,
        address _refundAddress
    ) external payable returns (MessagingReceipt memory);

    function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external;

    function verifiable(Origin calldata _origin, address _receiver) external view returns (bool);

    function initializable(Origin calldata _origin, address _receiver) external view returns (bool);

    function lzReceive(
        Origin calldata _origin,
        address _receiver,
        bytes32 _guid,
        bytes calldata _message,
        bytes calldata _extraData
    ) external payable;

    // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order
    function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external;

    function setLzToken(address _lzToken) external;

    function lzToken() external view returns (address);

    function nativeToken() external view returns (address);

    function setDelegate(address _delegate) external;
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

import { Origin } from "./ILayerZeroEndpointV2.sol";

interface ILayerZeroReceiver {
    function allowInitializePath(Origin calldata _origin) external view returns (bool);

    function nextNonce(uint32 _eid, bytes32 _sender) external view returns (uint64);

    function lzReceive(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) external payable;
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

struct SetConfigParam {
    uint32 eid;
    uint32 configType;
    bytes config;
}

interface IMessageLibManager {
    struct Timeout {
        address lib;
        uint256 expiry;
    }

    event LibraryRegistered(address newLib);
    event DefaultSendLibrarySet(uint32 eid, address newLib);
    event DefaultReceiveLibrarySet(uint32 eid, address newLib);
    event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry);
    event SendLibrarySet(address sender, uint32 eid, address newLib);
    event ReceiveLibrarySet(address receiver, uint32 eid, address newLib);
    event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout);

    function registerLibrary(address _lib) external;

    function isRegisteredLibrary(address _lib) external view returns (bool);

    function getRegisteredLibraries() external view returns (address[] memory);

    function setDefaultSendLibrary(uint32 _eid, address _newLib) external;

    function defaultSendLibrary(uint32 _eid) external view returns (address);

    function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _gracePeriod) external;

    function defaultReceiveLibrary(uint32 _eid) external view returns (address);

    function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external;

    function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry);

    function isSupportedEid(uint32 _eid) external view returns (bool);

    function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool);

    /// ------------------- OApp interfaces -------------------
    function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external;

    function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib);

    function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool);

    function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external;

    function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault);

    function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _expiry) external;

    function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry);

    function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external;

    function getConfig(
        address _oapp,
        address _lib,
        uint32 _eid,
        uint32 _configType
    ) external view returns (bytes memory config);
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface IMessagingChannel {
    event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce);
    event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);
    event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);

    function eid() external view returns (uint32);

    // this is an emergency function if a message cannot be verified for some reasons
    // required to provide _nextNonce to avoid race condition
    function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external;

    function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;

    function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;

    function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32);

    function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);

    function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64);

    function inboundPayloadHash(
        address _receiver,
        uint32 _srcEid,
        bytes32 _sender,
        uint64 _nonce
    ) external view returns (bytes32);

    function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface IMessagingComposer {
    event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message);
    event ComposeDelivered(address from, address to, bytes32 guid, uint16 index);
    event LzComposeAlert(
        address indexed from,
        address indexed to,
        address indexed executor,
        bytes32 guid,
        uint16 index,
        uint256 gas,
        uint256 value,
        bytes message,
        bytes extraData,
        bytes reason
    );

    function composeQueue(
        address _from,
        address _to,
        bytes32 _guid,
        uint16 _index
    ) external view returns (bytes32 messageHash);

    function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external;

    function lzCompose(
        address _from,
        address _to,
        bytes32 _guid,
        uint16 _index,
        bytes calldata _message,
        bytes calldata _extraData
    ) external payable;
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface IMessagingContext {
    function isSendingMessage() external view returns (bool);

    function getSendContext() external view returns (uint32 dstEid, address sender);
}

File 8 of 28 : OApp.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

// @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import { OAppSender, MessagingFee, MessagingReceipt } from "./OAppSender.sol";
// @dev Import the 'Origin' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import { OAppReceiver, Origin } from "./OAppReceiver.sol";
import { OAppCore } from "./OAppCore.sol";

/**
 * @title OApp
 * @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality.
 */
abstract contract OApp is OAppSender, OAppReceiver {
    /**
     * @dev Constructor to initialize the OApp with the provided endpoint and owner.
     * @param _endpoint The address of the LOCAL LayerZero endpoint.
     * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
     */
    constructor(address _endpoint, address _delegate) OAppCore(_endpoint, _delegate) {}

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol implementation.
     * @return receiverVersion The version of the OAppReceiver.sol implementation.
     */
    function oAppVersion()
        public
        pure
        virtual
        override(OAppSender, OAppReceiver)
        returns (uint64 senderVersion, uint64 receiverVersion)
    {
        return (SENDER_VERSION, RECEIVER_VERSION);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IOAppCore, ILayerZeroEndpointV2 } from "./interfaces/IOAppCore.sol";

/**
 * @title OAppCore
 * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.
 */
abstract contract OAppCore is IOAppCore, Ownable {
    // The LayerZero endpoint associated with the given OApp
    ILayerZeroEndpointV2 public immutable endpoint;

    // Mapping to store peers associated with corresponding endpoints
    mapping(uint32 eid => bytes32 peer) public peers;

    /**
     * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.
     * @param _endpoint The address of the LOCAL Layer Zero endpoint.
     * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
     *
     * @dev The delegate typically should be set as the owner of the contract.
     */
    constructor(address _endpoint, address _delegate) {
        endpoint = ILayerZeroEndpointV2(_endpoint);

        if (_delegate == address(0)) revert InvalidDelegate();
        endpoint.setDelegate(_delegate);
    }

    /**
     * @notice Sets the peer address (OApp instance) for a corresponding endpoint.
     * @param _eid The endpoint ID.
     * @param _peer The address of the peer to be associated with the corresponding endpoint.
     *
     * @dev Only the owner/admin of the OApp can call this function.
     * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
     * @dev Set this to bytes32(0) to remove the peer address.
     * @dev Peer is a bytes32 to accommodate non-evm chains.
     */
    function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {
        _setPeer(_eid, _peer);
    }

    /**
     * @notice Sets the peer address (OApp instance) for a corresponding endpoint.
     * @param _eid The endpoint ID.
     * @param _peer The address of the peer to be associated with the corresponding endpoint.
     *
     * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
     * @dev Set this to bytes32(0) to remove the peer address.
     * @dev Peer is a bytes32 to accommodate non-evm chains.
     */
    function _setPeer(uint32 _eid, bytes32 _peer) internal virtual {
        peers[_eid] = _peer;
        emit PeerSet(_eid, _peer);
    }

    /**
     * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.
     * ie. the peer is set to bytes32(0).
     * @param _eid The endpoint ID.
     * @return peer The address of the peer associated with the specified endpoint.
     */
    function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {
        bytes32 peer = peers[_eid];
        if (peer == bytes32(0)) revert NoPeer(_eid);
        return peer;
    }

    /**
     * @notice Sets the delegate address for the OApp.
     * @param _delegate The address of the delegate to be set.
     *
     * @dev Only the owner/admin of the OApp can call this function.
     * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.
     */
    function setDelegate(address _delegate) public onlyOwner {
        endpoint.setDelegate(_delegate);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { IOAppReceiver, Origin } from "./interfaces/IOAppReceiver.sol";
import { OAppCore } from "./OAppCore.sol";

/**
 * @title OAppReceiver
 * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers.
 */
abstract contract OAppReceiver is IOAppReceiver, OAppCore {
    // Custom error message for when the caller is not the registered endpoint/
    error OnlyEndpoint(address addr);

    // @dev The version of the OAppReceiver implementation.
    // @dev Version is bumped when changes are made to this contract.
    uint64 internal constant RECEIVER_VERSION = 2;

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol contract.
     * @return receiverVersion The version of the OAppReceiver.sol contract.
     *
     * @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented.
     * ie. this is a RECEIVE only OApp.
     * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions.
     */
    function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
        return (0, RECEIVER_VERSION);
    }

    /**
     * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint.
     * @dev _origin The origin information containing the source endpoint and sender address.
     *  - srcEid: The source chain endpoint ID.
     *  - sender: The sender address on the src chain.
     *  - nonce: The nonce of the message.
     * @dev _message The lzReceive payload.
     * @param _sender The sender address.
     * @return isSender Is a valid sender.
     *
     * @dev Applications can optionally choose to implement separate composeMsg senders that are NOT the bridging layer.
     * @dev The default sender IS the OAppReceiver implementer.
     */
    function isComposeMsgSender(
        Origin calldata /*_origin*/,
        bytes calldata /*_message*/,
        address _sender
    ) public view virtual returns (bool) {
        return _sender == address(this);
    }

    /**
     * @notice Checks if the path initialization is allowed based on the provided origin.
     * @param origin The origin information containing the source endpoint and sender address.
     * @return Whether the path has been initialized.
     *
     * @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received.
     * @dev This defaults to assuming if a peer has been set, its initialized.
     * Can be overridden by the OApp if there is other logic to determine this.
     */
    function allowInitializePath(Origin calldata origin) public view virtual returns (bool) {
        return peers[origin.srcEid] == origin.sender;
    }

    /**
     * @notice Retrieves the next nonce for a given source endpoint and sender address.
     * @dev _srcEid The source endpoint ID.
     * @dev _sender The sender address.
     * @return nonce The next nonce.
     *
     * @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement.
     * @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered.
     * @dev This is also enforced by the OApp.
     * @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0.
     */
    function nextNonce(uint32 /*_srcEid*/, bytes32 /*_sender*/) public view virtual returns (uint64 nonce) {
        return 0;
    }

    /**
     * @dev Entry point for receiving messages or packets from the endpoint.
     * @param _origin The origin information containing the source endpoint and sender address.
     *  - srcEid: The source chain endpoint ID.
     *  - sender: The sender address on the src chain.
     *  - nonce: The nonce of the message.
     * @param _guid The unique identifier for the received LayerZero message.
     * @param _message The payload of the received message.
     * @param _executor The address of the executor for the received message.
     * @param _extraData Additional arbitrary data provided by the corresponding executor.
     *
     * @dev Entry point for receiving msg/packet from the LayerZero endpoint.
     */
    function lzReceive(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) public payable virtual {
        // Ensures that only the endpoint can attempt to lzReceive() messages to this OApp.
        if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender);

        // Ensure that the sender matches the expected peer for the source endpoint.
        if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender);

        // Call the internal OApp implementation of lzReceive.
        _lzReceive(_origin, _guid, _message, _executor, _extraData);
    }

    /**
     * @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation.
     */
    function _lzReceive(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) internal virtual;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { MessagingParams, MessagingFee, MessagingReceipt } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import { OAppCore } from "./OAppCore.sol";

/**
 * @title OAppSender
 * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.
 */
abstract contract OAppSender is OAppCore {
    using SafeERC20 for IERC20;

    // Custom error messages
    error NotEnoughNative(uint256 msgValue);
    error LzTokenUnavailable();

    // @dev The version of the OAppSender implementation.
    // @dev Version is bumped when changes are made to this contract.
    uint64 internal constant SENDER_VERSION = 1;

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol contract.
     * @return receiverVersion The version of the OAppReceiver.sol contract.
     *
     * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.
     * ie. this is a SEND only OApp.
     * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions
     */
    function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
        return (SENDER_VERSION, 0);
    }

    /**
     * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.
     * @param _dstEid The destination endpoint ID.
     * @param _message The message payload.
     * @param _options Additional options for the message.
     * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.
     * @return fee The calculated MessagingFee for the message.
     *      - nativeFee: The native fee for the message.
     *      - lzTokenFee: The LZ token fee for the message.
     */
    function _quote(
        uint32 _dstEid,
        bytes memory _message,
        bytes memory _options,
        bool _payInLzToken
    ) internal view virtual returns (MessagingFee memory fee) {
        return
            endpoint.quote(
                MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),
                address(this)
            );
    }

    /**
     * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.
     * @param _dstEid The destination endpoint ID.
     * @param _message The message payload.
     * @param _options Additional options for the message.
     * @param _fee The calculated LayerZero fee for the message.
     *      - nativeFee: The native fee.
     *      - lzTokenFee: The lzToken fee.
     * @param _refundAddress The address to receive any excess fee values sent to the endpoint.
     * @return receipt The receipt for the sent message.
     *      - guid: The unique identifier for the sent message.
     *      - nonce: The nonce of the sent message.
     *      - fee: The LayerZero fee incurred for the message.
     */
    function _lzSend(
        uint32 _dstEid,
        bytes memory _message,
        bytes memory _options,
        MessagingFee memory _fee,
        address _refundAddress
    ) internal virtual returns (MessagingReceipt memory receipt) {
        // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.
        uint256 messageValue = _payNative(_fee.nativeFee);
        if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);

        return
            // solhint-disable-next-line check-send-result
            endpoint.send{ value: messageValue }(
                MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),
                _refundAddress
            );
    }

    /**
     * @dev Internal function to pay the native fee associated with the message.
     * @param _nativeFee The native fee to be paid.
     * @return nativeFee The amount of native currency paid.
     *
     * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,
     * this will need to be overridden because msg.value would contain multiple lzFees.
     * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.
     * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.
     * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.
     */
    function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {
        if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);
        return _nativeFee;
    }

    /**
     * @dev Internal function to pay the LZ token fee associated with the message.
     * @param _lzTokenFee The LZ token fee to be paid.
     *
     * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.
     * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().
     */
    function _payLzToken(uint256 _lzTokenFee) internal virtual {
        // @dev Cannot cache the token because it is not immutable in the endpoint.
        address lzToken = endpoint.lzToken();
        if (lzToken == address(0)) revert LzTokenUnavailable();

        // Pay LZ token fee by sending tokens to the endpoint.
        IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import { ILayerZeroEndpointV2 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";

/**
 * @title IOAppCore
 */
interface IOAppCore {
    // Custom error messages
    error OnlyPeer(uint32 eid, bytes32 sender);
    error NoPeer(uint32 eid);
    error InvalidEndpointCall();
    error InvalidDelegate();

    // Event emitted when a peer (OApp) is set for a corresponding endpoint
    event PeerSet(uint32 eid, bytes32 peer);

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol contract.
     * @return receiverVersion The version of the OAppReceiver.sol contract.
     */
    function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion);

    /**
     * @notice Retrieves the LayerZero endpoint associated with the OApp.
     * @return iEndpoint The LayerZero endpoint as an interface.
     */
    function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint);

    /**
     * @notice Retrieves the peer (OApp) associated with a corresponding endpoint.
     * @param _eid The endpoint ID.
     * @return peer The peer address (OApp instance) associated with the corresponding endpoint.
     */
    function peers(uint32 _eid) external view returns (bytes32 peer);

    /**
     * @notice Sets the peer address (OApp instance) for a corresponding endpoint.
     * @param _eid The endpoint ID.
     * @param _peer The address of the peer to be associated with the corresponding endpoint.
     */
    function setPeer(uint32 _eid, bytes32 _peer) external;

    /**
     * @notice Sets the delegate address for the OApp Core.
     * @param _delegate The address of the delegate to be set.
     */
    function setDelegate(address _delegate) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { ILayerZeroReceiver, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol";

interface IOAppReceiver is ILayerZeroReceiver {
    /**
     * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint.
     * @param _origin The origin information containing the source endpoint and sender address.
     *  - srcEid: The source chain endpoint ID.
     *  - sender: The sender address on the src chain.
     *  - nonce: The nonce of the message.
     * @param _message The lzReceive payload.
     * @param _sender The sender address.
     * @return isSender Is a valid sender.
     *
     * @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer.
     * @dev The default sender IS the OAppReceiver implementer.
     */
    function isComposeMsgSender(
        Origin calldata _origin,
        bytes calldata _message,
        address _sender
    ) external view returns (bool isSender);
}

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

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

File 16 of 28 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";

File 17 of 28 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

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

pragma solidity ^0.8.20;

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

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

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

pragma solidity ^0.8.20;

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

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    bool private _paused;

    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

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

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

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

File 24 of 28 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }

    /**
     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
     */
    function toUint(bool b) internal pure returns (uint256 u) {
        assembly ("memory-safe") {
            u := iszero(iszero(b))
        }
    }
}

File 25 of 28 : AoriUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ECDSA } from "solady/src/utils/ECDSA.sol";
import { IAori } from "./IAori.sol";

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/*                          VALIDATION                        */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/**
 * @notice Library for order validation functions
 * @dev Provides reusable validation logic for orders across different contract functions
 */
library ValidationUtils {
    /**
     * @notice Validates basic order parameters that are common to all validation flows
     * @dev Checks offerer, recipient, time bounds, amounts, and token addresses
     * @param order The order to validate
     */
    function validateCommonOrderParams(IAori.Order calldata order) internal view {
        require(order.offerer != address(0), "Invalid offerer");
        require(order.recipient != address(0), "Invalid recipient");
        require(order.startTime < order.endTime, "Invalid end time");
        require(order.startTime <= block.timestamp, "Order not started");
        require(order.endTime > block.timestamp, "Order has expired");
        require(order.inputAmount > 0, "Invalid input amount");
        require(order.outputAmount > 0, "Invalid output amount");
        require(order.inputToken != address(0) && order.outputToken != address(0), "Invalid token");
    }

    /**
     * @notice Validates deposit parameters including signature verification
     * @dev Performs comprehensive validation for deposit operations
     * @param order The order to validate
     * @param signature The EIP712 signature to verify
     * @param digest The EIP712 type hash digest of the order
     * @param endpointId The current chain's endpoint ID
     * @param orderStatus The status mapping function to check order status
     * @param isSupportedChain A function to check if the destination chain is supported
     * @return orderId The calculated order hash
     */
    function validateDeposit(
        IAori.Order calldata order,
        bytes calldata signature,
        bytes32 digest,
        uint32 endpointId,
        function(bytes32) external view returns (IAori.OrderStatus) orderStatus,
        function(uint32) external view returns (bool) isSupportedChain
    ) internal view returns (bytes32 orderId) {
        orderId = keccak256(abi.encode(order));
        require(orderStatus(orderId) == IAori.OrderStatus.Unknown, "Order already exists");
        require(isSupportedChain(order.dstEid), "Destination chain not supported");


        // Signature validation
        address recovered = ECDSA.recover(digest, signature);
        require(recovered == order.offerer, "InvalidSignature");

        // Order parameter validation
        validateCommonOrderParams(order);
        require(order.srcEid == endpointId, "Chain mismatch");
    }

    /**
     * @notice Validates fill parameters for both single-chain and cross-chain swaps
     * @dev Performs comprehensive validation for fill operations
     * @param order The order to validate
     * @param endpointId The current chain's endpoint ID
     * @param orderStatus The status mapping function to check order status
     * @return orderId The calculated order hash
     */
    function validateFill(
        IAori.Order calldata order,
        uint32 endpointId,
        function(bytes32) external view returns (IAori.OrderStatus) orderStatus
    ) internal view returns (bytes32 orderId) {
        // Order parameter validation
        validateCommonOrderParams(order);
        require(order.dstEid == endpointId, "Chain mismatch");

        orderId = keccak256(abi.encode(order));

        // Different validation based on whether it's a single-chain or cross-chain swap
        if (order.srcEid == order.dstEid) {
            // For single-chain swaps, the order should already be Active
            require(orderStatus(orderId) == IAori.OrderStatus.Active, "Order not active");
        } else {
            // For cross-chain swaps, the order should be Unknown on the destination chain
            require(orderStatus(orderId) == IAori.OrderStatus.Unknown, "Order not active");
        }
    }

    /**
     * @notice Validates the cancellation of a cross-chain order from the destination chain
     * @dev Allows whitelisted solvers (anytime), offerers (after expiry), and recipients (after expiry) to cancel
     * @param order The order details to cancel
     * @param orderId The hash of the order to cancel
     * @param endpointId The current chain's endpoint ID
     * @param orderStatus The status mapping function to check order status
     * @param sender The address of the transaction sender
     * @param isAllowedSolver A function to check if an address is a whitelisted solver
     */
    function validateCancel(
        IAori.Order calldata order,
        bytes32 orderId,
        uint32 endpointId,
        function(bytes32) external view returns (IAori.OrderStatus) orderStatus,
        address sender,
        function(address) external view returns (bool) isAllowedSolver
    ) internal view {
        require(order.dstEid == endpointId, "Not on destination chain");
        require(orderStatus(orderId) == IAori.OrderStatus.Unknown, "Order not active");
        require(
            (isAllowedSolver(sender)) ||
                (sender == order.offerer && block.timestamp > order.endTime) ||
                (sender == order.recipient && block.timestamp > order.endTime),
            "Only whitelisted solver, offerer, or recipient (after expiry) can cancel"
        );
    }

    /**
     * @notice Validates cancellation of an order on the source chain
     * @dev Only allows cancellation of single-chain orders or by solver (with expiry restriction for cross-chain)
     * @param order The order details to cancel
     * @param orderId The hash of the order to cancel
     * @param endpointId The current chain's endpoint ID
     * @param orderStatus The function to check order status
     * @param sender The transaction sender address
     * @param isAllowedSolver The function to check if an address is a whitelisted solver
     */
    function validateSourceChainCancel(
        IAori.Order memory order,
        bytes32 orderId,
        uint32 endpointId,
        function(bytes32) external view returns (IAori.OrderStatus) orderStatus,
        address sender,
        function(address) external view returns (bool) isAllowedSolver
    ) internal view {
        // Verify we're on the source chain
        require(order.srcEid == endpointId, "Not on source chain");
        
        // Verify order exists and is active
        require(orderStatus(orderId) == IAori.OrderStatus.Active, "Order not active");
        
        // Cross-chain orders cannot be cancelled from the source chain to prevent race conditions
        // with settlement messages. Use emergencyCancel for emergency situations.
        require(order.srcEid == order.dstEid, "Cross-chain orders must be cancelled from destination chain");
        
        // For single-chain orders: solver can always cancel, offerer can cancel after expiry
        require(
            isAllowedSolver(sender) || 
            (sender == order.offerer && block.timestamp > order.endTime),
            "Only solver or offerer (after expiry) can cancel"
        );
    }

    /**
     * @notice Checks if an order is a single-chain swap
     * @param order The order to check
     * @return True if the order is a single-chain swap
     */
    function isSingleChainSwap(IAori.Order calldata order) internal pure returns (bool) {
        return order.srcEid == order.dstEid;
    }
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/*                         BALANCE                           */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/**
 * @notice Balance struct for tracking locked and unlocked token amounts
 * @dev Uses uint128 for both values to pack them into a single storage slot
 */
struct Balance {
    uint128 locked; // Tokens locked in active orders
    uint128 unlocked; // Tokens available for withdrawal
}

using BalanceUtils for Balance global;

/**
 * @notice Utility library for managing token balances
 * @dev Provides functions for locking, unlocking, and managing token balances
 * with optimized storage operations
 */
library BalanceUtils {
    /**
     * @notice Locks a specified amount of tokens
     * @dev Increases the locked balance by the specified amount
     * @param balance The Balance struct reference
     * @param amount The amount to lock
     */
    function lock(Balance storage balance, uint128 amount) internal {
        balance.locked += amount;
    }

    /**
     * @notice Unlocks a specified amount of tokens from locked to unlocked state
     * @dev Decreases locked balance and increases unlocked balance
     * @param balance The Balance struct reference
     * @param amount The amount to unlock
     */
    function unlock(Balance storage balance, uint128 amount) internal {
        (uint128 locked, uint128 unlocked) = balance.loadBalance();
        require(locked >= amount, "Insufficient locked balance");
        unchecked {
            locked -= amount;
        }
        unlocked += amount;

        balance.storeBalance(locked, unlocked);
    }

    /**
     * @notice Decreases locked balance without reverting on underflow
     * @dev Safe version that returns false instead of reverting on underflow
     * @param balance The Balance struct reference
     * @param amount The amount to decrease
     * @return success Whether the operation was successful
     */
    function decreaseLockedNoRevert(
        Balance storage balance,
        uint128 amount
    ) internal returns (bool success) {
        uint128 locked = balance.locked;
        unchecked {
            uint128 newLocked = locked - amount;
            if (newLocked > locked) {
                return false; // Underflow
            }
            balance.locked = newLocked;
        }
        return true;
    }

    /**
     * @notice Increases unlocked balance without reverting on overflow
     * @dev Safe version that returns false instead of reverting on overflow
     * @param balance The Balance struct reference
     * @param amount The amount to increase
     * @return success Whether the operation was successful
     */
    function increaseUnlockedNoRevert(
        Balance storage balance,
        uint128 amount
    ) internal returns (bool success) {
        uint128 unlocked = balance.unlocked;
        unchecked {
            uint128 newUnlocked = unlocked + amount;
            if (newUnlocked < unlocked) {
                return false; // Overflow
            }
            balance.unlocked = newUnlocked;
        }
        return true;
    }

    /**
     * @notice Unlocks all locked tokens into the unlocked balance
     * @dev Moves the entire locked balance to unlocked
     * @param balance The Balance struct reference
     * @return amount The amount that was unlocked
     */
    function unlockAll(Balance storage balance) internal returns (uint128 amount) {
        (uint128 locked, uint128 unlocked) = balance.loadBalance();
        amount = locked;
        unlocked += amount;
        locked = 0;

        balance.storeBalance(locked, unlocked);
    }

    /**
     * @notice Gets the unlocked balance amount
     * @param balance The Balance struct reference
     * @return The unlocked balance amount
     */
    function getUnlocked(Balance storage balance) internal view returns (uint128) {
        return balance.unlocked;
    }

    /**
     * @notice Gets the locked balance amount
     * @param balance The Balance struct reference
     * @return The locked balance amount
     */
    function getLocked(Balance storage balance) internal view returns (uint128) {
        return balance.locked;
    }

    /**
     * @notice Load balance values using optimized storage operations
     * @dev Uses assembly to read both values in a single storage read
     * @param balance The Balance struct reference
     * @return locked The locked balance
     * @return unlocked The unlocked balance
     */
    function loadBalance(
        Balance storage balance
    ) internal view returns (uint128 locked, uint128 unlocked) {
        assembly {
            let fullSlot := sload(balance.slot)
            unlocked := shr(128, fullSlot)
            locked := fullSlot
        }
    }

    /**
     * @notice Store balance values using optimized storage operations
     * @dev Uses assembly to write both values in a single storage write
     * @param balance The Balance struct reference
     * @param locked The locked balance to store
     * @param unlocked The unlocked balance to store
     */
    function storeBalance(Balance storage balance, uint128 locked, uint128 unlocked) internal {
        assembly {
            sstore(balance.slot, or(shl(128, unlocked), locked))
        }
    }

    /**
     * @notice Validates a decrease in locked balance with a corresponding increase in unlocked balance
     * @dev Verifies that the token accounting was performed correctly during transfer operations
     * @param _balance The Balance struct reference (not used, but needed for extension method pattern)
     * @param initialOffererLocked The offerer's initial locked balance
     * @param finalOffererLocked The offerer's final locked balance
     * @param initialSolverUnlocked The solver's initial unlocked balance
     * @param finalSolverUnlocked The solver's final unlocked balance
     * @param transferAmount The amount that should have been transferred
     * @return success Whether the validation was successful
     */
    function validateBalanceTransfer(
        Balance storage _balance,
        uint128 initialOffererLocked,
        uint128 finalOffererLocked,
        uint128 initialSolverUnlocked,
        uint128 finalSolverUnlocked,
        uint128 transferAmount
    ) internal pure returns (bool success) {
        // Verify offerer's locked balance decreased by exactly the transfer amount
        if (initialOffererLocked != finalOffererLocked + transferAmount) {
            return false;
        }

        // Verify solver's unlocked balance increased by exactly the transfer amount
        if (finalSolverUnlocked != initialSolverUnlocked + transferAmount) {
            return false;
        }

        return true;
    }

    /**
     * @notice Validates a decrease in locked balance with a corresponding increase in unlocked balance with revert
     * @dev Same as validateBalanceTransfer but reverts with custom error messages if validation fails
     * @param _balance The Balance struct reference (not used, but needed for extension method pattern)
     * @param initialOffererLocked The offerer's initial locked balance
     * @param finalOffererLocked The offerer's final locked balance
     * @param initialSolverUnlocked The solver's initial unlocked balance
     * @param finalSolverUnlocked The solver's final unlocked balance
     * @param transferAmount The amount that should have been transferred
     */
    function validateBalanceTransferOrRevert(
        Balance storage _balance,
        uint128 initialOffererLocked,
        uint128 finalOffererLocked,
        uint128 initialSolverUnlocked,
        uint128 finalSolverUnlocked,
        uint128 transferAmount
    ) internal pure {
        // Verify offerer's locked balance decreased by exactly the transfer amount
        require(
            initialOffererLocked == finalOffererLocked + transferAmount,
            "Inconsistent offerer balance"
        );

        // Verify solver's unlocked balance increased by exactly the transfer amount
        require(
            finalSolverUnlocked == initialSolverUnlocked + transferAmount,
            "Inconsistent solver balance"
        );
    }
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/*                       EXECUTION                           */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/**
 * @notice Library for executing external calls and observing token balance changes
 * @dev Used for hook execution and token conversion operations
 */
library ExecutionUtils {
    /**
     * @notice Executes an external call and measures the resulting token balance change
     * @dev Useful for hook operations that convert tokens
     * @param target The target contract address to call
     * @param data The calldata to send to the target
     * @param observedToken The token address to observe balance changes for
     * @return The balance change (positive if tokens increased, reverts if decreased)
     */
    function observeBalChg(
        address target,
        bytes calldata data,
        address observedToken
    ) internal returns (uint256) {
        uint256 balBefore = NativeTokenUtils.balanceOf(observedToken, address(this));
        (bool success, ) = target.call(data);
        require(success, "Call failed");
        uint256 balAfter = NativeTokenUtils.balanceOf(observedToken, address(this));
        
        // Prevent underflow and provide clear error message
        require(balAfter >= balBefore, "Hook decreased contract balance");
        
        return balAfter - balBefore;
    }
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/*                          HOOKS                            */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/**
 * @notice Library for hook-related utility functions
 * @dev Provides helper functions for working with SrcHook and DstHook structs
 */
library HookUtils {
    /**
     * @notice Checks if a SrcHook is defined (has a non-zero address)
     * @param hook The SrcHook struct to check
     * @return True if the hook has a non-zero address
     */
    function isSome(IAori.SrcHook calldata hook) internal pure returns (bool) {
        return hook.hookAddress != address(0);
    }

    /**
     * @notice Checks if a DstHook is defined (has a non-zero address)
     * @param hook The DstHook struct to check
     * @return True if the hook has a non-zero address
     */
    function isSome(IAori.DstHook calldata hook) internal pure returns (bool) {
        return hook.hookAddress != address(0);
    }
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/*                      PAYLOAD TYPES                        */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/**
 * @notice Enum for different LayerZero message payload types
 */
enum PayloadType {
    Settlement, // Settlement message with multiple order fills (0)
    Cancellation // Cancellation message for a single order (1)
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/*                    PAYLOAD PACKING                        */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/**
 * @notice Library for packing LayerZero message payloads
 * @dev Provides functions to create properly formatted message payloads for cross-chain messaging
 * that will work with the MessagingReceipt tracking in the contract
 */
library PayloadPackUtils {
    /**
     * @notice Packs a settlement payload with order hashes for LayerZero messaging
     * @dev Creates a settlement payload and clears the filled orders from storage
     * The message will return a MessagingReceipt that is included in the SettleSent event
     * @param arr The array of order hashes to be packed
     * @param filler The address of the filler
     * @param takeSize The number of order hashes to take from the array
     * @return The packed payload
     *
     * @notice The payload structure is as follows:
     * Header
     * - 1 byte: Message type (0)
     * - 20 bytes: Filler address
     * - 2 bytes: Fill count
     * Body
     * - Fill count * 32 bytes: Order hashes
     */
    function packSettlement(
        bytes32[] storage arr,
        address filler,
        uint16 takeSize
    ) internal returns (bytes memory) {
        uint32 offset = 23;
        bytes memory payload = new bytes(offset + takeSize * 32);

        assembly {
            let payloadPtr := add(payload, 32)
            // Store msgType, filler and takeSize
            mstore(payloadPtr, or(shl(88, filler), shl(72, takeSize)))

            // Load array slot
            mstore(0x00, arr.slot)
            let base := keccak256(0x00, 32)

            let arrLength := sload(arr.slot)
            let min_i := sub(arrLength, takeSize)
            let dataPtr := add(payloadPtr, offset)

            // Store storage elements into memory and clear them
            for {
                let i := arrLength
            } gt(i, min_i) {} {
                i := sub(i, 1)
                let elementSlot := add(base, i)

                mstore(dataPtr, sload(elementSlot)) // Storage -> memory
                sstore(elementSlot, 0) // Clear the slot

                dataPtr := add(dataPtr, 32)
            }
            // Update the array length
            sstore(arr.slot, min_i)
        }
        return payload;
    }

    /**
     * @notice Packs a cancellation payload for LayerZero messaging
     * @dev Creates a properly formatted cancellation message payload
     * The message will return a MessagingReceipt that is included in the CancelSent event
     * @param orderHash The hash of the order to cancel
     * @return payload The packed cancellation payload
     */
    function packCancellation(bytes32 orderHash) internal pure returns (bytes memory) {
        uint8 msgType = uint8(PayloadType.Cancellation);
        return abi.encodePacked(msgType, orderHash);
    }
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/*                   PAYLOAD UNPACKING                       */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/**
 * @notice Library for unpacking LayerZero message payloads
 * @dev Provides functions to extract and validate data from received payloads
 */
library PayloadUnpackUtils {
    /**
     * @notice Validates the length of a cancellation payload
     * @dev Ensures the payload is exactly 33 bytes (1 byte type + 32 bytes order hash)
     * @param payload The payload to validate
     */
    function validateCancellationLen(bytes calldata payload) internal pure {
        require(payload.length == 33, "Invalid cancellation payload length");
    }

    /**
     * @notice Unpacks an order hash from a cancellation payload
     * @dev Extracts the 32-byte order hash, skipping the first byte (type)
     * @param payload The cancellation payload to unpack
     * @return orderHash The extracted order hash
     */
    function unpackCancellation(bytes calldata payload) internal pure returns (bytes32 orderHash) {
        assembly {
            orderHash := calldataload(add(payload.offset, 1))
        }
    }

    /**
     * @notice Validates the minimum length of a settlement payload
     * @dev Ensures the payload is at least 23 bytes (header size)
     * @param payload The payload to validate
     */
    function validateSettlementLen(bytes calldata payload) internal pure {
        require(payload.length >= 23, "Payload too short for settlement");
    }

    /**
     * @notice Validates the length of a settlement payload for a specific fill count
     * @dev Ensures the payload matches the expected size based on fill count
     * @param payload The payload to validate
     * @param fillCount The number of fills in the payload
     */
    function validateSettlementLen(bytes calldata payload, uint16 fillCount) internal pure {
        require(
            payload.length == 23 + uint256(fillCount) * 32,
            "Invalid payload length for settlement"
        );
    }

    /**
     * @notice Gets the payload type from a message payload
     * @dev Reads the first byte to determine the payload type
     * @param payload The payload to check
     * @return The payload type (Settlement or Cancellation)
     */
    function getType(bytes calldata payload) internal pure returns (PayloadType) {
        return PayloadType(uint8(payload[0]));
    }

    /**
     * @notice Unpacks the header from a settlement payload
     * @dev Extracts the filler address (20 bytes) and fill count (2 bytes)
     * @param payload The settlement payload to unpack
     * @return filler The filler address
     * @return fillCount The number of fills in the payload
     */
    function unpackSettlementHeader(
        bytes calldata payload
    ) internal pure returns (address filler, uint16 fillCount) {
        require(payload.length >= 23, "Invalid payload length");
        assembly {
            let word := calldataload(add(payload.offset, 1))
            filler := shr(96, word)
        }
        fillCount = (uint16(uint8(payload[21])) << 8) | uint16(uint8(payload[22]));
    }

    /**
     * @notice Unpacks an order hash from a specific position in the settlement payload body
     * @dev Extracts the order hash at the specified index
     * @param payload The settlement payload to unpack
     * @param index The index of the order hash to extract
     * @return orderHash The extracted order hash
     */
    function unpackSettlementBodyAt(
        bytes calldata payload,
        uint256 index
    ) internal pure returns (bytes32 orderHash) {
        require(payload.length >= 23, "Invalid payload length");
        require(index < (payload.length - 23) / 32, "Index out of bounds");
        assembly {
            orderHash := calldataload(add(add(payload.offset, 23), mul(index, 32)))
        }
    }
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/*                    PAYLOAD SIZES                        */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/**
 * @notice Calculates the size of a settlement payload based on fill count
 * @dev 1 byte type + 20 bytes filler + 2 bytes count + (fillCount * 32 bytes order hash)
 * @param fillCount The number of fills in the settlement
 * @return The total payload size in bytes
 */
function settlementPayloadSize(uint256 fillCount) pure returns (uint256) {
    return 1 + 20 + 2 + (fillCount * 32);
}

// Constant size of a cancellation payload: 1 byte type + 32 bytes order hash
uint256 constant CANCELLATION_PAYLOAD_SIZE = 33;

/**
 * @notice Library for payload size calculations
 * @dev Provides functions to calculate payload sizes for different message types
 */
library PayloadSizeUtils {
    /**
     * @notice Calculate payload size based on message type and other parameters
     * @dev Used for fee estimation when sending messages via LayerZero
     * @param msgType Message type (0 for settlement, 1 for cancellation)
     * @param fillsLength Number of fills available for the filler
     * @param maxFillsPerSettle Maximum fills allowed per settlement
     * @return The calculated payload size in bytes
     */
    function calculatePayloadSize(
        uint8 msgType,
        uint256 fillsLength,
        uint16 maxFillsPerSettle
    ) internal pure returns (uint256) {
        if (msgType == uint8(PayloadType.Cancellation)) {
            return CANCELLATION_PAYLOAD_SIZE; // 1 byte type + 32 bytes order hash
        } else if (msgType == uint8(PayloadType.Settlement)) {
            // Get the number of fills (capped by maxFillsPerSettle)
            uint16 fillCount = uint16(
                fillsLength < maxFillsPerSettle ? fillsLength : maxFillsPerSettle
            );

            // Calculate settlement payload size
            return settlementPayloadSize(fillCount);
        } else {
            revert("Invalid message type");
        }
    }
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/*                    NATIVE TOKEN UTILS                     */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

// Native token address constant
address constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

/**
 * @notice Library for native token operations
 * @dev Provides utilities for handling native ETH alongside ERC20 tokens
 */
library NativeTokenUtils {
    using SafeERC20 for IERC20;
    
    /**
     * @notice Checks if a token address represents native ETH
     * @param token The token address to check
     * @return True if the token is the native token address
     */
    function isNativeToken(address token) internal pure returns (bool) {
        return token == NATIVE_TOKEN;
    }

    /**
     * @notice Safely transfers tokens (native or ERC20) to a recipient
     * @param token The token address (use NATIVE_TOKEN for ETH)
     * @param to The recipient address
     * @param amount The amount to transfer
     */
    function safeTransfer(address token, address to, uint256 amount) internal {
        if (isNativeToken(token)) {
            (bool success, ) = payable(to).call{value: amount}("");
            require(success, "Native transfer failed");
        } else {
            IERC20(token).safeTransfer(to, amount);
        }
    }

    /**
     * @notice Gets the balance of a token for a specific address
     * @param token The token address (use NATIVE_TOKEN for ETH)
     * @param account The account to check balance for
     * @return The token balance
     */
    function balanceOf(address token, address account) internal view returns (uint256) {
        if (isNativeToken(token)) {
            return account.balance;
        } else {
            return IERC20(token).balanceOf(account);
        }
    }

    /**
     * @notice Validates that the contract has sufficient balance for a transfer
     * @param token The token address (use NATIVE_TOKEN for ETH)
     * @param amount The amount to validate
     */
    function validateSufficientBalance(address token, uint256 amount) internal view {
        if (isNativeToken(token)) {
            require(address(this).balance >= amount, "Insufficient contract native balance");
        } else {
            require(IERC20(token).balanceOf(address(this)) >= amount, "Insufficient contract balance");
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IAori {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           STATUS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    enum OrderStatus {
        Unknown, // Order not found
        Active, // Order deposited but not filled
        Filled, // Pending settlement
        Cancelled, // Order cancelled
        Settled // Order settled
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                             ORDER                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    struct Order {
        uint128 inputAmount;
        uint128 outputAmount;
        address inputToken;
        address outputToken;
        uint32 startTime;
        uint32 endTime;
        uint32 srcEid;
        uint32 dstEid;
        address offerer;
        address recipient;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                            HOOKS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    struct SrcHook {
        address hookAddress;
        address preferredToken;
        uint256 minPreferedTokenAmountOut;
        bytes instructions;
    }

    struct DstHook {
        address hookAddress;
        address preferredToken;
        bytes instructions;
        uint256 preferedDstInputAmount;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          SRC EVENTS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    event Deposit(bytes32 indexed orderId, Order order);
    event Cancel(bytes32 indexed orderId);
    event Settle(bytes32 indexed orderId);
    event Withdraw(address indexed holder, address indexed token, uint256 amount);

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    CHAIN MANAGEMENT EVENTS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    event ChainSupported(uint32 indexed eid);
    event ChainRemoved(uint32 indexed eid);

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          DST EVENTS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    event Fill(bytes32 indexed orderId, Order order);
    
    /**
     * @notice Emitted when an order is cancelled from the destination chain
     * @dev Contains MessagingReceipt data for cross-chain tracking
     * @param orderId The hash of the cancelled order
     * @param guid The unique identifier of the LayerZero message
     * @param nonce The nonce of the LayerZero message
     * @param fee The fee paid for the LayerZero message
     */
    event CancelSent(bytes32 indexed orderId, bytes32 guid, uint64 nonce, uint256 fee);
    
    /**
     * @notice Emitted when orders are settled from the destination chain
     * @dev Contains MessagingReceipt data for cross-chain tracking
     * @param srcEid The source endpoint ID
     * @param filler The address of the filler
     * @param payload The settlement payload
     * @param guid The unique identifier of the LayerZero message
     * @param nonce The nonce of the LayerZero message
     * @param fee The fee paid for the LayerZero message
     */
    event SettleSent(uint32 indexed srcEid, address indexed filler, bytes payload, bytes32 guid, uint64 nonce, uint256 fee);

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        SRC FUNCTIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function deposit(Order calldata order, bytes calldata signature) external;

    function deposit(
        Order calldata order,
        bytes calldata signature,
        SrcHook calldata data
    ) external;

    function depositNative(Order calldata order) external payable;

    function withdraw(address token, uint256 amount) external;

    function cancel(bytes32 orderId) external;

    event settlementFailed(bytes32 indexed orderId, uint32 expectedEid, uint32 submittedEid, string reason);


    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        DST FUNCTIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function fill(Order calldata order) external payable;

    function fill(Order calldata order, DstHook calldata hook) external payable;

    function settle(uint32 srcEid, address filler, bytes calldata extraOptions) external payable;

    function cancel(
        bytes32 orderId,
        Order calldata orderToCancel,
        bytes calldata extraOptions
    ) external payable;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        UTILITY FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function hash(Order calldata order) external pure returns (bytes32);

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       VIEW FUNCTIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function getLockedBalances(address offerer, address token) external view returns (uint256);

    function getUnlockedBalances(address offerer, address token) external view returns (uint256);

    function quote(
        uint32 _dstEid,
        uint8 _msgType,
        bytes calldata _options,
        bool _payInLzToken,
        uint32 _srcEid,
        address _filler
    ) external view returns (uint256 fee);

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        HOOK EVENTS                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /**
     * @notice Emitted when a source hook is executed during deposit
     * @param orderId The hash of the order being processed
     * @param preferredToken The token address that was received from the hook
     * @param amountReceived The amount of tokens received from hook execution
     */
    event SrcHookExecuted(bytes32 indexed orderId, address indexed preferredToken, uint256 amountReceived);

    /**
     * @notice Emitted when a destination hook is executed during fill
     * @param orderId The hash of the order being processed
     * @param preferredToken The token address that was converted by the hook
     * @param amountReceived The amount of output tokens received from hook execution
     */
    event DstHookExecuted(bytes32 indexed orderId, address indexed preferredToken, uint256 amountReceived);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Gas optimized ECDSA wrapper.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
///
/// @dev Note:
/// - The recovery functions use the ecrecover precompile (0x1).
/// - As of Solady version 0.0.68, the `recover` variants will revert upon recovery failure.
///   This is for more safety by default.
///   Use the `tryRecover` variants if you need to get the zero address back
///   upon recovery failure instead.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
///   regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
///   See: https://eips.ethereum.org/EIPS/eip-2098
///   This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT directly use signatures as unique identifiers:
/// - The recovery operations do NOT check if a signature is non-malleable.
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
///   EIP-712 also enables readable signing of typed data for better user safety.
/// - If you need a unique hash from a signature, please use the `canonicalHash` functions.
library ECDSA {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The order of the secp256k1 elliptic curve.
    uint256 internal constant N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141;

    /// @dev `N/2 + 1`. Used for checking the malleability of the signature.
    uint256 private constant _HALF_N_PLUS_1 =
        0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The signature is invalid.
    error InvalidSignature();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    RECOVERY OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
    function recover(bytes32 hash, bytes memory signature) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            for { let m := mload(0x40) } 1 {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            } {
                switch mload(signature)
                case 64 {
                    let vs := mload(add(signature, 0x40))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                    mstore(0x60, mload(add(signature, 0x40))) // `s`.
                }
                default { continue }
                mstore(0x00, hash)
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if returndatasize() { break }
            }
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
    function recoverCalldata(bytes32 hash, bytes calldata signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for { let m := mload(0x40) } 1 {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            } {
                switch signature.length
                case 64 {
                    let vs := calldataload(add(signature.offset, 0x20))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x40, calldataload(signature.offset)) // `r`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                    calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
                }
                default { continue }
                mstore(0x00, hash)
                result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if returndatasize() { break }
            }
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the EIP-2098 short form signature defined by `r` and `vs`.
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, add(shr(255, vs), 27)) // `v`.
            mstore(0x40, r)
            mstore(0x60, shr(1, shl(1, vs))) // `s`.
            result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the signature defined by `v`, `r`, `s`.
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, and(v, 0xff))
            mstore(0x40, r)
            mstore(0x60, s)
            result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   TRY-RECOVER OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // WARNING!
    // These functions will NOT revert upon recovery failure.
    // Instead, they will return the zero address upon recovery failure.
    // It is critical that the returned address is NEVER compared against
    // a zero address (e.g. an uninitialized address variable).

    /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
    function tryRecover(bytes32 hash, bytes memory signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for { let m := mload(0x40) } 1 {} {
                switch mload(signature)
                case 64 {
                    let vs := mload(add(signature, 0x40))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                    mstore(0x60, mload(add(signature, 0x40))) // `s`.
                }
                default { break }
                mstore(0x00, hash)
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
                mstore(0x60, 0) // Restore the zero slot.
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                result := mload(xor(0x60, returndatasize()))
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
    function tryRecoverCalldata(bytes32 hash, bytes calldata signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for { let m := mload(0x40) } 1 {} {
                switch signature.length
                case 64 {
                    let vs := calldataload(add(signature.offset, 0x20))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x40, calldataload(signature.offset)) // `r`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                    calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
                }
                default { break }
                mstore(0x00, hash)
                pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
                mstore(0x60, 0) // Restore the zero slot.
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                result := mload(xor(0x60, returndatasize()))
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the EIP-2098 short form signature defined by `r` and `vs`.
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, add(shr(255, vs), 27)) // `v`.
            mstore(0x40, r)
            mstore(0x60, shr(1, shl(1, vs))) // `s`.
            pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the signature defined by `v`, `r`, `s`.
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, and(v, 0xff))
            mstore(0x40, r)
            mstore(0x60, s)
            pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HASHING OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an Ethereum Signed Message, created from a `hash`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, hash) // Store into scratch space for keccak256.
            mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
            result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
        }
    }

    /// @dev Returns an Ethereum Signed Message, created from `s`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    /// Note: Supports lengths of `s` up to 999999 bytes.
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let sLength := mload(s)
            let o := 0x20
            mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
            mstore(0x00, 0x00)
            // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
            for { let temp := sLength } 1 {} {
                o := sub(o, 1)
                mstore8(o, add(48, mod(temp, 10)))
                temp := div(temp, 10)
                if iszero(temp) { break }
            }
            let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
            // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
            mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
            result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
            mstore(s, sLength) // Restore the length.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  CANONICAL HASH FUNCTIONS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // The following functions return the hash of the signature in its canonicalized format,
    // which is the 65-byte `abi.encodePacked(r, s, uint8(v))`, where `v` is either 27 or 28.
    // If `s` is greater than `N / 2` then it will be converted to `N - s`
    // and the `v` value will be flipped.
    // If the signature has an invalid length, or if `v` is invalid,
    // a uniquely corrupt hash will be returned.
    // These functions are useful for "poor-mans-VRF".

    /// @dev Returns the canonical hash of `signature`.
    function canonicalHash(bytes memory signature) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let l := mload(signature)
            for {} 1 {} {
                mstore(0x00, mload(add(signature, 0x20))) // `r`.
                let s := mload(add(signature, 0x40))
                let v := mload(add(signature, 0x41))
                if eq(l, 64) {
                    v := add(shr(255, s), 27)
                    s := shr(1, shl(1, s))
                }
                if iszero(lt(s, _HALF_N_PLUS_1)) {
                    v := xor(v, 7)
                    s := sub(N, s)
                }
                mstore(0x21, v)
                mstore(0x20, s)
                result := keccak256(0x00, 0x41)
                mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
                break
            }

            // If the length is neither 64 nor 65, return a uniquely corrupted hash.
            if iszero(lt(sub(l, 64), 2)) {
                // `bytes4(keccak256("InvalidSignatureLength"))`.
                result := xor(keccak256(add(signature, 0x20), l), 0xd62f1ab2)
            }
        }
    }

    /// @dev Returns the canonical hash of `signature`.
    function canonicalHashCalldata(bytes calldata signature)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                mstore(0x00, calldataload(signature.offset)) // `r`.
                let s := calldataload(add(signature.offset, 0x20))
                let v := calldataload(add(signature.offset, 0x21))
                if eq(signature.length, 64) {
                    v := add(shr(255, s), 27)
                    s := shr(1, shl(1, s))
                }
                if iszero(lt(s, _HALF_N_PLUS_1)) {
                    v := xor(v, 7)
                    s := sub(N, s)
                }
                mstore(0x21, v)
                mstore(0x20, s)
                result := keccak256(0x00, 0x41)
                mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
                break
            }
            // If the length is neither 64 nor 65, return a uniquely corrupted hash.
            if iszero(lt(sub(signature.length, 64), 2)) {
                calldatacopy(mload(0x40), signature.offset, signature.length)
                // `bytes4(keccak256("InvalidSignatureLength"))`.
                result := xor(keccak256(mload(0x40), signature.length), 0xd62f1ab2)
            }
        }
    }

    /// @dev Returns the canonical hash of `signature`.
    function canonicalHash(bytes32 r, bytes32 vs) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, r) // `r`.
            let v := add(shr(255, vs), 27)
            let s := shr(1, shl(1, vs))
            mstore(0x21, v)
            mstore(0x20, s)
            result := keccak256(0x00, 0x41)
            mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns the canonical hash of `signature`.
    function canonicalHash(uint8 v, bytes32 r, bytes32 s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, r) // `r`.
            if iszero(lt(s, _HALF_N_PLUS_1)) {
                v := xor(v, 7)
                s := sub(N, s)
            }
            mstore(0x21, v)
            mstore(0x20, s)
            result := keccak256(0x00, 0x41)
            mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   EMPTY CALLDATA HELPERS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an empty calldata bytes.
    function emptySignature() internal pure returns (bytes calldata signature) {
        /// @solidity memory-safe-assembly
        assembly {
            signature.length := 0
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Contract for EIP-712 typed structured data hashing and signing.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EIP712.sol)
/// @author Modified from Solbase (https://github.com/Sol-DAO/solbase/blob/main/src/utils/EIP712.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol)
///
/// @dev Note, this implementation:
/// - Uses `address(this)` for the `verifyingContract` field.
/// - Does NOT use the optional EIP-712 salt.
/// - Does NOT use any EIP-712 extensions.
/// This is for simplicity and to save gas.
/// If you need to customize, please fork / modify accordingly.
abstract contract EIP712 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  CONSTANTS AND IMMUTABLES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
    bytes32 internal constant _DOMAIN_TYPEHASH =
        0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;

    /// @dev `keccak256("EIP712Domain(string name,string version,address verifyingContract)")`.
    /// This is only used in `_hashTypedDataSansChainId`.
    bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID =
        0x91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a2766;

    /// @dev `keccak256("EIP712Domain(string name,string version)")`.
    /// This is only used in `_hashTypedDataSansChainIdAndVerifyingContract`.
    bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID_AND_VERIFYING_CONTRACT =
        0xb03948446334eb9b2196d5eb166f69b9d49403eb4a12f36de8d3f9f3cb8e15c3;

    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId)")`.
    /// This is only used in `_hashTypedDataSansVerifyingContract`.
    bytes32 internal constant _DOMAIN_TYPEHASH_SANS_VERIFYING_CONTRACT =
        0xc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6e;

    uint256 private immutable _cachedThis;
    uint256 private immutable _cachedChainId;
    bytes32 private immutable _cachedNameHash;
    bytes32 private immutable _cachedVersionHash;
    bytes32 private immutable _cachedDomainSeparator;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CONSTRUCTOR                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Cache the hashes for cheaper runtime gas costs.
    /// In the case of upgradeable contracts (i.e. proxies),
    /// or if the chain id changes due to a hard fork,
    /// the domain separator will be seamlessly calculated on-the-fly.
    constructor() {
        _cachedThis = uint256(uint160(address(this)));
        _cachedChainId = block.chainid;

        string memory name;
        string memory version;
        if (!_domainNameAndVersionMayChange()) (name, version) = _domainNameAndVersion();
        bytes32 nameHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(name));
        bytes32 versionHash =
            _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(version));
        _cachedNameHash = nameHash;
        _cachedVersionHash = versionHash;

        bytes32 separator;
        if (!_domainNameAndVersionMayChange()) {
            /// @solidity memory-safe-assembly
            assembly {
                let m := mload(0x40) // Load the free memory pointer.
                mstore(m, _DOMAIN_TYPEHASH)
                mstore(add(m, 0x20), nameHash)
                mstore(add(m, 0x40), versionHash)
                mstore(add(m, 0x60), chainid())
                mstore(add(m, 0x80), address())
                separator := keccak256(m, 0xa0)
            }
        }
        _cachedDomainSeparator = separator;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   FUNCTIONS TO OVERRIDE                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Please override this function to return the domain name and version.
    /// ```
    ///     function _domainNameAndVersion()
    ///         internal
    ///         pure
    ///         virtual
    ///         returns (string memory name, string memory version)
    ///     {
    ///         name = "Solady";
    ///         version = "1";
    ///     }
    /// ```
    ///
    /// Note: If the returned result may change after the contract has been deployed,
    /// you must override `_domainNameAndVersionMayChange()` to return true.
    function _domainNameAndVersion()
        internal
        view
        virtual
        returns (string memory name, string memory version);

    /// @dev Returns if `_domainNameAndVersion()` may change
    /// after the contract has been deployed (i.e. after the constructor).
    /// Default: false.
    function _domainNameAndVersionMayChange() internal pure virtual returns (bool result) {}

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HASHING OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the EIP-712 domain separator.
    function _domainSeparator() internal view virtual returns (bytes32 separator) {
        if (_domainNameAndVersionMayChange()) {
            separator = _buildDomainSeparator();
        } else {
            separator = _cachedDomainSeparator;
            if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator();
        }
    }

    /// @dev Returns the hash of the fully encoded EIP-712 message for this domain,
    /// given `structHash`, as defined in
    /// https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct.
    ///
    /// The hash can be used together with {ECDSA-recover} to obtain the signer of a message:
    /// ```
    ///     bytes32 digest = _hashTypedData(keccak256(abi.encode(
    ///         keccak256("Mail(address to,string contents)"),
    ///         mailTo,
    ///         keccak256(bytes(mailContents))
    ///     )));
    ///     address signer = ECDSA.recover(digest, signature);
    /// ```
    function _hashTypedData(bytes32 structHash) internal view virtual returns (bytes32 digest) {
        // We will use `digest` to store the domain separator to save a bit of gas.
        if (_domainNameAndVersionMayChange()) {
            digest = _buildDomainSeparator();
        } else {
            digest = _cachedDomainSeparator;
            if (_cachedDomainSeparatorInvalidated()) digest = _buildDomainSeparator();
        }
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the digest.
            mstore(0x00, 0x1901000000000000) // Store "\x19\x01".
            mstore(0x1a, digest) // Store the domain separator.
            mstore(0x3a, structHash) // Store the struct hash.
            digest := keccak256(0x18, 0x42)
            // Restore the part of the free memory slot that was overwritten.
            mstore(0x3a, 0)
        }
    }

    /// @dev Variant of `_hashTypedData` that excludes the chain ID.
    /// Included for the niche use case of cross-chain workflows.
    function _hashTypedDataSansChainId(bytes32 structHash)
        internal
        view
        virtual
        returns (bytes32 digest)
    {
        (string memory name, string memory version) = _domainNameAndVersion();
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(0x00, _DOMAIN_TYPEHASH_SANS_CHAIN_ID)
            mstore(0x20, keccak256(add(name, 0x20), mload(name)))
            mstore(0x40, keccak256(add(version, 0x20), mload(version)))
            mstore(0x60, address())
            // Compute the digest.
            mstore(0x20, keccak256(0x00, 0x80)) // Store the domain separator.
            mstore(0x00, 0x1901) // Store "\x19\x01".
            mstore(0x40, structHash) // Store the struct hash.
            digest := keccak256(0x1e, 0x42)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /// @dev Variant of `_hashTypedData` that excludes the chain ID and verifying contract.
    /// Included for the niche use case of cross-chain and multi-verifier workflows.
    function _hashTypedDataSansChainIdAndVerifyingContract(bytes32 structHash)
        internal
        view
        virtual
        returns (bytes32 digest)
    {
        (string memory name, string memory version) = _domainNameAndVersion();
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(0x00, _DOMAIN_TYPEHASH_SANS_CHAIN_ID_AND_VERIFYING_CONTRACT)
            mstore(0x20, keccak256(add(name, 0x20), mload(name)))
            mstore(0x40, keccak256(add(version, 0x20), mload(version)))
            // Compute the digest.
            mstore(0x20, keccak256(0x00, 0x60)) // Store the domain separator.
            mstore(0x00, 0x1901) // Store "\x19\x01".
            mstore(0x40, structHash) // Store the struct hash.
            digest := keccak256(0x1e, 0x42)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /// @dev Variant of `_hashTypedData` that excludes the chain ID and verifying contract.
    /// Included for the niche use case of multi-verifier workflows.
    function _hashTypedDataSansVerifyingContract(bytes32 structHash)
        internal
        view
        virtual
        returns (bytes32 digest)
    {
        (string memory name, string memory version) = _domainNameAndVersion();
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(0x00, _DOMAIN_TYPEHASH_SANS_VERIFYING_CONTRACT)
            mstore(0x20, keccak256(add(name, 0x20), mload(name)))
            mstore(0x40, keccak256(add(version, 0x20), mload(version)))
            mstore(0x60, chainid())
            // Compute the digest.
            mstore(0x20, keccak256(0x00, 0x80)) // Store the domain separator.
            mstore(0x00, 0x1901) // Store "\x19\x01".
            mstore(0x40, structHash) // Store the struct hash.
            digest := keccak256(0x1e, 0x42)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    EIP-5267 OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev See: https://eips.ethereum.org/EIPS/eip-5267
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        fields = hex"0f"; // `0b01111`.
        (name, version) = _domainNameAndVersion();
        chainId = block.chainid;
        verifyingContract = address(this);
        salt = salt; // `bytes32(0)`.
        extensions = extensions; // `new uint256[](0)`.
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the EIP-712 domain separator.
    function _buildDomainSeparator() private view returns (bytes32 separator) {
        // We will use `separator` to store the name hash to save a bit of gas.
        bytes32 versionHash;
        if (_domainNameAndVersionMayChange()) {
            (string memory name, string memory version) = _domainNameAndVersion();
            separator = keccak256(bytes(name));
            versionHash = keccak256(bytes(version));
        } else {
            separator = _cachedNameHash;
            versionHash = _cachedVersionHash;
        }
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Load the free memory pointer.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), separator) // Name hash.
            mstore(add(m, 0x40), versionHash)
            mstore(add(m, 0x60), chainid())
            mstore(add(m, 0x80), address())
            separator := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns if the cached domain separator has been invalidated.
    function _cachedDomainSeparatorInvalidated() private view returns (bool result) {
        uint256 cachedChainId = _cachedChainId;
        uint256 cachedThis = _cachedThis;
        /// @solidity memory-safe-assembly
        assembly {
            result := iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis)))
        }
    }
}

Settings
{
  "evmVersion": "paris",
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "remappings": [],
  "viaIR": true,
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_endpoint","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"uint16","name":"_maxFillsPerSettle","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"InvalidDelegate","type":"error"},{"inputs":[],"name":"InvalidEndpointCall","type":"error"},{"inputs":[],"name":"LzTokenUnavailable","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"NoPeer","type":"error"},{"inputs":[{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"NotEnoughNative","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"OnlyEndpoint","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"}],"name":"OnlyPeer","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"Cancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"CancelSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"eid","type":"uint32"}],"name":"ChainRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"eid","type":"uint32"}],"name":"ChainSupported","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"components":[{"internalType":"uint128","name":"inputAmount","type":"uint128"},{"internalType":"uint128","name":"outputAmount","type":"uint128"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"indexed":false,"internalType":"struct IAori.Order","name":"order","type":"tuple"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"preferredToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"}],"name":"DstHookExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"components":[{"internalType":"uint128","name":"inputAmount","type":"uint128"},{"internalType":"uint128","name":"outputAmount","type":"uint128"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"indexed":false,"internalType":"struct IAori.Order","name":"order","type":"tuple"}],"name":"Fill","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"eid","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"peer","type":"bytes32"}],"name":"PeerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"Settle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"srcEid","type":"uint32"},{"indexed":true,"internalType":"address","name":"filler","type":"address"},{"indexed":false,"internalType":"bytes","name":"payload","type":"bytes"},{"indexed":false,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"SettleSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"preferredToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"}],"name":"SrcHookExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"holder","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"expectedEid","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"submittedEid","type":"uint32"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"settlementFailed","type":"event"},{"inputs":[],"name":"ENDPOINT_ID","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FILLS_PER_SETTLE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hook","type":"address"}],"name":"addAllowedHook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"solver","type":"address"}],"name":"addAllowedSolver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"addSupportedChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"eids","type":"uint32[]"}],"name":"addSupportedChains","outputs":[{"internalType":"bool[]","name":"results","type":"bool[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"}],"name":"allowInitializePath","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"components":[{"internalType":"uint128","name":"inputAmount","type":"uint128"},{"internalType":"uint128","name":"outputAmount","type":"uint128"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IAori.Order","name":"orderToCancel","type":"tuple"},{"internalType":"bytes","name":"extraOptions","type":"bytes"}],"name":"cancel","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"inputAmount","type":"uint128"},{"internalType":"uint128","name":"outputAmount","type":"uint128"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IAori.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"components":[{"internalType":"address","name":"hookAddress","type":"address"},{"internalType":"address","name":"preferredToken","type":"address"},{"internalType":"uint256","name":"minPreferedTokenAmountOut","type":"uint256"},{"internalType":"bytes","name":"instructions","type":"bytes"}],"internalType":"struct IAori.SrcHook","name":"hook","type":"tuple"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"inputAmount","type":"uint128"},{"internalType":"uint128","name":"outputAmount","type":"uint128"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IAori.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"inputAmount","type":"uint128"},{"internalType":"uint128","name":"outputAmount","type":"uint128"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IAori.Order","name":"order","type":"tuple"}],"name":"depositNative","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"}],"name":"emergencyCancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"isLocked","type":"bool"},{"internalType":"address","name":"recipient","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpointV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"inputAmount","type":"uint128"},{"internalType":"uint128","name":"outputAmount","type":"uint128"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IAori.Order","name":"order","type":"tuple"}],"name":"fill","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"inputAmount","type":"uint128"},{"internalType":"uint128","name":"outputAmount","type":"uint128"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IAori.Order","name":"order","type":"tuple"},{"components":[{"internalType":"address","name":"hookAddress","type":"address"},{"internalType":"address","name":"preferredToken","type":"address"},{"internalType":"bytes","name":"instructions","type":"bytes"},{"internalType":"uint256","name":"preferedDstInputAmount","type":"uint256"}],"internalType":"struct IAori.DstHook","name":"hook","type":"tuple"}],"name":"fill","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"getLockedBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"getUnlockedBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"inputAmount","type":"uint128"},{"internalType":"uint128","name":"outputAmount","type":"uint128"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IAori.Order","name":"order","type":"tuple"}],"name":"hash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAllowedHook","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAllowedSolver","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"}],"name":"isComposeMsgSender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"isSupportedChain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"nextNonce","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oAppVersion","outputs":[{"internalType":"uint64","name":"senderVersion","type":"uint64"},{"internalType":"uint64","name":"receiverVersion","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"orderStatus","outputs":[{"internalType":"enum IAori.OrderStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"orders","outputs":[{"internalType":"uint128","name":"inputAmount","type":"uint128"},{"internalType":"uint128","name":"outputAmount","type":"uint128"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"peers","outputs":[{"internalType":"bytes32","name":"peer","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_dstEid","type":"uint32"},{"internalType":"uint8","name":"_msgType","type":"uint8"},{"internalType":"bytes","name":"_options","type":"bytes"},{"internalType":"bool","name":"_payInLzToken","type":"bool"},{"internalType":"uint32","name":"_srcEid","type":"uint32"},{"internalType":"address","name":"_filler","type":"address"}],"name":"quote","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hook","type":"address"}],"name":"removeAllowedHook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"solver","type":"address"}],"name":"removeAllowedSolver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"removeSupportedChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"address","name":"filler","type":"address"},{"internalType":"bytes","name":"extraOptions","type":"bytes"}],"name":"settle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"srcEidToFillerFills","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

61018080604052346102a6576000608082615ca9803803809161002282856102ab565b8339810103126102a357610035826102e4565b91610042602082016102e4565b604082015163ffffffff8116928382036102a157606001519161ffff831683036102a1576001600160a01b0316801561028d5784546001600160a01b0319811682178655604051969082906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08880a36001600160a01b0316608081905290813b1561028957602487878094829463ca5eb5e160e01b845260048401525af194851561027e5760409561026a575b5060016002553060a0524660c05260a085519461011587876102ab565b60048652602086019563416f726960e01b875287519661013589896102ab565b60058852602088019164302e332e3160d81b835251902091965190208160e05280610100528751917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8352602083015287820152466060820152306080820152206101205261014052610160528152600660205220600160ff198254161790556040516159b090816102f9823960805181818161054001528181610fb801528181611cfd01528181612f9c015281816139050152615013015260a05181505060c05181505060e05181505061010051815050610120518150506101405181818161074d0152818161098d01528181610dfd015281816110cc015281816115390152818161170b015281816118be01528181611ca90152611ef30152610160518181816108ce01528181610c910152612f0a0152f35b84610277919592956102ab565b92386100f8565b6040513d86823e3d90fd5b8580fd5b631e4fbdf760e01b85526004859052602485fd5b845b80fd5b600080fd5b601f909101601f19168101906001600160401b038211908210176102ce57604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036102a65756fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806305ef94ba1461030b5780630c89a13d1461030657806313137d651461030157806317442b70146102fc5780631c0166aa146102f75780631e2c273e146102f25780632c85455b146102ed5780632cee9acd146102e85780632d7c615a146102e35780632dff692d146102de5780633400288b146102d9578063344ba6fd146102d45780633f4ba83a146102cf57806344ae20c3146102ca57806350964586146102c5578063555c3898146102c0578063595490c8146102bb57806359f429a4146102b65780635c975abb146102b15780635e280f11146102ac5780636b624fdb146102a7578063715018a6146102a25780637ce5e33e1461029d5780637d25a05e146102985780637de637341461029357806382413eac1461028e5780638456cb591461028957806384b0196e146102845780638da5cb5b1461027f57806395ccea671461027a578063983f7fd114610275578063996628a0146102705780639c3f1e901461026b578063a9a683ba14610266578063b410f12214610261578063b8f480c61461025c578063bb0b6a5314610257578063c15c4b3714610252578063c4d252f51461024d578063ca5eb5e114610248578063cd77488714610243578063e86dfbbf1461023e578063e898841f14610239578063edb25d8114610234578063f2fde38b1461022f578063f3fef3a31461022a5763ff7bd03d0361000e576121df565b6120f5565b612068565b61201f565b611e56565b611e0e565b611d80565b611cd3565b611b4e565b611ae6565b611aab565b611a3f565b6119d6565b611854565b61175d565b611647565b6114b0565b6113fd565b6113d4565b611333565b611298565b61123a565b6111f8565b6111d1565b611086565b61102d565b610fe7565b610fa2565b610f7f565b610f3f565b610ef6565b610d2e565b610cb5565b610c76565b610c0d565b610bcb565b610b5c565b610b24565b6109bb565b610970565b6107e5565b61079f565b61061d565b6105d7565b6104d4565b61040a565b61035b565b6001600160a01b0381160361032157565b600080fd5b359061033182610310565b565b60409060031901126103215760043561034b81610310565b9060243561035881610310565b90565b3461032157602061036b36610333565b6001600160a01b039182166000908152600484526040808220929093168152602091909152206001600160801b03905416604051908152f35b63ffffffff81160361032157565b3590610331826103a4565b6001600160a01b0316600090815260046020526040902090565b634e487b7160e01b600052603260045260246000fd5b80548210156104055760005260206000200190600090565b6103d7565b3461032157606036600319011261032157600435610427816103a4565b61046460243561043681610310565b63ffffffff6044359316600052600a60205260406000209060018060a01b0316600052602052604060002090565b8054821015610321576104929161047a916103ed565b90549060031b1c604051918291829190602083019252565b0390f35b606090600319011261032157600490565b9181601f84011215610321578235916001600160401b038311610321576020838186019501011161032157565b60e0366003190112610321576104e936610496565b6064356084356001600160401b0381116103215761050b9036906004016104a7565b60a4929192359061051b82610310565b60c4356001600160401b0381116103215761053a9036906004016104a7565b949093337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316036105c257863596610579886103a4565b610582886130fc565b97602082013580990361059a57506100199750613130565b63ffffffff816105aa8b936103a4565b63309afaf360e21b6000521660045260245260446000fd5b6391ac5e4f60e01b6000523360045260246000fd5b3461032157600036600319011261032157604080516001815260026020820152f35b61014090600319011261032157600490565b61014090602319011261032157602490565b61014036600319011261032157610795610636366105f9565b61063e613210565b610646613230565b604081019061068161067c61065a84612230565b6001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1490565b61223a565b6106a361069c61069083612297565b6001600160801b031690565b34146122a1565b6106c96106c26106b66101008401612230565b6001600160a01b031690565b33146122e7565b6107836106d582612c60565b926107066106f76106f0866000526007602052604060002090565b5460ff1690565b61070081610b15565b15612342565b6107366107316106f061071b60e08701612226565b63ffffffff166000526006602052604060002090565b612385565b61077561074560c08501612226565b63ffffffff807f0000000000000000000000000000000000000000000000000000000000000000169116146123d1565b61077e8361344d565b612230565b61078f61069083612297565b90613551565b6100196001600255565b34610321576020366003190112610321576004356107bc81610310565b6107c46136a2565b6001600160a01b03166000908152600960205260409020805460ff19169055005b6060366003190112610321576004356107fd816103a4565b60243561080981610310565b604435906001600160401b0382116103215763ffffffff7fd054cd999785d4c556d1f55b27cc59caba458cd5663063989d47725b970092329161095c6108566109279536906004016104a7565b610861969196613210565b610869613230565b33600052600960205261088360ff6040600020541661240e565b6109006108bb856108a48b63ffffffff16600052600a602052604060002090565b9060018060a01b0316600052602052604060002090565b8561ffff82546108cc81151561244b565b7f000000000000000000000000000000000000000000000000000000000000000082168082101561096957505b16916136e2565b9661092061090c6124fe565b913483526000602084015233933691612547565b888a613888565b805190604061094060208301516001600160401b031690565b910151519160405195869560018060a01b03169916978561257e565b0390a36100196001600255565b90506108f9565b3461032157600036600319011261032157602060405163ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b8015150361032157565b346103215760a0366003190112610321576004356109d881610310565b6024359060008051602061595b833981519152610aae604435926109fb84610310565b610a948560643595610a0c876109b1565b8360843591610a1a83610310565b610a226136a2565b610a2d8415156125af565b6001600160a01b03811698610a438a15156125fa565b610a576001600160a01b038516151561263d565b15610ab357610a6f610a84926108a4610a7f936103bd565b6001600160801b03851690613979565b61271c565b610a8e8285613a73565b83613b0e565b6040519485526001600160a01b0316939081906020820190565b0390a3005b610af5826108a4610aef61069088610ade610690610ad7610afa9a6108a48b6103bd565b5460801c90565b610aea82821015612685565b6126e7565b936103bd565b6126f9565b610a84565b634e487b7160e01b600052602160045260246000fd5b60051115610b1f57565b610aff565b3461032157602036600319011261032157600435600052600760205260ff604060002054166040516005821015610b1f576020918152f35b34610321576040366003190112610321577f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b6040600435610b9c816103a4565b63ffffffff60243591610bad6136a2565b169081600052600160205280836000205582519182526020820152a1005b3461032157602036600319011261032157600435610be881610310565b60018060a01b03166000526008602052602060ff604060002054166040519015158152f35b3461032157600036600319011261032157610c266136a2565b60035460ff811615610c655760ff19166003557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b638dfc202b60e01b60005260046000fd5b3461032157600036600319011261032157602060405161ffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346103215760203660031901126103215763ffffffff600435610cd7816103a4565b610cdf6136a2565b168060005260066020526040600020600160ff198254161790557fa7dbeb6ef5cb64125bfb03ac211f1aea3f639de95ceb37b16706d4f0735d1863600080a2005b908160809103126103215790565b346103215761018036600319011261032157610d49366105f9565b610144356001600160401b03811161032157610d699036906004016104a7565b90610164356001600160401b03811161032157610e2a91610d91610e23923690600401610d20565b93610d9a613210565b610da2613230565b336000526009602052610dbc60ff6040600020541661240e565b610ddc610dd7610dd3604089013561065a81610310565b1590565b612772565b610ded610de886613bd5565b6127ca565b610df686613bed565b91309230927f00000000000000000000000000000000000000000000000000000000000000009289613d8f565b9183613f4f565b604051828152909391906001600160a01b0385169084907f86d7c80bc9d060acd32be0a39bbd97538a0e7b1f748c30d4e87b186b1d3589bb90602090a3610e7082614138565b15610ee85750819250610e90610e95926000526005602052604060002090565b612805565b610eb9610eac826000526007602052604060002090565b805460ff19166004179055565b7fe82916be8cebf4000a0d08979cca286e4bfe07a019f19c0c930305aceacdcaf6600080a26100196001600255565b610ef193613551565b610795565b3461032157602036600319011261032157600435610f1381610310565b610f1b6136a2565b6001600160a01b03166000908152600960205260409020805460ff19166001179055005b346103215760203660031901126103215763ffffffff600435610f61816103a4565b166000526006602052602060ff604060002054166040519015158152f35b3461032157600036600319011261032157602060ff600354166040519015158152f35b34610321576000366003190112610321576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346103215760203660031901126103215760043561100481610310565b61100c6136a2565b6001600160a01b03166000908152600860205260409020805460ff19169055005b34610321576000366003190112610321576110466136a2565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b6101403660031901126103215761109c366105f9565b6110a4613210565b6110ac613230565b3360005260096020526110c660ff6040600020541661240e565b6110f1307f0000000000000000000000000000000000000000000000000000000000000000836141a0565b90606081019161110361065a84612230565b156111c25761112161111a61069060208501612297565b3414612a28565b8161112b81614138565b156111b457506111479033906111413685612a7f565b906143c0565b61115361065a83612230565b156111875761116461079592612230565b90611181610690602061117a6101208501612230565b9301612297565b91613b0e565b6111966106b6610ef193612230565b906111ac610690602061117a6101208501612230565b913390614613565b6111bd916142c8565b611147565b6111cc34156129c4565b611121565b34610321576040366003190112610321576111ed6004356103a4565b602060405160008152f35b346103215760203660031901126103215760043561121581610310565b60018060a01b03166000526009602052602060ff604060002054166040519015158152f35b346103215760a03660031901126103215761125436610496565b506064356001600160401b038111610321576112749036906004016104a7565b5050602060843561128481610310565b6040516001600160a01b0390911630148152f35b34610321576000366003190112610321576112b16136a2565b6112b9613230565b600160ff1960035416176003557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b919082519283825260005b84811061131e575050826000602080949584010152601f8019910116010190565b806020809284010151828286010152016112fd565b3461032157600036600319011261032157611373611381611352614657565b604092919251938493600f60f81b855260e0602086015260e08501906112f2565b9083820360408501526112f2565b466060830152306080830152600060a083015281810360c0830152602060605191828152019060809060005b8181106113bb575050500390f35b82518452859450602093840193909201916001016113ad565b34610321576000366003190112610321576000546040516001600160a01b039091168152602090f35b346103215760403660031901126103215760043561141a81610310565b6024356114256136a2565b478061144b575b508061143457005b60005461001992906001600160a01b031690613b0e565b60008080809360018060a01b038254165af1611465612b3e565b5015611471573861142c565b60405162461bcd60e51b8152602060048201526017602482015276115d1a195c881dda5d1a191c985dd85b0819985a5b1959604a1b6044820152606490fd5b610180366003190112610321576004356114c93661060b565b610164356001600160401b038111610321576114e99036906004016104a7565b6114f4929192613210565b6114fc613230565b8361150683612c60565b036115ef577f8168c9ac1d18802efe1afee0a6bf2de2b35d9f041a5b42a072b06252ba84fe509261159d9261155f3033307f00000000000000000000000000000000000000000000000000000000000000008a86614763565b611583611576876000526007602052604060002090565b805460ff19166003179055565b61159860c0611591886148ce565b9201612226565b6148f0565b80516115e260406115b860208501516001600160401b031690565b93015151604051938493846001600160401b03604092959493606083019683521660208201520152565b0390a26100196001600255565b60405162461bcd60e51b815260206004820152602a60248201527f5375626d6974746564206f72646572206461746120646f65736e2774206d617460448201526918da081bdc99195c925960b21b6064820152608490fd5b346103215761016036600319011261032157611662366105f9565b610144356001600160401b03811161032157610795916116896107839236906004016104a7565b611694939193613210565b61169c613230565b3360005260096020526116b660ff6040600020541661240e565b61077e60408401916117376117318435976116d089610310565b6001600160a01b038916936116fb73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee861415612772565b61170489613bed565b91309230927f0000000000000000000000000000000000000000000000000000000000000000928c613d8f565b96610310565b6101008501359061174782610310565b611755863561069081612286565b913091614613565b346103215760203660031901126103215760043560005260056020526040600020805461049260018060a01b036001840154166002840154936117a08560e01c90565b6003820154906117d460046117c563ffffffff85169460201c6001600160a01b031690565b9401546001600160a01b031690565b604080516001600160801b0389168152608098891c60208201526001600160a01b0396871691810191909152858916606082015260a089811c63ffffffff9081169983019990995260c0998a1c89169082015291871697820197909752941660e08501528116610100840152909216610120820152908190610140820190565b6101603660031901126103215761186a366105f9565b610144356001600160401b0381116103215761188a903690600401610d20565b90611893613210565b61189b613230565b3360005260096020526118b560ff6040600020541661240e565b61199f6118e3307f0000000000000000000000000000000000000000000000000000000000000000846141a0565b916118ee8482614928565b936001600160a01b039061190490602001612230565b16837fd6fb3db9629fef5e875e0d0138b2fb4ae60575aba13837c23c1c9a6aa1e35bac6040518061193a89829190602083019252565b0390a3611957602082019461195161069087612297565b906126e7565b928161196281614138565b156119c857506119789033906111413685612a7f565b606081019361118161069061199961012061199289612230565b9501612230565b92612297565b806119ae576100196001600255565b6119c1916119bc3391612230565b613b0e565b3880610795565b6119d1916142c8565b611978565b34610321576101403660031901126103215760206119fb6119f6366105f9565b612c60565b604051908152f35b602060408183019282815284518094520192019060005b818110611a275750505090565b82511515845260209384019390920191600101611a1a565b34610321576020366003190112610321576004356001600160401b0381116103215736602382011215610321578060040135906001600160401b038211610321573660248360051b8301011161032157610492916024611a9f9201612c89565b60405191829182611a03565b346103215760203660031901126103215763ffffffff600435611acd816103a4565b1660005260016020526020604060002054604051908152f35b346103215760203660031901126103215763ffffffff600435611b08816103a4565b611b106136a2565b16806000526006602052604060002060ff1981541690557f79df5d328757ca456e42d3dc087c02eedd4cf61d984a6aa526cfac31f1542dcd600080a2005b3461032157602036600319011261032157610795600435611b6d613210565b611b75613230565b806000526005602052611cce6040600020611ca0611c8f6004611b9661250d565b84546001600160801b0381168252909490611bc690611bb6905b60801c90565b6001600160801b03166020870152565b6001810154611be9906001600160a01b03165b6001600160a01b03166040870152565b60028101546001600160a01b0381166060870152611c3990611c2c9063ffffffff60a082901c16608089015263ffffffff60c082901c1660a08901525b60e01c90565b63ffffffff1660c0870152565b611c81611c706003830154611c61611c548263ffffffff1690565b63ffffffff1660e08a0152565b60201c6001600160a01b031690565b6001600160a01b0316610100870152565b01546001600160a01b031690565b6001600160a01b0316610120830152565b309033903090857f000000000000000000000000000000000000000000000000000000000000000091614d00565b614e41565b346103215760006020366003190112611d7d5780600435611cf381610310565b611cfb6136a2565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15611d795760405163ca5eb5e160e01b81526001600160a01b0390921660048301529091908290602490829084905af18015611d74578290611d665780f35b611d6f916124dd565b388180f35b612e85565b5050fd5b80fd5b346103215760c036600319011261032157600435611d9d816103a4565b6024359060ff8216820361032157604435906001600160401b0382116103215761049292611dd2611dfe9336906004016104a7565b60643591611ddf836109b1565b60843593611dec856103a4565b60a43595611df987610310565b612ec3565b6040519081529081906020820190565b34610321576020611e4a611e2136610333565b6001600160a01b0391821660009081526004855260408082209290931681526020919091522090565b5460801c604051908152f35b3461032157604036600319011261032157600435602435611e7681610310565b611e7e6136a2565b611e92826000526007602052604060002090565b5460ff16611e9f81610b15565b600114611eab90613006565b6001600160a01b03811690611ec182151561263d565b611ed5836000526005602052604060002090565b611ede90612d9b565b9260c0840151611ef19063ffffffff1690565b7f000000000000000000000000000000000000000000000000000000000000000063ffffffff169063ffffffff1614611f2990613052565b604084015184516001600160801b0316946001600160a01b039091169290859081908590611f578383613a73565b611f6b866000526007602052604060002090565b805460ff1916600317905561010001516001600160a01b0316611f8d906103bd565b6001600160a01b0390911660009081526020919091526040902090611fb191613979565b611fba9061271c565b611fc49184613b0e565b6040519182917fe8d9861dbc9c663ed3accd261bbe2fe01e0d3d9e5f51fa38523b265c7757a93a600080a26001600160801b039490941690526001600160a01b039092169160008051602061595b83398151915290602090a3005b346103215760203660031901126103215760043561203c81610310565b6120446136a2565b6001600160a01b03166000908152600860205260409020805460ff19166001179055005b346103215760203660031901126103215760043561208581610310565b61208d6136a2565b6001600160a01b031680156120df57600080546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b631e4fbdf760e01b600052600060045260246000fd5b346103215760403660031901126103215760043561211281610310565b60243561211d613210565b612125613230565b80336000526004602052612152610ad78460406000209060018060a01b0316600052602052604060002090565b9161215e8315156130b4565b806121c257505061218961217c6106908380945b610aea8288613a73565b610af5846108a4336103bd565b612194813384613b0e565b6040519081526001600160a01b0390911690339060008051602061595b83398151915290806020810161095c565b61069082846121da61217c9461218996971015612685565b612172565b346103215760603660031901126103215760206121fb36610496565b63ffffffff813561220b816103a4565b16600052600182528160406000205491013560405191148152f35b35610358816103a4565b3561035881610310565b1561224157565b60405162461bcd60e51b815260206004820152601f60248201527f4f72646572206d7573742073706563696679206e617469766520746f6b656e006044820152606490fd5b6001600160801b0381160361032157565b3561035881612286565b156122a857565b60405162461bcd60e51b8152602060048201526017602482015276125b98dbdc9c9958dd081b985d1a5d9948185b5bdd5b9d604a1b6044820152606490fd5b156122ee57565b60405162461bcd60e51b815260206004820152602660248201527f4f6e6c79206f6666657265722063616e206465706f736974206e617469766520604482015265746f6b656e7360d01b6064820152608490fd5b1561234957565b60405162461bcd60e51b81526020600482015260146024820152734f7264657220616c72656164792065786973747360601b6044820152606490fd5b1561238c57565b60405162461bcd60e51b815260206004820152601f60248201527f44657374696e6174696f6e20636861696e206e6f7420737570706f72746564006044820152606490fd5b156123d857565b60405162461bcd60e51b815260206004820152600e60248201526d086d0c2d2dc40dad2e6dac2e8c6d60931b6044820152606490fd5b1561241557565b60405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21039b7b63b32b960911b6044820152606490fd5b1561245257565b60405162461bcd60e51b8152602060048201526012602482015271139bc81bdc99195c9cc81c1c9bdd9a59195960721b6044820152606490fd5b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b038211176124bd57604052565b61248c565b606081019081106001600160401b038211176124bd57604052565b90601f801991011681019081106001600160401b038211176124bd57604052565b604051906103316040836124dd565b60405190610331610140836124dd565b6040519061033160a0836124dd565b6001600160401b0381116124bd57601f01601f191660200190565b9291926125538261252c565b9161256160405193846124dd565b829481845281830111610321578281602093846000960137010152565b9060609295949361259f6001600160401b03926080855260808501906112f2565b9660208401521660408201520152565b156125b657565b606460405162461bcd60e51b815260206004820152602060248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152fd5b1561260157565b60405162461bcd60e51b8152602060048201526014602482015273496e76616c69642075736572206164647265737360601b6044820152606490fd5b1561264457565b60405162461bcd60e51b8152602060048201526019602482015278496e76616c696420726563697069656e74206164647265737360381b6044820152606490fd5b1561268c57565b60405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420756e6c6f636b65642062616c616e63650000006044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b919082039182116126f457565b6126d1565b80546001600160801b031660809290921b6001600160801b031916919091179055565b1561272357565b60405162461bcd60e51b815260206004820152602160248201527f4661696c656420746f206465637265617365206c6f636b65642062616c616e636044820152606560f81b6064820152608490fd5b1561277957565b60405162461bcd60e51b815260206004820152602360248201527f557365206465706f7369744e617469766520666f72206e617469766520746f6b604482015262656e7360e81b6064820152608490fd5b156127d157565b60405162461bcd60e51b815260206004820152600c60248201526b4d697373696e6720686f6f6b60a01b6044820152606490fd5b60046129a36101206103319461283961281d82612297565b86546001600160801b0319166001600160801b03909116178655565b61284e61284860208301612297565b866126f9565b61288061285d60408301612230565b6001870180546001600160a01b0319166001600160a01b03909216919091179055565b61293c600286016128b261289660608501612230565b82546001600160a01b0319166001600160a01b03909116178255565b6128e16128c160808501612226565b825463ffffffff60a01b191660a09190911b63ffffffff60a01b16178255565b6129106128f060a08501612226565b825463ffffffff60c01b191660c09190911b63ffffffff60c01b16178255565b61291c60c08401612226565b81546001600160e01b031660e09190911b6001600160e01b031916179055565b61299d6003860161296861295260e08501612226565b825463ffffffff191663ffffffff909116178255565b6129756101008401612230565b8154640100000000600160c01b03191660209190911b640100000000600160c01b0316179055565b01612230565b910180546001600160a01b0319166001600160a01b03909216919091179055565b156129cb57565b60405162461bcd60e51b815260206004820152602f60248201527f4e6f206e617469766520746f6b656e732073686f756c642062652073656e742060448201526e666f722045524332302066696c6c7360881b6064820152608490fd5b15612a2f57565b60405162461bcd60e51b815260206004820152601c60248201527f496e636f7272656374206e617469766520616d6f756e742073656e74000000006044820152606490fd5b359061033182612286565b91908261014091031261032157612b36610120612a9a61250d565b93612aa481612a74565b8552612ab260208201612a74565b6020860152612ac360408201610326565b6040860152612ad460608201610326565b6060860152612ae5608082016103b2565b6080860152612af660a082016103b2565b60a0860152612b0760c082016103b2565b60c0860152612b1860e082016103b2565b60e0860152612b2a6101008201610326565b61010086015201610326565b610120830152565b3d15612b69573d90612b4f8261252c565b91612b5d60405193846124dd565b82523d6000602084013e565b606090565b61033190929192610120612c5281610140840196612b9c85612b8f83612a74565b6001600160801b03169052565b612bab611bb660208301612a74565b612bba611bd960408301610326565b612bd9612bc960608301610326565b6001600160a01b03166060870152565b612bf5612be8608083016103b2565b63ffffffff166080870152565b612c11612c0460a083016103b2565b63ffffffff1660a0870152565b612c20611c2c60c083016103b2565b612c3c612c2f60e083016103b2565b63ffffffff1660e0870152565b612c4c611c706101008301610326565b01610326565b6001600160a01b0316910152565b604051612c8381612c75602082019485612b6e565b03601f1981018352826124dd565b51902090565b612c916136a2565b612c9a82612d60565b91612ca860405193846124dd565b808352601f19612cb782612d60565b0136602085013760005b818110612cce5750505090565b8063ffffffff612ce16001938587612d77565b35612ceb816103a4565b16600052600660205260406000208260ff19825416179055612d22612d19612d14838688612d77565b612226565b63ffffffff1690565b7fa7dbeb6ef5cb64125bfb03ac211f1aea3f639de95ceb37b16706d4f0735d1863600080a2612d5a612d548287612d87565b60019052565b01612cc1565b6001600160401b0381116124bd5760051b60200190565b91908110156104055760051b0190565b80518210156104055760209160051b010190565b90610331612e746004612dac61250d565b85546001600160801b0381168252909590612dda90612dca90611bb0565b6001600160801b03166020880152565b60018101546001600160a01b0316604087015260028101546001600160a01b0381166060880152612e3b90612e2e9063ffffffff60a082901c1660808a015263ffffffff60c082901c1660a08a0152611c26565b63ffffffff1660c0880152565b611c81612e636003830154611c61612e568263ffffffff1690565b63ffffffff1660e08b0152565b6001600160a01b0316610100880152565b6001600160a01b0316610120840152565b6040513d6000823e3d90fd5b90612e9b8261252c565b612ea860405191826124dd565b8281528092612eb9601f199161252c565b0190602036910137565b9391612f3c90612f34612f2f612f7d9694612f07612f989b63ffffffff60409c16600052600a6020528b6000209060018060a01b0316600052602052604060002090565b547f000000000000000000000000000000000000000000000000000000000000000091614f0e565b612e91565b923691612547565b90612f45613768565b50612f4f856130fc565b612f66612f5a61251d565b63ffffffff9097168752565b602086015285850152606084015215156080830152565b815180938192631bb8518b60e31b835230906004840161381a565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115611d7457600091612fd957505190565b612ffb915060403d604011612fff575b612ff381836124dd565b810190614f85565b5190565b503d612fe9565b1561300d57565b60405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c792063616e63656c20616374697665206f72646572730000006044820152606490fd5b1561305957565b60405162461bcd60e51b815260206004820152602d60248201527f456d657267656e63792063616e63656c206f6e6c7920616c6c6f776564206f6e60448201526c1039b7bab931b29031b430b4b760991b6064820152608490fd5b156130bb57565b60405162461bcd60e51b8152602060048201526019602482015278139bdb8b5e995c9bc818985b185b98d9481c995c5d5a5c9959603a1b6044820152606490fd5b63ffffffff1680600052600160205260406000205490811561311c575090565b63f6ff4fb760e01b60005260045260246000fd5b9350509350915061313f613230565b81156131db573561314f816103a4565b61315982846153fa565b3560f81c6002811015610b1f5761316f816148c4565b6001810361318257505061033191615550565b61318e819392936148c4565b61319b5761033192615403565b60405162461bcd60e51b8152602060048201526018602482015277556e737570706f72746564207061796c6f6164207479706560401b6044820152606490fd5b60405162461bcd60e51b815260206004820152600d60248201526c115b5c1d1e481c185e5b1bd859609a1b6044820152606490fd5b600280541461321f5760028055565b633ee5aeb560e01b60005260046000fd5b60ff6003541661323c57565b63d93c066560e01b60005260046000fd5b1561325457565b60405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b21037b33332b932b960891b6044820152606490fd5b1561329257565b60405162461bcd60e51b8152602060048201526011602482015270125b9d985b1a59081c9958da5c1a595b9d607a1b6044820152606490fd5b156132d257565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c696420656e642074696d6560801b6044820152606490fd5b1561331157565b60405162461bcd60e51b815260206004820152601160248201527013dc99195c881b9bdd081cdd185c9d1959607a1b6044820152606490fd5b1561335157565b60405162461bcd60e51b815260206004820152601160248201527013dc99195c881a185cc8195e1c1a5c9959607a1b6044820152606490fd5b1561339157565b60405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a59081a5b9c1d5d08185b5bdd5b9d60621b6044820152606490fd5b156133d457565b60405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081bdd5d1c1d5d08185b5bdd5b9d605a1b6044820152606490fd5b1561341857565b60405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b2103a37b5b2b760991b6044820152606490fd5b610331906134716001600160a01b036134696101008401612230565b16151561324d565b61348b6134846106b66101208401612230565b151561328b565b6134e5608082016134d26134c36134a183612226565b92612d1460a087019463ffffffff6134bb612d1988612226565b9116106132cb565b63ffffffff429116111561330a565b6134df612d194292612226565b1161334a565b6135016001600160801b036134f983612297565b16151561338a565b61351a61351361069060208401612297565b15156133cd565b6135296106b660408301612230565b15159081613538575b50613411565b613549915060606106b69101612230565b151538613532565b9161369161365e61369d936136597f8e45fa612720ed3142e896a3a29c981f4ca01c25bca19c3a5c203398ee1bc3d79661010086013561359081610310565b6001600160a01b0390811660009081526004602090815260408083209385168352929052206135f2906135d56135c586614f99565b82546001600160801b0316614fcc565b81546001600160801b0319166001600160801b0391909116179055565b8860005260076020526040600020600160ff1982541617905561362386610e908b6000526005602052604060002090565b60016136398a6000526005602052604060002090565b0180546001600160a01b0319166001600160a01b03909216919091179055565b614f99565b613672866000526005602052604060002090565b80546001600160801b0319166001600160801b03909216919091179055565b60405191829182612b6e565b0390a2565b6000546001600160a01b031633036136b657565b63118cdaa760e01b6000523360045260246000fd5b63ffffffff166017019063ffffffff82116126f457565b908260051b621fffe061ffe08216911681036126f457612f2f612d1961370f6137149396949661ffff1690565b6136cb565b928160481b9060581b17602084015281600052602060002093825491820393603781015b838681111561375c57906000602092811901958119908a0101805483525501613738565b50509392915093505590565b60405190613775826124a2565b60006020838281520152565b6040519061378e826124c2565b81600081526000602082015260406137a4613768565b910152565b9190826040910312610321576040516137c1816124a2565b6020808294805184520151910152565b60808183031261032157604051916137e8836124c2565b8151835260208201516001600160401b0381168103610321576020840152613812916040016137a9565b604082015290565b906020909392936040835263ffffffff8151166040840152818101516060840152608061386e613858604084015160a08488015260e08701906112f2565b6060840151868203603f190160a08801526112f2565b910151151560c08401526001600160a01b03909416910152565b6138e560809492613901969461389c613781565b5060206138a98651614fe5565b95019182518061396a575b506138be856130fc565b92511515926138ce612f5a61251d565b602086015260408501526060840152151585830152565b6040518095819482936302637a4560e41b84526004840161381a565b03917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1908115611d7457600091613941575090565b610358915060803d608011613963575b61395b81836124dd565b8101906137d1565b503d613951565b61397390615004565b386138b4565b805490916001600160801b039182169081039091169081116139b95781546001600160801b0319166001600160801b03909116179055600190565b600190565b5050600090565b90816020910312610321575190565b156139d657565b60405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e63650000006044820152606490fd5b15613a2257565b60405162461bcd60e51b8152602060048201526024808201527f496e73756666696369656e7420636f6e7472616374206e61746976652062616c604482015263616e636560e01b6064820152608490fd5b6001600160a01b03169073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8203613aa5576103319150471015613a1b565b6040516370a0823160e01b815230600482015291602090839060249082905afa8015611d745761033192600091613adf575b5010156139cf565b613b01915060203d602011613b07575b613af981836124dd565b8101906139c0565b38613ad7565b503d613aef565b6001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103613b9557506000918291829182916001600160a01b03165af1613b4f612b3e565b5015613b5757565b60405162461bcd60e51b815260206004820152601660248201527513985d1a5d99481d1c985b9cd9995c8819985a5b195960521b6044820152606490fd5b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448083019390935291815261033191613bd06064836124dd565b61537e565b35613bdf81610310565b6001600160a01b0316151590565b61035890803590613bfd82612286565b613d1b6020820135613c0e81612286565b612c75604084013593613c2085610310565b606081013590613c2f82610310565b613c3b60808201612226565b613c4760a08301612226565b613c5360c08401612226565b90613c6060e08501612226565b92613c7b610120613c746101008801612230565b9601612230565b956040519a8b9960208b019d8e7f16210483e9c961c9c307e53963eafad0795395f2fce68f0c9c294cca1ac5a06a81526001600160801b039182166020820152911660408201526001600160a01b039182166060820152918116608083015263ffffffff92831660a083015292821660c082015292811660e084015292909216610100820152918116610120830152919091166101408201526101600190565b5190206150bd565b90816020910312610321575160058110156103215790565b908160209103126103215751610358816109b1565b15613d5757565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c69645369676e617475726560801b6044820152606490fd5b90613dd49392959796602060405181810190613daf81612c758885612b6e565b519020809a6040518080998194632dff692d60e01b8352600483019190602083019252565b03915afa908115611d7457613dfb602092613e3097600091613edf575b5061070081610b15565b613e0760e08501612226565b60405163167d0a6960e21b815263ffffffff909116600482015295869190829081906024820190565b03915afa918215611d7457613e97613e7663ffffffff9695613e7060c0956103319b613e69613ea6998c9b600091613eb0575b50612385565b3691612547565b9061512a565b613e866106b66101008501612230565b6001600160a01b0390911614613d50565b613ea08161344d565b01612226565b92169116146123d1565b613ed2915060203d602011613ed8575b613eca81836124dd565b810190613d3b565b38613e63565b503d613ec0565b613eff9150843d8611613f05575b613ef781836124dd565b810190613d23565b38613df1565b503d613eed565b15613f1357565b60405162461bcd60e51b8152602060048201526014602482015273496e76616c696420686f6f6b206164647265737360601b6044820152606490fd5b91908035613f5c81610310565b6001600160a01b0316600090815260086020526040902054613f809060ff16613f0c565b613fbb613f926106b660408601612230565b613f9f6101008601612230565b613fa884612230565b90613fb561069088612297565b92614613565b613fc483614138565b1561407d57613ff8613fe3613fd883612230565b9260608101906140ba565b606086019391613ff285612230565b926151b6565b906140576140516106906020870161401d61401561069083612297565b8710156140ec565b61404c61402986612230565b9861404061012061403989612230565b9201612230565b61118161069085612297565b612297565b836126e7565b80614063575b50509190565b61406f61407692612230565b3390613b0e565b388061405d565b915061035861408b83612230565b61077e60406140af6140a060608801886140ba565b602089019591613ff287612230565b9501358510156140ec565b903590601e198136030182121561032157018035906001600160401b0382116103215760200191813603831361032157565b156140f357565b60405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e74206f75747075742066726f6d20686f6f6b0000006044820152606490fd5b63ffffffff8060e060c08401359361414f856103a4565b013561415a816103a4565b1691161490565b1561416857565b60405162461bcd60e51b815260206004820152601060248201526f4f72646572206e6f742061637469766560801b6044820152606490fd5b9291906141ac8461344d565b6141c360e085019163ffffffff80613ea685612226565b63ffffffff6141f9612d196141f360c060405160208101906141e981612c758d85612b6e565b5190209801612226565b93612226565b91160361426657604051632dff692d60e01b81526004810184905290602090829060249082905afa908115611d745761033191600191600091614247575b5061424181610b15565b14614161565b614260915060203d602011613f0557613ef781836124dd565b38614237565b604051632dff692d60e01b81526004810184905290602090829060249082905afa8015611d7457610331916000916142a9575b506142a381610b15565b15614161565b6142c2915060203d602011613f0557613ef781836124dd565b38614299565b908160005260076020526142e76040600020600260ff19825416179055565b63ffffffff60c08201356142fa816103a4565b166000908152600a60209081526040808320338452909152902080549091600160401b8210156124bd57614358827f7f80314442bfb82d1f9dfa4f96cbc84ae8fef158c7a93315024778ca3fc1671694600161369d950181556103ed565b81549060031b9086821b91600019901b191617905560405191829182612b6e565b1561438057565b60405162461bcd60e51b815260206004820152601860248201527710985b185b98d9481bdc195c985d1a5bdb8819985a5b195960421b6044820152606490fd5b610100820180519193916001600160a01b03166143dc906103bd565b604084810180516001600160a01b031660009081526020939093529120909390546001600160801b03169282614411826103bd565b86516001600160a01b03166000908152602091909152604090205460801c81519093908190889085906001600160a01b031661444c906103bd565b82516001600160a01b0316600090815260209190915260409020546001600160801b031683516001600160801b03166001600160801b031690600160801b600190031610156144d561451f610ad761450f61450961454f9f6144da6144d56145499d61453b9c6144e69b6144fc9561452d9c61458d575b505090516001600160a01b0316919050565b6103bd565b89516001600160a01b03165b60018060a01b0316600052602052604060002090565b546001600160801b031690565b9a6103bd565b86516001600160a01b03166144e6565b99516001600160a01b031690565b91516001600160a01b031690565b50516001600160801b031690565b936152a4565b614566610eac826000526007602052604060002090565b7fe82916be8cebf4000a0d08979cca286e4bfe07a019f19c0c930305aceacdcaf6600080a2565b614602926145f06145e26145f6936144e661452d6145dc6145ca6145ba6144d58d5160018060a01b031690565b85516001600160a01b03166144e6565b87516001600160801b03165b90613979565b976103bd565b91516001600160801b031690565b9061527e565b8161460b575b50614379565b8f8e908d6144c3565b9050386145fc565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815261033191613bd06084836124dd565b604090815161466683826124dd565b6004815263416f726960e01b602082015291614684815191826124dd565b6005815264302e332e3160d81b602082015290565b156146a057565b60405162461bcd60e51b81526020600482015260186024820152772737ba1037b7103232b9ba34b730ba34b7b71031b430b4b760411b6044820152606490fd5b156146e757565b60405162461bcd60e51b815260206004820152604860248201527f4f6e6c792077686974656c697374656420736f6c7665722c206f66666572657260448201527f2c206f7220726563697069656e742028616674657220657870697279292063616064820152671b8818d85b98d95b60c21b608482015260a490fd5b929060209161478b6147ab9463ffffffff8061478160e08a01612226565b9216911614614699565b6040518080958194632dff692d60e01b8352600483019190602083019252565b03915afa8015611d74576147ca916000916142a957506142a381610b15565b604051631f798dcd60e21b81526001600160a01b038316600482015292602090849060249082905afa918215611d7457610331936000936148a3575b508215614863575b821561481c575b50506146e0565b90915061482f6106b66101208401612230565b6001600160a01b0390911614908161484a575b503880614815565b61485b915060a0612d199101612226565b421138614842565b91506148756106b66101008301612230565b6001600160a01b038316148061488c575b9161480e565b5061489c612d1960a08301612226565b4211614886565b6148bd91935060203d602011613ed857613eca81836124dd565b9138614806565b60021115610b1f57565b60405190600160f81b60208301526021820152602181526103586041826124dd565b6103589392916148fe613781565b506149226040519361490f856124a2565b3485526000602086015233953691612547565b91613888565b906149e461069060206149dd61035894803561494381610310565b6001600160a01b031660009081526008845260409020546149669060ff16613f0c565b60608101358015614a175783820161498061065a82612230565b156149ec575060008080808461499a6149b9963414614ad1565b6149a96106b66106b689612230565b5af16149b3612b3e565b50614b31565b6149d06149c582612230565b9160408101906140ba565b90613ff260608a01612230565b9401612297565b821015614b7d565b90614a016106b6614a129361077e3415614a63565b614a0a84612230565b903390614613565b6149b9565b50614a1234614a2257565b60405162461bcd60e51b8152602060048201526019602482015278139bc81b985d1a5d99481d1bdad95b9cc8195e1c1958dd1959603a1b6044820152606490fd5b15614a6a57565b60405162461bcd60e51b815260206004820152603960248201527f4e6f206e617469766520746f6b656e732073686f756c642062652073656e74206044820152783337b91022a921991810383932b332b93932b2103a37b5b2b760391b6064820152608490fd5b15614ad857565b60405162461bcd60e51b815260206004820152602b60248201527f496e636f7272656374206e617469766520616d6f756e7420666f72207072656660448201526a32b93932b2103a37b5b2b760a91b6064820152608490fd5b15614b3857565b60405162461bcd60e51b815260206004820152601e60248201527f4e6174697665207472616e7366657220746f20686f6f6b206661696c656400006044820152606490fd5b15614b8457565b60405162461bcd60e51b815260206004820152603560248201527f486f6f6b206d7573742070726f76696465206174206c656173742074686520656044820152741e1c1958dd1959081bdd5d1c1d5d08185b5bdd5b9d605a1b6064820152608490fd5b15614bee57565b60405162461bcd60e51b81526020600482015260136024820152722737ba1037b71039b7bab931b29031b430b4b760691b6044820152606490fd5b15614c3057565b60405162461bcd60e51b815260206004820152603b60248201527f43726f73732d636861696e206f7264657273206d7573742062652063616e636560448201527f6c6c65642066726f6d2064657374696e6174696f6e20636861696e00000000006064820152608490fd5b15614ca257565b60405162461bcd60e51b815260206004820152603060248201527f4f6e6c7920736f6c766572206f72206f6666657265722028616674657220657860448201526f1c1a5c9e4a4818d85b8818d85b98d95b60821b6064820152608490fd5b92614d2e9160209161478b60c087019563ffffffff80614d24895163ffffffff1690565b9216911614614be7565b03915afa918215611d7457614d576001614d8294614d6194600091614247575061424181610b15565b5163ffffffff1690565b63ffffffff614d7a612d1960e086015163ffffffff1690565b911614614c29565b604051631f798dcd60e21b81526001600160a01b038316600482015292602090849060249082905afa918215611d745761033193600093614e20575b508215614dcd575b5050614c9b565b61010082015191925090614de9906001600160a01b03166106b6565b6001600160a01b03909116149081614e04575b503880614dc6565b60a00151614e18915063ffffffff16612d19565b421138614dfc565b614e3a91935060203d602011613ed857613eca81836124dd565b9138614dbe565b806000526007602052614e67600160ff60406000205416614e6181610b15565b14613006565b614ee7614e86614e81836000526005602052604060002090565b612d9b565b80516040820151610100909201516001600160801b03909116916001600160a01b039182169116614eb78382613a73565b614ece611576866000526007602052604060002090565b6119bc610a7f84614ee2846108a4876103bd565b613979565b7fe8d9861dbc9c663ed3accd261bbe2fe01e0d3d9e5f51fa38523b265c7757a93a600080a2565b90919060ff1660018103614f2457505050602190565b614f49576103589161ffff91821680821015614f4257505b166153d9565b9050614f3c565b60405162461bcd60e51b8152602060048201526014602482015273496e76616c6964206d657373616765207479706560601b6044820152606490fd5b9060408282031261032157610358916137a9565b6001600160801b038111614fb3576001600160801b031690565b6306dfcc6560e41b600052608060045260245260446000fd5b6001600160801b0391821690821601919082116126f457565b803403614fef5790565b6304fb820960e51b6000523460045260246000fd5b60405163393f876560e21b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169190602081600481865afa908115611d7457600091615082575b506001600160a01b031691821561507157610331923390614613565b6329b99a9560e11b60005260046000fd5b90506020813d6020116150b5575b8161509d602093836124dd565b8101031261032157516150af81610310565b38615055565b3d9150615090565b906150c6614657565b604093919351937f91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a276660005260208151910120602052602081519101206040523060605260806000206020526119016000526040526042601e20916040526000606052565b919091604051928051806040146151945760411461515557505050505b638baa579f6000526004601cfd5b602091606082015160001a835260408201516060525b60005201516040526020600160806000825afa519160006060526040523d610331575050615147565b506020916040820151601b8160ff1c01845260018060ff1b031660605261516b565b6000919392908291826151c930876155b6565b96826040519384928337810182815203925af16151e4612b3e565b501561524b576151f59030906155b6565b9080821061520657610358916126e7565b60405162461bcd60e51b815260206004820152601f60248201527f486f6f6b2064656372656173656420636f6e74726163742062616c616e6365006044820152606490fd5b60405162461bcd60e51b815260206004820152600b60248201526a10d85b1b0819985a5b195960aa1b6044820152606490fd5b8054909160809190911c9081016001600160801b03169081106139b9576139b4916126f9565b92939192906001600160801b03906152bd908490614fcc565b166001600160801b0390911603615339576001600160801b03916152e19190614fcc565b166001600160801b03909116036152f457565b60405162461bcd60e51b815260206004820152601b60248201527f496e636f6e73697374656e7420736f6c7665722062616c616e636500000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601c60248201527f496e636f6e73697374656e74206f6666657265722062616c616e6365000000006044820152606490fd5b906000602091828151910182855af115612e85576000513d6153d057506001600160a01b0381163b155b6153af5750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b600114156153a8565b8060051b90808204602014901517156126f457601701806017116126f45790565b90156104055790565b9190916017831061550c576154188382615678565b9390916154268583836156bc565b60005b61ffff8616811061543c57505050505050565b60018161544d61ffff938686615741565b868861547660e061546b614e81866000526005602052604060002090565b015163ffffffff1690565b63ffffffff821663ffffffff82160361549c57505061549491615805565b019050615429565b7fbb563f7e333f32ed0571f8dc4913648b41737753db5df83c58657c6bfcc2ef569250615504604051928392839060a09263ffffffff809216835216602082015260606040820152600c60608201526b08ad2c840dad2e6dac2e8c6d60a31b60808201520190565b0390a2615494565b606460405162461bcd60e51b815260206004820152602060248201527f5061796c6f616420746f6f2073686f727420666f7220736574746c656d656e746044820152fd5b90602103615565576001610331910135614e41565b60405162461bcd60e51b815260206004820152602360248201527f496e76616c69642063616e63656c6c6174696f6e207061796c6f6164206c656e6044820152620cee8d60eb1b6064820152608490fd5b6001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81036155df57503190565b6040516370a0823160e01b81526001600160a01b039092166004830152602090829060249082905afa908115611d745760009161561a575090565b610358915060203d602011613b0757613af981836124dd565b1561563a57565b60405162461bcd60e51b8152602060048201526016602482015275092dcecc2d8d2c840e0c2f2d8dec2c840d8cadccee8d60531b6044820152606490fd5b9190916156886017841015615633565b600181013560601c928060151015610405576016101561040557601581013560f01c61ff00166016919091013560f81c1790565b5090621fffe061ffff82169160051b1690808204602014901517156126f45760170190816017116126f457036156ee57565b60405162461bcd60e51b815260206004820152602560248201527f496e76616c6964207061796c6f6164206c656e67746820666f7220736574746c604482015264195b595b9d60da1b6064820152608490fd5b9061574f6017821015615633565b60161981019081116126f45760051c8210156157715760179160051b01013590565b60405162461bcd60e51b8152602060048201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152606490fd5b906040516157b9816124a2565b91546001600160801b038116835260801c6020830152565b815181546001600160801b0319166001600160801b039190911617815561033191602001516001600160801b0316906126f9565b90600161581f6106f0846000526007602052604060002090565b61582881610b15565b0361595657615844614e81836000526005602052604060002090565b6101008101805191929091615861906001600160a01b03166103bd565b6040840180519093916158869161588191906001600160a01b03166144e6565b6157ac565b9061589661588161450f856103bd565b946158e36158d36158c36158b36144d5865160018060a01b031690565b88516001600160a01b03166144e6565b83516001600160801b03166145d6565b916145f06145e26144da886103bd565b901590811561594d575b5061590e575050505050614566610eac826000526007602052604060002090565b51610331955061594893926144e69261452d926144d591908790615938906001600160a01b031684565b87516001600160a01b03166144e6565b6157d1565b905015386158ed565b505056fe9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eba26469706673582212202463fc3c173b6a5cc2bef337128c18ef1cd9704d7eb70d9979f92d42aa4971ad64736f6c634300081c00330000000000000000000000001a44076050125825900e736c501f859c50fe728c000000000000000000000000941327e206b8d8cfe1014a8a95b05e1536dfd00d00000000000000000000000000000000000000000000000000000000000075950000000000000000000000000000000000000000000000000000000000000064

Deployed Bytecode

0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806305ef94ba1461030b5780630c89a13d1461030657806313137d651461030157806317442b70146102fc5780631c0166aa146102f75780631e2c273e146102f25780632c85455b146102ed5780632cee9acd146102e85780632d7c615a146102e35780632dff692d146102de5780633400288b146102d9578063344ba6fd146102d45780633f4ba83a146102cf57806344ae20c3146102ca57806350964586146102c5578063555c3898146102c0578063595490c8146102bb57806359f429a4146102b65780635c975abb146102b15780635e280f11146102ac5780636b624fdb146102a7578063715018a6146102a25780637ce5e33e1461029d5780637d25a05e146102985780637de637341461029357806382413eac1461028e5780638456cb591461028957806384b0196e146102845780638da5cb5b1461027f57806395ccea671461027a578063983f7fd114610275578063996628a0146102705780639c3f1e901461026b578063a9a683ba14610266578063b410f12214610261578063b8f480c61461025c578063bb0b6a5314610257578063c15c4b3714610252578063c4d252f51461024d578063ca5eb5e114610248578063cd77488714610243578063e86dfbbf1461023e578063e898841f14610239578063edb25d8114610234578063f2fde38b1461022f578063f3fef3a31461022a5763ff7bd03d0361000e576121df565b6120f5565b612068565b61201f565b611e56565b611e0e565b611d80565b611cd3565b611b4e565b611ae6565b611aab565b611a3f565b6119d6565b611854565b61175d565b611647565b6114b0565b6113fd565b6113d4565b611333565b611298565b61123a565b6111f8565b6111d1565b611086565b61102d565b610fe7565b610fa2565b610f7f565b610f3f565b610ef6565b610d2e565b610cb5565b610c76565b610c0d565b610bcb565b610b5c565b610b24565b6109bb565b610970565b6107e5565b61079f565b61061d565b6105d7565b6104d4565b61040a565b61035b565b6001600160a01b0381160361032157565b600080fd5b359061033182610310565b565b60409060031901126103215760043561034b81610310565b9060243561035881610310565b90565b3461032157602061036b36610333565b6001600160a01b039182166000908152600484526040808220929093168152602091909152206001600160801b03905416604051908152f35b63ffffffff81160361032157565b3590610331826103a4565b6001600160a01b0316600090815260046020526040902090565b634e487b7160e01b600052603260045260246000fd5b80548210156104055760005260206000200190600090565b6103d7565b3461032157606036600319011261032157600435610427816103a4565b61046460243561043681610310565b63ffffffff6044359316600052600a60205260406000209060018060a01b0316600052602052604060002090565b8054821015610321576104929161047a916103ed565b90549060031b1c604051918291829190602083019252565b0390f35b606090600319011261032157600490565b9181601f84011215610321578235916001600160401b038311610321576020838186019501011161032157565b60e0366003190112610321576104e936610496565b6064356084356001600160401b0381116103215761050b9036906004016104a7565b60a4929192359061051b82610310565b60c4356001600160401b0381116103215761053a9036906004016104a7565b949093337f0000000000000000000000001a44076050125825900e736c501f859c50fe728c6001600160a01b0316036105c257863596610579886103a4565b610582886130fc565b97602082013580990361059a57506100199750613130565b63ffffffff816105aa8b936103a4565b63309afaf360e21b6000521660045260245260446000fd5b6391ac5e4f60e01b6000523360045260246000fd5b3461032157600036600319011261032157604080516001815260026020820152f35b61014090600319011261032157600490565b61014090602319011261032157602490565b61014036600319011261032157610795610636366105f9565b61063e613210565b610646613230565b604081019061068161067c61065a84612230565b6001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1490565b61223a565b6106a361069c61069083612297565b6001600160801b031690565b34146122a1565b6106c96106c26106b66101008401612230565b6001600160a01b031690565b33146122e7565b6107836106d582612c60565b926107066106f76106f0866000526007602052604060002090565b5460ff1690565b61070081610b15565b15612342565b6107366107316106f061071b60e08701612226565b63ffffffff166000526006602052604060002090565b612385565b61077561074560c08501612226565b63ffffffff807f0000000000000000000000000000000000000000000000000000000000007595169116146123d1565b61077e8361344d565b612230565b61078f61069083612297565b90613551565b6100196001600255565b34610321576020366003190112610321576004356107bc81610310565b6107c46136a2565b6001600160a01b03166000908152600960205260409020805460ff19169055005b6060366003190112610321576004356107fd816103a4565b60243561080981610310565b604435906001600160401b0382116103215763ffffffff7fd054cd999785d4c556d1f55b27cc59caba458cd5663063989d47725b970092329161095c6108566109279536906004016104a7565b610861969196613210565b610869613230565b33600052600960205261088360ff6040600020541661240e565b6109006108bb856108a48b63ffffffff16600052600a602052604060002090565b9060018060a01b0316600052602052604060002090565b8561ffff82546108cc81151561244b565b7f000000000000000000000000000000000000000000000000000000000000006482168082101561096957505b16916136e2565b9661092061090c6124fe565b913483526000602084015233933691612547565b888a613888565b805190604061094060208301516001600160401b031690565b910151519160405195869560018060a01b03169916978561257e565b0390a36100196001600255565b90506108f9565b3461032157600036600319011261032157602060405163ffffffff7f0000000000000000000000000000000000000000000000000000000000007595168152f35b8015150361032157565b346103215760a0366003190112610321576004356109d881610310565b6024359060008051602061595b833981519152610aae604435926109fb84610310565b610a948560643595610a0c876109b1565b8360843591610a1a83610310565b610a226136a2565b610a2d8415156125af565b6001600160a01b03811698610a438a15156125fa565b610a576001600160a01b038516151561263d565b15610ab357610a6f610a84926108a4610a7f936103bd565b6001600160801b03851690613979565b61271c565b610a8e8285613a73565b83613b0e565b6040519485526001600160a01b0316939081906020820190565b0390a3005b610af5826108a4610aef61069088610ade610690610ad7610afa9a6108a48b6103bd565b5460801c90565b610aea82821015612685565b6126e7565b936103bd565b6126f9565b610a84565b634e487b7160e01b600052602160045260246000fd5b60051115610b1f57565b610aff565b3461032157602036600319011261032157600435600052600760205260ff604060002054166040516005821015610b1f576020918152f35b34610321576040366003190112610321577f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b6040600435610b9c816103a4565b63ffffffff60243591610bad6136a2565b169081600052600160205280836000205582519182526020820152a1005b3461032157602036600319011261032157600435610be881610310565b60018060a01b03166000526008602052602060ff604060002054166040519015158152f35b3461032157600036600319011261032157610c266136a2565b60035460ff811615610c655760ff19166003557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b638dfc202b60e01b60005260046000fd5b3461032157600036600319011261032157602060405161ffff7f0000000000000000000000000000000000000000000000000000000000000064168152f35b346103215760203660031901126103215763ffffffff600435610cd7816103a4565b610cdf6136a2565b168060005260066020526040600020600160ff198254161790557fa7dbeb6ef5cb64125bfb03ac211f1aea3f639de95ceb37b16706d4f0735d1863600080a2005b908160809103126103215790565b346103215761018036600319011261032157610d49366105f9565b610144356001600160401b03811161032157610d699036906004016104a7565b90610164356001600160401b03811161032157610e2a91610d91610e23923690600401610d20565b93610d9a613210565b610da2613230565b336000526009602052610dbc60ff6040600020541661240e565b610ddc610dd7610dd3604089013561065a81610310565b1590565b612772565b610ded610de886613bd5565b6127ca565b610df686613bed565b91309230927f00000000000000000000000000000000000000000000000000000000000075959289613d8f565b9183613f4f565b604051828152909391906001600160a01b0385169084907f86d7c80bc9d060acd32be0a39bbd97538a0e7b1f748c30d4e87b186b1d3589bb90602090a3610e7082614138565b15610ee85750819250610e90610e95926000526005602052604060002090565b612805565b610eb9610eac826000526007602052604060002090565b805460ff19166004179055565b7fe82916be8cebf4000a0d08979cca286e4bfe07a019f19c0c930305aceacdcaf6600080a26100196001600255565b610ef193613551565b610795565b3461032157602036600319011261032157600435610f1381610310565b610f1b6136a2565b6001600160a01b03166000908152600960205260409020805460ff19166001179055005b346103215760203660031901126103215763ffffffff600435610f61816103a4565b166000526006602052602060ff604060002054166040519015158152f35b3461032157600036600319011261032157602060ff600354166040519015158152f35b34610321576000366003190112610321576040517f0000000000000000000000001a44076050125825900e736c501f859c50fe728c6001600160a01b03168152602090f35b346103215760203660031901126103215760043561100481610310565b61100c6136a2565b6001600160a01b03166000908152600860205260409020805460ff19169055005b34610321576000366003190112610321576110466136a2565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b6101403660031901126103215761109c366105f9565b6110a4613210565b6110ac613230565b3360005260096020526110c660ff6040600020541661240e565b6110f1307f0000000000000000000000000000000000000000000000000000000000007595836141a0565b90606081019161110361065a84612230565b156111c25761112161111a61069060208501612297565b3414612a28565b8161112b81614138565b156111b457506111479033906111413685612a7f565b906143c0565b61115361065a83612230565b156111875761116461079592612230565b90611181610690602061117a6101208501612230565b9301612297565b91613b0e565b6111966106b6610ef193612230565b906111ac610690602061117a6101208501612230565b913390614613565b6111bd916142c8565b611147565b6111cc34156129c4565b611121565b34610321576040366003190112610321576111ed6004356103a4565b602060405160008152f35b346103215760203660031901126103215760043561121581610310565b60018060a01b03166000526009602052602060ff604060002054166040519015158152f35b346103215760a03660031901126103215761125436610496565b506064356001600160401b038111610321576112749036906004016104a7565b5050602060843561128481610310565b6040516001600160a01b0390911630148152f35b34610321576000366003190112610321576112b16136a2565b6112b9613230565b600160ff1960035416176003557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b919082519283825260005b84811061131e575050826000602080949584010152601f8019910116010190565b806020809284010151828286010152016112fd565b3461032157600036600319011261032157611373611381611352614657565b604092919251938493600f60f81b855260e0602086015260e08501906112f2565b9083820360408501526112f2565b466060830152306080830152600060a083015281810360c0830152602060605191828152019060809060005b8181106113bb575050500390f35b82518452859450602093840193909201916001016113ad565b34610321576000366003190112610321576000546040516001600160a01b039091168152602090f35b346103215760403660031901126103215760043561141a81610310565b6024356114256136a2565b478061144b575b508061143457005b60005461001992906001600160a01b031690613b0e565b60008080809360018060a01b038254165af1611465612b3e565b5015611471573861142c565b60405162461bcd60e51b8152602060048201526017602482015276115d1a195c881dda5d1a191c985dd85b0819985a5b1959604a1b6044820152606490fd5b610180366003190112610321576004356114c93661060b565b610164356001600160401b038111610321576114e99036906004016104a7565b6114f4929192613210565b6114fc613230565b8361150683612c60565b036115ef577f8168c9ac1d18802efe1afee0a6bf2de2b35d9f041a5b42a072b06252ba84fe509261159d9261155f3033307f00000000000000000000000000000000000000000000000000000000000075958a86614763565b611583611576876000526007602052604060002090565b805460ff19166003179055565b61159860c0611591886148ce565b9201612226565b6148f0565b80516115e260406115b860208501516001600160401b031690565b93015151604051938493846001600160401b03604092959493606083019683521660208201520152565b0390a26100196001600255565b60405162461bcd60e51b815260206004820152602a60248201527f5375626d6974746564206f72646572206461746120646f65736e2774206d617460448201526918da081bdc99195c925960b21b6064820152608490fd5b346103215761016036600319011261032157611662366105f9565b610144356001600160401b03811161032157610795916116896107839236906004016104a7565b611694939193613210565b61169c613230565b3360005260096020526116b660ff6040600020541661240e565b61077e60408401916117376117318435976116d089610310565b6001600160a01b038916936116fb73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee861415612772565b61170489613bed565b91309230927f0000000000000000000000000000000000000000000000000000000000007595928c613d8f565b96610310565b6101008501359061174782610310565b611755863561069081612286565b913091614613565b346103215760203660031901126103215760043560005260056020526040600020805461049260018060a01b036001840154166002840154936117a08560e01c90565b6003820154906117d460046117c563ffffffff85169460201c6001600160a01b031690565b9401546001600160a01b031690565b604080516001600160801b0389168152608098891c60208201526001600160a01b0396871691810191909152858916606082015260a089811c63ffffffff9081169983019990995260c0998a1c89169082015291871697820197909752941660e08501528116610100840152909216610120820152908190610140820190565b6101603660031901126103215761186a366105f9565b610144356001600160401b0381116103215761188a903690600401610d20565b90611893613210565b61189b613230565b3360005260096020526118b560ff6040600020541661240e565b61199f6118e3307f0000000000000000000000000000000000000000000000000000000000007595846141a0565b916118ee8482614928565b936001600160a01b039061190490602001612230565b16837fd6fb3db9629fef5e875e0d0138b2fb4ae60575aba13837c23c1c9a6aa1e35bac6040518061193a89829190602083019252565b0390a3611957602082019461195161069087612297565b906126e7565b928161196281614138565b156119c857506119789033906111413685612a7f565b606081019361118161069061199961012061199289612230565b9501612230565b92612297565b806119ae576100196001600255565b6119c1916119bc3391612230565b613b0e565b3880610795565b6119d1916142c8565b611978565b34610321576101403660031901126103215760206119fb6119f6366105f9565b612c60565b604051908152f35b602060408183019282815284518094520192019060005b818110611a275750505090565b82511515845260209384019390920191600101611a1a565b34610321576020366003190112610321576004356001600160401b0381116103215736602382011215610321578060040135906001600160401b038211610321573660248360051b8301011161032157610492916024611a9f9201612c89565b60405191829182611a03565b346103215760203660031901126103215763ffffffff600435611acd816103a4565b1660005260016020526020604060002054604051908152f35b346103215760203660031901126103215763ffffffff600435611b08816103a4565b611b106136a2565b16806000526006602052604060002060ff1981541690557f79df5d328757ca456e42d3dc087c02eedd4cf61d984a6aa526cfac31f1542dcd600080a2005b3461032157602036600319011261032157610795600435611b6d613210565b611b75613230565b806000526005602052611cce6040600020611ca0611c8f6004611b9661250d565b84546001600160801b0381168252909490611bc690611bb6905b60801c90565b6001600160801b03166020870152565b6001810154611be9906001600160a01b03165b6001600160a01b03166040870152565b60028101546001600160a01b0381166060870152611c3990611c2c9063ffffffff60a082901c16608089015263ffffffff60c082901c1660a08901525b60e01c90565b63ffffffff1660c0870152565b611c81611c706003830154611c61611c548263ffffffff1690565b63ffffffff1660e08a0152565b60201c6001600160a01b031690565b6001600160a01b0316610100870152565b01546001600160a01b031690565b6001600160a01b0316610120830152565b309033903090857f000000000000000000000000000000000000000000000000000000000000759591614d00565b614e41565b346103215760006020366003190112611d7d5780600435611cf381610310565b611cfb6136a2565b7f0000000000000000000000001a44076050125825900e736c501f859c50fe728c6001600160a01b0316803b15611d795760405163ca5eb5e160e01b81526001600160a01b0390921660048301529091908290602490829084905af18015611d74578290611d665780f35b611d6f916124dd565b388180f35b612e85565b5050fd5b80fd5b346103215760c036600319011261032157600435611d9d816103a4565b6024359060ff8216820361032157604435906001600160401b0382116103215761049292611dd2611dfe9336906004016104a7565b60643591611ddf836109b1565b60843593611dec856103a4565b60a43595611df987610310565b612ec3565b6040519081529081906020820190565b34610321576020611e4a611e2136610333565b6001600160a01b0391821660009081526004855260408082209290931681526020919091522090565b5460801c604051908152f35b3461032157604036600319011261032157600435602435611e7681610310565b611e7e6136a2565b611e92826000526007602052604060002090565b5460ff16611e9f81610b15565b600114611eab90613006565b6001600160a01b03811690611ec182151561263d565b611ed5836000526005602052604060002090565b611ede90612d9b565b9260c0840151611ef19063ffffffff1690565b7f000000000000000000000000000000000000000000000000000000000000759563ffffffff169063ffffffff1614611f2990613052565b604084015184516001600160801b0316946001600160a01b039091169290859081908590611f578383613a73565b611f6b866000526007602052604060002090565b805460ff1916600317905561010001516001600160a01b0316611f8d906103bd565b6001600160a01b0390911660009081526020919091526040902090611fb191613979565b611fba9061271c565b611fc49184613b0e565b6040519182917fe8d9861dbc9c663ed3accd261bbe2fe01e0d3d9e5f51fa38523b265c7757a93a600080a26001600160801b039490941690526001600160a01b039092169160008051602061595b83398151915290602090a3005b346103215760203660031901126103215760043561203c81610310565b6120446136a2565b6001600160a01b03166000908152600860205260409020805460ff19166001179055005b346103215760203660031901126103215760043561208581610310565b61208d6136a2565b6001600160a01b031680156120df57600080546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b631e4fbdf760e01b600052600060045260246000fd5b346103215760403660031901126103215760043561211281610310565b60243561211d613210565b612125613230565b80336000526004602052612152610ad78460406000209060018060a01b0316600052602052604060002090565b9161215e8315156130b4565b806121c257505061218961217c6106908380945b610aea8288613a73565b610af5846108a4336103bd565b612194813384613b0e565b6040519081526001600160a01b0390911690339060008051602061595b83398151915290806020810161095c565b61069082846121da61217c9461218996971015612685565b612172565b346103215760603660031901126103215760206121fb36610496565b63ffffffff813561220b816103a4565b16600052600182528160406000205491013560405191148152f35b35610358816103a4565b3561035881610310565b1561224157565b60405162461bcd60e51b815260206004820152601f60248201527f4f72646572206d7573742073706563696679206e617469766520746f6b656e006044820152606490fd5b6001600160801b0381160361032157565b3561035881612286565b156122a857565b60405162461bcd60e51b8152602060048201526017602482015276125b98dbdc9c9958dd081b985d1a5d9948185b5bdd5b9d604a1b6044820152606490fd5b156122ee57565b60405162461bcd60e51b815260206004820152602660248201527f4f6e6c79206f6666657265722063616e206465706f736974206e617469766520604482015265746f6b656e7360d01b6064820152608490fd5b1561234957565b60405162461bcd60e51b81526020600482015260146024820152734f7264657220616c72656164792065786973747360601b6044820152606490fd5b1561238c57565b60405162461bcd60e51b815260206004820152601f60248201527f44657374696e6174696f6e20636861696e206e6f7420737570706f72746564006044820152606490fd5b156123d857565b60405162461bcd60e51b815260206004820152600e60248201526d086d0c2d2dc40dad2e6dac2e8c6d60931b6044820152606490fd5b1561241557565b60405162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21039b7b63b32b960911b6044820152606490fd5b1561245257565b60405162461bcd60e51b8152602060048201526012602482015271139bc81bdc99195c9cc81c1c9bdd9a59195960721b6044820152606490fd5b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b038211176124bd57604052565b61248c565b606081019081106001600160401b038211176124bd57604052565b90601f801991011681019081106001600160401b038211176124bd57604052565b604051906103316040836124dd565b60405190610331610140836124dd565b6040519061033160a0836124dd565b6001600160401b0381116124bd57601f01601f191660200190565b9291926125538261252c565b9161256160405193846124dd565b829481845281830111610321578281602093846000960137010152565b9060609295949361259f6001600160401b03926080855260808501906112f2565b9660208401521660408201520152565b156125b657565b606460405162461bcd60e51b815260206004820152602060248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f6044820152fd5b1561260157565b60405162461bcd60e51b8152602060048201526014602482015273496e76616c69642075736572206164647265737360601b6044820152606490fd5b1561264457565b60405162461bcd60e51b8152602060048201526019602482015278496e76616c696420726563697069656e74206164647265737360381b6044820152606490fd5b1561268c57565b60405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420756e6c6f636b65642062616c616e63650000006044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b919082039182116126f457565b6126d1565b80546001600160801b031660809290921b6001600160801b031916919091179055565b1561272357565b60405162461bcd60e51b815260206004820152602160248201527f4661696c656420746f206465637265617365206c6f636b65642062616c616e636044820152606560f81b6064820152608490fd5b1561277957565b60405162461bcd60e51b815260206004820152602360248201527f557365206465706f7369744e617469766520666f72206e617469766520746f6b604482015262656e7360e81b6064820152608490fd5b156127d157565b60405162461bcd60e51b815260206004820152600c60248201526b4d697373696e6720686f6f6b60a01b6044820152606490fd5b60046129a36101206103319461283961281d82612297565b86546001600160801b0319166001600160801b03909116178655565b61284e61284860208301612297565b866126f9565b61288061285d60408301612230565b6001870180546001600160a01b0319166001600160a01b03909216919091179055565b61293c600286016128b261289660608501612230565b82546001600160a01b0319166001600160a01b03909116178255565b6128e16128c160808501612226565b825463ffffffff60a01b191660a09190911b63ffffffff60a01b16178255565b6129106128f060a08501612226565b825463ffffffff60c01b191660c09190911b63ffffffff60c01b16178255565b61291c60c08401612226565b81546001600160e01b031660e09190911b6001600160e01b031916179055565b61299d6003860161296861295260e08501612226565b825463ffffffff191663ffffffff909116178255565b6129756101008401612230565b8154640100000000600160c01b03191660209190911b640100000000600160c01b0316179055565b01612230565b910180546001600160a01b0319166001600160a01b03909216919091179055565b156129cb57565b60405162461bcd60e51b815260206004820152602f60248201527f4e6f206e617469766520746f6b656e732073686f756c642062652073656e742060448201526e666f722045524332302066696c6c7360881b6064820152608490fd5b15612a2f57565b60405162461bcd60e51b815260206004820152601c60248201527f496e636f7272656374206e617469766520616d6f756e742073656e74000000006044820152606490fd5b359061033182612286565b91908261014091031261032157612b36610120612a9a61250d565b93612aa481612a74565b8552612ab260208201612a74565b6020860152612ac360408201610326565b6040860152612ad460608201610326565b6060860152612ae5608082016103b2565b6080860152612af660a082016103b2565b60a0860152612b0760c082016103b2565b60c0860152612b1860e082016103b2565b60e0860152612b2a6101008201610326565b61010086015201610326565b610120830152565b3d15612b69573d90612b4f8261252c565b91612b5d60405193846124dd565b82523d6000602084013e565b606090565b61033190929192610120612c5281610140840196612b9c85612b8f83612a74565b6001600160801b03169052565b612bab611bb660208301612a74565b612bba611bd960408301610326565b612bd9612bc960608301610326565b6001600160a01b03166060870152565b612bf5612be8608083016103b2565b63ffffffff166080870152565b612c11612c0460a083016103b2565b63ffffffff1660a0870152565b612c20611c2c60c083016103b2565b612c3c612c2f60e083016103b2565b63ffffffff1660e0870152565b612c4c611c706101008301610326565b01610326565b6001600160a01b0316910152565b604051612c8381612c75602082019485612b6e565b03601f1981018352826124dd565b51902090565b612c916136a2565b612c9a82612d60565b91612ca860405193846124dd565b808352601f19612cb782612d60565b0136602085013760005b818110612cce5750505090565b8063ffffffff612ce16001938587612d77565b35612ceb816103a4565b16600052600660205260406000208260ff19825416179055612d22612d19612d14838688612d77565b612226565b63ffffffff1690565b7fa7dbeb6ef5cb64125bfb03ac211f1aea3f639de95ceb37b16706d4f0735d1863600080a2612d5a612d548287612d87565b60019052565b01612cc1565b6001600160401b0381116124bd5760051b60200190565b91908110156104055760051b0190565b80518210156104055760209160051b010190565b90610331612e746004612dac61250d565b85546001600160801b0381168252909590612dda90612dca90611bb0565b6001600160801b03166020880152565b60018101546001600160a01b0316604087015260028101546001600160a01b0381166060880152612e3b90612e2e9063ffffffff60a082901c1660808a015263ffffffff60c082901c1660a08a0152611c26565b63ffffffff1660c0880152565b611c81612e636003830154611c61612e568263ffffffff1690565b63ffffffff1660e08b0152565b6001600160a01b0316610100880152565b6001600160a01b0316610120840152565b6040513d6000823e3d90fd5b90612e9b8261252c565b612ea860405191826124dd565b8281528092612eb9601f199161252c565b0190602036910137565b9391612f3c90612f34612f2f612f7d9694612f07612f989b63ffffffff60409c16600052600a6020528b6000209060018060a01b0316600052602052604060002090565b547f000000000000000000000000000000000000000000000000000000000000006491614f0e565b612e91565b923691612547565b90612f45613768565b50612f4f856130fc565b612f66612f5a61251d565b63ffffffff9097168752565b602086015285850152606084015215156080830152565b815180938192631bb8518b60e31b835230906004840161381a565b03817f0000000000000000000000001a44076050125825900e736c501f859c50fe728c6001600160a01b03165afa908115611d7457600091612fd957505190565b612ffb915060403d604011612fff575b612ff381836124dd565b810190614f85565b5190565b503d612fe9565b1561300d57565b60405162461bcd60e51b815260206004820152601d60248201527f43616e206f6e6c792063616e63656c20616374697665206f72646572730000006044820152606490fd5b1561305957565b60405162461bcd60e51b815260206004820152602d60248201527f456d657267656e63792063616e63656c206f6e6c7920616c6c6f776564206f6e60448201526c1039b7bab931b29031b430b4b760991b6064820152608490fd5b156130bb57565b60405162461bcd60e51b8152602060048201526019602482015278139bdb8b5e995c9bc818985b185b98d9481c995c5d5a5c9959603a1b6044820152606490fd5b63ffffffff1680600052600160205260406000205490811561311c575090565b63f6ff4fb760e01b60005260045260246000fd5b9350509350915061313f613230565b81156131db573561314f816103a4565b61315982846153fa565b3560f81c6002811015610b1f5761316f816148c4565b6001810361318257505061033191615550565b61318e819392936148c4565b61319b5761033192615403565b60405162461bcd60e51b8152602060048201526018602482015277556e737570706f72746564207061796c6f6164207479706560401b6044820152606490fd5b60405162461bcd60e51b815260206004820152600d60248201526c115b5c1d1e481c185e5b1bd859609a1b6044820152606490fd5b600280541461321f5760028055565b633ee5aeb560e01b60005260046000fd5b60ff6003541661323c57565b63d93c066560e01b60005260046000fd5b1561325457565b60405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b21037b33332b932b960891b6044820152606490fd5b1561329257565b60405162461bcd60e51b8152602060048201526011602482015270125b9d985b1a59081c9958da5c1a595b9d607a1b6044820152606490fd5b156132d257565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c696420656e642074696d6560801b6044820152606490fd5b1561331157565b60405162461bcd60e51b815260206004820152601160248201527013dc99195c881b9bdd081cdd185c9d1959607a1b6044820152606490fd5b1561335157565b60405162461bcd60e51b815260206004820152601160248201527013dc99195c881a185cc8195e1c1a5c9959607a1b6044820152606490fd5b1561339157565b60405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a59081a5b9c1d5d08185b5bdd5b9d60621b6044820152606490fd5b156133d457565b60405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081bdd5d1c1d5d08185b5bdd5b9d605a1b6044820152606490fd5b1561341857565b60405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b2103a37b5b2b760991b6044820152606490fd5b610331906134716001600160a01b036134696101008401612230565b16151561324d565b61348b6134846106b66101208401612230565b151561328b565b6134e5608082016134d26134c36134a183612226565b92612d1460a087019463ffffffff6134bb612d1988612226565b9116106132cb565b63ffffffff429116111561330a565b6134df612d194292612226565b1161334a565b6135016001600160801b036134f983612297565b16151561338a565b61351a61351361069060208401612297565b15156133cd565b6135296106b660408301612230565b15159081613538575b50613411565b613549915060606106b69101612230565b151538613532565b9161369161365e61369d936136597f8e45fa612720ed3142e896a3a29c981f4ca01c25bca19c3a5c203398ee1bc3d79661010086013561359081610310565b6001600160a01b0390811660009081526004602090815260408083209385168352929052206135f2906135d56135c586614f99565b82546001600160801b0316614fcc565b81546001600160801b0319166001600160801b0391909116179055565b8860005260076020526040600020600160ff1982541617905561362386610e908b6000526005602052604060002090565b60016136398a6000526005602052604060002090565b0180546001600160a01b0319166001600160a01b03909216919091179055565b614f99565b613672866000526005602052604060002090565b80546001600160801b0319166001600160801b03909216919091179055565b60405191829182612b6e565b0390a2565b6000546001600160a01b031633036136b657565b63118cdaa760e01b6000523360045260246000fd5b63ffffffff166017019063ffffffff82116126f457565b908260051b621fffe061ffe08216911681036126f457612f2f612d1961370f6137149396949661ffff1690565b6136cb565b928160481b9060581b17602084015281600052602060002093825491820393603781015b838681111561375c57906000602092811901958119908a0101805483525501613738565b50509392915093505590565b60405190613775826124a2565b60006020838281520152565b6040519061378e826124c2565b81600081526000602082015260406137a4613768565b910152565b9190826040910312610321576040516137c1816124a2565b6020808294805184520151910152565b60808183031261032157604051916137e8836124c2565b8151835260208201516001600160401b0381168103610321576020840152613812916040016137a9565b604082015290565b906020909392936040835263ffffffff8151166040840152818101516060840152608061386e613858604084015160a08488015260e08701906112f2565b6060840151868203603f190160a08801526112f2565b910151151560c08401526001600160a01b03909416910152565b6138e560809492613901969461389c613781565b5060206138a98651614fe5565b95019182518061396a575b506138be856130fc565b92511515926138ce612f5a61251d565b602086015260408501526060840152151585830152565b6040518095819482936302637a4560e41b84526004840161381a565b03917f0000000000000000000000001a44076050125825900e736c501f859c50fe728c6001600160a01b03165af1908115611d7457600091613941575090565b610358915060803d608011613963575b61395b81836124dd565b8101906137d1565b503d613951565b61397390615004565b386138b4565b805490916001600160801b039182169081039091169081116139b95781546001600160801b0319166001600160801b03909116179055600190565b600190565b5050600090565b90816020910312610321575190565b156139d657565b60405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e7420636f6e74726163742062616c616e63650000006044820152606490fd5b15613a2257565b60405162461bcd60e51b8152602060048201526024808201527f496e73756666696369656e7420636f6e7472616374206e61746976652062616c604482015263616e636560e01b6064820152608490fd5b6001600160a01b03169073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8203613aa5576103319150471015613a1b565b6040516370a0823160e01b815230600482015291602090839060249082905afa8015611d745761033192600091613adf575b5010156139cf565b613b01915060203d602011613b07575b613af981836124dd565b8101906139c0565b38613ad7565b503d613aef565b6001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103613b9557506000918291829182916001600160a01b03165af1613b4f612b3e565b5015613b5757565b60405162461bcd60e51b815260206004820152601660248201527513985d1a5d99481d1c985b9cd9995c8819985a5b195960521b6044820152606490fd5b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448083019390935291815261033191613bd06064836124dd565b61537e565b35613bdf81610310565b6001600160a01b0316151590565b61035890803590613bfd82612286565b613d1b6020820135613c0e81612286565b612c75604084013593613c2085610310565b606081013590613c2f82610310565b613c3b60808201612226565b613c4760a08301612226565b613c5360c08401612226565b90613c6060e08501612226565b92613c7b610120613c746101008801612230565b9601612230565b956040519a8b9960208b019d8e7f16210483e9c961c9c307e53963eafad0795395f2fce68f0c9c294cca1ac5a06a81526001600160801b039182166020820152911660408201526001600160a01b039182166060820152918116608083015263ffffffff92831660a083015292821660c082015292811660e084015292909216610100820152918116610120830152919091166101408201526101600190565b5190206150bd565b90816020910312610321575160058110156103215790565b908160209103126103215751610358816109b1565b15613d5757565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c69645369676e617475726560801b6044820152606490fd5b90613dd49392959796602060405181810190613daf81612c758885612b6e565b519020809a6040518080998194632dff692d60e01b8352600483019190602083019252565b03915afa908115611d7457613dfb602092613e3097600091613edf575b5061070081610b15565b613e0760e08501612226565b60405163167d0a6960e21b815263ffffffff909116600482015295869190829081906024820190565b03915afa918215611d7457613e97613e7663ffffffff9695613e7060c0956103319b613e69613ea6998c9b600091613eb0575b50612385565b3691612547565b9061512a565b613e866106b66101008501612230565b6001600160a01b0390911614613d50565b613ea08161344d565b01612226565b92169116146123d1565b613ed2915060203d602011613ed8575b613eca81836124dd565b810190613d3b565b38613e63565b503d613ec0565b613eff9150843d8611613f05575b613ef781836124dd565b810190613d23565b38613df1565b503d613eed565b15613f1357565b60405162461bcd60e51b8152602060048201526014602482015273496e76616c696420686f6f6b206164647265737360601b6044820152606490fd5b91908035613f5c81610310565b6001600160a01b0316600090815260086020526040902054613f809060ff16613f0c565b613fbb613f926106b660408601612230565b613f9f6101008601612230565b613fa884612230565b90613fb561069088612297565b92614613565b613fc483614138565b1561407d57613ff8613fe3613fd883612230565b9260608101906140ba565b606086019391613ff285612230565b926151b6565b906140576140516106906020870161401d61401561069083612297565b8710156140ec565b61404c61402986612230565b9861404061012061403989612230565b9201612230565b61118161069085612297565b612297565b836126e7565b80614063575b50509190565b61406f61407692612230565b3390613b0e565b388061405d565b915061035861408b83612230565b61077e60406140af6140a060608801886140ba565b602089019591613ff287612230565b9501358510156140ec565b903590601e198136030182121561032157018035906001600160401b0382116103215760200191813603831361032157565b156140f357565b60405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e74206f75747075742066726f6d20686f6f6b0000006044820152606490fd5b63ffffffff8060e060c08401359361414f856103a4565b013561415a816103a4565b1691161490565b1561416857565b60405162461bcd60e51b815260206004820152601060248201526f4f72646572206e6f742061637469766560801b6044820152606490fd5b9291906141ac8461344d565b6141c360e085019163ffffffff80613ea685612226565b63ffffffff6141f9612d196141f360c060405160208101906141e981612c758d85612b6e565b5190209801612226565b93612226565b91160361426657604051632dff692d60e01b81526004810184905290602090829060249082905afa908115611d745761033191600191600091614247575b5061424181610b15565b14614161565b614260915060203d602011613f0557613ef781836124dd565b38614237565b604051632dff692d60e01b81526004810184905290602090829060249082905afa8015611d7457610331916000916142a9575b506142a381610b15565b15614161565b6142c2915060203d602011613f0557613ef781836124dd565b38614299565b908160005260076020526142e76040600020600260ff19825416179055565b63ffffffff60c08201356142fa816103a4565b166000908152600a60209081526040808320338452909152902080549091600160401b8210156124bd57614358827f7f80314442bfb82d1f9dfa4f96cbc84ae8fef158c7a93315024778ca3fc1671694600161369d950181556103ed565b81549060031b9086821b91600019901b191617905560405191829182612b6e565b1561438057565b60405162461bcd60e51b815260206004820152601860248201527710985b185b98d9481bdc195c985d1a5bdb8819985a5b195960421b6044820152606490fd5b610100820180519193916001600160a01b03166143dc906103bd565b604084810180516001600160a01b031660009081526020939093529120909390546001600160801b03169282614411826103bd565b86516001600160a01b03166000908152602091909152604090205460801c81519093908190889085906001600160a01b031661444c906103bd565b82516001600160a01b0316600090815260209190915260409020546001600160801b031683516001600160801b03166001600160801b031690600160801b600190031610156144d561451f610ad761450f61450961454f9f6144da6144d56145499d61453b9c6144e69b6144fc9561452d9c61458d575b505090516001600160a01b0316919050565b6103bd565b89516001600160a01b03165b60018060a01b0316600052602052604060002090565b546001600160801b031690565b9a6103bd565b86516001600160a01b03166144e6565b99516001600160a01b031690565b91516001600160a01b031690565b50516001600160801b031690565b936152a4565b614566610eac826000526007602052604060002090565b7fe82916be8cebf4000a0d08979cca286e4bfe07a019f19c0c930305aceacdcaf6600080a2565b614602926145f06145e26145f6936144e661452d6145dc6145ca6145ba6144d58d5160018060a01b031690565b85516001600160a01b03166144e6565b87516001600160801b03165b90613979565b976103bd565b91516001600160801b031690565b9061527e565b8161460b575b50614379565b8f8e908d6144c3565b9050386145fc565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815261033191613bd06084836124dd565b604090815161466683826124dd565b6004815263416f726960e01b602082015291614684815191826124dd565b6005815264302e332e3160d81b602082015290565b156146a057565b60405162461bcd60e51b81526020600482015260186024820152772737ba1037b7103232b9ba34b730ba34b7b71031b430b4b760411b6044820152606490fd5b156146e757565b60405162461bcd60e51b815260206004820152604860248201527f4f6e6c792077686974656c697374656420736f6c7665722c206f66666572657260448201527f2c206f7220726563697069656e742028616674657220657870697279292063616064820152671b8818d85b98d95b60c21b608482015260a490fd5b929060209161478b6147ab9463ffffffff8061478160e08a01612226565b9216911614614699565b6040518080958194632dff692d60e01b8352600483019190602083019252565b03915afa8015611d74576147ca916000916142a957506142a381610b15565b604051631f798dcd60e21b81526001600160a01b038316600482015292602090849060249082905afa918215611d7457610331936000936148a3575b508215614863575b821561481c575b50506146e0565b90915061482f6106b66101208401612230565b6001600160a01b0390911614908161484a575b503880614815565b61485b915060a0612d199101612226565b421138614842565b91506148756106b66101008301612230565b6001600160a01b038316148061488c575b9161480e565b5061489c612d1960a08301612226565b4211614886565b6148bd91935060203d602011613ed857613eca81836124dd565b9138614806565b60021115610b1f57565b60405190600160f81b60208301526021820152602181526103586041826124dd565b6103589392916148fe613781565b506149226040519361490f856124a2565b3485526000602086015233953691612547565b91613888565b906149e461069060206149dd61035894803561494381610310565b6001600160a01b031660009081526008845260409020546149669060ff16613f0c565b60608101358015614a175783820161498061065a82612230565b156149ec575060008080808461499a6149b9963414614ad1565b6149a96106b66106b689612230565b5af16149b3612b3e565b50614b31565b6149d06149c582612230565b9160408101906140ba565b90613ff260608a01612230565b9401612297565b821015614b7d565b90614a016106b6614a129361077e3415614a63565b614a0a84612230565b903390614613565b6149b9565b50614a1234614a2257565b60405162461bcd60e51b8152602060048201526019602482015278139bc81b985d1a5d99481d1bdad95b9cc8195e1c1958dd1959603a1b6044820152606490fd5b15614a6a57565b60405162461bcd60e51b815260206004820152603960248201527f4e6f206e617469766520746f6b656e732073686f756c642062652073656e74206044820152783337b91022a921991810383932b332b93932b2103a37b5b2b760391b6064820152608490fd5b15614ad857565b60405162461bcd60e51b815260206004820152602b60248201527f496e636f7272656374206e617469766520616d6f756e7420666f72207072656660448201526a32b93932b2103a37b5b2b760a91b6064820152608490fd5b15614b3857565b60405162461bcd60e51b815260206004820152601e60248201527f4e6174697665207472616e7366657220746f20686f6f6b206661696c656400006044820152606490fd5b15614b8457565b60405162461bcd60e51b815260206004820152603560248201527f486f6f6b206d7573742070726f76696465206174206c656173742074686520656044820152741e1c1958dd1959081bdd5d1c1d5d08185b5bdd5b9d605a1b6064820152608490fd5b15614bee57565b60405162461bcd60e51b81526020600482015260136024820152722737ba1037b71039b7bab931b29031b430b4b760691b6044820152606490fd5b15614c3057565b60405162461bcd60e51b815260206004820152603b60248201527f43726f73732d636861696e206f7264657273206d7573742062652063616e636560448201527f6c6c65642066726f6d2064657374696e6174696f6e20636861696e00000000006064820152608490fd5b15614ca257565b60405162461bcd60e51b815260206004820152603060248201527f4f6e6c7920736f6c766572206f72206f6666657265722028616674657220657860448201526f1c1a5c9e4a4818d85b8818d85b98d95b60821b6064820152608490fd5b92614d2e9160209161478b60c087019563ffffffff80614d24895163ffffffff1690565b9216911614614be7565b03915afa918215611d7457614d576001614d8294614d6194600091614247575061424181610b15565b5163ffffffff1690565b63ffffffff614d7a612d1960e086015163ffffffff1690565b911614614c29565b604051631f798dcd60e21b81526001600160a01b038316600482015292602090849060249082905afa918215611d745761033193600093614e20575b508215614dcd575b5050614c9b565b61010082015191925090614de9906001600160a01b03166106b6565b6001600160a01b03909116149081614e04575b503880614dc6565b60a00151614e18915063ffffffff16612d19565b421138614dfc565b614e3a91935060203d602011613ed857613eca81836124dd565b9138614dbe565b806000526007602052614e67600160ff60406000205416614e6181610b15565b14613006565b614ee7614e86614e81836000526005602052604060002090565b612d9b565b80516040820151610100909201516001600160801b03909116916001600160a01b039182169116614eb78382613a73565b614ece611576866000526007602052604060002090565b6119bc610a7f84614ee2846108a4876103bd565b613979565b7fe8d9861dbc9c663ed3accd261bbe2fe01e0d3d9e5f51fa38523b265c7757a93a600080a2565b90919060ff1660018103614f2457505050602190565b614f49576103589161ffff91821680821015614f4257505b166153d9565b9050614f3c565b60405162461bcd60e51b8152602060048201526014602482015273496e76616c6964206d657373616765207479706560601b6044820152606490fd5b9060408282031261032157610358916137a9565b6001600160801b038111614fb3576001600160801b031690565b6306dfcc6560e41b600052608060045260245260446000fd5b6001600160801b0391821690821601919082116126f457565b803403614fef5790565b6304fb820960e51b6000523460045260246000fd5b60405163393f876560e21b81527f0000000000000000000000001a44076050125825900e736c501f859c50fe728c6001600160a01b03169190602081600481865afa908115611d7457600091615082575b506001600160a01b031691821561507157610331923390614613565b6329b99a9560e11b60005260046000fd5b90506020813d6020116150b5575b8161509d602093836124dd565b8101031261032157516150af81610310565b38615055565b3d9150615090565b906150c6614657565b604093919351937f91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a276660005260208151910120602052602081519101206040523060605260806000206020526119016000526040526042601e20916040526000606052565b919091604051928051806040146151945760411461515557505050505b638baa579f6000526004601cfd5b602091606082015160001a835260408201516060525b60005201516040526020600160806000825afa519160006060526040523d610331575050615147565b506020916040820151601b8160ff1c01845260018060ff1b031660605261516b565b6000919392908291826151c930876155b6565b96826040519384928337810182815203925af16151e4612b3e565b501561524b576151f59030906155b6565b9080821061520657610358916126e7565b60405162461bcd60e51b815260206004820152601f60248201527f486f6f6b2064656372656173656420636f6e74726163742062616c616e6365006044820152606490fd5b60405162461bcd60e51b815260206004820152600b60248201526a10d85b1b0819985a5b195960aa1b6044820152606490fd5b8054909160809190911c9081016001600160801b03169081106139b9576139b4916126f9565b92939192906001600160801b03906152bd908490614fcc565b166001600160801b0390911603615339576001600160801b03916152e19190614fcc565b166001600160801b03909116036152f457565b60405162461bcd60e51b815260206004820152601b60248201527f496e636f6e73697374656e7420736f6c7665722062616c616e636500000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601c60248201527f496e636f6e73697374656e74206f6666657265722062616c616e6365000000006044820152606490fd5b906000602091828151910182855af115612e85576000513d6153d057506001600160a01b0381163b155b6153af5750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b600114156153a8565b8060051b90808204602014901517156126f457601701806017116126f45790565b90156104055790565b9190916017831061550c576154188382615678565b9390916154268583836156bc565b60005b61ffff8616811061543c57505050505050565b60018161544d61ffff938686615741565b868861547660e061546b614e81866000526005602052604060002090565b015163ffffffff1690565b63ffffffff821663ffffffff82160361549c57505061549491615805565b019050615429565b7fbb563f7e333f32ed0571f8dc4913648b41737753db5df83c58657c6bfcc2ef569250615504604051928392839060a09263ffffffff809216835216602082015260606040820152600c60608201526b08ad2c840dad2e6dac2e8c6d60a31b60808201520190565b0390a2615494565b606460405162461bcd60e51b815260206004820152602060248201527f5061796c6f616420746f6f2073686f727420666f7220736574746c656d656e746044820152fd5b90602103615565576001610331910135614e41565b60405162461bcd60e51b815260206004820152602360248201527f496e76616c69642063616e63656c6c6174696f6e207061796c6f6164206c656e6044820152620cee8d60eb1b6064820152608490fd5b6001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81036155df57503190565b6040516370a0823160e01b81526001600160a01b039092166004830152602090829060249082905afa908115611d745760009161561a575090565b610358915060203d602011613b0757613af981836124dd565b1561563a57565b60405162461bcd60e51b8152602060048201526016602482015275092dcecc2d8d2c840e0c2f2d8dec2c840d8cadccee8d60531b6044820152606490fd5b9190916156886017841015615633565b600181013560601c928060151015610405576016101561040557601581013560f01c61ff00166016919091013560f81c1790565b5090621fffe061ffff82169160051b1690808204602014901517156126f45760170190816017116126f457036156ee57565b60405162461bcd60e51b815260206004820152602560248201527f496e76616c6964207061796c6f6164206c656e67746820666f7220736574746c604482015264195b595b9d60da1b6064820152608490fd5b9061574f6017821015615633565b60161981019081116126f45760051c8210156157715760179160051b01013590565b60405162461bcd60e51b8152602060048201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152606490fd5b906040516157b9816124a2565b91546001600160801b038116835260801c6020830152565b815181546001600160801b0319166001600160801b039190911617815561033191602001516001600160801b0316906126f9565b90600161581f6106f0846000526007602052604060002090565b61582881610b15565b0361595657615844614e81836000526005602052604060002090565b6101008101805191929091615861906001600160a01b03166103bd565b6040840180519093916158869161588191906001600160a01b03166144e6565b6157ac565b9061589661588161450f856103bd565b946158e36158d36158c36158b36144d5865160018060a01b031690565b88516001600160a01b03166144e6565b83516001600160801b03166145d6565b916145f06145e26144da886103bd565b901590811561594d575b5061590e575050505050614566610eac826000526007602052604060002090565b51610331955061594893926144e69261452d926144d591908790615938906001600160a01b031684565b87516001600160a01b03166144e6565b6157d1565b905015386158ed565b505056fe9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eba26469706673582212202463fc3c173b6a5cc2bef337128c18ef1cd9704d7eb70d9979f92d42aa4971ad64736f6c634300081c0033

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

0000000000000000000000001a44076050125825900e736c501f859c50fe728c000000000000000000000000941327e206b8d8cfe1014a8a95b05e1536dfd00d00000000000000000000000000000000000000000000000000000000000075950000000000000000000000000000000000000000000000000000000000000064

-----Decoded View---------------
Arg [0] : _endpoint (address): 0x1a44076050125825900e736c501f859c50fE728c
Arg [1] : _owner (address): 0x941327E206b8d8cfe1014A8A95B05E1536dFD00d
Arg [2] : _eid (uint32): 30101
Arg [3] : _maxFillsPerSettle (uint16): 100

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000001a44076050125825900e736c501f859c50fe728c
Arg [1] : 000000000000000000000000941327e206b8d8cfe1014a8a95b05e1536dfd00d
Arg [2] : 0000000000000000000000000000000000000000000000000000000000007595
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000064


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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