ETH Price: $1,975.21 (-0.76%)

Contract

0xbeb0b0623f66bE8cE162EbDfA2ec543A522F4ea6

Overview

ETH Balance

Taiko Alethia LogoTaiko Alethia LogoTaiko Alethia Logo0 ETH

ETH Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Settle10000492025-03-22 0:30:1140 secs ago1742603411IN
0xbeb0b062...A522F4ea6
0.011 ETH0.000025350.1
Settle Bebop Ble...10000452025-03-22 0:28:232 mins ago1742603303IN
0xbeb0b062...A522F4ea6
0 ETH0.00001920.101
Settle10000322025-03-22 0:21:239 mins ago1742602883IN
0xbeb0b062...A522F4ea6
0.0102 ETH0.00002170.1
Settle9994392025-03-21 17:10:237 hrs ago1742577023IN
0xbeb0b062...A522F4ea6
0 ETH0.000004590.0121485
Settle9994012025-03-21 16:43:237 hrs ago1742575403IN
0xbeb0b062...A522F4ea6
0.00003 ETH0.000022490.1000001
Settle9993802025-03-21 16:27:478 hrs ago1742574467IN
0xbeb0b062...A522F4ea6
0.0000199 ETH0.000002360.01068
Settle9988822025-03-21 10:42:3513 hrs ago1742553755IN
0xbeb0b062...A522F4ea6
0.005 ETH0.000024150.11142944
Settle Bebop Ble...9983622025-03-21 5:29:1119 hrs ago1742534951IN
0xbeb0b062...A522F4ea6
0 ETH0.000017820.101
Settle Bebop Ble...9983562025-03-21 5:25:3519 hrs ago1742534735IN
0xbeb0b062...A522F4ea6
0 ETH0.000016080.101
Settle Bebop Ble...9983542025-03-21 5:24:4719 hrs ago1742534687IN
0xbeb0b062...A522F4ea6
0 ETH0.000018570.101
Settle Bebop Ble...9983472025-03-21 5:21:3519 hrs ago1742534495IN
0xbeb0b062...A522F4ea6
0 ETH0.000016180.101
Settle Bebop Ble...9983412025-03-21 5:18:5919 hrs ago1742534339IN
0xbeb0b062...A522F4ea6
0 ETH0.000017910.101
Settle Bebop Ble...9983372025-03-21 5:16:1119 hrs ago1742534171IN
0xbeb0b062...A522F4ea6
0 ETH0.000016080.101
Settle9983212025-03-21 5:07:1119 hrs ago1742533631IN
0xbeb0b062...A522F4ea6
0 ETH0.00000320.0121485
Settle Bebop Ble...9983212025-03-21 5:07:1119 hrs ago1742533631IN
0xbeb0b062...A522F4ea6
0 ETH0.000019550.101
Settle9982962025-03-21 4:55:2319 hrs ago1742532923IN
0xbeb0b062...A522F4ea6
0.00020993 ETH0.000002470.01068367
Settle9980692025-03-21 2:45:5921 hrs ago1742525159IN
0xbeb0b062...A522F4ea6
0.0001 ETH0.000021430.1
Settle9980612025-03-21 2:40:5921 hrs ago1742524859IN
0xbeb0b062...A522F4ea6
0.000183 ETH0.000024480.1
Settle Bebop Ble...9980362025-03-21 2:26:1122 hrs ago1742523971IN
0xbeb0b062...A522F4ea6
0 ETH0.00001930.101
Settle9980302025-03-21 2:23:1122 hrs ago1742523791IN
0xbeb0b062...A522F4ea6
0.0104 ETH0.000023410.1
Settle Bebop Ble...9972592025-03-20 18:09:2330 hrs ago1742494163IN
0xbeb0b062...A522F4ea6
0 ETH0.000028960.101
Settle9971612025-03-20 16:56:2331 hrs ago1742489783IN
0xbeb0b062...A522F4ea6
0 ETH0.000007340.01966612
Settle Bebop Ble...9970502025-03-20 15:25:4733 hrs ago1742484347IN
0xbeb0b062...A522F4ea6
0 ETH0.00001920.101
Settle9970472025-03-20 15:22:4733 hrs ago1742484167IN
0xbeb0b062...A522F4ea6
0 ETH0.000004320.01367324
Settle9965302025-03-20 9:30:1139 hrs ago1742463011IN
0xbeb0b062...A522F4ea6
0 ETH0.000004170.01302162
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
10000492025-03-22 0:30:1140 secs ago1742603411
0xbeb0b062...A522F4ea6
0.011 ETH
10000322025-03-22 0:21:239 mins ago1742602883
0xbeb0b062...A522F4ea6
0.0102 ETH
9994012025-03-21 16:43:237 hrs ago1742575403
0xbeb0b062...A522F4ea6
0.00003 ETH
9993802025-03-21 16:27:478 hrs ago1742574467
0xbeb0b062...A522F4ea6
0.0000199 ETH
9988822025-03-21 10:42:3513 hrs ago1742553755
0xbeb0b062...A522F4ea6
0.005 ETH
9983212025-03-21 5:07:1119 hrs ago1742533631
0xbeb0b062...A522F4ea6
0.0002056 ETH
9983212025-03-21 5:07:1119 hrs ago1742533631
0xbeb0b062...A522F4ea6
0.0002056 ETH
9982962025-03-21 4:55:2319 hrs ago1742532923
0xbeb0b062...A522F4ea6
0.00020993 ETH
9980692025-03-21 2:45:5921 hrs ago1742525159
0xbeb0b062...A522F4ea6
0.0001 ETH
9980612025-03-21 2:40:5921 hrs ago1742524859
0xbeb0b062...A522F4ea6
0.000183 ETH
9980302025-03-21 2:23:1122 hrs ago1742523791
0xbeb0b062...A522F4ea6
0.0104 ETH
9965302025-03-20 9:30:1139 hrs ago1742463011
0xbeb0b062...A522F4ea6
0.00638212 ETH
9965302025-03-20 9:30:1139 hrs ago1742463011
0xbeb0b062...A522F4ea6
0.00638212 ETH
9964402025-03-20 8:37:5939 hrs ago1742459879
0xbeb0b062...A522F4ea6
0.00065868 ETH
9964402025-03-20 8:37:5939 hrs ago1742459879
0xbeb0b062...A522F4ea6
0.00065868 ETH
9962362025-03-20 6:42:1141 hrs ago1742452931
0xbeb0b062...A522F4ea6
0.01182988 ETH
9962362025-03-20 6:42:1141 hrs ago1742452931
0xbeb0b062...A522F4ea6
0.01182988 ETH
9948492025-03-19 15:36:352 days ago1742398595
0xbeb0b062...A522F4ea6
0.0446689 ETH
9948492025-03-19 15:36:352 days ago1742398595
0xbeb0b062...A522F4ea6
0.0446689 ETH
9947022025-03-19 13:51:112 days ago1742392271
0xbeb0b062...A522F4ea6
0.03175385 ETH
9947022025-03-19 13:51:112 days ago1742392271
0xbeb0b062...A522F4ea6
0.03175385 ETH
9946482025-03-19 13:11:112 days ago1742389871
0xbeb0b062...A522F4ea6
0.002 ETH
9946482025-03-19 13:11:112 days ago1742389871
0xbeb0b062...A522F4ea6
0.002 ETH
9945682025-03-19 12:25:232 days ago1742387123
0xbeb0b062...A522F4ea6
0.00487817 ETH
9945682025-03-19 12:25:232 days ago1742387123
0xbeb0b062...A522F4ea6
0.00487817 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
JamSettlement

Compiler Version
v0.8.27+commit.40a35a09

Optimization Enabled:
Yes with 1239 runs

Other Settings:
paris EvmVersion
File 1 of 22 : JamSettlement.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "./base/JamValidation.sol";
import "./base/JamTransfer.sol";
import "./interfaces/IJamSettlement.sol";
import "lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";

/// @title JamSettlement
/// @notice The settlement contract executes the full lifecycle of a trade on chain.
/// Solvers figure out what "interactions" to pass to this contract such that the user order is fulfilled.
/// The contract ensures that only the user agreed price can be executed and otherwise will fail to execute.
/// As long as the trade is fulfilled, the solver is allowed to keep any potential excess.
contract JamSettlement is IJamSettlement, ReentrancyGuard, JamValidation, JamTransfer {

    address public immutable bebopBlend;
    using BlendAggregateOrderLib for BlendAggregateOrder;
    using BlendMultiOrderLib for BlendMultiOrder;

    constructor(address _permit2, address _bebopBlend, address _treasuryAddress) JamPartner(_treasuryAddress) JamValidation(_permit2) {
        bebopBlend = _bebopBlend;
    }

    receive() external payable {}


    /// @inheritdoc IJamSettlement
    function settle(
        JamOrder calldata order,
        bytes calldata signature,
        JamInteraction.Data[] calldata interactions,
        bytes memory hooksData,
        address balanceRecipient
    ) external payable nonReentrant {
        JamHooks.Def memory hooks = hooksData.length != 0 ?
            abi.decode(hooksData, (JamHooks.Def)) : JamHooks.Def(new JamInteraction.Data[](0), new JamInteraction.Data[](0));
        bytes32 hooksHash = hooksData.length != 0 ? JamHooks.hash(hooks) : JamHooks.EMPTY_HOOKS_HASH;
        validateOrder(order, signature, hooksHash);
        if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){
            require(JamInteraction.runInteractionsM(hooks.beforeSettle, balanceManager), BeforeSettleHooksFailed());
        }
        if (order.usingPermit2) {
            balanceManager.transferTokensWithPermit2(order, signature, hooksHash, balanceRecipient);
        } else {
            balanceManager.transferTokens(order.sellTokens, order.sellAmounts, order.taker, balanceRecipient);
        }
        require(JamInteraction.runInteractions(interactions, balanceManager), InteractionsFailed());
        uint256[] memory buyAmounts = order.buyAmounts;
        transferTokensFromContract(order.buyTokens, order.buyAmounts, buyAmounts, order.receiver, order.partnerInfo, false);
        if (order.receiver == address(this)){
            require(!hasDuplicates(order.buyTokens), DuplicateTokens());
        }
        emit BebopJamOrderFilled(
            order.nonce, order.taker, order.sellTokens, order.buyTokens, order.sellAmounts, buyAmounts
        );
        if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){
            require(JamInteraction.runInteractionsM(hooks.afterSettle, balanceManager), AfterSettleHooksFailed());
        }
    }


    /// @inheritdoc IJamSettlement
    function settleInternal(
        JamOrder calldata order,
        bytes calldata signature,
        uint256[] calldata filledAmounts,
        bytes memory hooksData
    ) external payable nonReentrant {
        JamHooks.Def memory hooks = hooksData.length != 0 ?
            abi.decode(hooksData, (JamHooks.Def)) : JamHooks.Def(new JamInteraction.Data[](0),new JamInteraction.Data[](0));
        bytes32 hooksHash = hooksData.length != 0 ? JamHooks.hash(hooks) : JamHooks.EMPTY_HOOKS_HASH;
        validateOrder(order, signature, hooksHash);
        if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){
            require(JamInteraction.runInteractionsM(hooks.beforeSettle, balanceManager), BeforeSettleHooksFailed());
        }
        if (order.usingPermit2) {
            balanceManager.transferTokensWithPermit2(order, signature, hooksHash, msg.sender);
        } else {
            balanceManager.transferTokens(order.sellTokens, order.sellAmounts, order.taker, msg.sender);
        }
        if (order.partnerInfo == 0){
            uint256[] calldata buyAmounts = validateFilledAmounts(filledAmounts, order.buyAmounts);
            balanceManager.transferTokens(order.buyTokens, buyAmounts, msg.sender, order.receiver);
            emit BebopJamOrderFilled(order.nonce, order.taker, order.sellTokens, order.buyTokens, order.sellAmounts, buyAmounts);
        } else {
            (
                uint256[] memory buyAmounts, uint256[] memory protocolFees, uint256[] memory partnerFees, address partner
            ) = getUpdatedAmountsAndFees(filledAmounts, order.buyAmounts, order.partnerInfo);
            balanceManager.transferTokens(order.buyTokens, buyAmounts, msg.sender, order.receiver);
            if (protocolFees.length != 0){
                balanceManager.transferTokens(order.buyTokens, protocolFees, msg.sender, protocolFeeAddress);
            }
            if (partnerFees.length != 0){
                balanceManager.transferTokens(order.buyTokens, partnerFees, msg.sender, partner);
            }
            emit BebopJamOrderFilled(order.nonce, order.taker, order.sellTokens, order.buyTokens, order.sellAmounts, buyAmounts);
        }
        if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){
            require(JamInteraction.runInteractionsM(hooks.afterSettle, balanceManager), AfterSettleHooksFailed());
        }
    }


    /// @inheritdoc IJamSettlement
    function settleBatch(
        JamOrder[] calldata orders,
        bytes[] calldata signatures,
        JamInteraction.Data[] calldata interactions,
        JamHooks.Def[] calldata hooks,
        address balanceRecipient
    ) external payable nonReentrant {
        validateBatchOrders(orders, hooks, signatures);
        bool executeHooks = hooks.length != 0;
        for (uint i; i < orders.length; ++i) {
            if (executeHooks){
                require(JamInteraction.runInteractions(hooks[i].beforeSettle, balanceManager), BeforeSettleHooksFailed());
            }
            if (orders[i].usingPermit2) {
                balanceManager.transferTokensWithPermit2(
                    orders[i], signatures[i], executeHooks ? JamHooks.hash(hooks[i]) : JamHooks.EMPTY_HOOKS_HASH, balanceRecipient
                );
            } else {
                balanceManager.transferTokens(orders[i].sellTokens, orders[i].sellAmounts, orders[i].taker, balanceRecipient);
            }
        }
        require(JamInteraction.runInteractions(interactions, balanceManager), InteractionsFailed());
        for (uint i; i < orders.length; ++i) {
            uint256[] memory buyAmounts = calculateNewAmounts(i, orders);
            transferTokensFromContract(
                orders[i].buyTokens, orders[i].buyAmounts, buyAmounts, orders[i].receiver, orders[i].partnerInfo, true
            );
            emit BebopJamOrderFilled(
                orders[i].nonce, orders[i].taker, orders[i].sellTokens, orders[i].buyTokens, orders[i].sellAmounts, buyAmounts
            );
            if (executeHooks){
                require(JamInteraction.runInteractions(hooks[i].afterSettle, balanceManager), AfterSettleHooksFailed());
            }
        }
    }


    /// @inheritdoc IJamSettlement
    function settleBebopBlend(
        address takerAddress,
        IBebopBlend.BlendOrderType orderType,
        bytes memory data,
        bytes memory hooksData
    ) external payable nonReentrant {
        JamHooks.Def memory hooks = hooksData.length != 0 ?
            abi.decode(hooksData, (JamHooks.Def)) : JamHooks.Def(new JamInteraction.Data[](0),new JamInteraction.Data[](0));
        bytes32 hooksHash = hooksData.length != 0 ? JamHooks.hash(hooks) : JamHooks.EMPTY_HOOKS_HASH;
        if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){
            require(JamInteraction.runInteractionsM(hooks.beforeSettle, balanceManager), BeforeSettleHooksFailed());
        }
        if (orderType == IBebopBlend.BlendOrderType.Single){
            (
                BlendSingleOrder memory order,
                IBebopBlend.MakerSignature memory makerSignature,
                IBebopBlend.OldSingleQuote memory takerQuoteInfo,
                address makerAddress,
                uint256 newFlags,
                bytes memory takerSignature
            ) = abi.decode(data, (BlendSingleOrder, IBebopBlend.MakerSignature, IBebopBlend.OldSingleQuote, address, uint256, bytes));
            balanceManager.transferTokenForBlendSingleOrder(order, takerQuoteInfo, takerSignature, takerAddress, hooksHash);
            order.maker_address = makerAddress;
            if (newFlags != 0){
                require(uint64(order.flags >> 64) == uint64(newFlags >> 64), InvalidBlendPartnerId());
                order.flags = newFlags;
            }
            approveToken(IERC20(order.taker_token), order.taker_amount, bebopBlend);
            IBebopBlend(bebopBlend).settleSingle(order, makerSignature, 0, takerQuoteInfo, "0x");
            emit BebopBlendSingleOrderFilled(
                uint128(order.flags >> 128), order.receiver, order.taker_token,
                (order.packed_commands & 0x02) != 0 ? JamOrderLib.NATIVE_TOKEN : order.maker_token, order.taker_amount,
                takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmount : order.maker_amount
            );
        } else if (orderType == IBebopBlend.BlendOrderType.Multi){
            (
                BlendMultiOrder memory order,
                IBebopBlend.MakerSignature memory makerSignature,
                IBebopBlend.OldMultiQuote memory takerQuoteInfo,
                address makerAddress,
                uint256 newFlags,
                bytes memory takerSignature
            ) = abi.decode(data, (BlendMultiOrder, IBebopBlend.MakerSignature, IBebopBlend.OldMultiQuote, address, uint256, bytes));
            balanceManager.transferTokensForMultiBebopOrder(order, takerQuoteInfo, takerSignature, takerAddress, hooksHash);
            order.maker_address = makerAddress;
            if (newFlags != 0){
                require(uint64(order.flags >> 64) == uint64(newFlags >> 64), InvalidBlendPartnerId());
                order.flags = newFlags;
            }
            for (uint i; i < order.taker_tokens.length; ++i) {
                approveToken(IERC20(order.taker_tokens[i]), order.taker_amounts[i], bebopBlend);
            }
            IBebopBlend(bebopBlend).settleMulti(order, makerSignature, 0, takerQuoteInfo, "0x");
            emit BebopBlendMultiOrderFilled(
                uint128(order.flags >> 128), order.receiver, order.taker_tokens, order.getMakerTokens(), order.taker_amounts,
                takerQuoteInfo.useOldAmount ? takerQuoteInfo.makerAmounts : order.maker_amounts
            );
        } else if (orderType == IBebopBlend.BlendOrderType.Aggregate){
            (
                BlendAggregateOrder memory order,
                IBebopBlend.MakerSignature[] memory makerSignatures,
                IBebopBlend.OldAggregateQuote memory takerQuoteInfo,
                uint256 newFlags,
                bytes memory takerSignature
            ) = abi.decode(data, (BlendAggregateOrder, IBebopBlend.MakerSignature[], IBebopBlend.OldAggregateQuote, uint256, bytes));
            balanceManager.transferTokensForAggregateBebopOrder(order, takerQuoteInfo, takerSignature, takerAddress, hooksHash);
            if (newFlags != 0){
                require(uint64(order.flags >> 64) == uint64(newFlags >> 64), InvalidBlendPartnerId());
                order.flags = newFlags;
            }
            (address[] memory tokens, uint256[] memory amounts) = order.unpackTokensAndAmounts(true, takerQuoteInfo);
            for (uint i; i < tokens.length; ++i) {
                approveToken(IERC20(tokens[i]), amounts[i], bebopBlend);
            }
            IBebopBlend(bebopBlend).settleAggregate(order, makerSignatures, 0, takerQuoteInfo, "0x");
            (address[] memory buyTokens, uint256[] memory buyAmounts) = order.unpackTokensAndAmounts(false, takerQuoteInfo);
            emit BebopBlendAggregateOrderFilled(
                uint128(order.flags >> 128), order.receiver, tokens, buyTokens, amounts, buyAmounts
            );
        } else {
            revert InvalidBlendOrderType();
        }
        if (hooksHash != JamHooks.EMPTY_HOOKS_HASH){
            require(JamInteraction.runInteractionsM(hooks.afterSettle, balanceManager), AfterSettleHooksFailed());
        }
    }

}

File 2 of 22 : IERC1271.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

File 3 of 22 : IERC5267.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.20;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

File 4 of 22 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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);
}

File 5 of 22 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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;
    }
}

File 6 of 22 : Errors.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;


/// @notice Thrown when solver sends less than expected to settlement contract
error InvalidOutputBalance(address token, uint256 expected, uint256 actual);

/// @notice Thrown when sending ETH via call fails
error FailedToSendEth();

/// @notice Thrown when the passed in signature is not a valid length
error InvalidSignatureLength();

/// @notice Thrown when the recovered signer is equal to the zero address
error InvalidSignature();

/// @notice Thrown when the recovered signer does not equal the claimedSigner
error InvalidSigner();

/// @notice Thrown when the recovered contract signature is incorrect
error InvalidContractSignature();

/// @notice Thrown when msg.sender is not allowed to call a function
error InvalidExecutor();

/// @notice Thrown when length of sell tokens and sell amounts are not equal
error SellTokensInvalidLength();

/// @notice Thrown when length of buy tokens and buy amounts are not equal
error BuyTokensInvalidLength();

/// @notice Thrown when order is expired
error OrderExpired();

/// @notice Thrown when nonce is already invalidated
error InvalidNonce();

/// @notice Thrown when nonce is zero
error ZeroNonce();

/// @notice Thrown when length of filled amounts is not equal to tokens length
error InvalidFilledAmountsLength();

/// @notice Thrown when filled amounts is less than previous amount
error InvalidFilledAmounts(uint256 expected, uint256 actual);

/// @notice Thrown when length of signatures array is not equal to batch length
error InvalidBatchSignaturesLength();

/// @notice Thrown when length of hooks array is not equal to batch length
error InvalidBatchHooksLength();

/// @notice Thrown when one of the orders in batch has settlement contract as receiver
error InvalidReceiverInBatch();

/// @notice Thrown when different fees are passed in batch
error DifferentFeesInBatch();

/// @notice Thrown when invalid partner address is passed
error InvalidPartnerAddress();

/// @notice Thrown when caller is not settlement contract
error InvalidCaller();

/// @notice Thrown when interactions failed
error InteractionsFailed();

/// @notice Thrown when beforeSettle hooks failed
error BeforeSettleHooksFailed();

/// @notice Thrown when beforeSettle hooks failed
error AfterSettleHooksFailed();

/// @notice Thrown for unknown blend order type
error InvalidBlendOrderType();

/// @notice Thrown when invalid fee percentage is passed
error InvalidFeePercentage();

/// @notice Thrown when interactions contain call to balance manager
error CallToBalanceManagerNotAllowed();

/// @notice Thrown when there are duplicate buy tokens in the order
error DuplicateTokens();

/// @notice Thrown when new partner-id is different from the current one
error InvalidBlendPartnerId();

File 7 of 22 : JamPartner.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../base/Errors.sol";
import "../libraries/JamOrder.sol";
import "../external-libs/SafeTransferLib.sol";

/// @title JamPartner
abstract contract JamPartner {

    uint16 internal constant HUNDRED_PERCENT = 10000;  // 100% in bps
    address internal immutable protocolFeeAddress;

    event NativeTransfer(address indexed receiver, uint256 amount);
    using SafeTransferLib for IERC20;

    constructor(address _protocolFeeAddress){
        protocolFeeAddress = _protocolFeeAddress;
    }

    /// @notice Distribute fees to the partner and protocol, fees are optional
    /// @param partnerInfo The partner info, packed with the partner address, partner fee and protocol fee
    /// @param token The token to distribute fees in
    /// @param amount Token amount in order to distribute fees from
    /// @return totalFeesSent The total amount of tokens sent as fees
    function distributeFees(uint256 partnerInfo, address token, uint256 amount) internal returns (uint256 totalFeesSent){
        (address partnerAddress, uint16 partnerFee, uint16 protocolFee) = unpackPartnerInfo(partnerInfo);
        if (partnerFee > 0) {
            totalFeesSent += sendPartnerFee(token, amount, partnerFee, partnerAddress);
        }
        if (protocolFee > 0) {
            totalFeesSent += sendPartnerFee(token, amount, protocolFee, protocolFeeAddress);
        }
        return totalFeesSent;
    }

    /// @notice Unpack the partner info
    /// @param partnerInfo Packed info: [ .... | address | uint16 | uint16 ]
    function unpackPartnerInfo(uint256 partnerInfo) private pure returns (address, uint16, uint16) {
        uint16 protocolFeeBps = uint16(partnerInfo & 0xFFFF);
        uint16 partnerFeeBps = uint16((partnerInfo >> 16) & 0xFFFF);
        address partnerAddress = address(uint160(partnerInfo >> 32));
        require(partnerFeeBps + protocolFeeBps < HUNDRED_PERCENT, InvalidFeePercentage());
        require(partnerFeeBps > 0 || (partnerFeeBps == 0 && partnerAddress == address(0)), InvalidPartnerAddress());
        return (partnerAddress, partnerFeeBps, protocolFeeBps);
    }

    /// @notice Send the partner fee
    /// @param token The token to send
    /// @param amount The amount to send
    /// @param fee The fee percentage
    /// @param receiver The receiver of the fee
    /// @return feeAmount The amount of fee sent
    function sendPartnerFee(address token, uint256 amount, uint16 fee, address receiver) private returns (uint256){
        uint256 feeAmount = amount * fee / HUNDRED_PERCENT;
        if (token == JamOrderLib.NATIVE_TOKEN) {
            (bool sent, ) = payable(receiver).call{value: feeAmount}("");
            require(sent, FailedToSendEth());
            emit NativeTransfer(receiver, feeAmount);
        } else {
            IERC20(token).safeTransfer(receiver, feeAmount);
        }
        return feeAmount;
    }

    /// @notice Get total fees in bps
    /// @param partnerInfo The partner info
    /// @return totalFeesBps The total fees in bps
    function getTotalFeesBps(uint256 partnerInfo) internal pure returns (uint16){
        uint16 protocolFeeBps = uint16(partnerInfo & 0xFFFF);
        uint16 partnerFeeBps = uint16((partnerInfo >> 16) & 0xFFFF);
        return protocolFeeBps + partnerFeeBps;
    }

    /// @notice Get arrays with fees amounts for each token
    /// @param amounts The amounts to calculate fees for
    /// @param minAmounts Minimum amounts that user signed for
    /// @param partnerInfo The partner info
    /// @return newAmounts The new amounts after fees
    /// @return protocolFees The protocol fees, if empty then no protocol fees
    /// @return partnerFees The partner fees, if empty then no partner fees
    /// @return partnerAddress The partner address, or zero address if no partner fees
    function getUpdatedAmountsAndFees(
        uint256[] calldata amounts, uint256[] calldata minAmounts, uint256 partnerInfo
    ) internal pure returns (uint256[] memory newAmounts, uint256[] memory protocolFees, uint256[] memory partnerFees, address) {
        (address partnerAddress, uint16 partnerFee, uint16 protocolFee) = unpackPartnerInfo(partnerInfo);
        uint tokensLength = amounts.length;
        require(minAmounts.length == tokensLength, InvalidFilledAmountsLength());
        newAmounts = new uint256[](tokensLength);
        if (protocolFee > 0) {
            protocolFees = new uint256[](tokensLength);
            for (uint256 i; i < tokensLength; ++i) {
                protocolFees[i] = amounts[i] * protocolFee / HUNDRED_PERCENT;
                newAmounts[i] = amounts[i] - protocolFees[i];
            }
        }
        if (partnerFee > 0) {
            partnerFees = new uint256[](tokensLength);
            for (uint256 i; i < tokensLength; ++i) {
                partnerFees[i] = amounts[i] * partnerFee / HUNDRED_PERCENT;
                newAmounts[i] = newAmounts[i] == 0 ? amounts[i] - partnerFees[i] : newAmounts[i] - partnerFees[i];
            }
        }
        for (uint256 i; i < tokensLength; ++i) {
            require(newAmounts[i] >= minAmounts[i], InvalidFilledAmounts(minAmounts[i], newAmounts[i]));
        }
        return (newAmounts, protocolFees, partnerFees, partnerAddress);
    }

}

File 8 of 22 : JamTransfer.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "./JamPartner.sol";

/// @title JamTransfer
/// @notice Functions for transferring tokens from SettlementContract
abstract contract JamTransfer is JamPartner {

    using SafeTransferLib for IERC20;

    /// @dev Check if token is approved for spender, max approve if not
    /// max approval is fine for settlement contract, because we use BalanceManager for users approvals
    /// @param token token's address
    /// @param amount transfer amount
    /// @param spender spender's address, in our case it will BebopBlend contract
    function approveToken(IERC20 token, uint256 amount, address spender) internal {
        uint256 allowance = token.allowance(address(this), spender);
        if (allowance < amount) {
            token.safeApproveWithRetry(spender, type(uint256).max);
        }
    }

    /// @dev After solver settlement, transfer tokens from this contract to receiver
    /// @param tokens tokens' addresses
    /// @param minAmounts minimum amounts from order
    /// @param amounts tokens' filled amounts
    /// @param receiver address
    /// @param transferExactAmounts if true, transfer exact amounts, otherwise transfer full tokens balance
    function transferTokensFromContract(
        address[] calldata tokens,
        uint256[] calldata minAmounts,
        uint256[] memory amounts,
        address receiver,
        uint256 partnerInfo,
        bool transferExactAmounts
    ) internal {
        for (uint i; i < tokens.length; ++i) {
            if (!transferExactAmounts) {
                amounts[i] = tokens[i] == JamOrderLib.NATIVE_TOKEN ?
                    address(this).balance : IERC20(tokens[i]).balanceOf(address(this));
            }
            if (partnerInfo != 0){
                amounts[i] -= distributeFees(partnerInfo, tokens[i], amounts[i]);
            }
            require(amounts[i] >= minAmounts[i], InvalidOutputBalance(tokens[i], minAmounts[i], amounts[i]));
            if (tokens[i] == JamOrderLib.NATIVE_TOKEN) {
                (bool sent, ) = payable(receiver).call{value: amounts[i]}("");
                require(sent, FailedToSendEth());
                emit NativeTransfer(receiver, amounts[i]);
            } else {
                IERC20(tokens[i]).safeTransfer(receiver, amounts[i]);
            }
        }
    }

    /// @dev Transfer native tokens to receiver from this contract
    /// @param receiver address
    /// @param amount amount of native tokens
    function transferNativeFromContract(address receiver, uint256 amount) public {
        (bool sent, ) = payable(receiver).call{value: amount}("");
        require(sent, FailedToSendEth());
    }

    /// @dev Calculate new amounts of tokens if solver transferred excess to contract during settleBatch
    /// @param curInd index of current order
    /// @param orders array of orders
    /// @return array of new amounts
    function calculateNewAmounts(uint256 curInd, JamOrder[] calldata orders) internal view returns (uint256[] memory) {
        JamOrder calldata curOrder = orders[curInd];
        uint256[] memory newAmounts = new uint256[](curOrder.buyTokens.length);
        for (uint i; i < curOrder.buyTokens.length; ++i) {
            uint256 fullAmount;
            for (uint j = curInd; j < orders.length; ++j) {
                for (uint k; k < orders[j].buyTokens.length; ++k) {
                    if (orders[j].buyTokens[k] == curOrder.buyTokens[i]) {
                        fullAmount += orders[j].buyAmounts[k];
                        require(
                            getTotalFeesBps(curOrder.partnerInfo) == getTotalFeesBps(orders[j].partnerInfo),
                            DifferentFeesInBatch()
                        );
                    }
                }
            }
            uint256 tokenBalance = curOrder.buyTokens[i] == JamOrderLib.NATIVE_TOKEN ?
                address(this).balance : IERC20(curOrder.buyTokens[i]).balanceOf(address(this));
            // if at least two takers buy same token, we need to divide the whole tokenBalance among them.
            // for edge case with newAmounts[i] overflow, solver shouldn't submit txs in a batch
            newAmounts[i] = tokenBalance * curOrder.buyAmounts[i] / fullAmount;
            if (newAmounts[i] < curOrder.buyAmounts[i]) {
                newAmounts[i] = curOrder.buyAmounts[i];
            }
        }
        return newAmounts;
    }
}

File 9 of 22 : JamValidation.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../base/Errors.sol";
import "../libraries/JamOrder.sol";
import "../libraries/JamHooks.sol";
import "../JamBalanceManager.sol";
import "lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol";
import "lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol";

/// @title JamValidation
/// @notice Functions which handles the signing and validation of Jam orders
abstract contract JamValidation is IERC5267 {
    mapping(address => mapping(uint256 => uint256)) private standardNonces;
    mapping(address => mapping(uint256 => uint256)) private limitOrdersNonces;
    uint256 private constant INF_EXPIRY = 9999999999; // expiry for limit orders

    string public constant DOMAIN_NAME = "JamSettlement";
    string public constant DOMAIN_VERSION = "2";
    bytes32 private constant UPPER_BIT_MASK = (0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
    bytes4 private constant EIP1271_MAGICVALUE = bytes4(keccak256("isValidSignature(bytes32,bytes)"));
    bytes32 public constant EIP712_DOMAIN_TYPEHASH = keccak256(abi.encodePacked(
        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
    ));

    IJamBalanceManager public immutable balanceManager;
    IPermit2 private immutable PERMIT2;
    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
    uint256 private immutable _CACHED_CHAIN_ID;
    using JamOrderLib for JamOrder;

    constructor(address _permit2){
        balanceManager = new JamBalanceManager(address(this), _permit2);
        _CACHED_CHAIN_ID = block.chainid;
        _CACHED_DOMAIN_SEPARATOR = keccak256(
            abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256(bytes(DOMAIN_NAME)), keccak256(bytes(DOMAIN_VERSION)), block.chainid, address(this))
        );
        PERMIT2 = IPermit2(_permit2);
    }

    /// @notice The domain separator used in the order validation signature
    /// @return The domain separator used in encoding of order signature
    function DOMAIN_SEPARATOR() public view returns (bytes32) {
        return block.chainid == _CACHED_CHAIN_ID
            ? _CACHED_DOMAIN_SEPARATOR
            : keccak256(
                abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256(bytes(DOMAIN_NAME)), keccak256(bytes(DOMAIN_VERSION)), block.chainid, address(this))
            );
    }

    /// @notice ERC5267 implementation for requesting the EIP712 domain values
    function eip712Domain() public view returns (
        bytes1 fields, string memory name, string memory version, uint256 chainId,
        address verifyingContract, bytes32 salt, uint256[] memory extensions
    ){
        return (hex"0f", DOMAIN_NAME, DOMAIN_VERSION, block.chainid, address(this), bytes32(0), new uint256[](0));
    }

    /// @notice Validate the order signature
    /// @param validationAddress The address to validate the signature against
    /// @param hash The hash of the order
    /// @param signature The signature to validate
    function validateSignature(address validationAddress, bytes32 hash, bytes calldata signature) public view {
        bytes32 r;
        bytes32 s;
        uint8 v;
        if (validationAddress.code.length == 0) {
            if (signature.length == 65) {
                (r, s) = abi.decode(signature, (bytes32, bytes32));
                v = uint8(signature[64]);
            } else if (signature.length == 64) {
                // EIP-2098
                bytes32 vs;
                (r, vs) = abi.decode(signature, (bytes32, bytes32));
                s = vs & UPPER_BIT_MASK;
                v = uint8(uint256(vs >> 255)) + 27;
            } else {
                revert InvalidSignatureLength();
            }
            address signer = ecrecover(hash, v, r, s);
            if (signer == address(0)) revert InvalidSignature();
            if (signer != validationAddress) revert InvalidSigner();
        } else {
            bytes4 magicValue = IERC1271(validationAddress).isValidSignature(hash, signature);
            if (magicValue != EIP1271_MAGICVALUE) revert InvalidContractSignature();
        }
    }

    /// @notice Hash hooks and return the hash
    /// @param hooks The hooks to hash
    function hashHooks(JamHooks.Def calldata hooks) external pure returns (bytes32) {
        return JamHooks.hash(hooks);
    }

    /// @notice Hash Jam order and return the hash
    /// @param order The order to hash
    /// @param hooksHash The hash of the hooks to include in the order hash, 0x000..00 if no hooks
    function hashJamOrder(JamOrder calldata order, bytes32 hooksHash) external view returns (bytes32) {
        if (order.usingPermit2){
            return keccak256(abi.encodePacked(
                "\x19\x01", PERMIT2.DOMAIN_SEPARATOR(), order.permit2OrderHash(hooksHash, address(balanceManager))
            ));
        } else {
            return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), order.hash(hooksHash)));
        }
    }

    /// @notice Cancel limit order by invalidating nonce for the sender address
    /// @param nonce The nonce to invalidate
    function cancelLimitOrder(uint256 nonce) external {
        invalidateOrderNonce(msg.sender, nonce, true);
    }

    /// @notice Check if taker's limit order nonce is valid
    /// @param taker address
    /// @param nonce to check
    /// @return True if nonce is valid
    function isLimitOrderNonceValid(address taker, uint256 nonce) external view returns (bool) {
        uint256 invalidatorSlot = nonce >> 8;
        uint256 invalidatorBit = 1 << (nonce & 0xff);
        return (limitOrdersNonces[taker][invalidatorSlot] & invalidatorBit) == 0;
    }

    /// @notice Validate order data and in case of standard approvals validate the signature
    /// @param order The order to validate
    /// @param signature The signature to validate
    /// @param hooksHash The hash of the hooks to include in the order hash
    function validateOrder(JamOrder calldata order, bytes calldata signature, bytes32 hooksHash) internal {
        // Allow settle from user without sig; For permit2 case, we already validated witness during the transfer
        if (order.taker != msg.sender && !order.usingPermit2) {
            bytes32 orderHash = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), order.hash(hooksHash)));
            validateSignature(order.taker, orderHash, signature);
        }
        if (!order.usingPermit2 || order.expiry == INF_EXPIRY){
            invalidateOrderNonce(order.taker, order.nonce, order.expiry == INF_EXPIRY);
        }
        require(
            order.executor == msg.sender || order.executor == address(0) || block.timestamp > order.exclusivityDeadline,
            InvalidExecutor()
        );
        require(order.buyTokens.length == order.buyAmounts.length, BuyTokensInvalidLength());
        require(order.sellTokens.length == order.sellAmounts.length, SellTokensInvalidLength());
        require(block.timestamp < order.expiry, OrderExpired());
    }

    /// @notice Check if nonce is valid and invalidate it
    /// @param taker address
    /// @param nonce The nonce to invalidate
    /// @param isLimitOrder True if it is a limit order
    function invalidateOrderNonce(address taker, uint256 nonce, bool isLimitOrder) private {
        require(nonce != 0, ZeroNonce());
        uint256 invalidatorSlot = nonce >> 8;
        uint256 invalidatorBit = 1 << (nonce & 0xff);
        mapping(uint256 => uint256) storage invalidNonces = isLimitOrder ? limitOrdersNonces[taker] : standardNonces[taker];
        uint256 invalidator = invalidNonces[invalidatorSlot];
        require(invalidator & invalidatorBit != invalidatorBit, InvalidNonce());
        invalidNonces[invalidatorSlot] = invalidator | invalidatorBit;
    }

    /// @notice validate if filled amounts are more than initial amounts that user signed
    /// @param filledAmounts The increased amounts to validate (if empty, return initial amounts)
    /// @param initialAmounts The initial amounts to validate against
    /// @return The filled amounts if exist, otherwise the initial amounts
    function validateFilledAmounts(
        uint256[] calldata filledAmounts, uint256[] calldata initialAmounts
    ) internal pure returns (uint256[] calldata){
        if (filledAmounts.length == 0) {
            return initialAmounts;
        }
        require(filledAmounts.length == initialAmounts.length, InvalidFilledAmountsLength());
        for (uint256 i; i < filledAmounts.length; ++i) {
            require(filledAmounts[i] >= initialAmounts[i], InvalidFilledAmounts(initialAmounts[i], filledAmounts[i]));
        }
        return filledAmounts;
    }

    /// @notice Validate batch data and all orders in a batch
    /// @param orders The orders to validate
    /// @param hooks The array of hooks corresponding to each order, or empty array if no hooks
    /// @param signatures The signatures corresponding to each order
    function validateBatchOrders(
        JamOrder[] calldata orders, JamHooks.Def[] calldata hooks, bytes[] calldata signatures
    ) internal {
        bool noHooks = hooks.length == 0;
        require(orders.length == signatures.length, InvalidBatchSignaturesLength());
        require(orders.length == hooks.length || noHooks, InvalidBatchHooksLength());
        for (uint i; i < orders.length; ++i) {
            require(orders[i].receiver != address(this), InvalidReceiverInBatch());
            validateOrder(orders[i], signatures[i], noHooks ? JamHooks.EMPTY_HOOKS_HASH : JamHooks.hash(hooks[i]));
        }
    }

    /// @notice Check if there are any duplicates in the array of tokens
    /// @param tokens The array of tokens to validate
    /// @return True if there are duplicates
    function hasDuplicates(address[] calldata tokens) internal pure returns (bool) {
        for (uint i; i < tokens.length - 1; ++i) {
            for (uint j = i + 1; j < tokens.length; ++j) {
                if (tokens[i] == tokens[j]) {
                    return true;
                }
            }
        }
        return false;
    }
}

File 10 of 22 : PermitHash.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../interfaces/IPermit2.sol";

// from PermitHash.sol in Permit2
// https://github.com/Uniswap/permit2/blob/main/src/libraries/PermitHash.sol
library PermitHash {

    bytes32 private constant _TOKEN_PERMISSIONS_TYPEHASH = keccak256("TokenPermissions(address token,uint256 amount)");

    string private constant _PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB = "PermitBatchWitnessTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline,";

    function hashWithWitness(
        IPermit2.PermitBatchTransferFrom memory permit,
        bytes32 witness,
        string memory witnessTypeString,
        address spender
    ) internal pure returns (bytes32) {
        bytes32 typeHash = keccak256(abi.encodePacked(_PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB, witnessTypeString));

        uint256 numPermitted = permit.permitted.length;
        bytes32[] memory tokenPermissionHashes = new bytes32[](numPermitted);

        for (uint256 i = 0; i < numPermitted; ++i) {
            tokenPermissionHashes[i] = _hashTokenPermissions(permit.permitted[i]);
        }

        return keccak256(
            abi.encode(
                typeHash,
                keccak256(abi.encodePacked(tokenPermissionHashes)),
                spender,
                permit.nonce,
                permit.deadline,
                witness
            )
        );
    }

    function _hashTokenPermissions(IPermit2.TokenPermissions memory permitted) private pure returns (bytes32){
        return keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, permitted));
    }
}

File 11 of 22 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {IERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

/// @notice Safe ERC20 transfer library that gracefully handles missing return values.
/// From: Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// https://github.com/Vectorized/solady/blob/main/src/utils/SafeTransferLib.sol

library SafeTransferLib {


    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }


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


}

File 12 of 22 : IBebopBlend.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "../libraries/BlendSingleOrder.sol";
import "../libraries/BlendMultiOrder.sol";
import "../libraries/BlendAggregateOrder.sol";

/// @title IBebopBlend is interface for interacting with BebopBlend contract, which aggregates PMM liquidity.
/// Swaps through that contract have zero slippage.
/// Deployed on 0xbbbbbBB520d69a9775E85b458C58c648259FAD5F
interface IBebopBlend {

    enum BlendOrderType {
        Single, // 0
        Multi, // 1
        Aggregate // 2
    }

    struct OldSingleQuote {
        bool useOldAmount;
        uint256 makerAmount;
        uint256 makerNonce;
    }

    struct OldMultiQuote {
        bool useOldAmount;
        uint256[] makerAmounts;
        uint256 makerNonce;
    }

    struct OldAggregateQuote {
        bool useOldAmount;
        uint256[][] makerAmounts;
        uint256[] makerNonces;
    }

    struct MakerSignature {
        bytes signatureBytes;
        uint256 flags;
    }


    /// @notice Maker execution of one-to-one trade with one maker
    /// @param order Single order struct
    /// @param makerSignature Maker's signature for SingleOrder
    /// @param filledTakerAmount Partially filled taker amount, 0 for full fill
    /// @param takerQuoteInfo If maker_amount has improved then it contains old quote values that taker signed,
    ///                       otherwise it contains same values as in order
    /// @param takerSignature Taker's signature to approve executing order by maker,
    ///        if taker executes order himself then signature can be '0x' (recommended to use swapSingle for this case)
    function settleSingle(
        BlendSingleOrder calldata order,
        MakerSignature calldata makerSignature,
        uint256 filledTakerAmount,
        OldSingleQuote calldata takerQuoteInfo,
        bytes calldata takerSignature
    ) external payable;

    /// @notice Maker execution of one-to-many or many-to-one trade with one maker
    /// @param order Multi order struct
    /// @param makerSignature Maker's signature for MultiOrder
    /// @param filledTakerAmount Partially filled taker amount, 0 for full fill. Many-to-one doesnt support partial fill
    /// @param takerQuoteInfo If maker_amounts have improved then it contains old quote values that taker signed,
    ///                       otherwise it contains same values as in order
    /// @param takerSignature Taker's signature to approve executing order by maker,
    ///        if taker executes order himself then signature can be '0x' (recommended to use swapMulti for this case)
    function settleMulti(
        BlendMultiOrder calldata order,
        MakerSignature calldata makerSignature,
        uint256 filledTakerAmount,
        OldMultiQuote calldata takerQuoteInfo,
        bytes calldata takerSignature
    ) external payable;

    /// @notice Maker execution of any trade with multiple makers
    /// @param order Aggregate order struct
    /// @param makersSignatures Makers signatures for MultiOrder (can be contructed as part of current AggregateOrder)
    /// @param filledTakerAmount Partially filled taker amount, 0 for full fill. Many-to-one doesnt support partial fill
    /// @param takerQuoteInfo If maker_amounts have improved then it contains old quote values that taker signed,
    ///                       otherwise it contains same values as in order
    /// @param takerSignature Taker's signature to approve executing order by maker,
    ///      if taker executes order himself then signature can be '0x' (recommended to use swapAggregate for this case)
    function settleAggregate(
        BlendAggregateOrder calldata order,
        MakerSignature[] calldata makersSignatures,
        uint256 filledTakerAmount,
        OldAggregateQuote calldata takerQuoteInfo,
        bytes calldata takerSignature
    ) external payable;
}

File 13 of 22 : IJamBalanceManager.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../libraries/JamOrder.sol";
import "../libraries/BlendSingleOrder.sol";
import "../libraries/BlendMultiOrder.sol";
import "../libraries/BlendAggregateOrder.sol";
import "./IBebopBlend.sol";

/// @title IJamBalanceManager
/// @notice User approvals are made here. This handles the complexity of multiple allowance types. 
interface IJamBalanceManager {

    /// @dev Transfer user's tokens to receiver address for JamOrder
    /// @param order user signed order
    /// @param signature permit2 signature with order as witness
    /// @param hooksHash hash of hooks data
    /// @param receiver address to receive tokens, it can be operator address or solver address
    function transferTokensWithPermit2(
        JamOrder calldata order,
        bytes calldata signature,
        bytes32 hooksHash,
        address receiver
    ) external;

    /// @dev Transfer tokens to receiver address
    /// this function can be used not only for user's tokens, but also for maker's tokens in settleInternal
    /// @param tokens list of tokens to transfer
    /// @param amounts list of amounts to transfer
    /// @param sender address to transfer tokens from
    /// @param receiver address to transfer tokens to
    function transferTokens(
        address[] calldata tokens,
        uint256[] calldata amounts,
        address sender,
        address receiver
    ) external;

    /// @dev Transfer user's tokens to operator address for BlendSingleOrder
    /// @param order user signed order
    /// @param oldSingleQuote in case of amounts improvement, old quote is used to get old amounts signed by user
    /// @param takerSignature permit2 signature with order as witness
    /// @param takerAddress user address
    /// @param hooksHash hash of hooks data
    function transferTokenForBlendSingleOrder(
        BlendSingleOrder memory order,
        IBebopBlend.OldSingleQuote memory oldSingleQuote,
        bytes memory takerSignature,
        address takerAddress,
        bytes32 hooksHash
    ) external;

    /// @dev Transfer user's tokens to operator address for BlendMultiOrder
    /// @param order user signed order
    /// @param oldMultiQuote in case of amounts improvement, old quote is used to get old amounts signed by user
    /// @param takerSignature permit2 signature with order as witness
    /// @param takerAddress user address
    /// @param hooksHash hash of hooks data
    function transferTokensForMultiBebopOrder(
        BlendMultiOrder memory order,
        IBebopBlend.OldMultiQuote memory oldMultiQuote,
        bytes memory takerSignature,
        address takerAddress,
        bytes32 hooksHash
    ) external;

    /// @dev Transfer user's tokens to operator address for BlendAggregateOrder
    /// @param order user signed order
    /// @param oldAggregateQuote in case of amounts improvement, old quote is used to get old amounts signed by user
    /// @param takerSignature permit2 signature with order as witness
    /// @param takerAddress user address
    /// @param hooksHash hash of hooks data
    function transferTokensForAggregateBebopOrder(
        BlendAggregateOrder memory order,
        IBebopBlend.OldAggregateQuote memory oldAggregateQuote,
        bytes memory takerSignature,
        address takerAddress,
        bytes32 hooksHash
    ) external;

}

File 14 of 22 : IJamSettlement.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../libraries/JamInteraction.sol";
import "../libraries/JamOrder.sol";
import "../libraries/JamHooks.sol";

interface IJamSettlement {

    /// @dev Event emitted when a settlement of JamOrder is executed successfully
    event BebopJamOrderFilled(
        uint256 indexed nonce, address indexed user, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts
    );

    /// @dev Event with same eventId as will be emitted by the BebopBlend contract for SingleOrder using Order.extractEventId()
    event BebopBlendSingleOrderFilled(
        uint128 indexed eventId, address indexed receiver, address sellToken, address buyToken, uint256 sellAmount, uint256 buyAmount
    );

    /// @dev Event with same eventId as will be emitted by the BebopBlend contract for MultiOrder using Order.extractEventId()
    event BebopBlendMultiOrderFilled(
        uint128 indexed eventId, address indexed receiver, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts
    );

    /// @dev Event with same eventId as will be emitted by the BebopBlend contract for AggregateOrder using Order.extractEventId()
    event BebopBlendAggregateOrderFilled(
        uint128 indexed eventId, address indexed receiver, address[] sellTokens, address[] buyTokens, uint256[] sellAmounts, uint256[] buyAmounts
    );

    /// @dev Settle a jam order.
    /// Pulls sell tokens into the contract and ensures that after running interactions receiver has the minimum of buy
    /// @param order user signed order
    /// @param signature user signature
    /// @param interactions list of interactions to settle the order
    /// @param hooksData encoded hooks for pre and post interactions, empty if no hooks
    /// @param balanceRecipient solver specifies this address to receive the initial tokens from user
    function settle(
        JamOrder calldata order,
        bytes calldata signature,
        JamInteraction.Data[] calldata interactions,
        bytes memory hooksData,
        address balanceRecipient
    ) external payable;

    /// @dev Settle a jam order without interactions, just using balance of executor
    /// @param order user signed order
    /// @param signature user signature
    /// @param filledAmounts amounts that maker is transferring to taker
    /// @param hooksData encoded hooks for pre and post interactions, empty if no hooks
    function settleInternal(
        JamOrder calldata order,
        bytes calldata signature,
        uint256[] calldata filledAmounts,
        bytes memory hooksData
    ) external payable;

    /// @dev Settle a batch of orders.
    /// Pulls sell tokens into the contract and ensures that after running interactions receivers have the minimum of buy
    /// @param orders takers signed orders
    /// @param signatures takers signatures
    /// @param interactions list of interactions to settle the order
    /// @param hooks pre and post takers interactions, if empty then no interactions are run
    /// @param balanceRecipient solver specifies this address to receive the initial tokens from users
    function settleBatch(
        JamOrder[] calldata orders,
        bytes[] calldata signatures,
        JamInteraction.Data[] calldata interactions,
        JamHooks.Def[] calldata hooks,
        address balanceRecipient
    ) external payable;

    /// @dev Execute order on BebopBlend contract
    /// Using this contract as entry point for executing BebopBlend orders
    /// @param takerAddress address of the user
    /// @param orderType type of the order, Single, Multi or Aggregate
    /// @param data encoded order data, order has same structure as in BebopBlend contract
    /// @param hooksData encoded hooks for pre and post interactions, empty if no hooks
    function settleBebopBlend(
        address takerAddress,
        IBebopBlend.BlendOrderType orderType,
        bytes memory data,
        bytes memory hooksData
    ) external payable;
}

File 15 of 22 : IPermit2.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;


// Part of ISignatureTransfer(https://github.com/Uniswap/permit2/blob/main/src/interfaces/ISignatureTransfer.sol)
interface IPermit2 {

    /// @notice The token and amount details for a transfer signed in the permit transfer signature
    struct TokenPermissions {
        // ERC20 token address
        address token;
        // the maximum amount that can be spent
        uint256 amount;
    }

    /// @notice The signed permit message for a single token transfer
    struct PermitTransferFrom {
        TokenPermissions permitted;
        // a unique value for every token owner's signature to prevent signature replays
        uint256 nonce;
        // deadline on the permit signature
        uint256 deadline;
    }

    /// @notice Used to reconstruct the signed permit message for multiple token transfers
    /// @dev Do not need to pass in spender address as it is required that it is msg.sender
    /// @dev Note that a user still signs over a spender address
    struct PermitBatchTransferFrom {
        // the tokens and corresponding amounts permitted for a transfer
        TokenPermissions[] permitted;
        // a unique value for every token owner's signature to prevent signature replays
        uint256 nonce;
        // deadline on the permit signature
        uint256 deadline;
    }

    /// @notice Specifies the recipient address and amount for batched transfers.
    /// @dev Recipients and amounts correspond to the index of the signed token permissions array.
    /// @dev Reverts if the requested amount is greater than the permitted signed amount.
    struct SignatureTransferDetails {
        // recipient address
        address to;
        // spender requested amount
        uint256 requestedAmount;
    }

    /// @notice Transfers a token using a signed permit message
    /// @notice Includes extra data provided by the caller to verify signature over
    /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
    /// @dev Reverts if the requested amount is greater than the permitted signed amount
    /// @param permit The permit data signed over by the owner
    /// @param owner The owner of the tokens to transfer
    /// @param transferDetails The spender's requested transfer details for the permitted token
    /// @param witness Extra data to include when checking the user signature
    /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
    /// @param signature The signature to verify
    function permitWitnessTransferFrom(
        PermitTransferFrom memory permit,
        SignatureTransferDetails calldata transferDetails,
        address owner,
        bytes32 witness,
        string calldata witnessTypeString,
        bytes calldata signature
    ) external;


    /// @notice Transfers multiple tokens using a signed permit message
    /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
    /// @notice Includes extra data provided by the caller to verify signature over
    /// @param permit The permit data signed over by the owner
    /// @param owner The owner of the tokens to transfer
    /// @param transferDetails Specifies the recipient and requested amount for the token transfer
    /// @param witness Extra data to include when checking the user signature
    /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
    /// @param signature The signature to verify
    function permitWitnessTransferFrom(
        PermitBatchTransferFrom memory permit,
        SignatureTransferDetails[] calldata transferDetails,
        address owner,
        bytes32 witness,
        string calldata witnessTypeString,
        bytes calldata signature
    ) external;

    function DOMAIN_SEPARATOR() external view returns (bytes32);

}

File 16 of 22 : JamBalanceManager.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "./base/JamTransfer.sol";
import "./interfaces/IJamBalanceManager.sol";
import "./interfaces/IPermit2.sol";

/// @title JamBalanceManager
/// @notice The reason a balance manager exists is to prevent interaction to the settlement contract draining user funds
/// By having another contract that allowances are made to, we can enforce that it is only used to draw in user balances to settlement and not sent out
contract JamBalanceManager is IJamBalanceManager {

    using SafeTransferLib for IERC20;
    using JamOrderLib for JamOrder;
    using BlendSingleOrderLib for BlendSingleOrder;
    using BlendMultiOrderLib for BlendMultiOrder;
    using BlendAggregateOrderLib for BlendAggregateOrder;

    address private immutable operator;
    IPermit2 private immutable PERMIT2;

    constructor(address _operator, address _permit2) {
        // Operator can be defined at creation time with `msg.sender`
        // Pass in the settlement - and that can be the only caller.
        operator = _operator;
        PERMIT2 = IPermit2(_permit2);
    }

    modifier onlyOperator(address account) {
        require(account == operator, InvalidCaller());
        _;
    }

    /// @inheritdoc IJamBalanceManager
    function transferTokensWithPermit2(
        JamOrder calldata order,
        bytes calldata signature,
        bytes32 hooksHash,
        address receiver
    ) onlyOperator(msg.sender) external {
        PERMIT2.permitWitnessTransferFrom(
            order.toBatchPermit2(),
            order.toSignatureTransferDetails(receiver),
            order.taker,
            order.hash(hooksHash),
            JamOrderLib.PERMIT2_ORDER_TYPE,
            signature
        );
    }

    /// @inheritdoc IJamBalanceManager
    function transferTokens(
        address[] calldata tokens,
        uint256[] calldata amounts,
        address sender,
        address receiver
    ) onlyOperator(msg.sender) external {
        for (uint i; i < tokens.length; ++i){
            if (tokens[i] != JamOrderLib.NATIVE_TOKEN){
                IERC20(tokens[i]).safeTransferFrom(sender, receiver, amounts[i]);
            } else if (receiver != operator){
                JamTransfer(operator).transferNativeFromContract(receiver, amounts[i]);
            }
        }
    }

    /// @inheritdoc IJamBalanceManager
    function transferTokenForBlendSingleOrder(
        BlendSingleOrder memory order,
        IBebopBlend.OldSingleQuote memory oldSingleQuote,
        bytes memory takerSignature,
        address takerAddress,
        bytes32 hooksHash
    ) onlyOperator(msg.sender) external {
        PERMIT2.permitWitnessTransferFrom(
            IPermit2.PermitTransferFrom(
                IPermit2.TokenPermissions(order.taker_token, order.taker_amount), order.flags >> 128, order.expiry
            ),
            IPermit2.SignatureTransferDetails(operator, order.taker_amount),
            takerAddress,
            order.hash(oldSingleQuote.makerAmount, oldSingleQuote.makerNonce, hooksHash),
            BlendSingleOrderLib.PERMIT2_ORDER_TYPE,
            takerSignature
        );
    }

    /// @inheritdoc IJamBalanceManager
    function transferTokensForMultiBebopOrder(
        BlendMultiOrder memory order,
        IBebopBlend.OldMultiQuote memory oldMultiQuote,
        bytes memory takerSignature,
        address takerAddress,
        bytes32 hooksHash
    ) onlyOperator(msg.sender) external {
        PERMIT2.permitWitnessTransferFrom(
            order.toBatchPermit2(),
            order.toSignatureTransferDetails(operator),
            takerAddress,
            order.hash(oldMultiQuote.makerAmounts, oldMultiQuote.makerNonce, hooksHash),
            BlendMultiOrderLib.PERMIT2_ORDER_TYPE,
            takerSignature
        );
    }

    /// @inheritdoc IJamBalanceManager
    function transferTokensForAggregateBebopOrder(
        BlendAggregateOrder memory order,
        IBebopBlend.OldAggregateQuote memory oldAggregateQuote,
        bytes memory takerSignature,
        address takerAddress,
        bytes32 hooksHash
    ) onlyOperator(msg.sender) external {
        (address[] memory tokens, uint256[] memory amounts) = order.unpackTokensAndAmounts(true, oldAggregateQuote);
        PERMIT2.permitWitnessTransferFrom(
            order.toBatchPermit2(tokens, amounts),
            BlendAggregateOrderLib.toSignatureTransferDetails(amounts, operator),
            takerAddress,
            order.hash(oldAggregateQuote.makerAmounts, oldAggregateQuote.makerNonces, hooksHash),
            BlendAggregateOrderLib.PERMIT2_ORDER_TYPE,
            takerSignature
        );
    }

}

File 17 of 22 : BlendAggregateOrder.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../interfaces/IPermit2.sol";
import "../interfaces/IBebopBlend.sol";

/// @notice Struct for any trade with multiple makers
struct BlendAggregateOrder {
    uint256 expiry;
    address taker_address;
    address[] maker_addresses;
    uint256[] maker_nonces;
    address[][] taker_tokens;
    address[][] maker_tokens;
    uint256[][] taker_amounts;
    uint256[][] maker_amounts;
    address receiver;
    bytes commands;
    uint256 flags;
}


library BlendAggregateOrderLib {

    bytes internal constant ORDER_TYPE = abi.encodePacked(
        "AggregateOrder(uint64 partner_id,uint256 expiry,address taker_address,address[] maker_addresses,uint256[] maker_nonces,address[][] taker_tokens,address[][] maker_tokens,uint256[][] taker_amounts,uint256[][] maker_amounts,address receiver,bytes commands,bytes32 hooksHash)"
    );
    bytes32 internal constant ORDER_TYPE_HASH = keccak256(ORDER_TYPE);
    string internal constant PERMIT2_ORDER_TYPE = string(
        abi.encodePacked("AggregateOrder witness)", ORDER_TYPE, "TokenPermissions(address token,uint256 amount)")
    );
    address internal constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    /// @notice hash the given order using same schema as in BebopBlend contract
    /// @param order the order to hash
    /// @param updatedMakerAmounts amounts that taker signed
    /// @param updatedMakerNonces nonce that taker signed
    /// @return the eip-712 order hash
    function hash(
        BlendAggregateOrder memory order, uint256[][] memory updatedMakerAmounts, uint256[] memory updatedMakerNonces, bytes32 hooksHash
    ) internal pure returns (bytes32) {
        uint64 partnerId = uint64(order.flags >> 64);
        return keccak256(
            abi.encode(
                ORDER_TYPE_HASH, partnerId, order.expiry, order.taker_address,
                keccak256(abi.encodePacked(order.maker_addresses)), keccak256(abi.encodePacked(updatedMakerNonces)),
                keccak256(_encodeTightlyPackedNested(order.taker_tokens)), keccak256(_encodeTightlyPackedNested(order.maker_tokens)),
                keccak256(_encodeTightlyPackedNestedInt(order.taker_amounts)), keccak256(_encodeTightlyPackedNestedInt(updatedMakerAmounts)),
                order.receiver, keccak256(order.commands), hooksHash
            )
        );
    }

    function toBatchPermit2(
        BlendAggregateOrder memory order, address[] memory tokens, uint256[] memory amounts
    ) internal pure returns (IPermit2.PermitBatchTransferFrom memory) {
        IPermit2.TokenPermissions[] memory permitted = new IPermit2.TokenPermissions[](tokens.length);
        for (uint i; i < tokens.length; ++i) {
            permitted[i] = IPermit2.TokenPermissions(tokens[i], amounts[i]);
        }
        return IPermit2.PermitBatchTransferFrom(permitted, order.flags >> 128, order.expiry);
    }

    function toSignatureTransferDetails(
        uint256[] memory amounts, address receiver
    ) internal pure returns (IPermit2.SignatureTransferDetails[] memory) {
        IPermit2.SignatureTransferDetails[] memory details = new IPermit2.SignatureTransferDetails[](amounts.length);
        for (uint i; i < amounts.length; ++i) {
            details[i] = IPermit2.SignatureTransferDetails(receiver, amounts[i]);
        }
        return details;
    }

    /// @notice Unpack 2d arrays of tokens and amounts into 1d array without duplicates
    /// @param order the order to unpack
    /// @param unpackTakerAmounts if true, unpack taker amounts, otherwise unpack maker amounts
    function unpackTokensAndAmounts(
        BlendAggregateOrder memory order, bool unpackTakerAmounts, IBebopBlend.OldAggregateQuote memory oldAggregateQuote
    ) internal pure returns (address[] memory tokens, uint256[] memory amounts){
        uint maxLen;
        for (uint i; i < order.maker_addresses.length; ++i) {
            maxLen += unpackTakerAmounts ? order.taker_tokens[i].length : order.maker_tokens[i].length;
        }
        tokens = new address[](maxLen);
        amounts = new uint256[](maxLen);
        uint uniqueTokensCnt;
        uint commandsInd;
        for (uint256 i; i < order.maker_addresses.length; ++i) {
            if (unpackTakerAmounts) {
                commandsInd += order.maker_tokens[i].length;
            }
            uint curTokensLen = unpackTakerAmounts ? order.taker_tokens[i].length : order.maker_tokens[i].length;
            for (uint256 j; j < curTokensLen; ++j) {
                /// @dev  AggregateOrder contains multiple maker orders, 'commands' field indicates how to transfer tokens
                /// All commands packed into one variable with bytes type, for each token - command is 1 byte:
                /// '0x[maker1-order_maker-token1][maker1-order_taker-token1][maker2-order_maker-token1][maker2-order_taker-token1]...'
                /// ignoring TRANSFER_FROM_CONTRACT and TRANSFER_TO_CONTRACT commands, since they are transfers between makers
                if (
                    (unpackTakerAmounts && order.commands[commandsInd + j] != 0x08) ||  // Commands.TRANSFER_FROM_CONTRACT=0x08
                    (!unpackTakerAmounts && order.commands[commandsInd + j] != 0x07)    //Commands.TRANSFER_TO_CONTRACT=0x07
                ) {
                    bool isNew = true;
                    address token = unpackTakerAmounts ? order.taker_tokens[i][j] : order.maker_tokens[i][j];
                    if (order.commands[commandsInd + j] == 0x04) { // Commands.NATIVE_TRANSFER=0x04
                        token = NATIVE_TOKEN;
                    }
                    uint256 amount = unpackTakerAmounts ? order.taker_amounts[i][j] : (
                        oldAggregateQuote.useOldAmount ? oldAggregateQuote.makerAmounts[i][j] : order.maker_amounts[i][j]
                    );
                    for (uint256 k; k < uniqueTokensCnt; ++k) {
                        if (tokens[k] == token) {
                            amounts[k] += amount;
                            isNew = false;
                            break;
                        }
                    }
                    if (isNew) {
                        tokens[uniqueTokensCnt] = token;
                        amounts[uniqueTokensCnt++] = amount;
                    }
                }
            }
            if (unpackTakerAmounts) {
                commandsInd += order.taker_tokens[i].length;
            } else {
                commandsInd += order.maker_tokens[i].length + order.taker_tokens[i].length;
            }
        }
        assembly {
            mstore(tokens, uniqueTokensCnt)
            mstore(amounts, uniqueTokensCnt)
        }
    }

    /// @notice Pack 2D array of integers into tightly packed bytes for hashing
    function _encodeTightlyPackedNestedInt(uint256[][] memory nestedArray) private pure returns (bytes memory encoded) {
        uint nestedArrayLen = nestedArray.length;
        for (uint i; i < nestedArrayLen; ++i) {
            encoded = abi.encodePacked(encoded, keccak256(abi.encodePacked(nestedArray[i])));
        }
        return encoded;
    }

    /// @notice Pack 2D array of addresses into tightly packed bytes for hashing
    function _encodeTightlyPackedNested(address[][] memory nestedArray) private pure returns (bytes memory encoded) {
        uint nestedArrayLen = nestedArray.length;
        for (uint i; i < nestedArrayLen; ++i) {
            encoded = abi.encodePacked(encoded, keccak256(abi.encodePacked(nestedArray[i])));
        }
        return encoded;
    }

}

File 18 of 22 : BlendMultiOrder.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../interfaces/IPermit2.sol";


/// @notice Struct for many-to-one or one-to-many trade with one maker
struct BlendMultiOrder {
    uint256 expiry;
    address taker_address;
    address maker_address;
    uint256 maker_nonce;
    address[] taker_tokens;
    address[] maker_tokens;
    uint256[] taker_amounts;
    uint256[] maker_amounts;
    address receiver;
    bytes commands;
    uint256 flags;
}


library BlendMultiOrderLib {

    bytes internal constant ORDER_TYPE = abi.encodePacked(
        "MultiOrder(uint64 partner_id,uint256 expiry,address taker_address,address maker_address,uint256 maker_nonce,address[] taker_tokens,address[] maker_tokens,uint256[] taker_amounts,uint256[] maker_amounts,address receiver,bytes commands,bytes32 hooksHash)"
    );
    bytes32 internal constant ORDER_TYPE_HASH = keccak256(ORDER_TYPE);
    string internal constant PERMIT2_ORDER_TYPE = string(
        abi.encodePacked("MultiOrder witness)", ORDER_TYPE, "TokenPermissions(address token,uint256 amount)")
    );
    address internal constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    /// @notice hash the given order using same schema as in BebopBlend contract
    /// @param order the order to hash
    /// @param updatedMakerAmounts amounts that taker signed
    /// @param updatedMakerNonce nonce that taker signed
    /// @return the eip-712 order hash
    function hash(
        BlendMultiOrder memory order, uint256[] memory updatedMakerAmounts, uint256 updatedMakerNonce, bytes32 hooksHash
    ) internal pure returns (bytes32) {
        uint64 partnerId = uint64(order.flags >> 64);
        return keccak256(
            abi.encode(
                ORDER_TYPE_HASH, partnerId, order.expiry, order.taker_address, order.maker_address, updatedMakerNonce,
                keccak256(abi.encodePacked(order.taker_tokens)), keccak256(abi.encodePacked(order.maker_tokens)),
                keccak256(abi.encodePacked(order.taker_amounts)), keccak256(abi.encodePacked(updatedMakerAmounts)),
                order.receiver, keccak256(order.commands), hooksHash
            )
        );
    }

    function toBatchPermit2(BlendMultiOrder memory order) internal pure returns (IPermit2.PermitBatchTransferFrom memory) {
        IPermit2.TokenPermissions[] memory permitted = new IPermit2.TokenPermissions[](order.taker_tokens.length);
        for (uint i; i < order.taker_tokens.length; ++i) {
            permitted[i] = IPermit2.TokenPermissions(order.taker_tokens[i], order.taker_amounts[i]);
        }
        return IPermit2.PermitBatchTransferFrom(permitted, order.flags >> 128, order.expiry);
    }

    function toSignatureTransferDetails(
        BlendMultiOrder memory order, address receiver
    ) internal pure returns (IPermit2.SignatureTransferDetails[] memory) {
        IPermit2.SignatureTransferDetails[] memory details = new IPermit2.SignatureTransferDetails[](order.taker_tokens.length);
        for (uint i; i < order.taker_tokens.length; ++i) {
            details[i] = IPermit2.SignatureTransferDetails(receiver, order.taker_amounts[i]);
        }
        return details;
    }

    /// @notice Get maker tokens from the order
    /// replace all tokens with command=0x04(Commands.NATIVE_TRANSFER) with native token address
    function getMakerTokens(BlendMultiOrder memory order) internal pure returns (address[] memory makerTokens) {
        makerTokens = new address[](order.maker_tokens.length);
        for (uint i; i < order.maker_tokens.length; ++i) {
            makerTokens[i] = order.commands[i] == 0x04 ? NATIVE_TOKEN : order.maker_tokens[i];
        }
    }

}

File 19 of 22 : BlendSingleOrder.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../interfaces/IPermit2.sol";


/// @notice BebopBlend struct for one-to-one trade with one maker
struct BlendSingleOrder {
    uint256 expiry;
    address taker_address;
    address maker_address;
    uint256 maker_nonce;
    address taker_token;
    address maker_token;
    uint256 taker_amount;
    uint256 maker_amount;
    address receiver;
    uint256 packed_commands;
    uint256 flags;
}


library BlendSingleOrderLib {

    bytes internal constant ORDER_TYPE = abi.encodePacked(
        "SingleOrder(uint64 partner_id,uint256 expiry,address taker_address,address maker_address,uint256 maker_nonce,address taker_token,address maker_token,uint256 taker_amount,uint256 maker_amount,address receiver,uint256 packed_commands,bytes32 hooksHash)"
    );
    bytes32 internal constant ORDER_TYPE_HASH = keccak256(ORDER_TYPE);
    string internal constant PERMIT2_ORDER_TYPE = string(
        abi.encodePacked("SingleOrder witness)", ORDER_TYPE, "TokenPermissions(address token,uint256 amount)")
    );

    /// @notice hash the given order using same schema as in BebopBlend contract
    /// @param order the order to hash
    /// @param updatedMakerAmount amount that taker signed
    /// @param updatedMakerNonce nonce that taker signed
    /// @return the eip-712 order hash
    function hash(
        BlendSingleOrder memory order, uint256 updatedMakerAmount, uint256 updatedMakerNonce, bytes32 hooksHash
    ) internal pure returns (bytes32) {
        uint64 partnerId = uint64(order.flags >> 64);
        return keccak256(
            abi.encode(
                ORDER_TYPE_HASH, partnerId, order.expiry, order.taker_address, order.maker_address,
                updatedMakerNonce, order.taker_token, order.maker_token, order.taker_amount,
                updatedMakerAmount, order.receiver, order.packed_commands, hooksHash
            )
        );
    }

}

File 20 of 22 : JamHooks.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../libraries/JamInteraction.sol";

/// @title JamHooks
/// @notice JamHooks is a library for managing pre and post interactions
library JamHooks {

    bytes32 internal constant EMPTY_HOOKS_HASH = bytes32(0);

    /// @dev Data structure for pre and post interactions
    struct Def {
        JamInteraction.Data[] beforeSettle;
        JamInteraction.Data[] afterSettle;
    }

    function hash(Def memory hooks) internal pure returns (bytes32) {
        if (hooks.afterSettle.length == 0 && hooks.beforeSettle.length == 0){
            return EMPTY_HOOKS_HASH;
        }
        return keccak256(abi.encode(hooks));
    }
}

File 21 of 22 : JamInteraction.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../interfaces/IJamBalanceManager.sol";
import "../base/Errors.sol";

library JamInteraction {

    /// @dev Data representing an interaction on the chain
    struct Data {
        bool result; // If the interaction is required to succeed
        address to;
        uint256 value;
        bytes data;
    }

    function runInteractions(Data[] calldata interactions, IJamBalanceManager balanceManager) internal returns (bool) {
        for (uint i; i < interactions.length; ++i) {
            Data calldata interaction = interactions[i];
            require(interaction.to != address(balanceManager), CallToBalanceManagerNotAllowed());
            (bool execResult,) = payable(interaction.to).call{ value: interaction.value }(interaction.data);
            if (!execResult && interaction.result) return false;
        }
        return true;
    }

    function runInteractionsM(Data[] memory interactions, IJamBalanceManager balanceManager) internal returns (bool) {
        for (uint i; i < interactions.length; ++i) {
            Data memory interaction = interactions[i];
            require(interaction.to != address(balanceManager), CallToBalanceManagerNotAllowed());
            (bool execResult,) = payable(interaction.to).call{ value: interaction.value }(interaction.data);
            if (!execResult && interaction.result) return false;
        }
        return true;
    }
}

File 22 of 22 : JamOrder.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;

import "../interfaces/IPermit2.sol";
import "./JamHooks.sol";
import "../external-libs/PermitHash.sol";

/// @dev Data representing a Jam Order.
struct JamOrder {
    address taker;
    address receiver;
    uint256 expiry;
    uint256 exclusivityDeadline; // if block.timestamp > exclusivityDeadline, then order can be executed by any executor
    uint256 nonce;
    address executor; // only msg.sender=executor is allowed to execute (if executor=address(0), then order can be executed by anyone)
    uint256 partnerInfo; // partnerInfo is a packed struct of [partnerAddress,partnerFee,protocolFee]
    address[] sellTokens;
    address[] buyTokens;
    uint256[] sellAmounts;
    uint256[] buyAmounts;
    bool usingPermit2; // this field is excluded from ORDER_TYPE, so taker doesnt need to sign it
}


/// @title JamOrderLib
library JamOrderLib {

    address internal constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    bytes internal constant ORDER_TYPE = abi.encodePacked(
        "JamOrder(address taker,address receiver,uint256 expiry,uint256 exclusivityDeadline,uint256 nonce,address executor,uint256 partnerInfo,address[] sellTokens,address[] buyTokens,uint256[] sellAmounts,uint256[] buyAmounts,bytes32 hooksHash)"
    );
    bytes32 internal constant ORDER_TYPE_HASH = keccak256(ORDER_TYPE);
    string internal constant PERMIT2_ORDER_TYPE = string(
        abi.encodePacked("JamOrder witness)", ORDER_TYPE, "TokenPermissions(address token,uint256 amount)")
    );

    /// @notice hash the given order
    /// @param order the order to hash
    /// @return the eip-712 order hash
    function hash(JamOrder calldata order, bytes32 hooksHash) internal pure returns (bytes32) {
        return keccak256(
            abi.encode(
                ORDER_TYPE_HASH, order.taker, order.receiver, order.expiry, order.exclusivityDeadline, order.nonce,
                order.executor, order.partnerInfo, keccak256(abi.encodePacked(order.sellTokens)),
                keccak256(abi.encodePacked(order.buyTokens)), keccak256(abi.encodePacked(order.sellAmounts)),
                keccak256(abi.encodePacked(order.buyAmounts)), hooksHash
            )
        );
    }

    function toBatchPermit2(JamOrder calldata order) internal pure returns (IPermit2.PermitBatchTransferFrom memory) {
        IPermit2.TokenPermissions[] memory permitted = new IPermit2.TokenPermissions[](order.sellTokens.length);
        for (uint i; i < order.sellTokens.length; ++i) {
            permitted[i] = IPermit2.TokenPermissions(order.sellTokens[i], order.sellAmounts[i]);
        }
        return IPermit2.PermitBatchTransferFrom(permitted, order.nonce, order.expiry);
    }

    function toSignatureTransferDetails(
        JamOrder calldata order, address receiver
    ) internal pure returns (IPermit2.SignatureTransferDetails[] memory details) {
        details = new IPermit2.SignatureTransferDetails[](order.sellTokens.length);
        for (uint i; i < order.sellTokens.length; ++i) {
            details[i] = IPermit2.SignatureTransferDetails(receiver, order.sellAmounts[i]);
        }
    }

    function permit2OrderHash(JamOrder calldata order, bytes32 hooksHash, address spender) internal pure returns (bytes32) {
        return PermitHash.hashWithWitness(toBatchPermit2(order), hash(order, hooksHash), PERMIT2_ORDER_TYPE, spender);
    }


}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_permit2","type":"address"},{"internalType":"address","name":"_bebopBlend","type":"address"},{"internalType":"address","name":"_treasuryAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AfterSettleHooksFailed","type":"error"},{"inputs":[],"name":"BeforeSettleHooksFailed","type":"error"},{"inputs":[],"name":"BuyTokensInvalidLength","type":"error"},{"inputs":[],"name":"CallToBalanceManagerNotAllowed","type":"error"},{"inputs":[],"name":"DifferentFeesInBatch","type":"error"},{"inputs":[],"name":"DuplicateTokens","type":"error"},{"inputs":[],"name":"FailedToSendEth","type":"error"},{"inputs":[],"name":"InteractionsFailed","type":"error"},{"inputs":[],"name":"InvalidBatchHooksLength","type":"error"},{"inputs":[],"name":"InvalidBatchSignaturesLength","type":"error"},{"inputs":[],"name":"InvalidBlendOrderType","type":"error"},{"inputs":[],"name":"InvalidBlendPartnerId","type":"error"},{"inputs":[],"name":"InvalidContractSignature","type":"error"},{"inputs":[],"name":"InvalidExecutor","type":"error"},{"inputs":[],"name":"InvalidFeePercentage","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"InvalidFilledAmounts","type":"error"},{"inputs":[],"name":"InvalidFilledAmountsLength","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"InvalidOutputBalance","type":"error"},{"inputs":[],"name":"InvalidPartnerAddress","type":"error"},{"inputs":[],"name":"InvalidReceiverInBatch","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSignatureLength","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"OrderExpired","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"SellTokensInvalidLength","type":"error"},{"inputs":[],"name":"ZeroNonce","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"eventId","type":"uint128"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address[]","name":"sellTokens","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"buyTokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"}],"name":"BebopBlendAggregateOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"eventId","type":"uint128"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address[]","name":"sellTokens","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"buyTokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"}],"name":"BebopBlendMultiOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"eventId","type":"uint128"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"sellToken","type":"address"},{"indexed":false,"internalType":"address","name":"buyToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"sellAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"buyAmount","type":"uint256"}],"name":"BebopBlendSingleOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address[]","name":"sellTokens","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"buyTokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"}],"name":"BebopJamOrderFilled","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NativeTransfer","type":"event"},{"inputs":[],"name":"DOMAIN_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceManager","outputs":[{"internalType":"contract IJamBalanceManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bebopBlend","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"cancelLimitOrder","outputs":[],"stateMutability":"nonpayable","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":[{"components":[{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"beforeSettle","type":"tuple[]"},{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"afterSettle","type":"tuple[]"}],"internalType":"struct JamHooks.Def","name":"hooks","type":"tuple"}],"name":"hashHooks","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"exclusivityDeadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"uint256","name":"partnerInfo","type":"uint256"},{"internalType":"address[]","name":"sellTokens","type":"address[]"},{"internalType":"address[]","name":"buyTokens","type":"address[]"},{"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"},{"internalType":"bool","name":"usingPermit2","type":"bool"}],"internalType":"struct JamOrder","name":"order","type":"tuple"},{"internalType":"bytes32","name":"hooksHash","type":"bytes32"}],"name":"hashJamOrder","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"isLimitOrderNonceValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"exclusivityDeadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"uint256","name":"partnerInfo","type":"uint256"},{"internalType":"address[]","name":"sellTokens","type":"address[]"},{"internalType":"address[]","name":"buyTokens","type":"address[]"},{"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"},{"internalType":"bool","name":"usingPermit2","type":"bool"}],"internalType":"struct JamOrder","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"interactions","type":"tuple[]"},{"internalType":"bytes","name":"hooksData","type":"bytes"},{"internalType":"address","name":"balanceRecipient","type":"address"}],"name":"settle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"exclusivityDeadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"uint256","name":"partnerInfo","type":"uint256"},{"internalType":"address[]","name":"sellTokens","type":"address[]"},{"internalType":"address[]","name":"buyTokens","type":"address[]"},{"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"},{"internalType":"bool","name":"usingPermit2","type":"bool"}],"internalType":"struct JamOrder[]","name":"orders","type":"tuple[]"},{"internalType":"bytes[]","name":"signatures","type":"bytes[]"},{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"interactions","type":"tuple[]"},{"components":[{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"beforeSettle","type":"tuple[]"},{"components":[{"internalType":"bool","name":"result","type":"bool"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct JamInteraction.Data[]","name":"afterSettle","type":"tuple[]"}],"internalType":"struct JamHooks.Def[]","name":"hooks","type":"tuple[]"},{"internalType":"address","name":"balanceRecipient","type":"address"}],"name":"settleBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"enum IBebopBlend.BlendOrderType","name":"orderType","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"hooksData","type":"bytes"}],"name":"settleBebopBlend","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"taker","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"exclusivityDeadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"uint256","name":"partnerInfo","type":"uint256"},{"internalType":"address[]","name":"sellTokens","type":"address[]"},{"internalType":"address[]","name":"buyTokens","type":"address[]"},{"internalType":"uint256[]","name":"sellAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"buyAmounts","type":"uint256[]"},{"internalType":"bool","name":"usingPermit2","type":"bool"}],"internalType":"struct JamOrder","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256[]","name":"filledAmounts","type":"uint256[]"},{"internalType":"bytes","name":"hooksData","type":"bytes"}],"name":"settleInternal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferNativeFromContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validationAddress","type":"address"},{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"validateSignature","outputs":[],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

61014080604052346102e557606081618d6b803803809161002082856102ea565b8339810103126102e5576100338161030d565b61004b60406100446020850161030d565b930161030d565b60016000556040519091612ad88083019291906001600160401b038411838510176102cf57604091839161629383393085526001600160a01b031660208501819052930301906000f080156102c35760018060a01b03166080524660e05260405160208101907f454950373132446f6d61696e28737472696e67206e616d652c737472696e672082527f76657273696f6e2c75696e7432353620636861696e49642c6164647265737320604082015271766572696679696e67436f6e74726163742960701b6060820152605281526101246072826102ea565b5190206040516101356040826102ea565b600d81526c12985b54d95d1d1b195b595b9d609a1b602090910152604080517f05fca2bf864448463a9141ae37fa0b2158f24d3135772bc23bc081c1765a8c2c9161018090826102ea565b600181526020810190601960f91b82525190206040519160208301938452604083015260608201524660808201523060a082015260a081526101c360c0826102ea565b51902060c05260a0526101005261012052604051615f71908161032282396080518181816103d7015281816104d70152818161074c0152818161085601528181610b0401528181610d4f0152818161142d0152818161149601528181611615015281816116ca015281816130f90152818161318801528181613294015281816132fc01528181613515015281816135c0015281816136d7015281816138860152818161395501528181613a1b0152613cc3015260a05181613c7c015260c05181611db7015260e05181611d9101526101005181818161348d0152615a400152610120518181816105ae015281816108f601528181610b9601526111c30152f35b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b600080fd5b601f909101601f19168101906001600160401b038211908210176102cf57604052565b51906001600160a01b03821682036102e55756fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80632143d82c1461012b5780633644e51514610126578063416e6d5e146101215780634a0d98781461011c578063796f077b146101175780637c317e0f146101125780637eea39f21461010d57806384b0196e14610108578063971604c614610103578063a03f5274146100fe578063a5cdc8fc146100f9578063acb8cc49146100f4578063b06b61db146100ef578063b57f9fed146100ea578063c7977be7146100e5578063f0a5f8f2146100e05763f80b26e30361000e57611375565b611336565b61131b565b6111e7565b6111a3565b611187565b6110ba565b611020565b610fd4565b610f38565b610ea3565b610e61565b610e2d565b6103fb565b6103b7565b610394565b6102e3565b908161018091031261013f5790565b600080fd5b9181601f8401121561013f5782359167ffffffffffffffff831161013f576020838186019501011161013f57565b9181601f8401121561013f5782359167ffffffffffffffff831161013f576020808501948460051b01011161013f57565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff8211176101d557604052565b6101a3565b6040810190811067ffffffffffffffff8211176101d557604052565b6060810190811067ffffffffffffffff8211176101d557604052565b90601f8019910116810190811067ffffffffffffffff8211176101d557604052565b60405190610243604083610212565b565b6040519061024361016083610212565b60405190610243606083610212565b67ffffffffffffffff81116101d557601f01601f191660200190565b81601f8201121561013f5780359061029782610264565b926102a56040519485610212565b8284526020838301011161013f57816000926020809301838601378301015290565b6001600160a01b0381160361013f57565b3590610243826102c7565b60a036600319011261013f5760043567ffffffffffffffff811161013f5761030f903690600401610130565b60243567ffffffffffffffff811161013f5761032f903690600401610144565b919060443567ffffffffffffffff811161013f57610351903690600401610172565b906064359467ffffffffffffffff861161013f57610376610019963690600401610280565b9360843595610384876102c7565b6113be565b600091031261013f57565b3461013f57600036600319011261013f5760206103af611d8e565b604051908152f35b3461013f57600036600319011261013f5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261013f57600435610413816102c7565b602435600381101561013f5760443567ffffffffffffffff811161013f5761043f903690600401610280565b9160643567ffffffffffffffff811161013f57610460903690600401610280565b92610469613d76565b835115610d845761048360208551860101602086016118da565b935b5160009015610d7e575061049884613e3a565b905b8115159384610d45575b6104ad81611e2f565b8061081c5750806020806104c693518301019101612a48565b6001600160a01b03979396919495977f000000000000000000000000000000000000000000000000000000000000000016803b1561013f578760008a61053d8296604051998a97889687957f57c3af1e00000000000000000000000000000000000000000000000000000000875260048701612c0c565b03925af19081156107b75761056c926001600160a01b0392610807575b50166001600160a01b03166040860152565b806107bc575b50608083019061059861058c83516001600160a01b031690565b6001600160a01b031690565b916001600160a01b0360c08601936105d58551917f0000000000000000000000000000000000000000000000000000000000000000928391614be3565b16803b1561013f578460009161061c94836040518097819582947f1a4990260000000000000000000000000000000000000000000000000000000084528d60048501612c6f565b03925af180156107b7577fca180a308256a6e9607c256dd145d700f18b1ee21e9bfa2919258b31a211bb8a936001600160a01b039361072c9261079c575b5061068261066d61014089015160801c90565b6fffffffffffffffffffffffffffffffff1690565b966106a961069b6101008301516001600160a01b031690565b94516001600160a01b031690565b610120820151909790600216156107885773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee925b51916106dd8251151590565b1561077c575060200151915b6fffffffffffffffffffffffffffffffff6040519687961699169785909493926001600160a01b0360609381608085019816845216602083015260408201520152565b0390a35b61073f575b6100196001600055565b61077160206107769201517f00000000000000000000000000000000000000000000000000000000000000009061412f565b611d5d565b38610735565b60e091500151916106e9565b60a08201516001600160a01b0316926106d1565b806107ab60006107b193610212565b80610389565b3861065a565b611a91565b61014084016108006107df6107d2835160401c90565b67ffffffffffffffff1690565b67ffffffffffffffff6107f86107d26107d28760401c90565b911614612568565b5238610572565b806107ab600061081693610212565b3861055a565b61082881949394611e2f565b60018103610acb57508060208061084493518301019101612840565b6001600160a01b0399959693979194997f000000000000000000000000000000000000000000000000000000000000000016803b1561013f57886000896108bc8296604051998a97889687957ffbfa3c5b00000000000000000000000000000000000000000000000000000000875260048701612995565b03925af19081156107b7576108eb926001600160a01b0392610ab6575b50166001600160a01b03166040850152565b80610a99575b5091927f0000000000000000000000000000000000000000000000000000000000000000929060005b6080840151805182101561096757906109618661094c61058c61093f856001976125af565b516001600160a01b031690565b61095a8460c08a01516125af565b5190614be3565b0161091a565b505093926001600160a01b039095919516803b1561013f57836000916109be93836040518096819582947fefe34fe60000000000000000000000000000000000000000000000000000000084528a600485016129cc565b03925af180156107b757610a84575b507fa3f15217206817f5e14f76307e5f65cfdc211516553c6638ef4fc79c4d6a0f0a6001600160a01b03610a0961066d61014085015160801c90565b93610a70610a226101008601516001600160a01b031690565b91608086015195610a3281614cff565b9160c082015191610a438251151590565b15610a78575060200151915b6fffffffffffffffffffffffffffffffff604051968796169916978561268b565b0390a3610730565b60e09150015191610a4f565b806107ab6000610a9393610212565b386109cd565b6101408301610aaf6107df6107d2835160401c90565b52386108f1565b806107ab6000610ac593610212565b386108d9565b80610ada600292979697611e2f565b03610d1b5780602080610af29351830101910161214b565b6001600160a01b0397949592969193977f000000000000000000000000000000000000000000000000000000000000000016803b1561013f5787600088610b6a8296604051988997889687957f77c19c1f00000000000000000000000000000000000000000000000000000000875260048701612518565b03925af180156107b757610d06575b5080610ce9575b50610b8e8383959495614721565b9590926000947f0000000000000000000000000000000000000000000000000000000000000000955b8551811015610be85780610be2888b61095a84610bdc61058c61093f6001998f6125af565b926125af565b01610bb7565b50929690946001600160a01b039096929616803b1561013f5782600091610c4095836040518098819582947f14e7a7ab0000000000000000000000000000000000000000000000000000000084528d600485016125df565b03925af19283156107b757610c896001600160a01b0393610a70927f85272ea7cbfb5ccba50d6cfaad14ff2ea471614d48c96ed5ecef53f11e56657996610cd4575b5087614977565b9092610cb2610100610ca361066d6101408c015160801c90565b9901516001600160a01b031690565b936fffffffffffffffffffffffffffffffff604051968796169916978561268b565b806107ab6000610ce393610212565b38610c82565b6101408301610cff6107df6107d2835160401c90565b5238610b80565b806107ab6000610d1593610212565b38610b79565b7f7082a8de0000000000000000000000000000000000000000000000000000000060005260046000fd5b610d79610d7487517f00000000000000000000000000000000000000000000000000000000000000009061412f565b611953565b6104a4565b9061049a565b610d8c611737565b610d94611737565b610d9c610234565b918252602082015293610485565b60405190610db9604083610212565b600d82527f4a616d536574746c656d656e74000000000000000000000000000000000000006020830152565b60005b838110610df85750506000910152565b8181015183820152602001610de8565b90602091610e2181518092818552858086019101610de5565b601f01601f1916010190565b3461013f57600036600319011261013f57610e5d610e49610daa565b604051918291602083526020830190610e08565b0390f35b3461013f57604036600319011261013f576100196000808080600435610e86816102c7565b6001600160a01b0360243591165af1610e9d612ce3565b50612d13565b3461013f57604036600319011261013f57600160ff600435610ec4816102c7565b6001600160a01b036024359116600052600260205260406000208160081c600052602052161b604060002054161560405180916020820190151582520390f35b906020808351928381520192019060005b818110610f225750505090565b8251845260209384019390920191600101610f15565b3461013f57600036600319011261013f57610fa5610f54610daa565b610e5d610f5f61114c565b610fb3610f6a612d44565b916040519586957f0f00000000000000000000000000000000000000000000000000000000000000875260e0602088015260e0870190610e08565b908582036040870152610e08565b90466060850152306080850152600060a085015283820360c0850152610f04565b3461013f57606036600319011261013f57600435610ff1816102c7565b6024356044359167ffffffffffffffff831161013f57611018610019933690600401610144565b929091612e33565b608036600319011261013f5760043567ffffffffffffffff811161013f5761104c903690600401610130565b60243567ffffffffffffffff811161013f5761106c903690600401610144565b60449291923567ffffffffffffffff811161013f5761108f903690600401610172565b916064359467ffffffffffffffff861161013f576110b4610019963690600401610280565b94613089565b3461013f57602036600319011261013f5760043580156111225761111f600160ff8360081c93161b91336000526002602052604060002092816000528360205260406000205461110e828083161415615051565b179290600052602052604060002090565b55005b7f150b14ee0000000000000000000000000000000000000000000000000000000060005260046000fd5b6040519061115b604083610212565b600182527f32000000000000000000000000000000000000000000000000000000000000006020830152565b3461013f57600036600319011261013f57610e5d610e4961114c565b3461013f57600036600319011261013f5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b60a036600319011261013f5760043567ffffffffffffffff811161013f57611213903690600401610172565b9060243567ffffffffffffffff811161013f57611234903690600401610172565b9260443567ffffffffffffffff811161013f57611255903690600401610172565b906064359567ffffffffffffffff871161013f5761127a610019973690600401610172565b9590946084359761128a896102c7565b613697565b60405160208101907f454950373132446f6d61696e28737472696e67206e616d652c737472696e672082527f76657273696f6e2c75696e7432353620636861696e49642c616464726573732060408201527f766572696679696e67436f6e7472616374290000000000000000000000000000606082015260528152611315607282610212565b51902090565b3461013f57600036600319011261013f5760206103af61128f565b3461013f57604036600319011261013f5760043567ffffffffffffffff811161013f576103af61136c6020923690600401610130565b60243590613c33565b3461013f57602036600319011261013f5760043567ffffffffffffffff811161013f576040600319823603011261013f576103af6113b96020923690600401613bbd565b613e3a565b9290959193956113cc613d76565b8551156116f9576113e660208751880101602088016118da565b955b51600090156116f457506113fb86613e3a565b61140781878488613f5e565b80151595866116c0575b61141e6101608701611984565b15611608576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690813b1561013f576000809461147a604051988996879586946332910d0160e11b86528d60048701611afe565b03925af19081156107b7576114c2926114bd926115f3575b505b7f00000000000000000000000000000000000000000000000000000000000000009687916141fd565b611c63565b6101408101907f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd6001600160a01b036115056114fe858561198e565b3691611c94565b92611549846115446101008401976115296115208a8761198e565b9190928761198e565b602088019591611538876119c4565b9360c08a013595614310565b6119c4565b821630146115cc575b6115a0608082013594611564836119c4565b9261158161158f61157860e084018461198e565b92909a8461198e565b91909361012081019061198e565b939092604051988998169b88611d11565b0390a36115b4575b50506102436001600055565b6115c591602061077192015161412f565b38806115a8565b6115ee6115e96115e56115df888561198e565b90614683565b1590565b611ce0565b611552565b806107ab600061160293610212565b38611492565b5050506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661164260e085018561198e565b93909161165361012087018761198e565b95909261165f886119c4565b94833b1561013f5761168d6000969287936040519a8b9889978896635abff4df60e01b885260048801611a4f565b03925af19081156107b7576114c2926114bd926116ab575b50611494565b806107ab60006116ba93610212565b386116a5565b6116ef610d7489517f00000000000000000000000000000000000000000000000000000000000000009061412f565b611411565b6113fb565b611701611737565b611709611737565b611711610234565b9182526020820152956113e8565b67ffffffffffffffff81116101d55760051b60200190565b60405190611746602083610212565b6000825281601f19611758600061171f565b019060005b82811061176957505050565b602090604051611778816101b9565b60008152600083820152600060408201526060808201528282850101520161175d565b8015150361013f57565b5190610243826102c7565b81601f8201121561013f5780516117c681610264565b926117d46040519485610212565b8184526020828401011161013f576117f29160208085019101610de5565b90565b9080601f8301121561013f5781519161180d8361171f565b9261181b6040519485610212565b80845260208085019160051b8301019183831161013f5760208101915b83831061184757505050505090565b825167ffffffffffffffff811161013f578201906080828703601f19011261013f5760405190611876826101b9565b60208301516118848161179b565b82526040830151611894816102c7565b60208301526060830151604083015260808301519167ffffffffffffffff831161013f576118ca886020809695819601016117b0565b6060820152815201920191611838565b60208183031261013f5780519067ffffffffffffffff821161013f570160408183031261013f576040519161190e836101da565b815167ffffffffffffffff811161013f578161192b9184016117f5565b8352602082015167ffffffffffffffff811161013f5761194b92016117f5565b602082015290565b1561195a57565b7f08f0f0fa0000000000000000000000000000000000000000000000000000000060005260046000fd5b356117f28161179b565b903590601e198136030182121561013f570180359067ffffffffffffffff821161013f57602001918160051b3603831361013f57565b356117f2816102c7565b9160209082815201919060005b8181106119e85750505090565b9091926020806001926001600160a01b038735611a04816102c7565b1681520194019291016119db565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161013f5760209260051b809284830137010190565b949695916001600160a01b0393606095611a768694611a849460808b5260808b01916119ce565b9188830360208a0152611a12565b9616604085015216910152565b6040513d6000823e3d90fd5b9035601e198236030181121561013f57016020813591019167ffffffffffffffff821161013f578160051b3603831361013f57565b35906102438261179b565b908060209392818452848401376000828201840152601f01601f1916010190565b90611c4e906102439597969460609460808552611b2e60808601611b21856102d8565b6001600160a01b03169052565b611b4d611b3d602085016102d8565b6001600160a01b031660a0870152565b604083013560c08601528583013560e08601526080830135610100860152611b8b611b7a60a085016102d8565b6001600160a01b0316610120870152565b60c0830135610140860152611c41611c37610160611c30611c0f611bee611bcd8b610200611bbc60e08d018d611a9d565b9190926101808982015201916119ce565b611bdb6101008b018b611a9d565b8d8303607f19016101808f0152906119ce565b611bfc6101208a018a611a9d565b8c8303607f19016101a08e015290611a12565b611c1d610140890189611a9d565b8b8303607f19016101c08d015290611a12565b9501611ad2565b15156101e0870152565b8483036020860152611add565b95604082015201906001600160a01b03169052565b15611c6a57565b7fff774c530000000000000000000000000000000000000000000000000000000060005260046000fd5b929190611ca08161171f565b93611cae6040519586610212565b602085838152019160051b810192831161013f57905b828210611cd057505050565b8135815260209182019101611cc4565b15611ce757565b7f7a745d4b0000000000000000000000000000000000000000000000000000000060005260046000fd5b959192611d4f94611d33611d41936117f29a989660808b5260808b01916119ce565b9188830360208a01526119ce565b918583036040870152611a12565b916060818403910152610f04565b15611d6457565b7fe70c1fc90000000000000000000000000000000000000000000000000000000060005260046000fd5b467f000000000000000000000000000000000000000000000000000000000000000003611dd9577f000000000000000000000000000000000000000000000000000000000000000090565b611de161128f565b611de9610daa565b60208151910120611df861114c565b602081519101206040519160208301938452604083015260608201524660808201523060a082015260a0815261131560c082610212565b60031115611e3957565b634e487b7160e01b600052602160045260246000fd5b9080601f8301121561013f578151611e668161171f565b92611e746040519485610212565b81845260208085019260051b82010192831161013f57602001905b828210611e9c5750505090565b602080918351611eab816102c7565b815201910190611e8f565b9080601f8301121561013f578151611ecd8161171f565b92611edb6040519485610212565b81845260208085019260051b82010192831161013f57602001905b828210611f035750505090565b8151815260209182019101611ef6565b9080601f8301121561013f578151611f2a8161171f565b92611f386040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b838210611f6457505050505090565b815167ffffffffffffffff811161013f57602091611f8787848094880101611e4f565b815201910190611f55565b9080601f8301121561013f578151611fa98161171f565b92611fb76040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b838210611fe357505050505090565b815167ffffffffffffffff811161013f5760209161200687848094880101611eb6565b815201910190611fd4565b91909160408184031261013f576040519061202b826101da565b819381519167ffffffffffffffff831161013f5761204f60209392849383016117b0565b84520151910152565b9080601f8301121561013f57815161206f8161171f565b9261207d6040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b8382106120a957505050505090565b815167ffffffffffffffff811161013f576020916120cc87848094880101612011565b81520191019061209a565b919060608382031261013f57604051906120f0826101f6565b819380516120fd8161179b565b8352602081015167ffffffffffffffff811161013f578261211f918301611f92565b602084015260408101519167ffffffffffffffff831161013f576040926121469201611eb6565b910152565b91909160a08184031261013f57805167ffffffffffffffff811161013f5781016101608185031261013f5761217e610245565b908051825261218f602082016117a5565b6020830152604081015167ffffffffffffffff811161013f57856121b4918301611e4f565b6040830152606081015167ffffffffffffffff811161013f57856121d9918301611eb6565b6060830152608081015167ffffffffffffffff811161013f57856121fe918301611f13565b608083015260a081015167ffffffffffffffff811161013f5785612223918301611f13565b60a083015260c081015167ffffffffffffffff811161013f5785612248918301611f92565b60c083015260e081015167ffffffffffffffff811161013f578561226d918301611f92565b60e083015261227f61010082016117a5565b6101008301526101208101519067ffffffffffffffff821161013f576122aa866101409383016117b0565b610120840152015161014082015292602082015167ffffffffffffffff811161013f57816122d9918401612058565b92604083015167ffffffffffffffff811161013f57826122fa9185016120d7565b92606081015192608082015167ffffffffffffffff811161013f576117f292016117b0565b906020808351928381520192019060005b81811061233d5750505090565b82516001600160a01b0316845260209384019390920191600101612330565b9080602083519182815201916020808360051b8301019401926000915b83831061238857505050505090565b90919293946020806123a6600193601f19868203018752895161231f565b97019301930191939290612379565b9080602083519182815201916020808360051b8301019401926000915b8383106123e157505050505090565b90919293946020806123ff600193601f198682030187528951610f04565b970193019301919392906123d2565b805182526020808201516001600160a01b03169083015290610140806124d96124b161249f61248d61247b61246961245760408b015161016060408c01526101608b019061231f565b60608b01518a820360608c0152610f04565b60808a015189820360808b015261235c565b60a089015188820360a08a015261235c565b60c088015187820360c08901526123b5565b60e087015186820360e08801526123b5565b610100868101516001600160a01b031690860152610120860151858203610120870152610e08565b93015191015290565b6117f291815115158152604061250760208401516060602085015260608401906123b5565b920151906040818403910152610f04565b9160809361254f61255d926125416001600160a01b03959a99989a60a0885260a088019061240e565b9086820360208801526124e2565b908482036040860152610e08565b951660608201520152565b1561256f57565b7fe823bd5a0000000000000000000000000000000000000000000000000000000060005260046000fd5b634e487b7160e01b600052603260045260246000fd5b80518210156125c35760209160051b010190565b612599565b906020806124d98451604085526040850190610e08565b92906125f39060a0855260a085019061240e565b8381036020850152825180825260208201916020808360051b8301019501926000915b83831061265e575050505050829161263f91600060406117f296015283820360608501526124e2565b9060808183039101526040906002815261060f60f31b60208201520190565b909192939560208061267c600193601f198682030187528a516125c8565b98019301930191939290612616565b926126b76117f295936126a9611d4f9460808852608088019061231f565b90868203602088015261231f565b908482036040860152610f04565b91906101608382031261013f576126da610245565b92805184526126eb602082016117a5565b60208501526126fc604082016117a5565b604085015260608101516060850152608081015167ffffffffffffffff811161013f578261272b918301611e4f565b608085015260a081015167ffffffffffffffff811161013f5782612750918301611e4f565b60a085015260c081015167ffffffffffffffff811161013f5782612775918301611eb6565b60c085015260e081015167ffffffffffffffff811161013f578261279a918301611eb6565b60e08501526127ac61010082016117a5565b61010085015261012081015167ffffffffffffffff811161013f57610140926127d69183016117b0565b6101208501520151610140830152565b91909160608184031261013f5760405190612800826101f6565b8193815161280d8161179b565b835260208201519167ffffffffffffffff831161013f576128346040939284938301611eb6565b60208501520151910152565b9160c08383031261013f57825167ffffffffffffffff811161013f57826128689185016126c5565b92602081015167ffffffffffffffff811161013f5783612889918301612011565b92604082015167ffffffffffffffff811161013f57816128aa9184016127e6565b926128b7606084016117a5565b9260808101519260a082015167ffffffffffffffff811161013f576117f292016117b0565b805182526020808201516001600160a01b031690830152906040828101516001600160a01b03169082015260608201516060820152610140806124d96124b161296061294e61293c608089015161016060808a015261016089019061231f565b60a089015188820360a08a015261231f565b60c088015187820360c0890152610f04565b60e087015186820360e0880152610f04565b908151151581526040806124d96020850151606060208601526060850190610f04565b9160809361254f61255d926129be6001600160a01b03959a99989a60a0885260a08801906128dc565b908682036020880152612972565b91926129f86117f2946129ea61263f9460a0875260a08701906128dc565b9085820360208701526125c8565b90600060408501528382036060850152612972565b919082606091031261013f57604051612a25816101f6565b60408082948051612a358161179b565b8452602081015160208501520151910152565b91828203610240811261013f576101601361013f57612a65610245565b83518152612a75602085016117a5565b6020820152612a86604085016117a5565b604082015260608401516060820152612aa1608085016117a5565b6080820152612ab260a085016117a5565b60a082015260c084015160c082015260e084015160e0820152612ad861010085016117a5565b6101008201526101208401516101208201526101408401516101408201529261016081015167ffffffffffffffff811161013f5783612b18918301612011565b92612b27816101808401612a0d565b92612b356101e084016117a5565b926102008101519261022082015167ffffffffffffffff811161013f576117f292016117b0565b610140809180518452612b7f602082015160208601906001600160a01b03169052565b6040818101516001600160a01b03169085015260608101516060850152612bb6608082015160808601906001600160a01b03169052565b60a0818101516001600160a01b03169085015260c081015160c085015260e081015160e0850152612bf96101008201516101008601906001600160a01b03169052565b6101208101516101208501520151910152565b9161020093612c4f612c6392612c2e866001600160a01b03969b9a999b612b5c565b805115156101608701526020810151610180870152604001516101a0860152565b6102206101c0850152610220840190610e08565b95166101e08201520152565b90612c996117f29493612c8584612cc494612b5c565b6102206101608501526102208401906125c8565b6000610180840152835115156101a084015260208401516101c08401526040909301516101e0830152565b6102008183039101526040906002815261060f60f31b60208201520190565b3d15612d0e573d90612cf482610264565b91612d026040519384610212565b82523d6000602084013e565b606090565b15612d1a57565b7ffe8a94f40000000000000000000000000000000000000000000000000000000060005260046000fd5b60405190612d53602083610212565b6000808352366020840137565b90612d6a8261171f565b612d776040519182610212565b8281528092612d88601f199161171f565b0190602036910137565b9081602091031261013f57517fffffffff000000000000000000000000000000000000000000000000000000008116810361013f5790565b6040906117f2949281528160208201520191611add565b919082604091031261013f576020823592013590565b634e487b7160e01b600052601160045260246000fd5b60ff601b9116019060ff8211612e1f57565b612df7565b90604010156125c35760400190565b929091906000843b612fbd5760418203612f30575090602092612eab83612e83612e7d612e6f612e67600098880188612de1565b949097612e24565b356001600160f81b03191690565b60f81c90565b935b604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156107b7576001600160a01b0360005116908115612f06576001600160a01b031603612edc57565b7f815e1d640000000000000000000000000000000000000000000000000000000060005260046000fd5b7f8baa579f0000000000000000000000000000000000000000000000000000000060005260046000fd5b60408203612f955750602092612f4e83612eab936000950190612de1565b929092612f8f612f8a612f847f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84169360ff1c90565b60ff1690565b612e0d565b93612e85565b807f4be6321b0000000000000000000000000000000000000000000000000000000060049252fd5b936020926001600160a01b03612fea9560405196879586948593630b135d3f60e11b855260048501612dca565b0392165afa9081156107b757630b135d3f60e11b917fffffffff0000000000000000000000000000000000000000000000000000000091849161305a575b5016036130325750565b807fb0669cbc0000000000000000000000000000000000000000000000000000000060049252fd5b61307c915060203d602011613082575b6130748183610212565b810190612d92565b38613028565b503d61306a565b9291939093613096613d76565b8551156135f0576130b060208751880101602088016118da565b955b51600090156135ea57506130c586613e3a565b945b6130d386838388613f5e565b85151595866135b6575b6130ea6101608701611984565b15613508576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b1561013f57869360008094613148604051978896879586946332910d0160e11b8652339360048701611afe565b03925af180156107b7576134f3575b505b60c0830135806132d4575061317e9161317661014085018561198e565b929091614fde565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166101008401936131b8858261198e565b90926131c6602084016119c4565b90803b1561013f5786600080946131f78995604051998a9788968795635abff4df60e01b8752339360048801611a4f565b03925af180156107b7577f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd936001600160a01b0393613273926132bf575b50608083013595613245846119c4565b9361158161326261325960e084018461198e565b92909b8461198e565b939092604051998a99169c8961364b565b0390a35b613287575b506102436001600055565b61077160206132b99201517f00000000000000000000000000000000000000000000000000000000000000009061412f565b3861327c565b806107ab60006132ce93610212565b38613235565b906132ef926132e761014086018661198e565b929091614e3d565b9193906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169061010083019561332d878561198e565b613339602087016119c4565b853b1561013f576000916133658a926040519586948594635abff4df60e01b8652339260048701613616565b038183885af180156107b7576134de575b508051613460575b5080516133ce575b50507f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd91506001600160a01b03906133c6608082013594611564836119c4565b0390a3613277565b6133d8868461198e565b929091813b1561013f576000809461340860405198899687958694635abff4df60e01b8652339260048701613616565b03925af19081156107b7577f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd926001600160a01b039261344b575b819250613386565b806107ab600061345a93610212565b38613443565b61346a878561198e565b9190843b1561013f576000916134b86040519485938493635abff4df60e01b85527f000000000000000000000000000000000000000000000000000000000000000092339260048701613616565b038183875af180156107b7571561337e57806107ab60006134d893610212565b3861337e565b806107ab60006134ed93610212565b38613376565b806107ab600061350293610212565b38613157565b5050506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661354260e085018561198e565b909161355261012087018761198e565b919061355d886119c4565b94823b1561013f5760009461358c869260405198899788968795635abff4df60e01b8752339460048801611a4f565b03925af180156107b7576135a1575b50613159565b806107ab60006135b093610212565b3861359b565b6135e5610d7489517f00000000000000000000000000000000000000000000000000000000000000009061412f565b6130dd565b946130c7565b6135f8611737565b613600611737565b613608610234565b9182526020820152956130b2565b93959490611a8460609461363d6001600160a01b039593869460808a5260808a01916119ce565b908782036020890152610f04565b9694926136899461366d61367b936117f29b999560808c5260808c01916119ce565b9189830360208b01526119ce565b918683036040880152611a12565b926060818503910152611a12565b92979097969495969391936136aa613d76565b6136b88186888b8d89615157565b851515948860005b878c8210613855575050505050506114bd6136fe917f00000000000000000000000000000000000000000000000000000000000000009687916141fd565b60005b86811061371957505050505050506102436001600055565b808388613729818660019661525d565b61378f818761374761373c888784613a67565b61010081019061198e565b6137636137588a8986979597613a67565b61014081019061198e565b9160c06137878c8b613781602061377b84848d613a67565b016119c4565b98613a67565b013595614532565b7f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd6001600160a01b0360806137c587868b613a67565b01359261381d6137d961154489888d613a67565b918a6137f36137e98b8a84613a67565b60e081019061198e565b909861158f6138128d61380a61373c828689613a67565b949096613a67565b61012081019061198e565b0390a361382b575b01613701565b6138506107718761384a613840858a8d613a45565b602081019061198e565b906141fd565b613825565b6139ff575b8b61387261016061386c84848c613a67565b01611984565b1561394957896138ad836001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016938b613a67565b91836138ba818989613abd565b9390968d60009060001461393f57506138df926113b9926138da92613a45565b613c19565b945b813b1561013f576000809461390d8b604051998a97889687956332910d0160e11b875260048701611afe565b03925af19182156107b75760019261392a575b505b0189906136c0565b806107ab600061393993610212565b38613920565b92505050946138e1565b91506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016876139846137e9848684613a67565b6139a46115448661399c613812828b899a989a613a67565b999096613a67565b823b1561013f576000946139d18b87936040519a8b9889978896635abff4df60e01b885260048801611a4f565b03925af19182156107b7576001926139ea575b50613922565b806107ab60006139f993610212565b386139e4565b613a40610d74613a19613a13848d87613a45565b8061198e565b7f0000000000000000000000000000000000000000000000000000000000000000916141fd565b61385a565b91908110156125c35760051b81013590603e198136030182121561013f570190565b91908110156125c35760051b8101359061017e198136030182121561013f570190565b903590601e198136030182121561013f570180359067ffffffffffffffff821161013f5760200191813603831361013f57565b908210156125c357613ad49160051b810190613a8a565b9091565b9080601f8301121561013f57813591613af08361171f565b92613afe6040519485610212565b80845260208085019160051b8301019183831161013f5760208101915b838310613b2a57505050505090565b823567ffffffffffffffff811161013f578201906080828703601f19011261013f5760405190613b59826101b9565b6020830135613b678161179b565b82526040830135613b77816102c7565b60208301526060830135604083015260808301359167ffffffffffffffff831161013f57613bad88602080969581960101610280565b6060820152815201920191613b1b565b919060408382031261013f5760405190613bd6826101da565b8193803567ffffffffffffffff811161013f5782613bf5918301613ad8565b835260208101359167ffffffffffffffff831161013f576020926121469201613ad8565b6117f2903690613bbd565b9081602091031261013f575190565b613c406101608201611984565b15613d5d57604051917f3644e5150000000000000000000000000000000000000000000000000000000083526020836004816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa9283156107b757600093613d1e575b50613ce9613d1092611315926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169161592f565b604051928391602083019586909160429261190160f01b8352600283015260228201520190565b03601f198101835282610212565b611315919350613d1092613d4c613ce99260203d602011613d56575b613d448183610212565b810190613c24565b9492509250613cad565b503d613d3a565b90611315613ce9613d1092613d70611d8e565b946156b3565b600260005414613d87576002600055565b7f3ee5aeb50000000000000000000000000000000000000000000000000000000060005260046000fd5b9080602083519182815201916020808360051b8301019401926000915b838310613ddd57505050505090565b9091929394602080613e2b600193601f19868203018752608060608b518051151584526001600160a01b03868201511686850152604081015160408501520151918160608201520190610e08565b97019301930191939290613dce565b602081018051511580613e90575b613e8957611315613d1091604051928391613e76602084019660208852516040808601526080850190613db1565b9051838203603f19016060850152613db1565b5050600090565b5081515115613e48565b15613ea157565b7f710c94970000000000000000000000000000000000000000000000000000000060005260046000fd5b15613ed257565b7f83dfb46e0000000000000000000000000000000000000000000000000000000060005260046000fd5b15613f0357565b7fec7706630000000000000000000000000000000000000000000000000000000060005260046000fd5b15613f3457565b7fc56873ba0000000000000000000000000000000000000000000000000000000060005260046000fd5b909260409261024394613f70846119c4565b6001600160a01b0316331415806140e8575b61408d575b505050613f9a6115e56101608301611984565b801561407c575b614055575b60a0810133613fb761058c836119c4565b1490811561403a575b50801561402d575b613fd190613e9a565b613ffb613fe261010083018361198e565b9050613ff261014084018461198e565b91905014613ecb565b61402461400b60e083018361198e565b905061401b61012084018461198e565b91905014613efc565b01354210613f2d565b5060608101354211613fc8565b6001600160a01b03915061404d906119c4565b161538613fc0565b614077614061826119c4565b60808301356402540be3ff858501351491615082565b613fa6565b506402540be3ff8282013514613fa1565b6140e092613d106140cf6140a96140a2611d8e565b93886156b3565b8851928391602083019586909160429261190160f01b8352600283015260228201520190565b5190206140db856119c4565b612e33565b388080613f87565b506140f96115e56101608601611984565b613f82565b1561410557565b7f9eb00a7e0000000000000000000000000000000000000000000000000000000060005260046000fd5b9060005b82518110156141c55761414681846125af565b5160008061417f61058c61058c6020860161093f61416b82516001600160a01b031690565b6001600160a01b03808c16911614156140fe565b604084015190606085015191602083519301915af161419c612ce3565b501590816141ba575b506141b257600101614133565b505050600090565b5115159050386141a5565b505050600190565b91908110156125c35760051b81013590607e198136030182121561013f570190565b908092918237016000815290565b91909160005b8381106142135750505050600190565b61421e8185846141cd565b60008061424e61058c61058c6020860161154461423a826119c4565b6001600160a01b03808d16911614156140fe565b60408401356142606060860186613a8a565b9190614271604051809481936141ef565b03925af161427d612ce3565b5015908161429c575b5061429357600101614203565b50505050600090565b6142a69150611984565b38614286565b91908110156125c35760051b0190565b91908203918211612e1f57565b156142d357505050565b6001600160a01b03907f875c683c000000000000000000000000000000000000000000000000000000006000521660045260245260445260646000fd5b909194929460005b838110614329575050505050505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61434f61058c6115448488886142ac565b60009291036144ca5760019150475b61436882896125af565b5288614484575b6143b761437c82896125af565b51614388838b876142ac565b35614397611544858a8a6142ac565b6143a2858d896142ac565b35916143ae868d6125af565b519310156142c9565b86818773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6143e061058c611544858c8c6142ac565b03614456576000808061440161440d956001600160a01b03839616976125af565b51865af1610e9d612ce3565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b662061444c61443b848b6125af565b516040519081529081906020820190565b0390a25b01614318565b5061447f915061058c61154461446d9289896142ac565b87614478848b6125af565b5191615a8b565b614450565b6144ba6144aa6144986115448489896142ac565b6144a2848b6125af565b51908c615a0f565b6144b4838a6125af565b516142bc565b6144c482896125af565b5261436f565b6144de61058c61058c6115448489896142ac565b6040516370a0823160e01b815230600482015290602090829060249082905afa9081156107b75760019391614514575b5061435e565b61452c915060203d8111613d5657613d448183610212565b3861450e565b91909294939460005b84811061454c575050505050505050565b6001908861463e575b614595614562828a6125af565b518961456f8487896142ac565b3561457e611544868c8c6142ac565b906143ae8661458e818b8d6142ac565b35946125af565b87818873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6145be61058c611544858d8d6142ac565b0361461757600080806144016145df956001600160a01b03839616976125af565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b662061460d61443b848c6125af565b0390a25b0161453b565b50614639915061058c61154461462e928a8a6142ac565b88614478848c6125af565b614611565b61466661465c614652611544848a8a6142ac565b6144a2848c6125af565b6144b4838b6125af565b614670828a6125af565b52614555565b91908201809211612e1f57565b9060005b6000198201828111612e1f578110156141b25760018101808211612e1f575b8281106146b65750600101614687565b6146c382848694966142ac565b356146cd816102c7565b6001600160a01b036146e661058c6115448588886142ac565b9116146146f8576001019290926146a6565b50505050600190565b9081518110156125c3570160200190565b6000198114612e1f5760010190565b6000929150825b604082015151841015614759576147516001916147498660808601516125af565b515190614676565b930192614728565b92509061476e61476884612d60565b93612d60565b60009384805b60408601515187101561496b57614793906147498860a08901516125af565b6147a18760808801516125af565b515160005b8181106147cb5750506147c36001916147498960808a01516125af565b960195614774565b7f08000000000000000000000000000000000000000000000000000000000000006001600160f81b031961481f6148116101208c015161480b8689614676565b90614701565b516001600160f81b03191690565b1614158015614963575b614836575b6001016147a6565b8761485461093f8361484e8d608060019601516125af565b516125af565b8a838b600160fa1b6001600160f81b031961487c6148118b61480b8761012088015192614676565b1614614947575b6148949260c061484e9201516125af565b519160005b8781106148ed575b509060019392916148b6575b5050905061482e565b6148d2906148c4888a6125af565b906001600160a01b03169052565b6148e56148de87614712565b96896125af565b5238806148ad565b896148fb61093f838c6125af565b6001600160a01b038086169116146149165750600101614899565b849392506149346001969561492e8461493b946125af565b51614676565b918b6125af565b526000909192936148a1565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9350614883565b506000614829565b50808252825293509150565b600092835b6040830151518510156149a55761499d6001916147498760a08701516125af565b94019361497c565b935090916149bb6149b585612d60565b94612d60565b6000916001918391829190825b604089015151871015614bd4576149e38760a08b01516125af565b5151855b818110614a26575050614a1e600191614a188b6147498b6080614a0e8260a08601516125af565b51519301516125af565b90614676565b9601956149c8565b868b89614b89575b50614a3c575b6001016149e7565b60018b8a83614a5661093f8261484e8560a08801516125af565b92600160fa1b6001600160f81b0319614a7c6148118b61480b8761012088015192614676565b1614614b6d575b885115614b4f575061484e614a9c9260208a01516125af565b519088908f9493945b8b5b838110614aed575b50600195614ac3575b505050509050614a34565b614ad0926148c4916125af565b614ae3614adc89614712565b98886125af565b523887818f614ab8565b9193949592908a614b0161093f85846125af565b6001600160a01b03808816911614614b2557505050600101918f8a92959493614aa7565b8391929450614b408761492e60019a999896614b47946125af565b918c6125af565b528b95614aaf565b614b609260e061484e9201516125af565b519088908f949394614aa5565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9350614a83565b7f07000000000000000000000000000000000000000000000000000000000000009150614bcb6148116101206001600160f81b031993015161480b8689614676565b1614158b614a2e565b50509550925050508084528252565b91906040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03831660248201526020816044816001600160a01b0388165afa9081156107b757600091614ce0575b5010614c4b575050565b6014526000196034526f095ea7b3000000000000000000000000600052602060006044601082855af13d15600160005114171615614c8c575b506000603452565b60006044601082602094816034526f095ea7b300000000000000000000000082528138858583855af15081196034525af13d15600160005114171615614cd25738614c84565b633e3f8f736000526004601cfd5b614cf9915060203d602011613d5657613d448183610212565b38614c41565b9060a08201614d0f815151612d60565b9060005b815151811015614d9a5780600160fa1b6001600160f81b0319614d3d6001946101208a0151614701565b511614600090600014614d7d575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b6001600160a01b03614d7383876125af565b9116905201614d13565b6001600160a01b0390614d918386516125af565b90505116614d61565b50509150565b15614da757565b7f692f31020000000000000000000000000000000000000000000000000000000060005260046000fd5b81810292918115918404141715612e1f57565b8115614dee570490565b634e487b7160e01b600052601260045260246000fd5b15614e0d575050565b7f871cbeab0000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b92949190606095614e4e8796615b5b565b94919690614e5d858514614da0565b61ffff614e6986612d60565b961680614f7f575b5061ffff1680614ed5575b505060005b838110614e92575050505093929190565b80614ecf614ea2600193886125af565b51614eae8387876142ac565b35614eba8488886142ac565b3590614ec6858b6125af565b51921015614e04565b01614e81565b909750614ee184612d60565b9760005b858110614ef25750614e7c565b80614f15614f0d85614f076001958b886142ac565b35614dd1565b612710900490565b614f1f828d6125af565b52614f2a81896125af565b51614f6157614f508b614f4983614f42818c896142ac565b35926125af565b51906142bc565b614f5a828a6125af565b5201614ee5565b614f7a8b614f4983614f73818d6125af565b51926125af565b614f50565b9950614f8a85612d60565b9960005b8b87808310614f9f57505050614e71565b90614fb983610bdc614f0d87614f0784600199988d6142ac565b52614fcd8d614f4983614f42818d8b6142ac565b614fd7828b6125af565b5201614f8e565b91909392841561504957614ff3818614614da0565b60005b858110615004575050509190565b8061504361501560019389886142ac565b356150218386886142ac565b3561502d8487896142ac565b359061503a858c8b6142ac565b35921015614e04565b01614ff6565b935090509190565b1561505857565b7f756688fe0000000000000000000000000000000000000000000000000000000060005260046000fd5b908015611122576150d891600160ff8360081c93161b936000906000146150db57506001600160a01b031660005260026020526040600020925b816000528360205260406000205461110e828083161415615051565b55565b6001600160a01b03604092168152600160205220926150bc565b156150fc57565b7fa18792da0000000000000000000000000000000000000000000000000000000060005260046000fd5b1561512d57565b7fb82564ab0000000000000000000000000000000000000000000000000000000060005260046000fd5b939295948615918181036152025787811480156151fb575b615178906150f5565b60005b81811061518d57505050505050509050565b6001906151ae306151a761058c602061377b86898f613a67565b1415615126565b6151de6151bc82858b613a67565b828c6151c982898d613abd565b9290918b8b156151e457505050600092613f5e565b0161517b565b6151f5926113b9926138da92613a45565b92613f5e565b508261516f565b7f6e3779d80000000000000000000000000000000000000000000000000000000060005260046000fd5b1561523357565b7fadfbc6fc0000000000000000000000000000000000000000000000000000000060005260046000fd5b929161526a848284613a67565b93610100850161528461527d828861198e565b9050612d60565b9361014087019360005b615298848a61198e565b90508110156154e357600090855b8381106153f5575089878973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6152e061058c611544876152da8d8961198e565b906142ac565b14886000916000146153635750506152da8261533086809461532060019a61531b8a615314866152da6153379d479461198e565b3590614dd1565b614de4565b61532a83836125af565b526125af565b519461198e565b3511615344575b0161528e565b615352816152da898d61198e565b3561535d828a6125af565b5261533e565b61537f935061058c9250856152da6115449261058c949761198e565b6040516370a0823160e01b815230600482015290602090829060249082905afa9081156107b7576152da8a6153308f958e61532060019a61531b8a6153148d6152da8a6153379e839e849b916153d7575b509461198e565b6153ef915060203d8111613d5657613d448183610212565b386153d0565b95909860009a989294979a9593955b61541261373c89898c613a67565b90508110156154cd57896001600160a01b0361545161058c6115448f6152da8f8f8f8a8f9361373c61544b94611544946152da93613a67565b9761198e565b911614615461575b600101615404565b948561546e89898c613a67565b610140810161547c9161198e565b61548692916142ac565b3561549091614676565b9461549e60c08b0135615c0e565b6154a989898c613a67565b60c001356154b690615c0e565b61ffff166154c89161ffff161461522c565b615459565b509890956001909a979492989a959395016152a6565b509496505050505050565b6040517f4a616d4f7264657228616464726573732074616b65722c61646472657373207260208201527f656365697665722c75696e74323536206578706972792c75696e74323536206560408201527f78636c75736976697479446561646c696e652c75696e74323536206e6f6e636560608201527f2c61646472657373206578656375746f722c75696e7432353620706172746e6560808201527f72496e666f2c616464726573735b5d2073656c6c546f6b656e732c616464726560a08201527f73735b5d20627579546f6b656e732c75696e743235365b5d2073656c6c416d6f60c08201527f756e74732c75696e743235365b5d20627579416d6f756e74732c62797465733360e08201527f3220686f6f6b734861736829000000000000000000000000000000000000000061010082015260ec81526117f261010c82610212565b61563a6154ee565b6020815191012090565b9060005b8181106156555750505090565b9091926020806001926001600160a01b038735615671816102c7565b168152019401929101615648565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811161013f5760051b809282370190565b6156bb615632565b916156c5826119c4565b926156d2602084016119c4565b91604084013593606081013590608081013560a082016156f1906119c4565b60c083013561570360e085018561198e565b90604051809160208201809461571892615644565b03601f198101825261572a9082610212565b5190209161573c61010086018661198e565b90604051809160208201809461575192615644565b03601f19810182526157639082610212565b5190209361577561012087018761198e565b90604051809160208201809461578a9261567f565b03601f198101825261579c9082610212565b5190209561014081016157ae9161198e565b9060405180916020820180946157c39261567f565b03601f19810182526157d59082610212565b519020966040519b8c9b60208d019e8f9c61585d9d9a98969492909d9c9b99979593916101a08c019e8c526001600160a01b031660208c01526001600160a01b031660408b015260608a0152608089015260a08801526001600160a01b031660c087015260e08601526101008501526101208401526101408301526101608201526101800152565b03601f19810182526113159082610212565b9061588260209282815194859201610de5565b0190565b61588e6154ee565b6117f2602e603160405180947f4a616d4f72646572207769746e6573732900000000000000000000000000000060208301526158d38151809260208686019101610de5565b81017f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75838201527f696e7432353620616d6f756e742900000000000000000000000000000000000060518201520301600e810184520182610212565b9091615939615c22565b5060e0820161595261594b828561198e565b9050615c42565b9461012084019260005b615966848761198e565b90508110156159cd57806159836115446001936152da888b61198e565b615991826152da898b61198e565b356159ac61599d610234565b6001600160a01b039093168352565b60208201526159bb828b6125af565b526159c6818a6125af565b500161595c565b50936117f29591969350615a01925060808101356040820135906159ef610255565b958652602086015260408501526156b3565b615a09615886565b91615d7b565b9190615a1c600093615b5b565b919061ffff8116615a76575b505061ffff8116615a3a575b50505090565b615a65927f000000000000000000000000000000000000000000000000000000000000000092615e57565b8101809111612e1f57388080615a34565b615a839295508484615e57565b923880615a28565b600091826044926020956001600160a01b03604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d1160016000511416171615615ae757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b9061ffff8091169116019061ffff8211612e1f57565b9061ffff8216906001600160a01b0361ffff8460101c169360201c1661271061ffff615b878587615b45565b161015615be457831580801591615bce575b5015615ba457929190565b7fb7273bd50000000000000000000000000000000000000000000000000000000060005260046000fd5b905080615bdc575b38615b99565b508015615bd6565b7f721dbfea0000000000000000000000000000000000000000000000000000000060005260046000fd5b6117f29061ffff808260101c169116615b45565b60405190615c2f826101f6565b6000604083606081528260208201520152565b90615c4c8261171f565b615c596040519182610212565b8281528092615c6a601f199161171f565b019060005b828110615c7b57505050565b602090604051615c8a816101da565b6000815260008382015282828501015201615c6f565b60405190615caf60a083610212565b606b82527f3620646561646c696e652c0000000000000000000000000000000000000000006080837f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208201527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c6164647260408201527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608201520152565b805160209091019060005b818110615d655750505090565b8251845260209384019390920191600101615d58565b909291613d10615da7615d8c615ca0565b92604051928391615da160208401809761586f565b9061586f565b51902092815151615db781612d60565b9060005b818110615e2f5750506113159291613d1091604051615de281613d10602082018095615d4d565b51902092604060208201519101519060405196879560208701998a926001600160a01b039060a095929897969360c086019986526020860152166040840152606083015260808201520152565b80615e46615e4060019388516125af565b51615ee9565b615e5082866125af565b5201615dbb565b90615e736127109161ffff6001600160a01b0396951690614dd1565b049283911673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103615edf5750506001600160a01b0316615eb2600080808086865af1610e9d612ce3565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b66206020604051848152a290565b916117f292615a8b565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a184526001600160a01b038151166040840152015160608201526060815261131560808261021256fea2646970667358221220da6c85282a2cc6cde7c75dcde65f8361cd5c7c90ecba328016a401e28804a3c364736f6c634300081b003360c0346100bd57601f612ad838819003918201601f19168301916001600160401b038311848410176100c25780849260409485528339810103126100bd57610052602061004b836100d8565b92016100d8565b6080919091526001600160a01b031660a0526040516129eb90816100ed82396080518181816103b001528181610c140152818161109a015281816114e80152818161184a0152611ad7015260a051818181610c52015281816110cb015281816118200152611b150152f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036100bd5756fe6080604052600436101561001257600080fd5b60003560e01c806357c3af1e146100675780635abff4df1461006257806365221a021461005d57806377c19c1f146100585763fbfa3c5b1461005357600080fd5b610a27565b6107e5565b61050c565b610337565b34610141573660031901610220811261014157610160136101415761008a6101bb565b60043581526100976101fc565b60208201526100a4610209565b604082015260643560608201526100b9610216565b60808201526100c6610223565b60a082015260c43560c082015260e43560e08201526100e3610230565b610100820152610124356101208201526101443561014082015261010636610271565b906101c4359167ffffffffffffffff83116101415761012c61013f9336906004016102af565b61013461023e565b916102043593610c0b565b005b600080fd5b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff82111761017857604052565b610146565b6040810190811067ffffffffffffffff82111761017857604052565b90601f8019910116810190811067ffffffffffffffff82111761017857604052565b604051906101cb61016083610199565b565b604051906101cb604083610199565b604051906101cb606083610199565b6001600160a01b0381160361014157565b602435906101cb826101eb565b604435906101cb826101eb565b608435906101cb826101eb565b60a435906101cb826101eb565b61010435906101cb826101eb565b6101e435906101cb826101eb565b606435906101cb826101eb565b35906101cb826101eb565b3590811515820361014157565b606090610163190112610141576040519061028b8261015c565b8161016435801515810361014157815261018435602082015260406101a435910152565b81601f820112156101415780359067ffffffffffffffff821161017857604051926102e4601f8401601f191660200185610199565b8284526020838301011161014157816000926020809301838601378301015290565b9181601f840112156101415782359167ffffffffffffffff8311610141576020808501948460051b01011161014157565b346101415760803660031901126101415760043567ffffffffffffffff811161014157610368903690600401610306565b9060243567ffffffffffffffff811161014157610389903690600401610306565b60449391933590610399826101eb565b606435926103a6846101eb565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016946103dc863314610bda565b60005b8281106103e857005b87868686868673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6104256104196104148a868661106b565b611080565b6001600160a01b031690565b1461045c578661045695936104496104196104148460019c9b999761044f9761106b565b9561106b565b3592611f0a565b016103df565b505050508891506001600160a01b03160361047a575b600190610456565b61048581858a61106b565b3590873b15610141576040517f7c317e0f0000000000000000000000000000000000000000000000000000000081526001600160a01b03881660048201526024810192909252600082604481838c5af1918215610507576001926104ec575b509050610472565b806104fb600061050193610199565b80610f88565b386104e4565b611049565b346101415760803660031901126101415760043567ffffffffffffffff81116101415761018060031982360301126101415760243567ffffffffffffffff811161014157366023820112156101415780600401359167ffffffffffffffff83116101415736602484840101116101415761013f9260443591602461058e61024c565b94019060040161108a565b67ffffffffffffffff81116101785760051b60200190565b9080601f830112156101415781356105c881610599565b926105d66040519485610199565b81845260208085019260051b82010192831161014157602001905b8282106105fe5750505090565b60208091833561060d816101eb565b8152019101906105f1565b9080601f8301121561014157813561062f81610599565b9261063d6040519485610199565b81845260208085019260051b82010192831161014157602001905b8282106106655750505090565b8135815260209182019101610658565b9080601f8301121561014157813561068c81610599565b9261069a6040519485610199565b81845260208085019260051b820101918383116101415760208201905b8382106106c657505050505090565b813567ffffffffffffffff8111610141576020916106e9878480948801016105b1565b8152019101906106b7565b9080601f8301121561014157813561070b81610599565b926107196040519485610199565b81845260208085019260051b820101918383116101415760208201905b83821061074557505050505090565b813567ffffffffffffffff81116101415760209161076887848094880101610618565b815201910190610736565b9190606083820312610141576040519061078c8261015c565b819361079781610264565b8352602081013567ffffffffffffffff811161014157826107b99183016106f4565b602084015260408101359167ffffffffffffffff8311610141576040926107e09201610618565b910152565b346101415760a03660031901126101415760043567ffffffffffffffff81116101415761016060031982360301126101415761081f6101bb565b908060040135825261083360248201610259565b6020830152604481013567ffffffffffffffff81116101415761085c90600436918401016105b1565b6040830152606481013567ffffffffffffffff8111610141576108859060043691840101610618565b6060830152608481013567ffffffffffffffff8111610141576108ae9060043691840101610675565b608083015260a481013567ffffffffffffffff8111610141576108d79060043691840101610675565b60a083015260c481013567ffffffffffffffff81116101415761090090600436918401016106f4565b60c083015260e481013567ffffffffffffffff81116101415761092990600436918401016106f4565b60e083015261093b6101048201610259565b6101008301526101248101359067ffffffffffffffff82116101415761096a61014492600436918401016102af565b610120840152013561014082015260243567ffffffffffffffff811161014157610998903690600401610773565b906044359167ffffffffffffffff8311610141576109bd61013f9336906004016102af565b6109c561024c565b91608435936114d9565b91909160608184031261014157604051906109e98261015c565b81936109f482610264565b835260208201359167ffffffffffffffff831161014157610a1b6040939284938301610618565b60208501520135910152565b346101415760a03660031901126101415760043567ffffffffffffffff811161014157610160600319823603011261014157610a616101bb565b9080600401358252610a7560248201610259565b6020830152610a8660448201610259565b604083015260648101356060830152608481013567ffffffffffffffff811161014157610ab990600436918401016105b1565b608083015260a481013567ffffffffffffffff811161014157610ae290600436918401016105b1565b60a083015260c481013567ffffffffffffffff811161014157610b0b9060043691840101610618565b60c083015260e481013567ffffffffffffffff811161014157610b349060043691840101610618565b60e0830152610b466101048201610259565b6101008301526101248101359067ffffffffffffffff821161014157610b7561014492600436918401016102af565b610120840152013561014082015260243567ffffffffffffffff811161014157610ba39036906004016109cf565b906044359167ffffffffffffffff831161014157610bc861013f9336906004016102af565b610bd061024c565b9160843593611ad0565b15610be157565b7f48f5c3ed0000000000000000000000000000000000000000000000000000000060005260046000fd5b90929193610cfe7f000000000000000000000000000000000000000000000000000000000000000091610c486001600160a01b0384163314610bda565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693610c8760808201516001600160a01b031690565b9660c082018051610ca8610c996101cd565b6001600160a01b03909b168b52565b60208a015261014083015160801c835190610cc16101dc565b9a8b5260208b015260408a015251610ce9610cda6101cd565b6001600160a01b039097168752565b60208601526040602082015191015191611e40565b94610d07610ed8565b94833b1561014157610d4e600096928793604051998a98899788967f137c29fe00000000000000000000000000000000000000000000000000000000885260048801610fb8565b03925af1801561050757610d5f5750565b806104fb60006101cb93610199565b6040517f53696e676c654f726465722875696e74363420706172746e65725f69642c756960208201527f6e74323536206578706972792c616464726573732074616b65725f616464726560408201527f73732c61646472657373206d616b65725f616464726573732c75696e7432353660608201527f206d616b65725f6e6f6e63652c616464726573732074616b65725f746f6b656e60808201527f2c61646472657373206d616b65725f746f6b656e2c75696e743235362074616b60a08201527f65725f616d6f756e742c75696e74323536206d616b65725f616d6f756e742c6160c08201527f6464726573732072656365697665722c75696e74323536207061636b65645f6360e08201527f6f6d6d616e64732c6279746573333220686f6f6b73486173682900000000000061010082015260fa8152610eb261011a82610199565b90565b60005b838110610ec85750506000910152565b8181015183820152602001610eb8565b6034610eb2610ee5610d6e565b610f7a6040519384927f53696e676c654f72646572207769746e657373290000000000000000000000006020850152610f278151809260208588019101610eb5565b830101602e907f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c7581527f696e7432353620616d6f756e742900000000000000000000000000000000000060208201520190565b03601f198101835282610199565b600091031261014157565b90602091610fac81518092818552858086019101610eb5565b601f01601f1916010190565b949161103a9361101b6001600160a01b03926040610eb29a9895610ff08b8251602080916001600160a01b0381511684520151910152565b6020818101518c84015291015160608b015281516001600160a01b031660808b0152015160a0890152565b1660c086015260e0850152610140610100850152610140840190610f93565b91610120818403910152610f93565b6040513d6000823e3d90fd5b634e487b7160e01b600052603260045260246000fd5b919081101561107b5760051b0190565b611055565b35610eb2816101eb565b9190946110c16001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163314610bda565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916110f4611fcc565b5060e084019261110e6111078587611fec565b9050612022565b956000986101208701995b6111238789611fec565b905081101561119257808b6111568261114961114f6104146001978f8f61114991611fec565b9061106b565b938d611fec565b356111716111626101cd565b6001600160a01b039093168352565b6020820152611180828c612080565b5261118b818b612080565b5001611119565b509296976111c9919499506111d992955060808701356040880135906111b66101dc565b9a8b5260208b015260408a015286612094565b926111d386611080565b95612191565b956111e2611353565b843b15610141576000968793610d4e926040519a8b998a98899763fe8ec1a760e01b895260048901611464565b6040517f4a616d4f7264657228616464726573732074616b65722c61646472657373207260208201527f656365697665722c75696e74323536206578706972792c75696e74323536206560408201527f78636c75736976697479446561646c696e652c75696e74323536206e6f6e636560608201527f2c61646472657373206578656375746f722c75696e7432353620706172746e6560808201527f72496e666f2c616464726573735b5d2073656c6c546f6b656e732c616464726560a08201527f73735b5d20627579546f6b656e732c75696e743235365b5d2073656c6c416d6f60c08201527f756e74732c75696e743235365b5d20627579416d6f756e74732c62797465733360e08201527f3220686f6f6b734861736829000000000000000000000000000000000000000061010082015260ec8152610eb261010c82610199565b6031610eb261136061120f565b610f7a6040519384927f4a616d4f72646572207769746e657373290000000000000000000000000000006020850152610f278151809260208588019101610eb5565b90606081019180519260608352835180915260206080840194019060005b8181106113e0575050506040816020829301516020850152015191015290565b90919460206040826114086001948a51602080916001600160a01b0381511684520151910152565b0196019291016113c0565b906020808351928381520192019060005b8181106114315750505090565b90919260206040826114596001948851602080916001600160a01b0381511684520151910152565b019401929101611424565b959290948795946001600160a01b0361149c6114b59561148f60209c9960c08d5260c08d01906113a2565b908b82038d8d0152611413565b9316604089015260608801528682036080880152610f93565b9360a0818603910152818452848401376000828201840152601f01601f1916010190565b949361150f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163314610bda565b600092839484955b604089015151871015611548576115406001916115388960808d0151612080565b515190612351565b960195611517565b93979691945091945061156361155d84612363565b93612363565b936000926000986000995b60408a0151518b10156117fc5761158d906115388c60a08d0151612080565b8a8a61159d826080830151612080565b515160005b8181106115c7575050916115386115bf9260806001950151612080565b9a019961156e565b917f080000000000000000000000000000000000000000000000000000000000000091935061164f6116296101207fff000000000000000000000000000000000000000000000000000000000000009301516116238689612351565b90612395565b517fff000000000000000000000000000000000000000000000000000000000000001690565b16141580156117f4575b61166a575b6001018c918c916115a2565b8c8c6001918361169861168b82611685856080880151612080565b51612080565b516001600160a01b031690565b917f04000000000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000006116f26116298b611623876101208b015192612351565b16146117d8575b6117148f94968f928f959497989060c0611685920151612080565b51936000905b84821061176f575b5050600195611737575b50505050905061165e565b6117529261174491612080565b906001600160a01b03169052565b61176561175e8b6123a6565b9a8d612080565b523889818c61172c565b9092949596939161168b8461178392612080565b6001600160a01b038087169116146117a7575050600101918c8c929594938f61171a565b9092506117cd826117c7876117c160019a99989686612080565b51612351565b92612080565b528c6000958f611722565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92506116f9565b506000611659565b5093611880939950979095969197808652875261186f611847886001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001697846123b5565b977f000000000000000000000000000000000000000000000000000000000000000090612455565b936040602082015191015191612528565b94611889611a23565b94833b1561014157610d4e600096928793604051998a988997889663fe8ec1a760e01b885260048801611a72565b6040517f4167677265676174654f726465722875696e74363420706172746e65725f696460208201527f2c75696e74323536206578706972792c616464726573732074616b65725f616460408201527f64726573732c616464726573735b5d206d616b65725f6164647265737365732c60608201527f75696e743235365b5d206d616b65725f6e6f6e6365732c616464726573735b5d60808201527f5b5d2074616b65725f746f6b656e732c616464726573735b5d5b5d206d616b6560a08201527f725f746f6b656e732c75696e743235365b5d5b5d2074616b65725f616d6f756e60c08201527f74732c75696e743235365b5d5b5d206d616b65725f616d6f756e74732c61646460e08201527f726573732072656365697665722c627974657320636f6d6d616e64732c6279746101008201527f6573333220686f6f6b734861736829000000000000000000000000000000000061012082015261010f8152610eb261012f82610199565b6037610eb2611a306118b7565b610f7a6040519384927f4167677265676174654f72646572207769746e657373290000000000000000006020850152610f278151809260208588019101610eb5565b9490936001600160a01b03611aa9611ac29594611a9b610eb29a9860c08b5260c08b01906113a2565b9089820360208b0152611413565b9316604087015260608601528482036080860152610f93565b9160a0818403910152610f93565b94909392917f000000000000000000000000000000000000000000000000000000000000000092611b0b6001600160a01b0385163314610bda565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016611b3d611fcc565b506080880196611b4e885151612022565b9660009960c081019a5b8a518051821015611bac57908c611b7f82611b7861168b82600197612080565b9251612080565b51611b8b6111626101cd565b6020820152611b9a828d612080565b52611ba5818c612080565b5001611b58565b50509194985091949850611beb611bfc9396611bcd61014084015160801c90565b835190611bd86101dc565b9a8b5260208b015260408a0152826126b9565b936040602082015191015191612735565b94611889611d49565b6040517f4d756c74694f726465722875696e74363420706172746e65725f69642c75696e60208201527f74323536206578706972792c616464726573732074616b65725f61646472657360408201527f732c61646472657373206d616b65725f616464726573732c75696e743235362060608201527f6d616b65725f6e6f6e63652c616464726573735b5d2074616b65725f746f6b6560808201527f6e732c616464726573735b5d206d616b65725f746f6b656e732c75696e74323560a08201527f365b5d2074616b65725f616d6f756e74732c75696e743235365b5d206d616b6560c08201527f725f616d6f756e74732c616464726573732072656365697665722c627974657360e08201527f20636f6d6d616e64732c6279746573333220686f6f6b7348617368290000000061010082015260fc8152610eb261011c82610199565b6033610eb2611d56611c05565b610f7a6040519384927f4d756c74694f72646572207769746e65737329000000000000000000000000006020850152610f278151809260208588019101610eb5565b611da0610d6e565b6020815191012090565b9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a01526001600160a01b0316608089015260a08801526001600160a01b031660c087015260e08601611e18916001600160a01b03169052565b6101008501526101208401526001600160a01b03166101408301526101608201526101800152565b909161014082015160401c611e5c9067ffffffffffffffff1690565b93611e65611d98565b918351936020810151611e7e906001600160a01b031690565b956040820151611e94906001600160a01b031690565b926080830151611eaa906001600160a01b031690565b60a08401516001600160a01b03169060c085015192610100860151611ed5906001600160a01b031690565b956101200151966040519b8c9b60208d019e8f9c611ef29d611daa565b03601f1981018252611f049082610199565b51902090565b9060006064926020956001600160a01b03839681604051967f23b872dd00000000000000000000000000000000000000000000000000000000885216600487015216602485015260448401525af13d15601f3d1160016000511416171615611f6e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b60405190611fd98261015c565b6000604083606081528260208201520152565b903590601e1981360301821215610141570180359067ffffffffffffffff821161014157602001918160051b3603831361014157565b9061202c82610599565b6120396040519182610199565b828152809261204a601f1991610599565b019060005b82811061205b57505050565b60209060405161206a8161017d565b600081526000838201528282850101520161204f565b805182101561107b5760209160051b010190565b9060e08201916120a76111078483611fec565b9360005b6120b58584611fec565b9050811015612113576001816120d66120b593611149610120880188611fec565b35604051906120e48261017d565b6001600160a01b038816825260208201526120ff828a612080565b5261210a8189612080565b500190506120ab565b5092505050565b611da061120f565b9060005b8181106121335750505090565b9091926020806001926001600160a01b03873561214f816101eb565b168152019401929101612126565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81116101415760051b809282370190565b61219961211a565b916121a382611080565b926121b060208401611080565b91604084013593606081013590608081013560a082016121cf90611080565b60c08301356121e160e0850185611fec565b9060405180916020820180946121f692612122565b03601f19810182526122089082610199565b5190209161221a610100860186611fec565b90604051809160208201809461222f92612122565b03601f19810182526122419082610199565b51902093612253610120870187611fec565b9060405180916020820180946122689261215d565b03601f198101825261227a9082610199565b51902095610140810161228c91611fec565b9060405180916020820180946122a19261215d565b03601f19810182526122b39082610199565b519020966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c526001600160a01b031660208c01526001600160a01b031660408b015260608a0152608089015260a08801526001600160a01b031660c087015260e08601526101008501526101208401526101408301526101608201526101800152565b634e487b7160e01b600052601160045260246000fd5b9190820180921161235e57565b61233b565b9061236d82610599565b61237a6040519182610199565b828152809261238b601f1991610599565b0190602036910137565b90815181101561107b570160200190565b600019811461235e5760010190565b9291906123c0611fcc565b506123cb8151612022565b9260005b825181101561242657806001600160a01b036123ed60019386612080565b51166123f98287612080565b516124056111626101cd565b60208201526124148288612080565b5261241f8187612080565b50016123cf565b509391505061243a61014082015160801c90565b9051906124456101dc565b9283526020830152604082015290565b906124608251612022565b9160005b81518110156124b5578061247a60019284612080565b51604051906124888261017d565b6001600160a01b038616825260208201526124a38287612080565b526124ae8186612080565b5001612464565b50505090565b611da06118b7565b805160209091019060005b8181106124db5750505090565b82516001600160a01b03168452602093840193909201916001016124ce565b805160209091019060005b8181106125125750505090565b8251845260209384019390920191600101612505565b909161014082015161253a9060401c90565b67ffffffffffffffff169361254d6124bb565b918351936020810151612566906001600160a01b031690565b9560408201516040518060208101928361257f916124c3565b03601f19810182526125919082610199565b51902092604051806020810192836125a8916124fa565b03601f19810182526125ba9082610199565b5190209060808301516125cc9061290b565b8051906020012060a08401516125e19061290b565b805190602001209060c08501516125f79061296b565b80519060200120926126089061296b565b8051906020012093610100860151612626906001600160a01b031690565b95610120015180519060200120966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a0152608089015260a088015260c087015260e08601526101008501526101208401526001600160a01b03166101408301526101608201526101800152565b919060808301926126cb845151612022565b9260005b85515181101561272557806126ea60019260c0860151612080565b51604051906126f88261017d565b6001600160a01b038716825260208201526127138288612080565b5261271e8187612080565b50016126cf565b509350505090565b611da0611c05565b906101408201516127469060401c90565b67ffffffffffffffff169361275961272d565b918351936020810151612772906001600160a01b031690565b956040820151612788906001600160a01b031690565b926080830151604051806020810192836127a1916124c3565b03601f19810182526127b39082610199565b51902060a0840151604051806020810192836127ce916124c3565b03601f19810182526127e09082610199565b5190209060c0850151604051806020810192836127fc916124fa565b03601f198101825261280e9082610199565b5190209260405180602081019283612825916124fa565b03601f19810182526128379082610199565b51902093610100860151612851906001600160a01b031690565b95610120015180519060200120966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a01526001600160a01b0316608089015260a088015260c087015260e08601526101008501526101208401526001600160a01b03166101408301526101608201526101800152565b6020929190612903849282815194859201610eb5565b019081520190565b60609080516000905b8082106129215750505090565b909193926001906129616129358588612080565b5160405161294b81610f7a6020820180956124c3565b51902091610f7a604051938492602084016128ed565b9394920190612914565b60609080516000905b8082106129815750505090565b909193926001906129ab6129958588612080565b5160405161294b81610f7a6020820180956124fa565b939492019061297456fea264697066735822122090133a57e321b8c2b3310a805d062cbbf658583bcc121b2474df437f5235ceb564736f6c634300081b0033000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f0000000000000000000000001af49c826ea0a8f29ea448f2171d1bcb716cb22d

Deployed Bytecode

0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80632143d82c1461012b5780633644e51514610126578063416e6d5e146101215780634a0d98781461011c578063796f077b146101175780637c317e0f146101125780637eea39f21461010d57806384b0196e14610108578063971604c614610103578063a03f5274146100fe578063a5cdc8fc146100f9578063acb8cc49146100f4578063b06b61db146100ef578063b57f9fed146100ea578063c7977be7146100e5578063f0a5f8f2146100e05763f80b26e30361000e57611375565b611336565b61131b565b6111e7565b6111a3565b611187565b6110ba565b611020565b610fd4565b610f38565b610ea3565b610e61565b610e2d565b6103fb565b6103b7565b610394565b6102e3565b908161018091031261013f5790565b600080fd5b9181601f8401121561013f5782359167ffffffffffffffff831161013f576020838186019501011161013f57565b9181601f8401121561013f5782359167ffffffffffffffff831161013f576020808501948460051b01011161013f57565b634e487b7160e01b600052604160045260246000fd5b6080810190811067ffffffffffffffff8211176101d557604052565b6101a3565b6040810190811067ffffffffffffffff8211176101d557604052565b6060810190811067ffffffffffffffff8211176101d557604052565b90601f8019910116810190811067ffffffffffffffff8211176101d557604052565b60405190610243604083610212565b565b6040519061024361016083610212565b60405190610243606083610212565b67ffffffffffffffff81116101d557601f01601f191660200190565b81601f8201121561013f5780359061029782610264565b926102a56040519485610212565b8284526020838301011161013f57816000926020809301838601378301015290565b6001600160a01b0381160361013f57565b3590610243826102c7565b60a036600319011261013f5760043567ffffffffffffffff811161013f5761030f903690600401610130565b60243567ffffffffffffffff811161013f5761032f903690600401610144565b919060443567ffffffffffffffff811161013f57610351903690600401610172565b906064359467ffffffffffffffff861161013f57610376610019963690600401610280565b9360843595610384876102c7565b6113be565b600091031261013f57565b3461013f57600036600319011261013f5760206103af611d8e565b604051908152f35b3461013f57600036600319011261013f5760206040516001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a168152f35b608036600319011261013f57600435610413816102c7565b602435600381101561013f5760443567ffffffffffffffff811161013f5761043f903690600401610280565b9160643567ffffffffffffffff811161013f57610460903690600401610280565b92610469613d76565b835115610d845761048360208551860101602086016118da565b935b5160009015610d7e575061049884613e3a565b905b8115159384610d45575b6104ad81611e2f565b8061081c5750806020806104c693518301019101612a48565b6001600160a01b03979396919495977f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16803b1561013f578760008a61053d8296604051998a97889687957f57c3af1e00000000000000000000000000000000000000000000000000000000875260048701612c0c565b03925af19081156107b75761056c926001600160a01b0392610807575b50166001600160a01b03166040860152565b806107bc575b50608083019061059861058c83516001600160a01b031690565b6001600160a01b031690565b916001600160a01b0360c08601936105d58551917f000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f928391614be3565b16803b1561013f578460009161061c94836040518097819582947f1a4990260000000000000000000000000000000000000000000000000000000084528d60048501612c6f565b03925af180156107b7577fca180a308256a6e9607c256dd145d700f18b1ee21e9bfa2919258b31a211bb8a936001600160a01b039361072c9261079c575b5061068261066d61014089015160801c90565b6fffffffffffffffffffffffffffffffff1690565b966106a961069b6101008301516001600160a01b031690565b94516001600160a01b031690565b610120820151909790600216156107885773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee925b51916106dd8251151590565b1561077c575060200151915b6fffffffffffffffffffffffffffffffff6040519687961699169785909493926001600160a01b0360609381608085019816845216602083015260408201520152565b0390a35b61073f575b6100196001600055565b61077160206107769201517f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9061412f565b611d5d565b38610735565b60e091500151916106e9565b60a08201516001600160a01b0316926106d1565b806107ab60006107b193610212565b80610389565b3861065a565b611a91565b61014084016108006107df6107d2835160401c90565b67ffffffffffffffff1690565b67ffffffffffffffff6107f86107d26107d28760401c90565b911614612568565b5238610572565b806107ab600061081693610212565b3861055a565b61082881949394611e2f565b60018103610acb57508060208061084493518301019101612840565b6001600160a01b0399959693979194997f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16803b1561013f57886000896108bc8296604051998a97889687957ffbfa3c5b00000000000000000000000000000000000000000000000000000000875260048701612995565b03925af19081156107b7576108eb926001600160a01b0392610ab6575b50166001600160a01b03166040850152565b80610a99575b5091927f000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f929060005b6080840151805182101561096757906109618661094c61058c61093f856001976125af565b516001600160a01b031690565b61095a8460c08a01516125af565b5190614be3565b0161091a565b505093926001600160a01b039095919516803b1561013f57836000916109be93836040518096819582947fefe34fe60000000000000000000000000000000000000000000000000000000084528a600485016129cc565b03925af180156107b757610a84575b507fa3f15217206817f5e14f76307e5f65cfdc211516553c6638ef4fc79c4d6a0f0a6001600160a01b03610a0961066d61014085015160801c90565b93610a70610a226101008601516001600160a01b031690565b91608086015195610a3281614cff565b9160c082015191610a438251151590565b15610a78575060200151915b6fffffffffffffffffffffffffffffffff604051968796169916978561268b565b0390a3610730565b60e09150015191610a4f565b806107ab6000610a9393610212565b386109cd565b6101408301610aaf6107df6107d2835160401c90565b52386108f1565b806107ab6000610ac593610212565b386108d9565b80610ada600292979697611e2f565b03610d1b5780602080610af29351830101910161214b565b6001600160a01b0397949592969193977f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16803b1561013f5787600088610b6a8296604051988997889687957f77c19c1f00000000000000000000000000000000000000000000000000000000875260048701612518565b03925af180156107b757610d06575b5080610ce9575b50610b8e8383959495614721565b9590926000947f000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f955b8551811015610be85780610be2888b61095a84610bdc61058c61093f6001998f6125af565b926125af565b01610bb7565b50929690946001600160a01b039096929616803b1561013f5782600091610c4095836040518098819582947f14e7a7ab0000000000000000000000000000000000000000000000000000000084528d600485016125df565b03925af19283156107b757610c896001600160a01b0393610a70927f85272ea7cbfb5ccba50d6cfaad14ff2ea471614d48c96ed5ecef53f11e56657996610cd4575b5087614977565b9092610cb2610100610ca361066d6101408c015160801c90565b9901516001600160a01b031690565b936fffffffffffffffffffffffffffffffff604051968796169916978561268b565b806107ab6000610ce393610212565b38610c82565b6101408301610cff6107df6107d2835160401c90565b5238610b80565b806107ab6000610d1593610212565b38610b79565b7f7082a8de0000000000000000000000000000000000000000000000000000000060005260046000fd5b610d79610d7487517f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9061412f565b611953565b6104a4565b9061049a565b610d8c611737565b610d94611737565b610d9c610234565b918252602082015293610485565b60405190610db9604083610212565b600d82527f4a616d536574746c656d656e74000000000000000000000000000000000000006020830152565b60005b838110610df85750506000910152565b8181015183820152602001610de8565b90602091610e2181518092818552858086019101610de5565b601f01601f1916010190565b3461013f57600036600319011261013f57610e5d610e49610daa565b604051918291602083526020830190610e08565b0390f35b3461013f57604036600319011261013f576100196000808080600435610e86816102c7565b6001600160a01b0360243591165af1610e9d612ce3565b50612d13565b3461013f57604036600319011261013f57600160ff600435610ec4816102c7565b6001600160a01b036024359116600052600260205260406000208160081c600052602052161b604060002054161560405180916020820190151582520390f35b906020808351928381520192019060005b818110610f225750505090565b8251845260209384019390920191600101610f15565b3461013f57600036600319011261013f57610fa5610f54610daa565b610e5d610f5f61114c565b610fb3610f6a612d44565b916040519586957f0f00000000000000000000000000000000000000000000000000000000000000875260e0602088015260e0870190610e08565b908582036040870152610e08565b90466060850152306080850152600060a085015283820360c0850152610f04565b3461013f57606036600319011261013f57600435610ff1816102c7565b6024356044359167ffffffffffffffff831161013f57611018610019933690600401610144565b929091612e33565b608036600319011261013f5760043567ffffffffffffffff811161013f5761104c903690600401610130565b60243567ffffffffffffffff811161013f5761106c903690600401610144565b60449291923567ffffffffffffffff811161013f5761108f903690600401610172565b916064359467ffffffffffffffff861161013f576110b4610019963690600401610280565b94613089565b3461013f57602036600319011261013f5760043580156111225761111f600160ff8360081c93161b91336000526002602052604060002092816000528360205260406000205461110e828083161415615051565b179290600052602052604060002090565b55005b7f150b14ee0000000000000000000000000000000000000000000000000000000060005260046000fd5b6040519061115b604083610212565b600182527f32000000000000000000000000000000000000000000000000000000000000006020830152565b3461013f57600036600319011261013f57610e5d610e4961114c565b3461013f57600036600319011261013f5760206040516001600160a01b037f000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f168152f35b60a036600319011261013f5760043567ffffffffffffffff811161013f57611213903690600401610172565b9060243567ffffffffffffffff811161013f57611234903690600401610172565b9260443567ffffffffffffffff811161013f57611255903690600401610172565b906064359567ffffffffffffffff871161013f5761127a610019973690600401610172565b9590946084359761128a896102c7565b613697565b60405160208101907f454950373132446f6d61696e28737472696e67206e616d652c737472696e672082527f76657273696f6e2c75696e7432353620636861696e49642c616464726573732060408201527f766572696679696e67436f6e7472616374290000000000000000000000000000606082015260528152611315607282610212565b51902090565b3461013f57600036600319011261013f5760206103af61128f565b3461013f57604036600319011261013f5760043567ffffffffffffffff811161013f576103af61136c6020923690600401610130565b60243590613c33565b3461013f57602036600319011261013f5760043567ffffffffffffffff811161013f576040600319823603011261013f576103af6113b96020923690600401613bbd565b613e3a565b9290959193956113cc613d76565b8551156116f9576113e660208751880101602088016118da565b955b51600090156116f457506113fb86613e3a565b61140781878488613f5e565b80151595866116c0575b61141e6101608701611984565b15611608576001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a1690813b1561013f576000809461147a604051988996879586946332910d0160e11b86528d60048701611afe565b03925af19081156107b7576114c2926114bd926115f3575b505b7f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9687916141fd565b611c63565b6101408101907f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd6001600160a01b036115056114fe858561198e565b3691611c94565b92611549846115446101008401976115296115208a8761198e565b9190928761198e565b602088019591611538876119c4565b9360c08a013595614310565b6119c4565b821630146115cc575b6115a0608082013594611564836119c4565b9261158161158f61157860e084018461198e565b92909a8461198e565b91909361012081019061198e565b939092604051988998169b88611d11565b0390a36115b4575b50506102436001600055565b6115c591602061077192015161412f565b38806115a8565b6115ee6115e96115e56115df888561198e565b90614683565b1590565b611ce0565b611552565b806107ab600061160293610212565b38611492565b5050506001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a1661164260e085018561198e565b93909161165361012087018761198e565b95909261165f886119c4565b94833b1561013f5761168d6000969287936040519a8b9889978896635abff4df60e01b885260048801611a4f565b03925af19081156107b7576114c2926114bd926116ab575b50611494565b806107ab60006116ba93610212565b386116a5565b6116ef610d7489517f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9061412f565b611411565b6113fb565b611701611737565b611709611737565b611711610234565b9182526020820152956113e8565b67ffffffffffffffff81116101d55760051b60200190565b60405190611746602083610212565b6000825281601f19611758600061171f565b019060005b82811061176957505050565b602090604051611778816101b9565b60008152600083820152600060408201526060808201528282850101520161175d565b8015150361013f57565b5190610243826102c7565b81601f8201121561013f5780516117c681610264565b926117d46040519485610212565b8184526020828401011161013f576117f29160208085019101610de5565b90565b9080601f8301121561013f5781519161180d8361171f565b9261181b6040519485610212565b80845260208085019160051b8301019183831161013f5760208101915b83831061184757505050505090565b825167ffffffffffffffff811161013f578201906080828703601f19011261013f5760405190611876826101b9565b60208301516118848161179b565b82526040830151611894816102c7565b60208301526060830151604083015260808301519167ffffffffffffffff831161013f576118ca886020809695819601016117b0565b6060820152815201920191611838565b60208183031261013f5780519067ffffffffffffffff821161013f570160408183031261013f576040519161190e836101da565b815167ffffffffffffffff811161013f578161192b9184016117f5565b8352602082015167ffffffffffffffff811161013f5761194b92016117f5565b602082015290565b1561195a57565b7f08f0f0fa0000000000000000000000000000000000000000000000000000000060005260046000fd5b356117f28161179b565b903590601e198136030182121561013f570180359067ffffffffffffffff821161013f57602001918160051b3603831361013f57565b356117f2816102c7565b9160209082815201919060005b8181106119e85750505090565b9091926020806001926001600160a01b038735611a04816102c7565b1681520194019291016119db565b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161013f5760209260051b809284830137010190565b949695916001600160a01b0393606095611a768694611a849460808b5260808b01916119ce565b9188830360208a0152611a12565b9616604085015216910152565b6040513d6000823e3d90fd5b9035601e198236030181121561013f57016020813591019167ffffffffffffffff821161013f578160051b3603831361013f57565b35906102438261179b565b908060209392818452848401376000828201840152601f01601f1916010190565b90611c4e906102439597969460609460808552611b2e60808601611b21856102d8565b6001600160a01b03169052565b611b4d611b3d602085016102d8565b6001600160a01b031660a0870152565b604083013560c08601528583013560e08601526080830135610100860152611b8b611b7a60a085016102d8565b6001600160a01b0316610120870152565b60c0830135610140860152611c41611c37610160611c30611c0f611bee611bcd8b610200611bbc60e08d018d611a9d565b9190926101808982015201916119ce565b611bdb6101008b018b611a9d565b8d8303607f19016101808f0152906119ce565b611bfc6101208a018a611a9d565b8c8303607f19016101a08e015290611a12565b611c1d610140890189611a9d565b8b8303607f19016101c08d015290611a12565b9501611ad2565b15156101e0870152565b8483036020860152611add565b95604082015201906001600160a01b03169052565b15611c6a57565b7fff774c530000000000000000000000000000000000000000000000000000000060005260046000fd5b929190611ca08161171f565b93611cae6040519586610212565b602085838152019160051b810192831161013f57905b828210611cd057505050565b8135815260209182019101611cc4565b15611ce757565b7f7a745d4b0000000000000000000000000000000000000000000000000000000060005260046000fd5b959192611d4f94611d33611d41936117f29a989660808b5260808b01916119ce565b9188830360208a01526119ce565b918583036040870152611a12565b916060818403910152610f04565b15611d6457565b7fe70c1fc90000000000000000000000000000000000000000000000000000000060005260046000fd5b467f0000000000000000000000000000000000000000000000000000000000028c5803611dd9577f3b5143daea1dc0453cc708354ef2cd7a878c077cbb2da3339ce3e7099cdcdf4490565b611de161128f565b611de9610daa565b60208151910120611df861114c565b602081519101206040519160208301938452604083015260608201524660808201523060a082015260a0815261131560c082610212565b60031115611e3957565b634e487b7160e01b600052602160045260246000fd5b9080601f8301121561013f578151611e668161171f565b92611e746040519485610212565b81845260208085019260051b82010192831161013f57602001905b828210611e9c5750505090565b602080918351611eab816102c7565b815201910190611e8f565b9080601f8301121561013f578151611ecd8161171f565b92611edb6040519485610212565b81845260208085019260051b82010192831161013f57602001905b828210611f035750505090565b8151815260209182019101611ef6565b9080601f8301121561013f578151611f2a8161171f565b92611f386040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b838210611f6457505050505090565b815167ffffffffffffffff811161013f57602091611f8787848094880101611e4f565b815201910190611f55565b9080601f8301121561013f578151611fa98161171f565b92611fb76040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b838210611fe357505050505090565b815167ffffffffffffffff811161013f5760209161200687848094880101611eb6565b815201910190611fd4565b91909160408184031261013f576040519061202b826101da565b819381519167ffffffffffffffff831161013f5761204f60209392849383016117b0565b84520151910152565b9080601f8301121561013f57815161206f8161171f565b9261207d6040519485610212565b81845260208085019260051b8201019183831161013f5760208201905b8382106120a957505050505090565b815167ffffffffffffffff811161013f576020916120cc87848094880101612011565b81520191019061209a565b919060608382031261013f57604051906120f0826101f6565b819380516120fd8161179b565b8352602081015167ffffffffffffffff811161013f578261211f918301611f92565b602084015260408101519167ffffffffffffffff831161013f576040926121469201611eb6565b910152565b91909160a08184031261013f57805167ffffffffffffffff811161013f5781016101608185031261013f5761217e610245565b908051825261218f602082016117a5565b6020830152604081015167ffffffffffffffff811161013f57856121b4918301611e4f565b6040830152606081015167ffffffffffffffff811161013f57856121d9918301611eb6565b6060830152608081015167ffffffffffffffff811161013f57856121fe918301611f13565b608083015260a081015167ffffffffffffffff811161013f5785612223918301611f13565b60a083015260c081015167ffffffffffffffff811161013f5785612248918301611f92565b60c083015260e081015167ffffffffffffffff811161013f578561226d918301611f92565b60e083015261227f61010082016117a5565b6101008301526101208101519067ffffffffffffffff821161013f576122aa866101409383016117b0565b610120840152015161014082015292602082015167ffffffffffffffff811161013f57816122d9918401612058565b92604083015167ffffffffffffffff811161013f57826122fa9185016120d7565b92606081015192608082015167ffffffffffffffff811161013f576117f292016117b0565b906020808351928381520192019060005b81811061233d5750505090565b82516001600160a01b0316845260209384019390920191600101612330565b9080602083519182815201916020808360051b8301019401926000915b83831061238857505050505090565b90919293946020806123a6600193601f19868203018752895161231f565b97019301930191939290612379565b9080602083519182815201916020808360051b8301019401926000915b8383106123e157505050505090565b90919293946020806123ff600193601f198682030187528951610f04565b970193019301919392906123d2565b805182526020808201516001600160a01b03169083015290610140806124d96124b161249f61248d61247b61246961245760408b015161016060408c01526101608b019061231f565b60608b01518a820360608c0152610f04565b60808a015189820360808b015261235c565b60a089015188820360a08a015261235c565b60c088015187820360c08901526123b5565b60e087015186820360e08801526123b5565b610100868101516001600160a01b031690860152610120860151858203610120870152610e08565b93015191015290565b6117f291815115158152604061250760208401516060602085015260608401906123b5565b920151906040818403910152610f04565b9160809361254f61255d926125416001600160a01b03959a99989a60a0885260a088019061240e565b9086820360208801526124e2565b908482036040860152610e08565b951660608201520152565b1561256f57565b7fe823bd5a0000000000000000000000000000000000000000000000000000000060005260046000fd5b634e487b7160e01b600052603260045260246000fd5b80518210156125c35760209160051b010190565b612599565b906020806124d98451604085526040850190610e08565b92906125f39060a0855260a085019061240e565b8381036020850152825180825260208201916020808360051b8301019501926000915b83831061265e575050505050829161263f91600060406117f296015283820360608501526124e2565b9060808183039101526040906002815261060f60f31b60208201520190565b909192939560208061267c600193601f198682030187528a516125c8565b98019301930191939290612616565b926126b76117f295936126a9611d4f9460808852608088019061231f565b90868203602088015261231f565b908482036040860152610f04565b91906101608382031261013f576126da610245565b92805184526126eb602082016117a5565b60208501526126fc604082016117a5565b604085015260608101516060850152608081015167ffffffffffffffff811161013f578261272b918301611e4f565b608085015260a081015167ffffffffffffffff811161013f5782612750918301611e4f565b60a085015260c081015167ffffffffffffffff811161013f5782612775918301611eb6565b60c085015260e081015167ffffffffffffffff811161013f578261279a918301611eb6565b60e08501526127ac61010082016117a5565b61010085015261012081015167ffffffffffffffff811161013f57610140926127d69183016117b0565b6101208501520151610140830152565b91909160608184031261013f5760405190612800826101f6565b8193815161280d8161179b565b835260208201519167ffffffffffffffff831161013f576128346040939284938301611eb6565b60208501520151910152565b9160c08383031261013f57825167ffffffffffffffff811161013f57826128689185016126c5565b92602081015167ffffffffffffffff811161013f5783612889918301612011565b92604082015167ffffffffffffffff811161013f57816128aa9184016127e6565b926128b7606084016117a5565b9260808101519260a082015167ffffffffffffffff811161013f576117f292016117b0565b805182526020808201516001600160a01b031690830152906040828101516001600160a01b03169082015260608201516060820152610140806124d96124b161296061294e61293c608089015161016060808a015261016089019061231f565b60a089015188820360a08a015261231f565b60c088015187820360c0890152610f04565b60e087015186820360e0880152610f04565b908151151581526040806124d96020850151606060208601526060850190610f04565b9160809361254f61255d926129be6001600160a01b03959a99989a60a0885260a08801906128dc565b908682036020880152612972565b91926129f86117f2946129ea61263f9460a0875260a08701906128dc565b9085820360208701526125c8565b90600060408501528382036060850152612972565b919082606091031261013f57604051612a25816101f6565b60408082948051612a358161179b565b8452602081015160208501520151910152565b91828203610240811261013f576101601361013f57612a65610245565b83518152612a75602085016117a5565b6020820152612a86604085016117a5565b604082015260608401516060820152612aa1608085016117a5565b6080820152612ab260a085016117a5565b60a082015260c084015160c082015260e084015160e0820152612ad861010085016117a5565b6101008201526101208401516101208201526101408401516101408201529261016081015167ffffffffffffffff811161013f5783612b18918301612011565b92612b27816101808401612a0d565b92612b356101e084016117a5565b926102008101519261022082015167ffffffffffffffff811161013f576117f292016117b0565b610140809180518452612b7f602082015160208601906001600160a01b03169052565b6040818101516001600160a01b03169085015260608101516060850152612bb6608082015160808601906001600160a01b03169052565b60a0818101516001600160a01b03169085015260c081015160c085015260e081015160e0850152612bf96101008201516101008601906001600160a01b03169052565b6101208101516101208501520151910152565b9161020093612c4f612c6392612c2e866001600160a01b03969b9a999b612b5c565b805115156101608701526020810151610180870152604001516101a0860152565b6102206101c0850152610220840190610e08565b95166101e08201520152565b90612c996117f29493612c8584612cc494612b5c565b6102206101608501526102208401906125c8565b6000610180840152835115156101a084015260208401516101c08401526040909301516101e0830152565b6102008183039101526040906002815261060f60f31b60208201520190565b3d15612d0e573d90612cf482610264565b91612d026040519384610212565b82523d6000602084013e565b606090565b15612d1a57565b7ffe8a94f40000000000000000000000000000000000000000000000000000000060005260046000fd5b60405190612d53602083610212565b6000808352366020840137565b90612d6a8261171f565b612d776040519182610212565b8281528092612d88601f199161171f565b0190602036910137565b9081602091031261013f57517fffffffff000000000000000000000000000000000000000000000000000000008116810361013f5790565b6040906117f2949281528160208201520191611add565b919082604091031261013f576020823592013590565b634e487b7160e01b600052601160045260246000fd5b60ff601b9116019060ff8211612e1f57565b612df7565b90604010156125c35760400190565b929091906000843b612fbd5760418203612f30575090602092612eab83612e83612e7d612e6f612e67600098880188612de1565b949097612e24565b356001600160f81b03191690565b60f81c90565b935b604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156107b7576001600160a01b0360005116908115612f06576001600160a01b031603612edc57565b7f815e1d640000000000000000000000000000000000000000000000000000000060005260046000fd5b7f8baa579f0000000000000000000000000000000000000000000000000000000060005260046000fd5b60408203612f955750602092612f4e83612eab936000950190612de1565b929092612f8f612f8a612f847f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84169360ff1c90565b60ff1690565b612e0d565b93612e85565b807f4be6321b0000000000000000000000000000000000000000000000000000000060049252fd5b936020926001600160a01b03612fea9560405196879586948593630b135d3f60e11b855260048501612dca565b0392165afa9081156107b757630b135d3f60e11b917fffffffff0000000000000000000000000000000000000000000000000000000091849161305a575b5016036130325750565b807fb0669cbc0000000000000000000000000000000000000000000000000000000060049252fd5b61307c915060203d602011613082575b6130748183610212565b810190612d92565b38613028565b503d61306a565b9291939093613096613d76565b8551156135f0576130b060208751880101602088016118da565b955b51600090156135ea57506130c586613e3a565b945b6130d386838388613f5e565b85151595866135b6575b6130ea6101608701611984565b15613508576001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16803b1561013f57869360008094613148604051978896879586946332910d0160e11b8652339360048701611afe565b03925af180156107b7576134f3575b505b60c0830135806132d4575061317e9161317661014085018561198e565b929091614fde565b6001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a166101008401936131b8858261198e565b90926131c6602084016119c4565b90803b1561013f5786600080946131f78995604051998a9788968795635abff4df60e01b8752339360048801611a4f565b03925af180156107b7577f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd936001600160a01b0393613273926132bf575b50608083013595613245846119c4565b9361158161326261325960e084018461198e565b92909b8461198e565b939092604051998a99169c8961364b565b0390a35b613287575b506102436001600055565b61077160206132b99201517f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9061412f565b3861327c565b806107ab60006132ce93610212565b38613235565b906132ef926132e761014086018661198e565b929091614e3d565b9193906001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a169061010083019561332d878561198e565b613339602087016119c4565b853b1561013f576000916133658a926040519586948594635abff4df60e01b8652339260048701613616565b038183885af180156107b7576134de575b508051613460575b5080516133ce575b50507f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd91506001600160a01b03906133c6608082013594611564836119c4565b0390a3613277565b6133d8868461198e565b929091813b1561013f576000809461340860405198899687958694635abff4df60e01b8652339260048701613616565b03925af19081156107b7577f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd926001600160a01b039261344b575b819250613386565b806107ab600061345a93610212565b38613443565b61346a878561198e565b9190843b1561013f576000916134b86040519485938493635abff4df60e01b85527f0000000000000000000000001af49c826ea0a8f29ea448f2171d1bcb716cb22d92339260048701613616565b038183875af180156107b7571561337e57806107ab60006134d893610212565b3861337e565b806107ab60006134ed93610212565b38613376565b806107ab600061350293610212565b38613157565b5050506001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a1661354260e085018561198e565b909161355261012087018761198e565b919061355d886119c4565b94823b1561013f5760009461358c869260405198899788968795635abff4df60e01b8752339460048801611a4f565b03925af180156107b7576135a1575b50613159565b806107ab60006135b093610212565b3861359b565b6135e5610d7489517f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9061412f565b6130dd565b946130c7565b6135f8611737565b613600611737565b613608610234565b9182526020820152956130b2565b93959490611a8460609461363d6001600160a01b039593869460808a5260808a01916119ce565b908782036020890152610f04565b9694926136899461366d61367b936117f29b999560808c5260808c01916119ce565b9189830360208b01526119ce565b918683036040880152611a12565b926060818503910152611a12565b92979097969495969391936136aa613d76565b6136b88186888b8d89615157565b851515948860005b878c8210613855575050505050506114bd6136fe917f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a9687916141fd565b60005b86811061371957505050505050506102436001600055565b808388613729818660019661525d565b61378f818761374761373c888784613a67565b61010081019061198e565b6137636137588a8986979597613a67565b61014081019061198e565b9160c06137878c8b613781602061377b84848d613a67565b016119c4565b98613a67565b013595614532565b7f9659aee63163c5924fca8de09494faaf9169aef36315127310d6e86596eb83dd6001600160a01b0360806137c587868b613a67565b01359261381d6137d961154489888d613a67565b918a6137f36137e98b8a84613a67565b60e081019061198e565b909861158f6138128d61380a61373c828689613a67565b949096613a67565b61012081019061198e565b0390a361382b575b01613701565b6138506107718761384a613840858a8d613a45565b602081019061198e565b906141fd565b613825565b6139ff575b8b61387261016061386c84848c613a67565b01611984565b1561394957896138ad836001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16938b613a67565b91836138ba818989613abd565b9390968d60009060001461393f57506138df926113b9926138da92613a45565b613c19565b945b813b1561013f576000809461390d8b604051998a97889687956332910d0160e11b875260048701611afe565b03925af19182156107b75760019261392a575b505b0189906136c0565b806107ab600061393993610212565b38613920565b92505050946138e1565b91506001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a16876139846137e9848684613a67565b6139a46115448661399c613812828b899a989a613a67565b999096613a67565b823b1561013f576000946139d18b87936040519a8b9889978896635abff4df60e01b885260048801611a4f565b03925af19182156107b7576001926139ea575b50613922565b806107ab60006139f993610212565b386139e4565b613a40610d74613a19613a13848d87613a45565b8061198e565b7f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a916141fd565b61385a565b91908110156125c35760051b81013590603e198136030182121561013f570190565b91908110156125c35760051b8101359061017e198136030182121561013f570190565b903590601e198136030182121561013f570180359067ffffffffffffffff821161013f5760200191813603831361013f57565b908210156125c357613ad49160051b810190613a8a565b9091565b9080601f8301121561013f57813591613af08361171f565b92613afe6040519485610212565b80845260208085019160051b8301019183831161013f5760208101915b838310613b2a57505050505090565b823567ffffffffffffffff811161013f578201906080828703601f19011261013f5760405190613b59826101b9565b6020830135613b678161179b565b82526040830135613b77816102c7565b60208301526060830135604083015260808301359167ffffffffffffffff831161013f57613bad88602080969581960101610280565b6060820152815201920191613b1b565b919060408382031261013f5760405190613bd6826101da565b8193803567ffffffffffffffff811161013f5782613bf5918301613ad8565b835260208101359167ffffffffffffffff831161013f576020926121469201613ad8565b6117f2903690613bbd565b9081602091031261013f575190565b613c406101608201611984565b15613d5d57604051917f3644e5150000000000000000000000000000000000000000000000000000000083526020836004816001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3165afa9283156107b757600093613d1e575b50613ce9613d1092611315926001600160a01b037f000000000000000000000000c5a350853e4e36b73eb0c24aaa4b8816c9a3579a169161592f565b604051928391602083019586909160429261190160f01b8352600283015260228201520190565b03601f198101835282610212565b611315919350613d1092613d4c613ce99260203d602011613d56575b613d448183610212565b810190613c24565b9492509250613cad565b503d613d3a565b90611315613ce9613d1092613d70611d8e565b946156b3565b600260005414613d87576002600055565b7f3ee5aeb50000000000000000000000000000000000000000000000000000000060005260046000fd5b9080602083519182815201916020808360051b8301019401926000915b838310613ddd57505050505090565b9091929394602080613e2b600193601f19868203018752608060608b518051151584526001600160a01b03868201511686850152604081015160408501520151918160608201520190610e08565b97019301930191939290613dce565b602081018051511580613e90575b613e8957611315613d1091604051928391613e76602084019660208852516040808601526080850190613db1565b9051838203603f19016060850152613db1565b5050600090565b5081515115613e48565b15613ea157565b7f710c94970000000000000000000000000000000000000000000000000000000060005260046000fd5b15613ed257565b7f83dfb46e0000000000000000000000000000000000000000000000000000000060005260046000fd5b15613f0357565b7fec7706630000000000000000000000000000000000000000000000000000000060005260046000fd5b15613f3457565b7fc56873ba0000000000000000000000000000000000000000000000000000000060005260046000fd5b909260409261024394613f70846119c4565b6001600160a01b0316331415806140e8575b61408d575b505050613f9a6115e56101608301611984565b801561407c575b614055575b60a0810133613fb761058c836119c4565b1490811561403a575b50801561402d575b613fd190613e9a565b613ffb613fe261010083018361198e565b9050613ff261014084018461198e565b91905014613ecb565b61402461400b60e083018361198e565b905061401b61012084018461198e565b91905014613efc565b01354210613f2d565b5060608101354211613fc8565b6001600160a01b03915061404d906119c4565b161538613fc0565b614077614061826119c4565b60808301356402540be3ff858501351491615082565b613fa6565b506402540be3ff8282013514613fa1565b6140e092613d106140cf6140a96140a2611d8e565b93886156b3565b8851928391602083019586909160429261190160f01b8352600283015260228201520190565b5190206140db856119c4565b612e33565b388080613f87565b506140f96115e56101608601611984565b613f82565b1561410557565b7f9eb00a7e0000000000000000000000000000000000000000000000000000000060005260046000fd5b9060005b82518110156141c55761414681846125af565b5160008061417f61058c61058c6020860161093f61416b82516001600160a01b031690565b6001600160a01b03808c16911614156140fe565b604084015190606085015191602083519301915af161419c612ce3565b501590816141ba575b506141b257600101614133565b505050600090565b5115159050386141a5565b505050600190565b91908110156125c35760051b81013590607e198136030182121561013f570190565b908092918237016000815290565b91909160005b8381106142135750505050600190565b61421e8185846141cd565b60008061424e61058c61058c6020860161154461423a826119c4565b6001600160a01b03808d16911614156140fe565b60408401356142606060860186613a8a565b9190614271604051809481936141ef565b03925af161427d612ce3565b5015908161429c575b5061429357600101614203565b50505050600090565b6142a69150611984565b38614286565b91908110156125c35760051b0190565b91908203918211612e1f57565b156142d357505050565b6001600160a01b03907f875c683c000000000000000000000000000000000000000000000000000000006000521660045260245260445260646000fd5b909194929460005b838110614329575050505050505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61434f61058c6115448488886142ac565b60009291036144ca5760019150475b61436882896125af565b5288614484575b6143b761437c82896125af565b51614388838b876142ac565b35614397611544858a8a6142ac565b6143a2858d896142ac565b35916143ae868d6125af565b519310156142c9565b86818773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6143e061058c611544858c8c6142ac565b03614456576000808061440161440d956001600160a01b03839616976125af565b51865af1610e9d612ce3565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b662061444c61443b848b6125af565b516040519081529081906020820190565b0390a25b01614318565b5061447f915061058c61154461446d9289896142ac565b87614478848b6125af565b5191615a8b565b614450565b6144ba6144aa6144986115448489896142ac565b6144a2848b6125af565b51908c615a0f565b6144b4838a6125af565b516142bc565b6144c482896125af565b5261436f565b6144de61058c61058c6115448489896142ac565b6040516370a0823160e01b815230600482015290602090829060249082905afa9081156107b75760019391614514575b5061435e565b61452c915060203d8111613d5657613d448183610212565b3861450e565b91909294939460005b84811061454c575050505050505050565b6001908861463e575b614595614562828a6125af565b518961456f8487896142ac565b3561457e611544868c8c6142ac565b906143ae8661458e818b8d6142ac565b35946125af565b87818873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6145be61058c611544858d8d6142ac565b0361461757600080806144016145df956001600160a01b03839616976125af565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b662061460d61443b848c6125af565b0390a25b0161453b565b50614639915061058c61154461462e928a8a6142ac565b88614478848c6125af565b614611565b61466661465c614652611544848a8a6142ac565b6144a2848c6125af565b6144b4838b6125af565b614670828a6125af565b52614555565b91908201809211612e1f57565b9060005b6000198201828111612e1f578110156141b25760018101808211612e1f575b8281106146b65750600101614687565b6146c382848694966142ac565b356146cd816102c7565b6001600160a01b036146e661058c6115448588886142ac565b9116146146f8576001019290926146a6565b50505050600190565b9081518110156125c3570160200190565b6000198114612e1f5760010190565b6000929150825b604082015151841015614759576147516001916147498660808601516125af565b515190614676565b930192614728565b92509061476e61476884612d60565b93612d60565b60009384805b60408601515187101561496b57614793906147498860a08901516125af565b6147a18760808801516125af565b515160005b8181106147cb5750506147c36001916147498960808a01516125af565b960195614774565b7f08000000000000000000000000000000000000000000000000000000000000006001600160f81b031961481f6148116101208c015161480b8689614676565b90614701565b516001600160f81b03191690565b1614158015614963575b614836575b6001016147a6565b8761485461093f8361484e8d608060019601516125af565b516125af565b8a838b600160fa1b6001600160f81b031961487c6148118b61480b8761012088015192614676565b1614614947575b6148949260c061484e9201516125af565b519160005b8781106148ed575b509060019392916148b6575b5050905061482e565b6148d2906148c4888a6125af565b906001600160a01b03169052565b6148e56148de87614712565b96896125af565b5238806148ad565b896148fb61093f838c6125af565b6001600160a01b038086169116146149165750600101614899565b849392506149346001969561492e8461493b946125af565b51614676565b918b6125af565b526000909192936148a1565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9350614883565b506000614829565b50808252825293509150565b600092835b6040830151518510156149a55761499d6001916147498760a08701516125af565b94019361497c565b935090916149bb6149b585612d60565b94612d60565b6000916001918391829190825b604089015151871015614bd4576149e38760a08b01516125af565b5151855b818110614a26575050614a1e600191614a188b6147498b6080614a0e8260a08601516125af565b51519301516125af565b90614676565b9601956149c8565b868b89614b89575b50614a3c575b6001016149e7565b60018b8a83614a5661093f8261484e8560a08801516125af565b92600160fa1b6001600160f81b0319614a7c6148118b61480b8761012088015192614676565b1614614b6d575b885115614b4f575061484e614a9c9260208a01516125af565b519088908f9493945b8b5b838110614aed575b50600195614ac3575b505050509050614a34565b614ad0926148c4916125af565b614ae3614adc89614712565b98886125af565b523887818f614ab8565b9193949592908a614b0161093f85846125af565b6001600160a01b03808816911614614b2557505050600101918f8a92959493614aa7565b8391929450614b408761492e60019a999896614b47946125af565b918c6125af565b528b95614aaf565b614b609260e061484e9201516125af565b519088908f949394614aa5565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9350614a83565b7f07000000000000000000000000000000000000000000000000000000000000009150614bcb6148116101206001600160f81b031993015161480b8689614676565b1614158b614a2e565b50509550925050508084528252565b91906040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03831660248201526020816044816001600160a01b0388165afa9081156107b757600091614ce0575b5010614c4b575050565b6014526000196034526f095ea7b3000000000000000000000000600052602060006044601082855af13d15600160005114171615614c8c575b506000603452565b60006044601082602094816034526f095ea7b300000000000000000000000082528138858583855af15081196034525af13d15600160005114171615614cd25738614c84565b633e3f8f736000526004601cfd5b614cf9915060203d602011613d5657613d448183610212565b38614c41565b9060a08201614d0f815151612d60565b9060005b815151811015614d9a5780600160fa1b6001600160f81b0319614d3d6001946101208a0151614701565b511614600090600014614d7d575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b6001600160a01b03614d7383876125af565b9116905201614d13565b6001600160a01b0390614d918386516125af565b90505116614d61565b50509150565b15614da757565b7f692f31020000000000000000000000000000000000000000000000000000000060005260046000fd5b81810292918115918404141715612e1f57565b8115614dee570490565b634e487b7160e01b600052601260045260246000fd5b15614e0d575050565b7f871cbeab0000000000000000000000000000000000000000000000000000000060005260045260245260446000fd5b92949190606095614e4e8796615b5b565b94919690614e5d858514614da0565b61ffff614e6986612d60565b961680614f7f575b5061ffff1680614ed5575b505060005b838110614e92575050505093929190565b80614ecf614ea2600193886125af565b51614eae8387876142ac565b35614eba8488886142ac565b3590614ec6858b6125af565b51921015614e04565b01614e81565b909750614ee184612d60565b9760005b858110614ef25750614e7c565b80614f15614f0d85614f076001958b886142ac565b35614dd1565b612710900490565b614f1f828d6125af565b52614f2a81896125af565b51614f6157614f508b614f4983614f42818c896142ac565b35926125af565b51906142bc565b614f5a828a6125af565b5201614ee5565b614f7a8b614f4983614f73818d6125af565b51926125af565b614f50565b9950614f8a85612d60565b9960005b8b87808310614f9f57505050614e71565b90614fb983610bdc614f0d87614f0784600199988d6142ac565b52614fcd8d614f4983614f42818d8b6142ac565b614fd7828b6125af565b5201614f8e565b91909392841561504957614ff3818614614da0565b60005b858110615004575050509190565b8061504361501560019389886142ac565b356150218386886142ac565b3561502d8487896142ac565b359061503a858c8b6142ac565b35921015614e04565b01614ff6565b935090509190565b1561505857565b7f756688fe0000000000000000000000000000000000000000000000000000000060005260046000fd5b908015611122576150d891600160ff8360081c93161b936000906000146150db57506001600160a01b031660005260026020526040600020925b816000528360205260406000205461110e828083161415615051565b55565b6001600160a01b03604092168152600160205220926150bc565b156150fc57565b7fa18792da0000000000000000000000000000000000000000000000000000000060005260046000fd5b1561512d57565b7fb82564ab0000000000000000000000000000000000000000000000000000000060005260046000fd5b939295948615918181036152025787811480156151fb575b615178906150f5565b60005b81811061518d57505050505050509050565b6001906151ae306151a761058c602061377b86898f613a67565b1415615126565b6151de6151bc82858b613a67565b828c6151c982898d613abd565b9290918b8b156151e457505050600092613f5e565b0161517b565b6151f5926113b9926138da92613a45565b92613f5e565b508261516f565b7f6e3779d80000000000000000000000000000000000000000000000000000000060005260046000fd5b1561523357565b7fadfbc6fc0000000000000000000000000000000000000000000000000000000060005260046000fd5b929161526a848284613a67565b93610100850161528461527d828861198e565b9050612d60565b9361014087019360005b615298848a61198e565b90508110156154e357600090855b8381106153f5575089878973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6152e061058c611544876152da8d8961198e565b906142ac565b14886000916000146153635750506152da8261533086809461532060019a61531b8a615314866152da6153379d479461198e565b3590614dd1565b614de4565b61532a83836125af565b526125af565b519461198e565b3511615344575b0161528e565b615352816152da898d61198e565b3561535d828a6125af565b5261533e565b61537f935061058c9250856152da6115449261058c949761198e565b6040516370a0823160e01b815230600482015290602090829060249082905afa9081156107b7576152da8a6153308f958e61532060019a61531b8a6153148d6152da8a6153379e839e849b916153d7575b509461198e565b6153ef915060203d8111613d5657613d448183610212565b386153d0565b95909860009a989294979a9593955b61541261373c89898c613a67565b90508110156154cd57896001600160a01b0361545161058c6115448f6152da8f8f8f8a8f9361373c61544b94611544946152da93613a67565b9761198e565b911614615461575b600101615404565b948561546e89898c613a67565b610140810161547c9161198e565b61548692916142ac565b3561549091614676565b9461549e60c08b0135615c0e565b6154a989898c613a67565b60c001356154b690615c0e565b61ffff166154c89161ffff161461522c565b615459565b509890956001909a979492989a959395016152a6565b509496505050505050565b6040517f4a616d4f7264657228616464726573732074616b65722c61646472657373207260208201527f656365697665722c75696e74323536206578706972792c75696e74323536206560408201527f78636c75736976697479446561646c696e652c75696e74323536206e6f6e636560608201527f2c61646472657373206578656375746f722c75696e7432353620706172746e6560808201527f72496e666f2c616464726573735b5d2073656c6c546f6b656e732c616464726560a08201527f73735b5d20627579546f6b656e732c75696e743235365b5d2073656c6c416d6f60c08201527f756e74732c75696e743235365b5d20627579416d6f756e74732c62797465733360e08201527f3220686f6f6b734861736829000000000000000000000000000000000000000061010082015260ec81526117f261010c82610212565b61563a6154ee565b6020815191012090565b9060005b8181106156555750505090565b9091926020806001926001600160a01b038735615671816102c7565b168152019401929101615648565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811161013f5760051b809282370190565b6156bb615632565b916156c5826119c4565b926156d2602084016119c4565b91604084013593606081013590608081013560a082016156f1906119c4565b60c083013561570360e085018561198e565b90604051809160208201809461571892615644565b03601f198101825261572a9082610212565b5190209161573c61010086018661198e565b90604051809160208201809461575192615644565b03601f19810182526157639082610212565b5190209361577561012087018761198e565b90604051809160208201809461578a9261567f565b03601f198101825261579c9082610212565b5190209561014081016157ae9161198e565b9060405180916020820180946157c39261567f565b03601f19810182526157d59082610212565b519020966040519b8c9b60208d019e8f9c61585d9d9a98969492909d9c9b99979593916101a08c019e8c526001600160a01b031660208c01526001600160a01b031660408b015260608a0152608089015260a08801526001600160a01b031660c087015260e08601526101008501526101208401526101408301526101608201526101800152565b03601f19810182526113159082610212565b9061588260209282815194859201610de5565b0190565b61588e6154ee565b6117f2602e603160405180947f4a616d4f72646572207769746e6573732900000000000000000000000000000060208301526158d38151809260208686019101610de5565b81017f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75838201527f696e7432353620616d6f756e742900000000000000000000000000000000000060518201520301600e810184520182610212565b9091615939615c22565b5060e0820161595261594b828561198e565b9050615c42565b9461012084019260005b615966848761198e565b90508110156159cd57806159836115446001936152da888b61198e565b615991826152da898b61198e565b356159ac61599d610234565b6001600160a01b039093168352565b60208201526159bb828b6125af565b526159c6818a6125af565b500161595c565b50936117f29591969350615a01925060808101356040820135906159ef610255565b958652602086015260408501526156b3565b615a09615886565b91615d7b565b9190615a1c600093615b5b565b919061ffff8116615a76575b505061ffff8116615a3a575b50505090565b615a65927f0000000000000000000000001af49c826ea0a8f29ea448f2171d1bcb716cb22d92615e57565b8101809111612e1f57388080615a34565b615a839295508484615e57565b923880615a28565b600091826044926020956001600160a01b03604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d1160016000511416171615615ae757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b9061ffff8091169116019061ffff8211612e1f57565b9061ffff8216906001600160a01b0361ffff8460101c169360201c1661271061ffff615b878587615b45565b161015615be457831580801591615bce575b5015615ba457929190565b7fb7273bd50000000000000000000000000000000000000000000000000000000060005260046000fd5b905080615bdc575b38615b99565b508015615bd6565b7f721dbfea0000000000000000000000000000000000000000000000000000000060005260046000fd5b6117f29061ffff808260101c169116615b45565b60405190615c2f826101f6565b6000604083606081528260208201520152565b90615c4c8261171f565b615c596040519182610212565b8281528092615c6a601f199161171f565b019060005b828110615c7b57505050565b602090604051615c8a816101da565b6000815260008382015282828501015201615c6f565b60405190615caf60a083610212565b606b82527f3620646561646c696e652c0000000000000000000000000000000000000000006080837f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208201527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c6164647260408201527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608201520152565b805160209091019060005b818110615d655750505090565b8251845260209384019390920191600101615d58565b909291613d10615da7615d8c615ca0565b92604051928391615da160208401809761586f565b9061586f565b51902092815151615db781612d60565b9060005b818110615e2f5750506113159291613d1091604051615de281613d10602082018095615d4d565b51902092604060208201519101519060405196879560208701998a926001600160a01b039060a095929897969360c086019986526020860152166040840152606083015260808201520152565b80615e46615e4060019388516125af565b51615ee9565b615e5082866125af565b5201615dbb565b90615e736127109161ffff6001600160a01b0396951690614dd1565b049283911673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8103615edf5750506001600160a01b0316615eb2600080808086865af1610e9d612ce3565b7f88479153c5a43e333375e4daf2e98cddbb4cb43428c64efdab6e987c263b66206020604051848152a290565b916117f292615a8b565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a184526001600160a01b038151166040840152015160608201526060815261131560808261021256fea2646970667358221220da6c85282a2cc6cde7c75dcde65f8361cd5c7c90ecba328016a401e28804a3c364736f6c634300081b0033

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

000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f0000000000000000000000001af49c826ea0a8f29ea448f2171d1bcb716cb22d

-----Decoded View---------------
Arg [0] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
Arg [1] : _bebopBlend (address): 0xbbbbbBB520d69a9775E85b458C58c648259FAD5F
Arg [2] : _treasuryAddress (address): 0x1af49c826Ea0A8F29ea448f2171D1BCb716cB22D

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [1] : 000000000000000000000000bbbbbbb520d69a9775e85b458c58c648259fad5f
Arg [2] : 0000000000000000000000001af49c826ea0a8f29ea448f2171d1bcb716cb22d


Block Transaction Gas Used Reward
view all blocks sequenced

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

Validator Index Block Amount
View All Withdrawals

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

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