HYPE Price: $37.24 (-3.50%)

Contract

0xC5a350853E4e36b73EB0C24aaA4b8816C9A3579a

Overview

HYPE Balance

HyperEvm LogoHyperEvm LogoHyperEvm Logo0 HYPE

HYPE Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
30948912025-04-28 11:52:0070 days ago1745841120  Contract Creation0 HYPE
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
JamBalanceManager

Compiler Version
v0.8.27+commit.40a35a09

Optimization Enabled:
Yes with 1239 runs

Other Settings:
paris EvmVersion
// 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
        );
    }

}

// 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 3 of 16 : 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();

// 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);
    }

}

// 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;
    }
}

// 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));
    }
}

// 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.
        }
    }


}

// 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;
}

// 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;

}

// 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);

}

// 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;
    }

}

// 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 13 of 16 : 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
            )
        );
    }

}

// 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));
    }
}

// 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;
    }
}

// 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
{
  "evmVersion": "paris",
  "libraries": {},
  "optimizer": {
    "enabled": true,
    "runs": 1239
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_permit2","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address","name":"taker_token","type":"address"},{"internalType":"address","name":"maker_token","type":"address"},{"internalType":"uint256","name":"taker_amount","type":"uint256"},{"internalType":"uint256","name":"maker_amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"packed_commands","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct BlendSingleOrder","name":"order","type":"tuple"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256","name":"makerAmount","type":"uint256"},{"internalType":"uint256","name":"makerNonce","type":"uint256"}],"internalType":"struct IBebopBlend.OldSingleQuote","name":"oldSingleQuote","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"bytes32","name":"hooksHash","type":"bytes32"}],"name":"transferTokenForBlendSingleOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"transferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address[]","name":"maker_addresses","type":"address[]"},{"internalType":"uint256[]","name":"maker_nonces","type":"uint256[]"},{"internalType":"address[][]","name":"taker_tokens","type":"address[][]"},{"internalType":"address[][]","name":"maker_tokens","type":"address[][]"},{"internalType":"uint256[][]","name":"taker_amounts","type":"uint256[][]"},{"internalType":"uint256[][]","name":"maker_amounts","type":"uint256[][]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct BlendAggregateOrder","name":"order","type":"tuple"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256[][]","name":"makerAmounts","type":"uint256[][]"},{"internalType":"uint256[]","name":"makerNonces","type":"uint256[]"}],"internalType":"struct IBebopBlend.OldAggregateQuote","name":"oldAggregateQuote","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"bytes32","name":"hooksHash","type":"bytes32"}],"name":"transferTokensForAggregateBebopOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"taker_address","type":"address"},{"internalType":"address","name":"maker_address","type":"address"},{"internalType":"uint256","name":"maker_nonce","type":"uint256"},{"internalType":"address[]","name":"taker_tokens","type":"address[]"},{"internalType":"address[]","name":"maker_tokens","type":"address[]"},{"internalType":"uint256[]","name":"taker_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"maker_amounts","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"uint256","name":"flags","type":"uint256"}],"internalType":"struct BlendMultiOrder","name":"order","type":"tuple"},{"components":[{"internalType":"bool","name":"useOldAmount","type":"bool"},{"internalType":"uint256[]","name":"makerAmounts","type":"uint256[]"},{"internalType":"uint256","name":"makerNonce","type":"uint256"}],"internalType":"struct IBebopBlend.OldMultiQuote","name":"oldMultiQuote","type":"tuple"},{"internalType":"bytes","name":"takerSignature","type":"bytes"},{"internalType":"address","name":"takerAddress","type":"address"},{"internalType":"bytes32","name":"hooksHash","type":"bytes32"}],"name":"transferTokensForMultiBebopOrder","outputs":[],"stateMutability":"nonpayable","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":"bytes32","name":"hooksHash","type":"bytes32"},{"internalType":"address","name":"receiver","type":"address"}],"name":"transferTokensWithPermit2","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c0346100bd57601f612ad838819003918201601f19168301916001600160401b038311848410176100c25780849260409485528339810103126100bd57610052602061004b836100d8565b92016100d8565b6080919091526001600160a01b031660a0526040516129eb90816100ed82396080518181816103b001528181610c140152818161109a015281816114e80152818161184a0152611ad7015260a051818181610c52015281816110cb015281816118200152611b150152f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036100bd5756fe6080604052600436101561001257600080fd5b60003560e01c806357c3af1e146100675780635abff4df1461006257806365221a021461005d57806377c19c1f146100585763fbfa3c5b1461005357600080fd5b610a27565b6107e5565b61050c565b610337565b34610141573660031901610220811261014157610160136101415761008a6101bb565b60043581526100976101fc565b60208201526100a4610209565b604082015260643560608201526100b9610216565b60808201526100c6610223565b60a082015260c43560c082015260e43560e08201526100e3610230565b610100820152610124356101208201526101443561014082015261010636610271565b906101c4359167ffffffffffffffff83116101415761012c61013f9336906004016102af565b61013461023e565b916102043593610c0b565b005b600080fd5b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff82111761017857604052565b610146565b6040810190811067ffffffffffffffff82111761017857604052565b90601f8019910116810190811067ffffffffffffffff82111761017857604052565b604051906101cb61016083610199565b565b604051906101cb604083610199565b604051906101cb606083610199565b6001600160a01b0381160361014157565b602435906101cb826101eb565b604435906101cb826101eb565b608435906101cb826101eb565b60a435906101cb826101eb565b61010435906101cb826101eb565b6101e435906101cb826101eb565b606435906101cb826101eb565b35906101cb826101eb565b3590811515820361014157565b606090610163190112610141576040519061028b8261015c565b8161016435801515810361014157815261018435602082015260406101a435910152565b81601f820112156101415780359067ffffffffffffffff821161017857604051926102e4601f8401601f191660200185610199565b8284526020838301011161014157816000926020809301838601378301015290565b9181601f840112156101415782359167ffffffffffffffff8311610141576020808501948460051b01011161014157565b346101415760803660031901126101415760043567ffffffffffffffff811161014157610368903690600401610306565b9060243567ffffffffffffffff811161014157610389903690600401610306565b60449391933590610399826101eb565b606435926103a6846101eb565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016946103dc863314610bda565b60005b8281106103e857005b87868686868673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6104256104196104148a868661106b565b611080565b6001600160a01b031690565b1461045c578661045695936104496104196104148460019c9b999761044f9761106b565b9561106b565b3592611f0a565b016103df565b505050508891506001600160a01b03160361047a575b600190610456565b61048581858a61106b565b3590873b15610141576040517f7c317e0f0000000000000000000000000000000000000000000000000000000081526001600160a01b03881660048201526024810192909252600082604481838c5af1918215610507576001926104ec575b509050610472565b806104fb600061050193610199565b80610f88565b386104e4565b611049565b346101415760803660031901126101415760043567ffffffffffffffff81116101415761018060031982360301126101415760243567ffffffffffffffff811161014157366023820112156101415780600401359167ffffffffffffffff83116101415736602484840101116101415761013f9260443591602461058e61024c565b94019060040161108a565b67ffffffffffffffff81116101785760051b60200190565b9080601f830112156101415781356105c881610599565b926105d66040519485610199565b81845260208085019260051b82010192831161014157602001905b8282106105fe5750505090565b60208091833561060d816101eb565b8152019101906105f1565b9080601f8301121561014157813561062f81610599565b9261063d6040519485610199565b81845260208085019260051b82010192831161014157602001905b8282106106655750505090565b8135815260209182019101610658565b9080601f8301121561014157813561068c81610599565b9261069a6040519485610199565b81845260208085019260051b820101918383116101415760208201905b8382106106c657505050505090565b813567ffffffffffffffff8111610141576020916106e9878480948801016105b1565b8152019101906106b7565b9080601f8301121561014157813561070b81610599565b926107196040519485610199565b81845260208085019260051b820101918383116101415760208201905b83821061074557505050505090565b813567ffffffffffffffff81116101415760209161076887848094880101610618565b815201910190610736565b9190606083820312610141576040519061078c8261015c565b819361079781610264565b8352602081013567ffffffffffffffff811161014157826107b99183016106f4565b602084015260408101359167ffffffffffffffff8311610141576040926107e09201610618565b910152565b346101415760a03660031901126101415760043567ffffffffffffffff81116101415761016060031982360301126101415761081f6101bb565b908060040135825261083360248201610259565b6020830152604481013567ffffffffffffffff81116101415761085c90600436918401016105b1565b6040830152606481013567ffffffffffffffff8111610141576108859060043691840101610618565b6060830152608481013567ffffffffffffffff8111610141576108ae9060043691840101610675565b608083015260a481013567ffffffffffffffff8111610141576108d79060043691840101610675565b60a083015260c481013567ffffffffffffffff81116101415761090090600436918401016106f4565b60c083015260e481013567ffffffffffffffff81116101415761092990600436918401016106f4565b60e083015261093b6101048201610259565b6101008301526101248101359067ffffffffffffffff82116101415761096a61014492600436918401016102af565b610120840152013561014082015260243567ffffffffffffffff811161014157610998903690600401610773565b906044359167ffffffffffffffff8311610141576109bd61013f9336906004016102af565b6109c561024c565b91608435936114d9565b91909160608184031261014157604051906109e98261015c565b81936109f482610264565b835260208201359167ffffffffffffffff831161014157610a1b6040939284938301610618565b60208501520135910152565b346101415760a03660031901126101415760043567ffffffffffffffff811161014157610160600319823603011261014157610a616101bb565b9080600401358252610a7560248201610259565b6020830152610a8660448201610259565b604083015260648101356060830152608481013567ffffffffffffffff811161014157610ab990600436918401016105b1565b608083015260a481013567ffffffffffffffff811161014157610ae290600436918401016105b1565b60a083015260c481013567ffffffffffffffff811161014157610b0b9060043691840101610618565b60c083015260e481013567ffffffffffffffff811161014157610b349060043691840101610618565b60e0830152610b466101048201610259565b6101008301526101248101359067ffffffffffffffff821161014157610b7561014492600436918401016102af565b610120840152013561014082015260243567ffffffffffffffff811161014157610ba39036906004016109cf565b906044359167ffffffffffffffff831161014157610bc861013f9336906004016102af565b610bd061024c565b9160843593611ad0565b15610be157565b7f48f5c3ed0000000000000000000000000000000000000000000000000000000060005260046000fd5b90929193610cfe7f000000000000000000000000000000000000000000000000000000000000000091610c486001600160a01b0384163314610bda565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693610c8760808201516001600160a01b031690565b9660c082018051610ca8610c996101cd565b6001600160a01b03909b168b52565b60208a015261014083015160801c835190610cc16101dc565b9a8b5260208b015260408a015251610ce9610cda6101cd565b6001600160a01b039097168752565b60208601526040602082015191015191611e40565b94610d07610ed8565b94833b1561014157610d4e600096928793604051998a98899788967f137c29fe00000000000000000000000000000000000000000000000000000000885260048801610fb8565b03925af1801561050757610d5f5750565b806104fb60006101cb93610199565b6040517f53696e676c654f726465722875696e74363420706172746e65725f69642c756960208201527f6e74323536206578706972792c616464726573732074616b65725f616464726560408201527f73732c61646472657373206d616b65725f616464726573732c75696e7432353660608201527f206d616b65725f6e6f6e63652c616464726573732074616b65725f746f6b656e60808201527f2c61646472657373206d616b65725f746f6b656e2c75696e743235362074616b60a08201527f65725f616d6f756e742c75696e74323536206d616b65725f616d6f756e742c6160c08201527f6464726573732072656365697665722c75696e74323536207061636b65645f6360e08201527f6f6d6d616e64732c6279746573333220686f6f6b73486173682900000000000061010082015260fa8152610eb261011a82610199565b90565b60005b838110610ec85750506000910152565b8181015183820152602001610eb8565b6034610eb2610ee5610d6e565b610f7a6040519384927f53696e676c654f72646572207769746e657373290000000000000000000000006020850152610f278151809260208588019101610eb5565b830101602e907f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c7581527f696e7432353620616d6f756e742900000000000000000000000000000000000060208201520190565b03601f198101835282610199565b600091031261014157565b90602091610fac81518092818552858086019101610eb5565b601f01601f1916010190565b949161103a9361101b6001600160a01b03926040610eb29a9895610ff08b8251602080916001600160a01b0381511684520151910152565b6020818101518c84015291015160608b015281516001600160a01b031660808b0152015160a0890152565b1660c086015260e0850152610140610100850152610140840190610f93565b91610120818403910152610f93565b6040513d6000823e3d90fd5b634e487b7160e01b600052603260045260246000fd5b919081101561107b5760051b0190565b611055565b35610eb2816101eb565b9190946110c16001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163314610bda565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916110f4611fcc565b5060e084019261110e6111078587611fec565b9050612022565b956000986101208701995b6111238789611fec565b905081101561119257808b6111568261114961114f6104146001978f8f61114991611fec565b9061106b565b938d611fec565b356111716111626101cd565b6001600160a01b039093168352565b6020820152611180828c612080565b5261118b818b612080565b5001611119565b509296976111c9919499506111d992955060808701356040880135906111b66101dc565b9a8b5260208b015260408a015286612094565b926111d386611080565b95612191565b956111e2611353565b843b15610141576000968793610d4e926040519a8b998a98899763fe8ec1a760e01b895260048901611464565b6040517f4a616d4f7264657228616464726573732074616b65722c61646472657373207260208201527f656365697665722c75696e74323536206578706972792c75696e74323536206560408201527f78636c75736976697479446561646c696e652c75696e74323536206e6f6e636560608201527f2c61646472657373206578656375746f722c75696e7432353620706172746e6560808201527f72496e666f2c616464726573735b5d2073656c6c546f6b656e732c616464726560a08201527f73735b5d20627579546f6b656e732c75696e743235365b5d2073656c6c416d6f60c08201527f756e74732c75696e743235365b5d20627579416d6f756e74732c62797465733360e08201527f3220686f6f6b734861736829000000000000000000000000000000000000000061010082015260ec8152610eb261010c82610199565b6031610eb261136061120f565b610f7a6040519384927f4a616d4f72646572207769746e657373290000000000000000000000000000006020850152610f278151809260208588019101610eb5565b90606081019180519260608352835180915260206080840194019060005b8181106113e0575050506040816020829301516020850152015191015290565b90919460206040826114086001948a51602080916001600160a01b0381511684520151910152565b0196019291016113c0565b906020808351928381520192019060005b8181106114315750505090565b90919260206040826114596001948851602080916001600160a01b0381511684520151910152565b019401929101611424565b959290948795946001600160a01b0361149c6114b59561148f60209c9960c08d5260c08d01906113a2565b908b82038d8d0152611413565b9316604089015260608801528682036080880152610f93565b9360a0818603910152818452848401376000828201840152601f01601f1916010190565b949361150f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163314610bda565b600092839484955b604089015151871015611548576115406001916115388960808d0151612080565b515190612351565b960195611517565b93979691945091945061156361155d84612363565b93612363565b936000926000986000995b60408a0151518b10156117fc5761158d906115388c60a08d0151612080565b8a8a61159d826080830151612080565b515160005b8181106115c7575050916115386115bf9260806001950151612080565b9a019961156e565b917f080000000000000000000000000000000000000000000000000000000000000091935061164f6116296101207fff000000000000000000000000000000000000000000000000000000000000009301516116238689612351565b90612395565b517fff000000000000000000000000000000000000000000000000000000000000001690565b16141580156117f4575b61166a575b6001018c918c916115a2565b8c8c6001918361169861168b82611685856080880151612080565b51612080565b516001600160a01b031690565b917f04000000000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000006116f26116298b611623876101208b015192612351565b16146117d8575b6117148f94968f928f959497989060c0611685920151612080565b51936000905b84821061176f575b5050600195611737575b50505050905061165e565b6117529261174491612080565b906001600160a01b03169052565b61176561175e8b6123a6565b9a8d612080565b523889818c61172c565b9092949596939161168b8461178392612080565b6001600160a01b038087169116146117a7575050600101918c8c929594938f61171a565b9092506117cd826117c7876117c160019a99989686612080565b51612351565b92612080565b528c6000958f611722565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92506116f9565b506000611659565b5093611880939950979095969197808652875261186f611847886001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001697846123b5565b977f000000000000000000000000000000000000000000000000000000000000000090612455565b936040602082015191015191612528565b94611889611a23565b94833b1561014157610d4e600096928793604051998a988997889663fe8ec1a760e01b885260048801611a72565b6040517f4167677265676174654f726465722875696e74363420706172746e65725f696460208201527f2c75696e74323536206578706972792c616464726573732074616b65725f616460408201527f64726573732c616464726573735b5d206d616b65725f6164647265737365732c60608201527f75696e743235365b5d206d616b65725f6e6f6e6365732c616464726573735b5d60808201527f5b5d2074616b65725f746f6b656e732c616464726573735b5d5b5d206d616b6560a08201527f725f746f6b656e732c75696e743235365b5d5b5d2074616b65725f616d6f756e60c08201527f74732c75696e743235365b5d5b5d206d616b65725f616d6f756e74732c61646460e08201527f726573732072656365697665722c627974657320636f6d6d616e64732c6279746101008201527f6573333220686f6f6b734861736829000000000000000000000000000000000061012082015261010f8152610eb261012f82610199565b6037610eb2611a306118b7565b610f7a6040519384927f4167677265676174654f72646572207769746e657373290000000000000000006020850152610f278151809260208588019101610eb5565b9490936001600160a01b03611aa9611ac29594611a9b610eb29a9860c08b5260c08b01906113a2565b9089820360208b0152611413565b9316604087015260608601528482036080860152610f93565b9160a0818403910152610f93565b94909392917f000000000000000000000000000000000000000000000000000000000000000092611b0b6001600160a01b0385163314610bda565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016611b3d611fcc565b506080880196611b4e885151612022565b9660009960c081019a5b8a518051821015611bac57908c611b7f82611b7861168b82600197612080565b9251612080565b51611b8b6111626101cd565b6020820152611b9a828d612080565b52611ba5818c612080565b5001611b58565b50509194985091949850611beb611bfc9396611bcd61014084015160801c90565b835190611bd86101dc565b9a8b5260208b015260408a0152826126b9565b936040602082015191015191612735565b94611889611d49565b6040517f4d756c74694f726465722875696e74363420706172746e65725f69642c75696e60208201527f74323536206578706972792c616464726573732074616b65725f61646472657360408201527f732c61646472657373206d616b65725f616464726573732c75696e743235362060608201527f6d616b65725f6e6f6e63652c616464726573735b5d2074616b65725f746f6b6560808201527f6e732c616464726573735b5d206d616b65725f746f6b656e732c75696e74323560a08201527f365b5d2074616b65725f616d6f756e74732c75696e743235365b5d206d616b6560c08201527f725f616d6f756e74732c616464726573732072656365697665722c627974657360e08201527f20636f6d6d616e64732c6279746573333220686f6f6b7348617368290000000061010082015260fc8152610eb261011c82610199565b6033610eb2611d56611c05565b610f7a6040519384927f4d756c74694f72646572207769746e65737329000000000000000000000000006020850152610f278151809260208588019101610eb5565b611da0610d6e565b6020815191012090565b9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a01526001600160a01b0316608089015260a08801526001600160a01b031660c087015260e08601611e18916001600160a01b03169052565b6101008501526101208401526001600160a01b03166101408301526101608201526101800152565b909161014082015160401c611e5c9067ffffffffffffffff1690565b93611e65611d98565b918351936020810151611e7e906001600160a01b031690565b956040820151611e94906001600160a01b031690565b926080830151611eaa906001600160a01b031690565b60a08401516001600160a01b03169060c085015192610100860151611ed5906001600160a01b031690565b956101200151966040519b8c9b60208d019e8f9c611ef29d611daa565b03601f1981018252611f049082610199565b51902090565b9060006064926020956001600160a01b03839681604051967f23b872dd00000000000000000000000000000000000000000000000000000000885216600487015216602485015260448401525af13d15601f3d1160016000511416171615611f6e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b60405190611fd98261015c565b6000604083606081528260208201520152565b903590601e1981360301821215610141570180359067ffffffffffffffff821161014157602001918160051b3603831361014157565b9061202c82610599565b6120396040519182610199565b828152809261204a601f1991610599565b019060005b82811061205b57505050565b60209060405161206a8161017d565b600081526000838201528282850101520161204f565b805182101561107b5760209160051b010190565b9060e08201916120a76111078483611fec565b9360005b6120b58584611fec565b9050811015612113576001816120d66120b593611149610120880188611fec565b35604051906120e48261017d565b6001600160a01b038816825260208201526120ff828a612080565b5261210a8189612080565b500190506120ab565b5092505050565b611da061120f565b9060005b8181106121335750505090565b9091926020806001926001600160a01b03873561214f816101eb565b168152019401929101612126565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81116101415760051b809282370190565b61219961211a565b916121a382611080565b926121b060208401611080565b91604084013593606081013590608081013560a082016121cf90611080565b60c08301356121e160e0850185611fec565b9060405180916020820180946121f692612122565b03601f19810182526122089082610199565b5190209161221a610100860186611fec565b90604051809160208201809461222f92612122565b03601f19810182526122419082610199565b51902093612253610120870187611fec565b9060405180916020820180946122689261215d565b03601f198101825261227a9082610199565b51902095610140810161228c91611fec565b9060405180916020820180946122a19261215d565b03601f19810182526122b39082610199565b519020966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c526001600160a01b031660208c01526001600160a01b031660408b015260608a0152608089015260a08801526001600160a01b031660c087015260e08601526101008501526101208401526101408301526101608201526101800152565b634e487b7160e01b600052601160045260246000fd5b9190820180921161235e57565b61233b565b9061236d82610599565b61237a6040519182610199565b828152809261238b601f1991610599565b0190602036910137565b90815181101561107b570160200190565b600019811461235e5760010190565b9291906123c0611fcc565b506123cb8151612022565b9260005b825181101561242657806001600160a01b036123ed60019386612080565b51166123f98287612080565b516124056111626101cd565b60208201526124148288612080565b5261241f8187612080565b50016123cf565b509391505061243a61014082015160801c90565b9051906124456101dc565b9283526020830152604082015290565b906124608251612022565b9160005b81518110156124b5578061247a60019284612080565b51604051906124888261017d565b6001600160a01b038616825260208201526124a38287612080565b526124ae8186612080565b5001612464565b50505090565b611da06118b7565b805160209091019060005b8181106124db5750505090565b82516001600160a01b03168452602093840193909201916001016124ce565b805160209091019060005b8181106125125750505090565b8251845260209384019390920191600101612505565b909161014082015161253a9060401c90565b67ffffffffffffffff169361254d6124bb565b918351936020810151612566906001600160a01b031690565b9560408201516040518060208101928361257f916124c3565b03601f19810182526125919082610199565b51902092604051806020810192836125a8916124fa565b03601f19810182526125ba9082610199565b5190209060808301516125cc9061290b565b8051906020012060a08401516125e19061290b565b805190602001209060c08501516125f79061296b565b80519060200120926126089061296b565b8051906020012093610100860151612626906001600160a01b031690565b95610120015180519060200120966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a0152608089015260a088015260c087015260e08601526101008501526101208401526001600160a01b03166101408301526101608201526101800152565b919060808301926126cb845151612022565b9260005b85515181101561272557806126ea60019260c0860151612080565b51604051906126f88261017d565b6001600160a01b038716825260208201526127138288612080565b5261271e8187612080565b50016126cf565b509350505090565b611da0611c05565b906101408201516127469060401c90565b67ffffffffffffffff169361275961272d565b918351936020810151612772906001600160a01b031690565b956040820151612788906001600160a01b031690565b926080830151604051806020810192836127a1916124c3565b03601f19810182526127b39082610199565b51902060a0840151604051806020810192836127ce916124c3565b03601f19810182526127e09082610199565b5190209060c0850151604051806020810192836127fc916124fa565b03601f198101825261280e9082610199565b5190209260405180602081019283612825916124fa565b03601f19810182526128379082610199565b51902093610100860151612851906001600160a01b031690565b95610120015180519060200120966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a01526001600160a01b0316608089015260a088015260c087015260e08601526101008501526101208401526001600160a01b03166101408301526101608201526101800152565b6020929190612903849282815194859201610eb5565b019081520190565b60609080516000905b8082106129215750505090565b909193926001906129616129358588612080565b5160405161294b81610f7a6020820180956124c3565b51902091610f7a604051938492602084016128ed565b9394920190612914565b60609080516000905b8082106129815750505090565b909193926001906129ab6129958588612080565b5160405161294b81610f7a6020820180956124fa565b939492019061297456fea26469706673582212200e61f2bd5da65278e0dc9c3a6fe1f6c1228d2d4f1bf2d5a52191ba5c84e51f0d64736f6c634300081b0033000000000000000000000000beb0b0623f66be8ce162ebdfa2ec543a522f4ea6000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

Deployed Bytecode

0x6080604052600436101561001257600080fd5b60003560e01c806357c3af1e146100675780635abff4df1461006257806365221a021461005d57806377c19c1f146100585763fbfa3c5b1461005357600080fd5b610a27565b6107e5565b61050c565b610337565b34610141573660031901610220811261014157610160136101415761008a6101bb565b60043581526100976101fc565b60208201526100a4610209565b604082015260643560608201526100b9610216565b60808201526100c6610223565b60a082015260c43560c082015260e43560e08201526100e3610230565b610100820152610124356101208201526101443561014082015261010636610271565b906101c4359167ffffffffffffffff83116101415761012c61013f9336906004016102af565b61013461023e565b916102043593610c0b565b005b600080fd5b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff82111761017857604052565b610146565b6040810190811067ffffffffffffffff82111761017857604052565b90601f8019910116810190811067ffffffffffffffff82111761017857604052565b604051906101cb61016083610199565b565b604051906101cb604083610199565b604051906101cb606083610199565b6001600160a01b0381160361014157565b602435906101cb826101eb565b604435906101cb826101eb565b608435906101cb826101eb565b60a435906101cb826101eb565b61010435906101cb826101eb565b6101e435906101cb826101eb565b606435906101cb826101eb565b35906101cb826101eb565b3590811515820361014157565b606090610163190112610141576040519061028b8261015c565b8161016435801515810361014157815261018435602082015260406101a435910152565b81601f820112156101415780359067ffffffffffffffff821161017857604051926102e4601f8401601f191660200185610199565b8284526020838301011161014157816000926020809301838601378301015290565b9181601f840112156101415782359167ffffffffffffffff8311610141576020808501948460051b01011161014157565b346101415760803660031901126101415760043567ffffffffffffffff811161014157610368903690600401610306565b9060243567ffffffffffffffff811161014157610389903690600401610306565b60449391933590610399826101eb565b606435926103a6846101eb565b6001600160a01b037f000000000000000000000000beb0b0623f66be8ce162ebdfa2ec543a522f4ea616946103dc863314610bda565b60005b8281106103e857005b87868686868673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6104256104196104148a868661106b565b611080565b6001600160a01b031690565b1461045c578661045695936104496104196104148460019c9b999761044f9761106b565b9561106b565b3592611f0a565b016103df565b505050508891506001600160a01b03160361047a575b600190610456565b61048581858a61106b565b3590873b15610141576040517f7c317e0f0000000000000000000000000000000000000000000000000000000081526001600160a01b03881660048201526024810192909252600082604481838c5af1918215610507576001926104ec575b509050610472565b806104fb600061050193610199565b80610f88565b386104e4565b611049565b346101415760803660031901126101415760043567ffffffffffffffff81116101415761018060031982360301126101415760243567ffffffffffffffff811161014157366023820112156101415780600401359167ffffffffffffffff83116101415736602484840101116101415761013f9260443591602461058e61024c565b94019060040161108a565b67ffffffffffffffff81116101785760051b60200190565b9080601f830112156101415781356105c881610599565b926105d66040519485610199565b81845260208085019260051b82010192831161014157602001905b8282106105fe5750505090565b60208091833561060d816101eb565b8152019101906105f1565b9080601f8301121561014157813561062f81610599565b9261063d6040519485610199565b81845260208085019260051b82010192831161014157602001905b8282106106655750505090565b8135815260209182019101610658565b9080601f8301121561014157813561068c81610599565b9261069a6040519485610199565b81845260208085019260051b820101918383116101415760208201905b8382106106c657505050505090565b813567ffffffffffffffff8111610141576020916106e9878480948801016105b1565b8152019101906106b7565b9080601f8301121561014157813561070b81610599565b926107196040519485610199565b81845260208085019260051b820101918383116101415760208201905b83821061074557505050505090565b813567ffffffffffffffff81116101415760209161076887848094880101610618565b815201910190610736565b9190606083820312610141576040519061078c8261015c565b819361079781610264565b8352602081013567ffffffffffffffff811161014157826107b99183016106f4565b602084015260408101359167ffffffffffffffff8311610141576040926107e09201610618565b910152565b346101415760a03660031901126101415760043567ffffffffffffffff81116101415761016060031982360301126101415761081f6101bb565b908060040135825261083360248201610259565b6020830152604481013567ffffffffffffffff81116101415761085c90600436918401016105b1565b6040830152606481013567ffffffffffffffff8111610141576108859060043691840101610618565b6060830152608481013567ffffffffffffffff8111610141576108ae9060043691840101610675565b608083015260a481013567ffffffffffffffff8111610141576108d79060043691840101610675565b60a083015260c481013567ffffffffffffffff81116101415761090090600436918401016106f4565b60c083015260e481013567ffffffffffffffff81116101415761092990600436918401016106f4565b60e083015261093b6101048201610259565b6101008301526101248101359067ffffffffffffffff82116101415761096a61014492600436918401016102af565b610120840152013561014082015260243567ffffffffffffffff811161014157610998903690600401610773565b906044359167ffffffffffffffff8311610141576109bd61013f9336906004016102af565b6109c561024c565b91608435936114d9565b91909160608184031261014157604051906109e98261015c565b81936109f482610264565b835260208201359167ffffffffffffffff831161014157610a1b6040939284938301610618565b60208501520135910152565b346101415760a03660031901126101415760043567ffffffffffffffff811161014157610160600319823603011261014157610a616101bb565b9080600401358252610a7560248201610259565b6020830152610a8660448201610259565b604083015260648101356060830152608481013567ffffffffffffffff811161014157610ab990600436918401016105b1565b608083015260a481013567ffffffffffffffff811161014157610ae290600436918401016105b1565b60a083015260c481013567ffffffffffffffff811161014157610b0b9060043691840101610618565b60c083015260e481013567ffffffffffffffff811161014157610b349060043691840101610618565b60e0830152610b466101048201610259565b6101008301526101248101359067ffffffffffffffff821161014157610b7561014492600436918401016102af565b610120840152013561014082015260243567ffffffffffffffff811161014157610ba39036906004016109cf565b906044359167ffffffffffffffff831161014157610bc861013f9336906004016102af565b610bd061024c565b9160843593611ad0565b15610be157565b7f48f5c3ed0000000000000000000000000000000000000000000000000000000060005260046000fd5b90929193610cfe7f000000000000000000000000beb0b0623f66be8ce162ebdfa2ec543a522f4ea691610c486001600160a01b0384163314610bda565b6001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31693610c8760808201516001600160a01b031690565b9660c082018051610ca8610c996101cd565b6001600160a01b03909b168b52565b60208a015261014083015160801c835190610cc16101dc565b9a8b5260208b015260408a015251610ce9610cda6101cd565b6001600160a01b039097168752565b60208601526040602082015191015191611e40565b94610d07610ed8565b94833b1561014157610d4e600096928793604051998a98899788967f137c29fe00000000000000000000000000000000000000000000000000000000885260048801610fb8565b03925af1801561050757610d5f5750565b806104fb60006101cb93610199565b6040517f53696e676c654f726465722875696e74363420706172746e65725f69642c756960208201527f6e74323536206578706972792c616464726573732074616b65725f616464726560408201527f73732c61646472657373206d616b65725f616464726573732c75696e7432353660608201527f206d616b65725f6e6f6e63652c616464726573732074616b65725f746f6b656e60808201527f2c61646472657373206d616b65725f746f6b656e2c75696e743235362074616b60a08201527f65725f616d6f756e742c75696e74323536206d616b65725f616d6f756e742c6160c08201527f6464726573732072656365697665722c75696e74323536207061636b65645f6360e08201527f6f6d6d616e64732c6279746573333220686f6f6b73486173682900000000000061010082015260fa8152610eb261011a82610199565b90565b60005b838110610ec85750506000910152565b8181015183820152602001610eb8565b6034610eb2610ee5610d6e565b610f7a6040519384927f53696e676c654f72646572207769746e657373290000000000000000000000006020850152610f278151809260208588019101610eb5565b830101602e907f546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c7581527f696e7432353620616d6f756e742900000000000000000000000000000000000060208201520190565b03601f198101835282610199565b600091031261014157565b90602091610fac81518092818552858086019101610eb5565b601f01601f1916010190565b949161103a9361101b6001600160a01b03926040610eb29a9895610ff08b8251602080916001600160a01b0381511684520151910152565b6020818101518c84015291015160608b015281516001600160a01b031660808b0152015160a0890152565b1660c086015260e0850152610140610100850152610140840190610f93565b91610120818403910152610f93565b6040513d6000823e3d90fd5b634e487b7160e01b600052603260045260246000fd5b919081101561107b5760051b0190565b611055565b35610eb2816101eb565b9190946110c16001600160a01b037f000000000000000000000000beb0b0623f66be8ce162ebdfa2ec543a522f4ea6163314610bda565b6001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba316916110f4611fcc565b5060e084019261110e6111078587611fec565b9050612022565b956000986101208701995b6111238789611fec565b905081101561119257808b6111568261114961114f6104146001978f8f61114991611fec565b9061106b565b938d611fec565b356111716111626101cd565b6001600160a01b039093168352565b6020820152611180828c612080565b5261118b818b612080565b5001611119565b509296976111c9919499506111d992955060808701356040880135906111b66101dc565b9a8b5260208b015260408a015286612094565b926111d386611080565b95612191565b956111e2611353565b843b15610141576000968793610d4e926040519a8b998a98899763fe8ec1a760e01b895260048901611464565b6040517f4a616d4f7264657228616464726573732074616b65722c61646472657373207260208201527f656365697665722c75696e74323536206578706972792c75696e74323536206560408201527f78636c75736976697479446561646c696e652c75696e74323536206e6f6e636560608201527f2c61646472657373206578656375746f722c75696e7432353620706172746e6560808201527f72496e666f2c616464726573735b5d2073656c6c546f6b656e732c616464726560a08201527f73735b5d20627579546f6b656e732c75696e743235365b5d2073656c6c416d6f60c08201527f756e74732c75696e743235365b5d20627579416d6f756e74732c62797465733360e08201527f3220686f6f6b734861736829000000000000000000000000000000000000000061010082015260ec8152610eb261010c82610199565b6031610eb261136061120f565b610f7a6040519384927f4a616d4f72646572207769746e657373290000000000000000000000000000006020850152610f278151809260208588019101610eb5565b90606081019180519260608352835180915260206080840194019060005b8181106113e0575050506040816020829301516020850152015191015290565b90919460206040826114086001948a51602080916001600160a01b0381511684520151910152565b0196019291016113c0565b906020808351928381520192019060005b8181106114315750505090565b90919260206040826114596001948851602080916001600160a01b0381511684520151910152565b019401929101611424565b959290948795946001600160a01b0361149c6114b59561148f60209c9960c08d5260c08d01906113a2565b908b82038d8d0152611413565b9316604089015260608801528682036080880152610f93565b9360a0818603910152818452848401376000828201840152601f01601f1916010190565b949361150f6001600160a01b037f000000000000000000000000beb0b0623f66be8ce162ebdfa2ec543a522f4ea6163314610bda565b600092839484955b604089015151871015611548576115406001916115388960808d0151612080565b515190612351565b960195611517565b93979691945091945061156361155d84612363565b93612363565b936000926000986000995b60408a0151518b10156117fc5761158d906115388c60a08d0151612080565b8a8a61159d826080830151612080565b515160005b8181106115c7575050916115386115bf9260806001950151612080565b9a019961156e565b917f080000000000000000000000000000000000000000000000000000000000000091935061164f6116296101207fff000000000000000000000000000000000000000000000000000000000000009301516116238689612351565b90612395565b517fff000000000000000000000000000000000000000000000000000000000000001690565b16141580156117f4575b61166a575b6001018c918c916115a2565b8c8c6001918361169861168b82611685856080880151612080565b51612080565b516001600160a01b031690565b917f04000000000000000000000000000000000000000000000000000000000000007fff000000000000000000000000000000000000000000000000000000000000006116f26116298b611623876101208b015192612351565b16146117d8575b6117148f94968f928f959497989060c0611685920151612080565b51936000905b84821061176f575b5050600195611737575b50505050905061165e565b6117529261174491612080565b906001600160a01b03169052565b61176561175e8b6123a6565b9a8d612080565b523889818c61172c565b9092949596939161168b8461178392612080565b6001600160a01b038087169116146117a7575050600101918c8c929594938f61171a565b9092506117cd826117c7876117c160019a99989686612080565b51612351565b92612080565b528c6000958f611722565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92506116f9565b506000611659565b5093611880939950979095969197808652875261186f611847886001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba31697846123b5565b977f000000000000000000000000beb0b0623f66be8ce162ebdfa2ec543a522f4ea690612455565b936040602082015191015191612528565b94611889611a23565b94833b1561014157610d4e600096928793604051998a988997889663fe8ec1a760e01b885260048801611a72565b6040517f4167677265676174654f726465722875696e74363420706172746e65725f696460208201527f2c75696e74323536206578706972792c616464726573732074616b65725f616460408201527f64726573732c616464726573735b5d206d616b65725f6164647265737365732c60608201527f75696e743235365b5d206d616b65725f6e6f6e6365732c616464726573735b5d60808201527f5b5d2074616b65725f746f6b656e732c616464726573735b5d5b5d206d616b6560a08201527f725f746f6b656e732c75696e743235365b5d5b5d2074616b65725f616d6f756e60c08201527f74732c75696e743235365b5d5b5d206d616b65725f616d6f756e74732c61646460e08201527f726573732072656365697665722c627974657320636f6d6d616e64732c6279746101008201527f6573333220686f6f6b734861736829000000000000000000000000000000000061012082015261010f8152610eb261012f82610199565b6037610eb2611a306118b7565b610f7a6040519384927f4167677265676174654f72646572207769746e657373290000000000000000006020850152610f278151809260208588019101610eb5565b9490936001600160a01b03611aa9611ac29594611a9b610eb29a9860c08b5260c08b01906113a2565b9089820360208b0152611413565b9316604087015260608601528482036080860152610f93565b9160a0818403910152610f93565b94909392917f000000000000000000000000beb0b0623f66be8ce162ebdfa2ec543a522f4ea692611b0b6001600160a01b0385163314610bda565b6001600160a01b037f000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba316611b3d611fcc565b506080880196611b4e885151612022565b9660009960c081019a5b8a518051821015611bac57908c611b7f82611b7861168b82600197612080565b9251612080565b51611b8b6111626101cd565b6020820152611b9a828d612080565b52611ba5818c612080565b5001611b58565b50509194985091949850611beb611bfc9396611bcd61014084015160801c90565b835190611bd86101dc565b9a8b5260208b015260408a0152826126b9565b936040602082015191015191612735565b94611889611d49565b6040517f4d756c74694f726465722875696e74363420706172746e65725f69642c75696e60208201527f74323536206578706972792c616464726573732074616b65725f61646472657360408201527f732c61646472657373206d616b65725f616464726573732c75696e743235362060608201527f6d616b65725f6e6f6e63652c616464726573735b5d2074616b65725f746f6b6560808201527f6e732c616464726573735b5d206d616b65725f746f6b656e732c75696e74323560a08201527f365b5d2074616b65725f616d6f756e74732c75696e743235365b5d206d616b6560c08201527f725f616d6f756e74732c616464726573732072656365697665722c627974657360e08201527f20636f6d6d616e64732c6279746573333220686f6f6b7348617368290000000061010082015260fc8152610eb261011c82610199565b6033610eb2611d56611c05565b610f7a6040519384927f4d756c74694f72646572207769746e65737329000000000000000000000000006020850152610f278151809260208588019101610eb5565b611da0610d6e565b6020815191012090565b9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a01526001600160a01b0316608089015260a08801526001600160a01b031660c087015260e08601611e18916001600160a01b03169052565b6101008501526101208401526001600160a01b03166101408301526101608201526101800152565b909161014082015160401c611e5c9067ffffffffffffffff1690565b93611e65611d98565b918351936020810151611e7e906001600160a01b031690565b956040820151611e94906001600160a01b031690565b926080830151611eaa906001600160a01b031690565b60a08401516001600160a01b03169060c085015192610100860151611ed5906001600160a01b031690565b956101200151966040519b8c9b60208d019e8f9c611ef29d611daa565b03601f1981018252611f049082610199565b51902090565b9060006064926020956001600160a01b03839681604051967f23b872dd00000000000000000000000000000000000000000000000000000000885216600487015216602485015260448401525af13d15601f3d1160016000511416171615611f6e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b60405190611fd98261015c565b6000604083606081528260208201520152565b903590601e1981360301821215610141570180359067ffffffffffffffff821161014157602001918160051b3603831361014157565b9061202c82610599565b6120396040519182610199565b828152809261204a601f1991610599565b019060005b82811061205b57505050565b60209060405161206a8161017d565b600081526000838201528282850101520161204f565b805182101561107b5760209160051b010190565b9060e08201916120a76111078483611fec565b9360005b6120b58584611fec565b9050811015612113576001816120d66120b593611149610120880188611fec565b35604051906120e48261017d565b6001600160a01b038816825260208201526120ff828a612080565b5261210a8189612080565b500190506120ab565b5092505050565b611da061120f565b9060005b8181106121335750505090565b9091926020806001926001600160a01b03873561214f816101eb565b168152019401929101612126565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81116101415760051b809282370190565b61219961211a565b916121a382611080565b926121b060208401611080565b91604084013593606081013590608081013560a082016121cf90611080565b60c08301356121e160e0850185611fec565b9060405180916020820180946121f692612122565b03601f19810182526122089082610199565b5190209161221a610100860186611fec565b90604051809160208201809461222f92612122565b03601f19810182526122419082610199565b51902093612253610120870187611fec565b9060405180916020820180946122689261215d565b03601f198101825261227a9082610199565b51902095610140810161228c91611fec565b9060405180916020820180946122a19261215d565b03601f19810182526122b39082610199565b519020966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c526001600160a01b031660208c01526001600160a01b031660408b015260608a0152608089015260a08801526001600160a01b031660c087015260e08601526101008501526101208401526101408301526101608201526101800152565b634e487b7160e01b600052601160045260246000fd5b9190820180921161235e57565b61233b565b9061236d82610599565b61237a6040519182610199565b828152809261238b601f1991610599565b0190602036910137565b90815181101561107b570160200190565b600019811461235e5760010190565b9291906123c0611fcc565b506123cb8151612022565b9260005b825181101561242657806001600160a01b036123ed60019386612080565b51166123f98287612080565b516124056111626101cd565b60208201526124148288612080565b5261241f8187612080565b50016123cf565b509391505061243a61014082015160801c90565b9051906124456101dc565b9283526020830152604082015290565b906124608251612022565b9160005b81518110156124b5578061247a60019284612080565b51604051906124888261017d565b6001600160a01b038616825260208201526124a38287612080565b526124ae8186612080565b5001612464565b50505090565b611da06118b7565b805160209091019060005b8181106124db5750505090565b82516001600160a01b03168452602093840193909201916001016124ce565b805160209091019060005b8181106125125750505090565b8251845260209384019390920191600101612505565b909161014082015161253a9060401c90565b67ffffffffffffffff169361254d6124bb565b918351936020810151612566906001600160a01b031690565b9560408201516040518060208101928361257f916124c3565b03601f19810182526125919082610199565b51902092604051806020810192836125a8916124fa565b03601f19810182526125ba9082610199565b5190209060808301516125cc9061290b565b8051906020012060a08401516125e19061290b565b805190602001209060c08501516125f79061296b565b80519060200120926126089061296b565b8051906020012093610100860151612626906001600160a01b031690565b95610120015180519060200120966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a0152608089015260a088015260c087015260e08601526101008501526101208401526001600160a01b03166101408301526101608201526101800152565b919060808301926126cb845151612022565b9260005b85515181101561272557806126ea60019260c0860151612080565b51604051906126f88261017d565b6001600160a01b038716825260208201526127138288612080565b5261271e8187612080565b50016126cf565b509350505090565b611da0611c05565b906101408201516127469060401c90565b67ffffffffffffffff169361275961272d565b918351936020810151612772906001600160a01b031690565b956040820151612788906001600160a01b031690565b926080830151604051806020810192836127a1916124c3565b03601f19810182526127b39082610199565b51902060a0840151604051806020810192836127ce916124c3565b03601f19810182526127e09082610199565b5190209060c0850151604051806020810192836127fc916124fa565b03601f198101825261280e9082610199565b5190209260405180602081019283612825916124fa565b03601f19810182526128379082610199565b51902093610100860151612851906001600160a01b031690565b95610120015180519060200120966040519b8c9b60208d019e8f9c611ef29d9a98969492909d9c9b99979593916101a08c019e8c5267ffffffffffffffff1660208c015260408b01526001600160a01b031660608a01526001600160a01b0316608089015260a088015260c087015260e08601526101008501526101208401526001600160a01b03166101408301526101608201526101800152565b6020929190612903849282815194859201610eb5565b019081520190565b60609080516000905b8082106129215750505090565b909193926001906129616129358588612080565b5160405161294b81610f7a6020820180956124c3565b51902091610f7a604051938492602084016128ed565b9394920190612914565b60609080516000905b8082106129815750505090565b909193926001906129ab6129958588612080565b5160405161294b81610f7a6020820180956124fa565b939492019061297456fea26469706673582212200e61f2bd5da65278e0dc9c3a6fe1f6c1228d2d4f1bf2d5a52191ba5c84e51f0d64736f6c634300081b0033

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

000000000000000000000000beb0b0623f66be8ce162ebdfa2ec543a522f4ea6000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3

-----Decoded View---------------
Arg [0] : _operator (address): 0xbeb0b0623f66bE8cE162EbDfA2ec543A522F4ea6
Arg [1] : _permit2 (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000beb0b0623f66be8ce162ebdfa2ec543a522f4ea6
Arg [1] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3


Block Transaction Gas Used Reward
view all blocks ##produced##

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

Validator Index Block Amount
View All Withdrawals

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

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.